From: Baikal Electronics Date: Wed, 5 Jul 2023 11:04:36 +0000 (+0300) Subject: SDK 6.2 X-Git-Tag: baikal/aarch64/sdk6.2 X-Git-Url: https://git.baikalelectronics.ru/sdk/?a=commitdiff_plain;h=refs%2Fheads%2Fbaikal%2Faarch64%2F6.1.31.y;p=kernel.git SDK 6.2 --- diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 76580b932e446..fea21819f6c9d 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -33,6 +33,17 @@ config ARCH_APPLE This enables support for Apple's in-house ARM SoC family, starting with the Apple M1. +config ARCH_BAIKAL + bool "Baikal Electronics SoC family" + select DW_APB_TIMER_OF + select GPIOLIB + select GPIO_DWAPB + select MULTIPLEXER + select OF_GPIO + select PINCTRL + help + This enables support for Baikal Electronics SoC family + menuconfig ARCH_BCM bool "Broadcom SoC Support" @@ -354,4 +365,15 @@ config ARCH_ZYNQMP help This enables support for Xilinx ZynqMP Family +# The GPIO number here must be sorted by descending number. +# In a case of multiplatform kernel we want the highest value +# required by selected platforms +config ARCH_NR_GPIO + int + default 0 + help + Maximum number of GPIOs in the system. + + If unsure, leave the default value. + endmenu # "Platform selection" diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index 7b107fa7414bf..b02494b61441e 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -8,6 +8,7 @@ subdir-y += amlogic subdir-y += apm subdir-y += apple subdir-y += arm +subdir-y += baikal subdir-y += bitmain subdir-y += broadcom subdir-y += cavium diff --git a/arch/arm64/boot/dts/baikal/Makefile b/arch/arm64/boot/dts/baikal/Makefile new file mode 100644 index 0000000000000..17201158be656 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +dtb-$(CONFIG_ARCH_BAIKAL) += bm1000-dbm10.dtb +dtb-$(CONFIG_ARCH_BAIKAL) += bm1000-dbm20.dtb +dtb-$(CONFIG_ARCH_BAIKAL) += bm1000-mbm10.dtb +dtb-$(CONFIG_ARCH_BAIKAL) += bm1000-mbm20.dtb +dtb-$(CONFIG_ARCH_BAIKAL) += bm1000-qemu-m.dtb +dtb-$(CONFIG_ARCH_BAIKAL) += bs1000-dbs.dtb +dtb-$(CONFIG_ARCH_BAIKAL) += bs1000-dbs-ov.dtb +dtb-$(CONFIG_ARCH_BAIKAL) += bs1000-qemu-s.dtb diff --git a/arch/arm64/boot/dts/baikal/bm1000-coresight.dtsi b/arch/arm64/boot/dts/baikal/bm1000-coresight.dtsi new file mode 100644 index 0000000000000..e4a6f94ff9e6d --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000-coresight.dtsi @@ -0,0 +1,522 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for BE-M1000 SoC CoreSight subsystem + * Copyright (C) 2023 Baikal Electronics, JSC + */ + +#include + +#define CA57_DEBUG(cl, c, base, n) \ + debug##c: debug@##base##10000 { \ + compatible = "arm,coresight-cpu-debug", "arm,primecell"; \ + reg = <0x0 0x##base##10000 0x0 0x1000>; \ + clocks = <&cs_pclk>; \ + clock-names = "apb_pclk"; \ + cpu = <&cpu##c>; \ + }; \ + \ + etm##c: etm@##base##40000 { \ + compatible = "arm,coresight-etm4x", "arm,primecell"; \ + reg = <0x0 0x##base##40000 0x0 0x1000>; \ + clocks = <&cs_pclk>, <&cs_atclk>; \ + clock-names = "apb_pclk", "atclk"; \ + cpu = <&cpu##c>; \ + \ + out-ports { \ + port { \ + etm##c##_out_port: endpoint { \ + remote-endpoint = \ + <&funnel##cl##_in_port##n>; \ + }; \ + }; \ + }; \ + }; \ + \ + cti##cl##_##n: cti@##base##20000 { \ + compatible = "arm,coresight-cti-v8-arch", "arm,coresight-cti", \ + "arm,primecell"; \ + reg = <0x0 0x##base##20000 0x0 0x1000>; \ + clocks = <&cs_pclk>; \ + clock-names = "apb_pclk"; \ + \ + cpu = <&cpu##c>; \ + arm,cs-dev-assoc = <&etm##c>; \ + } + +#define CA57_CS(cl, c0, c1, cs_base, debug0_base, debug1_base) \ + CA57_DEBUG(cl,c0,debug0_base,0); \ + CA57_DEBUG(cl,c1,debug1_base,1); \ + \ + funnel##cl: funnel##cl { \ + /* \ + * non-configurable replicators don't show up on the \ + * AMBA bus. As such no need to add "arm,primecell". \ + */ \ + compatible = "arm,coresight-static-funnel"; \ + \ + out-ports { \ + port { \ + funnel##cl##_out_port: endpoint { \ + remote-endpoint = \ + <&etf##cl##_in_port>; \ + }; \ + }; \ + }; \ + \ + in-ports { \ + #address-cells = <1>; \ + #size-cells = <0>; \ + \ + port@0 { \ + reg = <0>; \ + funnel##cl##_in_port0: endpoint { \ + remote-endpoint = \ + <&etm##c0##_out_port>; \ + }; \ + }; \ + \ + port@1 { \ + reg = <1>; \ + funnel##cl##_in_port1: endpoint { \ + remote-endpoint = \ + <&etm##c1##_out_port>; \ + }; \ + }; \ + }; \ + }; \ + \ + etf##cl: etf@##cs_base { /* ETF 512B */ \ + compatible = "arm,coresight-tmc", "arm,primecell"; \ + reg = <0x0 0x##cs_base 0x0 0x1000>; \ + clocks = <&cs_pclk>, <&cs_atclk>; \ + clock-names = "apb_pclk", "atclk"; \ + \ + out-ports { \ + port { \ + etf##cl##_out_port: endpoint { \ + remote-endpoint = \ + <&funnel_in_port##cl>; \ + }; \ + }; \ + }; \ + \ + in-ports { \ + port { \ + etf##cl##_in_port: endpoint { \ + remote-endpoint = \ + <&funnel##cl##_out_port>; \ + }; \ + }; \ + }; \ + } + +/ { + clocks { + cs_pclk: cs_pclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <250000000>; + clock-output-names = "cs_pclk"; + }; + + cs_atclk: cs_atclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <250000000>; + clock-output-names = "cs_atclk"; + }; + }; + + soc { + /* CA57 MM's */ + + CA57_CS(0,0,1,5009000,52,53); + CA57_CS(1,2,3,500a000,54,55); + CA57_CS(2,4,5,500b000,56,57); + CA57_CS(3,6,7,500c000,58,59); + + /* CoreSight MM */ + + tpiu: tpiu@500e000 { + compatible = "arm,coresight-tpiu", "arm,primecell"; + reg = <0x0 0x500e000 0x0 0x1000>; + clocks = <&cs_pclk>, <&cs_atclk>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + port { + tpiu_in_port: endpoint { + remote-endpoint = + <&etb_out_port>; + }; + }; + }; + }; + + etb: etb@5007000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x5007000 0x0 0x1000>; + clocks = <&cs_pclk>, <&cs_atclk>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + etb_out_port: endpoint { + remote-endpoint = + <&tpiu_in_port>; + }; + }; + }; + + in-ports { + port { + etb_in_port: endpoint { + remote-endpoint = + <&replicator_out_port1>; + }; + }; + }; + }; + + etr: etr@5008000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x5008000 0x0 0x1000>; + clocks = <&cs_pclk>, <&cs_atclk>; + clock-names = "apb_pclk", "atclk"; + + in-ports { + port { + etr_in_port: endpoint { + remote-endpoint = + <&replicator_out_port0>; + }; + }; + }; + }; + + replicator: replicator@5010000 { + compatible = "arm,coresight-dynamic-replicator", "arm,primecell"; + reg = <0x0 0x5010000 0x0 0x1000>; + clocks = <&cs_pclk>, <&cs_atclk>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + #address-cells = <1>; + #size-cells = <0>; + + /* replicator output ports */ + port@0 { + reg = <0>; + replicator_out_port0: endpoint { + remote-endpoint = + <&etr_in_port>; + }; + }; + + port@1 { + reg = <1>; + replicator_out_port1: endpoint { + remote-endpoint = + <&etb_in_port>; + }; + }; + }; + + in-ports { + port { + replicator_in_port: endpoint { + remote-endpoint = + <&etf_out_port>; + }; + }; + }; + }; + + etf: etf@500d000 { /* ETF 2048B */ + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x500d000 0x0 0x1000>; + clocks = <&cs_pclk>, <&cs_atclk>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + etf_out_port: endpoint { + remote-endpoint = + <&replicator_in_port>; + }; + }; + }; + + in-ports { + port { + etf_in_port: endpoint { + remote-endpoint = + <&funnel_out_port>; + }; + }; + }; + }; + + funnel: funnel@5011000 { + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; + reg = <0x0 0x5011000 0x0 0x1000>; + clocks = <&cs_pclk>, <&cs_atclk>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + funnel_out_port: endpoint { + remote-endpoint = + <&etf_in_port>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in_port0: endpoint { + remote-endpoint = + <&etf0_out_port>; + }; + }; + + port@1 { + reg = <1>; + funnel_in_port1: endpoint { + remote-endpoint = + <&etf1_out_port>; + }; + }; + + port@2 { + reg = <2>; + funnel_in_port2: endpoint { + remote-endpoint = + <&etf2_out_port>; + }; + }; + + port@3 { + reg = <3>; + funnel_in_port3: endpoint { + remote-endpoint = + <&etf3_out_port>; + }; + }; + + port@4 { + reg = <4>; + funnel_in_port4: endpoint { + remote-endpoint = + <&stm0_out_port>; + }; + }; +#if 0 + /* + * Disable stm1 port due to coresight-stm driver + * doesn't initialize stm node without stimulus area. + */ + port@05 { + reg = <5>; + funnel_in_port5: endpoint { + remote-endpoint = + <&stm1_out_port>; + }; + }; +#endif + }; + }; + + stm0: stm@5001000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0x0 0x5001000 0x0 0x1000>, + <0x0 0x7000000 0x0 0x1000000>; + reg-names = "stm-base", "stm-stimulus-base"; + clocks = <&cs_pclk>, <&cs_atclk>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + stm0_out_port: endpoint { + remote-endpoint = + <&funnel_in_port4>; + }; + }; + }; + }; +#if 0 + /* + * Disable stm1 node due to coresight-stm driver + * doesn't initialize stm node without stimulus area. + */ + stm1: stm@5002000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0x0 0x5002000 0x0 0x1000>; + reg-names = "stm-base"; + clocks = <&cs_pclk>, <&cs_atclk>; + clock-names = "apb_pclk", "atclk"; + + out-ports { + port { + stm1_out_port: endpoint { + remote-endpoint = + <&funnel_in_port1>; + }; + }; + }; + }; +#endif + cti0: cti@5004000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x5004000 0x0 0x1000>; + clocks = <&cs_pclk>; + clock-names = "apb_pclk"; + + #address-cells = <1>; + #size-cells = <0>; + + trig-conns@0 { + reg = <0>; + arm,trig-in-sigs = <0>; + arm,trig-conn-name = "ccn_dbgwatchtrig"; + }; + + trig-conns@1 { + reg = <1>; + arm,trig-in-sigs = <2 3 4 5>; + arm,trig-in-types = ; + arm,trig-out-sigs = <6 7>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&stm0>; + }; + + trig-conns@3 { + reg = <3>; + arm,trig-out-sigs = <0 1>; + arm,trig-out-types = ; + arm,trig-conn-name = "cctr"; + }; + + trig-conns@4 { + reg = <4>; + arm,trig-out-sigs = <2>; + arm,trig-conn-name = "ccn_pmusnapshot"; + }; + + trig-conns@5 { + reg = <5>; + arm,trig-out-sigs = <3 4>; + arm,trig-out-types = ; + arm,trig-conn-name = "gic_cs_ppii"; + }; +#if 0 + /* + * Disable stm1 events due to coresight-stm driver + * doesn't initialize stm node without stimulus area. + */ + trig-conns@6 { + reg = <6>; + arm,trig-in-sigs = <6 7>; + arm,trig-in-types = ; + arm,cs-dev-assoc = <&stm1>; + }; +#endif + }; + + cti1: cti@5005000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x5005000 0x0 0x1000>; + clocks = <&cs_pclk>; + clock-names = "apb_pclk"; + + #address-cells = <1>; + #size-cells = <0>; + + trig-conns@0 { + reg = <0>; + arm,trig-in-sigs = <0 1>; + arm,trig-in-types = ; + arm,trig-out-sigs = <0 1>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etf0>; + }; + + trig-conns@1 { + reg = <1>; + arm,trig-in-sigs = <2 3>; + arm,trig-in-types = ; + arm,trig-out-sigs = <2 3>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etf1>; + }; + + trig-conns@2 { + reg = <2>; + arm,trig-in-sigs = <4 5>; + arm,trig-in-types = ; + arm,trig-out-sigs = <4 5>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etf2>; + }; + + trig-conns@3 { + reg = <3>; + arm,trig-in-sigs = <6 7>; + arm,trig-in-types = ; + arm,trig-out-sigs = <6 7>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etf3>; + }; + }; + + cti2: cti@5006000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x5006000 0x0 0x1000>; + clocks = <&cs_pclk>; + clock-names = "apb_pclk"; + + #address-cells = <1>; + #size-cells = <0>; + + trig-conns@0 { + reg = <0>; + arm,trig-in-sigs = <0 1>; + arm,trig-in-types = ; + arm,trig-out-sigs = <0 1>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etr>; + }; + + trig-conns@1 { + reg = <1>; + arm,trig-in-sigs = <2 3>; + arm,trig-in-types = ; + arm,trig-out-sigs = <2 3>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etb>; + }; + + trig-conns@2 { + reg = <2>; + arm,trig-in-sigs = <4 5>; + arm,trig-in-types = ; + arm,trig-out-sigs = <4 5>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etf>; + }; + + trig-conns@3 { + reg = <3>; + arm,trig-out-sigs = <6 7>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&tpiu>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bm1000-dbm.dtsi b/arch/arm64/boot/dts/baikal/bm1000-dbm.dtsi new file mode 100644 index 0000000000000..f70bbcbc301fe --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000-dbm.dtsi @@ -0,0 +1,410 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for Baikal Electronics DBM boards + * Copyright (C) 2019-2023 Baikal Electronics, JSC + */ + +#include +#include "bm1000.dtsi" + +/ { + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + mdio-gpio0 = &mdio_gpio; + }; + + chosen { }; + + buttons-backlight { + compatible = "gpio-keys"; + autorepeat; + button-brightness-down { + label = "Brightness Down Button"; + linux,code = ; + gpios = <&porta 18 GPIO_ACTIVE_LOW>; + debounce-interval = <50>; + }; + button-brightness-up { + label = "Brightness Up Button"; + linux,code = ; + gpios = <&porta 17 GPIO_ACTIVE_LOW>; + debounce-interval = <50>; + }; + button-brightness-toggle { + label = "Brightness Toggle Button"; + linux,code = ; + gpios = <&porta 31 GPIO_ACTIVE_LOW>; + debounce-interval = <50>; + }; + }; + + panel { + /* Change status to "okay" to make use of LVDS LCD panel */ + status = "disabled"; + compatible = "panel-lvds"; + width-mm = <223>; + height-mm = <125>; + data-mapping = "vesa-24"; + panel-timing { + /* 1920x1080 @ 60 Hz */ + /* Replace values below with actual panel timings */ + clock-frequency = <148500000>; + hactive = <1920>; + vactive = <1080>; + hsync-len = <44>; + hfront-porch = <88>; + hback-porch = <148>; + vsync-len = <5>; + vfront-porch = <4>; + vback-porch = <36>; + }; + port { + panel_in: endpoint@0 { + remote-endpoint = <&vdu_lvds_out>; + }; + }; + }; + + soc { + mdio_gpio: mdio { + compatible = "baikal,mdio-gpio"; + #address-cells = <1>; + #size-cells = <0>; + mdc-pin = <&porta 28 GPIO_ACTIVE_HIGH>; + mdio-pin = <&porta 29 GPIO_ACTIVE_HIGH>; + rst-pin = <&porta 30 GPIO_ACTIVE_LOW>; + clocks = <&gpio_clk>; + clock-names = "gpioclk"; + status = "okay"; + + ethphy2: ethernet-phy@c { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0xc>; + phy-mode = "xgmii"; + mv,line-mode = "KR"; + mv,host-mode = "KX4"; + }; + + ethphy3: ethernet-phy@e { + compatible = "ethernet-phy-ieee802.3-c45"; + reg = <0xe>; + phy-mode = "xgmii"; + mv,line-mode = "KR"; + mv,host-mode = "KX4"; + }; + }; + }; + + sound { + compatible = "baikal,snd-soc-baikal"; + baikal,cpu-dai = <&i2s>; + baikal,audio-codec = <&tlv320aic3x>; + baikal,dai-name = "tlv320aic3x"; + baikal,codec-name = "tlv320aic3x-hifi"; + baikal,stream-name = "tlv320aic3x hifi"; + }; + + sfp-xgmac0 { + compatible = "sff,sfp"; + i2c-bus = <&i2c1>; + }; + + sfp-xgmac1 { + compatible = "sff,sfp"; + i2c-bus = <&i2c1>; + }; +}; + +&dmac_lsp { + status = "okay"; +}; + +&dmac_m2m { + status = "okay"; +}; + +&gmac0 { + status = "okay"; + phy-handle = <ðphy0>; + phy-mode = "rgmii-id"; +}; + +&gmac1 { + status = "okay"; + phy-handle = <ðphy1>; + phy-mode = "rgmii-id"; +}; + +&gpio32 { + status = "okay"; +}; + +&hda { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + tlv320aic3x: tlv320aic3x@18 { + #sound-dai-cells = <0>; + compatible = "ti,tlv320aic3x"; + reg = <0x18>; + reset-gpios = <&porta 4 GPIO_ACTIVE_LOW>; + status = "okay"; + ai3x-micbias-vg = <1>; + ai3x-ocmv = <1>; + }; +}; + +&i2c2 { + status = "okay"; +}; + +&i2s { + status = "okay"; + sound-dai = <&tlv320aic3x>; +}; + +&mdio0 { + ethphy0: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x3>; + txd0-skew-ps = <0>; + txd1-skew-ps = <0>; + txd2-skew-ps = <0>; + txd3-skew-ps = <0>; + txc-skew-ps = <0xff>; + }; +}; + +&mdio1 { + ethphy1: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x3>; + txd0-skew-ps = <0>; + txd1-skew-ps = <0>; + txd2-skew-ps = <0>; + txd3-skew-ps = <0>; + txc-skew-ps = <0xff>; + }; +}; + +#if 0 +&mmc { + /* eMMC */ + no-sdio; + no-sd; + non-removable; + bus-width = <8>; + max-frequency = <200000000>; + status = "okay"; +} +#else +&mmc { + /* SD */ + no-mmc; + no-sdio; + disable-wp; + bus-width = <4>; + max-frequency = <25000000>; + status = "okay"; +}; +#endif + +&pcie0 { + status = "okay"; + bm1000,gen3-eq-fb-mode = <0>; + bm1000,phy-rx-ctle = <0xf4>; + bm1000,phy-rx-dfe = <0>; +}; + +&pcie1 { + status = "okay"; + bm1000,gen3-eq-fb-mode = <0>; + bm1000,phy-rx-ctle = <0x64>; + bm1000,phy-rx-dfe = <0>; +}; + +&pcie2 { + status = "okay"; + bm1000,gen3-eq-fb-mode = <0>; + bm1000,phy-rx-ctle = <0x34>; + bm1000,phy-rx-dfe = <0>; +}; + +&pvt_cluster0 { + status = "okay"; +}; + +&pvt_cluster1 { + status = "okay"; +}; + +&pvt_cluster2 { + status = "okay"; +}; + +&pvt_cluster3 { + status = "okay"; +}; + +&pvt_mali { + status = "okay"; +}; + +&sata0 { + status = "okay"; +}; + +&sata1 { + status = "okay"; +}; + +&smbus1 { + status = "okay"; +}; + +&smbus2 { + status = "okay"; +}; + +&spi0 { + num-cs = <4>; + cs-gpios = <&porta 24 GPIO_ACTIVE_LOW>, /* SS0 XP8 - DD53 normal flash */ + <&porta 25 GPIO_ACTIVE_LOW>, /* SS1 XP9 */ + <&porta 26 GPIO_ACTIVE_LOW>, /* SS2 XP10 */ + <&porta 27 GPIO_ACTIVE_LOW>; /* SS3 XP11 */ + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <12500000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl1"; + reg = <0x000000 0x40000>; + }; + + partition@40000 { + label = "dtb"; + reg = <0x040000 0x40000>; + }; + + partition@80000 { + label = "uefi-vars"; + reg = <0x080000 0xc0000>; + }; + + partition@140000 { + label = "fip"; + reg = <0x140000 0x6c0000>; + }; + }; + }; +}; + +&spi1 { + num-cs = <8>; + cs-gpios = <&porta 0 GPIO_ACTIVE_LOW>; + status = "okay"; + + espi_test0@0 { + compatible = "jedec,spi-nor"; + reg = <0>; /* CS #0 */ + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-cpha; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + }; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&timer4 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb2 { + status = "okay"; +}; + +&usb3 { + status = "okay"; +}; + +&vdec { + status = "okay"; +}; + +&vdu { + /* + * 'lvds-lanes' property is mandatory to enable LVDS. Valid values are 1, 2 or 4. + * It is also mandatory to provide actual values for 'enable-gpios' property. + * Also make sure that panel's 'status' (see above) is "okay". + */ + status = "okay"; + enable-gpios = <&porta 16 GPIO_ACTIVE_LOW>; + lvds-lanes = <2>; + backlight { + min-brightness-level = <10>; + default-brightness-level = <60>; + brightness-level-step = <2>; + pwm-frequency = <20000>; + }; + ports { + port@1 { + reg = <1>; + vdu_lvds_out: endpoint@0 { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; + +&xgmac0 { + status = "okay"; + ext-phy-handle = <ðphy2>; +}; + +&xgmac1 { + status = "okay"; + ext-phy-handle = <ðphy3>; +}; diff --git a/arch/arm64/boot/dts/baikal/bm1000-dbm10.dts b/arch/arm64/boot/dts/baikal/bm1000-dbm10.dts new file mode 100644 index 0000000000000..e5751636f48f0 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000-dbm10.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for Baikal Electronics DBM 1.0 board + * Copyright (C) 2022 Baikal Electronics, JSC + */ + +/dts-v1/; + +#include "bm1000-dbm.dtsi" + +/ { + model = "Baikal Electronics DBM 1.0"; + compatible = "baikal,dbm10", "baikal,bm1000"; +}; + +&i2c1 { + rtc@56 { + compatible = "abracon,abeoz9"; + reg = <0x56>; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bm1000-dbm20.dts b/arch/arm64/boot/dts/baikal/bm1000-dbm20.dts new file mode 100644 index 0000000000000..12bcd1bd67ec1 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000-dbm20.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for Baikal Electronics DBM 2.0 board + * Copyright (C) 2022 Baikal Electronics, JSC + */ + +/dts-v1/; + +#include "bm1000-dbm.dtsi" + +/ { + model = "Baikal Electronics DBM 2.0"; + compatible = "baikal,dbm20", "baikal,bm1000"; +}; + +&i2c2 { + rtc@56 { + compatible = "abracon,abeoz9"; + reg = <0x56>; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bm1000-mbm.dtsi b/arch/arm64/boot/dts/baikal/bm1000-mbm.dtsi new file mode 100644 index 0000000000000..5964f25bc73b1 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000-mbm.dtsi @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for MBM-compatible boards + * Copyright (C) 2021-2023 Baikal Electronics, JSC + */ + +#include "bm1000.dtsi" + +/ { + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + }; + + chosen { }; + + leds { + compatible = "gpio-leds"; + led0 { + gpios = <&porta 8 GPIO_ACTIVE_HIGH>; + default-state = "keep"; + }; + }; + + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "MITX-Sound-Card"; + simple-audio-card,bitclock-master = <&codec0>; + simple-audio-card,frame-master = <&codec0>; + simple-audio-card,widgets = + "Microphone", "Mic Jack", + "Headphone", "Headphones", + "Speaker", "AUX Out", + "Line", "Line In"; + simple-audio-card,routing = + "Headphones", "RHP", + "Headphones", "LHP", + "AUX Out", "AUXOUT1", + "AUX Out", "AUXOUT2", + "L2", "Mic Jack", + "R2", "Mic Jack", + "LAUX", "Line In", + "RAUX", "Line In"; + simple-audio-card,mic-det-gpio = <&porta 26 GPIO_ACTIVE_LOW>; + simple-audio-card,format = "i2s"; + simple-audio-card,cpu { + sound-dai = <&i2s>; + }; + codec0: simple-audio-card,codec { + sound-dai = <&nau8822 0>; + }; + }; +}; + +&dmac_lsp { + status = "okay"; +}; + +&dmac_m2m { + status = "okay"; +}; + +&gmac0 { + status = "okay"; + phy-handle = <ðphy0>; + phy-mode = "rgmii-id"; +}; + +&gmac1 { + status = "okay"; + phy-handle = <ðphy1>; + phy-mode = "rgmii-id"; +}; + +&gpio32 { + status = "okay"; +}; + +&hdmi { + status = "okay"; +}; + +&i2c1 { + status = "okay"; + + bmc@8 { + compatible = "tp,mitx2-bmc"; + reg = <0x08>; + }; + + nau8822: nau8822@1a { + compatible = "nuvoton,nau8822"; + #sound-dai-cells = <1>; + reg = <0x1a>; + }; + + gpio@50 { + compatible = "nxp,pca9670"; + #gpio-cells = <2>; + gpio-controller; + reg = <0x50>; + }; + + rtc@51 { + compatible = "nxp,pcf2129", "nxp,pcf2127"; + reg = <0x51>; + }; + + /* FRU */ + eeprom@53 { + compatible = "atmel,24c32"; + pagesize = <32>; + reg = <0x53>; + }; +}; + +&i2c2 { + status = "okay"; +}; + +&i2s { + status = "okay"; +}; + +&mdio0 { + ethphy0: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x3>; + txd0-skew-ps = <0>; + txd1-skew-ps = <0>; + txd2-skew-ps = <0>; + txd3-skew-ps = <0>; + txc-skew-ps = <0xff>; + }; +}; + +&mdio1 { + ethphy1: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x3>; + txd0-skew-ps = <0>; + txd1-skew-ps = <0>; + txd2-skew-ps = <0>; + txd3-skew-ps = <0>; + txc-skew-ps = <0xff>; + }; +}; + +&mmc { + /* SD */ + no-mmc; + no-sdio; + disable-wp; + bus-width = <4>; + max-frequency = <25000000>; + status = "okay"; +}; + +&pcie0 { + status = "okay"; + reset-gpios = <&porta 6 GPIO_ACTIVE_LOW>; + bm1000,gen3-eq-fb-mode = <0>; + bm1000,phy-rx-ctle = <0x34>; + bm1000,phy-rx-dfe = <0>; +}; + +&pcie2 { + status = "okay"; + reset-gpios = <&porta 3 GPIO_ACTIVE_LOW>; + bm1000,gen3-eq-fb-mode = <0>; + bm1000,phy-rx-ctle = <0x34>; + bm1000,phy-rx-dfe = <0>; +}; + +&porta { + pcieclk { + gpio-hog; + gpios = <1 GPIO_ACTIVE_LOW>; + output-high; + line-name = "pcie-x8-clock"; + }; +}; + +&pvt_cluster0 { + status = "okay"; +}; + +&pvt_cluster1 { + status = "okay"; +}; + +&pvt_cluster2 { + status = "okay"; +}; + +&pvt_cluster3 { + status = "okay"; +}; + +&pvt_mali { + status = "okay"; +}; + +&sata0 { + status = "okay"; +}; + +&sata1 { + status = "okay"; +}; + +&smbus1 { + status = "okay"; +}; + +&smbus2 { + status = "okay"; +}; + +&spi0 { + num-cs = <4>; + cs-gpios = <0>; + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&timer4 { + status = "okay"; +}; + +&uart1 { + status = "okay"; +}; + +&uart2 { + status = "okay"; +}; + +&usb2 { + status = "okay"; +}; + +&usb3 { + status = "okay"; +}; + +&vdec { + status = "okay"; +}; + +&vdu { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/baikal/bm1000-mbm10.dts b/arch/arm64/boot/dts/baikal/bm1000-mbm10.dts new file mode 100644 index 0000000000000..7dd80e5a24f6e --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000-mbm10.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for MBM 1.0 compatible boards: + * - TP-TF307-MB-A0 Rev.1.0 (BM1BM1-A) + * - TF307-MB-S-C Rev.3.0 + * + * Copyright (C) 2021-2022 Baikal Electronics, JSC + */ + +/dts-v1/; + +#include "bm1000-mbm.dtsi" + +/ { + model = "Baikal Electronics MBM 1.0"; + compatible = "baikal,mbm10", "baikal,bm1000"; + + sound { + simple-audio-card,hp-det-gpio = <&porta 27 GPIO_ACTIVE_HIGH>; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bm1000-mbm20.dts b/arch/arm64/boot/dts/baikal/bm1000-mbm20.dts new file mode 100644 index 0000000000000..23ed4e333e801 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000-mbm20.dts @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for MBM 2.0 compatible boards: + * - TF307-MB-S-D Rev.4.0 (BM1BM1-D) + * + * Copyright (C) 2021-2023 Baikal Electronics, JSC + */ + +/dts-v1/; + +#include +#include "bm1000-mbm.dtsi" + +/ { + model = "Baikal Electronics MBM 2.0"; + compatible = "baikal,mbm20", "baikal,bm1000"; + + buttons-backlight { + compatible = "gpio-keys"; + autorepeat; + button-brightness-down { + label = "Brightness Down Button"; + linux,code = ; + gpios = <&porta 18 GPIO_ACTIVE_LOW>; + debounce-interval = <50>; + }; + button-brightness-up { + label = "Brightness Up Button"; + linux,code = ; + gpios = <&porta 17 GPIO_ACTIVE_LOW>; + debounce-interval = <50>; + }; + button-brightness-toggle { + label = "Brightness Toggle Button"; + linux,code = ; + gpios = <&porta 31 GPIO_ACTIVE_LOW>; + debounce-interval = <50>; + }; + }; + + panel { + /* + * In order to utilize LVDS LCD panel, make sure that + * 'status' is "okay" along with &vdu 'status' (see below). + */ + status = "disabled"; + compatible = "panel-lvds"; + width-mm = <223>; + height-mm = <125>; + data-mapping = "vesa-24"; + panel-timing { + /* 1920x1080 @ 60 Hz */ + /* Replace values below with actual panel timings */ + clock-frequency = <148500000>; + hactive = <1920>; + vactive = <1080>; + hsync-len = <44>; + hfront-porch = <88>; + hback-porch = <148>; + vsync-len = <5>; + vfront-porch = <4>; + vback-porch = <36>; + }; + port { + panel_in: endpoint@0 { + remote-endpoint = <&vdu_lvds_out>; + }; + }; + }; + + sound { + simple-audio-card,hp-det-gpio = <&porta 29 GPIO_ACTIVE_HIGH>; + }; +}; + +&gmac0 { + snps,reset-gpios = <&porta 19 GPIO_ACTIVE_LOW>; + snps,reset-delays-us = <0 10000 50000>; +}; + +&gmac1 { + snps,reset-gpios = <&porta 20 GPIO_ACTIVE_LOW>; + snps,reset-delays-us = <0 10000 50000>; +}; + +&vdu { + /* + * 'lvds-lanes' property is mandatory to enable LVDS. Valid values are 1, 2 or 4. + * It is also mandatory to provide actual values for 'enable-gpios' property. + * Also make sure that panel's 'status' (see above) is "okay". + */ + enable-gpios = <&porta 16 GPIO_ACTIVE_LOW>; + lvds-lanes = <2>; + backlight { + min-brightness-level = <10>; + default-brightness-level = <60>; + brightness-level-step = <2>; + pwm-frequency = <20000>; + }; + ports { + port@1 { + reg = <1>; + vdu_lvds_out: endpoint@0 { + remote-endpoint = <&panel_in>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bm1000-qemu-m.dts b/arch/arm64/boot/dts/baikal/bm1000-qemu-m.dts new file mode 100644 index 0000000000000..fd6b1c237108e --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000-qemu-m.dts @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for Baikal Electronics QEMU-M virtual platform + * Copyright (C) 2018-2023 Baikal Electronics, JSC + */ + +/dts-v1/; + +#include "bm1000.dtsi" + +/ { + model = "Baikal Electronics QEMU-M"; + compatible = "baikal,qemu-m", "baikal,bm1000"; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + }; + + chosen { }; + + memory@80000000 { + device_type = "memory"; + reg = <0x00000000 0x80000000 0x0 0x80000000>; /* 2 GiB */ + }; + + /* + * Device is necessary for UEFI to boot on QEMU, + * need to replace it with something later. + */ + flash@0 { + compatible = "cfi-flash"; + reg = <0x0 0x4000000 0x0 0x4000000>; + bank-width = <0x4>; + }; + + panel: panel { + compatible = "auo,b133htn01"; /* 1920x1080 */ + port { + lcd_panel: endpoint { + remote-endpoint = <&vdu_pads>; + }; + }; + }; +}; + +&gmac0 { + status = "okay"; + phy-handle = <ðphy0>; + phy-mode = "rgmii-id"; +}; + +&gmac1 { + status = "okay"; + phy-handle = <ðphy1>; + phy-mode = "rgmii-id"; +}; + +&mdio0 { + ethphy0: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x3>; + }; +}; + +&mdio1 { + ethphy1: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x3>; + }; +}; + +&mmc { + /* SD */ + no-mmc; + no-sdio; + disable-wp; + bus-width = <4>; + max-frequency = <25000000>; + status = "okay"; + +}; + +&sata0 { + status = "okay"; +}; + +&sata1 { + status = "okay"; +}; + +&spi0 { + num-cs = <6>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <12500000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl1"; + reg = <0x000000 0x40000>; + }; + + partition@40000 { + label = "dtb"; + reg = <0x040000 0x40000>; + }; + + partition@80000 { + label = "uefi-vars"; + reg = <0x080000 0xc0000>; + }; + + partition@140000 { + label = "fip"; + reg = <0x140000 0x6c0000>; + }; + }; + }; +}; + +&uart1 { + status = "okay"; + clocks = <&avlsp_cmu0 1>, <&apb_clk>, <&apb_clk>; + clock-names = "soc_uartclk", "apb_pclk", "baudclk"; +}; + +&vdu { + port { + vdu_pads: endpoint { + remote-endpoint = <&lcd_panel>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bm1000.dtsi b/arch/arm64/boot/dts/baikal/bm1000.dtsi new file mode 100644 index 0000000000000..5007df239405b --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bm1000.dtsi @@ -0,0 +1,1399 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for BE-M1000 SoC + * Copyright (C) 2017-2023 Baikal Electronics, JSC + */ + +#include +#include + +#define CLUSTER_OPP_TABLE(idx) \ + cluster##idx##_opp: opp-table-cluster##idx { \ + compatible = "operating-points-v2"; \ + opp-shared; \ + \ + opp-500000000 { \ + opp-hz = /bits/ 64 <500000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-600000000 { \ + opp-hz = /bits/ 64 <600000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-700000000 { \ + opp-hz = /bits/ 64 <700000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-800000000 { \ + opp-hz = /bits/ 64 <800000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-900000000 { \ + opp-hz = /bits/ 64 <900000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-1000000000 { \ + opp-hz = /bits/ 64 <1000000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-1100000000 { \ + opp-hz = /bits/ 64 <1100000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-1200000000 { \ + opp-hz = /bits/ 64 <1200000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-1300000000 { \ + opp-hz = /bits/ 64 <1300000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-1400000000 { \ + opp-hz = /bits/ 64 <1400000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + opp-1500000000 { \ + opp-hz = /bits/ 64 <1500000000>; \ + clock-latency-ns = <10000000>; \ + }; \ + } + +/ { + compatible = "baikal,bm1000"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic>; + + aliases { + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &smbus1; + i2c4 = &smbus2; + serial0 = &uart1; + serial1 = &uart2; + }; + + clocks { + osc25: oscillator25 { /* external oscillator */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + clock-output-names = "osc25"; + }; + osc27: oscillator27 { /* external oscillator */ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + clock-output-names = "osc27"; + }; + cpu_clk: cpu_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1500000000>; + clock-output-names = "cpuclk"; + }; + apb_clk: apb_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "apb_pclk"; + }; + uart_clk: uart_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <7372800>; + clock-output-names = "soc_uartclk"; + }; + i2c_clk: i2c_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "soc_i2cclk"; + }; + smbus_clk: smbus_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_smbusclk"; + }; + timer1_clk: timer1_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_timer1clk"; + }; + timer2_clk: timer2_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_timer2clk"; + }; + timer3_clk: timer3_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_timer3clk"; + }; + timer4_clk: timer4_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_timer4clk"; + }; + gpio_clk: gpio_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + clock-output-names = "soc_gpioclk"; + }; + spi_clk: spi_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_spiclk"; + }; + soc_ethclk: ethclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "eth_clk"; + }; + soc_xgbeclk: xgbeclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <156250000>; + clock-output-names = "xgbe_clk"; + }; + soc_smc50mhz: clk50mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "smc_clk"; + }; + soc_faxiclk: refclk400mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <400000000>; + clock-output-names = "faxi_clk"; + }; + soc_tmp_clk: refclkXXXmhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "tmpclk"; + }; + gpu_clk: gpu_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <750000000>; + clock-output-names = "gpuclk"; + }; + clk_ahb: clk_ahb { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "clk_ahb"; + }; + clk_xin: clk_xin { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "clk_xin"; + }; + avlsp_cmu1_div7: avlsp_cmu1_div7 { + compatible = "allwinner,sun4i-a10-pll3-2x-clk", "fixed-factor-clock"; + #clock-cells = <0>; + clocks = <&avlsp_cmu1>; + clock-div = <7>; + clock-mult = <1>; + clock-output-names = "lvds_clk"; + }; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + /* Do not use 'cpu-map'. It leads to wrong topology. */ + + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x0>; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&cluster0_l2>; + clocks = <&cluster0_cmu0>; + operating-points-v2 = <&cluster0_opp>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x1>; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&cluster0_l2>; + clocks = <&cluster0_cmu0>; + operating-points-v2 = <&cluster0_opp>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x100>; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&cluster1_l2>; + clocks = <&cluster1_cmu0>; + operating-points-v2 = <&cluster1_opp>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x101>; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&cluster1_l2>; + clocks = <&cluster1_cmu0>; + operating-points-v2 = <&cluster1_opp>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu4: cpu@200 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x200>; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&cluster2_l2>; + clocks = <&cluster2_cmu0>; + operating-points-v2 = <&cluster2_opp>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu5: cpu@201 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x201>; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&cluster2_l2>; + clocks = <&cluster2_cmu0>; + operating-points-v2 = <&cluster2_opp>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu6: cpu@300 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x300>; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&cluster3_l2>; + clocks = <&cluster3_cmu0>; + operating-points-v2 = <&cluster3_opp>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + cpu7: cpu@301 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x0 0x301>; + enable-method = "psci"; + i-cache-size = <0xc000>; + i-cache-line-size = <64>; + i-cache-sets = <256>; + d-cache-size = <0x8000>; + d-cache-line-size = <64>; + d-cache-sets = <256>; + next-level-cache = <&cluster3_l2>; + clocks = <&cluster3_cmu0>; + operating-points-v2 = <&cluster3_opp>; + cpu-idle-states = <&CPU_SLEEP>; + }; + + idle-states { + entry-method = "psci"; + + CPU_SLEEP: cpu-sleep { + compatible = "arm,idle-state"; + local-timer-stop; + arm,psci-suspend-param = <0x0000001>; + entry-latency-us = <300>; + exit-latency-us = <1200>; + min-residency-us = <2000>; + }; + }; + + cluster0_l2: l2-cache0 { + compatible = "cache"; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; + cache-unified; + cache-level = <2>; + next-level-cache = <&l3>; + }; + + cluster1_l2: l2-cache1 { + compatible = "cache"; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; + cache-unified; + cache-level = <2>; + next-level-cache = <&l3>; + }; + + cluster2_l2: l2-cache2 { + compatible = "cache"; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; + cache-unified; + cache-level = <2>; + next-level-cache = <&l3>; + }; + + cluster3_l2: l2-cache3 { + compatible = "cache"; + cache-size = <0x100000>; + cache-line-size = <64>; + cache-sets = <1024>; + cache-unified; + cache-level = <2>; + next-level-cache = <&l3>; + }; + + l3: l3-cache { + cache-size = <0x800000>; + cache-unified; + cache-level = <3>; + }; + }; + + CLUSTER_OPP_TABLE(0); + CLUSTER_OPP_TABLE(1); + CLUSTER_OPP_TABLE(2); + CLUSTER_OPP_TABLE(3); + + pmu { + compatible = "arm,cortex-a57-pmu"; + interrupts = ; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + cluster0_cmu0: clock-controller@28000000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0x28000000 0x0 0x10000>; + clock-output-names = "bm1000-cluster0-cmu0"; + #clock-cells = <0>; + clocks = <&osc25>; + clock-frequency = <1500000000>; + min = <500000000>; + max = <1500000000>; + }; + + cluster1_cmu0: clock-controller@c000000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0xc000000 0x0 0x10000>; + clock-output-names = "bm1000-cluster1-cmu0"; + #clock-cells = <0>; + clocks = <&osc25>; + clock-frequency = <1500000000>; + min = <500000000>; + max = <1500000000>; + }; + + cluster2_cmu0: clock-controller@a000000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0xa000000 0x0 0x10000>; + clock-output-names = "bm1000-cluster2-cmu0"; + #clock-cells = <0>; + clocks = <&osc25>; + clock-frequency = <1500000000>; + min = <500000000>; + max = <1500000000>; + }; + + cluster3_cmu0: clock-controller@26000000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0x26000000 0x0 0x10000>; + clock-output-names = "bm1000-cluster3-cmu0"; + #clock-cells = <0>; + clocks = <&osc25>; + clock-frequency = <1500000000>; + min = <500000000>; + max = <1500000000>; + }; + + avlsp_cmu0: clock-controller@20000000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0x20000000 0x0 0x10000>; + clock-output-names = "bm1000-avlsp-cmu0"; + #clock-cells = <1>; + clocks = <&osc25>; + clock-frequency = <1200000000>; + min = <800000>; + max = <2100000000>; + clock-names = "gpio", + "uart1", + "uart2", + "apb", + "spi", + "espi", + "i2c1", + "i2c2", + "timer1", + "timer2", + "timer3", + "timer4", + "hclk", + "smbus1", + "smbus2", + "hda_sys_clk", + "hda_clk48", + "mshc_axi", + "mshc_ahb", + "mshc_tx_x2", + "mshc_b", + "mshc_tm", + "mshc_cqetm", + "hwa_clu", + "hwa_clu_hf", + "hwa_axi", + "vdu_axi", + "smmu"; + clock-indices = <0>, <1>, <2>, <3>, <4>, <5>, <6>, + <7>, <8>, <9>, <10>, <11>, <12>, <13>, + <14>, <15>, <16>, <17>, <18>, <19>, <20>, + <21>, <22>, <23>, <24>, <25>, <26>, <27>; + }; + + avlsp_cmu1: clock-controller@20010000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0x20010000 0x0 0x10000>; + clock-output-names = "bm1000-avlsp-cmu1"; + #clock-cells = <0>; + clocks = <&osc27>; + clock-frequency = <1039500000>; + min = <13500000>; + max = <2100000000>; + }; + + mali_cmu0: clock-controller@2a000000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0x2a000000 0x0 0x10000>; + clock-output-names = "bm1000-mali-cmu0"; + #clock-cells = <0>; + clocks = <&osc25>; + clock-frequency = <750000000>; + min = <400000000>; + max = <800000000>; + clock-names = "aclk"; + }; + + usb_cmu0: clock-controller@2c000000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0x2c000000 0x0 0x10000>; + clock-output-names = "bm1000-usb-cmu0"; + #clock-cells = <1>; + clocks = <&osc25>; + clock-frequency = <800000000>; + min = <100000000>; + max = <800000000>; + clock-names = "sata_ref_alt_clk", + "sata_aclk_u0", + "sata_aclk_u1", + "usb2_phy0_ref_clk", + "usb2_phy1_ref_clk", + "usb2_aclk", + "usb2_clk_sofitp", + "usb3_phy0_ref_clk", + "usb3_phy1_ref_clk", + "usb3_phy2_ref_clk", + "usb3_phy3_ref_clk", + "usb3_aclk", + "usb3_clk_sofitp", + "usb3_clk_suspend", + "smmu_aclk", + "dmac_aclk", + "gic_aclk"; + clock-indices = <0>, <1>, <2>, <3>, <4>, <5>, + <6>, <7>, <8>, <9>, <10>, <11>, + <12>, <13>, <14>, <15>, <16>; + }; + + xgbe_cmu0: clock-controller@30000000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0x30000000 0x0 0x10000>; + clock-output-names = "bm1000-xgbe-cmu0"; + #clock-cells = <1>; + clocks = <&osc25>; + clock-frequency = <1250000000>; + min = <50000000>; + max = <1250000000>; + clock-names = "csr50mhz", + "gmac0_tx2", + "gmac1_tx2", + "hdmi_aclk", + "isfr"; + clock-indices = <0>, <10>, <13>, <15>, <17>; + }; + + xgbe_cmu1: clock-controller@30010000 { + compatible = "baikal,bm1000-cmu"; + reg = <0x0 0x30010000 0x0 0x10000>; + clock-output-names = "bm1000-xgbe-cmu1"; + #clock-cells = <1>; + clocks = <&osc27>; + clock-frequency = <25250000>; + min = <13500000>; + max = <600000000>; + clock-names = "pixelclk"; + clock-indices = <0>; + }; + + pcie_gpr: syscon@2050000 { + compatible = "baikal,bm1000-pcie-gpr", "syscon"; + reg = <0x0 0x2050000 0x0 0x100>; + }; + + pcie0: pcie@2200000 { /* PCIe x4 #0 */ + device_type = "pci"; + compatible = "baikal,bm1000-pcie"; + reg = <0x00000000 0x02200000 0x0 0x1000>, + <0x00000040 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "config"; + bus-range = <0x0 0xff>; + interrupts = , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "aer", "pme", "msi", + "msi0", "msi1", "msi2", "msi3", + "msi4", "msi5", "msi6", "msi7"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00000000 0x0 0x4ff00000 0x0 0x100000>, + <0x82000000 0x0 0x40100000 0x0 0x40100000 0x0 0xfe00000>; + num-lanes = <4>; + num-viewport = <4>; + msi-parent = <&its>; + msi-map = <0x0 &its 0x0 0x10000>; + status = "disabled"; + }; + + pcie1: pcie@2210000 { /* PCIe x4 #1 */ + device_type = "pci"; + compatible = "baikal,bm1000-pcie"; + reg = <0x00000000 0x02210000 0x0 0x1000>, + <0x00000050 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "config"; + bus-range = <0x0 0xff>; + interrupts = , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "aer", "pme", "msi", + "msi0", "msi1", "msi2", "msi3", + "msi4", "msi5", "msi6", "msi7"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00100000 0x0 0x5ff00000 0x0 0x100000>, + <0x82000000 0x0 0x50000000 0x0 0x50000000 0x0 0xff00000>; + num-lanes = <4>; + num-viewport = <4>; + msi-parent = <&its>; + msi-map = <0x0 &its 0x10000 0x10000>; + status = "disabled"; + }; + + pcie2: pcie@2220000 { /* PCIe x8 */ + device_type = "pci"; + compatible = "baikal,bm1000-pcie"; + reg = <0x00000000 0x02220000 0x0 0x1000>, + <0x00000060 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "config"; + bus-range = <0x0 0xff>; + interrupts = , + , + , + , + , + , + , + , + , + , + ; + interrupt-names = "aer", "pme", "msi", + "msi0", "msi1", "msi2", "msi3", + "msi4", "msi5", "msi6", "msi7"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00200000 0x0 0x7ff00000 0x0 0x100000>, + <0x82000000 0x0 0x60000000 0x0 0x60000000 0x0 0x1ff00000>; + num-lanes = <8>; + num-viewport = <16>; + msi-parent = <&its>; + msi-map = <0x0 &its 0x20000 0x10000>; + status = "disabled"; + }; + + ccn: ccn@9000000 { + compatible = "arm,ccn-504"; + reg = <0x0 0x9000000 0 0x1000000>; + interrupts = ; + }; + + ddr0: memory-controller@e200000 { + compatible = "baikal,bm1000-edac-mc"; + reg = <0x0 0x0e200000 0x0 0x10000>; + interrupts = , /* dfi_alert_err */ + , /* ecc_corrected_err */ + , /* ecc_uncorrected_err */ + , /* sbr_done */ + , /* ecc_corrected_err_fault */ + ; /* ecc_uncorrected_err_fault */ + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + ddr1: memory-controller@22200000 { + compatible = "baikal,bm1000-edac-mc"; + reg = <0x0 0x22200000 0x0 0x10000>; + interrupts = , /* dfi_alert_err */ + , /* ecc_corrected_err */ + , /* ecc_uncorrected_err */ + , /* sbr_done */ + , /* ecc_corrected_err_fault */ + ; /* ecc_uncorrected_err_fault */ + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gpio32: gpio@20200000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0 0x20200000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + porta: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + }; + + spi0: spi@20210000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x0 0x20210000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&avlsp_cmu0 4>; + clock-names = "ssi_clk"; + status = "disabled"; + }; + + i2s: i2s@20220000 { + compatible = "snps,designware-i2s"; + reg = <0x0 0x20220000 0x0 0x10000>; + #sound-dai-cells = <0>; + system-clock-frequency = <12000000>; + interrupts = , /* rx_da */ + /* , rx_or */ + , /* tx_emp */ + ; /* tx_or */ + /* + * dmas = <&dmac_lsp 0 1 0>, + * <&dmac_lsp 1 0 1>; + * dma-names = "tx", "rx"; + */ + clocks = <&soc_tmp_clk>; + clock-names = "i2sclk"; + status = "disabled"; + }; + + uart1: serial@20230000 { + compatible = "baikal,bm1000-uart", "snps,dw-apb-uart"; + reg = <0x0 0x20230000 0x0 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&avlsp_cmu0 1>, <&apb_clk>; + clock-names = "baudclk", "apb_pclk"; + status = "disabled"; + }; + + uart2: serial@20240000 { + compatible = "baikal,bm1000-uart", "snps,dw-apb-uart"; + reg = <0x0 0x20240000 0x0 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&avlsp_cmu0 2>, <&apb_clk>; + clock-names = "baudclk", "apb_pclk"; + status = "disabled"; + }; + + i2c1: i2c@20250000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x20250000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + i2c-sda-hold-time-ns = <500>; + clock-frequency = <400000>; + clocks = <&i2c_clk>; + clock-names = "ref"; + status = "disabled"; + }; + + i2c2: i2c@20260000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x20260000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + i2c-sda-hold-time-ns = <500>; + clock-frequency = <400000>; + clocks = <&i2c_clk>; + clock-names = "ref"; + status = "disabled"; + }; + + smbus1: i2c@20270000 { + compatible = "baikal,bm1000-smbus"; + reg = <0x0 0x20270000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clock-frequency = <100000>; + clocks = <&smbus_clk>; + clock-names = "soc_smbusclk"; + status = "disabled"; + }; + + smbus2: i2c@20280000 { + compatible = "baikal,bm1000-smbus"; + reg = <0x0 0x20280000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clock-frequency = <100000>; + clocks = <&smbus_clk>; + clock-names = "soc_smbusclk"; + status = "disabled"; + }; + + timer1: timer@20290000 { + compatible = "snps,dw-apb-timer"; + reg = <0x0 0x20290000 0x0 0x14>; + interrupts = ; + clocks = <&timer1_clk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer2: timer@20290014 { + compatible = "snps,dw-apb-timer"; + reg = <0x0 0x20290014 0x0 0x14>; + interrupts = ; + clocks = <&timer2_clk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer3: timer@20290028 { + compatible = "snps,dw-apb-timer"; + reg = <0x0 0x20290028 0x0 0x14>; + interrupts = ; + clocks = <&timer3_clk>; + clock-names = "timer"; + status = "disabled"; + }; + + timer4: timer@2029003c { + compatible = "snps,dw-apb-timer"; + reg = <0x0 0x2029003c 0x0 0x14>; + interrupts = ; + clocks = <&timer4_clk>; + clock-names = "timer"; + status = "disabled"; + }; + + spi1: spi@202a0000 { + compatible = "baikal,bm1000-espi"; + reg = <0x0 0x202a0000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&avlsp_cmu0 5>; + clock-names = "soc_espiclk"; + status = "disabled"; + /* + * Block Configuration: + * - master/slave + * - 32-bit APB slave + * - tx-fifo = rx-fifo = 256 byte + * - 4 SPI IO channels + * - 8 slave select IO channels + * - DMA - missing + * - M-flash controller - missing + */ + }; + + dmac_lsp: dma-controller@202b0000 { + compatible = "snps,dma-spear1340"; + reg = <0x0 0x202b0000 0x0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + + clocks = <&avlsp_cmu0 12>; + clock-names = "hclk"; + + dma-channels = <8>; + dma-requests = <16>; + dma-masters = <2>; + #dma-cells = <4>; + + chan_allocation_order = <0>; + chan_priority = <0>; + block_size = <0xff>; + data-width = <4 16>; + multi-block = <1 1 1 1 1 1 1 1>; + snps,max-burst-len = <32 32 32 32 32 32 32 32>; + snps,dma-protection-control = <1>; + + status = "disabled"; + }; + + hda: hda@202c0000 { + compatible = "baikal,bm1000-hda"; + reg = <0x0 0x202c0000 0x0 0x1000>; + interrupts = ; + clocks = <&avlsp_cmu0 15>, <&avlsp_cmu0 16>; + clock-names = "hda_sys_clk", "hda_clk48"; + status = "disabled"; + force-polling-mode; + broken-response-irq; + increment-codec-address; + cyclic-codec-probe; + }; + + mmc: mmc@202e0000 { + compatible = "baikal,dwcmshc-sdhci"; + reg = <0x0 0x202e0000 0x0 0x10000>; + interrupts = , + ; + clocks = <&avlsp_cmu0 18>, <&avlsp_cmu0 19>; + clock-names = "bus", "core"; + no-1-8-v; + status = "disabled"; + }; + + vdec: vdec@24200000 { + compatible = "baikal,d5500-vxd"; + reg = <0x0 0x24200000 0x0 0x10000>; + interrupts = ; + status = "disabled"; + }; + + mali: gpu@2a200000 { + compatible = "arm,mali-midgard", "arm,mali-t628"; + reg = <0x0 0x2a200000 0x0 0x4000>; + #cooling-cells = <2>; /* min followed by max */ + interrupts = , + , + ; + interrupt-names = "job", "mmu", "gpu"; + clocks = <&mali_cmu0>; + clock-names = "gpuclk"; + operating-points-v2 = <&gpu_opp_table>; + dma-coherent; + + gpu_opp_table: opp-table { + compatible = "operating-points-v2", "operating-points-v2-mali"; + + opp-400000000 { + opp-hz = /bits/ 64 <400000000>; + clock-latency-ns = <10000000>; + }; + opp-450000000 { + opp-hz = /bits/ 64 <450000000>; + clock-latency-ns = <10000000>; + }; + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + clock-latency-ns = <10000000>; + }; + opp-550000000 { + opp-hz = /bits/ 64 <550000000>; + clock-latency-ns = <10000000>; + }; + opp-600000000 { + opp-hz = /bits/ 64 <600000000>; + clock-latency-ns = <10000000>; + }; + opp-650000000 { + opp-hz = /bits/ 64 <650000000>; + clock-latency-ns = <10000000>; + }; + opp-700000000 { + opp-hz = /bits/ 64 <700000000>; + clock-latency-ns = <10000000>; + }; + opp-750000000 { + opp-hz = /bits/ 64 <750000000>; + clock-latency-ns = <10000000>; + }; + }; + }; + + usb2: usb@2c400000 { + compatible = "snps,dwc3"; + reg = <0x0 0x2c400000 0x0 0x100000>; + interrupts = ; + interrupt-names = "dwc_usb3"; + dr_mode="host"; + dma-coherent; + clocks = <&usb_cmu0 5>, <&usb_cmu0 6>; + clock-names = "bus_early", "ref"; + phys = <&usb_phy 0>; + phy-names = "usb2-phy"; + }; + + usb3: usb@2c500000 { + compatible = "snps,dwc3"; + reg = <0x0 0x2c500000 0x0 0x100000>; + interrupts = ; + interrupt-names = "dwc_usb3"; + dr_mode="host"; + dma-coherent; + clocks = <&usb_cmu0 11>, <&usb_cmu0 12>, <&usb_cmu0 13>; + clock-names = "bus_early", "ref", "suspend"; + phys = <&usb_phy 1>, <&usb_phy 2>; + phy-names = "usb3-phy", "usb2-phy"; + }; + + usb_phy: usb_phy { + compatible = "baikal,bm1000-usb-phy"; + status = "okay"; + clocks = <&usb_cmu0 3>, <&usb_cmu0 4>, <&usb_cmu0 7>, + <&usb_cmu0 8>, <&usb_cmu0 9>, <&usb_cmu0 10>; + #phy-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + usb-phy@0 { + reg = <0>; + enable; + }; + usb-phy@1 { + reg = <1>; + enable; + }; + usb-phy@2 { + reg = <2>; + enable; + }; + }; + + sata0: sata@2c600000 { + compatible = "baikal,bm1000-ahci"; + reg = <0x0 0x2c600000 0 0x10000>; + interrupts = ; + ports-implemented = <1>; + dma-coherent; + clocks = <&soc_faxiclk>; + clock-names = "aclk"; + status = "disabled"; + }; + + sata1: sata@2c610000 { + compatible = "baikal,bm1000-ahci"; + reg = <0x0 0x2c610000 0 0x10000>; + interrupts = ; + ports-implemented = <1>; + dma-coherent; + clocks = <&soc_faxiclk>; + clock-names = "aclk"; + status = "disabled"; + }; + + dmac_m2m: dma-controller@2c630000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0x2c630000 0 0x10000>; + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <32>; + interrupts = , + , + , + , + , + , + , + , + ; + clocks = <&soc_faxiclk>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + gic: interrupt-controller@2d000000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x2d000000 0x0 0x10000>, /* GICD */ + <0x0 0x2d100000 0x0 0x200000>, /* GICR */ + <0x0 0x10200000 0x0 0x2000>, /* GICC */ + <0x0 0x10210000 0x0 0x1000>, /* GICH */ + <0x0 0x10220000 0x0 0x2000>; /* GICV */ + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + interrupt-controller; + interrupts = ; + + its: interrupt-controller@2d020000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x2d020000 0x0 0x20000>; /* GITS */ + msi-controller; + }; + }; + + xgmac0: ethernet@30200000 { + compatible = "amd,xgbe-seattle-v1a"; + reg = <0x0 0x30200000 0x0 0x10000>, + <0x0 0x30210000 0x0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + fsl,num-rx-queues = <3>; + clocks = <&soc_xgbeclk>, <&soc_xgbeclk>, <&soc_xgbeclk>; + clock-names = "dma_clk", "ptp_clk", "xgbe_clk"; + phy-mode = "xgmii"; + be,pcs-mode = "KX4"; + status = "disabled"; + amd,per-channel-interrupt; + amd,speed-set = <0>; + #stream-id-cells = <16>; + }; + + xgmac1: ethernet@30220000 { + compatible = "amd,xgbe-seattle-v1a"; + reg = <0x0 0x30220000 0x0 0x10000>, + <0x0 0x30230000 0x0 0x10000>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + fsl,num-rx-queues = <3>; + clocks = <&soc_xgbeclk>, <&soc_xgbeclk>, <&soc_xgbeclk>; + clock-names = "dma_clk", "ptp_clk", "xgbe_clk"; + phy-mode = "xgmii"; + be,pcs-mode = "KX4"; + status = "disabled"; + amd,per-channel-interrupt; + amd,speed-set = <0>; + #stream-id-cells = <16>; + }; + + stmmac_axi_setup: stmmac-axi-config { + snps,wr_osr_lmt = <0x0>; + snps,rd_osr_lmt = <0x0>; + snps,blen = <0 0 0 0 0 0 4>; + }; + + gmac0: ethernet@30240000 { + compatible = "baikal,bm1000-gmac"; + reg = <0x0 0x30240000 0x0 0x10000>; + interrupts = ; + interrupt-names = "macirq"; + max-speed = <1000>; + clocks = <&soc_ethclk>, <&xgbe_cmu0 10>; + clock-names = "stmmaceth", "tx2_clk"; + snps,axi-config = <&stmmac_axi_setup>; + snps,fixed-burst; + snps,no-pbl-x8; + snps,txpbl = <4>; + snps,rxpbl = <4>; + status = "disabled"; + dma-coherent; + + mdio0: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + gmac1: ethernet@30250000 { + compatible = "baikal,bm1000-gmac"; + reg = <0x0 0x30250000 0x0 0x10000>; + interrupts = ; + interrupt-names = "macirq"; + max-speed = <1000>; + clocks = <&soc_ethclk>, <&xgbe_cmu0 13>; + clock-names = "stmmaceth", "tx2_clk"; + snps,axi-config = <&stmmac_axi_setup>; + snps,fixed-burst; + snps,no-pbl-x8; + snps,txpbl = <4>; + snps,rxpbl = <4>; + status = "disabled"; + dma-coherent; + + mdio1: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + vdu: vdu@202d0000 { + compatible = "baikal,vdu"; + reg = <0x0 0x202d0000 0x0 0x1000>, + <0x0 0x30260000 0x0 0x1000>; + reg-names = "lvds_regs", "hdmi_regs"; + interrupts = , + ; + interrupt-names = "lvds_irq", "hdmi_irq"; + clocks = <&avlsp_cmu1_div7>, <&xgbe_cmu1 0>; + clock-names = "lvds_pclk", "hdmi_pclk"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + vdu_hdmi_out: endpoint { + remote-endpoint = <&hdmi_tx_in>; + }; + }; + }; + }; + + hdmi: hdmi@30280000 { + compatible = "baikal,hdmi"; + reg = <0x0 0x30280000 0x0 0x20000>; + reg-io-width = <4>; + interrupts = ; + clocks = <&xgbe_cmu0 0>, <&xgbe_cmu0 17>; + clock-names = "iahb", "isfr"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + hdmi_tx_in: endpoint { + remote-endpoint = <&vdu_hdmi_out>; + }; + }; + port@1 { + reg = <1>; + hdmi_tx_out: endpoint { + remote-endpoint = <&hdmi_con>; + }; + }; + }; + }; + + pvt_cluster0: pvt@28200000 { + compatible = "baikal,bm1000-pvt"; + reg = <0x0 0x28200000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_cluster1: pvt@c200000 { + compatible = "baikal,bm1000-pvt"; + reg = <0x0 0xc200000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_cluster2: pvt@a200000 { + compatible = "baikal,bm1000-pvt"; + reg = <0x0 0xa200000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_cluster3: pvt@26200000 { + compatible = "baikal,bm1000-pvt"; + reg = <0x0 0x26200000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_mali: pvt@2a060000 { + compatible = "baikal,bm1000-pvt"; + reg = <0x0 0x2a060000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + }; + + hdmi-out { + compatible = "hdmi-connector"; + label = "HDMI0 OUT"; + type = "a"; + + port { + hdmi_con: endpoint { + remote-endpoint = <&hdmi_tx_out>; + }; + }; + }; +}; + +#include "bm1000-coresight.dtsi" diff --git a/arch/arm64/boot/dts/baikal/bs1000-clocks.dtsi b/arch/arm64/boot/dts/baikal/bs1000-clocks.dtsi new file mode 100644 index 0000000000000..585c84ae9fa1a --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000-clocks.dtsi @@ -0,0 +1,619 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for BE-S1000 SoC clocks + * Copyright (C) 2021-2023 Baikal Electronics, JSC + */ + +#define CLK_TYPE_NO 0 +#define CLK_TYPE_REFCLK 1 /* fout = 25 MHz or 100 MHz */ +#define CLK_TYPE_PLL 2 /* fout = fref * NF / (NR * OD) */ +#define CLK_TYPE_CLKCH 3 /* fout = fref / (VAL_CLKDIV + 1) */ +#define CLK_TYPE_CLKEN 4 /* fout = fref / DIV_VAL */ +#define CLK_TYPE_CLKDIV 5 /* fout = fref / 2^(DIV_VAL - 1) */ + +#define CA75_CLOCKS(num, base) \ + /* pll */ \ + cluster##num##_cmu0_pll: \ + cluster##num##_cmu0_pll { \ + compatible = "baikal,bs1000-cmu"; \ + reg = <(base + 0x0)>; \ + type = ; \ + clocks = <&clk_ref>; \ + #clock-cells = <0>; \ + /*clock-frequency = <1600000000>;*/ \ + clock-output-names = "cmu0_pll"; \ + }; \ + cluster##num##_cmu1_pll: \ + cluster##num##_cmu1_pll { \ + compatible = "baikal,bs1000-cmu"; \ + reg = <(base + 0x10000)>; \ + type = ; \ + clocks = <&clk_ref>; \ + #clock-cells = <0>; \ + /*clock-frequency = <2000000000>;*/ \ + clock-output-names = "cmu1_pll"; \ + }; \ + /* clkch */ \ + cluster##num##_cmu0: \ + cluster##num##_cmu0 { \ + compatible = "baikal,bs1000-cmu"; \ + reg = <(base + 0x100)>; \ + type = ; \ + clocks = <&cluster##num##_cmu0_pll>; \ + #clock-cells = <1>; \ + clock-output-names = \ + "sclk", /* 0 */ \ + "periph", /* 1 */ \ + "pclk", /* 2 */ \ + "at", /* 3 */ \ + "gic", /* 4 */ \ + "cfg_int", /* 5 */ \ + "cfg_out", /* 6 */ \ + "bisr", /* 7 */ \ + "crp"; /* 8 */ \ + }; \ + /* clken */ \ + cluster##num##_cmu0_en0: \ + cluster##num##_cmu0_en0 { \ + compatible = "baikal,bs1000-cmu"; \ + reg = <(base + 0x500)>; \ + type = ; \ + clocks = <&cluster##num##_cmu0 0>; /* "sclk" */ \ + #clock-cells = <0>; \ + clock-output-names = "clken"; \ + }; \ + cluster##num##_cmu0_en1: \ + cluster##num##_cmu0_en1 { \ + compatible = "baikal,bs1000-cmu"; \ + reg = <(base + 0x510)>; \ + type = ; \ + clocks = <&cluster##num##_cmu0 1>; /* "periph" */ \ + #clock-cells = <1>; \ + clock-output-names = \ + "cntclken", /* 0 */ \ + "tsclken"; /* 1 */ \ + }; \ + /* core */ \ + cluster##num##_cmu1: \ + cluster##num##_cmu1 { \ + compatible = "baikal,bs1000-cmu"; \ + reg = <(base + 0x10020)>; \ + type = ; \ + clocks = <&cluster##num##_cmu1_pll>; \ + #clock-cells = <1>; \ + clock-output-names = \ + "core0", /* 0 */ \ + "core1", /* 1 */ \ + "core2", /* 2 */ \ + "core3"; /* 3 */ \ + } + +/ { + soc { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + /* TODO: it is fixed-clocks for QEMU, remove it */ + apb_clk: apb_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "apb_pclk"; + }; + osc25: oscillator25 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + clock-output-names = "osc25"; + }; + osc27: oscillator27 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <27000000>; + clock-output-names = "osc27"; + }; + uart1_clk: uart1_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <8000000>; + clock-output-names = "uart1_clk"; + }; + uart2_clk: uart2_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <8000000>; + clock-output-names = "uart2_clk"; + }; + uart_clk: uart_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <7372800>; + clock-output-names = "soc_uartclk"; + }; + i2c_clk: i2c_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <200000000>; + clock-output-names = "soc_i2cclk"; + }; + timer1_clk: timer1_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_timer1clk"; + }; + timer2_clk: timer2_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_timer2clk"; + }; + timer3_clk: timer3_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_timer3clk"; + }; + timer4_clk: timer4_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_timer4clk"; + }; + wdt_clk: wdt_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + clock-output-names = "wdtclk"; + }; + gpio_clk: gpio_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + clock-output-names = "soc_gpioclk"; + }; + spi_clk: spi_clk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "soc_spiclk"; + }; + soc_ethclk: ethclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "eth_clk"; + }; + soc_xgbeclk: xgbeclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <156250000>; + clock-output-names = "xgbe_clk"; + }; + soc_smc50mhz: clk50mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "smc_clk"; + }; + soc_faxiclk: refclk400mhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <400000000>; + clock-output-names = "faxi_clk"; + }; + soc_tmp_clk: refclkXXXmhz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "tmpclk"; + }; + clk_ahb: clk_ahb { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "clk_ahb"; + }; + clk_xin: clk_xin { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "clk_xin"; + }; + + /* CLK_REF */ + clk_ref: clk_ref { + compatible = "baikal,bs1000-cmu"; + reg = <0xdead>; + type = ; + #clock-cells = <0>; + //clock-frequency = <25000000>; // 25 or 100 MHz + clock-output-names = "clk_ref"; + }; + + /* CA75 */ + CA75_CLOCKS(0, 0x04000000); + CA75_CLOCKS(1, 0x08000000); + CA75_CLOCKS(2, 0x0c000000); + CA75_CLOCKS(3, 0x10000000); + CA75_CLOCKS(4, 0x14000000); + CA75_CLOCKS(5, 0x18000000); + CA75_CLOCKS(6, 0x1c000000); + CA75_CLOCKS(7, 0x20000000); + CA75_CLOCKS(8, 0x24000000); + CA75_CLOCKS(9, 0x28000000); + CA75_CLOCKS(10,0x2c000000); + CA75_CLOCKS(11,0x30000000); + + /* PCIe */ + /* pci.pll */ + cmu_pci_0_pll: cmu_pci_0_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x38000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2000000000>; */ + clock-output-names = "pci_0_pll"; + }; + cmu_pci_1_pll: cmu_pci_1_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x3c000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2000000000>; */ + clock-output-names = "pci_1_pll"; + }; + cmu_pci_2_pll: cmu_pci_2_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x44000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2000000000>; */ + clock-output-names = "pci_2_pll"; + }; + cmu_pci_3_pll: cmu_pci_3_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x48000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2000000000>; */ + clock-output-names = "pci_3_pll"; + }; + cmu_pci_4_pll: cmu_pci_4_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x4c000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2000000000>; */ + clock-output-names = "pci_4_pll"; + }; + + /* pci.clkch */ + cmu_pci_0: cmu_pci_0 { + compatible = "baikal,bs1000-cmu"; + reg = <0x38000020>; + type = ; + clocks = <&cmu_pci_0_pll>; + #clock-cells = <1>; + clock-output-names = + "nic_cfg0m_ssa_x16p0s", // 0 + "nic_cfg1m_ssa_x8p1s", // 1 + "nic_cfg2m_mmu_tcus", // 2 + "nic_cfg3m_ssa_apbs", // 3 + "nic_cfg4m_nic_slv_gpvs", // 4 + "nic_slv0m_ssa_x16p0s", // 5 + "nic_slv1m_ssa_x8p1s", // 6 + "ssa_x16p0m_nic_mstr0s", // 7 + "ssa_x8p1m_nic_mstr1s", // 8 + "nic_mstrm_mmu_tbu0s", // 9 + "a4sw_intern", // 10 + "phy_ref", // 11 + "ssa_aux", // 12 + "ahb2axim_axi2ahbs", // 13 + "ahb2ahbm_outp_ahbs", // 14 + "ssa_x16p0m_cxlas"; // 15 + }; + cmu_pci_1: cmu_pci_1 { + compatible = "baikal,bs1000-cmu"; + reg = <0x3c000020>; + type = ; + clocks = <&cmu_pci_1_pll>; + #clock-cells = <1>; + clock-output-names = + "nic_cfg0m_ssa_x16p0s", // 0 + "nic_cfg1m_ssa_x8p1s", // 1 + "nic_cfg2m_mmu_tcus", // 2 + "nic_cfg3m_ssa_apbs", // 3 + "nic_cfg4m_nic_slv_gpvs", // 4 + "nic_slv0m_ssa_x16p0s", // 5 + "nic_slv1m_ssa_x8p1s", // 6 + "ssa_x16p0m_nic_mstr0s", // 7 + "ssa_x8p1m_nic_mstr1s", // 8 + "nic_mstrm_mmu_tbu0s", // 9 + "a4sw_intern", // 10 + "phy_ref", // 11 + "ssa_aux", // 12 + "ahb2axim_axi2ahbs", // 13 + "ahb2ahbm_outp_ahbs", // 14 + "ssa_x16p0m_cxlas"; // 15 + }; + cmu_pci_2: cmu_pci_2 { + compatible = "baikal,bs1000-cmu"; + reg = <0x44000020>; + type = ; + clocks = <&cmu_pci_2_pll>; + #clock-cells = <1>; + clock-output-names = + "a", // 0 + "b"; // 1 + }; + cmu_pci_3: cmu_pci_3 { + compatible = "baikal,bs1000-cmu"; + reg = <0x48000020>; + type = ; + clocks = <&cmu_pci_3_pll>; + #clock-cells = <1>; + clock-output-names = + "a", // 0 + "b"; // 1 + }; + cmu_pci_4: cmu_pci_4 { + compatible = "baikal,bs1000-cmu"; + reg = <0x4c000020>; + type = ; + clocks = <&cmu_pci_4_pll>; + #clock-cells = <1>; + clock-output-names = + "a", // 0 + "b"; // 1 + }; + + /* DDR */ + /* ddr.pll */ + cmu_ddr_0_pll: cmu_ddr_0_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x50000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2200000000>; */ + clock-output-names = "ddr_0_pll"; + }; + cmu_ddr_1_pll: cmu_ddr_1_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x54000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2200000000>; */ + clock-output-names = "ddr_1_pll"; + }; + cmu_ddr_2_pll: cmu_ddr_2_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x58000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2200000000>; */ + clock-output-names = "ddr_3_pll"; + }; + cmu_ddr_3_pll: cmu_ddr_3_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x60000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2200000000>; */ + clock-output-names = "ddr_3_pll"; + }; + cmu_ddr_4_pll: cmu_ddr_4_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x64000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2200000000>; */ + clock-output-names = "ddr_4_pll"; + }; + cmu_ddr_5_pll: cmu_ddr_5_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x68000000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <2200000000>; */ + clock-output-names = "ddr_5_pll"; + }; + + /* ddr.clkch */ + cmu_ddr_0: cmu_ddr_0 { + compatible = "baikal,bs1000-cmu"; + reg = <0x50000020>; + type = ; + clocks = <&cmu_ddr_0_pll>; + #clock-cells = <1>; + clock-output-names = + "ddr_ctrl_phy", // 0 + "ddr_axi_slv", // 1 + "ddr_apb_slv"; // 2 + }; + cmu_ddr_1: cmu_ddr_1 { + compatible = "baikal,bs1000-cmu"; + reg = <0x54000020>; + type = ; + clocks = <&cmu_ddr_1_pll>; + #clock-cells = <1>; + clock-output-names = + "ddr_ctrl_phy", // 0 + "ddr_axi_slv", // 1 + "ddr_apb_slv", // 2 + "axi_ext_cfg", // 3 + "axi_middle_cfg", // 4 + "axi_top_cfg", // 5 + "axi_bottom_cfg"; // 6 + }; + cmu_ddr_2: cmu_ddr_2 { + compatible = "baikal,bs1000-cmu"; + reg = <0x58000020>; + type = ; + clocks = <&cmu_ddr_2_pll>; + #clock-cells = <1>; + clock-output-names = + "ddr_ctrl_phy", // 0 + "ddr_axi_slv", // 1 + "ddr_apb_slv"; // 2 + }; + cmu_ddr_3: cmu_ddr_3 { + compatible = "baikal,bs1000-cmu"; + reg = <0x60000020>; + type = ; + clocks = <&cmu_ddr_3_pll>; + #clock-cells = <1>; + clock-output-names = + "ddr_ctrl_phy", // 0 + "ddr_axi_slv", // 1 + "ddr_apb_slv"; // 2 + }; + cmu_ddr_4: cmu_ddr_4 { + compatible = "baikal,bs1000-cmu"; + reg = <0x64000020>; + type = ; + clocks = <&cmu_ddr_4_pll>; + #clock-cells = <1>; + clock-output-names = + "ddr_ctrl_phy", // 0 + "ddr_axi_slv", // 1 + "ddr_apb_slv", // 2 + "axi_ext_cfg", // 3 + "axi_middle_cfg", // 4 + "axi_top_cfg", // 5 + "axi_bottom_cfg"; // 6 + }; + cmu_ddr_5: cmu_ddr_5 { + compatible = "baikal,bs1000-cmu"; + reg = <0x68000020>; + type = ; + clocks = <&cmu_ddr_5_pll>; + #clock-cells = <1>; + clock-output-names = + "ddr_ctrl_phy", // 0 + "ddr_axi_slv", // 1 + "ddr_apb_slv"; // 2 + }; + + /* System Control */ + /* sc.pll */ + cmu_sc_0_pll: cmu_sc_0_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x00400000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <1200000000>; */ + clock-output-names = "sc_0_pll"; + }; + cmu_sc_1_pll: cmu_sc_1_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x00410000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <1200000000>; */ + clock-output-names = "sc_1_pll"; + }; + cmu_sc_2_pll: cmu_sc_2_pll { + compatible = "baikal,bs1000-cmu"; + reg = <0x00420000>; + type = ; + clocks = <&clk_ref>; + #clock-cells = <0>; + /* clock-frequency = <1500000000>; */ + clock-output-names = "sc_2_pll"; + }; + + /* sc.clkch */ + cmu_sc_0: cmu_sc_0 { + compatible = "baikal,bs1000-cmu"; + reg = <0x00400020>; + type = ; + clocks = <&cmu_sc_0_pll>; + #clock-cells = <1>; + clock-output-names = + "cmn", // 0 + "cmn_cs"; // 1 + }; + cmu_sc_1: cmu_sc_1 { + compatible = "baikal,bs1000-cmu"; + reg = <0x00410020>; + type = ; + clocks = <&cmu_sc_1_pll>; + #clock-cells = <1>; + clock-output-names = + "apb_cfg", // 0 + "scp_efuse", // 1 + "scp_ext_cfg", // 2 + "scp_apb_spi", // 3 + "scp_uart", // 4 + "scp_gpio8_x16", // 5, additional divisor by 16 + "scp_spi", // 6 + "scp_smbus_i2c0", // 7 + "scp_smbus_i2c1", // 8 + "gmac1_apb", // 9 + "gmac1_axi", // 10 + "gmac2_apb", // 11 + "gmac2_axi", // 12 + "usb_h", // 13 + "usb_ohci", // 14 + "lsp_apb", // 15 + "lsp_gpio_x16", // 16, additional divisor by 16 + "lsp_uart", // 17 + "lsp_uart_arm1", // 18 + "lsp_uart_arm2", // 19 + "lsp_spi1", // 20 + "lsp_spi2", // 21 + "lsp_espi", // 22 + "lsp_smbus_i2c2", // 23 + "lsp_smbus_i2c3", // 24 + "lsp_smbus_i2c4", // 25 + "lsp_smbus_i2c5", // 26 + "lsp_smbus_i2c6", // 27 + "lsp_timer1", // 28 + "lsp_timer2", // 29 + "lsp_timer3", // 30 + "lsp_timer4", // 31 + "lsp_wdt_x16", // 32, additional divisor by 16 + "tcu", // 33 + "sc_axi_cfg", // 34 + "ca75_ahb_cfg"; // 35 + }; + cmu_sc_2: cmu_sc_2 { + compatible = "baikal,bs1000-cmu"; + reg = <0x00420020>; + type = ; + clocks = <&cmu_sc_2_pll>; + #clock-cells = <1>; + clock-output-names = + "scp", // 0 + "gmac1_ptp", // 1 + "gmac1_txx2", // 2 + "gmac2_ptp", // 3 + "gmac2_txx2", // 4 + "gic_distr", // 5 + "dbg", // 6 + "cnt_valueb", // 7 + "ts_valueb", // 8 + "lpd", // 9 + "tbu", // 10 + "hs_cfg", // 11 + "scp_bisr"; // 12 + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bs1000-coresight.dtsi b/arch/arm64/boot/dts/baikal/bs1000-coresight.dtsi new file mode 100644 index 0000000000000..440fc354ef4cd --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000-coresight.dtsi @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for BE-S1000 SoC CoreSight subsystem + * Copyright (C) 2023 Baikal Electronics, JSC + */ + +#include + +#define CA75_DEBUG(cl, c, base, n) \ + debug##c: debug@##base##n##10000 { \ + compatible = "arm,coresight-cpu-debug", "arm,primecell"; \ + reg = <0x0 0x##base##n##10000 0x0 0x1000>; \ + clocks = <&cluster##cl##_cmu0 2>; \ + clock-names = "apb_pclk"; \ + cpu = <&cpu##c>; \ + }; \ + \ + etm##c: etm@##base##n##40000 { \ + compatible = "arm,coresight-etm4x", "arm,primecell"; \ + reg = <0x0 0x##base##n##40000 0x0 0x1000>; \ + clocks = <&cluster##cl##_cmu0 2>; \ + clock-names = "apb_pclk"; \ + cpu = <&cpu##c>; \ + \ + out-ports { \ + port { \ + etm##c##_out_port: endpoint { \ + remote-endpoint = \ + <&funnel##cl##_in_port##n>; \ + }; \ + }; \ + }; \ + }; \ + \ + cti##cl##_##n: cti@##base##n##20000 { \ + compatible = "arm,coresight-cti-v8-arch", "arm,coresight-cti", \ + "arm,primecell"; \ + reg = <0x0 0x##base##n##20000 0x0 0x1000>; \ + clocks = <&cluster##cl##_cmu0 2>; \ + clock-names = "apb_pclk"; \ + cpu = <&cpu##c>; \ + arm,cs-dev-assoc = <&etm##c>; \ + } + +#define CA75_CS(cl, c0, c1, c2, c3, cs_base, debug_base) \ + CA75_DEBUG(cl,c0,debug_base,0); \ + CA75_DEBUG(cl,c1,debug_base,1); \ + CA75_DEBUG(cl,c2,debug_base,2); \ + CA75_DEBUG(cl,c3,debug_base,3); \ + \ + funnel##cl: funnel@##cs_base##020000 { \ + compatible = "arm,coresight-dynamic-funnel", "arm,primecell"; \ + reg = <0x0 0x##cs_base##020000 0x0 0x1000>; \ + clocks = <&cluster##cl##_cmu0 2>; \ + clock-names = "apb_pclk"; \ + \ + out-ports { \ + port { \ + funnel##cl##_out_port: endpoint { \ + remote-endpoint = \ + <&etb##cl##_in_port>; \ + }; \ + }; \ + }; \ + \ + in-ports { \ + #address-cells = <1>; \ + #size-cells = <0>; \ + \ + port@0 { \ + reg = <0>; \ + funnel##cl##_in_port0: endpoint { \ + remote-endpoint = \ + <&etm##c0##_out_port>; \ + }; \ + }; \ + \ + port@1 { \ + reg = <1>; \ + funnel##cl##_in_port1: endpoint { \ + remote-endpoint = \ + <&etm##c1##_out_port>; \ + }; \ + }; \ + \ + port@2 { \ + reg = <2>; \ + funnel##cl##_in_port2: endpoint { \ + remote-endpoint = \ + <&etm##c2##_out_port>; \ + }; \ + }; \ + \ + port@3 { \ + reg = <3>; \ + funnel##cl##_in_port3: endpoint { \ + remote-endpoint = \ + <&etm##c3##_out_port>; \ + }; \ + }; \ + }; \ + }; \ + \ + etb##cl: etb@##cs_base##030000 { \ + compatible = "arm,coresight-tmc", "arm,primecell"; \ + reg = <0x0 0x##cs_base##030000 0x0 0x1000>; \ + clocks = <&cluster##cl##_cmu0 2>; \ + clock-names = "apb_pclk"; \ + \ + in-ports { \ + port { \ + etb##cl##_in_port: endpoint { \ + remote-endpoint = \ + <&funnel##cl##_out_port>; \ + }; \ + }; \ + }; \ + }; \ + \ + cti##cl: cti@##cs_base##010000 { \ + compatible = "arm,coresight-cti", "arm,primecell"; \ + reg = <0x0 0x##cs_base##010000 0x0 0x1000>; \ + clocks = <&cluster##cl##_cmu0 2>; \ + clock-names = "apb_pclk"; \ + \ + #address-cells = <1>; \ + #size-cells = <0>; \ + \ + trig-conns@0 { \ + reg = <0>; \ + arm,trig-in-sigs = <0 1 2>; \ + arm,trig-in-types = ; \ + arm,trig-out-sigs = <0 1>; \ + arm,trig-out-types = ; \ + arm,cs-dev-assoc = <&etb##cl>; \ + }; \ + \ + trig-conns@1 { \ + reg = <1>; \ + arm,trig-out-sigs = <2>; \ + arm,trig-conn-name = "pmu_snapshot"; \ + }; \ + } + +/ { + soc { + /* CA75 Blocks */ + + CA75_CS(0,0,1,2,3,6,7); + CA75_CS(1,4,5,6,7,a,b); + CA75_CS(2,8,9,10,11,e,f); + CA75_CS(3,12,13,14,15,12,13); + CA75_CS(4,16,17,18,19,16,17); + CA75_CS(5,20,21,22,23,1a,1b); + CA75_CS(6,24,25,26,27,1e,1f); + CA75_CS(7,28,29,30,31,22,23); + CA75_CS(8,32,33,34,35,26,27); + CA75_CS(9,36,37,38,39,2a,2b); + CA75_CS(10,40,41,42,43,2e,2f); + CA75_CS(11,44,45,46,47,32,33); + + /* STM Block */ + + etr: etr@2080000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x2080000 0x0 0x1000>; + clocks = <&cmu_sc_1 6>; + clock-names = "apb_pclk"; + + in-ports { + port { + etr_in_port: endpoint { + remote-endpoint = + <&etf_out_port>; + }; + }; + }; + }; + + etf: etf@2070000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x2070000 0x0 0x1000>; + clocks = <&cmu_sc_1 6>; + clock-names = "apb_pclk"; + + out-ports { + port { + etf_out_port: endpoint { + remote-endpoint = + <&etr_in_port>; + }; + }; + }; + + in-ports { + port { + etf_in_port: endpoint { + remote-endpoint = + <&stm_out_port>; + }; + }; + }; + }; + + stm: stm@2060000 { + compatible = "arm,coresight-stm", "arm,primecell"; + reg = <0x0 0x2060000 0x0 0x1000>, + <0x0 0x3000000 0x0 0x1000000>; + reg-names = "stm-base", "stm-stimulus-base"; + clocks = <&cmu_sc_1 6>; + clock-names = "apb_pclk"; + + out-ports { + port { + stm_out_port: endpoint { + remote-endpoint = + <&etf_in_port>; + }; + }; + }; + }; + + /* CMN Block */ + + funnel: funnel@2050000 { + compatible = "arm,coresight-dynamic-funnel", + "arm,primecell"; + reg = <0x0 0x2050000 0x0 0x1000>; + clocks = <&cmu_sc_1 6>; + clock-names = "apb_pclk"; + + out-ports { + port { + funnel_out_port: endpoint { + remote-endpoint = + <&etb_in_port>; + }; + }; + }; + + in-ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in_port0: endpoint { + }; + }; + + port@1 { + reg = <1>; + funnel_in_port1: endpoint { + }; + }; + }; + }; + + etb: etb@2040000 { + compatible = "arm,coresight-tmc", "arm,primecell"; + reg = <0x0 0x2040000 0x0 0x1000>; + clocks = <&cmu_sc_1 6>; + clock-names = "apb_pclk"; + + in-ports { + port { + etb_in_port: endpoint { + remote-endpoint = + <&funnel_out_port>; + }; + }; + }; + }; + + /* CTI */ + + cti: cti@2010000 { + compatible = "arm,coresight-cti", "arm,primecell"; + reg = <0x0 0x2010000 0x0 0x1000>; + clocks = <&cmu_sc_1 6>; + clock-names = "apb_pclk"; + + #address-cells = <1>; + #size-cells = <0>; + + trig-conns@0 { + reg = <0>; + arm,trig-out-sigs = <0 1>; + arm,trig-out-types = ; + arm,trig-conn-name = "tsgen"; + }; + + trig-conns@1 { + reg = <1>; + arm,trig-in-sigs = <0 1 2>; + arm,trig-in-types = ; + arm,trig-out-sigs = <2 3>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etb>; + }; + + trig-conns@2 { + reg = <2>; + arm,trig-in-sigs = <3 4>; + arm,trig-conn-name = "cmn_debug_watchtrig"; + }; + + trig-conns@3 { + reg = <3>; + arm,trig-out-sigs = <4>; + arm,trig-conn-name = "cmn_pmu_snapshot"; + }; + + trig-conns@4 { + reg = <4>; + arm,trig-in-sigs = <5 6 7>; + arm,trig-in-types = ; + arm,trig-out-sigs = <5 6>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etf>; + }; + + trig-conns@5 { + reg = <5>; + arm,trig-in-sigs = <8 9 10>; + arm,trig-in-types = ; + arm,trig-out-sigs = <7 8>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&etr>; + }; + + trig-conns@6 { + reg = <6>; + arm,trig-in-sigs = <11 12 13 14>; + arm,trig-in-types = ; + arm,trig-out-sigs = <9 10 11 12>; + arm,trig-out-types = ; + arm,cs-dev-assoc = <&stm>; + }; + + trig-conns@7 { + reg = <7>; + arm,trig-out-sigs = <13>; + arm,trig-conn-name = "dpeventstatus"; + }; + + trig-conns@8 { + reg = <8>; + arm,trig-out-sigs = <14 15 16 17>; + arm,trig-out-types = ; + arm,trig-conn-name = "cti_interrupt"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bs1000-dbs-mezzanine-espi.dtsi b/arch/arm64/boot/dts/baikal/bs1000-dbs-mezzanine-espi.dtsi new file mode 100644 index 0000000000000..0ef4c1c7d92f2 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000-dbs-mezzanine-espi.dtsi @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for DBS socket X6.16 mezzanine board + * Copyright (C) 2023 Baikal Electronics, JSC + */ + +&espi { + num-cs = <4>; + status = "okay"; + + flash@0 { + compatible = "rohm,dh2228fv"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + }; + + flash@1 { + compatible = "rohm,dh2228fv"; + reg = <1>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + }; + + flash@2 { + compatible = "rohm,dh2228fv"; + reg = <2>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + }; + + flash@3 { + compatible = "rohm,dh2228fv"; + reg = <3>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bs1000-dbs-mezzanine-qspi2.dtsi b/arch/arm64/boot/dts/baikal/bs1000-dbs-mezzanine-qspi2.dtsi new file mode 100644 index 0000000000000..929210b0692cf --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000-dbs-mezzanine-qspi2.dtsi @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for DBS socket X11.16 mezzanine board + * Copyright (C) 2023 Baikal Electronics, JSC + */ + +&qspi2 { + num-cs = <2>; + status = "okay"; + + flash@0 { + compatible = "rohm,dh2228fv"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + }; + + flash@1 { + compatible = "rohm,dh2228fv"; + reg = <1>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + }; +}; diff --git a/arch/arm64/boot/dts/baikal/bs1000-dbs-ov.dts b/arch/arm64/boot/dts/baikal/bs1000-dbs-ov.dts new file mode 100644 index 0000000000000..86113d20e32a7 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000-dbs-ov.dts @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for DBS-OV compatible boards: + * - DBS-OV vA0 + * + * Copyright (C) 2022-2023 Baikal Electronics, JSC + */ + +/dts-v1/; + +#include "bs1000-dbs.dtsi" + +/ { + model = "Baikal Electronics DBS-OV"; + compatible = "baikal,dbs-ov", "baikal,bs1000"; +}; + +&pcie0_p0 { + num-lanes = <16>; + status = "okay"; +}; + +&pcie0_p0_ep { + num-lanes = <16>; + status = "okay"; +}; + +/delete-node/ &pcie0_p0_ep; + +&pcie1_p0 { + num-lanes = <16>; + status = "okay"; +}; + +&pcie1_p0_ep { + num-lanes = <16>; + status = "okay"; +}; + +/delete-node/ &pcie1_p0_ep; + +&pcie2_p0 { + num-lanes = <16>; + status = "okay"; +}; + +&pcie2_p0_ep { + num-lanes = <16>; + status = "okay"; +}; + +/delete-node/ &pcie2_p0_ep; + +&pcie3_p0 { + num-lanes = <8>; + status = "okay"; +}; + +&pcie3_p2 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie3_p3 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie4_p0 { + num-lanes = <8>; + status = "okay"; +}; + +&pcie4_p2 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie4_p3 { + num-lanes = <4>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/baikal/bs1000-dbs.dts b/arch/arm64/boot/dts/baikal/bs1000-dbs.dts new file mode 100644 index 0000000000000..b260ac03c2c7c --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000-dbs.dts @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for DBS compatible boards: + * - DBS vA0 + * + * Copyright (C) 2021-2023 Baikal Electronics, JSC + */ + +/dts-v1/; + +#include "bs1000-dbs.dtsi" + +/ { + model = "Baikal Electronics DBS"; + compatible = "baikal,dbs", "baikal,bs1000"; +}; + +&pcie0_p0 { + num-lanes = <8>; + status = "okay"; +}; + +&pcie0_p0_ep { + num-lanes = <8>; + status = "okay"; +}; + +/delete-node/ &pcie0_p0_ep; + +&pcie0_p1 { + num-lanes = <8>; + status = "okay"; +}; + +&pcie1_p0 { + num-lanes = <8>; + status = "okay"; +}; + +&pcie1_p0_ep { + num-lanes = <8>; + status = "okay"; +}; + +/delete-node/ &pcie1_p0_ep; + +&pcie1_p1 { + num-lanes = <8>; + status = "okay"; +}; + +&pcie2_p0 { + num-lanes = <8>; + status = "okay"; +}; + +&pcie2_p0_ep { + num-lanes = <8>; + status = "okay"; +}; + +/delete-node/ &pcie2_p0_ep; + +&pcie2_p1 { + num-lanes = <8>; + status = "okay"; +}; + +&pcie3_p0 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie3_p1 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie3_p2 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie3_p3 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie4_p0 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie4_p1 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie4_p2 { + num-lanes = <4>; + status = "okay"; +}; + +&pcie4_p3 { + num-lanes = <4>; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/baikal/bs1000-dbs.dtsi b/arch/arm64/boot/dts/baikal/bs1000-dbs.dtsi new file mode 100644 index 0000000000000..25b7001bd5383 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000-dbs.dtsi @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for DBS-compatible boards + * Copyright (C) 2021-2023 Baikal Electronics, JSC + */ + +#include "bs1000.dtsi" + +/ { + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + }; + + chosen { }; +}; + +&ehci { + status = "okay"; +}; + +&gmac0 { + status = "okay"; + phy-handle = <ðphy0>; + phy-mode = "rgmii-rxid"; +}; + +&gmac1 { + status = "okay"; + phy-handle = <ðphy1>; + phy-mode = "rgmii-rxid"; +}; + +&gpio32 { + status = "okay"; +}; + +&i2c2 { + status = "okay"; +}; + +&i2c3 { + status = "okay"; +}; + +&i2c4 { + status = "okay"; +}; + +&mdio0 { + ethphy0: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + }; +}; + +&mdio1 { + ethphy1: ethernet-phy@1 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x1>; + }; +}; + +&mux { + status = "okay"; +}; + +&mux0 { + status = "okay"; +}; + +&mux1 { + status = "okay"; +}; + +&mux2 { + status = "okay"; +}; + +&ohci { + status = "okay"; +}; + +&pvt_cluster0 { + status = "okay"; +}; + +&pvt_cluster1 { + status = "okay"; +}; + +&pvt_cluster2 { + status = "okay"; +}; + +&pvt_cluster3 { + status = "okay"; +}; + +&pvt_cluster4 { + status = "okay"; +}; + +&pvt_cluster5 { + status = "okay"; +}; + +&pvt_cluster6 { + status = "okay"; +}; + +&pvt_cluster7 { + status = "okay"; +}; + +&pvt_cluster8 { + status = "okay"; +}; + +&pvt_cluster9 { + status = "okay"; +}; + +&pvt_cluster10 { + status = "okay"; +}; + +&pvt_cluster11 { + status = "okay"; +}; + +&pvt_ddr0 { + status = "okay"; +}; + +&pvt_ddr1 { + status = "okay"; +}; + +&pvt_ddr2 { + status = "okay"; +}; + +&pvt_ddr3 { + status = "okay"; +}; + +&pvt_ddr4 { + status = "okay"; +}; + +&pvt_ddr5 { + status = "okay"; +}; + +&pvt_pcie0 { + status = "okay"; +}; + +&pvt_pcie1 { + status = "okay"; +}; + +&pvt_pcie2 { + status = "okay"; +}; + +&pvt_pcie3 { + status = "okay"; +}; + +&pvt_pcie4 { + status = "okay"; +}; + +&qspi1 { + num-cs = <4>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl1"; + reg = <0x000000 0x40000>; + }; + + partition@40000 { + label = "dtb"; + reg = <0x040000 0x40000>; + }; + + partition@80000 { + label = "uefi-vars"; + reg = <0x080000 0xc0000>; + }; + + partition@140000 { + label = "fip"; + reg = <0x140000 0x6c0000>; + }; + }; + }; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&timer4 { + status = "okay"; +}; + +&uart_a1 { + status = "okay"; +}; + +&uart_a2 { + status = "okay"; +}; + +&uart_s { + status = "okay"; +}; + +&wdt { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/baikal/bs1000-qemu-s.dts b/arch/arm64/boot/dts/baikal/bs1000-qemu-s.dts new file mode 100644 index 0000000000000..16ec325abf8d9 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000-qemu-s.dts @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree source for Baikal Electronics QEMU-S virtual platform + * Copyright (C) 2021-2022 Baikal Electronics, JSC + */ + +/dts-v1/; + +#include "bs1000.dtsi" + +/ { + model = "Baikal Electronics QEMU-S"; + compatible = "baikal,qemu-s", "baikal,bs1000"; + + aliases { + ethernet0 = &gmac0; + ethernet1 = &gmac1; + }; + + chosen { }; + + /* + * Device is necessary for UEFI to boot on QEMU, + * need to replace it with something later. + */ + flash@0 { + compatible = "cfi-flash"; + reg = <0x0 0x4000000 0x0 0x4000000>; + bank-width = <0x4>; + }; +}; + +&ehci { + status = "okay"; +}; + +&gmac0 { + status = "okay"; + phy-handle = <ðphy0>; + phy-mode = "rgmii-rxid"; +}; + +&gmac1 { + status = "okay"; + phy-handle = <ðphy1>; + phy-mode = "rgmii-rxid"; +}; + +&mdio0 { + ethphy0: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x3>; + }; +}; + +&mdio1 { + ethphy1: ethernet-phy@3 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x3>; + }; +}; + +&ohci { + status = "okay"; +}; + +&qspi1 { + num-cs = <4>; + status = "okay"; + + flash@0 { + compatible = "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <10000000>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <1>; + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "bl1"; + reg = <0x000000 0x40000>; + }; + + partition@40000 { + label = "dtb"; + reg = <0x040000 0x40000>; + }; + + partition@80000 { + label = "uefi-vars"; + reg = <0x080000 0xc0000>; + }; + + partition@140000 { + label = "fip"; + reg = <0x140000 0x6c0000>; + }; + }; + }; +}; + +&timer1 { + status = "okay"; +}; + +&uart_a1 { + status = "okay"; +}; + +&uart_a2 { + status = "okay"; +}; + +&uart_s { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/baikal/bs1000.dtsi b/arch/arm64/boot/dts/baikal/bs1000.dtsi new file mode 100644 index 0000000000000..fdfff16622017 --- /dev/null +++ b/arch/arm64/boot/dts/baikal/bs1000.dtsi @@ -0,0 +1,1196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device tree include file for BE-S1000 SoC + * Copyright (C) 2021-2023 Baikal Electronics, JSC + */ + +#include +#include "bs1000-clocks.dtsi" + +#define CA75_CLUSTER(group, a,b,c,d) \ + cluster##group: \ + cluster##group { \ + core0 { \ + cpu = <&cpu##a>; \ + }; \ + core1 { \ + cpu = <&cpu##b>; \ + }; \ + core2 { \ + cpu = <&cpu##c>; \ + }; \ + core3 { \ + cpu = <&cpu##d>; \ + }; \ + l3_##group: l3-cache##group { \ + compatible = "cache"; \ + cache-size = <0x200000>; \ + cache-line-size = <64>; \ + cache-sets = <2048>; \ + cache-unified; \ + cache-level = <3>; \ + next-level-cache = <&l4>; \ + }; \ + } + +#define CA75_CPU(core, group, affinity) \ + cpu##core: cpu@##affinity { \ + device_type = "cpu"; \ + compatible = "arm,cortex-a75"; \ + reg = <0x0 0x##affinity>; \ + enable-method = "psci"; \ + i-cache-size = <0x10000>; \ + i-cache-line-size = <64>; \ + i-cache-sets = <256>; \ + d-cache-size = <0x10000>; \ + d-cache-line-size = <64>; \ + d-cache-sets = <64>; \ + next-level-cache = <&l2_##core>; \ + operating-points-v2 = <&cpu_opp_table>; \ + clocks = <&cluster##group##_cmu1 (core%4)>; \ + l2_##core: l2-cache { \ + compatible = "cache"; \ + cache-size = <0x80000>; \ + cache-line-size = <64>; \ + cache-sets = <1024>; \ + cache-unified; \ + cache-level = <2>; \ + next-level-cache = <&l3_##group>; \ + }; \ + } + +/ { + compatible = "baikal,bs1000"; + #address-cells = <2>; + #size-cells = <2>; + interrupt-parent = <&gic>; + + aliases { + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c4; + i2c5 = &i2c5; + i2c6 = &i2c6; + serial0 = &uart_a1; + serial1 = &uart_a2; + serial2 = &uart_s; + }; + + psci { + compatible = "arm,psci-1.0", "arm,psci-0.2"; + method = "smc"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu-map { + CA75_CLUSTER(0, 0, 1, 2, 3 ); + CA75_CLUSTER(1, 4, 5, 6, 7 ); + CA75_CLUSTER(2, 8, 9, 10,11); + CA75_CLUSTER(3, 12,13,14,15); + CA75_CLUSTER(4, 16,17,18,19); + CA75_CLUSTER(5, 20,21,22,23); + CA75_CLUSTER(6, 24,25,26,27); + CA75_CLUSTER(7, 28,29,30,31); + CA75_CLUSTER(8, 32,33,34,35); + CA75_CLUSTER(9, 36,37,38,39); + CA75_CLUSTER(10, 40,41,42,43); + CA75_CLUSTER(11, 44,45,46,47); + }; + + CA75_CPU(0,0,0); + CA75_CPU(1,0,100); + CA75_CPU(2,0,200); + CA75_CPU(3,0,300); + CA75_CPU(4,1,10000); + CA75_CPU(5,1,10100); + CA75_CPU(6,1,10200); + CA75_CPU(7,1,10300); + CA75_CPU(8,2,20000); + CA75_CPU(9,2,20100); + CA75_CPU(10,2,20200); + CA75_CPU(11,2,20300); + CA75_CPU(12,3,30000); + CA75_CPU(13,3,30100); + CA75_CPU(14,3,30200); + CA75_CPU(15,3,30300); + CA75_CPU(16,4,40000); + CA75_CPU(17,4,40100); + CA75_CPU(18,4,40200); + CA75_CPU(19,4,40300); + CA75_CPU(20,5,50000); + CA75_CPU(21,5,50100); + CA75_CPU(22,5,50200); + CA75_CPU(23,5,50300); + CA75_CPU(24,6,60000); + CA75_CPU(25,6,60100); + CA75_CPU(26,6,60200); + CA75_CPU(27,6,60300); + CA75_CPU(28,7,70000); + CA75_CPU(29,7,70100); + CA75_CPU(30,7,70200); + CA75_CPU(31,7,70300); + CA75_CPU(32,8,80000); + CA75_CPU(33,8,80100); + CA75_CPU(34,8,80200); + CA75_CPU(35,8,80300); + CA75_CPU(36,9,90000); + CA75_CPU(37,9,90100); + CA75_CPU(38,9,90200); + CA75_CPU(39,9,90300); + CA75_CPU(40,10,a0000); + CA75_CPU(41,10,a0100); + CA75_CPU(42,10,a0200); + CA75_CPU(43,10,a0300); + CA75_CPU(44,11,b0000); + CA75_CPU(45,11,b0100); + CA75_CPU(46,11,b0200); + CA75_CPU(47,11,b0300); + + l4: l4-cache { + cache-size = <0x2000000>; + cache-unified; + cache-level = <4>; + }; + }; + + cpu_opp_table: opp_table { + compatible = "operating-points-v2"; + opp-250000000 { + opp-hz = /bits/ 64 <250000000>; + }; + opp-500000000 { + opp-hz = /bits/ 64 <500000000>; + }; + opp-1000000000 { + opp-hz = /bits/ 64 <1000000000>; + }; + opp-2000000000 { + opp-hz = /bits/ 64 <2000000000>; + }; + }; + + pmu { + compatible = "arm,cortex-a75-pmu", "arm,armv8-pmuv3"; + interrupts = ; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + soc { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + ohci: usb@a00000 { + compatible = "generic-ohci"; + reg = <0x0 0xa00000 0x0 0x1000>; + interrupts = ; + dr_mode = "host"; + dma-coherent; + clocks = <&cmu_sc_1 13>, <&cmu_sc_1 14>; + clock-names = "ohci_hclk", "ohci_clk48"; + status = "disabled"; + }; + + ehci: usb@a10000 { + compatible = "generic-ehci"; + reg = <0x0 0xa10000 0x0 0x1000>; + interrupts = ; + dr_mode = "host"; + dma-coherent; + clocks = <&cmu_sc_1 13>; + clock-names = "ehci_hclk"; + status = "disabled"; + }; + + gmac0: ethernet@a20000 { + compatible = "baikal,bs1000-gmac"; + reg = <0x0 0xa20000 0x0 0x10000>; + interrupts = ; + interrupt-names = "macirq"; + clocks = <&cmu_sc_1 9>, <&cmu_sc_2 1>, <&cmu_sc_2 2>; + clock-names = "stmmaceth", "ptp_ref", "tx2_clk"; + dma-coherent; + status = "disabled"; + + mdio0: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + gmac1: ethernet@a30000 { + compatible = "baikal,bs1000-gmac"; + reg = <0x0 0xa30000 0x0 0x10000>; + interrupts = ; + interrupt-names = "macirq"; + clocks = <&cmu_sc_1 11>, <&cmu_sc_2 3>, <&cmu_sc_2 4>; + clock-names = "stmmaceth", "ptp_ref", "tx2_clk"; + dma-coherent; + status = "disabled"; + + mdio1: mdio { + compatible = "snps,dwmac-mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + uart_a1: serial@c00000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0xc00000 0x0 0x1000>; + interrupts = ; + clocks = <&uart1_clk>, <&apb_clk>; + // clocks = <&cmu_sc_1 18>, <&cmu_sc_1 15>; // "lsp_uart_arm1", "lsp_apb" + clock-names = "uartclk", "apb_pclk"; + status = "disabled"; + }; + + uart_a2: serial@c10000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0xc10000 0x0 0x1000>; + interrupts = ; + clocks = <&uart2_clk>, <&apb_clk>; + // clocks = <&cmu_sc_1 19>, <&cmu_sc_1 15>; // "lsp_uart_arm2", "lsp_apb" + clock-names = "uartclk", "apb_pclk"; + status = "disabled"; + }; + + qspi1: spi@c20000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x0 0xc20000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&spi_clk>; + // clocks = <&cmu_sc_1 20>; // "lsp_spi1" + status = "disabled"; + }; + + gpio32: gpio@c50000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0 0xc50000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&gpio_clk>; + // clocks = <&cmu_sc_1 16>; // "lsp_gpio_x16" + status = "disabled"; + + porta: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <32>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + }; + + i2c2: i2c@c90000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0xc90000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + i2c-sda-hold-time-ns = <500>; + clock-frequency = <400000>; + clocks = <&i2c_clk>; + // clocks = <&cmu_sc_1 23>; // "lsp_smbus_i2c2" + clock-names = "ref"; + status = "disabled"; + }; + + i2c3: i2c@ca0000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0xca0000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + i2c-sda-hold-time-ns = <500>; + clock-frequency = <400000>; + clocks = <&i2c_clk>; + // clocks = <&cmu_sc_1 24>; // "lsp_smbus_i2c3" + clock-names = "ref"; + status = "disabled"; + }; + + i2c4: i2c@cb0000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0xcb0000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + i2c-sda-hold-time-ns = <500>; + clock-frequency = <400000>; + clocks = <&i2c_clk>; + // clocks = <&cmu_sc_1 25>; // "lsp_smbus_i2c4" + clock-names = "ref"; + status = "disabled"; + }; + + wdt: watchdog@ce0000 { + compatible = "snps,dw-wdt"; + reg = <0x0 0xce0000 0x0 0x1000>; + interrupts = ; + clocks = <&wdt_clk 0>; + // clocks = <&cmu_sc_1 32>; // "lsp_wdt_x16" + clock-names = "tclk"; + snps,watchdog-tops = <0x000000ff 0x000001ff 0x000003ff 0x000007ff + 0x0000ffff 0x0001ffff 0x0003ffff 0x0007ffff + 0x000fffff 0x001fffff 0x003fffff 0x007fffff + 0x00ffffff 0x01ffffff 0x03ffffff 0x07ffffff>; + status = "disabled"; + }; + + timer1: timer@cf0000 { + compatible = "snps,dw-apb-timer"; + reg = <0x0 0xcf0000 0x0 0x14>; + interrupts = ; + clocks = <&timer1_clk>; + // clocks = <&cmu_sc_1 28>; // "lsp_timer1" + clock-names = "timer"; + status = "disabled"; + }; + + timer2: timer@cf0014 { + compatible = "snps,dw-apb-timer"; + reg = <0x0 0xcf0014 0x0 0x14>; + interrupts = ; + clocks = <&timer2_clk>; + // clocks = <&cmu_sc_1 29>; // "lsp_timer2" + clock-names = "timer"; + status = "disabled"; + }; + + timer3: timer@cf0028 { + compatible = "snps,dw-apb-timer"; + reg = <0x0 0xcf0028 0x0 0x14>; + interrupts = ; + clocks = <&timer3_clk>; + // clocks = <&cmu_sc_1 30>; // "lsp_timer3" + clock-names = "timer"; + status = "disabled"; + }; + + timer4: timer@cf003c { + compatible = "snps,dw-apb-timer"; + reg = <0x0 0xcf003c 0x0 0x14>; + interrupts = ; + clocks = <&timer4_clk>; + //clocks = <&cmu_sc_1 31>; // "lsp_timer4" + clock-names = "timer"; + status = "disabled"; + }; + + gic: interrupt-controller@1000000 { + compatible = "arm,gic-v3"; + reg = <0x0 0x1000000 0x0 0x10000>, /* GICD */ + <0x0 0x1240000 0x0 0x600000>; /* GICR */ + /* TODO: optional ranges - GICC, GICH, GICV */ + #interrupt-cells = <3>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + interrupt-controller; + interrupts = ; + + its0: interrupt-controller@1040000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1040000 0x0 0x20000>; + msi-controller; + }; + its1: interrupt-controller@1060000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1060000 0x0 0x20000>; + msi-controller; + }; + its2: interrupt-controller@1080000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1080000 0x0 0x20000>; + msi-controller; + }; + its3: interrupt-controller@10a0000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x10a0000 0x0 0x20000>; + msi-controller; + }; + its4: interrupt-controller@10c0000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x10c0000 0x0 0x20000>; + msi-controller; + }; + its5: interrupt-controller@10e0000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x10e0000 0x0 0x20000>; + msi-controller; + }; + its6: interrupt-controller@1100000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1100000 0x0 0x20000>; + msi-controller; + }; + its7: interrupt-controller@1120000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1120000 0x0 0x20000>; + msi-controller; + }; + its8: interrupt-controller@1140000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1140000 0x0 0x20000>; + msi-controller; + }; + its9: interrupt-controller@1160000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1160000 0x0 0x20000>; + msi-controller; + }; + its10: interrupt-controller@1180000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1180000 0x0 0x20000>; + msi-controller; + }; + its11: interrupt-controller@11a0000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x11a0000 0x0 0x20000>; + msi-controller; + }; + its12: interrupt-controller@11c0000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x11c0000 0x0 0x20000>; + msi-controller; + }; + its13: interrupt-controller@11e0000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x11e0000 0x0 0x20000>; + msi-controller; + }; + its14: interrupt-controller@1200000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1200000 0x0 0x20000>; + msi-controller; + }; + its15: interrupt-controller@1220000 { + compatible = "arm,gic-v3-its"; + reg = <0x0 0x1220000 0x0 0x20000>; + msi-controller; + }; + }; + + pcie0_p0: pcie@39000000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x39000000 0x0 0x400000>, + <0x00000000 0x38d40000 0x0 0x100>, + <0x00000700 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00000000 0x701 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x702 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its0>; + msi-map = <0x0 &its0 0x0 0x10000>; + status = "disabled"; + }; + + pcie0_p0_ep: pcie-ep@39000000 { + compatible = "baikal,bs1000-pcie-ep"; + reg = <0x00000000 0x39000000 0x0 0x400000>, + <0x00000000 0x38d40000 0x0 0x100>, + <0x00000700 0x00000000 0x1 0x00000000>; + reg-names = "dbi", "apb", "addr_space"; + num-ib-windows = <4>; + num-ob-windows = <4>; + status = "disabled"; + }; + + pcie0_p1: pcie@39400000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x39400000 0x0 0x400000>, + <0x00000000 0x38d41000 0x0 0x100>, + <0x00000740 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00100000 0x741 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x742 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its0>; + msi-map = <0x0 &its0 0x10000 0x10000>; + status = "disabled"; + }; + + pcie1_p0: pcie@3d000000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x3d000000 0x0 0x400000>, + <0x00000000 0x3cd40000 0x0 0x100>, + <0x00000780 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00200000 0x781 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x782 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its2>; + msi-map = <0x0 &its2 0x0 0x10000>; + status = "disabled"; + }; + + pcie1_p0_ep: pcie-ep@3d000000 { + compatible = "baikal,bs1000-pcie-ep"; + reg = <0x00000000 0x3d000000 0x0 0x400000>, + <0x00000000 0x3cd40000 0x0 0x100>, + <0x00000780 0x00000000 0x1 0x00000000>; + reg-names = "dbi", "apb", "addr_space"; + num-ib-windows = <4>; + num-ob-windows = <4>; + status = "disabled"; + }; + + pcie1_p1: pcie@3d400000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x3d400000 0x0 0x400000>, + <0x00000000 0x3cd41000 0x0 0x100>, + <0x000007c0 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00300000 0x7c1 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x7c2 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its2>; + msi-map = <0x0 &its2 0x10000 0x10000>; + status = "disabled"; + }; + + pcie2_p0: pcie@45000000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x45000000 0x0 0x400000>, + <0x00000000 0x44d40000 0x0 0x100>, + <0x00000500 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00400000 0x501 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x502 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its4>; + msi-map = <0x0 &its4 0x0 0x10000>; + status = "disabled"; + }; + + pcie2_p0_ep: pcie-ep@45000000 { + compatible = "baikal,bs1000-pcie-ep"; + reg = <0x00000000 0x45000000 0x0 0x400000>, + <0x00000000 0x44d40000 0x0 0x100>, + <0x00000500 0x00000000 0x1 0x00000000>; + reg-names = "dbi", "apb", "addr_space"; + num-ib-windows = <4>; + num-ob-windows = <4>; + status = "disabled"; + }; + + pcie2_p1: pcie@45400000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x45400000 0x0 0x400000>, + <0x00000000 0x44d41000 0x0 0x100>, + <0x00000540 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00500000 0x541 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x542 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its4>; + msi-map = <0x0 &its4 0x10000 0x10000>; + status = "disabled"; + }; + + pcie3_p0: pcie@49000000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x49000000 0x0 0x400000>, + <0x00000000 0x48d40000 0x0 0x100>, + <0x00000400 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00600000 0x401 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x402 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its6>; + msi-map = <0x0 &its6 0x0 0x10000>; + status = "disabled"; + }; + + pcie3_p1: pcie@49400000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x49400000 0x0 0x400000>, + <0x00000000 0x48d41000 0x0 0x100>, + <0x00000440 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00700000 0x441 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x442 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its7>; + msi-map = <0x0 &its7 0x10000 0x10000>; + status = "disabled"; + }; + + pcie3_p2: pcie@49800000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x49800000 0x0 0x400000>, + <0x00000000 0x48d42000 0x0 0x100>, + <0x00000480 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00800000 0x481 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x482 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its8>; + msi-map = <0x0 &its8 0x20000 0x10000>; + status = "disabled"; + }; + + pcie3_p3: pcie@49c00000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x49c00000 0x0 0x400000>, + <0x00000000 0x48d43000 0x0 0x100>, + <0x000004c0 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00900000 0x4c1 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x4c2 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its9>; + msi-map = <0x0 &its9 0x30000 0x10000>; + status = "disabled"; + }; + + pcie4_p0: pcie@4d000000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x4d000000 0x0 0x400000>, + <0x00000000 0x4cd40000 0x0 0x100>, + <0x00000600 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00a00000 0x601 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x602 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its11>; + msi-map = <0x0 &its11 0x0 0x10000>; + status = "disabled"; + }; + + pcie4_p1: pcie@4d400000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x4d400000 0x0 0x400000>, + <0x00000000 0x4cd41000 0x0 0x100>, + <0x00000640 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00b00000 0x641 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x642 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its12>; + msi-map = <0x0 &its12 0x10000 0x10000>; + status = "disabled"; + }; + + pcie4_p2: pcie@4d800000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x4d800000 0x0 0x400000>, + <0x00000000 0x4cd42000 0x0 0x100>, + <0x00000680 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00c00000 0x681 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x682 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its13>; + msi-map = <0x0 &its13 0x20000 0x10000>; + status = "disabled"; + }; + + pcie4_p3: pcie@4dc00000 { + device_type = "pci"; + compatible = "baikal,bs1000-pcie"; + reg = <0x00000000 0x4dc00000 0x0 0x400000>, + <0x00000000 0x4cd43000 0x0 0x100>, + <0x000006c0 0x00000000 0x0 0x10000000>; + reg-names = "dbi", "apb", "config"; + bus-range = <0x0 0xff>; + interrupts = , + ; + interrupt-names = "intr", "msi"; + #interrupt-cells = <1>; + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x81000000 0x0 0x00d00000 0x6c1 0x00000000 0x0 0x100000>, + <0x82000000 0x0 0x40000000 0x6c2 0x00000000 0x0 0x40000000>; + num-viewport = <4>; + msi-parent = <&its14>; + msi-map = <0x0 &its14 0x30000 0x10000>; + status = "disabled"; + }; + + ddr0: memory-controller@53000000 { + compatible = "baikal,bs1000-edac-mc"; + reg = <0x0 0x53000000 0x0 0x10000>; + interrupts = , /* dfi_alert_err */ + , /* ecc_corrected_err */ + , /* ecc_uncorrected_err */ + , /* sbr_done */ + , /* ecc_corrected_err_fault */ + ; /* ecc_uncorrected_err_fault */ + // clocks = <&cmu_ddr_0 0>; + // clock-names = "apb_pclk"; + status = "disabled"; + }; + + ddr1: memory-controller@57000000 { + compatible = "baikal,bs1000-edac-mc"; + reg = <0x0 0x57000000 0x0 0x10000>; + interrupts = , /* dfi_alert_err */ + , /* ecc_corrected_err */ + , /* ecc_uncorrected_err */ + , /* sbr_done */ + , /* ecc_corrected_err_fault */ + ; /* ecc_uncorrected_err_fault */ + // clocks = <&cmu_ddr_1 0>; + // clock-names = "apb_pclk"; + status = "disabled"; + }; + + ddr2: memory-controller@5b000000 { + compatible = "baikal,bs1000-edac-mc"; + reg = <0x0 0x5b000000 0x0 0x10000>; + interrupts = , /* dfi_alert_err */ + , /* ecc_corrected_err */ + , /* ecc_uncorrected_err */ + , /* sbr_done */ + , /* ecc_corrected_err_fault */ + ; /* ecc_uncorrected_err_fault */ + // clocks = <&cmu_ddr_2 0>; + // clock-names = "apb_pclk"; + status = "disabled"; + }; + + ddr3: memory-controller@63000000 { + compatible = "baikal,bs1000-edac-mc"; + reg = <0x0 0x63000000 0x0 0x10000>; + interrupts = , /* dfi_alert_err */ + , /* ecc_corrected_err */ + , /* ecc_uncorrected_err */ + , /* sbr_done */ + , /* ecc_corrected_err_fault */ + ; /* ecc_uncorrected_err_fault */ + // clocks = <&cmu_ddr_3 0>; + // clock-names = "apb_pclk"; + status = "disabled"; + }; + + ddr4: memory-controller@67000000 { + compatible = "baikal,bs1000-edac-mc"; + reg = <0x0 0x67000000 0x0 0x10000>; + interrupts = , /* dfi_alert_err */ + , /* ecc_corrected_err */ + , /* ecc_uncorrected_err */ + , /* sbr_done */ + , /* ecc_corrected_err_fault */ + ; /* ecc_uncorrected_err_fault */ + // clocks = <&cmu_ddr_4 0>; + // clock-names = "apb_pclk"; + status = "disabled"; + }; + + ddr5: memory-controller@6b000000 { + compatible = "baikal,bs1000-edac-mc"; + reg = <0x0 0x6b000000 0x0 0x10000>; + interrupts = , /* dfi_alert_err */ + , /* ecc_corrected_err */ + , /* ecc_uncorrected_err */ + , /* sbr_done */ + , /* ecc_corrected_err_fault */ + ; /* ecc_uncorrected_err_fault */ + // clocks = <&cmu_ddr_5 0>; + // clock-names = "apb_pclk"; + status = "disabled"; + }; + + pvt_cluster0: pvt@4030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x4030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster1: pvt@8030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x8030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster2: pvt@c030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0xc030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster3: pvt@10030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x10030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster4: pvt@14030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x14030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster5: pvt@18030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x18030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster6: pvt@1c030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x1c030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster7: pvt@20030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x20030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster8: pvt@24030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x24030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster9: pvt@28030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x28030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster10: pvt@2c030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x2c030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_cluster11: pvt@30030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x30030000 0x0 0x1000>; + status = "disabled"; + }; + pvt_pcie0: pvt@38030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x38030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_pcie1: pvt@3c030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x3c030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_pcie2: pvt@44030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x44030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_pcie3: pvt@48030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x48030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_pcie4: pvt@4c030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x4c030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_ddr0: pvt@50030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x50030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_ddr1: pvt@54030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x54030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_ddr2: pvt@58030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x58030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_ddr3: pvt@60030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x60030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_ddr4: pvt@64030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x64030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + pvt_ddr5: pvt@68030000 { + compatible = "baikal,bs1000-pvt"; + reg = <0x0 0x68030000 0x0 0x1000>; + interrupts = ; + status = "disabled"; + }; + + mux: mux-controller { + compatible = "baikal,bs1000-lsp-mux"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + #mux-control-cells = <1>; + status = "disabled"; + + qspi2: spi@c30000 { + compatible = "snps,dw-apb-ssi"; + reg = <0x0 0xc30000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&spi_clk>; + // clocks = <&cmu_sc_1 21>; // "lsp_spi2" + }; + + espi: spi@c40000 { + compatible = "baikal,bs1000-espi"; + reg = <0x0 0xc40000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clocks = <&spi_clk>; + // clocks = <&cmu_sc_1 22>; // "lsp_espi" + }; + + gpio16: gpio@c60000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0 0xc60000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&gpio_clk>; + // clocks = <&cmu_sc_1 16>; // "lsp_gpio_x16" + + portb: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + }; + + gpio8_1: gpio@c70000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0 0xc70000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&gpio_clk>; + // clocks = <&cmu_sc_1 16>; // "lsp_gpio_x16" + + portc: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + }; + + gpio8_2: gpio@c80000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x0 0xc80000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&gpio_clk>; + // clocks = <&cmu_sc_1 16>; // "lsp_gpio_x16" + + portd: gpio-controller@0 { + compatible = "snps,dw-apb-gpio-port"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <8>; + reg = <0>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = ; + }; + }; + + i2c5: i2c@cc0000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0xcc0000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + i2c-sda-hold-time-ns = <500>; + clock-frequency = <400000>; + clocks = <&i2c_clk>; + // clocks = <&cmu_sc_1 26>; // "lsp_smbus_i2c5" + clock-names = "ref"; + }; + + i2c6: i2c@cd0000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0xcd0000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + i2c-sda-hold-time-ns = <500>; + clock-frequency = <400000>; + clocks = <&i2c_clk>; + // clocks = <&cmu_sc_1 27>; // "lsp_smbus_i2c6" + clock-names = "ref"; + }; + + uart_s: serial@e00000 { + compatible = "snps,dw-apb-uart"; + reg = <0x0 0xe00000 0x0 0x100>; + interrupts = ; + reg-shift = <2>; + reg-io-width = <4>; + clocks = <&uart_clk>, <&apb_clk>; + // clocks = <&cmu_sc_1 17>, <&cmu_sc_1 15>; // "lsp_uart", "lsp_apb" + clock-names = "baudclk", "apb_pclk"; + }; + }; + + mux0: mux0 { + compatible = "baikal,bs1000-lsp-mux-channel"; + mux-controls = <&mux 0>; + mux-state0 = <&gpio8_1>; + mux-state1 = <&uart_s &i2c5 &i2c6>; + status = "disabled"; + }; + + mux1: mux1 { + compatible = "baikal,bs1000-lsp-mux-channel"; + mux-controls = <&mux 1>; + mux-state0 = <&gpio8_2>; + mux-state1 = <&qspi2>; + status = "disabled"; + }; + + mux2: mux2 { + compatible = "baikal,bs1000-lsp-mux-channel"; + mux-controls = <&mux 2>; + mux-state0 = <&gpio16>; + mux-state1 = <&espi>; + status = "disabled"; + }; + }; +}; + +#include "bs1000-coresight.dtsi" diff --git a/arch/arm64/configs/baikal_defconfig b/arch/arm64/configs/baikal_defconfig new file mode 100644 index 0000000000000..a886644921fdb --- /dev/null +++ b/arch/arm64/configs/baikal_defconfig @@ -0,0 +1,846 @@ +CONFIG_LOCALVERSION="-baikal-arm64" +CONFIG_DEFAULT_HOSTNAME="baikal" +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_NO_HZ_IDLE=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_PREEMPT=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_MEMCG=y +CONFIG_BLK_CGROUP=y +CONFIG_CFS_BANDWIDTH=y +CONFIG_CGROUP_PIDS=y +CONFIG_CGROUP_HUGETLB=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_PERF=y +CONFIG_CGROUP_BPF=y +CONFIG_USER_NS=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_PROFILING=y +CONFIG_ARCH_BAIKAL=y +# CONFIG_ARM64_ERRATUM_826319 is not set +# CONFIG_ARM64_ERRATUM_827319 is not set +# CONFIG_ARM64_ERRATUM_824069 is not set +# CONFIG_ARM64_ERRATUM_819472 is not set +# CONFIG_ARM64_ERRATUM_832075 is not set +# CONFIG_ARM64_ERRATUM_834220 is not set +# CONFIG_ARM64_ERRATUM_845719 is not set +# CONFIG_ARM64_ERRATUM_843419 is not set +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_ARM64_ERRATUM_1418040 is not set +# CONFIG_ARM64_ERRATUM_1165522 is not set +# CONFIG_ARM64_ERRATUM_1530923 is not set +# CONFIG_ARM64_ERRATUM_2441007 is not set +# CONFIG_ARM64_ERRATUM_1286807 is not set +# CONFIG_ARM64_ERRATUM_1463225 is not set +# CONFIG_ARM64_ERRATUM_1542419 is not set +# CONFIG_ARM64_ERRATUM_1508412 is not set +# CONFIG_ARM64_ERRATUM_2051678 is not set +# CONFIG_ARM64_ERRATUM_2077057 is not set +# CONFIG_ARM64_ERRATUM_2658417 is not set +# CONFIG_ARM64_ERRATUM_2139208 is not set +# CONFIG_ARM64_ERRATUM_2067961 is not set +# CONFIG_ARM64_ERRATUM_2253138 is not set +# CONFIG_ARM64_ERRATUM_2441009 is not set +# CONFIG_ARM64_ERRATUM_2064142 is not set +# CONFIG_ARM64_ERRATUM_2038923 is not set +# CONFIG_ARM64_ERRATUM_1902691 is not set +# CONFIG_ARM64_ERRATUM_2457168 is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_CAVIUM_TX2_ERRATUM_219 is not set +# CONFIG_FUJITSU_ERRATUM_010001 is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_NVIDIA_CARMEL_CNP_ERRATUM is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +CONFIG_ARM64_VA_BITS_48=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=48 +CONFIG_HOTPLUG_CPU=y +CONFIG_HZ_1000=y +CONFIG_KEXEC_FILE=y +CONFIG_COMPAT=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_SUSPEND is not set +CONFIG_PM=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_ARM_PSCI_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPUFREQ_DT=y +CONFIG_BAIKAL_CPUFREQ=y +CONFIG_ACPI=y +CONFIG_VIRTUALIZATION=y +CONFIG_KVM=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_STATIC_KEYS_SELFTEST=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +CONFIG_BLK_DEV_THROTTLING=y +CONFIG_BLK_WBT=y +CONFIG_BLK_CGROUP_IOLATENCY=y +CONFIG_BLK_CGROUP_IOCOST=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_IOSCHED_BFQ=y +CONFIG_BFQ_GROUP_IOSCHED=y +CONFIG_BINFMT_MISC=m +CONFIG_ZSWAP=y +CONFIG_Z3FOLD=m +CONFIG_SLAB=y +CONFIG_KSM=y +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y +CONFIG_CMA=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_PACKET_DIAG=y +CONFIG_UNIX=y +CONFIG_UNIX_DIAG=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_SUB_POLICY=y +CONFIG_NET_KEY=y +CONFIG_NET_KEY_MIGRATE=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_FIB_TRIE_STATS=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_NET_IPVTI=m +CONFIG_NET_FOU=m +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_DIAG=m +CONFIG_INET_UDP_DIAG=m +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_VEGAS=m +CONFIG_TCP_CONG_NV=m +CONFIG_TCP_CONG_SCALABLE=m +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6=m +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MIP6=m +CONFIG_IPV6_ILA=m +CONFIG_IPV6_VTI=m +CONFIG_IPV6_SIT_6RD=y +CONFIG_IPV6_GRE=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_MROUTE=y +CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y +CONFIG_IPV6_PIMSM_V2=y +CONFIG_NETWORK_SECMARK=y +CONFIG_NETWORK_PHY_TIMESTAMPING=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_CT_NETLINK_HELPER=m +CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NF_TABLES=m +CONFIG_NFT_NUMGEN=m +CONFIG_NFT_CT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NETFILTER_XT_SET=m +CONFIG_NETFILTER_XT_TARGET_AUDIT=m +CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m +CONFIG_NETFILTER_XT_TARGET_CT=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_HMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TRACE=m +CONFIG_NETFILTER_XT_TARGET_SECMARK=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_BPF=m +CONFIG_NETFILTER_XT_MATCH_CGROUP=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLABEL=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPCOMP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_NFACCT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SOCKET=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_SET=m +CONFIG_IP_SET_BITMAP_IP=m +CONFIG_IP_SET_BITMAP_IPMAC=m +CONFIG_IP_SET_BITMAP_PORT=m +CONFIG_IP_SET_HASH_IP=m +CONFIG_IP_SET_HASH_IPMARK=m +CONFIG_IP_SET_HASH_IPPORT=m +CONFIG_IP_SET_HASH_IPPORTIP=m +CONFIG_IP_SET_HASH_IPPORTNET=m +CONFIG_IP_SET_HASH_MAC=m +CONFIG_IP_SET_HASH_NETPORTNET=m +CONFIG_IP_SET_HASH_NET=m +CONFIG_IP_SET_HASH_NETNET=m +CONFIG_IP_SET_HASH_NETPORT=m +CONFIG_IP_SET_HASH_NETIFACE=m +CONFIG_IP_SET_LIST_SET=m +CONFIG_IP_VS=m +CONFIG_IP_VS_IPV6=y +CONFIG_IP_VS_PROTO_TCP=y +CONFIG_IP_VS_PROTO_UDP=y +CONFIG_IP_VS_PROTO_ESP=y +CONFIG_IP_VS_PROTO_AH=y +CONFIG_IP_VS_PROTO_SCTP=y +CONFIG_IP_VS_RR=m +CONFIG_IP_VS_WRR=m +CONFIG_IP_VS_LC=m +CONFIG_IP_VS_WLC=m +CONFIG_IP_VS_FO=m +CONFIG_IP_VS_OVF=m +CONFIG_IP_VS_LBLC=m +CONFIG_IP_VS_LBLCR=m +CONFIG_IP_VS_DH=m +CONFIG_IP_VS_SH=m +CONFIG_IP_VS_SED=m +CONFIG_IP_VS_NQ=m +CONFIG_IP_VS_FTP=m +CONFIG_IP_VS_PE_SIP=m +CONFIG_NF_LOG_ARP=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_RPFILTER=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_SYNPROXY=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NF_TABLES_BRIDGE=m +CONFIG_NFT_BRIDGE_META=m +CONFIG_BRIDGE_NF_EBTABLES=m +CONFIG_BRIDGE_EBT_BROUTE=m +CONFIG_BRIDGE_EBT_T_FILTER=m +CONFIG_BRIDGE_EBT_T_NAT=m +CONFIG_BRIDGE_EBT_802_3=m +CONFIG_BRIDGE_EBT_AMONG=m +CONFIG_BRIDGE_EBT_ARP=m +CONFIG_BRIDGE_EBT_IP=m +CONFIG_BRIDGE_EBT_IP6=m +CONFIG_BRIDGE_EBT_LIMIT=m +CONFIG_BRIDGE_EBT_MARK=m +CONFIG_BRIDGE_EBT_PKTTYPE=m +CONFIG_BRIDGE_EBT_STP=m +CONFIG_BRIDGE_EBT_VLAN=m +CONFIG_BRIDGE_EBT_ARPREPLY=m +CONFIG_BRIDGE_EBT_DNAT=m +CONFIG_BRIDGE_EBT_MARK_T=m +CONFIG_BRIDGE_EBT_REDIRECT=m +CONFIG_BRIDGE_EBT_SNAT=m +CONFIG_BRIDGE_EBT_LOG=m +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_IP_SCTP=m +CONFIG_SCTP_COOKIE_HMAC_SHA1=y +CONFIG_RDS=m +CONFIG_RDS_TCP=m +CONFIG_TIPC=m +CONFIG_ATM=m +CONFIG_ATM_CLIP=m +CONFIG_ATM_LANE=m +CONFIG_ATM_MPOA=m +CONFIG_ATM_BR2684=m +CONFIG_ATM_BR2684_IPFILTER=y +CONFIG_L2TP=m +CONFIG_L2TP_DEBUGFS=m +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_NET_DSA=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y +CONFIG_VLAN_8021Q_MVRP=y +CONFIG_IEEE802154=m +CONFIG_IEEE802154_NL802154_EXPERIMENTAL=y +CONFIG_MAC802154=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_HTB=m +CONFIG_NET_SCH_HFSC=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFB=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +CONFIG_NET_SCH_GRED=m +CONFIG_NET_SCH_DSMARK=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_SCH_DRR=m +CONFIG_NET_SCH_MQPRIO=m +CONFIG_NET_SCH_CHOKE=m +CONFIG_NET_SCH_QFQ=m +CONFIG_NET_SCH_CODEL=m +CONFIG_NET_SCH_FQ_CODEL=m +CONFIG_NET_SCH_FQ=m +CONFIG_NET_SCH_HHF=m +CONFIG_NET_SCH_PIE=m +CONFIG_NET_SCH_PLUG=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_ROUTE4=m +CONFIG_NET_CLS_FW=m +CONFIG_NET_CLS_U32=m +CONFIG_CLS_U32_PERF=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_RSVP=m +CONFIG_NET_CLS_RSVP6=m +CONFIG_NET_CLS_FLOW=m +CONFIG_NET_CLS_CGROUP=m +CONFIG_NET_CLS_BPF=m +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_CLS_MATCHALL=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_EMATCH_NBYTE=m +CONFIG_NET_EMATCH_U32=m +CONFIG_NET_EMATCH_META=m +CONFIG_NET_EMATCH_TEXT=m +CONFIG_NET_EMATCH_IPSET=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=m +CONFIG_NET_ACT_GACT=m +CONFIG_GACT_PROB=y +CONFIG_NET_ACT_MIRRED=m +CONFIG_NET_ACT_IPT=m +CONFIG_NET_ACT_NAT=m +CONFIG_NET_ACT_PEDIT=m +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_NET_ACT_CSUM=m +CONFIG_NET_ACT_VLAN=m +CONFIG_NET_ACT_BPF=m +CONFIG_NET_ACT_CONNMARK=m +CONFIG_NET_ACT_SKBMOD=m +CONFIG_NET_ACT_IFE=m +CONFIG_NET_ACT_TUNNEL_KEY=m +CONFIG_NET_IFE_SKBMARK=m +CONFIG_NET_IFE_SKBPRIO=m +CONFIG_NET_IFE_SKBTCINDEX=m +CONFIG_DCB=y +CONFIG_BATMAN_ADV=m +# CONFIG_BATMAN_ADV_BATMAN_V is not set +CONFIG_BATMAN_ADV_NC=y +CONFIG_OPENVSWITCH=m +CONFIG_VSOCKETS=m +CONFIG_VIRTIO_VSOCKETS=m +CONFIG_NETLINK_DIAG=m +CONFIG_HSR=m +CONFIG_CGROUP_NET_PRIO=y +CONFIG_NET_PKTGEN=y +CONFIG_BT=m +CONFIG_BT_RFCOMM=m +CONFIG_BT_BNEP=m +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_H4=y +CONFIG_CFG80211=m +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_MESH=y +CONFIG_RFKILL=y +CONFIG_RFKILL_GPIO=m +CONFIG_NET_9P=m +CONFIG_CEPH_LIB_USE_DNS_RESOLVER=y +CONFIG_PCI=y +CONFIG_PCIEPORTBUS=y +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_PCIE_PTM=y +CONFIG_PCI_REALLOC_ENABLE_AUTO=y +CONFIG_PCI_STUB=m +CONFIG_PCI_IOV=y +CONFIG_PCI_PRI=y +CONFIG_PCI_PASID=y +CONFIG_HOTPLUG_PCI=y +CONFIG_PCIE_BAIKAL_HOST=y +CONFIG_PCIE_BAIKAL_EP=y +CONFIG_PCI_ENDPOINT=y +CONFIG_PCI_ENDPOINT_CONFIGFS=y +CONFIG_PCI_EPF_TEST=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y +CONFIG_EFI_BOOTLOADER_CONTROL=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BAIKAL_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_JEDECPROBE=y +CONFIG_MTD_SPI_NOR=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_DRBD=y +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_ATA_OVER_ETH=m +CONFIG_VIRTIO_BLK=m +CONFIG_BLK_DEV_RBD=y +CONFIG_BLK_DEV_NVME=y +CONFIG_TP_BMC=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=m +CONFIG_RAID_ATTRS=m +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=m +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_FC_ATTRS=m +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_SRP_ATTRS=m +CONFIG_ISCSI_TCP=m +CONFIG_SCSI_HPSA=m +CONFIG_SCSI_QLA_FC=m +CONFIG_SCSI_VIRTIO=m +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_SATA_AHCI_PLATFORM=y +CONFIG_AHCI_DWC=y +CONFIG_SATA_SIL24=m +# CONFIG_ATA_SFF is not set +CONFIG_MD=y +CONFIG_MD_LINEAR=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BCACHE=m +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_THIN_PROVISIONING=m +CONFIG_DM_CACHE=m +CONFIG_DM_MIRROR=m +CONFIG_DM_RAID=m +CONFIG_DM_ZERO=m +CONFIG_DM_MULTIPATH=m +CONFIG_DM_MULTIPATH_QL=m +CONFIG_DM_MULTIPATH_ST=m +CONFIG_DM_UEVENT=y +CONFIG_DM_SWITCH=m +CONFIG_TARGET_CORE=m +CONFIG_TCM_IBLOCK=m +CONFIG_TCM_FILEIO=m +CONFIG_TCM_PSCSI=m +CONFIG_LOOPBACK_TARGET=m +CONFIG_ISCSI_TARGET=m +CONFIG_FIREWIRE=m +CONFIG_FIREWIRE_OHCI=m +CONFIG_FIREWIRE_SBP2=m +CONFIG_FIREWIRE_NET=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_DUMMY=m +CONFIG_NET_FC=y +CONFIG_NET_TEAM=m +CONFIG_MACVLAN=m +CONFIG_MACVTAP=m +CONFIG_IPVLAN=m +CONFIG_VXLAN=m +CONFIG_GENEVE=m +CONFIG_GTP=m +CONFIG_MACSEC=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_TUN=m +CONFIG_VETH=m +CONFIG_NLMON=m +CONFIG_NET_VRF=m +CONFIG_ATM_TCP=m +CONFIG_AMD_XGBE=y +CONFIG_E1000E=m +CONFIG_IXGB=m +CONFIG_IXGBE=m +CONFIG_IXGBEVF=m +CONFIG_STMMAC_ETH=y +CONFIG_DWMAC_BAIKAL=y +CONFIG_MARVELL_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_REALTEK_PHY=y +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_GPIO=m +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_ZAURUS is not set +CONFIG_ATH10K=m +CONFIG_ATH10K_PCI=m +CONFIG_RTL8192CE=m +CONFIG_RTL8192SE=m +CONFIG_RTL8192DE=m +CONFIG_RTL8723AE=m +CONFIG_RTL8723BE=m +CONFIG_RTL8188EE=m +CONFIG_RTL8192EE=m +CONFIG_RTL8821AE=m +# CONFIG_IEEE802154_DRIVERS is not set +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_EVDEV=y +# CONFIG_MOUSE_PS2 is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=2 +CONFIG_SERIAL_8250_RUNTIME_UARTS=2 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_BAIKAL_SMBUS=y +CONFIG_I2C_DESIGNWARE_SLAVE=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +CONFIG_SPI=y +CONFIG_SPI_BAIKAL_ESPI=y +CONFIG_SPI_DESIGNWARE=y +CONFIG_SPI_DW_DMA=y +CONFIG_SPI_DW_MMIO=y +CONFIG_SPI_SPIDEV=y +CONFIG_GPIO_GENERIC_PLATFORM=y +CONFIG_GPIO_PCF857X=y +CONFIG_SENSORS_BT1_PVT=y +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +# CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is not set +CONFIG_GPIO_WATCHDOG=m +CONFIG_DW_WATCHDOG=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_PWC=m +CONFIG_USB_S2255=m +CONFIG_VIDEO_USBTV=m +CONFIG_USB_VIDEO_CLASS=m +CONFIG_VIDEO_EM28XX=m +CONFIG_VIDEO_EM28XX_V4L2=m +CONFIG_VIDEO_EM28XX_ALSA=m +CONFIG_DRM=y +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +CONFIG_DRM_BAIKAL_VDU=y +CONFIG_DRM_RADEON=m +CONFIG_DRM_AMDGPU=m +CONFIG_DRM_NOUVEAU=m +CONFIG_DRM_VGEM=m +CONFIG_DRM_QXL=m +CONFIG_DRM_VIRTIO_GPU=m +CONFIG_DRM_PANEL_BAIKAL_LVDS=y +CONFIG_DRM_PANEL_LVDS=y +CONFIG_DRM_BAIKAL_HDMI=y +CONFIG_DRM_BAIKAL_HDMI_AHB_AUDIO=y +CONFIG_DRM_CIRRUS_QEMU=m +CONFIG_DRM_PANFROST=m +CONFIG_FB=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=m +CONFIG_SND_PCM_OSS=m +CONFIG_SND_HRTIMER=m +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_SEQUENCER=m +CONFIG_SND_SEQUENCER_OSS=m +CONFIG_SND_DUMMY=m +CONFIG_SND_HDA_BAIKAL=y +CONFIG_SND_HDA_CODEC_REALTEK=y +# CONFIG_SND_SPI is not set +CONFIG_SND_USB_AUDIO=y +# CONFIG_SND_FIREWIRE is not set +CONFIG_SND_SOC=y +CONFIG_SND_BAIKAL_I2S=y +CONFIG_SND_BAIKAL_PIO_PCM=y +CONFIG_SND_SOC_AC97_CODEC=m +CONFIG_SND_SOC_SPDIF=m +CONFIG_SND_SOC_TLV320AIC3X_I2C=y +CONFIG_SND_SOC_NAU8822=y +CONFIG_SND_SIMPLE_CARD=y +CONFIG_HID_BATTERY_STRENGTH=y +CONFIG_HIDRAW=y +CONFIG_UHID=m +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_HIDPP=m +CONFIG_USB_ULPI_BUS=y +CONFIG_USB=y +CONFIG_USB_MON=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_HCD_TEST_MODE=y +CONFIG_USB_ACM=m +CONFIG_USB_STORAGE=y +CONFIG_USB_UAS=y +CONFIG_USBIP_CORE=m +CONFIG_USBIP_VHCI_HCD=m +CONFIG_USBIP_HOST=m +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_ULPI=y +# CONFIG_USB_DWC3_HAPS is not set +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_ULPI=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_DWCMSHC=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_USER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_ABEOZ9=y +CONFIG_RTC_DRV_PCF2127=y +CONFIG_DMADEVICES=y +CONFIG_PL330_DMA=m +CONFIG_DW_DMAC=y +CONFIG_VIRT_DRIVERS=y +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=m +CONFIG_VHOST_NET=m +CONFIG_VHOST_SCSI=m +CONFIG_VHOST_VSOCK=m +CONFIG_VHOST_CROSS_ENDIAN_LEGACY=y +CONFIG_BAIKAL_DW_APB_TIMER=y +# CONFIG_FSL_ERRATUM_A008585 is not set +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +CONFIG_MAILBOX=y +CONFIG_ARM_MHU=m +CONFIG_ARM_SMMU=y +CONFIG_ARM_SMMU_V3=y +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_USB_PHY_BAIKAL=y +CONFIG_ARM_CCN=y +CONFIG_MUX_BAIKAL=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_XFS_FS=y +CONFIG_XFS_QUOTA=y +CONFIG_XFS_POSIX_ACL=y +CONFIG_XFS_RT=y +CONFIG_BTRFS_FS=m +CONFIG_BTRFS_FS_POSIX_ACL=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FANOTIFY=y +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=m +CONFIG_FSCACHE=y +CONFIG_FSCACHE_STATS=y +CONFIG_CACHEFILES=y +CONFIG_ISO9660_FS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +CONFIG_FAT_DEFAULT_UTF8=y +CONFIG_NTFS_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_CHILDREN=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_EFIVAR_FS=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_FILE_DIRECT=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZSTD=y +CONFIG_PSTORE=y +# CONFIG_PSTORE_DEFLATE_COMPRESS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFS_SWAP=y +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="y" +CONFIG_NFS_V4_1_MIGRATION=y +CONFIG_NFSD=y +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_NFSD_BLOCKLAYOUT=y +CONFIG_NFSD_SCSILAYOUT=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_9P_FS=m +CONFIG_9P_FS_POSIX_ACL=y +CONFIG_9P_FS_SECURITY=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_852=y +CONFIG_NLS_CODEPAGE_866=y +CONFIG_NLS_CODEPAGE_1251=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_5=y +CONFIG_NLS_KOI8_R=y +CONFIG_NLS_UTF8=y +CONFIG_PERSISTENT_KEYRINGS=y +CONFIG_ENCRYPTED_KEYS=y +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_ARC4=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_DEFLATE=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_LZ4HC=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_USER_API_HASH=y +CONFIG_CRYPTO_USER_API_SKCIPHER=y +CONFIG_CRYPTO_USER_API_AEAD=y +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=256 +CONFIG_IRQ_POLL=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_PAGE_EXTENSION=y +CONFIG_PAGE_POISONING=y +CONFIG_IO_STRICT_DEVMEM=y +CONFIG_CORESIGHT=m +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=m +CONFIG_CORESIGHT_SINK_TPIU=m +CONFIG_CORESIGHT_SOURCE_ETM4X=m +CONFIG_ETM4X_IMPDEF_FEATURE=y +CONFIG_CORESIGHT_STM=m +CONFIG_CORESIGHT_CPU_DEBUG=m +CONFIG_CORESIGHT_CTI=m +CONFIG_CORESIGHT_TRBE=m +CONFIG_TEST_USER_COPY=m +CONFIG_TEST_BPF=m +CONFIG_TEST_FIRMWARE=m +CONFIG_TEST_STATIC_KEYS=m diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index 860014b89b8eb..f627d0cb45663 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -171,6 +171,30 @@ static struct mcfg_fixup mcfg_quirks[] = { ALTRA_ECAM_QUIRK(1, 13), ALTRA_ECAM_QUIRK(1, 14), ALTRA_ECAM_QUIRK(1, 15), + +#define BAIKAL_ECAM(table_id, rev, seg, ops) \ + { "BAIKAL", table_id, rev, seg, MCFG_BUS_ANY, ops } + + /* Baikal-M Synopsys DesignWare PCIe */ + BAIKAL_ECAM("BKLEMCFG", 1, 0, &baikal_m_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 1, 1, &baikal_m_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 1, 2, &baikal_m_pcie_ecam_ops), + + /* Baikal-S Synopsys DesignWare PCIe */ + BAIKAL_ECAM("BKLEMCFG", 2, 0, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 1, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 2, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 3, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 4, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 5, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 6, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 7, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 8, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 9, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 10, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 11, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 12, &baikal_s_pcie_ecam_ops), + BAIKAL_ECAM("BKLEMCFG", 2, 13, &baikal_s_pcie_ecam_ops), #endif /* ARM64 */ #ifdef CONFIG_LOONGARCH diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c index 8fb66860db318..a694e6c2dae4e 100644 --- a/drivers/ata/ahci_dwc.c +++ b/drivers/ata/ahci_dwc.c @@ -468,10 +468,15 @@ static struct ahci_dwc_plat_data ahci_bt1_plat = { .init = ahci_bt1_init, }; +static struct ahci_dwc_plat_data ahci_bm1000_plat = { + .pflags = AHCI_PLATFORM_GET_RESETS | AHCI_PLATFORM_RST_TRIGGER, +}; + static const struct of_device_id ahci_dwc_of_match[] = { { .compatible = "snps,dwc-ahci", &ahci_dwc_plat }, { .compatible = "snps,spear-ahci", &ahci_dwc_plat }, { .compatible = "baikal,bt1-ahci", &ahci_bt1_plat }, + { .compatible = "baikal,bm1000-ahci", &ahci_bm1000_plat }, {}, }; MODULE_DEVICE_TABLE(of, ahci_dwc_of_match); diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e3ca0d058a256..5e86cc0f7a251 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -83,6 +83,7 @@ obj-y += analogbits/ obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_ARCH_ARTPEC) += axis/ obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/ +obj-$(CONFIG_ARCH_BAIKAL) += baikal/ obj-$(CONFIG_CLK_BAIKAL_T1) += baikal-t1/ obj-y += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ diff --git a/drivers/clk/baikal/Makefile b/drivers/clk/baikal/Makefile new file mode 100644 index 0000000000000..dc94047aa9131 --- /dev/null +++ b/drivers/clk/baikal/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-y += clk-bm1000.o +obj-y += clk-bs1000.o diff --git a/drivers/clk/baikal/clk-bm1000.c b/drivers/clk/baikal/clk-bm1000.c new file mode 100644 index 0000000000000..d986c8ea2a633 --- /dev/null +++ b/drivers/clk/baikal/clk-bm1000.c @@ -0,0 +1,841 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015-2023 Baikal Electronics, JSC + * Author: Ekaterina Skachko + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BAIKAL_SMC_CMU_CMD 0x82000000 +#define CMU_PLL_SET_RATE 0 +#define CMU_PLL_GET_RATE 1 +#define CMU_PLL_ENABLE 2 +#define CMU_PLL_DISABLE 3 +#define CMU_PLL_ROUND_RATE 4 +#define CMU_PLL_IS_ENABLED 5 +#define CMU_CLK_CH_SET_RATE 6 +#define CMU_CLK_CH_GET_RATE 7 +#define CMU_CLK_CH_ENABLE 8 +#define CMU_CLK_CH_DISABLE 9 +#define CMU_CLK_CH_ROUND_RATE 10 +#define CMU_CLK_CH_IS_ENABLED 11 + +struct baikal_clk_cmu { + struct clk_hw hw; + u32 base; + unsigned int parent; + const char *name; + u32 is_clk_ch; +}; + +#define to_baikal_cmu(_hw) container_of(_hw, struct baikal_clk_cmu, hw) + +static int baikal_clk_enable(struct clk_hw *hw) +{ + struct arm_smccc_res res; + struct baikal_clk_cmu *pclk = to_baikal_cmu(hw); + u32 cmd; + + if (pclk->is_clk_ch) + cmd = CMU_CLK_CH_ENABLE; + else + cmd = CMU_PLL_ENABLE; + + /* If clock valid */ + arm_smccc_smc(BAIKAL_SMC_CMU_CMD, pclk->base, cmd, 0, + pclk->parent, 0, 0, 0, &res); + + pr_debug("%s(%s, %s@0x%x): %s\n", + __func__, + pclk->name, + pclk->is_clk_ch ? "clkch" : "pll", + pclk->base, + res.a0 ? "error" : "ok"); + + return res.a0; +} + +static void baikal_clk_disable(struct clk_hw *hw) +{ + struct arm_smccc_res res; + struct baikal_clk_cmu *pclk = to_baikal_cmu(hw); + u32 cmd; + + if (pclk->is_clk_ch) + cmd = CMU_CLK_CH_DISABLE; + else + cmd = CMU_PLL_DISABLE; + + /* If clock valid */ + arm_smccc_smc(BAIKAL_SMC_CMU_CMD, pclk->base, cmd, 0, + pclk->parent, 0, 0, 0, &res); + + pr_debug("%s(%s, %s@0x%x): %s\n", + __func__, + pclk->name, + pclk->is_clk_ch ? "clkch" : "pll", + pclk->base, + res.a0 ? "error" : "ok"); +} + +static int baikal_clk_is_enabled(struct clk_hw *hw) +{ + struct arm_smccc_res res; + struct baikal_clk_cmu *pclk = to_baikal_cmu(hw); + u32 cmd; + + if (pclk->is_clk_ch) + cmd = CMU_CLK_CH_IS_ENABLED; + else + cmd = CMU_PLL_IS_ENABLED; + + /* If clock valid */ + arm_smccc_smc(BAIKAL_SMC_CMU_CMD, pclk->base, cmd, 0, + pclk->parent, 0, 0, 0, &res); + + pr_debug("%s(%s, %s@0x%x): %s\n", + __func__, + pclk->name, + pclk->is_clk_ch ? "clkch" : "pll", + pclk->base, + res.a0 ? "true" : "false"); + + return res.a0; +} + +static unsigned long baikal_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct arm_smccc_res res; + struct baikal_clk_cmu *pclk = to_baikal_cmu(hw); + u32 cmd; + unsigned long parent; + + if (pclk->is_clk_ch) { + cmd = CMU_CLK_CH_GET_RATE; + parent = pclk->parent; + } else { + cmd = CMU_PLL_GET_RATE; + parent = parent_rate; + } + + /* If clock valid */ + arm_smccc_smc(BAIKAL_SMC_CMU_CMD, pclk->base, cmd, 0, + parent, 0, 0, 0, &res); + + pr_debug("%s(%s, %s@0x%x): %ld Hz\n", + __func__, + pclk->name, + pclk->is_clk_ch ? "clkch" : "pll", + pclk->base, + res.a0); + + /* Return actual freq */ + return res.a0; +} + +static int baikal_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct arm_smccc_res res; + struct baikal_clk_cmu *pclk = to_baikal_cmu(hw); + u32 cmd; + unsigned long parent; + + if (pclk->is_clk_ch) { + cmd = CMU_CLK_CH_SET_RATE; + parent = pclk->parent; + } else { + cmd = CMU_PLL_SET_RATE; + parent = parent_rate; + } + + arm_smccc_smc(BAIKAL_SMC_CMU_CMD, pclk->base, cmd, rate, + parent, 0, 0, 0, &res); + + pr_debug("%s(%s, %s@0x%x, %ld Hz): %s\n", + __func__, + pclk->name, + pclk->is_clk_ch ? "clkch" : "pll", + pclk->base, + rate, + res.a0 ? "error" : "ok"); + + return res.a0; +} + +static long baikal_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct arm_smccc_res res; + struct baikal_clk_cmu *pclk = to_baikal_cmu(hw); + u32 cmd; + unsigned long parent; + + if (pclk->is_clk_ch) { + cmd = CMU_CLK_CH_ROUND_RATE; + parent = pclk->parent; + } else { + cmd = CMU_PLL_ROUND_RATE; + parent = *prate; + } + + /* If clock valid */ + arm_smccc_smc(BAIKAL_SMC_CMU_CMD, pclk->base, cmd, rate, + parent, 0, 0, 0, &res); + + pr_debug("%s(%s, %s@0x%x): %ld Hz\n", + __func__, + pclk->name, + pclk->is_clk_ch ? "clkch" : "pll", + pclk->base, + res.a0); + + /* Return actual freq */ + return res.a0; +} + +static const struct clk_ops baikal_clk_ops = { + .enable = baikal_clk_enable, + .disable = baikal_clk_disable, + .is_enabled = baikal_clk_is_enabled, + .recalc_rate = baikal_clk_recalc_rate, + .set_rate = baikal_clk_set_rate, + .round_rate = baikal_clk_round_rate, +}; + +static int baikal_clk_probe(struct platform_device *pdev) +{ + struct clk_init_data init; + struct clk_init_data *init_ch; + struct baikal_clk_cmu *cmu; + struct baikal_clk_cmu **cmu_ch; + struct device_node *node = pdev->dev.of_node; + + struct clk *clk; + struct clk_onecell_data *clk_ch; + + int i = 0, number, rc; + u32 index; + u64 base; + struct property *prop; + const __be32 *p; + const char *clk_ch_name; + const char *parent_name; + + cmu = kmalloc(sizeof(*cmu), GFP_KERNEL); + if (!cmu) + return -ENOMEM; + + of_property_read_string(node, "clock-output-names", &cmu->name); + of_property_read_u32(node, "clock-frequency", &cmu->parent); + rc = of_property_read_u64(node, "reg", &base); + if (rc) + return rc; + + cmu->base = base; + + parent_name = of_clk_get_parent_name(node, 0); + + /* Setup clock init structure */ + init.parent_names = &parent_name; + init.num_parents = 1; + init.name = cmu->name; + init.ops = &baikal_clk_ops; + init.flags = CLK_IGNORE_UNUSED; + + cmu->hw.init = &init; + cmu->is_clk_ch = 0; + + pr_debug("%s: add %s, parent %s\n", + __func__, cmu->name, parent_name ? parent_name : "null"); + + clk = clk_register(NULL, &cmu->hw); + if (IS_ERR(clk)) { + pr_err("%s: could not register clk %s\n", __func__, cmu->name); + return -ENOMEM; + } + + /* Register the clock for lookup */ + rc = clk_register_clkdev(clk, cmu->name, NULL); + if (rc != 0) { + pr_err("%s: could not register lookup clk %s\n", + __func__, cmu->name); + } + + /* FIXME: we probably shouldn't enable it here */ + clk_prepare_enable(clk); + + number = of_property_count_u32_elems(node, "clock-indices"); + + if (number > 0) { + clk_ch = kmalloc(sizeof(*clk_ch), GFP_KERNEL); + if (!clk_ch) + return -ENOMEM; + + /* Get the last index to find out max number of children*/ + of_property_for_each_u32(node, "clock-indices", prop, p, index) { + ; + } + + clk_ch->clks = kcalloc(index + 1, sizeof(struct clk *), GFP_KERNEL); + clk_ch->clk_num = index + 1; + cmu_ch = kcalloc((index + 1), sizeof(struct baikal_clk_cmu *), GFP_KERNEL); + if (!cmu_ch) { + kfree(clk_ch); + return -ENOMEM; + } + + init_ch = kcalloc((number + 1), sizeof(struct clk_init_data), GFP_KERNEL); + if (!init_ch) { + kfree(cmu_ch); + kfree(clk_ch); + return -ENOMEM; + } + + of_property_for_each_u32(node, "clock-indices", prop, p, index) { + of_property_read_string_index(node, "clock-names", + i, &clk_ch_name); + pr_debug("%s: clkch <%s>, index %d, i %d\n", __func__, clk_ch_name, index, i); + init_ch[i].parent_names = &cmu->name; + init_ch[i].num_parents = 1; + init_ch[i].name = clk_ch_name; + init_ch[i].ops = &baikal_clk_ops; + init_ch[i].flags = CLK_IGNORE_UNUSED; + + cmu_ch[index] = kmalloc(sizeof(*cmu_ch[index]), GFP_KERNEL); + cmu_ch[index]->name = clk_ch_name; + cmu_ch[index]->base = index; + cmu_ch[index]->parent = cmu->base; + cmu_ch[index]->is_clk_ch = 1; + cmu_ch[index]->hw.init = &init_ch[i]; + clk_ch->clks[index] = clk_register(NULL, &cmu_ch[index]->hw); + + if (IS_ERR(clk_ch->clks[index])) { + pr_err("%s: could not register clk %s\n", + __func__, clk_ch_name); + } + + /* Register the clock for lookup */ + rc = clk_register_clkdev(clk_ch->clks[index], clk_ch_name, NULL); + if (rc != 0) { + pr_err("%s: could not register lookup clk %s\n", + __func__, clk_ch_name); + } + + /* FIXME: we probably shouldn't enable it here */ + clk_prepare_enable(clk_ch->clks[index]); + i++; + } + + return of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, clk_ch); + } + + return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk); +} + +static int baikal_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +#ifdef CONFIG_ACPI +const char *baikal_acpi_clk_osc25_str[] = { "osc25" }; +const char *baikal_acpi_clk_osc27_str[] = { "osc27" }; + +static struct clk *baikal_acpi_clk_osc25; +static struct clk *baikal_acpi_clk_osc27; + +#define BAIKAL_CMU_CLK_CH 0x0 +#define BAIKAL_FIXED_CLK 0x1 +#define BAIKAL_FIXED_FACTOR_CLK 0x2 +#define BAIKAL_CMU_CLK 0xffffffffffffffff + +struct baikal_acpi_clk_data { + struct clk *cmu_clk; + struct clk_lookup *cmu_clk_l; + struct clk_lookup **cmu_clk_refs_l; + struct clk **clk; + struct clk_lookup **clk_l; + u8 *type; + unsigned int clk_num; + unsigned int cmu_clk_refs_num; +}; + +static int baikal_acpi_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct acpi_device *ref_dev, *adev = to_acpi_device_node(pdev->dev.fwnode); + struct clk_init_data init, *init_ch; + struct baikal_clk_cmu *cmu, *cmu_ch; + struct baikal_acpi_clk_data *clk_data = NULL; + union acpi_object *package, *element; + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + int osc27, i, ret = 0; + char *str, *str2; + + cmu = devm_kzalloc(dev, sizeof(*cmu), GFP_KERNEL); + if (!cmu) + return -ENOMEM; + + status = acpi_evaluate_object_typed(adev->handle, "PROP", NULL, &buffer, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + dev_err(dev, "failed to get PROP data\n"); + return -ENODEV; + } + + package = buffer.pointer; + if (package->package.count != 4) { + dev_err(dev, "invalid PROP data\n"); + ret = -EINVAL; + goto ret; + } + + element = &package->package.elements[0]; + if (element->type != ACPI_TYPE_INTEGER) { + dev_err(dev, "failed to get CMU id\n"); + ret = -EINVAL; + goto ret; + } + + cmu->base = element->integer.value; + + element = &package->package.elements[1]; + if (element->type != ACPI_TYPE_STRING) { + dev_err(dev, "failed to get CMU clock name\n"); + ret = -EINVAL; + goto ret; + } + + str = devm_kzalloc(dev, element->string.length + 1, GFP_KERNEL); + if (!str) { + ret = -ENOMEM; + goto ret; + } + + memcpy(str, element->string.pointer, element->string.length); + cmu->name = str; + + element = &package->package.elements[2]; + if (element->type != ACPI_TYPE_INTEGER) { + dev_err(dev, "failed to get CMU frequency\n"); + ret = -EINVAL; + goto ret; + } + + cmu->parent = element->integer.value; + + element = &package->package.elements[3]; + if (element->type != ACPI_TYPE_INTEGER) { + dev_err(dev, "failed to get CMU osc type\n"); + ret = -EINVAL; + goto ret; + } + + osc27 = element->integer.value ? 1 : 0; + + acpi_os_free(buffer.pointer); + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + + init.parent_names = osc27 ? baikal_acpi_clk_osc27_str : baikal_acpi_clk_osc25_str; + init.num_parents = 1; + init.name = cmu->name; + init.ops = &baikal_clk_ops; + init.flags = CLK_IGNORE_UNUSED; + + cmu->hw.init = &init; + cmu->is_clk_ch = 0; + + clk_data = devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->cmu_clk = clk_register(NULL, &cmu->hw); + if (IS_ERR(clk_data->cmu_clk)) { + dev_err(dev, "failed to register CMU clock\n"); + return PTR_ERR(clk_data->cmu_clk); + } + + clk_data->cmu_clk_l = clkdev_create(clk_data->cmu_clk, cmu->name, NULL); + if (!clk_data->cmu_clk_l) { + dev_err(dev, "failed to register CMU clock lookup\n"); + clk_unregister(clk_data->cmu_clk); + return -ENOMEM; + } + + clk_prepare_enable(clk_data->cmu_clk); + + platform_set_drvdata(pdev, clk_data); + + /* CPU clock */ + status = acpi_evaluate_object_typed(adev->handle, "CMU", NULL, &buffer, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + buffer.pointer = NULL; + goto clk_channels; + } + + package = buffer.pointer; + if (!package->package.count || package->package.count % 2) { + dev_err(dev, "invalid CMU data\n"); + ret = -EINVAL; + goto ret; + } + + clk_data->cmu_clk_refs_num = package->package.count >> 1; + clk_data->cmu_clk_refs_l = devm_kzalloc(dev, + clk_data->cmu_clk_refs_num * sizeof(struct clk_lookup *), + GFP_KERNEL); + if (!clk_data->cmu_clk_refs_l) { + ret = -ENOMEM; + goto ret; + } + + for (i = 0; i < clk_data->cmu_clk_refs_num; ++i) { + ref_dev = NULL; + + element = &package->package.elements[2 * i]; + if (element->type == ACPI_TYPE_LOCAL_REFERENCE && element->reference.handle) + ref_dev = acpi_fetch_acpi_dev(element->reference.handle); + + element = &package->package.elements[2 * i + 1]; + if (element->type == ACPI_TYPE_STRING) { + str2 = devm_kzalloc(dev, element->string.length + 1, GFP_KERNEL); + if (str2) + memcpy(str2, element->string.pointer, element->string.length); + } else { + str2 = NULL; + } + + if (ref_dev && acpi_get_first_physical_node(ref_dev)) + clk_data->cmu_clk_refs_l[i] = + clkdev_create(clk_data->cmu_clk, str2, "%s", + dev_name(acpi_get_first_physical_node(ref_dev))); + else + clk_data->cmu_clk_refs_l[i] = clkdev_create(clk_data->cmu_clk, str2, NULL); + } + + acpi_os_free(buffer.pointer); + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + +clk_channels: + status = acpi_evaluate_object_typed(adev->handle, "CLKS", NULL, &buffer, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + buffer.pointer = NULL; + clk_data = NULL; + goto ret; + } + + package = buffer.pointer; + if (!package->package.count || package->package.count % 4) { + dev_err(dev, "invalid CLKS data\n"); + ret = -EINVAL; + goto ret; + } + + clk_data->clk_num = package->package.count >> 2; + clk_data->clk = devm_kzalloc(dev, clk_data->clk_num * sizeof(struct clk *), GFP_KERNEL); + if (!clk_data->clk) { + ret = -ENOMEM; + goto ret; + } + + clk_data->clk_l = devm_kzalloc(dev, clk_data->clk_num * sizeof(struct clk_lookup *), + GFP_KERNEL); + if (!clk_data->clk_l) { + ret = -ENOMEM; + goto ret; + } + + clk_data->type = devm_kzalloc(dev, clk_data->clk_num * sizeof(u8), GFP_KERNEL); + if (!clk_data->type) { + ret = -ENOMEM; + goto ret; + } + + init_ch = devm_kzalloc(dev, clk_data->clk_num * sizeof(struct clk_init_data), GFP_KERNEL); + if (!init_ch) { + ret = -ENOMEM; + goto ret; + } + + cmu_ch = devm_kzalloc(dev, clk_data->clk_num * sizeof(struct baikal_clk_cmu), GFP_KERNEL); + if (!cmu_ch) { + ret = -ENOMEM; + goto ret; + } + + for (i = 0; i < clk_data->clk_num; ++i) { + ref_dev = NULL; + + element = &package->package.elements[4 * i]; + if (element->type == ACPI_TYPE_LOCAL_REFERENCE && element->reference.handle) + ref_dev = acpi_fetch_acpi_dev(element->reference.handle); + + element = &package->package.elements[4 * i + 1]; + if (element->type == ACPI_TYPE_STRING) { + str = devm_kzalloc(dev, element->string.length + 1, GFP_KERNEL); + if (str) + memcpy(str, element->string.pointer, element->string.length); + } else { + dev_err(dev, "failed to process clock device name #%i\n", i); + continue; + } + + element = &package->package.elements[4 * i + 2]; + if (element->type == ACPI_TYPE_INTEGER) { + if (element->integer.value != BAIKAL_CMU_CLK) { + init_ch[i].parent_names = &cmu->name; + init_ch[i].num_parents = 1; + init_ch[i].name = str; + init_ch[i].ops = &baikal_clk_ops; + init_ch[i].flags = CLK_IGNORE_UNUSED; + + cmu_ch[i].name = str; + cmu_ch[i].base = element->integer.value; + cmu_ch[i].parent = cmu->base; + cmu_ch[i].is_clk_ch = 1; + cmu_ch[i].hw.init = &init_ch[i]; + + clk_data->type[i] = BAIKAL_CMU_CLK_CH; + clk_data->clk[i] = clk_register(ref_dev ? &ref_dev->dev : NULL, + &cmu_ch[i].hw); + if (IS_ERR(clk_data->clk[i])) { + dev_err(dev, "failed to register CMU channel clock #%i\n", i); + clk_data->clk[i] = NULL; + continue; + } + } + } else if (element->type == ACPI_TYPE_PACKAGE && + element->package.count == 3 && + element->package.elements[0].type == ACPI_TYPE_INTEGER && + element->package.elements[1].type == ACPI_TYPE_INTEGER && + element->package.elements[2].type == ACPI_TYPE_INTEGER) { + /* Fixed clock */ + struct clk_hw *hw; + u64 type = element->package.elements[0].integer.value; + u64 val1 = element->package.elements[1].integer.value; + u64 val2 = element->package.elements[2].integer.value; + + switch (type) { + case BAIKAL_FIXED_CLK: + clk_data->type[i] = BAIKAL_FIXED_CLK; + hw = clk_hw_register_fixed_rate_with_accuracy(ref_dev ? + &ref_dev->dev : NULL, + str, NULL, 0, + val1, val2); + if (IS_ERR(hw)) { + dev_err(dev, "failed to register fixed clock #%i\n", i); + continue; + } + clk_data->clk[i] = hw->clk; + break; + case BAIKAL_FIXED_FACTOR_CLK: + clk_data->type[i] = BAIKAL_FIXED_FACTOR_CLK; + hw = clk_hw_register_fixed_factor(ref_dev ? &ref_dev->dev : NULL, + str, cmu->name, 0, val1, val2); + if (IS_ERR(hw)) { + dev_err(dev, "failed to register fixed-factor clock #%i\n", i); + continue; + } + clk_data->clk[i] = hw->clk; + break; + default: + dev_err(dev, "failed to create clock #%i\n", i); + continue; + } + } else { + dev_err(dev, "failed to process clock device id #%i\n", i); + continue; + } + + element = &package->package.elements[4 * i + 3]; + if (element->type == ACPI_TYPE_STRING) { + str2 = devm_kzalloc(dev, element->string.length + 1, GFP_KERNEL); + if (str2) + memcpy(str2, element->string.pointer, element->string.length); + } else { + str2 = NULL; + } + + if (ref_dev || str2) { + if (!clk_data->clk[i]) { + if (ref_dev) + clk_data->clk_l[i] = clkdev_create(clk_data->cmu_clk, + str2, "%s", + dev_name(&ref_dev->dev)); + else + clk_data->clk_l[i] = clkdev_create(clk_data->cmu_clk, + str2, NULL); + } else { + if (ref_dev) + clk_data->clk_l[i] = clkdev_create(clk_data->clk[i], + str2, "%s", + dev_name(&ref_dev->dev)); + else + clk_data->clk_l[i] = clkdev_create(clk_data->clk[i], + str2, NULL); + } + + if (!clk_data->clk_l[i]) { + dev_err(dev, "failed to register clock lookup #%i\n", i); + clk_unregister(clk_data->clk[i]); + clk_data->clk[i] = NULL; + continue; + } + } + + clk_prepare_enable(clk_data->clk[i]); + } + + clk_data = NULL; + +ret: + if (buffer.pointer) + acpi_os_free(buffer.pointer); + + if (clk_data) { + clk_disable_unprepare(clk_data->cmu_clk); + clkdev_drop(clk_data->cmu_clk_l); + clk_unregister(clk_data->cmu_clk); + } + + return ret; +} + +static int baikal_acpi_clk_remove(struct platform_device *pdev) +{ + struct baikal_acpi_clk_data *clk_data = platform_get_drvdata(pdev); + int i; + + if (clk_data) { + clk_disable_unprepare(clk_data->cmu_clk); + clkdev_drop(clk_data->cmu_clk_l); + clk_unregister(clk_data->cmu_clk); + + for (i = 0; i < clk_data->cmu_clk_refs_num; ++i) { + if (clk_data->cmu_clk_refs_l[i]) + clkdev_drop(clk_data->cmu_clk_refs_l[i]); + } + + for (i = 0; i < clk_data->clk_num; ++i) { + if (clk_data->clk_l[i]) + clkdev_drop(clk_data->clk_l[i]); + if (clk_data->clk[i]) { + switch (clk_data->type[i]) { + case BAIKAL_FIXED_CLK: + clk_unregister_fixed_rate(clk_data->clk[i]); + break; + case BAIKAL_FIXED_FACTOR_CLK: + clk_unregister_fixed_factor(clk_data->clk[i]); + break; + default: + clk_unregister(clk_data->clk[i]); + break; + } + } + } + } + + return 0; +} + +static const struct acpi_device_id baikal_acpi_clk_device_ids[] = { + { "BKLE0001" }, + { } +}; + +static struct platform_driver baikal_acpi_clk_driver = { + .probe = baikal_acpi_clk_probe, + .remove = baikal_acpi_clk_remove, + .driver = { + .name = "bm1000-cmu-acpi", + .acpi_match_table = ACPI_PTR(baikal_acpi_clk_device_ids) + } +}; + +static int __init bm1000_cmu_driver_acpi_init(void) +{ + if (!acpi_disabled) { + struct clk_lookup *baikal_acpi_clk_lookup_osc25; + struct clk_lookup *baikal_acpi_clk_lookup_osc27; + + baikal_acpi_clk_osc25 = clk_register_fixed_rate(NULL, baikal_acpi_clk_osc25_str[0], + NULL, 0, 25000000); + if (IS_ERR(baikal_acpi_clk_osc25)) { + pr_err("%s: failed to register osc25 clock\n", __func__); + return PTR_ERR(baikal_acpi_clk_osc25); + } + + baikal_acpi_clk_osc27 = clk_register_fixed_rate(NULL, baikal_acpi_clk_osc27_str[0], + NULL, 0, 27000000); + if (IS_ERR(baikal_acpi_clk_osc27)) { + clk_unregister_fixed_rate(baikal_acpi_clk_osc25); + pr_err("%s: failed to register osc27 clock\n", __func__); + return PTR_ERR(baikal_acpi_clk_osc27); + } + + baikal_acpi_clk_lookup_osc25 = clkdev_create(baikal_acpi_clk_osc25, NULL, "%s", + baikal_acpi_clk_osc25_str[0]); + if (!baikal_acpi_clk_lookup_osc25) { + clk_unregister_fixed_rate(baikal_acpi_clk_osc27); + clk_unregister_fixed_rate(baikal_acpi_clk_osc25); + pr_err("%s: failed to register osc25 clock lookup\n", __func__); + return -ENOMEM; + } + + baikal_acpi_clk_lookup_osc27 = clkdev_create(baikal_acpi_clk_osc27, NULL, "%s", + baikal_acpi_clk_osc27_str[0]); + if (!baikal_acpi_clk_lookup_osc27) { + clkdev_drop(baikal_acpi_clk_lookup_osc25); + clk_unregister_fixed_rate(baikal_acpi_clk_osc27); + clk_unregister_fixed_rate(baikal_acpi_clk_osc25); + pr_err("%s: failed to register osc27 clock lookup\n", __func__); + return -ENOMEM; + } + + clk_prepare_enable(baikal_acpi_clk_osc25); + clk_prepare_enable(baikal_acpi_clk_osc27); + + return platform_driver_register(&baikal_acpi_clk_driver); + } + + return 0; +} + +device_initcall(bm1000_cmu_driver_acpi_init); +#endif + +static const struct of_device_id baikal_clk_of_match[] = { + { .compatible = "baikal,bm1000-cmu" }, + { } +}; + +static struct platform_driver bm1000_cmu_driver = { + .probe = baikal_clk_probe, + .remove = baikal_clk_remove, + .driver = { + .name = "bm1000-cmu", + .of_match_table = baikal_clk_of_match + } +}; +module_platform_driver(bm1000_cmu_driver); + +MODULE_DESCRIPTION("Baikal BE-M1000 clock driver"); +MODULE_AUTHOR("Ekaterina Skachko "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bm1000-cmu"); diff --git a/drivers/clk/baikal/clk-bs1000.c b/drivers/clk/baikal/clk-bs1000.c new file mode 100644 index 0000000000000..a10c52e2dec8c --- /dev/null +++ b/drivers/clk/baikal/clk-bs1000.c @@ -0,0 +1,498 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2021-2023 Baikal Electronics, JSC + * Author: Ekaterina Skachko + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BAIKAL_SMC_CLK_ROUND 0x82000400 +#define BAIKAL_SMC_CLK_SET 0x82000401 +#define BAIKAL_SMC_CLK_GET 0x82000402 +#define BAIKAL_SMC_CLK_ENABLE 0x82000403 +#define BAIKAL_SMC_CLK_DISABLE 0x82000404 +#define BAIKAL_SMC_CLK_IS_ENABLED 0x82000405 + +struct baikal_clk { + struct clk_hw hw; + u32 base; +}; + +#define to_baikal_clk(_hw) container_of(_hw, struct baikal_clk, hw) + +static int baikal_clk_enable(struct clk_hw *hw) +{ + struct baikal_clk *clk = to_baikal_clk(hw); + struct arm_smccc_res res; + + arm_smccc_smc(BAIKAL_SMC_CLK_ENABLE, clk->base, 0, 0, 0, 0, 0, 0, &res); + return res.a0; +} + +static void baikal_clk_disable(struct clk_hw *hw) +{ + struct baikal_clk *clk = to_baikal_clk(hw); + struct arm_smccc_res res; + + arm_smccc_smc(BAIKAL_SMC_CLK_DISABLE, clk->base, 0, 0, 0, 0, 0, 0, &res); +} + +static int baikal_clk_is_enabled(struct clk_hw *hw) +{ + struct baikal_clk *clk = to_baikal_clk(hw); + struct arm_smccc_res res; + + arm_smccc_smc(BAIKAL_SMC_CLK_IS_ENABLED, clk->base, 0, 0, 0, 0, 0, 0, &res); + return res.a0; +} + +static unsigned long baikal_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct baikal_clk *clk = to_baikal_clk(hw); + struct arm_smccc_res res; + + arm_smccc_smc(BAIKAL_SMC_CLK_GET, clk->base, 0, 0, 0, 0, 0, 0, &res); + return res.a0; +} + +static int baikal_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct baikal_clk *clk = to_baikal_clk(hw); + struct arm_smccc_res res; + + arm_smccc_smc(BAIKAL_SMC_CLK_SET, clk->base, rate, 0, 0, 0, 0, 0, &res); + return res.a0; +} + +static long baikal_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct baikal_clk *clk = to_baikal_clk(hw); + struct arm_smccc_res res; + + arm_smccc_smc(BAIKAL_SMC_CLK_ROUND, clk->base, rate, 0, 0, 0, 0, 0, &res); + return res.a0; +} + +static const struct clk_ops baikal_clk_ops = { + .enable = baikal_clk_enable, + .disable = baikal_clk_disable, + .is_enabled = baikal_clk_is_enabled, + .recalc_rate = baikal_clk_recalc_rate, + .set_rate = baikal_clk_set_rate, + .round_rate = baikal_clk_round_rate, +}; + +static int baikal_clk_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_init_data init; + struct baikal_clk *cmu; + struct clk_onecell_data *clk_data; + const char *clk_name; + struct property *prop; + const __be32 *p; + int clk_index; + int clk_index_max; + int clk_index_cnt; + int clk_name_cnt; + int clk_cnt; + int i; + u32 base; + struct clk *clk; + int ret; + int multi; + + ret = of_property_read_u32(node, "reg", &base); + if (ret) + base = 0; + + clk_index_cnt = of_property_count_u32_elems(node, "clock-indices"); + clk_name_cnt = of_property_count_strings(node, "clock-output-names"); + clk_cnt = clk_index_cnt > clk_name_cnt ? clk_index_cnt : clk_name_cnt; + if (clk_cnt < 1) + clk_cnt = 1; + + multi = clk_cnt > 1; + + if (multi) { + clk_index_max = clk_cnt - 1; + of_property_for_each_u32(node, "clock-indices", prop, p, clk_index) { + if (clk_index_max < clk_index) + clk_index_max = clk_index; + } + + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); + clk_data->clks = kcalloc(clk_index_max + 1, sizeof(struct clk *), GFP_KERNEL); + clk_data->clk_num = clk_index_max + 1; + } + + for (i = 0; i < clk_cnt; i++) { + ret = of_property_read_u32_index(node, "clock-indices", i, &clk_index); + if (ret) + clk_index = i; + + ret = of_property_read_string_index(node, "clock-output-names", i, &clk_name); + if (ret) { + if (multi) + init.name = kasprintf(GFP_KERNEL, "%s.%d", node->name, clk_index); + else + init.name = kasprintf(GFP_KERNEL, "%s", node->name); + } else { + init.name = kasprintf(GFP_KERNEL, "%s.%s", node->name, clk_name); + } + + init.ops = &baikal_clk_ops; + init.flags = CLK_IGNORE_UNUSED; + init.parent_names = NULL; + init.num_parents = 0; + + cmu = kmalloc(sizeof(*cmu), GFP_KERNEL); + cmu->base = base + 0x10 * clk_index; + cmu->hw.init = &init; + + clk = clk_register(NULL, &cmu->hw); + if (!IS_ERR(clk)) { + clk_register_clkdev(clk, init.name, NULL); + if (multi) + clk_data->clks[clk_index] = clk; + } + } + + if (multi) + ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, clk_data); + else + ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk); + + return ret; +} + +static int baikal_clk_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); + return 0; +} + +#ifdef CONFIG_ACPI +const char *baikal_acpi_ref_clk_str[] = { "baikal_ref_clk" }; + +static struct clk *baikal_acpi_ref_clk; + +struct baikal_acpi_clk_data { + struct clk *cmu_clk; + struct clk_lookup *cmu_clk_l; + struct clk **clk; + struct clk_lookup **clk_l; + unsigned int clk_num; +}; + +static int baikal_acpi_clk_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct acpi_device *ref_dev, *adev = to_acpi_device_node(pdev->dev.fwnode); + struct clk_init_data init, *init_ch; + struct baikal_clk *cmu, *cmu_ch; + struct baikal_acpi_clk_data *clk_data = NULL; + union acpi_object *package, *element; + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + int size, i, index, ret = 0; + char *str, *str2; + const char *cmu_name; + + cmu = devm_kzalloc(dev, sizeof(*cmu), GFP_KERNEL); + if (!cmu) + return -ENOMEM; + + status = acpi_evaluate_object_typed(adev->handle, "PROP", NULL, &buffer, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + dev_err(dev, "failed to get PROP data\n"); + return -ENODEV; + } + + package = buffer.pointer; + if (package->package.count != 2) { + dev_err(dev, "invalid PROP data\n"); + ret = -EINVAL; + goto ret; + } + + element = &package->package.elements[0]; + if (element->type != ACPI_TYPE_INTEGER) { + dev_err(dev, "failed to get CMU id\n"); + ret = -EINVAL; + goto ret; + } + + cmu->base = element->integer.value; + + element = &package->package.elements[1]; + if (element->type != ACPI_TYPE_STRING) { + dev_err(dev, "failed to get CMU clock name\n"); + ret = -EINVAL; + goto ret; + } + + str = devm_kzalloc(dev, element->string.length + 1, GFP_KERNEL); + if (!str) { + ret = -ENOMEM; + goto ret; + } + + memcpy(str, element->string.pointer, element->string.length); + cmu_name = str; + + acpi_os_free(buffer.pointer); + buffer.length = ACPI_ALLOCATE_BUFFER; + buffer.pointer = NULL; + + init.parent_names = baikal_acpi_ref_clk_str; + init.num_parents = 1; + init.name = cmu_name; + init.ops = &baikal_clk_ops; + init.flags = CLK_IGNORE_UNUSED; + + cmu->hw.init = &init; + + clk_data = devm_kzalloc(dev, sizeof(*clk_data), GFP_KERNEL); + if (!clk_data) + return -ENOMEM; + + clk_data->cmu_clk = clk_register(NULL, &cmu->hw); + if (IS_ERR(clk_data->cmu_clk)) { + dev_err(dev, "failed to register CMU clock\n"); + return PTR_ERR(clk_data->cmu_clk); + } + + clk_data->cmu_clk_l = clkdev_create(clk_data->cmu_clk, cmu_name, NULL); + if (!clk_data->cmu_clk_l) { + dev_err(dev, "failed to register CMU clock lookup\n"); + clk_unregister(clk_data->cmu_clk); + return -ENOMEM; + } + + platform_set_drvdata(pdev, clk_data); + + status = acpi_evaluate_object_typed(adev->handle, "CLKS", NULL, &buffer, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + buffer.pointer = NULL; + goto ret; + } + + package = buffer.pointer; + if (!package->package.count || package->package.count % 4) { + dev_err(dev, "invalid CLKS data\n"); + ret = -EINVAL; + goto ret; + } + + clk_data->clk_num = package->package.count >> 2; + clk_data->clk = devm_kzalloc(dev, clk_data->clk_num * sizeof(struct clk *), GFP_KERNEL); + if (!clk_data->clk) { + ret = -ENOMEM; + goto ret; + } + + clk_data->clk_l = devm_kzalloc(dev, clk_data->clk_num * sizeof(struct clk_lookup *), GFP_KERNEL); + if (!clk_data->clk_l) { + ret = -ENOMEM; + goto ret; + } + + init_ch = devm_kzalloc(dev, clk_data->clk_num * sizeof(struct clk_init_data), GFP_KERNEL); + if (!init_ch) { + ret = -ENOMEM; + goto ret; + } + + cmu_ch = devm_kzalloc(dev, clk_data->clk_num * sizeof(struct baikal_clk), GFP_KERNEL); + if (!cmu_ch) { + ret = -ENOMEM; + goto ret; + } + + for (i = 0; i < clk_data->clk_num; ++i) { + ref_dev = NULL; + size = 0; + + element = &package->package.elements[4 * i]; + if (element->type == ACPI_TYPE_LOCAL_REFERENCE && element->reference.handle) + ref_dev = acpi_fetch_acpi_dev(element->reference.handle); + + element = &package->package.elements[4 * i + 1]; + if (element->type == ACPI_TYPE_STRING) { + if (ref_dev) + size = strlen(dev_name(&ref_dev->dev)) + 1; + + str = devm_kzalloc(dev, size + element->string.length + 1, GFP_KERNEL); + if (str) { + if (ref_dev) { + memcpy(str, dev_name(&ref_dev->dev), size - 1); + str[size - 1] = '_'; + memcpy(str + size, element->string.pointer, element->string.length); + } else { + memcpy(str, element->string.pointer, element->string.length); + } + } + } else { + dev_err(dev, "failed to process clock device name #%i\n", i); + continue; + } + + element = &package->package.elements[4 * i + 2]; + if (element->type == ACPI_TYPE_INTEGER) { + index = element->integer.value; + } else { + dev_err(dev, "failed to process clock device id #%i\n", i); + continue; + } + + element = &package->package.elements[4 * i + 3]; + if (element->type == ACPI_TYPE_STRING) { + str2 = devm_kzalloc(dev, element->string.length + 1, GFP_KERNEL); + if (str2) + memcpy(str2, element->string.pointer, element->string.length); + } else { + str2 = NULL; + } + + init_ch[i].parent_names = &cmu_name; + init_ch[i].num_parents = 1; + init_ch[i].name = str; + init_ch[i].ops = &baikal_clk_ops; + init_ch[i].flags = CLK_IGNORE_UNUSED; + + cmu_ch[i].base = cmu->base + 0x20 + 0x10 * index; + cmu_ch[i].hw.init = &init_ch[i]; + + clk_data->clk[i] = clk_register(ref_dev ? &ref_dev->dev : NULL, &cmu_ch[i].hw); + if (IS_ERR(clk_data->clk[i])) { + dev_err(dev, "failed to register CMU channel clock #%i\n", i); + clk_data->clk[i] = NULL; + continue; + } + + if (ref_dev) + clk_data->clk_l[i] = clkdev_create(clk_data->clk[i], str2, "%s", dev_name(&ref_dev->dev)); + else + clk_data->clk_l[i] = clkdev_create(clk_data->clk[i], str2, NULL); + + if (!clk_data->clk_l[i]) { + dev_err(dev, "failed to register CMU channel clock lookup #%i\n", i); + clk_unregister(clk_data->clk[i]); + clk_data->clk[i] = NULL; + continue; + } + } + + clk_data = NULL; + +ret: + if (buffer.pointer) + acpi_os_free(buffer.pointer); + + if (clk_data) { + clk_disable_unprepare(clk_data->cmu_clk); + clkdev_drop(clk_data->cmu_clk_l); + clk_unregister(clk_data->cmu_clk); + } + + return ret; +} + +static int baikal_acpi_clk_remove(struct platform_device *pdev) +{ + struct baikal_acpi_clk_data *clk_data = platform_get_drvdata(pdev); + int i; + + if (clk_data) { + clk_disable_unprepare(clk_data->cmu_clk); + clkdev_drop(clk_data->cmu_clk_l); + clk_unregister(clk_data->cmu_clk); + + for (i = 0; i < clk_data->clk_num; ++i) { + if (clk_data->clk_l[i]) + clkdev_drop(clk_data->clk_l[i]); + if (clk_data->clk[i]) + clk_unregister(clk_data->clk[i]); + } + } + + return 0; +} + +static const struct acpi_device_id baikal_acpi_clk_device_ids[] = { + { "BKLE0001" }, + { } +}; + +static struct platform_driver baikal_acpi_clk_driver = { + .probe = baikal_acpi_clk_probe, + .remove = baikal_acpi_clk_remove, + .driver = { + .name = "bs1000-cmu-acpi", + .acpi_match_table = ACPI_PTR(baikal_acpi_clk_device_ids) + } +}; + +static int __init baikal_acpi_clk_driver_init(void) +{ + if (!acpi_disabled) { + struct clk_lookup *baikal_acpi_ref_clk_lookup; + + baikal_acpi_ref_clk = clk_register_fixed_rate(NULL, baikal_acpi_ref_clk_str[0], NULL, 0, 25000000); + if (IS_ERR(baikal_acpi_ref_clk)) { + pr_err("%s: failed to register reference clock\n", __func__); + return PTR_ERR(baikal_acpi_ref_clk); + } + + baikal_acpi_ref_clk_lookup = clkdev_create(baikal_acpi_ref_clk, NULL, "%s", baikal_acpi_ref_clk_str[0]); + if (!baikal_acpi_ref_clk_lookup) { + clk_unregister_fixed_rate(baikal_acpi_ref_clk); + pr_err("%s: failed to register reference clock lookup\n", __func__); + return -ENOMEM; + } + + clk_prepare_enable(baikal_acpi_ref_clk); + + return platform_driver_register(&baikal_acpi_clk_driver); + } + + return 0; +} + +device_initcall(baikal_acpi_clk_driver_init); +#endif + +static const struct of_device_id baikal_clk_of_match[] = { + { .compatible = "baikal,bs1000-cmu" }, + { /* sentinel */ } +}; + +static struct platform_driver bs1000_cmu_driver = { + .probe = baikal_clk_probe, + .remove = baikal_clk_remove, + .driver = { + .name = "bs1000-cmu", + .of_match_table = baikal_clk_of_match + } +}; +module_platform_driver(bs1000_cmu_driver); + +MODULE_DESCRIPTION("Baikal BE-S1000 clock driver"); +MODULE_AUTHOR("Ekaterina Skachko "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:bs1000-cmu"); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4469e7f555e97..9420cb338095f 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -73,6 +73,13 @@ config DW_APB_TIMER_OF select DW_APB_TIMER select TIMER_OF +config BAIKAL_DW_APB_TIMER + bool "Baikal ACPI support for DW APB timer driver" + depends on ARCH_BAIKAL && ACPI + select DW_APB_TIMER + help + Enables the support for the dw_apb timer in ACPI. + config FTTMR010_TIMER bool "Faraday Technology timer driver" if COMPILE_TEST depends on HAS_IOMEM diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 64ab547de97b9..610a995efd41a 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_OMAP_DM_TIMER) += timer-ti-dm.o obj-$(CONFIG_OMAP_DM_SYSTIMER) += timer-ti-dm-systimer.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o +obj-$(CONFIG_BAIKAL_DW_APB_TIMER) += baikal_dw_apb_timer.o obj-$(CONFIG_FTTMR010_TIMER) += timer-fttmr010.o obj-$(CONFIG_IXP4XX_TIMER) += timer-ixp4xx.o obj-$(CONFIG_ROCKCHIP_TIMER) += timer-rockchip.o diff --git a/drivers/clocksource/baikal_dw_apb_timer.c b/drivers/clocksource/baikal_dw_apb_timer.c new file mode 100644 index 0000000000000..e66d2831ee21b --- /dev/null +++ b/drivers/clocksource/baikal_dw_apb_timer.c @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Baikal DW APB timer driver for ACPI + * + * Copyright (C) 2023 Baikal Electronics, JSC + * Author: Aleksandr Efimov + * + * Implementation based on dw_apb_timer_of.c + */ + +#include +#include +#include +#include +#include + +static int __init timer_get_base_and_rate(struct platform_device *pdev, + void __iomem **base, unsigned long *rate) +{ + struct device *dev = &pdev->dev; + struct clk *clk; + int ret; + + *base = devm_platform_ioremap_resource(pdev, 0); + if (!*base) { + dev_err(dev, "Unable to map regs\n"); + return PTR_ERR(*base); + } + + clk = devm_clk_get(dev, "timer"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ret = clk_prepare_enable(clk); + if (ret) + return ret; + + *rate = clk_get_rate(clk); + if (!*rate) { + clk_disable_unprepare(clk); + return -EINVAL; + } + + return 0; +} + +static int __init add_clockevent(struct platform_device *pdev) +{ + struct dw_apb_clock_event_device *ced; + void __iomem *iobase; + unsigned long rate; + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No IRQ for clock event timer\n"); + return -EINVAL; + } + + ret = timer_get_base_and_rate(pdev, &iobase, &rate); + if (ret) + return ret; + + ced = dw_apb_clockevent_init(-1, pdev->name, 300, iobase, irq, rate); + if (!ced) + return -EINVAL; + + dw_apb_clockevent_register(ced); + + return 0; +} + +static void __iomem *sched_io_base; +static unsigned long sched_rate; + +static int __init add_clocksource(struct platform_device *pdev) +{ + struct dw_apb_clocksource *cs; + void __iomem *iobase; + unsigned long rate; + int ret; + + ret = timer_get_base_and_rate(pdev, &iobase, &rate); + if (ret) + return ret; + + cs = dw_apb_clocksource_init(300, pdev->name, iobase, rate); + if (!cs) + return -EINVAL; + + dw_apb_clocksource_start(cs); + dw_apb_clocksource_register(cs); + + sched_io_base = iobase + 0x04; + sched_rate = rate; + + return 0; +} + +static u64 notrace read_sched_clock(void) +{ + return ~readl_relaxed(sched_io_base); +} + +static int num_called; + +static int __init baikal_dw_apb_timer_probe(struct platform_device *pdev) +{ + int ret; + + switch (num_called) { + case 1: + pr_debug("%s: found clocksource timer\n", __func__); + ret = add_clocksource(pdev); + if (ret) + return ret; + sched_clock_register(read_sched_clock, 32, sched_rate); + break; + default: + pr_debug("%s: found clockevent timer\n", __func__); + ret = add_clockevent(pdev); + if (ret) + return ret; + break; + } + + ++num_called; + + return 0; +} + +static const struct of_device_id baikal_dw_apb_timer_of_match[] = { + { .compatible = "baikal,bm1000-dw-apb-timer" }, + {} +}; + +static struct platform_driver baikal_dw_apb_timer = { + .driver = { + .name = "baikal-dw-apb-timer", + .of_match_table = baikal_dw_apb_timer_of_match, + .suppress_bind_attrs = true + }, + .probe = baikal_dw_apb_timer_probe +}; +builtin_platform_driver(baikal_dw_apb_timer); diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 82e5de1f6f8c9..1d37974f3af8c 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -357,3 +357,11 @@ config ARM_PXA2xx_CPUFREQ This add the CPUFreq driver support for Intel PXA2xx SOCs. If in doubt, say N. + +config BAIKAL_CPUFREQ + bool "Baikal-M cpufreq support for ACPI" + depends on ARCH_BAIKAL && ACPI + help + This adds the CPUFreq driver for Baikal-M. + + If in doubt, say N. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 49b98c62c5af5..fcc10b06921a3 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -91,6 +91,7 @@ obj-$(CONFIG_ARM_TEGRA186_CPUFREQ) += tegra186-cpufreq.o obj-$(CONFIG_ARM_TEGRA194_CPUFREQ) += tegra194-cpufreq.o obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o +obj-$(CONFIG_BAIKAL_CPUFREQ) += baikal-cpufreq.o ################################################################################## diff --git a/drivers/cpufreq/baikal-cpufreq.c b/drivers/cpufreq/baikal-cpufreq.c new file mode 100644 index 0000000000000..bc1c2b75724cc --- /dev/null +++ b/drivers/cpufreq/baikal-cpufreq.c @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Baikal-M cpufreq driver + * + * Copyright (C) 2023 Baikal Electronics, JSC + * Author: Aleksandr Efimov + * + * Implementation based on cpufreq-dt.c + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../opp/opp.h" + +struct private_data { + struct list_head node; + + cpumask_var_t cpus; + struct device *cpu_dev; + struct cpufreq_frequency_table *freq_table; +}; + +static LIST_HEAD(priv_list); + +static struct freq_attr *baikal_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static int baikal_cpufreq_target_index(struct cpufreq_policy *policy, + unsigned int index) +{ + struct private_data *priv = policy->driver_data; + unsigned long freq = policy->freq_table[index].frequency; + + return dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000); +} + +static struct private_data *baikal_cpufreq_find_data(int cpu) +{ + struct private_data *priv; + + list_for_each_entry(priv, &priv_list, node) { + if (cpumask_test_cpu(cpu, priv->cpus)) + return priv; + } + + return NULL; +} + +static int baikal_cpufreq_init(struct cpufreq_policy *policy) +{ + struct private_data *priv; + struct device *cpu_dev; + struct clk *cpu_clk; + unsigned int transition_latency; + int ret; + + priv = baikal_cpufreq_find_data(policy->cpu); + if (!priv) { + pr_err("failed to find data for cpu%d\n", policy->cpu); + return -ENODEV; + } + cpu_dev = priv->cpu_dev; + + cpu_clk = clk_get(cpu_dev, NULL); + if (IS_ERR(cpu_clk)) { + ret = PTR_ERR(cpu_clk); + dev_err(cpu_dev, "%s: failed to get clk: %d\n", __func__, ret); + return ret; + } + + transition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev); + if (!transition_latency) + transition_latency = CPUFREQ_ETERNAL; + + cpumask_copy(policy->cpus, priv->cpus); + policy->driver_data = priv; + policy->clk = cpu_clk; + policy->freq_table = priv->freq_table; + policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; + policy->cpuinfo.transition_latency = transition_latency; + policy->dvfs_possible_from_any_cpu = true; + + return 0; +} + +static int baikal_cpufreq_online(struct cpufreq_policy *policy) +{ + return 0; +} + +static int baikal_cpufreq_offline(struct cpufreq_policy *policy) +{ + return 0; +} + +static int baikal_cpufreq_exit(struct cpufreq_policy *policy) +{ + clk_put(policy->clk); + return 0; +} + +static struct cpufreq_driver baikal_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK | + CPUFREQ_IS_COOLING_DEV, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = baikal_cpufreq_target_index, + .get = cpufreq_generic_get, + .init = baikal_cpufreq_init, + .exit = baikal_cpufreq_exit, + .online = baikal_cpufreq_online, + .offline = baikal_cpufreq_offline, + .name = "baikal-cpufreq", + .attr = baikal_cpufreq_attr, + .suspend = cpufreq_generic_suspend, +}; + +static unsigned long baikal_cpufreq_opp_table_hz[] = { + 500000000, + 600000000, + 700000000, + 800000000, + 900000000, + 1000000000, + 1100000000, + 1200000000, + 1300000000, + 1400000000, + 1500000000 +}; + +static struct dev_pm_opp *baikal_cpufreq_opp_get(struct opp_table *opp_table, + int num) +{ + struct dev_pm_opp *opp = NULL, *temp; + + mutex_lock(&opp_table->lock); + list_for_each_entry(temp, &opp_table->opp_list, node) { + if (!temp->removed && temp->dynamic && + temp->rates[0] == baikal_cpufreq_opp_table_hz[num]) { + opp = temp; + break; + } + } + mutex_unlock(&opp_table->lock); + + return opp; +} + +static int baikal_cpufreq_add_opp(struct device *dev) +{ + struct opp_table *opp_table = NULL; + struct dev_pm_opp *opp; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(baikal_cpufreq_opp_table_hz); ++i) { + ret = dev_pm_opp_add(dev, baikal_cpufreq_opp_table_hz[i], 0); + if (ret) + return ret; + + if (!opp_table) { + opp_table = dev_pm_opp_get_opp_table(dev); + if (!IS_ERR_OR_NULL(opp_table)) + opp_table->clock_latency_ns_max = 10000000; + } + + opp = baikal_cpufreq_opp_get(opp_table, i); + if (opp) { + mutex_lock(&opp_table->lock); + opp->clock_latency_ns = 10000000; + mutex_unlock(&opp_table->lock); + } + } + + if (!IS_ERR_OR_NULL(opp_table)) + dev_pm_opp_put_opp_table(opp_table); + + return 0; +} + +static void baikal_dev_pm_opp_remove_all_dynamic(const struct cpumask *cpumask) +{ + struct device *cpu_dev; + int cpu; + + if (cpumask_empty(cpumask)) + return; + + for_each_cpu(cpu, cpumask) { + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) + continue; + + dev_pm_opp_remove_all_dynamic(cpu_dev); + } +} + +static int baikal_cpufreq_add_opp_table(const struct cpumask *cpumask) +{ + struct device *cpu_dev; + int cpu, ret; + + if (cpumask_empty(cpumask)) + return -ENODEV; + + for_each_cpu(cpu, cpumask) { + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_err("%s: failed to get cpu%d device\n", __func__, + cpu); + ret = -ENODEV; + goto remove_table; + } + + ret = baikal_cpufreq_add_opp(cpu_dev); + if (ret) + goto remove_table; + } + + return 0; + +remove_table: + baikal_dev_pm_opp_remove_all_dynamic(cpumask); + + return ret; +} + +static int baikal_cpufreq_early_init(struct device *dev, int cpu) +{ + struct private_data *priv; + struct device *cpu_dev, *tmp; + int ret, i; + + /* Check if this CPU is already covered by some other policy */ + if (baikal_cpufreq_find_data(cpu)) + return 0; + + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) + return -EPROBE_DEFER; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + if (!alloc_cpumask_var(&priv->cpus, GFP_KERNEL)) + return -ENOMEM; + + cpumask_set_cpu(cpu, priv->cpus); + priv->cpu_dev = cpu_dev; + + for_each_possible_cpu(i) { + if (i == cpu_dev->id) + continue; + + tmp = get_cpu_device(i); + if (!tmp) { + ret = -ENODEV; + goto free_cpumask; + } + + if (ACPI_COMPANION(cpu_dev)->dev.parent == + ACPI_COMPANION(tmp)->dev.parent) + cpumask_set_cpu(i, priv->cpus); + } + + ret = baikal_cpufreq_add_opp_table(priv->cpus); + if (ret) + goto free_cpumask; + + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &priv->freq_table); + if (ret) { + dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret); + goto out; + } + + list_add(&priv->node, &priv_list); + return 0; + +out: + dev_pm_opp_remove_all_dynamic(priv->cpu_dev); +free_cpumask: + free_cpumask_var(priv->cpus); + return ret; +} + +static void baikal_cpufreq_release(void) +{ + struct private_data *priv, *tmp; + + list_for_each_entry_safe(priv, tmp, &priv_list, node) { + dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &priv->freq_table); + baikal_dev_pm_opp_remove_all_dynamic(priv->cpus); + free_cpumask_var(priv->cpus); + list_del(&priv->node); + } +} + +static int baikal_cpufreq_probe(struct platform_device *pdev) +{ + int ret, cpu; + + for_each_possible_cpu(cpu) { + ret = baikal_cpufreq_early_init(&pdev->dev, cpu); + if (ret) { + dev_err(&pdev->dev, "failed to add cpufreq table: %d\n", ret); + goto err; + } + } + + ret = cpufreq_register_driver(&baikal_cpufreq_driver); + if (ret) { + dev_err(&pdev->dev, "failed register driver: %d\n", ret); + goto err; + } + + return 0; +err: + baikal_cpufreq_release(); + return ret; +} + +static int baikal_cpufreq_remove(struct platform_device *pdev) +{ + cpufreq_unregister_driver(&baikal_cpufreq_driver); + baikal_cpufreq_release(); + return 0; +} + +static struct platform_driver baikal_cpufreq_platform_driver = { + .driver = { + .name = "baikal-cpufreq", + .suppress_bind_attrs = true + }, + .probe = baikal_cpufreq_probe, + .remove = baikal_cpufreq_remove +}; +builtin_platform_driver(baikal_cpufreq_platform_driver); + +static int __init baikal_cpufreq_driver_init(void) +{ + if (!acpi_disabled) + return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "baikal-cpufreq", -1, + NULL, 0)); + + return 0; +} +core_initcall(baikal_cpufreq_driver_init); + +MODULE_ALIAS("platform:baikal-cpufreq"); +MODULE_AUTHOR("Aleksandr Efimov "); +MODULE_DESCRIPTION("Baikal-M cpufreq driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index 69a8742c0a7a3..de1917aca5ea1 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -32,6 +32,9 @@ static const struct of_device_id allowlist[] __initconst = { { .compatible = "arm,integrator-ap", }, { .compatible = "arm,integrator-cp", }, + { .compatible = "baikal,bm1000", }, + { .compatible = "baikal,bs1000", }, + { .compatible = "hisilicon,hi3660", }, { .compatible = "fsl,imx27", }, diff --git a/drivers/dma/dw/acpi.c b/drivers/dma/dw/acpi.c index c510c109d2c3a..fbe06669c7608 100644 --- a/drivers/dma/dw/acpi.c +++ b/drivers/dma/dw/acpi.c @@ -16,6 +16,18 @@ static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param) .m_master = 0, .p_master = 1, }; + struct fwnode_reference_args args = {}; + + if (!fwnode_property_get_reference_args(dma_spec->dev->fwnode, + "baikal,masters", NULL, 3, + dma_spec->slave_id, &args)) { + if (args.nargs > 1) { + slave.m_master = args.args[0]; + slave.p_master = args.args[1]; + } + if (args.nargs == 3) + slave.channels = args.args[2]; + } return dw_dma_filter(chan, &slave); } diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 97ba3bfc10b13..39bf45553a2ea 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1070,6 +1070,8 @@ int do_dma_probe(struct dw_dma_chip *chip) unsigned int dw_params; unsigned int i; int err; + int irq_num; + dw->pdata = devm_kzalloc(chip->dev, sizeof(*dw->pdata), GFP_KERNEL); if (!dw->pdata) @@ -1141,10 +1143,13 @@ int do_dma_probe(struct dw_dma_chip *chip) tasklet_setup(&dw->tasklet, dw_dma_tasklet); - err = request_irq(chip->irq, dw_dma_interrupt, IRQF_SHARED, - dw->name, dw); - if (err) - goto err_pdata; + irq_num = chip->irq_num; + while (irq_num--) { + err = request_irq(chip->irq[irq_num], dw_dma_interrupt, + IRQF_SHARED, dw->name, dw); + if (err) + goto err_pdata; + } INIT_LIST_HEAD(&dw->dma.channels); for (i = 0; i < pdata->nr_channels; i++) { @@ -1267,7 +1272,9 @@ int do_dma_probe(struct dw_dma_chip *chip) return 0; err_dma_register: - free_irq(chip->irq, dw); + irq_num = chip->irq_num; + while (irq_num--) + free_irq(chip->irq[irq_num], dw); err_pdata: pm_runtime_put_sync_suspend(chip->dev); return err; @@ -1277,13 +1284,17 @@ int do_dma_remove(struct dw_dma_chip *chip) { struct dw_dma *dw = chip->dw; struct dw_dma_chan *dwc, *_dwc; + int irq_num; pm_runtime_get_sync(chip->dev); do_dw_dma_off(dw); dma_async_device_unregister(&dw->dma); - free_irq(chip->irq, dw); + irq_num = chip->irq_num; + while (irq_num--) + free_irq(chip->irq[irq_num], dw); + tasklet_kill(&dw->tasklet); list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels, diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h index 563ce73488db3..b89baa0c06796 100644 --- a/drivers/dma/dw/internal.h +++ b/drivers/dma/dw/internal.h @@ -33,15 +33,12 @@ static inline void dw_dma_acpi_controller_free(struct dw_dma *dw) {} struct platform_device; +struct dw_dma_platform_data *dw_dma_parse_properties(struct platform_device *pdev); + #ifdef CONFIG_OF -struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev); void dw_dma_of_controller_register(struct dw_dma *dw); void dw_dma_of_controller_free(struct dw_dma *dw); #else -static inline struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) -{ - return NULL; -} static inline void dw_dma_of_controller_register(struct dw_dma *dw) {} static inline void dw_dma_of_controller_free(struct dw_dma *dw) {} #endif diff --git a/drivers/dma/dw/of.c b/drivers/dma/dw/of.c index 523ca806837cb..87561fa0acaac 100644 --- a/drivers/dma/dw/of.c +++ b/drivers/dma/dw/of.c @@ -46,58 +46,6 @@ static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec, return dma_request_channel(cap, dw_dma_filter, &slave); } -struct dw_dma_platform_data *dw_dma_parse_dt(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct dw_dma_platform_data *pdata; - u32 tmp, arr[DW_DMA_MAX_NR_MASTERS]; - u32 nr_masters; - u32 nr_channels; - - if (of_property_read_u32(np, "dma-masters", &nr_masters)) - return NULL; - if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) - return NULL; - - if (of_property_read_u32(np, "dma-channels", &nr_channels)) - return NULL; - if (nr_channels > DW_DMA_MAX_NR_CHANNELS) - return NULL; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - - pdata->nr_masters = nr_masters; - pdata->nr_channels = nr_channels; - - of_property_read_u32(np, "chan_allocation_order", &pdata->chan_allocation_order); - of_property_read_u32(np, "chan_priority", &pdata->chan_priority); - - of_property_read_u32(np, "block_size", &pdata->block_size); - - /* Try deprecated property first */ - if (!of_property_read_u32_array(np, "data_width", arr, nr_masters)) { - for (tmp = 0; tmp < nr_masters; tmp++) - pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); - } - - /* If "data_width" and "data-width" both provided use the latter one */ - of_property_read_u32_array(np, "data-width", pdata->data_width, nr_masters); - - memset32(pdata->multi_block, 1, nr_channels); - of_property_read_u32_array(np, "multi-block", pdata->multi_block, nr_channels); - - memset32(pdata->max_burst, DW_DMA_MAX_BURST, nr_channels); - of_property_read_u32_array(np, "snps,max-burst-len", pdata->max_burst, nr_channels); - - of_property_read_u32(np, "snps,dma-protection-control", &pdata->protctl); - if (pdata->protctl > CHAN_PROTCTL_MASK) - return NULL; - - return pdata; -} - void dw_dma_of_controller_register(struct dw_dma *dw) { struct device *dev = dw->dma.dev; diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 47f2292dba983..edd997e764eb0 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -23,12 +23,65 @@ #define DRV_NAME "dw_dmac" +struct dw_dma_platform_data *dw_dma_parse_properties(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct dw_dma_platform_data *pdata; + u32 tmp, arr[DW_DMA_MAX_NR_MASTERS]; + u32 nr_masters; + u32 nr_channels; + + if (device_property_read_u32(dev, "dma-masters", &nr_masters)) + return NULL; + if (nr_masters < 1 || nr_masters > DW_DMA_MAX_NR_MASTERS) + return NULL; + + if (device_property_read_u32(dev, "dma-channels", &nr_channels)) + return NULL; + if (nr_channels > DW_DMA_MAX_NR_CHANNELS) + return NULL; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->nr_masters = nr_masters; + pdata->nr_channels = nr_channels; + + device_property_read_u32(dev, "chan_allocation_order", &pdata->chan_allocation_order); + device_property_read_u32(dev, "chan_priority", &pdata->chan_priority); + + device_property_read_u32(dev, "block_size", &pdata->block_size); + + /* Try deprecated property first */ + if (!device_property_read_u32_array(dev, "data_width", arr, nr_masters)) { + for (tmp = 0; tmp < nr_masters; tmp++) + pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); + } + + /* If "data_width" and "data-width" both provided use the latter one */ + device_property_read_u32_array(dev, "data-width", pdata->data_width, nr_masters); + + memset32(pdata->multi_block, 1, nr_channels); + device_property_read_u32_array(dev, "multi-block", pdata->multi_block, nr_channels); + + memset32(pdata->max_burst, DW_DMA_MAX_BURST, nr_channels); + device_property_read_u32_array(dev, "snps,max-burst-len", pdata->max_burst, nr_channels); + + device_property_read_u32(dev, "snps,dma-protection-control", &pdata->protctl); + if (pdata->protctl > CHAN_PROTCTL_MASK) + return NULL; + + return pdata; +} + static int dw_probe(struct platform_device *pdev) { const struct dw_dma_chip_pdata *match; struct dw_dma_chip_pdata *data; struct dw_dma_chip *chip; struct device *dev = &pdev->dev; + int irq_num; int err; match = device_get_match_data(dev); @@ -43,9 +96,15 @@ static int dw_probe(struct platform_device *pdev) if (!chip) return -ENOMEM; - chip->irq = platform_get_irq(pdev, 0); - if (chip->irq < 0) - return chip->irq; + irq_num = platform_irq_count(pdev); + if (!irq_num) + dev_err(&pdev->dev, "no irq found on device\n"); + + chip->irq = devm_kzalloc(dev, irq_num * sizeof(int), GFP_KERNEL); + chip->irq_num = irq_num; + + while (irq_num--) + chip->irq[irq_num] = platform_get_irq(pdev, irq_num); chip->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->regs)) @@ -58,7 +117,7 @@ static int dw_probe(struct platform_device *pdev) if (!data->pdata) data->pdata = dev_get_platdata(dev); if (!data->pdata) - data->pdata = dw_dma_parse_dt(pdev); + data->pdata = dw_dma_parse_properties(pdev); chip->dev = dev; chip->id = pdev->id; @@ -148,6 +207,7 @@ static const struct acpi_device_id dw_dma_acpi_id_table[] = { { "INTL9C60", (kernel_ulong_t)&dw_dma_chip_pdata }, { "80862286", (kernel_ulong_t)&dw_dma_chip_pdata }, { "808622C0", (kernel_ulong_t)&dw_dma_chip_pdata }, + { "BKLE0005", (kernel_ulong_t)&dw_dma_chip_pdata }, /* Elkhart Lake iDMA 32-bit (PSE DMA) */ { "80864BB4", (kernel_ulong_t)&xbar_chip_pdata }, diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index f30f99166531f..8080fece78148 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -233,6 +233,7 @@ config DRM_SCHED source "drivers/gpu/drm/i2c/Kconfig" source "drivers/gpu/drm/arm/Kconfig" +source "drivers/gpu/drm/baikal/Kconfig" config DRM_RADEON tristate "ATI Radeon" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 0b283e46f28b8..db0456c3dd20f 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -148,3 +148,4 @@ obj-y += gud/ obj-$(CONFIG_DRM_HYPERV) += hyperv/ obj-y += solomon/ obj-$(CONFIG_DRM_SPRD) += sprd/ +obj-$(CONFIG_DRM_BAIKAL_VDU) += baikal/ diff --git a/drivers/gpu/drm/baikal/Kconfig b/drivers/gpu/drm/baikal/Kconfig new file mode 100644 index 0000000000000..4a18055cd22fa --- /dev/null +++ b/drivers/gpu/drm/baikal/Kconfig @@ -0,0 +1,12 @@ +config DRM_BAIKAL_VDU + tristate "DRM Support for Baikal-M VDU" + depends on DRM + depends on ARM || ARM64 || COMPILE_TEST + depends on COMMON_CLK + select DRM_KMS_HELPER + select DRM_GEM_DMA_HELPER + select DRM_PANEL + select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE + help + Choose this option for DRM support for the Baikal-M Video Display Unit (VDU). + If M is selected the module will be called baikal_vdu_drm. diff --git a/drivers/gpu/drm/baikal/Makefile b/drivers/gpu/drm/baikal/Makefile new file mode 100644 index 0000000000000..321d3be96b814 --- /dev/null +++ b/drivers/gpu/drm/baikal/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +baikal_vdu_drm-y += baikal_vdu_backlight.o \ + baikal_vdu_crtc.o \ + baikal_vdu_drv.o \ + baikal_vdu_panel.o \ + baikal_vdu_plane.o + +baikal_vdu_drm-$(CONFIG_DEBUG_FS) += baikal_vdu_debugfs.o + +obj-$(CONFIG_DRM_BAIKAL_VDU) += baikal_vdu_drm.o +obj-$(CONFIG_DRM_BAIKAL_HDMI) += baikal-hdmi.o diff --git a/drivers/gpu/drm/baikal/baikal-hdmi.c b/drivers/gpu/drm/baikal/baikal-hdmi.c new file mode 100644 index 0000000000000..7d3d0f0c7358e --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal-hdmi.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Baikal Electronics BE-M1000 DesignWare HDMI 2.0 Tx PHY support driver + * + * Copyright (C) 2019-2022 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +#include +#include +#include + +#include + +#include "baikal_vdu_drm.h" + +int fixed_clock = 0; +int max_clock = 0; + +static const struct dw_hdmi_mpll_config baikal_hdmi_mpll_cfg[] = { + /* pixelclk opmode gmp */ + { 44900000, { { 0x00b3, 0x0000 }, }, }, + { 90000000, { { 0x0072, 0x0001 }, }, }, + { 182750000, { { 0x0051, 0x0002 }, }, }, + { 340000000, { { 0x0040, 0x0003 }, }, }, + { 594000000, { { 0x1a40, 0x0003 }, }, }, + { ~0UL, { { 0x0000, 0x0000 }, }, } +}; + +static const struct dw_hdmi_curr_ctrl baikal_hdmi_cur_ctr[] = { + /* pixelclk current */ + { 44900000, { 0x0000, }, }, + { 90000000, { 0x0008, }, }, + { 182750000, { 0x001b, }, }, + { 340000000, { 0x0036, }, }, + { 594000000, { 0x003f, }, }, + { ~0UL, { 0x0000, }, } +}; + +static const struct dw_hdmi_phy_config baikal_hdmi_phy_cfg[] = { + /* pixelclk symbol term vlev */ + { 148250000, 0x8009, 0x0004, 0x0232}, + { 218250000, 0x8009, 0x0004, 0x0230}, + { 288000000, 0x8009, 0x0004, 0x0273}, + { 340000000, 0x8029, 0x0004, 0x0273}, + { 594000000, 0x8039, 0x0004, 0x014a}, + { ~0UL, 0x0000, 0x0000, 0x0000} +}; + +static enum drm_mode_status +baikal_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, + const struct drm_display_info *info, + const struct drm_display_mode *mode) +{ + if (mode->clock < 13500) + return MODE_CLOCK_LOW; + if (mode->clock >= 340000) + return MODE_CLOCK_HIGH; + if (fixed_clock && mode->clock != fixed_clock) + return MODE_BAD; + if (max_clock && mode->clock > max_clock) + return MODE_BAD; + + return MODE_OK; +} + +static struct dw_hdmi_plat_data baikal_dw_hdmi_plat_data = { + .mpll_cfg = baikal_hdmi_mpll_cfg, + .cur_ctr = baikal_hdmi_cur_ctr, + .phy_config = baikal_hdmi_phy_cfg, + .mode_valid = baikal_hdmi_mode_valid, +}; + +static int baikal_dw_hdmi_probe(struct platform_device *pdev) +{ + struct baikal_hdmi_bridge *priv; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + platform_set_drvdata(pdev, priv); + + priv->hdmi = dw_hdmi_probe(pdev, &baikal_dw_hdmi_plat_data); + if (IS_ERR(priv->hdmi)) + return PTR_ERR(priv->hdmi); + + priv->bridge = dw_hdmi_get_bridge(priv->hdmi); + return 0; +} + +static int baikal_dw_hdmi_remove(struct platform_device *pdev) +{ + struct baikal_hdmi_bridge *priv = platform_get_drvdata(pdev); + + dw_hdmi_remove(priv->hdmi); + return 0; +} + +static const struct of_device_id baikal_dw_hdmi_of_table[] = { + { .compatible = "baikal,hdmi" }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, baikal_dw_hdmi_of_table); + +static struct platform_driver baikal_dw_hdmi_platform_driver = { + .probe = baikal_dw_hdmi_probe, + .remove = baikal_dw_hdmi_remove, + .driver = { + .name = "baikal-dw-hdmi", + .of_match_table = baikal_dw_hdmi_of_table, + }, +}; + +module_param(fixed_clock, int, 0644); +module_param(max_clock, int, 0644); + +module_platform_driver(baikal_dw_hdmi_platform_driver); + +MODULE_AUTHOR("Pavel Parkhomenko "); +MODULE_DESCRIPTION("Baikal BE-M1000 SoC DesignWare HDMI 2.0 Tx + Gen2 PHY Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/baikal/baikal_vdu_backlight.c b/drivers/gpu/drm/baikal/baikal_vdu_backlight.c new file mode 100644 index 0000000000000..c906de69683e0 --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal_vdu_backlight.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2023 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +/** + * baikal_vdu_backlight.c + * Implementation of backlight functions for + * Baikal Electronics BE-M1000 SoC's VDU + */ + +#include +#include +#include + +#include + +#include "baikal_vdu_drm.h" +#include "baikal_vdu_regs.h" + +#define BAIKAL_VDU_MIN_BRIGHTNESS 0 +#define BAIKAL_VDU_DEFAULT_BRIGHTNESS 50 +#define BAIKAL_VDU_BRIGHTNESS_STEP 5 +#define BAIKAL_VDU_DEFAULT_PWM_FREQ 10000 + +static int baikal_vdu_backlight_update_status(struct backlight_device *bl_dev) +{ + struct baikal_vdu_private *priv = bl_get_data(bl_dev); + int brightness_on = 1; + int brightness = bl_dev->props.brightness; + u8 pwmdc; + + if (bl_dev->props.power != FB_BLANK_UNBLANK || + bl_dev->props.fb_blank != FB_BLANK_UNBLANK || + bl_dev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) { + brightness_on = 0; + brightness = priv->min_brightness; + } + + if (priv->enable_gpio) + gpiod_set_value_cansleep(priv->enable_gpio, brightness_on); + + pwmdc = brightness ? ((brightness << 6) / 25 - 1) : 0; + + writel(pwmdc, priv->regs + PWMDCR); + + return 0; +} + +static const struct backlight_ops baikal_vdu_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = baikal_vdu_backlight_update_status, +}; + +static void baikal_vdu_input_event(struct input_handle *handle, + unsigned int type, unsigned int code, + int value) +{ + struct baikal_vdu_private *priv = handle->private; + int brightness; + + if (type != EV_KEY || value == 0) + return; + + switch (code) { + case KEY_BRIGHTNESSDOWN: + brightness = priv->bl_dev->props.brightness - + priv->brightness_step; + if (brightness >= priv->min_brightness) + backlight_device_set_brightness(priv->bl_dev, + brightness); + break; + + case KEY_BRIGHTNESSUP: + brightness = priv->bl_dev->props.brightness + + priv->brightness_step; + backlight_device_set_brightness(priv->bl_dev, brightness); + break; + + case KEY_BRIGHTNESS_TOGGLE: + priv->brightness_on = !priv->brightness_on; + if (priv->brightness_on) + backlight_enable(priv->bl_dev); + else + backlight_disable(priv->bl_dev); + break; + + default: + return; + } + + backlight_force_update(priv->bl_dev, BACKLIGHT_UPDATE_HOTKEY); +} + +static int baikal_vdu_input_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int ret; + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->private = handler->private; + handle->name = KBUILD_MODNAME; + handle->dev = dev; + handle->handler = handler; + + ret = input_register_handle(handle); + if (ret) + goto err_free_handle; + + ret = input_open_device(handle); + if (ret) + goto err_unregister_handle; + + return 0; + +err_unregister_handle: + input_unregister_handle(handle); +err_free_handle: + kfree(handle); + return ret; +} + +static void baikal_vdu_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id baikal_vdu_input_ids[] = { + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, baikal_vdu_input_ids); + +int baikal_vdu_backlight_create(struct drm_device *drm) +{ + struct baikal_vdu_crossbar *crossbar = drm_to_baikal_vdu_crossbar(drm); + struct baikal_vdu_private *priv = &crossbar->lvds; + struct device *dev = drm->dev; + struct backlight_properties props; + struct input_handler *handler; + struct fwnode_handle *node; + u32 min_brightness = BAIKAL_VDU_MIN_BRIGHTNESS; + u32 dfl_brightness = BAIKAL_VDU_DEFAULT_BRIGHTNESS; + u32 brightness_step = BAIKAL_VDU_BRIGHTNESS_STEP; + u32 pwm_frequency = 0; + int ret = 0; + unsigned long rate; + unsigned int pwmfr = 0; + + priv->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_ASIS); + if (IS_ERR(priv->enable_gpio)) { + dev_warn(dev, "failed to get ENABLE GPIO\n"); + priv->enable_gpio = NULL; + } + + if (priv->enable_gpio && gpiod_get_direction(priv->enable_gpio) != 0) + gpiod_direction_output(priv->enable_gpio, 1); + + node = fwnode_get_named_child_node(dev->fwnode, is_of_node(dev->fwnode) ? + "backlight" : "BCKL"); + if (!node) + return 0; + + fwnode_property_read_u32(node, "min-brightness-level", &min_brightness); + fwnode_property_read_u32(node, "default-brightness-level", &dfl_brightness); + fwnode_property_read_u32(node, "brightness-level-step", &brightness_step); + fwnode_property_read_u32(node, "pwm-frequency", &pwm_frequency); + + if (pwm_frequency == 0) { + dev_warn(dev, "using default PWM frequency %u\n", + BAIKAL_VDU_DEFAULT_PWM_FREQ); + pwm_frequency = BAIKAL_VDU_DEFAULT_PWM_FREQ; + } + + memset(&props, 0, sizeof(props)); + props.max_brightness = 100; + props.type = BACKLIGHT_RAW; + props.scale = BACKLIGHT_SCALE_LINEAR; + + if (min_brightness > props.max_brightness) { + dev_warn(dev, "invalid min brightness level: %u, using %u\n", + min_brightness, props.max_brightness); + min_brightness = props.max_brightness; + } + + if (dfl_brightness > props.max_brightness || + dfl_brightness < min_brightness) { + dev_warn(dev, + "invalid default brightness level: %u, using %u\n", + dfl_brightness, props.max_brightness); + dfl_brightness = props.max_brightness; + } + + priv->min_brightness = min_brightness; + priv->brightness_step = brightness_step; + priv->brightness_on = true; + + props.brightness = dfl_brightness; + props.power = FB_BLANK_UNBLANK; + + priv->bl_dev = + devm_backlight_device_register(dev, dev_name(dev), dev, priv, + &baikal_vdu_backlight_ops, + &props); + if (IS_ERR(priv->bl_dev)) { + dev_err(dev, "failed to register backlight device\n"); + ret = PTR_ERR(priv->bl_dev); + priv->bl_dev = NULL; + goto out; + } + + handler = devm_kzalloc(dev, sizeof(*handler), GFP_KERNEL); + if (!handler) { + dev_err(dev, "failed to allocate input handler\n"); + ret = -ENOMEM; + goto out; + } + + handler->private = priv; + handler->event = baikal_vdu_input_event; + handler->connect = baikal_vdu_input_connect; + handler->disconnect = baikal_vdu_input_disconnect; + handler->name = KBUILD_MODNAME; + handler->id_table = baikal_vdu_input_ids; + + ret = input_register_handler(handler); + if (ret) { + dev_err(dev, "failed to register input handler\n"); + goto out; + } + + /* Hold PWM Clock Domain Reset, disable clocking */ + writel(0, priv->regs + PWMFR); + + rate = clk_get_rate(priv->clk); + pwmfr |= PWMFR_PWMFCD(rate / pwm_frequency - 1) | PWMFR_PWMFCI; + writel(pwmfr, priv->regs + PWMFR); + + /* Release PWM Clock Domain Reset, enable clocking */ + writel(pwmfr | PWMFR_PWMPCR | PWMFR_PWMFCE, priv->regs + PWMFR); + + backlight_update_status(priv->bl_dev); +out: + fwnode_handle_put(node); + return ret; +} diff --git a/drivers/gpu/drm/baikal/baikal_vdu_crtc.c b/drivers/gpu/drm/baikal/baikal_vdu_crtc.c new file mode 100644 index 0000000000000..ab369db2df8b6 --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal_vdu_crtc.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2023 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +/** + * baikal_vdu_crtc.c + * Implementation of the CRTC functions for Baikal Electronics BE-M1000 VDU driver + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "baikal_vdu_drm.h" +#include "baikal_vdu_regs.h" + +irqreturn_t baikal_vdu_irq(int irq, void *data) +{ + struct baikal_vdu_private *priv = data; + irqreturn_t status = IRQ_NONE; + u32 raw_stat; + u32 irq_stat; + + priv->counters[0]++; + irq_stat = readl(priv->regs + IVR); + raw_stat = readl(priv->regs + ISR); + + if (raw_stat & INTR_UFU) { + priv->counters[4]++; + status = IRQ_HANDLED; + } + + if (raw_stat & INTR_IFO) { + priv->counters[5]++; + status = IRQ_HANDLED; + } + + if (raw_stat & INTR_OFU) { + priv->counters[6]++; + status = IRQ_HANDLED; + } + + if (irq_stat & INTR_FER) { + priv->counters[11]++; + priv->counters[12] = readl(priv->regs + DBAR); + priv->counters[13] = readl(priv->regs + DCAR); + priv->counters[14] = readl(priv->regs + MRR); + status = IRQ_HANDLED; + } + + priv->counters[3] |= raw_stat; + + /* Clear all interrupts */ + writel(raw_stat, priv->regs + ISR); + + return status; +} + +static void baikal_vdu_crtc_helper_mode_set_nofb(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct baikal_vdu_private *priv = crtc_to_baikal_vdu(crtc); + const struct drm_display_mode *mode = &crtc->state->mode; + unsigned long rate; + unsigned int ppl, hsw, hfp, hbp; + unsigned int lpp, vsw, vfp, vbp; + unsigned int reg; + int ret = 0; + + drm_mode_debug_printmodeline(mode); + + rate = mode->clock * 1000; + + if (rate != clk_get_rate(priv->clk)) { + DRM_DEV_DEBUG_DRIVER(dev->dev, "Requested pixel clock is %lu Hz\n", rate); + + /* hold clock domain reset; disable clocking */ + writel(0, priv->regs + PCTR); + + if (__clk_is_enabled(priv->clk)) + clk_disable_unprepare(priv->clk); + ret = clk_set_rate(priv->clk, rate); + + if (ret >= 0) { + clk_prepare_enable(priv->clk); + if (!__clk_is_enabled(priv->clk)) + ret = -1; + } + + /* release clock domain reset; enable clocking */ + reg = readl(priv->regs + PCTR); + reg |= PCTR_PCR + PCTR_PCI; + writel(reg, priv->regs + PCTR); + } + + if (ret < 0) + DRM_ERROR("Cannot set desired pixel clock (%lu Hz)\n", rate); + + ppl = mode->hdisplay / 16; + if (priv->index == CRTC_LVDS && priv-> num_lanes == 2) { + hsw = mode->hsync_end - mode->hsync_start; + hfp = mode->hsync_start - mode->hdisplay - 1; + } else { + hsw = mode->hsync_end - mode->hsync_start - 1; + hfp = mode->hsync_start - mode->hdisplay; + } + hbp = mode->htotal - mode->hsync_end; + + lpp = mode->vdisplay; + vsw = mode->vsync_end - mode->vsync_start; + vfp = mode->vsync_start - mode->vdisplay; + vbp = mode->vtotal - mode->vsync_end; + + writel((HTR_HFP(hfp) & HTR_HFP_MASK) | + (HTR_PPL(ppl) & HTR_PPL_MASK) | + (HTR_HBP(hbp) & HTR_HBP_MASK) | + (HTR_HSW(hsw) & HTR_HSW_MASK), + priv->regs + HTR); + + if (mode->hdisplay > 4080 || ppl * 16 != mode->hdisplay) + writel((HPPLOR_HPPLO(mode->hdisplay) & HPPLOR_HPPLO_MASK) | HPPLOR_HPOE, + priv->regs + HPPLOR); + + writel((VTR1_VSW(vsw) & VTR1_VSW_MASK) | + (VTR1_VFP(vfp) & VTR1_VFP_MASK) | + (VTR1_VBP(vbp) & VTR1_VBP_MASK), + priv->regs + VTR1); + + writel(lpp & VTR2_LPP_MASK, priv->regs + VTR2); + + writel((HVTER_VSWE(vsw >> VTR1_VSW_LSB_WIDTH) & HVTER_VSWE_MASK) | + (HVTER_HSWE(hsw >> HTR_HSW_LSB_WIDTH) & HVTER_HSWE_MASK) | + (HVTER_VBPE(vbp >> VTR1_VBP_LSB_WIDTH) & HVTER_VBPE_MASK) | + (HVTER_VFPE(vfp >> VTR1_VFP_LSB_WIDTH) & HVTER_VFPE_MASK) | + (HVTER_HBPE(hbp >> HTR_HBP_LSB_WIDTH) & HVTER_HBPE_MASK) | + (HVTER_HFPE(hfp >> HTR_HFP_LSB_WIDTH) & HVTER_HFPE_MASK), + priv->regs + HVTER); + + /* Set polarities */ + reg = readl(priv->regs + CR1); + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + reg |= CR1_HSP; + else + reg &= ~CR1_HSP; + reg &= ~CR1_VSP; // always set VSP to active high + reg |= CR1_DEP; // set DE to active high; + writel(reg, priv->regs + CR1); +} + +static enum drm_mode_status baikal_vdu_mode_valid(struct drm_crtc *crtc, + const struct drm_display_mode *mode) +{ + struct baikal_vdu_private *priv = crtc_to_baikal_vdu(crtc); + if (!priv->mode_override && (mode->hdisplay > 2560 || + mode->vdisplay > 1440)) + return MODE_BAD; + else + return MODE_OK; +} + +static void baikal_vdu_crtc_helper_enable(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct baikal_vdu_private *priv = crtc_to_baikal_vdu(crtc); + const char *data_mapping = NULL; + u32 cntl, gpio; + + DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, "enabling pixel clock\n"); + clk_prepare_enable(priv->clk); + + /* Set 16-word input FIFO watermark */ + /* Enable and Power Up */ + cntl = readl(priv->regs + CR1); + cntl &= ~(CR1_FDW_MASK | CR1_OPS_MASK); + cntl |= CR1_LCE | CR1_FDW_16_WORDS; + + if (priv->index == CRTC_LVDS) { + if (priv->bridge->of_node) { + of_property_read_string(priv->bridge->of_node, + "data-mapping", &data_mapping); + } else { + struct fwnode_handle *fwnode; + + fwnode = fwnode_find_reference(priv->bridge->dev->dev->fwnode, + "baikal,lvds-panel", 0); + if (!IS_ERR_OR_NULL(fwnode)) + fwnode_property_read_string(fwnode, "data-mapping", + &data_mapping); + } + + if (!data_mapping) { + cntl |= CR1_OPS_LCD18; + } else if (!strncmp(data_mapping, "vesa-24", 7)) + cntl |= CR1_OPS_LCD24; + else if (!strncmp(data_mapping, "jeida-18", 8)) + cntl |= CR1_OPS_LCD18; + else { + dev_warn(crtc->dev->dev, "%s data mapping is not supported, vesa-24 is set\n", data_mapping); + cntl |= CR1_OPS_LCD24; + } + gpio = GPIOR_UHD_ENB; + if (priv->num_lanes == 4) + gpio |= GPIOR_UHD_QUAD_PORT; + else if (priv->num_lanes == 2) + gpio |= GPIOR_UHD_DUAL_PORT; + else + gpio |= GPIOR_UHD_SNGL_PORT; + writel(gpio, priv->regs + GPIOR); + } else + cntl |= CR1_OPS_LCD24; + writel(cntl, priv->regs + CR1); + + writel(0x3ffff, priv->regs + ISR); + writel(INTR_FER, priv->regs + IMR); +} + +void baikal_vdu_crtc_helper_disable(struct drm_crtc *crtc) +{ + struct baikal_vdu_private *priv = crtc_to_baikal_vdu(crtc); + + writel(0x3ffff, priv->regs + ISR); + writel(0, priv->regs + IMR); + + /* Disable clock */ + DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, "disabling pixel clock\n"); + clk_disable_unprepare(priv->clk); +} + +static void baikal_vdu_crtc_helper_atomic_flush(struct drm_crtc *crtc, + struct drm_atomic_state *old_state) +{ + struct drm_pending_vblank_event *event = crtc->state->event; + + if (event) { + crtc->state->event = NULL; + + spin_lock_irq(&crtc->dev->event_lock); + if (crtc->state->active && drm_crtc_vblank_get(crtc) == 0) + drm_crtc_arm_vblank_event(crtc, event); + else + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } +} + +const struct drm_crtc_funcs crtc_funcs = { + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, + .reset = drm_atomic_helper_crtc_reset, + .destroy = drm_crtc_cleanup, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, +}; + +const struct drm_crtc_helper_funcs crtc_helper_funcs = { + .mode_set_nofb = baikal_vdu_crtc_helper_mode_set_nofb, + .mode_valid = baikal_vdu_mode_valid, + .atomic_flush = baikal_vdu_crtc_helper_atomic_flush, + .disable = baikal_vdu_crtc_helper_disable, + .atomic_enable = baikal_vdu_crtc_helper_enable, +}; + +int baikal_vdu_crtc_create(struct baikal_vdu_private *priv) +{ + struct drm_device *dev = priv->drm; + struct drm_crtc *crtc = &priv->crtc; + + drm_crtc_init_with_planes(dev, crtc, + &priv->primary, NULL, + &crtc_funcs, "primary"); + drm_crtc_helper_add(crtc, &crtc_helper_funcs); + + DRM_DEV_DEBUG_DRIVER(crtc->dev->dev, "enabling pixel clock\n"); + clk_prepare_enable(priv->clk); + + return 0; +} diff --git a/drivers/gpu/drm/baikal/baikal_vdu_debugfs.c b/drivers/gpu/drm/baikal/baikal_vdu_debugfs.c new file mode 100644 index 0000000000000..1fda8c2173117 --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal_vdu_debugfs.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2023 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +#include +#include +#include +#include +#include + +#include "baikal_vdu_drm.h" +#include "baikal_vdu_regs.h" + +#define REGDEF(reg) { reg, #reg } +static const struct { + u32 reg; + const char *name; +} baikal_vdu_reg_defs[] = { + REGDEF(CR1), + REGDEF(HTR), + REGDEF(VTR1), + REGDEF(VTR2), + REGDEF(PCTR), + REGDEF(ISR), + REGDEF(IMR), + REGDEF(IVR), + REGDEF(ISCR), + REGDEF(DBAR), + REGDEF(DCAR), + REGDEF(DEAR), + REGDEF(PWMFR), + REGDEF(PWMDCR), + REGDEF(HVTER), + REGDEF(HPPLOR), + REGDEF(GPIOR), + REGDEF(MRR), +}; + +#define REGS_HDMI "regs_hdmi" +#define REGS_LVDS "regs_lvds" + +int baikal_vdu_debugfs_regs(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = (struct drm_info_node *)m->private; + struct drm_device *dev = node->minor->dev; + struct baikal_vdu_crossbar *crossbar = drm_to_baikal_vdu_crossbar(dev); + char *filename = m->file->f_path.dentry->d_iname; + struct baikal_vdu_private *priv = NULL; + int i; + + if (!strcmp(REGS_HDMI, filename)) + priv = &crossbar->hdmi; + if (!strcmp(REGS_LVDS, filename)) + priv = &crossbar->lvds; + + if (!priv || !priv->regs) + return 0; + + for (i = 0; i < ARRAY_SIZE(baikal_vdu_reg_defs); i++) { + seq_printf(m, "%s (0x%04x): 0x%08x\n", + baikal_vdu_reg_defs[i].name, baikal_vdu_reg_defs[i].reg, + readl(priv->regs + baikal_vdu_reg_defs[i].reg)); + } + for (i = 0; i < ARRAY_SIZE(priv->counters); i++) { + seq_printf(m, "COUNTER[%d]: 0x%08x\n", i, priv->counters[i]); + } + + return 0; +} + +static const struct drm_info_list baikal_vdu_hdmi_debugfs_list[] = { + {REGS_HDMI, baikal_vdu_debugfs_regs, 0}, +}; + +static const struct drm_info_list baikal_vdu_lvds_debugfs_list[] = { + {REGS_LVDS, baikal_vdu_debugfs_regs, 0}, +}; + +void baikal_vdu_hdmi_debugfs_init(struct drm_minor *minor) +{ + drm_debugfs_create_files(baikal_vdu_hdmi_debugfs_list, + ARRAY_SIZE(baikal_vdu_hdmi_debugfs_list), + minor->debugfs_root, minor); +} + +void baikal_vdu_lvds_debugfs_init(struct drm_minor *minor) +{ + drm_debugfs_create_files(baikal_vdu_lvds_debugfs_list, + ARRAY_SIZE(baikal_vdu_lvds_debugfs_list), + minor->debugfs_root, minor); +} diff --git a/drivers/gpu/drm/baikal/baikal_vdu_drm.h b/drivers/gpu/drm/baikal/baikal_vdu_drm.h new file mode 100644 index 0000000000000..04d7ba650a555 --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal_vdu_drm.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019-2023 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +#ifndef __BAIKAL_VDU_DRM_H__ +#define __BAIKAL_VDU_DRM_H__ + +#include +#include +#include + +#include + +#include +#include +#include + +#define CRTC_HDMI 0 +#define CRTC_LVDS 1 + +#define crtc_to_baikal_vdu(x) \ + container_of(x, struct baikal_vdu_private, crtc) +#define bridge_to_baikal_lvds_bridge(x) \ + container_of(x, struct baikal_lvds_bridge, bridge) +#define connector_to_baikal_lvds_bridge(x) \ + container_of(x, struct baikal_lvds_bridge, connector) +#define drm_to_baikal_vdu_crossbar(x) \ + container_of(x, struct baikal_vdu_crossbar, drm) + +#define VDU_NAME_LEN 5 + +struct baikal_vdu_private { + struct drm_device *drm; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_bridge *bridge; + struct drm_plane primary; + void *regs; + int irq; + struct clk *clk; + spinlock_t lock; + u32 counters[20]; + int mode_override; + int index; + char name[VDU_NAME_LEN]; + char irq_name[VDU_NAME_LEN + 4]; + char pclk_name[VDU_NAME_LEN + 5]; + char regs_name[VDU_NAME_LEN + 5]; + int num_lanes; + int data_mapping; + int off; + int ready; + + /* backlight */ + struct gpio_desc *enable_gpio; + struct backlight_device *bl_dev; + int min_brightness; + int brightness_step; + bool brightness_on; +}; + +struct baikal_vdu_crossbar { + struct drm_device drm; + struct baikal_vdu_private hdmi; + struct baikal_vdu_private lvds; +}; + +struct baikal_lvds_bridge { + struct baikal_vdu_private *vdu; + struct drm_bridge bridge; + struct drm_connector connector; + struct drm_panel *panel; + u32 connector_type; +}; + +struct baikal_hdmi_bridge { + struct dw_hdmi *hdmi; + struct drm_bridge *bridge; +}; + +/* Generic functions */ +inline void baikal_vdu_switch_on(struct baikal_vdu_private *priv); + +inline void baikal_vdu_switch_off(struct baikal_vdu_private *priv); + +/* Bridge functions */ +bool bridge_is_baikal_lvds_bridge(const struct drm_bridge *bridge); + +struct drm_bridge *devm_baikal_lvds_bridge_add(struct device *dev, + struct drm_panel *panel, + u32 connector_type); + +/* CRTC Functions */ +int baikal_vdu_crtc_create(struct baikal_vdu_private *priv); + +irqreturn_t baikal_vdu_irq(int irq, void *data); + +int baikal_vdu_primary_plane_init(struct baikal_vdu_private *priv); + +/* Backlight Functions */ +int baikal_vdu_backlight_create(struct drm_device *drm); + +/* Debugfs functions */ +void baikal_vdu_hdmi_debugfs_init(struct drm_minor *minor); + +void baikal_vdu_lvds_debugfs_init(struct drm_minor *minor); + +#endif /* __BAIKAL_VDU_DRM_H__ */ diff --git a/drivers/gpu/drm/baikal/baikal_vdu_drv.c b/drivers/gpu/drm/baikal/baikal_vdu_drv.c new file mode 100644 index 0000000000000..b1e41dea4f98e --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal_vdu_drv.c @@ -0,0 +1,500 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2023 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * Bugfixes by Alexey Sheplyakov + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "baikal_vdu_drm.h" +#include "baikal_vdu_regs.h" + +#define DRIVER_NAME "baikal-vdu" +#define DRIVER_DESC "Baikal VDU DRM driver" +#define DRIVER_DATE "20230221" + +#define BAIKAL_SMC_LOG_DISABLE 0x82000200 +#define IFIFO_SIZE 16384 +#define UHD_FIFO_SIZE 16384 + +int mode_override = 0; +int hdmi_off = 0; +int lvds_off = 0; + +static struct drm_mode_config_funcs mode_config_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +const struct drm_encoder_funcs baikal_vdu_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static struct drm_bridge *devm_baikal_get_bridge(struct device *dev, + u32 port, u32 endpoint) +{ + struct baikal_hdmi_bridge *priv_hdmi; + struct device *tmp; + struct drm_bridge *bridge; + struct drm_panel *panel; + struct fwnode_handle *fwnode; + int ret = 0; + + if (is_of_node(dev->fwnode)) { + ret = drm_of_find_panel_or_bridge(to_of_node(dev->fwnode), port, + endpoint, &panel, &bridge); + } else { + if (port == CRTC_HDMI) { + fwnode = fwnode_find_reference(dev->fwnode, + "baikal,hdmi-bridge", 0); + if (IS_ERR_OR_NULL(fwnode)) + return ERR_PTR(-ENODEV); + + tmp = bus_find_device_by_fwnode(&platform_bus_type, fwnode); + if (IS_ERR_OR_NULL(tmp)) + return ERR_PTR(-ENODEV); + + priv_hdmi = dev_get_drvdata(tmp); + if (!priv_hdmi) + return ERR_PTR(-EPROBE_DEFER); + + bridge = priv_hdmi->bridge; + panel = NULL; + } else if (port == CRTC_LVDS) { + fwnode = fwnode_find_reference(dev->fwnode, + "baikal,lvds-panel", 0); + if (IS_ERR_OR_NULL(fwnode)) + return ERR_PTR(-ENODEV); + + panel = fwnode_drm_find_panel(fwnode); + if (IS_ERR(panel)) + return ERR_CAST(panel); + } else { + return ERR_PTR(-ENODEV); + } + } + + if (ret) + return ERR_PTR(ret); + + if (panel) { + bridge = devm_baikal_lvds_bridge_add(dev, panel, DRM_MODE_CONNECTOR_LVDS); + } + + return bridge; +} + +static int baikal_vdu_remove_efifb(struct drm_device *dev) +{ + int err; + err = drm_aperture_remove_framebuffers("baikal-vdudrmfb", false); + if (err) + dev_warn(dev->dev, "failed to remove firmware framebuffer\n"); + return err; +} + +inline void baikal_vdu_switch_off(struct baikal_vdu_private *priv) +{ + u32 cntl = readl(priv->regs + CR1); + cntl &= ~CR1_LCE; + writel(cntl, priv->regs + CR1); +} + +inline void baikal_vdu_switch_on(struct baikal_vdu_private *priv) +{ + u32 cntl = readl(priv->regs + CR1); + cntl |= CR1_LCE; + writel(cntl, priv->regs + CR1); +} + +static int baikal_vdu_modeset_init(struct baikal_vdu_private *priv) +{ + struct drm_device *dev = priv->drm; + struct drm_encoder *encoder; + int ret = 0; + int index; + + if (priv == NULL) + return -EINVAL; + index = priv->index; + + ret = baikal_vdu_primary_plane_init(priv); + if (ret != 0) { + dev_err(dev->dev, "%s: failed to init primary plane\n", priv->name); + return ret; + } + + ret = baikal_vdu_crtc_create(priv); + if (ret) { + dev_err(dev->dev, "%s: failed to create CRTC\n", priv->name); + return ret; + } + + if (priv->bridge) { + encoder = &priv->encoder; + ret = drm_encoder_init(dev, encoder, &baikal_vdu_encoder_funcs, + DRM_MODE_ENCODER_NONE, NULL); + if (ret) { + dev_err(dev->dev, "%s: failed to create DRM encoder\n", priv->name); + return ret; + } + encoder->crtc = &priv->crtc; + encoder->possible_crtcs = BIT(drm_crtc_index(encoder->crtc)); + priv->bridge->encoder = encoder; + ret = drm_bridge_attach(encoder, priv->bridge, NULL, 0); + if (ret) { + dev_err(dev->dev, "%s: failed to attach DRM bridge (%d)\n", priv->name, ret); + return ret; + } + } else { + dev_err(dev->dev, "%s: no bridge or panel attached\n", priv->name); + return -ENODEV; + } + + priv->mode_override = mode_override; + + return ret; +} + +static int baikal_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + args->size = args->pitch * args->height + IFIFO_SIZE + UHD_FIFO_SIZE; + + return drm_gem_dma_dumb_create_internal(file, dev, args); +} + +DEFINE_DRM_GEM_DMA_FOPS(baikal_drm_fops); + +static struct drm_driver vdu_drm_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + DRM_GEM_DMA_DRIVER_OPS, + .lastclose = drm_fb_helper_lastclose, + .ioctls = NULL, + .fops = &baikal_drm_fops, + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = 2, + .minor = 0, + .patchlevel = 0, + .dumb_create = baikal_dumb_create, + .dumb_map_offset = drm_gem_dumb_map_offset, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_import_sg_table = drm_gem_dma_prime_import_sg_table, + .gem_prime_mmap = drm_gem_prime_mmap, +}; + +static int baikal_vdu_allocate_resources(struct platform_device *pdev, + struct baikal_vdu_private *priv) +{ + struct device *dev = &pdev->dev; + struct resource *mem; + int ret; + + mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, priv->regs_name); + if (!mem) + mem = platform_get_resource(pdev, IORESOURCE_MEM, priv->index); + + if (!mem) { + dev_err(dev, "%s %s: no MMIO resource specified\n", __func__, priv->name); + return -EINVAL; + } + + priv->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(priv->regs)) { + dev_err(dev, "%s %s: MMIO allocation failed\n", __func__, priv->name); + return PTR_ERR(priv->regs); + } + + if (priv->off) { + baikal_vdu_switch_off(priv); + return -EPERM; + } else { + ret = baikal_vdu_modeset_init(priv); + if (ret) { + dev_err(dev, "%s %s: failed to init modeset\n", __func__, priv->name); + if (ret == -ENODEV) { + baikal_vdu_switch_off(priv); + } + return ret; + } else { + writel(MRR_MAX_VALUE, priv->regs + MRR); + spin_lock_init(&priv->lock); + return 0; + } + } +} + +static int baikal_vdu_allocate_irq(struct platform_device *pdev, + struct baikal_vdu_private *priv) +{ + struct device *dev = &pdev->dev; + int ret; + + priv->irq = fwnode_irq_get_byname(dev->fwnode, priv->irq_name); + if (priv->irq < 0) { + dev_err(dev, "%s %s: no IRQ resource specified\n", __func__, priv->name); + return -EINVAL; + } + + /* turn off interrupts before requesting the irq */ + writel(0, priv->regs + IMR); + ret = request_irq(priv->irq, baikal_vdu_irq, IRQF_SHARED, dev->driver->name, priv); + if (ret != 0) + dev_err(dev, "%s %s: IRQ %d allocation failed\n", __func__, priv->name, priv->irq); + return ret; +} + +static void baikal_vdu_free_irq(struct baikal_vdu_private *priv) +{ + writel(0, priv->regs + IMR); + writel(0x3ffff, priv->regs + ISR); + free_irq(priv->irq, priv->drm->dev); +} + +static int baikal_vdu_allocate_clk(struct baikal_vdu_private *priv) +{ + priv->clk = clk_get(priv->drm->dev, priv->pclk_name); + if (IS_ERR(priv->clk)) { + dev_err(priv->drm->dev, "%s: unable to get %s, err %ld\n", priv->name, priv->pclk_name, PTR_ERR(priv->clk)); + return PTR_ERR(priv->clk); + } else + return 0; +} + +static void baikal_vdu_set_name(struct baikal_vdu_private *priv, int index, const char *name) +{ + char *c; + int len = sizeof(priv->name) / sizeof(priv->name[0]) - 1; + strncpy(priv->name, name, len); + for (c = priv->name; c < priv->name + len && *c; c++) { + *c = toupper(*c); + } + sprintf(priv->irq_name, "%s_irq", name); + sprintf(priv->pclk_name, "%s_pclk", name); + sprintf(priv->regs_name, "%s_regs", name); + priv->index = index; +} + +static int baikal_vdu_bridge_init(struct baikal_vdu_private *priv, struct drm_device *drm) { + int ret = 0; + struct device *dev; + struct drm_bridge *bridge; + if (!priv || !drm) + return -ENODEV; + priv->drm = drm; + dev = drm->dev; + bridge = devm_baikal_get_bridge(dev, priv->index, 0); + if (IS_ERR(bridge)) { + ret = PTR_ERR(bridge); + if (ret == -EPROBE_DEFER) { + dev_info(dev, "%s: bridge probe deferred\n", priv->name); + } + priv->bridge = NULL; + } else { + priv->bridge = bridge; + } + return ret; +} + +static int baikal_vdu_resources_init(struct platform_device *pdev, struct baikal_vdu_private *priv) +{ + int ret = baikal_vdu_allocate_resources(pdev, priv); + if (ret) + return 0; + ret = baikal_vdu_allocate_irq(pdev, priv); + if (ret) + return 0; + ret = baikal_vdu_allocate_clk(priv); + if (ret) { + baikal_vdu_free_irq(priv); + return 0; + } else { + return 1; + } +} + +static int baikal_vdu_drm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct baikal_lvds_bridge *panel_bridge; + struct baikal_vdu_crossbar *crossbar; + struct baikal_vdu_private *hdmi; + struct baikal_vdu_private *lvds; + struct drm_device *drm; + struct drm_mode_config *mode_config; + struct arm_smccc_res res; + int ret; + + crossbar = devm_drm_dev_alloc(dev, &vdu_drm_driver, + struct baikal_vdu_crossbar, drm); + if (IS_ERR(crossbar)) + return PTR_ERR(crossbar); + + drm = &crossbar->drm; + platform_set_drvdata(pdev, drm); + hdmi = &crossbar->hdmi; + baikal_vdu_set_name(hdmi, CRTC_HDMI, "hdmi"); + lvds = &crossbar->lvds; + baikal_vdu_set_name(lvds, CRTC_LVDS, "lvds"); + + ret = baikal_vdu_bridge_init(hdmi, drm); + if (ret == -EPROBE_DEFER) { + goto out_drm; + } + + ret = device_property_read_u32(&pdev->dev, "lvds-lanes", + &lvds->num_lanes); + if (ret) + lvds->num_lanes = 0; + if (lvds->num_lanes) { + ret = baikal_vdu_bridge_init(lvds, drm); + if (ret == -EPROBE_DEFER) { + goto out_drm; + } + } + + drm_mode_config_init(drm); + mode_config = &drm->mode_config; + mode_config->funcs = &mode_config_funcs; + mode_config->min_width = 1; + mode_config->max_width = 8192; + mode_config->min_height = 1; + mode_config->max_height = 8192; + + hdmi->off = hdmi_off; + hdmi->ready = baikal_vdu_resources_init(pdev, hdmi); + if (lvds->num_lanes) { + lvds->off = lvds_off; + lvds->ready = baikal_vdu_resources_init(pdev, lvds); + } else { + lvds->ready = 0; + lvds->bridge = NULL; + dev_info(dev, "No 'lvds-lanes' property found\n"); + } + if (lvds->ready) { + ret = baikal_vdu_backlight_create(drm); + if (ret) { + dev_err(dev, "LVDS: failed to create backlight\n"); + } + if (bridge_is_baikal_lvds_bridge(lvds->bridge)) { + panel_bridge = bridge_to_baikal_lvds_bridge(lvds->bridge); + panel_bridge->vdu = lvds; + } else { + // TODO implement handling of third-party bridges + } + } + if (hdmi->bridge) { + // TODO implement functions specific to HDMI bridge + } + + hdmi->ready = hdmi->ready & !hdmi->off; + lvds->ready = lvds->ready & !lvds->off; + dev_info(dev, "%s output %s\n", hdmi->name, hdmi->ready ? "enabled" : "disabled"); + dev_info(dev, "%s output %s\n", lvds->name, lvds->ready ? "enabled" : "disabled"); + baikal_vdu_remove_efifb(drm); + + if (hdmi->ready || lvds->ready) { + /* Disable SCP debug output as it may affect VDU performance */ + arm_smccc_smc(BAIKAL_SMC_LOG_DISABLE, 0, 0, 0, 0, 0, 0, 0, &res); + + drm_mode_config_reset(drm); + drm_kms_helper_poll_init(drm); + ret = drm_dev_register(drm, 0); + if (ret) { + dev_err(dev, "failed to register DRM device\n"); + goto out_config; + } + drm_fbdev_generic_setup(drm, 32); +#if defined(CONFIG_DEBUG_FS) + if (hdmi->ready) + baikal_vdu_hdmi_debugfs_init(drm->primary); + if (lvds->ready) + baikal_vdu_lvds_debugfs_init(drm->primary); +#endif + return 0; + } else { + dev_err(dev, "no active outputs configured\n"); + ret = -ENODEV; + } +out_config: + drm_mode_config_cleanup(drm); +out_drm: + dev_err(dev, "failed to probe: %d\n", ret); + return ret; +} + +static int baikal_vdu_drm_remove(struct platform_device *pdev) +{ + struct drm_device *drm = platform_get_drvdata(pdev); + struct baikal_vdu_crossbar *crossbar = drm_to_baikal_vdu_crossbar(drm); + + drm_dev_unregister(drm); + drm_mode_config_cleanup(drm); + if (crossbar->hdmi.irq) + free_irq(crossbar->hdmi.irq, drm->dev); + if (crossbar->lvds.irq) + free_irq(crossbar->lvds.irq, drm->dev); + + return 0; +} + +static const struct of_device_id baikal_vdu_of_match[] = { + { .compatible = "baikal,vdu" }, + { }, +}; +MODULE_DEVICE_TABLE(of, baikal_vdu_of_match); + +static struct platform_driver baikal_vdu_platform_driver = { + .probe = baikal_vdu_drm_probe, + .remove = baikal_vdu_drm_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = baikal_vdu_of_match, + }, +}; + +module_param(mode_override, int, 0644); +module_param(hdmi_off, int, 0644); +module_param(lvds_off, int, 0644); + +module_platform_driver(baikal_vdu_platform_driver); + +MODULE_AUTHOR("Pavel Parkhomenko "); +MODULE_DESCRIPTION("Baikal Electronics BE-M1000 Video Display Unit (VDU) DRM Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); +MODULE_SOFTDEP("pre: baikal_hdmi"); diff --git a/drivers/gpu/drm/baikal/baikal_vdu_panel.c b/drivers/gpu/drm/baikal/baikal_vdu_panel.c new file mode 100644 index 0000000000000..9983f36b94f1e --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal_vdu_panel.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +#include +#include +#include +#include + +#include "baikal_vdu_drm.h" +#include "baikal_vdu_regs.h" + +static void baikal_lvds_connector_force(struct drm_connector *connector) +{ + struct baikal_lvds_bridge *bridge = connector_to_baikal_lvds_bridge(connector); + struct baikal_vdu_private *priv = bridge->vdu; + u32 cntl = readl(priv->regs + CR1); + if (connector->force == DRM_FORCE_OFF) + cntl &= ~CR1_LCE; + else + cntl |= CR1_LCE; + writel(cntl, priv->regs + CR1); +} + +static int baikal_lvds_connector_get_modes(struct drm_connector *connector) +{ + struct baikal_lvds_bridge *panel_bridge = + connector_to_baikal_lvds_bridge(connector); + + return drm_panel_get_modes(panel_bridge->panel, connector); +} + +static const struct drm_connector_helper_funcs +baikal_lvds_bridge_connector_helper_funcs = { + .get_modes = baikal_lvds_connector_get_modes, +}; + +static const struct drm_connector_funcs baikal_lvds_bridge_connector_funcs = { + .reset = drm_atomic_helper_connector_reset, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .force = baikal_lvds_connector_force, +}; + +static int baikal_lvds_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) +{ + struct baikal_lvds_bridge *panel_bridge = bridge_to_baikal_lvds_bridge(bridge); + struct drm_connector *connector = &panel_bridge->connector; + int ret; + + if (!bridge->encoder) { + DRM_ERROR("Missing encoder\n"); + return -ENODEV; + } + + drm_connector_helper_add(connector, + &baikal_lvds_bridge_connector_helper_funcs); + + ret = drm_connector_init(bridge->dev, connector, + &baikal_lvds_bridge_connector_funcs, + panel_bridge->connector_type); + if (ret) { + DRM_ERROR("Failed to initialize connector\n"); + return ret; + } + + ret = drm_connector_attach_encoder(&panel_bridge->connector, + bridge->encoder); + if (ret < 0) + return ret; + + return 0; +} + +static void baikal_lvds_bridge_pre_enable(struct drm_bridge *bridge) +{ + struct baikal_lvds_bridge *panel_bridge = bridge_to_baikal_lvds_bridge(bridge); + + baikal_vdu_switch_on(panel_bridge->vdu); + drm_panel_prepare(panel_bridge->panel); +} + +static void baikal_lvds_bridge_enable(struct drm_bridge *bridge) +{ + struct baikal_lvds_bridge *panel_bridge = bridge_to_baikal_lvds_bridge(bridge); + + drm_panel_enable(panel_bridge->panel); +} + +static void baikal_lvds_bridge_disable(struct drm_bridge *bridge) +{ + struct baikal_lvds_bridge *panel_bridge = bridge_to_baikal_lvds_bridge(bridge); + + drm_panel_disable(panel_bridge->panel); +} + +static void baikal_lvds_bridge_post_disable(struct drm_bridge *bridge) +{ + struct baikal_lvds_bridge *panel_bridge = bridge_to_baikal_lvds_bridge(bridge); + + drm_panel_unprepare(panel_bridge->panel); + baikal_vdu_switch_off(panel_bridge->vdu); +} + +static const struct drm_bridge_funcs baikal_lvds_bridge_funcs = { + .attach = baikal_lvds_bridge_attach, + .pre_enable = baikal_lvds_bridge_pre_enable, + .enable = baikal_lvds_bridge_enable, + .disable = baikal_lvds_bridge_disable, + .post_disable = baikal_lvds_bridge_post_disable, +}; + +static struct drm_bridge *baikal_lvds_bridge_add(struct drm_panel *panel, + u32 connector_type) +{ + struct baikal_lvds_bridge *panel_bridge; + + if (!panel) + return ERR_PTR(-EINVAL); + + panel_bridge = devm_kzalloc(panel->dev, sizeof(*panel_bridge), + GFP_KERNEL); + if (!panel_bridge) + return ERR_PTR(-ENOMEM); + + panel_bridge->connector_type = connector_type; + panel_bridge->panel = panel; + + panel_bridge->bridge.funcs = &baikal_lvds_bridge_funcs; +#ifdef CONFIG_OF + panel_bridge->bridge.of_node = panel->dev->of_node; +#endif + + drm_bridge_add(&panel_bridge->bridge); + + return &panel_bridge->bridge; +} + +static void baikal_lvds_bridge_remove(struct drm_bridge *bridge) +{ + struct baikal_lvds_bridge *panel_bridge; + + if (!bridge) + return; + + if (bridge->funcs != &baikal_lvds_bridge_funcs) + return; + + panel_bridge = bridge_to_baikal_lvds_bridge(bridge); + + drm_bridge_remove(bridge); + devm_kfree(panel_bridge->panel->dev, bridge); +} + +static void devm_baikal_lvds_bridge_release(struct device *dev, void *res) +{ + struct drm_bridge **bridge = res; + + baikal_lvds_bridge_remove(*bridge); +} + +struct drm_bridge *devm_baikal_lvds_bridge_add(struct device *dev, + struct drm_panel *panel, + u32 connector_type) +{ + struct drm_bridge **ptr, *bridge; + + ptr = devres_alloc(devm_baikal_lvds_bridge_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + bridge = baikal_lvds_bridge_add(panel, connector_type); + if (!IS_ERR(bridge)) { + *ptr = bridge; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return bridge; +} + +bool bridge_is_baikal_lvds_bridge(const struct drm_bridge *bridge) +{ + return bridge && (bridge->funcs == &baikal_lvds_bridge_funcs); +} diff --git a/drivers/gpu/drm/baikal/baikal_vdu_plane.c b/drivers/gpu/drm/baikal/baikal_vdu_plane.c new file mode 100644 index 0000000000000..d9bdb95a8d962 --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal_vdu_plane.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2023 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "baikal_vdu_drm.h" +#include "baikal_vdu_regs.h" + +static void baikal_vdu_primary_plane_atomic_update(struct drm_plane *plane, + struct drm_atomic_state *old_state) +{ + struct baikal_vdu_private *priv; + struct drm_plane_state *state = plane->state; + struct drm_crtc *crtc = state->crtc; + struct drm_framebuffer *fb = state->fb; + uint32_t cntl; + uint32_t addr; + unsigned long flags; + + if (!fb) + return; + + priv = crtc_to_baikal_vdu(crtc); + addr = drm_fb_dma_get_gem_addr(fb, state, 0); + + spin_lock_irqsave(&priv->lock, flags); + writel(addr, priv->regs + DBAR); + spin_unlock_irqrestore(&priv->lock, flags); + priv->counters[16]++; + + cntl = readl(priv->regs + CR1); + cntl &= ~CR1_BPP_MASK; + + /* Note that the the hardware's format reader takes 'r' from + * the low bit, while DRM formats list channels from high bit + * to low bit as you read left to right. + */ + switch (fb->format->format) { + case DRM_FORMAT_BGR888: + cntl |= CR1_BPP24 | CR1_FBP | CR1_BGR; + break; + case DRM_FORMAT_RGB888: + cntl |= CR1_BPP24 | CR1_FBP; + break; + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + cntl |= CR1_BPP24 | CR1_BGR; + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + cntl |= CR1_BPP24; + break; + case DRM_FORMAT_BGR565: + cntl |= CR1_BPP16_565 | CR1_BGR; + break; + case DRM_FORMAT_RGB565: + cntl |= CR1_BPP16_565; + break; + case DRM_FORMAT_ABGR1555: + case DRM_FORMAT_XBGR1555: + cntl |= CR1_BPP16_555 | CR1_BGR; + break; + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_XRGB1555: + cntl |= CR1_BPP16_555; + break; + default: + WARN_ONCE(true, "Unknown FB format 0x%08x, set XRGB8888 instead\n", + fb->format->format); + cntl |= CR1_BPP24; + break; + } + + writel(cntl, priv->regs + CR1); +} + +static const struct drm_plane_helper_funcs baikal_vdu_primary_plane_helper_funcs = { + .atomic_update = baikal_vdu_primary_plane_atomic_update, +}; + +static const struct drm_plane_funcs baikal_vdu_primary_plane_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .reset = drm_atomic_helper_plane_reset, + .destroy = drm_plane_cleanup, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +int baikal_vdu_primary_plane_init(struct baikal_vdu_private *priv) +{ + struct drm_device *drm = priv->drm; + struct drm_plane *plane = &priv->primary; + static const u32 formats[] = { + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_BGR565, + DRM_FORMAT_RGB565, + DRM_FORMAT_ABGR1555, + DRM_FORMAT_XBGR1555, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + }; + int ret; + + ret = drm_universal_plane_init(drm, plane, 0, + &baikal_vdu_primary_plane_funcs, + formats, + ARRAY_SIZE(formats), + NULL, + DRM_PLANE_TYPE_PRIMARY, + NULL); + if (ret) + return ret; + + drm_plane_helper_add(plane, &baikal_vdu_primary_plane_helper_funcs); + + return 0; +} diff --git a/drivers/gpu/drm/baikal/baikal_vdu_regs.h b/drivers/gpu/drm/baikal/baikal_vdu_regs.h new file mode 100644 index 0000000000000..d48ea8d12051f --- /dev/null +++ b/drivers/gpu/drm/baikal/baikal_vdu_regs.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019-2023 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +#ifndef __BAIKAL_VDU_REGS_H__ +#define __BAIKAL_VDU_REGS_H__ + +#define CR1 0x000 +#define HTR 0x008 +#define VTR1 0x00C +#define VTR2 0x010 +#define PCTR 0x014 +#define ISR 0x018 +#define IMR 0x01C +#define IVR 0x020 +#define ISCR 0x024 +#define DBAR 0x028 +#define DCAR 0x02C +#define DEAR 0x030 +#define PWMFR 0x034 +#define PWMDCR 0x038 +#define HVTER 0x044 +#define HPPLOR 0x048 +#define GPIOR 0x1F8 +#define MRR 0xFFC + +#define INTR_UFU BIT(16) +#define INTR_BAU BIT(7) +#define INTR_VCT BIT(6) +#define INTR_MBE BIT(5) +#define INTR_FER BIT(4) +#define INTR_IFO BIT(3) +#define INTR_OFU BIT(0) + +#define CR1_FBP BIT(19) +#define CR1_FDW_MASK GENMASK(17, 16) +#define CR1_FDW_4_WORDS (0 << 16) +#define CR1_FDW_8_WORDS (1 << 16) +#define CR1_FDW_16_WORDS (2 << 16) +#define CR1_OPS_MASK GENMASK(14, 12) +#define CR1_OPS_LCD18 (0 << 13) +#define CR1_OPS_LCD24 (1 << 13) +#define CR1_OPS_565 (0 << 12) +#define CR1_OPS_555 (1 << 12) +#define CR1_VSP BIT(11) +#define CR1_HSP BIT(10) +#define CR1_DEP BIT(8) +#define CR1_BGR BIT(5) +#define CR1_BPP_MASK GENMASK(4, 2) +#define CR1_BPP1 (0 << 2) +#define CR1_BPP2 (1 << 2) +#define CR1_BPP4 (2 << 2) +#define CR1_BPP8 (3 << 2) +#define CR1_BPP16 (4 << 2) +#define CR1_BPP18 (5 << 2) +#define CR1_BPP24 (6 << 2) +#define CR1_LCE BIT(0) + +#define CR1_BPP16_555 ((CR1_BPP16) | (CR1_OPS_555)) +#define CR1_BPP16_565 ((CR1_BPP16) | (CR1_OPS_565)) + +#define VTR1_VBP_MASK GENMASK(23, 16) +#define VTR1_VBP(x) ((x) << 16) +#define VTR1_VBP_LSB_WIDTH 8 +#define VTR1_VFP_MASK GENMASK(15, 8) +#define VTR1_VFP(x) ((x) << 8) +#define VTR1_VFP_LSB_WIDTH 8 +#define VTR1_VSW_MASK GENMASK(7, 0) +#define VTR1_VSW(x) ((x) << 0) +#define VTR1_VSW_LSB_WIDTH 8 + +#define VTR2_LPP_MASK GENMASK(11, 0) + +#define HTR_HSW_MASK GENMASK(31, 24) +#define HTR_HSW(x) ((x) << 24) +#define HTR_HSW_LSB_WIDTH 8 +#define HTR_HBP_MASK GENMASK(23, 16) +#define HTR_HBP(x) ((x) << 16) +#define HTR_HBP_LSB_WIDTH 8 +#define HTR_PPL_MASK GENMASK(15, 8) +#define HTR_PPL(x) ((x) << 8) +#define HTR_HFP_MASK GENMASK(7, 0) +#define HTR_HFP(x) ((x) << 0) +#define HTR_HFP_LSB_WIDTH 8 + +#define PCTR_PCI2 BIT(11) +#define PCTR_PCR BIT(10) +#define PCTR_PCI BIT(9) +#define PCTR_PCB BIT(8) +#define PCTR_PCD_MASK GENMASK(7, 0) +#define PCTR_MAX_PCD 128 + +#define ISCR_VSC_OFF 0x0 +#define ISCR_VSC_VSW 0x4 +#define ISCR_VSC_VBP 0x5 +#define ISCR_VSC_VACTIVE 0x6 +#define ISCR_VSC_VFP 0x7 + +#define PWMFR_PWMPCR BIT(24) +#define PWMFR_PWMFCI BIT(23) +#define PWMFR_PWMFCE BIT(22) +#define PWMFR_PWMFCD_MASK GENMASK(21, 0) +#define PWMFR_PWMFCD(x) ((x) << 0) + +#define HVTER_VSWE_MASK GENMASK(25, 24) +#define HVTER_VSWE(x) ((x) << 24) +#define HVTER_HSWE_MASK GENMASK(17, 16) +#define HVTER_HSWE(x) ((x) << 16) +#define HVTER_VBPE_MASK GENMASK(13, 12) +#define HVTER_VBPE(x) ((x) << 12) +#define HVTER_VFPE_MASK GENMASK(9, 8) +#define HVTER_VFPE(x) ((x) << 8) +#define HVTER_HBPE_MASK GENMASK(5, 4) +#define HVTER_HBPE(x) ((x) << 4) +#define HVTER_HFPE_MASK GENMASK(1, 0) +#define HVTER_HFPE(x) ((x) << 0) + +#define HPPLOR_HPOE BIT(31) +#define HPPLOR_HPPLO_MASK GENMASK(11, 0) +#define HPPLOR_HPPLO(x) ((x) << 0) + +#define GPIOR_UHD_MASK GENMASK(23, 16) +#define GPIOR_UHD_SNGL_PORT (0 << 18) +#define GPIOR_UHD_DUAL_PORT (1 << 18) +#define GPIOR_UHD_QUAD_PORT (2 << 18) +#define GPIOR_UHD_ENB BIT(17) + +#define MRR_DEAR_MRR_MASK GENMASK(31, 3) +#define MRR_OUTSTND_RQ_MASK GENMASK(2, 0) +#define MRR_OUTSTND_RQ(x) ((x >> 1) << 0) +#define MRR_MAX_VALUE ((0xffffffff & MRR_DEAR_MRR_MASK) | MRR_OUTSTND_RQ(4)) + +#endif /* __BAIKAL_VDU_REGS_H__ */ diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig b/drivers/gpu/drm/bridge/synopsys/Kconfig index 15fc182d05ef0..61a8542708c71 100644 --- a/drivers/gpu/drm/bridge/synopsys/Kconfig +++ b/drivers/gpu/drm/bridge/synopsys/Kconfig @@ -51,3 +51,19 @@ config DRM_DW_MIPI_DSI select DRM_KMS_HELPER select DRM_MIPI_DSI select DRM_PANEL_BRIDGE + +config DRM_BAIKAL_HDMI + tristate "Baikal-M HDMI transmitter" + select DRM_DW_HDMI + help + Choose this if you want to use HDMI on Baikal-M. + +config DRM_BAIKAL_HDMI_AHB_AUDIO + tristate "Baikal-M HDMI Audio interface" + depends on DRM_BAIKAL_HDMI && SND + select SND_PCM + select SND_PCM_ELD + select SND_PCM_IEC958 + help + Support the AHB Audio interface which is part of the + Baikal-M HDMI Tx block. diff --git a/drivers/gpu/drm/bridge/synopsys/Makefile b/drivers/gpu/drm/bridge/synopsys/Makefile index ce715562e9e52..b5285a4261d8b 100644 --- a/drivers/gpu/drm/bridge/synopsys/Makefile +++ b/drivers/gpu/drm/bridge/synopsys/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o +obj-$(CONFIG_DRM_BAIKAL_HDMI_AHB_AUDIO) += baikal-hdmi-ahb-audio.o obj-$(CONFIG_DRM_DW_HDMI_GP_AUDIO) += dw-hdmi-gp-audio.o obj-$(CONFIG_DRM_DW_HDMI_I2S_AUDIO) += dw-hdmi-i2s-audio.o obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o diff --git a/drivers/gpu/drm/bridge/synopsys/baikal-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/baikal-hdmi-ahb-audio.c new file mode 100644 index 0000000000000..c1c71a8d7abdb --- /dev/null +++ b/drivers/gpu/drm/bridge/synopsys/baikal-hdmi-ahb-audio.c @@ -0,0 +1,683 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Baikal Electronics BE-M1000 DesignWare HDMI AHB audio driver + * + * Copyright (C) 2020-2022 Baikal Electronics, JSC + * + * Author: Pavel Parkhomenko + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "dw-hdmi-audio.h" + +#define DRIVER_NAME "dw-hdmi-ahb-audio" + +#define BAIKAL_HDMI_REG_SHIFT 2 + +/* Provide some bits rather than bit offsets */ +enum { + HDMI_AHB_DMA_CONF0_SW_FIFO_RST = BIT(7), + HDMI_AHB_DMA_CONF0_EN_HLOCK = BIT(3), + HDMI_AHB_DMA_START_START = BIT(0), + HDMI_AHB_DMA_STOP_STOP = BIT(0), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_OVERRUN = BIT(6), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = BIT(5), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = BIT(4), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = BIT(3), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = BIT(2), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = BIT(1), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0), + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL = + HDMI_IH_MUTE_AHBDMAAUD_STAT0_OVERRUN | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL | + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY, + HDMI_IH_AHBDMAAUD_STAT0_OVERRUN = BIT(6), + HDMI_IH_AHBDMAAUD_STAT0_ERROR = BIT(5), + HDMI_IH_AHBDMAAUD_STAT0_LOST = BIT(4), + HDMI_IH_AHBDMAAUD_STAT0_RETRY = BIT(3), + HDMI_IH_AHBDMAAUD_STAT0_DONE = BIT(2), + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = BIT(1), + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = BIT(0), + HDMI_IH_AHBDMAAUD_STAT0_ALL = + HDMI_IH_AHBDMAAUD_STAT0_OVERRUN | + HDMI_IH_AHBDMAAUD_STAT0_ERROR | + HDMI_IH_AHBDMAAUD_STAT0_LOST | + HDMI_IH_AHBDMAAUD_STAT0_RETRY | + HDMI_IH_AHBDMAAUD_STAT0_DONE | + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL | + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY, + HDMI_AHB_DMA_CONF0_INCR16 = 2 << 1, + HDMI_AHB_DMA_CONF0_INCR8 = 1 << 1, + HDMI_AHB_DMA_CONF0_INCR4 = 0, + HDMI_AHB_DMA_CONF0_BURST_MODE = BIT(0), + HDMI_AHB_DMA_MASK_DONE = BIT(7), + + HDMI_REVISION_ID = 0x0001, + HDMI_IH_AHBDMAAUD_STAT0 = 0x0109, + HDMI_IH_MUTE_AHBDMAAUD_STAT0 = 0x0189, + HDMI_FC_AUDICONF2 = 0x1027, + HDMI_FC_AUDSCONF = 0x1063, + HDMI_FC_AUDSCONF_LAYOUT1 = 1 << 0, + HDMI_FC_AUDSCONF_LAYOUT0 = 0 << 0, + HDMI_AHB_DMA_CONF0 = 0x3600, + HDMI_AHB_DMA_START = 0x3601, + HDMI_AHB_DMA_STOP = 0x3602, + HDMI_AHB_DMA_THRSLD = 0x3603, + HDMI_AHB_DMA_STRADDR0 = 0x3604, + HDMI_AHB_DMA_STPADDR0 = 0x3608, + HDMI_AHB_DMA_MASK = 0x3614, + HDMI_AHB_DMA_POL = 0x3615, + HDMI_AHB_DMA_CONF1 = 0x3616, + HDMI_AHB_DMA_BUFFPOL = 0x361a, +}; + +struct dw_hdmi_channel_conf { + u8 conf1; + u8 ca; +}; + +/* + * The default mapping of ALSA channels to HDMI channels and speaker + * allocation bits. Note that we can't do channel remapping here - + * channels must be in the same order. + * + * Mappings for alsa-lib pcm/surround*.conf files: + * + * Front Sur4.0 Sur4.1 Sur5.0 Sur5.1 Sur7.1 + * Channels 2 4 6 6 6 8 + * + * Our mapping from ALSA channel to CEA686D speaker name and HDMI channel: + * + * Number of ALSA channels + * ALSA Channel 2 3 4 5 6 7 8 + * 0 FL:0 = = = = = = + * 1 FR:1 = = = = = = + * 2 FC:3 RL:4 LFE:2 = = = + * 3 RR:5 RL:4 FC:3 = = + * 4 RR:5 RL:4 = = + * 5 RR:5 = = + * 6 RC:6 = + * 7 RLC/FRC RLC/FRC + */ +static struct dw_hdmi_channel_conf default_hdmi_channel_config[7] = { + { 0x03, 0x00 }, /* FL,FR */ + { 0x0b, 0x02 }, /* FL,FR,FC */ + { 0x33, 0x08 }, /* FL,FR,RL,RR */ + { 0x37, 0x09 }, /* FL,FR,LFE,RL,RR */ + { 0x3f, 0x0b }, /* FL,FR,LFE,FC,RL,RR */ + { 0x7f, 0x0f }, /* FL,FR,LFE,FC,RL,RR,RC */ + { 0xff, 0x13 }, /* FL,FR,LFE,FC,RL,RR,[FR]RC,[FR]LC */ +}; + +struct snd_dw_hdmi { + struct snd_card *card; + struct snd_pcm *pcm; + spinlock_t lock; + struct dw_hdmi_audio_data data; + struct snd_pcm_substream *substream; + void (*reformat)(struct snd_dw_hdmi *, size_t, size_t); + void *buf_src; + void *buf_dst; + dma_addr_t buf_addr; + unsigned buf_offset; + unsigned buf_period; + unsigned buf_size; + unsigned channels; + u8 revision; + u8 iec_offset; + u8 cs[192][8]; +}; + +static inline void baikal_hdmi_writeb(u8 val, void __iomem *base, uint offset) +{ + writeb(val, base + (offset << BAIKAL_HDMI_REG_SHIFT)); +} + +static inline void baikal_hdmi_writeb_relaxed(u8 val, void __iomem *base, uint offset) +{ + writeb_relaxed(val, base + (offset << BAIKAL_HDMI_REG_SHIFT)); +} + +static inline u8 baikal_hdmi_readb_relaxed(void __iomem *base, uint offset) +{ + return readb_relaxed(base + (offset << BAIKAL_HDMI_REG_SHIFT)); +} + +static void baikal_hdmi_writel(u32 val, void __iomem *base, uint offset) +{ + writeb_relaxed(val, base + (offset << BAIKAL_HDMI_REG_SHIFT)); + writeb_relaxed(val >> 8, base + ((offset + 1) << BAIKAL_HDMI_REG_SHIFT)); + writeb_relaxed(val >> 16, base + ((offset + 2) << BAIKAL_HDMI_REG_SHIFT)); + writeb_relaxed(val >> 24, base + ((offset + 3) << BAIKAL_HDMI_REG_SHIFT)); +} + +/* + * Convert to hardware format: The userspace buffer contains IEC958 samples, + * with the PCUV bits in bits 31..28 and audio samples in bits 27..4. We + * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio + * samples in 23..0. + * + * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd + * + * Ideally, we could do with having the data properly formatted in userspace. + */ +static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw, + size_t offset, size_t bytes) +{ + u32 *src = dw->buf_src + offset; + u32 *dst = dw->buf_dst + offset; + u32 *end = dw->buf_src + offset + bytes; + + do { + u32 b, sample = *src++; + + b = (sample & 8) << (28 - 3); + + sample >>= 4; + + *dst++ = sample | b; + } while (src < end); +} + +static u32 parity(u32 sample) +{ + sample ^= sample >> 16; + sample ^= sample >> 8; + sample ^= sample >> 4; + sample ^= sample >> 2; + sample ^= sample >> 1; + return (sample & 1) << 27; +} + +static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw, + size_t offset, size_t bytes) +{ + u32 *src = dw->buf_src + offset; + u32 *dst = dw->buf_dst + offset; + u32 *end = dw->buf_src + offset + bytes; + + do { + unsigned i; + u8 *cs; + + cs = dw->cs[dw->iec_offset++]; + if (dw->iec_offset >= 192) + dw->iec_offset = 0; + + i = dw->channels; + do { + u32 sample = *src++; + + sample &= ~0xff000000; + sample |= *cs++ << 24; + sample |= parity(sample & ~0xf8000000); + + *dst++ = sample; + } while (--i); + } while (src < end); +} + +static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw, + struct snd_pcm_runtime *runtime) +{ + u8 cs[4]; + unsigned ch, i, j; + + snd_pcm_create_iec958_consumer(runtime, cs, sizeof(cs)); + + memset(dw->cs, 0, sizeof(dw->cs)); + + for (ch = 0; ch < 8; ch++) { + cs[2] &= ~IEC958_AES2_CON_CHANNEL; + cs[2] |= (ch + 1) << 4; + + for (i = 0; i < ARRAY_SIZE(cs); i++) { + unsigned c = cs[i]; + + for (j = 0; j < 8; j++, c >>= 1) + dw->cs[i * 8 + j][ch] = (c & 1) << 2; + } + } + dw->cs[0][0] |= BIT(4); +} + +static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw) +{ + void __iomem *base = dw->data.base; + unsigned offset = dw->buf_offset; + unsigned period = dw->buf_period; + u32 start, stop; + + dw->reformat(dw, offset, period); + + /* Clear all irqs before enabling irqs and starting DMA */ + baikal_hdmi_writeb_relaxed(HDMI_IH_AHBDMAAUD_STAT0_ALL, + base, HDMI_IH_AHBDMAAUD_STAT0); + + start = dw->buf_addr + offset; + stop = start + period - 1; + + /* Setup the hardware start/stop addresses */ + baikal_hdmi_writel(start, base, HDMI_AHB_DMA_STRADDR0); + baikal_hdmi_writel(stop, base, HDMI_AHB_DMA_STPADDR0); + + baikal_hdmi_writeb_relaxed((u8)~HDMI_AHB_DMA_MASK_DONE, base, HDMI_AHB_DMA_MASK); + baikal_hdmi_writeb(HDMI_AHB_DMA_START_START, base, HDMI_AHB_DMA_START); + + offset += period; + if (offset >= dw->buf_size) + offset = 0; + dw->buf_offset = offset; +} + +static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw) +{ + /* Disable interrupts before disabling DMA */ + baikal_hdmi_writeb_relaxed(~0, dw->data.base, HDMI_AHB_DMA_MASK); + baikal_hdmi_writeb_relaxed(HDMI_AHB_DMA_STOP_STOP, dw->data.base, HDMI_AHB_DMA_STOP); +} + +static irqreturn_t snd_dw_hdmi_irq(int irq, void *data) +{ + struct snd_dw_hdmi *dw = data; + struct snd_pcm_substream *substream; + unsigned stat; + + stat = baikal_hdmi_readb_relaxed(dw->data.base, HDMI_IH_AHBDMAAUD_STAT0); + if (!stat) + return IRQ_NONE; + + baikal_hdmi_writeb_relaxed(stat, dw->data.base, HDMI_IH_AHBDMAAUD_STAT0); + + substream = dw->substream; + if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) { + snd_pcm_period_elapsed(substream); + + spin_lock(&dw->lock); + if (dw->substream) + dw_hdmi_start_dma(dw); + spin_unlock(&dw->lock); + } + + return IRQ_HANDLED; +} + +static struct snd_pcm_hardware dw_hdmi_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .channels_min = 2, + .channels_max = 8, + .buffer_bytes_max = 1024 * 1024, + .period_bytes_min = 256, + .period_bytes_max = 8192, /* ERR004323: must limit to 8k */ + .periods_min = 2, + .periods_max = 16, + .fifo_size = 0, +}; + +static int dw_hdmi_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dw_hdmi *dw = substream->private_data; + void __iomem *base = dw->data.base; + u8 *eld; + int ret; + + runtime->hw = dw_hdmi_hw; + + eld = dw->data.get_eld(dw->data.hdmi); + if (eld) { + ret = snd_pcm_hw_constraint_eld(runtime, eld); + if (ret < 0) + return ret; + } + + ret = snd_pcm_limit_hw_rates(runtime); + if (ret < 0) + return ret; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + /* Limit the buffer size to the size of the preallocated buffer */ + ret = snd_pcm_hw_constraint_minmax(runtime, + SNDRV_PCM_HW_PARAM_BUFFER_SIZE, + 0, substream->dma_buffer.bytes); + if (ret < 0) + return ret; + + /* Clear FIFO */ + baikal_hdmi_writeb_relaxed(HDMI_AHB_DMA_CONF0_SW_FIFO_RST, + base, HDMI_AHB_DMA_CONF0); + + /* Configure interrupt polarities */ + baikal_hdmi_writeb_relaxed(~0, base, HDMI_AHB_DMA_POL); + baikal_hdmi_writeb_relaxed(~0, base, HDMI_AHB_DMA_BUFFPOL); + + /* Keep interrupts masked, and clear any pending */ + baikal_hdmi_writeb_relaxed(~0, base, HDMI_AHB_DMA_MASK); + baikal_hdmi_writeb_relaxed(~0, base, HDMI_IH_AHBDMAAUD_STAT0); + + ret = request_irq(dw->data.irq, snd_dw_hdmi_irq, IRQF_SHARED, + "dw-hdmi-audio", dw); + if (ret) + return ret; + + /* Un-mute done interrupt */ + baikal_hdmi_writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL & + ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE, + base, HDMI_IH_MUTE_AHBDMAAUD_STAT0); + + return 0; +} + +static int dw_hdmi_close(struct snd_pcm_substream *substream) +{ + struct snd_dw_hdmi *dw = substream->private_data; + + /* Mute all interrupts */ + baikal_hdmi_writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL, + dw->data.base, HDMI_IH_MUTE_AHBDMAAUD_STAT0); + + free_irq(dw->data.irq, dw); + + return 0; +} + +static int dw_hdmi_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_vmalloc_buffer(substream); +} + +static int dw_hdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + /* Allocate the PCM runtime buffer, which is exposed to userspace. */ + return snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(params)); +} + +static int dw_hdmi_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dw_hdmi *dw = substream->private_data; + u8 threshold, conf0, conf1, layout, ca; + + /* Setup as per 3.0.5 FSL 4.1.0 BSP */ + switch (dw->revision) { + case 0x0a: + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | + HDMI_AHB_DMA_CONF0_INCR4; + if (runtime->channels == 2) + threshold = 126; + else + threshold = 124; + break; + case 0x1a: + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | + HDMI_AHB_DMA_CONF0_INCR8; + threshold = 128; + break; + case 0x2a: /* this revision is used in Baikal-M SoC */ + conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE | + HDMI_AHB_DMA_CONF0_INCR16; + threshold = 128; + break; + default: + /* NOTREACHED */ + return -EINVAL; + } + + dw_hdmi_set_sample_rate(dw->data.hdmi, runtime->rate); + + /* Minimum number of bytes in the fifo. */ + runtime->hw.fifo_size = threshold * 32; + + conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK; + conf1 = default_hdmi_channel_config[runtime->channels - 2].conf1; + ca = default_hdmi_channel_config[runtime->channels - 2].ca; + + /* + * For >2 channel PCM audio, we need to select layout 1 + * and set an appropriate channel map. + */ + if (runtime->channels > 2) + layout = HDMI_FC_AUDSCONF_LAYOUT1; + else + layout = HDMI_FC_AUDSCONF_LAYOUT0; + + baikal_hdmi_writeb_relaxed(threshold, dw->data.base, HDMI_AHB_DMA_THRSLD); + baikal_hdmi_writeb_relaxed(conf0, dw->data.base, HDMI_AHB_DMA_CONF0); + baikal_hdmi_writeb_relaxed(conf1, dw->data.base, HDMI_AHB_DMA_CONF1); + baikal_hdmi_writeb_relaxed(layout, dw->data.base, HDMI_FC_AUDSCONF); + baikal_hdmi_writeb_relaxed(ca, dw->data.base, HDMI_FC_AUDICONF2); + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + dw->reformat = dw_hdmi_reformat_iec958; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dw_hdmi_create_cs(dw, runtime); + dw->reformat = dw_hdmi_reformat_s24; + break; + } + dw->iec_offset = 0; + dw->channels = runtime->channels; + dw->buf_src = runtime->dma_area; + dw->buf_dst = substream->dma_buffer.area; + dw->buf_addr = substream->dma_buffer.addr; + dw->buf_period = snd_pcm_lib_period_bytes(substream); + dw->buf_size = snd_pcm_lib_buffer_bytes(substream); + + return 0; +} + +static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_dw_hdmi *dw = substream->private_data; + unsigned long flags; + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + spin_lock_irqsave(&dw->lock, flags); + dw->buf_offset = 0; + dw->substream = substream; + dw_hdmi_start_dma(dw); + dw_hdmi_audio_enable(dw->data.hdmi); + spin_unlock_irqrestore(&dw->lock, flags); + substream->runtime->delay = substream->runtime->period_size; + break; + + case SNDRV_PCM_TRIGGER_STOP: + spin_lock_irqsave(&dw->lock, flags); + dw->substream = NULL; + dw_hdmi_stop_dma(dw); + dw_hdmi_audio_disable(dw->data.hdmi); + spin_unlock_irqrestore(&dw->lock, flags); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_dw_hdmi *dw = substream->private_data; + + /* + * We are unable to report the exact hardware position as + * reading the 32-bit DMA position using 8-bit reads is racy. + */ + return bytes_to_frames(runtime, dw->buf_offset); +} + +static struct snd_pcm_ops snd_dw_hdmi_ops = { + .open = dw_hdmi_open, + .close = dw_hdmi_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = dw_hdmi_hw_params, + .hw_free = dw_hdmi_hw_free, + .prepare = dw_hdmi_prepare, + .trigger = dw_hdmi_trigger, + .pointer = dw_hdmi_pointer, + .page = snd_pcm_lib_get_vmalloc_page, +}; + +static int snd_dw_hdmi_probe(struct platform_device *pdev) +{ + const struct dw_hdmi_audio_data *data = pdev->dev.platform_data; + struct device *dev = pdev->dev.parent; + struct snd_dw_hdmi *dw; + struct snd_card *card; + struct snd_pcm *pcm; + unsigned revision; + int ret; + + baikal_hdmi_writeb_relaxed(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL, + data->base, HDMI_IH_MUTE_AHBDMAAUD_STAT0); + revision = baikal_hdmi_readb_relaxed(data->base, HDMI_REVISION_ID); + if (revision != 0x0a && revision != 0x1a && revision != 0x2a) { + dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n", + revision); + return -ENXIO; + } + + ret = snd_card_new(dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, sizeof(struct snd_dw_hdmi), &card); + if (ret < 0) + return ret; + + strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); + strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname)); + snprintf(card->longname, sizeof(card->longname), + "%s rev 0x%02x, irq %d", card->shortname, revision, + data->irq); + + dw = card->private_data; + dw->card = card; + dw->data = *data; + dw->revision = revision; + + spin_lock_init(&dw->lock); + + ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm); + if (ret < 0) + goto err; + + dw->pcm = pcm; + pcm->private_data = dw; + strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops); + + /* + * To support 8-channel 96kHz audio reliably, we need 512k + * to satisfy alsa with our restricted period (ERR004323). + */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + dev, 128 * 1024, 1024 * 1024); + + ret = snd_card_register(card); + if (ret < 0) + goto err; + + platform_set_drvdata(pdev, dw); + + return 0; + +err: + snd_card_free(card); + return ret; +} + +static int snd_dw_hdmi_remove(struct platform_device *pdev) +{ + struct snd_dw_hdmi *dw = platform_get_drvdata(pdev); + + snd_card_free(dw->card); + + return 0; +} + +#if defined(CONFIG_PM_SLEEP) && defined(IS_NOT_BROKEN) +/* + * This code is fine, but requires implementation in the dw_hdmi_trigger() + * method which is currently missing as I have no way to test this. + */ +static int snd_dw_hdmi_suspend(struct device *dev) +{ + struct snd_dw_hdmi *dw = dev_get_drvdata(dev); + + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D3cold); + snd_pcm_suspend_all(dw->pcm); + + return 0; +} + +static int snd_dw_hdmi_resume(struct device *dev) +{ + struct snd_dw_hdmi *dw = dev_get_drvdata(dev); + + snd_power_change_state(dw->card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(snd_dw_hdmi_pm, snd_dw_hdmi_suspend, + snd_dw_hdmi_resume); +#define PM_OPS &snd_dw_hdmi_pm +#else +#define PM_OPS NULL +#endif + +static struct platform_driver snd_dw_hdmi_driver = { + .probe = snd_dw_hdmi_probe, + .remove = snd_dw_hdmi_remove, + .driver = { + .name = DRIVER_NAME, + .pm = PM_OPS, + }, +}; + +module_platform_driver(snd_dw_hdmi_driver); + +MODULE_AUTHOR("Russell King "); +MODULE_DESCRIPTION("Synopsis Designware HDMI AHB ALSA interface"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index aa51c61a78c71..212bb0707bbc6 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -3403,7 +3403,7 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, if (!plat_data->regm) { const struct regmap_config *reg_config; - of_property_read_u32(np, "reg-io-width", &val); + device_property_read_u32(dev, "reg-io-width", &val); switch (val) { case 4: reg_config = &hdmi_regmap_32bit_config; @@ -3703,6 +3703,15 @@ void dw_hdmi_resume(struct dw_hdmi *hdmi) } EXPORT_SYMBOL_GPL(dw_hdmi_resume); +struct drm_bridge *dw_hdmi_get_bridge(struct dw_hdmi *hdmi) +{ + if (IS_ERR_OR_NULL(hdmi)) + return NULL; + + return &hdmi->bridge; +} +EXPORT_SYMBOL_GPL(dw_hdmi_get_bridge); + MODULE_AUTHOR("Sascha Hauer "); MODULE_AUTHOR("Andy Yan "); MODULE_AUTHOR("Yakir Yang "); diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index f634371c717a8..e8a596a2a375b 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -223,6 +223,43 @@ int drm_panel_get_modes(struct drm_panel *panel, } EXPORT_SYMBOL(drm_panel_get_modes); +/** + * fwnode_drm_find_panel - look up a panel using a fwnode + * @fwnode: fwnode of the panel + * + * Searches the set of registered panels for one that matches the given fwnode. + * If a matching panel is found, return a pointer to it. + * + * Return: A pointer to the panel registered for the specified fwnode or + * an ERR_PTR() if no panel matching the fwnode can be found. + * + * Possible error codes returned by this function: + * + * - EPROBE_DEFER: the panel device has not been probed yet, and the caller + * should retry later + * - ENODEV: the device is not available + */ +struct drm_panel *fwnode_drm_find_panel(const struct fwnode_handle *fwnode) +{ + struct drm_panel *panel; + + if (!fwnode_device_is_available(fwnode)) + return ERR_PTR(-ENODEV); + + mutex_lock(&panel_lock); + + list_for_each_entry(panel, &panel_list, list) { + if (panel->dev->fwnode == fwnode) { + mutex_unlock(&panel_lock); + return panel; + } + } + + mutex_unlock(&panel_lock); + return ERR_PTR(-EPROBE_DEFER); +} +EXPORT_SYMBOL(fwnode_drm_find_panel); + #ifdef CONFIG_OF /** * of_drm_find_panel - look up a panel using a device tree node diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index a582ddd583c24..f9ae53ecaecc1 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -37,6 +37,14 @@ config DRM_PANEL_ASUS_Z00T_TM5P5_NT35596 NT35596 1080x1920 video mode panel as found in some Asus Zenfone 2 Laser Z00T devices. +config DRM_PANEL_BAIKAL_LVDS + tristate "Baikal LVDS panel driver" + select VIDEOMODE_HELPERS + help + This driver supports LVDS panels that don't require device-specific + handling of power supplies or control signals. Used in Baikal SoCs + for ACPI. + config DRM_PANEL_BOE_BF060Y8M_AJ0 tristate "Boe BF060Y8M-AJ0 panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 34e717382dbb6..ef380bfaa811a 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_DRM_PANEL_ABT_Y030XX067A) += panel-abt-y030xx067a.o obj-$(CONFIG_DRM_PANEL_ARM_VERSATILE) += panel-arm-versatile.o obj-$(CONFIG_DRM_PANEL_ASUS_Z00T_TM5P5_NT35596) += panel-asus-z00t-tm5p5-n35596.o +obj-$(CONFIG_DRM_PANEL_BAIKAL_LVDS) += panel-baikal-lvds.o obj-$(CONFIG_DRM_PANEL_BOE_BF060Y8M_AJ0) += panel-boe-bf060y8m-aj0.o obj-$(CONFIG_DRM_PANEL_BOE_HIMAX8279D) += panel-boe-himax8279d.o obj-$(CONFIG_DRM_PANEL_BOE_TV101WUM_NL6) += panel-boe-tv101wum-nl6.o diff --git a/drivers/gpu/drm/panel/panel-baikal-lvds.c b/drivers/gpu/drm/panel/panel-baikal-lvds.c new file mode 100644 index 0000000000000..b593bcbad3c8f --- /dev/null +++ b/drivers/gpu/drm/panel/panel-baikal-lvds.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Baikal LVDS panel driver + * + * Copyright (C) 2023 Baikal Electronics, JSC + * Author: Aleksandr Efimov + * + * Implementation based on panel-lvds.c + */ + +#include +#include +#include +#include +#include +#include + +#include