diff --git a/Documentation/devicetree/bindings/clock/sun8i-de2.txt b/Documentation/devicetree/bindings/clock/sun8i-de2.txt index 631d27c..a7d558a 100644 --- a/Documentation/devicetree/bindings/clock/sun8i-de2.txt +++ b/Documentation/devicetree/bindings/clock/sun8i-de2.txt @@ -4,22 +4,28 @@ Allwinner Display Engine 2.0 Clock Control Binding Required properties : - compatible: must contain one of the following compatibles: - "allwinner,sun8i-a83t-de2-clk" + - "allwinner,sun8i-h3-de2-clk" - "allwinner,sun8i-v3s-de2-clk" + - "allwinner,sun50i-a64-de2-clk" - "allwinner,sun50i-h5-de2-clk" - reg: Must contain the registers base address and length - clocks: phandle to the clocks feeding the display engine subsystem. Three are needed: - - "mod": the display engine module clock + - "mod": the display engine module clock (on A83T it's the DE PLL) - "bus": the bus clock for the whole display engine subsystem - clock-names: Must contain the clock names described just above - resets: phandle to the reset control for the display engine subsystem. - #clock-cells : must contain 1 - #reset-cells : must contain 1 +Additional required properties for "allwinner,sun50i-a64-de2-clk" : +- allwinner,sram: See Documentation/devicetree/bindings/sram/sunxi-sram.txt, + should be the SRAM C section on A64 SoC. + Example: de2_clocks: clock@1000000 { - compatible = "allwinner,sun8i-a83t-de2-clk"; + compatible = "allwinner,sun8i-h3-de2-clk"; reg = <0x01000000 0x100000>; clocks = <&ccu CLK_BUS_DE>, <&ccu CLK_DE>; diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 9244108..8473992 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -87,18 +87,19 @@ Required properties: * allwinner,sun6i-a31-tcon * allwinner,sun6i-a31s-tcon * allwinner,sun8i-a33-tcon + * allwinner,sun8i-h3-tcon * allwinner,sun8i-v3s-tcon + * allwinner,sun50i-a64-tcon0 + * allwinner,sun50i-a64-tcon1 - reg: base address and size of memory-mapped region - interrupts: interrupt associated to this IP - clocks: phandles to the clocks feeding the TCON. Three are needed: - 'ahb': the interface clocks - - 'tcon-ch0': The clock driving the TCON channel 0 - resets: phandles to the reset controllers driving the encoder - "lcd": the reset line for the TCON channel 0 - clock-names: the clock names mentioned above - reset-names: the reset names mentioned above - - clock-output-names: Name of the pixel clock created - ports: A ports node with endpoint definitions as defined in Documentation/devicetree/bindings/media/video-interfaces.txt. The @@ -112,7 +113,25 @@ Required properties: channel the endpoint is associated to. If that property is not present, the endpoint number will be used as the channel number. -On SoCs other than the A33 and V3s, there is one more clock required: +For the following compatibles: + * allwinner,sun5i-a13-tcon + * allwinner,sun6i-a31-tcon + * allwinner,sun6i-a31s-tcon + * allwinner,sun8i-a33-tcon + * allwinner,sun8i-v3s-tcon + * allwinner,snu50i-a64-tcon0 +there is one more clock and one more property required: + - clocks: + - 'tcon-ch0': The clock driving the TCON channel 0 + - clock-output-names: Name of the pixel clock created + +For the following compatibles: + * allwinner,sun5i-a13-tcon + * allwinner,sun6i-a31-tcon + * allwinner,sun6i-a31s-tcon + * allwinner,sun8i-h3-tcon + * allwinner,sun50i-a64-tcon1 +there is one more clock required: - 'tcon-ch1': The clock driving the TCON channel 1 DRC @@ -207,6 +226,10 @@ supported. Required properties: - compatible: value must be one of: * allwinner,sun8i-v3s-de2-mixer + * allwinner,sun8i-h3-de2-mixer0 + * allwinner,sun8i-h3-de2-mixer1 + * allwinner,sun50i-a64-de2-mixer0 + * allwinner,sun50i-a64-de2-mixer1 - reg: base address and size of the memory-mapped region. - clocks: phandles to the clocks feeding the mixer * bus: the mixer interface clock @@ -218,7 +241,6 @@ Required properties: Documentation/devicetree/bindings/media/video-interfaces.txt. The first port should be the input endpoints, the second one the output - Display Engine Pipeline ----------------------- @@ -233,7 +255,9 @@ Required properties: * allwinner,sun6i-a31-display-engine * allwinner,sun6i-a31s-display-engine * allwinner,sun8i-a33-display-engine + * allwinner,sun8i-h3-display-engine * allwinner,sun8i-v3s-display-engine + * allwinner,sun50i-a64-display-engine - allwinner,pipelines: list of phandle to the display engine frontends (DE 1.0) or mixers (DE 2.0) available. diff --git a/arch/arm64/boot/dts/allwinner/axp803.dtsi b/arch/arm64/boot/dts/allwinner/axp803.dtsi index ff8af52..3a86152 100644 --- a/arch/arm64/boot/dts/allwinner/axp803.dtsi +++ b/arch/arm64/boot/dts/allwinner/axp803.dtsi @@ -49,6 +49,16 @@ interrupt-controller; #interrupt-cells = <1>; + ac_power_supply: ac-power-supply { + compatible = "x-powers,axp221-ac-power-supply"; + status = "disabled"; + }; + + battery_power_supply: battery-power-supply { + compatible = "x-powers,axp803-battery-power-supply"; + status = "disabled"; + }; + regulators { /* Default work frequency for buck regulators */ x-powers,dcdc-freq = <3000>; @@ -147,4 +157,9 @@ regulator-name = "rtc-ldo"; }; }; + + usb_power_supply: usb_power_supply { + compatible = "x-powers,axp803-usb-power-supply"; + status = "disabled"; + }; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts index 45bdbfb..19b6817 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts @@ -66,6 +66,14 @@ }; }; +&de { + status = "okay"; +}; + +&ehci0 { + status = "okay"; +}; + &ehci1 { status = "okay"; }; @@ -75,6 +83,12 @@ pinctrl-0 = <&rgmii_pins>; phy-mode = "rgmii"; phy-handle = <&ext_rgmii_phy>; + phy-supply = <®_dc1sw>; + status = "okay"; +}; + +&hdmi { + hvcc-supply = <®_dldo1>; status = "okay"; }; @@ -88,13 +102,17 @@ bias-pull-up; }; -&mdio { +&external_mdio { ext_rgmii_phy: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22"; reg = <1>; }; }; +&mixer1 { + status = "okay"; +}; + &mmc0 { pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins>; @@ -135,6 +153,10 @@ status = "okay"; }; +&ohci0 { + status = "okay"; +}; + &ohci1 { status = "okay"; }; @@ -152,6 +174,12 @@ #include "axp803.dtsi" +®_aldo1 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-name = "vcc-csi"; +}; + ®_aldo2 { regulator-always-on; regulator-min-microvolt = <1800000>; @@ -161,12 +189,13 @@ ®_aldo3 { regulator-always-on; - regulator-min-microvolt = <3000000>; - regulator-max-microvolt = <3000000>; + regulator-min-microvolt = <2700000>; + regulator-max-microvolt = <3300000>; regulator-name = "vcc-pll-avcc"; }; ®_dc1sw { + regulator-always-on; regulator-name = "vcc-phy"; }; @@ -212,6 +241,12 @@ regulator-name = "vcc-wifi"; }; +®_dldo3 { + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "avdd-csi"; +}; + ®_dldo4 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <3300000>; @@ -224,6 +259,12 @@ regulator-name = "cpvdd"; }; +®_eldo3 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vdd-1v8-csi"; +}; + ®_fldo1 { regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; @@ -246,6 +287,14 @@ regulator-name = "vcc-rtc"; }; +&simplefb_hdmi { + vcc-hdmi-supply = <®_dldo1>; +}; + +&tcon1 { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts index 2beef9e..7cbbbf2 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-nanopi-a64.dts @@ -196,6 +196,10 @@ regulator-name = "vcc-rtc"; }; +&simplefb_hdmi { + vcc-hdmi-supply = <®_dldo1>; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts index 338e786..d4e822e 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-olinuxino.dts @@ -192,6 +192,10 @@ regulator-name = "vcc-rtc"; }; +&simplefb_hdmi { + vcc-hdmi-supply = <®_dldo1>; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts index 6ecb700..376d7bf 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-orangepi-win.dts @@ -51,31 +51,15 @@ compatible = "xunlong,orangepi-win", "allwinner,sun50i-a64"; aliases { + ethernet0 = &emac; serial0 = &uart0; + serial1 = &uart1; }; chosen { stdout-path = "serial0:115200n8"; }; - reg_vcc3v3: vcc3v3 { - compatible = "regulator-fixed"; - regulator-name = "vcc3v3"; - regulator-min-microvolt = <3300000>; - regulator-max-microvolt = <3300000>; - }; - - reg_usb1_vbus: usb1-vbus { - compatible = "regulator-fixed"; - regulator-name = "usb1-vbus"; - regulator-min-microvolt = <5000000>; - regulator-max-microvolt = <5000000>; - regulator-boot-on; - enable-active-high; - gpio = <&pio 3 7 GPIO_ACTIVE_HIGH>; - status = "okay"; - }; - wifi_pwrseq: wifi_pwrseq { compatible = "mmc-pwrseq-simple"; reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>; /* PL8 */ @@ -83,6 +67,10 @@ }; }; +&de { + status = "okay"; +}; + &ehci0 { status = "okay"; }; @@ -91,12 +79,49 @@ status = "okay"; }; +&emac { + pinctrl-names = "default"; + pinctrl-0 = <&rgmii_pins>; + phy-mode = "rgmii"; + phy-handle = <&ext_rgmii_phy>; + phy-supply = <®_dc1sw>; + status = "okay"; +}; + +&hdmi { + hvcc-supply = <®_dldo1>; + status = "okay"; +}; + +&i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + status = "okay"; +}; + +&i2c1_pins { + bias-pull-up; +}; + +&external_mdio { + ext_rgmii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + }; +}; + +&mixer1 { + status = "okay"; +}; + &mmc0 { pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins>; - vmmc-supply = <®_vcc3v3>; + vmmc-supply = <®_dcdc1>; cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; cd-inverted; + disable-wp; + bus-width = <4>; status = "okay"; }; @@ -119,6 +144,16 @@ }; }; +&mmc2 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc2_pins>; + vmmc-supply = <®_dcdc1>; + bus-width = <8>; + non-removable; + cap-mmc-hw-reset; + status = "okay"; +}; + &ohci0 { status = "okay"; }; @@ -133,12 +168,12 @@ axp803: pmic@3a3 { compatible = "x-powers,axp803"; reg = <0x3a3>; - interrupt-parent = <&nmi_intc>; + interrupt-parent = <&r_intc>; interrupts = <0 IRQ_TYPE_LEVEL_LOW>; }; }; -#include +#include "axp803.dtsi" ®_aldo1 { regulator-min-microvolt = <2800000>; @@ -174,7 +209,7 @@ ®_dcdc2 { regulator-always-on; - regulator-min-microvolt = <1000000>; + regulator-min-microvolt = <1040000>; regulator-max-microvolt = <1300000>; regulator-name = "vdd-cpux"; }; @@ -198,7 +233,7 @@ ®_dldo1 { regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; - regulator-name = "vcc-hdmi"; + regulator-name = "vcc-hdmi-dsi"; }; ®_dldo2 { @@ -237,6 +272,11 @@ regulator-name = "vcc-1v2-hsic"; }; +/* + * The A64 chip cannot work without this regulator off, although + * it seems to be only driving the AR100 core. + * Maybe we don't still know well about CPUs domain. + */ ®_fldo2 { regulator-always-on; regulator-min-microvolt = <1100000>; @@ -248,14 +288,27 @@ regulator-name = "vcc-rtc"; }; +&simplefb_hdmi { + vcc-hdmi-supply = <®_dldo1>; +}; + +&tcon1 { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; status = "okay"; }; +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&uart1_pins>, <&uart1_rts_cts_pins>; + status = "okay"; +}; + &usbphy { - usb1_vbus-supply = <®_usb1_vbus>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts index 806442d..5bb2807 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-pine64.dts @@ -62,6 +62,15 @@ chosen { stdout-path = "serial0:115200n8"; }; + + wifi_pwrseq: wifi_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */ + }; +}; + +&de { + status = "okay"; }; &ehci0 { @@ -77,8 +86,13 @@ pinctrl-0 = <&rmii_pins>; phy-mode = "rmii"; phy-handle = <&ext_rmii_phy1>; + phy-supply = <®_dc1sw>; status = "okay"; +}; +&hdmi { + hvcc-supply = <®_dldo1>; + status = "okay"; }; &i2c1 { @@ -98,6 +112,10 @@ }; }; +&mixer1 { + status = "okay"; +}; + &mmc0 { pinctrl-names = "default"; pinctrl-0 = <&mmc0_pins>; @@ -109,6 +127,17 @@ status = "okay"; }; +&mmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + vmmc-supply = <®_dldo4>; + vqmmc-supply = <®_eldo1>; + mmc-pwrseq = <&wifi_pwrseq>; + non-removable; + bus-width = <4>; + status = "okay"; +}; + &ohci0 { status = "okay"; }; @@ -130,6 +159,14 @@ #include "axp803.dtsi" +&ac_power_supply { + status = "okay"; +}; + +&battery_power_supply { + status = "okay"; +}; + ®_aldo2 { regulator-always-on; regulator-min-microvolt = <1800000>; @@ -229,6 +266,14 @@ regulator-name = "vcc-rtc"; }; +&simplefb_hdmi { + vcc-hdmi-supply = <®_dldo1>; +}; + +&tcon1 { + status = "okay"; +}; + /* On Exp and Euler connectors */ &uart0 { pinctrl-names = "default"; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts index 0eb2ace..f9f9484 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-sopine-baseboard.dts @@ -47,6 +47,8 @@ #include "sun50i-a64-sopine.dtsi" +#include + / { model = "SoPine with baseboard"; compatible = "pine64,sopine-baseboard", "pine64,sopine", @@ -67,6 +69,15 @@ regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; + + wifi_pwrseq: wifi_pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&r_pio 0 2 GPIO_ACTIVE_LOW>; /* PL2 */ + }; +}; + +&de { + status = "okay"; }; &ehci0 { @@ -82,6 +93,12 @@ pinctrl-0 = <&rgmii_pins>; phy-mode = "rgmii"; phy-handle = <&ext_rgmii_phy>; + phy-supply = <®_dc1sw>; + status = "okay"; +}; + +&hdmi { + hvcc-supply = <®_dldo1>; status = "okay"; }; @@ -92,6 +109,21 @@ }; }; +&mixer1 { + status = "okay"; +}; + +&mmc1 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc1_pins>; + vmmc-supply = <®_dldo4>; + vqmmc-supply = <®_eldo1>; + mmc-pwrseq = <&wifi_pwrseq>; + non-removable; + bus-width = <4>; + status = "okay"; +}; + &mmc2 { pinctrl-names = "default"; pinctrl-0 = <&mmc2_pins>; @@ -133,6 +165,14 @@ regulator-name = "vcc-wifi"; }; +&simplefb_hdmi { + vcc-hdmi-supply = <®_dldo1>; +}; + +&tcon1 { + status = "okay"; +}; + &uart0 { pinctrl-names = "default"; pinctrl-0 = <&uart0_pins_a>; diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 9366256..a7e72c7 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -42,16 +42,111 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include #include +#include #include +#include +#include +#include +#include +#include / { interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>; + chosen { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + simplefb_lcd: framebuffer-lcd { + compatible = "allwinner,simple-framebuffer", + "simple-framebuffer"; + allwinner,pipeline = "mixer0-lcd0"; + clocks = <&display_clocks CLK_BUS_MIXER0>, + <&ccu CLK_BUS_TCON0>, <&ccu CLK_BUS_TCON0>, + <&display_clocks CLK_MIXER0>, + <&ccu CLK_TCON0>; + status = "disabled"; + }; + + simplefb_hdmi: framebuffer-hdmi { + compatible = "allwinner,simple-framebuffer", + "simple-framebuffer"; + allwinner,pipeline = "mixer1-lcd1-hdmi"; + clocks = <&display_clocks CLK_BUS_MIXER1>, + <&ccu CLK_BUS_TCON1>, <&ccu CLK_BUS_HDMI>, + <&display_clocks CLK_MIXER1>, + <&ccu CLK_TCON1>, <&ccu CLK_HDMI>, + <&ccu CLK_HDMI_DDC>; + status = "disabled"; + }; + }; + + cpu_opp_table: opp_table { + compatible = "operating-points-v2"; + opp-shared; + + opp@408000000 { + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <1000000 1000000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@648000000 { + opp-hz = /bits/ 64 <648000000>; + opp-microvolt = <1040000 1040000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@816000000 { + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <1080000 1080000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@912000000 { + opp-hz = /bits/ 64 <912000000>; + opp-microvolt = <1120000 1120000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@960000000 { + opp-hz = /bits/ 64 <960000000>; + opp-microvolt = <1160000 1160000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@1008000000 { + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <1200000 1200000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@1056000000 { + opp-hz = /bits/ 64 <1056000000>; + opp-microvolt = <1240000 1240000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@1104000000 { + opp-hz = /bits/ 64 <1104000000>; + opp-microvolt = <1260000 1260000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + + opp@1152000000 { + opp-hz = /bits/ 64 <1152000000>; + opp-microvolt = <1300000 1300000 1300000>; + clock-latency-ns = <244144>; /* 8 32k periods */ + }; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -61,6 +156,9 @@ device_type = "cpu"; reg = <0>; enable-method = "psci"; + operating-points-v2 = <&cpu_opp_table>; + cpu-supply = <®_cpu_fallback>; + #cooling-cells = <2>; }; cpu1: cpu@1 { @@ -68,6 +166,7 @@ device_type = "cpu"; reg = <1>; enable-method = "psci"; + operating-points-v2 = <&cpu_opp_table>; }; cpu2: cpu@2 { @@ -75,6 +174,7 @@ device_type = "cpu"; reg = <2>; enable-method = "psci"; + operating-points-v2 = <&cpu_opp_table>; }; cpu3: cpu@3 { @@ -82,9 +182,17 @@ device_type = "cpu"; reg = <3>; enable-method = "psci"; + operating-points-v2 = <&cpu_opp_table>; }; }; + de: display-engine { + compatible = "allwinner,sun50i-a64-display-engine"; + allwinner,pipelines = <&mixer0>, + <&mixer1>; + status = "disabled"; + }; + osc24M: osc24M_clk { #clock-cells = <0>; compatible = "fixed-clock"; @@ -112,6 +220,100 @@ method = "smc"; }; + thermal-zones { + cpu-thermal { + /* milliseconds */ + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&ths>; + + trips { + cpu_warm: cpu_warm { + temperature = <65000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_hot_pre: cpu_hot_pre { + temperature = <70000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_hot: cpu_hot { + temperature = <75000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_very_hot_pre: cpu_very_hot_pre { + temperature = <85000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_very_hot: cpu_very_hot { + temperature = <90000>; + hysteresis = <2000>; + type = "passive"; + }; + + cpu_crit: cpu_crit { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + cooling-maps { + cpu_warm_limit_cpu { + trip = <&cpu_warm>; + cooling-device = <&cpu0 THERMAL_NO_LIMIT 2>; + }; + + cpu_hot_pre_limit_cpu { + trip = <&cpu_hot_pre>; + cooling-device = <&cpu0 2 3>; + }; + + cpu_hot_limit_cpu { + trip = <&cpu_hot>; + cooling-device = <&cpu0 3 4>; + }; + + cpu_very_hot_pre_limit_cpu { + trip = <&cpu_very_hot>; + cooling-device = <&cpu0 5 6>; + }; + + cpu_very_hot_limit_cpu { + trip = <&cpu_very_hot>; + cooling-device = <&cpu0 7 THERMAL_NO_LIMIT>; + }; + }; + }; + }; + + reg_cpu_fallback: reg_cpu_fallback { + compatible = "regulator-fixed"; + regulator-name = "vdd-cpux-dummy"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + }; + + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + cma: linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x4000000>; + alignment = <0x2000>; + linux,cma-default; + }; + }; timer { compatible = "arm,armv8-timer"; fsl,erratum-a008585; @@ -131,12 +333,217 @@ #size-cells = <1>; ranges; + ths: thermal-sensor@1c25000 { + compatible = "allwinner,sun50i-h5-ths"; + reg = <0x01c25000 0x100>; + clocks = <&ccu CLK_BUS_THS>, <&ccu CLK_THS>; + clock-names = "bus", "mod"; + resets = <&ccu RST_BUS_THS>; + #thermal-sensor-cells = <0>; + #io-channel-cells = <0>; + }; + + display_clocks: clock@1000000 { + compatible = "allwinner,sun50i-a64-de2-clk"; + reg = <0x01000000 0x100000>; + clocks = <&ccu CLK_DE>, + <&ccu CLK_BUS_DE>; + clock-names = "mod", + "bus"; + resets = <&ccu RST_BUS_DE>; + allwinner,sram = <&de2_sram 1>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + mixer0: mixer@1100000 { + compatible = "allwinner,sun50i-a64-de2-mixer0"; + reg = <0x01100000 0x100000>; + clocks = <&display_clocks CLK_MIXER0>, + <&display_clocks CLK_BUS_MIXER0>; + clock-names = "mod", + "bus"; + resets = <&display_clocks RST_MIXER0>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + mixer0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + mixer0_out_tcon0: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon0_in_mixer0>; + }; + + mixer0_out_tcon1: endpoint@1 { + reg = <1>; + remote-endpoint = <&tcon1_in_mixer0>; + }; + }; + }; + }; + + mixer1: mixer@1200000 { + compatible = "allwinner,sun50i-a64-de2-mixer1"; + reg = <0x01200000 0x100000>; + clocks = <&display_clocks CLK_MIXER1>, + <&display_clocks CLK_BUS_MIXER1>; + clock-names = "mod", + "bus"; + resets = <&display_clocks RST_MIXER1>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + mixer1_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + mixer1_out_tcon1: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon1_in_mixer1>; + }; + + mixer1_out_tcon0: endpoint@1 { + reg = <1>; + remote-endpoint = <&tcon0_in_mixer1>; + }; + }; + }; + }; + + tcon0: lcd-controller@01c0c000 { + compatible = "allwinner,sun50i-a64-tcon0"; + reg = <0x01c0c000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_TCON0>, + <&ccu CLK_TCON0>; + clock-names = "ahb", + "tcon-ch0"; + clock-output-names = "tcon-pixel-clock"; + resets = <&ccu RST_BUS_TCON0>; + reset-names = "lcd"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + tcon0_in: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + tcon0_in_mixer0: endpoint@0 { + reg = <0>; + remote-endpoint = <&mixer0_out_tcon0>; + }; + + tcon0_in_mixer1: endpoint@1 { + reg = <1>; + remote-endpoint = <&mixer1_out_tcon0>; + }; + }; + + tcon0_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + }; + }; + }; + + tcon1: lcd-controller@1c0d000 { + compatible = "allwinner,sun50i-a64-tcon1"; + reg = <0x01c0d000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_TCON1>, + <&ccu CLK_TCON1>; + clock-names = "ahb", + "tcon-ch1"; + resets = <&ccu RST_BUS_TCON1>; + reset-names = "lcd"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + tcon1_in: port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + tcon1_in_mixer1: endpoint@0 { + reg = <0>; + remote-endpoint = <&mixer1_out_tcon1>; + }; + + tcon1_in_mixer0: endpoint@1 { + reg = <1>; + remote-endpoint = <&mixer0_out_tcon1>; + }; + }; + + tcon1_out: port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + tcon1_out_hdmi: endpoint@1 { + reg = <1>; + remote-endpoint = <&hdmi_in_tcon1>; + }; + }; + }; + }; + syscon: syscon@1c00000 { compatible = "allwinner,sun50i-a64-system-controller", "syscon"; reg = <0x01c00000 0x1000>; }; + dma: dma-controller@1c02000 { + compatible = "allwinner,sun50i-a64-dma"; + reg = <0x01c02000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_DMA>; + dma-channels = <8>; + dma-requests = <27>; + resets = <&ccu RST_BUS_DMA>; + #dma-cells = <1>; + }; + + sram-controller@1c00000 { + compatible = "allwinner,sun50i-a64-sram-controller"; + reg = <0x01c00000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + sram_c: sram@18000 { + compatible = "mmio-sram"; + reg = <0x00018000 0x28000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x00018000 0x28000>; + + de2_sram: sram-section@0 { + compatible = "allwinner,sun50i-a64-sram-c"; + reg = <0x0000 0x28000>; + }; + }; + }; + mmc0: mmc@1c0f000 { compatible = "allwinner,sun50i-a64-mmc"; reg = <0x01c0f000 0x1000>; @@ -286,6 +693,15 @@ function = "i2c1"; }; + lcd_rgb666_pins: lcd-rgb666 { + pins = "PD0", "PD1", "PD2", "PD3", "PD4", + "PD5", "PD6", "PD7", "PD8", "PD9", + "PD10", "PD11", "PD12", "PD13", + "PD14", "PD15", "PD16", "PD17", + "PD18", "PD19", "PD20", "PD21"; + function = "lcd0"; + }; + mmc0_pins: mmc0-pins { pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5"; @@ -311,6 +727,11 @@ bias-pull-up; }; + pwm0_pins: pwm0 { + pins = "PD22"; + function = "pwm"; + }; + rmii_pins: rmii_pins { pins = "PD10", "PD11", "PD13", "PD14", "PD17", "PD18", "PD19", "PD20", "PD22", "PD23"; @@ -372,6 +793,14 @@ }; }; + pwm: pwm@01c21400 { + compatible = "allwinner,sun50i-a64-pwm"; + reg = <0x01c21400 0x8>; + clocks = <&osc24M>; + #pwm-cells = <3>; + status = "disabled"; + }; + spi0: spi@01c68000 { compatible = "allwinner,sun8i-h3-spi"; reg = <0x01c68000 0x1000>; @@ -505,7 +934,63 @@ mdio: mdio { #address-cells = <1>; #size-cells = <0>; + compatible = "snps,dwmac-mdio"; }; + + mdio-mux { + compatible = "allwinner,sun8i-h3-mdio-mux"; + #address-cells = <1>; + #size-cells = <0>; + + mdio-parent-bus = <&mdio>; + /* Only one MDIO is usable at the time */ + internal_mdio: mdio@1 { + compatible = "allwinner,sun50i-a64-emac"; + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + int_mii_phy: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <1>; + clocks = <&ccu CLK_BUS_EMAC>; + resets = <&ccu RST_BUS_EMAC>; + }; + }; + + external_mdio: mdio@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + mali: gpu@1c40000 { + compatible = "allwinner,sun50i-a64-mali", + "allwinner,sun7i-a20-mali", "arm,mali-400"; + reg = <0x01c40000 0x10000>; + interrupts = , + , + , + , + , + , + ; + interrupt-names = "gp", + "gpmmu", + "pp0", + "ppmmu0", + "pp1", + "ppmmu1", + "pmu"; + clocks = <&ccu CLK_BUS_GPU>, <&ccu CLK_GPU>; + clock-names = "bus", "core"; + resets = <&ccu RST_BUS_GPU>; + memory-region = <&cma>; + + assigned-clocks = <&ccu CLK_GPU>; + assigned-clock-rates = <384000000>; }; gic: interrupt-controller@1c81000 { @@ -519,6 +1004,36 @@ #interrupt-cells = <3>; }; + hdmi: hdmi@1ee0000 { + compatible = "allwinner,h3-dw-hdmi"; + reg = <0x01ee0000 0x10000>, + <0x01ef0000 0x10000>; + reg-io-width = <1>; + interrupts = ; + clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI>, + <&ccu CLK_HDMI_DDC>; + clock-names = "iahb", "isfr", "iddc"; + resets = <&ccu RST_BUS_HDMI0>, <&ccu RST_BUS_HDMI1>; + reset-names = "hdmi", "ddc"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + hdmi_in_tcon1: endpoint@0 { + reg = <0>; + remote-endpoint = <&tcon1_out_hdmi>; + }; + }; + }; + }; + rtc: rtc@1f00000 { compatible = "allwinner,sun6i-a31-rtc"; reg = <0x01f00000 0x54>; @@ -553,6 +1068,17 @@ #reset-cells = <1>; }; + r_i2c: i2c@1f02400 { + compatible = "allwinner,sun6i-a31-i2c"; + reg = <0x01f02400 0x400>; + interrupts = ; + clocks = <&r_ccu CLK_APB0_I2C>; + resets = <&r_ccu RST_APB0_I2C>; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + r_pio: pinctrl@01f02c00 { compatible = "allwinner,sun50i-a64-r-pinctrl"; reg = <0x01f02c00 0x400>; @@ -568,6 +1094,11 @@ pins = "PL0", "PL1"; function = "s_rsb"; }; + + r_i2c_pins_a: i2c-a { + pins = "PL8", "PL9"; + function = "s_i2c"; + }; }; r_rsb: rsb@1f03400 { diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index 2bb4cab..2795408 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -513,7 +513,7 @@ static struct ccu_div tcon1_clk = { .hw.init = CLK_HW_INIT_PARENTS("tcon1", tcon1_parents, &ccu_div_ops, - CLK_SET_RATE_PARENT), + 0), }, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 5cdaf52..38b029b 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "ccu_common.h" #include "ccu_div.h" @@ -46,6 +47,13 @@ static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4, static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4, CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(mixer0_div_a83_clk, "mixer0-div", "pll-de", 0x0c, 0, 4, + CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(mixer1_div_a83_clk, "mixer1-div", "pll-de", 0x0c, 4, 4, + CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4, + CLK_SET_RATE_PARENT); + static struct ccu_common *sun8i_a83t_de2_clks[] = { &mixer0_clk.common, &mixer1_clk.common, @@ -55,6 +63,20 @@ static struct ccu_common *sun8i_a83t_de2_clks[] = { &bus_mixer1_clk.common, &bus_wb_clk.common, + &mixer0_div_a83_clk.common, + &mixer1_div_a83_clk.common, + &wb_div_a83_clk.common, +}; + +static struct ccu_common *sun8i_h3_de2_clks[] = { + &mixer0_clk.common, + &mixer1_clk.common, + &wb_clk.common, + + &bus_mixer0_clk.common, + &bus_mixer1_clk.common, + &bus_wb_clk.common, + &mixer0_div_clk.common, &mixer1_div_clk.common, &wb_div_clk.common, @@ -81,6 +103,23 @@ static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = { [CLK_BUS_MIXER1] = &bus_mixer1_clk.common.hw, [CLK_BUS_WB] = &bus_wb_clk.common.hw, + [CLK_MIXER0_DIV] = &mixer0_div_a83_clk.common.hw, + [CLK_MIXER1_DIV] = &mixer1_div_a83_clk.common.hw, + [CLK_WB_DIV] = &wb_div_a83_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct clk_hw_onecell_data sun8i_h3_de2_hw_clks = { + .hws = { + [CLK_MIXER0] = &mixer0_clk.common.hw, + [CLK_MIXER1] = &mixer1_clk.common.hw, + [CLK_WB] = &wb_clk.common.hw, + + [CLK_BUS_MIXER0] = &bus_mixer0_clk.common.hw, + [CLK_BUS_MIXER1] = &bus_mixer1_clk.common.hw, + [CLK_BUS_WB] = &bus_wb_clk.common.hw, + [CLK_MIXER0_DIV] = &mixer0_div_clk.common.hw, [CLK_MIXER1_DIV] = &mixer1_div_clk.common.hw, [CLK_WB_DIV] = &wb_div_clk.common.hw, @@ -128,11 +167,21 @@ static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), }; +static const struct sunxi_ccu_desc sun8i_h3_de2_clk_desc = { + .ccu_clks = sun8i_h3_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_h3_de2_clks), + + .hw_clks = &sun8i_h3_de2_hw_clks, + + .resets = sun8i_a83t_de2_resets, + .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), +}; + static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = { - .ccu_clks = sun8i_a83t_de2_clks, - .num_ccu_clks = ARRAY_SIZE(sun8i_a83t_de2_clks), + .ccu_clks = sun8i_h3_de2_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_h3_de2_clks), - .hw_clks = &sun8i_a83t_de2_hw_clks, + .hw_clks = &sun8i_h3_de2_hw_clks, .resets = sun50i_a64_de2_resets, .num_resets = ARRAY_SIZE(sun50i_a64_de2_resets), @@ -148,6 +197,11 @@ static const struct sunxi_ccu_desc sun8i_v3s_de2_clk_desc = { .num_resets = ARRAY_SIZE(sun8i_a83t_de2_resets), }; +static bool sunxi_de2_clk_has_sram(const struct device_node *node) +{ + return of_device_is_compatible(node, "allwinner,sun50i-a64-de2-clk"); +} + static int sunxi_de2_clk_probe(struct platform_device *pdev) { struct resource *res; @@ -191,11 +245,20 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev) return ret; } + if (sunxi_de2_clk_has_sram(pdev->dev.of_node)) { + ret = sunxi_sram_claim(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, + "Error couldn't map SRAM to device\n"); + return ret; + } + } + /* The clocks need to be enabled for us to access the registers */ ret = clk_prepare_enable(bus_clk); if (ret) { dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret); - return ret; + goto err_release_sram; } ret = clk_prepare_enable(mod_clk); @@ -224,6 +287,10 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev) clk_disable_unprepare(mod_clk); err_disable_bus_clk: clk_disable_unprepare(bus_clk); +err_release_sram: + if (sunxi_de2_clk_has_sram(pdev->dev.of_node)) + sunxi_sram_release(&pdev->dev); + return ret; } @@ -233,20 +300,21 @@ static const struct of_device_id sunxi_de2_clk_ids[] = { .data = &sun8i_a83t_de2_clk_desc, }, { + .compatible = "allwinner,sun8i-h3-de2-clk", + .data = &sun8i_h3_de2_clk_desc, + }, + { .compatible = "allwinner,sun8i-v3s-de2-clk", .data = &sun8i_v3s_de2_clk_desc, }, { + .compatible = "allwinner,sun50i-a64-de2-clk", + .data = &sun50i_a64_de2_clk_desc, + }, + { .compatible = "allwinner,sun50i-h5-de2-clk", .data = &sun50i_a64_de2_clk_desc, }, - /* - * The Allwinner A64 SoC needs some bit to be poke in syscon to make - * DE2 really working. - * So there's currently no A64 compatible here. - * H5 shares the same reset line with A64, so here H5 is using the - * clock description of A64. - */ { } }; diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index bcd496e..0cd13f1 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -42,12 +42,18 @@ #define DMA_STAT 0x30 +/* Offset between DMA_IRQ_EN and DMA_IRQ_STAT limits number of channels */ +#define DMA_MAX_CHANNELS (DMA_IRQ_CHAN_NR * 0x10 / 4) + /* * sun8i specific registers */ #define SUN8I_DMA_GATE 0x20 #define SUN8I_DMA_GATE_ENABLE 0x4 +#define SUNXI_H3_SECURE_REG 0x20 +#define SUNXI_H3_DMA_GATE 0x28 +#define SUNXI_H3_DMA_GATE_ENABLE 0x4 /* * Channels specific registers */ @@ -62,16 +68,19 @@ #define DMA_CHAN_LLI_ADDR 0x08 #define DMA_CHAN_CUR_CFG 0x0c -#define DMA_CHAN_CFG_SRC_DRQ(x) ((x) & 0x1f) +#define DMA_CHAN_MAX_DRQ 0x1f +#define DMA_CHAN_CFG_SRC_DRQ(x) ((x) & DMA_CHAN_MAX_DRQ) #define DMA_CHAN_CFG_SRC_IO_MODE BIT(5) #define DMA_CHAN_CFG_SRC_LINEAR_MODE (0 << 5) -#define DMA_CHAN_CFG_SRC_BURST(x) (((x) & 0x3) << 7) +#define DMA_CHAN_CFG_SRC_BURST_A31(x) (((x) & 0x3) << 7) +#define DMA_CHAN_CFG_SRC_BURST_H3(x) (((x) & 0x3) << 6) #define DMA_CHAN_CFG_SRC_WIDTH(x) (((x) & 0x3) << 9) #define DMA_CHAN_CFG_DST_DRQ(x) (DMA_CHAN_CFG_SRC_DRQ(x) << 16) #define DMA_CHAN_CFG_DST_IO_MODE (DMA_CHAN_CFG_SRC_IO_MODE << 16) #define DMA_CHAN_CFG_DST_LINEAR_MODE (DMA_CHAN_CFG_SRC_LINEAR_MODE << 16) -#define DMA_CHAN_CFG_DST_BURST(x) (DMA_CHAN_CFG_SRC_BURST(x) << 16) +#define DMA_CHAN_CFG_DST_BURST_A31(x) (DMA_CHAN_CFG_SRC_BURST_A31(x) << 16) +#define DMA_CHAN_CFG_DST_BURST_H3(x) (DMA_CHAN_CFG_SRC_BURST_H3(x) << 16) #define DMA_CHAN_CFG_DST_WIDTH(x) (DMA_CHAN_CFG_SRC_WIDTH(x) << 16) #define DMA_CHAN_CUR_SRC 0x10 @@ -90,6 +99,9 @@ #define NORMAL_WAIT 8 #define DRQ_SDRAM 1 +/* forward declaration */ +struct sun6i_dma_dev; + /* * Hardware channels / ports representation * @@ -111,7 +123,12 @@ struct sun6i_dma_config { * however these SoCs really have and need this bit, as seen in the * BSP kernel source code. */ - bool gate_needed; + void (*clock_autogate_enable)(struct sun6i_dma_dev *); + void (*set_burst_length)(u32 *p_cfg, s8 src_burst, s8 dst_burst); + u32 src_burst_lengths; + u32 dst_burst_lengths; + u32 src_addr_widths; + u32 dst_addr_widths; }; /* @@ -175,6 +192,9 @@ struct sun6i_dma_dev { struct sun6i_pchan *pchans; struct sun6i_vchan *vchans; const struct sun6i_dma_config *cfg; + u32 num_pchans; + u32 num_vchans; + u32 max_request; }; static struct device *chan2dev(struct dma_chan *chan) @@ -251,8 +271,12 @@ static inline s8 convert_burst(u32 maxburst) switch (maxburst) { case 1: return 0; + case 4: + return 1; case 8: return 2; + case 16: + return 3; default: return -EINVAL; } @@ -260,11 +284,29 @@ static inline s8 convert_burst(u32 maxburst) static inline s8 convert_buswidth(enum dma_slave_buswidth addr_width) { - if ((addr_width < DMA_SLAVE_BUSWIDTH_1_BYTE) || - (addr_width > DMA_SLAVE_BUSWIDTH_4_BYTES)) - return -EINVAL; + return ilog2(addr_width); +} + +static void sun6i_enable_clock_autogate_a23(struct sun6i_dma_dev *sdev) +{ + writel(SUN8I_DMA_GATE_ENABLE, sdev->base + SUN8I_DMA_GATE); +} + +static void sun6i_enable_clock_autogate_h3(struct sun6i_dma_dev *sdev) +{ + writel(SUNXI_H3_DMA_GATE_ENABLE, sdev->base + SUNXI_H3_DMA_GATE); +} - return addr_width >> 1; +static void sun6i_set_burst_length_a31(u32 *p_cfg, s8 src_burst, s8 dst_burst) +{ + *p_cfg |= DMA_CHAN_CFG_SRC_BURST_A31(src_burst) | + DMA_CHAN_CFG_DST_BURST_A31(dst_burst); +} + +static void sun6i_set_burst_length_h3(u32 *p_cfg, s8 src_burst, s8 dst_burst) +{ + *p_cfg |= DMA_CHAN_CFG_SRC_BURST_H3(src_burst) | + DMA_CHAN_CFG_DST_BURST_H3(dst_burst); } static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan) @@ -399,7 +441,6 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan) static void sun6i_dma_tasklet(unsigned long data) { struct sun6i_dma_dev *sdev = (struct sun6i_dma_dev *)data; - const struct sun6i_dma_config *cfg = sdev->cfg; struct sun6i_vchan *vchan; struct sun6i_pchan *pchan; unsigned int pchan_alloc = 0; @@ -427,7 +468,7 @@ static void sun6i_dma_tasklet(unsigned long data) } spin_lock_irq(&sdev->lock); - for (pchan_idx = 0; pchan_idx < cfg->nr_max_channels; pchan_idx++) { + for (pchan_idx = 0; pchan_idx < sdev->num_pchans; pchan_idx++) { pchan = &sdev->pchans[pchan_idx]; if (pchan->vchan || list_empty(&sdev->pending)) @@ -448,7 +489,7 @@ static void sun6i_dma_tasklet(unsigned long data) } spin_unlock_irq(&sdev->lock); - for (pchan_idx = 0; pchan_idx < cfg->nr_max_channels; pchan_idx++) { + for (pchan_idx = 0; pchan_idx < sdev->num_pchans; pchan_idx++) { if (!(pchan_alloc & BIT(pchan_idx))) continue; @@ -470,7 +511,7 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id) int i, j, ret = IRQ_NONE; u32 status; - for (i = 0; i < sdev->cfg->nr_max_channels / DMA_IRQ_CHAN_NR; i++) { + for (i = 0; i < sdev->num_pchans / DMA_IRQ_CHAN_NR; i++) { status = readl(sdev->base + DMA_IRQ_STAT(i)); if (!status) continue; @@ -510,47 +551,49 @@ static int set_config(struct sun6i_dma_dev *sdev, enum dma_transfer_direction direction, u32 *p_cfg) { + enum dma_slave_buswidth src_addr_width, dst_addr_width; + u32 src_maxburst, dst_maxburst; s8 src_width, dst_width, src_burst, dst_burst; + src_addr_width = sconfig->src_addr_width; + dst_addr_width = sconfig->dst_addr_width; + src_maxburst = sconfig->src_maxburst; + dst_maxburst = sconfig->dst_maxburst; + switch (direction) { case DMA_MEM_TO_DEV: - src_burst = convert_burst(sconfig->src_maxburst ? - sconfig->src_maxburst : 8); - src_width = convert_buswidth(sconfig->src_addr_width != - DMA_SLAVE_BUSWIDTH_UNDEFINED ? - sconfig->src_addr_width : - DMA_SLAVE_BUSWIDTH_4_BYTES); - dst_burst = convert_burst(sconfig->dst_maxburst); - dst_width = convert_buswidth(sconfig->dst_addr_width); + if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) + src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + src_maxburst = src_maxburst ? src_maxburst : 8; break; case DMA_DEV_TO_MEM: - src_burst = convert_burst(sconfig->src_maxburst); - src_width = convert_buswidth(sconfig->src_addr_width); - dst_burst = convert_burst(sconfig->dst_maxburst ? - sconfig->dst_maxburst : 8); - dst_width = convert_buswidth(sconfig->dst_addr_width != - DMA_SLAVE_BUSWIDTH_UNDEFINED ? - sconfig->dst_addr_width : - DMA_SLAVE_BUSWIDTH_4_BYTES); + if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) + dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dst_maxburst = dst_maxburst ? dst_maxburst : 8; break; default: return -EINVAL; } - if (src_burst < 0) - return src_burst; - if (src_width < 0) - return src_width; - if (dst_burst < 0) - return dst_burst; - if (dst_width < 0) - return dst_width; - - *p_cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) | - DMA_CHAN_CFG_SRC_WIDTH(src_width) | - DMA_CHAN_CFG_DST_BURST(dst_burst) | + if (!(BIT(src_addr_width) & sdev->slave.src_addr_widths)) + return -EINVAL; + if (!(BIT(dst_addr_width) & sdev->slave.dst_addr_widths)) + return -EINVAL; + if (!(BIT(src_maxburst) & sdev->cfg->src_burst_lengths)) + return -EINVAL; + if (!(BIT(dst_maxburst) & sdev->cfg->dst_burst_lengths)) + return -EINVAL; + + src_width = convert_buswidth(src_addr_width); + dst_width = convert_buswidth(dst_addr_width); + dst_burst = convert_burst(dst_maxburst); + src_burst = convert_burst(src_maxburst); + + *p_cfg = DMA_CHAN_CFG_SRC_WIDTH(src_width) | DMA_CHAN_CFG_DST_WIDTH(dst_width); + sdev->cfg->set_burst_length(p_cfg, src_burst, dst_burst); + return 0; } @@ -593,11 +636,11 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy( DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) | DMA_CHAN_CFG_DST_LINEAR_MODE | DMA_CHAN_CFG_SRC_LINEAR_MODE | - DMA_CHAN_CFG_SRC_BURST(burst) | DMA_CHAN_CFG_SRC_WIDTH(width) | - DMA_CHAN_CFG_DST_BURST(burst) | DMA_CHAN_CFG_DST_WIDTH(width); + sdev->cfg->set_burst_length(&v_lli->cfg, burst, burst); + sun6i_dma_lli_add(NULL, v_lli, p_lli, txd); sun6i_dma_dump_lli(vchan, v_lli); @@ -948,7 +991,7 @@ static struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec, struct dma_chan *chan; u8 port = dma_spec->args[0]; - if (port > sdev->cfg->nr_max_requests) + if (port > sdev->max_request) return NULL; chan = dma_get_any_slave_channel(&sdev->slave); @@ -981,7 +1024,7 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev) { int i; - for (i = 0; i < sdev->cfg->nr_max_vchans; i++) { + for (i = 0; i < sdev->num_vchans; i++) { struct sun6i_vchan *vchan = &sdev->vchans[i]; list_del(&vchan->vc.chan.device_node); @@ -1009,6 +1052,15 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = { .nr_max_channels = 16, .nr_max_requests = 30, .nr_max_vchans = 53, + .set_burst_length = sun6i_set_burst_length_a31, + .src_burst_lengths = BIT(1) | BIT(8), + .dst_burst_lengths = BIT(1) | BIT(8), + .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), + .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), }; /* @@ -1020,24 +1072,76 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = { .nr_max_channels = 8, .nr_max_requests = 24, .nr_max_vchans = 37, - .gate_needed = true, + .clock_autogate_enable = sun6i_enable_clock_autogate_a23, + .set_burst_length = sun6i_set_burst_length_a31, + .src_burst_lengths = BIT(1) | BIT(8), + .dst_burst_lengths = BIT(1) | BIT(8), + .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), + .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), }; static struct sun6i_dma_config sun8i_a83t_dma_cfg = { .nr_max_channels = 8, .nr_max_requests = 28, .nr_max_vchans = 39, + .clock_autogate_enable = sun6i_enable_clock_autogate_a23, + .set_burst_length = sun6i_set_burst_length_a31, + .src_burst_lengths = BIT(1) | BIT(8), + .dst_burst_lengths = BIT(1) | BIT(8), + .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), + .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), }; /* * The H3 has 12 physical channels, a maximum DRQ port id of 27, * and a total of 34 usable source and destination endpoints. + * It also supports additional burst lengths and bus widths, + * and the burst length fields have different offsets. */ static struct sun6i_dma_config sun8i_h3_dma_cfg = { .nr_max_channels = 12, .nr_max_requests = 27, .nr_max_vchans = 34, + .clock_autogate_enable = sun6i_enable_clock_autogate_h3, + .set_burst_length = sun6i_set_burst_length_h3, + .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), + .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), + .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), + .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), +}; + +/* + * The A64 binding uses the number of dma channels from the + * device tree node. + */ +static struct sun6i_dma_config sun50i_a64_dma_cfg = { + .clock_autogate_enable = sun6i_enable_clock_autogate_h3, + .set_burst_length = sun6i_set_burst_length_h3, + .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), + .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), + .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), + .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), }; /* @@ -1049,7 +1153,16 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = { .nr_max_channels = 8, .nr_max_requests = 23, .nr_max_vchans = 24, - .gate_needed = true, + .clock_autogate_enable = sun6i_enable_clock_autogate_a23, + .set_burst_length = sun6i_set_burst_length_a31, + .src_burst_lengths = BIT(1) | BIT(8), + .dst_burst_lengths = BIT(1) | BIT(8), + .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), + .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), }; static const struct of_device_id sun6i_dma_match[] = { @@ -1058,13 +1171,14 @@ static const struct of_device_id sun6i_dma_match[] = { { .compatible = "allwinner,sun8i-a83t-dma", .data = &sun8i_a83t_dma_cfg }, { .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg }, { .compatible = "allwinner,sun8i-v3s-dma", .data = &sun8i_v3s_dma_cfg }, + { .compatible = "allwinner,sun50i-a64-dma", .data = &sun50i_a64_dma_cfg }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sun6i_dma_match); static int sun6i_dma_probe(struct platform_device *pdev) { - const struct of_device_id *device; + struct device_node *np = pdev->dev.of_node; struct sun6i_dma_dev *sdc; struct resource *res; int ret, i; @@ -1073,10 +1187,9 @@ static int sun6i_dma_probe(struct platform_device *pdev) if (!sdc) return -ENOMEM; - device = of_match_device(sun6i_dma_match, &pdev->dev); - if (!device) + sdc->cfg = of_device_get_match_data(&pdev->dev); + if (!sdc->cfg) return -ENODEV; - sdc->cfg = device->data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sdc->base = devm_ioremap_resource(&pdev->dev, res); @@ -1129,37 +1242,57 @@ static int sun6i_dma_probe(struct platform_device *pdev) sdc->slave.device_pause = sun6i_dma_pause; sdc->slave.device_resume = sun6i_dma_resume; sdc->slave.device_terminate_all = sun6i_dma_terminate_all; - sdc->slave.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | - BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | - BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); - sdc->slave.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | - BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | - BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + sdc->slave.src_addr_widths = sdc->cfg->src_addr_widths; + sdc->slave.dst_addr_widths = sdc->cfg->dst_addr_widths; sdc->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); sdc->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; sdc->slave.dev = &pdev->dev; - sdc->pchans = devm_kcalloc(&pdev->dev, sdc->cfg->nr_max_channels, + sdc->num_pchans = sdc->cfg->nr_max_channels; + sdc->num_vchans = sdc->cfg->nr_max_vchans; + sdc->max_request = sdc->cfg->nr_max_requests; + + ret = of_property_read_u32(np, "dma-channels", &sdc->num_pchans); + if (ret && !sdc->num_pchans) { + dev_err(&pdev->dev, "Can't get dma-channels.\n"); + return ret; + } + + ret = of_property_read_u32(np, "dma-requests", &sdc->max_request); + if (ret && !sdc->max_request) { + dev_info(&pdev->dev, "Missing dma-requests, using %u.\n", + DMA_CHAN_MAX_DRQ); + sdc->max_request = DMA_CHAN_MAX_DRQ; + } + + /* + * If the number of vchans is not specified, derive it from the + * highest port number, at most one channel per port and direction. + */ + if (!sdc->num_vchans) + sdc->num_vchans = 2 * (sdc->max_request + 1); + + sdc->pchans = devm_kcalloc(&pdev->dev, sdc->num_pchans, sizeof(struct sun6i_pchan), GFP_KERNEL); if (!sdc->pchans) return -ENOMEM; - sdc->vchans = devm_kcalloc(&pdev->dev, sdc->cfg->nr_max_vchans, + sdc->vchans = devm_kcalloc(&pdev->dev, sdc->num_vchans, sizeof(struct sun6i_vchan), GFP_KERNEL); if (!sdc->vchans) return -ENOMEM; tasklet_init(&sdc->task, sun6i_dma_tasklet, (unsigned long)sdc); - for (i = 0; i < sdc->cfg->nr_max_channels; i++) { + for (i = 0; i < sdc->num_pchans; i++) { struct sun6i_pchan *pchan = &sdc->pchans[i]; pchan->idx = i; pchan->base = sdc->base + 0x100 + i * 0x40; } - for (i = 0; i < sdc->cfg->nr_max_vchans; i++) { + for (i = 0; i < sdc->num_vchans; i++) { struct sun6i_vchan *vchan = &sdc->vchans[i]; INIT_LIST_HEAD(&vchan->node); @@ -1199,8 +1332,8 @@ static int sun6i_dma_probe(struct platform_device *pdev) goto err_dma_unregister; } - if (sdc->cfg->gate_needed) - writel(SUN8I_DMA_GATE_ENABLE, sdc->base + SUN8I_DMA_GATE); + if (sdc->cfg->clock_autogate_enable) + sdc->cfg->clock_autogate_enable(sdc); return 0; diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 6d23f1d..f8b8d54 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -341,6 +341,12 @@ static const struct sun4i_pwm_data sun4i_pwm_data_h3 = { .npwm = 1, }; +static const struct sun4i_pwm_data sun4i_pwm_data_a64 = { + .has_prescaler_bypass = true, + .has_rdy = true, + .npwm = 1, +}; + static const struct of_device_id sun4i_pwm_dt_ids[] = { { .compatible = "allwinner,sun4i-a10-pwm", @@ -358,6 +364,9 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = { .compatible = "allwinner,sun8i-h3-pwm", .data = &sun4i_pwm_data_h3, }, { + .compatible = "allwinner,sun50i-a64-pwm", + .data = &sun4i_pwm_data_a64, + }, { /* sentinel */ }, };