From c2647d5bd61a2157305d968f6ba305e58f2bd5f9 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 6 Jan 2020 19:27:10 +0100 Subject: [PATCH] Allwinner: Sort Linux patches --- ...s-sun8i-h3-Add-rc-map-for-Beelink-X2.patch | 27 - .../devices/H6/patches/linux/07-opi3.patch | 186 -- .../H6/patches/linux/10-beelink-gs1.patch | 207 -- .../devices/H6/patches/linux/11-pwm.patch | 344 --- .../H6/patches/linux/13-Tanix-TX6.patch | 47 +- .../linux/0001-backport-from-5.5.patch | 667 +++++ .../linux/0002-backport-from-5.6.patch | 2220 +++++++++++++++++ .../linux/0005-cedrus-improvements.patch | 124 - .../patches/linux/0007-thermal.patch | 946 ------- .../patches/linux/0012-H6-USB3.patch | 252 -- 10 files changed, 2892 insertions(+), 2128 deletions(-) delete mode 100644 projects/Allwinner/devices/H3/patches/linux/02-ARM-dts-sun8i-h3-Add-rc-map-for-Beelink-X2.patch delete mode 100644 projects/Allwinner/devices/H6/patches/linux/10-beelink-gs1.patch delete mode 100644 projects/Allwinner/devices/H6/patches/linux/11-pwm.patch create mode 100644 projects/Allwinner/patches/linux/0002-backport-from-5.6.patch delete mode 100644 projects/Allwinner/patches/linux/0007-thermal.patch delete mode 100644 projects/Allwinner/patches/linux/0012-H6-USB3.patch diff --git a/projects/Allwinner/devices/H3/patches/linux/02-ARM-dts-sun8i-h3-Add-rc-map-for-Beelink-X2.patch b/projects/Allwinner/devices/H3/patches/linux/02-ARM-dts-sun8i-h3-Add-rc-map-for-Beelink-X2.patch deleted file mode 100644 index e06ba1a196..0000000000 --- a/projects/Allwinner/devices/H3/patches/linux/02-ARM-dts-sun8i-h3-Add-rc-map-for-Beelink-X2.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 806099cadd96ebbf908e5cd29fe55eb6868cb28e Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Sat, 9 Nov 2019 19:13:36 +0100 -Subject: [PATCH] ARM: dts: sun8i: h3: Add rc map for Beelink X2 - -Beelink X2 box comes with a remote. Add a mapping for it. - -Signed-off-by: Jernej Skrabec ---- - arch/arm/boot/dts/sun8i-h3-beelink-x2.dts | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts -index ac9e26b1d906..45a24441ff18 100644 ---- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts -+++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts -@@ -143,6 +143,7 @@ hdmi_out_con: endpoint { - }; - - &ir { -+ linux,rc-map-name = "rc-tanix-tx3mini"; - pinctrl-names = "default"; - pinctrl-0 = <&r_ir_rx_pin>; - status = "okay"; --- -2.24.0 - diff --git a/projects/Allwinner/devices/H6/patches/linux/07-opi3.patch b/projects/Allwinner/devices/H6/patches/linux/07-opi3.patch index f324521525..c87d148344 100644 --- a/projects/Allwinner/devices/H6/patches/linux/07-opi3.patch +++ b/projects/Allwinner/devices/H6/patches/linux/07-opi3.patch @@ -30,106 +30,6 @@ index 17d496990108..93bdd33694fb 100644 -- 2.22.0 -From 5141fbafc9bf5f1a7cbb6923bc719f595ce54dae Mon Sep 17 00:00:00 2001 -From: Icenowy Zheng -Date: Mon, 25 Dec 2017 12:10:06 +0800 -Subject: [PATCH 26/34] arm64: dts: allwinner: h6: add USB3 device nodes - -Allwinner H6 SoC features USB3 functionality, with a DWC3 controller and -a custom PHY. - -Add device tree nodes for them. - -Signed-off-by: Icenowy Zheng -Reviewed-by: Chen-Yu Tsai ---- - arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 32 ++++++++++++++++++++ - 1 file changed, 32 insertions(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -index c5c0608e67403..38784589558ca 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -@@ -420,6 +420,38 @@ - status = "disabled"; - }; - -+ dwc3: dwc3@5200000 { -+ compatible = "snps,dwc3"; -+ reg = <0x05200000 0x10000>; -+ interrupts = ; -+ clocks = <&ccu CLK_BUS_XHCI>, -+ <&ccu CLK_BUS_XHCI>, -+ <&rtc 0>; -+ clock-names = "ref", "bus_early", "suspend"; -+ resets = <&ccu RST_BUS_XHCI>; -+ /* -+ * The datasheet of the chip doesn't declare the -+ * peripheral function, and there's no boards known -+ * to have a USB Type-B port routed to the port. -+ * In addition, no one has tested the peripheral -+ * function yet. -+ * So set the dr_mode to "host" in the DTSI file. -+ */ -+ dr_mode = "host"; -+ phys = <&usb3phy>; -+ phy-names = "usb3-phy"; -+ status = "disabled"; -+ }; -+ -+ usb3phy: phy@5210000 { -+ compatible = "allwinner,sun50i-h6-usb3-phy"; -+ reg = <0x5210000 0x10000>; -+ clocks = <&ccu CLK_USB_PHY1>; -+ resets = <&ccu RST_USB_PHY1>; -+ #phy-cells = <0>; -+ status = "disabled"; -+ }; -+ - ehci3: usb@5311000 { - compatible = "allwinner,sun50i-h6-ehci", "generic-ehci"; - reg = <0x05311000 0x100>; - -From c74e4ba1e28d5808cda02b34eee59dc1a5f15a6d Mon Sep 17 00:00:00 2001 -From: Ondrej Jirman -Date: Wed, 27 Mar 2019 13:43:25 +0100 -Subject: [PATCH 34/34] arm64: dts: allwinner: orange-pi-3: Enable USB 3.0 host - support - -Enable Allwinner's USB 3.0 phy and the host controller. Orange Pi 3 -board has GL3510 USB 3.0 4-port hub connected to the SoC's USB 3.0 -port. All four ports are exposed via USB3-A connectors. The hub is -powered directly from DCIN/VCC-5V. - -Signed-off-by: Ondrej Jirman ---- - arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts -index d9e8610b5f83f..afee79fb88f18 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts -@@ -126,6 +126,10 @@ - status = "okay"; - }; - -+&dwc3 { -+ status = "okay"; -+}; -+ - &ehci0 { - status = "okay"; - }; -@@ -359,3 +363,8 @@ - usb3_vbus-supply = <®_vcc5v>; - status = "okay"; - }; -+ -+&usb3phy { -+ phy-supply = <®_vcc5v>; -+ status = "okay"; -+}; From 0b2bbc6708ef986e2f8d281f65e0c1ca3ff14562 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Wed, 27 Mar 2019 13:21:06 +0100 @@ -572,89 +472,3 @@ index a7ffee494488..f7c7d89da7f8 100644 -- 2.24.0 -From: Andre Heider -Subject: [PATCH] arm64: dts: allwinner: orange-pi-3: Enable IR receiver -Date: Sat, 9 Nov 2019 12:34:36 +0100 - -Orange Pi 3 has an on-board IR receiver, enable it. - -Signed-off-by: Andre Heider -Acked-by: Jernej Skrabec ---- - arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts -index eb379cd402ac..d3e30a67587c 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts -@@ -263,6 +263,10 @@ - }; - }; - -+&r_ir { -+ status = "okay"; -+}; -+ - &uart0 { - pinctrl-names = "default"; - pinctrl-0 = <&uart0_ph_pins>; - - -From: Andre Heider -Date: Tue, 19 Nov 2019 09:35:10 +0100 -Subject: [PATCH 2/2] WIP: Bluetooth: Accept - HCI_QUIRK_INVALID_BDADDR|HCI_QUIRK_USE_BDADDR_PROPERTY - -Don't bail out if the former is set (in case of bcm: default controller -address), but an address was supplied because of the latter. ---- - net/bluetooth/hci_core.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c -index 04bc79359a17..7bc384be89f8 100644 ---- a/net/bluetooth/hci_core.c -+++ b/net/bluetooth/hci_core.c -@@ -1470,7 +1470,8 @@ static int hci_dev_do_open(struct hci_dev *hdev) - * start up as unconfigured. - */ - if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || -- test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks)) -+ (test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks) && -+ !test_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks))) - hci_dev_set_flag(hdev, HCI_UNCONFIGURED); - - /* For an unconfigured controller it is required to --- -2.24.0 - - -From: Andre Heider -Date: Sun, 17 Nov 2019 20:31:17 +0100 -Subject: [PATCH 1/2] bluetooth: bcm: Use HCI_QUIRK_USE_BDADDR_PROPERTY - -Some devices ship with the controller default address, like the -Orange Pi 3 (BCM4345C5). - -Allow the bootloader to set a valid address through the device tree. - -Signed-off-by: Andre Heider ---- - drivers/bluetooth/btbcm.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c -index 2d2e6d862068..9d16162d01ea 100644 ---- a/drivers/bluetooth/btbcm.c -+++ b/drivers/bluetooth/btbcm.c -@@ -439,6 +439,7 @@ int btbcm_finalize(struct hci_dev *hdev) - btbcm_check_bdaddr(hdev); - - set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); -+ set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); - - return 0; - } --- -2.24.0 diff --git a/projects/Allwinner/devices/H6/patches/linux/10-beelink-gs1.patch b/projects/Allwinner/devices/H6/patches/linux/10-beelink-gs1.patch deleted file mode 100644 index 6820b2ade2..0000000000 --- a/projects/Allwinner/devices/H6/patches/linux/10-beelink-gs1.patch +++ /dev/null @@ -1,207 +0,0 @@ -From 37354fa373d0eba8adaeb594f7c0b78436e5dc1a Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= -Date: Sat, 10 Aug 2019 13:21:55 +0200 -Subject: [PATCH] arm64: allwinner: dts: h6: enable USB3 port on Beelink GS1 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Clément Péron ---- - arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts -index 0dc33c90dd60..ef595e6a0cd6 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts -@@ -57,6 +57,10 @@ - status = "okay"; - }; - -+&dwc3 { -+ status = "okay"; -+}; -+ - &ehci0 { - status = "okay"; - }; -@@ -258,3 +262,8 @@ - usb0_vbus-supply = <®_vcc5v>; - status = "okay"; - }; -+ -+&usb3phy { -+ vbus-supply = <®_vcc5v>; -+ status = "okay"; -+}; --- -2.20.1 -From b1cff682042c5aa6f5fc9204018fe7466503e2cf Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= -Date: Mon, 21 Oct 2019 23:09:10 +0200 -Subject: [PATCH 1/2] media: rc: add keymap for Beelink GS1 remote control -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Beelink GS1 Andoid TV Box ships with a simple NEC remote. - -Signed-off-by: Clément Péron ---- - drivers/media/rc/keymaps/Makefile | 1 + - drivers/media/rc/keymaps/rc-beelink-gs1.c | 84 +++++++++++++++++++ - include/media/rc-map.h | 1 + - 4 files changed, 87 insertions(+) - create mode 100644 drivers/media/rc/keymaps/rc-beelink-gs1.c - -diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile -index 4ab4af062abf..63261ef6380a 100644 ---- a/drivers/media/rc/keymaps/Makefile -+++ b/drivers/media/rc/keymaps/Makefile -@@ -17,6 +17,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-avermedia-rm-ks.o \ - rc-avertv-303.o \ - rc-azurewave-ad-tu700.o \ -+ rc-beelink-gs1.o \ - rc-behold.o \ - rc-behold-columbus.o \ - rc-budget-ci-old.o \ -diff --git a/drivers/media/rc/keymaps/rc-beelink-gs1.c b/drivers/media/rc/keymaps/rc-beelink-gs1.c -new file mode 100644 -index 000000000000..cedbd5d20bc7 ---- /dev/null -+++ b/drivers/media/rc/keymaps/rc-beelink-gs1.c -@@ -0,0 +1,84 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+// Copyright (c) 2019 Clément Péron -+ -+#include -+#include -+ -+/* -+ * Keymap for the Beelink GS1 remote control -+ */ -+ -+static struct rc_map_table beelink_gs1_table[] = { -+ /* -+ * TV Keys (Power, Learn and Volume) -+ * { 0x40400d, KEY_TV }, -+ * { 0x80f1, KEY_TV }, -+ * { 0x80f3, KEY_TV }, -+ * { 0x80f4, KEY_TV }, -+ */ -+ -+ { 0x8051, KEY_POWER }, -+ { 0x804d, KEY_MUTE }, -+ { 0x8040, KEY_CONFIG }, -+ -+ { 0x8026, KEY_UP }, -+ { 0x8028, KEY_DOWN }, -+ { 0x8025, KEY_LEFT }, -+ { 0x8027, KEY_RIGHT }, -+ { 0x800d, KEY_OK }, -+ -+ { 0x8053, KEY_HOME }, -+ { 0x80bc, KEY_MEDIA }, -+ { 0x801b, KEY_BACK }, -+ { 0x8049, KEY_MENU }, -+ -+ { 0x804e, KEY_VOLUMEUP }, -+ { 0x8056, KEY_VOLUMEDOWN }, -+ -+ { 0x8054, KEY_SUBTITLE }, /* Web */ -+ { 0x8052, KEY_EPG }, /* Media */ -+ -+ { 0x8041, KEY_CHANNELUP }, -+ { 0x8042, KEY_CHANNELDOWN }, -+ -+ { 0x8031, KEY_1 }, -+ { 0x8032, KEY_2 }, -+ { 0x8033, KEY_3 }, -+ -+ { 0x8034, KEY_4 }, -+ { 0x8035, KEY_5 }, -+ { 0x8036, KEY_6 }, -+ -+ { 0x8037, KEY_7 }, -+ { 0x8038, KEY_8 }, -+ { 0x8039, KEY_9 }, -+ -+ { 0x8044, KEY_DELETE }, -+ { 0x8030, KEY_0 }, -+ { 0x8058, KEY_MODE }, /* # Input Method */ -+}; -+ -+static struct rc_map_list beelink_gs1_map = { -+ .map = { -+ .scan = beelink_gs1_table, -+ .size = ARRAY_SIZE(beelink_gs1_table), -+ .rc_proto = RC_PROTO_NEC, -+ .name = RC_MAP_BEELINK_GS1, -+ } -+}; -+ -+static int __init init_rc_map_beelink_gs1(void) -+{ -+ return rc_map_register(&beelink_gs1_map); -+} -+ -+static void __exit exit_rc_map_beelink_gs1(void) -+{ -+ rc_map_unregister(&beelink_gs1_map); -+} -+ -+module_init(init_rc_map_beelink_gs1) -+module_exit(exit_rc_map_beelink_gs1) -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Clément Péron "); -diff --git a/include/media/rc-map.h b/include/media/rc-map.h -index 0a8669daeaaa..f99575a0d29c 100644 ---- a/include/media/rc-map.h -+++ b/include/media/rc-map.h -@@ -168,6 +168,7 @@ struct rc_map *rc_map_get(const char *name); - #define RC_MAP_AVERMEDIA_RM_KS "rc-avermedia-rm-ks" - #define RC_MAP_AVERTV_303 "rc-avertv-303" - #define RC_MAP_AZUREWAVE_AD_TU700 "rc-azurewave-ad-tu700" -+#define RC_MAP_BEELINK_GS1 "rc-beelink-gs1" - #define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" - #define RC_MAP_BEHOLD "rc-behold" - #define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old" --- -2.20.1 - -From 4dd806bd04e98e3800b3c4ab3f9d0d42155451b6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= -Date: Fri, 25 Oct 2019 15:04:20 +0200 -Subject: [PATCH 2/2] arm64: dts: allwinner: beelink-gs1: Add rc-beelink-gs1 - keymap -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Beelink GS1 ships with a NEC remote control. - -Add the rc keymap to the device-tree. - -Signed-off-by: Clément Péron ---- - arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts -index 1d05d570142f..ce4b0679839d 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts -@@ -252,6 +252,7 @@ - }; - - &r_ir { -+ linux,rc-map-name = "rc-beelink-gs1"; - status = "okay"; - }; - --- -2.20.1 - diff --git a/projects/Allwinner/devices/H6/patches/linux/11-pwm.patch b/projects/Allwinner/devices/H6/patches/linux/11-pwm.patch deleted file mode 100644 index cc156dca07..0000000000 --- a/projects/Allwinner/devices/H6/patches/linux/11-pwm.patch +++ /dev/null @@ -1,344 +0,0 @@ -From 0e014d5d469b49173f89897c898ee4d350f2b183 Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Fri, 26 Jul 2019 17:31:20 +0200 -Subject: [PATCH 1/5] pwm: sun4i: Add a quirk for reset line - -H6 PWM core needs deasserted reset line in order to work. - -Add a quirk for it. - -Signed-off-by: Jernej Skrabec ---- - drivers/pwm/pwm-sun4i.c | 27 +++++++++++++++++++++++++-- - 1 file changed, 25 insertions(+), 2 deletions(-) - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index de78c824bbfd..1b7be8fbde86 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -16,6 +16,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -72,12 +73,14 @@ static const u32 prescaler_table[] = { - - struct sun4i_pwm_data { - bool has_prescaler_bypass; -+ bool has_reset; - unsigned int npwm; - }; - - struct sun4i_pwm_chip { - struct pwm_chip chip; - struct clk *clk; -+ struct reset_control *rst; - void __iomem *base; - spinlock_t ctrl_lock; - const struct sun4i_pwm_data *data; -@@ -371,6 +374,14 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - if (IS_ERR(pwm->clk)) - return PTR_ERR(pwm->clk); - -+ if (pwm->data->has_reset) { -+ pwm->rst = devm_reset_control_get(&pdev->dev, NULL); -+ if (IS_ERR(pwm->rst)) -+ return PTR_ERR(pwm->rst); -+ -+ reset_control_deassert(pwm->rst); -+ } -+ - pwm->chip.dev = &pdev->dev; - pwm->chip.ops = &sun4i_pwm_ops; - pwm->chip.base = -1; -@@ -383,19 +394,31 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - ret = pwmchip_add(&pwm->chip); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); -- return ret; -+ goto err_pwm_add; - } - - platform_set_drvdata(pdev, pwm); - - return 0; -+ -+err_pwm_add: -+ reset_control_assert(pwm->rst); -+ -+ return ret; - } - - static int sun4i_pwm_remove(struct platform_device *pdev) - { - struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev); -+ int ret; -+ -+ ret = pwmchip_remove(&pwm->chip); -+ if (ret) -+ return ret; - -- return pwmchip_remove(&pwm->chip); -+ reset_control_assert(pwm->rst); -+ -+ return 0; - } - - static struct platform_driver sun4i_pwm_driver = { --- -2.22.1 - - -From 56755aaa0610275f5348ac840c76b4e2b8572281 Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Fri, 26 Jul 2019 17:42:06 +0200 -Subject: [PATCH 2/5] pwm: sun4i: Add a quirk for bus clock - -H6 PWM core needs bus clock to be enabled in order to work. - -Add a quirk for it. - -Signed-off-by: Jernej Skrabec ---- - drivers/pwm/pwm-sun4i.c | 15 +++++++++++++++ - 1 file changed, 15 insertions(+) - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index 1b7be8fbde86..7d3ac3f2dc3f 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -72,6 +72,7 @@ static const u32 prescaler_table[] = { - }; - - struct sun4i_pwm_data { -+ bool has_bus_clock; - bool has_prescaler_bypass; - bool has_reset; - unsigned int npwm; -@@ -79,6 +80,7 @@ struct sun4i_pwm_data { - - struct sun4i_pwm_chip { - struct pwm_chip chip; -+ struct clk *bus_clk; - struct clk *clk; - struct reset_control *rst; - void __iomem *base; -@@ -382,6 +384,16 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - reset_control_deassert(pwm->rst); - } - -+ if (pwm->data->has_bus_clock) { -+ pwm->bus_clk = devm_clk_get(&pdev->dev, "bus"); -+ if (IS_ERR(pwm->bus_clk)) { -+ ret = PTR_ERR(pwm->bus_clk); -+ goto err_bus; -+ } -+ -+ clk_prepare_enable(pwm->bus_clk); -+ } -+ - pwm->chip.dev = &pdev->dev; - pwm->chip.ops = &sun4i_pwm_ops; - pwm->chip.base = -1; -@@ -402,6 +414,8 @@ static int sun4i_pwm_probe(struct platform_device *pdev) - return 0; - - err_pwm_add: -+ clk_disable_unprepare(pwm->bus_clk); -+err_bus: - reset_control_assert(pwm->rst); - - return ret; -@@ -416,6 +430,7 @@ static int sun4i_pwm_remove(struct platform_device *pdev) - if (ret) - return ret; - -+ clk_disable_unprepare(pwm->bus_clk); - reset_control_assert(pwm->rst); - - return 0; --- -2.22.1 - - -From 68c1b688e1e57ce22dfc6a72ad2b6f403953823a Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Fri, 26 Jul 2019 17:45:40 +0200 -Subject: [PATCH 3/5] pwm: sun4i: Add support for H6 PWM - -Now that sun4i PWM driver supports deasserting reset line and enabling -bus clock, support for H6 PWM can be added. - -Note that while H6 PWM has two channels, only first one is wired to -output pin. Second channel is used as a clock source to companion AC200 -chip which is bundled into same package. - -Signed-off-by: Jernej Skrabec ---- - drivers/pwm/pwm-sun4i.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index 7d3ac3f2dc3f..9e0eca79ff88 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -331,6 +331,13 @@ static const struct sun4i_pwm_data sun4i_pwm_single_bypass = { - .npwm = 1, - }; - -+static const struct sun4i_pwm_data sun50i_pwm_dual_bypass_clk_rst = { -+ .has_bus_clock = true, -+ .has_prescaler_bypass = true, -+ .has_reset = true, -+ .npwm = 2, -+}; -+ - static const struct of_device_id sun4i_pwm_dt_ids[] = { - { - .compatible = "allwinner,sun4i-a10-pwm", -@@ -347,6 +354,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = { - }, { - .compatible = "allwinner,sun8i-h3-pwm", - .data = &sun4i_pwm_single_bypass, -+ }, { -+ .compatible = "allwinner,sun50i-h6-pwm", -+ .data = &sun50i_pwm_dual_bypass_clk_rst, - }, { - /* sentinel */ - }, --- -2.22.1 - - -From b78fc7d807a6d4b715cad9b87c134a3cb6289f62 Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Fri, 26 Jul 2019 17:53:36 +0200 -Subject: [PATCH 4/5] pwm: sun4i: Add support to output source clock directly - -PWM core has an option to bypass whole logic and output unchanged source -clock as PWM output. This is achieved by enabling bypass bit. - -Note that when bypass is enabled, no other setting has any meaning, not -even enable bit. - -This mode of operation is needed to achieve high enough frequency to -serve as clock source for AC200 chip, which is integrated into same -package as H6 SoC. - -Signed-off-by: Jernej Skrabec ---- - drivers/pwm/pwm-sun4i.c | 31 ++++++++++++++++++++++++++++++- - 1 file changed, 30 insertions(+), 1 deletion(-) - -diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c -index 9e0eca79ff88..848cff26f385 100644 ---- a/drivers/pwm/pwm-sun4i.c -+++ b/drivers/pwm/pwm-sun4i.c -@@ -120,6 +120,19 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, - - val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); - -+ /* -+ * PWM chapter in H6 manual has a diagram which explains that if bypass -+ * bit is set, no other setting has any meaning. Even more, experiment -+ * proved that also enable bit is ignored in this case. -+ */ -+ if (val & BIT_CH(PWM_BYPASS, pwm->hwpwm)) { -+ state->period = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, clk_rate); -+ state->duty_cycle = state->period / 2; -+ state->polarity = PWM_POLARITY_NORMAL; -+ state->enabled = true; -+ return; -+ } -+ - if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) && - sun4i_pwm->data->has_prescaler_bypass) - prescaler = 1; -@@ -211,7 +224,8 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - { - struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip); - struct pwm_state cstate; -- u32 ctrl; -+ u32 ctrl, clk_rate; -+ bool bypass; - int ret; - unsigned int delay_us; - unsigned long now; -@@ -226,6 +240,16 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - } - } - -+ /* -+ * Although it would make much more sense to check for bypass in -+ * sun4i_pwm_calculate(), value of bypass bit also depends on "enabled". -+ * Period is allowed to be rounded up or down. -+ */ -+ clk_rate = clk_get_rate(sun4i_pwm->clk); -+ bypass = (state->period == NSEC_PER_SEC / clk_rate || -+ state->period == DIV_ROUND_UP(NSEC_PER_SEC, clk_rate)) && -+ state->enabled; -+ - spin_lock(&sun4i_pwm->ctrl_lock); - ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); - -@@ -273,6 +297,11 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); - } - -+ if (bypass) -+ ctrl |= BIT_CH(PWM_BYPASS, pwm->hwpwm); -+ else -+ ctrl &= ~BIT_CH(PWM_BYPASS, pwm->hwpwm); -+ - sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); - - spin_unlock(&sun4i_pwm->ctrl_lock); --- -2.22.1 - - -From e5fa4d2acf30ccac7f3817c299a2fa6f20c23c50 Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Fri, 26 Jul 2019 18:02:50 +0200 -Subject: [PATCH 5/5] arm64: dts: allwinner: h6: Add PWM node - -Allwinner H6 PWM is similar to that in A20 except that it has additional -bus clock and reset line. - -Note that first PWM channel is connected to output pin and second -channel is used internally, as a clock source to AC200 co-packaged chip. -This means that any combination of these two channels can be used and -thus it doesn't make sense to add pinctrl nodes at this point. - -Signed-off-by: Jernej Skrabec ---- - arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -index e8bed58e7246..c1abd805cfdc 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -@@ -229,6 +229,16 @@ - status = "disabled"; - }; - -+ pwm: pwm@300a000 { -+ compatible = "allwinner,sun50i-h6-pwm"; -+ reg = <0x0300a000 0x400>; -+ clocks = <&osc24M>, <&ccu CLK_BUS_PWM>; -+ clock-names = "pwm", "bus"; -+ resets = <&ccu RST_BUS_PWM>; -+ #pwm-cells = <3>; -+ status = "disabled"; -+ }; -+ - pio: pinctrl@300b000 { - compatible = "allwinner,sun50i-h6-pinctrl"; - reg = <0x0300b000 0x400>; --- -2.22.1 - diff --git a/projects/Allwinner/devices/H6/patches/linux/13-Tanix-TX6.patch b/projects/Allwinner/devices/H6/patches/linux/13-Tanix-TX6.patch index 3c27a7a336..da724d2bf7 100644 --- a/projects/Allwinner/devices/H6/patches/linux/13-Tanix-TX6.patch +++ b/projects/Allwinner/devices/H6/patches/linux/13-Tanix-TX6.patch @@ -21,7 +21,7 @@ index 7e7cb10e3d96..3de430b631f2 100644 serial0 = &uart0; }; -@@ -41,10 +42,26 @@ +@@ -41,14 +42,26 @@ }; }; @@ -33,10 +33,10 @@ index 7e7cb10e3d96..3de430b631f2 100644 status = "okay"; }; -+&dwc3 { -+ status = "okay"; -+}; -+ + &dwc3 { + status = "okay"; + }; + +&emac { + pinctrl-names = "default"; + pinctrl-0 = <&ext_rmii_pins>; @@ -92,14 +92,6 @@ index 7e7cb10e3d96..3de430b631f2 100644 &r_ir { status = "okay"; }; -@@ -98,3 +138,7 @@ - &usb2phy { - status = "okay"; - }; -+ -+&usb3phy { -+ status = "okay"; -+}; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi index 67b732e34091..e436fc78ac71 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi @@ -120,32 +112,3 @@ index 67b732e34091..e436fc78ac71 100644 function = "hdmi"; -- 2.23.0 - -From d73a0d0c3465fa34008cf8fba6ef9da7fb46a0ef Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Wed, 23 Oct 2019 19:58:34 +0200 -Subject: [PATCH] arm64: dts: allwinner: h6: tanix-tx6: Add IR remote mapping - -Tanix TX6 box comes with a remote. Add a mapping for it. - -Suggested-by: Michael Lange -Signed-off-by: Jernej Skrabec ---- - arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts -index bccfe1e65b6a..898eee82888c 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts -@@ -85,6 +85,7 @@ &ohci3 { - }; - - &r_ir { -+ linux,rc-map-name = "rc-tanix-tx5max"; - status = "okay"; - }; - --- -2.24.0 - diff --git a/projects/Allwinner/patches/linux/0001-backport-from-5.5.patch b/projects/Allwinner/patches/linux/0001-backport-from-5.5.patch index 62289ffabd..01adcffecd 100644 --- a/projects/Allwinner/patches/linux/0001-backport-from-5.5.patch +++ b/projects/Allwinner/patches/linux/0001-backport-from-5.5.patch @@ -4921,3 +4921,670 @@ index 7e7cb10e3d96..bccfe1e65b6a 100644 &hdmi { status = "okay"; }; +From a228890f94586c2f8417831c228ac8ed955ef856 Mon Sep 17 00:00:00 2001 +From: Icenowy Zheng +Date: Tue, 29 Oct 2019 21:17:39 +0100 +Subject: [PATCH] phy: allwinner: add phy driver for USB3 PHY on Allwinner H6 + SoC + +Allwinner H6 SoC contains a USB3 PHY (with USB2 DP/DM lines also +controlled). + +Add a driver for it. + +The register operations in this driver is mainly extracted from the BSP +USB3 driver. + +Signed-off-by: Ondrej Jirman +Signed-off-by: Icenowy Zheng +Reviewed-by: Chen-Yu Tsai +Acked-by: Maxime Ripard +Signed-off-by: Kishon Vijay Abraham I +--- + drivers/phy/allwinner/Kconfig | 11 ++ + drivers/phy/allwinner/Makefile | 1 + + drivers/phy/allwinner/phy-sun50i-usb3.c | 190 ++++++++++++++++++++++++ + 3 files changed, 202 insertions(+) + create mode 100644 drivers/phy/allwinner/phy-sun50i-usb3.c + +diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig +index 215425296c77..3dab79e9d52b 100644 +--- a/drivers/phy/allwinner/Kconfig ++++ b/drivers/phy/allwinner/Kconfig +@@ -45,3 +45,14 @@ config PHY_SUN9I_USB + sun9i SoCs. + + This driver controls each individual USB 2 host PHY. ++ ++config PHY_SUN50I_USB3 ++ tristate "Allwinner H6 SoC USB3 PHY driver" ++ depends on ARCH_SUNXI && HAS_IOMEM && OF ++ depends on RESET_CONTROLLER ++ select GENERIC_PHY ++ help ++ Enable this to support the USB3.0-capable transceiver that is ++ part of Allwinner H6 SoC. ++ ++ This driver controls each individual USB 2+3 host PHY combo. +diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile +index 799a65c0b58d..bd74901a1255 100644 +--- a/drivers/phy/allwinner/Makefile ++++ b/drivers/phy/allwinner/Makefile +@@ -2,3 +2,4 @@ + obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o + obj-$(CONFIG_PHY_SUN6I_MIPI_DPHY) += phy-sun6i-mipi-dphy.o + obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o ++obj-$(CONFIG_PHY_SUN50I_USB3) += phy-sun50i-usb3.o +diff --git a/drivers/phy/allwinner/phy-sun50i-usb3.c b/drivers/phy/allwinner/phy-sun50i-usb3.c +new file mode 100644 +index 000000000000..1169f3e83a6f +--- /dev/null ++++ b/drivers/phy/allwinner/phy-sun50i-usb3.c +@@ -0,0 +1,190 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Allwinner sun50i(H6) USB 3.0 phy driver ++ * ++ * Copyright (C) 2017 Icenowy Zheng ++ * ++ * Based on phy-sun9i-usb.c, which is: ++ * ++ * Copyright (C) 2014-2015 Chen-Yu Tsai ++ * ++ * Based on code from Allwinner BSP, which is: ++ * ++ * Copyright (c) 2010-2015 Allwinner Technology Co., Ltd. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Interface Status and Control Registers */ ++#define SUNXI_ISCR 0x00 ++#define SUNXI_PIPE_CLOCK_CONTROL 0x14 ++#define SUNXI_PHY_TUNE_LOW 0x18 ++#define SUNXI_PHY_TUNE_HIGH 0x1c ++#define SUNXI_PHY_EXTERNAL_CONTROL 0x20 ++ ++/* USB2.0 Interface Status and Control Register */ ++#define SUNXI_ISCR_FORCE_VBUS (3 << 12) ++ ++/* PIPE Clock Control Register */ ++#define SUNXI_PCC_PIPE_CLK_OPEN (1 << 6) ++ ++/* PHY External Control Register */ ++#define SUNXI_PEC_EXTERN_VBUS (3 << 1) ++#define SUNXI_PEC_SSC_EN (1 << 24) ++#define SUNXI_PEC_REF_SSP_EN (1 << 26) ++ ++/* PHY Tune High Register */ ++#define SUNXI_TX_DEEMPH_3P5DB(n) ((n) << 19) ++#define SUNXI_TX_DEEMPH_3P5DB_MASK GENMASK(24, 19) ++#define SUNXI_TX_DEEMPH_6DB(n) ((n) << 13) ++#define SUNXI_TX_DEEMPH_6GB_MASK GENMASK(18, 13) ++#define SUNXI_TX_SWING_FULL(n) ((n) << 6) ++#define SUNXI_TX_SWING_FULL_MASK GENMASK(12, 6) ++#define SUNXI_LOS_BIAS(n) ((n) << 3) ++#define SUNXI_LOS_BIAS_MASK GENMASK(5, 3) ++#define SUNXI_TXVBOOSTLVL(n) ((n) << 0) ++#define SUNXI_TXVBOOSTLVL_MASK GENMASK(0, 2) ++ ++struct sun50i_usb3_phy { ++ struct phy *phy; ++ void __iomem *regs; ++ struct reset_control *reset; ++ struct clk *clk; ++}; ++ ++static void sun50i_usb3_phy_open(struct sun50i_usb3_phy *phy) ++{ ++ u32 val; ++ ++ val = readl(phy->regs + SUNXI_PHY_EXTERNAL_CONTROL); ++ val |= SUNXI_PEC_EXTERN_VBUS; ++ val |= SUNXI_PEC_SSC_EN | SUNXI_PEC_REF_SSP_EN; ++ writel(val, phy->regs + SUNXI_PHY_EXTERNAL_CONTROL); ++ ++ val = readl(phy->regs + SUNXI_PIPE_CLOCK_CONTROL); ++ val |= SUNXI_PCC_PIPE_CLK_OPEN; ++ writel(val, phy->regs + SUNXI_PIPE_CLOCK_CONTROL); ++ ++ val = readl(phy->regs + SUNXI_ISCR); ++ val |= SUNXI_ISCR_FORCE_VBUS; ++ writel(val, phy->regs + SUNXI_ISCR); ++ ++ /* ++ * All the magic numbers written to the PHY_TUNE_{LOW_HIGH} ++ * registers are directly taken from the BSP USB3 driver from ++ * Allwiner. ++ */ ++ writel(0x0047fc87, phy->regs + SUNXI_PHY_TUNE_LOW); ++ ++ val = readl(phy->regs + SUNXI_PHY_TUNE_HIGH); ++ val &= ~(SUNXI_TXVBOOSTLVL_MASK | SUNXI_LOS_BIAS_MASK | ++ SUNXI_TX_SWING_FULL_MASK | SUNXI_TX_DEEMPH_6GB_MASK | ++ SUNXI_TX_DEEMPH_3P5DB_MASK); ++ val |= SUNXI_TXVBOOSTLVL(0x7); ++ val |= SUNXI_LOS_BIAS(0x7); ++ val |= SUNXI_TX_SWING_FULL(0x55); ++ val |= SUNXI_TX_DEEMPH_6DB(0x20); ++ val |= SUNXI_TX_DEEMPH_3P5DB(0x15); ++ writel(val, phy->regs + SUNXI_PHY_TUNE_HIGH); ++} ++ ++static int sun50i_usb3_phy_init(struct phy *_phy) ++{ ++ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy); ++ int ret; ++ ++ ret = clk_prepare_enable(phy->clk); ++ if (ret) ++ return ret; ++ ++ ret = reset_control_deassert(phy->reset); ++ if (ret) { ++ clk_disable_unprepare(phy->clk); ++ return ret; ++ } ++ ++ sun50i_usb3_phy_open(phy); ++ return 0; ++} ++ ++static int sun50i_usb3_phy_exit(struct phy *_phy) ++{ ++ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy); ++ ++ reset_control_assert(phy->reset); ++ clk_disable_unprepare(phy->clk); ++ ++ return 0; ++} ++ ++static const struct phy_ops sun50i_usb3_phy_ops = { ++ .init = sun50i_usb3_phy_init, ++ .exit = sun50i_usb3_phy_exit, ++ .owner = THIS_MODULE, ++}; ++ ++static int sun50i_usb3_phy_probe(struct platform_device *pdev) ++{ ++ struct sun50i_usb3_phy *phy; ++ struct device *dev = &pdev->dev; ++ struct phy_provider *phy_provider; ++ struct resource *res; ++ ++ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); ++ if (!phy) ++ return -ENOMEM; ++ ++ phy->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(phy->clk)) { ++ if (PTR_ERR(phy->clk) != -EPROBE_DEFER) ++ dev_err(dev, "failed to get phy clock\n"); ++ return PTR_ERR(phy->clk); ++ } ++ ++ phy->reset = devm_reset_control_get(dev, NULL); ++ if (IS_ERR(phy->reset)) { ++ dev_err(dev, "failed to get reset control\n"); ++ return PTR_ERR(phy->reset); ++ } ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ phy->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(phy->regs)) ++ return PTR_ERR(phy->regs); ++ ++ phy->phy = devm_phy_create(dev, NULL, &sun50i_usb3_phy_ops); ++ if (IS_ERR(phy->phy)) { ++ dev_err(dev, "failed to create PHY\n"); ++ return PTR_ERR(phy->phy); ++ } ++ ++ phy_set_drvdata(phy->phy, phy); ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++} ++ ++static const struct of_device_id sun50i_usb3_phy_of_match[] = { ++ { .compatible = "allwinner,sun50i-h6-usb3-phy" }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, sun50i_usb3_phy_of_match); ++ ++static struct platform_driver sun50i_usb3_phy_driver = { ++ .probe = sun50i_usb3_phy_probe, ++ .driver = { ++ .of_match_table = sun50i_usb3_phy_of_match, ++ .name = "sun50i-usb3-phy", ++ } ++}; ++module_platform_driver(sun50i_usb3_phy_driver); ++ ++MODULE_DESCRIPTION("Allwinner H6 USB 3.0 phy driver"); ++MODULE_AUTHOR("Icenowy Zheng "); ++MODULE_LICENSE("GPL"); +-- +2.24.1 + +From 0b6f7014adc1cc12c7c3ba988594514602919eca Mon Sep 17 00:00:00 2001 +From: Icenowy Zheng +Date: Sun, 20 Oct 2019 15:42:28 +0200 +Subject: [PATCH] arm64: dts: allwinner: h6: add USB3 device nodes + +Allwinner H6 SoC features USB3 functionality, with a DWC3 controller and +a custom PHY. + +Add device tree nodes for them. + +Signed-off-by: Ondrej Jirman +Signed-off-by: Icenowy Zheng +Reviewed-by: Chen-Yu Tsai +Signed-off-by: Maxime Ripard +--- + arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 32 ++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +index 4abfed2e9ff6..8f3f81725fb7 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -570,6 +570,38 @@ ohci0: usb@5101400 { + status = "disabled"; + }; + ++ dwc3: dwc3@5200000 { ++ compatible = "snps,dwc3"; ++ reg = <0x05200000 0x10000>; ++ interrupts = ; ++ clocks = <&ccu CLK_BUS_XHCI>, ++ <&ccu CLK_BUS_XHCI>, ++ <&rtc 0>; ++ clock-names = "ref", "bus_early", "suspend"; ++ resets = <&ccu RST_BUS_XHCI>; ++ /* ++ * The datasheet of the chip doesn't declare the ++ * peripheral function, and there's no boards known ++ * to have a USB Type-B port routed to the port. ++ * In addition, no one has tested the peripheral ++ * function yet. ++ * So set the dr_mode to "host" in the DTSI file. ++ */ ++ dr_mode = "host"; ++ phys = <&usb3phy>; ++ phy-names = "usb3-phy"; ++ status = "disabled"; ++ }; ++ ++ usb3phy: phy@5210000 { ++ compatible = "allwinner,sun50i-h6-usb3-phy"; ++ reg = <0x5210000 0x10000>; ++ clocks = <&ccu CLK_USB_PHY1>; ++ resets = <&ccu RST_USB_PHY1>; ++ #phy-cells = <0>; ++ status = "disabled"; ++ }; ++ + ehci3: usb@5311000 { + compatible = "allwinner,sun50i-h6-ehci", "generic-ehci"; + reg = <0x05311000 0x100>; +-- +2.24.1 + +From b5d84ff8ae180e443623ede8a16852f671b0bb05 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Sun, 20 Oct 2019 15:42:29 +0200 +Subject: [PATCH] arm64: dts: allwinner: orange-pi-3: Enable USB 3.0 host + support + +Enable Allwinner's USB 3.0 phy and the host controller. Orange Pi 3 +board has GL3510 USB 3.0 4-port hub connected to the SoC's USB 3.0 +port. All four ports are exposed via USB3-A connectors. VBUS is +always on, since it's powered directly from DCIN (VCC-5V) and +not switchable. + +Signed-off-by: Ondrej Jirman +Signed-off-by: Maxime Ripard +--- + arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +index b99e9db35d50..4ed3fc2c7734 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +@@ -95,6 +95,10 @@ &de { + status = "okay"; + }; + ++&dwc3 { ++ status = "okay"; ++}; ++ + &ehci0 { + status = "okay"; + }; +@@ -310,3 +314,7 @@ &usb2phy { + usb3_vbus-supply = <®_vcc5v>; + status = "okay"; + }; ++ ++&usb3phy { ++ status = "okay"; ++}; +-- +2.24.1 + +From 6555431ba2c58ac3a2fccde2b92607437577cc8f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Sun, 27 Oct 2019 21:07:38 +0100 +Subject: [PATCH] media: arm64: dts: allwinner: beelink-gs1: Add rc-beelink-gs1 + keymap +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Beelink GS1 ships with a NEC remote control. + +Add the rc keymap to the device-tree. + +Signed-off-by: Clément Péron +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +--- + arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +index 1d05d570142f..ce4b0679839d 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +@@ -252,6 +252,7 @@ sw { + }; + + &r_ir { ++ linux,rc-map-name = "rc-beelink-gs1"; + status = "okay"; + }; + +-- +2.24.1 + +From d2f383d6b8cd85cbb0e8ebece4ef9408237eef68 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Fri, 11 Oct 2019 05:25:20 -0300 +Subject: [PATCH] media: rc-map: Sort rc map name MACROs + +Some MACROS such as RC_MAP_SU3000 and RC_MAP_HAUPPAUGE are not +alphabetically sorted. Sort names alphabetically. + +Signed-off-by: Jisheng Zhang +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +--- + include/media/rc-map.h | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index 04b5efc1fe39..0a8669daeaaa 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -159,21 +159,21 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_ASUS_PS3_100 "rc-asus-ps3-100" + #define RC_MAP_ATI_TV_WONDER_HD_600 "rc-ati-tv-wonder-hd-600" + #define RC_MAP_ATI_X10 "rc-ati-x10" ++#define RC_MAP_AVERMEDIA "rc-avermedia" + #define RC_MAP_AVERMEDIA_A16D "rc-avermedia-a16d" + #define RC_MAP_AVERMEDIA_CARDBUS "rc-avermedia-cardbus" + #define RC_MAP_AVERMEDIA_DVBT "rc-avermedia-dvbt" + #define RC_MAP_AVERMEDIA_M135A "rc-avermedia-m135a" + #define RC_MAP_AVERMEDIA_M733A_RM_K6 "rc-avermedia-m733a-rm-k6" + #define RC_MAP_AVERMEDIA_RM_KS "rc-avermedia-rm-ks" +-#define RC_MAP_AVERMEDIA "rc-avermedia" + #define RC_MAP_AVERTV_303 "rc-avertv-303" + #define RC_MAP_AZUREWAVE_AD_TU700 "rc-azurewave-ad-tu700" +-#define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" + #define RC_MAP_BEHOLD "rc-behold" ++#define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" + #define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old" + #define RC_MAP_CEC "rc-cec" +-#define RC_MAP_CINERGY_1400 "rc-cinergy-1400" + #define RC_MAP_CINERGY "rc-cinergy" ++#define RC_MAP_CINERGY_1400 "rc-cinergy-1400" + #define RC_MAP_D680_DMB "rc-d680-dmb" + #define RC_MAP_DELOCK_61959 "rc-delock-61959" + #define RC_MAP_DIB0700_NEC_TABLE "rc-dib0700-nec" +@@ -181,17 +181,17 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_DIGITALNOW_TINYTWIN "rc-digitalnow-tinytwin" + #define RC_MAP_DIGITTRADE "rc-digittrade" + #define RC_MAP_DM1105_NEC "rc-dm1105-nec" +-#define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" + #define RC_MAP_DNTV_LIVE_DVB_T "rc-dntv-live-dvb-t" ++#define RC_MAP_DNTV_LIVE_DVBT_PRO "rc-dntv-live-dvbt-pro" + #define RC_MAP_DTT200U "rc-dtt200u" + #define RC_MAP_DVBSKY "rc-dvbsky" + #define RC_MAP_DVICO_MCE "rc-dvico-mce" + #define RC_MAP_DVICO_PORTABLE "rc-dvico-portable" + #define RC_MAP_EMPTY "rc-empty" + #define RC_MAP_EM_TERRATEC "rc-em-terratec" ++#define RC_MAP_ENCORE_ENLTV "rc-encore-enltv" + #define RC_MAP_ENCORE_ENLTV2 "rc-encore-enltv2" + #define RC_MAP_ENCORE_ENLTV_FM53 "rc-encore-enltv-fm53" +-#define RC_MAP_ENCORE_ENLTV "rc-encore-enltv" + #define RC_MAP_EVGA_INDTUBE "rc-evga-indtube" + #define RC_MAP_EZTV "rc-eztv" + #define RC_MAP_FLYDVB "rc-flydvb" +@@ -201,6 +201,7 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_GEEKBOX "rc-geekbox" + #define RC_MAP_GENIUS_TVGO_A11MCE "rc-genius-tvgo-a11mce" + #define RC_MAP_GOTVIEW7135 "rc-gotview7135" ++#define RC_MAP_HAUPPAUGE "rc-hauppauge" + #define RC_MAP_HAUPPAUGE_NEW "rc-hauppauge" + #define RC_MAP_HISI_POPLAR "rc-hisi-poplar" + #define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo" +@@ -223,8 +224,8 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_MEDION_X10_OR2X "rc-medion-x10-or2x" + #define RC_MAP_MSI_DIGIVOX_II "rc-msi-digivox-ii" + #define RC_MAP_MSI_DIGIVOX_III "rc-msi-digivox-iii" +-#define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" + #define RC_MAP_MSI_TVANYWHERE "rc-msi-tvanywhere" ++#define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus" + #define RC_MAP_NEBULA "rc-nebula" + #define RC_MAP_NEC_TERRATEC_CINERGY_XS "rc-nec-terratec-cinergy-xs" + #define RC_MAP_NORWOOD "rc-norwood" +@@ -234,21 +235,21 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color" + #define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey" + #define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd" +-#define RC_MAP_PIXELVIEW_NEW "rc-pixelview-new" + #define RC_MAP_PIXELVIEW "rc-pixelview" +-#define RC_MAP_PIXELVIEW_002T "rc-pixelview-002t" ++#define RC_MAP_PIXELVIEW_002T "rc-pixelview-002t" + #define RC_MAP_PIXELVIEW_MK12 "rc-pixelview-mk12" ++#define RC_MAP_PIXELVIEW_NEW "rc-pixelview-new" + #define RC_MAP_POWERCOLOR_REAL_ANGEL "rc-powercolor-real-angel" + #define RC_MAP_PROTEUS_2309 "rc-proteus-2309" + #define RC_MAP_PURPLETV "rc-purpletv" + #define RC_MAP_PV951 "rc-pv951" +-#define RC_MAP_HAUPPAUGE "rc-hauppauge" + #define RC_MAP_RC5_TV "rc-rc5-tv" + #define RC_MAP_RC6_MCE "rc-rc6-mce" + #define RC_MAP_REAL_AUDIO_220_32_KEYS "rc-real-audio-220-32-keys" + #define RC_MAP_REDDO "rc-reddo" + #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" + #define RC_MAP_STREAMZAP "rc-streamzap" ++#define RC_MAP_SU3000 "rc-su3000" + #define RC_MAP_TANGO "rc-tango" + #define RC_MAP_TANIX_TX3MINI "rc-tanix-tx3mini" + #define RC_MAP_TANIX_TX5MAX "rc-tanix-tx5max" +@@ -276,9 +277,8 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_WETEK_PLAY2 "rc-wetek-play2" + #define RC_MAP_WINFAST "rc-winfast" + #define RC_MAP_WINFAST_USBII_DELUXE "rc-winfast-usbii-deluxe" +-#define RC_MAP_SU3000 "rc-su3000" +-#define RC_MAP_XBOX_DVD "rc-xbox-dvd" + #define RC_MAP_X96MAX "rc-x96max" ++#define RC_MAP_XBOX_DVD "rc-xbox-dvd" + #define RC_MAP_ZX_IRDEC "rc-zx-irdec" + + /* +-- +2.24.1 + +From 4f0fac3b1aa5f356e0625f7d767ec71e1c198a73 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Sun, 27 Oct 2019 21:07:37 +0100 +Subject: [PATCH] media: rc: add keymap for Beelink GS1 remote control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Beelink GS1 Andoid TV Box ships with a simple NEC remote. + +Signed-off-by: Clément Péron +Signed-off-by: Sean Young +Signed-off-by: Mauro Carvalho Chehab +--- + .../devicetree/bindings/media/rc.yaml | 1 + + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-beelink-gs1.c | 84 +++++++++++++++++++ + include/media/rc-map.h | 1 + + 4 files changed, 87 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-beelink-gs1.c + +diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml +index 3d5c154fd230..ceb283f7888a 100644 +--- a/Documentation/devicetree/bindings/media/rc.yaml ++++ b/Documentation/devicetree/bindings/media/rc.yaml +@@ -39,6 +39,7 @@ properties: + - rc-avermedia-rm-ks + - rc-avertv-303 + - rc-azurewave-ad-tu700 ++ - rc-beelink-gs1 + - rc-behold + - rc-behold-columbus + - rc-budget-ci-old +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index 4ab4af062abf..63261ef6380a 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -17,6 +17,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-avermedia-rm-ks.o \ + rc-avertv-303.o \ + rc-azurewave-ad-tu700.o \ ++ rc-beelink-gs1.o \ + rc-behold.o \ + rc-behold-columbus.o \ + rc-budget-ci-old.o \ +diff --git a/drivers/media/rc/keymaps/rc-beelink-gs1.c b/drivers/media/rc/keymaps/rc-beelink-gs1.c +new file mode 100644 +index 000000000000..cedbd5d20bc7 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-beelink-gs1.c +@@ -0,0 +1,84 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2019 Clément Péron ++ ++#include ++#include ++ ++/* ++ * Keymap for the Beelink GS1 remote control ++ */ ++ ++static struct rc_map_table beelink_gs1_table[] = { ++ /* ++ * TV Keys (Power, Learn and Volume) ++ * { 0x40400d, KEY_TV }, ++ * { 0x80f1, KEY_TV }, ++ * { 0x80f3, KEY_TV }, ++ * { 0x80f4, KEY_TV }, ++ */ ++ ++ { 0x8051, KEY_POWER }, ++ { 0x804d, KEY_MUTE }, ++ { 0x8040, KEY_CONFIG }, ++ ++ { 0x8026, KEY_UP }, ++ { 0x8028, KEY_DOWN }, ++ { 0x8025, KEY_LEFT }, ++ { 0x8027, KEY_RIGHT }, ++ { 0x800d, KEY_OK }, ++ ++ { 0x8053, KEY_HOME }, ++ { 0x80bc, KEY_MEDIA }, ++ { 0x801b, KEY_BACK }, ++ { 0x8049, KEY_MENU }, ++ ++ { 0x804e, KEY_VOLUMEUP }, ++ { 0x8056, KEY_VOLUMEDOWN }, ++ ++ { 0x8054, KEY_SUBTITLE }, /* Web */ ++ { 0x8052, KEY_EPG }, /* Media */ ++ ++ { 0x8041, KEY_CHANNELUP }, ++ { 0x8042, KEY_CHANNELDOWN }, ++ ++ { 0x8031, KEY_1 }, ++ { 0x8032, KEY_2 }, ++ { 0x8033, KEY_3 }, ++ ++ { 0x8034, KEY_4 }, ++ { 0x8035, KEY_5 }, ++ { 0x8036, KEY_6 }, ++ ++ { 0x8037, KEY_7 }, ++ { 0x8038, KEY_8 }, ++ { 0x8039, KEY_9 }, ++ ++ { 0x8044, KEY_DELETE }, ++ { 0x8030, KEY_0 }, ++ { 0x8058, KEY_MODE }, /* # Input Method */ ++}; ++ ++static struct rc_map_list beelink_gs1_map = { ++ .map = { ++ .scan = beelink_gs1_table, ++ .size = ARRAY_SIZE(beelink_gs1_table), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_BEELINK_GS1, ++ } ++}; ++ ++static int __init init_rc_map_beelink_gs1(void) ++{ ++ return rc_map_register(&beelink_gs1_map); ++} ++ ++static void __exit exit_rc_map_beelink_gs1(void) ++{ ++ rc_map_unregister(&beelink_gs1_map); ++} ++ ++module_init(init_rc_map_beelink_gs1) ++module_exit(exit_rc_map_beelink_gs1) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Clément Péron "); +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index 0a8669daeaaa..f99575a0d29c 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -168,6 +168,7 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_AVERMEDIA_RM_KS "rc-avermedia-rm-ks" + #define RC_MAP_AVERTV_303 "rc-avertv-303" + #define RC_MAP_AZUREWAVE_AD_TU700 "rc-azurewave-ad-tu700" ++#define RC_MAP_BEELINK_GS1 "rc-beelink-gs1" + #define RC_MAP_BEHOLD "rc-behold" + #define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus" + #define RC_MAP_BUDGET_CI_OLD "rc-budget-ci-old" +-- +2.24.1 + diff --git a/projects/Allwinner/patches/linux/0002-backport-from-5.6.patch b/projects/Allwinner/patches/linux/0002-backport-from-5.6.patch new file mode 100644 index 0000000000..67ce770326 --- /dev/null +++ b/projects/Allwinner/patches/linux/0002-backport-from-5.6.patch @@ -0,0 +1,2220 @@ +From 2c63afdafa5100397308036a9dfbde24db5aecd5 Mon Sep 17 00:00:00 2001 +From: Andre Heider +Date: Sat, 9 Nov 2019 12:34:36 +0100 +Subject: [PATCH] arm64: dts: allwinner: orange-pi-3: Enable IR receiver + +Orange Pi 3 has an on-board IR receiver, enable it. + +Signed-off-by: Andre Heider +Acked-by: Jernej Skrabec +Signed-off-by: Maxime Ripard +--- + arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +index 4ed3fc2c7734..d422bc68dcf3 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-3.dts +@@ -274,6 +274,10 @@ sw { + }; + }; + ++&r_ir { ++ status = "okay"; ++}; ++ + &uart0 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_ph_pins>; +-- +2.24.1 + +From 59f3f4dcf68d276ff2ed0245f7c1938403de4c91 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Thu, 14 Nov 2019 11:25:41 +0100 +Subject: [PATCH] arm64: dts: allwinner: h6: Enable USB 3.0 host for Beelink + GS1 and Tanix TX6 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Enable USB 3.0 phy and host controller. + +VBUS is directly connected to DCIN 5V and doesn't +require to be switched on. + +Signed-off-by: Clément Péron +Signed-off-by: Maxime Ripard +--- + arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts | 8 ++++++++ + arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts | 8 ++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +index f335f7482a73..b004e151222a 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-beelink-gs1.dts +@@ -76,6 +76,10 @@ &de { + status = "okay"; + }; + ++&dwc3 { ++ status = "okay"; ++}; ++ + &ehci0 { + status = "okay"; + }; +@@ -292,3 +296,7 @@ &usb2phy { + usb0_vbus-supply = <®_vcc5v>; + status = "okay"; + }; ++ ++&usb3phy { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts +index bccfe1e65b6a..0b6361a5c172 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts +@@ -45,6 +45,10 @@ &de { + status = "okay"; + }; + ++&dwc3 { ++ status = "okay"; ++}; ++ + &ehci0 { + status = "okay"; + }; +@@ -102,3 +106,7 @@ &usb2otg { + &usb2phy { + status = "okay"; + }; ++ ++&usb3phy { ++ status = "okay"; ++}; +-- +2.24.1 + +From 42ccc3d79b7f5685beef2e0b26e6ec01c61f5162 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sun, 17 Nov 2019 14:00:58 +0100 +Subject: [PATCH] arm64: dts: allwinner: h6: tanix-tx6: Add IR remote mapping + +Tanix TX6 box comes with a remote. Add a mapping for it. + +Suggested-by: Michael Lange +Signed-off-by: Jernej Skrabec +Signed-off-by: Maxime Ripard +--- + arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts +index 0b6361a5c172..50d51f69dc5d 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-tanix-tx6.dts +@@ -89,6 +89,7 @@ &ohci3 { + }; + + &r_ir { ++ linux,rc-map-name = "rc-tanix-tx5max"; + status = "okay"; + }; + +-- +2.24.1 + +From 88432f5f8469ba67a2e20aeda04bd64cb88f9c6c Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Tue, 19 Nov 2019 18:53:18 +0100 +Subject: [PATCH] arm64: dts: allwinner: h6: Add PWM node +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Allwinner H6 PWM is similar to that in A20 except that it has additional +bus clock and reset line. + +Note that first PWM channel is connected to output pin and second +channel is used internally, as a clock source to AC200 co-packaged chip. +This means that any combination of these two channels can be used and +thus it doesn't make sense to add pinctrl nodes at this point. + +Signed-off-by: Jernej Skrabec +Signed-off-by: Clément Péron +Signed-off-by: Maxime Ripard +--- + arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +index 24ffe2dcbddb..83f98bd75ee6 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -255,6 +255,16 @@ watchdog: watchdog@30090a0 { + status = "disabled"; + }; + ++ pwm: pwm@300a000 { ++ compatible = "allwinner,sun50i-h6-pwm"; ++ reg = <0x0300a000 0x400>; ++ clocks = <&osc24M>, <&ccu CLK_BUS_PWM>; ++ clock-names = "mod", "bus"; ++ resets = <&ccu RST_BUS_PWM>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ + pio: pinctrl@300b000 { + compatible = "allwinner,sun50i-h6-pinctrl"; + reg = <0x0300b000 0x400>; +-- +2.24.1 + +From 730a45ccd9322dd918a5dcaf8ae1482400fa5b23 Mon Sep 17 00:00:00 2001 +From: Yangtao Li +Date: Thu, 19 Dec 2019 09:28:17 -0800 +Subject: [PATCH] thermal/drivers/sun8i: Add thermal driver for + H6/H5/H3/A64/A83T/R40 + +This patch adds the support for allwinner thermal sensor, within +allwinner SoC. It will register sensors for thermal framework +and use device tree to bind cooling device. + +Signed-off-by: Yangtao Li +Signed-off-by: Ondrej Jirman +Signed-off-by: Vasily Khoruzhick +Acked-by: Maxime Ripard +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20191219172823.1652600-2-anarsoul@gmail.com +--- + MAINTAINERS | 8 + + drivers/thermal/Kconfig | 14 + + drivers/thermal/Makefile | 1 + + drivers/thermal/sun8i_thermal.c | 639 ++++++++++++++++++++++++++++++++ + 4 files changed, 662 insertions(+) + create mode 100644 drivers/thermal/sun8i_thermal.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index 6d4940474674..723513023ec6 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -694,6 +694,14 @@ L: linux-crypto@vger.kernel.org + S: Maintained + F: drivers/crypto/allwinner/ + ++ALLWINNER THERMAL DRIVER ++M: Vasily Khoruzhick ++M: Yangtao Li ++L: linux-pm@vger.kernel.org ++S: Maintained ++F: Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml ++F: drivers/thermal/sun8i_thermal.c ++ + ALLWINNER VPU DRIVER + M: Maxime Ripard + M: Paul Kocialkowski +diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig +index dc36941aef6e..5a05db5438d6 100644 +--- a/drivers/thermal/Kconfig ++++ b/drivers/thermal/Kconfig +@@ -280,6 +280,20 @@ config SPEAR_THERMAL + Enable this to plug the SPEAr thermal sensor driver into the Linux + thermal framework. + ++config SUN8I_THERMAL ++ tristate "Allwinner sun8i thermal driver" ++ depends on ARCH_SUNXI || COMPILE_TEST ++ depends on HAS_IOMEM ++ depends on NVMEM ++ depends on OF ++ depends on RESET_CONTROLLER ++ help ++ Support for the sun8i thermal sensor driver into the Linux thermal ++ framework. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called sun8i-thermal. ++ + config ROCKCHIP_THERMAL + tristate "Rockchip thermal driver" + depends on ARCH_ROCKCHIP || COMPILE_TEST +diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile +index d502a597a717..9fb88e26fb10 100644 +--- a/drivers/thermal/Makefile ++++ b/drivers/thermal/Makefile +@@ -32,6 +32,7 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o + obj-y += broadcom/ + obj-$(CONFIG_THERMAL_MMIO) += thermal_mmio.o + obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o ++obj-$(CONFIG_SUN8I_THERMAL) += sun8i_thermal.o + obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o + obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o + obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o +diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c +new file mode 100644 +index 000000000000..23a5f4aa4be4 +--- /dev/null ++++ b/drivers/thermal/sun8i_thermal.c +@@ -0,0 +1,639 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Thermal sensor driver for Allwinner SOC ++ * Copyright (C) 2019 Yangtao Li ++ * ++ * Based on the work of Icenowy Zheng ++ * Based on the work of Ondrej Jirman ++ * Based on the work of Josef Gajdusek ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAX_SENSOR_NUM 4 ++ ++#define FT_TEMP_MASK GENMASK(11, 0) ++#define TEMP_CALIB_MASK GENMASK(11, 0) ++#define CALIBRATE_DEFAULT 0x800 ++ ++#define SUN8I_THS_CTRL0 0x00 ++#define SUN8I_THS_CTRL2 0x40 ++#define SUN8I_THS_IC 0x44 ++#define SUN8I_THS_IS 0x48 ++#define SUN8I_THS_MFC 0x70 ++#define SUN8I_THS_TEMP_CALIB 0x74 ++#define SUN8I_THS_TEMP_DATA 0x80 ++ ++#define SUN50I_THS_CTRL0 0x00 ++#define SUN50I_H6_THS_ENABLE 0x04 ++#define SUN50I_H6_THS_PC 0x08 ++#define SUN50I_H6_THS_DIC 0x10 ++#define SUN50I_H6_THS_DIS 0x20 ++#define SUN50I_H6_THS_MFC 0x30 ++#define SUN50I_H6_THS_TEMP_CALIB 0xa0 ++#define SUN50I_H6_THS_TEMP_DATA 0xc0 ++ ++#define SUN8I_THS_CTRL0_T_ACQ0(x) (GENMASK(15, 0) & (x)) ++#define SUN8I_THS_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) & (x)) << 16) ++#define SUN8I_THS_DATA_IRQ_STS(x) BIT(x + 8) ++ ++#define SUN50I_THS_CTRL0_T_ACQ(x) ((GENMASK(15, 0) & (x)) << 16) ++#define SUN50I_THS_FILTER_EN BIT(2) ++#define SUN50I_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x)) ++#define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12) ++#define SUN50I_H6_THS_DATA_IRQ_STS(x) BIT(x) ++ ++/* millidegree celsius */ ++#define THS_EFUSE_CP_FT_MASK 0x3000 ++#define THS_EFUSE_CP_FT_BIT 12 ++#define THS_CALIBRATION_IN_FT 1 ++ ++struct tsensor { ++ struct ths_device *tmdev; ++ struct thermal_zone_device *tzd; ++ int id; ++}; ++ ++struct ths_thermal_chip { ++ bool has_mod_clk; ++ bool has_bus_clk_reset; ++ int sensor_num; ++ int offset; ++ int scale; ++ int ft_deviation; ++ int temp_data_base; ++ int (*calibrate)(struct ths_device *tmdev, ++ u16 *caldata, int callen); ++ int (*init)(struct ths_device *tmdev); ++ int (*irq_ack)(struct ths_device *tmdev); ++ int (*calc_temp)(struct ths_device *tmdev, ++ int id, int reg); ++}; ++ ++struct ths_device { ++ const struct ths_thermal_chip *chip; ++ struct device *dev; ++ struct regmap *regmap; ++ struct reset_control *reset; ++ struct clk *bus_clk; ++ struct clk *mod_clk; ++ struct tsensor sensor[MAX_SENSOR_NUM]; ++ u32 cp_ft_flag; ++}; ++ ++/* Temp Unit: millidegree Celsius */ ++static int sun8i_ths_calc_temp(struct ths_device *tmdev, ++ int id, int reg) ++{ ++ return tmdev->chip->offset - (reg * tmdev->chip->scale / 10); ++} ++ ++static int sun50i_h5_calc_temp(struct ths_device *tmdev, ++ int id, int reg) ++{ ++ if (reg >= 0x500) ++ return -1191 * reg / 10 + 223000; ++ else if (!id) ++ return -1452 * reg / 10 + 259000; ++ else ++ return -1590 * reg / 10 + 276000; ++} ++ ++static int sun8i_ths_get_temp(void *data, int *temp) ++{ ++ struct tsensor *s = data; ++ struct ths_device *tmdev = s->tmdev; ++ int val = 0; ++ ++ regmap_read(tmdev->regmap, tmdev->chip->temp_data_base + ++ 0x4 * s->id, &val); ++ ++ /* ths have no data yet */ ++ if (!val) ++ return -EAGAIN; ++ ++ *temp = tmdev->chip->calc_temp(tmdev, s->id, val); ++ /* ++ * According to the original sdk, there are some platforms(rarely) ++ * that add a fixed offset value after calculating the temperature ++ * value. We can't simply put it on the formula for calculating the ++ * temperature above, because the formula for calculating the ++ * temperature above is also used when the sensor is calibrated. If ++ * do this, the correct calibration formula is hard to know. ++ */ ++ *temp += tmdev->chip->ft_deviation; ++ ++ return 0; ++} ++ ++static const struct thermal_zone_of_device_ops ths_ops = { ++ .get_temp = sun8i_ths_get_temp, ++}; ++ ++static const struct regmap_config config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .fast_io = true, ++ .max_register = 0xfc, ++}; ++ ++static int sun8i_h3_irq_ack(struct ths_device *tmdev) ++{ ++ int i, state, ret = 0; ++ ++ regmap_read(tmdev->regmap, SUN8I_THS_IS, &state); ++ ++ for (i = 0; i < tmdev->chip->sensor_num; i++) { ++ if (state & SUN8I_THS_DATA_IRQ_STS(i)) { ++ regmap_write(tmdev->regmap, SUN8I_THS_IS, ++ SUN8I_THS_DATA_IRQ_STS(i)); ++ ret |= BIT(i); ++ } ++ } ++ ++ return ret; ++} ++ ++static int sun50i_h6_irq_ack(struct ths_device *tmdev) ++{ ++ int i, state, ret = 0; ++ ++ regmap_read(tmdev->regmap, SUN50I_H6_THS_DIS, &state); ++ ++ for (i = 0; i < tmdev->chip->sensor_num; i++) { ++ if (state & SUN50I_H6_THS_DATA_IRQ_STS(i)) { ++ regmap_write(tmdev->regmap, SUN50I_H6_THS_DIS, ++ SUN50I_H6_THS_DATA_IRQ_STS(i)); ++ ret |= BIT(i); ++ } ++ } ++ ++ return ret; ++} ++ ++static irqreturn_t sun8i_irq_thread(int irq, void *data) ++{ ++ struct ths_device *tmdev = data; ++ int i, state; ++ ++ state = tmdev->chip->irq_ack(tmdev); ++ ++ for (i = 0; i < tmdev->chip->sensor_num; i++) { ++ if (state & BIT(i)) ++ thermal_zone_device_update(tmdev->sensor[i].tzd, ++ THERMAL_EVENT_UNSPECIFIED); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int sun8i_h3_ths_calibrate(struct ths_device *tmdev, ++ u16 *caldata, int callen) ++{ ++ int i; ++ ++ if (!caldata[0] || callen < 2 * tmdev->chip->sensor_num) ++ return -EINVAL; ++ ++ for (i = 0; i < tmdev->chip->sensor_num; i++) { ++ int offset = (i % 2) << 4; ++ ++ regmap_update_bits(tmdev->regmap, ++ SUN8I_THS_TEMP_CALIB + (4 * (i >> 1)), ++ 0xfff << offset, ++ caldata[i] << offset); ++ } ++ ++ return 0; ++} ++ ++static int sun50i_h6_ths_calibrate(struct ths_device *tmdev, ++ u16 *caldata, int callen) ++{ ++ struct device *dev = tmdev->dev; ++ int i, ft_temp; ++ ++ if (!caldata[0] || callen < 2 + 2 * tmdev->chip->sensor_num) ++ return -EINVAL; ++ ++ /* ++ * efuse layout: ++ * ++ * 0 11 16 32 ++ * +-------+-------+-------+ ++ * |temp| |sensor0|sensor1| ++ * +-------+-------+-------+ ++ * ++ * The calibration data on the H6 is the ambient temperature and ++ * sensor values that are filled during the factory test stage. ++ * ++ * The unit of stored FT temperature is 0.1 degreee celusis. ++ * ++ * We need to calculate a delta between measured and caluclated ++ * register values and this will become a calibration offset. ++ */ ++ ft_temp = (caldata[0] & FT_TEMP_MASK) * 100; ++ tmdev->cp_ft_flag = (caldata[0] & THS_EFUSE_CP_FT_MASK) ++ >> THS_EFUSE_CP_FT_BIT; ++ ++ for (i = 0; i < tmdev->chip->sensor_num; i++) { ++ int sensor_reg = caldata[i + 1]; ++ int cdata, offset; ++ int sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg); ++ ++ /* ++ * Calibration data is CALIBRATE_DEFAULT - (calculated ++ * temperature from sensor reading at factory temperature ++ * minus actual factory temperature) * 14.88 (scale from ++ * temperature to register values) ++ */ ++ cdata = CALIBRATE_DEFAULT - ++ ((sensor_temp - ft_temp) * 10 / tmdev->chip->scale); ++ if (cdata & ~TEMP_CALIB_MASK) { ++ /* ++ * Calibration value more than 12-bit, but calibration ++ * register is 12-bit. In this case, ths hardware can ++ * still work without calibration, although the data ++ * won't be so accurate. ++ */ ++ dev_warn(dev, "sensor%d is not calibrated.\n", i); ++ continue; ++ } ++ ++ offset = (i % 2) * 16; ++ regmap_update_bits(tmdev->regmap, ++ SUN50I_H6_THS_TEMP_CALIB + (i / 2 * 4), ++ 0xfff << offset, ++ cdata << offset); ++ } ++ ++ return 0; ++} ++ ++static int sun8i_ths_calibrate(struct ths_device *tmdev) ++{ ++ struct nvmem_cell *calcell; ++ struct device *dev = tmdev->dev; ++ u16 *caldata; ++ size_t callen; ++ int ret = 0; ++ ++ calcell = devm_nvmem_cell_get(dev, "calibration"); ++ if (IS_ERR(calcell)) { ++ if (PTR_ERR(calcell) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ /* ++ * Even if the external calibration data stored in sid is ++ * not accessible, the THS hardware can still work, although ++ * the data won't be so accurate. ++ * ++ * The default value of calibration register is 0x800 for ++ * every sensor, and the calibration value is usually 0x7xx ++ * or 0x8xx, so they won't be away from the default value ++ * for a lot. ++ * ++ * So here we do not return error if the calibartion data is ++ * not available, except the probe needs deferring. ++ */ ++ goto out; ++ } ++ ++ caldata = nvmem_cell_read(calcell, &callen); ++ if (IS_ERR(caldata)) { ++ ret = PTR_ERR(caldata); ++ goto out; ++ } ++ ++ tmdev->chip->calibrate(tmdev, caldata, callen); ++ ++ kfree(caldata); ++out: ++ return ret; ++} ++ ++static int sun8i_ths_resource_init(struct ths_device *tmdev) ++{ ++ struct device *dev = tmdev->dev; ++ struct platform_device *pdev = to_platform_device(dev); ++ void __iomem *base; ++ int ret; ++ ++ base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ tmdev->regmap = devm_regmap_init_mmio(dev, base, &config); ++ if (IS_ERR(tmdev->regmap)) ++ return PTR_ERR(tmdev->regmap); ++ ++ if (tmdev->chip->has_bus_clk_reset) { ++ tmdev->reset = devm_reset_control_get(dev, 0); ++ if (IS_ERR(tmdev->reset)) ++ return PTR_ERR(tmdev->reset); ++ ++ tmdev->bus_clk = devm_clk_get(&pdev->dev, "bus"); ++ if (IS_ERR(tmdev->bus_clk)) ++ return PTR_ERR(tmdev->bus_clk); ++ } ++ ++ if (tmdev->chip->has_mod_clk) { ++ tmdev->mod_clk = devm_clk_get(&pdev->dev, "mod"); ++ if (IS_ERR(tmdev->mod_clk)) ++ return PTR_ERR(tmdev->mod_clk); ++ } ++ ++ ret = reset_control_deassert(tmdev->reset); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(tmdev->bus_clk); ++ if (ret) ++ goto assert_reset; ++ ++ ret = clk_set_rate(tmdev->mod_clk, 24000000); ++ if (ret) ++ goto bus_disable; ++ ++ ret = clk_prepare_enable(tmdev->mod_clk); ++ if (ret) ++ goto bus_disable; ++ ++ ret = sun8i_ths_calibrate(tmdev); ++ if (ret) ++ goto mod_disable; ++ ++ return 0; ++ ++mod_disable: ++ clk_disable_unprepare(tmdev->mod_clk); ++bus_disable: ++ clk_disable_unprepare(tmdev->bus_clk); ++assert_reset: ++ reset_control_assert(tmdev->reset); ++ ++ return ret; ++} ++ ++static int sun8i_h3_thermal_init(struct ths_device *tmdev) ++{ ++ int val; ++ ++ /* average over 4 samples */ ++ regmap_write(tmdev->regmap, SUN8I_THS_MFC, ++ SUN50I_THS_FILTER_EN | ++ SUN50I_THS_FILTER_TYPE(1)); ++ /* ++ * clkin = 24MHz ++ * filter_samples = 4 ++ * period = 0.25s ++ * ++ * x = period * clkin / 4096 / filter_samples - 1 ++ * = 365 ++ */ ++ val = GENMASK(7 + tmdev->chip->sensor_num, 8); ++ regmap_write(tmdev->regmap, SUN8I_THS_IC, ++ SUN50I_H6_THS_PC_TEMP_PERIOD(365) | val); ++ /* ++ * T_acq = 20us ++ * clkin = 24MHz ++ * ++ * x = T_acq * clkin - 1 ++ * = 479 ++ */ ++ regmap_write(tmdev->regmap, SUN8I_THS_CTRL0, ++ SUN8I_THS_CTRL0_T_ACQ0(479)); ++ val = GENMASK(tmdev->chip->sensor_num - 1, 0); ++ regmap_write(tmdev->regmap, SUN8I_THS_CTRL2, ++ SUN8I_THS_CTRL2_T_ACQ1(479) | val); ++ ++ return 0; ++} ++ ++/* ++ * Without this undocummented value, the returned temperatures would ++ * be higher than real ones by about 20C. ++ */ ++#define SUN50I_H6_CTRL0_UNK 0x0000002f ++ ++static int sun50i_h6_thermal_init(struct ths_device *tmdev) ++{ ++ int val; ++ ++ /* ++ * T_acq = 20us ++ * clkin = 24MHz ++ * ++ * x = T_acq * clkin - 1 ++ * = 479 ++ */ ++ regmap_write(tmdev->regmap, SUN50I_THS_CTRL0, ++ SUN50I_H6_CTRL0_UNK | SUN50I_THS_CTRL0_T_ACQ(479)); ++ /* average over 4 samples */ ++ regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC, ++ SUN50I_THS_FILTER_EN | ++ SUN50I_THS_FILTER_TYPE(1)); ++ /* ++ * clkin = 24MHz ++ * filter_samples = 4 ++ * period = 0.25s ++ * ++ * x = period * clkin / 4096 / filter_samples - 1 ++ * = 365 ++ */ ++ regmap_write(tmdev->regmap, SUN50I_H6_THS_PC, ++ SUN50I_H6_THS_PC_TEMP_PERIOD(365)); ++ /* enable sensor */ ++ val = GENMASK(tmdev->chip->sensor_num - 1, 0); ++ regmap_write(tmdev->regmap, SUN50I_H6_THS_ENABLE, val); ++ /* thermal data interrupt enable */ ++ val = GENMASK(tmdev->chip->sensor_num - 1, 0); ++ regmap_write(tmdev->regmap, SUN50I_H6_THS_DIC, val); ++ ++ return 0; ++} ++ ++static int sun8i_ths_register(struct ths_device *tmdev) ++{ ++ int i; ++ ++ for (i = 0; i < tmdev->chip->sensor_num; i++) { ++ tmdev->sensor[i].tmdev = tmdev; ++ tmdev->sensor[i].id = i; ++ tmdev->sensor[i].tzd = ++ devm_thermal_zone_of_sensor_register(tmdev->dev, ++ i, ++ &tmdev->sensor[i], ++ &ths_ops); ++ if (IS_ERR(tmdev->sensor[i].tzd)) ++ return PTR_ERR(tmdev->sensor[i].tzd); ++ } ++ ++ return 0; ++} ++ ++static int sun8i_ths_probe(struct platform_device *pdev) ++{ ++ struct ths_device *tmdev; ++ struct device *dev = &pdev->dev; ++ int ret, irq; ++ ++ tmdev = devm_kzalloc(dev, sizeof(*tmdev), GFP_KERNEL); ++ if (!tmdev) ++ return -ENOMEM; ++ ++ tmdev->dev = dev; ++ tmdev->chip = of_device_get_match_data(&pdev->dev); ++ if (!tmdev->chip) ++ return -EINVAL; ++ ++ platform_set_drvdata(pdev, tmdev); ++ ++ ret = sun8i_ths_resource_init(tmdev); ++ if (ret) ++ return ret; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return irq; ++ ++ ret = tmdev->chip->init(tmdev); ++ if (ret) ++ return ret; ++ ++ ret = sun8i_ths_register(tmdev); ++ if (ret) ++ return ret; ++ ++ /* ++ * Avoid entering the interrupt handler, the thermal device is not ++ * registered yet, we deffer the registration of the interrupt to ++ * the end. ++ */ ++ ret = devm_request_threaded_irq(dev, irq, NULL, ++ sun8i_irq_thread, ++ IRQF_ONESHOT, "ths", tmdev); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int sun8i_ths_remove(struct platform_device *pdev) ++{ ++ struct ths_device *tmdev = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(tmdev->mod_clk); ++ clk_disable_unprepare(tmdev->bus_clk); ++ reset_control_assert(tmdev->reset); ++ ++ return 0; ++} ++ ++static const struct ths_thermal_chip sun8i_a83t_ths = { ++ .sensor_num = 3, ++ .scale = 705, ++ .offset = 191668, ++ .temp_data_base = SUN8I_THS_TEMP_DATA, ++ .calibrate = sun8i_h3_ths_calibrate, ++ .init = sun8i_h3_thermal_init, ++ .irq_ack = sun8i_h3_irq_ack, ++ .calc_temp = sun8i_ths_calc_temp, ++}; ++ ++static const struct ths_thermal_chip sun8i_h3_ths = { ++ .sensor_num = 1, ++ .scale = 1211, ++ .offset = 217000, ++ .has_mod_clk = true, ++ .has_bus_clk_reset = true, ++ .temp_data_base = SUN8I_THS_TEMP_DATA, ++ .calibrate = sun8i_h3_ths_calibrate, ++ .init = sun8i_h3_thermal_init, ++ .irq_ack = sun8i_h3_irq_ack, ++ .calc_temp = sun8i_ths_calc_temp, ++}; ++ ++static const struct ths_thermal_chip sun8i_r40_ths = { ++ .sensor_num = 3, ++ .offset = 251086, ++ .scale = 1130, ++ .has_mod_clk = true, ++ .has_bus_clk_reset = true, ++ .temp_data_base = SUN8I_THS_TEMP_DATA, ++ .calibrate = sun8i_h3_ths_calibrate, ++ .init = sun8i_h3_thermal_init, ++ .irq_ack = sun8i_h3_irq_ack, ++ .calc_temp = sun8i_ths_calc_temp, ++}; ++ ++static const struct ths_thermal_chip sun50i_a64_ths = { ++ .sensor_num = 3, ++ .offset = 260890, ++ .scale = 1170, ++ .has_mod_clk = true, ++ .has_bus_clk_reset = true, ++ .temp_data_base = SUN8I_THS_TEMP_DATA, ++ .calibrate = sun8i_h3_ths_calibrate, ++ .init = sun8i_h3_thermal_init, ++ .irq_ack = sun8i_h3_irq_ack, ++ .calc_temp = sun8i_ths_calc_temp, ++}; ++ ++static const struct ths_thermal_chip sun50i_h5_ths = { ++ .sensor_num = 2, ++ .has_mod_clk = true, ++ .has_bus_clk_reset = true, ++ .temp_data_base = SUN8I_THS_TEMP_DATA, ++ .calibrate = sun8i_h3_ths_calibrate, ++ .init = sun8i_h3_thermal_init, ++ .irq_ack = sun8i_h3_irq_ack, ++ .calc_temp = sun50i_h5_calc_temp, ++}; ++ ++static const struct ths_thermal_chip sun50i_h6_ths = { ++ .sensor_num = 2, ++ .has_bus_clk_reset = true, ++ .ft_deviation = 7000, ++ .offset = 187744, ++ .scale = 672, ++ .temp_data_base = SUN50I_H6_THS_TEMP_DATA, ++ .calibrate = sun50i_h6_ths_calibrate, ++ .init = sun50i_h6_thermal_init, ++ .irq_ack = sun50i_h6_irq_ack, ++ .calc_temp = sun8i_ths_calc_temp, ++}; ++ ++static const struct of_device_id of_ths_match[] = { ++ { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths }, ++ { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths }, ++ { .compatible = "allwinner,sun8i-r40-ths", .data = &sun8i_r40_ths }, ++ { .compatible = "allwinner,sun50i-a64-ths", .data = &sun50i_a64_ths }, ++ { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths }, ++ { .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, of_ths_match); ++ ++static struct platform_driver ths_driver = { ++ .probe = sun8i_ths_probe, ++ .remove = sun8i_ths_remove, ++ .driver = { ++ .name = "sun8i-thermal", ++ .of_match_table = of_ths_match, ++ }, ++}; ++module_platform_driver(ths_driver); ++ ++MODULE_DESCRIPTION("Thermal sensor driver for Allwinner SOC"); ++MODULE_LICENSE("GPL v2"); +-- +2.24.1 + +From 59f5e9b9a802a177727017218dcf026dc390c37d Mon Sep 17 00:00:00 2001 +From: Vasily Khoruzhick +Date: Thu, 19 Dec 2019 09:28:23 -0800 +Subject: [PATCH] arm64: dts: allwinner: a64: Add thermal sensors and thermal + zones + +A64 has 3 thermal sensors: 1 for CPU, 2 for GPU. + +Signed-off-by: Vasily Khoruzhick +Signed-off-by: Maxime Ripard +--- + arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 42 +++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +index ab42c0664b3e..9a89324d02db 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + + / { + interrupt-parent = <&gic>; +@@ -172,6 +173,29 @@ timer { + (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; + }; + ++ thermal-zones { ++ cpu_thermal: cpu0-thermal { ++ /* milliseconds */ ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&ths 0>; ++ }; ++ ++ gpu0_thermal: gpu0-thermal { ++ /* milliseconds */ ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&ths 1>; ++ }; ++ ++ gpu1_thermal: gpu1-thermal { ++ /* milliseconds */ ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&ths 2>; ++ }; ++ }; ++ + soc { + compatible = "simple-bus"; + #address-cells = <1>; +@@ -446,6 +470,12 @@ mmc2: mmc@1c11000 { + sid: eeprom@1c14000 { + compatible = "allwinner,sun50i-a64-sid"; + reg = <0x1c14000 0x400>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ths_calibration: thermal-sensor-calibration@34 { ++ reg = <0x34 0x8>; ++ }; + }; + + crypto: crypto@1c15000 { +@@ -771,6 +801,18 @@ codec: codec@1c22e00 { + status = "disabled"; + }; + ++ ths: thermal-sensor@1c25000 { ++ compatible = "allwinner,sun50i-a64-ths"; ++ reg = <0x01c25000 0x100>; ++ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>; ++ clock-names = "bus", "mod"; ++ interrupts = ; ++ resets = <&ccu RST_BUS_THS>; ++ nvmem-cells = <&ths_calibration>; ++ nvmem-cell-names = "calibration"; ++ #thermal-sensor-cells = <1>; ++ }; ++ + uart0: serial@1c28000 { + compatible = "snps,dw-apb-uart"; + reg = <0x01c28000 0x400>; +-- +2.24.1 + +From d7cfb661b206c0f9e66c9cdb3634f416c4283449 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Thu, 19 Dec 2019 09:28:22 -0800 +Subject: [PATCH] arm64: dts: allwinner: h6: Add thermal sensor and thermal + zones + +There are two sensors, one for CPU, one for GPU. + +Signed-off-by: Ondrej Jirman +Signed-off-by: Vasily Khoruzhick +Signed-off-by: Maxime Ripard +--- + arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 33 ++++++++++++++++++++ + 1 file changed, 33 insertions(+) + +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +index 6567dabbc0c7..3329283e38ab 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + / { + interrupt-parent = <&gic>; +@@ -241,6 +242,12 @@ dma: dma-controller@3002000 { + sid: efuse@3006000 { + compatible = "allwinner,sun50i-h6-sid"; + reg = <0x03006000 0x400>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ths_calibration: thermal-sensor-calibration@14 { ++ reg = <0x14 0x8>; ++ }; + }; + + watchdog: watchdog@30090a0 { +@@ -874,5 +881,31 @@ r_i2c: i2c@7081400 { + #address-cells = <1>; + #size-cells = <0>; + }; ++ ++ ths: thermal-sensor@5070400 { ++ compatible = "allwinner,sun50i-h6-ths"; ++ reg = <0x05070400 0x100>; ++ interrupts = ; ++ clocks = <&ccu CLK_BUS_THS>; ++ clock-names = "bus"; ++ resets = <&ccu RST_BUS_THS>; ++ nvmem-cells = <&ths_calibration>; ++ nvmem-cell-names = "calibration"; ++ #thermal-sensor-cells = <1>; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu-thermal { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&ths 0>; ++ }; ++ ++ gpu-thermal { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&ths 1>; ++ }; + }; + }; +-- +2.24.1 + +From fe67dfcb44c6477dbde6c897c7787bf20e2281a3 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sun, 17 Nov 2019 13:52:50 +0100 +Subject: [PATCH] ARM: dts: sun8i: h3: Add rc map for Beelink X2 + +Beelink X2 box comes with a remote. Add a mapping for it. + +Signed-off-by: Jernej Skrabec +Signed-off-by: Maxime Ripard +--- + arch/arm/boot/dts/sun8i-h3-beelink-x2.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts +index ac9e26b1d906..45a24441ff18 100644 +--- a/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts ++++ b/arch/arm/boot/dts/sun8i-h3-beelink-x2.dts +@@ -143,6 +143,7 @@ hdmi_out_con: endpoint { + }; + + &ir { ++ linux,rc-map-name = "rc-tanix-tx3mini"; + pinctrl-names = "default"; + pinctrl-0 = <&r_ir_rx_pin>; + status = "okay"; +-- +2.24.1 + +From b37da9c8e62ef8ea14c19d40837dcd5beb8470e6 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Thu, 19 Dec 2019 09:28:20 -0800 +Subject: [PATCH] ARM: dts: sun8i-h3: Add thermal sensor and thermal zones + +There is just one sensor for the CPU. + +Signed-off-by: Ondrej Jirman +Signed-off-by: Vasily Khoruzhick +Signed-off-by: Maxime Ripard +--- + arch/arm/boot/dts/sun8i-h3.dtsi | 20 ++++++++++++++++++++ + arch/arm/boot/dts/sunxi-h3-h5.dtsi | 6 ++++++ + 2 files changed, 26 insertions(+) + +diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi +index b4f1673df9ee..20217e2ca4d3 100644 +--- a/arch/arm/boot/dts/sun8i-h3.dtsi ++++ b/arch/arm/boot/dts/sun8i-h3.dtsi +@@ -208,6 +208,26 @@ mali: gpu@1c40000 { + assigned-clocks = <&ccu CLK_GPU>; + assigned-clock-rates = <384000000>; + }; ++ ++ ths: thermal-sensor@1c25000 { ++ compatible = "allwinner,sun8i-h3-ths"; ++ reg = <0x01c25000 0x400>; ++ interrupts = ; ++ resets = <&ccu RST_BUS_THS>; ++ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>; ++ clock-names = "bus", "mod"; ++ nvmem-cells = <&ths_calibration>; ++ nvmem-cell-names = "calibration"; ++ #thermal-sensor-cells = <0>; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu_thermal: cpu-thermal { ++ polling-delay-passive = <0>; ++ polling-delay = <0>; ++ thermal-sensors = <&ths 0>; ++ }; + }; + }; + +diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi +index 0afea59486c2..6e68ed831015 100644 +--- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi ++++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi +@@ -231,6 +231,12 @@ mmc2: mmc@1c11000 { + sid: eeprom@1c14000 { + /* compatible is in per SoC .dtsi file */ + reg = <0x1c14000 0x400>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ ths_calibration: thermal-sensor-calibration@34 { ++ reg = <0x34 4>; ++ }; + }; + + usb_otg: usb@1c19000 { +-- +2.24.1 + +From 7fdf6c6a0d0e032aac2aa4537a23af1e04a397ce Mon Sep 17 00:00:00 2001 +From: Marcel Holtmann +Date: Fri, 22 Nov 2019 00:33:45 +0100 +Subject: [PATCH] Bluetooth: Allow combination of BDADDR_PROPERTY and + INVALID_BDADDR quirks + +When utilizing BDADDR_PROPERTY and INVALID_BDADDR quirks together it +results in an unconfigured controller even if the bootloader provides +a valid address. Fix this by allowing a bootloader provided address +to mark the controller as configured. + +Signed-off-by: Marcel Holtmann +Tested-by: Andre Heider +Signed-off-by: Johan Hedberg +--- + net/bluetooth/hci_core.c | 26 ++++++++++++++++++++++++-- + 1 file changed, 24 insertions(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c +index 0cc9ce917222..9e19d5a3aac8 100644 +--- a/net/bluetooth/hci_core.c ++++ b/net/bluetooth/hci_core.c +@@ -1444,11 +1444,20 @@ static int hci_dev_do_open(struct hci_dev *hdev) + + if (hci_dev_test_flag(hdev, HCI_SETUP) || + test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks)) { ++ bool invalid_bdaddr; ++ + hci_sock_dev_event(hdev, HCI_DEV_SETUP); + + if (hdev->setup) + ret = hdev->setup(hdev); + ++ /* The transport driver can set the quirk to mark the ++ * BD_ADDR invalid before creating the HCI device or in ++ * its setup callback. ++ */ ++ invalid_bdaddr = test_bit(HCI_QUIRK_INVALID_BDADDR, ++ &hdev->quirks); ++ + if (ret) + goto setup_failed; + +@@ -1457,20 +1466,33 @@ static int hci_dev_do_open(struct hci_dev *hdev) + hci_dev_get_bd_addr_from_property(hdev); + + if (bacmp(&hdev->public_addr, BDADDR_ANY) && +- hdev->set_bdaddr) ++ hdev->set_bdaddr) { + ret = hdev->set_bdaddr(hdev, + &hdev->public_addr); ++ ++ /* If setting of the BD_ADDR from the device ++ * property succeeds, then treat the address ++ * as valid even if the invalid BD_ADDR ++ * quirk indicates otherwise. ++ */ ++ if (!ret) ++ invalid_bdaddr = false; ++ } + } + + setup_failed: + /* The transport driver can set these quirks before + * creating the HCI device or in its setup callback. + * ++ * For the invalid BD_ADDR quirk it is possible that ++ * it becomes a valid address if the bootloader does ++ * provide it (see above). ++ * + * In case any of them is set, the controller has to + * start up as unconfigured. + */ + if (test_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks) || +- test_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks)) ++ invalid_bdaddr) + hci_dev_set_flag(hdev, HCI_UNCONFIGURED); + + /* For an unconfigured controller it is required to +-- +2.24.1 + +From a4f95f31a9f38d9bb1fd313fcc2d0c0d48116ee3 Mon Sep 17 00:00:00 2001 +From: Andre Heider +Date: Fri, 22 Nov 2019 13:31:42 +0100 +Subject: [PATCH] Bluetooth: btbcm: Use the BDADDR_PROPERTY quirk + +Some devices ship with the controller default address, like the +Orange Pi 3 (BCM4345C5). + +Allow the bootloader to set a valid address through the device tree. + +Signed-off-by: Andre Heider +Signed-off-by: Marcel Holtmann +--- + drivers/bluetooth/btbcm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index 689c7f36fea2..8e05706fe5d9 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -444,6 +444,12 @@ int btbcm_finalize(struct hci_dev *hdev) + + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + ++ /* Some devices ship with the controller default address. ++ * Allow the bootloader to set a valid address through the ++ * device tree. ++ */ ++ set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); ++ + return 0; + } + EXPORT_SYMBOL_GPL(btbcm_finalize); +-- +2.24.1 + +From 675a6d467b432c8b4a0703ded02e6ef068e0c7e9 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sat, 28 Dec 2019 20:59:21 -0600 +Subject: [PATCH] clk: sunxi-ng: h6-r: Simplify R_APB1 clock definition + +Like the APB0 clock on previous chips, this is a simple single-parent +clock with an M divider. Use the equivalent helper macro instead of +writing out the whole clock description manually. + +Signed-off-by: Samuel Holland +Signed-off-by: Maxime Ripard +--- + drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c +index 45a1ed3fe674..df9c01831699 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c ++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c +@@ -51,17 +51,7 @@ static struct ccu_div ar100_clk = { + + static CLK_FIXED_FACTOR_HW(r_ahb_clk, "r-ahb", &ar100_clk.common.hw, 1, 1, 0); + +-static struct ccu_div r_apb1_clk = { +- .div = _SUNXI_CCU_DIV(0, 2), +- +- .common = { +- .reg = 0x00c, +- .hw.init = CLK_HW_INIT("r-apb1", +- "r-ahb", +- &ccu_div_ops, +- 0), +- }, +-}; ++static SUNXI_CCU_M(r_apb1_clk, "r-apb1", "r-ahb", 0x00c, 0, 2, 0); + + static struct ccu_div r_apb2_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO), +-- +2.24.1 + +From 0c545240aebc2ccb8f661dc54283a14d64659804 Mon Sep 17 00:00:00 2001 +From: Samuel Holland +Date: Sat, 28 Dec 2019 20:59:22 -0600 +Subject: [PATCH] clk: sunxi-ng: h6-r: Fix AR100/R_APB2 parent order + +According to the BSP source code, both the AR100 and R_APB2 clocks have +PLL_PERIPH0 as mux index 3, not 2 as it was on previous chips. The pre- +divider used for PLL_PERIPH0 should be changed to index 3 to match. + +This was verified by running a rough benchmark on the AR100 with various +clock settings: + + | mux | pre-divider | iterations/second | clock source | + |=====|=============|===================|==============| + | 0 | 0 | 19033 (stable) | osc24M | + | 2 | 5 | 11466 (unstable) | iosc/osc16M | + | 2 | 17 | 11422 (unstable) | iosc/osc16M | + | 3 | 5 | 85338 (stable) | pll-periph0 | + | 3 | 17 | 27167 (stable) | pll-periph0 | + +The relative performance numbers all match up (with pll-periph0 running +at its default 600MHz). + +Signed-off-by: Samuel Holland +Signed-off-by: Maxime Ripard +--- + drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c +index df9c01831699..50f8d1bc7046 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c ++++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c +@@ -23,9 +23,9 @@ + */ + + static const char * const ar100_r_apb2_parents[] = { "osc24M", "osc32k", +- "pll-periph0", "iosc" }; ++ "iosc", "pll-periph0" }; + static const struct ccu_mux_var_prediv ar100_r_apb2_predivs[] = { +- { .index = 2, .shift = 0, .width = 5 }, ++ { .index = 3, .shift = 0, .width = 5 }, + }; + + static struct ccu_div ar100_clk = { +-- +2.24.1 + +From ec97faff743b398e21f74a54c81333f3390093aa Mon Sep 17 00:00:00 2001 +From: Icenowy Zheng +Date: Fri, 3 Jan 2020 22:35:03 -0800 +Subject: [PATCH] clk: sunxi-ng: add mux and pll notifiers for A64 CPU clock + +The A64 PLL_CPU clock has the same instability if some factor changed +without the PLL gated like other SoCs with sun6i-style CCU, e.g. A33, +H3. + +Add the mux and pll notifiers for A64 CPU clock to workaround the +problem. + +Fixes: c6a0637460c2 ("clk: sunxi-ng: Add A64 clocks") +Signed-off-by: Icenowy Zheng +Signed-off-by: Vasily Khoruzhick +Signed-off-by: Maxime Ripard +--- + drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 28 ++++++++++++++++++++++++++- + 1 file changed, 27 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +index 49bd7a4c015c..5f66bf879772 100644 +--- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c ++++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +@@ -921,11 +921,26 @@ static const struct sunxi_ccu_desc sun50i_a64_ccu_desc = { + .num_resets = ARRAY_SIZE(sun50i_a64_ccu_resets), + }; + ++static struct ccu_pll_nb sun50i_a64_pll_cpu_nb = { ++ .common = &pll_cpux_clk.common, ++ /* copy from pll_cpux_clk */ ++ .enable = BIT(31), ++ .lock = BIT(28), ++}; ++ ++static struct ccu_mux_nb sun50i_a64_cpu_nb = { ++ .common = &cpux_clk.common, ++ .cm = &cpux_clk.mux, ++ .delay_us = 1, /* > 8 clock cycles at 24 MHz */ ++ .bypass_index = 1, /* index of 24 MHz oscillator */ ++}; ++ + static int sun50i_a64_ccu_probe(struct platform_device *pdev) + { + struct resource *res; + void __iomem *reg; + u32 val; ++ int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg = devm_ioremap_resource(&pdev->dev, res); +@@ -939,7 +954,18 @@ static int sun50i_a64_ccu_probe(struct platform_device *pdev) + + writel(0x515, reg + SUN50I_A64_PLL_MIPI_REG); + +- return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc); ++ ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a64_ccu_desc); ++ if (ret) ++ return ret; ++ ++ /* Gate then ungate PLL CPU after any rate changes */ ++ ccu_pll_notifier_register(&sun50i_a64_pll_cpu_nb); ++ ++ /* Reparent CPU during PLL CPU rate changes */ ++ ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, ++ &sun50i_a64_cpu_nb); ++ ++ return 0; + } + + static const struct of_device_id sun50i_a64_ccu_ids[] = { +-- +2.24.1 + +From 624b4b48d9d870c2858c016d8709715495409654 Mon Sep 17 00:00:00 2001 +From: Ondrej Jirman +Date: Tue, 29 Oct 2019 12:28:46 +0100 +Subject: [PATCH] drm: sun4i: Add support for suspending the display driver + +Shut down the display engine during suspend. + +Signed-off-by: Ondrej Jirman +Signed-off-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20191029112846.3604925-1-megous@megous.com +--- + drivers/gpu/drm/sun4i/sun4i_drv.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c +index a5757b11b730..5ae67d526b1d 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_drv.c ++++ b/drivers/gpu/drm/sun4i/sun4i_drv.c +@@ -346,6 +346,27 @@ static int sun4i_drv_add_endpoints(struct device *dev, + return count; + } + ++#ifdef CONFIG_PM_SLEEP ++static int sun4i_drv_drm_sys_suspend(struct device *dev) ++{ ++ struct drm_device *drm = dev_get_drvdata(dev); ++ ++ return drm_mode_config_helper_suspend(drm); ++} ++ ++static int sun4i_drv_drm_sys_resume(struct device *dev) ++{ ++ struct drm_device *drm = dev_get_drvdata(dev); ++ ++ return drm_mode_config_helper_resume(drm); ++} ++#endif ++ ++static const struct dev_pm_ops sun4i_drv_drm_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(sun4i_drv_drm_sys_suspend, ++ sun4i_drv_drm_sys_resume) ++}; ++ + static int sun4i_drv_probe(struct platform_device *pdev) + { + struct component_match *match = NULL; +@@ -418,6 +439,7 @@ static struct platform_driver sun4i_drv_platform_driver = { + .driver = { + .name = "sun4i-drm", + .of_match_table = sun4i_drv_of_table, ++ .pm = &sun4i_drv_drm_pm_ops, + }, + }; + module_platform_driver(sun4i_drv_platform_driver); +-- +2.24.1 + +From 57177d214ee0816c4436c23d6c933ccb32c571f1 Mon Sep 17 00:00:00 2001 +From: Stefan Mavrodiev +Date: Tue, 17 Dec 2019 14:46:32 +0200 +Subject: [PATCH] drm/sun4i: hdmi: Remove duplicate cleanup calls + +When the HDMI unbinds drm_connector_cleanup() and drm_encoder_cleanup() +are called. This also happens when the connector and the encoder are +destroyed. This double call triggers a NULL pointer exception. + +The patch fixes this by removing the cleanup calls in the unbind +function. + +Cc: +Fixes: 9c5681011a0c ("drm/sun4i: Add HDMI support") +Signed-off-by: Stefan Mavrodiev +Signed-off-by: Maxime Ripard +Link: https://patchwork.freedesktop.org/patch/msgid/20191217124632.20820-1-stefan@olimex.com +--- + drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +index a7c4654445c7..68d4644ac2dc 100644 +--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c ++++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +@@ -685,8 +685,6 @@ static void sun4i_hdmi_unbind(struct device *dev, struct device *master, + struct sun4i_hdmi *hdmi = dev_get_drvdata(dev); + + cec_unregister_adapter(hdmi->cec_adap); +- drm_connector_cleanup(&hdmi->connector); +- drm_encoder_cleanup(&hdmi->encoder); + i2c_del_adapter(hdmi->i2c); + i2c_put_adapter(hdmi->ddc_i2c); + clk_disable_unprepare(hdmi->mod_clk); +-- +2.24.1 + +From a7fe985633f927401037d2905df2c9701dff09a1 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sun, 24 Nov 2019 18:29:03 +0100 +Subject: [PATCH 1/6] pwm: sun4i: Add an optional probe for reset line +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +H6 PWM core needs deasserted reset line in order to work. + +Add an optional probe for it. + +Signed-off-by: Jernej Skrabec +Reviewed-by: Uwe Kleine-König +Signed-off-by: Clément Péron +Signed-off-by: Thierry Reding +--- + drivers/pwm/pwm-sun4i.c | 34 ++++++++++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c +index 581d23287333..487899d4cc3f 100644 +--- a/drivers/pwm/pwm-sun4i.c ++++ b/drivers/pwm/pwm-sun4i.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -78,6 +79,7 @@ struct sun4i_pwm_data { + struct sun4i_pwm_chip { + struct pwm_chip chip; + struct clk *clk; ++ struct reset_control *rst; + void __iomem *base; + spinlock_t ctrl_lock; + const struct sun4i_pwm_data *data; +@@ -364,6 +366,22 @@ static int sun4i_pwm_probe(struct platform_device *pdev) + if (IS_ERR(pwm->clk)) + return PTR_ERR(pwm->clk); + ++ pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); ++ if (IS_ERR(pwm->rst)) { ++ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "get reset failed %pe\n", ++ pwm->rst); ++ return PTR_ERR(pwm->rst); ++ } ++ ++ /* Deassert reset */ ++ ret = reset_control_deassert(pwm->rst); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot deassert reset control: %pe\n", ++ ERR_PTR(ret)); ++ return ret; ++ } ++ + pwm->chip.dev = &pdev->dev; + pwm->chip.ops = &sun4i_pwm_ops; + pwm->chip.base = -1; +@@ -376,19 +394,31 @@ static int sun4i_pwm_probe(struct platform_device *pdev) + ret = pwmchip_add(&pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); +- return ret; ++ goto err_pwm_add; + } + + platform_set_drvdata(pdev, pwm); + + return 0; ++ ++err_pwm_add: ++ reset_control_assert(pwm->rst); ++ ++ return ret; + } + + static int sun4i_pwm_remove(struct platform_device *pdev) + { + struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev); ++ int ret; ++ ++ ret = pwmchip_remove(&pwm->chip); ++ if (ret) ++ return ret; ++ ++ reset_control_assert(pwm->rst); + +- return pwmchip_remove(&pwm->chip); ++ return 0; + } + + static struct platform_driver sun4i_pwm_driver = { +-- +2.24.1 + + +From b8d74644f34a82a6dcd5f45d5bd57e64f1db0d4d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Sun, 24 Nov 2019 18:29:04 +0100 +Subject: [PATCH 2/6] pwm: sun4i: Prefer "mod" clock to unnamed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +New device tree bindings called the source clock of the module +"mod" when several clocks are defined. + +Try to get a clock called "mod" if nothing is found try to get +an unnamed clock. + +Reviewed-by: Uwe Kleine-König +Signed-off-by: Clément Péron +Signed-off-by: Thierry Reding +--- + drivers/pwm/pwm-sun4i.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c +index 487899d4cc3f..80026167044b 100644 +--- a/drivers/pwm/pwm-sun4i.c ++++ b/drivers/pwm/pwm-sun4i.c +@@ -362,9 +362,34 @@ static int sun4i_pwm_probe(struct platform_device *pdev) + if (IS_ERR(pwm->base)) + return PTR_ERR(pwm->base); + +- pwm->clk = devm_clk_get(&pdev->dev, NULL); +- if (IS_ERR(pwm->clk)) ++ /* ++ * All hardware variants need a source clock that is divided and ++ * then feeds the counter that defines the output wave form. In the ++ * device tree this clock is either unnamed or called "mod". ++ * Some variants (e.g. H6) need another clock to access the ++ * hardware registers; this is called "bus". ++ * So we request "mod" first (and ignore the corner case that a ++ * parent provides a "mod" clock while the right one would be the ++ * unnamed one of the PWM device) and if this is not found we fall ++ * back to the first clock of the PWM. ++ */ ++ pwm->clk = devm_clk_get_optional(&pdev->dev, "mod"); ++ if (IS_ERR(pwm->clk)) { ++ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "get mod clock failed %pe\n", ++ pwm->clk); + return PTR_ERR(pwm->clk); ++ } ++ ++ if (!pwm->clk) { ++ pwm->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(pwm->clk)) { ++ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "get unnamed clock failed %pe\n", ++ pwm->clk); ++ return PTR_ERR(pwm->clk); ++ } ++ } + + pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); + if (IS_ERR(pwm->rst)) { +-- +2.24.1 + + +From 5b090b430d750961305030232314b6acdb0102aa Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sun, 24 Nov 2019 18:29:05 +0100 +Subject: [PATCH 3/6] pwm: sun4i: Add an optional probe for bus clock +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +H6 PWM core needs bus clock to be enabled in order to work. + +Add an optional probe for it. + +Signed-off-by: Jernej Skrabec +Signed-off-by: Clément Péron +Reviewed-by: Uwe Kleine-König +Signed-off-by: Thierry Reding +--- + drivers/pwm/pwm-sun4i.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c +index 80026167044b..a6727dd89e28 100644 +--- a/drivers/pwm/pwm-sun4i.c ++++ b/drivers/pwm/pwm-sun4i.c +@@ -78,6 +78,7 @@ struct sun4i_pwm_data { + + struct sun4i_pwm_chip { + struct pwm_chip chip; ++ struct clk *bus_clk; + struct clk *clk; + struct reset_control *rst; + void __iomem *base; +@@ -391,6 +392,14 @@ static int sun4i_pwm_probe(struct platform_device *pdev) + } + } + ++ pwm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus"); ++ if (IS_ERR(pwm->bus_clk)) { ++ if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "get bus clock failed %pe\n", ++ pwm->bus_clk); ++ return PTR_ERR(pwm->bus_clk); ++ } ++ + pwm->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); + if (IS_ERR(pwm->rst)) { + if (PTR_ERR(pwm->rst) != -EPROBE_DEFER) +@@ -407,6 +416,17 @@ static int sun4i_pwm_probe(struct platform_device *pdev) + return ret; + } + ++ /* ++ * We're keeping the bus clock on for the sake of simplicity. ++ * Actually it only needs to be on for hardware register accesses. ++ */ ++ ret = clk_prepare_enable(pwm->bus_clk); ++ if (ret) { ++ dev_err(&pdev->dev, "cannot prepare and enable bus_clk %pe\n", ++ ERR_PTR(ret)); ++ goto err_bus; ++ } ++ + pwm->chip.dev = &pdev->dev; + pwm->chip.ops = &sun4i_pwm_ops; + pwm->chip.base = -1; +@@ -427,6 +447,8 @@ static int sun4i_pwm_probe(struct platform_device *pdev) + return 0; + + err_pwm_add: ++ clk_disable_unprepare(pwm->bus_clk); ++err_bus: + reset_control_assert(pwm->rst); + + return ret; +@@ -441,6 +463,7 @@ static int sun4i_pwm_remove(struct platform_device *pdev) + if (ret) + return ret; + ++ clk_disable_unprepare(pwm->bus_clk); + reset_control_assert(pwm->rst); + + return 0; +-- +2.24.1 + + +From fa4d81784681a26bcf7d2a43c6ac5cf991ef28f5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Cl=C3=A9ment=20P=C3=A9ron?= +Date: Sun, 24 Nov 2019 18:29:06 +0100 +Subject: [PATCH 4/6] pwm: sun4i: Always calculate params when applying new + parameters +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Bypass mode will require to be re-calculated when the pwm state +is changed. + +Remove the condition so pwm_sun4i_calculate is always called. + +Reviewed-by: Uwe Kleine-König +Signed-off-by: Clément Péron +Signed-off-by: Thierry Reding +--- + drivers/pwm/pwm-sun4i.c | 52 ++++++++++++++++++----------------------- + 1 file changed, 23 insertions(+), 29 deletions(-) + +diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c +index a6727dd89e28..e369b5a398f4 100644 +--- a/drivers/pwm/pwm-sun4i.c ++++ b/drivers/pwm/pwm-sun4i.c +@@ -202,9 +202,9 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + { + struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip); + struct pwm_state cstate; +- u32 ctrl; ++ u32 ctrl, duty, period, val; + int ret; +- unsigned int delay_us; ++ unsigned int delay_us, prescaler; + unsigned long now; + + pwm_get_state(pwm, &cstate); +@@ -220,43 +220,37 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + spin_lock(&sun4i_pwm->ctrl_lock); + ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); + +- if ((cstate.period != state->period) || +- (cstate.duty_cycle != state->duty_cycle)) { +- u32 period, duty, val; +- unsigned int prescaler; +- +- ret = sun4i_pwm_calculate(sun4i_pwm, state, +- &duty, &period, &prescaler); +- if (ret) { +- dev_err(chip->dev, "period exceeds the maximum value\n"); +- spin_unlock(&sun4i_pwm->ctrl_lock); +- if (!cstate.enabled) +- clk_disable_unprepare(sun4i_pwm->clk); +- return ret; +- } +- +- if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) { +- /* Prescaler changed, the clock has to be gated */ +- ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); +- sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); ++ ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler); ++ if (ret) { ++ dev_err(chip->dev, "period exceeds the maximum value\n"); ++ spin_unlock(&sun4i_pwm->ctrl_lock); ++ if (!cstate.enabled) ++ clk_disable_unprepare(sun4i_pwm->clk); ++ return ret; ++ } + +- ctrl &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm); +- ctrl |= BIT_CH(prescaler, pwm->hwpwm); +- } ++ if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) { ++ /* Prescaler changed, the clock has to be gated */ ++ ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); ++ sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); + +- val = (duty & PWM_DTY_MASK) | PWM_PRD(period); +- sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm)); +- sun4i_pwm->next_period[pwm->hwpwm] = jiffies + +- usecs_to_jiffies(cstate.period / 1000 + 1); +- sun4i_pwm->needs_delay[pwm->hwpwm] = true; ++ ctrl &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm); ++ ctrl |= BIT_CH(prescaler, pwm->hwpwm); + } + ++ val = (duty & PWM_DTY_MASK) | PWM_PRD(period); ++ sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm)); ++ sun4i_pwm->next_period[pwm->hwpwm] = jiffies + ++ usecs_to_jiffies(cstate.period / 1000 + 1); ++ sun4i_pwm->needs_delay[pwm->hwpwm] = true; ++ + if (state->polarity != PWM_POLARITY_NORMAL) + ctrl &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm); + else + ctrl |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm); + + ctrl |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm); ++ + if (state->enabled) { + ctrl |= BIT_CH(PWM_EN, pwm->hwpwm); + } else if (!sun4i_pwm->needs_delay[pwm->hwpwm]) { +-- +2.24.1 + + +From 9f28e95b5286fce63a3d0d90dc7ca43eca8dda58 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sun, 24 Nov 2019 18:29:07 +0100 +Subject: [PATCH 5/6] pwm: sun4i: Add support to output source clock directly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +PWM core has an option to bypass whole logic and output unchanged source +clock as PWM output. This is achieved by enabling bypass bit. + +Note that when bypass is enabled, no other setting has any meaning, not +even enable bit. + +This mode of operation is needed to achieve high enough frequency to +serve as clock source for AC200 chip which is integrated into same +package as H6 SoC. + +Signed-off-by: Jernej Skrabec +Signed-off-by: Clément Péron +Reviewed-by: Uwe Kleine-König +Signed-off-by: Thierry Reding +--- + drivers/pwm/pwm-sun4i.c | 48 +++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 46 insertions(+), 2 deletions(-) + +diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c +index e369b5a398f4..63aa9da92c22 100644 +--- a/drivers/pwm/pwm-sun4i.c ++++ b/drivers/pwm/pwm-sun4i.c +@@ -3,6 +3,10 @@ + * Driver for Allwinner sun4i Pulse Width Modulation Controller + * + * Copyright (C) 2014 Alexandre Belloni ++ * ++ * Limitations: ++ * - When outputing the source clock directly, the PWM logic will be bypassed ++ * and the currently running period is not guaranteed to be completed + */ + + #include +@@ -73,6 +77,7 @@ static const u32 prescaler_table[] = { + + struct sun4i_pwm_data { + bool has_prescaler_bypass; ++ bool has_direct_mod_clk_output; + unsigned int npwm; + }; + +@@ -118,6 +123,20 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, + + val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); + ++ /* ++ * PWM chapter in H6 manual has a diagram which explains that if bypass ++ * bit is set, no other setting has any meaning. Even more, experiment ++ * proved that also enable bit is ignored in this case. ++ */ ++ if ((val & BIT_CH(PWM_BYPASS, pwm->hwpwm)) && ++ sun4i_pwm->data->has_direct_mod_clk_output) { ++ state->period = DIV_ROUND_UP_ULL(NSEC_PER_SEC, clk_rate); ++ state->duty_cycle = DIV_ROUND_UP_ULL(state->period, 2); ++ state->polarity = PWM_POLARITY_NORMAL; ++ state->enabled = true; ++ return; ++ } ++ + if ((PWM_REG_PRESCAL(val, pwm->hwpwm) == PWM_PRESCAL_MASK) && + sun4i_pwm->data->has_prescaler_bypass) + prescaler = 1; +@@ -149,13 +168,24 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, + + static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, + const struct pwm_state *state, +- u32 *dty, u32 *prd, unsigned int *prsclr) ++ u32 *dty, u32 *prd, unsigned int *prsclr, ++ bool *bypass) + { + u64 clk_rate, div = 0; + unsigned int pval, prescaler = 0; + + clk_rate = clk_get_rate(sun4i_pwm->clk); + ++ *bypass = sun4i_pwm->data->has_direct_mod_clk_output && ++ state->enabled && ++ (state->period * clk_rate >= NSEC_PER_SEC) && ++ (state->period * clk_rate < 2 * NSEC_PER_SEC) && ++ (state->duty_cycle * clk_rate * 2 >= NSEC_PER_SEC); ++ ++ /* Skip calculation of other parameters if we bypass them */ ++ if (*bypass) ++ return 0; ++ + if (sun4i_pwm->data->has_prescaler_bypass) { + /* First, test without any prescaler when available */ + prescaler = PWM_PRESCAL_MASK; +@@ -206,6 +236,7 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + int ret; + unsigned int delay_us, prescaler; + unsigned long now; ++ bool bypass; + + pwm_get_state(pwm, &cstate); + +@@ -220,7 +251,8 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + spin_lock(&sun4i_pwm->ctrl_lock); + ctrl = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG); + +- ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler); ++ ret = sun4i_pwm_calculate(sun4i_pwm, state, &duty, &period, &prescaler, ++ &bypass); + if (ret) { + dev_err(chip->dev, "period exceeds the maximum value\n"); + spin_unlock(&sun4i_pwm->ctrl_lock); +@@ -229,6 +261,18 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + return ret; + } + ++ if (sun4i_pwm->data->has_direct_mod_clk_output) { ++ if (bypass) { ++ ctrl |= BIT_CH(PWM_BYPASS, pwm->hwpwm); ++ /* We can skip other parameter */ ++ sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG); ++ spin_unlock(&sun4i_pwm->ctrl_lock); ++ return 0; ++ } ++ ++ ctrl &= ~BIT_CH(PWM_BYPASS, pwm->hwpwm); ++ } ++ + if (PWM_REG_PRESCAL(ctrl, pwm->hwpwm) != prescaler) { + /* Prescaler changed, the clock has to be gated */ + ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); +-- +2.24.1 + + +From fdd2c12e3761f0418596cd0e0156719a255d23c8 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Sun, 24 Nov 2019 18:29:08 +0100 +Subject: [PATCH 6/6] pwm: sun4i: Add support for H6 PWM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now that sun4i PWM driver supports deasserting reset line and enabling +bus clock, support for H6 PWM can be added. + +Note that while H6 PWM has two channels, only first one is wired to +output pin. Second channel is used as a clock source to companion AC200 +chip which is bundled into same package. + +Signed-off-by: Jernej Skrabec +Acked-by: Uwe Kleine-König +Signed-off-by: Clément Péron +Signed-off-by: Thierry Reding +--- + drivers/pwm/pwm-sun4i.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c +index 63aa9da92c22..1afd41ebd3fd 100644 +--- a/drivers/pwm/pwm-sun4i.c ++++ b/drivers/pwm/pwm-sun4i.c +@@ -360,6 +360,12 @@ static const struct sun4i_pwm_data sun4i_pwm_single_bypass = { + .npwm = 1, + }; + ++static const struct sun4i_pwm_data sun50i_h6_pwm_data = { ++ .has_prescaler_bypass = true, ++ .has_direct_mod_clk_output = true, ++ .npwm = 2, ++}; ++ + static const struct of_device_id sun4i_pwm_dt_ids[] = { + { + .compatible = "allwinner,sun4i-a10-pwm", +@@ -376,6 +382,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = { + }, { + .compatible = "allwinner,sun8i-h3-pwm", + .data = &sun4i_pwm_single_bypass, ++ }, { ++ .compatible = "allwinner,sun50i-h6-pwm", ++ .data = &sun50i_h6_pwm_data, + }, { + /* sentinel */ + }, +-- +2.24.1 + +From 7678c5462680c1aba8d07926ab4d8ee906fb98cf Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Fri, 13 Dec 2019 17:15:15 +0100 +Subject: [PATCH] media: cedrus: Fix decoding for some HEVC videos + +It seems that for some HEVC videos at least one bitstream parsing +trigger must be called in order to be decoded correctly. There is no +explanation why this helps, but it was observed that several videos +with this fix are now decoded correctly and there is no regression with +others. + +Without this fix, those same videos totally crash HEVC decoder (other +decoder engines are unaffected). After decoding those problematic +videos, HEVC decoder always returns only green image (all zeros). +Only complete HW reset helps. + +This fix is similar to that for H264. + +Signed-off-by: Jernej Skrabec +Acked-by: Paul Kocialkowski +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + .../staging/media/sunxi/cedrus/cedrus_h265.c | 25 ++++++++++++++++--- + .../staging/media/sunxi/cedrus/cedrus_regs.h | 1 + + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +index 6945dc74e1d7..c17d30e74bb1 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +@@ -7,6 +7,7 @@ + * Copyright (C) 2018 Bootlin + */ + ++#include + #include + + #include +@@ -220,6 +221,23 @@ static void cedrus_h265_pred_weight_write(struct cedrus_dev *dev, + } + } + ++static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num) ++{ ++ int count = 0; ++ ++ while (count < num) { ++ int tmp = min(num - count, 32); ++ ++ cedrus_write(dev, VE_DEC_H265_TRIGGER, ++ VE_DEC_H265_TRIGGER_FLUSH_BITS | ++ VE_DEC_H265_TRIGGER_TYPE_N_BITS(tmp)); ++ while (cedrus_read(dev, VE_DEC_H265_STATUS) & VE_DEC_H265_STATUS_VLD_BUSY) ++ udelay(1); ++ ++ count += tmp; ++ } ++} ++ + static void cedrus_h265_setup(struct cedrus_ctx *ctx, + struct cedrus_run *run) + { +@@ -280,10 +298,9 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, + + /* Source offset and length in bits. */ + +- reg = slice_params->data_bit_offset; +- cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, reg); ++ cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, 0); + +- reg = slice_params->bit_size - slice_params->data_bit_offset; ++ reg = slice_params->bit_size; + cedrus_write(dev, VE_DEC_H265_BITS_LEN, reg); + + /* Source beginning and end addresses. */ +@@ -316,6 +333,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, + /* Initialize bitstream access. */ + cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC); + ++ cedrus_h265_skip_bits(dev, slice_params->data_bit_offset); ++ + /* Bitstream parameters. */ + + reg = VE_DEC_H265_DEC_NAL_HDR_NAL_UNIT_TYPE(slice_params->nal_unit_type) | +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +index 7beb03d3bb39..66b152f18d17 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +@@ -424,6 +424,7 @@ + + #define VE_DEC_H265_TRIGGER (VE_ENGINE_DEC_H265 + 0x34) + ++#define VE_DEC_H265_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8) + #define VE_DEC_H265_TRIGGER_STCD_VC1 (0x02 << 4) + #define VE_DEC_H265_TRIGGER_STCD_AVS (0x01 << 4) + #define VE_DEC_H265_TRIGGER_STCD_HEVC (0x00 << 4) +-- +2.24.1 + +From 7fcaed4ab4bc454757da266076f4b28fa93f54d1 Mon Sep 17 00:00:00 2001 +From: Jernej Skrabec +Date: Fri, 13 Dec 2019 17:15:16 +0100 +Subject: [PATCH] media: cedrus: hevc: Add luma bit depth + +Add luma bit depth. + +Signed-off-by: Jernej Skrabec +Acked-by: Paul Kocialkowski +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +--- + drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +index c17d30e74bb1..ce497d0197df 100644 +--- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c ++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +@@ -351,6 +351,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, + VE_DEC_H265_DEC_SPS_HDR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE(sps->log2_diff_max_min_luma_coding_block_size) | + VE_DEC_H265_DEC_SPS_HDR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3(sps->log2_min_luma_coding_block_size_minus3) | + VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_CHROMA_MINUS8(sps->bit_depth_chroma_minus8) | ++ VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_LUMA_MINUS8(sps->bit_depth_luma_minus8) | + VE_DEC_H265_DEC_SPS_HDR_CHROMA_FORMAT_IDC(sps->chroma_format_idc); + + reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SPS_HDR_FLAG_STRONG_INTRA_SMOOTHING_ENABLE, +-- +2.24.1 + diff --git a/projects/Allwinner/patches/linux/0005-cedrus-improvements.patch b/projects/Allwinner/patches/linux/0005-cedrus-improvements.patch index adc9029777..196868a3e0 100644 --- a/projects/Allwinner/patches/linux/0005-cedrus-improvements.patch +++ b/projects/Allwinner/patches/linux/0005-cedrus-improvements.patch @@ -485,104 +485,6 @@ index 15cf1f10221b..497b1199d3fe 100644 2.24.0 -From 3be57e9b0d05bbe59aa60eb037d46b523a8a4103 Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Sun, 3 Nov 2019 12:36:52 +0100 -Subject: [PATCH 08/14] media: cedrus: Fix decoding for some HEVC videos - -It seems that for some HEVC videos at least one bitstream parsing -trigger must be called in order to be decoded correctly. There is no -explanation why this helps, but it was observed that several videos -with this fix are now decoded correctly and there is no regression with -others. - -Without this fix, those same videos totaly crash HEVC decoder (others -are unaffected). After decoding those problematic videos, HEVC decoder -always returns only green image (all zeros). Only complete HW reset -helps. - -This fix is similar to that for H264. - -Signed-off-by: Jernej Skrabec ---- - .../staging/media/sunxi/cedrus/cedrus_h265.c | 25 ++++++++++++++++--- - .../staging/media/sunxi/cedrus/cedrus_regs.h | 1 + - 2 files changed, 23 insertions(+), 3 deletions(-) - -diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c -index 109d3289418c..5a207f1e137c 100644 ---- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c -+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c -@@ -7,6 +7,7 @@ - * Copyright (C) 2018 Bootlin - */ - -+#include - #include - - #include -@@ -283,6 +284,23 @@ static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx, - } - } - -+static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num) -+{ -+ int count = 0; -+ -+ while (count < num) { -+ int tmp = min(num - count, 32); -+ -+ cedrus_write(dev, VE_DEC_H265_TRIGGER, -+ VE_DEC_H265_TRIGGER_FLUSH_BITS | -+ VE_DEC_H265_TRIGGER_TYPE_N_BITS(tmp)); -+ while (cedrus_read(dev, VE_DEC_H265_STATUS) & VE_DEC_H265_STATUS_VLD_BUSY) -+ udelay(1); -+ -+ count += tmp; -+ } -+} -+ - static void cedrus_h265_setup(struct cedrus_ctx *ctx, - struct cedrus_run *run) - { -@@ -347,10 +365,9 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, - - /* Source offset and length in bits. */ - -- reg = slice_params->data_bit_offset; -- cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, reg); -+ cedrus_write(dev, VE_DEC_H265_BITS_OFFSET, 0); - -- reg = slice_params->bit_size - slice_params->data_bit_offset; -+ reg = slice_params->bit_size; - cedrus_write(dev, VE_DEC_H265_BITS_LEN, reg); - - /* Source beginning and end addresses. */ -@@ -385,6 +402,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, - /* Initialize bitstream access. */ - cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC); - -+ cedrus_h265_skip_bits(dev, slice_params->data_bit_offset); -+ - /* Bitstream parameters. */ - - reg = VE_DEC_H265_DEC_NAL_HDR_NAL_UNIT_TYPE(slice_params->nal_unit_type) | -diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h -index 0d9449fe2b28..df1cceef8d93 100644 ---- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h -+++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h -@@ -424,6 +424,7 @@ - - #define VE_DEC_H265_TRIGGER (VE_ENGINE_DEC_H265 + 0x34) - -+#define VE_DEC_H265_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8) - #define VE_DEC_H265_TRIGGER_STCD_VC1 (0x02 << 4) - #define VE_DEC_H265_TRIGGER_STCD_AVS (0x01 << 4) - #define VE_DEC_H265_TRIGGER_STCD_HEVC (0x00 << 4) --- -2.24.0 - - From cf4ceb6095f67569dc22b09a150176d42ded09a5 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sat, 26 Oct 2019 21:23:55 +0200 @@ -874,32 +776,6 @@ index ab83a6f1f921..b0ee4aed79f9 100644 2.24.0 -From 6c1b98710d93611eec39bbcfcf07b3fc48e11459 Mon Sep 17 00:00:00 2001 -From: Jernej Skrabec -Date: Sat, 9 Nov 2019 11:50:40 +0100 -Subject: [PATCH 11/14] media: cedrus: hevc: Add luma bit depth - -Signed-off-by: Jernej Skrabec ---- - drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c -index 97dce6ffbbc5..89e269cc066d 100644 ---- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c -+++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c -@@ -483,6 +483,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, - VE_DEC_H265_DEC_SPS_HDR_LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE(sps->log2_diff_max_min_luma_coding_block_size) | - VE_DEC_H265_DEC_SPS_HDR_LOG2_MIN_LUMA_CODING_BLOCK_SIZE_MINUS3(sps->log2_min_luma_coding_block_size_minus3) | - VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_CHROMA_MINUS8(sps->bit_depth_chroma_minus8) | -+ VE_DEC_H265_DEC_SPS_HDR_BIT_DEPTH_LUMA_MINUS8(sps->bit_depth_luma_minus8) | - VE_DEC_H265_DEC_SPS_HDR_CHROMA_FORMAT_IDC(sps->chroma_format_idc); - - reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_SPS_HDR_FLAG_STRONG_INTRA_SMOOTHING_ENABLE, --- -2.24.0 - - From 187e20b079317e312a1be425ff4c19f838b9e625 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sat, 9 Nov 2019 13:06:15 +0100 diff --git a/projects/Allwinner/patches/linux/0007-thermal.patch b/projects/Allwinner/patches/linux/0007-thermal.patch deleted file mode 100644 index bcffc19158..0000000000 --- a/projects/Allwinner/patches/linux/0007-thermal.patch +++ /dev/null @@ -1,946 +0,0 @@ -From 6be5a0d1823f83f64f38276c7c7e020011da60c8 Mon Sep 17 00:00:00 2001 -From: Yangtao Li -Date: Sat, 10 Aug 2019 05:28:12 +0000 -Subject: [PATCH 1/7] thermal: sun8i: add thermal driver for - H6/H5/H3/A64/A83T/R40 - -This patch adds the support for allwinner thermal sensor, within -allwinner SoC. It will register sensors for thermal framework -and use device tree to bind cooling device. - -Signed-off-by: Yangtao Li -Signed-off-by: Ondrej Jirman -Signed-off-by: Vasily Khoruzhick -Acked-by: Maxime Ripard ---- - MAINTAINERS | 8 + - drivers/thermal/Kconfig | 14 + - drivers/thermal/Makefile | 1 + - drivers/thermal/sun8i_thermal.c | 639 ++++++++++++++++++++++++++++++++ - 4 files changed, 662 insertions(+) - create mode 100644 drivers/thermal/sun8i_thermal.c - -diff --git a/MAINTAINERS b/MAINTAINERS -index a049abccaa269..50535a18379ae 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -694,6 +694,14 @@ L: linux-crypto@vger.kernel.org - S: Maintained - F: drivers/crypto/allwinner/ - -+ALLWINNER THERMAL DRIVER -+M: Vasily Khoruzhick -+M: Yangtao Li -+L: linux-pm@vger.kernel.org -+S: Maintained -+F: Documentation/devicetree/bindings/thermal/allwinner,sun8i-a83t-ths.yaml -+F: drivers/thermal/sun8i_thermal.c -+ - ALLWINNER VPU DRIVER - M: Maxime Ripard - M: Paul Kocialkowski -diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig -index 79b27865c6f42..8cef77fdef5ab 100644 ---- a/drivers/thermal/Kconfig -+++ b/drivers/thermal/Kconfig -@@ -263,6 +263,20 @@ config SPEAR_THERMAL - Enable this to plug the SPEAr thermal sensor driver into the Linux - thermal framework. - -+config SUN8I_THERMAL -+ tristate "Allwinner sun8i thermal driver" -+ depends on ARCH_SUNXI || COMPILE_TEST -+ depends on HAS_IOMEM -+ depends on NVMEM -+ depends on OF -+ depends on RESET_CONTROLLER -+ help -+ Support for the sun8i thermal sensor driver into the Linux thermal -+ framework. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called sun8i-thermal. -+ - config ROCKCHIP_THERMAL - tristate "Rockchip thermal driver" - depends on ARCH_ROCKCHIP || COMPILE_TEST -diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile -index baeb70bf0568c..939301195b9ee 100644 ---- a/drivers/thermal/Makefile -+++ b/drivers/thermal/Makefile -@@ -31,6 +31,7 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o - obj-y += broadcom/ - obj-$(CONFIG_THERMAL_MMIO) += thermal_mmio.o - obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o -+obj-$(CONFIG_SUN8I_THERMAL) += sun8i_thermal.o - obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o - obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o - obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o -diff --git a/drivers/thermal/sun8i_thermal.c b/drivers/thermal/sun8i_thermal.c -new file mode 100644 -index 0000000000000..639a06061305c ---- /dev/null -+++ b/drivers/thermal/sun8i_thermal.c -@@ -0,0 +1,639 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Thermal sensor driver for Allwinner SOC -+ * Copyright (C) 2019 Yangtao Li -+ * -+ * Based on the work of Icenowy Zheng -+ * Based on the work of Ondrej Jirman -+ * Based on the work of Josef Gajdusek -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define MAX_SENSOR_NUM 4 -+ -+#define FT_TEMP_MASK GENMASK(11, 0) -+#define TEMP_CALIB_MASK GENMASK(11, 0) -+#define CALIBRATE_DEFAULT 0x800 -+ -+#define SUN8I_THS_CTRL0 0x00 -+#define SUN8I_THS_CTRL2 0x40 -+#define SUN8I_THS_IC 0x44 -+#define SUN8I_THS_IS 0x48 -+#define SUN8I_THS_MFC 0x70 -+#define SUN8I_THS_TEMP_CALIB 0x74 -+#define SUN8I_THS_TEMP_DATA 0x80 -+ -+#define SUN50I_THS_CTRL0 0x00 -+#define SUN50I_H6_THS_ENABLE 0x04 -+#define SUN50I_H6_THS_PC 0x08 -+#define SUN50I_H6_THS_DIC 0x10 -+#define SUN50I_H6_THS_DIS 0x20 -+#define SUN50I_H6_THS_MFC 0x30 -+#define SUN50I_H6_THS_TEMP_CALIB 0xa0 -+#define SUN50I_H6_THS_TEMP_DATA 0xc0 -+ -+#define SUN8I_THS_CTRL0_T_ACQ0(x) (GENMASK(15, 0) & (x)) -+#define SUN8I_THS_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) & (x)) << 16) -+#define SUN8I_THS_DATA_IRQ_STS(x) BIT(x + 8) -+ -+#define SUN50I_THS_CTRL0_T_ACQ(x) ((GENMASK(15, 0) & (x)) << 16) -+#define SUN50I_THS_FILTER_EN BIT(2) -+#define SUN50I_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x)) -+#define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12) -+#define SUN50I_H6_THS_DATA_IRQ_STS(x) BIT(x) -+ -+/* millidegree celsius */ -+#define THS_EFUSE_CP_FT_MASK 0x3000 -+#define THS_EFUSE_CP_FT_BIT 12 -+#define THS_CALIBRATION_IN_FT 1 -+ -+struct tsensor { -+ struct ths_device *tmdev; -+ struct thermal_zone_device *tzd; -+ int id; -+}; -+ -+struct ths_thermal_chip { -+ bool has_mod_clk; -+ bool has_bus_clk_reset; -+ int sensor_num; -+ int offset; -+ int scale; -+ int ft_deviation; -+ int temp_data_base; -+ int (*calibrate)(struct ths_device *tmdev, -+ u16 *caldata, int callen); -+ int (*init)(struct ths_device *tmdev); -+ int (*irq_ack)(struct ths_device *tmdev); -+ int (*calc_temp)(struct ths_device *tmdev, -+ int id, int reg); -+}; -+ -+struct ths_device { -+ const struct ths_thermal_chip *chip; -+ struct device *dev; -+ struct regmap *regmap; -+ struct reset_control *reset; -+ struct clk *bus_clk; -+ struct clk *mod_clk; -+ struct tsensor sensor[MAX_SENSOR_NUM]; -+ u32 cp_ft_flag; -+}; -+ -+/* Temp Unit: millidegree Celsius */ -+static int sun8i_ths_calc_temp(struct ths_device *tmdev, -+ int id, int reg) -+{ -+ return tmdev->chip->offset - (reg * tmdev->chip->scale / 10); -+} -+ -+static int sun50i_h5_calc_temp(struct ths_device *tmdev, -+ int id, int reg) -+{ -+ if (reg >= 0x500) -+ return -1191 * reg / 10 + 223000; -+ else if (!id) -+ return -1452 * reg / 10 + 259000; -+ else -+ return -1590 * reg / 10 + 276000; -+} -+ -+static int sun8i_ths_get_temp(void *data, int *temp) -+{ -+ struct tsensor *s = data; -+ struct ths_device *tmdev = s->tmdev; -+ int val = 0; -+ -+ regmap_read(tmdev->regmap, tmdev->chip->temp_data_base + -+ 0x4 * s->id, &val); -+ -+ /* ths have no data yet */ -+ if (!val) -+ return -EAGAIN; -+ -+ *temp = tmdev->chip->calc_temp(tmdev, s->id, val); -+ /* -+ * According to the original sdk, there are some platforms(rarely) -+ * that add a fixed offset value after calculating the temperature -+ * value. We can't simply put it on the formula for calculating the -+ * temperature above, because the formula for calculating the -+ * temperature above is also used when the sensor is calibrated. If -+ * do this, the correct calibration formula is hard to know. -+ */ -+ *temp += tmdev->chip->ft_deviation; -+ -+ return 0; -+} -+ -+static const struct thermal_zone_of_device_ops ths_ops = { -+ .get_temp = sun8i_ths_get_temp, -+}; -+ -+static const struct regmap_config config = { -+ .reg_bits = 32, -+ .val_bits = 32, -+ .reg_stride = 4, -+ .fast_io = true, -+ .max_register = 0xfc, -+}; -+ -+static int sun8i_h3_irq_ack(struct ths_device *tmdev) -+{ -+ int i, state, ret = 0; -+ -+ regmap_read(tmdev->regmap, SUN8I_THS_IS, &state); -+ -+ for (i = 0; i < tmdev->chip->sensor_num; i++) { -+ if (state & SUN8I_THS_DATA_IRQ_STS(i)) { -+ regmap_write(tmdev->regmap, SUN8I_THS_IS, -+ SUN8I_THS_DATA_IRQ_STS(i)); -+ ret |= BIT(i); -+ } -+ } -+ -+ return ret; -+} -+ -+static int sun50i_h6_irq_ack(struct ths_device *tmdev) -+{ -+ int i, state, ret = 0; -+ -+ regmap_read(tmdev->regmap, SUN50I_H6_THS_DIS, &state); -+ -+ for (i = 0; i < tmdev->chip->sensor_num; i++) { -+ if (state & SUN50I_H6_THS_DATA_IRQ_STS(i)) { -+ regmap_write(tmdev->regmap, SUN50I_H6_THS_DIS, -+ SUN50I_H6_THS_DATA_IRQ_STS(i)); -+ ret |= BIT(i); -+ } -+ } -+ -+ return ret; -+} -+ -+static irqreturn_t sun8i_irq_thread(int irq, void *data) -+{ -+ struct ths_device *tmdev = data; -+ int i, state; -+ -+ state = tmdev->chip->irq_ack(tmdev); -+ -+ for (i = 0; i < tmdev->chip->sensor_num; i++) { -+ if (state & BIT(i)) -+ thermal_zone_device_update(tmdev->sensor[i].tzd, -+ THERMAL_EVENT_UNSPECIFIED); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int sun8i_h3_ths_calibrate(struct ths_device *tmdev, -+ u16 *caldata, int callen) -+{ -+ int i; -+ -+ if (!caldata[0] || callen < 2 * tmdev->chip->sensor_num) -+ return -EINVAL; -+ -+ for (i = 0; i < tmdev->chip->sensor_num; i++) { -+ int offset = (i % 2) << 4; -+ -+ regmap_update_bits(tmdev->regmap, -+ SUN8I_THS_TEMP_CALIB + (4 * (i >> 1)), -+ 0xfff << offset, -+ caldata[i] << offset); -+ } -+ -+ return 0; -+} -+ -+static int sun50i_h6_ths_calibrate(struct ths_device *tmdev, -+ u16 *caldata, int callen) -+{ -+ struct device *dev = tmdev->dev; -+ int i, ft_temp; -+ -+ if (!caldata[0] || callen < 2 + 2 * tmdev->chip->sensor_num) -+ return -EINVAL; -+ -+ /* -+ * efuse layout: -+ * -+ * 0 11 16 32 -+ * +-------+-------+-------+ -+ * |temp| |sensor0|sensor1| -+ * +-------+-------+-------+ -+ * -+ * The calibration data on the H6 is the ambient temperature and -+ * sensor values that are filled during the factory test stage. -+ * -+ * The unit of stored FT temperature is 0.1 degreee celusis. -+ * -+ * We need to calculate a delta between measured and caluclated -+ * register values and this will become a calibration offset. -+ */ -+ ft_temp = (caldata[0] & FT_TEMP_MASK) * 100; -+ tmdev->cp_ft_flag = (caldata[0] & THS_EFUSE_CP_FT_MASK) -+ >> THS_EFUSE_CP_FT_BIT; -+ -+ for (i = 0; i < tmdev->chip->sensor_num; i++) { -+ int sensor_reg = caldata[i + 1]; -+ int cdata, offset; -+ int sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg); -+ -+ /* -+ * Calibration data is CALIBRATE_DEFAULT - (calculated -+ * temperature from sensor reading at factory temperature -+ * minus actual factory temperature) * 14.88 (scale from -+ * temperature to register values) -+ */ -+ cdata = CALIBRATE_DEFAULT - -+ ((sensor_temp - ft_temp) * 10 / tmdev->chip->scale); -+ if (cdata & ~TEMP_CALIB_MASK) { -+ /* -+ * Calibration value more than 12-bit, but calibration -+ * register is 12-bit. In this case, ths hardware can -+ * still work without calibration, although the data -+ * won't be so accurate. -+ */ -+ dev_warn(dev, "sensor%d is not calibrated.\n", i); -+ continue; -+ } -+ -+ offset = (i % 2) * 16; -+ regmap_update_bits(tmdev->regmap, -+ SUN50I_H6_THS_TEMP_CALIB + (i / 2 * 4), -+ 0xfff << offset, -+ cdata << offset); -+ } -+ -+ return 0; -+} -+ -+static int sun8i_ths_calibrate(struct ths_device *tmdev) -+{ -+ struct nvmem_cell *calcell; -+ struct device *dev = tmdev->dev; -+ u16 *caldata; -+ size_t callen; -+ int ret = 0; -+ -+ calcell = devm_nvmem_cell_get(dev, "calibration"); -+ if (IS_ERR(calcell)) { -+ if (PTR_ERR(calcell) == -EPROBE_DEFER) -+ return -EPROBE_DEFER; -+ /* -+ * Even if the external calibration data stored in sid is -+ * not accessible, the THS hardware can still work, although -+ * the data won't be so accurate. -+ * -+ * The default value of calibration register is 0x800 for -+ * every sensor, and the calibration value is usually 0x7xx -+ * or 0x8xx, so they won't be away from the default value -+ * for a lot. -+ * -+ * So here we do not return error if the calibartion data is -+ * not available, except the probe needs deferring. -+ */ -+ goto out; -+ } -+ -+ caldata = nvmem_cell_read(calcell, &callen); -+ if (IS_ERR(caldata)) { -+ ret = PTR_ERR(caldata); -+ goto out; -+ } -+ -+ tmdev->chip->calibrate(tmdev, caldata, callen); -+ -+ kfree(caldata); -+out: -+ return ret; -+} -+ -+static int sun8i_ths_resource_init(struct ths_device *tmdev) -+{ -+ struct device *dev = tmdev->dev; -+ struct platform_device *pdev = to_platform_device(dev); -+ void __iomem *base; -+ int ret; -+ -+ base = devm_platform_ioremap_resource(pdev, 0); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ tmdev->regmap = devm_regmap_init_mmio(dev, base, &config); -+ if (IS_ERR(tmdev->regmap)) -+ return PTR_ERR(tmdev->regmap); -+ -+ if (tmdev->chip->has_bus_clk_reset) { -+ tmdev->reset = devm_reset_control_get(dev, 0); -+ if (IS_ERR(tmdev->reset)) -+ return PTR_ERR(tmdev->reset); -+ -+ tmdev->bus_clk = devm_clk_get(&pdev->dev, "bus"); -+ if (IS_ERR(tmdev->bus_clk)) -+ return PTR_ERR(tmdev->bus_clk); -+ } -+ -+ if (tmdev->chip->has_mod_clk) { -+ tmdev->mod_clk = devm_clk_get(&pdev->dev, "mod"); -+ if (IS_ERR(tmdev->mod_clk)) -+ return PTR_ERR(tmdev->mod_clk); -+ } -+ -+ ret = reset_control_deassert(tmdev->reset); -+ if (ret) -+ return ret; -+ -+ ret = clk_prepare_enable(tmdev->bus_clk); -+ if (ret) -+ goto assert_reset; -+ -+ ret = clk_set_rate(tmdev->mod_clk, 24000000); -+ if (ret) -+ goto bus_disable; -+ -+ ret = clk_prepare_enable(tmdev->mod_clk); -+ if (ret) -+ goto bus_disable; -+ -+ ret = sun8i_ths_calibrate(tmdev); -+ if (ret) -+ goto mod_disable; -+ -+ return 0; -+ -+mod_disable: -+ clk_disable_unprepare(tmdev->mod_clk); -+bus_disable: -+ clk_disable_unprepare(tmdev->bus_clk); -+assert_reset: -+ reset_control_assert(tmdev->reset); -+ -+ return ret; -+} -+ -+static int sun8i_h3_thermal_init(struct ths_device *tmdev) -+{ -+ int val; -+ -+ /* average over 4 samples */ -+ regmap_write(tmdev->regmap, SUN8I_THS_MFC, -+ SUN50I_THS_FILTER_EN | -+ SUN50I_THS_FILTER_TYPE(1)); -+ /* -+ * clkin = 24MHz -+ * filter_samples = 4 -+ * period = 0.25s -+ * -+ * x = period * clkin / 4096 / filter_samples - 1 -+ * = 365 -+ */ -+ val = GENMASK(7 + tmdev->chip->sensor_num, 8); -+ regmap_write(tmdev->regmap, SUN8I_THS_IC, -+ SUN50I_H6_THS_PC_TEMP_PERIOD(365) | val); -+ /* -+ * T_acq = 20us -+ * clkin = 24MHz -+ * -+ * x = T_acq * clkin - 1 -+ * = 479 -+ */ -+ regmap_write(tmdev->regmap, SUN8I_THS_CTRL0, -+ SUN8I_THS_CTRL0_T_ACQ0(479)); -+ val = GENMASK(tmdev->chip->sensor_num - 1, 0); -+ regmap_write(tmdev->regmap, SUN8I_THS_CTRL2, -+ SUN8I_THS_CTRL2_T_ACQ1(479) | val); -+ -+ return 0; -+} -+ -+/* -+ * Without this undocummented value, the returned temperatures would -+ * be higher than real ones by about 20C. -+ */ -+#define SUN50I_H6_CTRL0_UNK 0x0000002f -+ -+static int sun50i_h6_thermal_init(struct ths_device *tmdev) -+{ -+ int val; -+ -+ /* -+ * T_acq = 20us -+ * clkin = 24MHz -+ * -+ * x = T_acq * clkin - 1 -+ * = 479 -+ */ -+ regmap_write(tmdev->regmap, SUN50I_THS_CTRL0, -+ SUN50I_H6_CTRL0_UNK | SUN50I_THS_CTRL0_T_ACQ(479)); -+ /* average over 4 samples */ -+ regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC, -+ SUN50I_THS_FILTER_EN | -+ SUN50I_THS_FILTER_TYPE(1)); -+ /* -+ * clkin = 24MHz -+ * filter_samples = 4 -+ * period = 0.25s -+ * -+ * x = period * clkin / 4096 / filter_samples - 1 -+ * = 365 -+ */ -+ regmap_write(tmdev->regmap, SUN50I_H6_THS_PC, -+ SUN50I_H6_THS_PC_TEMP_PERIOD(365)); -+ /* enable sensor */ -+ val = GENMASK(tmdev->chip->sensor_num - 1, 0); -+ regmap_write(tmdev->regmap, SUN50I_H6_THS_ENABLE, val); -+ /* thermal data interrupt enable */ -+ val = GENMASK(tmdev->chip->sensor_num - 1, 0); -+ regmap_write(tmdev->regmap, SUN50I_H6_THS_DIC, val); -+ -+ return 0; -+} -+ -+static int sun8i_ths_register(struct ths_device *tmdev) -+{ -+ int i; -+ -+ for (i = 0; i < tmdev->chip->sensor_num; i++) { -+ tmdev->sensor[i].tmdev = tmdev; -+ tmdev->sensor[i].id = i; -+ tmdev->sensor[i].tzd = -+ devm_thermal_zone_of_sensor_register(tmdev->dev, -+ i, -+ &tmdev->sensor[i], -+ &ths_ops); -+ if (IS_ERR(tmdev->sensor[i].tzd)) -+ return PTR_ERR(tmdev->sensor[i].tzd); -+ } -+ -+ return 0; -+} -+ -+static int sun8i_ths_probe(struct platform_device *pdev) -+{ -+ struct ths_device *tmdev; -+ struct device *dev = &pdev->dev; -+ int ret, irq; -+ -+ tmdev = devm_kzalloc(dev, sizeof(*tmdev), GFP_KERNEL); -+ if (!tmdev) -+ return -ENOMEM; -+ -+ tmdev->dev = dev; -+ tmdev->chip = of_device_get_match_data(&pdev->dev); -+ if (!tmdev->chip) -+ return -EINVAL; -+ -+ platform_set_drvdata(pdev, tmdev); -+ -+ ret = sun8i_ths_resource_init(tmdev); -+ if (ret) -+ return ret; -+ -+ irq = platform_get_irq(pdev, 0); -+ if (irq < 0) -+ return irq; -+ -+ ret = tmdev->chip->init(tmdev); -+ if (ret) -+ return ret; -+ -+ ret = sun8i_ths_register(tmdev); -+ if (ret) -+ return ret; -+ -+ /* -+ * Avoid entering the interrupt handler, the thermal device is not -+ * registered yet, we deffer the registration of the interrupt to -+ * the end. -+ */ -+ ret = devm_request_threaded_irq(dev, irq, NULL, -+ sun8i_irq_thread, -+ IRQF_ONESHOT, "ths", tmdev); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int sun8i_ths_remove(struct platform_device *pdev) -+{ -+ struct ths_device *tmdev = platform_get_drvdata(pdev); -+ -+ clk_disable_unprepare(tmdev->mod_clk); -+ clk_disable_unprepare(tmdev->bus_clk); -+ reset_control_assert(tmdev->reset); -+ -+ return 0; -+} -+ -+static const struct ths_thermal_chip sun8i_a83t_ths = { -+ .sensor_num = 3, -+ .scale = 705, -+ .offset = 191668, -+ .temp_data_base = SUN8I_THS_TEMP_DATA, -+ .calibrate = sun8i_h3_ths_calibrate, -+ .init = sun8i_h3_thermal_init, -+ .irq_ack = sun8i_h3_irq_ack, -+ .calc_temp = sun8i_ths_calc_temp, -+}; -+ -+static const struct ths_thermal_chip sun8i_h3_ths = { -+ .sensor_num = 1, -+ .scale = 1211, -+ .offset = 217000, -+ .has_mod_clk = true, -+ .has_bus_clk_reset = true, -+ .temp_data_base = SUN8I_THS_TEMP_DATA, -+ .calibrate = sun8i_h3_ths_calibrate, -+ .init = sun8i_h3_thermal_init, -+ .irq_ack = sun8i_h3_irq_ack, -+ .calc_temp = sun8i_ths_calc_temp, -+}; -+ -+static const struct ths_thermal_chip sun8i_r40_ths = { -+ .sensor_num = 3, -+ .offset = 251086, -+ .scale = 1130, -+ .has_mod_clk = true, -+ .has_bus_clk_reset = true, -+ .temp_data_base = SUN8I_THS_TEMP_DATA, -+ .calibrate = sun8i_h3_ths_calibrate, -+ .init = sun8i_h3_thermal_init, -+ .irq_ack = sun8i_h3_irq_ack, -+ .calc_temp = sun8i_ths_calc_temp, -+}; -+ -+static const struct ths_thermal_chip sun50i_a64_ths = { -+ .sensor_num = 3, -+ .offset = 253890, -+ .scale = 1170, -+ .has_mod_clk = true, -+ .has_bus_clk_reset = true, -+ .temp_data_base = SUN8I_THS_TEMP_DATA, -+ .calibrate = sun8i_h3_ths_calibrate, -+ .init = sun8i_h3_thermal_init, -+ .irq_ack = sun8i_h3_irq_ack, -+ .calc_temp = sun8i_ths_calc_temp, -+}; -+ -+static const struct ths_thermal_chip sun50i_h5_ths = { -+ .sensor_num = 2, -+ .has_mod_clk = true, -+ .has_bus_clk_reset = true, -+ .temp_data_base = SUN8I_THS_TEMP_DATA, -+ .calibrate = sun8i_h3_ths_calibrate, -+ .init = sun8i_h3_thermal_init, -+ .irq_ack = sun8i_h3_irq_ack, -+ .calc_temp = sun50i_h5_calc_temp, -+}; -+ -+static const struct ths_thermal_chip sun50i_h6_ths = { -+ .sensor_num = 2, -+ .has_bus_clk_reset = true, -+ .ft_deviation = 7000, -+ .offset = 187744, -+ .scale = 672, -+ .temp_data_base = SUN50I_H6_THS_TEMP_DATA, -+ .calibrate = sun50i_h6_ths_calibrate, -+ .init = sun50i_h6_thermal_init, -+ .irq_ack = sun50i_h6_irq_ack, -+ .calc_temp = sun8i_ths_calc_temp, -+}; -+ -+static const struct of_device_id of_ths_match[] = { -+ { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths }, -+ { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths }, -+ { .compatible = "allwinner,sun8i-r40-ths", .data = &sun8i_r40_ths }, -+ { .compatible = "allwinner,sun50i-a64-ths", .data = &sun50i_a64_ths }, -+ { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths }, -+ { .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths }, -+ { /* sentinel */ }, -+}; -+MODULE_DEVICE_TABLE(of, of_ths_match); -+ -+static struct platform_driver ths_driver = { -+ .probe = sun8i_ths_probe, -+ .remove = sun8i_ths_remove, -+ .driver = { -+ .name = "sun8i-thermal", -+ .of_match_table = of_ths_match, -+ }, -+}; -+module_platform_driver(ths_driver); -+ -+MODULE_DESCRIPTION("Thermal sensor driver for Allwinner SOC"); -+MODULE_LICENSE("GPL v2"); - -From 5cee221232537ac4843034517709c894398d50e6 Mon Sep 17 00:00:00 2001 -From: Ondrej Jirman -Date: Sun, 1 Sep 2019 19:47:55 +0200 -Subject: [PATCH 4/7] ARM: dts: sun8i-h3: Add thermal sensor and thermal zones - -There is just one sensor for the CPU. - -Signed-off-by: Ondrej Jirman -Signed-off-by: Vasily Khoruzhick ---- - arch/arm/boot/dts/sun8i-h3.dtsi | 20 ++++++++++++++++++++ - arch/arm/boot/dts/sunxi-h3-h5.dtsi | 6 ++++++ - 2 files changed, 26 insertions(+) - -diff --git a/arch/arm/boot/dts/sun8i-h3.dtsi b/arch/arm/boot/dts/sun8i-h3.dtsi -index fe773c72a69b7..be8f601ab8cf7 100644 ---- a/arch/arm/boot/dts/sun8i-h3.dtsi -+++ b/arch/arm/boot/dts/sun8i-h3.dtsi -@@ -199,6 +199,26 @@ - assigned-clocks = <&ccu CLK_GPU>; - assigned-clock-rates = <384000000>; - }; -+ -+ ths: thermal-sensor@1c25000 { -+ compatible = "allwinner,sun8i-h3-ths"; -+ reg = <0x01c25000 0x400>; -+ interrupts = ; -+ resets = <&ccu RST_BUS_THS>; -+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>; -+ clock-names = "bus", "mod"; -+ nvmem-cells = <&ths_calibration>; -+ nvmem-cell-names = "calibration"; -+ #thermal-sensor-cells = <0>; -+ }; -+ }; -+ -+ thermal-zones { -+ cpu_thermal: cpu-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&ths 0>; -+ }; - }; - }; - -diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi -index 0afea59486c24..6e68ed8310159 100644 ---- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi -+++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi -@@ -231,6 +231,12 @@ - sid: eeprom@1c14000 { - /* compatible is in per SoC .dtsi file */ - reg = <0x1c14000 0x400>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ ths_calibration: thermal-sensor-calibration@34 { -+ reg = <0x34 4>; -+ }; - }; - - usb_otg: usb@1c19000 { - -From eb01e1bd43602faba360a93c7aaee42637e58284 Mon Sep 17 00:00:00 2001 -From: Ondrej Jirman -Date: Sun, 1 Sep 2019 01:05:46 +0200 -Subject: [PATCH 6/7] arm64: dts: allwinner: h6: Add thermal sensor and thermal - zones - -There are two sensors, one for CPU, one for GPU. - -Signed-off-by: Ondrej Jirman -Signed-off-by: Vasily Khoruzhick ---- - arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 33 ++++++++++++++++++++ - 1 file changed, 33 insertions(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -index 29824081b43b0..345a4c851c8d9 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -+++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - - / { - interrupt-parent = <&gic>; -@@ -233,6 +234,12 @@ - sid: efuse@3006000 { - compatible = "allwinner,sun50i-h6-sid"; - reg = <0x03006000 0x400>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ ths_calibration: thermal-sensor-calibration@14 { -+ reg = <0x14 0x8>; -+ }; - }; - - watchdog: watchdog@30090a0 { -@@ -856,5 +863,31 @@ - #address-cells = <1>; - #size-cells = <0>; - }; -+ -+ ths: thermal-sensor@5070400 { -+ compatible = "allwinner,sun50i-h6-ths"; -+ reg = <0x05070400 0x100>; -+ interrupts = ; -+ clocks = <&ccu CLK_BUS_THS>; -+ clock-names = "bus"; -+ resets = <&ccu RST_BUS_THS>; -+ nvmem-cells = <&ths_calibration>; -+ nvmem-cell-names = "calibration"; -+ #thermal-sensor-cells = <1>; -+ }; -+ }; -+ -+ thermal-zones { -+ cpu-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&ths 0>; -+ }; -+ -+ gpu-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&ths 1>; -+ }; - }; - }; - -From cec68b6c7aed4739a725178c7c33a04d859b37c8 Mon Sep 17 00:00:00 2001 -From: Vasily Khoruzhick -Date: Sat, 13 Jul 2019 09:54:31 -0700 -Subject: [PATCH 7/7] arm64: dts: allwinner: a64: Add thermal sensors and - thermal zones - -A64 has 3 thermal sensors: 1 for CPU, 2 for GPU. - -Signed-off-by: Vasily Khoruzhick ---- - arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 42 +++++++++++++++++++ - 1 file changed, 42 insertions(+) - -diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi -index 27e48234f1c23..5e3f16c3b706c 100644 ---- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi -+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi -@@ -49,6 +49,7 @@ - #include - #include - #include -+#include - - / { - interrupt-parent = <&gic>; -@@ -211,6 +212,29 @@ - (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>; - }; - -+ thermal-zones { -+ cpu_thermal: cpu0-thermal { -+ /* milliseconds */ -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&ths 0>; -+ }; -+ -+ gpu0_thermal: gpu0-thermal { -+ /* milliseconds */ -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&ths 1>; -+ }; -+ -+ gpu1_thermal: gpu1-thermal { -+ /* milliseconds */ -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&ths 2>; -+ }; -+ }; -+ - soc { - compatible = "simple-bus"; - #address-cells = <1>; -@@ -485,6 +509,12 @@ - sid: eeprom@1c14000 { - compatible = "allwinner,sun50i-a64-sid"; - reg = <0x1c14000 0x400>; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ -+ ths_calibration: thermal-sensor-calibration@34 { -+ reg = <0x34 0x8>; -+ }; - }; - - crypto: crypto@1c15000 { -@@ -810,6 +840,18 @@ - status = "disabled"; - }; - -+ ths: thermal-sensor@1c25000 { -+ compatible = "allwinner,sun50i-a64-ths"; -+ reg = <0x01c25000 0x100>; -+ clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>; -+ clock-names = "bus", "mod"; -+ interrupts = ; -+ resets = <&ccu RST_BUS_THS>; -+ nvmem-cells = <&ths_calibration>; -+ nvmem-cell-names = "calibration"; -+ #thermal-sensor-cells = <1>; -+ }; -+ - uart0: serial@1c28000 { - compatible = "snps,dw-apb-uart"; - reg = <0x01c28000 0x400>; diff --git a/projects/Allwinner/patches/linux/0012-H6-USB3.patch b/projects/Allwinner/patches/linux/0012-H6-USB3.patch deleted file mode 100644 index 49c10afe6d..0000000000 --- a/projects/Allwinner/patches/linux/0012-H6-USB3.patch +++ /dev/null @@ -1,252 +0,0 @@ -From d996492e1f700a9f0a104c50b126a022dee77dd6 Mon Sep 17 00:00:00 2001 -From: Icenowy Zheng -Date: Mon, 25 Dec 2017 12:04:02 +0800 -Subject: [PATCH 20/34] phy: allwinner: add phy driver for USB3 PHY on - Allwinner H6 SoC - -Allwinner H6 SoC contains a USB3 PHY (with USB2 DP/DM lines also -controlled). - -Add a driver for it. - -The register operations in this driver is mainly extracted from the BSP -USB3 driver. - -Signed-off-by: Icenowy Zheng -Reviewed-by: Chen-Yu Tsai ---- - drivers/phy/allwinner/Kconfig | 12 ++ - drivers/phy/allwinner/Makefile | 1 + - drivers/phy/allwinner/phy-sun50i-usb3.c | 194 ++++++++++++++++++++++++ - 3 files changed, 207 insertions(+) - create mode 100644 drivers/phy/allwinner/phy-sun50i-usb3.c - -diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig -index fb1204bcc4548..2c363db177f20 100644 ---- a/drivers/phy/allwinner/Kconfig -+++ b/drivers/phy/allwinner/Kconfig -@@ -41,3 +41,15 @@ config PHY_SUN9I_USB - sun9i SoCs. - - This driver controls each individual USB 2 host PHY. -+ -+config PHY_SUN50I_USB3 -+ tristate "Allwinner sun50i SoC USB3 PHY driver" -+ depends on ARCH_SUNXI && HAS_IOMEM && OF -+ depends on RESET_CONTROLLER -+ select USB_COMMON -+ select GENERIC_PHY -+ help -+ Enable this to support the USB3.0-capable transceiver that is -+ part of some Allwinner sun50i SoCs. -+ -+ This driver controls each individual USB 2+3 host PHY combo. -diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile -index 7d0053efbfaa6..59575a895779b 100644 ---- a/drivers/phy/allwinner/Makefile -+++ b/drivers/phy/allwinner/Makefile -@@ -1,3 +1,4 @@ - obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o - obj-$(CONFIG_PHY_SUN6I_MIPI_DPHY) += phy-sun6i-mipi-dphy.o - obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o -+obj-$(CONFIG_PHY_SUN50I_USB3) += phy-sun50i-usb3.o -diff --git a/drivers/phy/allwinner/phy-sun50i-usb3.c b/drivers/phy/allwinner/phy-sun50i-usb3.c -new file mode 100644 -index 0000000000000..226c99c2d664c ---- /dev/null -+++ b/drivers/phy/allwinner/phy-sun50i-usb3.c -@@ -0,0 +1,194 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Allwinner sun50i(H6) USB 3.0 phy driver -+ * -+ * Copyright (C) 2017 Icenowy Zheng -+ * -+ * Based on phy-sun9i-usb.c, which is: -+ * -+ * Copyright (C) 2014-2015 Chen-Yu Tsai -+ * -+ * Based on code from Allwinner BSP, which is: -+ * -+ * Copyright (c) 2010-2015 Allwinner Technology Co., Ltd. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Interface Status and Control Registers */ -+#define SUNXI_ISCR 0x00 -+#define SUNXI_PIPE_CLOCK_CONTROL 0x14 -+#define SUNXI_PHY_TUNE_LOW 0x18 -+#define SUNXI_PHY_TUNE_HIGH 0x1c -+#define SUNXI_PHY_EXTERNAL_CONTROL 0x20 -+ -+/* USB2.0 Interface Status and Control Register */ -+#define SUNXI_ISCR_FORCE_VBUS (3 << 12) -+ -+/* PIPE Clock Control Register */ -+#define SUNXI_PCC_PIPE_CLK_OPEN (1 << 6) -+ -+/* PHY External Control Register */ -+#define SUNXI_PEC_EXTERN_VBUS (3 << 1) -+#define SUNXI_PEC_SSC_EN (1 << 24) -+#define SUNXI_PEC_REF_SSP_EN (1 << 26) -+ -+/* PHY Tune High Register */ -+#define SUNXI_TX_DEEMPH_3P5DB(n) ((n) << 19) -+#define SUNXI_TX_DEEMPH_3P5DB_MASK GENMASK(24, 19) -+#define SUNXI_TX_DEEMPH_6DB(n) ((n) << 13) -+#define SUNXI_TX_DEEMPH_6GB_MASK GENMASK(18, 13) -+#define SUNXI_TX_SWING_FULL(n) ((n) << 6) -+#define SUNXI_TX_SWING_FULL_MASK GENMASK(12, 6) -+#define SUNXI_LOS_BIAS(n) ((n) << 3) -+#define SUNXI_LOS_BIAS_MASK GENMASK(5, 3) -+#define SUNXI_TXVBOOSTLVL(n) ((n) << 0) -+#define SUNXI_TXVBOOSTLVL_MASK GENMASK(0, 2) -+ -+struct sun50i_usb3_phy { -+ struct phy *phy; -+ void __iomem *regs; -+ struct reset_control *reset; -+ struct clk *clk; -+}; -+ -+static void sun50i_usb3_phy_open(struct sun50i_usb3_phy *phy) -+{ -+ u32 val; -+ -+ val = readl(phy->regs + SUNXI_PHY_EXTERNAL_CONTROL); -+ val |= SUNXI_PEC_EXTERN_VBUS; -+ val |= SUNXI_PEC_SSC_EN | SUNXI_PEC_REF_SSP_EN; -+ writel(val, phy->regs + SUNXI_PHY_EXTERNAL_CONTROL); -+ -+ val = readl(phy->regs + SUNXI_PIPE_CLOCK_CONTROL); -+ val |= SUNXI_PCC_PIPE_CLK_OPEN; -+ writel(val, phy->regs + SUNXI_PIPE_CLOCK_CONTROL); -+ -+ val = readl(phy->regs + SUNXI_ISCR); -+ val |= SUNXI_ISCR_FORCE_VBUS; -+ writel(val, phy->regs + SUNXI_ISCR); -+ -+ /* -+ * All the magic numbers written to the PHY_TUNE_{LOW_HIGH} -+ * registers are directly taken from the BSP USB3 driver from -+ * Allwiner. -+ */ -+ writel(0x0047fc87, phy->regs + SUNXI_PHY_TUNE_LOW); -+ -+ val = readl(phy->regs + SUNXI_PHY_TUNE_HIGH); -+ val &= ~(SUNXI_TXVBOOSTLVL_MASK | SUNXI_LOS_BIAS_MASK | -+ SUNXI_TX_SWING_FULL_MASK | SUNXI_TX_DEEMPH_6GB_MASK | -+ SUNXI_TX_DEEMPH_3P5DB_MASK); -+ val |= SUNXI_TXVBOOSTLVL(0x7); -+ val |= SUNXI_LOS_BIAS(0x7); -+ val |= SUNXI_TX_SWING_FULL(0x55); -+ val |= SUNXI_TX_DEEMPH_6DB(0x20); -+ val |= SUNXI_TX_DEEMPH_3P5DB(0x15); -+ writel(val, phy->regs + SUNXI_PHY_TUNE_HIGH); -+} -+ -+static int sun50i_usb3_phy_init(struct phy *_phy) -+{ -+ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy); -+ int ret; -+ -+ ret = clk_prepare_enable(phy->clk); -+ if (ret) -+ goto err_clk; -+ -+ ret = reset_control_deassert(phy->reset); -+ if (ret) -+ goto err_reset; -+ -+ sun50i_usb3_phy_open(phy); -+ return 0; -+ -+err_reset: -+ clk_disable_unprepare(phy->clk); -+ -+err_clk: -+ return ret; -+} -+ -+static int sun50i_usb3_phy_exit(struct phy *_phy) -+{ -+ struct sun50i_usb3_phy *phy = phy_get_drvdata(_phy); -+ -+ reset_control_assert(phy->reset); -+ clk_disable_unprepare(phy->clk); -+ -+ return 0; -+} -+ -+static const struct phy_ops sun50i_usb3_phy_ops = { -+ .init = sun50i_usb3_phy_init, -+ .exit = sun50i_usb3_phy_exit, -+ .owner = THIS_MODULE, -+}; -+ -+static int sun50i_usb3_phy_probe(struct platform_device *pdev) -+{ -+ struct sun50i_usb3_phy *phy; -+ struct device *dev = &pdev->dev; -+ struct phy_provider *phy_provider; -+ struct resource *res; -+ -+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); -+ if (!phy) -+ return -ENOMEM; -+ -+ phy->clk = devm_clk_get(dev, NULL); -+ if (IS_ERR(phy->clk)) { -+ dev_err(dev, "failed to get phy clock\n"); -+ return PTR_ERR(phy->clk); -+ } -+ -+ phy->reset = devm_reset_control_get(dev, NULL); -+ if (IS_ERR(phy->reset)) { -+ dev_err(dev, "failed to get reset control\n"); -+ return PTR_ERR(phy->reset); -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ phy->regs = devm_ioremap_resource(dev, res); -+ if (IS_ERR(phy->regs)) -+ return PTR_ERR(phy->regs); -+ -+ phy->phy = devm_phy_create(dev, NULL, &sun50i_usb3_phy_ops); -+ if (IS_ERR(phy->phy)) { -+ dev_err(dev, "failed to create PHY\n"); -+ return PTR_ERR(phy->phy); -+ } -+ -+ phy_set_drvdata(phy->phy, phy); -+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); -+ -+ return PTR_ERR_OR_ZERO(phy_provider); -+} -+ -+static const struct of_device_id sun50i_usb3_phy_of_match[] = { -+ { .compatible = "allwinner,sun50i-h6-usb3-phy" }, -+ { }, -+}; -+MODULE_DEVICE_TABLE(of, sun50i_usb3_phy_of_match); -+ -+static struct platform_driver sun50i_usb3_phy_driver = { -+ .probe = sun50i_usb3_phy_probe, -+ .driver = { -+ .of_match_table = sun50i_usb3_phy_of_match, -+ .name = "sun50i-usb3-phy", -+ } -+}; -+module_platform_driver(sun50i_usb3_phy_driver); -+ -+MODULE_DESCRIPTION("Allwinner sun50i USB 3.0 phy driver"); -+MODULE_AUTHOR("Icenowy Zheng "); -+MODULE_LICENSE("GPL");