From 1c44b2c7ee26d4a3b6d6710181203bf3c8491a79 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wens@csie.org>
Date: Wed, 20 Jun 2018 15:13:41 +0800
Subject: [PATCH 08/45] arm64: dts: allwinner: h6: Add LED device nodes for
 Pine H64

The Pine H64 has 3 GPIO-controlled LEDs, which are labeled "heartbeat",
"link", and "status".

Add device nodes for them.

Acked-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 .../boot/dts/allwinner/sun50i-h6-pine-h64.dts | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
index b6f2d6b2ecae..2e97173c9204 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
@@ -20,6 +20,25 @@
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		heartbeat {
+			label = "pine-h64:green:heartbeat";
+			gpios = <&r_pio 0 4 GPIO_ACTIVE_HIGH>; /* PL4 */
+		};
+
+		link {
+			label = "pine-h64:white:link";
+			gpios = <&r_pio 0 3 GPIO_ACTIVE_HIGH>; /* PL3 */
+		};
+
+		status {
+			label = "pine-h64:blue:status";
+			gpios = <&r_pio 0 7 GPIO_ACTIVE_HIGH>; /* PL7 */
+		};
+	};
 };

 &r_i2c {
--
2.17.1


From 6bfc6aab9a9cd82578a7e782c83d04f4cf7fe6c4 Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 27 Jul 2018 16:22:01 +0800
Subject: [PATCH 37/45] nvmem: sunxi-sid: add support for H6 SID

The SID controller in Allwinner H6 SoC is similar to the one in
Allwinner A64, except the size of the eFUSE is enlarged to 512 bytes
(4Kbit).

Add support for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 .../devicetree/bindings/nvmem/allwinner,sunxi-sid.txt       | 1 +
 drivers/nvmem/sunxi_sid.c                                   | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
index e319fe5e205a..332de580e321 100644
--- a/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
+++ b/Documentation/devicetree/bindings/nvmem/allwinner,sunxi-sid.txt
@@ -7,6 +7,7 @@ Required properties:
   "allwinner,sun8i-a83t-sid"
   "allwinner,sun8i-h3-sid"
   "allwinner,sun50i-a64-sid"
+  "allwinner,sun50i-h6-sid"

 - reg: Should contain registers location and length

diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index d020f89248fd..fa58c3574afa 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -232,11 +232,17 @@ static const struct sunxi_sid_cfg sun50i_a64_cfg = {
 	.size = 0x100,
 };

+static const struct sunxi_sid_cfg sun50i_h6_cfg = {
+	.value_offset = 0x200,
+	.size = 0x200,
+};
+
 static const struct of_device_id sunxi_sid_of_match[] = {
 	{ .compatible = "allwinner,sun4i-a10-sid", .data = &sun4i_a10_cfg },
 	{ .compatible = "allwinner,sun7i-a20-sid", .data = &sun7i_a20_cfg },
 	{ .compatible = "allwinner,sun8i-h3-sid", .data = &sun8i_h3_cfg },
 	{ .compatible = "allwinner,sun50i-a64-sid", .data = &sun50i_a64_cfg },
+	{ .compatible = "allwinner,sun50i-h6-sid", .data = &sun50i_h6_cfg },
 	{/* sentinel */},
 };
 MODULE_DEVICE_TABLE(of, sunxi_sid_of_match);
--
2.17.1


From de62065cf1b55e48049c44076500a32eac08fe2f Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 27 Jul 2018 16:24:18 +0800
Subject: [PATCH 38/45] arm64: allwinner: dts: h6: add H6 SID device tree node

The Allwinner H6 SoC has a SID like previous Allwinner SoCs.

Add a device tree node for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 1a8086476514..8e3c47c7c797 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -174,6 +174,11 @@
 			#interrupt-cells = <3>;
 		};

+		sid: efuse@3006000 {
+			compatible = "allwinner,sun50i-h6-sid";
+			reg = <0x03006000 0x1000>;
+		};
+
 		pio: pinctrl@300b000 {
 			compatible = "allwinner,sun50i-h6-pinctrl";
 			reg = <0x0300b000 0x400>;
--
2.17.1


From 8cdaf449f2936b608862b0a0175dd05fb52233b1 Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 27 Jul 2018 17:34:35 +0800
Subject: [PATCH 39/45] nvmem: sunxi-sid: fix endian

The data in the SID is stored as little endian. However, when accessing
the SID via sunxi-sid driver, it converts little endian to big endian at
4 byte border. This makes addressing sub-4-byte items in the SID wrong.

Fix the endian by read out the SID 4-byte words as little endian, not
big endian.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 drivers/nvmem/sunxi_sid.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/nvmem/sunxi_sid.c b/drivers/nvmem/sunxi_sid.c
index fa58c3574afa..af30d62b1426 100644
--- a/drivers/nvmem/sunxi_sid.c
+++ b/drivers/nvmem/sunxi_sid.c
@@ -63,7 +63,7 @@ static u8 sunxi_sid_read_byte(const struct sunxi_sid *sid,
 {
 	u32 sid_key;

-	sid_key = ioread32be(sid->base + round_down(offset, 4));
+	sid_key = readl(sid->base + round_down(offset, 4));
 	sid_key >>= (offset % 4) * 8;

 	return sid_key; /* Only return the last byte */
--
2.17.1


From e7690d51c51dd6c97475bef2b207244d3a5f91b3 Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 27 Jul 2018 16:18:35 +0800
Subject: [PATCH 40/45] sun50i-h6-ths

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 drivers/thermal/Kconfig         |  11 +
 drivers/thermal/Makefile        |   1 +
 drivers/thermal/sun50i_h6_ths.c | 365 ++++++++++++++++++++++++++++++++
 3 files changed, 377 insertions(+)
 create mode 100644 drivers/thermal/sun50i_h6_ths.c

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 82979880f985..1b302248633a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -415,6 +415,17 @@ config MTK_THERMAL
 	  Enable this option if you want to have support for thermal management
 	  controller present in Mediatek SoCs

+config SUN50I_H6_THS
+	tristate "Thermal sensor driver for Allwinner H6"
+	depends on ARCH_SUNXI || COMPILE_TEST
+	depends on HAS_IOMEM
+	depends on NVMEM
+	depends on OF
+	depends on RESET_CONTROLLER
+	help
+	  Enable this option if you want to have support for thermal reporting
+	  on Allwinner H6.
+
 menu "Broadcom thermal drivers"
 depends on ARCH_BCM || ARCH_BRCMSTB || ARCH_BCM2835 || COMPILE_TEST
 source "drivers/thermal/broadcom/Kconfig"
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 610344eb3e03..bdc5ba49f170 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_QCOM_TSENS)	+= qcom/
 obj-y				+= tegra/
 obj-$(CONFIG_HISI_THERMAL)     += hisi_thermal.o
 obj-$(CONFIG_MTK_THERMAL)	+= mtk_thermal.o
+obj-$(CONFIG_SUN50I_H6_THS)	+= sun50i_h6_ths.o
 obj-$(CONFIG_GENERIC_ADC_THERMAL)	+= thermal-generic-adc.o
 obj-$(CONFIG_ZX2967_THERMAL)	+= zx2967_thermal.o
 obj-$(CONFIG_UNIPHIER_THERMAL)	+= uniphier_thermal.o
diff --git a/drivers/thermal/sun50i_h6_ths.c b/drivers/thermal/sun50i_h6_ths.c
new file mode 100644
index 000000000000..ad3c5f3e47c7
--- /dev/null
+++ b/drivers/thermal/sun50i_h6_ths.c
@@ -0,0 +1,365 @@
+/*
+ * Thermal sensor driver for Allwinner H6
+ *
+ * Copyright (C) 2018 Icenowy Zheng
+ *
+ * Based on the work of Ondřej Jirman
+ * Based on the work of Josef Gajdusek <atx@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_H6_MAX_SENSOR_NUM	4
+
+#define THS_H6_CTRL0		0x00
+#define THS_H6_CTRL2		0x04
+#define THS_H6_PER		0x08
+#define THS_H6_DATA_INT_CTRL	0x10
+#define THS_H6_DATA_INT_STAT	0x20
+#define THS_H6_FILTER		0x30
+#define THS_H6_CDATA(n)		(0xa0 + 4 * (n))
+#define THS_H6_DATA(n)		(0xc0 + 4 * (n))
+
+#define THS_H6_CTRL0_SENSOR_ACQ0(x)	((x) << 16)
+#define THS_H6_CTRL2_SENSE_EN(n)	BIT(0 + (n))
+#define THS_H6_PER_THERMAL_PER(x)	((x) << 12)
+#define THS_H6_INT_CTRL_DATA_IRQ_EN(n)	BIT(0 + (n))
+#define THS_H6_STAT_DATA_IRQ_STS(n)	BIT(0 + (n))
+#define THS_H6_FILTER_TYPE(x)		((x) << 0)
+#define THS_H6_FILTER_EN		BIT(2)
+
+#define THS_H6_CLK_IN		240000000 /* Hz */
+#define THS_H6_DATA_PERIOD	10 /* ms */
+
+#define THS_H6_FILTER_TYPE_VALUE	2 /* average over 2^(n+1) samples */
+#define THS_H6_FILTER_DIV		(1 << (THS_H6_FILTER_TYPE_VALUE + 1))
+#define THS_H6_INT_CTRL_THERMAL_PER_VALUE \
+	(THS_H6_DATA_PERIOD * (THS_H6_CLK_IN / 1000) / THS_H6_FILTER_DIV / 4096 - 1)
+#define THS_H6_CTRL0_SENSOR_ACQ0_VALUE	0x1df /* 20us */
+#define THS_H6_CTRL0_UNK		0x0000002f
+
+#define THS_H6_CAL_FT_TEMP_MASK		0x0fff
+#define THS_H6_CAL_FT_TEMP_DEVIATION_EN	0x3000
+#define THS_H6_CAL_DEFAULT		0x800
+#define THS_H6_CAL_VAL_MASK		0xfff
+
+struct sun50i_h6_ths_data;
+
+struct sun50i_h6_ths_sensor {
+	struct sun50i_h6_ths_data *data;
+	int id;
+	struct thermal_zone_device *tzd;
+	u32 val;
+};
+
+struct sun50i_h6_ths_cfg {
+	int sensor_num;
+	int (*calc_temp)(u32 val);
+};
+
+struct sun50i_h6_ths_data {
+	struct reset_control *reset;
+	struct clk *busclk;
+	void __iomem *regs;
+	const struct sun50i_h6_ths_cfg *cfg;
+	struct nvmem_cell *calcell;
+	struct sun50i_h6_ths_sensor sensors[THS_H6_MAX_SENSOR_NUM];
+};
+
+static int sun50i_h6_ths_calc_temp(u32 val)
+{
+	return (187744 - (int)((val * 1000000) / 14882));
+}
+
+static u16 sun50i_h6_ths_recalc_reg(u32 temp)
+{
+	return (u16)(2794 - temp * 14882 / 1000000);
+}
+
+static int sun50i_h6_ths_get_temp(void *_data, int *out)
+{
+	struct sun50i_h6_ths_sensor *sensor = _data;
+
+	if (sensor->val == 0)
+		return -EBUSY;
+
+	/* Formula and parameters from the Allwinner 3.4 kernel */
+	*out = sensor->data->cfg->calc_temp(sensor->val);
+	return 0;
+}
+
+static irqreturn_t sun50i_h6_ths_irq_thread(int irq, void *_data)
+{
+	struct sun50i_h6_ths_data *data = _data;
+	int i;
+
+	for (i = 0; i < data->cfg->sensor_num; i++) {
+		if (!(readl(data->regs + THS_H6_DATA_INT_STAT) &
+		      THS_H6_STAT_DATA_IRQ_STS(i)))
+			continue;
+
+		writel(THS_H6_STAT_DATA_IRQ_STS(i),
+		       data->regs + THS_H6_DATA_INT_STAT);
+
+		data->sensors[i].val = readl(data->regs + THS_H6_DATA(i));
+		if (data->sensors[i].val)
+			thermal_zone_device_update(data->sensors[i].tzd,
+						   THERMAL_EVENT_TEMP_SAMPLE);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void sun50i_h6_ths_init(struct sun50i_h6_ths_data *data)
+{
+	u32 val;
+	int i;
+
+	writel(THS_H6_CTRL0_SENSOR_ACQ0(THS_H6_CTRL0_SENSOR_ACQ0_VALUE) |
+	       THS_H6_CTRL0_UNK, data->regs + THS_H6_CTRL0);
+	writel(THS_H6_FILTER_EN | THS_H6_FILTER_TYPE(THS_H6_FILTER_TYPE_VALUE),
+	       data->regs + THS_H6_FILTER);
+
+	val = 0;
+	for (i = 0; i < data->cfg->sensor_num; i++)
+		val |= THS_H6_CTRL2_SENSE_EN(i);
+	writel(val, data->regs + THS_H6_CTRL2);
+
+	val = THS_H6_PER_THERMAL_PER(THS_H6_INT_CTRL_THERMAL_PER_VALUE);
+	writel(val, data->regs + THS_H6_PER);
+
+	val = 0;
+	for (i = 0; i < data->cfg->sensor_num; i++)
+		val |= THS_H6_INT_CTRL_DATA_IRQ_EN(i);
+	writel(val, data->regs + THS_H6_DATA_INT_CTRL);
+}
+
+static const struct thermal_zone_of_device_ops sun50i_h6_ths_thermal_ops = {
+	.get_temp = sun50i_h6_ths_get_temp,
+};
+
+static int sun50i_h6_ths_calibrate(struct sun50i_h6_ths_data *data)
+{
+	u16 *caldata;
+	size_t callen;
+	int i;
+	int ft_temp;
+	s16 ft_temp_orig_reg, diff, cal_val;
+	u32 reg_val;
+
+	caldata = nvmem_cell_read(data->calcell, &callen);
+	if (IS_ERR(caldata))
+		return PTR_ERR(caldata);
+
+	if (callen < 2 + 2 * data->cfg->sensor_num)
+		return -EINVAL;
+
+	if (!caldata[0])
+		return -EINVAL;
+
+	/*
+	 * The calbration data on H6 is stored as temperature-value
+	 * pair when being filled at factory test stage.
+	 * The unit of stored FT temperature is 0.1 degreee celusis.
+	 */
+	ft_temp = (caldata[0] & THS_H6_CAL_FT_TEMP_MASK) * 100;
+	ft_temp_orig_reg = sun50i_h6_ths_recalc_reg(ft_temp);
+
+	for (i = 0; i < data->cfg->sensor_num; i++)
+	{
+		diff = (ft_temp_orig_reg - (s16)caldata[1 + i]);
+		cal_val = THS_H6_CAL_DEFAULT - diff;
+
+		if (cal_val & ~THS_H6_CAL_VAL_MASK) {
+			pr_warn("Faulty thermal sensor %d calibration value, beyond the valid range.\n", i);
+			continue;
+		}
+
+		if (i % 2) {
+			reg_val = readl(data->regs + THS_H6_CDATA(i / 2));
+			reg_val &= 0xffff;
+			reg_val |= cal_val << 16;
+			writel(reg_val, data->regs + THS_H6_CDATA(i / 2));
+		} else {
+			writel(cal_val, data->regs + THS_H6_CDATA(i / 2));
+		}
+	}
+
+	kfree(caldata);
+	return 0;
+}
+
+static int sun50i_h6_ths_probe(struct platform_device *pdev)
+{
+	struct sun50i_h6_ths_data *data;
+	struct resource *res;
+	int ret, irq, i;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->cfg = of_device_get_match_data(&pdev->dev);
+	if (!data->cfg)
+		return -EINVAL;
+
+	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;
+	}
+
+	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,
+					sun50i_h6_ths_irq_thread, IRQF_ONESHOT,
+					dev_name(&pdev->dev), data);
+	if (ret)
+		return ret;
+
+	data->busclk = devm_clk_get(&pdev->dev, "bus");
+	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->reset = devm_reset_control_get(&pdev->dev, NULL);
+	if (IS_ERR(data->reset)) {
+		ret = PTR_ERR(data->reset);
+		dev_err(&pdev->dev, "failed to get reset: %d\n", ret);
+		return ret;
+	}
+
+	ret = reset_control_deassert(data->reset);
+	if (ret) {
+		dev_err(&pdev->dev, "reset deassert failed: %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);
+		goto err_assert_reset;
+	}
+
+	data->calcell = devm_nvmem_cell_get(&pdev->dev, "calibration");
+	if (IS_ERR(data->calcell)) {
+		if (PTR_ERR(data->calcell) == -EPROBE_DEFER) {
+			ret = PTR_ERR(data->calcell);
+			goto err_disable_bus;
+		}
+		/*
+		* Even if the external calibration data stored in eFUSE is
+		* not accessible, the THS hardware can still work, although
+		* the data won't be so accurate.
+		* The default value of calibration register is 0x800 for
+		* every sensor, and the calibration value is usually 0x7xx
+		* or 0x8xx, so they won't be away from the default value
+		* for a lot.
+		* So here we do not return if the calibartion data is not
+		* available, except the probe needs deferring.
+		*/
+	} else {
+		ret = sun50i_h6_ths_calibrate(data);
+		if (ret) {
+			/* Revert calibrating */
+			for (i = 0; i < data->cfg->sensor_num; i += 2) {
+				writew(THS_H6_CAL_DEFAULT,
+				       data->regs + THS_H6_CDATA(i / 2));
+			}
+		}
+	}
+
+	for (i = 0; i < data->cfg->sensor_num; i++) {
+		data->sensors[i].data = data;
+		data->sensors[i].id = i;
+		data->sensors[i].tzd =
+			devm_thermal_zone_of_sensor_register(&pdev->dev,
+				i, &data->sensors[i], &sun50i_h6_ths_thermal_ops);
+		if (IS_ERR(data->sensors[i].tzd)) {
+			ret = PTR_ERR(data->sensors[i].tzd);
+			dev_err(&pdev->dev,
+				"failed to register thermal zone %d: %d\n",
+				i, ret);
+			goto err_disable_bus;
+		}
+	}
+
+	sun50i_h6_ths_init(data);
+
+	platform_set_drvdata(pdev, data);
+	return 0;
+
+err_disable_bus:
+	clk_disable_unprepare(data->busclk);
+err_assert_reset:
+	reset_control_assert(data->reset);
+	return ret;
+}
+
+static int sun50i_h6_ths_remove(struct platform_device *pdev)
+{
+	struct sun50i_h6_ths_data *data = platform_get_drvdata(pdev);
+
+	reset_control_assert(data->reset);
+	clk_disable_unprepare(data->busclk);
+	return 0;
+}
+
+static const struct sun50i_h6_ths_cfg sun50i_h6_ths_cfg = {
+	.sensor_num = 2,
+	.calc_temp = sun50i_h6_ths_calc_temp,
+};
+
+static const struct of_device_id sun50i_h6_ths_id_table[] = {
+	{ .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths_cfg },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sun50i_h6_ths_id_table);
+
+static struct platform_driver sun50i_h6_ths_driver = {
+	.probe = sun50i_h6_ths_probe,
+	.remove = sun50i_h6_ths_remove,
+	.driver = {
+		.name = "sun50i_h6_ths",
+		.of_match_table = sun50i_h6_ths_id_table,
+	},
+};
+
+module_platform_driver(sun50i_h6_ths_driver);
+
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_DESCRIPTION("Thermal sensor driver for Allwinner H6");
+MODULE_LICENSE("GPL v2");
--
2.17.1


From b2efe78569663e3188d712699209126a535df23d Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 27 Jul 2018 16:18:42 +0800
Subject: [PATCH 41/45] basic ths dt

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 35 ++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 8e3c47c7c797..cf125ebd1c7b 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -10,6 +10,7 @@
 #include <dt-bindings/clock/sun50i-h6-r-ccu.h>
 #include <dt-bindings/reset/sun50i-h6-ccu.h>
 #include <dt-bindings/reset/sun50i-h6-r-ccu.h>
+#include <dt-bindings/thermal/thermal.h>

 / {
 	interrupt-parent = <&gic>;
@@ -177,6 +178,12 @@
 		sid: efuse@3006000 {
 			compatible = "allwinner,sun50i-h6-sid";
 			reg = <0x03006000 0x1000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			ths_calib: thermal-sensor-calibration@14 {
+				reg = <0x14 0x6>;
+			};
 		};

 		pio: pinctrl@300b000 {
@@ -445,6 +452,18 @@
 			};
 		};

+		ths: ths@5070400 {
+			compatible = "allwinner,sun50i-h6-ths";
+			reg = <0x05070400 0x100>;
+			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_THS>;
+			clock-names = "bus";
+			resets = <&ccu RST_BUS_THS>;
+			nvmem-cells = <&ths_calib>;
+			nvmem-cell-names = "calibration";
+			#thermal-sensor-cells = <1>;
+		};
+
 		r_ccu: clock@7010000 {
 			compatible = "allwinner,sun50i-h6-r-ccu";
 			reg = <0x07010000 0x400>;
@@ -495,4 +514,20 @@
 			#size-cells = <0>;
 		};
 	};
+
+	thermal-zones {
+		cpu_thermal {
+			/* milliseconds */
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+			thermal-sensors = <&ths 0>;
+		};
+
+		gpu_thermal {
+			/* milliseconds */
+			polling-delay-passive = <250>;
+			polling-delay = <1000>;
+			thermal-sensors = <&ths 1>;
+		};
+	};
 };
--
2.17.1


From 5568aa53d90402816fe45ce30f7aaa6e577810aa Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 27 Jul 2018 19:19:28 +0800
Subject: [PATCH 43/45] arm64: allwinner: dts: h6: add CPU supply for Pine H64

The Pine H64, follows the reference design on the AXP805 DCDC
assignment, connects DCDCA (polyphased with DCDCB) to the ARM
cores' power supply.

Add this to the device tree, to enable voltage scaling.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
index 3c74cbed319b..fb45e68bc441 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-pine-h64.dts
@@ -92,6 +92,10 @@
 	};
 };

+&cpu0 {
+	cpu-supply = <&reg_dcdca>;
+};
+
 &mmc0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&mmc0_pins>;
--
2.17.1


From 6a83e3542e2ad0388f5ee5b9beb7774467ab08bd Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 27 Jul 2018 19:28:31 +0800
Subject: [PATCH 44/45] bind trips

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 35 ++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 5cc72c943374..000a681fb515 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -540,6 +540,41 @@
 			polling-delay-passive = <250>;
 			polling-delay = <1000>;
 			thermal-sensors = <&ths 0>;
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+
+				map1 {
+					trip = <&cpu_alert1>;
+					cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+
+			trips {
+				cpu_alert0: cpu_alert0 {
+					/* milliCelsius */
+					temperature = <75000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
+				cpu_alert1: cpu_alert1 {
+					/* milliCelsius */
+					temperature = <90000>;
+					hysteresis = <2000>;
+					type = "hot";
+				};
+
+				cpu_crit: cpu_crit {
+					/* milliCelsius */
+					temperature = <1000000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
 		};

 		gpu_thermal {
--
2.17.1


From 32a3eba2d813fb311430f2275ba1dbe73c37da73 Mon Sep 17 00:00:00 2001
From: Icenowy Zheng <icenowy@aosc.io>
Date: Fri, 27 Jul 2018 19:30:10 +0800
Subject: [PATCH 45/45] add extra opps

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
index 000a681fb515..bec8c4a46ec7 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
@@ -41,6 +41,30 @@
 			opp-microvolt = <880000>;
 			clock-latency-ns = <244144>; /* 8 32k periods */
 		};
+
+		opp-1008000000 {
+			opp-hz = /bits/ 64 <1008000000>;
+			opp-microvolt = <940000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp-1320000000 {
+			opp-hz = /bits/ 64 <1320000000>;
+			opp-microvolt = <1000000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp-1488000000 {
+			opp-hz = /bits/ 64 <1488000000>;
+			opp-microvolt = <1060000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
+
+		opp-1800000000 {
+			opp-hz = /bits/ 64 <1800000000>;
+			opp-microvolt = <1160000>;
+			clock-latency-ns = <244144>; /* 8 32k periods */
+		};
 	};

 	cpus {
--
2.17.1

