From nobody Fri Jul 24 22:54:36 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 875672EC086; Wed, 22 Jul 2026 13:36:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784727363; cv=none; b=Hl8HHOzLQJ+Zps+KX0LKamuNOSRvDxGu5+Bnim6hw2sgoG/OABO6JmyBswajrC8sYktiBX4iVYnc5t4OcnZKejSgQHAbq1vS0bhLP3vTKLtBKATdoweU0LzD59bxEdKnzGMfe4OokrmafgnAynMl3bOIA26qQzF2pTXiw7fhkUs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784727363; c=relaxed/simple; bh=FieeTyDaNaPOsrYGGB6iD+vvTeAt0ZU7WNnsiuauFTk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CjNipMqyihpkxH6EYJZO39Axko6THgVFNDqL5hQU0jfz8OSiqfMIgO5kuZIvZ5rYouqRGjjpF3s5XOUnd/R9w5jJt7LtmuW7p1BuxjaURNHGEzZGKiZcSdU9Ji9cLU1oTzJ71TMYNmAPV8aQl0ukIvaMNukbwC6hb7s7PDVNcxQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=hoWv1yPK; arc=none smtp.client-ip=198.175.65.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="hoWv1yPK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784727362; x=1816263362; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FieeTyDaNaPOsrYGGB6iD+vvTeAt0ZU7WNnsiuauFTk=; b=hoWv1yPKIZbQoAuSU/Z/Ht10fs8p1uY3B6aFKcfgQ6mYQ1CJywRUAyOw oE7bZ74RpXkIzQSdxdbZQ2CxuaR2bKXRsgBm5Jg5Pf7eAKgsj65Dv9HXI 034suqmf24ke+Wgl0ZIhvGTmjbRIcCaaT55n3rKSLW6qnrRTrZsrBz5pl 64iDrBOAjPOrfFBNYyNnJghBQO0PjtF/+eypFmU5xiBRdGpi7Gl0UYCms FfUw9aEw4Z0Xb3xL+Vm+LiJMl41pu2byVf2so5pQ560vaBq0HcCVQgWSd gjlhy5H3nfZsz8IaeAgxMqQD6BB4A7iEXX1Or9yaYf2owSL/FN0XbqNlw w==; X-CSE-ConnectionGUID: HHLXUjseTnmpVm8+CT8FiQ== X-CSE-MsgGUID: DvwgyGBOSDGdG3p7G0EglQ== X-IronPort-AV: E=McAfee;i="6800,10657,11854"; a="85453397" X-IronPort-AV: E=Sophos;i="6.25,178,1779174000"; d="scan'208";a="85453397" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jul 2026 06:36:01 -0700 X-CSE-ConnectionGUID: 7hdKmHNISn+0P+GWZ3cZyg== X-CSE-MsgGUID: 64sI14AFSwWAqdtx0aHEeA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,178,1779174000"; d="scan'208";a="263040975" Received: from black.igk.intel.com ([10.91.253.5]) by fmviesa005.fm.intel.com with ESMTP; 22 Jul 2026 06:35:58 -0700 From: Heikki Krogerus To: Matthew Brost , =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= , Rodrigo Vivi , Raag Jadav , Mika Westerberg , Andy Shevchenko Cc: Andi Shyti , Ramesh Babu B , "Michael J. Ruhl" , linux-kernel@vger.kernel.org, intel-xe@lists.freedesktop.org, stable@vger.kernel.org Subject: [PATCH v6 1/3] i2c: designware: Global register definitions Date: Wed, 22 Jul 2026 15:35:52 +0200 Message-ID: <20260722133554.2079612-2-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260722133554.2079612-1-heikki.krogerus@linux.intel.com> References: <20260722133554.2079612-1-heikki.krogerus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Moving the register definitions to a global header file include/linux/designware_i2c.h. That removes the need to duplicate them in the adaptation layers for this driver outside of drivers/i2c/busses/. There is at least one of those in drivers/gpu/drm/xe/xe_i2c.c. Suggested-by: Andy Shevchenko Suggested-by: Raag Jadav Reviewed-by: Raag Jadav Reviewed-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Heikki Krogerus --- MAINTAINERS | 1 + drivers/i2c/busses/i2c-designware-common.c | 2 + drivers/i2c/busses/i2c-designware-core.h | 85 +--------------- drivers/i2c/busses/i2c-designware-master.c | 2 + drivers/i2c/busses/i2c-designware-slave.c | 2 + include/linux/designware_i2c.h | 107 +++++++++++++++++++++ 6 files changed, 116 insertions(+), 83 deletions(-) create mode 100644 include/linux/designware_i2c.h diff --git a/MAINTAINERS b/MAINTAINERS index 1ecdc6cd9c147..08a11bff8eea1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26247,6 +26247,7 @@ R: Andy Shevchenko L: linux-i2c@vger.kernel.org S: Supported F: drivers/i2c/busses/i2c-designware-* +F: include/linux/designware_i2c.h =20 SYNOPSYS DESIGNWARE I2C DRIVER - AMDISP M: Nirujogi Pratap diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busse= s/i2c-designware-common.c index e4dfa2ec58bb7..a1eca6cd4b75e 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -33,6 +33,8 @@ #include #include =20 +#include + #include "i2c-designware-core.h" =20 #define DW_IC_DEFAULT_BUS_CAPACITANCE_pF 100 diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/= i2c-designware-core.h index c71aa2dd368d5..2c929a6e8da2a 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -18,6 +18,8 @@ #include #include =20 +#include + #define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ I2C_FUNC_SMBUS_BYTE | \ I2C_FUNC_SMBUS_BYTE_DATA | \ @@ -25,23 +27,6 @@ I2C_FUNC_SMBUS_BLOCK_DATA | \ I2C_FUNC_SMBUS_I2C_BLOCK) =20 -#define DW_IC_CON_MASTER BIT(0) -#define DW_IC_CON_SPEED_STD (1 << 1) -#define DW_IC_CON_SPEED_FAST (2 << 1) -#define DW_IC_CON_SPEED_HIGH (3 << 1) -#define DW_IC_CON_SPEED_MASK GENMASK(2, 1) -#define DW_IC_CON_10BITADDR_SLAVE BIT(3) -#define DW_IC_CON_10BITADDR_MASTER BIT(4) -#define DW_IC_CON_RESTART_EN BIT(5) -#define DW_IC_CON_SLAVE_DISABLE BIT(6) -#define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7) -#define DW_IC_CON_TX_EMPTY_CTRL BIT(8) -#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9) -#define DW_IC_CON_BUS_CLEAR_CTRL BIT(11) - -#define DW_IC_DATA_CMD_DAT GENMASK(7, 0) -#define DW_IC_DATA_CMD_FIRST_DATA_BYTE BIT(11) - /* * Register access parameters */ @@ -55,65 +40,9 @@ #define DW_IC_FIFO_RX_FIELD GENMASK(15, 8) #define DW_IC_FIFO_MIN_DEPTH 2 =20 -/* - * Registers offset - */ -#define DW_IC_CON 0x00 -#define DW_IC_TAR 0x04 -#define DW_IC_SAR 0x08 -#define DW_IC_DATA_CMD 0x10 -#define DW_IC_SS_SCL_HCNT 0x14 -#define DW_IC_SS_SCL_LCNT 0x18 -#define DW_IC_FS_SCL_HCNT 0x1c -#define DW_IC_FS_SCL_LCNT 0x20 -#define DW_IC_HS_SCL_HCNT 0x24 -#define DW_IC_HS_SCL_LCNT 0x28 -#define DW_IC_INTR_STAT 0x2c -#define DW_IC_INTR_MASK 0x30 -#define DW_IC_RAW_INTR_STAT 0x34 -#define DW_IC_RX_TL 0x38 -#define DW_IC_TX_TL 0x3c -#define DW_IC_CLR_INTR 0x40 -#define DW_IC_CLR_RX_UNDER 0x44 -#define DW_IC_CLR_RX_OVER 0x48 -#define DW_IC_CLR_TX_OVER 0x4c -#define DW_IC_CLR_RD_REQ 0x50 -#define DW_IC_CLR_TX_ABRT 0x54 -#define DW_IC_CLR_RX_DONE 0x58 -#define DW_IC_CLR_ACTIVITY 0x5c -#define DW_IC_CLR_STOP_DET 0x60 -#define DW_IC_CLR_START_DET 0x64 -#define DW_IC_CLR_GEN_CALL 0x68 -#define DW_IC_ENABLE 0x6c -#define DW_IC_STATUS 0x70 -#define DW_IC_TXFLR 0x74 -#define DW_IC_RXFLR 0x78 -#define DW_IC_SDA_HOLD 0x7c -#define DW_IC_TX_ABRT_SOURCE 0x80 -#define DW_IC_ENABLE_STATUS 0x9c -#define DW_IC_CLR_RESTART_DET 0xa8 -#define DW_IC_SMBUS_INTR_MASK 0xcc -#define DW_IC_COMP_PARAM_1 0xf4 -#define DW_IC_COMP_VERSION 0xf8 #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" =3D=3D v1.11* */ -#define DW_IC_COMP_TYPE 0xfc #define DW_IC_COMP_TYPE_VALUE 0x44570140 /* "DW" + 0x0140 */ =20 -#define DW_IC_INTR_RX_UNDER BIT(0) -#define DW_IC_INTR_RX_OVER BIT(1) -#define DW_IC_INTR_RX_FULL BIT(2) -#define DW_IC_INTR_TX_OVER BIT(3) -#define DW_IC_INTR_TX_EMPTY BIT(4) -#define DW_IC_INTR_RD_REQ BIT(5) -#define DW_IC_INTR_TX_ABRT BIT(6) -#define DW_IC_INTR_RX_DONE BIT(7) -#define DW_IC_INTR_ACTIVITY BIT(8) -#define DW_IC_INTR_STOP_DET BIT(9) -#define DW_IC_INTR_START_DET BIT(10) -#define DW_IC_INTR_GEN_CALL BIT(11) -#define DW_IC_INTR_RESTART_DET BIT(12) -#define DW_IC_INTR_MST_ON_HOLD BIT(13) - #define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \ DW_IC_INTR_TX_ABRT | \ DW_IC_INTR_STOP_DET) @@ -123,16 +52,6 @@ DW_IC_INTR_RX_UNDER | \ DW_IC_INTR_RD_REQ) =20 -#define DW_IC_ENABLE_ENABLE BIT(0) -#define DW_IC_ENABLE_ABORT BIT(1) - -#define DW_IC_STATUS_ACTIVITY BIT(0) -#define DW_IC_STATUS_TFE BIT(2) -#define DW_IC_STATUS_RFNE BIT(3) -#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5) -#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6) -#define DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY BIT(7) - #define DW_IC_SDA_HOLD_RX_SHIFT 16 #define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16) =20 diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busse= s/i2c-designware-master.c index 7a301c8b604ef..a1bcc3797e4ff 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -25,6 +25,8 @@ #include #include =20 +#include + #include "i2c-designware-core.h" =20 #define AMD_TIMEOUT_MIN_US 25 diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses= /i2c-designware-slave.c index ad0d5fbfa6d5e..0abcc7757b231 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -19,6 +19,8 @@ #include #include =20 +#include + #include "i2c-designware-core.h" =20 int i2c_dw_reg_slave(struct i2c_client *slave) diff --git a/include/linux/designware_i2c.h b/include/linux/designware_i2c.h new file mode 100644 index 0000000000000..53f37f18a7229 --- /dev/null +++ b/include/linux/designware_i2c.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Synopsys DesignWare I2C register definitions + * + * Copyright (C) 2026, Intel Corporation + */ + +#ifndef __LINUX_DESIGNWARE_I2C_H +#define __LINUX_DESIGNWARE_I2C_H + +#include + +/* + * Registers offset + */ +#define DW_IC_CON 0x00 +#define DW_IC_TAR 0x04 +#define DW_IC_SAR 0x08 +#define DW_IC_DATA_CMD 0x10 +#define DW_IC_SS_SCL_HCNT 0x14 +#define DW_IC_SS_SCL_LCNT 0x18 +#define DW_IC_FS_SCL_HCNT 0x1c +#define DW_IC_FS_SCL_LCNT 0x20 +#define DW_IC_HS_SCL_HCNT 0x24 +#define DW_IC_HS_SCL_LCNT 0x28 +#define DW_IC_INTR_STAT 0x2c +#define DW_IC_INTR_MASK 0x30 +#define DW_IC_RAW_INTR_STAT 0x34 +#define DW_IC_RX_TL 0x38 +#define DW_IC_TX_TL 0x3c +#define DW_IC_CLR_INTR 0x40 +#define DW_IC_CLR_RX_UNDER 0x44 +#define DW_IC_CLR_RX_OVER 0x48 +#define DW_IC_CLR_TX_OVER 0x4c +#define DW_IC_CLR_RD_REQ 0x50 +#define DW_IC_CLR_TX_ABRT 0x54 +#define DW_IC_CLR_RX_DONE 0x58 +#define DW_IC_CLR_ACTIVITY 0x5c +#define DW_IC_CLR_STOP_DET 0x60 +#define DW_IC_CLR_START_DET 0x64 +#define DW_IC_CLR_GEN_CALL 0x68 +#define DW_IC_ENABLE 0x6c +#define DW_IC_STATUS 0x70 +#define DW_IC_TXFLR 0x74 +#define DW_IC_RXFLR 0x78 +#define DW_IC_SDA_HOLD 0x7c +#define DW_IC_TX_ABRT_SOURCE 0x80 +#define DW_IC_ENABLE_STATUS 0x9c +#define DW_IC_CLR_RESTART_DET 0xa8 +#define DW_IC_SMBUS_INTR_STAT 0xc8 +#define DW_IC_SMBUS_INTR_MASK 0xcc +#define DW_IC_CLR_SMBUS_INTR 0xd4 +#define DW_IC_COMP_PARAM_1 0xf4 +#define DW_IC_COMP_VERSION 0xf8 +#define DW_IC_COMP_TYPE 0xfc + +/* DW_IC_CON bits */ +#define DW_IC_CON_MASTER BIT(0) +#define DW_IC_CON_SPEED_STD (1 << 1) +#define DW_IC_CON_SPEED_FAST (2 << 1) +#define DW_IC_CON_SPEED_HIGH (3 << 1) +#define DW_IC_CON_SPEED_MASK GENMASK(2, 1) +#define DW_IC_CON_10BITADDR_SLAVE BIT(3) +#define DW_IC_CON_10BITADDR_MASTER BIT(4) +#define DW_IC_CON_RESTART_EN BIT(5) +#define DW_IC_CON_SLAVE_DISABLE BIT(6) +#define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7) +#define DW_IC_CON_TX_EMPTY_CTRL BIT(8) +#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9) +#define DW_IC_CON_BUS_CLEAR_CTRL BIT(11) + +/* DW_IC_DATA_CMD bits */ +#define DW_IC_DATA_CMD_DAT GENMASK(7, 0) +#define DW_IC_DATA_CMD_FIRST_DATA_BYTE BIT(11) + +/* DW_IC_INTR_* bits */ +#define DW_IC_INTR_RX_UNDER BIT(0) +#define DW_IC_INTR_RX_OVER BIT(1) +#define DW_IC_INTR_RX_FULL BIT(2) +#define DW_IC_INTR_TX_OVER BIT(3) +#define DW_IC_INTR_TX_EMPTY BIT(4) +#define DW_IC_INTR_RD_REQ BIT(5) +#define DW_IC_INTR_TX_ABRT BIT(6) +#define DW_IC_INTR_RX_DONE BIT(7) +#define DW_IC_INTR_ACTIVITY BIT(8) +#define DW_IC_INTR_STOP_DET BIT(9) +#define DW_IC_INTR_START_DET BIT(10) +#define DW_IC_INTR_GEN_CALL BIT(11) +#define DW_IC_INTR_RESTART_DET BIT(12) +#define DW_IC_INTR_MST_ON_HOLD BIT(13) + +/* DW_IC_ENABLE bits */ +#define DW_IC_ENABLE_ENABLE BIT(0) +#define DW_IC_ENABLE_ABORT BIT(1) + +/* DW_IC_STATUS bits */ +#define DW_IC_STATUS_ACTIVITY BIT(0) +#define DW_IC_STATUS_TFE BIT(2) +#define DW_IC_STATUS_RFNE BIT(3) +#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5) +#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6) +#define DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY BIT(7) + +/* DW_IC_SMBUS_INTR_* bits */ +#define DW_IC_SMBUS_INTR_ALERT BIT(10) + +#endif /* __LINUX_DESIGNWARE_I2C_H */ --=20 2.50.1 From nobody Fri Jul 24 22:54:36 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CCEF5285CB9; Wed, 22 Jul 2026 13:36:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784727366; cv=none; b=kkEbG/xFgTmQ/X76NCSsxmllIK+H7mIfarTHKpFJ3o/NExhswa0msmC/o5LX6sFA+6chWT/BF1m0CRFZ0aG1KrnGUlfEccMAqulAhpWaPzd1NHrTCCYb9nMbM7Fv3RqLy2wDdpOgCiYGAhiSLDA3HNbWx8+EpjKGZb+24ZGNePU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784727366; c=relaxed/simple; bh=zJr0/T3wDMfcKCcVWjSfjDuLwOJrYfwozxzx+vne6Nk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ISMy3vxbO6q/99wHzBUKVlq+GuW3Esv2hMW68wf/5BCNSrC4QT0yPqjSTw3GyR/1YlKL+maOkYiGE2JG1iIkEbS2R0w7Z6rGZXSLTC6TMZQh4FZ5/z6oTKRlBnVNHy1/lVlsle7TvehHltcX84j2LhcedWBoy68uZD/8Sw+B0Xw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=j4pIUr0N; arc=none smtp.client-ip=198.175.65.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="j4pIUr0N" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784727365; x=1816263365; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=zJr0/T3wDMfcKCcVWjSfjDuLwOJrYfwozxzx+vne6Nk=; b=j4pIUr0N3cjgcFypoyNwR8uyquQFQ52RUVN6BLIlDpYmo1DJovSYi9am hirfsSDFxAxMdMB+nv99Efr0pNBV2er0nzPlUvgVlsAe+ZeFGOqqObh97 sa+banempHhhF/xmKaFl/9ehtFmUAr7Ka541k8O0iegws2JEFezCvWx0X RlwIv9nHni8eUGZzK4QJq5MdcrWjlzmjHMV1B/PXVHOruT6Sal5Zavvrl PdCgIxm2lE+EoO1rTHyR0w/1x7c8FpPvBtkc+Mjj7vE8usFK9uf2IW5Eq 1LTot59Elh8z0QFXXIACnI2rqlgqvNKv5/eh7909aCOVSjZoRmpKGHdeY g==; X-CSE-ConnectionGUID: z8cucK5gQgKasmrjSqdO0A== X-CSE-MsgGUID: EyTjozsYT7SwOZ7TMYmnqA== X-IronPort-AV: E=McAfee;i="6800,10657,11854"; a="85453406" X-IronPort-AV: E=Sophos;i="6.25,178,1779174000"; d="scan'208";a="85453406" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jul 2026 06:36:04 -0700 X-CSE-ConnectionGUID: TZ6HyrksSQiyCbtPlTyL8A== X-CSE-MsgGUID: FIDfWbVRQoew0cvK/5OvRg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,178,1779174000"; d="scan'208";a="263040990" Received: from black.igk.intel.com ([10.91.253.5]) by fmviesa005.fm.intel.com with ESMTP; 22 Jul 2026 06:36:01 -0700 From: Heikki Krogerus To: Matthew Brost , =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= , Rodrigo Vivi , Raag Jadav , Mika Westerberg , Andy Shevchenko Cc: Andi Shyti , Ramesh Babu B , "Michael J. Ruhl" , linux-kernel@vger.kernel.org, intel-xe@lists.freedesktop.org, stable@vger.kernel.org Subject: [PATCH v6 2/3] drm/xe/i2c: Fix the interrupt handling Date: Wed, 22 Jul 2026 15:35:53 +0200 Message-ID: <20260722133554.2079612-3-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260722133554.2079612-1-heikki.krogerus@linux.intel.com> References: <20260722133554.2079612-1-heikki.krogerus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The platforms that support the interrupt from the I2C adapter can not handle the amount of interrupts the adapter generates because of the way the IRQ is routed in the hardware. The I2C controller driver has to be kept in polling mode because of that. The AMC MCU can still generate critical alerts that have to be handled. The interrupt from SMBus Alert is left enabled and handled separately in the Xe. The alerts from the AMC will cause the device to be declared wedged for now. Fixes: f0e53aadd702 ("drm/xe: Support for I2C attached MCUs") Cc: stable@vger.kernel.org Co-developed-by: Ramesh Babu B Signed-off-by: Ramesh Babu B Signed-off-by: Heikki Krogerus --- drivers/gpu/drm/xe/Makefile | 4 +- drivers/gpu/drm/xe/regs/xe_i2c_regs.h | 2 + drivers/gpu/drm/xe/xe_amc.c | 187 ++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_amc.h | 25 ++++ drivers/gpu/drm/xe/xe_i2c.c | 128 +++++++----------- drivers/gpu/drm/xe/xe_i2c.h | 13 +- 6 files changed, 272 insertions(+), 87 deletions(-) create mode 100644 drivers/gpu/drm/xe/xe_amc.c create mode 100644 drivers/gpu/drm/xe/xe_amc.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 67ada1d6c2fb9..c92468cb9b894 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -153,7 +153,9 @@ xe-y +=3D xe_bb.o \ xe_wait_user_fence.o \ xe_wopcm.o =20 -xe-$(CONFIG_I2C) +=3D xe_i2c.o +xe-$(CONFIG_I2C) +=3D xe_i2c.o \ + xe_amc.o + xe-$(CONFIG_DRM_XE_GPUSVM) +=3D xe_svm.o xe-$(CONFIG_DRM_GPUSVM) +=3D xe_userptr.o =20 diff --git a/drivers/gpu/drm/xe/regs/xe_i2c_regs.h b/drivers/gpu/drm/xe/reg= s/xe_i2c_regs.h index f2e455e2bfe45..37550e4a20f80 100644 --- a/drivers/gpu/drm/xe/regs/xe_i2c_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_i2c_regs.h @@ -20,4 +20,6 @@ #define I2C_CONFIG_CMD XE_REG(I2C_CONFIG_SPACE_OFFSET + PCI_COMMAND) #define I2C_CONFIG_PMCSR XE_REG(I2C_CONFIG_SPACE_OFFSET + 0x84) =20 +#define I2C_REG(reg) XE_REG((reg) + I2C_MEM_SPACE_OFFSET) + #endif /* _XE_I2C_REGS_H_ */ diff --git a/drivers/gpu/drm/xe/xe_amc.c b/drivers/gpu/drm/xe/xe_amc.c new file mode 100644 index 0000000000000..5a1286ad58be4 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_amc.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Intel Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "regs/xe_i2c_regs.h" + +#include "xe_amc.h" +#include "xe_device.h" +#include "xe_i2c.h" +#include "xe_mmio.h" + +/** + * DOC: Add-In Management Controller (AMC) + * + * Handler for the SMBus Alerts from the AMC. All the alerts from AMC will= cause + * the device to be declared wedged. + */ + +#define AMC_COMMAND 0x0f +#define AMC_GPU_I2C_ADDR 0x8f +#define AMC_VERSION_V1 0x01 +#define AMC_DESTINATION_ID 12 +#define AMC_SOURCE_ID 8 +#define AMC_FLAGS 0xc8 + +#define AMC_MSG_TYPE 0x7e +#define AMC_GET_ALERT_REASON 0x01 + +enum xe_amc_alert { + AMC_ALERT_UNKNOWN, + AMC_ALERT_FW_DOWNLOAD, + AMC_ALERT_THERMAL_TRIP, + AMC_ALERT_OOB_REQUEST, + AMC_ALERT_OOB_RESET, + AMC_ALERT_CATERR, +}; + +struct xe_amc { + struct xe_i2c *i2c; + struct work_struct work; +}; + +struct amc_header { + u8 command; + u8 len; + u8 address; + u8 version; + u8 destination; + u8 source; + u8 flags; +} __packed; + +struct amc_message { + u8 type; + u16 vendor; + u8 command; +} __packed; + +struct amc_request { + struct amc_header header; + struct amc_message message; + u32 reserved; +} __packed; + +struct amc_response { + struct amc_header header; + struct amc_message message; + u8 error; + u8 value; +} __packed; + +static const struct amc_request amc_get_alert_reason =3D { + .header =3D { + .command =3D AMC_COMMAND, + .len =3D sizeof(struct amc_request) - 2, + .address =3D AMC_GPU_I2C_ADDR, + .version =3D AMC_VERSION_V1, + .destination =3D AMC_DESTINATION_ID, + .source =3D AMC_SOURCE_ID, + .flags =3D AMC_FLAGS, + }, + .message =3D { + .type =3D AMC_MSG_TYPE, + .vendor =3D htons(PCI_VENDOR_ID_INTEL), + .command =3D AMC_GET_ALERT_REASON, + }, +}; + +static void xe_amc_work(struct work_struct *work) +{ + const struct amc_request *request =3D &amc_get_alert_reason; + struct xe_amc *amc =3D from_work(amc, work, work); + u8 alert_reason =3D AMC_ALERT_UNKNOWN; + struct amc_response response; + struct i2c_client *client; + int ret; + + client =3D amc->i2c->client[XE_I2C_CLIENT_AMC]; + if (IS_ERR_OR_NULL(client)) + goto out_reassert_interrupt; + + ret =3D i2c_master_send(client, (u8 *)request, sizeof(*request)); + if (ret < 0) { + dev_err(&client->dev, "failed to send request (%d)\n", ret); + goto out_reassert_interrupt; + } + + /* AMC needs 20ms to generate the response. */ + fsleep(20 * USEC_PER_MSEC); + + ret =3D i2c_master_recv(client, (u8 *)&response, sizeof(response)); + if (ret < 0) { + dev_err(&client->dev, "failed to read response (%d)\n", ret); + goto out_reassert_interrupt; + } + + if (!response.header.len) { + dev_err(&client->dev, "empty response from AMC\n"); + goto out_reassert_interrupt; + } + + if (memcmp(&response.message, &request->message, sizeof(struct amc_messag= e))) { + dev_err(&client->dev, "response does not match the request\n"); + goto out_reassert_interrupt; + } + + if (response.error) { + dev_err(&client->dev, "AMC error 0x%02x\n", response.error); + goto out_reassert_interrupt; + } + + alert_reason =3D response.value; + dev_dbg(&client->dev, "Alert reason: %d\n", alert_reason); + +out_reassert_interrupt: + xe_mmio_rmw32(amc->i2c->mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0= ); + + switch (alert_reason) { + case AMC_ALERT_FW_DOWNLOAD: + case AMC_ALERT_THERMAL_TRIP: + case AMC_ALERT_OOB_REQUEST: + case AMC_ALERT_OOB_RESET: + case AMC_ALERT_CATERR: + xe_device_declare_wedged(i2c_client_to_xe_device(client)); + break; + default: + break; + } +} + +void xe_amc_handle_alert(struct xe_i2c *i2c) +{ + queue_work(system_long_wq, &i2c->amc->work); +} + +int xe_amc_init(struct xe_i2c *i2c) +{ + struct xe_amc *amc; + + amc =3D kzalloc(sizeof(*amc), GFP_KERNEL); + if (!amc) + return -ENOMEM; + + INIT_WORK(&amc->work, xe_amc_work); + i2c->amc =3D amc; + amc->i2c =3D i2c; + + return 0; +} + +void xe_amc_exit(struct xe_i2c *i2c) +{ + if (i2c->amc) { + cancel_work_sync(&i2c->amc->work); + kfree(i2c->amc); + } +} diff --git a/drivers/gpu/drm/xe/xe_amc.h b/drivers/gpu/drm/xe/xe_amc.h new file mode 100644 index 0000000000000..b1d5311fee536 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_amc.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _XE_AMC_H_ +#define _XE_AMC_H_ + +#include + +#include "xe_device.h" + +struct xe_i2c; + +static inline struct xe_device *i2c_adapter_to_xe_device(struct i2c_adapte= r *adapter) +{ + return kdev_to_xe_device(adapter->dev.parent->parent); +} + +static inline struct xe_device *i2c_client_to_xe_device(struct i2c_client = *client) +{ + return i2c_adapter_to_xe_device(client->adapter); +} + +int xe_amc_init(struct xe_i2c *i2c); +void xe_amc_exit(struct xe_i2c *i2c); +void xe_amc_handle_alert(struct xe_i2c *i2c); + +#endif /* _XE_AMC_H_ */ diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c index bd956776b10be..f1bd4ddad26f5 100644 --- a/drivers/gpu/drm/xe/xe_i2c.c +++ b/drivers/gpu/drm/xe/xe_i2c.c @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include #include #include @@ -24,9 +22,12 @@ #include #include =20 +#include + #include "regs/xe_i2c_regs.h" #include "regs/xe_irq_regs.h" =20 +#include "xe_amc.h" #include "xe_device.h" #include "xe_i2c.h" #include "xe_mmio.h" @@ -61,16 +62,32 @@ static inline void xe_i2c_read_endpoint(struct xe_mmio = *mmio, void *ep) val[1] =3D xe_mmio_read32(mmio, REG_SG_REMAP_ADDR_POSTFIX); } =20 +static void xe_i2c_handle_smbus_alert(struct xe_i2c *i2c) +{ + u32 stat; + + stat =3D xe_mmio_read32(i2c->mmio, I2C_REG(DW_IC_SMBUS_INTR_STAT)); + if (!stat) + return; + + xe_mmio_write32(i2c->mmio, I2C_REG(DW_IC_CLR_SMBUS_INTR), stat); + + if (stat & DW_IC_SMBUS_INTR_ALERT && i2c->amc) + xe_amc_handle_alert(i2c); + else + xe_mmio_rmw32(i2c->mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0); +} + static void xe_i2c_client_work(struct work_struct *work) { struct xe_i2c *i2c =3D container_of(work, struct xe_i2c, work); struct i2c_board_info info =3D { .type =3D "amc", .flags =3D I2C_CLIENT_HOST_NOTIFY, - .addr =3D i2c->ep.addr[1], + .addr =3D i2c->ep.addr[XE_I2C_CLIENT_AMC], }; =20 - i2c->client[0] =3D i2c_new_client_device(i2c->adapter, &info); + i2c->client[XE_I2C_CLIENT_AMC] =3D i2c_new_client_device(i2c->adapter, &i= nfo); } =20 static int xe_i2c_notifier(struct notifier_block *nb, unsigned long action= , void *data) @@ -112,16 +129,6 @@ static int xe_i2c_register_adapter(struct xe_i2c *i2c) goto err_fwnode_remove; } =20 - if (i2c->adapter_irq) { - struct resource res; - - res =3D DEFINE_RES_IRQ_NAMED(i2c->adapter_irq, "xe_i2c"); - - ret =3D platform_device_add_resources(pdev, &res, 1); - if (ret) - goto err_pdev_put; - } - pdev->dev.parent =3D i2c->drm_dev; pdev->dev.fwnode =3D fwnode; i2c->adapter_node =3D fwnode; @@ -163,7 +170,8 @@ bool xe_i2c_present(struct xe_device *xe) =20 static bool xe_i2c_irq_present(struct xe_device *xe) { - return xe->i2c && xe->i2c->adapter_irq; + return xe->i2c && xe->i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ && + !xe_survivability_mode_is_boot_enabled(xe); } =20 /** @@ -176,18 +184,10 @@ static bool xe_i2c_irq_present(struct xe_device *xe) */ void xe_i2c_irq_handler(struct xe_device *xe, u32 master_ctl) { - struct xe_mmio *mmio =3D xe_root_tile_mmio(xe); - if (!(master_ctl & I2C_IRQ) || !xe_i2c_irq_present(xe)) return; =20 - /* Forward interrupt to I2C adapter */ - generic_handle_irq_safe(xe->i2c->adapter_irq); - - /* Deassert after I2C adapter clears the interrupt */ - xe_mmio_rmw32(mmio, I2C_CONFIG_CMD, 0, PCI_COMMAND_INTX_DISABLE); - /* Reassert to allow subsequent interrupt generation */ - xe_mmio_rmw32(mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0); + xe_i2c_handle_smbus_alert(xe->i2c); } =20 void xe_i2c_irq_reset(struct xe_device *xe) @@ -212,45 +212,6 @@ void xe_i2c_irq_postinstall(struct xe_device *xe) xe_mmio_rmw32(mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0); } =20 -static int xe_i2c_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw_irq_num) -{ - irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); - return 0; -} - -static const struct irq_domain_ops xe_i2c_irq_ops =3D { - .map =3D xe_i2c_irq_map, -}; - -static int xe_i2c_create_irq(struct xe_device *xe) -{ - struct xe_i2c *i2c =3D xe->i2c; - struct irq_domain *domain; - - if (!(i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ) || - xe_survivability_mode_is_boot_enabled(xe)) - return 0; - - domain =3D irq_domain_create_linear(dev_fwnode(i2c->drm_dev), 1, &xe_i2c_= irq_ops, NULL); - if (!domain) - return -ENOMEM; - - i2c->adapter_irq =3D irq_create_mapping(domain, 0); - i2c->irqdomain =3D domain; - - return 0; -} - -static void xe_i2c_remove_irq(struct xe_i2c *i2c) -{ - if (!i2c->irqdomain) - return; - - irq_dispose_mapping(i2c->adapter_irq); - irq_domain_remove(i2c->irqdomain); -} - static int xe_i2c_read(void *context, unsigned int reg, unsigned int *val) { struct xe_i2c *i2c =3D context; @@ -264,8 +225,16 @@ static int xe_i2c_write(void *context, unsigned int re= g, unsigned int val) { struct xe_i2c *i2c =3D context; =20 - xe_mmio_write32(i2c->mmio, XE_REG(reg + I2C_MEM_SPACE_OFFSET), val); + switch (reg) { + case DW_IC_SMBUS_INTR_MASK: + /* Make sure the Alert is never masked. */ + val |=3D DW_IC_SMBUS_INTR_ALERT; + break; + default: + break; + } =20 + xe_mmio_write32(i2c->mmio, I2C_REG(reg), val); return 0; } =20 @@ -307,12 +276,15 @@ static void xe_i2c_remove(void *data) struct xe_i2c *i2c =3D data; unsigned int i; =20 - for (i =3D 0; i < XE_I2C_MAX_CLIENTS; i++) + xe_amc_exit(i2c); + + for (i =3D 0; i < XE_I2C_MAX_CLIENTS; i++) { i2c_unregister_device(i2c->client[i]); + i2c->client[i] =3D NULL; + } =20 bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier); xe_i2c_unregister_adapter(i2c); - xe_i2c_remove_irq(i2c); } =20 /** @@ -360,22 +332,18 @@ int xe_i2c_probe(struct xe_device *xe) if (ret) return ret; =20 - ret =3D xe_i2c_create_irq(xe); - if (ret) - goto err_unregister_notifier; - ret =3D xe_i2c_register_adapter(i2c); - if (ret) - goto err_remove_irq; + if (ret) { + bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier); + return ret; + } + + ret =3D xe_amc_init(i2c); + if (ret) { + xe_i2c_remove(i2c); + return ret; + } =20 xe_i2c_irq_postinstall(xe); return devm_add_action_or_reset(drm_dev, xe_i2c_remove, i2c); - -err_remove_irq: - xe_i2c_remove_irq(i2c); - -err_unregister_notifier: - bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier); - - return ret; } diff --git a/drivers/gpu/drm/xe/xe_i2c.h b/drivers/gpu/drm/xe/xe_i2c.h index 425d8160835f4..b200966b00484 100644 --- a/drivers/gpu/drm/xe/xe_i2c.h +++ b/drivers/gpu/drm/xe/xe_i2c.h @@ -11,18 +11,21 @@ struct device; struct fwnode_handle; struct i2c_adapter; struct i2c_client; -struct irq_domain; struct platform_device; +struct xe_amc; struct xe_device; struct xe_mmio; =20 -#define XE_I2C_MAX_CLIENTS 3 - #define XE_I2C_EP_COOKIE_DEVICE 0xde =20 /* Endpoint Capabilities */ #define XE_I2C_EP_CAP_IRQ BIT(0) =20 +enum XE_I2C_CLIENT { + XE_I2C_CLIENT_AMC =3D 1, + XE_I2C_MAX_CLIENTS =3D 3, +}; + struct xe_i2c_endpoint { u8 cookie; u8 capabilities; @@ -38,13 +41,11 @@ struct xe_i2c { struct notifier_block bus_notifier; struct work_struct work; =20 - struct irq_domain *irqdomain; - int adapter_irq; - struct xe_i2c_endpoint ep; struct device *drm_dev; =20 struct xe_mmio *mmio; + struct xe_amc *amc; }; =20 #if IS_ENABLED(CONFIG_I2C) --=20 2.50.1 From nobody Fri Jul 24 22:54:36 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8F7F9353A8A; Wed, 22 Jul 2026 13:36:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784727369; cv=none; b=PELnKHjdPCefhIqYlDQfwK2ymYTXCCwdgsCzMrFLofmxpDHxs66AXNfWVp3mwhrvo7Hg8nkT5KH8o9RAWsZbcVtSHxeOmyv/WV1hRS/3bApVZ6UPoIIndk0QsvX4dJzsrbhY1p2X2ytaxYvHvNFljBLV4iNCw6IOQhrr+YOMQoM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784727369; c=relaxed/simple; bh=lytLbx90lJ+N4Y1x7HPjwJyuNOwUmtIajyrVL9ORe9c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=neACpXCzDg2UH95SV4Fdt0tKKv18Vh006R3cfhdWroJSeu1FMamt0yJ3eBR12FAYIOUDjn2Ard4mFPro5kUUcgbK9Vh5QpsrYaAyBMGzZQPQvMt3pvOqPjBPD/OAsq3yM5SwEJflbDGkpoYQnV543O2TDUqVvY8UvJUGV1LgOzc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=CGSOX6wh; arc=none smtp.client-ip=198.175.65.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="CGSOX6wh" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1784727368; x=1816263368; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=lytLbx90lJ+N4Y1x7HPjwJyuNOwUmtIajyrVL9ORe9c=; b=CGSOX6whufWEJkeYcitmS8XI2dfjxtIBET3z4aFjlQWKWi36CjYYsVPI IjoC20OKeEjrc03JylTw3EmFIHKd9tbzVMIVXyvH6TnykCLKY6zAx5vaZ etxBsAPwPaOINtT6A8SB83eR6UwrB3t3UAzffa37F8+dKQGiV2AmcSr6Y dccpDgS3X4F5D1Xg+qlCS6rAi1CBaVMJEjpt1HMvTAKtImT/fc90g/nQJ 5QG9So+kW+kNBEU/2Bv59d3+TJnAl+988mca4wv1dyG0wDvPWfi46VCNf AExr+Mpsj/6OtUp2CfsTkDIH3w99vRA+0C6ZuNoax1TwkzvtUb+mAu9bV w==; X-CSE-ConnectionGUID: 3PzQaGPsTTmsor19mkSxNA== X-CSE-MsgGUID: Q+ZKWddRTL644dza+0/4Lw== X-IronPort-AV: E=McAfee;i="6800,10657,11854"; a="85453411" X-IronPort-AV: E=Sophos;i="6.25,178,1779174000"; d="scan'208";a="85453411" Received: from fmviesa005.fm.intel.com ([10.60.135.145]) by orvoesa110.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Jul 2026 06:36:07 -0700 X-CSE-ConnectionGUID: 6RO5m1mCQie5VO7uUHEpZA== X-CSE-MsgGUID: k2ECa/PtSwek7Hfu8l7qmw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,178,1779174000"; d="scan'208";a="263041002" Received: from black.igk.intel.com ([10.91.253.5]) by fmviesa005.fm.intel.com with ESMTP; 22 Jul 2026 06:36:04 -0700 From: Heikki Krogerus To: Matthew Brost , =?UTF-8?q?Thomas=20Hellstr=C3=B6m?= , Rodrigo Vivi , Raag Jadav , Mika Westerberg , Andy Shevchenko Cc: Andi Shyti , Ramesh Babu B , "Michael J. Ruhl" , linux-kernel@vger.kernel.org, intel-xe@lists.freedesktop.org, stable@vger.kernel.org Subject: [PATCH v6 3/3] drm/xe/i2c: Keep the i2c controller always enabled Date: Wed, 22 Jul 2026 15:35:54 +0200 Message-ID: <20260722133554.2079612-4-heikki.krogerus@linux.intel.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20260722133554.2079612-1-heikki.krogerus@linux.intel.com> References: <20260722133554.2079612-1-heikki.krogerus@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Some platforms make an assumption that the i2c controller's enabled state indicates also the power state of the controller. This can create a problem when the controller is in disabled state, because the hardware may assume incorrectly that it is then also in low-power state. To fix this, the controller is kept enabled by taking over the IC_ENABLE register. The controller has to be disabled when the configuration is updated and when the target address or the slave address are assigned, so disabling it when IC_CON, IC_TAR or IC_SAR registers are programmed, and then re-enabling it again. Fixes: f0e53aadd702 ("drm/xe: Support for I2C attached MCUs") Cc: stable@vger.kernel.org Signed-off-by: Heikki Krogerus --- drivers/gpu/drm/xe/xe_i2c.c | 49 ++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/xe/xe_i2c.h | 1 + 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c index f1bd4ddad26f5..a7737422baefc 100644 --- a/drivers/gpu/drm/xe/xe_i2c.c +++ b/drivers/gpu/drm/xe/xe_i2c.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -212,11 +213,40 @@ void xe_i2c_irq_postinstall(struct xe_device *xe) xe_mmio_rmw32(mmio, I2C_CONFIG_CMD, PCI_COMMAND_INTX_DISABLE, 0); } =20 +/* See "Disabling DW_apb_i2c" in the DesignWare DW_abp_i2c databook. */ +static void xe_i2c_disable(struct xe_i2c *i2c) +{ + int timeout =3D 100; + u32 status; + + xe_mmio_rmw32(i2c->mmio, I2C_REG(DW_IC_ENABLE), DW_IC_ENABLE_ENABLE, 0); + + do { + status =3D xe_mmio_read32(i2c->mmio, I2C_REG(DW_IC_ENABLE_STATUS)); + if (!(status & DW_IC_ENABLE_ENABLE)) + return; + /* Can't sleep here. */ + udelay(25); + } while (timeout--); + + dev_warn(i2c->drm_dev, "timeout in disabling i2c adapter\n"); +} + static int xe_i2c_read(void *context, unsigned int reg, unsigned int *val) { struct xe_i2c *i2c =3D context; =20 - *val =3D xe_mmio_read32(i2c->mmio, XE_REG(reg + I2C_MEM_SPACE_OFFSET)); + *val =3D xe_mmio_read32(i2c->mmio, I2C_REG(reg)); + + switch (reg) { + case DW_IC_ENABLE: + case DW_IC_ENABLE_STATUS: + FIELD_MODIFY(DW_IC_ENABLE_ENABLE, val, + i2c->ic_enable & DW_IC_ENABLE_ENABLE); + break; + default: + break; + } =20 return 0; } @@ -226,6 +256,23 @@ static int xe_i2c_write(void *context, unsigned int re= g, unsigned int val) struct xe_i2c *i2c =3D context; =20 switch (reg) { + case DW_IC_CON: + case DW_IC_TAR: + case DW_IC_SAR: + /* Disable the controller. */ + xe_i2c_disable(i2c); + + /* Write the register. */ + xe_mmio_write32(i2c->mmio, I2C_REG(reg), val); + + /* Enable the controller. */ + xe_mmio_rmw32(i2c->mmio, I2C_REG(DW_IC_ENABLE), 0, DW_IC_ENABLE_ENABLE); + return 0; + case DW_IC_ENABLE: + i2c->ic_enable =3D val; + /* Other fields can be updated except the enable bit. */ + val |=3D DW_IC_ENABLE_ENABLE; + break; case DW_IC_SMBUS_INTR_MASK: /* Make sure the Alert is never masked. */ val |=3D DW_IC_SMBUS_INTR_ALERT; diff --git a/drivers/gpu/drm/xe/xe_i2c.h b/drivers/gpu/drm/xe/xe_i2c.h index b200966b00484..d63adacfefe71 100644 --- a/drivers/gpu/drm/xe/xe_i2c.h +++ b/drivers/gpu/drm/xe/xe_i2c.h @@ -37,6 +37,7 @@ struct xe_i2c { struct platform_device *pdev; struct i2c_adapter *adapter; struct i2c_client *client[XE_I2C_MAX_CLIENTS]; + unsigned int ic_enable; =20 struct notifier_block bus_notifier; struct work_struct work; --=20 2.50.1