diff options
author | Zoltan HERPAI <wigyori@uid0.hu> | 2020-04-24 09:58:53 +0200 |
---|---|---|
committer | Zoltan HERPAI <wigyori@uid0.hu> | 2021-04-11 23:14:55 +0200 |
commit | 3225241c2bc61e907ea2980cd2f14ea6589cdf2d (patch) | |
tree | ba2c6a1e637ac8a24c3f03449157b314a290c342 | |
parent | c2163530db3c95745c822e4a573a220ba9f98ca7 (diff) | |
download | upstream-3225241c2bc61e907ea2980cd2f14ea6589cdf2d.tar.gz upstream-3225241c2bc61e907ea2980cd2f14ea6589cdf2d.tar.bz2 upstream-3225241c2bc61e907ea2980cd2f14ea6589cdf2d.zip |
sunxi: add support for H6 boards and OrangePiOnePlus
Specifications:
SoC Allwinner H6 @ 1.8 Ghz
DRAM 1Gb LPDDR3
Power DC 5V @ 3A
Video HDMI (Type 2.0A - full)
Audio HDMI, on-board microphone
Network 10/100/1000Mbps Ethernet (Realtek RTL8211)
Storage microSD
USB 1 USB2.0 Host, 1 USB2.0 OTG
Debug Serial UART
Flashing instructions:
Standard sunxi SD card installation procedure - copy image to SD card,
insert into SD card slot on the device and boot.
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
8 files changed, 531 insertions, 2 deletions
diff --git a/package/boot/arm-trusted-firmware-sunxi/Makefile b/package/boot/arm-trusted-firmware-sunxi/Makefile index e2a11c8bd7..0abfbae750 100644 --- a/package/boot/arm-trusted-firmware-sunxi/Makefile +++ b/package/boot/arm-trusted-firmware-sunxi/Makefile @@ -37,6 +37,11 @@ define Package/arm-trusted-firmware-sunxi-a64 VARIANT:=sun50i_a64 endef +define Package/arm-trusted-firmware-sunxi-h6 + $(call Package/arm-trusted-firmware-sunxi/Default) + VARIANT:=sun50i_h6 +endef + export GCC_HONOUR_COPTS=s MAKE_VARS = \ @@ -55,3 +60,4 @@ define Package/arm-trusted-firmware-sunxi/install endef $(eval $(call BuildPackage,arm-trusted-firmware-sunxi-a64)) +$(eval $(call BuildPackage,arm-trusted-firmware-sunxi-h6)) diff --git a/package/boot/uboot-sunxi/Makefile b/package/boot/uboot-sunxi/Makefile index 18288cdd3a..17f1c0d158 100644 --- a/package/boot/uboot-sunxi/Makefile +++ b/package/boot/uboot-sunxi/Makefile @@ -204,6 +204,15 @@ define U-Boot/orangepi_one BUILD_DEVICES:=xunlong_orangepi-one endef +define U-Boot/orangepi_one_plus + BUILD_SUBTARGET:=cortexa53 + NAME:=Orange Pi One Plus (H6) + DEPENDS:=+PACKAGE_u-boot-orangepi_one_plus:arm-trusted-firmware-sunxi-h6 + BUILD_DEVICES:=xunlong_orangepi-one-plus + UENV:=h6 + ATF:=h6 +endef + define U-Boot/orangepi_pc BUILD_SUBTARGET:=cortexa7 NAME:=Orange Pi PC (H3) @@ -344,6 +353,7 @@ UBOOT_TARGETS := \ orangepi_zero \ orangepi_r1 \ orangepi_one \ + orangepi_one_plus \ orangepi_pc \ orangepi_pc_plus \ orangepi_plus \ diff --git a/package/boot/uboot-sunxi/uEnv-h6.txt b/package/boot/uboot-sunxi/uEnv-h6.txt new file mode 100644 index 0000000000..78810ff223 --- /dev/null +++ b/package/boot/uboot-sunxi/uEnv-h6.txt @@ -0,0 +1,7 @@ +setenv mmc_rootpart 2 +part uuid mmc ${mmc_bootdev}:${mmc_rootpart} uuid +setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_addr_r uImage +setenv loaddtb fatload mmc \$mmc_bootdev \$fdt_addr_r dtb +setenv bootargs console=ttyS0,115200 earlyprintk root=PARTUUID=${uuid} rootwait +setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \$kernel_addr_r - \$fdt_addr_r +run uenvcmd diff --git a/target/linux/sunxi/image/cortexa53.mk b/target/linux/sunxi/image/cortexa53.mk index fe561d0923..2d18b0b227 100644 --- a/target/linux/sunxi/image/cortexa53.mk +++ b/target/linux/sunxi/image/cortexa53.mk @@ -9,13 +9,18 @@ define Device/sun50i KERNEL := kernel-bin endef +define Device/sun50i-a64 + SOC := sun50i-a64 + $(Device/sun50i) +endef + define Device/sun50i-h5 SOC := sun50i-h5 $(Device/sun50i) endef -define Device/sun50i-a64 - SOC := sun50i-a64 +define Device/sun50i-h6 + SOC := sun50i-h6 $(Device/sun50i) endef @@ -79,6 +84,14 @@ define Device/pine64_sopine-baseboard endef TARGET_DEVICES += pine64_sopine-baseboard +define Device/xunlong_orangepi-one-plus + $(Device/sun50i-h6) + DEVICE_VENDOR := Xunlong + DEVICE_MODEL := Orange Pi One Plus + SUNXI_DTS_DIR := allwinner/ +endef +TARGET_DEVICES += xunlong_orangepi-one-plus + define Device/xunlong_orangepi-pc2 DEVICE_VENDOR := Xunlong DEVICE_MODEL := Orange Pi PC 2 diff --git a/target/linux/sunxi/patches-5.4/440-add-h6-pwm.patch b/target/linux/sunxi/patches-5.4/440-add-h6-pwm.patch new file mode 100644 index 0000000000..64ffd719ac --- /dev/null +++ b/target/linux/sunxi/patches-5.4/440-add-h6-pwm.patch @@ -0,0 +1,400 @@ +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 <linux/of_device.h> + #include <linux/platform_device.h> + #include <linux/pwm.h> ++#include <linux/reset.h> + #include <linux/slab.h> + #include <linux/spinlock.h> + #include <linux/time.h> +@@ -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 = { + +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)) { + +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; + +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]) { + +diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c +index e369b5a398f4..07bf7be6074b 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 <alexandre.belloni@free-electrons.com> ++ * ++ * 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 <linux/bitops.h> +@@ -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; ++ } else { ++ 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); + +diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c +index 07bf7be6074b..c394878c7e5d 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 */ + }, diff --git a/target/linux/sunxi/patches-5.4/441-arm64-dts-add-PWM-node.patch b/target/linux/sunxi/patches-5.4/441-arm64-dts-add-PWM-node.patch new file mode 100644 index 0000000000..60e653dcba --- /dev/null +++ b/target/linux/sunxi/patches-5.4/441-arm64-dts-add-PWM-node.patch @@ -0,0 +1,37 @@ +From: Jernej Skrabec <jernej.skrabec@siol.net> + +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 <jernej.skrabec@siol.net> +Signed-off-by: Clément Péron <peron.clem@gmail.com> +--- + 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 29824081b43b..6d4bde488f15 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi +@@ -245,6 +245,16 @@ + 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>; diff --git a/target/linux/sunxi/patches-5.4/442-arm64-dts-orangepi-one-plus-enable-PWM.patch b/target/linux/sunxi/patches-5.4/442-arm64-dts-orangepi-one-plus-enable-PWM.patch new file mode 100644 index 0000000000..d95c3c8987 --- /dev/null +++ b/target/linux/sunxi/patches-5.4/442-arm64-dts-orangepi-one-plus-enable-PWM.patch @@ -0,0 +1,12 @@ +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts +index f335f7482a73..cf684bc7374d 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts +@@ -45,3 +45,7 @@ + reg = <1>; + }; + }; ++ ++&pwm { ++ status = "okay"; ++}; diff --git a/target/linux/sunxi/patches-5.4/443-board-h6-orangepioneplus-fix-missing-ethernet.patch b/target/linux/sunxi/patches-5.4/443-board-h6-orangepioneplus-fix-missing-ethernet.patch new file mode 100644 index 0000000000..5f7974c609 --- /dev/null +++ b/target/linux/sunxi/patches-5.4/443-board-h6-orangepioneplus-fix-missing-ethernet.patch @@ -0,0 +1,44 @@ +diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts +index 12e1756..79139f3 100644 +--- a/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts ++++ b/arch/arm64/boot/dts/allwinner/sun50i-h6-orangepi-one-plus.dts +@@ -9,4 +9,39 @@ + / { + model = "OrangePi One Plus"; + compatible = "xunlong,orangepi-one-plus", "allwinner,sun50i-h6"; ++ ++ aliases { ++ serial0 = &uart0; ++ ethernet0 = &emac; ++ }; ++ ++ reg_gmac_3v3: gmac-3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc-gmac-3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ startup-delay-us = <100000>; ++ enable-active-high; ++ gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>; /* PD6 */ ++ vin-supply = <®_aldo2>; ++ }; ++}; ++ ++ ++&emac { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&ext_rgmii_pins>; ++ phy-mode = "rgmii"; ++ phy-handle = <&ext_rgmii_phy>; ++ phy-supply = <®_gmac_3v3>; ++ allwinner,rx-delay-ps = <200>; ++ allwinner,tx-delay-ps = <200>; ++ status = "okay"; ++}; ++ ++&mdio { ++ ext_rgmii_phy: ethernet-phy@1 { ++ compatible = "ethernet-phy-ieee802.3-c22"; ++ reg = <1>; ++ }; + }; |