Port patches from PR #8831

This commit is contained in:
EvilOlaf 2025-12-22 04:54:14 +00:00 committed by Igor
parent 145fd0b799
commit 430d9ab41b
9 changed files with 1467 additions and 2 deletions

View File

@ -0,0 +1,64 @@
From 72286070835a37fe74b630f36a8b5c56ad26b89d Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 19 Sep 2025 01:00:17 +0100
Subject: [PATCH 1/5] dt-bindings: mfd: x-powers,axp152: Add polyphased
property
Some X-Powers AXP PMICs can combine some of their DC/DC buck converter
outputs in a multi-phase fashion, to achieve higher currents and
decrease the output ripple. The datasheets call this poly-phase. This is
programmable in the PMIC, although often set up as the PMIC's reset
default.
Add the "x-powers,polyphased" property to the binding, to describe those
pairs or tuples of regulators that should work together. In the lead
regulator node, the property lists the phandles of the connected
regulators. Just an empty property means no poly-phasing.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
.../devicetree/bindings/mfd/x-powers,axp152.yaml | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
index 45f015d63df1..260c4c0afc47 100644
--- a/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
+++ b/Documentation/devicetree/bindings/mfd/x-powers,axp152.yaml
@@ -304,6 +304,15 @@ properties:
noise. This probably makes sense for HiFi audio related
applications that aren't battery constrained.
+ x-powers,polyphased:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description:
+ A list of phandles pointing to other regulators that should be
+ polyphased with this regulator. The linked regulators will be
+ synchronised with this regulator, within the PMIC, but only if
+ supported by the PMIC. An empty list means this regulator
+ should be configured in a single-phase setup.
+
additionalProperties: false
required:
@@ -377,6 +386,7 @@ examples:
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1450000>;
regulator-name = "vdd-cpu";
+ x-powers,polyphased = <&reg_dcdc4>;
};
reg_dcdc3: dcdc3 {
@@ -386,6 +396,10 @@ examples:
regulator-name = "vdd-int-dll";
};
+ reg_dcdc4: dcdc4 {
+ /* dual-phased with DCDC2 */
+ };
+
reg_ldo1: ldo1 {
/* LDO1 is a fixed output regulator */
regulator-always-on;
--
2.43.0

View File

@ -0,0 +1,148 @@
From 0cb44fa029c3a41b769ebbd7e4044682cad9a685 Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 19 Sep 2025 01:00:17 +0100
Subject: [PATCH 2/5] mfd: axp20x: Refactor axp20x_is_polyphase_slave()
Some X-Powers AXP PMICs allow to combine certain DC/DC rails together in
a multi-phase fashion. So far we don't actively program those
connections, but we detect the existing setup, and prevent the connected
regulators from being re-programmed or turned off. At the moment this is
done in a switch/case construct, listing the known regulator pairs for
those PMICs supported.
To get rid of this ever growing code section, create a data structure
that describes the relationship, and have generic code that iterates
over the entries and checks for matches.
This not only cleans that function up and makes extensions much simpler,
but also allows to reuse this information for the upcoming programming
of those poly-phase setups.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/regulator/axp20x-regulator.c | 91 ++++++++++++++--------------
1 file changed, 45 insertions(+), 46 deletions(-)
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index da891415efc0..19c9a98d1835 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -1481,70 +1481,69 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
return regmap_update_bits(rdev->regmap, reg, mask, workmode);
}
+struct dualphase_regulator {
+ int axp_id;
+ int reg1, reg2;
+ unsigned int polyphase_reg;
+ unsigned int bitmask;
+} dualphase_regulators[] = {
+ { AXP323_ID, AXP313A_DCDC1, AXP313A_DCDC2,
+ AXP323_DCDC_MODE_CTRL2, BIT(1), },
+ { AXP803_ID, AXP803_DCDC2, AXP803_DCDC3, AXP803_POLYPHASE_CTRL,
+ AXP803_DCDC23_POLYPHASE_DUAL, },
+ { AXP803_ID, AXP803_DCDC5, AXP803_DCDC6, AXP803_POLYPHASE_CTRL,
+ AXP803_DCDC56_POLYPHASE_DUAL, },
+ /* AXP806's DCDC-A/B/C is a tri-phase regulator */
+ { AXP806_ID, AXP806_DCDCD, AXP806_DCDCE, AXP806_DCDC_MODE_CTRL2,
+ AXP806_DCDCDE_POLYPHASE_DUAL, },
+ { AXP813_ID, AXP803_DCDC2, AXP803_DCDC3, AXP803_POLYPHASE_CTRL,
+ AXP803_DCDC23_POLYPHASE_DUAL, },
+ { AXP813_ID, AXP803_DCDC5, AXP803_DCDC6, AXP803_POLYPHASE_CTRL,
+ AXP803_DCDC56_POLYPHASE_DUAL, },
+ { AXP15060_ID, AXP15060_DCDC2, AXP15060_DCDC3, AXP15060_DCDC_MODE_CTRL1,
+ AXP15060_DCDC23_POLYPHASE_DUAL_MASK, },
+ { AXP15060_ID, AXP15060_DCDC4, AXP15060_DCDC6, AXP15060_DCDC_MODE_CTRL1,
+ AXP15060_DCDC46_POLYPHASE_DUAL_MASK, },
+};
+
/*
* This function checks whether a regulator is part of a poly-phase
* output setup based on the registers settings. Returns true if it is.
*/
static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
{
+ struct dualphase_regulator *dpreg;
u32 reg = 0;
+ int i;
- /*
- * Currently in our supported AXP variants, only AXP803, AXP806,
- * AXP813 and AXP15060 have polyphase regulators.
- */
- switch (axp20x->variant) {
- case AXP803_ID:
- case AXP813_ID:
- regmap_read(axp20x->regmap, AXP803_POLYPHASE_CTRL, &reg);
+ for (i = 0; i < ARRAY_SIZE(dualphase_regulators); i++) {
+ dpreg = &dualphase_regulators[i];
- switch (id) {
- case AXP803_DCDC3:
- return !!(reg & AXP803_DCDC23_POLYPHASE_DUAL);
- case AXP803_DCDC6:
- return !!(reg & AXP803_DCDC56_POLYPHASE_DUAL);
+ if (axp20x->variant != dpreg->axp_id)
+ continue;
+ /* Is this the second regulator from a dual-phase pair? */
+ if (id == dpreg->reg2) {
+ regmap_read(axp20x->regmap, dpreg->polyphase_reg, &reg);
+
+ return !!(reg & dpreg->bitmask);
}
- break;
+ }
- case AXP806_ID:
+ /*
+ * DCDC-A/B/C can be configured either as a dual-phase (A+B) or
+ * as a triple-phase regulator (A+B+C), but not in any other
+ * combination. Treat this as a special case here.
+ */
+ if (axp20x->variant == AXP806_ID) {
regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, &reg);
-
- switch (id) {
- case AXP806_DCDCB:
+ if (id == AXP806_DCDCB)
return (((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
AXP806_DCDCAB_POLYPHASE_DUAL) ||
((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
AXP806_DCDCABC_POLYPHASE_TRI));
- case AXP806_DCDCC:
+ if (id == AXP806_DCDCC)
return ((reg & AXP806_DCDCABC_POLYPHASE_MASK) ==
AXP806_DCDCABC_POLYPHASE_TRI);
- case AXP806_DCDCE:
- return !!(reg & AXP806_DCDCDE_POLYPHASE_DUAL);
- }
- break;
-
- case AXP15060_ID:
- regmap_read(axp20x->regmap, AXP15060_DCDC_MODE_CTRL1, &reg);
-
- switch (id) {
- case AXP15060_DCDC3:
- return !!(reg & AXP15060_DCDC23_POLYPHASE_DUAL_MASK);
- case AXP15060_DCDC6:
- return !!(reg & AXP15060_DCDC46_POLYPHASE_DUAL_MASK);
- }
- break;
-
- case AXP323_ID:
- regmap_read(axp20x->regmap, AXP323_DCDC_MODE_CTRL2, &reg);
-
- switch (id) {
- case AXP313A_DCDC2:
- return !!(reg & BIT(1));
- }
- break;
-
- default:
- return false;
}
return false;
--
2.43.0

View File

@ -0,0 +1,120 @@
From d8f1a6d20eef731149c58b1847696425fdd56f83 Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 19 Sep 2025 01:00:17 +0100
Subject: [PATCH 3/5] mfd: axp20x: Allow programming dual-phase regulator pairs
Some X-Powers AXP PMICs allow to combine certain DC/DC rails together in
a multi-phase fashion. So far we don't actively program those connections,
since the PMIC reset default for the multi-phasing setup was always
correct for the existing boards.
Now a new set of boards appeared where the reset default is not correct,
so we need to actively program the multi-phase setup.
Use the new data structure describing the dual-phased regulators, and
the new "x-powers,polyphased" DT property to enable or disable the
dual-phase setup on the PMICs that support it.
This works by checking how many regulators this DT property list:
- If it's none, this means any existing poly-phase setup should be broken
up.
- If the property references at least one other regulator, we can use our
dual-phase regulator table to find the register and bitmask required to
establish the dual-phase connection.
This supports only dual-phased regulator pairs so far, but we will
somewhat paper fix this in the next patch.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/regulator/axp20x-regulator.c | 68 ++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index 19c9a98d1835..e3acc4635a0e 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -1549,6 +1549,70 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
return false;
}
+static int axp20x_find_polyphased_reg(const struct regulator_desc *regs,
+ int nregulators,
+ const struct device_node *np, int index)
+{
+ struct of_phandle_args args;
+ int ret, i;
+
+ ret = of_parse_phandle_with_fixed_args(np, "x-powers,polyphased",
+ 0, index, &args);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nregulators; i++) {
+ if (!strcmp(regs[i].name, args.np->name))
+ return i;
+ }
+
+ return -ENODEV;
+}
+
+static int axp20x_parse_polyphase(struct axp20x_dev *axp20x, int primary_reg_id,
+ const struct regulator_desc *regs,
+ int nregulators, const struct device_node *np)
+{
+ struct dualphase_regulator *dpreg;
+ int reg_id, i;
+
+ if (!of_property_present(np, "x-powers,polyphased"))
+ return 0;
+
+ reg_id = axp20x_find_polyphased_reg(regs, nregulators, np, 0);
+ if (reg_id < 0 && reg_id != -ENOENT) /* not just empty property */
+ return reg_id;
+
+ for (i = 0; i < ARRAY_SIZE(dualphase_regulators); i++) {
+ dpreg = &dualphase_regulators[i];
+
+ if (axp20x->variant != dpreg->axp_id)
+ continue;
+
+ if (dpreg->reg1 != primary_reg_id &&
+ dpreg->reg2 != primary_reg_id)
+ continue;
+
+ /* Empty property means breaking any polyphase setup. */
+ if (reg_id == -ENOENT) {
+ regmap_update_bits(axp20x->regmap, dpreg->polyphase_reg,
+ dpreg->bitmask, 0);
+
+ return 0;
+ }
+
+ if ((dpreg->reg1 == primary_reg_id && dpreg->reg2 == reg_id) ||
+ (dpreg->reg2 == primary_reg_id && dpreg->reg1 == reg_id)) {
+ regmap_update_bits(axp20x->regmap, dpreg->polyphase_reg,
+ dpreg->bitmask, dpreg->bitmask);
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
static int axp20x_regulator_probe(struct platform_device *pdev)
{
struct regulator_dev *rdev;
@@ -1703,6 +1767,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
rdev->desc->name);
}
+ if (rdev->dev.of_node)
+ axp20x_parse_polyphase(axp20x, i, regulators,
+ nregulators, rdev->dev.of_node);
+
/*
* Save AXP22X DCDC1 / DCDC5 / AXP15060 ALDO1 regulator names for later.
*/
--
2.43.0

View File

@ -0,0 +1,93 @@
From 008942ec8d1bd6615e71765d1ef2679642515fa4 Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 19 Sep 2025 01:00:17 +0100
Subject: [PATCH 4/5] mfd: axp20x: Support tri-phase setup
Of the PMICs that support multi-phased regulators, all but one just
support a dual-phase setup, with exactly two regulators tied together.
This allows for a simple data model, since just two is somewhat of a
special case.
However there is the AXP806, which supports a triple-phase setup, that is
also used on at least one board: the Cubieboard 4, where DCDC-A+B+C
together supply the Cortex-A15 CPU cluster.
Since this is just one case, and a fairly old one now, let's not boil
the ocean by coming up with a complex data structure that allows
describing arbitrary combinations, but instead handle this as a special
case. This is supported by the fact, that the AXP806 only supports two
specific setups: DCDC-A+B or DCDC-A+B+C, but nothing else.
Add a function that checks for the regulators on this PMIC, and handle
the two cases, plus the one without any poly-phasing.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
drivers/regulator/axp20x-regulator.c | 45 ++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index e3acc4635a0e..9dd666f228b1 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -1569,6 +1569,39 @@ static int axp20x_find_polyphased_reg(const struct regulator_desc *regs,
return -ENODEV;
}
+static int axp20x_handle_triphase(struct axp20x_dev *axp20x,
+ int reg1, int reg2, int reg3)
+{
+ if (axp20x->variant == AXP806_ID && reg1 == AXP806_DCDCA) {
+ /* no other regulator listed: single phase setup */
+ if (reg2 == -ENOENT && reg3 == -ENOENT) {
+ regmap_update_bits(axp20x->regmap,
+ AXP806_DCDC_MODE_CTRL2,
+ AXP806_DCDCABC_POLYPHASE_MASK, 0);
+ return 0;
+ }
+ /* only regulator listed is DCDC-B: dual phase setup */
+ if (reg2 == AXP806_DCDCB && reg3 == -ENOENT) {
+ regmap_update_bits(axp20x->regmap,
+ AXP806_DCDC_MODE_CTRL2,
+ AXP806_DCDCABC_POLYPHASE_MASK,
+ AXP806_DCDCAB_POLYPHASE_DUAL);
+ return 0;
+ }
+ /* both DCDC-B+C regulators listed: tri phase setup */
+ if ((reg2 == AXP806_DCDCB && reg3 == AXP806_DCDCC) ||
+ (reg2 == AXP806_DCDCC && reg3 == AXP806_DCDCB)) {
+ regmap_update_bits(axp20x->regmap,
+ AXP806_DCDC_MODE_CTRL2,
+ AXP806_DCDCABC_POLYPHASE_MASK,
+ AXP806_DCDCABC_POLYPHASE_TRI);
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
static int axp20x_parse_polyphase(struct axp20x_dev *axp20x, int primary_reg_id,
const struct regulator_desc *regs,
int nregulators, const struct device_node *np)
@@ -1610,6 +1643,18 @@ static int axp20x_parse_polyphase(struct axp20x_dev *axp20x, int primary_reg_id,
}
}
+ /* Special handling for the AXP806 DCDC-A/B/C tri-phase regulator. */
+ if (axp20x->variant == AXP806_ID && primary_reg_id == AXP806_DCDCA) {
+ int reg3_id;
+
+ reg3_id = axp20x_find_polyphased_reg(regs, nregulators, np, 1);
+ if (reg3_id < 0 && reg3_id != -ENOENT)
+ return reg_id;
+
+ return axp20x_handle_triphase(axp20x, primary_reg_id,
+ reg_id, reg3_id);
+ }
+
return 0;
}
--
2.43.0

View File

@ -0,0 +1,97 @@
From 87274e8d73915412aa8b0fcefa27a1c0e982c975 Mon Sep 17 00:00:00 2001
From: Andre Przywara <andre.przywara@arm.com>
Date: Fri, 19 Sep 2025 01:00:17 +0100
Subject: [PATCH 5/5] arm64: dts: allwinner: a523: Mark dual-phased regulators
The X-Powers AXP323 PMIC on the boards with a SoC from the Allwinner
A523 family typically uses DCDC1 and DCDC2 in a dual-phase setup to
supply the "big" CPU cluster. For some reason this dual-phase
configuration is not the PMIC's reset default, but needs to be actively
programmed at runtime.
Add the newly introduced x-powers,polyphased property in the board DTs,
to mark this connection and let drivers program the dual-phase setup.
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts | 5 ++++-
arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts | 5 ++++-
arch/arm64/boot/dts/allwinner/sun55i-t527-avaota-a1.dts | 5 ++++-
arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts | 5 ++++-
4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
index bfdf1728cd14..9e52ea338ce5 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
@@ -320,9 +320,12 @@ reg_dcdc1_323: dcdc1 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1160000>;
regulator-name = "vdd-cpub";
+ x-powers,polyphased = <&reg_dcdc2_323>;
};
- /* DCDC2 is polyphased with DCDC1 */
+ reg_dcdc2_323: dcdc2 {
+ /* dual-phased with DCDC1 */
+ };
/* RISC-V management core supply */
reg_dcdc3_323: dcdc3 {
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts b/arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts
index a96927fbdadd..9dd4178bdff1 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-h728-x96qpro+.dts
@@ -252,9 +252,12 @@ reg_dcdc1_323: dcdc1 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1160000>;
regulator-name = "vdd-cpub";
+ x-powers,polyphased = <&reg_dcdc2_323>;
};
- /* DCDC2 is polyphased with DCDC1 */
+ reg_dcdc2_323: dcdc2 {
+ /* dual-phased with DCDC1 */
+ };
reg_dcdc3_323: dcdc3 {
regulator-always-on;
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-t527-avaota-a1.dts b/arch/arm64/boot/dts/allwinner/sun55i-t527-avaota-a1.dts
index 054d0357c139..678736e3b717 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-t527-avaota-a1.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-t527-avaota-a1.dts
@@ -330,9 +330,12 @@ reg_dcdc1_323: dcdc1 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1160000>;
regulator-name = "vdd-cpub";
+ x-powers,polyphased = <&reg_dcdc2_323>;
};
- /* DCDC2 is polyphased with DCDC1 */
+ reg_dcdc2_323: dcdc2 {
+ /* dual-phased with DCDC1 */
+ };
/* Some RISC-V management core related voltage */
reg_dcdc3_323: dcdc3 {
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts b/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
index 39a4e194712a..ef0837ffa38f 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-t527-orangepi-4a.dts
@@ -345,9 +345,12 @@ reg_dcdc1_323: dcdc1 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1150000>;
regulator-name = "vdd-cpub";
+ x-powers,polyphased = <&reg_dcdc2_323>;
};
- /* DCDC2 is polyphased with DCDC1 */
+ reg_dcdc2_323: dcdc2 {
+ /* dual-phased with DCDC1 */
+ };
/* Some RISC-V management core related voltage */
reg_dcdc3_323: dcdc3 {
--
2.43.0

View File

@ -0,0 +1,803 @@
From 8476f1b10b6acc327455c840d3f89a56ec6dedea Mon Sep 17 00:00:00 2001
From: Mikhail Kalashnikov <iuncuim@gmail.com>
Date: Fri, 07 Nov 2025 12:46:30 -0000
Subject: [PATCH] [PATCH v3 1/6] dt-bindings: thermal: sun8i: Add A523 THS0/1
Add a binding for D1/T113s thermal sensor controller. Add dt-bindings
description of the thermal sensors in the A523 processor.
The controllers require activation of the additional frequency of the
associated gpadc controller, so a new clock property has been added.
The calibration data is split into two cells that are in different areas
of nvmem. Both controllers require access to both memory cell, so a new
property nvmem-cells has been added. To maintain backward compatibility,
the name of the old cell remains the same and the new nvmem-cell-names is
called calibration-second-part
Signed-off-by: Mikhail Kalashnikov <iuncuim@gmail.com>
---
.../thermal/allwinner,sun8i-a83t-ths.yaml | 56 ++++++++++++++++++-
1 file changed, 53 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml b/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml
index 3e61689f6..b2f750ef2 100644
--- a/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml
+++ b/Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml
@@ -24,18 +24,23 @@ properties:
- allwinner,sun50i-h5-ths
- allwinner,sun50i-h6-ths
- allwinner,sun50i-h616-ths
+ - allwinner,sun55i-a523-ths0
+ - allwinner,sun55i-a523-ths1
clocks:
minItems: 1
items:
- description: Bus Clock
- description: Module Clock
+ - description: GPADC Clock
clock-names:
minItems: 1
+ maxItems: 2
items:
- const: bus
- const: mod
+ - const: gpadc
reg:
maxItems: 1
@@ -47,11 +52,16 @@ properties:
maxItems: 1
nvmem-cells:
- maxItems: 1
- description: Calibration data for thermal sensors
+ minItems: 1
+ items:
+ - description: Calibration data for thermal sensors
+ - description: Additional cell in case of separate calibration data
nvmem-cell-names:
- const: calibration
+ minItems: 1
+ items:
+ - const: calibration
+ - const: calibration-second-part
allwinner,sram:
maxItems: 1
@@ -107,6 +117,7 @@ allOf:
enum:
- allwinner,sun8i-h3-ths
- allwinner,sun20i-d1-ths
+ - allwinner,sun55i-a523-ths0
then:
properties:
@@ -132,6 +143,32 @@ allOf:
- clock-names
- resets
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - allwinner,sun55i-a523-ths0
+ - allwinner,sun55i-a523-ths1
+ then:
+ properties:
+ clocks:
+ minItems: 2
+ clock-names:
+ enum: [ bus, gpadc ]
+ nvmem-cells:
+ minItems: 2
+ nvmem-cell-names:
+ minItems: 2
+ else:
+ properties:
+ nvmem-cells:
+ maxItems: 1
+ nvmem-cell-names:
+ maxItems: 1
+ items:
+ - const: calibration
+
required:
- compatible
- reg
@@ -176,4 +213,17 @@ examples:
#thermal-sensor-cells = <1>;
};
+ - |
+ thermal-sensor@2009400 {
+ compatible = "allwinner,sun55i-a523-ths1";
+ reg = <0x02009400 0x400>;
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_GPADC1>;
+ clock-names = "bus", "gpadc";
+ resets = <&ccu RST_BUS_THS>;
+ nvmem-cells = <&ths_calibration0>, <&ths_calibration1>;
+ nvmem-cell-names = "calibration",
+ "calibration-second-part";
+ #thermal-sensor-cells = <1>;
+ };
...
From 955935d64eeca888d0cde1dd3475b5b82ad37331 Mon Sep 17 00:00:00 2001
From: Mikhail Kalashnikov <iuncuim@gmail.com>
Date: Fri, 07 Nov 2025 12:46:30 -0000
Subject: [PATCH 2/X] auto-split from bundle
Some processors (e.g. Allwinner A523) require GPADC clocking activation for
temperature sensors to work. So let's add support for enabling it.
Signed-off-by: Mikhail Kalashnikov <iuncuim@gmail.com>
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
---
drivers/thermal/sun8i_thermal.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
index 226747906..c02c398b0 100644
--- a/drivers/thermal/sun8i_thermal.c
+++ b/drivers/thermal/sun8i_thermal.c
@@ -66,6 +66,7 @@ struct tsensor {
};
struct ths_thermal_chip {
+ bool has_gpadc_clk;
bool has_mod_clk;
bool has_bus_clk_reset;
bool needs_sram;
@@ -89,6 +90,7 @@ struct ths_device {
struct regmap_field *sram_regmap_field;
struct reset_control *reset;
struct clk *bus_clk;
+ struct clk *gpadc_clk;
struct clk *mod_clk;
struct tsensor sensor[MAX_SENSOR_NUM];
};
@@ -417,6 +419,12 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
if (ret)
return ret;
+ if (tmdev->chip->has_gpadc_clk) {
+ tmdev->gpadc_clk = devm_clk_get_enabled(&pdev->dev, "gpadc");
+ if (IS_ERR(tmdev->gpadc_clk))
+ return PTR_ERR(tmdev->gpadc_clk);
+ }
+
if (tmdev->chip->needs_sram) {
struct regmap *regmap;
From d047c1633c69dca78a06517d595cbbd694a621c7 Mon Sep 17 00:00:00 2001
From: Mikhail Kalashnikov <iuncuim@gmail.com>
Date: Fri, 07 Nov 2025 12:46:30 -0000
Subject: [PATCH 3/X] auto-split from bundle
The A523 processor has two temperature controllers, but they share a
common reset line. Make it shared with the shared variant of
devm_reset_control_get(), and also simplify the driver by switching to
devm_reset_control_get_shared_deasserted().
Signed-off-by: Mikhail Kalashnikov <iuncuim@gmail.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/thermal/sun8i_thermal.c | 16 +---------------
1 file changed, 1 insertion(+), 15 deletions(-)
diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
index c02c398b0..aa496e1ba 100644
--- a/drivers/thermal/sun8i_thermal.c
+++ b/drivers/thermal/sun8i_thermal.c
@@ -344,11 +344,6 @@ static int sun8i_ths_calibrate(struct ths_device *tmdev)
return ret;
}
-static void sun8i_ths_reset_control_assert(void *data)
-{
- reset_control_assert(data);
-}
-
static struct regmap *sun8i_ths_get_sram_regmap(struct device_node *node)
{
struct platform_device *sram_pdev;
@@ -391,19 +386,10 @@ static int sun8i_ths_resource_init(struct ths_device *tmdev)
return PTR_ERR(tmdev->regmap);
if (tmdev->chip->has_bus_clk_reset) {
- tmdev->reset = devm_reset_control_get(dev, NULL);
+ tmdev->reset = devm_reset_control_get_shared_deasserted(dev, NULL);
if (IS_ERR(tmdev->reset))
return PTR_ERR(tmdev->reset);
- ret = reset_control_deassert(tmdev->reset);
- if (ret)
- return ret;
-
- ret = devm_add_action_or_reset(dev, sun8i_ths_reset_control_assert,
- tmdev->reset);
- if (ret)
- return ret;
-
tmdev->bus_clk = devm_clk_get_enabled(&pdev->dev, "bus");
if (IS_ERR(tmdev->bus_clk))
return PTR_ERR(tmdev->bus_clk);
From c71a090a859ac701105f82166d6ffd03204bfcd0 Mon Sep 17 00:00:00 2001
From: Mikhail Kalashnikov <iuncuim@gmail.com>
Date: Fri, 07 Nov 2025 12:46:30 -0000
Subject: [PATCH 4/X] auto-split from bundle
The A523 processor has calibration data in two nvmem cell. To be able to
add support, the ability to add data from two cells into one array must be
added.
Signed-off-by: Mikhail Kalashnikov <iuncuim@gmail.com>
---
drivers/thermal/sun8i_thermal.c | 77 ++++++++++++++++++++++-----------
1 file changed, 52 insertions(+), 25 deletions(-)
diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
index aa496e1ba..d6d8e13e5 100644
--- a/drivers/thermal/sun8i_thermal.c
+++ b/drivers/thermal/sun8i_thermal.c
@@ -303,43 +303,70 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
static int sun8i_ths_calibrate(struct ths_device *tmdev)
{
- struct nvmem_cell *calcell;
+ struct nvmem_cell *calcell = NULL;
struct device *dev = tmdev->dev;
- u16 *caldata;
- size_t callen;
+ struct device_node *np = dev_of_node(dev);
+ struct property *prop;
+ const char *cellname;
+ u8 *caldata = NULL;
+ size_t callen = 0;
int ret = 0;
- calcell = nvmem_cell_get(dev, "calibration");
- if (IS_ERR(calcell)) {
- if (PTR_ERR(calcell) == -EPROBE_DEFER)
- return -EPROBE_DEFER;
- /*
- * Even if the external calibration data stored in sid is
- * not accessible, the THS hardware can still work, although
- * the data won't be so accurate.
- *
- * The default value of calibration register is 0x800 for
- * every sensor, and the calibration value is usually 0x7xx
- * or 0x8xx, so they won't be away from the default value
- * for a lot.
- *
- * So here we do not return error if the calibration data is
- * not available, except the probe needs deferring.
- */
- goto out;
+ of_property_for_each_string(np, "nvmem-cell-names", prop, cellname) {
+ size_t len;
+ u8 *caldatapart;
+
+ calcell = of_nvmem_cell_get(np, cellname);
+ if (IS_ERR(calcell)) {
+ if (PTR_ERR(calcell) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ /*
+ * Even if the external calibration data stored in sid is
+ * not accessible, the THS hardware can still work, although
+ * the data won't be so accurate.
+ *
+ * The default value of calibration register is 0x800 for
+ * every sensor, and the calibration value is usually 0x7xx
+ * or 0x8xx, so they won't be away from the default value
+ * for a lot.
+ *
+ * So here we do not return error if the calibration data is
+ * not available, except the probe needs deferring.
+ */
+ goto out;
+ }
+
+ caldatapart = nvmem_cell_read(calcell, &len);
+ nvmem_cell_put(calcell);
+ calcell = NULL;
+ if (IS_ERR(caldatapart)) {
+ ret = PTR_ERR(caldatapart);
+ goto out;
+ }
+
+ caldata = devm_krealloc(dev, caldata, callen + len, GFP_KERNEL);
+ if (!caldata) {
+ kfree(caldatapart);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(caldata + callen, caldatapart, len);
+ callen += len;
+ kfree(caldatapart);
}
- caldata = nvmem_cell_read(calcell, &callen);
if (IS_ERR(caldata)) {
ret = PTR_ERR(caldata);
goto out;
}
- tmdev->chip->calibrate(tmdev, caldata, callen);
+ tmdev->chip->calibrate(tmdev, (u16 *)caldata, callen);
- kfree(caldata);
+ devm_kfree(dev, caldata);
+ caldata = NULL;
out:
- if (!IS_ERR(calcell))
+ if (calcell && !IS_ERR(calcell))
nvmem_cell_put(calcell);
return ret;
}
From 6157843778fda7cd704d2c553e7ee9593b831fcb Mon Sep 17 00:00:00 2001
From: Mikhail Kalashnikov <iuncuim@gmail.com>
Date: Fri, 07 Nov 2025 12:46:30 -0000
Subject: [PATCH 5/X] auto-split from bundle
The A523 processor has two temperature controllers, THS0 and THS1.
THS0 has only one temperature sensor, which is located in the DRAM.
THS1 does have 3 sensors:
ths1_0 - "big" cores
ths1_1 - "little" cores
ths1_2 - gpu
The datasheet mentions a fourth sensor in the NPU, but lacks any registers
for operation other than calibration registers. The vendor code reads the
value from ths1_2, but uses separate calibration data, so we get two
different values from real one.
Signed-off-by: Mikhail Kalashnikov <iuncuim@gmail.com>
---
drivers/thermal/sun8i_thermal.c | 133 ++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)
diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c
index d6d8e13e5..7d35ea3c4 100644
--- a/drivers/thermal/sun8i_thermal.c
+++ b/drivers/thermal/sun8i_thermal.c
@@ -59,6 +59,12 @@
#define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12)
#define SUN50I_H6_THS_DATA_IRQ_STS(x) BIT(x)
+#define SUN55I_A523_DELIMITER 0x7c8
+#define SUN55I_A523_OFFSET_ABOVE 2736
+#define SUN55I_A523_OFFSET_BELOW 2825
+#define SUN55I_A523_SCALE_ABOVE 74
+#define SUN55I_A523_SCALE_BELOW 65
+
struct tsensor {
struct ths_device *tmdev;
struct thermal_zone_device *tzd;
@@ -116,6 +122,15 @@ static int sun50i_h5_calc_temp(struct ths_device *tmdev,
return -1590 * reg / 10 + 276000;
}
+static int sun55i_a523_calc_temp(struct ths_device *tmdev,
+ int id, int reg)
+{
+ if (reg >= SUN55I_A523_DELIMITER)
+ return SUN55I_A523_SCALE_ABOVE * (SUN55I_A523_OFFSET_ABOVE - reg);
+ else
+ return SUN55I_A523_SCALE_BELOW * (SUN55I_A523_OFFSET_BELOW - reg);
+}
+
static int sun8i_ths_get_temp(struct thermal_zone_device *tz, int *temp)
{
struct tsensor *s = thermal_zone_device_priv(tz);
@@ -301,6 +316,97 @@ static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
return 0;
}
+/*
+ * The A523 nvmem calibration values. The ths1_3 is not used as it
+ * doesn't have its own sensor and doesn't have any internal switch.
+ * Instead, the value from the ths1_2 sensor is used, which gives the
+ * illusion of an independent sensor for NPU and GPU when using
+ * different calibration values.
+ *
+ * efuse layout 0x38-0x3F (caldata[0..3]):
+ * caldata[0] caldata[1] caldata[2] caldata[3]
+ * 0 16 24 32 36 48 60 64
+ * +---------------+---------------+---------------+---------------+
+ * | | | temp | ths1_0 | ths1_1 | +
+ * +---------------+---------------+---------------+---------------+
+ *
+ * efuse layout 0x44-0x4B (caldata[4..7]):
+ * caldata[4] caldata[5] caldata[6] caldata[7]
+ * 0 12 16 24 32 36 48 64
+ * +---------------+---------------+---------------+---------------+
+ * | ths1_2 | ths1_3 | ths0 | | +
+ * +---------------+---------------+---------------+---------------+
+ */
+static int sun55i_a523_ths_calibrate(struct ths_device *tmdev,
+ u16 *caldata, int callen)
+{
+ struct device *dev = tmdev->dev;
+ int i, ft_temp;
+
+ if (!caldata[0])
+ return -EINVAL;
+
+ ft_temp = (((caldata[2] << 8) | (caldata[1] >> 8)) & FT_TEMP_MASK) * 100;
+
+ for (i = 0; i < tmdev->chip->sensor_num; i++) {
+ int sensor_reg, sensor_temp, cdata, offset;
+ /*
+ * Chips ths0 and ths1 have common parameters for value
+ * calibration. To separate them we can use the number of
+ * temperature sensors on each chip.
+ * For ths0 this value is 1.
+ */
+ if (tmdev->chip->sensor_num == 1) {
+ sensor_reg = ((caldata[5] >> 8) | (caldata[6] << 8)) & TEMP_CALIB_MASK;
+ } else {
+ switch (i) {
+ case 0:
+ sensor_reg = (caldata[2] >> 4) & TEMP_CALIB_MASK;
+ break;
+ case 1:
+ sensor_reg = caldata[3] & TEMP_CALIB_MASK;
+ break;
+ case 2:
+ sensor_reg = caldata[4] & TEMP_CALIB_MASK;
+ break;
+ default:
+ sensor_reg = 0;
+ break;
+ }
+ }
+
+ sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg);
+
+ /*
+ * Calibration data is CALIBRATE_DEFAULT - (calculated
+ * temperature from sensor reading at factory temperature
+ * minus actual factory temperature) * X (scale from
+ * temperature to register values)
+ */
+ cdata = CALIBRATE_DEFAULT -
+ ((sensor_temp - ft_temp) / SUN55I_A523_SCALE_ABOVE);
+
+ if (cdata & ~TEMP_CALIB_MASK) {
+ /*
+ * Calibration value more than 12-bit, but calibration
+ * register is 12-bit. In this case, ths hardware can
+ * still work without calibration, although the data
+ * won't be so accurate.
+ */
+ dev_warn(dev, "sensor%d is not calibrated.\n", i);
+ continue;
+ }
+
+ offset = (i % 2) * 16;
+ regmap_update_bits(tmdev->regmap,
+ SUN50I_H6_THS_TEMP_CALIB + (i / 2 * 4),
+ TEMP_CALIB_MASK << offset,
+ cdata << offset);
+ }
+
+ return 0;
+}
+
static int sun8i_ths_calibrate(struct ths_device *tmdev)
{
struct nvmem_cell *calcell = NULL;
@@ -730,6 +836,31 @@ static const struct ths_thermal_chip sun50i_h616_ths = {
.calc_temp = sun8i_ths_calc_temp,
};
+/* The A523 has a shared reset line for both chips */
+static const struct ths_thermal_chip sun55i_a523_ths0 = {
+ .sensor_num = 1,
+ .has_bus_clk_reset = true,
+ .has_gpadc_clk = true,
+ .ft_deviation = 5000,
+ .temp_data_base = SUN50I_H6_THS_TEMP_DATA,
+ .calibrate = sun55i_a523_ths_calibrate,
+ .init = sun50i_h6_thermal_init,
+ .irq_ack = sun50i_h6_irq_ack,
+ .calc_temp = sun55i_a523_calc_temp,
+};
+
+static const struct ths_thermal_chip sun55i_a523_ths1 = {
+ .sensor_num = 3,
+ .has_bus_clk_reset = true,
+ .has_gpadc_clk = true,
+ .ft_deviation = 5000,
+ .temp_data_base = SUN50I_H6_THS_TEMP_DATA,
+ .calibrate = sun55i_a523_ths_calibrate,
+ .init = sun50i_h6_thermal_init,
+ .irq_ack = sun50i_h6_irq_ack,
+ .calc_temp = sun55i_a523_calc_temp,
+};
+
static const struct of_device_id of_ths_match[] = {
{ .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths },
{ .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths },
@@ -740,6 +871,8 @@ static const struct of_device_id of_ths_match[] = {
{ .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths },
{ .compatible = "allwinner,sun20i-d1-ths", .data = &sun20i_d1_ths },
{ .compatible = "allwinner,sun50i-h616-ths", .data = &sun50i_h616_ths },
+ { .compatible = "allwinner,sun55i-a523-ths0", .data = &sun55i_a523_ths0 },
+ { .compatible = "allwinner,sun55i-a523-ths1", .data = &sun55i_a523_ths1 },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, of_ths_match);
From 74804cbc70cbd2aa933b3b9144bc9ed7115a14c5 Mon Sep 17 00:00:00 2001
From: Mikhail Kalashnikov <iuncuim@gmail.com>
Date: Fri, 07 Nov 2025 12:46:30 -0000
Subject: [PATCH 6/X] auto-split from bundle
The A523 processor has two temperature controllers, THS0 and THS1.
THS0 has only one temperature sensor, which is located in the DRAM.
THS1 does have 3 sensors:
ths1_0 - "big" cores
ths1_1 - "little" cores
ths1_2 - gpu
Add the thermal sensor configuration and the thermal zones.
Trips temperature, polling-delay and sustainable-power parameters are
derived from the manufacturer's BSP.
Signed-off-by: Mikhail Kalashnikov <iuncuim@gmail.com>
---
.../arm64/boot/dts/allwinner/sun55i-a523.dtsi | 154 ++++++++++++++++++
1 file changed, 154 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
index 7b36c47a3..0cbe73601 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi
@@ -11,6 +11,7 @@
#include <dt-bindings/reset/sun55i-a523-r-ccu.h>
#include <dt-bindings/power/allwinner,sun55i-a523-ppu.h>
#include <dt-bindings/power/allwinner,sun55i-a523-pck-600.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
interrupt-parent = <&gic>;
@@ -26,6 +27,7 @@ cpu0: cpu@0 {
device_type = "cpu";
reg = <0x000>;
enable-method = "psci";
+ #cooling-cells = <2>;
};
cpu1: cpu@100 {
@@ -33,6 +35,7 @@ cpu1: cpu@100 {
device_type = "cpu";
reg = <0x100>;
enable-method = "psci";
+ #cooling-cells = <2>;
};
cpu2: cpu@200 {
@@ -40,6 +43,7 @@ cpu2: cpu@200 {
device_type = "cpu";
reg = <0x200>;
enable-method = "psci";
+ #cooling-cells = <2>;
};
cpu3: cpu@300 {
@@ -47,6 +51,7 @@ cpu3: cpu@300 {
device_type = "cpu";
reg = <0x300>;
enable-method = "psci";
+ #cooling-cells = <2>;
};
cpu4: cpu@400 {
@@ -54,6 +59,7 @@ cpu4: cpu@400 {
device_type = "cpu";
reg = <0x400>;
enable-method = "psci";
+ #cooling-cells = <2>;
};
cpu5: cpu@500 {
@@ -61,6 +67,7 @@ cpu5: cpu@500 {
device_type = "cpu";
reg = <0x500>;
enable-method = "psci";
+ #cooling-cells = <2>;
};
cpu6: cpu@600 {
@@ -68,6 +75,7 @@ cpu6: cpu@600 {
device_type = "cpu";
reg = <0x600>;
enable-method = "psci";
+ #cooling-cells = <2>;
};
cpu7: cpu@700 {
@@ -75,6 +83,7 @@ cpu7: cpu@700 {
device_type = "cpu";
reg = <0x700>;
enable-method = "psci";
+ #cooling-cells = <2>;
};
};
@@ -398,12 +407,46 @@ syscon: syscon@3000000 {
ranges;
};
+ ths1: thermal-sensor@2009400 {
+ compatible = "allwinner,sun55i-a523-ths1";
+ reg = <0x02009400 0x400>;
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_GPADC1>;
+ clock-names = "bus", "gpadc";
+ resets = <&ccu RST_BUS_THS>;
+ nvmem-cells = <&ths_calibration0>, <&ths_calibration1>;
+ nvmem-cell-names = "calibration",
+ "calibration-second-part";
+ #thermal-sensor-cells = <1>;
+ };
+
+ ths0: thermal-sensor@200a000 {
+ compatible = "allwinner,sun55i-a523-ths0";
+ reg = <0x0200a000 0x400>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_GPADC0>;
+ clock-names = "bus", "gpadc";
+ resets = <&ccu RST_BUS_THS>;
+ nvmem-cells = <&ths_calibration0>, <&ths_calibration1>;
+ nvmem-cell-names = "calibration",
+ "calibration-second-part";
+ #thermal-sensor-cells = <0>;
+ };
+
sid: efuse@3006000 {
compatible = "allwinner,sun55i-a523-sid",
"allwinner,sun50i-a64-sid";
reg = <0x03006000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
+
+ ths_calibration0: ths-calibration0@38 {
+ reg = <0x38 0x8>;
+ };
+
+ ths_calibration1: ths-calibration1@44 {
+ reg = <0x44 0x8>;
+ };
};
gic: interrupt-controller@3400000 {
@@ -732,4 +775,115 @@ npu: npu@7122000 {
power-domains = <&ppu PD_NPU>;
};
};
+
+ thermal-zones {
+ cpu0_thermal: cpu0-thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths1 1>;
+ sustainable-power = <1200>;
+
+ trips {
+ cpu0_threshold: cpu-trip-0 {
+ temperature = <70000>;
+ type = "passive";
+ hysteresis = <0>;
+ };
+ cpu0_target: cpu-trip-1 {
+ temperature = <90000>;
+ type = "passive";
+ hysteresis = <0>;
+ };
+ cpu0_critical: cpu-trip-2 {
+ temperature = <110000>;
+ type = "critical";
+ hysteresis = <0>;
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu0_target>;
+ cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ cpu4_thermal: cpu4-thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths1 0>;
+ sustainable-power = <1600>;
+
+ trips {
+ cpu4_threshold: cpu-trip-0 {
+ temperature = <70000>;
+ type = "passive";
+ hysteresis = <0>;
+ };
+ cpu4_target: cpu-trip-1 {
+ temperature = <90000>;
+ type = "passive";
+ hysteresis = <0>;
+ };
+ cpu4_critical: cpu-trip-2 {
+ temperature = <110000>;
+ type = "critical";
+ hysteresis = <0>;
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu4_target>;
+ cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+ };
+
+ gpu-thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths1 2>;
+ sustainable-power = <2400>;
+
+ gpu-trips {
+ gpu_temp_threshold: gpu-trip-0 {
+ temperature = <60000>;
+ type = "passive";
+ hysteresis = <0>;
+ };
+ gpu_temp_target: gpu-trip-1 {
+ temperature = <90000>;
+ type = "passive";
+ hysteresis = <0>;
+ };
+ gpu_temp_critical: gpu-trip-2 {
+ temperature = <110000>;
+ type = "critical";
+ hysteresis = <0>;
+ };
+ };
+ };
+
+ ddr-thermal {
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ thermal-sensors = <&ths0>;
+
+ trips {
+ ddr_temp_critical: ddr-trip-0 {
+ temperature = <110000>;
+ type = "critical";
+ hysteresis = <0>;
+ };
+ };
+ };
+ };
};

View File

@ -0,0 +1,78 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Juan Sanchez <juanesf91@gmail.com>
Date: Fri, 4 Jul 2025 15:17:54 -0400
Subject: Add wifi (mmc1) to Radxa Cubie A5E
Signed-off-by: Juan Sanchez <juanesf91@gmail.com>
---
arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts | 28 ++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
index 1c56306dffa1..d9bbfb916090 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
@@ -12,10 +12,11 @@ / {
compatible = "radxa,cubie-a5e", "allwinner,sun55i-a527";
aliases {
ethernet0 = &gmac0;
ethernet1 = &gmac1;
+ ethernet2 = &sdio_wifi;
serial0 = &uart0;
};
chosen {
stdout-path = "serial0:115200n8";
@@ -41,10 +42,20 @@ iio-hwmon {
compatible = "iio-hwmon";
io-channels = <&axp717_adc 3>, /* vsys_v */
<&axp717_adc 4>; /* pmic_temp */
};
+ reg_3v3_wifi: 3v3-wifi {
+ compatible = "regulator-fixed";
+ regulator-name = "3v3-wifi";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&reg_vcc5v>;
+ gpio = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
+ enable-active-high;
+ };
+
reg_vcc5v: vcc5v {
/* board wide 5V supply from the USB-C connector */
compatible = "regulator-fixed";
regulator-name = "vcc-5v";
regulator-min-microvolt = <5000000>;
@@ -94,10 +105,27 @@ &mmc0 {
cd-gpios = <&pio 5 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; /* PF6 */
bus-width = <4>;
status = "okay";
};
+&mmc1_pins {
+ drive-strength = <40>;
+};
+
+&mmc1 {
+ bus-width = <4>;
+ vmmc-supply = <&reg_3v3_wifi>;
+ non-removable;
+ // todo: investigate why clock above 40MHz makes data errors
+ max-frequency = <35000000>;
+ status = "okay";
+
+ sdio_wifi: wifi@1 {
+ reg = <1>;
+ };
+};
+
&ohci0 {
status = "okay";
};
&ohci1 {
--
Created with Armbian build tools https://github.com/armbian/build

View File

@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Juan Sanchez <juanesf91@gmail.com>
Date: Tue, 5 Aug 2025 14:55:52 -0400
Subject: Enable uart1 (bluetooth) on Radxa Cubie A5E
Signed-off-by: Juan Sanchez <juanesf91@gmail.com>
---
arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
index 369bde1556ff..37585cac6648 100644
--- a/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
+++ b/arch/arm64/boot/dts/allwinner/sun55i-a527-cubie-a5e.dts
@@ -14,10 +14,11 @@ / {
aliases {
ethernet0 = &gmac0;
ethernet1 = &gmac1;
ethernet2 = &sdio_wifi;
serial0 = &uart0;
+ serial1 = &uart1;
};
chosen {
stdout-path = "serial0:115200n8";
};
@@ -360,10 +361,18 @@ &uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pb_pins>;
status = "okay";
};
+/* Bluetooth */
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>;
+ uart-has-rtscts;
+ status = "okay";
+};
+
&usb_otg {
/*
* The USB-C port is the primary power supply, so in this configuration
* relies on the other end of the USB cable to supply the VBUS power.
* So use this port in peripheral mode.
--
Created with Armbian build tools https://github.com/armbian/build

View File

@ -109,7 +109,7 @@
patches.megous/ebaz4205-6.18/0002-dt-bindings-Add-Zynq-clocks.patch
patches.megous/ebaz4205-6.18/0003-arm-xilinx-ebaz4205-Add-test-config-for-various-PL-p.patch
patches.megous/err-6.18/0001-sunxi-Use-dev_err_probe-to-handle-EPROBE_DEFER-error.patch
patches.megous/err-6.18/0002-thermal-sun8i-Be-loud-when-probe-fails.patch
- patches.megous/err-6.18/0002-thermal-sun8i-Be-loud-when-probe-fails.patch
patches.megous/err-6.18/0003-i2c-mv64xxx-Don-t-make-a-fuss-when-pinctrl-recovery-.patch
patches.megous/err-6.18/0004-iio-st_sensors-Don-t-report-error-when-the-device-is.patch
patches.megous/err-6.18/0005-opp-core-Avoid-confusing-error-when-no-regulator-is-.patch
@ -392,6 +392,20 @@
patches.backports/0001-dt-bindings-dma-allwinner-sun50i-a64-dma-Add-compati.patch
patches.backports/0001-arm64-dts-allwinner-a527-cubie-a5e-Enable-second-Eth.patch
################################################################################
#
# Port from https://github.com/armbian/build/pull/8831
#
################################################################################
patches.backports/05-dt-bindings-mfd-x-powers-axp152-Add-polyphased-prope.patch
patches.backports/06-mfd-axp20x-Refactor-axp20x_is_polyphase_slave.patch
patches.backports/07-mfd-axp20x-Allow-programming-dual-phase-regulator-pa.patch
patches.backports/08-mfd-axp20x-Support-tri-phase-setup.patch
patches.backports/09-arm64-dts-allwinner-a523-Mark-dual-phased-regulators.patch
patches.backports/10-Allwinner-A523-add-support-for-A523-THS0-1-controllers.patch
patches.backports/20-Add-wifi-to-Radxa-Cubie-A5E.patch
patches.backports/21-Enable-uart1-on-Radxa-Cubie-A5E.patch
################################################################################
#
@ -571,4 +585,4 @@
patches.armbian/arm64-allwinner-Add-sun50i-h618-bananapi-m4-berry-support.patch
patches.armbian/h616-add-keys.patch
patches.armbian/sun50i-h616-Add-the-missing-digital-audio-node.patch
patches.armbian/drv-spi-spidev-Add-armbian-spi-dev-compatible.patch
patches.armbian/drv-spi-spidev-Add-armbian-spi-dev-compatible.patch