* [PATCH 1/6] dt-bindings: opp: h6: Add A133 operating points
2026-11-05 4:40 [PATCH 0/6] sunxi: A133: Add CPU speed grade detection and OPP table Rajan Yadav via B4 Relay
@ 2026-11-05 4:40 ` Rajan Yadav via B4 Relay
2026-11-05 4:40 ` [PATCH 2/6] cpufreq: sun50i: Move nvmem cell reading into a helper Rajan Yadav via B4 Relay
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rajan Yadav via B4 Relay @ 2026-11-05 4:40 UTC (permalink / raw)
To: Yangtao Li, Viresh Kumar, Nishanth Menon, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland, Maxime Ripard, Rafael J. Wysocki,
Viresh Kumar, Andre Przywara
Cc: linux-pm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel, Cody Eksal, Alexander Sverdlin, Rajan Yadav
From: Rajan Yadav <rajanyadav0307@gmail.com>
The vendor BSP for the A100/A133 family (sun50iw10) selects the CPU
speed grade from four efuse fields and the die revision: the speed bin
(SID offset 0x1c, which also holds the ICPU current), the chip marking
ID (0x00), a value programmed at production that the BSP calls PCPU
(0x20) and a bin extension bit (0x28). It knows 11 grades, a0-a6 and
b0-b3. The A100 operating points describe only three speed bins, taken
from 0x1c.
Add allwinner,sun50i-a133-operating-points for this. In its tables the
N of opp-microvolt-speedN is the vendor grade: 0-5 are a0-a5 (a6 has
the same OPPs and voltages as a5) and 6-9 are b0-b3. The four cells are
named, with the speed bin first. The meaning of the PCPU field is not
documented; the name follows the vendor BSP.
Indices 0-2 are the vendor grades a0-a2, which have the voltages of the
three A100 speed bins. So allwinner,sun50i-a100-operating-points is a
valid fallback: software that knows only the A100 compatible reads the
first cell, selects one of speed0-2 with the A100 rule and gets the
OPPs and voltages of the A100 table today, with 1008 instead of
1080 MHz. That is the A100 selection, not the vendor's; the new
compatible adds the vendor's. The binding requires indices 0-2 to stay
usable this way.
The new compatible is SoC specific, like the root compatible
allwinner,sun50i-a133; the A100 compatible stays as it is for existing
DTBs. The schema now also limits the other compatibles to the single
unnamed cell that all in-tree users have.
Claude Code (Anthropic) drafted this change and its message from the
vendor BSP sources (field layout and numbers only, no code copied); I
reviewed it and checked it with dt_binding_check and dtbs_check.
Signed-off-by: Rajan Yadav <rajanyadav0307@gmail.com>
---
.../opp/allwinner,sun50i-h6-operating-points.yaml | 94 ++++++++++++++++++++--
1 file changed, 86 insertions(+), 8 deletions(-)
diff --git a/Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml b/Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml
index 75ab552f6ec..5fa6a1074da 100644
--- a/Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml
+++ b/Documentation/devicetree/bindings/opp/allwinner,sun50i-h6-operating-points.yaml
@@ -16,24 +16,70 @@ description: |
Voltage Scaling Tables define the voltage and frequency values based
on the speedbin blown in the efuse combination.
+ With allwinner,sun50i-a133-operating-points, the speed bin index N of
+ opp-microvolt-speedN and opp-supported-hw is the speed grade of the
+ Allwinner BSP: 0-5 are a0-a5 (a6 uses the a5 values) and 6-9 are b0-b3.
+ Indices 0-2 must be usable as the A100 speed bins 0-2, because software
+ using the A100 fallback compatible selects only these.
+
allOf:
- $ref: opp-v2-base.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: allwinner,sun50i-a133-operating-points
+ then:
+ properties:
+ nvmem-cells:
+ minItems: 4
+ required:
+ - nvmem-cell-names
+ else:
+ properties:
+ nvmem-cells:
+ maxItems: 1
+ nvmem-cell-names: false
properties:
compatible:
- enum:
- - allwinner,sun50i-a100-operating-points
- - allwinner,sun50i-h6-operating-points
- - allwinner,sun50i-h616-operating-points
+ oneOf:
+ - enum:
+ - allwinner,sun50i-a100-operating-points
+ - allwinner,sun50i-h6-operating-points
+ - allwinner,sun50i-h616-operating-points
+ - items:
+ - const: allwinner,sun50i-a133-operating-points
+ - const: allwinner,sun50i-a100-operating-points
nvmem-cells:
description: |
- A phandle pointing to a nvmem-cells node representing the efuse
- register that has information about the speedbin that is used
- to select the right frequency/voltage value pair. Please refer
- to the nvmem-cells bindings in
+ Phandles pointing to nvmem-cells nodes representing the efuse
+ registers that have information about the speedbin that is used
+ to select the right frequency/voltage value pair. Please refer to
+ the nvmem-cells bindings in
Documentation/devicetree/bindings/nvmem/nvmem.yaml and also the
examples below.
+ minItems: 1
+ items:
+ - description:
+ Speed bin, or the chip marking ID on the H616. With the A133
+ compatible, bits 15:12 are the CPU bin and bits 11:0 the ICPU
+ current in units of 0.1 mA.
+ - description: Chip marking ID.
+ - description:
+ Value programmed at production, called PCPU by Allwinner. Bits
+ 11:0 are used together with the ICPU current to select the speed
+ grade; their unit is not documented.
+ - description:
+ Bin extension. Bit 31 is used to select the speed grade.
+
+ nvmem-cell-names:
+ items:
+ - const: bin
+ - const: marking
+ - const: pcpu
+ - const: bin-ext
opp-shared: true
@@ -132,4 +178,36 @@ examples:
};
};
+ - |
+ opp-table {
+ compatible = "allwinner,sun50i-a133-operating-points",
+ "allwinner,sun50i-a100-operating-points";
+ nvmem-cells = <&cpu_speed_grade>, <&chip_marking>,
+ <&cpu_pcpu>, <&cpu_bin_ext>;
+ nvmem-cell-names = "bin", "marking", "pcpu", "bin-ext";
+ opp-shared;
+
+ opp-408000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <408000000>;
+
+ opp-microvolt-speed0 = <900000>;
+ opp-microvolt-speed1 = <900000>;
+ opp-microvolt-speed2 = <900000>;
+ opp-microvolt-speed8 = <940000>;
+ opp-supported-hw = <0x107>;
+ };
+
+ opp-1512000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1512000000>;
+
+ opp-microvolt-speed6 = <1180000>;
+ opp-microvolt-speed7 = <1130000 1130000 1140000>;
+ opp-microvolt-speed8 = <1100000>;
+ opp-microvolt-speed9 = <1080000>;
+ opp-supported-hw = <0x3c0>;
+ };
+ };
+
...
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 2/6] cpufreq: sun50i: Move nvmem cell reading into a helper
2026-11-05 4:40 [PATCH 0/6] sunxi: A133: Add CPU speed grade detection and OPP table Rajan Yadav via B4 Relay
2026-11-05 4:40 ` [PATCH 1/6] dt-bindings: opp: h6: Add A133 operating points Rajan Yadav via B4 Relay
@ 2026-11-05 4:40 ` Rajan Yadav via B4 Relay
2026-11-05 4:40 ` [PATCH 3/6] cpufreq: sun50i: Add A133 speed grade detection Rajan Yadav via B4 Relay
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rajan Yadav via B4 Relay @ 2026-11-05 4:40 UTC (permalink / raw)
To: Yangtao Li, Viresh Kumar, Nishanth Menon, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland, Maxime Ripard, Rafael J. Wysocki,
Viresh Kumar, Andre Przywara
Cc: linux-pm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel, Cody Eksal, Alexander Sverdlin, kernel test robot,
Rajan Yadav
From: Rajan Yadav <rajanyadav0307@gmail.com>
The A133 speed grade needs several efuse cells, but the cell reading
is open coded in sun50i_cpufreq_get_efuse() for a single cell. Move it
into sun50i_cpufreq_read_cell(), which takes the cell name, so the next
patch can read the A133 cells by name.
No functional change: the existing users read the first cell, as
before, with the same length check, byte order and error message. The
raw bytes are now held in a __le32, the type le32_to_cpu() expects,
which also removes the sparse warning "cast to restricted __le32" that
the kernel test robot reported.
Claude Code (Anthropic) drafted this refactor and its message; I
reviewed and tested it.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202603021703.aBD0w99y-lkp@intel.com/
Signed-off-by: Rajan Yadav <rajanyadav0307@gmail.com>
---
drivers/cpufreq/sun50i-cpufreq-nvmem.c | 55 ++++++++++++++++++++--------------
1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
index 9261d148a16..34c0897c22c 100644
--- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
@@ -31,6 +31,34 @@ struct sunxi_cpufreq_data {
u32 (*efuse_xlate)(u32 speedbin);
};
+static int sun50i_cpufreq_read_cell(struct device *cpu_dev,
+ struct device_node *np, const char *id,
+ u32 *value)
+{
+ struct nvmem_cell *cell;
+ void *buf;
+ size_t len;
+ __le32 tmp = 0;
+
+ cell = of_nvmem_cell_get(np, id);
+ if (IS_ERR(cell))
+ return dev_err_probe(cpu_dev, PTR_ERR(cell),
+ "Could not get nvmem cell\n");
+
+ buf = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ if (len <= 4)
+ memcpy(&tmp, buf, len);
+ *value = le32_to_cpu(tmp);
+
+ kfree(buf);
+
+ return 0;
+}
+
static u32 sun50i_h6_efuse_xlate(u32 speedbin)
{
u32 efuse_value;
@@ -191,12 +219,9 @@ static bool dt_has_supported_hw(void)
static int sun50i_cpufreq_get_efuse(void)
{
const struct sunxi_cpufreq_data *opp_data;
- struct nvmem_cell *speedbin_nvmem;
const struct of_device_id *match;
struct device *cpu_dev;
- void *speedbin_ptr;
- u32 speedbin = 0;
- size_t len;
+ u32 speedbin;
int ret;
cpu_dev = get_cpu_device(0);
@@ -214,25 +239,11 @@ static int sun50i_cpufreq_get_efuse(void)
opp_data = match->data;
- speedbin_nvmem = of_nvmem_cell_get(np, NULL);
- if (IS_ERR(speedbin_nvmem))
- return dev_err_probe(cpu_dev, PTR_ERR(speedbin_nvmem),
- "Could not get nvmem cell\n");
-
- speedbin_ptr = nvmem_cell_read(speedbin_nvmem, &len);
- nvmem_cell_put(speedbin_nvmem);
- if (IS_ERR(speedbin_ptr))
- return PTR_ERR(speedbin_ptr);
-
- if (len <= 4)
- memcpy(&speedbin, speedbin_ptr, len);
- speedbin = le32_to_cpu(speedbin);
-
- ret = opp_data->efuse_xlate(speedbin);
-
- kfree(speedbin_ptr);
+ ret = sun50i_cpufreq_read_cell(cpu_dev, np, NULL, &speedbin);
+ if (ret)
+ return ret;
- return ret;
+ return opp_data->efuse_xlate(speedbin);
};
static int sun50i_cpufreq_nvmem_probe(struct platform_device *pdev)
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 3/6] cpufreq: sun50i: Add A133 speed grade detection
2026-11-05 4:40 [PATCH 0/6] sunxi: A133: Add CPU speed grade detection and OPP table Rajan Yadav via B4 Relay
2026-11-05 4:40 ` [PATCH 1/6] dt-bindings: opp: h6: Add A133 operating points Rajan Yadav via B4 Relay
2026-11-05 4:40 ` [PATCH 2/6] cpufreq: sun50i: Move nvmem cell reading into a helper Rajan Yadav via B4 Relay
@ 2026-11-05 4:40 ` Rajan Yadav via B4 Relay
2026-11-05 4:40 ` [PATCH 4/6] arm64: dts: allwinner: a100: Add A133 speed grade efuse cells Rajan Yadav via B4 Relay
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rajan Yadav via B4 Relay @ 2026-11-05 4:40 UTC (permalink / raw)
To: Yangtao Li, Viresh Kumar, Nishanth Menon, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland, Maxime Ripard, Rafael J. Wysocki,
Viresh Kumar, Andre Przywara
Cc: linux-pm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel, Cody Eksal, Alexander Sverdlin, Rajan Yadav
From: Rajan Yadav <rajanyadav0307@gmail.com>
The A133 is handled as an A100 today: only the CPU bin field at SID
offset 0x1c is read, which gives one of three A100 voltage tables.
The vendor BSP for this family (sun50iw10) selects one of 11 grades
from the chip marking ID, the CPU bin, the ICPU current, the PCPU
field, a bin extension bit and the die revision:
- "high speed" marking IDs use the b0-b3 grades, which have 1416 and
1512 MHz instead of 1464 MHz
- the other parts use a0-a6
- die revisions 0, 3 and 4 ("A-E") use different grades from all other
revisions ("F and later")
- revision A-E normal parts with ICPU and PCPU within fixed ranges use
a0
On a KickPi K5C (A133, marking 0x1400, bin 0b010, revision 6), the BSP
selects b2: 408-1512 MHz with 1.10 V at 1512 MHz. Mainline selects the
A100 speed1 table instead. So the chip runs 40 mV below the vendor
voltage at 408-816 MHz and 40 mV above it at 1200 and 1320 MHz, and its
top OPP is 1464 MHz at 1.18 V instead of 1512 MHz at 1.10 V. Grades
with 1416 and 1512 MHz cannot be described at all.
Add the vendor selection for the new A133 OPP compatible. a5 and a6
share their voltages, so the 11 grades map to speed0-9:
index: 0 1 2 3 4 5 6 7 8 9
vendor: a0 a1 a2 a3 a4 a5/a6 b0 b1 b2 b3
The die revision comes from SMCCC SOC_ID, as for the H616. On the A133
this needs TF-A with the sun50i_a133 platform, added in commit
a584e8632a7a ("feat(allwinner): add support for allwinner A133 SoC")
and not yet in a release; it reads the same SYSCON register as the
BSP. Neither the A-E nor the F grades always have the lower voltage
(for the same bin, A-E is mostly lower or equal up to 816 MHz and higher
or equal from 1008 MHz). So without SOC_ID the driver keeps the A100
selection, as before, adds the BSP's a0 rule for normal parts, which
never lowers a voltage, and warns. Revision F parts then still run
20-40 mV below the vendor voltage at 408 and 600 MHz, some of them also
at 816 MHz.
The error message for a missing named cell now names the cell.
Testing:
- the function, built on the host from the driver source with stubbed
cells and revision, matches a transcription of the BSP rules for
120,960 combinations of boundary and typical field values, and gives
the A100 selection with the BSP's a0 rule when the revision is
unknown
- on the K5C it selects b2; the vdd-cpu regulator reads 0.94 V at
408 MHz, 0.96 V at 1008 MHz, 1.06 V at 1416 MHz and 1.10 V at
1512 MHz, as in the BSP table
- one hour of full load held 1512 MHz without throttling (max 79 C,
with the 90 C trip from the A100 thermal trips patch)
- with the revision forced to unknown it warns and selects speed1
- the same kernel with the A100 OPP table gives the same OPPs as
before
- a missing cell fails the probe with an error naming the cell, and
the system keeps running without cpufreq
Claude Code (Anthropic) drafted this patch and its message from the
selection rules in the vendor BSP cpufreq driver (no code copied) and
from my test results; I reviewed and tested it.
Suggested-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Rajan Yadav <rajanyadav0307@gmail.com>
---
drivers/cpufreq/sun50i-cpufreq-nvmem.c | 162 ++++++++++++++++++++++++++++++++-
1 file changed, 161 insertions(+), 1 deletion(-)
diff --git a/drivers/cpufreq/sun50i-cpufreq-nvmem.c b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
index 34c0897c22c..6bccea2887b 100644
--- a/drivers/cpufreq/sun50i-cpufreq-nvmem.c
+++ b/drivers/cpufreq/sun50i-cpufreq-nvmem.c
@@ -27,8 +27,10 @@
static struct platform_device *cpufreq_dt_pdev, *sun50i_cpufreq_pdev;
+/* Exactly one of the two callbacks is set */
struct sunxi_cpufreq_data {
u32 (*efuse_xlate)(u32 speedbin);
+ int (*get_speed)(struct device *cpu_dev, struct device_node *np);
};
static int sun50i_cpufreq_read_cell(struct device *cpu_dev,
@@ -41,9 +43,14 @@ static int sun50i_cpufreq_read_cell(struct device *cpu_dev,
__le32 tmp = 0;
cell = of_nvmem_cell_get(np, id);
- if (IS_ERR(cell))
+ if (IS_ERR(cell)) {
+ if (id)
+ return dev_err_probe(cpu_dev, PTR_ERR(cell),
+ "Could not get nvmem cell %s\n",
+ id);
return dev_err_probe(cpu_dev, PTR_ERR(cell),
"Could not get nvmem cell\n");
+ }
buf = nvmem_cell_read(cell, &len);
nvmem_cell_put(cell);
@@ -152,6 +159,149 @@ static u32 sun50i_h616_efuse_xlate(u32 speedbin)
return value;
}
+/*
+ * A133 speed grades, as selected by the vendor BSP (sun50iw10): a0-a6 for
+ * normal parts and b0-b3 for "high speed" parts. a5 and a6 have the same
+ * OPPs and voltages and share an index. The index is the N of
+ * opp-microvolt-speedN and the bit in opp-supported-hw. a0-a2 have the
+ * same voltages as the A100 speed0-speed2.
+ */
+enum sun50i_a133_grade {
+ SUN50I_A133_GRADE_A0,
+ SUN50I_A133_GRADE_A1,
+ SUN50I_A133_GRADE_A2,
+ SUN50I_A133_GRADE_A3,
+ SUN50I_A133_GRADE_A4,
+ SUN50I_A133_GRADE_A5, /* also a6 */
+ SUN50I_A133_GRADE_B0,
+ SUN50I_A133_GRADE_B1,
+ SUN50I_A133_GRADE_B2,
+ SUN50I_A133_GRADE_B3,
+};
+
+#define SUN50I_A133_MARKING_MASK 0xffff
+#define SUN50I_A133_BIN_SHIFT 12
+#define SUN50I_A133_BIN_MASK 0xf
+#define SUN50I_A133_ICPU_MASK 0xfff
+#define SUN50I_A133_PCPU_MASK 0xfff
+#define SUN50I_A133_BIN_EXT BIT(31)
+#define SUN50I_A133_REV_MASK 0x7
+
+/*
+ * The BSP runs revision A-E normal parts at a0 when both the ICPU current
+ * (in 0.1 mA) and the PCPU field are in these ranges (upper bounds
+ * exclusive).
+ */
+#define SUN50I_A133_ICPU_A0_MIN 84
+#define SUN50I_A133_ICPU_A0_MAX 160
+#define SUN50I_A133_PCPU_A0_MIN 2900
+#define SUN50I_A133_PCPU_A0_MAX 3100
+
+static bool sun50i_a133_force_a0(u32 icpu, u32 pcpu)
+{
+ return icpu >= SUN50I_A133_ICPU_A0_MIN &&
+ icpu < SUN50I_A133_ICPU_A0_MAX &&
+ pcpu >= SUN50I_A133_PCPU_A0_MIN &&
+ pcpu < SUN50I_A133_PCPU_A0_MAX;
+}
+
+/* Marking IDs that the BSP treats as "high speed" parts */
+static bool sun50i_a133_is_high_speed(u32 marking)
+{
+ switch (marking) {
+ case 0x0200:
+ case 0x0600:
+ case 0x0620:
+ case 0x0640:
+ case 0x0800:
+ case 0x1000:
+ case 0x1400:
+ case 0x2000:
+ case 0x4000:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int sun50i_a133_get_speed(struct device *cpu_dev,
+ struct device_node *np)
+{
+ u32 marking, bin_cell, pcpu, bin_ext, bin, icpu;
+ enum sun50i_a133_grade grade;
+ int ver_bits, ver;
+ bool before_f;
+ int ret;
+
+ ret = sun50i_cpufreq_read_cell(cpu_dev, np, "marking", &marking);
+ if (ret)
+ return ret;
+ ret = sun50i_cpufreq_read_cell(cpu_dev, np, "bin", &bin_cell);
+ if (ret)
+ return ret;
+ ret = sun50i_cpufreq_read_cell(cpu_dev, np, "pcpu", &pcpu);
+ if (ret)
+ return ret;
+ ret = sun50i_cpufreq_read_cell(cpu_dev, np, "bin-ext", &bin_ext);
+ if (ret)
+ return ret;
+
+ marking &= SUN50I_A133_MARKING_MASK;
+ bin = (bin_cell >> SUN50I_A133_BIN_SHIFT) & SUN50I_A133_BIN_MASK;
+ icpu = bin_cell & SUN50I_A133_ICPU_MASK;
+ pcpu &= SUN50I_A133_PCPU_MASK;
+
+ /*
+ * Neither the revision A-E nor the revision F grades always have the
+ * lower voltage, so there is no safe guess without the revision.
+ * Keep the A100 selection then (a0-a2), which these SoCs used so far,
+ * plus the BSP's a0 rule for normal parts, which never lowers a
+ * voltage. Revision F parts then still run 20-40 mV below the vendor
+ * voltage at 408 and 600 MHz, some of them also at 816 MHz, and "high
+ * speed" parts get 1464 MHz instead of 1416 and 1512 MHz.
+ */
+ ver_bits = get_soc_id_revision();
+ if (ver_bits < 0) {
+ dev_warn(cpu_dev,
+ "SMCCC SOC_ID not available, using speed grades a0-a2\n");
+ if (!sun50i_a133_is_high_speed(marking) &&
+ sun50i_a133_force_a0(icpu, pcpu))
+ return SUN50I_A133_GRADE_A0;
+ return sun50i_a100_efuse_xlate(bin_cell);
+ }
+
+ /*
+ * The BSP treats revisions 0, 3 and 4 as "A-E" and all others as
+ * "F and later".
+ */
+ ver = ver_bits & SUN50I_A133_REV_MASK;
+ before_f = ver == 0 || ver == 3 || ver == 4;
+
+ if (sun50i_a133_is_high_speed(marking)) {
+ if (bin == 0b100)
+ grade = before_f ? SUN50I_A133_GRADE_B1 :
+ SUN50I_A133_GRADE_B3;
+ else
+ grade = before_f ? SUN50I_A133_GRADE_B0 :
+ SUN50I_A133_GRADE_B2;
+ } else if (!before_f && (bin_ext & SUN50I_A133_BIN_EXT)) {
+ grade = SUN50I_A133_GRADE_A5; /* a6 */
+ } else if (before_f && sun50i_a133_force_a0(icpu, pcpu)) {
+ grade = SUN50I_A133_GRADE_A0;
+ } else if (bin == 0b100) {
+ grade = before_f ? SUN50I_A133_GRADE_A2 : SUN50I_A133_GRADE_A5;
+ } else if (bin == 0b010) {
+ grade = before_f ? SUN50I_A133_GRADE_A1 : SUN50I_A133_GRADE_A4;
+ } else {
+ grade = before_f ? SUN50I_A133_GRADE_A0 : SUN50I_A133_GRADE_A3;
+ }
+
+ dev_dbg(cpu_dev, "marking 0x%04x, bin %u, revision %d: speed grade %d\n",
+ marking, bin, ver, grade);
+
+ return grade;
+}
+
static struct sunxi_cpufreq_data sun50i_h6_cpufreq_data = {
.efuse_xlate = sun50i_h6_efuse_xlate,
};
@@ -160,6 +310,10 @@ static struct sunxi_cpufreq_data sun50i_a100_cpufreq_data = {
.efuse_xlate = sun50i_a100_efuse_xlate,
};
+static struct sunxi_cpufreq_data sun50i_a133_cpufreq_data = {
+ .get_speed = sun50i_a133_get_speed,
+};
+
static struct sunxi_cpufreq_data sun50i_h616_cpufreq_data = {
.efuse_xlate = sun50i_h616_efuse_xlate,
};
@@ -171,6 +325,9 @@ static const struct of_device_id cpu_opp_match_list[] = {
{ .compatible = "allwinner,sun50i-a100-operating-points",
.data = &sun50i_a100_cpufreq_data,
},
+ { .compatible = "allwinner,sun50i-a133-operating-points",
+ .data = &sun50i_a133_cpufreq_data,
+ },
{ .compatible = "allwinner,sun50i-h616-operating-points",
.data = &sun50i_h616_cpufreq_data,
},
@@ -239,6 +396,9 @@ static int sun50i_cpufreq_get_efuse(void)
opp_data = match->data;
+ if (opp_data->get_speed)
+ return opp_data->get_speed(cpu_dev, np);
+
ret = sun50i_cpufreq_read_cell(cpu_dev, np, NULL, &speedbin);
if (ret)
return ret;
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 4/6] arm64: dts: allwinner: a100: Add A133 speed grade efuse cells
2026-11-05 4:40 [PATCH 0/6] sunxi: A133: Add CPU speed grade detection and OPP table Rajan Yadav via B4 Relay
` (2 preceding siblings ...)
2026-11-05 4:40 ` [PATCH 3/6] cpufreq: sun50i: Add A133 speed grade detection Rajan Yadav via B4 Relay
@ 2026-11-05 4:40 ` Rajan Yadav via B4 Relay
2026-11-05 4:41 ` [PATCH 5/6] arm64: dts: allwinner: a133: Add CPU OPP table Rajan Yadav via B4 Relay
2026-11-05 4:41 ` [PATCH 6/6] arm64: dts: allwinner: a133: Use the A133 " Rajan Yadav via B4 Relay
5 siblings, 0 replies; 7+ messages in thread
From: Rajan Yadav via B4 Relay @ 2026-11-05 4:40 UTC (permalink / raw)
To: Yangtao Li, Viresh Kumar, Nishanth Menon, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland, Maxime Ripard, Rafael J. Wysocki,
Viresh Kumar, Andre Przywara
Cc: linux-pm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel, Cody Eksal, Alexander Sverdlin, Rajan Yadav
From: Rajan Yadav <rajanyadav0307@gmail.com>
The A133 speed grade selection also needs the chip marking ID (SID
offset 0x00), the word at 0x20, whose low 12 bits the vendor BSP calls
PCPU, and the word at 0x28 with the bin extension bit. Add nvmem cells
for them at the offsets the BSP uses. The H616 reads the same kind of
marking ID at offset 0x00 as its speed grade.
The cells are used by the A133 OPP table added later in this series;
the A100 OPP table keeps using only the existing 0x1c cell.
Claude Code (Anthropic) drafted this change and its message from the
vendor BSP device tree; I reviewed it and checked it with dtbs_check.
Signed-off-by: Rajan Yadav <rajanyadav0307@gmail.com>
---
arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi
index ba6020989ce..d1164f3b549 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a100.dtsi
@@ -176,6 +176,10 @@ efuse@3006000 {
#address-cells = <1>;
#size-cells = <1>;
+ chip_marking: chip-marking@0 {
+ reg = <0x0 0x2>;
+ };
+
ths_calibration: calib@14 {
reg = <0x14 8>;
};
@@ -183,6 +187,14 @@ ths_calibration: calib@14 {
cpu_speed_grade: cpu-speed-grade@1c {
reg = <0x1c 0x2>;
};
+
+ cpu_pcpu: cpu-pcpu@20 {
+ reg = <0x20 0x2>;
+ };
+
+ cpu_bin_ext: cpu-bin-ext@28 {
+ reg = <0x28 0x4>;
+ };
};
watchdog@30090a0 {
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 5/6] arm64: dts: allwinner: a133: Add CPU OPP table
2026-11-05 4:40 [PATCH 0/6] sunxi: A133: Add CPU speed grade detection and OPP table Rajan Yadav via B4 Relay
` (3 preceding siblings ...)
2026-11-05 4:40 ` [PATCH 4/6] arm64: dts: allwinner: a100: Add A133 speed grade efuse cells Rajan Yadav via B4 Relay
@ 2026-11-05 4:41 ` Rajan Yadav via B4 Relay
2026-11-05 4:41 ` [PATCH 6/6] arm64: dts: allwinner: a133: Use the A133 " Rajan Yadav via B4 Relay
5 siblings, 0 replies; 7+ messages in thread
From: Rajan Yadav via B4 Relay @ 2026-11-05 4:41 UTC (permalink / raw)
To: Yangtao Li, Viresh Kumar, Nishanth Menon, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland, Maxime Ripard, Rafael J. Wysocki,
Viresh Kumar, Andre Przywara
Cc: linux-pm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel, Cody Eksal, Alexander Sverdlin, Rajan Yadav
From: Rajan Yadav <rajanyadav0307@gmail.com>
Add the A133 CPU OPPs from the vendor BSP (sun50iw10p1.dtsi). There
are ten voltage sets, speed0-5 for the a0-a5/a6 grades and speed6-9
for the "high speed" b0-b3 grades. opp-supported-hw selects the
frequencies of each grade:
- 1464 MHz only for the a grades
- 1416 and 1512 MHz only for the b grades
- 408-1320 MHz for all
The highest voltage is 1.18 V, inside the 0.81-1.2 V recommended
operating range of VDD_CPU in the A133 datasheet (V1.5, table 5-2).
The BSP uses 1008 MHz where the A100 table uses 1080 MHz, at the same
voltages for a0-a2. U-Boot starts the CPU at 1008 MHz, which mainline
now reports as an unlisted initial frequency. This table follows the
BSP. The BSP table stops at 1512 MHz, so there is no 1608 MHz OPP,
although some datasheet versions list 1.6 GHz for the A133. A newer
factory kernel adds 1608 MHz for b0 and b1 only; that is left for a
follow-up.
The table has the A100 compatible as a fallback and the speed bin cell
first, so a kernel without A133 support selects speed0-2 from the speed
bin and gets the voltages of the A100 table, with 1008 instead of
1080 MHz. It needs the efuse cells added to sun50i-a100.dtsi in the
previous patch.
A script compared every voltage and the frequency set of every grade
with the BSP file and found no difference.
Claude Code (Anthropic) drafted this table and its message from the
vendor BSP device tree (numbers only) and wrote the comparison script;
I reviewed it and tested it on a KickPi K5C.
Suggested-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Rajan Yadav <rajanyadav0307@gmail.com>
---
.../boot/dts/allwinner/sun50i-a133-cpu-opp.dtsi | 172 +++++++++++++++++++++
1 file changed, 172 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a133-cpu-opp.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a133-cpu-opp.dtsi
new file mode 100644
index 00000000000..12b6612a920
--- /dev/null
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a133-cpu-opp.dtsi
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+// Copyright (C) 2026 Rajan Yadav <rajanyadav0307@gmail.com>
+/*
+ * A133 CPU OPPs. The voltages and grade selection follow the Allwinner
+ * vendor BSP (sun50iw10p1.dtsi). Index 0-5 are the vendor's a0-a5 grades
+ * (a6 uses the a5 values), index 6-9 are the "high speed" b0-b3 grades.
+ * This needs the efuse cells from sun50i-a100.dtsi.
+ */
+
+/ {
+ cpu_opp_table: opp-table-cpu {
+ compatible = "allwinner,sun50i-a133-operating-points",
+ "allwinner,sun50i-a100-operating-points";
+ nvmem-cells = <&cpu_speed_grade>, <&chip_marking>,
+ <&cpu_pcpu>, <&cpu_bin_ext>;
+ nvmem-cell-names = "bin", "marking", "pcpu", "bin-ext";
+ opp-shared;
+
+ opp-408000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <408000000>;
+
+ opp-microvolt-speed0 = <900000>;
+ opp-microvolt-speed1 = <900000>;
+ opp-microvolt-speed2 = <900000>;
+ opp-microvolt-speed3 = <940000>;
+ opp-microvolt-speed4 = <940000>;
+ opp-microvolt-speed5 = <920000>;
+ opp-microvolt-speed6 = <900000>;
+ opp-microvolt-speed7 = <900000>;
+ opp-microvolt-speed8 = <940000>;
+ opp-microvolt-speed9 = <920000>;
+ opp-supported-hw = <0x3ff>;
+ };
+
+ opp-600000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <600000000>;
+
+ opp-microvolt-speed0 = <900000>;
+ opp-microvolt-speed1 = <900000>;
+ opp-microvolt-speed2 = <900000>;
+ opp-microvolt-speed3 = <940000>;
+ opp-microvolt-speed4 = <940000>;
+ opp-microvolt-speed5 = <920000>;
+ opp-microvolt-speed6 = <900000>;
+ opp-microvolt-speed7 = <900000>;
+ opp-microvolt-speed8 = <940000>;
+ opp-microvolt-speed9 = <920000>;
+ opp-supported-hw = <0x3ff>;
+ };
+
+ opp-816000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <816000000>;
+
+ opp-microvolt-speed0 = <940000>;
+ opp-microvolt-speed1 = <900000>;
+ opp-microvolt-speed2 = <900000>;
+ opp-microvolt-speed3 = <940000>;
+ opp-microvolt-speed4 = <940000>;
+ opp-microvolt-speed5 = <920000>;
+ opp-microvolt-speed6 = <900000>;
+ opp-microvolt-speed7 = <900000>;
+ opp-microvolt-speed8 = <940000>;
+ opp-microvolt-speed9 = <920000>;
+ opp-supported-hw = <0x3ff>;
+ };
+
+ opp-1008000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1008000000>;
+
+ opp-microvolt-speed0 = <1020000>;
+ opp-microvolt-speed1 = <980000>;
+ opp-microvolt-speed2 = <950000>;
+ opp-microvolt-speed3 = <1020000>;
+ opp-microvolt-speed4 = <960000>;
+ opp-microvolt-speed5 = <940000>;
+ opp-microvolt-speed6 = <980000>;
+ opp-microvolt-speed7 = <950000>;
+ opp-microvolt-speed8 = <960000>;
+ opp-microvolt-speed9 = <940000>;
+ opp-supported-hw = <0x3ff>;
+ };
+
+ opp-1200000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1200000000>;
+
+ opp-microvolt-speed0 = <1100000>;
+ opp-microvolt-speed1 = <1020000>;
+ opp-microvolt-speed2 = <1000000>;
+ opp-microvolt-speed3 = <1100000>;
+ opp-microvolt-speed4 = <980000>;
+ opp-microvolt-speed5 = <960000>;
+ opp-microvolt-speed6 = <1020000>;
+ opp-microvolt-speed7 = <1000000>;
+ opp-microvolt-speed8 = <980000>;
+ opp-microvolt-speed9 = <960000>;
+ opp-supported-hw = <0x3ff>;
+ };
+
+ opp-1320000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1320000000>;
+
+ opp-microvolt-speed0 = <1160000>;
+ opp-microvolt-speed1 = <1060000>;
+ opp-microvolt-speed2 = <1030000>;
+ opp-microvolt-speed3 = <1160000>;
+ opp-microvolt-speed4 = <1020000>;
+ opp-microvolt-speed5 = <1000000>;
+ opp-microvolt-speed6 = <1060000>;
+ opp-microvolt-speed7 = <1030000>;
+ opp-microvolt-speed8 = <1020000>;
+ opp-microvolt-speed9 = <1000000>;
+ opp-supported-hw = <0x3ff>;
+ };
+
+ opp-1416000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1416000000>;
+
+ opp-microvolt-speed6 = <1100000>;
+ opp-microvolt-speed7 = <1070000>;
+ opp-microvolt-speed8 = <1060000>;
+ opp-microvolt-speed9 = <1040000>;
+ opp-supported-hw = <0x3c0>;
+ };
+
+ opp-1464000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1464000000>;
+
+ opp-microvolt-speed0 = <1180000>;
+ opp-microvolt-speed1 = <1180000>;
+ opp-microvolt-speed2 = <1130000>;
+ opp-microvolt-speed3 = <1180000>;
+ opp-microvolt-speed4 = <1100000>;
+ opp-microvolt-speed5 = <1080000>;
+ opp-supported-hw = <0x3f>;
+ };
+
+ opp-1512000000 {
+ clock-latency-ns = <244144>; /* 8 32k periods */
+ opp-hz = /bits/ 64 <1512000000>;
+
+ opp-microvolt-speed6 = <1180000>;
+ opp-microvolt-speed7 = <1130000 1130000 1140000>;
+ opp-microvolt-speed8 = <1100000>;
+ opp-microvolt-speed9 = <1080000>;
+ opp-supported-hw = <0x3c0>;
+ };
+ };
+};
+
+&cpu0 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu1 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu2 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu3 {
+ operating-points-v2 = <&cpu_opp_table>;
+};
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH 6/6] arm64: dts: allwinner: a133: Use the A133 CPU OPP table
2026-11-05 4:40 [PATCH 0/6] sunxi: A133: Add CPU speed grade detection and OPP table Rajan Yadav via B4 Relay
` (4 preceding siblings ...)
2026-11-05 4:41 ` [PATCH 5/6] arm64: dts: allwinner: a133: Add CPU OPP table Rajan Yadav via B4 Relay
@ 2026-11-05 4:41 ` Rajan Yadav via B4 Relay
5 siblings, 0 replies; 7+ messages in thread
From: Rajan Yadav via B4 Relay @ 2026-11-05 4:41 UTC (permalink / raw)
To: Yangtao Li, Viresh Kumar, Nishanth Menon, Stephen Boyd,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland, Maxime Ripard, Rafael J. Wysocki,
Viresh Kumar, Andre Przywara
Cc: linux-pm, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel, Cody Eksal, Alexander Sverdlin, Rajan Yadav
From: Rajan Yadav <rajanyadav0307@gmail.com>
Switch the three A133 boards in mainline (Baijie Helperboard A133,
Liontron H-A133L and Teclast P80) from the A100 OPP table to the A133
one, so the speed grade is selected as the vendor does it.
What changes depends on the chip:
- revision A-E parts with a normal marking ID get a0-a2 from the bin
field, as they get speed0-2 today, with the same voltages; only
1080 MHz becomes 1008 MHz. The exception is a part whose ICPU and
PCPU values are in the range for which the BSP forces a0.
- revision F and later parts with a normal marking ID get the a3-a6
voltages: higher at 408 and 600 MHz, equal or lower from 1008 MHz,
and 1008 instead of 1080 MHz.
- "high speed" parts get the b grades, with 1416 and 1512 MHz instead
of 1464 MHz.
- if the firmware does not provide SMCCC SOC_ID, the driver keeps the
A100 selection, adds the BSP's a0 rule for normal parts and warns at
boot.
All three boards supply the CPUs from AXP803 DCDC2 with a 0.81-1.2 V
range, which covers every new voltage. Without the A133 support in
sun50i-cpufreq-nvmem the A100 fallback applies. The Teclast P80 also
needs "cpufreq: sun50i: Handle boards with the allwinner,sun50i-a133
compatible" to get cpufreq at all.
Claude Code (Anthropic) drafted this change and its message; I
reviewed it. I tested the A133 table on a KickPi K5C; I cannot test
these three boards.
Suggested-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Rajan Yadav <rajanyadav0307@gmail.com>
---
arch/arm64/boot/dts/allwinner/sun50i-a133-helperboard-core.dtsi | 2 +-
arch/arm64/boot/dts/allwinner/sun50i-a133-liontron-h-a133l.dts | 2 +-
arch/arm64/boot/dts/allwinner/sun50i-a133-teclast-p80.dts | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a133-helperboard-core.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a133-helperboard-core.dtsi
index 545972d2324..3a89d3f74b3 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a133-helperboard-core.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a133-helperboard-core.dtsi
@@ -7,7 +7,7 @@
/dts-v1/;
#include "sun50i-a100.dtsi"
-#include "sun50i-a100-cpu-opp.dtsi"
+#include "sun50i-a133-cpu-opp.dtsi"
/{
model = "Baijie A133 HelperBoard Core";
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a133-liontron-h-a133l.dts b/arch/arm64/boot/dts/allwinner/sun50i-a133-liontron-h-a133l.dts
index 90a50910f07..1b9cbcbe5f3 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a133-liontron-h-a133l.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a133-liontron-h-a133l.dts
@@ -6,7 +6,7 @@
/dts-v1/;
#include "sun50i-a100.dtsi"
-#include "sun50i-a100-cpu-opp.dtsi"
+#include "sun50i-a133-cpu-opp.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/leds/common.h>
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a133-teclast-p80.dts b/arch/arm64/boot/dts/allwinner/sun50i-a133-teclast-p80.dts
index 47b5f2ac824..7d4c346276e 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a133-teclast-p80.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a133-teclast-p80.dts
@@ -6,7 +6,7 @@
/dts-v1/;
#include "sun50i-a100.dtsi"
-#include "sun50i-a100-cpu-opp.dtsi"
+#include "sun50i-a133-cpu-opp.dtsi"
#include <dt-bindings/gpio/gpio.h>
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread