From 430d9ab41ba0fc80947bd4a27428c1ec77f24fdc Mon Sep 17 00:00:00 2001 From: EvilOlaf Date: Mon, 22 Dec 2025 04:54:14 +0000 Subject: [PATCH] Port patches from PR #8831 --- ...x-powers-axp152-Add-polyphased-prope.patch | 64 ++ ...x-Refactor-axp20x_is_polyphase_slave.patch | 148 ++++ ...-programming-dual-phase-regulator-pa.patch | 120 +++ ...8-mfd-axp20x-Support-tri-phase-setup.patch | 93 ++ ...ner-a523-Mark-dual-phased-regulators.patch | 97 +++ ...-support-for-A523-THS0-1-controllers.patch | 803 ++++++++++++++++++ .../20-Add-wifi-to-Radxa-Cubie-A5E.patch | 78 ++ .../21-Enable-uart1-on-Radxa-Cubie-A5E.patch | 48 ++ patch/kernel/archive/sunxi-6.18/series.conf | 18 +- 9 files changed, 1467 insertions(+), 2 deletions(-) create mode 100644 patch/kernel/archive/sunxi-6.18/patches.backports/05-dt-bindings-mfd-x-powers-axp152-Add-polyphased-prope.patch create mode 100644 patch/kernel/archive/sunxi-6.18/patches.backports/06-mfd-axp20x-Refactor-axp20x_is_polyphase_slave.patch create mode 100644 patch/kernel/archive/sunxi-6.18/patches.backports/07-mfd-axp20x-Allow-programming-dual-phase-regulator-pa.patch create mode 100644 patch/kernel/archive/sunxi-6.18/patches.backports/08-mfd-axp20x-Support-tri-phase-setup.patch create mode 100644 patch/kernel/archive/sunxi-6.18/patches.backports/09-arm64-dts-allwinner-a523-Mark-dual-phased-regulators.patch create mode 100644 patch/kernel/archive/sunxi-6.18/patches.backports/10-Allwinner-A523-add-support-for-A523-THS0-1-controllers.patch create mode 100644 patch/kernel/archive/sunxi-6.18/patches.backports/20-Add-wifi-to-Radxa-Cubie-A5E.patch create mode 100644 patch/kernel/archive/sunxi-6.18/patches.backports/21-Enable-uart1-on-Radxa-Cubie-A5E.patch diff --git a/patch/kernel/archive/sunxi-6.18/patches.backports/05-dt-bindings-mfd-x-powers-axp152-Add-polyphased-prope.patch b/patch/kernel/archive/sunxi-6.18/patches.backports/05-dt-bindings-mfd-x-powers-axp152-Add-polyphased-prope.patch new file mode 100644 index 000000000..a9ee81c60 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.18/patches.backports/05-dt-bindings-mfd-x-powers-axp152-Add-polyphased-prope.patch @@ -0,0 +1,64 @@ +From 72286070835a37fe74b630f36a8b5c56ad26b89d Mon Sep 17 00:00:00 2001 +From: Andre Przywara +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 +--- + .../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 = <®_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 + diff --git a/patch/kernel/archive/sunxi-6.18/patches.backports/06-mfd-axp20x-Refactor-axp20x_is_polyphase_slave.patch b/patch/kernel/archive/sunxi-6.18/patches.backports/06-mfd-axp20x-Refactor-axp20x_is_polyphase_slave.patch new file mode 100644 index 000000000..39080cc23 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.18/patches.backports/06-mfd-axp20x-Refactor-axp20x_is_polyphase_slave.patch @@ -0,0 +1,148 @@ +From 0cb44fa029c3a41b769ebbd7e4044682cad9a685 Mon Sep 17 00:00:00 2001 +From: Andre Przywara +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 +--- + 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, ®); ++ 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, ®); ++ ++ 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, ®); +- +- 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, ®); +- +- 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, ®); +- +- switch (id) { +- case AXP313A_DCDC2: +- return !!(reg & BIT(1)); +- } +- break; +- +- default: +- return false; + } + + return false; +-- +2.43.0 + diff --git a/patch/kernel/archive/sunxi-6.18/patches.backports/07-mfd-axp20x-Allow-programming-dual-phase-regulator-pa.patch b/patch/kernel/archive/sunxi-6.18/patches.backports/07-mfd-axp20x-Allow-programming-dual-phase-regulator-pa.patch new file mode 100644 index 000000000..30221455c --- /dev/null +++ b/patch/kernel/archive/sunxi-6.18/patches.backports/07-mfd-axp20x-Allow-programming-dual-phase-regulator-pa.patch @@ -0,0 +1,120 @@ +From d8f1a6d20eef731149c58b1847696425fdd56f83 Mon Sep 17 00:00:00 2001 +From: Andre Przywara +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 +--- + 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 + diff --git a/patch/kernel/archive/sunxi-6.18/patches.backports/08-mfd-axp20x-Support-tri-phase-setup.patch b/patch/kernel/archive/sunxi-6.18/patches.backports/08-mfd-axp20x-Support-tri-phase-setup.patch new file mode 100644 index 000000000..0645aadab --- /dev/null +++ b/patch/kernel/archive/sunxi-6.18/patches.backports/08-mfd-axp20x-Support-tri-phase-setup.patch @@ -0,0 +1,93 @@ +From 008942ec8d1bd6615e71765d1ef2679642515fa4 Mon Sep 17 00:00:00 2001 +From: Andre Przywara +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 +--- + 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 + diff --git a/patch/kernel/archive/sunxi-6.18/patches.backports/09-arm64-dts-allwinner-a523-Mark-dual-phased-regulators.patch b/patch/kernel/archive/sunxi-6.18/patches.backports/09-arm64-dts-allwinner-a523-Mark-dual-phased-regulators.patch new file mode 100644 index 000000000..405be1245 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.18/patches.backports/09-arm64-dts-allwinner-a523-Mark-dual-phased-regulators.patch @@ -0,0 +1,97 @@ +From 87274e8d73915412aa8b0fcefa27a1c0e982c975 Mon Sep 17 00:00:00 2001 +From: Andre Przywara +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 +--- + 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 = <®_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 = <®_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 = <®_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 = <®_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 + diff --git a/patch/kernel/archive/sunxi-6.18/patches.backports/10-Allwinner-A523-add-support-for-A523-THS0-1-controllers.patch b/patch/kernel/archive/sunxi-6.18/patches.backports/10-Allwinner-A523-add-support-for-A523-THS0-1-controllers.patch new file mode 100644 index 000000000..b8d032c5e --- /dev/null +++ b/patch/kernel/archive/sunxi-6.18/patches.backports/10-Allwinner-A523-add-support-for-A523-THS0-1-controllers.patch @@ -0,0 +1,803 @@ +From 8476f1b10b6acc327455c840d3f89a56ec6dedea Mon Sep 17 00:00:00 2001 +From: Mikhail Kalashnikov +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 +--- + .../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 = ; ++ 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 +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 +Reviewed-by: Chen-Yu Tsai +--- + 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 +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 +Reviewed-by: Chen-Yu Tsai +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + .../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 + #include + #include ++#include + + / { + 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 = ; ++ 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 = ; ++ 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>; ++ }; ++ }; ++ }; ++ }; + }; diff --git a/patch/kernel/archive/sunxi-6.18/patches.backports/20-Add-wifi-to-Radxa-Cubie-A5E.patch b/patch/kernel/archive/sunxi-6.18/patches.backports/20-Add-wifi-to-Radxa-Cubie-A5E.patch new file mode 100644 index 000000000..0e7dc3105 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.18/patches.backports/20-Add-wifi-to-Radxa-Cubie-A5E.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Juan Sanchez +Date: Fri, 4 Jul 2025 15:17:54 -0400 +Subject: Add wifi (mmc1) to Radxa Cubie A5E + +Signed-off-by: Juan Sanchez +--- + 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 = <®_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 = <®_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 + diff --git a/patch/kernel/archive/sunxi-6.18/patches.backports/21-Enable-uart1-on-Radxa-Cubie-A5E.patch b/patch/kernel/archive/sunxi-6.18/patches.backports/21-Enable-uart1-on-Radxa-Cubie-A5E.patch new file mode 100644 index 000000000..ef8377636 --- /dev/null +++ b/patch/kernel/archive/sunxi-6.18/patches.backports/21-Enable-uart1-on-Radxa-Cubie-A5E.patch @@ -0,0 +1,48 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Juan Sanchez +Date: Tue, 5 Aug 2025 14:55:52 -0400 +Subject: Enable uart1 (bluetooth) on Radxa Cubie A5E + +Signed-off-by: Juan Sanchez +--- + 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 + diff --git a/patch/kernel/archive/sunxi-6.18/series.conf b/patch/kernel/archive/sunxi-6.18/series.conf index 822202a4f..26e8db69c 100644 --- a/patch/kernel/archive/sunxi-6.18/series.conf +++ b/patch/kernel/archive/sunxi-6.18/series.conf @@ -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 \ No newline at end of file + patches.armbian/drv-spi-spidev-Add-armbian-spi-dev-compatible.patch