[PATCH 08/14] ARM: dts: sun8i: Add r_twi I2C controller

1,146 views
Skip to first unread message

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

H3 SoC contains I2C controller optionally available
on the PL0 and PL1 pins. This patch makes this controller
available.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 82faefc..8d86f57 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -320,8 +320,9 @@
reg = <0x01f01428 0x4>;
#clock-cells = <1>;
clocks = <&apb0>;
- clock-indices = <0>, <1>;
- clock-output-names = "apb0_pio", "apb0_ir";
+ clock-indices = <0>, <1>, <6>;
+ clock-output-names = "apb0_pio", "apb0_ir", "apb0_i2c";
+
};

ir_clk: ir_clk@01f01454 {
@@ -666,6 +667,20 @@
status = "disabled";
};

+ r_twi: i2c@01f02400 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01f02400 0x400>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_twi_pins_a>;
+ clocks = <&apb0_gates 6>;
+ clock-frequency = <100000>;
+ resets = <&apb0_reset 6>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
gic: interrupt-controller@01c81000 {
compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
reg = <0x01c81000 0x1000>,
@@ -717,6 +732,13 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ r_twi_pins_a: r_twi@0 {
+ allwinner,pins = "PL0", "PL1";
+ allwinner,function = "s_twi";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
};
};
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

This patch adds nodes for the THS driver and the THS clock to
the Allwinner sun8i-h3.dtsi file.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 172576d..9938972 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -77,6 +77,14 @@
};
};

+ thermal-zones {
+ cpu_thermal: cpu_thermal {
+ polling-delay-passive = <330>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths 0>;
+ };
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -239,6 +247,14 @@
"bus_scr", "bus_ephy", "bus_dbg";
};

+ ths_clk: clk@01c20074 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-h3-ths-clk";
+ reg = <0x01c20074 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "ths";
+ };
+
mmc0_clk: clk@01c20088 {
#clock-cells = <1>;
compatible = "allwinner,sun4i-a10-mmc-clk";
@@ -394,6 +410,10 @@
reg = <0x01c14000 0x400>;
#address-cells = <1>;
#size-cells = <1>;
+
+ ths_calibration: calib@234 {
+ reg = <0x234 0x4>;
+ };
};

usbphy: phy@01c19400 {
@@ -581,6 +601,19 @@
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
};

+ ths: ths@01c25000 {
+ #thermal-sensor-cells = <0>;
+ compatible = "allwinner,sun8i-h3-ths";
+ reg = <0x01c25000 0x400>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&apb1_rst 8>;
+ reset-names = "ahb";
+ clocks = <&bus_gates 72>, <&ths_clk>;
+ clock-names = "ahb", "ths";
+ nvmem-cells = <&ths_calibration>;
+ nvmem-cell-names = "calibration";
+ };
+
uart0: serial@01c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Enable I2C controller where the SY8106A regulator for
CPUX voltage is attached on Orange Pi PC SBC.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index daf50b9a6..e5991da 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -90,6 +90,10 @@
};
};

+&r_twi {
+ status = "okay";
+};
+
&ehci1 {
status = "okay";
};
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Add label to the first cpu so that it can be referenced
from derived dts files.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 9938972..82faefc 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -52,7 +52,7 @@
#address-cells = <1>;
#size-cells = <0>;

- cpu@0 {
+ cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Liam Girdwood, Mark Brown, open list
From: Ondrej Jirman <meg...@megous.com>

SY8106A is I2C attached single output voltage regulator
made by Silergy.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
drivers/regulator/Kconfig | 8 +-
drivers/regulator/Makefile | 2 +-
drivers/regulator/sy8106a-regulator.c | 153 ++++++++++++++++++++++++++++++++++
3 files changed, 161 insertions(+), 2 deletions(-)
create mode 100644 drivers/regulator/sy8106a-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 144cbf5..fc3fae2 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -860,5 +860,11 @@ config REGULATOR_WM8994
This driver provides support for the voltage regulators on the
WM8994 CODEC.

-endif
+config REGULATOR_SY8106A
+ tristate "Silergy SY8106A"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ This driver provides support for the voltage regulator SY8106A.

+endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 85a1d44..f382095 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -110,6 +110,6 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
-
+obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o

ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c
new file mode 100644
index 0000000..34bd69c
--- /dev/null
+++ b/drivers/regulator/sy8106a-regulator.c
@@ -0,0 +1,153 @@
+/*
+ * sy8106a-regulator.c - Regulator device driver for SY8106A
+ *
+ * Copyright (C) 2016 Ondřej Jirman <meg...@megous.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regmap.h>
+
+#define SY8106A_REG_VOUT1_SEL 0x01
+#define SY8106A_REG_VOUT_COM 0x02
+#define SY8106A_REG_VOUT1_SEL_MASK 0x7f
+#define SY8106A_DISABLE_REG 0x01
+
+struct sy8106a {
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+};
+
+static const struct regmap_config sy8106a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
+{
+ return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
+ 0xff, sel | 0x80);
+}
+
+static const struct regulator_ops sy8106a_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_voltage_sel = sy8106a_set_voltage_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+/* Default limits measured in millivolts and milliamps */
+#define SY8106A_MIN_MV 680
+#define SY8106A_MAX_MV 1950
+#define SY8106A_STEP_MV 10
+
+static const struct regulator_desc sy8106a_reg = {
+ .name = "SY8106A",
+ .id = 0,
+ .ops = &sy8106a_ops,
+ .type = REGULATOR_VOLTAGE,
+ .n_voltages = ((SY8106A_MAX_MV - SY8106A_MIN_MV) / SY8106A_STEP_MV) + 1,
+ .min_uV = (SY8106A_MIN_MV * 1000),
+ .uV_step = (SY8106A_STEP_MV * 1000),
+ .vsel_reg = SY8106A_REG_VOUT1_SEL,
+ .vsel_mask = SY8106A_REG_VOUT1_SEL_MASK,
+ .enable_reg = SY8106A_REG_VOUT_COM,
+ .enable_mask = SY8106A_DISABLE_REG,
+ .disable_val = SY8106A_DISABLE_REG,
+ .enable_is_inverted = 1,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * I2C driver interface functions
+ */
+static int sy8106a_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct sy8106a *chip;
+ struct device *dev = &i2c->dev;
+ struct regulator_dev *rdev = NULL;
+ struct regulator_config config = { };
+ unsigned int selector;
+ int error;
+
+ chip = devm_kzalloc(&i2c->dev, sizeof(struct sy8106a), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ error = PTR_ERR(chip->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ error);
+ return error;
+ }
+
+ config.dev = &i2c->dev;
+ config.init_data = of_get_regulator_init_data(dev, dev->of_node, &sy8106a_reg);
+ config.driver_data = chip;
+ config.regmap = chip->regmap;
+ config.of_node = dev->of_node;
+
+ /* Probe regulator */
+ error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, &selector);
+ dev_info(&i2c->dev, "SY8106A voltage at boot: %u mV\n", SY8106A_MIN_MV + SY8106A_STEP_MV * (selector & SY8106A_REG_VOUT1_SEL_MASK));
+ if (error) {
+ dev_err(&i2c->dev, "Failed to read voltage at probe time: %d\n", error);
+ return error;
+ }
+
+ rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&i2c->dev, "Failed to register SY8106A regulator\n");
+ return PTR_ERR(rdev);
+ }
+
+ chip->rdev = rdev;
+
+ i2c_set_clientdata(i2c, chip);
+
+ return 0;
+}
+
+static const struct i2c_device_id sy8106a_i2c_id[] = {
+ {"sy8106a", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
+
+static struct i2c_driver sy8106a_regulator_driver = {
+ .driver = {
+ .name = "sy8106a",
+ },
+ .probe = sy8106a_i2c_probe,
+ .id_table = sy8106a_i2c_id,
+};
+
+module_i2c_driver(sy8106a_regulator_driver);
+
+MODULE_AUTHOR("Ondřej Jirman <meg...@megous.com>");
+MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
+MODULE_LICENSE("GPL v2");
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Josef Gajdusek, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Josef Gajdusek <a...@atx.name>

Add a node describing the Security ID memory to the Allwinner H3 .dtsi file.

Signed-off-by: Josef Gajdusek <a...@atx.name>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 4a4926b..172576d 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -389,6 +389,13 @@
#size-cells = <0>;
};

+ sid: eeprom@01c14000 {
+ compatible = "allwinner,sun4i-a10-sid";
+ reg = <0x01c14000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
usbphy: phy@01c19400 {
compatible = "allwinner,sun8i-h3-usb-phy";
reg = <0x01c19400 0x2c>,
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Zhang Rui, Eduardo Valentin, Maxime Ripard, Chen-Yu Tsai, open list, open list:THERMAL
From: Ondrej Jirman <meg...@megous.com>

This patch adds support for the sun8i thermal sensor on
Allwinner H3 SoC.

Signed-off-by: Ondřej Jirman <meg...@megous.com>
---
drivers/thermal/Kconfig | 7 ++
drivers/thermal/Makefile | 1 +
drivers/thermal/sun8i_ths.c | 295 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 303 insertions(+)
create mode 100644 drivers/thermal/sun8i_ths.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2d702ca..3de0f8d 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -351,6 +351,13 @@ config MTK_THERMAL
Enable this option if you want to have support for thermal management
controller present in Mediatek SoCs

+config SUN8I_THS
+ tristate "sun8i THS driver"
+ depends on MACH_SUN8I
+ depends on OF
+ help
+ Enable this to support thermal reporting on some newer Allwinner SoCs.
+
menu "Texas Instruments thermal drivers"
depends on ARCH_HAS_BANDGAP || COMPILE_TEST
depends on HAS_IOMEM
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 10b07c1..7261ee8 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
+obj-$(CONFIG_SUN8I_THS) += sun8i_ths.o
diff --git a/drivers/thermal/sun8i_ths.c b/drivers/thermal/sun8i_ths.c
new file mode 100644
index 0000000..618ccc3
--- /dev/null
+++ b/drivers/thermal/sun8i_ths.c
@@ -0,0 +1,295 @@
+/*
+ * sun8i THS driver
+ *
+ * Copyright (C) 2016 Ondřej Jirman
+ * Based on the work of Josef Gajdusek <a...@atx.name>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+#include <linux/printk.h>
+
+#define THS_H3_CTRL0 0x00
+#define THS_H3_CTRL2 0x40
+#define THS_H3_INT_CTRL 0x44
+#define THS_H3_STAT 0x48
+#define THS_H3_FILTER 0x70
+#define THS_H3_CDATA 0x74
+#define THS_H3_DATA 0x80
+
+#define THS_H3_CTRL0_SENSOR_ACQ0_OFFS 0
+#define THS_H3_CTRL0_SENSOR_ACQ0(x) \
+ ((x) << THS_H3_CTRL0_SENSOR_ACQ0_OFFS)
+#define THS_H3_CTRL2_SENSE_EN_OFFS 0
+#define THS_H3_CTRL2_SENSE_EN \
+ BIT(THS_H3_CTRL2_SENSE_EN_OFFS)
+#define THS_H3_CTRL2_SENSOR_ACQ1_OFFS 16
+#define THS_H3_CTRL2_SENSOR_ACQ1(x) \
+ ((x) << THS_H3_CTRL2_SENSOR_ACQ1_OFFS)
+
+#define THS_H3_INT_CTRL_DATA_IRQ_EN_OFFS 8
+#define THS_H3_INT_CTRL_DATA_IRQ_EN \
+ BIT(THS_H3_INT_CTRL_DATA_IRQ_EN_OFFS)
+#define THS_H3_INT_CTRL_THERMAL_PER_OFFS 12
+#define THS_H3_INT_CTRL_THERMAL_PER(x) \
+ ((x) << THS_H3_INT_CTRL_THERMAL_PER_OFFS)
+
+#define THS_H3_STAT_DATA_IRQ_STS_OFFS 8
+#define THS_H3_STAT_DATA_IRQ_STS \
+ BIT(THS_H3_STAT_DATA_IRQ_STS_OFFS)
+
+#define THS_H3_FILTER_TYPE_OFFS 0
+#define THS_H3_FILTER_TYPE(x) \
+ ((x) << THS_H3_FILTER_TYPE_OFFS)
+#define THS_H3_FILTER_EN_OFFS 2
+#define THS_H3_FILTER_EN \
+ BIT(THS_H3_FILTER_EN_OFFS)
+
+#define THS_H3_CLK_IN 40000000 /* Hz */
+#define THS_H3_DATA_PERIOD 330 /* ms */
+
+#define THS_H3_FILTER_TYPE_VALUE 2 /* average over 2^(n+1) samples */
+#define THS_H3_FILTER_DIV (1 << (THS_H3_FILTER_TYPE_VALUE + 1))
+#define THS_H3_INT_CTRL_THERMAL_PER_VALUE \
+ (THS_H3_DATA_PERIOD * (THS_H3_CLK_IN / 1000) / THS_H3_FILTER_DIV / 4096 - 1)
+#define THS_H3_CTRL0_SENSOR_ACQ0_VALUE 0x3f /* 16us */
+#define THS_H3_CTRL2_SENSOR_ACQ1_VALUE 0x3f
+
+struct sun8i_ths_data {
+ struct reset_control *reset;
+ struct clk *clk;
+ struct clk *busclk;
+ void __iomem *regs;
+ struct nvmem_cell *calcell;
+ struct platform_device *pdev;
+ struct thermal_zone_device *tzd;
+ u32 temp;
+};
+
+static int sun8i_ths_get_temp(void *_data, int *out)
+{
+ struct sun8i_ths_data *data = _data;
+
+ if (data->temp == 0)
+ return -EINVAL;
+
+ /* Formula and parameters from the Allwinner 3.4 kernel */
+ *out = 217000 - (data->temp * 1000000) / 8253;
+ return 0;
+}
+
+static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data)
+{
+ struct sun8i_ths_data *data = _data;
+
+ writel(THS_H3_STAT_DATA_IRQ_STS, data->regs + THS_H3_STAT);
+
+ data->temp = readl(data->regs + THS_H3_DATA);
+ if (data->temp)
+ thermal_zone_device_update(data->tzd);
+
+ return IRQ_HANDLED;
+}
+
+static int sun8i_ths_h3_init(struct platform_device *pdev,
+ struct sun8i_ths_data *data)
+{
+ int ret;
+ size_t callen;
+ s32 *caldata;
+
+ data->busclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(data->busclk)) {
+ ret = PTR_ERR(data->busclk);
+ dev_err(&pdev->dev, "failed to get ahb clk: %d\n", ret);
+ return ret;
+ }
+
+ data->clk = devm_clk_get(&pdev->dev, "ths");
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ dev_err(&pdev->dev, "failed to get ths clk: %d\n", ret);
+ return ret;
+ }
+
+ data->reset = devm_reset_control_get(&pdev->dev, "ahb");
+ if (IS_ERR(data->reset)) {
+ ret = PTR_ERR(data->reset);
+ dev_err(&pdev->dev, "failed to get reset: %d\n", ret);
+ return ret;
+ }
+
+ if (data->calcell) {
+ caldata = nvmem_cell_read(data->calcell, &callen);
+ if (IS_ERR(caldata))
+ return PTR_ERR(caldata);
+
+ writel(be32_to_cpu(*caldata), data->regs + THS_H3_CDATA);
+ kfree(caldata);
+ }
+
+ ret = clk_prepare_enable(data->busclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret);
+ goto err_disable_bus;
+ }
+
+ ret = reset_control_deassert(data->reset);
+ if (ret) {
+ dev_err(&pdev->dev, "reset deassert failed: %d\n", ret);
+ goto err_disable_ths;
+ }
+
+ ret = clk_set_rate(data->clk, THS_H3_CLK_IN);
+ if (ret)
+ goto err_disable_ths;
+
+ writel(THS_H3_CTRL0_SENSOR_ACQ0(THS_H3_CTRL0_SENSOR_ACQ0_VALUE),
+ data->regs + THS_H3_CTRL0);
+ writel(THS_H3_INT_CTRL_THERMAL_PER(THS_H3_INT_CTRL_THERMAL_PER_VALUE) |
+ THS_H3_INT_CTRL_DATA_IRQ_EN,
+ data->regs + THS_H3_INT_CTRL);
+ writel(THS_H3_FILTER_EN | THS_H3_FILTER_TYPE(THS_H3_FILTER_TYPE_VALUE),
+ data->regs + THS_H3_FILTER);
+ writel(THS_H3_CTRL2_SENSOR_ACQ1(THS_H3_CTRL2_SENSOR_ACQ1_VALUE) |
+ THS_H3_CTRL2_SENSE_EN,
+ data->regs + THS_H3_CTRL2);
+
+ return 0;
+
+err_disable_ths:
+ clk_disable_unprepare(data->clk);
+err_disable_bus:
+ clk_disable_unprepare(data->busclk);
+
+ return ret;
+}
+
+static void sun8i_ths_h3_deinit(struct sun8i_ths_data *data)
+{
+ reset_control_assert(data->reset);
+ clk_disable_unprepare(data->clk);
+ clk_disable_unprepare(data->busclk);
+}
+
+static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = {
+ .get_temp = sun8i_ths_get_temp,
+};
+
+static const struct of_device_id sun8i_ths_id_table[] = {
+ {
+ .compatible = "allwinner,sun8i-h3-ths",
+ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sun8i_ths_id_table);
+
+static int sun8i_ths_probe(struct platform_device *pdev)
+{
+ struct sun8i_ths_data *data;
+ struct resource *res;
+ int ret;
+ int irq;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->pdev = pdev;
+
+ data->calcell = devm_nvmem_cell_get(&pdev->dev, "calibration");
+ if (IS_ERR(data->calcell)) {
+ if (PTR_ERR(data->calcell) == -EPROBE_DEFER)
+ return PTR_ERR(data->calcell);
+
+ data->calcell = NULL; /* No calibration data */
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->regs)) {
+ ret = PTR_ERR(data->regs);
+ dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ sun8i_ths_irq_thread, IRQF_ONESHOT,
+ dev_name(&pdev->dev), data);
+ if (ret)
+ return ret;
+
+ ret = sun8i_ths_h3_init(pdev, data);
+ if (ret)
+ return ret;
+
+ data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
+ &sun8i_ths_thermal_ops);
+ if (IS_ERR(data->tzd)) {
+ ret = PTR_ERR(data->tzd);
+ dev_err(&pdev->dev, "failed to register thermal zone: %d\n",
+ ret);
+ goto err_deinit;
+ }
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+
+err_deinit:
+ sun8i_ths_h3_deinit(data);
+ return ret;
+}
+
+static int sun8i_ths_remove(struct platform_device *pdev)
+{
+ struct sun8i_ths_data *data = platform_get_drvdata(pdev);
+
+ thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
+ sun8i_ths_h3_deinit(data);
+ return 0;
+}
+
+static struct platform_driver sun8i_ths_driver = {
+ .probe = sun8i_ths_probe,
+ .remove = sun8i_ths_remove,
+ .driver = {
+ .name = "sun8i_ths",
+ .of_match_table = sun8i_ths_id_table,
+ },
+};
+
+module_platform_driver(sun8i_ths_driver);
+
+MODULE_AUTHOR("Ondřej Jirman <meg...@megous.com>");
+MODULE_DESCRIPTION("sun8i THS driver");

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org
This patch series implements thermal regulation on Orange Pi PC
and Orange Pi One. For that purpose I've taken over the work on THS
of Josef Gajdusek, and cleaned up his patches according to the
previous review on the mailing list.

The patch series also contains:
- Regulator driver for sy8106a I2C connected regulator
- DTS setup for gpio regulator used on Orange Pi One
- Operating points and thermal zone setup for both SBCs

Fixes/cleanups in the THS driver:
- Return EBUSY until thermal data are available to prevent incorrect
readings early during boot, which caused critical temperature
shutdowns.
- Remove unused infrastructure for support of other future SoCs.
The driver is for sun8i only ATM.
- Make readings quicker (once per 330ms) for faster regulation
loop.
- Remove some magic numbers from the code, and calculate parameters
automatically, based on required readout period.

Enabling frequency scaling lead to kernel crashes/lockups. I revrse
engineered arisc firmware from the BSP kernel to identify how it changes
PLL1 frequency and it uses algorithm that sets clock factors progressively.

This series also includes proposed patch to sunxi clk-factors code,
to allow for more complicated clock factors application algorithms.

regards,
Ondřej Jirman


meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Xulong Orange Pi One uses GPIO based regulator that
switches between two voltages: 1.1V and 1.3V. The
regulator is controlled from the PL6 pin.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
index 0adf932..ce4ba91 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
@@ -88,6 +88,25 @@
gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
};
};
+
+ vdd_soc: gpio-regulator {
+ compatible = "regulator-gpio";
+
+ regulator-name = "soc-vdd-supply";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-boot-on;
+ regulator-type = "voltage";
+
+ gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>;
+ states = <1100000 0x0
+ 1300000 0x1>;
+
+ startup-delay-us = <100000>;
+ enable-active-high;
+ };
+};
+
};

&ehci1 {
@@ -131,6 +150,13 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ soc_reg0: soc_reg@0 {
+ allwinner,pins = "PL6";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};

&uart0 {
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Add sy8106a regulator to r_twi bus on Orange Pi PC. This
regulator controls the CPUX voltage.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index e5991da..7e04017 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -92,6 +92,16 @@

&r_twi {
status = "okay";
+
+ vdd_cpu: regulator@65 {
+ compatible = "sy8106a";
+ reg = <0x65>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-ramp-delay = <200>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
};

&ehci1 {
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Josef Gajdusek, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Maxime Ripard, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Josef Gajdusek <a...@atx.name>

This patch adds a driver for the THS clock which is present on the
Allwinner H3.

Signed-off-by: Josef Gajdusek <a...@atx.name>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-h3-ths.c | 98 +++++++++++++++++++++++
3 files changed, 100 insertions(+)
create mode 100644 drivers/clk/sunxi/clk-h3-ths.c

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 8f7619d..5faae05 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -87,6 +87,7 @@ Required properties:
"allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
"allwinner,sun4i-a10-ve-clk" - for the Video Engine clock
"allwinner,sun6i-a31-display-clk" - for the display clocks
+ "allwinner,sun8i-h3-ths-clk" - for THS on H3

Required properties for all clocks:
- reg : shall be the control register address for the clock.
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 39d2044..8e245e3 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -9,6 +9,7 @@ obj-y += clk-a10-mod1.o
obj-y += clk-a10-pll2.o
obj-y += clk-a10-ve.o
obj-y += clk-a20-gmac.o
+obj-y += clk-h3-ths.o
obj-y += clk-mod0.o
obj-y += clk-simple-gates.o
obj-y += clk-sun4i-display.o
diff --git a/drivers/clk/sunxi/clk-h3-ths.c b/drivers/clk/sunxi/clk-h3-ths.c
new file mode 100644
index 0000000..c1d6d32
--- /dev/null
+++ b/drivers/clk/sunxi/clk-h3-ths.c
@@ -0,0 +1,98 @@
+/*
+ * sun8i THS clock driver
+ *
+ * Copyright (C) 2015 Josef Gajdusek
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define SUN8I_H3_THS_CLK_ENABLE 31
+#define SUN8I_H3_THS_CLK_DIVIDER_SHIFT 0
+#define SUN8I_H3_THS_CLK_DIVIDER_WIDTH 2
+
+static DEFINE_SPINLOCK(sun8i_h3_ths_clk_lock);
+
+static const struct clk_div_table sun8i_h3_ths_clk_table[] __initconst = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 4 },
+ { .val = 3, .div = 6 },
+ { } /* sentinel */
+};
+
+static void __init sun8i_h3_ths_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct clk_gate *gate;
+ struct clk_divider *div;
+ const char *parent;
+ const char *clk_name = node->name;
+ void __iomem *reg;
+ int err;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+
+ if (IS_ERR(reg))
+ return;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ goto err_unmap;
+
+ div = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!div)
+ goto err_gate_free;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ parent = of_clk_get_parent_name(node, 0);
+
+ gate->reg = reg;
+ gate->bit_idx = SUN8I_H3_THS_CLK_ENABLE;
+ gate->lock = &sun8i_h3_ths_clk_lock;
+
+ div->reg = reg;
+ div->shift = SUN8I_H3_THS_CLK_DIVIDER_SHIFT;
+ div->width = SUN8I_H3_THS_CLK_DIVIDER_WIDTH;
+ div->table = sun8i_h3_ths_clk_table;
+ div->lock = &sun8i_h3_ths_clk_lock;
+
+ clk = clk_register_composite(NULL, clk_name, &parent, 1,
+ NULL, NULL,
+ &div->hw, &clk_divider_ops,
+ &gate->hw, &clk_gate_ops,
+ CLK_SET_RATE_PARENT);
+
+ if (IS_ERR(clk))
+ goto err_div_free;
+
+ err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (err)
+ goto err_unregister_clk;
+
+ return;
+
+err_unregister_clk:
+ clk_unregister(clk);
+err_gate_free:
+ kfree(gate);
+err_div_free:
+ kfree(div);
+err_unmap:
+ iounmap(reg);
+}
+
+CLK_OF_DECLARE(sun8i_h3_ths_clk, "allwinner,sun8i-h3-ths-clk",
+ sun8i_h3_ths_clk_setup);
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland, Maxime Ripard, Chen-Yu Tsai, open list:THERMAL, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

This patch adds the binding documentation for the sun8i_ths driver

Signed-off-by: Ondřej Jirman <meg...@megous.com>
---
.../devicetree/bindings/thermal/sun8i-ths.txt | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 Documentation/devicetree/bindings/thermal/sun8i-ths.txt

diff --git a/Documentation/devicetree/bindings/thermal/sun8i-ths.txt b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt
new file mode 100644
index 0000000..826cd57
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt
@@ -0,0 +1,31 @@
+* sun8i THS
+
+Required properties:
+- compatible : "allwinner,sun8i-h3-ths"
+- reg : Address range of the thermal registers and location of the calibration
+ value
+- resets : Must contain an entry for each entry in reset-names.
+ see ../reset/reset.txt for details
+- reset-names : Must include the name "ahb"
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names : Must contain "ahb" for the bus gate and "ths" for the THS
+ clock
+
+Optional properties:
+- nvmem-cells : Must contain an entry for each entry in nvmem-cell-names
+- nvmem-cell-names : Must contain "calibration" for the cell containing the
+ temperature calibration cell, if available
+
+Example:
+ths: ths@01c25000 {
+ #thermal-sensor-cells = <0>;
+ compatible = "allwinner,sun8i-h3-ths";
+ reg = <0x01c25000 0x400>;
+ interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&bus_rst 136>;
+ reset-names = "ahb";
+ clocks = <&bus_gates 72>, <&ths_clk>;
+ clock-names = "ahb", "ths";
+ nvmem-cells = <&ths_calibration>;
+ nvmem-cell-names = "calibration";
+};
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, Emilio López, Michael Turquette, Stephen Boyd, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list, open list:COMMON CLK FRAMEWORK
From: Ondrej Jirman <meg...@megous.com>

PLL1 on H3 requires special factors application algorithm,
when the rate is changed. This algorithm was extracted
from the arisc code that handles frequency scaling
in the BSP kernel.

This commit adds optional apply function to
struct factors_data, that can implement non-trivial
factors application method, when necessary.

Also struct clk_factors_config is extended with position
of the PLL lock flag.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 2 +-
drivers/clk/sunxi/clk-factors.c | 34 +++++++++----------
drivers/clk/sunxi/clk-factors.h | 12 +++++++
drivers/clk/sunxi/clk-sunxi.c | 72 +++++++++++++++++++++++++++++++++++++++--
4 files changed, 98 insertions(+), 22 deletions(-)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 8d86f57..58a49db 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -114,7 +114,7 @@

pll1: clk@01c20000 {
#clock-cells = <0>;
- compatible = "allwinner,sun8i-a23-pll1-clk";
+ compatible = "allwinner,sun8i-h3-pll1-clk";
reg = <0x01c20000 0x4>;
clocks = <&osc24M>;
clock-output-names = "pll1";
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index ddefe96..7c165db 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -34,13 +34,6 @@

#define FACTORS_MAX_PARENTS 5

-#define SETMASK(len, pos) (((1U << (len)) - 1) << (pos))
-#define CLRMASK(len, pos) (~(SETMASK(len, pos)))
-#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
-
-#define FACTOR_SET(bit, len, reg, val) \
- (((reg) & CLRMASK(len, bit)) | (val << (bit)))
-
static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -150,20 +143,24 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
if (factors->lock)
spin_lock_irqsave(factors->lock, flags);

- /* Fetch the register value */
- reg = readl(factors->reg);
+ if (factors->apply) {
+ factors->apply(factors, &req);
+ } else {
+ /* Fetch the register value */
+ reg = readl(factors->reg);

- /* Set up the new factors - macros do not do anything if width is 0 */
- reg = FACTOR_SET(config->nshift, config->nwidth, reg, req.n);
- reg = FACTOR_SET(config->kshift, config->kwidth, reg, req.k);
- reg = FACTOR_SET(config->mshift, config->mwidth, reg, req.m);
- reg = FACTOR_SET(config->pshift, config->pwidth, reg, req.p);
+ /* Set up the new factors - macros do not do anything if width is 0 */
+ reg = FACTOR_SET(config->nshift, config->nwidth, reg, req.n);
+ reg = FACTOR_SET(config->kshift, config->kwidth, reg, req.k);
+ reg = FACTOR_SET(config->mshift, config->mwidth, reg, req.m);
+ reg = FACTOR_SET(config->pshift, config->pwidth, reg, req.p);

- /* Apply them now */
- writel(reg, factors->reg);
+ /* Apply them now */
+ writel(reg, factors->reg);

- /* delay 500us so pll stabilizes */
- __delay((rate >> 20) * 500 / 2);
+ /* delay 500us so pll stabilizes */
+ __delay((rate >> 20) * 500 / 2);
+ }

if (factors->lock)
spin_unlock_irqrestore(factors->lock, flags);
@@ -213,6 +210,7 @@ struct clk *sunxi_factors_register(struct device_node *node,
factors->config = data->table;
factors->get_factors = data->getter;
factors->recalc = data->recalc;
+ factors->apply = data->apply;
factors->lock = lock;

/* Add a gate if this factor clock can be gated */
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
index 1e63c5b..661a45a 100644
--- a/drivers/clk/sunxi/clk-factors.h
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -6,6 +6,13 @@

#define SUNXI_FACTORS_NOT_APPLICABLE (0)

+#define SETMASK(len, pos) (((1U << (len)) - 1) << (pos))
+#define CLRMASK(len, pos) (~(SETMASK(len, pos)))
+#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
+
+#define FACTOR_SET(bit, len, reg, val) \
+ (((reg) & CLRMASK(len, bit)) | (val << (bit)))
+
struct clk_factors_config {
u8 nshift;
u8 nwidth;
@@ -16,6 +23,7 @@ struct clk_factors_config {
u8 pshift;
u8 pwidth;
u8 n_start;
+ u8 lock;
};

struct factors_request {
@@ -28,6 +36,8 @@ struct factors_request {
u8 p;
};

+struct clk_factors;
+
struct factors_data {
int enable;
int mux;
@@ -35,6 +45,7 @@ struct factors_data {
const struct clk_factors_config *table;
void (*getter)(struct factors_request *req);
void (*recalc)(struct factors_request *req);
+ void (*apply)(struct clk_factors *factors, struct factors_request *req);
const char *name;
};

@@ -44,6 +55,7 @@ struct clk_factors {
const struct clk_factors_config *config;
void (*get_factors)(struct factors_request *req);
void (*recalc)(struct factors_request *req);
+ void (*apply)(struct clk_factors *factors, struct factors_request *req);
spinlock_t *lock;
/* for cleanup */
struct clk_mux *mux;
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 838b22a..e4bb908 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/log2.h>
+#include <linux/delay.h>

#include "clk-factors.h"

@@ -200,6 +201,56 @@ static void sun8i_a23_get_pll1_factors(struct factors_request *req)
}

/**
+ * sun8i_h3_apply_pll1_factors() - applies n, k, m, p factors to the
+ * register using an algorithm that tries to reserve the PLL lock
+ */
+
+static void sun8i_h3_apply_pll1_factors(struct clk_factors *factors, struct factors_request *req)
+{
+ const struct clk_factors_config *config = factors->config;
+ u32 reg;
+
+ /* Fetch the register value */
+ reg = readl(factors->reg);
+
+ if (FACTOR_GET(config->pshift, config->pwidth, reg) < req->p) {
+ reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
+
+ writel(reg, factors->reg);
+ __delay(2000);
+ }
+
+ if (FACTOR_GET(config->mshift, config->mwidth, reg) < req->m) {
+ reg = FACTOR_SET(config->mshift, config->mwidth, reg, req->m);
+
+ writel(reg, factors->reg);
+ __delay(2000);
+ }
+
+ reg = FACTOR_SET(config->nshift, config->nwidth, reg, req->n);
+ reg = FACTOR_SET(config->kshift, config->kwidth, reg, req->k);
+
+ writel(reg, factors->reg);
+ __delay(20);
+
+ while (!(readl(factors->reg) & (1 << config->lock)));
+
+ if (FACTOR_GET(config->mshift, config->mwidth, reg) > req->m) {
+ reg = FACTOR_SET(config->mshift, config->mwidth, reg, req->m);
+
+ writel(reg, factors->reg);
+ __delay(2000);
+ }
+
+ if (FACTOR_GET(config->pshift, config->pwidth, reg) > req->p) {
+ reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
+
+ writel(reg, factors->reg);
+ __delay(2000);
+ }
+}
+
+/**
* sun4i_get_pll5_factors() - calculates n, k factors for PLL5
* PLL5 rate is calculated as follows
* rate = parent_rate * n * (k + 1)
@@ -451,6 +502,7 @@ static const struct clk_factors_config sun8i_a23_pll1_config = {
.pshift = 16,
.pwidth = 2,
.n_start = 1,
+ .lock = 28
};

static const struct clk_factors_config sun4i_pll5_config = {
@@ -513,6 +565,13 @@ static const struct factors_data sun8i_a23_pll1_data __initconst = {
.getter = sun8i_a23_get_pll1_factors,
};

+static const struct factors_data sun8i_h3_pll1_data __initconst = {
+ .enable = 31,
+ .table = &sun8i_a23_pll1_config,
+ .getter = sun8i_a23_get_pll1_factors,
+ .apply = sun8i_h3_apply_pll1_factors,
+};
+
static const struct factors_data sun7i_a20_pll4_data __initconst = {
.enable = 31,
.table = &sun4i_pll5_config,
@@ -590,12 +649,19 @@ static void __init sun6i_pll1_clk_setup(struct device_node *node)
CLK_OF_DECLARE(sun6i_pll1, "allwinner,sun6i-a31-pll1-clk",
sun6i_pll1_clk_setup);

-static void __init sun8i_pll1_clk_setup(struct device_node *node)
+static void __init sun8i_a23_pll1_clk_setup(struct device_node *node)
{
sunxi_factors_clk_setup(node, &sun8i_a23_pll1_data);
}
-CLK_OF_DECLARE(sun8i_pll1, "allwinner,sun8i-a23-pll1-clk",
- sun8i_pll1_clk_setup);
+CLK_OF_DECLARE(sun8i_a23_pll1, "allwinner,sun8i-a23-pll1-clk",
+ sun8i_a23_pll1_clk_setup);
+
+static void __init sun8i_h3_pll1_clk_setup(struct device_node *node)
+{
+ sunxi_factors_clk_setup(node, &sun8i_h3_pll1_data);
+}
+CLK_OF_DECLARE(sun8i_h3_pll1, "allwinner,sun8i-h3-pll1-clk",
+ sun8i_h3_pll1_clk_setup);

static void __init sun7i_pll4_clk_setup(struct device_node *node)
{
--
2.9.0

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Orange PI PC uses SY8106A regulator for fine grained CPUX voltage
regulation. Setup appropriate operating points for the board.
---
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 50 ++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index 7e04017..e85fe91 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -90,6 +90,56 @@
};
};

+&cpu0 {
+ clocks = <&cpu>;
+ clock-latency = <244144>; /* 8 32k periods */
+ operating-points = <
+ /* kHz uV */
+ 1512000 1400000
+ 1440000 1400000
+ 1368000 1340000
+ 1344000 1340000
+ 1296000 1340000
+ 1248000 1300000
+ 1224000 1300000
+ 1200000 1300000
+ 1104000 1200000
+ 1008000 1140000
+ 960000 1100000
+ 648000 1100000
+ 480000 1100000
+ 240000 1100000
+ 120000 1100000
+ >;
+ #cooling-cells = <2>;
+ cooling-min-level = <0>;
+ cooling-max-level = <14>;
+ cpu0-supply = <&vdd_cpu>;
+};
+
+&cpu_thermal {
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&cpu0 (-1) (-1)>;
+ };
+ };
+
+ trips {
+ cpu_alert0: cpu_alert0 {
+ temperature = <80000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit: cpu_crit {
+ temperature = <100000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+};
+
&r_twi {

meg...@megous.com

unread,
Jun 23, 2016, 3:39:03 PM6/23/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Use Xulong Orange Pi One GPIO based regulator for
passive cooling and thermal management.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 39 +++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
index ce4ba91..6bd4367 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
@@ -107,6 +107,45 @@
};
};

+&cpu0 {
+ clocks = <&cpu>;
+ clock-latency = <244144>; /* 8 32k periods */
+ operating-points = <
+ /* kHz uV */
+ 1296000 1300000
+ 1200000 1300000
+ 624000 1100000
+ 480000 1100000
+ 312000 1100000
+ 240000 1100000
+ >;
+ #cooling-cells = <2>;
+ cooling-min-level = <0>;
+ cooling-max-level = <5>;
+ cpu0-supply = <&vdd_soc>;
+};
+
+&cpu_thermal {
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&cpu0 (-1) (-1)>;
+ };
+ };
+
+ trips {
+ cpu_alert0: cpu_alert0 {
+ temperature = <80000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit: cpu_crit {
+ temperature = <100000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
};

&ehci1 {
--
2.9.0

Chen-Yu Tsai

unread,
Jun 23, 2016, 10:42:11 PM6/23/16
to meg...@megous.com, dev, linux-arm-kernel, Josef Gajdusek, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On Fri, Jun 24, 2016 at 3:20 AM, <meg...@megous.com> wrote:
> From: Josef Gajdusek <a...@atx.name>
>
> Add a node describing the Security ID memory to the Allwinner H3 .dtsi file.
>
> Signed-off-by: Josef Gajdusek <a...@atx.name>
> ---
> arch/arm/boot/dts/sun8i-h3.dtsi | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
> index 4a4926b..172576d 100644
> --- a/arch/arm/boot/dts/sun8i-h3.dtsi
> +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
> @@ -389,6 +389,13 @@
> #size-cells = <0>;
> };
>
> + sid: eeprom@01c14000 {
> + compatible = "allwinner,sun4i-a10-sid";

This has been discussed before. The hardware is not compatible.
The write control registers are at different offsets.

ChenYu

Chen-Yu Tsai

unread,
Jun 23, 2016, 10:46:41 PM6/23/16
to meg...@megous.com, dev, linux-arm-kernel, Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland, Maxime Ripard, Chen-Yu Tsai, open list:THERMAL, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On Fri, Jun 24, 2016 at 3:20 AM, <meg...@megous.com> wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> This patch adds the binding documentation for the sun8i_ths driver
>
> Signed-off-by: Ondřej Jirman <meg...@megous.com>
> ---
> .../devicetree/bindings/thermal/sun8i-ths.txt | 31 ++++++++++++++++++++++
> 1 file changed, 31 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/thermal/sun8i-ths.txt
>
> diff --git a/Documentation/devicetree/bindings/thermal/sun8i-ths.txt b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt
> new file mode 100644
> index 0000000..826cd57
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt
> @@ -0,0 +1,31 @@
> +* sun8i THS

An explanation of the acronym would be nice, both in the docs,
and in the commit message.

> +
> +Required properties:
> +- compatible : "allwinner,sun8i-h3-ths"
> +- reg : Address range of the thermal registers and location of the calibration

*sensor*

Also you only specify one address range in the example. The "location
of the calibration value" is handled by the nvram-* properties. Please
remove the description.

> + value
> +- resets : Must contain an entry for each entry in reset-names.

This, and clocks below, should probably read "must contain phandles
to reset/clock controls matching the entries of the names".

Regards
ChenYu

Julian Calaby

unread,
Jun 23, 2016, 10:51:58 PM6/23/16
to meg...@megous.com, Linux Sunxi, Mailing List, Arm, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi Ondrej,
Don't you need to reference the new pinctl node in this one?

Thanks,

--
Julian Calaby

Email: julian...@gmail.com
Profile: http://www.google.com/profiles/julian.calaby/

Julian Calaby

unread,
Jun 23, 2016, 10:53:44 PM6/23/16
to meg...@megous.com, Linux Sunxi, Mailing List, Arm, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, Emilio López, Michael Turquette, Stephen Boyd, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list, open list:COMMON CLK FRAMEWORK
Hi Ondrej,

On Fri, Jun 24, 2016 at 5:21 AM, <meg...@megous.com> wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> PLL1 on H3 requires special factors application algorithm,
> when the rate is changed. This algorithm was extracted
> from the arisc code that handles frequency scaling
> in the BSP kernel.
>
> This commit adds optional apply function to
> struct factors_data, that can implement non-trivial
> factors application method, when necessary.
>
> Also struct clk_factors_config is extended with position
> of the PLL lock flag.
>
> Signed-off-by: Ondrej Jirman <meg...@megous.com>
> ---
> arch/arm/boot/dts/sun8i-h3.dtsi | 2 +-
> drivers/clk/sunxi/clk-factors.c | 34 +++++++++----------
> drivers/clk/sunxi/clk-factors.h | 12 +++++++
> drivers/clk/sunxi/clk-sunxi.c | 72 +++++++++++++++++++++++++++++++++++++++--
> 4 files changed, 98 insertions(+), 22 deletions(-)

Shouldn't the .dtsi changes be in a separate patch?

Julian Calaby

unread,
Jun 23, 2016, 10:55:38 PM6/23/16
to meg...@megous.com, Linux Sunxi, Mailing List, Arm, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi Ondrej,

On Fri, Jun 24, 2016 at 5:21 AM, <meg...@megous.com> wrote:
Also, isn't adding another closing bracket here a syntax error?

> };

Chen-Yu Tsai

unread,
Jun 23, 2016, 11:19:14 PM6/23/16
to meg...@megous.com, dev, linux-arm-kernel, Zhang Rui, Eduardo Valentin, Maxime Ripard, Chen-Yu Tsai, open list, open list:THERMAL
Hi,

On Fri, Jun 24, 2016 at 3:20 AM, <meg...@megous.com> wrote:
> From: Ondrej Jirman <meg...@megous.com>
>

The subject could read:

thermal: sun8i_ths: Add support for the thermal sensor on Allwinner H3

> This patch adds support for the sun8i thermal sensor on
> Allwinner H3 SoC.
>
> Signed-off-by: Ondřej Jirman <meg...@megous.com>
> ---
> drivers/thermal/Kconfig | 7 ++
> drivers/thermal/Makefile | 1 +
> drivers/thermal/sun8i_ths.c | 295 ++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 303 insertions(+)
> create mode 100644 drivers/thermal/sun8i_ths.c
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index 2d702ca..3de0f8d 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -351,6 +351,13 @@ config MTK_THERMAL
> Enable this option if you want to have support for thermal management
> controller present in Mediatek SoCs
>
> +config SUN8I_THS
> + tristate "sun8i THS driver"

Explain THS.
Explain THS.
Is it really necessary to split the lines of all the macros?
It makes it harder to find and read stuff.

You're also not using any of the *_OFFS macros in the actual code,
so just drop them.
IIRC with the new shared reset control stuff merged, you are supposed
to specify whether you want a shared or exclusive one when you ask for
it.

Also you seem to be requesting some resources here, while others
directly in the probe function. Could you put them in the same place?
Maybe requesting all resources in the probe function, and this init
function turns everything on?

> + if (IS_ERR(data->reset)) {
> + ret = PTR_ERR(data->reset);
> + dev_err(&pdev->dev, "failed to get reset: %d\n", ret);
> + return ret;
> + }
> +
> + if (data->calcell) {
> + caldata = nvmem_cell_read(data->calcell, &callen);
> + if (IS_ERR(caldata))
> + return PTR_ERR(caldata);

Check the returned length in case of a bogus cell?
This enables the interrupts. You already requested IRQs from the kernel, which
means as soon as this line executes, interrupts will start firing.

You should do this last, after you've finishing all the configuration,
i.e. move this after the next writel calls.
Nit. You could fit it in one line.
Is a threaded irq required? The thermal core seems to use atomics,
so this shouldn't be necessary.
Explain THS.

Regards
ChenYu

Chen-Yu Tsai

unread,
Jun 23, 2016, 11:42:03 PM6/23/16
to meg...@megous.com, dev, Mark Brown, Liam Girdwood, linux-arm-kernel, open list
On Fri, Jun 24, 2016 at 3:20 AM, <meg...@megous.com> wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> SY8106A is I2C attached single output voltage regulator
> made by Silergy.
>
> Signed-off-by: Ondrej Jirman <meg...@megous.com>
> ---
> drivers/regulator/Kconfig | 8 +-
> drivers/regulator/Makefile | 2 +-
> drivers/regulator/sy8106a-regulator.c | 153 ++++++++++++++++++++++++++++++++++
> 3 files changed, 161 insertions(+), 2 deletions(-)
> create mode 100644 drivers/regulator/sy8106a-regulator.c
>
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index 144cbf5..fc3fae2 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -860,5 +860,11 @@ config REGULATOR_WM8994
> This driver provides support for the voltage regulators on the
> WM8994 CODEC.
>
> -endif
> +config REGULATOR_SY8106A
> + tristate "Silergy SY8106A"
> + depends on I2C

Maybe you should also depend on OF since the driver is going to crippled
without any constraints set, or (OF || COMPILE_TEST) if you want some
compile test coverage.

> + select REGMAP_I2C
> + help
> + This driver provides support for the voltage regulator SY8106A.
>
> +endif
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 85a1d44..f382095 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -110,6 +110,6 @@ obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
> obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
> obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
> obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
> -
> +obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o

Follow the existing ordering in the Makefile.
Do you need this one?

> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>

And this one?

> +#include <linux/regulator/of_regulator.h>
> +#include <linux/regmap.h>

Sort alphabetically please.

> +
> +#define SY8106A_REG_VOUT1_SEL 0x01
> +#define SY8106A_REG_VOUT_COM 0x02
> +#define SY8106A_REG_VOUT1_SEL_MASK 0x7f
> +#define SY8106A_DISABLE_REG 0x01

BIT(0) would be clearer.

> +
> +struct sy8106a {
> + struct regulator_dev *rdev;
> + struct regmap *regmap;
> +};
> +
> +static const struct regmap_config sy8106a_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> +};
> +
> +static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
> +{
> + return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg,
> + 0xff, sel | 0x80);

Can you use .apply_bit / .apply_reg with regulator_set_voltage_sel_regmap?
Check for possible failures?
Extra line.

> +MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);

IMHO probing explicitly through DT (of_device_id) would be better.


Regards
ChenYu

> +
> +static struct i2c_driver sy8106a_regulator_driver = {
> + .driver = {
> + .name = "sy8106a",
> + },
> + .probe = sy8106a_i2c_probe,
> + .id_table = sy8106a_i2c_id,
> +};
> +
> +module_i2c_driver(sy8106a_regulator_driver);
> +
> +MODULE_AUTHOR("Ondřej Jirman <meg...@megous.com>");
> +MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");
> +MODULE_LICENSE("GPL v2");
> --
> 2.9.0
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-ar...@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Chen-Yu Tsai

unread,
Jun 23, 2016, 11:48:50 PM6/23/16
to meg...@megous.com, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On Fri, Jun 24, 2016 at 3:20 AM, <meg...@megous.com> wrote:
Can you also set the cpu clock here? It is part of the SoC
and does not belong in the board DTS files.

Otherwise this one looks good.

ChenYu

> --
> 2.9.0
>

Chen-Yu Tsai

unread,
Jun 24, 2016, 5:14:31 AM6/24/16
to meg...@megous.com, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
This should be merged with the previous "enable r_twi" patch.

ChenYu

> };
>
> &ehci1 {
> --
> 2.9.0
>

Ondřej Jirman

unread,
Jun 24, 2016, 3:58:24 PM6/24/16
to Chen-Yu Tsai, dev, linux-arm-kernel, Josef Gajdusek, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hello,

thank you for the review.

On 24.6.2016 04:41, Chen-Yu Tsai wrote:
> On Fri, Jun 24, 2016 at 3:20 AM, <meg...@megous.com> wrote:
>> From: Josef Gajdusek <a...@atx.name>
>>
>> Add a node describing the Security ID memory to the Allwinner H3 .dtsi file.
>>
>> Signed-off-by: Josef Gajdusek <a...@atx.name>
>> ---
>> arch/arm/boot/dts/sun8i-h3.dtsi | 7 +++++++
>> 1 file changed, 7 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
>> index 4a4926b..172576d 100644
>> --- a/arch/arm/boot/dts/sun8i-h3.dtsi
>> +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
>> @@ -389,6 +389,13 @@
>> #size-cells = <0>;
>> };
>>
>> + sid: eeprom@01c14000 {
>> + compatible = "allwinner,sun4i-a10-sid";
>
> This has been discussed before. The hardware is not compatible.
> The write control registers are at different offsets.

I'm not sure what you mean by write control registers. Code in
sunxi_sid.c implements only read access to the nvram. Can you pelase
elaborate?

Ondrej
signature.asc

Ondřej Jirman

unread,
Jun 24, 2016, 5:51:11 PM6/24/16
to Chen-Yu Tsai, dev, linux-arm-kernel, Zhang Rui, Eduardo Valentin, Maxime Ripard, open list, open list:THERMAL
Thanks, I've incorporated all the suggestions (and more :)), except for
the threaded IRQ, which si expalined below.

regards,
Ondrej
As I understand it, thermal_zone_device_update(data->tzd) can do quite a
lot of work and all other thermal drivers defer this call from the hard
irq handler. So, yes, it is necessary.
signature.asc

Ondřej Jirman

unread,
Jun 24, 2016, 6:40:04 PM6/24/16
to Julian Calaby, Linux Sunxi, Mailing List, Arm, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi Julian,

thank you for the review. You're right. I added the pinctrl client
nodes. Also the patches were split incorrectly, so I fixed that too.

regards,
Ondrej
signature.asc

Ondřej Jirman

unread,
Jun 24, 2016, 6:52:02 PM6/24/16
to Chen-Yu Tsai, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hello,

comments below.
Do you mean operating-points, or something else? Different SBCs will
probably require different combinations of operating points just for
safety's sake, because they have different regulators and [some have
botched] thermal designs, so it might make sense to customize it for
differnt boards, and I don't feel adventurous enough setting it for all
H3 boards out there.

Or is this comment related to the missing cpu clock rate message I see
on every boot?

[ 0.058912] /cpus/cpu@0 missing clock-frequency property

regards,
Ondrej
signature.asc

Ondřej Jirman

unread,
Jun 24, 2016, 8:11:39 PM6/24/16
to Chen-Yu Tsai, dev, Mark Brown, Liam Girdwood, linux-arm-kernel, open list
Hi,

thank you for the review. I've resolved most of the issues. Some more
comments below.
I understand the code savings, but I'd rather avoid that, because it
would involve 2 needless readouts and rewrites of the voltage setting
register. I'd rather change this to regmap_write, so that the regulator
only receives writes over I2C, to minimize possibility of bit flip error
by minimizing the communication over the I2C bus.
I checked out a few recently added i2c regulator drivers, and this is
the way they're written. I'd rather not differ, especially since I'm a
beginner with this thing, atm. Also, I'm not sure what chanhge in
particular you're suggesting.

thanks,
Ondrej
signature.asc

Ondřej Jirman

unread,
Jun 24, 2016, 8:35:48 PM6/24/16
to Chen-Yu Tsai, dev, linux-arm-kernel, Zhang Rui, Eduardo Valentin, open list, open list:THERMAL
On 24.6.2016 05:09, Chen-Yu Tsai wrote:
Here devm_reset_control_get will get the exclusive reference. So this
should be ok.

regards,
Ondrej
signature.asc

Chen-Yu Tsai

unread,
Jun 24, 2016, 8:55:28 PM6/24/16
to Ondřej Jirman, Chen-Yu Tsai, dev, linux-arm-kernel, Zhang Rui, Eduardo Valentin, open list, open list:THERMAL
See https://patchwork.kernel.org/patch/9158691/

The generic ones might be removed later on. I remember in another thread
it was asked that new users should use the explicit API, and avoid having
to be converted.

ChenYu

Ondřej Jirman

unread,
Jun 24, 2016, 8:57:07 PM6/24/16
to Chen-Yu Tsai, dev, linux-arm-kernel, open list, open list:THERMAL
I see, thank you, I'll change that.

regards,
Ondrej
signature.asc

Chen-Yu Tsai

unread,
Jun 24, 2016, 9:01:23 PM6/24/16
to Ondřej Jirman, Chen-Yu Tsai, dev, Mark Brown, Liam Girdwood, linux-arm-kernel, open list
OK. It's best to add a comment then, in case someone comes in and refactors it.
See drivers/mfd/axp20x-i2c.c , the last 50 lines or so.

ChenYu

Chen-Yu Tsai

unread,
Jun 24, 2016, 9:03:14 PM6/24/16
to Ondřej Jirman, Chen-Yu Tsai, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
I meant clocks = <...> and clock-latency = <...>.

These 2 are part of the SoC.

The OPP can stay in the board files. It's a pity there's no standard
OPP table for H3 though. :(

ChenYu

Chen-Yu Tsai

unread,
Jun 24, 2016, 9:09:59 PM6/24/16
to Ondřej Jirman, Chen-Yu Tsai, dev, linux-arm-kernel, Josef Gajdusek, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi,

On Sat, Jun 25, 2016 at 3:58 AM, Ondřej Jirman <meg...@megous.com> wrote:
> Hello,
>
> thank you for the review.
>
> On 24.6.2016 04:41, Chen-Yu Tsai wrote:
>> On Fri, Jun 24, 2016 at 3:20 AM, <meg...@megous.com> wrote:
>>> From: Josef Gajdusek <a...@atx.name>
>>>
>>> Add a node describing the Security ID memory to the Allwinner H3 .dtsi file.
>>>
>>> Signed-off-by: Josef Gajdusek <a...@atx.name>
>>> ---
>>> arch/arm/boot/dts/sun8i-h3.dtsi | 7 +++++++
>>> 1 file changed, 7 insertions(+)
>>>
>>> diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
>>> index 4a4926b..172576d 100644
>>> --- a/arch/arm/boot/dts/sun8i-h3.dtsi
>>> +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
>>> @@ -389,6 +389,13 @@
>>> #size-cells = <0>;
>>> };
>>>
>>> + sid: eeprom@01c14000 {
>>> + compatible = "allwinner,sun4i-a10-sid";
>>
>> This has been discussed before. The hardware is not compatible.
>> The write control registers are at different offsets.
>
> I'm not sure what you mean by write control registers. Code in
> sunxi_sid.c implements only read access to the nvram. Can you pelase
> elaborate?

See http://lists.infradead.org/pipermail/linux-arm-kernel/2015-November/388022.html

Also, different compatibles are used for different hardware, regardless
of how close the drivers may be. The driver might only be compatible when
implementing a subset of the possible features. If one were to fully
implement it, they would become incompatible.

To put it another way, the compatible string designates the hardware,
and the driver implements support for that compatible string.

ChenYu

> Ondrej
>
>>
>> ChenYu
>>
>>> + reg = <0x01c14000 0x400>;
>>> + #address-cells = <1>;
>>> + #size-cells = <1>;
>>> + };
>>> +
>>> usbphy: phy@01c19400 {
>>> compatible = "allwinner,sun8i-h3-usb-phy";
>>> reg = <0x01c19400 0x2c>,
>>> --
>>> 2.9.0
>>>
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

meg...@megous.com

unread,
Jun 24, 2016, 11:45:19 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org
This patch series implements thermal regulation on Orange Pi PC
and Orange Pi One.

The patch series contains:
- Thermal sensor driver for Allwinner H3 SoC
- Regulator driver for sy8106a I2C connected regulator
- DTS setup for gpio regulator used on Orange Pi One
- Operating points and thermal zone setup for both SBCs

This is the second version of the patch series with incorporated
changes from the review of the first series.

Changes in v2:

ths:
- removed incorrect use of SID driver in sun8i_ths
- read calibration data directly from iomem
- better explanation for the thermal sensor driver
- dt documentation fixes
- dropped unncecessary macros and init code reorganization
- moved resource aquisition from init to probe function
- deassert reset after clock rate is set, not before
- enable irq after all other registers are configured

sy8106a:
- added dt-bindings for the regulator
- changed to use of_device_id for probing
- added initialization failure checks

dts:
- add missing pinctrl-names for gpio-regulator
- move clocks/clock-latency to sun8i-h3.dtsi

regards,
Ondřej Jirman


meg...@megous.com

unread,
Jun 24, 2016, 11:45:19 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Zhang Rui, Eduardo Valentin, Maxime Ripard, Chen-Yu Tsai, open list, open list:THERMAL
From: Ondrej Jirman <meg...@megous.com>

This patch adds support for the sun8i thermal sensor on
Allwinner H3 SoC.

Signed-off-by: Ondřej Jirman <meg...@megous.com>
---
v2:
- removed incorrect use of SID driver in sun8i_ths
- read calibration data directly from iomem
- better explanation for the thermal sensor driver
- dt documentation fixes
- dropped unncecessary macros and init code reorganization
- moved resource aquisition from init to probe function
- deassert reset after clock rate is set, not before
- enable irq after all other registers are configured
---
drivers/thermal/Kconfig | 7 ++
drivers/thermal/Makefile | 1 +
drivers/thermal/sun8i_ths.c | 260 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 268 insertions(+)
create mode 100644 drivers/thermal/sun8i_ths.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2d702ca..d3209d9 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -351,6 +351,13 @@ config MTK_THERMAL
Enable this option if you want to have support for thermal management
controller present in Mediatek SoCs

+config SUN8I_THS
+ tristate "Thermal sensor driver for Allwinner H3"
+ depends on MACH_SUN8I
+ depends on OF
+ help
+ Enable this to support thermal reporting on some newer Allwinner SoCs.
+
menu "Texas Instruments thermal drivers"
depends on ARCH_HAS_BANDGAP || COMPILE_TEST
depends on HAS_IOMEM
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 10b07c1..7261ee8 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -51,3 +51,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
+obj-$(CONFIG_SUN8I_THS) += sun8i_ths.o
diff --git a/drivers/thermal/sun8i_ths.c b/drivers/thermal/sun8i_ths.c
new file mode 100644
index 0000000..9ba0f96
--- /dev/null
+++ b/drivers/thermal/sun8i_ths.c
@@ -0,0 +1,260 @@
+/*
+ * Thermal sensor driver for Allwinner H3 SoC
+ *
+ * Copyright (C) 2016 Ondřej Jirman
+ * Based on the work of Josef Gajdusek <a...@atx.name>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+#include <linux/printk.h>
+
+#define THS_H3_CTRL0 0x00
+#define THS_H3_CTRL2 0x40
+#define THS_H3_INT_CTRL 0x44
+#define THS_H3_STAT 0x48
+#define THS_H3_FILTER 0x70
+#define THS_H3_CDATA 0x74
+#define THS_H3_DATA 0x80
+
+#define THS_H3_CTRL0_SENSOR_ACQ0(x) (x)
+#define THS_H3_CTRL2_SENSE_EN BIT(0)
+#define THS_H3_CTRL2_SENSOR_ACQ1(x) ((x) << 16)
+#define THS_H3_INT_CTRL_DATA_IRQ_EN BIT(8)
+#define THS_H3_INT_CTRL_THERMAL_PER(x) ((x) << 12)
+#define THS_H3_STAT_DATA_IRQ_STS BIT(8)
+#define THS_H3_FILTER_TYPE(x) ((x) << 0)
+#define THS_H3_FILTER_EN BIT(2)
+
+#define THS_H3_CLK_IN 40000000 /* Hz */
+#define THS_H3_DATA_PERIOD 330 /* ms */
+
+#define THS_H3_FILTER_TYPE_VALUE 2 /* average over 2^(n+1) samples */
+#define THS_H3_FILTER_DIV (1 << (THS_H3_FILTER_TYPE_VALUE + 1))
+#define THS_H3_INT_CTRL_THERMAL_PER_VALUE \
+ (THS_H3_DATA_PERIOD * (THS_H3_CLK_IN / 1000) / THS_H3_FILTER_DIV / 4096 - 1)
+#define THS_H3_CTRL0_SENSOR_ACQ0_VALUE 0x3f /* 16us */
+#define THS_H3_CTRL2_SENSOR_ACQ1_VALUE 0x3f
+
+struct sun8i_ths_data {
+ struct reset_control *reset;
+ struct clk *clk;
+ struct clk *busclk;
+ void __iomem *regs;
+ void __iomem *calreg;
+ struct thermal_zone_device *tzd;
+ u32 temp;
+};
+
+static int sun8i_ths_get_temp(void *_data, int *out)
+{
+ struct sun8i_ths_data *data = _data;
+
+ if (data->temp == 0)
+ return -EINVAL;
+
+ /* Formula and parameters from the Allwinner 3.4 kernel */
+ *out = 217000 - (int)((data->temp * 1000000) / 8253);
+ return 0;
+}
+
+static irqreturn_t sun8i_ths_irq_thread(int irq, void *_data)
+{
+ struct sun8i_ths_data *data = _data;
+
+ writel(THS_H3_STAT_DATA_IRQ_STS, data->regs + THS_H3_STAT);
+
+ data->temp = readl(data->regs + THS_H3_DATA);
+ if (data->temp)
+ thermal_zone_device_update(data->tzd);
+
+ return IRQ_HANDLED;
+}
+
+static void sun8i_ths_h3_init(struct sun8i_ths_data *data)
+{
+ u32 caldata;
+
+ caldata = readl(data->calreg) & 0xfff;
+ if (caldata != 0)
+ writel(caldata, data->regs + THS_H3_CDATA);
+
+ writel(THS_H3_CTRL0_SENSOR_ACQ0(THS_H3_CTRL0_SENSOR_ACQ0_VALUE),
+ data->regs + THS_H3_CTRL0);
+ writel(THS_H3_FILTER_EN | THS_H3_FILTER_TYPE(THS_H3_FILTER_TYPE_VALUE),
+ data->regs + THS_H3_FILTER);
+ writel(THS_H3_CTRL2_SENSOR_ACQ1(THS_H3_CTRL2_SENSOR_ACQ1_VALUE) |
+ THS_H3_CTRL2_SENSE_EN,
+ data->regs + THS_H3_CTRL2);
+ writel(THS_H3_INT_CTRL_THERMAL_PER(THS_H3_INT_CTRL_THERMAL_PER_VALUE) |
+ THS_H3_INT_CTRL_DATA_IRQ_EN,
+ data->regs + THS_H3_INT_CTRL);
+}
+
+static const struct thermal_zone_of_device_ops sun8i_ths_thermal_ops = {
+ .get_temp = sun8i_ths_get_temp,
+};
+
+static int sun8i_ths_probe(struct platform_device *pdev)
+{
+ struct sun8i_ths_data *data;
+ struct resource *res;
+ int ret;
+ int irq;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no memory resources defined\n");
+ return -EINVAL;
+ }
+
+ data->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->regs)) {
+ ret = PTR_ERR(data->regs);
+ dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "no calibration data memory resource defined\n");
+ return -EINVAL;
+ }
+
+ data->calreg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->calreg)) {
+ ret = PTR_ERR(data->calreg);
+ dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret);
+ return ret;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ: %d\n", irq);
+ return irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ sun8i_ths_irq_thread, IRQF_ONESHOT,
+ dev_name(&pdev->dev), data);
+ if (ret)
+ return ret;
+
+ data->busclk = devm_clk_get(&pdev->dev, "ahb");
+ if (IS_ERR(data->busclk)) {
+ ret = PTR_ERR(data->busclk);
+ dev_err(&pdev->dev, "failed to get ahb clk: %d\n", ret);
+ return ret;
+ }
+
+ data->clk = devm_clk_get(&pdev->dev, "ths");
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ dev_err(&pdev->dev, "failed to get ths clk: %d\n", ret);
+ return ret;
+ }
+
+ data->reset = devm_reset_control_get(&pdev->dev, "ahb");
+ if (IS_ERR(data->reset)) {
+ ret = PTR_ERR(data->reset);
+ dev_err(&pdev->dev, "failed to get reset: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(data->busclk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable bus clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable ths clk: %d\n", ret);
+ goto err_disable_bus;
+ }
+
+ ret = clk_set_rate(data->clk, THS_H3_CLK_IN);
+ if (ret)
+ goto err_disable_ths;
+
+ ret = reset_control_deassert(data->reset);
+ if (ret) {
+ dev_err(&pdev->dev, "reset deassert failed: %d\n", ret);
+ goto err_disable_ths;
+ }
+
+ sun8i_ths_h3_init(data);
+
+ data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
+ &sun8i_ths_thermal_ops);
+ if (IS_ERR(data->tzd)) {
+ ret = PTR_ERR(data->tzd);
+ dev_err(&pdev->dev, "failed to register thermal zone: %d\n",
+ ret);
+ goto err_assert_reset;
+ }
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+
+err_assert_reset:
+ reset_control_assert(data->reset);
+err_disable_ths:
+ clk_disable_unprepare(data->clk);
+err_disable_bus:
+ clk_disable_unprepare(data->busclk);
+ return ret;
+}
+
+static int sun8i_ths_remove(struct platform_device *pdev)
+{
+ struct sun8i_ths_data *data = platform_get_drvdata(pdev);
+
+ thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
+ reset_control_assert(data->reset);
+ clk_disable_unprepare(data->clk);
+ clk_disable_unprepare(data->busclk);
+ return 0;
+}
+
+static const struct of_device_id sun8i_ths_id_table[] = {
+ { .compatible = "allwinner,sun8i-h3-ths", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sun8i_ths_id_table);
+
+static struct platform_driver sun8i_ths_driver = {
+ .probe = sun8i_ths_probe,
+ .remove = sun8i_ths_remove,
+ .driver = {
+ .name = "sun8i_ths",
+ .of_match_table = sun8i_ths_id_table,
+ },
+};
+
+module_platform_driver(sun8i_ths_driver);
+
+MODULE_AUTHOR("Ondřej Jirman <meg...@megous.com>");
+MODULE_DESCRIPTION("Thermal sensor driver for Allwinner H3 SoC");

meg...@megous.com

unread,
Jun 24, 2016, 11:45:19 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Josef Gajdusek, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Maxime Ripard, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Josef Gajdusek <a...@atx.name>

This patch adds a driver for the THS clock which is present on the
Allwinner H3.

Signed-off-by: Josef Gajdusek <a...@atx.name>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-h3-ths.c | 98 +++++++++++++++++++++++
3 files changed, 100 insertions(+)
create mode 100644 drivers/clk/sunxi/clk-h3-ths.c

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 8f7619d..5faae05 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -87,6 +87,7 @@ Required properties:
"allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
"allwinner,sun4i-a10-ve-clk" - for the Video Engine clock
"allwinner,sun6i-a31-display-clk" - for the display clocks
+ "allwinner,sun8i-h3-ths-clk" - for THS on H3

Required properties for all clocks:
- reg : shall be the control register address for the clock.
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 39d2044..8e245e3 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -9,6 +9,7 @@ obj-y += clk-a10-mod1.o
obj-y += clk-a10-pll2.o
obj-y += clk-a10-ve.o
obj-y += clk-a20-gmac.o
+obj-y += clk-h3-ths.o
obj-y += clk-mod0.o
obj-y += clk-simple-gates.o
obj-y += clk-sun4i-display.o
diff --git a/drivers/clk/sunxi/clk-h3-ths.c b/drivers/clk/sunxi/clk-h3-ths.c
new file mode 100644
index 0000000..c1d6d32
--- /dev/null
+++ b/drivers/clk/sunxi/clk-h3-ths.c
@@ -0,0 +1,98 @@
+/*
+ * sun8i THS clock driver
+ *
+ * Copyright (C) 2015 Josef Gajdusek
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define SUN8I_H3_THS_CLK_ENABLE 31
+#define SUN8I_H3_THS_CLK_DIVIDER_SHIFT 0
+#define SUN8I_H3_THS_CLK_DIVIDER_WIDTH 2
+
+static DEFINE_SPINLOCK(sun8i_h3_ths_clk_lock);
+
+static const struct clk_div_table sun8i_h3_ths_clk_table[] __initconst = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 2 },
+ { .val = 2, .div = 4 },
+ { .val = 3, .div = 6 },
+ { } /* sentinel */
+};
+
+static void __init sun8i_h3_ths_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct clk_gate *gate;
+ struct clk_divider *div;
+ const char *parent;
+ const char *clk_name = node->name;
+ void __iomem *reg;
+ int err;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+
+ if (IS_ERR(reg))
+ return;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ goto err_unmap;
+
+ div = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!div)
+ goto err_gate_free;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ parent = of_clk_get_parent_name(node, 0);
+
+ gate->reg = reg;
+ gate->bit_idx = SUN8I_H3_THS_CLK_ENABLE;
+ gate->lock = &sun8i_h3_ths_clk_lock;
+
+ div->reg = reg;
+ div->shift = SUN8I_H3_THS_CLK_DIVIDER_SHIFT;
+ div->width = SUN8I_H3_THS_CLK_DIVIDER_WIDTH;
+ div->table = sun8i_h3_ths_clk_table;
+ div->lock = &sun8i_h3_ths_clk_lock;
+
+ clk = clk_register_composite(NULL, clk_name, &parent, 1,
+ NULL, NULL,
+ &div->hw, &clk_divider_ops,
+ &gate->hw, &clk_gate_ops,
+ CLK_SET_RATE_PARENT);
+
+ if (IS_ERR(clk))
+ goto err_div_free;
+
+ err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (err)
+ goto err_unregister_clk;
+
+ return;
+
+err_unregister_clk:
+ clk_unregister(clk);
+err_gate_free:
+ kfree(gate);
+err_div_free:
+ kfree(div);
+err_unmap:
+ iounmap(reg);
+}
+
+CLK_OF_DECLARE(sun8i_h3_ths_clk, "allwinner,sun8i-h3-ths-clk",
+ sun8i_h3_ths_clk_setup);
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:21 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland, Maxime Ripard, Chen-Yu Tsai, open list:THERMAL, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

This patch adds the binding documentation for the
sun8i_ths driver. This is a driver for thermal sensor
found in Allwinner H3 SoC.

Signed-off-by: Ondřej Jirman <meg...@megous.com>
---
.../devicetree/bindings/thermal/sun8i-ths.txt | 26 ++++++++++++++++++++++
1 file changed, 26 insertions(+)
create mode 100644 Documentation/devicetree/bindings/thermal/sun8i-ths.txt

diff --git a/Documentation/devicetree/bindings/thermal/sun8i-ths.txt b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt
new file mode 100644
index 0000000..76859d4
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/sun8i-ths.txt
@@ -0,0 +1,26 @@
+* Thermal sensor driver for Allwinner H3 SoC
+
+Required properties:
+- compatible : "allwinner,sun8i-h3-ths"
+- reg : Address range of the thermal sensor registers and of the calibration
+ data
+- resets : Must contain phandles to reset controls matching the entries
+ of the names
+- reset-names : Must include the name "ahb"
+- clocks : Must contain phandles to clock controls matching the entries
+ of the names
+- clock-names : Must contain "ahb" for the bus gate and "ths" for the THS
+ clock
+
+Example:
+ths: ths@01c25000 {
+ #thermal-sensor-cells = <0>;
+ compatible = "allwinner,sun8i-h3-ths";
+ reg = <0x01c25000 0x400>,
+ <0x01c14234 0x4>;
+ interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&bus_rst 136>;
+ reset-names = "ahb";
+ clocks = <&bus_gates 72>, <&ths_clk>;
+ clock-names = "ahb", "ths";
+};
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:22 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Liam Girdwood, Mark Brown, open list
From: Ondrej Jirman <meg...@megous.com>

SY8106A is I2C attached single output voltage regulator
made by Silergy.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
v2
- added dt-bindings for the regulator
- changed to use of_device_id for probing
- added initialization failure checks
---
drivers/regulator/Kconfig | 8 +-
drivers/regulator/Makefile | 2 +-
drivers/regulator/sy8106a-regulator.c | 171 ++++++++++++++++++++++++++++++++++
3 files changed, 179 insertions(+), 2 deletions(-)
create mode 100644 drivers/regulator/sy8106a-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 144cbf5..93f3fe4f 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -702,6 +702,13 @@ config REGULATOR_STW481X_VMMC
This driver supports the internal VMMC regulator in the STw481x
PMIC chips.

+config REGULATOR_SY8106A
+ tristate "Silergy SY8106A"
+ depends on I2C && (OF || COMPILE_TEST)
+ select REGMAP_I2C
+ help
+ This driver provides support for SY8106A voltage regulator.
+
config REGULATOR_TPS51632
tristate "TI TPS51632 Power Regulator"
depends on I2C
@@ -861,4 +868,3 @@ config REGULATOR_WM8994
WM8994 CODEC.

endif
-
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 85a1d44..e3f720f 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_REGULATOR_SKY81452) += sky81452-regulator.o
obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o
+obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o
obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
@@ -111,5 +112,4 @@ obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o

-
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/sy8106a-regulator.c b/drivers/regulator/sy8106a-regulator.c
new file mode 100644
index 0000000..98626bc
--- /dev/null
+++ b/drivers/regulator/sy8106a-regulator.c
@@ -0,0 +1,171 @@
+/*
+ * sy8106a-regulator.c - Regulator device driver for SY8106A
+ *
+ * Copyright (C) 2016 Ondřej Jirman <meg...@megous.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SY8106A_REG_VOUT1_SEL 0x01
+#define SY8106A_REG_VOUT_COM 0x02
+#define SY8106A_REG_VOUT1_SEL_MASK 0x7f
+#define SY8106A_DISABLE_REG BIT(0)
+#define SY8106A_GO_BIT BIT(7)
+
+struct sy8106a {
+ struct regulator_dev *rdev;
+ struct regmap *regmap;
+};
+
+static const struct regmap_config sy8106a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int sy8106a_set_voltage_sel(struct regulator_dev *rdev, unsigned sel)
+{
+ /* We use our set_voltage_sel in order to avoid unnecessary I2C chatter,
+ * because the regulator_get_voltage_sel_regmap using apply_bit
+ * would perform 4 unnecessary transfers instead of one, increasing the
+ * chance of error.
+ */
+ return regmap_write(rdev->regmap, rdev->desc->vsel_reg,
+ sel | SY8106A_GO_BIT);
+}
+
+ return -ENOMEM;
+
+ chip->regmap = devm_regmap_init_i2c(i2c, &sy8106a_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ error = PTR_ERR(chip->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ error);
+ return error;
+ }
+
+ config.dev = &i2c->dev;
+ config.regmap = chip->regmap;
+ config.of_node = dev->of_node;
+ config.driver_data = chip;
+ config.init_data = of_get_regulator_init_data(dev, dev->of_node, &sy8106a_reg);
+ if (!config.init_data) {
+ return -EINVAL;
+ }
+
+ /* Probe regulator */
+ error = regmap_read(chip->regmap, SY8106A_REG_VOUT1_SEL, &selector);
+ if (error) {
+ dev_err(&i2c->dev, "Failed to read voltage at probe time: %d\n", error);
+ return error;
+ }
+
+ dev_info(&i2c->dev, "SY8106A voltage at boot: %u mV\n", SY8106A_MIN_MV +
+ SY8106A_STEP_MV * (selector & SY8106A_REG_VOUT1_SEL_MASK));
+
+ rdev = devm_regulator_register(&i2c->dev, &sy8106a_reg, &config);
+ if (IS_ERR(rdev)) {
+ error = PTR_ERR(rdev);
+ dev_err(&i2c->dev, "Failed to register SY8106A regulator: %d\n", error);
+ return error;
+ }
+
+ chip->rdev = rdev;
+
+ i2c_set_clientdata(i2c, chip);
+
+ return 0;
+}
+
+static const struct of_device_id sy8106a_i2c_of_match[] = {
+ { .compatible = "silergy,sy8106a" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sy8106a_i2c_of_match);
+
+/*
+ * This is useless for OF-enabled devices, but it is needed by I2C subsystem
+ */
+static const struct i2c_device_id sy8106a_i2c_id[] = {
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);
+
+static struct i2c_driver sy8106a_regulator_driver = {
+ .driver = {
+ .name = "sy8106a",
+ .of_match_table = of_match_ptr(sy8106a_i2c_of_match),
+ },
+ .probe = sy8106a_i2c_probe,
+ .id_table = sy8106a_i2c_id,
+};
+
+module_i2c_driver(sy8106a_regulator_driver);
+
+MODULE_AUTHOR("Ondřej Jirman <meg...@megous.com>");
+MODULE_DESCRIPTION("Regulator device driver for Silergy SY8106A");

meg...@megous.com

unread,
Jun 24, 2016, 11:45:23 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Maxime Ripard, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

PLL1 on H3 requires special factors application algorithm,
when the rate is changed. This algorithm was extracted
from the arisc code that handles frequency scaling
in the BSP kernel.

This commit adds optional apply function to
struct factors_data, that can implement non-trivial
factors application method, when necessary.

Also struct clk_factors_config is extended with position
of the PLL lock flag.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
drivers/clk/sunxi/clk-factors.c | 34 +++++------
drivers/clk/sunxi/clk-factors.h | 12 ++++
drivers/clk/sunxi/clk-sunxi.c | 72 ++++++++++++++++++++++-
4 files changed, 98 insertions(+), 21 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 5faae05..774500c 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -10,6 +10,7 @@ Required properties:
"allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
"allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
+ "allwinner,sun8i-h3-pll1-clk" - for the main PLL clock on H3
"allwinner,sun4i-a10-pll3-clk" - for the video PLL clock on A10
"allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80
"allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index ddefe96..7c165db 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -34,13 +34,6 @@

#define FACTORS_MAX_PARENTS 5

-#define SETMASK(len, pos) (((1U << (len)) - 1) << (pos))
-#define CLRMASK(len, pos) (~(SETMASK(len, pos)))
-#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
-
-#define FACTOR_SET(bit, len, reg, val) \
- (((reg) & CLRMASK(len, bit)) | (val << (bit)))
-
static unsigned long clk_factors_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -150,20 +143,24 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
if (factors->lock)
spin_lock_irqsave(factors->lock, flags);

- /* Fetch the register value */
- reg = readl(factors->reg);
+ if (factors->apply) {
+ factors->apply(factors, &req);
+ } else {
+ /* Fetch the register value */
+ reg = readl(factors->reg);

- /* Set up the new factors - macros do not do anything if width is 0 */
- reg = FACTOR_SET(config->nshift, config->nwidth, reg, req.n);
- reg = FACTOR_SET(config->kshift, config->kwidth, reg, req.k);
- reg = FACTOR_SET(config->mshift, config->mwidth, reg, req.m);
- reg = FACTOR_SET(config->pshift, config->pwidth, reg, req.p);
+ /* Set up the new factors - macros do not do anything if width is 0 */
+ reg = FACTOR_SET(config->nshift, config->nwidth, reg, req.n);
+ reg = FACTOR_SET(config->kshift, config->kwidth, reg, req.k);
+ reg = FACTOR_SET(config->mshift, config->mwidth, reg, req.m);
+ reg = FACTOR_SET(config->pshift, config->pwidth, reg, req.p);

- /* Apply them now */
- writel(reg, factors->reg);
+ /* Apply them now */
+ writel(reg, factors->reg);

- /* delay 500us so pll stabilizes */
- __delay((rate >> 20) * 500 / 2);
+ /* delay 500us so pll stabilizes */
+ __delay((rate >> 20) * 500 / 2);
+ }

if (factors->lock)
spin_unlock_irqrestore(factors->lock, flags);
@@ -213,6 +210,7 @@ struct clk *sunxi_factors_register(struct device_node *node,
factors->config = data->table;
factors->get_factors = data->getter;
factors->recalc = data->recalc;
+ factors->apply = data->apply;
factors->lock = lock;

/* Add a gate if this factor clock can be gated */
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
index 1e63c5b..661a45a 100644
--- a/drivers/clk/sunxi/clk-factors.h
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -6,6 +6,13 @@

#define SUNXI_FACTORS_NOT_APPLICABLE (0)

+#define SETMASK(len, pos) (((1U << (len)) - 1) << (pos))
+#define CLRMASK(len, pos) (~(SETMASK(len, pos)))
+#define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
+
+#define FACTOR_SET(bit, len, reg, val) \
+ (((reg) & CLRMASK(len, bit)) | (val << (bit)))
+
struct clk_factors_config {
u8 nshift;
u8 nwidth;
@@ -16,6 +23,7 @@ struct clk_factors_config {
u8 pshift;
u8 pwidth;
u8 n_start;
+ u8 lock;
};

struct factors_request {
@@ -28,6 +36,8 @@ struct factors_request {
u8 p;
};

+struct clk_factors;
+
struct factors_data {
int enable;
int mux;
@@ -35,6 +45,7 @@ struct factors_data {
const struct clk_factors_config *table;
void (*getter)(struct factors_request *req);
void (*recalc)(struct factors_request *req);
+ void (*apply)(struct clk_factors *factors, struct factors_request *req);
const char *name;
};

@@ -44,6 +55,7 @@ struct clk_factors {
const struct clk_factors_config *config;
void (*get_factors)(struct factors_request *req);
void (*recalc)(struct factors_request *req);
+ void (*apply)(struct clk_factors *factors, struct factors_request *req);
spinlock_t *lock;
/* for cleanup */
struct clk_mux *mux;
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 838b22a..e4bb908 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/log2.h>
+#include <linux/delay.h>

#include "clk-factors.h"

@@ -200,6 +201,56 @@ static void sun8i_a23_get_pll1_factors(struct factors_request *req)
}

/**
+ * sun8i_h3_apply_pll1_factors() - applies n, k, m, p factors to the
+ * register using an algorithm that tries to reserve the PLL lock
+ */
+
+static void sun8i_h3_apply_pll1_factors(struct clk_factors *factors, struct factors_request *req)
+{
+ const struct clk_factors_config *config = factors->config;
+ u32 reg;
+
+ /* Fetch the register value */
+ reg = readl(factors->reg);
+
+ if (FACTOR_GET(config->pshift, config->pwidth, reg) < req->p) {
+ reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
+
+ writel(reg, factors->reg);
+ __delay(2000);
+ }
+
+ if (FACTOR_GET(config->mshift, config->mwidth, reg) < req->m) {
+ reg = FACTOR_SET(config->mshift, config->mwidth, reg, req->m);
+
+ writel(reg, factors->reg);
+ __delay(2000);
+ }
+
+ reg = FACTOR_SET(config->nshift, config->nwidth, reg, req->n);
+ reg = FACTOR_SET(config->kshift, config->kwidth, reg, req->k);
+
+ writel(reg, factors->reg);
+ __delay(20);
+
+ while (!(readl(factors->reg) & (1 << config->lock)));
+
+ if (FACTOR_GET(config->mshift, config->mwidth, reg) > req->m) {
+ reg = FACTOR_SET(config->mshift, config->mwidth, reg, req->m);
+
+ writel(reg, factors->reg);
+ __delay(2000);
+ }
+
+ if (FACTOR_GET(config->pshift, config->pwidth, reg) > req->p) {
+ reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
+
+ writel(reg, factors->reg);
+ __delay(2000);
+ }
+}
+
+/**
* sun4i_get_pll5_factors() - calculates n, k factors for PLL5
* PLL5 rate is calculated as follows
* rate = parent_rate * n * (k + 1)
@@ -451,6 +502,7 @@ static const struct clk_factors_config sun8i_a23_pll1_config = {
.pshift = 16,
.pwidth = 2,
.n_start = 1,
+ .lock = 28
};

static const struct clk_factors_config sun4i_pll5_config = {
@@ -513,6 +565,13 @@ static const struct factors_data sun8i_a23_pll1_data __initconst = {
.getter = sun8i_a23_get_pll1_factors,
};

+static const struct factors_data sun8i_h3_pll1_data __initconst = {
+ .enable = 31,
+ .table = &sun8i_a23_pll1_config,
+ .getter = sun8i_a23_get_pll1_factors,
+ .apply = sun8i_h3_apply_pll1_factors,
+};
+
static const struct factors_data sun7i_a20_pll4_data __initconst = {
.enable = 31,
.table = &sun4i_pll5_config,
@@ -590,12 +649,19 @@ static void __init sun6i_pll1_clk_setup(struct device_node *node)
CLK_OF_DECLARE(sun6i_pll1, "allwinner,sun6i-a31-pll1-clk",
sun6i_pll1_clk_setup);

-static void __init sun8i_pll1_clk_setup(struct device_node *node)
+static void __init sun8i_a23_pll1_clk_setup(struct device_node *node)
{
sunxi_factors_clk_setup(node, &sun8i_a23_pll1_data);
}
-CLK_OF_DECLARE(sun8i_pll1, "allwinner,sun8i-a23-pll1-clk",
- sun8i_pll1_clk_setup);
+CLK_OF_DECLARE(sun8i_a23_pll1, "allwinner,sun8i-a23-pll1-clk",
+ sun8i_a23_pll1_clk_setup);
+
+static void __init sun8i_h3_pll1_clk_setup(struct device_node *node)
+{
+ sunxi_factors_clk_setup(node, &sun8i_h3_pll1_data);
+}
+CLK_OF_DECLARE(sun8i_h3_pll1, "allwinner,sun8i-h3-pll1-clk",
+ sun8i_h3_pll1_clk_setup);

static void __init sun7i_pll4_clk_setup(struct device_node *node)
{
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:23 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

PLL1 on H3 requires special factors application algorithm,
when the rate is changed. This algorithm was extracted
from the arisc code that handles frequency scaling
in the BSP kernel.

This algorithm is implemented by sun8i-h3-pll1-clk.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 4a4926b..b3247f4 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -106,7 +106,7 @@

pll1: clk@01c20000 {
#clock-cells = <0>;
- compatible = "allwinner,sun8i-a23-pll1-clk";
+ compatible = "allwinner,sun8i-h3-pll1-clk";
reg = <0x01c20000 0x4>;
clocks = <&osc24M>;
clock-output-names = "pll1";
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:23 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Liam Girdwood, Mark Brown, Rob Herring, Mark Rutland, open list:VOLTAGE AND CURRENT REGULATOR FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
From: Ondrej Jirman <meg...@megous.com>

This patch adds the binding documentation for the
sy8106a regulator driver.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
.../bindings/regulator/sy8106a-regulator.txt | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt

diff --git a/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
new file mode 100644
index 0000000..1e623a34
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/sy8106a-regulator.txt
@@ -0,0 +1,21 @@
+SY8106A Voltage regulator
+
+Required properties:
+- compatible: Must be "silergy,sy8106a"
+- reg: I2C slave address - must be <0x65>
+
+Any property defined as part of the core regulator binding, defined in
+regulator.txt, can also be used.
+
+Example:
+
+ sy8106a {
+ compatible = "silergy,sy8106a";
+ reg = <0x65>;
+ regulator-name = "sy8106a-vdd";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-ramp-delay = <200>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:24 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Add label to the first cpu so that it can be referenced
from derived dts files.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
v2
- move clocks/clock-latency to sun8i-h3.dtsi
---
arch/arm/boot/dts/sun8i-h3.dtsi | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index d3c29cc..56f211e 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -52,7 +52,9 @@
#address-cells = <1>;
#size-cells = <0>;

- cpu@0 {
+ cpu0: cpu@0 {
+ clocks = <&cpu>;
+ clock-latency = <244144>; /* 8 32k periods */
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:24 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

This patch adds nodes for the thermal sensor driver and
the THS clock to the Allwinner sun8i-h3.dtsi file.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index b3247f4..d3c29cc 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -77,6 +77,14 @@
};
};

+ thermal-zones {
+ cpu_thermal: cpu_thermal {
+ polling-delay-passive = <330>;
+ polling-delay = <1000>;
+ thermal-sensors = <&ths 0>;
+ };
+ };
+
timer {
compatible = "arm,armv7-timer";
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -239,6 +247,14 @@
"bus_scr", "bus_ephy", "bus_dbg";
};

+ ths_clk: clk@01c20074 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun8i-h3-ths-clk";
+ reg = <0x01c20074 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "ths";
+ };
+
mmc0_clk: clk@01c20088 {
#clock-cells = <1>;
compatible = "allwinner,sun4i-a10-mmc-clk";
@@ -574,6 +590,18 @@
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
};

+ ths: ths@01c25000 {
+ #thermal-sensor-cells = <0>;
+ compatible = "allwinner,sun8i-h3-ths";
+ reg = <0x01c25000 0x400>,
+ <0x01c14234 0x4>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ resets = <&apb1_rst 8>;
+ reset-names = "ahb";
+ clocks = <&bus_gates 72>, <&ths_clk>;
+ clock-names = "ahb", "ths";
+ };
+
uart0: serial@01c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:24 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

H3 SoC contains I2C controller optionally available
on the PL0 and PL1 pins. This patch makes this controller
available.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3.dtsi | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
index 56f211e..e32f211 100644
--- a/arch/arm/boot/dts/sun8i-h3.dtsi
+++ b/arch/arm/boot/dts/sun8i-h3.dtsi
@@ -322,8 +322,9 @@
reg = <0x01f01428 0x4>;
#clock-cells = <1>;
clocks = <&apb0>;
- clock-indices = <0>, <1>;
- clock-output-names = "apb0_pio", "apb0_ir";
+ clock-indices = <0>, <1>, <6>;
+ clock-output-names = "apb0_pio", "apb0_ir", "apb0_i2c";
+
};

ir_clk: ir_clk@01f01454 {
@@ -656,6 +657,20 @@
status = "disabled";
};

+ r_twi: i2c@01f02400 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x01f02400 0x400>;
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_twi_pins_a>;
+ clocks = <&apb0_gates 6>;
+ clock-frequency = <100000>;
+ resets = <&apb0_reset 6>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
gic: interrupt-controller@01c81000 {
compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
reg = <0x01c81000 0x1000>,
@@ -707,6 +722,13 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ r_twi_pins_a: r_twi@0 {
+ allwinner,pins = "PL0", "PL1";
+ allwinner,function = "s_twi";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
};
};
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:25 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Orange PI PC uses SY8106A regulator for fine grained CPUX voltage
regulation. Setup appropriate operating points for the board.
---
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 48 ++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index 79f0b49..1b029e9 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -90,6 +90,54 @@
};
};

+&cpu0 {
+ operating-points = <
+ /* kHz uV */
+ 1512000 1400000
+ 1440000 1400000
+ 1368000 1340000
+ 1344000 1340000
+ 1296000 1340000
+ 1248000 1300000
+ 1224000 1300000
+ 1200000 1300000
+ 1104000 1200000
+ 1008000 1140000
+ 960000 1100000
+ 648000 1100000
+ 480000 1100000
+ 240000 1100000
+ 120000 1100000
+ >;
+ #cooling-cells = <2>;
+ cooling-min-level = <0>;
+ cooling-max-level = <14>;
+ cpu0-supply = <&vdd_cpu>;
+};
+
+&cpu_thermal {
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&cpu0 (-1) (-1)>;
+ };
+ };
+
+ trips {
+ cpu_alert0: cpu_alert0 {
+ temperature = <80000>;
+ hysteresis = <2000>;
+ type = "passive";
+ };
+
+ cpu_crit: cpu_crit {
+ temperature = <100000>;
+ hysteresis = <2000>;
+ type = "critical";
+ };
+ };
+};
+
&r_twi {
status = "okay";

--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:25 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Xulong Orange Pi One uses GPIO based regulator that
switches between two voltages: 1.1V and 1.3V. The
regulator is controlled from the PL6 pin.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
v2
- add missing pinctrl-names for gpio-regulator
---
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
index 0adf932..b1bd6b0 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
@@ -88,6 +88,25 @@
gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
};
};
+
+ vdd_soc: gpio-regulator {
+ compatible = "regulator-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&vdd_reg_r_opc>;
+
+ regulator-name = "soc-vdd-supply";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-boot-on;
+ regulator-type = "voltage";
+
+ gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>;
+ states = <1100000 0x0
+ 1300000 0x1>;
+
+ startup-delay-us = <100000>;
+ enable-active-high;
+ };
};

&ehci1 {
@@ -131,6 +150,13 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ vdd_reg_r_opc: regulator_pins@0 {
+ allwinner,pins = "PL6";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};

&uart0 {
--
2.9.0

meg...@megous.com

unread,
Jun 24, 2016, 11:45:25 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Use Xulong Orange Pi One GPIO based regulator for
passive cooling and thermal management.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 39 +++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
index b1bd6b0..a38d871 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
@@ -109,6 +109,45 @@
};
};

+&cpu0 {
+ operating-points = <
+ /* kHz uV */
+ 1296000 1300000
+ 1200000 1300000
+ 624000 1100000
+ 480000 1100000
+ 312000 1100000
+ 240000 1100000
+ >;
+ #cooling-cells = <2>;
+ cooling-min-level = <0>;
+ cooling-max-level = <5>;
+ cpu0-supply = <&vdd_soc>;
&ehci1 {

meg...@megous.com

unread,
Jun 24, 2016, 11:45:25 PM6/24/16
to d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Ondrej Jirman, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
From: Ondrej Jirman <meg...@megous.com>

Add sy8106a regulator to r_twi bus and enable the r_twi bus on
Orange Pi PC. This regulator controls the CPUX voltage.

Signed-off-by: Ondrej Jirman <meg...@megous.com>
---
arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index daf50b9a6..79f0b49 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -90,6 +90,20 @@
};
};

+&r_twi {
+ status = "okay";
+
+ vdd_cpu: regulator@65 {
+ compatible = "silergy,sy8106a";
+ reg = <0x65>;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-ramp-delay = <200>;
+ regulator-boot-on;
+ regulator-always-on;

Maxime Ripard

unread,
Jun 25, 2016, 3:02:10 AM6/25/16
to Chen-Yu Tsai, Ondřej Jirman, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
This has never been the case, and we always had some deviation in the
FEX files for all the SoCs.

If we could come up with standard OPPs that work for every one,
there's no reason it can't happen here.

I don't really see why the thermal design should change anything. If a
boards heats faster, it will throttle down to a lower OPP faster, but
those OPPs are not going to change.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
signature.asc

Maxime Ripard

unread,
Jun 25, 2016, 3:10:51 AM6/25/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Zhang Rui, Eduardo Valentin, Chen-Yu Tsai, open list, open list:THERMAL
Why did you remove the SID use through the nvmem framework ?!
Having runtime_pm support would be great.


> + sun8i_ths_h3_init(data);
> +
> + data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
> + &sun8i_ths_thermal_ops);
> + if (IS_ERR(data->tzd)) {
> + ret = PTR_ERR(data->tzd);
> + dev_err(&pdev->dev, "failed to register thermal zone: %d\n",
> + ret);
> + goto err_assert_reset;
> + }

You reference data->tzd in your interrupt handler, and the interrupts
have been activated before initializing that field. That is likely to
cause a kernel crash when you receive an interrupt between your
request_irq and that call.
Looks quite good otherwise. It looks very similar to the older
touchscreen driver (without the touchscreen part).

Have you tried to merge the two?

Thanks,
signature.asc

Maxime Ripard

unread,
Jun 25, 2016, 3:13:40 AM6/25/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Josef Gajdusek, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi,

On Sat, Jun 25, 2016 at 05:44:58AM +0200, meg...@megous.com wrote:
> From: Josef Gajdusek <a...@atx.name>
>
> This patch adds a driver for the THS clock which is present on the
> Allwinner H3.
>
> Signed-off-by: Josef Gajdusek <a...@atx.name>

You might not have noticed, but we are currently rewriting the whole
clock support for the Allwinner SoCs, targetting the H3 as the first
SoC to use it.

There's already some support for the H3 THS clock, so please use that
instead.

Thanks!
signature.asc

Maxime Ripard

unread,
Jun 25, 2016, 3:16:36 AM6/25/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi,

On Sat, Jun 25, 2016 at 05:45:07AM +0200, meg...@megous.com wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> H3 SoC contains I2C controller optionally available
> on the PL0 and PL1 pins. This patch makes this controller
> available.
>
> Signed-off-by: Ondrej Jirman <meg...@megous.com>
> ---
> arch/arm/boot/dts/sun8i-h3.dtsi | 26 ++++++++++++++++++++++++--
> 1 file changed, 24 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi
> index 56f211e..e32f211 100644
> --- a/arch/arm/boot/dts/sun8i-h3.dtsi
> +++ b/arch/arm/boot/dts/sun8i-h3.dtsi
> @@ -322,8 +322,9 @@
> reg = <0x01f01428 0x4>;
> #clock-cells = <1>;
> clocks = <&apb0>;
> - clock-indices = <0>, <1>;
> - clock-output-names = "apb0_pio", "apb0_ir";
> + clock-indices = <0>, <1>, <6>;
> + clock-output-names = "apb0_pio", "apb0_ir", "apb0_i2c";
> +

The new line is not needed, and it should be part of a separate patch.

> };
>
> ir_clk: ir_clk@01f01454 {
> @@ -656,6 +657,20 @@
> status = "disabled";
> };
>
> + r_twi: i2c@01f02400 {

We call it i2c everywhere, please call it that way too.
Separate patch please.

Thanks!
signature.asc

Maxime Ripard

unread,
Jun 25, 2016, 3:18:11 AM6/25/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
It should be marked as always-on.

Otherwise, if the cpufreq driver is not enabled, the regulator will be
shutdown, which is not that great :)

Maxime
signature.asc

Ondřej Jirman

unread,
Jun 25, 2016, 10:50:26 AM6/25/16
to Maxime Ripard, Chen-Yu Tsai, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
I've no way to test, but I've been told some Sinovoip boards are really
bad in this regard (SoC is not even well thermally connected to the
PCB/PCB not having copper layer to spread the heat). Thermal sensor
readings happen at fixed intervals, so the question is if you can heat
up the soc from say 80°C (first trip point) to over 110°C in less than
that period (330ms currently).

I say it shouldn't be a problem, if that small thing is drawing say 2W
at max load. It will burn or trigger a second trip point before the
first one has a chance to trigger and the kernel will shut down. I
remember tkaiser saying that he has to run that board at 240MHz max. But
perhaps I'm misremembering.

I'm just speculating.

regards,
Ondrej



> Maxime
>

Ondřej Jirman

unread,
Jun 25, 2016, 11:12:44 AM6/25/16
to Maxime Ripard, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Zhang Rui, Eduardo Valentin, Chen-Yu Tsai, open list, open list:THERMAL
Because it's overkill for reading a single word from memeory, the sunxi
nvmem driver doesn't support H3, the sid is not documented in the
datasheet, aside from some registger name/offset dump on the mailing
list some time ago.

Aside from that, I've yet to see H3 soc that has anything else than 0 in
the calibration data memory location. So this is basically nop.

Proposed solution seems simpler with no drawbacks that I can see,
without resorting to dropping the thing entirely from this driver. Which
I would be fine with too. Calibration is optional feature in the BSP
kernel, so I assume dropping it may not do too much harm either.

If anyone wants to implement sid in the future, it will be easy enough
to do with backwards compatibility. The second reg will become optional,
and the driver can check for nvmem.
Suspend/resume handling? I would have no way of testing it, other than
blindly impelementing what BSP kernel does. Other than that, I can add
it quite easily. It should be rather simple.

>
>> + sun8i_ths_h3_init(data);
>> +
>> + data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
>> + &sun8i_ths_thermal_ops);
>> + if (IS_ERR(data->tzd)) {
>> + ret = PTR_ERR(data->tzd);
>> + dev_err(&pdev->dev, "failed to register thermal zone: %d\n",
>> + ret);
>> + goto err_assert_reset;
>> + }
>
> You reference data->tzd in your interrupt handler, and the interrupts
> have been activated before initializing that field. That is likely to
> cause a kernel crash when you receive an interrupt between your
> request_irq and that call.

Good catch. I'll just move the above sun8i_ths_h3_init call below the
tzd initialization. That should fix it.
What driver?

Thank you very much for the review.

regards,
Ondrej

> Thanks,
> Maxime
>

Ondřej Jirman

unread,
Jun 25, 2016, 11:23:16 AM6/25/16
to Maxime Ripard, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Josef Gajdusek, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi Maxime,

I try to base everything on the torvalds's kernel.

I did notice the patches. Is there some main git tree/branch where this
work is tracked in? I'd gladly use it.

Also there's a PLL1 rate application patch, that would need to be ported
to the new CCU code, in the case I would use it as a base for this work.
Given that the new CCU code is your work and it's fresh in your mind, do
you have suggestion how to approach it?

It is [PATCH v2 06/14] in this series.

regards,
o.

Mark Brown

unread,
Jun 26, 2016, 7:27:09 AM6/26/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Liam Girdwood, open list
On Sat, Jun 25, 2016 at 05:45:01AM +0200, meg...@megous.com wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> SY8106A is I2C attached single output voltage regulator
> made by Silergy.

I'm missing almost all of this series, I've just got this and another
patch which look like a standalone driver so it's hard to see any
dependencies. What's going on here?
signature.asc

Mark Brown

unread,
Jun 26, 2016, 7:27:29 AM6/26/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Liam Girdwood, Rob Herring, Mark Rutland, open list:VOLTAGE AND CURRENT REGULATOR FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
On Sat, Jun 25, 2016 at 05:45:02AM +0200, meg...@megous.com wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> This patch adds the binding documentation for the
> sy8106a regulator driver.

Please submit patches using subject lines reflecting the style for the
subsystem. This makes it easier for people to identify relevant
patches.
signature.asc

Ondřej Jirman

unread,
Jun 26, 2016, 11:07:19 AM6/26/16
to Mark Brown, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Liam Girdwood, open list

Ondřej Jirman

unread,
Jun 26, 2016, 11:10:08 AM6/26/16
to Mark Brown, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Liam Girdwood, Rob Herring, Mark Rutland, open list:VOLTAGE AND CURRENT REGULATOR FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
Hello, I assume that means "regulator: dt-bindings: ..." in this case.
I'll keep that in mind in the future. Thank you.

Mark Brown

unread,
Jun 26, 2016, 2:53:15 PM6/26/16
to Ondřej Jirman, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Liam Girdwood, Rob Herring, Mark Rutland, open list:VOLTAGE AND CURRENT REGULATOR FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
On Sun, Jun 26, 2016 at 05:10:06PM +0200, Ondřej Jirman wrote:

> Hello, I assume that means "regulator: dt-bindings: ..." in this case.
> I'll keep that in mind in the future. Thank you.

Yes, or "regulator: sy8106a: " - as ever take a look at how other
commits in the same file/directory are done.
signature.asc

Mark Brown

unread,
Jun 27, 2016, 10:54:16 AM6/27/16
to Ondřej Jirman, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Liam Girdwood, open list
These aren't really enlightening I'm afraid, there's nothing in there
about why these are a single series and no dependency information.
Indeed it looks like something is really confused as the thread is
missing at least patches 2 and 3.
signature.asc

Mark Brown

unread,
Jun 27, 2016, 11:10:22 AM6/27/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Liam Girdwood, open list
On Sat, Jun 25, 2016 at 05:45:01AM +0200, meg...@megous.com wrote:

> + config.init_data = of_get_regulator_init_data(dev, dev->of_node, &sy8106a_reg);
> + if (!config.init_data) {
> + return -EINVAL;
> + }

This is broken, constraints are entirely optional - the driver should
just instantiate no matter what (if anything) the constraints are. This
means people can read the current state even if there is no need for
runtime configuration.

> + dev_info(&i2c->dev, "SY8106A voltage at boot: %u mV\n", SY8106A_MIN_MV +
> + SY8106A_STEP_MV * (selector & SY8106A_REG_VOUT1_SEL_MASK));

This is just noise, remove it - if we want to list the voltage for
regulators at probe we should be doing it consistently for all
regulators in the core rather than in individual drivers.

> +/*
> + * This is useless for OF-enabled devices, but it is needed by I2C subsystem
> + */
> +static const struct i2c_device_id sy8106a_i2c_id[] = {
> + { },
> +};
> +MODULE_DEVICE_TABLE(i2c, sy8106a_i2c_id);

No, this is not the case - supporting DT does not mean that other
enumeration mechanisms can't be supported and there's no reason not to
list a sensible ID here.
signature.asc

Maxime Ripard

unread,
Jun 28, 2016, 7:39:49 AM6/28/16
to Ondřej Jirman, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Zhang Rui, Eduardo Valentin, Chen-Yu Tsai, open list, open list:THERMAL
On Sat, Jun 25, 2016 at 05:12:41PM +0200, Ondřej Jirman wrote:
> >> + data->calreg = devm_ioremap_resource(&pdev->dev, res);
> >> + if (IS_ERR(data->calreg)) {
> >> + ret = PTR_ERR(data->calreg);
> >> + dev_err(&pdev->dev, "failed to ioremap THS registers: %d\n", ret);
> >> + return ret;
> >> + }
> >
> > Why did you remove the SID use through the nvmem framework ?!
>
> Because it's overkill for reading a single word from memeory, the sunxi
> nvmem driver doesn't support H3, the sid is not documented in the
> datasheet, aside from some registger name/offset dump on the mailing
> list some time ago.
>
> Aside from that, I've yet to see H3 soc that has anything else than 0 in
> the calibration data memory location. So this is basically nop.
>
> Proposed solution seems simpler with no drawbacks that I can see,
> without resorting to dropping the thing entirely from this driver. Which
> I would be fine with too. Calibration is optional feature in the BSP
> kernel, so I assume dropping it may not do too much harm either.
>
> If anyone wants to implement sid in the future, it will be easy enough
> to do with backwards compatibility. The second reg will become optional,
> and the driver can check for nvmem.

A lot of things in drivers boil down to "reading a single word from
memory". However, abstractions are here for a reason, and there's none
to not use it.

If that's not something we can use today, remove it entirely. And if
that becomes necessary, we will add an optional nvmem property.
No, I mean runtime_pm, with runtime_suspend and runtime_resume, to
allow only powering up the device when it's used, and shut it down
when not used.

> >> +MODULE_AUTHOR("Ondřej Jirman <meg...@megous.com>");
> >> +MODULE_DESCRIPTION("Thermal sensor driver for Allwinner H3 SoC");
> >> +MODULE_LICENSE("GPL v2");
> >
> > Looks quite good otherwise. It looks very similar to the older
> > touchscreen driver (without the touchscreen part).
> >
> > Have you tried to merge the two?
>
> What driver?

drivers/input/touchscreen/sun4i-ts.c
signature.asc

Maxime Ripard

unread,
Jun 28, 2016, 7:52:28 AM6/28/16
to Ondřej Jirman, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Josef Gajdusek, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi,

On Sat, Jun 25, 2016 at 05:23:12PM +0200, Ondřej Jirman wrote:
> Hi Maxime,
>
> I try to base everything on the torvalds's kernel.
>
> I did notice the patches. Is there some main git tree/branch where this
> work is tracked in? I'd gladly use it.

I just pushed it, branch sunxi/pen/clk-rework, on my github repo:
https://github.com/mripard/linux

> Also there's a PLL1 rate application patch, that would need to be ported
> to the new CCU code, in the case I would use it as a base for this work.
> Given that the new CCU code is your work and it's fresh in your mind, do
> you have suggestion how to approach it?
>
> It is [PATCH v2 06/14] in this series.

Yes, it's still in my queue of things to review, let's discuss this on
this patch thread.
signature.asc

Ondřej Jirman

unread,
Jun 28, 2016, 12:27:41 PM6/28/16
to Mark Brown, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Liam Girdwood, open list
You're right there's not much about the regulator there. Xulong Orange
Pi PC is ARM SBC, that uses Allwinner H3 Soc, to which this regulator is
connected via I2C bus, to regulate the main CPU supply voltage. It is
used on some other SBC's from Xulong.

It is fairly simple single output, fixed I2C address voltage regulator.
It has just 3 registers, which allow for: slew rate control (not used in
this driver), setting and reading out the voltage, switching between
voltage set via I2C and via external resistor divider and
enabling/disabling output. It also has status reporting for
over-tempertature and over-current conditions. That's all the features
it has.

The patch series uses it to provide dynamic vltage scaling of the ARM
cores in the SoC to be able to achieve higher CPU frequency.

Datasheet is here:

https://01916271185794791722.googlegroups.com/attach/93415fbd5402/SY8106A_datasheet.pdf?part=0.1&vt=ANaJVrHMej8w8XRfd-7A3XoyiryMDDhrHU2SS-tYyHCpOIXRqIaICOIlZTWAUV74vToesmic457zPvODDuvrNnRpomPOPbtV8bMMFV65VX5aYb5NciMkh8E

I'll also include this information in the revised patch.

thank you and regards,
Ondrej Jirman

signature.asc

Rob Herring

unread,
Jun 28, 2016, 4:56:37 PM6/28/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Zhang Rui, Eduardo Valentin, Mark Rutland, Maxime Ripard, Chen-Yu Tsai, open list:THERMAL, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On Sat, Jun 25, 2016 at 05:45:00AM +0200, meg...@megous.com wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> This patch adds the binding documentation for the
> sun8i_ths driver. This is a driver for thermal sensor
> found in Allwinner H3 SoC.
>
> Signed-off-by: Ondřej Jirman <meg...@megous.com>
> ---
> .../devicetree/bindings/thermal/sun8i-ths.txt | 26 ++++++++++++++++++++++
> 1 file changed, 26 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/thermal/sun8i-ths.txt

I guess the example will change for the clocks some, but otherwise:

Acked-by: Rob Herring <ro...@kernel.org>

Maxime Ripard

unread,
Jun 29, 2016, 4:46:06 PM6/29/16
to Ondřej Jirman, Chen-Yu Tsai, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi,
Yes, but that's just poor thermal design. What I was saying is that
even if we really need to throttle the SoC to 240 MHz on that board
because it heats too much, the couple of the frequency and the voltage
will likely be the same across all boards. It's just the amount of
time we'll spend using it that will differ.

But that's just my understanding, I might be speaking non-sense :)
signature.asc

Ondřej Jirman

unread,
Jun 29, 2016, 5:11:18 PM6/29/16
to Maxime Ripard, Chen-Yu Tsai, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
You're probably right. Operating points should be part of h3.dtsi, and
if some board is particularly bad, and can't handle being above certain
frequency safely, due to thermal design issues, we can override
operating points in its dts file.

regards,
Ondrej

signature.asc

Michal Suchanek

unread,
Jun 30, 2016, 7:05:22 AM6/30/16
to meg...@megous.com, Maxime Ripard, Chen-Yu Tsai, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hello,
Can you override them?

AFAIK you cannot replace a property set in SoC file in a board file.
If you can keep the operating point list and just add option which
selects acceptable subset for the board that should work. On some
boards this subset would be determined by regulator voltage
constraints but not sure how you would select the subset for the
boards with thermal problems.

Thanks

Michal

Michal Suchanek

unread,
Jun 30, 2016, 7:14:30 AM6/30/16
to meg...@megous.com, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hello,

On 25 June 2016 at 05:45, <meg...@megous.com> wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> Use Xulong Orange Pi One GPIO based regulator for
> passive cooling and thermal management.
>
> Signed-off-by: Ondrej Jirman <meg...@megous.com>
> ---
> arch/arm/boot/dts/sun8i-h3-orangepi-one.dts | 39 +++++++++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
> index b1bd6b0..a38d871 100644
> --- a/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
> +++ b/arch/arm/boot/dts/sun8i-h3-orangepi-one.dts
> @@ -109,6 +109,45 @@
> };
> };
>
> +&cpu0 {
> + operating-points = <
> + /* kHz uV */
> + 1296000 1300000
> + 1200000 1300000

First problem is that the board boots at 1008000 which is not listed
and the kernel complains.

Second problem is that the board locks up during boot with this enabled.

Do you have some suggestion for alternate configuration to test?

Thanks

Michal

Ondřej Jirman

unread,
Jun 30, 2016, 10:19:41 AM6/30/16
to Michal Suchanek, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hello,
Just to verify, did you test with the entire series applied? (especially
the PLL1 clk application changes)

You may try dropping the highest operating point, it's probably overly
optimistic for Orange Pi One.

Is the power supply/cable you're using hard enough?

Where during the boot process does it lock up?

regards,
Ondrej

> Thanks
>
> Michal
>

signature.asc

Siarhei Siamashka

unread,
Jun 30, 2016, 10:23:34 AM6/30/16
to Michal Suchanek, meg...@megous.com, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Maybe try the Allwinner's original DVFS table instead of these
undervolted values and see if it helps?

https://linux-sunxi.org/index.php?title=Xunlong_Orange_Pi_PC&oldid=17753#CPU_clock_speed_limit

While undervolting is tempting because it helps to decrease the SoC
temperature and avoid throttling, different units may have different
tolerances and one needs to be very careful when picking defaults
that are intended to work correctly on all boards. Some safety
headroom exists there for a reason.

If I remember correctly, some people pushed for undervolting experiments
at least twice in the past (on the Banana Pi and C.H.I.P.). In both
cases this did not end up well and had to be fixed later to solve
reliability problems.

In order to allow individual per-unit tuning, a concept of "speed
grading" may be probably introduced later. So that the board is tested
for reliability and then the speed grade rating is stored somewhere on
the non-removable storage (EEPROM, SPI flash, eFUSE, ...). Some SoC
manufacturers, such as Samsung, are already doing this with their chips.

Michal Suchanek

unread,
Jun 30, 2016, 11:17:17 AM6/30/16
to meg...@megous.com, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Yes, I applied the whole series.

>
> You may try dropping the highest operating point, it's probably overly
> optimistic for Orange Pi One.
>
> Is the power supply/cable you're using hard enough?

I use a 7 port hub to power the board. It worked with some other small
devboards.

The cable is some random Chinese USB to power jack adaptor with an
extra adaptor to fit the Pi socket. It looks ok but I did not test
this particular combination thoroughly.

>
> Where during the boot process does it lock up?

Usually sometime around enabling cpufreq before getty starts.
Different runs and settings give slightly different results. In
particular adding the 1008000 point seems to make it go further.

Removing all traces of the regulator, cpufreq and thermal I can boot
pretty much 100% to login prompt.

I don't think the difference between 1GHz and 1.3GHz frequency on the
core would put much additional stress on the supply but I can try with
35W PSU and some alternative cabling to be sure.

I did some more tests and it seems 100...@1.1V is fine but switching
to 1.3V crashes the board. Even with only the first 1.3V state. Maybe
there is need for some delay somewhere for the regulator to get
stable?

Thanks

Michal

Ondřej Jirman

unread,
Jun 30, 2016, 11:32:30 AM6/30/16
to Michal Suchanek, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Please try adding:

regulator-ramp-delay = <10>

to the gpio regulator.

which will allow 100ms per 1V change, which should b enough for
determining, if this is the cause.

regards,
Ondrej

> Thanks
>
> Michal
>

signature.asc

Michal Suchanek

unread,
Jun 30, 2016, 11:51:07 AM6/30/16
to meg...@megous.com, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hm, the AW table shows 100...@1.3V as supported state and it indeed
works. So the voltage switching works or does nothing. Can I measure
the regulator output somewhere? Clocking the chip higher does not
work.

I will try with another PSU later.

Thanks

Michal

Ondřej Jirman

unread,
Jun 30, 2016, 11:53:16 AM6/30/16
to Michal Suchanek, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Regulator output is TP1 on the bottom of the board, next ot the CSI
connector.

regards,
Ondrej
signature.asc

Maxime Ripard

unread,
Jun 30, 2016, 4:40:09 PM6/30/16
to meg...@megous.com, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi,

On Sat, Jun 25, 2016 at 05:45:03AM +0200, meg...@megous.com wrote:
> From: Ondrej Jirman <meg...@megous.com>
>
> PLL1 on H3 requires special factors application algorithm,
> when the rate is changed. This algorithm was extracted
> from the arisc code that handles frequency scaling
> in the BSP kernel.
>
> This commit adds optional apply function to
> struct factors_data, that can implement non-trivial
> factors application method, when necessary.
>
> Also struct clk_factors_config is extended with position
> of the PLL lock flag.

Have you tested the current implementation, and found that it was not
working, or did you duplicate the arisc code directly?

> /**
> + * sun8i_h3_apply_pll1_factors() - applies n, k, m, p factors to the
> + * register using an algorithm that tries to reserve the PLL lock
> + */
> +
> +static void sun8i_h3_apply_pll1_factors(struct clk_factors *factors, struct factors_request *req)
> +{
> + const struct clk_factors_config *config = factors->config;
> + u32 reg;
> +
> + /* Fetch the register value */
> + reg = readl(factors->reg);
> +
> + if (FACTOR_GET(config->pshift, config->pwidth, reg) < req->p) {
> + reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
> +
> + writel(reg, factors->reg);
> + __delay(2000);
> + }

So there was some doubts about the fact that P was being used, or at
least that it was useful.

> + if (FACTOR_GET(config->mshift, config->mwidth, reg) < req->m) {
> + reg = FACTOR_SET(config->mshift, config->mwidth, reg, req->m);
> +
> + writel(reg, factors->reg);
> + __delay(2000);
> + }
> +
> + reg = FACTOR_SET(config->nshift, config->nwidth, reg, req->n);
> + reg = FACTOR_SET(config->kshift, config->kwidth, reg, req->k);
> +
> + writel(reg, factors->reg);
> + __delay(20);
> +
> + while (!(readl(factors->reg) & (1 << config->lock)));

So, they are applying the dividers first, and then applying the
multipliers, and then wait for the PLL to stabilize.

> +
> + if (FACTOR_GET(config->mshift, config->mwidth, reg) > req->m) {
> + reg = FACTOR_SET(config->mshift, config->mwidth, reg, req->m);
> +
> + writel(reg, factors->reg);
> + __delay(2000);
> + }
> +
> + if (FACTOR_GET(config->pshift, config->pwidth, reg) > req->p) {
> + reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
> +
> + writel(reg, factors->reg);
> + __delay(2000);
> + }

However, this is kind of weird, why would you need to re-apply the
dividers? Nothing really changes. Have you tried without that part?

Since this is really specific, I guess you could simply make the
clk_ops for the nkmp clocks public, and just re-implement set_rate
using that logic.

You might also need to set an upper limit on P, since the last value
(4) is not a valid one.

I guess you could do that by adding a max field in the __ccu_div
structure.
signature.asc

Maxime Ripard

unread,
Jun 30, 2016, 4:41:54 PM6/30/16
to Michal Suchanek, meg...@megous.com, Chen-Yu Tsai, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On Thu, Jun 30, 2016 at 01:04:40PM +0200, Michal Suchanek wrote:
> > You're probably right. Operating points should be part of h3.dtsi, and
> > if some board is particularly bad, and can't handle being above certain
> > frequency safely, due to thermal design issues, we can override
> > operating points in its dts file.
> >
>
> Can you override them?
>
> AFAIK you cannot replace a property set in SoC file in a board file.

You totally can, we have litterally dozens of examples of that already.
signature.asc

Ondřej Jirman

unread,
Jun 30, 2016, 8:51:04 PM6/30/16
to Maxime Ripard, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Hi,

On 30.6.2016 22:40, Maxime Ripard wrote:
> Hi,
>
> On Sat, Jun 25, 2016 at 05:45:03AM +0200, meg...@megous.com wrote:
>> From: Ondrej Jirman <meg...@megous.com>
>>
>> PLL1 on H3 requires special factors application algorithm,
>> when the rate is changed. This algorithm was extracted
>> from the arisc code that handles frequency scaling
>> in the BSP kernel.
>>
>> This commit adds optional apply function to
>> struct factors_data, that can implement non-trivial
>> factors application method, when necessary.
>>
>> Also struct clk_factors_config is extended with position
>> of the PLL lock flag.
>
> Have you tested the current implementation, and found that it was not
> working, or did you duplicate the arisc code directly?

I have tested the current implementation, and it was not working. It
depended on some other factors, like the initial setup done by u-boot.
It didn't work reliably.

Then I reverse engineered arisc, in an effort to see what's the
difference, between mainline and BSP code.

>> /**
>> + * sun8i_h3_apply_pll1_factors() - applies n, k, m, p factors to the
>> + * register using an algorithm that tries to reserve the PLL lock
>> + */
>> +
>> +static void sun8i_h3_apply_pll1_factors(struct clk_factors *factors, struct factors_request *req)
>> +{
>> + const struct clk_factors_config *config = factors->config;
>> + u32 reg;
>> +
>> + /* Fetch the register value */
>> + reg = readl(factors->reg);
>> +
>> + if (FACTOR_GET(config->pshift, config->pwidth, reg) < req->p) {
>> + reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
>> +
>> + writel(reg, factors->reg);
>> + __delay(2000);
>> + }
>
> So there was some doubts about the fact that P was being used, or at
> least that it was useful.

p is necessary to reduce frequencies below 288 MHz according to the
datasheet.

>> + if (FACTOR_GET(config->mshift, config->mwidth, reg) < req->m) {
>> + reg = FACTOR_SET(config->mshift, config->mwidth, reg, req->m);
>> +
>> + writel(reg, factors->reg);
>> + __delay(2000);
>> + }
>> +
>> + reg = FACTOR_SET(config->nshift, config->nwidth, reg, req->n);
>> + reg = FACTOR_SET(config->kshift, config->kwidth, reg, req->k);
>> +
>> + writel(reg, factors->reg);
>> + __delay(20);
>> +
>> + while (!(readl(factors->reg) & (1 << config->lock)));
>
> So, they are applying the dividers first, and then applying the
> multipliers, and then wait for the PLL to stabilize.

Not exactly, first we are increasing dividers if the new dividers are
higher that that what's already set. This ensures that because
application of dividers is immediate by the design of the PLL, the
application of multipliers isn't. So the VCO would still run at the same
frequency for a while gradually rising to a new value for example,
while the dividers would be reduced immediately. Leading to crash.

PLL
--------------------------
PRE DIV(f0) -> VCO(f1) -> POST DIV(f2)
P K,N M

Example: (we set all factors at once, reducing dividers and multipliers
at the same time at 0ms - this should lead to no change in the output
frequency, but...)

-1ms: f0 = 24MHz, f1 = 2GHz, f2 = 1GHz
0ms: f0 = 24MHz, f1 = 2GHz, f2 = 2GHz - boom
1ms: f0 = 24MHz, f1 = 1.5GHz, f2 = 1.5GHz
2ms: f0 = 24MHz, f1 = 1GHz, f2 = 1GHz

The current code crashes exactly at boom, you don't get any more
instructions to execute.

See.

So this patch first increases dividers (only if necessary), changes
multipliers and waits for change to happen (takes around 2000 cycles),
and then decreases dividers (only if necessary).

So we get:

-1ms: f0 = 24MHz, f1 = 2GHz, f2 = 1GHz
0ms: f0 = 24MHz, f1 = 2GHz, f2 = 1GHz - no boom, multiplier
reduced
1ms: f0 = 24MHz, f1 = 1.5GHz, f2 = 0.75GHz
1.9ms: f0 = 24MHz, f1 = 1GHz, f2 = 0.5GHz - we got PLL sync
2ms: f0 = 24MHz, f1 = 1GHz, f2 = 1GHz - and here we reduce divider
at last

>> +
>> + if (FACTOR_GET(config->mshift, config->mwidth, reg) > req->m) {
>> + reg = FACTOR_SET(config->mshift, config->mwidth, reg, req->m);
>> +
>> + writel(reg, factors->reg);
>> + __delay(2000);
>> + }
>> +
>> + if (FACTOR_GET(config->pshift, config->pwidth, reg) > req->p) {
>> + reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
>> +
>> + writel(reg, factors->reg);
>> + __delay(2000);
>> + }
>
> However, this is kind of weird, why would you need to re-apply the
> dividers? Nothing really changes. Have you tried without that part?

See above, we either increase before PLL change, or reduce dividers
after the change. Nothing is re-applied.

> Since this is really specific, I guess you could simply make the
> clk_ops for the nkmp clocks public, and just re-implement set_rate
> using that logic.

I would argue that this may be necessary for other PLL clocks too, if
you can get out of bounds output frequency, by changing the dividers too
early or too late. So perhaps this code should be generalized for other
PLL clocks too, instead.

>
> You might also need to set an upper limit on P, since the last value
> (4) is not a valid one.

I think, that should be done by the factors calculation function already.

> I guess you could do that by adding a max field in the __ccu_div
> structure.
>
> Maxime
>

regards,
Ondrej

signature.asc

Ondřej Jirman

unread,
Jun 30, 2016, 8:53:54 PM6/30/16
to Maxime Ripard, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On 30.6.2016 22:40, Maxime Ripard wrote:
> Hi,
>
> On Sat, Jun 25, 2016 at 05:45:03AM +0200, meg...@megous.com wrote:
>> From: Ondrej Jirman <meg...@megous.com>
>>
>> PLL1 on H3 requires special factors application algorithm,
>> when the rate is changed. This algorithm was extracted
>> from the arisc code that handles frequency scaling
>> in the BSP kernel.
>>
>> This commit adds optional apply function to
>> struct factors_data, that can implement non-trivial
>> factors application method, when necessary.
>>
>> Also struct clk_factors_config is extended with position
>> of the PLL lock flag.
>
> Have you tested the current implementation, and found that it was not
> working, or did you duplicate the arisc code directly?

Also of note is that similar code probably doesn't crash in u-boot,
because there, before changing the PLL1 clock, the cpu is switched to
24MHz osc, so it is not overclocked, even if factors align in such a way
that you'd get the behavior I described in the other email.
signature.asc

Ondřej Jirman

unread,
Jun 30, 2016, 9:17:43 PM6/30/16
to Siarhei Siamashka, Michal Suchanek, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Thanks, I'll use these. I'm not sure what will happen if regulator is
not capable of providing the exact voltages specified in the operating
points, though. Will it do the sane thing? :)

Also LV6+ in the table is bellow specified minimum voltage in the
datasheet. But then Orange Pi works at much lower voltages for me.

Conversly LV1 is the absolute maximum. Recommended maximum is 1.4V So I
would not use that.

It might be nice to have something like that dram clock test, but for
cpux freq/voltage, and collect some statistics.

regards,
Ondrej
signature.asc

Ondřej Jirman

unread,
Jul 1, 2016, 2:34:30 AM7/1/16
to Jean-Francois Moine, Maxime Ripard, Mark Rutland, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, d...@linux-sunxi.org, Michael Turquette, Stephen Boyd, open list, Emilio López, Chen-Yu Tsai, Rob Herring, open list:COMMON CLK FRAMEWORK, linux-ar...@lists.infradead.org
On 1.7.2016 07:37, Jean-Francois Moine wrote:
> On Fri, 1 Jul 2016 02:50:57 +0200
> Ondřej Jirman <meg...@megous.com> wrote:
>
>>> Since this is really specific, I guess you could simply make the
>>> clk_ops for the nkmp clocks public, and just re-implement set_rate
>>> using that logic.
>>
>> I would argue that this may be necessary for other PLL clocks too, if
>> you can get out of bounds output frequency, by changing the dividers too
>> early or too late. So perhaps this code should be generalized for other
>> PLL clocks too, instead.
>
> The documentation says that only the CPU and DDR PLLs can be dynamically
> changed after boot.

The question is what exactly is meant by after boot. :) Anyway, if the
kernel has no business changing some other PLLs, if there's code for
changing them, should it be dropped?

regards,
Ondrej

signature.asc

Michal Suchanek

unread,
Jul 1, 2016, 6:55:37 AM7/1/16
to meg...@megous.com, dev, linux-ar...@lists.infradead.org, Rob Herring, Mark Rutland, Russell King, Maxime Ripard, Chen-Yu Tsai, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On 30 June 2016 at 17:50, Michal Suchanek <hram...@gmail.com> wrote:
> On 30 June 2016 at 17:16, Michal Suchanek <hram...@gmail.com> wrote:
>> On 30 June 2016 at 16:19, Ondřej Jirman <meg...@megous.com> wrote:
>>> Hello,
>>)k, so I tried>
Ok, so I tried. The result is the same.

A Chinese USB power meter shows voltage 5.1V which drops to like 4.95V
when the board is running. The power draw is around 170mA and
about 200mA when switch to 1.3V is attempted.
The voltage drop is not nice and is probably due to excessive cabling used
to distribute power to multiple boards.
The USB hub starts at 5.2V and drops to something like 5.1V.

When the top frequency is 100...@1.3V and governor is performance
the board keeps running 100...@1.1V as set up by u-boot.

Changing the top point to 100...@1.1V the board locks up as soon as
governor is changed to conservative. So any attempt at frequency scaling
crashes even without touching the regulator.

Thanks

Michal

Jean-Francois Moine

unread,
Jul 1, 2016, 9:30:16 AM7/1/16
to Ondřej Jirman, Maxime Ripard, Mark Rutland, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, d...@linux-sunxi.org, Michael Turquette, Stephen Boyd, open list, Emilio López, Chen-Yu Tsai, Rob Herring, open list:COMMON CLK FRAMEWORK, linux-ar...@lists.infradead.org
On Fri, 1 Jul 2016 02:50:57 +0200
Ondřej Jirman <meg...@megous.com> wrote:

> > Since this is really specific, I guess you could simply make the
> > clk_ops for the nkmp clocks public, and just re-implement set_rate
> > using that logic.
>
> I would argue that this may be necessary for other PLL clocks too, if
> you can get out of bounds output frequency, by changing the dividers too
> early or too late. So perhaps this code should be generalized for other
> PLL clocks too, instead.

The documentation says that only the CPU and DDR PLLs can be dynamically
changed after boot.

--
Ken ar c'hentañ | ** Breizh ha Linux atav! **
Jef | http://moinejf.free.fr/

Jean-Francois Moine

unread,
Jul 1, 2016, 9:30:16 AM7/1/16
to Ondřej Jirman, Maxime Ripard, Mark Rutland, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, d...@linux-sunxi.org, Michael Turquette, Stephen Boyd, open list, Emilio López, Chen-Yu Tsai, Rob Herring, open list:COMMON CLK FRAMEWORK, linux-ar...@lists.infradead.org
On Fri, 1 Jul 2016 08:34:21 +0200
Ondřej Jirman <meg...@megous.com> wrote:

> > The documentation says that only the CPU and DDR PLLs can be dynamically
> > changed after boot.
>
> The question is what exactly is meant by after boot. :) Anyway, if the
> kernel has no business changing some other PLLs, if there's code for
> changing them, should it be dropped?

No, because all the other PLLs may not be initialized by the U-boot
(audio, video, gpu...), and also, their rate may be changed safely by
stopping them (gate).

Maxime Ripard

unread,
Jul 15, 2016, 6:10:21 AM7/15/16
to Ondřej Jirman, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On Fri, Jul 01, 2016 at 02:53:52AM +0200, Ondřej Jirman wrote:
> On 30.6.2016 22:40, Maxime Ripard wrote:
> > Hi,
> >
> > On Sat, Jun 25, 2016 at 05:45:03AM +0200, meg...@megous.com wrote:
> >> From: Ondrej Jirman <meg...@megous.com>
> >>
> >> PLL1 on H3 requires special factors application algorithm,
> >> when the rate is changed. This algorithm was extracted
> >> from the arisc code that handles frequency scaling
> >> in the BSP kernel.
> >>
> >> This commit adds optional apply function to
> >> struct factors_data, that can implement non-trivial
> >> factors application method, when necessary.
> >>
> >> Also struct clk_factors_config is extended with position
> >> of the PLL lock flag.
> >
> > Have you tested the current implementation, and found that it was not
> > working, or did you duplicate the arisc code directly?
>
> Also of note is that similar code probably doesn't crash in u-boot,
> because there, before changing the PLL1 clock, the cpu is switched to
> 24MHz osc, so it is not overclocked, even if factors align in such a way
> that you'd get the behavior I described in the other email.

That's also something that we can do.

See Meson's clk-cpu clock notifiers for example.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
signature.asc

Maxime Ripard

unread,
Jul 15, 2016, 6:10:21 AM7/15/16
to Ondřej Jirman, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
On Fri, Jul 01, 2016 at 02:50:57AM +0200, Ondřej Jirman wrote:
> >> /**
> >> + * sun8i_h3_apply_pll1_factors() - applies n, k, m, p factors to the
> >> + * register using an algorithm that tries to reserve the PLL lock
> >> + */
> >> +
> >> +static void sun8i_h3_apply_pll1_factors(struct clk_factors *factors, struct factors_request *req)
> >> +{
> >> + const struct clk_factors_config *config = factors->config;
> >> + u32 reg;
> >> +
> >> + /* Fetch the register value */
> >> + reg = readl(factors->reg);
> >> +
> >> + if (FACTOR_GET(config->pshift, config->pwidth, reg) < req->p) {
> >> + reg = FACTOR_SET(config->pshift, config->pwidth, reg, req->p);
> >> +
> >> + writel(reg, factors->reg);
> >> + __delay(2000);
> >> + }
> >
> > So there was some doubts about the fact that P was being used, or at
> > least that it was useful.
>
> p is necessary to reduce frequencies below 288 MHz according to the
> datasheet.

Yes, but you could reach those frequencies without P, too, and it's
not part of any OPP provided by Allwinner.
Awesome explanation, thanks!

So I guess it really all boils down to the fact that the CPU is
clocked way outside of it's operating frequency while the PLL
stabilizes, right?

If so, then yes, trying to switch to the 24MHz oscillator before
applying the factors, and then switching back when the PLL is stable
would be a nice solution.

I just checked, and all the SoCs we've had so far have that
possibility, so if it works, for now, I'd like to stick to that.
We can scale down the problem a bit. The only PLL we modify are the
CPU, audio and video ones.

The CPU should definitely be addressed, but what would be the outcome
of an out of bounds audio pll for example? Is it just taking more time
to stabilize, or would it hurt the system?

In the former case, then we can just wait. In the latter, we of course
need to come up with a solution.

Maxime


--
Maxime Ripard, Free Electrons
signature.asc

Ondřej Jirman

unread,
Jul 15, 2016, 6:39:03 AM7/15/16
to Maxime Ripard, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
The arisc firmware for H3 contains table of factors for frequences from
0 to 2GHz and, P is used below 240MHz. M is never used, BTW. (other
datasheets specify M as for testing use only, whatever that means - not
H3, but it seems it's the same PLL block)


... snip ...
{ .n = 9, .k = 0, .m = 0, .p = 2 }, // 60 => 60 MHz
{ .n = 10, .k = 0, .m = 0, .p = 2 }, // 66 => 66 MHz
{ .n = 11, .k = 0, .m = 0, .p = 2 }, // 72 => 72 MHz
{ .n = 12, .k = 0, .m = 0, .p = 2 }, // 78 => 78 MHz
{ .n = 13, .k = 0, .m = 0, .p = 2 }, // 84 => 84 MHz
{ .n = 14, .k = 0, .m = 0, .p = 2 }, // 90 => 90 MHz
{ .n = 15, .k = 0, .m = 0, .p = 2 }, // 96 => 96 MHz
{ .n = 16, .k = 0, .m = 0, .p = 2 }, // 102 => 102 MHz
{ .n = 17, .k = 0, .m = 0, .p = 2 }, // 108 => 108 MHz
{ .n = 18, .k = 0, .m = 0, .p = 2 }, // 114 => 114 MHz
{ .n = 9, .k = 0, .m = 0, .p = 1 }, // 120 => 120 MHz
{ .n = 10, .k = 0, .m = 0, .p = 1 }, // 126 => 132 MHz
{ .n = 10, .k = 0, .m = 0, .p = 1 }, // 132 => 132 MHz
{ .n = 11, .k = 0, .m = 0, .p = 1 }, // 138 => 144 MHz
{ .n = 11, .k = 0, .m = 0, .p = 1 }, // 144 => 144 MHz
{ .n = 12, .k = 0, .m = 0, .p = 1 }, // 150 => 156 MHz
{ .n = 12, .k = 0, .m = 0, .p = 1 }, // 156 => 156 MHz
{ .n = 13, .k = 0, .m = 0, .p = 1 }, // 162 => 168 MHz
{ .n = 13, .k = 0, .m = 0, .p = 1 }, // 168 => 168 MHz
{ .n = 14, .k = 0, .m = 0, .p = 1 }, // 174 => 180 MHz
{ .n = 14, .k = 0, .m = 0, .p = 1 }, // 180 => 180 MHz
{ .n = 15, .k = 0, .m = 0, .p = 1 }, // 186 => 192 MHz
{ .n = 15, .k = 0, .m = 0, .p = 1 }, // 192 => 192 MHz
{ .n = 16, .k = 0, .m = 0, .p = 1 }, // 198 => 204 MHz
{ .n = 16, .k = 0, .m = 0, .p = 1 }, // 204 => 204 MHz
{ .n = 17, .k = 0, .m = 0, .p = 1 }, // 210 => 216 MHz
{ .n = 17, .k = 0, .m = 0, .p = 1 }, // 216 => 216 MHz
{ .n = 18, .k = 0, .m = 0, .p = 1 }, // 222 => 228 MHz
{ .n = 18, .k = 0, .m = 0, .p = 1 }, // 228 => 228 MHz
{ .n = 9, .k = 0, .m = 0, .p = 0 }, // 234 => 240 MHz
{ .n = 9, .k = 0, .m = 0, .p = 0 }, // 240 => 240 MHz
{ .n = 10, .k = 0, .m = 0, .p = 0 }, // 246 => 264 MHz
{ .n = 10, .k = 0, .m = 0, .p = 0 }, // 252 => 264 MHz
{ .n = 10, .k = 0, .m = 0, .p = 0 }, // 258 => 264 MHz
{ .n = 10, .k = 0, .m = 0, .p = 0 }, // 264 => 264 MHz
{ .n = 11, .k = 0, .m = 0, .p = 0 }, // 270 => 288 MHz
{ .n = 11, .k = 0, .m = 0, .p = 0 }, // 276 => 288 MHz
... snip ...
It may be, depending on the factors before and after change. I haven't
tested what factors the mainline kernel calculates for each frequency.
The arisc never uses M, and only uses P at frequencies that would not
allow for this behavior.

I created a test program for arisc that runs a loop on the main CPU
using msgbox to send pings to the arisc CPU, and the vary the PLL1
randomly from the arisc, and haven't been able to lockup the main CPU
yet with either method.

There's also AXI clock, that depends on PLL1. Arisc firmware uses the
same method to change it while changing CPUX clock. If the clock would
rise above certain frequency, AXI divider is increased before the PLL1
change. If it would fall below certain frequency it is decreased after
the PLL1 change.

Though, aw kernel has axi divider set to 3 for all PLL1 frequencies, so
this has no effect in practice.

It's all smoke and mirrors. :D

> If so, then yes, trying to switch to the 24MHz oscillator before
> applying the factors, and then switching back when the PLL is stable
> would be a nice solution.
>
> I just checked, and all the SoCs we've had so far have that
> possibility, so if it works, for now, I'd like to stick to that.

It would need to be tested. U-boot does the change only once, while the
kernel would be doing it all the time and between various frequencies
and PLL settings. So the issues may show up with this solution too.
I have no idea. Given the low frequencies, you'll probably just get some
transient audio noise.
signature.asc

Ondřej Jirman

unread,
Jul 15, 2016, 9:48:52 AM7/15/16
to Jean-Francois Moine, Maxime Ripard, Mark Rutland, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, d...@linux-sunxi.org, Michael Turquette, Stephen Boyd, open list, Emilio López, Chen-Yu Tsai, Rob Herring, open list:COMMON CLK FRAMEWORK, linux-ar...@lists.infradead.org


On 15.7.2016 15:27, Jean-Francois Moine wrote:
> On Fri, 15 Jul 2016 12:38:54 +0200
> Ondřej Jirman <meg...@megous.com> wrote:
>
>>> If so, then yes, trying to switch to the 24MHz oscillator before
>>> applying the factors, and then switching back when the PLL is stable
>>> would be a nice solution.
>>>
>>> I just checked, and all the SoCs we've had so far have that
>>> possibility, so if it works, for now, I'd like to stick to that.
>>
>> It would need to be tested. U-boot does the change only once, while the
>> kernel would be doing it all the time and between various frequencies
>> and PLL settings. So the issues may show up with this solution too.
>
> I don't think this is a good idea: the CPU clock may be changed at any
> time with the CPUFreq governor. I don't see the system moving from
> 1008MHz to 24MHz and then to 1200MHz when some computation is needed!

PLL lock time is around 10-20us, I'd guess based on the number of loops
in the PLL lock wait loop. So unless you'll be switching frequencies
many times per second, this should be barely noticeable.

But I'd like a different solution too.

> BTW, Ondřej, in my BPi M2+, I tried to change the CPU clock with your
> code at kernel start time from 792MHz to 1008MHz, but the hardware
> (arisc?) set an other value, and the system speed was lower than before
> (the PLL-CPUx register is 0x90031521 on boot, I want to set it to
> xxxx1410 and I read 0x91031f33 - sorry, I did not have a look at the
> CPU SD pattern). Do you know why?

No idea. Arisc shouldn't do anything, unless you load some firmware into
it, and release its reset line.

signature.asc

Michal Suchanek

unread,
Jul 15, 2016, 10:23:13 AM7/15/16
to meg...@megous.com, Jean-Francois Moine, Maxime Ripard, Mark Rutland, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, dev, Michael Turquette, Stephen Boyd, open list, Emilio López, Chen-Yu Tsai, Rob Herring, open list:COMMON CLK FRAMEWORK, linux-ar...@lists.infradead.org
Hello,

On 15 July 2016 at 15:48, Ondřej Jirman <meg...@megous.com> wrote:
>
>
> On 15.7.2016 15:27, Jean-Francois Moine wrote:
>> On Fri, 15 Jul 2016 12:38:54 +0200
>> Ondřej Jirman <meg...@megous.com> wrote:
>>
>>>> If so, then yes, trying to switch to the 24MHz oscillator before
>>>> applying the factors, and then switching back when the PLL is stable
>>>> would be a nice solution.
>>>>
>>>> I just checked, and all the SoCs we've had so far have that
>>>> possibility, so if it works, for now, I'd like to stick to that.
>>>
>>> It would need to be tested. U-boot does the change only once, while the
>>> kernel would be doing it all the time and between various frequencies
>>> and PLL settings. So the issues may show up with this solution too.
>>
>> I don't think this is a good idea: the CPU clock may be changed at any
>> time with the CPUFreq governor. I don't see the system moving from
>> 1008MHz to 24MHz and then to 1200MHz when some computation is needed!
>
> PLL lock time is around 10-20us, I'd guess based on the number of loops
> in the PLL lock wait loop. So unless you'll be switching frequencies
> many times per second, this should be barely noticeable.
>
> But I'd like a different solution too.

Do you have a patch to test this?

For me changing CPU frequency on Orange Pi One always locks up the
system. I keep running it on the u-boot setup 1.08GHz at 1.1V

Thanks

Michal

Ondřej Jirman

unread,
Jul 15, 2016, 12:33:51 PM7/15/16
to Michal Suchanek, Jean-Francois Moine, Maxime Ripard, Mark Rutland, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, dev, Michael Turquette, Stephen Boyd, open list, Emilio López, Chen-Yu Tsai, Rob Herring, open list:COMMON CLK FRAMEWORK, linux-ar...@lists.infradead.org
Not anymore. But it's quite simple to hack it into the
drivers/clk/sunxi/clk-factors.c:clk_factors_set_rate()

You can look at u-boot arch/arm/mach-sunxi/clock_sun6i.c:clock_set_pll1
for how to change the CPU clock source.

> Thanks
>
> Michal
>

signature.asc

Ondřej Jirman

unread,
Jul 17, 2016, 10:39:35 AM7/17/16
to Maxime Ripard, Chen-Yu Tsai, dev, linux-arm-kernel, Rob Herring, Mark Rutland, Russell King, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list


On 25.6.2016 09:02, Maxime Ripard wrote:
> On Sat, Jun 25, 2016 at 09:02:48AM +0800, Chen-Yu Tsai wrote:
>> On Sat, Jun 25, 2016 at 6:51 AM, Ondřej Jirman <meg...@megous.com> wrote:
>>> Hello,
>>>
>>> comments below.
>>>
>>> On 24.6.2016 05:48, Chen-Yu Tsai wrote:
>>>> On Fri, Jun 24, 2016 at 3:20 AM, <meg...@megous.com> wrote:
>>>>> From: Ondrej Jirman <meg...@megous.com>
>>>>>
>>>>> Add label to the first cpu so that it can be referenced
>>>>> from derived dts files.
>>>>>
>>>>> Signed-off-by: Ondrej Jirman <meg...@megous.com>
>>>>> ---
So I tried, and found out that it will not be so easy. Different boards
have different regulators, and linux doesn't deal well with voltages
that are not supported by the regulator.

So even if the board can run at certain frequency if you round the
voltage to the next higher voltage supported by the regulator, opp
implementation doesn't do the rounding and just drops the operating
points that have no support in the voltage regulator.

We have boards that have 1.1/1.3V switching, only 1.3V, fine tuned
voltage regulation and every such board will need it's own set of
operating points.

I'd leave the OPP definitions in the board files for now.

cpu cpu0: _opp_add: OPP not supported by regulators (1368000000)
core: _opp_supported_by_regulators: OPP minuV: 1340000 maxuV: 1340000,
not supported by regulator
cpu cpu0: _opp_add: OPP not supported by regulators (1344000000)
core: _opp_supported_by_regulators: OPP minuV: 1340000 maxuV: 1340000,
not supported by regulator
cpu cpu0: _opp_add: OPP not supported by regulators (1296000000)
core: _opp_supported_by_regulators: OPP minuV: 1200000 maxuV: 1200000,
not supported by regulator
cpu cpu0: _opp_add: OPP not supported by regulators (1104000000)
core: _opp_supported_by_regulators: OPP minuV: 1140000 maxuV: 1140000,
not supported by regulator
cpu cpu0: _opp_add: OPP not supported by regulators (1008000000)

regards,
o.

> Maxime
>

signature.asc

Jean-Francois Moine

unread,
Jul 19, 2016, 9:23:37 AM7/19/16
to Ondřej Jirman, Maxime Ripard, Mark Rutland, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, d...@linux-sunxi.org, Michael Turquette, Stephen Boyd, open list, Emilio López, Chen-Yu Tsai, Rob Herring, open list:COMMON CLK FRAMEWORK, linux-ar...@lists.infradead.org
On Fri, 15 Jul 2016 12:38:54 +0200
Ondřej Jirman <meg...@megous.com> wrote:

> > If so, then yes, trying to switch to the 24MHz oscillator before
> > applying the factors, and then switching back when the PLL is stable
> > would be a nice solution.
> >
> > I just checked, and all the SoCs we've had so far have that
> > possibility, so if it works, for now, I'd like to stick to that.
>
> It would need to be tested. U-boot does the change only once, while the
> kernel would be doing it all the time and between various frequencies
> and PLL settings. So the issues may show up with this solution too.

I don't think this is a good idea: the CPU clock may be changed at any
time with the CPUFreq governor. I don't see the system moving from
1008MHz to 24MHz and then to 1200MHz when some computation is needed!

BTW, Ondřej, in my BPi M2+, I tried to change the CPU clock with your
code at kernel start time from 792MHz to 1008MHz, but the hardware
(arisc?) set an other value, and the system speed was lower than before
(the PLL-CPUx register is 0x90031521 on boot, I want to set it to
xxxx1410 and I read 0x91031f33 - sorry, I did not have a look at the
CPU SD pattern). Do you know why?

Thomas Kaiser

unread,
Jul 19, 2016, 10:10:55 AM7/19/16
to linux-sunxi, maxime...@free-electrons.com, we...@csie.org, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, rob...@kernel.org, mark.r...@arm.com, li...@armlinux.org.uk, devic...@vger.kernel.org, linux-...@vger.kernel.org, meg...@megous.com
Hi,

Ondřej Jirman wrote:
We have boards that have 1.1/1.3V switching, only 1.3V, fine tuned
voltage regulation and every such board will need it's own set of
operating points.

Yes, and Allwinner's current BSP kernel code might encourage board makers to implement a forth variant: switching between 4 different voltages through GPIOs.

Currently we have 4 boards that rely on the simple '2 voltage regulation' all using 1.1V/1.3V: Orange Pi One and Lite and NanoPi M1 and NEO. Then there are 2 devices with (legacy) Linux support existing that use no voltage regulation at all: Banana Pi M2+ (according to schematic using 1.2V but in reality it's 1.3V VDD_CPUX) and Beelink X2. And according to Tsvetan if/when Olimex will release their 2 H3 boards we have two more with fixed but yet unknown VDD_CPUX voltage (since olimex fears overheating maybe they use 1.1V or 1.2V limiting max cpufreq to 816 or 1008 MHz). And all the bigger H3 based Orange Pi use the SY8106A voltage regulator being able to adjust VDD_CPUX in steps of 20mV allowing VDD_CPUX to exceed 1200 MHz (a reasonable value seems to be 1296 MHz since above throttling will be an issue without active cooling)

Things get even worse since Xunlong uses copper layers inside the PCB to spread the heat away from H3 so Orange Pi One/Lite do not overheat that much like eg. NanoPi M1 (and maybe NEO -- can tell next week when I get dev samples to play with). So while eg. Orange Pi One and NanoPi M1 switch between the same voltages in the same way we (Armbian) found that we have to allow M1 to downclock to even 240 MHz since when testing with legacy kernel really heavy workloads led to throttling that low (even CPU cores were killed at this low clockspeed -- same applies to BPi M2+ and Beelink X2)

So i would second Ondřej's suggestions since when we're talking about H3 devices we're not talking about tablet SoCs with accompanied PMU but 3 classes of devices behaving totally different in regard to cpufreq limits and dvfs OPPs (and maybe someone is already developing a new H3 device adding a forth variant switching between 4 different VDD_CPUX voltages)

Thomas

Maxime Ripard

unread,
Jul 21, 2016, 5:48:54 AM7/21/16
to Ondřej Jirman, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
Interesting. Which SoCs in particular?
If we ever need to change that, we can always rely on a clock notifier
to adjust the divider before the change happen (and support all the
scenarios, like the clock change has been aborted).

> > If so, then yes, trying to switch to the 24MHz oscillator before
> > applying the factors, and then switching back when the PLL is stable
> > would be a nice solution.
> >
> > I just checked, and all the SoCs we've had so far have that
> > possibility, so if it works, for now, I'd like to stick to that.
>
> It would need to be tested. U-boot does the change only once, while the
> kernel would be doing it all the time and between various frequencies
> and PLL settings. So the issues may show up with this solution too.

That would have the benefit of being quite easy to document, not be a
huge amount of code and it would work on all the CPUs PLLs we have so
far, so still, a pretty big win. If it doesn't, of course, we don't
really have the choice.
signature.asc

Maxime Ripard

unread,
Jul 21, 2016, 5:51:20 AM7/21/16
to Jean-Francois Moine, Ondřej Jirman, Mark Rutland, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, d...@linux-sunxi.org, Michael Turquette, Stephen Boyd, open list, Emilio López, Chen-Yu Tsai, Rob Herring, open list:COMMON CLK FRAMEWORK, linux-ar...@lists.infradead.org
On Fri, Jul 15, 2016 at 03:27:56PM +0200, Jean-Francois Moine wrote:
> On Fri, 15 Jul 2016 12:38:54 +0200
> Ondřej Jirman <meg...@megous.com> wrote:
>
> > > If so, then yes, trying to switch to the 24MHz oscillator before
> > > applying the factors, and then switching back when the PLL is stable
> > > would be a nice solution.
> > >
> > > I just checked, and all the SoCs we've had so far have that
> > > possibility, so if it works, for now, I'd like to stick to that.
> >
> > It would need to be tested. U-boot does the change only once, while the
> > kernel would be doing it all the time and between various frequencies
> > and PLL settings. So the issues may show up with this solution too.
>
> I don't think this is a good idea: the CPU clock may be changed at any
> time with the CPUFreq governor. I don't see the system moving from
> 1008MHz to 24MHz and then to 1200MHz when some computation is needed!

It wouldn't happen that often. The sampling rate for the governor is
1000 times the latency, so, at most, 0.1% of the time would be spent
at 24MHz.

And if you're really concerned about performances, you won't enable
cpufreq anyway.
signature.asc

Ondřej Jirman

unread,
Jul 21, 2016, 5:52:23 AM7/21/16
to Maxime Ripard, d...@linux-sunxi.org, linux-ar...@lists.infradead.org, Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland, Chen-Yu Tsai, Emilio López, open list:COMMON CLK FRAMEWORK, open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS, open list
It's probably more code though. It has to access different register from
the one that is already defined in dts, which would add a lot of code
and require dts changes. The original patch I sent is simpler than that.

regards,
Ondrej

> Maxime
>

signature.asc
It is loading more messages.
0 new messages