Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection
From: Arnaldo Carvalho de Melo @ 2026-03-31 20:42 UTC (permalink / raw)
  To: Ian Rogers
  Cc: 9erthalion6, adrian.hunter, alex, alexander.shishkin,
	andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
	howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
	libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
	linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
	tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260305221927.3237145-2-irogers@google.com>

On Thu, Mar 05, 2026 at 02:19:20PM -0800, Ian Rogers wrote:
> Currently, both libdw and libunwind define 'unwind__get_entries'. This
> causes a duplicate symbol build failure when both are compiled into
> perf.
> 
> This commit refactors the DWARF unwind post-processing to be
> configurable at runtime via the .perfconfig file option
> 'unwind.style', or using the argument '--unwind-style' in the commands
> 'perf report', 'perf script' and 'perf inject', in a similar manner to
> the addr2line or the disassembler style.
> 
> The file 'tools/perf/util/unwind.c' adds the top-level dispatch
> function 'unwind__get_entries'. The backend implementations are
> renamed to 'libdw__get_entries' and 'libunwind__get_entries'. Both are
> attempted as fallbacks if not configured, or if the primary backend
> fails.
> 
> Fixes: 2e9191573a69 ("perf build: Remove NO_LIBDW_DWARF_UNWIND option")
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
>  tools/perf/builtin-inject.c        |   4 ++
>  tools/perf/builtin-report.c        |   4 ++
>  tools/perf/builtin-script.c        |   4 ++
>  tools/perf/util/Build              |   1 +
>  tools/perf/util/symbol_conf.h      |  15 +++++
>  tools/perf/util/unwind-libdw.c     |   2 +-
>  tools/perf/util/unwind-libunwind.c |   2 +-
>  tools/perf/util/unwind.c           | 102 +++++++++++++++++++++++++++++
>  tools/perf/util/unwind.h           |  40 +++++------
>  9 files changed, 149 insertions(+), 25 deletions(-)
>  create mode 100644 tools/perf/util/unwind.c
> 
> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index 5b29f4296861..9ad681b3c0dc 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
> @@ -26,6 +26,7 @@
>  #include "util/synthetic-events.h"
>  #include "util/thread.h"
>  #include "util/namespaces.h"
> +#include "util/unwind.h"
>  #include "util/util.h"
>  #include "util/tsc.h"
>  
> @@ -2539,6 +2540,9 @@ int cmd_inject(int argc, const char **argv)
>  		OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
>  			   "guest mount directory under which every guest os"
>  			   " instance has a subdir"),
> +		OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
> +			     "unwind styles (libdw,libunwind)",
> +			     unwind__option),
>  		OPT_BOOLEAN(0, "convert-callchain", &inject.convert_callchain,
>  			    "Generate callchains using DWARF and drop register/stack data"),
>  		OPT_END()
> diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
> index 3b81f4b3dc49..ae20c0679990 100644
> --- a/tools/perf/builtin-report.c
> +++ b/tools/perf/builtin-report.c
> @@ -48,6 +48,7 @@
>  #include "util/time-utils.h"
>  #include "util/auxtrace.h"
>  #include "util/units.h"
> +#include "util/unwind.h"
>  #include "util/util.h" // perf_tip()
>  #include "ui/ui.h"
>  #include "ui/progress.h"
> @@ -1455,6 +1456,9 @@ int cmd_report(int argc, const char **argv)
>  	OPT_CALLBACK(0, "addr2line-style", NULL, "addr2line style",
>  		     "addr2line styles (libdw,llvm,libbfd,addr2line)",
>  		     report_parse_addr2line_config),
> +	OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
> +		     "unwind styles (libdw,libunwind)",
> +		     unwind__option),
>  	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
>  		    "Symbol demangling. Enabled by default, use --no-demangle to disable."),
>  	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
> diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> index 9f8b0fd27a0a..b6c7c164d02d 100644
> --- a/tools/perf/builtin-script.c
> +++ b/tools/perf/builtin-script.c
> @@ -63,6 +63,7 @@
>  #include <linux/err.h>
>  #include "util/dlfilter.h"
>  #include "util/record.h"
> +#include "util/unwind.h"
>  #include "util/util.h"
>  #include "util/cgroup.h"
>  #include "util/annotate.h"
> @@ -4164,6 +4165,9 @@ int cmd_script(int argc, const char **argv)
>  			"Enable symbol demangling"),
>  	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
>  			"Enable kernel symbol demangling"),
> +	OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
> +		     "unwind styles (libdw,libunwind)",
> +		     unwind__option),
>  	OPT_STRING(0, "addr2line", &symbol_conf.addr2line_path, "path",
>  			"addr2line binary to use for line numbers"),
>  	OPT_STRING(0, "time", &script.time_str, "str",
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index bcccad7487a9..6190a8f5b0fa 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -218,6 +218,7 @@ ifndef CONFIG_SETNS
>  perf-util-y += setns.o
>  endif
>  
> +perf-util-y += unwind.o
>  perf-util-$(CONFIG_LIBDW) += probe-finder.o
>  perf-util-$(CONFIG_LIBDW) += dwarf-aux.o
>  perf-util-$(CONFIG_LIBDW) += dwarf-regs.o
> diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
> index 71bb17372a6c..25d92bbbfee7 100644
> --- a/tools/perf/util/symbol_conf.h
> +++ b/tools/perf/util/symbol_conf.h
> @@ -9,6 +9,19 @@
>  struct strlist;
>  struct intlist;
>  
> +enum unwind_style {
> +
> +	UNWIND_STYLE_UNKNOWN = 0,
> +
> +	UNWIND_STYLE_LIBDW,
> +
> +	UNWIND_STYLE_LIBUNWIND,
> +
> +};
> +
> +#define MAX_UNWIND_STYLE (UNWIND_STYLE_LIBUNWIND + 1)
> +
> +
>  enum a2l_style {
>  	A2L_STYLE_UNKNOWN = 0,
>  	A2L_STYLE_LIBDW,
> @@ -80,6 +93,7 @@ struct symbol_conf {
>  			*bt_stop_list_str;
>  	const char		*addr2line_path;
>  	enum a2l_style	addr2line_style[MAX_A2L_STYLE];
> +	enum unwind_style unwind_style[MAX_UNWIND_STYLE];
>  	unsigned long	time_quantum;
>         struct strlist	*dso_list,
>  			*comm_list,
> @@ -103,3 +117,4 @@ struct symbol_conf {
>  extern struct symbol_conf symbol_conf;
>  
>  #endif // __PERF_SYMBOL_CONF
> +
> diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
> index 05e8e68bd49c..d8a5b7d54192 100644
> --- a/tools/perf/util/unwind-libdw.c
> +++ b/tools/perf/util/unwind-libdw.c
> @@ -339,7 +339,7 @@ frame_callback(Dwfl_Frame *state, void *arg)
>  	       DWARF_CB_ABORT : DWARF_CB_OK;
>  }
>  
> -int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
> +int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
>  			struct thread *thread,
>  			struct perf_sample *data,
>  			int max_stack,
> diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
> index cb8be6acfb6f..a0016b897dae 100644
> --- a/tools/perf/util/unwind-libunwind.c
> +++ b/tools/perf/util/unwind-libunwind.c
> @@ -79,7 +79,7 @@ void unwind__finish_access(struct maps *maps)
>  		ops->finish_access(maps);
>  }
>  
> -int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
> +int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
>  			 struct thread *thread,
>  			 struct perf_sample *data, int max_stack,
>  			 bool best_effort)
> diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
> new file mode 100644
> index 000000000000..9ae7d5ad246d
> --- /dev/null
> +++ b/tools/perf/util/unwind.c
> @@ -0,0 +1,102 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include "debug.h"
> +#include "symbol_conf.h"
> +#include "unwind.h"
> +#include <linux/string.h>
> +#include <string.h>
> +#include <stdlib.h>
> +
> +int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
> +			struct thread *thread __maybe_unused,
> +			struct perf_sample *data __maybe_unused,
> +			int max_stack __maybe_unused,
> +			bool best_effort __maybe_unused)
> +{
> +	int ret = 0;
> +
> +#if defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
> +	if (symbol_conf.unwind_style[0] == UNWIND_STYLE_UNKNOWN) {
> +		int i = 0;
> +#ifdef HAVE_LIBDW_SUPPORT
> +		symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBDW;
> +#endif
> +#ifdef HAVE_LIBUNWIND_SUPPORT
> +		symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBUNWIND;
> +#endif
> +	}
> +#endif //defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
> +
> +	for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.unwind_style); i++) {
> +		switch (symbol_conf.unwind_style[i]) {
> +		case UNWIND_STYLE_LIBDW:
> +#ifdef HAVE_LIBDW_SUPPORT
> +			ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
> +#endif
> +			break;
> +		case UNWIND_STYLE_LIBUNWIND:
> +#ifdef HAVE_LIBUNWIND_SUPPORT
> +			ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
> +#endif
> +			break;


What if the user asks for one of the unwinders, symbol_conf.unwind_style
will be populated with the user's choices, but then here in
unwind__get_entries() we end up returning 0 because the user choice is
not built-in?

Also no warning will be emitted that what was asked for is not
available?

Maybe remove the ifdefs here and have a dummy libdw__get_entries() when
HAVE_LIBDW_SUPPORT ins't defined that emits the warning and returns -1?
Ditto for UNWIND_STYLE_LIBUNWIND?

- Arnaldo

> +		case UNWIND_STYLE_UNKNOWN:
> +		default:
> +#if !defined(HAVE_LIBDW_SUPPORT) && !defined(HAVE_LIBUNWIND_SUPPORT)
> +			pr_warning_once(
> +				"Error: dwarf unwinding not supported, build perf with libdw or libunwind.\n");
> +#endif
> +			ret = -1;
> +			break;
> +		}
> +		if (ret == 0)
> +			break;
> +	}
> +	return ret;
> +}
> +
> +int unwind__configure(const char *var, const char *value, void *cb __maybe_unused)
> +{
> +	static const char * const unwind_style_names[] = {
> +		[UNWIND_STYLE_LIBDW] = "libdw",
> +		[UNWIND_STYLE_LIBUNWIND] = "libunwind",
> +		NULL
> +	};
> +	char *s, *p, *saveptr;
> +	size_t i = 0;
> +
> +	if (strcmp(var, "unwind.style"))
> +		return 0;
> +
> +	if (!value)
> +		return -1;
> +
> +	s = strdup(value);
> +	if (!s)
> +		return -1;
> +
> +	p = strtok_r(s, ",", &saveptr);
> +	while (p && i < ARRAY_SIZE(symbol_conf.unwind_style)) {
> +		bool found = false;
> +		char *q = strim(p);
> +
> +		for (size_t j = UNWIND_STYLE_LIBDW; j < MAX_UNWIND_STYLE; j++) {
> +			if (!strcasecmp(q, unwind_style_names[j])) {
> +				symbol_conf.unwind_style[i++] = j;
> +				found = true;
> +				break;
> +			}
> +		}
> +		if (!found)
> +			pr_warning("Unknown unwind style: %s\n", q);
> +		p = strtok_r(NULL, ",", &saveptr);
> +	}
> +
> +	free(s);
> +	return 0;
> +}
> +
> +int unwind__option(const struct option *opt __maybe_unused,
> +		   const char *arg,
> +		   int unset __maybe_unused)
> +{
> +	return unwind__configure("unwind.style", arg, NULL);
> +}
> diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
> index 9f7164c6d9aa..581d042e170a 100644
> --- a/tools/perf/util/unwind.h
> +++ b/tools/perf/util/unwind.h
> @@ -7,6 +7,7 @@
>  #include "util/map_symbol.h"
>  
>  struct maps;
> +struct option;
>  struct perf_sample;
>  struct thread;
>  
> @@ -26,7 +27,9 @@ struct unwind_libunwind_ops {
>  			   struct perf_sample *data, int max_stack, bool best_effort);
>  };
>  
> -#ifdef HAVE_DWARF_UNWIND_SUPPORT
> +int unwind__configure(const char *var, const char *value, void *cb);
> +int unwind__option(const struct option *opt, const char *arg, int unset);
> +
>  /*
>   * When best_effort is set, don't report errors and fail silently. This could
>   * be expanded in the future to be more permissive about things other than
> @@ -36,8 +39,20 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
>  			struct thread *thread,
>  			struct perf_sample *data, int max_stack,
>  			bool best_effort);
> -/* libunwind specific */
> +
> +#ifdef HAVE_LIBDW_SUPPORT
> +int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
> +		       struct thread *thread,
> +		       struct perf_sample *data, int max_stack,
> +		       bool best_effort);
> +#endif
> +
>  #ifdef HAVE_LIBUNWIND_SUPPORT
> +/* libunwind specific */
> +int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
> +			   struct thread *thread,
> +			   struct perf_sample *data, int max_stack,
> +			   bool best_effort);
>  #ifndef LIBUNWIND__ARCH_REG_ID
>  #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum)
>  #endif
> @@ -57,26 +72,5 @@ static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
>  static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
>  static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
>  #endif
> -#else
> -static inline int
> -unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
> -		    void *arg __maybe_unused,
> -		    struct thread *thread __maybe_unused,
> -		    struct perf_sample *data __maybe_unused,
> -		    int max_stack __maybe_unused,
> -		    bool best_effort __maybe_unused)
> -{
> -	return 0;
> -}
> -
> -static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
> -					 struct map *map __maybe_unused,
> -					 bool *initialized __maybe_unused)
> -{
> -	return 0;
> -}
>  
> -static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
> -static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
> -#endif /* HAVE_DWARF_UNWIND_SUPPORT */
>  #endif /* __UNWIND_H */
> -- 
> 2.53.0.473.g4a7958ca14-goog


^ permalink raw reply

* [GIT PULL] More Qualcomm Arm64 DeviceTree fixes for v7.0
From: Bjorn Andersson @ 2026-03-31 20:53 UTC (permalink / raw)
  To: arm, soc
  Cc: linux-arm-msm, linux-arm-kernel, Arnd Bergmann,
	Krzysztof Kozlowski, Ziyue Zhang


The following changes since commit 2c409e03fc04b5cded81b7add9ce509706c922e3:

  arm64: dts: qcom: agatti: Fix IOMMU DT properties (2026-03-23 22:31:40 -0500)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git tags/qcom-arm64-fixes-for-7.0-2

for you to fetch changes up to 11b72b1ca9891c77bc876ef9fc39d6825847ffee:

  arm64: dts: qcom: hamoa: Fix incomplete Root Port property migration (2026-03-30 08:08:48 -0500)

----------------------------------------------------------------
More Qualcomm Arm64 DeviceTree fixes for v7.0

The shuffling of reset and wake GPIO properties across various Hamoa
devices left things in an incomplete state, fix this.

Add the missing "ranges" property to the QCM2290 MDSS DeviceTree binding
example, to fix the validation warning that was introduced by the
previous fix.

----------------------------------------------------------------
Krzysztof Kozlowski (1):
      dt-bindings: display/msm: qcm2290-mdss: Fix missing ranges in example

Ziyue Zhang (1):
      arm64: dts: qcom: hamoa: Fix incomplete Root Port property migration

 .../bindings/display/msm/qcom,qcm2290-mdss.yaml    |  1 +
 arch/arm64/boot/dts/qcom/x1-asus-zenbook-a14.dtsi  | 16 +++++++++------
 arch/arm64/boot/dts/qcom/x1-crd.dtsi               | 24 ++++++++++++++--------
 arch/arm64/boot/dts/qcom/x1-dell-thena.dtsi        | 14 +++++++------
 arch/arm64/boot/dts/qcom/x1-hp-omnibook-x14.dtsi   | 14 +++++++------
 arch/arm64/boot/dts/qcom/x1-microsoft-denali.dtsi  |  8 +++++---
 .../boot/dts/qcom/x1e80100-lenovo-yoga-slim7x.dts  |  6 +++---
 .../dts/qcom/x1e80100-medion-sprchrgd-14-s1.dts    | 15 +++++++-------
 .../boot/dts/qcom/x1p42100-lenovo-thinkbook-16.dts | 14 +++++++------
 9 files changed, 66 insertions(+), 46 deletions(-)


^ permalink raw reply

* Re: [PATCH RFC net-next] net: stmmac: qcom-ethqos: set clk_csr
From: Mohd Ayaan Anwar @ 2026-03-31 20:58 UTC (permalink / raw)
  To: Russell King (Oracle)
  Cc: Konrad Dybcio, Alexandre Torgue, Andrew Lunn, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, linux-arm-kernel,
	linux-arm-msm, linux-stm32, netdev, Paolo Abeni
In-Reply-To: <acpqgpCsbo3lJs3l@shell.armlinux.org.uk>

On Mon, Mar 30, 2026 at 01:20:18PM +0100, Russell King (Oracle) wrote:
> On Mon, Mar 30, 2026 at 01:18:56PM +0200, Konrad Dybcio wrote:
> > On 3/27/26 6:02 PM, Russell King (Oracle) wrote:
> > > The clocks for qcom-ethqos return a rate of zero as firmware manages
> > > their rate. According to hardware documentation, the clock which is
> > > fed to the slave AHB interface can crange between 50 and 100MHz.
> > 
> > FWIW this __may__ possibly differ between platforms, but I'm not sure
> > to what degree. Will there be visible impact if we e.g. have a 200 or
> > 300 MHz clock somewhere?
> 

While I had made an identical change while retesting the PCS series,
I was holding off on posting this patch for the same concern - what
if some boards fall outside the 50 - 100 MHz range.

After some digging, the AHB clock appears to operate within:
 - 50 to 100 MHz for lemans/monaco derivative boards (2500BASE-X
   interface)
 - 30 to 75 MHz for boards with an RGMII interface.

This is not exhaustive, but it covers all boards I have access to
which actually boot with the upstream kernel.

Therefore, I think using the /42 divisor should be fine as it will
ensure that MDC never goes beyond 2.5 MHz.

If a future platform exceeds this range, we could switch to something
like: plat_dat->clk_csr = data->clk_csr, with each EMAC version
selecting the appropriate divisor.

Due to some urgent work tasks, I am still finishing PCS series
testing. I will provide a t-b once done.

In the meanwhile, please feel free to add:

Reviewed-by: Mohd Ayaan Anwar <mohd.anwar@oss.qualcomm.com>

	Ayaan



^ permalink raw reply

* Re: [PATCH v5 8/8] Bluetooth: btusb: Add MT7927 ID for ASUS X870E / ProArt X870E-Creator
From: Javier Tia @ 2026-03-31 20:58 UTC (permalink / raw)
  To: Paul Menzel
  Cc: Marcel Holtmann, Luiz Augusto von Dentz, Matthias Brugger,
	AngeloGioacchino Del Regno, linux-bluetooth, linux-kernel,
	linux-arm-kernel, linux-mediatek, Jose Tiburcio Ribeiro Netto,
	Ivan Lubnin

Hi Paul,

Thank you for the review.

On Mon, 31 Mar 2026 Paul Menzel wrote:
> > +	{ USB_DEVICE(0x13d3, 0x3588), .driver_info = BTUSB_MEDIATEK |
> > +						     BTUSB_WIDEBAND_SPEECH },
>
> This is not sorted. Is there a reason to place it here?

The placement is a consequence of the series structure - each USB ID
patch inserts after the previous one to keep patches independent and
conflict-free. The existing 0x13d3 MediaTek entries in the table are
also not strictly sorted (e.g. 3560, 3620, 3621, 3622, 3563, 3564),
as they are grouped by chip generation rather than numerical order.

That said, Luiz has already applied v4 of this series to
bluetooth-next with this ordering, so any resorting would need a
separate follow-up patch.

Best,
Javier


^ permalink raw reply

* [GIT PULL] Qualcomm Arm32 DeviceTree updates for v7.1
From: Bjorn Andersson @ 2026-03-31 21:16 UTC (permalink / raw)
  To: arm, soc
  Cc: linux-arm-msm, linux-arm-kernel, Arnd Bergmann, Dmitry Baryshkov,
	Rob Herring


The following changes since commit 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f:

  Linux 7.0-rc1 (2026-02-22 13:18:59 -0800)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git tags/qcom-arm32-for-7.1

for you to fetch changes up to 6453ad0865b68ab0de5873c1a8bb4addbbde5c19:

  ARM: dts: qcom: msm8974: Drop RPM bus clocks (2026-03-31 15:59:12 -0500)

----------------------------------------------------------------
Qualcomm Arm32 DeviceTree updates for v7.1

Qualcomm APQ8084 is incomplete and hasn't seen functional contributions
since 2016, so drop the platform (for now?). Also drop a number of
unused IPQ-related dtsi files.

Lastly clean up the RPM bus clocks in MSM8974 interconnect nodes.

----------------------------------------------------------------
Dmitry Baryshkov (2):
      ARM: dts: qcom: drop apq8084 support
      ARM: dts: qcom: msm8974: Drop RPM bus clocks

Rob Herring (Arm) (1):
      ARM: dts: qcom: Drop unused .dtsi

 arch/arm/boot/dts/qcom/Makefile                    |   2 -
 arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts    |  34 -
 arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts        |  23 -
 arch/arm/boot/dts/qcom/qcom-apq8084.dtsi           | 852 ---------------------
 arch/arm/boot/dts/qcom/qcom-ipq8062-smb208.dtsi    |  37 -
 arch/arm/boot/dts/qcom/qcom-ipq8062.dtsi           |   8 -
 arch/arm/boot/dts/qcom/qcom-ipq8064-smb208.dtsi    |  37 -
 .../boot/dts/qcom/qcom-ipq8064-v2.0-smb208.dtsi    |  37 -
 arch/arm/boot/dts/qcom/qcom-ipq8065-smb208.dtsi    |  37 -
 arch/arm/boot/dts/qcom/qcom-ipq8065.dtsi           |   8 -
 arch/arm/boot/dts/qcom/qcom-msm8974.dtsi           |  21 +-
 11 files changed, 3 insertions(+), 1093 deletions(-)
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-apq8084-ifc6540.dts
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-apq8084-mtp.dts
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-apq8084.dtsi
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-ipq8062-smb208.dtsi
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-ipq8062.dtsi
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-ipq8064-smb208.dtsi
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-ipq8064-v2.0-smb208.dtsi
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-ipq8065-smb208.dtsi
 delete mode 100644 arch/arm/boot/dts/qcom/qcom-ipq8065.dtsi


^ permalink raw reply

* Re: [PATCH v2 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection
From: Ian Rogers @ 2026-03-31 21:21 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: 9erthalion6, adrian.hunter, alex, alexander.shishkin,
	andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
	howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
	libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
	linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
	tglozar, tmricht, will, yuzhuo
In-Reply-To: <acwxuPAo8g6C867R@x1>

On Tue, Mar 31, 2026 at 1:42 PM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Thu, Mar 05, 2026 at 02:19:20PM -0800, Ian Rogers wrote:
> > Currently, both libdw and libunwind define 'unwind__get_entries'. This
> > causes a duplicate symbol build failure when both are compiled into
> > perf.
> >
> > This commit refactors the DWARF unwind post-processing to be
> > configurable at runtime via the .perfconfig file option
> > 'unwind.style', or using the argument '--unwind-style' in the commands
> > 'perf report', 'perf script' and 'perf inject', in a similar manner to
> > the addr2line or the disassembler style.
> >
> > The file 'tools/perf/util/unwind.c' adds the top-level dispatch
> > function 'unwind__get_entries'. The backend implementations are
> > renamed to 'libdw__get_entries' and 'libunwind__get_entries'. Both are
> > attempted as fallbacks if not configured, or if the primary backend
> > fails.
> >
> > Fixes: 2e9191573a69 ("perf build: Remove NO_LIBDW_DWARF_UNWIND option")
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> >  tools/perf/builtin-inject.c        |   4 ++
> >  tools/perf/builtin-report.c        |   4 ++
> >  tools/perf/builtin-script.c        |   4 ++
> >  tools/perf/util/Build              |   1 +
> >  tools/perf/util/symbol_conf.h      |  15 +++++
> >  tools/perf/util/unwind-libdw.c     |   2 +-
> >  tools/perf/util/unwind-libunwind.c |   2 +-
> >  tools/perf/util/unwind.c           | 102 +++++++++++++++++++++++++++++
> >  tools/perf/util/unwind.h           |  40 +++++------
> >  9 files changed, 149 insertions(+), 25 deletions(-)
> >  create mode 100644 tools/perf/util/unwind.c
> >
> > diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> > index 5b29f4296861..9ad681b3c0dc 100644
> > --- a/tools/perf/builtin-inject.c
> > +++ b/tools/perf/builtin-inject.c
> > @@ -26,6 +26,7 @@
> >  #include "util/synthetic-events.h"
> >  #include "util/thread.h"
> >  #include "util/namespaces.h"
> > +#include "util/unwind.h"
> >  #include "util/util.h"
> >  #include "util/tsc.h"
> >
> > @@ -2539,6 +2540,9 @@ int cmd_inject(int argc, const char **argv)
> >               OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
> >                          "guest mount directory under which every guest os"
> >                          " instance has a subdir"),
> > +             OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
> > +                          "unwind styles (libdw,libunwind)",
> > +                          unwind__option),
> >               OPT_BOOLEAN(0, "convert-callchain", &inject.convert_callchain,
> >                           "Generate callchains using DWARF and drop register/stack data"),
> >               OPT_END()
> > diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
> > index 3b81f4b3dc49..ae20c0679990 100644
> > --- a/tools/perf/builtin-report.c
> > +++ b/tools/perf/builtin-report.c
> > @@ -48,6 +48,7 @@
> >  #include "util/time-utils.h"
> >  #include "util/auxtrace.h"
> >  #include "util/units.h"
> > +#include "util/unwind.h"
> >  #include "util/util.h" // perf_tip()
> >  #include "ui/ui.h"
> >  #include "ui/progress.h"
> > @@ -1455,6 +1456,9 @@ int cmd_report(int argc, const char **argv)
> >       OPT_CALLBACK(0, "addr2line-style", NULL, "addr2line style",
> >                    "addr2line styles (libdw,llvm,libbfd,addr2line)",
> >                    report_parse_addr2line_config),
> > +     OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
> > +                  "unwind styles (libdw,libunwind)",
> > +                  unwind__option),
> >       OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
> >                   "Symbol demangling. Enabled by default, use --no-demangle to disable."),
> >       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
> > diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
> > index 9f8b0fd27a0a..b6c7c164d02d 100644
> > --- a/tools/perf/builtin-script.c
> > +++ b/tools/perf/builtin-script.c
> > @@ -63,6 +63,7 @@
> >  #include <linux/err.h>
> >  #include "util/dlfilter.h"
> >  #include "util/record.h"
> > +#include "util/unwind.h"
> >  #include "util/util.h"
> >  #include "util/cgroup.h"
> >  #include "util/annotate.h"
> > @@ -4164,6 +4165,9 @@ int cmd_script(int argc, const char **argv)
> >                       "Enable symbol demangling"),
> >       OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
> >                       "Enable kernel symbol demangling"),
> > +     OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
> > +                  "unwind styles (libdw,libunwind)",
> > +                  unwind__option),
> >       OPT_STRING(0, "addr2line", &symbol_conf.addr2line_path, "path",
> >                       "addr2line binary to use for line numbers"),
> >       OPT_STRING(0, "time", &script.time_str, "str",
> > diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> > index bcccad7487a9..6190a8f5b0fa 100644
> > --- a/tools/perf/util/Build
> > +++ b/tools/perf/util/Build
> > @@ -218,6 +218,7 @@ ifndef CONFIG_SETNS
> >  perf-util-y += setns.o
> >  endif
> >
> > +perf-util-y += unwind.o
> >  perf-util-$(CONFIG_LIBDW) += probe-finder.o
> >  perf-util-$(CONFIG_LIBDW) += dwarf-aux.o
> >  perf-util-$(CONFIG_LIBDW) += dwarf-regs.o
> > diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
> > index 71bb17372a6c..25d92bbbfee7 100644
> > --- a/tools/perf/util/symbol_conf.h
> > +++ b/tools/perf/util/symbol_conf.h
> > @@ -9,6 +9,19 @@
> >  struct strlist;
> >  struct intlist;
> >
> > +enum unwind_style {
> > +
> > +     UNWIND_STYLE_UNKNOWN = 0,
> > +
> > +     UNWIND_STYLE_LIBDW,
> > +
> > +     UNWIND_STYLE_LIBUNWIND,
> > +
> > +};

I'll remove the blank lines in the next version.

> > +
> > +#define MAX_UNWIND_STYLE (UNWIND_STYLE_LIBUNWIND + 1)
> > +
> > +
> >  enum a2l_style {
> >       A2L_STYLE_UNKNOWN = 0,
> >       A2L_STYLE_LIBDW,
> > @@ -80,6 +93,7 @@ struct symbol_conf {
> >                       *bt_stop_list_str;
> >       const char              *addr2line_path;
> >       enum a2l_style  addr2line_style[MAX_A2L_STYLE];
> > +     enum unwind_style unwind_style[MAX_UNWIND_STYLE];
> >       unsigned long   time_quantum;
> >         struct strlist        *dso_list,
> >                       *comm_list,
> > @@ -103,3 +117,4 @@ struct symbol_conf {
> >  extern struct symbol_conf symbol_conf;
> >
> >  #endif // __PERF_SYMBOL_CONF
> > +
> > diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
> > index 05e8e68bd49c..d8a5b7d54192 100644
> > --- a/tools/perf/util/unwind-libdw.c
> > +++ b/tools/perf/util/unwind-libdw.c
> > @@ -339,7 +339,7 @@ frame_callback(Dwfl_Frame *state, void *arg)
> >              DWARF_CB_ABORT : DWARF_CB_OK;
> >  }
> >
> > -int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
> > +int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
> >                       struct thread *thread,
> >                       struct perf_sample *data,
> >                       int max_stack,
> > diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
> > index cb8be6acfb6f..a0016b897dae 100644
> > --- a/tools/perf/util/unwind-libunwind.c
> > +++ b/tools/perf/util/unwind-libunwind.c
> > @@ -79,7 +79,7 @@ void unwind__finish_access(struct maps *maps)
> >               ops->finish_access(maps);
> >  }
> >
> > -int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
> > +int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
> >                        struct thread *thread,
> >                        struct perf_sample *data, int max_stack,
> >                        bool best_effort)
> > diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
> > new file mode 100644
> > index 000000000000..9ae7d5ad246d
> > --- /dev/null
> > +++ b/tools/perf/util/unwind.c
> > @@ -0,0 +1,102 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +#include "debug.h"
> > +#include "symbol_conf.h"
> > +#include "unwind.h"
> > +#include <linux/string.h>
> > +#include <string.h>
> > +#include <stdlib.h>
> > +
> > +int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
> > +                     struct thread *thread __maybe_unused,
> > +                     struct perf_sample *data __maybe_unused,
> > +                     int max_stack __maybe_unused,
> > +                     bool best_effort __maybe_unused)
> > +{
> > +     int ret = 0;
> > +
> > +#if defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
> > +     if (symbol_conf.unwind_style[0] == UNWIND_STYLE_UNKNOWN) {
> > +             int i = 0;
> > +#ifdef HAVE_LIBDW_SUPPORT
> > +             symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBDW;
> > +#endif
> > +#ifdef HAVE_LIBUNWIND_SUPPORT
> > +             symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBUNWIND;
> > +#endif
> > +     }
> > +#endif //defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
> > +
> > +     for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.unwind_style); i++) {
> > +             switch (symbol_conf.unwind_style[i]) {
> > +             case UNWIND_STYLE_LIBDW:
> > +#ifdef HAVE_LIBDW_SUPPORT
> > +                     ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
> > +#endif
> > +                     break;
> > +             case UNWIND_STYLE_LIBUNWIND:
> > +#ifdef HAVE_LIBUNWIND_SUPPORT
> > +                     ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
> > +#endif
> > +                     break;
>
>
> What if the user asks for one of the unwinders, symbol_conf.unwind_style
> will be populated with the user's choices, but then here in
> unwind__get_entries() we end up returning 0 because the user choice is
> not built-in?
>
> Also no warning will be emitted that what was asked for is not
> available?
>
> Maybe remove the ifdefs here and have a dummy libdw__get_entries() when
> HAVE_LIBDW_SUPPORT ins't defined that emits the warning and returns -1?
> Ditto for UNWIND_STYLE_LIBUNWIND?

Makes sense, I'll add it to the next version. Since the later patches
are larger I'll wait to address review feedback there before sending
out the next version - this will avoid unnecessary mailing list churn.

Thanks,
Ian

> - Arnaldo
>
> > +             case UNWIND_STYLE_UNKNOWN:
> > +             default:
> > +#if !defined(HAVE_LIBDW_SUPPORT) && !defined(HAVE_LIBUNWIND_SUPPORT)
> > +                     pr_warning_once(
> > +                             "Error: dwarf unwinding not supported, build perf with libdw or libunwind.\n");
> > +#endif
> > +                     ret = -1;
> > +                     break;
> > +             }
> > +             if (ret == 0)
> > +                     break;
> > +     }
> > +     return ret;
> > +}
> > +
> > +int unwind__configure(const char *var, const char *value, void *cb __maybe_unused)
> > +{
> > +     static const char * const unwind_style_names[] = {
> > +             [UNWIND_STYLE_LIBDW] = "libdw",
> > +             [UNWIND_STYLE_LIBUNWIND] = "libunwind",
> > +             NULL
> > +     };
> > +     char *s, *p, *saveptr;
> > +     size_t i = 0;
> > +
> > +     if (strcmp(var, "unwind.style"))
> > +             return 0;
> > +
> > +     if (!value)
> > +             return -1;
> > +
> > +     s = strdup(value);
> > +     if (!s)
> > +             return -1;
> > +
> > +     p = strtok_r(s, ",", &saveptr);
> > +     while (p && i < ARRAY_SIZE(symbol_conf.unwind_style)) {
> > +             bool found = false;
> > +             char *q = strim(p);
> > +
> > +             for (size_t j = UNWIND_STYLE_LIBDW; j < MAX_UNWIND_STYLE; j++) {
> > +                     if (!strcasecmp(q, unwind_style_names[j])) {
> > +                             symbol_conf.unwind_style[i++] = j;
> > +                             found = true;
> > +                             break;
> > +                     }
> > +             }
> > +             if (!found)
> > +                     pr_warning("Unknown unwind style: %s\n", q);
> > +             p = strtok_r(NULL, ",", &saveptr);
> > +     }
> > +
> > +     free(s);
> > +     return 0;
> > +}
> > +
> > +int unwind__option(const struct option *opt __maybe_unused,
> > +                const char *arg,
> > +                int unset __maybe_unused)
> > +{
> > +     return unwind__configure("unwind.style", arg, NULL);
> > +}
> > diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
> > index 9f7164c6d9aa..581d042e170a 100644
> > --- a/tools/perf/util/unwind.h
> > +++ b/tools/perf/util/unwind.h
> > @@ -7,6 +7,7 @@
> >  #include "util/map_symbol.h"
> >
> >  struct maps;
> > +struct option;
> >  struct perf_sample;
> >  struct thread;
> >
> > @@ -26,7 +27,9 @@ struct unwind_libunwind_ops {
> >                          struct perf_sample *data, int max_stack, bool best_effort);
> >  };
> >
> > -#ifdef HAVE_DWARF_UNWIND_SUPPORT
> > +int unwind__configure(const char *var, const char *value, void *cb);
> > +int unwind__option(const struct option *opt, const char *arg, int unset);
> > +
> >  /*
> >   * When best_effort is set, don't report errors and fail silently. This could
> >   * be expanded in the future to be more permissive about things other than
> > @@ -36,8 +39,20 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
> >                       struct thread *thread,
> >                       struct perf_sample *data, int max_stack,
> >                       bool best_effort);
> > -/* libunwind specific */
> > +
> > +#ifdef HAVE_LIBDW_SUPPORT
> > +int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
> > +                    struct thread *thread,
> > +                    struct perf_sample *data, int max_stack,
> > +                    bool best_effort);
> > +#endif
> > +
> >  #ifdef HAVE_LIBUNWIND_SUPPORT
> > +/* libunwind specific */
> > +int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
> > +                        struct thread *thread,
> > +                        struct perf_sample *data, int max_stack,
> > +                        bool best_effort);
> >  #ifndef LIBUNWIND__ARCH_REG_ID
> >  #define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum)
> >  #endif
> > @@ -57,26 +72,5 @@ static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
> >  static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
> >  static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
> >  #endif
> > -#else
> > -static inline int
> > -unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
> > -                 void *arg __maybe_unused,
> > -                 struct thread *thread __maybe_unused,
> > -                 struct perf_sample *data __maybe_unused,
> > -                 int max_stack __maybe_unused,
> > -                 bool best_effort __maybe_unused)
> > -{
> > -     return 0;
> > -}
> > -
> > -static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
> > -                                      struct map *map __maybe_unused,
> > -                                      bool *initialized __maybe_unused)
> > -{
> > -     return 0;
> > -}
> >
> > -static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
> > -static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
> > -#endif /* HAVE_DWARF_UNWIND_SUPPORT */
> >  #endif /* __UNWIND_H */
> > --
> > 2.53.0.473.g4a7958ca14-goog


^ permalink raw reply

* [GIT PULL] Qualcomm driver updates for v7.1
From: Bjorn Andersson @ 2026-03-31 21:47 UTC (permalink / raw)
  To: arm, soc
  Cc: linux-arm-msm, linux-arm-kernel, Arnd Bergmann,
	Krzysztof Kozlowski, Dmitry Baryshkov, Kathiravan Thirumoorthy,
	Abel Vesa, Anjelique Melendez, Daniel Lezcano, Aelin Reidel,
	Alok Tiwari, Chris Lew, Gopikrishna Garmidi, Lei wang,
	Richard Acayan, Unnathi Chalicheemala, Hrishabh Rajput,
	Jens Glathe, Le Qi, Luca Weiss, Mukesh Ojha, Pankaj Patil,
	Rosen Penev, Srinivas Kandagatla, Val Packett, Vladimir Zapolskiy,
	Yijie Yang


The following changes since commit 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f:

  Linux 7.0-rc1 (2026-02-22 13:18:59 -0800)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git tags/qcom-drivers-for-7.1

for you to fetch changes up to d6e766e391ef0b2be62682e007223fc72ba7764f:

  Merge branch '20260125-iris-ubwc-v4-1-1ff30644ac81@oss.qualcomm.com' into drivers-for-7.1 (2026-03-30 12:46:14 -0500)

----------------------------------------------------------------
Qualcomm driver updates for v7.1

Add ECS LIVA QC710, Glymur CRD, Mahua CRD, Purwa IoT EVK, and Asus
Vivobook to the QSEECOM allow-list, to enable UEFI variable access
through uefisecapp.

Register the Gunyah watchdog device if the SCM driver finds itself
running under Gunyah. Clean up some locking using guards.

Handle possible cases where AOSS cooling state is given a non-boolean
state.

Replace LLCC per-slice activation bitmap with reference counting. Also
add SDM670 support.

Improve probe deferral handling in the OCMEM driver.

Add Milos, QCS615, Eliza, Glymur, and Mahua support to the pd-mapper.

Add support for SoCCP-based pmic-glink, as found in Glymur and
Kaanapali.

Add common QMI service ids to the main qmi headerfile, to avoid
spreading these constants in various drivers.

Add support for version 2 of SMP2P and implement the irqchip state
reading support.

Add CQ7790, SA8650P, SM7450, SM7450P, and IPQ5210 SoC and the PM7550BA
PMIC identifiers to the socinfo driver.

Add Eliza and Mahua support to the UBWC driver, introduce helpers for
drivers to read out min_acc length and other programmable values, and
disable bank swizzling for Glymur.

Simplify the logic related to allocation of NV download request in the
WCNSS control driver.

----------------------------------------------------------------
Abel Vesa (3):
      soc: qcom: socinfo: Add PM7550BA PMIC
      dt-bindings: firmware: qcom,scm: document Eliza SCM Firmware Interface
      soc: qcom: pd-mapper: Add support for Eliza

Aelin Reidel (2):
      dt-bindings: arm: qcom,ids: Add SoC IDs for SM7450 and SM7450P
      soc: qcom: socinfo: Add SoC IDs for SM7450 and SM7450P

Alok Tiwari (2):
      soc: qcom: llcc: fix v1 SB syndrome register offset
      soc: qcom: aoss: compare against normalized cooling state

Anjelique Melendez (3):
      dt-bindings: soc: qcom: qcom,pmic-glink: Add Glymur and Kaanapali compatibles
      soc: qcom: pmic_glink: Add charger PDR service information to client data
      soc: qcom: pmic_glink: Add support for Glymur and Kaanapali

Bjorn Andersson (2):
      Merge branch '20260309230346.3584252-2-daniel.lezcano@oss.qualcomm.com' into drivers-for-7.1
      Merge branch '20260125-iris-ubwc-v4-1-1ff30644ac81@oss.qualcomm.com' into drivers-for-7.1

Chris Lew (2):
      soc: qcom: smp2p: Add irqchip state support
      soc: qcom: smp2p: Add support for smp2p v2

Daniel Lezcano (3):
      soc: qcom: qmi: Enumerate the service IDs of QMI
      soc: qcom: pdr: Use the unified QMI service ID instead of defining it locally
      samples: qmi: Use the unified QMI service ID instead of defining it locally

Dmitry Baryshkov (6):
      soc: qcom: ubwc: disable bank swizzling for Glymur platform
      soc: qcom: ocmem: make the core clock optional
      soc: qcom: ocmem: register reasons for probe deferrals
      soc: qcom: ocmem: return -EPROBE_DEFER is ocmem is not available
      soc: qcom: ubwc: add helper to get min_acc length
      soc: qcom: ubwc: add helpers to get programmable values

Gopikrishna Garmidi (2):
      soc: qcom: ubwc: Add support for Mahua
      firmware: qcom: scm: Allow QSEECOM on Mahua CRD

Hrishabh Rajput (1):
      firmware: qcom: scm: Register gunyah watchdog device

Jens Glathe (1):
      firmware: qcom: scm: allow QSEECOM on ASUS Vivobook X1P42100 variant

Kathiravan Thirumoorthy (4):
      dt-bindings: arm: qcom,ids: add SOC IDs for IPQ5210 family
      soc: qcom: socinfo: add SoC ID for IPQ5210 family
      dt-bindings: firmware: qcom,scm: Document ipq5210 SCM
      dt-bindings: firmware: qcom,scm: Document ipq9650 SCM

Krzysztof Kozlowski (7):
      dt-bindings: arm: qcom,ids: Add SoC ID for CQ7790
      soc: qcom: socinfo: Add SoC ID for CQ7790
      firmware: qcom: uefisecapp: Simplify mutex with guard
      firmware: qcom: uefisecapp: Annotate acquiring locks for context tracking
      firmware: qcom: scom: Simplify mutex with guard
      soc: qcom: ubwc: Remove redundant x1e80100_data
      soc: qcom: ubwc: Add configuration Eliza SoC

Le Qi (1):
      soc: qcom: pd-mapper: Add QCS615 power domain mappings

Lei wang (2):
      dt-bindings: arm: qcom,ids: Add SoC ID for SA8650P
      soc: qcom: socinfo: Add SoC ID for SA8650P

Luca Weiss (1):
      soc: qcom: pd-mapper: Add Milos compatible

Mukesh Ojha (1):
      firmware: qcom_scm: don't opencode kmemdup

Pankaj Patil (1):
      firmware: qcom: scm: Allow QSEECOM on Glymur CRD

Richard Acayan (2):
      dt-bindings: cache: qcom,llcc: Add SDM670 compatible
      soc: qcom: llcc: Add configuration data for SDM670

Rosen Penev (1):
      soc: qcom: wcnss: simplify allocation of req

Srinivas Kandagatla (1):
      soc: qcom: pd-mapper: Add support for Glymur and Mahua

Unnathi Chalicheemala (2):
      soc: qcom: llcc: Add per-slice counter and common llcc slice descriptor
      soc: qcom: llcc: Use guards for mutex handling

Val Packett (1):
      firmware: qcom: scm: Allow QSEECOM on ECS LIVA QC710

Vladimir Zapolskiy (1):
      soc: qcom: pd-mapper: Simplify code using of_root to get root device tree node

Yijie Yang (1):
      firmware: qcom: scm: Allow QSEECOM on PURWA-IOT-EVK

 .../devicetree/bindings/cache/qcom,llcc.yaml       |   2 +
 .../devicetree/bindings/firmware/qcom,scm.yaml     |   4 +
 .../bindings/soc/qcom/qcom,pmic-glink.yaml         |   2 +
 drivers/firmware/qcom/qcom_qseecom_uefisecapp.c    |   9 +-
 drivers/firmware/qcom/qcom_scm.c                   |  70 +++++++-
 drivers/soc/qcom/llcc-qcom.c                       | 188 +++++++++++++++------
 drivers/soc/qcom/ocmem.c                           |  17 +-
 drivers/soc/qcom/pdr_interface.c                   |   4 +-
 drivers/soc/qcom/pdr_internal.h                    |   3 -
 drivers/soc/qcom/pmic_glink.c                      |  66 +++++---
 drivers/soc/qcom/qcom_aoss.c                       |   2 +-
 drivers/soc/qcom/qcom_pd_mapper.c                  |  33 +++-
 drivers/soc/qcom/smp2p.c                           | 103 ++++++++++-
 drivers/soc/qcom/socinfo.c                         |  11 ++
 drivers/soc/qcom/ubwc_config.c                     |  31 ++--
 drivers/soc/qcom/wcnss_ctrl.c                      |  17 +-
 include/dt-bindings/arm/qcom,ids.h                 |  10 ++
 include/linux/soc/qcom/llcc-qcom.h                 |   8 +-
 include/linux/soc/qcom/qmi.h                       |  12 ++
 include/linux/soc/qcom/ubwc.h                      |  25 +++
 samples/qmi/qmi_sample_client.c                    |   2 +-
 21 files changed, 480 insertions(+), 139 deletions(-)


^ permalink raw reply

* [GIT PULL] Qualcomm Arm64 defconfig updates for v7.1
From: Bjorn Andersson @ 2026-03-31 21:55 UTC (permalink / raw)
  To: arm, soc
  Cc: linux-arm-msm, linux-arm-kernel, Arnd Bergmann, Luca Weiss,
	Taniya Das, Abel Vesa, Ajay Kumar Nandam, Harshal Dev,
	Kathiravan Thirumoorthy, Krzysztof Kozlowski, Neil Armstrong,
	Pankaj Patil, Srinivas Kandagatla, Vishnu Saini


The following changes since commit 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f:

  Linux 7.0-rc1 (2026-02-22 13:18:59 -0800)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git tags/qcom-arm64-defconfig-for-7.1

for you to fetch changes up to fdeb077b8ae53a6ef772c5b3c4d1f3a408dac2a0:

  arm64: defconfig: enable pci-pwrctrl-generic as module (2026-03-23 21:40:52 -0500)

----------------------------------------------------------------
Qualcomm Arm64 defconfig updates for v7.1

Enable base drivers for booting boards based on Kaanapali, Glymur,
Eliza, SM8750, and IPQ5210 SoCs.

Enable the Milos LPASS LPI driver. Enable the Qualcomm WCD937x headphone
codec driver, used on QCM6490 boards.

Enable the QCOMTEE driver, to support the interface found in various
Qualcomm SoCs.

Enable ethernet and analog codecs used on the Arduino Ventuno Q.

Enable the Lontium LT8713sx driver, used for the Monaco EVK board.

Enable the PCI pwrctrl generic driver used in a few different
Qualcomm-based boards with USB controllers on PCI buses.

----------------------------------------------------------------
Abel Vesa (1):
      arm64: defconfig: Enable Qualcomm Eliza basic resource providers

Ajay Kumar Nandam (1):
      arm64: defconfig: Enable Qualcomm WCD937x headphone codec as module

Harshal Dev (1):
      arm64: defconfig: Enable QCOMTEE module for QTEE-enabled Qualcomm SoCs

Kathiravan Thirumoorthy (1):
      arm64: defconfig: enable IPQ5210 RDP504 base configs

Krzysztof Kozlowski (1):
      arm64: defconfig: Enable Qualcomm Eliza SoC display clock controller

Luca Weiss (2):
      arm64: defconfig: Enable S5KJN1 camera sensor
      arm64: defconfig: Enable Milos LPASS LPI pinctrl driver

Neil Armstrong (1):
      arm64: defconfig: enable pci-pwrctrl-generic as module

Pankaj Patil (1):
      arm64: defconfig: Enable configs for Qualcomm Glymur SoC

Srinivas Kandagatla (1):
      arm64: defconfig: Enable configs for Arduino VENTUNO Q

Taniya Das (2):
      arm64: defconfig: Enable SM8750 clock controllers
      arm64: defconfig: Enable Kaanapali clock controllers

Vishnu Saini (1):
      arm64: defconfig: Enable Lontium LT8713sx driver

 arch/arm64/configs/defconfig | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)


^ permalink raw reply

* Re: (subset) [PATCH v5 0/4] arm64: dts: rockchip: Fix vdec register blocks order on RK3576/RK3588
From: Heiko Stuebner @ 2026-03-31 22:22 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Detlev Casanova,
	Ezequiel Garcia, Mauro Carvalho Chehab, Nicolas Dufresne,
	Hans Verkuil, Cristian Ciocaltea
  Cc: Heiko Stuebner, kernel, devicetree, linux-arm-kernel,
	linux-rockchip, linux-kernel, Conor Dooley, linux-media,
	Conor Dooley, Krzysztof Kozlowski
In-Reply-To: <20260304-vdec-reg-order-rk3576-v5-0-7006fad42c3a@collabora.com>


On Wed, 04 Mar 2026 23:00:39 +0200, Cristian Ciocaltea wrote:
> When building device trees for the RK3576 based boards, DTC shows the
> following complaint:
> 
>   rk3576.dtsi:1282.30-1304.5: Warning (simple_bus_reg): /soc/video-codec@27b00000: simple-bus unit address format error, expected "27b00100"
> 
> The first two patches updates 'reg-names' property in rockchip,vdec
> binding to make it mandatory for RK3576 & RK3588, since this is what the
> driver expects, as well as to allow providing the register blocks
> following the address-based order and, consequently, ensure the video
> decoder unit address points to the primary register range.
> 
> [...]

Applied, thanks!

[3/4] arm64: dts: rockchip: Fix vdec register blocks order on RK3576
      commit: f8fa98aa23699b7019023cc7cd8bbb8d837f2d3b
[4/4] arm64: dts: rockchip: Update vdec register blocks order on RK3588
      commit: 6c4a6f7f19e69bedddee87bebd4f1f1c7411b820

Best regards,
-- 
Heiko Stuebner <heiko@sntech.de>


^ permalink raw reply

* Re: [PATCH 1/5] lib/crc: arm64: Drop unnecessary chunking logic from crc64
From: Eric Biggers @ 2026-03-31 22:33 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: linux-crypto, linux-arm-kernel, Demian Shulhan
In-Reply-To: <20260330144630.33026-8-ardb@kernel.org>

On Mon, Mar 30, 2026 at 04:46:32PM +0200, Ard Biesheuvel wrote:
> On arm64, kernel mode NEON executes with preemption enabled, so there is
> no need to chunk the input by hand.
> 
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

There's still similar "chunking" in other arm64 code:

    $ git grep -E 'SZ_4K|cond_yield' lib/crypto/arm64
    lib/crypto/arm64/chacha.h:              unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
    lib/crypto/arm64/poly1305.h:                    unsigned int todo = min_t(unsigned int, len, SZ_4K);
    lib/crypto/arm64/sha1-ce-core.S:        cond_yield      1f, x5, x6
    lib/crypto/arm64/sha256-ce.S:   cond_yield      1f, x5, x6
    lib/crypto/arm64/sha3-ce-core.S:        cond_yield 4f, x8, x9
    lib/crypto/arm64/sha512-ce-core.S:      cond_yield      3f, x4, x5

I thought it was still sticking around, despite kernel-mode NEON now
being preemptible on arm64, because of CONFIG_PREEMPT_VOLUNTARY.

However, I see that support for CONFIG_PREEMPT_VOLUNTARY was recently
removed on arm64.  So that's what finally makes this no longer needed,
and we can now clean up these other cases too, right?

(Though, I can't find where the voluntary preemption points actually
were.  So maybe they weren't actually there anyway.)

- Eric


^ permalink raw reply

* Re: [PATCH 5/5] lib/crc: arm: Enable arm64's NEON intrinsics implementation of crc64
From: Eric Biggers @ 2026-03-31 22:41 UTC (permalink / raw)
  To: Ard Biesheuvel; +Cc: linux-crypto, linux-arm-kernel, Demian Shulhan
In-Reply-To: <20260330144630.33026-12-ardb@kernel.org>

On Mon, Mar 30, 2026 at 04:46:36PM +0200, Ard Biesheuvel wrote:
> Enable big-endian support only on GCC - the code generated by Clang is
> horribly broken.
[...]
> +#if defined(CONFIG_ARM) && defined(CONFIG_CC_IS_CLANG)
> +static inline uint64x2_t pmull64(uint64x2_t a, uint64x2_t b)
> +{
> +	uint64_t l = vgetq_lane_u64(a, 0);
> +	uint64_t m = vgetq_lane_u64(b, 0);
> +	uint64x2_t result;
> +
> +	asm("vmull.p64	%q0, %1, %2" : "=w"(result) : "w"(l), "w"(m));
> +
> +	return result;
> +}

Perhaps omit big endian support, and use the inline asm implementation
of these functions with both gcc and clang?  The more unique
combinations need to be tested to cover all the code, the higher the
chance of one being missed in testing.

Also, leaving shared code in lib/crc/arm64/ will be confusing.  How
about lib/crc/arm-common/, and crc64_nvme_arm64_c => crc64_nvme_neon()?
Or even just put crc64-neon.c directly in lib/crc/.

- Eric


^ permalink raw reply

* Re: [PATCH V3 7/7] arm64/hw_breakpoint: Enable FEAT_Debugv8p9
From: Rob Herring @ 2026-03-31 22:58 UTC (permalink / raw)
  To: Mark Rutland
  Cc: Anshuman Khandual, linux-arm-kernel, linux-kernel,
	Jonathan Corbet, Marc Zyngier, Oliver Upton, James Morse,
	Suzuki K Poulose, Catalin Marinas, Will Deacon, Mark Brown,
	kvmarm
In-Reply-To: <Z2AH1SN5CipWkkE4@J2N7QTR9R3>

On Mon, Dec 16, 2024 at 10:58:29AM +0000, Mark Rutland wrote:
> On Mon, Dec 16, 2024 at 09:38:31AM +0530, Anshuman Khandual wrote:
> > Currently there can be maximum 16 breakpoints, and 16 watchpoints available
> > on a given platform - as detected from ID_AA64DFR0_EL1.[BRPs|WRPs] register
> > fields. But these breakpoint, and watchpoints can be extended further up to
> > 64 via a new arch feature FEAT_Debugv8p9.
> > 
> > This first enables banked access for the breakpoint and watchpoint register
> > set via MDSELR_EL1, extended exceptions via MDSCR_EL1.EMBWE and determining
> > available breakpoints and watchpoints in the platform from ID_AA64DFR1_EL1,
> > when FEAT_Debugv8p9 is enabled.
> 
> [...]

Well, this series has landed on my plate...


> > +static u64 read_wb_reg(int reg, int n)
> > +{
> > +	unsigned long flags;
> > +	u64 val;
> > +
> > +	if (!is_debug_v8p9_enabled())
> > +		return __read_wb_reg(reg, n);
> > +
> > +	/*
> > +	 * Bank selection in MDSELR_EL1, followed by an indexed read from
> > +	 * breakpoint (or watchpoint) registers cannot be interrupted, as
> > +	 * that might cause misread from the wrong targets instead. Hence
> > +	 * this requires mutual exclusion.
> > +	 */
> > +	local_irq_save(flags);
> > +	write_sysreg_s(SYS_FIELD_PREP(MDSELR_EL1, BANK, n / MAX_PER_BANK), SYS_MDSELR_EL1);
> > +	isb();
> > +	val = __read_wb_reg(reg, n % MAX_PER_BANK);
> > +	local_irq_restore(flags);
> > +	return val;
> > +}
> >  NOKPROBE_SYMBOL(read_wb_reg);
> 
> I don't believe that disabling interrupts here is sufficient. On the
> last version I asked about the case of racing with a watchpoint handler:
> 
> | For example, what prevents watchpoint_handler() from firing in the
> | middle of arch_install_hw_breakpoint() or
> | arch_uninstall_hw_breakpoint()?
> 
> ... and disabling interrupts cannot prevent that, because
> local_irq_{save,restore}() do not affect the behaviour of watchpoints or
> breakpoints.

I think the answer is we just need NOKPROBE_SYMBOL() annotation on 
hw_breakpoint_control() (what arch_install_hw_breakpoint() and 
arch_uninstall_hw_breakpoint() wrap). We also need that on __read_wb_reg 
and __read_wb_reg though I would think those are folded into the calling 
functions by the compiler. Interestly, the x86 code doesn't use the 
annotation at all.

I initially thought the IRQ disabling is also still needed as IRQ 
handlers can trigger breakpoints. However, the x86 version of 
arch_install_hw_breakpoint() contains a lockdep_assert_irqs_disabled(), 
so it seems for that case interrupts are already disabled. And in debug 
exceptions, we disable interrupts. So I think the interrupt disabling 
can be dropped.


> Please can you try to answer the questions I asked last time, i.e.
> 
> | What prevents a race with an exception handler? e.g. 
> | 
> | * Does the structure of the code prevent that somehow?

If you can't set a breakpoint/watchpoint in NOKPROBE_SYMBOL() annotated 
code, you can't race.

However, there's no such annotation for data. It looks like the kernel 
policy is "don't do that" or disable all breakpoints/watchpoints.

> | 
> | * What context(s) does this code execute in?
> |   - Are debug exceptions always masked?

No.

> |   - Do we disable breakpoints/watchpoints around (some) manipulation of
> |     the relevant registers?

Yes, with NOKPROBE_SYMBOL().

Rob


^ permalink raw reply

* Re: [PATCH V3 7/7] arm64/hw_breakpoint: Enable FEAT_Debugv8p9
From: Rob Herring @ 2026-03-31 23:02 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: linux-arm-kernel, linux-kernel, Jonathan Corbet, Marc Zyngier,
	Oliver Upton, James Morse, Suzuki K Poulose, Catalin Marinas,
	Will Deacon, Mark Brown, Mark Rutland, kvmarm
In-Reply-To: <20241216040831.2448257-8-anshuman.khandual@arm.com>

On Mon, Dec 16, 2024 at 09:38:31AM +0530, Anshuman Khandual wrote:
> Currently there can be maximum 16 breakpoints, and 16 watchpoints available
> on a given platform - as detected from ID_AA64DFR0_EL1.[BRPs|WRPs] register
> fields. But these breakpoint, and watchpoints can be extended further up to
> 64 via a new arch feature FEAT_Debugv8p9.
> 
> This first enables banked access for the breakpoint and watchpoint register
> set via MDSELR_EL1, extended exceptions via MDSCR_EL1.EMBWE and determining
> available breakpoints and watchpoints in the platform from ID_AA64DFR1_EL1,
> when FEAT_Debugv8p9 is enabled.
> 
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com>
> ---
> Changes in V3:
> 
> - Used SYS_FIELD_PREP() in read_wb_reg() and write_wb_reg()
> - Added MAX_PER_BANK based BUILD_BUG_ON() tests in arch_hw_breakpoint_init()
> - Dropped local variables i.e mdsel_bank and index
> - Derived bank and index from MAX_PER_BANK as required
> 
>  arch/arm64/include/asm/debug-monitors.h |  1 +
>  arch/arm64/include/asm/hw_breakpoint.h  | 47 ++++++++++++++++++------
>  arch/arm64/kernel/debug-monitors.c      | 15 +++++---
>  arch/arm64/kernel/hw_breakpoint.c       | 48 +++++++++++++++++++++++--
>  4 files changed, 95 insertions(+), 16 deletions(-)
> 

[...]

>  void enable_debug_monitors(enum dbg_active_el el)
>  {
> -	u32 mdscr, enable = 0;
> +	u64 mdscr, enable = 0;
>  
>  	WARN_ON(preemptible());
>  
> @@ -90,6 +91,9 @@ void enable_debug_monitors(enum dbg_active_el el)
>  	    this_cpu_inc_return(kde_ref_count) == 1)
>  		enable |= DBG_MDSCR_KDE;
>  
> +	if (is_debug_v8p9_enabled())
> +		enable |= DBG_MDSCR_EMBWE;

Just to record my own findings, this is in the wrong place. This will 
cause the below code to run every time, not just on the first enable or 
kernel or user mode breakpoints. it needs to be moved into the below if.

> +
>  	if (enable && debug_enabled) {
>  		mdscr = mdscr_read();
>  		mdscr |= enable;


^ permalink raw reply

* [PATCH v10 0/6] Introduce MAX77759 charger driver
From: Amit Sunil Dhamne via B4 Relay @ 2026-03-31 23:22 UTC (permalink / raw)
  To: André Draszik, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jagan Sridharan, Mark Brown,
	Matti Vaittinen, Andrew Morton, Sebastian Reichel,
	Amit Sunil Dhamne, Heikki Krogerus, Peter Griffin, Tudor Ambarus,
	Alim Akhtar
  Cc: linux-kernel, devicetree, linux-usb, linux-pm, linux-arm-kernel,
	linux-samsung-soc, RD Babiera, Kyle Tso, Krzysztof Kozlowski

MAX77759 PMIC is used in Pixel 6 and 6 Pro (Oriole/Raven) boards.
One of the functions of the MAX77759 PMIC is a battery charger. This
patchset introduces a driver for this function. One of the unique
features of this charger driver is that it works with a USB input where
the Type-C controller is TCPCI based.

Changes to the board files will follow soon once this patchset is reviewed.

For reference to the MAX77759 MFD based patchset (present in upstream):
https://lore.kernel.org/all/20250509-max77759-mfd-v10-0-962ac15ee3ef@linaro.org/

Dependency list for patches (directionality indicates depends on):
[6] -> [5] -> [4] & [3]

The changes need to be applied in order. In this case this probably
would be the USB subsystem as that's the leaf in the dependency list.

---
Kernel-doc output for include/linux/mfd/max77759.h (partial and only for
the changes introduced by me:

.. c:enum:: max77759_chgr_chgin_dtls_status

  Charger Input Status

.. container:: kernelindent

    **Constants**

    ``MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE``
      Charger input voltage (Vchgin) < Under Voltage Threshold (Vuvlo)

    ``MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE``
      Vchgin > Vuvlo and Vchgin < (Battery Voltage (Vbatt) + system voltage (Vsys))

    ``MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE``
      Vchgin > Over Voltage threshold (Vovlo)

    ``MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID``
      Vchgin > Vuvlo, Vchgin < Vovlo and Vchgin > (Vsys + Vbatt)

.. c:enum:: max77759_chgr_bat_dtls_states

  Battery Details

.. container:: kernelindent

    **Constants**

    ``MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP``
      No battery and the charger suspended

    ``MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY``
      Vbatt < Vtrickle

    ``MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT``
      Charging suspended due to timer fault

    ``MAX77759_CHGR_BAT_DTLS_BAT_OKAY``
      Battery okay and Vbatt > Min Sys Voltage (Vsysmin)

    ``MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE``
      Battery is okay. Vtrickle < Vbatt < Vsysmin

    ``MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE``
      Battery voltage > Overvoltage threshold

    ``MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT``
      Battery current exceeds overcurrent threshold

    ``MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE``
      Battery only mode and battery level not available

.. c:enum:: max77759_chgr_chg_dtls_states

  Charger Details

.. container:: kernelindent

    **Constants**

    ``MAX77759_CHGR_CHG_DTLS_PREQUAL``
      Charger in prequalification mode

    ``MAX77759_CHGR_CHG_DTLS_CC``
      Charger in fast charge const curr mode

    ``MAX77759_CHGR_CHG_DTLS_CV``
      Charger in fast charge const voltage mode

    ``MAX77759_CHGR_CHG_DTLS_TO``
      Charger is in top off mode

    ``MAX77759_CHGR_CHG_DTLS_DONE``
      Charger is done

    ``MAX77759_CHGR_CHG_DTLS_RSVD_1``
      Reserved

    ``MAX77759_CHGR_CHG_DTLS_TIMER_FAULT``
      Charger is in timer fault mode

    ``MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM``
      Charger is suspended as battery removal detected

    ``MAX77759_CHGR_CHG_DTLS_OFF``
      Charger is off. Input invalid or charger disabled

    ``MAX77759_CHGR_CHG_DTLS_RSVD_2``
      Reserved

    ``MAX77759_CHGR_CHG_DTLS_RSVD_3``
      Reserved

    ``MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER``
      Charger is off as watchdog timer expired

    ``MAX77759_CHGR_CHG_DTLS_SUSP_JEITA``
      Charger is in JEITA control mode
---

To: Sebastian Reichel <sre@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
To: André Draszik <andre.draszik@linaro.org>
To: Lee Jones <lee@kernel.org>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: Badhri Jagan Sridharan <badhri@google.com>
To: Heikki Krogerus <heikki.krogerus@linux.intel.com>
To: Peter Griffin <peter.griffin@linaro.org>
To: Tudor Ambarus <tudor.ambarus@linaro.org>
To: Alim Akhtar <alim.akhtar@samsung.com>
To: Mark Brown <broonie@kernel.org>
To: Matti Vaittinen <mazziesaccount@gmail.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org
Cc: linux-pm@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-usb@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-samsung-soc@vger.kernel.org
Cc: RD Babiera <rdbabiera@google.com>
Cc: Kyle Tso <kyletso@google.com>
Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
---
Changes in v10:
- Fixed comment style (/* -> /**) to make it a kernel-doc comment. (Lee
  Jones)
- Link to v9: https://lore.kernel.org/r/20260325-max77759-charger-v9-0-4486dd297adc@google.com

Changes in v9:
- Fixed nits in mfd/max77759.* (Lee Jones)
  - s/max77759_chrg_irq_chip/max77759_chgr_irq_chip
  - s/bettery/battery
  - Fix alignment in descriptions in kerneldoc comments
- Link to v8 resend: https://lore.kernel.org/r/20260314-max77759-charger-v8-0-226ca5f8c7d2@google.com
- Link to v8: https://lore.kernel.org/all/20260224-max77759-charger-v8-0-eb86bd570e9c@google.com/

Changes in v8:
- Add an newline char at the end of dev_* prints. (André Draszik)
- Return PTR_ERR() instead of -EPROBE_DEFER when devm_power_supply_register()
  fails in max77759 charger probe. (André Draszik)
- Link to v7: https://lore.kernel.org/r/20260218-max77759-charger-v7-0-e8d907ce69c5@google.com

Changes in v7:
- Add register relock for protected registers in fail path. (André Draszik)
- Switch to usage of scoped_guard instead of guard. (LKP test bot)
- Link to v6: https://lore.kernel.org/r/20260214-max77759-charger-v6-0-28c09bda74b4@google.com

Changes in v6:
-  Linear Range usage (André Draszik):
  - Dedicate individual arrays for inlim, chgcc & chg_cv_prm to simplify
    code.
  - Use numerical values instead of macros for linear_range array init.
  - Remove macros defining current and voltage limits due to above.
  - Didn't use Reviewed-by tag for Patch 3 due to the above.
  - Add new linear_ranges api to leverage it for obtaining selector
    values.
  - Improve voltage and current getters and setters functions by leveraging
    existing and new linear_ranges API.
- IRQ related changes (André Draszik)
  - Dedicated names for individual irqs.
  - Refactor irq handlers.
  - Ratelimit prints
- Retry mechanism (André Draszik):
  - Initialize error retry counter to 0 when psy work is scheduled on a
    new notifier event.
  - Protect the counter using a lock.
  - Add appropriate prints.
- Link to v5: https://lore.kernel.org/r/20260203-max77759-charger-v5-0-b50395376a5f@google.com

Changes in v5:
- Use linear_range library instead of reinventing it. (André Draszik)
  - This requires a selector_max value so modified mfd/max77759.h to
    include it for CHGCC and CHG_ILIM.
  - Removed "reviewed-by" for Patch 3 (mfd) due to above
- Use asnyc probe type. (André Draszik)
- Retry mechanism for psy_work. (André Draszik)
- Minor nits (André Draszik):
  - Use named initializers for instantiating structs.
  - Use static qualifier for `psy_name` variable.
  - Refactor if-else ladder to remove else handling if return in prior
    "if" loop.
  - Remove redundant `unlikely`.
- Link to v4: https://lore.kernel.org/r/20260121-max77759-charger-v4-0-694234c8ded1@google.com

Changes in v4:
- Removed a stray tabspace in mfd/max77759.h. (André Draszik)
- Fixed the following issues in Patch 4/5 (André Draszik):
  - Re-order Kconfig entry
  - Refactored to not use global variable
  - Use of clamp() to clamp values instead of duplicating logic
  - Return IRQ_NONE for unhandled irqs or error conditions
  - Remove debug messages in irq handler
  - Refactor code to use dev_err_probe in *_init_irqhandler()
  - Remove unneeded irq_flags
  - Check return values of regmap ops
  - Other nits like newlines, not using greedy init, using print stmnts
- Link to v3: https://lore.kernel.org/r/20251227-max77759-charger-v3-0-54e664f5ca92@google.com

Changes in v3:
- Had incorrectly folded the charger sub-device with the pmic parent.
  Corrected it. (Krzysztof Kozlowski)
- Link to v2: https://lore.kernel.org/r/20251218-max77759-charger-v2-0-2b259980a686@google.com

Changes in v2:
- Fold charger binding in maxim,max77759-charger.yaml to its parent
  node. (Krzysztof Kozlowski)
- Renamed regulator supplier & consumer. (Krzysztof Kozlowski & Heikki
  Krogerus)
- Removed explicit setting of irq trigger types in max77759 driver.
  (André Draszik & Krzysztof Kozlowski)
- Complete bit definitions for IRQ registers. (André Draszik)
- Consolidate all bit definitions for charger IP in mfd/max77759.h.
  (André Draszik)
- Modify the handling of charger IRQs such that regmap IRQ chip handles
  masking, de-mux and acking of interrupts. (André Draszik)
- Remove unused macro definitions relating to Charger modes in tcpci
  maxim driver (André Draszik)
- Add dependency on Regulator class in Kconfig definition for max77759
  chg. (Kernel Test Robot)
- Link to v1: https://lore.kernel.org/r/20251123-max77759-charger-v1-0-6b2e4b8f7f54@google.com

---
Amit Sunil Dhamne (6):
      dt-bindings: mfd: maxim,max77759: reference power-supply schema and add regulator property
      dt-bindings: usb: maxim,max33359: Add supply property for vbus
      mfd: max77759: add register bitmasks and modify irq configs for charger
      lib/linear_ranges: Add linear_range_get_selector_high_array
      power: supply: max77759: add charger driver
      usb: typec: tcpm/tcpci_maxim: deprecate WAR for setting charger mode

 .../devicetree/bindings/mfd/maxim,max77759.yaml    |  16 +-
 .../devicetree/bindings/usb/maxim,max33359.yaml    |   4 +
 MAINTAINERS                                        |   6 +
 drivers/mfd/max77759.c                             |  95 ++-
 drivers/power/supply/Kconfig                       |  11 +
 drivers/power/supply/Makefile                      |   1 +
 drivers/power/supply/max77759_charger.c            | 774 +++++++++++++++++++++
 drivers/usb/typec/tcpm/tcpci_maxim.h               |   1 +
 drivers/usb/typec/tcpm/tcpci_maxim_core.c          |  54 +-
 include/linux/linear_range.h                       |   3 +
 include/linux/mfd/max77759.h                       | 166 ++++-
 lib/linear_ranges.c                                |  36 +
 12 files changed, 1106 insertions(+), 61 deletions(-)
---
base-commit: ecc64d2dc9ff9738d2a896beb68e02c2feaf9a02
change-id: 20251105-max77759-charger-852b626d661a

Best regards,
-- 
Amit Sunil Dhamne <amitsd@google.com>




^ permalink raw reply

* [PATCH v10 1/6] dt-bindings: mfd: maxim,max77759: reference power-supply schema and add regulator property
From: Amit Sunil Dhamne via B4 Relay @ 2026-03-31 23:22 UTC (permalink / raw)
  To: André Draszik, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jagan Sridharan, Mark Brown,
	Matti Vaittinen, Andrew Morton, Sebastian Reichel,
	Amit Sunil Dhamne, Heikki Krogerus, Peter Griffin, Tudor Ambarus,
	Alim Akhtar
  Cc: linux-kernel, devicetree, linux-usb, linux-pm, linux-arm-kernel,
	linux-samsung-soc, RD Babiera, Kyle Tso, Krzysztof Kozlowski
In-Reply-To: <20260331-max77759-charger-v10-0-76f59233c369@google.com>

From: Amit Sunil Dhamne <amitsd@google.com>

Extend the max77759 binding to reference power-supply schema, so that
PMIC node can reference its supplier. Also, add regulator property to
control CHGIN (OTG) voltage.

Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Reviewed-by: André Draszik <andre.draszik@linaro.org>
---
 .../devicetree/bindings/mfd/maxim,max77759.yaml          | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
index 525de9ab3c2b..42e4a84d5204 100644
--- a/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
+++ b/Documentation/devicetree/bindings/mfd/maxim,max77759.yaml
@@ -16,6 +16,9 @@ description: |
   The MAX77759 includes Battery Charger, Fuel Gauge, temperature sensors, USB
   Type-C Port Controller (TCPC), NVMEM, and a GPIO expander.
 
+allOf:
+  - $ref: /schemas/power/supply/power-supply.yaml#
+
 properties:
   compatible:
     const: maxim,max77759
@@ -37,12 +40,18 @@ properties:
   nvmem-0:
     $ref: /schemas/nvmem/maxim,max77759-nvmem.yaml
 
+  chgin-otg-regulator:
+    type: object
+    description: Provides Boost for sourcing VBUS.
+    $ref: /schemas/regulator/regulator.yaml#
+    unevaluatedProperties: false
+
 required:
   - compatible
   - interrupts
   - reg
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
@@ -59,6 +68,11 @@ examples:
 
             interrupt-controller;
             #interrupt-cells = <2>;
+            power-supplies = <&maxtcpci>;
+
+            chgin-otg-regulator {
+                regulator-name = "chgin-otg";
+            };
 
             gpio {
                 compatible = "maxim,max77759-gpio";

-- 
2.53.0.1118.gaef5881109-goog




^ permalink raw reply related

* [PATCH v10 2/6] dt-bindings: usb: maxim,max33359: Add supply property for vbus
From: Amit Sunil Dhamne via B4 Relay @ 2026-03-31 23:22 UTC (permalink / raw)
  To: André Draszik, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jagan Sridharan, Mark Brown,
	Matti Vaittinen, Andrew Morton, Sebastian Reichel,
	Amit Sunil Dhamne, Heikki Krogerus, Peter Griffin, Tudor Ambarus,
	Alim Akhtar
  Cc: linux-kernel, devicetree, linux-usb, linux-pm, linux-arm-kernel,
	linux-samsung-soc, RD Babiera, Kyle Tso, Krzysztof Kozlowski
In-Reply-To: <20260331-max77759-charger-v10-0-76f59233c369@google.com>

From: Amit Sunil Dhamne <amitsd@google.com>

Add a regulator supply property for vbus. This notifies the regulator
provider to source vbus when Type-C operates in Source power mode,
while turn off sourcing vbus when operating in Sink mode or
disconnected.

Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/usb/maxim,max33359.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
index 3de4dc40b791..e652a24902ea 100644
--- a/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
+++ b/Documentation/devicetree/bindings/usb/maxim,max33359.yaml
@@ -32,6 +32,9 @@ properties:
     description:
       Properties for usb c connector.
 
+  vbus-supply:
+    description: Regulator to control sourcing Vbus.
+
 required:
   - compatible
   - reg
@@ -53,6 +56,7 @@ examples:
             reg = <0x25>;
             interrupt-parent = <&gpa8>;
             interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+            vbus-supply = <&chgin_otg_reg>;
 
             connector {
                 compatible = "usb-c-connector";

-- 
2.53.0.1118.gaef5881109-goog




^ permalink raw reply related

* [PATCH v10 6/6] usb: typec: tcpm/tcpci_maxim: deprecate WAR for setting charger mode
From: Amit Sunil Dhamne via B4 Relay @ 2026-03-31 23:22 UTC (permalink / raw)
  To: André Draszik, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jagan Sridharan, Mark Brown,
	Matti Vaittinen, Andrew Morton, Sebastian Reichel,
	Amit Sunil Dhamne, Heikki Krogerus, Peter Griffin, Tudor Ambarus,
	Alim Akhtar
  Cc: linux-kernel, devicetree, linux-usb, linux-pm, linux-arm-kernel,
	linux-samsung-soc, RD Babiera, Kyle Tso
In-Reply-To: <20260331-max77759-charger-v10-0-76f59233c369@google.com>

From: Amit Sunil Dhamne <amitsd@google.com>

TCPCI maxim driver directly writes to the charger's register space to
set charger mode depending on the power role. As MAX77759 chg driver
exists, this WAR is not required.

Instead, use a regulator interface to source vbus when typec is in
source power mode. In other power modes, this regulator will be turned
off if active.

Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Reviewed-by: André Draszik <andre.draszik@linaro.org>
---
 drivers/usb/typec/tcpm/tcpci_maxim.h      |  1 +
 drivers/usb/typec/tcpm/tcpci_maxim_core.c | 54 +++++++++++++++++++------------
 2 files changed, 34 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.h b/drivers/usb/typec/tcpm/tcpci_maxim.h
index b33540a42a95..b314606eb0f6 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim.h
+++ b/drivers/usb/typec/tcpm/tcpci_maxim.h
@@ -60,6 +60,7 @@ struct max_tcpci_chip {
 	struct tcpm_port *port;
 	enum contamiant_state contaminant_state;
 	bool veto_vconn_swap;
+	struct regulator *vbus_reg;
 };
 
 static inline int max_tcpci_read16(struct max_tcpci_chip *chip, unsigned int reg, u16 *val)
diff --git a/drivers/usb/typec/tcpm/tcpci_maxim_core.c b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
index 19f638650796..c0ee7e6959ed 100644
--- a/drivers/usb/typec/tcpm/tcpci_maxim_core.c
+++ b/drivers/usb/typec/tcpm/tcpci_maxim_core.c
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
 #include <linux/usb/pd.h>
 #include <linux/usb/tcpci.h>
 #include <linux/usb/tcpm.h>
@@ -35,12 +36,6 @@
  */
 #define TCPC_RECEIVE_BUFFER_LEN				32
 
-#define MAX_BUCK_BOOST_SID				0x69
-#define MAX_BUCK_BOOST_OP				0xb9
-#define MAX_BUCK_BOOST_OFF				0
-#define MAX_BUCK_BOOST_SOURCE				0xa
-#define MAX_BUCK_BOOST_SINK				0x5
-
 static const struct regmap_range max_tcpci_tcpci_range[] = {
 	regmap_reg_range(0x00, 0x95)
 };
@@ -202,32 +197,49 @@ static void process_rx(struct max_tcpci_chip *chip, u16 status)
 	tcpm_pd_receive(chip->port, &msg, rx_type);
 }
 
+static int get_vbus_regulator_handle(struct max_tcpci_chip *chip)
+{
+	if (IS_ERR_OR_NULL(chip->vbus_reg)) {
+		chip->vbus_reg = devm_regulator_get_exclusive(chip->dev,
+							      "vbus");
+		if (IS_ERR_OR_NULL(chip->vbus_reg)) {
+			dev_err(chip->dev,
+				"Failed to get vbus regulator handle\n");
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
 static int max_tcpci_set_vbus(struct tcpci *tcpci, struct tcpci_data *tdata, bool source, bool sink)
 {
 	struct max_tcpci_chip *chip = tdata_to_max_tcpci(tdata);
-	u8 buffer_source[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SOURCE};
-	u8 buffer_sink[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_SINK};
-	u8 buffer_none[2] = {MAX_BUCK_BOOST_OP, MAX_BUCK_BOOST_OFF};
-	struct i2c_client *i2c = chip->client;
 	int ret;
 
-	struct i2c_msg msgs[] = {
-		{
-			.addr = MAX_BUCK_BOOST_SID,
-			.flags = i2c->flags & I2C_M_TEN,
-			.len = 2,
-			.buf = source ? buffer_source : sink ? buffer_sink : buffer_none,
-		},
-	};
-
 	if (source && sink) {
 		dev_err(chip->dev, "Both source and sink set\n");
 		return -EINVAL;
 	}
 
-	ret = i2c_transfer(i2c->adapter, msgs, 1);
+	ret = get_vbus_regulator_handle(chip);
+	if (ret) {
+		/*
+		 * Regulator is not necessary for sink only applications. Return
+		 * success in cases where sink mode is being modified.
+		 */
+		return source ? ret : 1;
+	}
+
+	if (source) {
+		if (!regulator_is_enabled(chip->vbus_reg))
+			ret = regulator_enable(chip->vbus_reg);
+	} else {
+		if (regulator_is_enabled(chip->vbus_reg))
+			ret = regulator_disable(chip->vbus_reg);
+	}
 
-	return  ret < 0 ? ret : 1;
+	return ret < 0 ? ret : 1;
 }
 
 static void process_power_status(struct max_tcpci_chip *chip)

-- 
2.53.0.1118.gaef5881109-goog




^ permalink raw reply related

* [PATCH v10 4/6] lib/linear_ranges: Add linear_range_get_selector_high_array
From: Amit Sunil Dhamne via B4 Relay @ 2026-03-31 23:22 UTC (permalink / raw)
  To: André Draszik, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jagan Sridharan, Mark Brown,
	Matti Vaittinen, Andrew Morton, Sebastian Reichel,
	Amit Sunil Dhamne, Heikki Krogerus, Peter Griffin, Tudor Ambarus,
	Alim Akhtar
  Cc: linux-kernel, devicetree, linux-usb, linux-pm, linux-arm-kernel,
	linux-samsung-soc, RD Babiera, Kyle Tso
In-Reply-To: <20260331-max77759-charger-v10-0-76f59233c369@google.com>

From: Amit Sunil Dhamne <amitsd@google.com>

Add a helper function to find the selector for a given value in a linear
range array. The selector should be such that the value it represents
should be higher or equal to the given value.

Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: Matti Vaittinen <mazziesaccount@gmail.com>
Acked-by: Mark Brown <broonie@kernel.org>
---
 include/linux/linear_range.h |  3 +++
 lib/linear_ranges.c          | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/include/linux/linear_range.h b/include/linux/linear_range.h
index 2e4f4c3539c0..0f3037f1a94f 100644
--- a/include/linux/linear_range.h
+++ b/include/linux/linear_range.h
@@ -57,5 +57,8 @@ void linear_range_get_selector_within(const struct linear_range *r,
 int linear_range_get_selector_low_array(const struct linear_range *r,
 					int ranges, unsigned int val,
 					unsigned int *selector, bool *found);
+int linear_range_get_selector_high_array(const struct linear_range *r,
+					 int ranges, unsigned int val,
+					 unsigned int *selector, bool *found);
 
 #endif
diff --git a/lib/linear_ranges.c b/lib/linear_ranges.c
index a1a7dfa881de..c85583678f6b 100644
--- a/lib/linear_ranges.c
+++ b/lib/linear_ranges.c
@@ -241,6 +241,42 @@ int linear_range_get_selector_high(const struct linear_range *r,
 }
 EXPORT_SYMBOL_GPL(linear_range_get_selector_high);
 
+/**
+ * linear_range_get_selector_high_array - return linear range selector for value
+ * @r:		pointer to array of linear ranges where selector is looked from
+ * @ranges:	amount of ranges to scan from array
+ * @val:	value for which the selector is searched
+ * @selector:	address where found selector value is updated
+ * @found:	flag to indicate that given value was in the range
+ *
+ * Scan array of ranges for selector for which range value matches given
+ * input value. Value is matching if it is equal or higher than given value
+ * If given value is found to be in a range scanning is stopped and @found is
+ * set true. If a range with values greater than given value is found
+ * but the range min is being greater than given value, then the range's
+ * lowest selector is updated to @selector and scanning is stopped.
+ *
+ * Return: 0 on success, -EINVAL if range array is invalid or does not contain
+ * range with a value greater or equal to given value
+ */
+int linear_range_get_selector_high_array(const struct linear_range *r,
+					 int ranges, unsigned int val,
+					 unsigned int *selector, bool *found)
+{
+	int i;
+	int ret;
+
+	for (i = 0; i < ranges; i++) {
+		ret = linear_range_get_selector_high(&r[i], val, selector,
+						     found);
+		if (!ret)
+			return 0;
+	}
+
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(linear_range_get_selector_high_array);
+
 /**
  * linear_range_get_selector_within - return linear range selector for value
  * @r:		pointer to linear range where selector is looked from

-- 
2.53.0.1118.gaef5881109-goog




^ permalink raw reply related

* [PATCH v10 3/6] mfd: max77759: add register bitmasks and modify irq configs for charger
From: Amit Sunil Dhamne via B4 Relay @ 2026-03-31 23:22 UTC (permalink / raw)
  To: André Draszik, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jagan Sridharan, Mark Brown,
	Matti Vaittinen, Andrew Morton, Sebastian Reichel,
	Amit Sunil Dhamne, Heikki Krogerus, Peter Griffin, Tudor Ambarus,
	Alim Akhtar
  Cc: linux-kernel, devicetree, linux-usb, linux-pm, linux-arm-kernel,
	linux-samsung-soc, RD Babiera, Kyle Tso
In-Reply-To: <20260331-max77759-charger-v10-0-76f59233c369@google.com>

From: Amit Sunil Dhamne <amitsd@google.com>

Add register bitmasks for charger function.
In addition split the charger IRQs further such that each bit represents
an IRQ downstream of charger regmap irq chip. In addition populate the
ack_base to offload irq ack to the regmap irq chip framework.

Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: André Draszik <andre.draszik@linaro.org>
---
 drivers/mfd/max77759.c       |  95 ++++++++++++++++++++++---
 include/linux/mfd/max77759.h | 166 +++++++++++++++++++++++++++++++++++--------
 2 files changed, 222 insertions(+), 39 deletions(-)

diff --git a/drivers/mfd/max77759.c b/drivers/mfd/max77759.c
index a7efe233ec8c..9fa6027a92c4 100644
--- a/drivers/mfd/max77759.c
+++ b/drivers/mfd/max77759.c
@@ -201,8 +201,24 @@ static const struct regmap_config max77759_regmap_config_charger = {
  *         - SYSUVLO_INT
  *         - FSHIP_NOT_RD
  *     - CHGR_INT: charger
- *       - CHG_INT
- *       - CHG_INT2
+ *       - INT1
+ *         - AICL
+ *         - CHGIN
+ *         - WCIN
+ *         - CHG
+ *         - BAT
+ *         - INLIM
+ *         - THM2
+ *         - BYP
+ *       - INT2
+ *         - INSEL
+ *         - SYS_UVLO1
+ *         - SYS_UVLO2
+ *         - BAT_OILO
+ *         - CHG_STA_CC
+ *         - CHG_STA_CV
+ *         - CHG_STA_TO
+ *         - CHG_STA_DONE
  */
 enum {
 	MAX77759_INT_MAXQ,
@@ -228,8 +244,22 @@ enum {
 };
 
 enum {
-	MAX77759_CHARGER_INT_1,
-	MAX77759_CHARGER_INT_2,
+	MAX77759_CHGR_INT1_AICL,
+	MAX77759_CHGR_INT1_CHGIN,
+	MAX77759_CHGR_INT1_WCIN,
+	MAX77759_CHGR_INT1_CHG,
+	MAX77759_CHGR_INT1_BAT,
+	MAX77759_CHGR_INT1_INLIM,
+	MAX77759_CHGR_INT1_THM2,
+	MAX77759_CHGR_INT1_BYP,
+	MAX77759_CHGR_INT2_INSEL,
+	MAX77759_CHGR_INT2_SYS_UVLO1,
+	MAX77759_CHGR_INT2_SYS_UVLO2,
+	MAX77759_CHGR_INT2_BAT_OILO,
+	MAX77759_CHGR_INT2_CHG_STA_CC,
+	MAX77759_CHGR_INT2_CHG_STA_CV,
+	MAX77759_CHGR_INT2_CHG_STA_TO,
+	MAX77759_CHGR_INT2_CHG_STA_DONE,
 };
 
 static const struct regmap_irq max77759_pmic_irqs[] = {
@@ -256,8 +286,38 @@ static const struct regmap_irq max77759_topsys_irqs[] = {
 };
 
 static const struct regmap_irq max77759_chgr_irqs[] = {
-	REGMAP_IRQ_REG(MAX77759_CHARGER_INT_1, 0, GENMASK(7, 0)),
-	REGMAP_IRQ_REG(MAX77759_CHARGER_INT_2, 1, GENMASK(7, 0)),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_AICL, 0,
+		       MAX77759_CHGR_REG_CHG_INT_AICL),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_CHGIN, 0,
+		       MAX77759_CHGR_REG_CHG_INT_CHGIN),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_WCIN, 0,
+		       MAX77759_CHGR_REG_CHG_INT_WCIN),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_CHG, 0,
+		       MAX77759_CHGR_REG_CHG_INT_CHG),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_BAT, 0,
+		       MAX77759_CHGR_REG_CHG_INT_BAT),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_INLIM, 0,
+		       MAX77759_CHGR_REG_CHG_INT_INLIM),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_THM2, 0,
+		       MAX77759_CHGR_REG_CHG_INT_THM2),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT1_BYP, 0,
+		       MAX77759_CHGR_REG_CHG_INT_BYP),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_INSEL, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_INSEL),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_SYS_UVLO1, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO1),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_SYS_UVLO2, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO2),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_BAT_OILO, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_BAT_OILO),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_CC, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CC),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_CV, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CV),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_TO, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_TO),
+	REGMAP_IRQ_REG(MAX77759_CHGR_INT2_CHG_STA_DONE, 1,
+		       MAX77759_CHGR_REG_CHG_INT2_CHG_STA_DONE),
 };
 
 static const struct regmap_irq_chip max77759_pmic_irq_chip = {
@@ -297,11 +357,12 @@ static const struct regmap_irq_chip max77759_topsys_irq_chip = {
 	.num_irqs = ARRAY_SIZE(max77759_topsys_irqs),
 };
 
-static const struct regmap_irq_chip max77759_chrg_irq_chip = {
+static const struct regmap_irq_chip max77759_chgr_irq_chip = {
 	.name = "max77759-chgr",
 	.domain_suffix = "CHGR",
 	.status_base = MAX77759_CHGR_REG_CHG_INT,
 	.mask_base = MAX77759_CHGR_REG_CHG_INT_MASK,
+	.ack_base = MAX77759_CHGR_REG_CHG_INT,
 	.num_regs = 2,
 	.irqs = max77759_chgr_irqs,
 	.num_irqs = ARRAY_SIZE(max77759_chgr_irqs),
@@ -325,8 +386,22 @@ static const struct resource max77759_gpio_resources[] = {
 };
 
 static const struct resource max77759_charger_resources[] = {
-	DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_1, "INT1"),
-	DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_2, "INT2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_AICL,         "AICL"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_CHGIN,        "CHGIN"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_WCIN,         "WCIN"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_CHG,          "CHG"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_BAT,          "BAT"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_INLIM,        "INLIM"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_THM2,         "THM2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT1_BYP,          "BYP"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_INSEL,        "INSEL"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_SYS_UVLO1,    "SYS_UVLO1"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_SYS_UVLO2,    "SYS_UVLO2"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_BAT_OILO,     "BAT_OILO"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_CC,   "CHG_STA_CC"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_CV,   "CHG_STA_CV"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_TO,   "CHG_STA_TO"),
+	DEFINE_RES_IRQ_NAMED(MAX77759_CHGR_INT2_CHG_STA_DONE, "CHG_STA_DONE"),
 };
 
 static const struct mfd_cell max77759_cells[] = {
@@ -567,7 +642,7 @@ static int max77759_add_chained_charger(struct i2c_client *client,
 					    max77759->regmap_charger,
 					    MAX77759_INT_CHGR,
 					    parent,
-					    &max77759_chrg_irq_chip,
+					    &max77759_chgr_irq_chip,
 					    &irq_chip_data);
 	if (ret)
 		return ret;
diff --git a/include/linux/mfd/max77759.h b/include/linux/mfd/max77759.h
index c6face34e385..ec19be952877 100644
--- a/include/linux/mfd/max77759.h
+++ b/include/linux/mfd/max77759.h
@@ -59,35 +59,65 @@
 #define MAX77759_MAXQ_REG_AP_DATAIN0            0xb1
 #define MAX77759_MAXQ_REG_UIC_SWRST             0xe0
 
-#define MAX77759_CHGR_REG_CHG_INT               0xb0
-#define MAX77759_CHGR_REG_CHG_INT2              0xb1
-#define MAX77759_CHGR_REG_CHG_INT_MASK          0xb2
-#define MAX77759_CHGR_REG_CHG_INT2_MASK         0xb3
-#define MAX77759_CHGR_REG_CHG_INT_OK            0xb4
-#define MAX77759_CHGR_REG_CHG_DETAILS_00        0xb5
-#define MAX77759_CHGR_REG_CHG_DETAILS_01        0xb6
-#define MAX77759_CHGR_REG_CHG_DETAILS_02        0xb7
-#define MAX77759_CHGR_REG_CHG_DETAILS_03        0xb8
-#define MAX77759_CHGR_REG_CHG_CNFG_00           0xb9
-#define MAX77759_CHGR_REG_CHG_CNFG_01           0xba
-#define MAX77759_CHGR_REG_CHG_CNFG_02           0xbb
-#define MAX77759_CHGR_REG_CHG_CNFG_03           0xbc
-#define MAX77759_CHGR_REG_CHG_CNFG_04           0xbd
-#define MAX77759_CHGR_REG_CHG_CNFG_05           0xbe
-#define MAX77759_CHGR_REG_CHG_CNFG_06           0xbf
-#define MAX77759_CHGR_REG_CHG_CNFG_07           0xc0
-#define MAX77759_CHGR_REG_CHG_CNFG_08           0xc1
-#define MAX77759_CHGR_REG_CHG_CNFG_09           0xc2
-#define MAX77759_CHGR_REG_CHG_CNFG_10           0xc3
-#define MAX77759_CHGR_REG_CHG_CNFG_11           0xc4
-#define MAX77759_CHGR_REG_CHG_CNFG_12           0xc5
-#define MAX77759_CHGR_REG_CHG_CNFG_13           0xc6
-#define MAX77759_CHGR_REG_CHG_CNFG_14           0xc7
-#define MAX77759_CHGR_REG_CHG_CNFG_15           0xc8
-#define MAX77759_CHGR_REG_CHG_CNFG_16           0xc9
-#define MAX77759_CHGR_REG_CHG_CNFG_17           0xca
-#define MAX77759_CHGR_REG_CHG_CNFG_18           0xcb
-#define MAX77759_CHGR_REG_CHG_CNFG_19           0xcc
+#define MAX77759_CHGR_REG_CHG_INT                      0xb0
+#define   MAX77759_CHGR_REG_CHG_INT_AICL               BIT(7)
+#define   MAX77759_CHGR_REG_CHG_INT_CHGIN              BIT(6)
+#define   MAX77759_CHGR_REG_CHG_INT_WCIN               BIT(5)
+#define   MAX77759_CHGR_REG_CHG_INT_CHG                BIT(4)
+#define   MAX77759_CHGR_REG_CHG_INT_BAT                BIT(3)
+#define   MAX77759_CHGR_REG_CHG_INT_INLIM              BIT(2)
+#define   MAX77759_CHGR_REG_CHG_INT_THM2               BIT(1)
+#define   MAX77759_CHGR_REG_CHG_INT_BYP                BIT(0)
+#define MAX77759_CHGR_REG_CHG_INT2                     0xb1
+#define   MAX77759_CHGR_REG_CHG_INT2_INSEL             BIT(7)
+#define   MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO1         BIT(6)
+#define   MAX77759_CHGR_REG_CHG_INT2_SYS_UVLO2         BIT(5)
+#define   MAX77759_CHGR_REG_CHG_INT2_BAT_OILO          BIT(4)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CC        BIT(3)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_CV        BIT(2)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_TO        BIT(1)
+#define   MAX77759_CHGR_REG_CHG_INT2_CHG_STA_DONE      BIT(0)
+#define MAX77759_CHGR_REG_CHG_INT_MASK                 0xb2
+#define MAX77759_CHGR_REG_CHG_INT2_MASK                0xb3
+#define MAX77759_CHGR_REG_CHG_INT_OK                   0xb4
+#define MAX77759_CHGR_REG_CHG_DETAILS_00               0xb5
+#define   MAX77759_CHGR_REG_CHG_DETAILS_00_CHGIN_DTLS  GENMASK(6, 5)
+#define MAX77759_CHGR_REG_CHG_DETAILS_01               0xb6
+#define   MAX77759_CHGR_REG_CHG_DETAILS_01_BAT_DTLS    GENMASK(6, 4)
+#define   MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS    GENMASK(3, 0)
+#define MAX77759_CHGR_REG_CHG_DETAILS_02               0xb7
+#define   MAX77759_CHGR_REG_CHG_DETAILS_02_CHGIN_STS   BIT(5)
+#define MAX77759_CHGR_REG_CHG_DETAILS_03               0xb8
+#define MAX77759_CHGR_REG_CHG_CNFG_00                  0xb9
+#define   MAX77759_CHGR_REG_CHG_CNFG_00_MODE           GENMASK(3, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_01                  0xba
+#define MAX77759_CHGR_REG_CHG_CNFG_02                  0xbb
+#define   MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC          GENMASK(5, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_03                  0xbc
+#define MAX77759_CHGR_REG_CHG_CNFG_04                  0xbd
+#define   MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM     GENMASK(5, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_05                  0xbe
+#define MAX77759_CHGR_REG_CHG_CNFG_06                  0xbf
+#define   MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT        GENMASK(3, 2)
+#define MAX77759_CHGR_REG_CHG_CNFG_07                  0xc0
+#define MAX77759_CHGR_REG_CHG_CNFG_08                  0xc1
+#define MAX77759_CHGR_REG_CHG_CNFG_09                  0xc2
+#define   MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM     GENMASK(6, 0)
+#define MAX77759_CHGR_REG_CHG_CNFG_10                  0xc3
+#define MAX77759_CHGR_REG_CHG_CNFG_11                  0xc4
+#define MAX77759_CHGR_REG_CHG_CNFG_12                  0xc5
+/* Wireless Charging input channel select */
+#define   MAX77759_CHGR_REG_CHG_CNFG_12_WCINSEL        BIT(6)
+/* CHGIN/USB input channel select */
+#define   MAX77759_CHGR_REG_CHG_CNFG_12_CHGINSEL       BIT(5)
+#define MAX77759_CHGR_REG_CHG_CNFG_13                  0xc6
+#define MAX77759_CHGR_REG_CHG_CNFG_14                  0xc7
+#define MAX77759_CHGR_REG_CHG_CNFG_15                  0xc8
+#define MAX77759_CHGR_REG_CHG_CNFG_16                  0xc9
+#define MAX77759_CHGR_REG_CHG_CNFG_17                  0xca
+#define MAX77759_CHGR_REG_CHG_CNFG_18                  0xcb
+#define   MAX77759_CHGR_REG_CHG_CNFG_18_WDTEN          BIT(0)
+#define MAX77759_CHGR_REG_CHG_CNFG_19                  0xcc
 
 /* MaxQ opcodes for max77759_maxq_command() */
 #define MAX77759_MAXQ_OPCODE_MAXLENGTH (MAX77759_MAXQ_REG_AP_DATAOUT32 - \
@@ -101,6 +131,84 @@
 #define MAX77759_MAXQ_OPCODE_USER_SPACE_READ     0x81
 #define MAX77759_MAXQ_OPCODE_USER_SPACE_WRITE    0x82
 
+/**
+ * enum max77759_chgr_chgin_dtls_status - Charger Input Status
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE:
+ *     Charger input voltage (Vchgin) < Under Voltage Threshold (Vuvlo)
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE:
+ *     Vchgin > Vuvlo and Vchgin < (Battery Voltage (Vbatt) + system voltage (Vsys))
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE:
+ *     Vchgin > Over Voltage threshold (Vovlo)
+ * @MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID:
+ *     Vchgin > Vuvlo, Vchgin < Vovlo and Vchgin > (Vsys + Vbatt)
+ */
+enum max77759_chgr_chgin_dtls_status {
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE,
+	MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID,
+};
+
+/**
+ * enum max77759_chgr_bat_dtls_states - Battery Details
+ * @MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP:	No battery and the charger suspended
+ * @MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY:	Vbatt < Vtrickle
+ * @MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT:	Charging suspended due to timer fault
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OKAY:		Battery okay and Vbatt > Min Sys Voltage (Vsysmin)
+ * @MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE:	Battery is okay. Vtrickle < Vbatt < Vsysmin
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE:	Battery voltage > Overvoltage threshold
+ * @MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT:	Battery current exceeds overcurrent threshold
+ * @MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE:	Battery only mode and battery level not available
+ */
+enum max77759_chgr_bat_dtls_states {
+	MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP,
+	MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY,
+	MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT,
+	MAX77759_CHGR_BAT_DTLS_BAT_OKAY,
+	MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE,
+	MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE,
+	MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT,
+	MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE,
+};
+
+/**
+ * enum max77759_chgr_chg_dtls_states - Charger Details
+ * @MAX77759_CHGR_CHG_DTLS_PREQUAL:		Charger in prequalification mode
+ * @MAX77759_CHGR_CHG_DTLS_CC:			Charger in fast charge const curr mode
+ * @MAX77759_CHGR_CHG_DTLS_CV:			Charger in fast charge const voltage mode
+ * @MAX77759_CHGR_CHG_DTLS_TO:			Charger is in top off mode
+ * @MAX77759_CHGR_CHG_DTLS_DONE:		Charger is done
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_1:		Reserved
+ * @MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:		Charger is in timer fault mode
+ * @MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:	Charger is suspended as battery removal detected
+ * @MAX77759_CHGR_CHG_DTLS_OFF:			Charger is off. Input invalid or charger disabled
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_2:		Reserved
+ * @MAX77759_CHGR_CHG_DTLS_RSVD_3:		Reserved
+ * @MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:	Charger is off as watchdog timer expired
+ * @MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:		Charger is in JEITA control mode
+ */
+enum max77759_chgr_chg_dtls_states {
+	MAX77759_CHGR_CHG_DTLS_PREQUAL,
+	MAX77759_CHGR_CHG_DTLS_CC,
+	MAX77759_CHGR_CHG_DTLS_CV,
+	MAX77759_CHGR_CHG_DTLS_TO,
+	MAX77759_CHGR_CHG_DTLS_DONE,
+	MAX77759_CHGR_CHG_DTLS_RSVD_1,
+	MAX77759_CHGR_CHG_DTLS_TIMER_FAULT,
+	MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM,
+	MAX77759_CHGR_CHG_DTLS_OFF,
+	MAX77759_CHGR_CHG_DTLS_RSVD_2,
+	MAX77759_CHGR_CHG_DTLS_RSVD_3,
+	MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER,
+	MAX77759_CHGR_CHG_DTLS_SUSP_JEITA,
+};
+
+enum max77759_chgr_mode {
+	MAX77759_CHGR_MODE_OFF,
+	MAX77759_CHGR_MODE_CHG_BUCK_ON = 0x5,
+	MAX77759_CHGR_MODE_OTG_BOOST_ON = 0xA,
+};
+
 /**
  * struct max77759 - core max77759 internal data structure
  *

-- 
2.53.0.1118.gaef5881109-goog




^ permalink raw reply related

* [PATCH v10 5/6] power: supply: max77759: add charger driver
From: Amit Sunil Dhamne via B4 Relay @ 2026-03-31 23:22 UTC (permalink / raw)
  To: André Draszik, Lee Jones, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jagan Sridharan, Mark Brown,
	Matti Vaittinen, Andrew Morton, Sebastian Reichel,
	Amit Sunil Dhamne, Heikki Krogerus, Peter Griffin, Tudor Ambarus,
	Alim Akhtar
  Cc: linux-kernel, devicetree, linux-usb, linux-pm, linux-arm-kernel,
	linux-samsung-soc, RD Babiera, Kyle Tso
In-Reply-To: <20260331-max77759-charger-v10-0-76f59233c369@google.com>

From: Amit Sunil Dhamne <amitsd@google.com>

Add support for MAX77759 battery charger driver. This is a 4A 1-Cell
Li+/LiPoly dual input switch mode charger. While the device can support
USB & wireless charger inputs, this implementation only supports USB
input. This implementation supports both buck and boost modes.

Signed-off-by: Amit Sunil Dhamne <amitsd@google.com>
Reviewed-by: André Draszik <andre.draszik@linaro.org>
---
 MAINTAINERS                             |   6 +
 drivers/power/supply/Kconfig            |  11 +
 drivers/power/supply/Makefile           |   1 +
 drivers/power/supply/max77759_charger.c | 774 ++++++++++++++++++++++++++++++++
 4 files changed, 792 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 61bf550fd37c..eefd78c72d82 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15716,6 +15716,12 @@ F:	drivers/mfd/max77759.c
 F:	drivers/nvmem/max77759-nvmem.c
 F:	include/linux/mfd/max77759.h
 
+MAXIM MAX77759 BATTERY CHARGER DRIVER
+M:	Amit Sunil Dhamne <amitsd@google.com>
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+F:	drivers/power/supply/max77759_charger.c
+
 MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
 M:	Javier Martinez Canillas <javier@dowhile0.org>
 L:	linux-kernel@vger.kernel.org
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index 92f9f7aae92f..3a2cdb95c98e 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -631,6 +631,17 @@ config CHARGER_MAX77705
 	help
 	  Say Y to enable support for the Maxim MAX77705 battery charger.
 
+config CHARGER_MAX77759
+	tristate "Maxim MAX77759 battery charger driver"
+	depends on MFD_MAX77759 && REGULATOR
+	default MFD_MAX77759
+	help
+	  Say M or Y here to enable the MAX77759 battery charger. MAX77759
+	  charger is a function of the MAX77759 PMIC. This is a dual input
+	  switch-mode charger. This driver supports buck and OTG boost modes.
+
+	  If built as a module, it will be called max77759_charger.
+
 config CHARGER_MAX77976
 	tristate "Maxim MAX77976 battery charger driver"
 	depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 4b79d5abc49a..6af905875ad5 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -128,3 +128,4 @@ obj-$(CONFIG_CHARGER_SURFACE)	+= surface_charger.o
 obj-$(CONFIG_BATTERY_UG3105)	+= ug3105_battery.o
 obj-$(CONFIG_CHARGER_QCOM_SMB2)	+= qcom_smbx.o
 obj-$(CONFIG_FUEL_GAUGE_MM8013)	+= mm8013.o
+obj-$(CONFIG_CHARGER_MAX77759)	+= max77759_charger.o
diff --git a/drivers/power/supply/max77759_charger.c b/drivers/power/supply/max77759_charger.c
new file mode 100644
index 000000000000..9bb414599f16
--- /dev/null
+++ b/drivers/power/supply/max77759_charger.c
@@ -0,0 +1,774 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * max77759_charger.c - Battery charger driver for MAX77759 charger device.
+ *
+ * Copyright 2025 Google LLC.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/devm-helpers.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/linear_range.h>
+#include <linux/mfd/max77759.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/string_choices.h>
+#include <linux/workqueue.h>
+
+/* Default values for Fast Charge Current & Float Voltage */
+#define CHG_CC_DEFAULT_UA			2266770
+#define CHG_FV_DEFAULT_MV			4300
+
+#define MAX_NUM_RETRIES				3
+#define PSY_WORK_RETRY_DELAY_MS			10
+
+#define FOREACH_IRQ(S)			\
+	S(AICL),			\
+	S(CHGIN),			\
+	S(CHG),				\
+	S(INLIM),			\
+	S(BAT_OILO),			\
+	S(CHG_STA_CC),			\
+	S(CHG_STA_CV),			\
+	S(CHG_STA_TO),			\
+	S(CHG_STA_DONE)
+
+#define GENERATE_ENUM(e)		e
+#define GENERATE_STRING(s)		#s
+
+enum {
+	FOREACH_IRQ(GENERATE_ENUM)
+};
+
+static const char *const chgr_irqs_str[] = {
+	FOREACH_IRQ(GENERATE_STRING)
+};
+
+#define NUM_IRQS			ARRAY_SIZE(chgr_irqs_str)
+
+/* Fast charge current limits (in uA) */
+static const struct linear_range chgcc_limit_ranges[] = {
+	LINEAR_RANGE(133330, 0x0, 0x2, 0),
+	LINEAR_RANGE(200000, 0x3, 0x3C, 66670),
+};
+
+/* Charge Termination Voltage Limits (in mV) */
+static const struct linear_range chg_cv_prm_ranges[] = {
+	LINEAR_RANGE(3800, 0x38, 0x39, 100),
+	LINEAR_RANGE(4000, 0x0, 0x32, 10),
+};
+
+/* USB input current limits (in uA) */
+static const struct linear_range chgin_ilim_ranges[] = {
+	LINEAR_RANGE(100000, 0x3, 0x7F, 25000),
+};
+
+struct max77759_charger {
+	struct device *dev;
+	struct regmap *regmap;
+	struct power_supply *psy;
+	struct regulator_dev *chgin_otg_rdev;
+	struct notifier_block nb;
+	struct power_supply *tcpm_psy;
+	struct delayed_work psy_work;
+	struct mutex retry_lock; /* Protects psy_work_retry_cnt */
+	u32 psy_work_retry_cnt;
+	int irqs[NUM_IRQS];
+	struct mutex lock; /* protects the state below */
+	enum max77759_chgr_mode mode;
+};
+
+static inline int unlock_prot_regs(struct max77759_charger *chg, bool unlock)
+{
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_06,
+				  MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT, unlock
+				  ? MAX77759_CHGR_REG_CHG_CNFG_06_CHGPROT : 0);
+}
+
+static int charger_input_valid(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_INT_OK, &val);
+	if (ret)
+		return ret;
+
+	return (val & MAX77759_CHGR_REG_CHG_INT_CHG) &&
+		(val & MAX77759_CHGR_REG_CHG_INT_CHGIN);
+}
+
+static int get_online(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = charger_input_valid(chg);
+	if (ret <= 0)
+		return ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_02, &val);
+	if (ret)
+		return ret;
+
+	guard(mutex)(&chg->lock);
+
+	return (val & MAX77759_CHGR_REG_CHG_DETAILS_02_CHGIN_STS) &&
+		(chg->mode == MAX77759_CHGR_MODE_CHG_BUCK_ON);
+}
+
+static int get_status(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS, val)) {
+	case MAX77759_CHGR_CHG_DTLS_PREQUAL:
+	case MAX77759_CHGR_CHG_DTLS_CC:
+	case MAX77759_CHGR_CHG_DTLS_CV:
+	case MAX77759_CHGR_CHG_DTLS_TO:
+		return POWER_SUPPLY_STATUS_CHARGING;
+	case MAX77759_CHGR_CHG_DTLS_DONE:
+		return POWER_SUPPLY_STATUS_FULL;
+	case MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
+	case MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:
+		return POWER_SUPPLY_STATUS_NOT_CHARGING;
+	case MAX77759_CHGR_CHG_DTLS_OFF:
+		return POWER_SUPPLY_STATUS_DISCHARGING;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_STATUS_UNKNOWN;
+}
+
+static int get_charge_type(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_CHG_DTLS, val)) {
+	case MAX77759_CHGR_CHG_DTLS_PREQUAL:
+		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+	case MAX77759_CHGR_CHG_DTLS_CC:
+	case MAX77759_CHGR_CHG_DTLS_CV:
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+	case MAX77759_CHGR_CHG_DTLS_TO:
+		return POWER_SUPPLY_CHARGE_TYPE_STANDARD;
+	case MAX77759_CHGR_CHG_DTLS_DONE:
+	case MAX77759_CHGR_CHG_DTLS_TIMER_FAULT:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_BATT_THM:
+	case MAX77759_CHGR_CHG_DTLS_OFF_WDOG_TIMER:
+	case MAX77759_CHGR_CHG_DTLS_SUSP_JEITA:
+	case MAX77759_CHGR_CHG_DTLS_OFF:
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+}
+
+static int get_chg_health(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_00, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_00_CHGIN_DTLS, val)) {
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_UNDERVOLTAGE:
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_MARGINAL_VOLTAGE:
+		return POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_OVERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	case MAX77759_CHGR_CHGIN_DTLS_VBUS_VALID:
+		return POWER_SUPPLY_HEALTH_GOOD;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_HEALTH_UNKNOWN;
+}
+
+static int get_batt_health(struct max77759_charger *chg)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_DETAILS_01, &val);
+	if (ret)
+		return ret;
+
+	switch (FIELD_GET(MAX77759_CHGR_REG_CHG_DETAILS_01_BAT_DTLS, val)) {
+	case MAX77759_CHGR_BAT_DTLS_NO_BATT_CHG_SUSP:
+		return POWER_SUPPLY_HEALTH_NO_BATTERY;
+	case MAX77759_CHGR_BAT_DTLS_DEAD_BATTERY:
+		return POWER_SUPPLY_HEALTH_DEAD;
+	case MAX77759_CHGR_BAT_DTLS_BAT_CHG_TIMER_FAULT:
+		return POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OKAY:
+	case MAX77759_CHGR_BAT_DTLS_BAT_ONLY_MODE:
+		return POWER_SUPPLY_HEALTH_GOOD;
+	case MAX77759_CHGR_BAT_DTLS_BAT_UNDERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OVERVOLTAGE:
+		return POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	case MAX77759_CHGR_BAT_DTLS_BAT_OVERCURRENT:
+		return POWER_SUPPLY_HEALTH_OVERCURRENT;
+	default:
+		break;
+	}
+
+	return POWER_SUPPLY_HEALTH_UNKNOWN;
+}
+
+static int get_health(struct max77759_charger *chg)
+{
+	int ret;
+
+	ret = get_online(chg);
+	if (ret < 0)
+		return ret;
+
+	if (ret) {
+		ret = get_chg_health(chg);
+		if (ret < 0 || ret != POWER_SUPPLY_HEALTH_GOOD)
+			return ret;
+	}
+
+	return get_batt_health(chg);
+}
+
+static int get_fast_charge_current(struct max77759_charger *chg)
+{
+	u32 regval, val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_02, &regval);
+	if (ret)
+		return ret;
+
+	regval = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC, regval);
+	ret = linear_range_get_value_array(chgcc_limit_ranges,
+					   ARRAY_SIZE(chgcc_limit_ranges),
+					   regval, &val);
+	return ret ? ret : val;
+}
+
+static int set_fast_charge_current_limit(struct max77759_charger *chg,
+					 u32 cc_max_ua)
+{
+	bool found;
+	u32 regval;
+
+	linear_range_get_selector_high_array(chgcc_limit_ranges,
+					     ARRAY_SIZE(chgcc_limit_ranges),
+					     cc_max_ua, &regval, &found);
+	if (!found)
+		return -EINVAL;
+
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_02,
+				  MAX77759_CHGR_REG_CHG_CNFG_02_CHGCC, regval);
+}
+
+static int get_float_voltage(struct max77759_charger *chg)
+{
+	u32 regval, val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_04, &regval);
+	if (ret)
+		return ret;
+
+	regval = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM, regval);
+	ret = linear_range_get_value_array(chg_cv_prm_ranges,
+					   ARRAY_SIZE(chg_cv_prm_ranges),
+					   regval, &val);
+
+	return ret ? ret : val;
+}
+
+static int set_float_voltage_limit(struct max77759_charger *chg, u32 fv_mv)
+{
+	u32 regval;
+	bool found;
+
+	linear_range_get_selector_high_array(chg_cv_prm_ranges,
+					     ARRAY_SIZE(chg_cv_prm_ranges),
+					     fv_mv, &regval, &found);
+	if (!found)
+		return -EINVAL;
+
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_04,
+				  MAX77759_CHGR_REG_CHG_CNFG_04_CHG_CV_PRM,
+				  regval);
+}
+
+static int get_input_current_limit(struct max77759_charger *chg)
+{
+	u32 regval, val;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_09, &regval);
+	if (ret)
+		return ret;
+
+	regval = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM, regval);
+	regval = umax(regval, chgin_ilim_ranges[0].min_sel);
+
+	ret = linear_range_get_value_array(chgin_ilim_ranges,
+					   ARRAY_SIZE(chgin_ilim_ranges),
+					   regval, &val);
+
+	return ret ? ret : val;
+}
+
+static int set_input_current_limit(struct max77759_charger *chg, int ilim_ua)
+{
+	u32 regval;
+
+	if (ilim_ua < 0)
+		return -EINVAL;
+
+	linear_range_get_selector_within(chgin_ilim_ranges, ilim_ua, &regval);
+
+	return regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_09,
+				  MAX77759_CHGR_REG_CHG_CNFG_09_CHGIN_ILIM,
+				  regval);
+}
+
+static const enum power_supply_property max77759_charger_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
+};
+
+static int max77759_charger_get_property(struct power_supply *psy,
+					 enum power_supply_property psp,
+					 union power_supply_propval *pval)
+{
+	struct max77759_charger *chg = power_supply_get_drvdata(psy);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = get_online(chg);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		ret = charger_input_valid(chg);
+		break;
+	case POWER_SUPPLY_PROP_STATUS:
+		ret = get_status(chg);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		ret = get_charge_type(chg);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = get_health(chg);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		ret = get_fast_charge_current(chg);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		ret = get_float_voltage(chg);
+		break;
+	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
+		ret = get_input_current_limit(chg);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	pval->intval = ret;
+	return ret < 0 ? ret : 0;
+}
+
+static const struct power_supply_desc max77759_charger_desc = {
+	.name = "max77759-charger",
+	.type = POWER_SUPPLY_TYPE_USB,
+	.properties = max77759_charger_props,
+	.num_properties = ARRAY_SIZE(max77759_charger_props),
+	.get_property = max77759_charger_get_property,
+};
+
+static int charger_set_mode(struct max77759_charger *chg,
+			    enum max77759_chgr_mode mode)
+{
+	int ret;
+
+	guard(mutex)(&chg->lock);
+
+	if (chg->mode == mode)
+		return 0;
+
+	if ((mode == MAX77759_CHGR_MODE_CHG_BUCK_ON ||
+	     mode == MAX77759_CHGR_MODE_OTG_BOOST_ON) &&
+	    chg->mode != MAX77759_CHGR_MODE_OFF) {
+		dev_err(chg->dev, "Invalid mode transition from %d to %d\n",
+			chg->mode, mode);
+		return -EINVAL;
+	}
+
+	ret = regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_00,
+				 MAX77759_CHGR_REG_CHG_CNFG_00_MODE, mode);
+	if (ret)
+		return ret;
+
+	chg->mode = mode;
+	return 0;
+}
+
+static int enable_chgin_otg(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	return charger_set_mode(chg, MAX77759_CHGR_MODE_OTG_BOOST_ON);
+}
+
+static int disable_chgin_otg(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	return charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+}
+
+static int chgin_otg_status(struct regulator_dev *rdev)
+{
+	struct max77759_charger *chg = rdev_get_drvdata(rdev);
+
+	guard(mutex)(&chg->lock);
+
+	return chg->mode == MAX77759_CHGR_MODE_OTG_BOOST_ON;
+}
+
+static const struct regulator_ops chgin_otg_reg_ops = {
+	.enable = enable_chgin_otg,
+	.disable = disable_chgin_otg,
+	.is_enabled = chgin_otg_status,
+};
+
+static const struct regulator_desc chgin_otg_reg_desc = {
+	.name = "chgin-otg",
+	.of_match = of_match_ptr("chgin-otg-regulator"),
+	.owner = THIS_MODULE,
+	.ops = &chgin_otg_reg_ops,
+	.fixed_uV = 5000000,
+	.n_voltages = 1,
+};
+
+static irqreturn_t irq_handler(int irq, void *data)
+{
+	struct max77759_charger *chg = data;
+
+	power_supply_changed(chg->psy);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t bat_oilo_irq_handler(int irq, void *data)
+{
+	struct max77759_charger *chg = data;
+
+	dev_warn_ratelimited(chg->dev,
+			     "Battery over-current threshold crossed\n");
+
+	return irq_handler(irq, data);
+}
+
+static int max77759_init_irqhandler(struct max77759_charger *chg)
+{
+	struct device *dev = chg->dev;
+	irq_handler_t thread_fn;
+	char *name;
+	int i, ret;
+
+	for (i = 0; i < ARRAY_SIZE(chgr_irqs_str); i++) {
+		ret = platform_get_irq_byname(to_platform_device(dev),
+					      chgr_irqs_str[i]);
+		if (ret < 0)
+			return dev_err_probe(dev, ret,
+					     "Failed to get irq resource for %s\n",
+					     chgr_irqs_str[i]);
+
+		chg->irqs[i] = ret;
+		name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s", dev_name(dev),
+				      chgr_irqs_str[i]);
+		if (!name)
+			return dev_err_probe(dev, -ENOMEM,
+					     "Failed to allocate space for irqname: %s\n",
+					     chgr_irqs_str[i]);
+
+		if (i == BAT_OILO)
+			thread_fn = bat_oilo_irq_handler;
+		else
+			thread_fn = irq_handler;
+
+		ret = devm_request_threaded_irq(dev, chg->irqs[i], NULL,
+						thread_fn, 0, name, chg);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Unable to register irq handler for %s\n",
+					     chgr_irqs_str[i]);
+	}
+
+	return 0;
+}
+
+static int max77759_charger_init(struct max77759_charger *chg)
+{
+	struct power_supply_battery_info *info;
+	u32 regval, fast_chg_curr, fv;
+	int ret;
+
+	ret = regmap_read(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_00, &regval);
+	if (ret)
+		return ret;
+
+	chg->mode = FIELD_GET(MAX77759_CHGR_REG_CHG_CNFG_00_MODE, regval);
+	ret = charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+	if (ret)
+		return ret;
+
+	if (power_supply_get_battery_info(chg->psy, &info)) {
+		fv = CHG_FV_DEFAULT_MV;
+		fast_chg_curr = CHG_CC_DEFAULT_UA;
+	} else {
+		fv = info->constant_charge_voltage_max_uv / 1000;
+		fast_chg_curr = info->constant_charge_current_max_ua;
+	}
+
+	ret = set_fast_charge_current_limit(chg, fast_chg_curr);
+	if (ret)
+		return ret;
+
+	ret = set_float_voltage_limit(chg, fv);
+	if (ret)
+		return ret;
+
+	ret = unlock_prot_regs(chg, true);
+	if (ret)
+		return ret;
+
+	/* Disable wireless charging input */
+	ret = regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_12,
+				 MAX77759_CHGR_REG_CHG_CNFG_12_WCINSEL, 0);
+	if (ret)
+		goto relock;
+
+	ret = regmap_update_bits(chg->regmap, MAX77759_CHGR_REG_CHG_CNFG_18,
+				 MAX77759_CHGR_REG_CHG_CNFG_18_WDTEN, 0);
+	if (ret)
+		goto relock;
+
+	return unlock_prot_regs(chg, false);
+
+relock:
+	(void)unlock_prot_regs(chg, false);
+	return ret;
+}
+
+static void psy_work_item(struct work_struct *work)
+{
+	struct max77759_charger *chg =
+		container_of(work, struct max77759_charger, psy_work.work);
+	union power_supply_propval current_limit, online;
+	int ret;
+
+	ret = power_supply_get_property(chg->tcpm_psy,
+					POWER_SUPPLY_PROP_CURRENT_MAX,
+					&current_limit);
+	if (ret) {
+		dev_err(chg->dev,
+			"Failed to get CURRENT_MAX psy property, ret=%d\n",
+			ret);
+		goto err;
+	}
+
+	ret = power_supply_get_property(chg->tcpm_psy, POWER_SUPPLY_PROP_ONLINE,
+					&online);
+	if (ret) {
+		dev_err(chg->dev,
+			"Failed to get ONLINE psy property, ret=%d\n",
+			ret);
+		goto err;
+	}
+
+	if (online.intval && current_limit.intval) {
+		ret = set_input_current_limit(chg, current_limit.intval);
+		if (ret) {
+			dev_err(chg->dev,
+				"Unable to set current limit, ret=%d\n", ret);
+			goto err;
+		}
+
+		charger_set_mode(chg, MAX77759_CHGR_MODE_CHG_BUCK_ON);
+	} else {
+		charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+	}
+
+	scoped_guard(mutex, &chg->retry_lock) {
+		if (chg->psy_work_retry_cnt)
+			dev_dbg(chg->dev,
+				"chg psy_work succeeded after %u tries\n",
+				chg->psy_work_retry_cnt);
+		chg->psy_work_retry_cnt = 0;
+	}
+
+	return;
+
+err:
+	charger_set_mode(chg, MAX77759_CHGR_MODE_OFF);
+	scoped_guard(mutex, &chg->retry_lock) {
+		if (chg->psy_work_retry_cnt >= MAX_NUM_RETRIES) {
+			dev_err(chg->dev, "chg psy work failed, giving up\n");
+			return;
+		}
+
+		++chg->psy_work_retry_cnt;
+		dev_dbg(chg->dev, "Retrying %u/%u chg psy_work\n",
+			chg->psy_work_retry_cnt, MAX_NUM_RETRIES);
+		schedule_delayed_work(&chg->psy_work,
+				      msecs_to_jiffies(PSY_WORK_RETRY_DELAY_MS));
+	}
+}
+
+static int psy_changed(struct notifier_block *nb, unsigned long evt, void *data)
+{
+	struct max77759_charger *chg = container_of(nb, struct max77759_charger,
+						    nb);
+	static const char *psy_name = "tcpm-source";
+	struct power_supply *psy = data;
+
+	if (!strnstr(psy->desc->name, psy_name, strlen(psy_name)) ||
+	    evt != PSY_EVENT_PROP_CHANGED)
+		return NOTIFY_OK;
+
+	chg->tcpm_psy = psy;
+	scoped_guard(mutex, &chg->retry_lock)
+		chg->psy_work_retry_cnt = 0;
+
+	schedule_delayed_work(&chg->psy_work, 0);
+
+	return NOTIFY_OK;
+}
+
+static void max_tcpci_unregister_psy_notifier(void *nb)
+{
+	power_supply_unreg_notifier(nb);
+}
+
+static int max77759_charger_probe(struct platform_device *pdev)
+{
+	struct regulator_config chgin_otg_reg_cfg;
+	struct power_supply_config psy_cfg;
+	struct device *dev = &pdev->dev;
+	struct max77759_charger *chg;
+	int ret;
+
+	device_set_of_node_from_dev(dev, dev->parent);
+	chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
+	if (!chg)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, chg);
+	chg->dev = dev;
+	chg->regmap = dev_get_regmap(dev->parent, "charger");
+	if (!chg->regmap)
+		return dev_err_probe(dev, -ENODEV, "Missing regmap\n");
+
+	ret = devm_mutex_init(dev, &chg->lock);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize lock\n");
+
+	ret = devm_mutex_init(dev, &chg->retry_lock);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to initialize retry_lock\n");
+
+	psy_cfg.fwnode = dev_fwnode(dev);
+	psy_cfg.drv_data = chg;
+	chg->psy = devm_power_supply_register(dev, &max77759_charger_desc,
+					      &psy_cfg);
+	if (IS_ERR(chg->psy))
+		return dev_err_probe(dev, PTR_ERR(chg->psy),
+				     "Failed to register psy\n");
+
+	ret = max77759_charger_init(chg);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to initialize max77759 charger\n");
+
+	chgin_otg_reg_cfg.dev = dev;
+	chgin_otg_reg_cfg.driver_data = chg;
+	chgin_otg_reg_cfg.of_node = dev_of_node(dev);
+	chg->chgin_otg_rdev = devm_regulator_register(dev, &chgin_otg_reg_desc,
+						      &chgin_otg_reg_cfg);
+	if (IS_ERR(chg->chgin_otg_rdev))
+		return dev_err_probe(dev, PTR_ERR(chg->chgin_otg_rdev),
+				     "Failed to register chgin otg regulator\n");
+
+	ret = devm_delayed_work_autocancel(dev, &chg->psy_work, psy_work_item);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize psy work\n");
+
+	chg->nb.notifier_call = psy_changed;
+	ret = power_supply_reg_notifier(&chg->nb);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Unable to register psy notifier\n");
+
+	ret = devm_add_action_or_reset(dev, max_tcpci_unregister_psy_notifier,
+				       &chg->nb);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "Failed to add devm action to unregister psy notifier\n");
+
+	return max77759_init_irqhandler(chg);
+}
+
+static const struct platform_device_id max77759_charger_id[] = {
+	{ .name = "max77759-charger", },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, max77759_charger_id);
+
+static struct platform_driver max77759_charger_driver = {
+	.driver = {
+		.name = "max77759-charger",
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe = max77759_charger_probe,
+	.id_table = max77759_charger_id,
+};
+module_platform_driver(max77759_charger_driver);
+
+MODULE_AUTHOR("Amit Sunil Dhamne <amitsd@google.com>");
+MODULE_DESCRIPTION("Maxim MAX77759 charger driver");
+MODULE_LICENSE("GPL");

-- 
2.53.0.1118.gaef5881109-goog




^ permalink raw reply related

* Re: [PATCH v2] ARM: dts: aspeed: Enable networking for Asus Kommando IPMI Card
From: Andrew Lunn @ 2026-03-31 23:35 UTC (permalink / raw)
  To: Anirudh Srinivasan
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
	Andrew Jeffery, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
In-Reply-To: <20260331-asus-kommando-networking-v2-1-f7d72ae5d40d@gmail.com>

On Tue, Mar 31, 2026 at 09:18:00AM -0500, Anirudh Srinivasan wrote:
> Adds the DT nodes needed for ethernet support for Asus Kommando, with
> phy mode set to rgmii-id.
> 
> When this DT was originally added, the phy mode was set to rgmii (which
> was incorrect). It was suggested to remove networking support from the
> DT till the Aspeed networking driver was patched so that the correct phy
> mode could be used.
> 
> The discussion in [1] mentions that u-boot was inserting clk delays that
> weren't needed, which resulted in needing to set the phy mode in linux
> to rgmii incorrectly. The solution suggested there was to patch u-boot to
> no longer insert these clk delays and use rgmii-id as the phy mode for
> any future DTs added to linux.
> 
> This DT was tested (on the OpenBMC u-boot fork [2]) with a u-boot DT
> modified to insert clk delays of 0 (instead of patching u-boot itself).
> [3] adds a u-boot DT for this device (without networking) and describes
> how to patch it to add networking support. If this patched DT is used,
> then networking works with rgmii-id phy mode in both u-boot and linux.
> 
> [1] https://lore.kernel.org/linux-aspeed/ef88bb50-9f2c-458d-a7e5-dc5ecb9c777a@lunn.ch/
> [2] https://github.com/openbmc/u-boot/tree/v2019.04-aspeed-openbmc
> [3] https://lore.kernel.org/openbmc/20260328-asus-kommando-v2-1-2a656f8cd314@gmail.com/
> 
> Signed-off-by: Anirudh Srinivasan <anirudhsriniv@gmail.com>

Thanks for the updated commit message.

Is anybody trying to get the changes in the forked version upstream?
It seems like a reasonable way to solve the problem, at least for new
boards.

Reviewed-by: Andrew Lunn <andrew@lunn.ch>

    Andrew


^ permalink raw reply

* [PATCH 0/9] lib/crypto: arm64: Remove obsolete chunking logic
From: Eric Biggers @ 2026-04-01  0:05 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, Eric Biggers

Since commit aefbab8e77eb ("arm64: fpsimd: Preserve/restore kernel mode
NEON at context switch"), kernel-mode NEON sections have been
preemptible on arm64.  And since commit 7dadeaa6e851 ("sched: Further
restrict the preemption modes"), voluntary preemption is no longer
supported on arm64 either.  Therefore, there's no longer any need to
limit the length of kernel-mode NEON sections on arm64.

This series simplifies the code in lib/crypto/arm64/ accordingly by
using longer kernel-mode NEON sections instead of multiple shorter ones.

This series is targeting libcrypto-next.

Eric Biggers (9):
  lib/crypto: arm64/aes: Remove obsolete chunking logic
  lib/crypto: arm64/chacha: Remove obsolete chunking logic
  lib/crypto: arm64/gf128hash: Remove obsolete chunking logic
  lib/crypto: arm64/poly1305: Remove obsolete chunking logic
  lib/crypto: arm64/sha1: Remove obsolete chunking logic
  lib/crypto: arm64/sha256: Remove obsolete chunking logic
  lib/crypto: arm64/sha512: Remove obsolete chunking logic
  lib/crypto: arm64/sha3: Remove obsolete chunking logic
  arm64: fpsimd: Remove obsolete cond_yield macro

 arch/arm64/crypto/aes-ce-ccm-glue.c | 13 ++++-------
 arch/arm64/include/asm/assembler.h  | 22 ------------------
 include/crypto/aes.h                |  6 ++---
 lib/crypto/arm64/aes-modes.S        |  8 +++----
 lib/crypto/arm64/aes.h              | 35 +++++++++++------------------
 lib/crypto/arm64/chacha.h           | 16 ++++---------
 lib/crypto/arm64/gf128hash.h        | 24 ++++----------------
 lib/crypto/arm64/poly1305.h         | 14 ++++--------
 lib/crypto/arm64/sha1-ce-core.S     | 14 +++++-------
 lib/crypto/arm64/sha1.h             | 15 ++++---------
 lib/crypto/arm64/sha256-ce.S        | 14 +++++-------
 lib/crypto/arm64/sha256.h           | 29 +++++++-----------------
 lib/crypto/arm64/sha3-ce-core.S     |  8 +++----
 lib/crypto/arm64/sha3.h             | 15 ++++---------
 lib/crypto/arm64/sha512-ce-core.S   | 12 +++++-----
 lib/crypto/arm64/sha512.h           | 15 ++++---------
 16 files changed, 73 insertions(+), 187 deletions(-)


base-commit: 7ac21b4032e5b9b8a6a312b6f1d54f4ba24d1c16
-- 
2.53.0



^ permalink raw reply

* [PATCH 2/9] lib/crypto: arm64/chacha: Remove obsolete chunking logic
From: Eric Biggers @ 2026-04-01  0:05 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, Eric Biggers
In-Reply-To: <20260401000548.133151-1-ebiggers@kernel.org>

Since commit aefbab8e77eb ("arm64: fpsimd: Preserve/restore kernel mode
NEON at context switch"), kernel-mode NEON sections have been
preemptible on arm64.  And since commit 7dadeaa6e851 ("sched: Further
restrict the preemption modes"), voluntary preemption is no longer
supported on arm64 either.  Therefore, there's no longer any need to
limit the length of kernel-mode NEON sections on arm64.

Simplify the ChaCha code accordingly.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 lib/crypto/arm64/chacha.h | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/lib/crypto/arm64/chacha.h b/lib/crypto/arm64/chacha.h
index ca8c6a8b0578..c6f8ddf98e2d 100644
--- a/lib/crypto/arm64/chacha.h
+++ b/lib/crypto/arm64/chacha.h
@@ -34,13 +34,13 @@ asmlinkage void hchacha_block_neon(const struct chacha_state *state,
 				   u32 out[HCHACHA_OUT_WORDS], int nrounds);
 
 static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
 
 static void chacha_doneon(struct chacha_state *state, u8 *dst, const u8 *src,
-			  int bytes, int nrounds)
+			  unsigned int bytes, int nrounds)
 {
-	while (bytes > 0) {
+	while (bytes) {
 		int l = min(bytes, CHACHA_BLOCK_SIZE * 5);
 
 		if (l <= CHACHA_BLOCK_SIZE) {
 			u8 buf[CHACHA_BLOCK_SIZE];
 
@@ -74,20 +74,12 @@ static void chacha_crypt_arch(struct chacha_state *state, u8 *dst,
 {
 	if (!static_branch_likely(&have_neon) || bytes <= CHACHA_BLOCK_SIZE ||
 	    !crypto_simd_usable())
 		return chacha_crypt_generic(state, dst, src, bytes, nrounds);
 
-	do {
-		unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
-
-		scoped_ksimd()
-			chacha_doneon(state, dst, src, todo, nrounds);
-
-		bytes -= todo;
-		src += todo;
-		dst += todo;
-	} while (bytes);
+	scoped_ksimd()
+		chacha_doneon(state, dst, src, bytes, nrounds);
 }
 
 #define chacha_mod_init_arch chacha_mod_init_arch
 static void chacha_mod_init_arch(void)
 {
-- 
2.53.0



^ permalink raw reply related

* [PATCH 1/9] lib/crypto: arm64/aes: Remove obsolete chunking logic
From: Eric Biggers @ 2026-04-01  0:05 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, Eric Biggers
In-Reply-To: <20260401000548.133151-1-ebiggers@kernel.org>

Since commit aefbab8e77eb ("arm64: fpsimd: Preserve/restore kernel mode
NEON at context switch"), kernel-mode NEON sections have been
preemptible on arm64.  And since commit 7dadeaa6e851 ("sched: Further
restrict the preemption modes"), voluntary preemption is no longer
supported on arm64 either.  Therefore, there's no longer any need to
limit the length of kernel-mode NEON sections on arm64.

Simplify the AES-CBC-MAC code accordingly.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 arch/arm64/crypto/aes-ce-ccm-glue.c | 13 ++++-------
 include/crypto/aes.h                |  6 ++---
 lib/crypto/arm64/aes-modes.S        |  8 +++----
 lib/crypto/arm64/aes.h              | 35 +++++++++++------------------
 4 files changed, 23 insertions(+), 39 deletions(-)

diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c
index 45aed0073283..a304375ce724 100644
--- a/arch/arm64/crypto/aes-ce-ccm-glue.c
+++ b/arch/arm64/crypto/aes-ce-ccm-glue.c
@@ -99,20 +99,15 @@ static u32 ce_aes_ccm_auth_data(u8 mac[], u8 const in[], u32 abytes,
 
 	do {
 		u32 blocks = abytes / AES_BLOCK_SIZE;
 
 		if (macp == AES_BLOCK_SIZE || (!macp && blocks > 0)) {
-			u32 rem = ce_aes_mac_update(in, rk, rounds, blocks, mac,
-						    macp, enc_after);
-			u32 adv = (blocks - rem) * AES_BLOCK_SIZE;
-
+			ce_aes_mac_update(in, rk, rounds, blocks, mac, macp,
+					  enc_after);
 			macp = enc_after ? 0 : AES_BLOCK_SIZE;
-			in += adv;
-			abytes -= adv;
-
-			if (unlikely(rem))
-				macp = 0;
+			in += blocks * AES_BLOCK_SIZE;
+			abytes -= blocks * AES_BLOCK_SIZE;
 		} else {
 			u32 l = min(AES_BLOCK_SIZE - macp, abytes);
 
 			crypto_xor(&mac[macp], in, l);
 			in += l;
diff --git a/include/crypto/aes.h b/include/crypto/aes.h
index 3feb4105c2a2..16fbfd93e2bd 100644
--- a/include/crypto/aes.h
+++ b/include/crypto/aes.h
@@ -228,13 +228,13 @@ asmlinkage void ce_aes_essiv_cbc_encrypt(u8 out[], u8 const in[],
 					 u32 const rk1[], int rounds,
 					 int blocks, u8 iv[], u32 const rk2[]);
 asmlinkage void ce_aes_essiv_cbc_decrypt(u8 out[], u8 const in[],
 					 u32 const rk1[], int rounds,
 					 int blocks, u8 iv[], u32 const rk2[]);
-asmlinkage size_t ce_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
-				    size_t blocks, u8 dg[], int enc_before,
-				    int enc_after);
+asmlinkage void ce_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
+				  size_t blocks, u8 dg[], int enc_before,
+				  int enc_after);
 #elif defined(CONFIG_PPC)
 void ppc_expand_key_128(u32 *key_enc, const u8 *key);
 void ppc_expand_key_192(u32 *key_enc, const u8 *key);
 void ppc_expand_key_256(u32 *key_enc, const u8 *key);
 void ppc_generate_decrypt_key(u32 *key_dec, u32 *key_enc, unsigned int key_len);
diff --git a/lib/crypto/arm64/aes-modes.S b/lib/crypto/arm64/aes-modes.S
index fc89cd02b642..10e537317eaf 100644
--- a/lib/crypto/arm64/aes-modes.S
+++ b/lib/crypto/arm64/aes-modes.S
@@ -815,13 +815,13 @@ AES_FUNC_START(aes_xts_decrypt)
 	b		.Lxtsdecctsout
 AES_FUNC_END(aes_xts_decrypt)
 
 #if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC_MACS)
 	/*
-	 * size_t aes_mac_update(u8 const in[], u32 const rk[], int rounds,
-	 *			 size_t blocks, u8 dg[], int enc_before,
-	 *			 int enc_after);
+	 * void aes_mac_update(u8 const in[], u32 const rk[], int rounds,
+	 *		       size_t blocks, u8 dg[], int enc_before,
+	 *		       int enc_after);
 	 */
 AES_FUNC_START(aes_mac_update)
 	ld1		{v0.16b}, [x4]			/* get dg */
 	enc_prepare	w2, x1, x7
 	cbz		w5, .Lmacloop4x
@@ -842,11 +842,10 @@ AES_FUNC_START(aes_mac_update)
 	cmp		x3, xzr
 	csinv		w5, w6, wzr, eq
 	cbz		w5, .Lmacout
 	encrypt_block	v0, w2, x1, x7, w8
 	st1		{v0.16b}, [x4]			/* return dg */
-	cond_yield	.Lmacout, x7, x8
 	b		.Lmacloop4x
 .Lmac1x:
 	add		x3, x3, #4
 .Lmacloop:
 	cbz		x3, .Lmacout
@@ -861,9 +860,8 @@ AES_FUNC_START(aes_mac_update)
 	encrypt_block	v0, w2, x1, x7, w8
 	b		.Lmacloop
 
 .Lmacout:
 	st1		{v0.16b}, [x4]			/* return dg */
-	mov		x0, x3
 	ret
 AES_FUNC_END(aes_mac_update)
 #endif /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
diff --git a/lib/crypto/arm64/aes.h b/lib/crypto/arm64/aes.h
index 135d3324a30a..9e9e45a6f787 100644
--- a/lib/crypto/arm64/aes.h
+++ b/lib/crypto/arm64/aes.h
@@ -27,13 +27,13 @@ asmlinkage void __aes_ce_encrypt(const u32 rk[], u8 out[AES_BLOCK_SIZE],
 asmlinkage void __aes_ce_decrypt(const u32 inv_rk[], u8 out[AES_BLOCK_SIZE],
 				 const u8 in[AES_BLOCK_SIZE], int rounds);
 asmlinkage u32 __aes_ce_sub(u32 l);
 asmlinkage void __aes_ce_invert(struct aes_block *out,
 				const struct aes_block *in);
-asmlinkage size_t neon_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
-				      size_t blocks, u8 dg[], int enc_before,
-				      int enc_after);
+asmlinkage void neon_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
+				    size_t blocks, u8 dg[], int enc_before,
+				    int enc_after);
 
 /*
  * Expand an AES key using the crypto extensions if supported and usable or
  * generic code otherwise.  The expanded key format is compatible between the
  * two cases.  The outputs are @rndkeys (required) and @inv_rndkeys (optional).
@@ -190,29 +190,20 @@ static bool aes_cbcmac_blocks_arch(u8 h[AES_BLOCK_SIZE],
 				   const struct aes_enckey *key, const u8 *data,
 				   size_t nblocks, bool enc_before,
 				   bool enc_after)
 {
 	if (static_branch_likely(&have_neon) && likely(may_use_simd())) {
-		do {
-			size_t rem;
-
-			scoped_ksimd() {
-				if (static_branch_likely(&have_aes))
-					rem = ce_aes_mac_update(
-						data, key->k.rndkeys,
-						key->nrounds, nblocks, h,
-						enc_before, enc_after);
-				else
-					rem = neon_aes_mac_update(
-						data, key->k.rndkeys,
-						key->nrounds, nblocks, h,
-						enc_before, enc_after);
-			}
-			data += (nblocks - rem) * AES_BLOCK_SIZE;
-			nblocks = rem;
-			enc_before = false;
-		} while (nblocks);
+		scoped_ksimd() {
+			if (static_branch_likely(&have_aes))
+				ce_aes_mac_update(data, key->k.rndkeys,
+						  key->nrounds, nblocks, h,
+						  enc_before, enc_after);
+			else
+				neon_aes_mac_update(data, key->k.rndkeys,
+						    key->nrounds, nblocks, h,
+						    enc_before, enc_after);
+		}
 		return true;
 	}
 	return false;
 }
 #endif /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
-- 
2.53.0



^ permalink raw reply related

* [PATCH 7/9] lib/crypto: arm64/sha512: Remove obsolete chunking logic
From: Eric Biggers @ 2026-04-01  0:05 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, Eric Biggers
In-Reply-To: <20260401000548.133151-1-ebiggers@kernel.org>

Since commit aefbab8e77eb ("arm64: fpsimd: Preserve/restore kernel mode
NEON at context switch"), kernel-mode NEON sections have been
preemptible on arm64.  And since commit 7dadeaa6e851 ("sched: Further
restrict the preemption modes"), voluntary preemption is no longer
supported on arm64 either.  Therefore, there's no longer any need to
limit the length of kernel-mode NEON sections on arm64.

Simplify the SHA-512 code accordingly.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 lib/crypto/arm64/sha512-ce-core.S | 12 +++++-------
 lib/crypto/arm64/sha512.h         | 15 ++++-----------
 2 files changed, 9 insertions(+), 18 deletions(-)

diff --git a/lib/crypto/arm64/sha512-ce-core.S b/lib/crypto/arm64/sha512-ce-core.S
index ffd51acfd1ee..26834921e8d6 100644
--- a/lib/crypto/arm64/sha512-ce-core.S
+++ b/lib/crypto/arm64/sha512-ce-core.S
@@ -91,15 +91,15 @@
 	add		v\i4\().2d, v\i1\().2d, v\i3\().2d
 	sha512h2	q\i3, q\i1, v\i0\().2d
 	.endm
 
 	/*
-	 * size_t __sha512_ce_transform(struct sha512_block_state *state,
-	 *				const u8 *data, size_t nblocks);
+	 * void sha512_ce_transform(struct sha512_block_state *state,
+	 *			    const u8 *data, size_t nblocks);
 	 */
 	.text
-SYM_FUNC_START(__sha512_ce_transform)
+SYM_FUNC_START(sha512_ce_transform)
 	/* load state */
 	ld1		{v8.2d-v11.2d}, [x0]
 
 	/* load first 4 round constants */
 	adr_l		x3, .Lsha512_rcon
@@ -184,14 +184,12 @@ CPU_LE(	rev64		v19.16b, v19.16b	)
 	add		v8.2d, v8.2d, v0.2d
 	add		v9.2d, v9.2d, v1.2d
 	add		v10.2d, v10.2d, v2.2d
 	add		v11.2d, v11.2d, v3.2d
 
-	cond_yield	3f, x4, x5
 	/* handled all input blocks? */
 	cbnz		x2, 0b
 
 	/* store new state */
-3:	st1		{v8.2d-v11.2d}, [x0]
-	mov		x0, x2
+	st1		{v8.2d-v11.2d}, [x0]
 	ret
-SYM_FUNC_END(__sha512_ce_transform)
+SYM_FUNC_END(sha512_ce_transform)
diff --git a/lib/crypto/arm64/sha512.h b/lib/crypto/arm64/sha512.h
index d978c4d07e90..5da27e6e23ea 100644
--- a/lib/crypto/arm64/sha512.h
+++ b/lib/crypto/arm64/sha512.h
@@ -10,27 +10,20 @@
 
 static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_sha512_insns);
 
 asmlinkage void sha512_block_data_order(struct sha512_block_state *state,
 					const u8 *data, size_t nblocks);
-asmlinkage size_t __sha512_ce_transform(struct sha512_block_state *state,
-					const u8 *data, size_t nblocks);
+asmlinkage void sha512_ce_transform(struct sha512_block_state *state,
+				    const u8 *data, size_t nblocks);
 
 static void sha512_blocks(struct sha512_block_state *state,
 			  const u8 *data, size_t nblocks)
 {
 	if (static_branch_likely(&have_sha512_insns) &&
 	    likely(may_use_simd())) {
-		do {
-			size_t rem;
-
-			scoped_ksimd()
-				rem = __sha512_ce_transform(state, data, nblocks);
-
-			data += (nblocks - rem) * SHA512_BLOCK_SIZE;
-			nblocks = rem;
-		} while (nblocks);
+		scoped_ksimd()
+			sha512_ce_transform(state, data, nblocks);
 	} else {
 		sha512_block_data_order(state, data, nblocks);
 	}
 }
 
-- 
2.53.0



^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox