diff -Naur a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile --- a/arch/arm/boot/Makefile 2022-05-27 17:20:13.781877650 +0800 +++ b/arch/arm/boot/Makefile 2022-05-31 11:56:47.693259679 +0800 @@ -16,6 +16,7 @@ ifneq ($(MACHINE),) include $(MACHINE)/Makefile.boot endif +include $(srctree)/arch/arm/boot/dts/Makefile # Note: the following conditions must always be true: # ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET) @@ -24,10 +25,12 @@ ZRELADDR := $(zreladdr-y) PARAMS_PHYS := $(params_phys-y) INITRD_PHYS := $(initrd_phys-y) +DTB_OBJS ?= $(dtb-y) +DTB_OBJS_FULL := $(addprefix $(obj)/dts/,$(DTB_OBJS)) export ZRELADDR INITRD_PHYS PARAMS_PHYS -targets := Image zImage xipImage bootpImage uImage +targets := Image zImage xipImage bootpImage uImage zImage-dtb ifeq ($(CONFIG_XIP_KERNEL),y) @@ -66,6 +69,10 @@ $(obj)/zImage: $(obj)/compressed/vmlinux FORCE $(call if_changed,objcopy) +$(obj)/zImage-dtb: $(obj)/zImage $(DTB_OBJS_FULL) FORCE + @cat $(obj)/zImage $(DTB_OBJS_FULL) > $@ + @$(kecho) ' Kernel: $@ is ready' + endif ifneq ($(LOADADDR),) @@ -86,7 +93,7 @@ false; \ fi -$(obj)/uImage: $(obj)/zImage FORCE +$(obj)/uImage: $(obj)/zImage-dtb FORCE @$(check_for_multiple_loadaddr) $(call if_changed,uimage) diff -Naur a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile --- a/arch/arm64/boot/dts/amlogic/Makefile 2022-05-27 17:20:14.013880643 +0800 +++ b/arch/arm64/boot/dts/amlogic/Makefile 2022-06-04 12:12:41.042068628 +0800 @@ -1,50 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 -dtb-$(CONFIG_ARCH_MESON) += meson-axg-s400.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12a-sei510.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12a-u200.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12a-x96-max.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gtking.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12b-gtking-pro.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12b-a311d-khadas-vim3.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12b-s922x-khadas-vim3.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2-plus.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-g12b-ugoos-am6.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-kii-pro.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-odroidc2.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-p200.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-p201.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-pro.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-meta.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-vega-s95-telos.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-wetek-hub.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-wetek-play2.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s805x-libretech-ac.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-hwacom-amazetv.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-khadas-vim.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-libretech-cc.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-libretech-cc-v2.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-nexbox-a95x.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905x-p212.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p230.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-p231.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-phicomm-n1.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-sml5442tw.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s805x-p241.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-p281.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905w-tx3-mini.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxl-s905d-libretech-pc.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxm-khadas-vim2.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxm-nexbox-a1.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q200.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxm-q201.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxm-rbox-pro.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxm-s912-libretech-pc.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxm-vega-s96.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-gxm-wetek-core2.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-sm1-sei610.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-sm1-khadas-vim3l.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-sm1-odroid-c4.dtb -dtb-$(CONFIG_ARCH_MESON) += meson-a1-ad401.dtb +dtb-$(CONFIG_ARCH_MESON) += meson-g12b-unionpi-tiger.dtb \ No newline at end of file diff -Naur a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi --- a/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi 2022-05-27 17:20:14.013880643 +0800 +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-a311d.dtsi 2022-05-31 11:56:47.693259679 +0800 @@ -11,26 +11,6 @@ compatible = "operating-points-v2"; opp-shared; - opp-100000000 { - opp-hz = /bits/ 64 <100000000>; - opp-microvolt = <731000>; - }; - - opp-250000000 { - opp-hz = /bits/ 64 <250000000>; - opp-microvolt = <731000>; - }; - - opp-500000000 { - opp-hz = /bits/ 64 <500000000>; - opp-microvolt = <731000>; - }; - - opp-667000000 { - opp-hz = /bits/ 64 <667000000>; - opp-microvolt = <731000>; - }; - opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <761000>; @@ -65,31 +45,21 @@ opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <1001000>; }; - }; - - cpub_opp_table_1: opp-table-1 { - compatible = "operating-points-v2"; - opp-shared; - opp-100000000 { - opp-hz = /bits/ 64 <100000000>; - opp-microvolt = <731000>; + opp-1908000000 { + opp-hz = /bits/ 64 <1908000000>; + opp-microvolt = <1022000>; }; - opp-250000000 { - opp-hz = /bits/ 64 <250000000>; - opp-microvolt = <731000>; - }; - - opp-500000000 { - opp-hz = /bits/ 64 <500000000>; - opp-microvolt = <731000>; + opp-2016000000 { + opp-hz = /bits/ 64 <2016000000>; + opp-microvolt = <1022000>; }; + }; - opp-667000000 { - opp-hz = /bits/ 64 <667000000>; - opp-microvolt = <731000>; - }; + cpub_opp_table_1: opp-table-1 { + compatible = "operating-points-v2"; + opp-shared; opp-1000000000 { opp-hz = /bits/ 64 <1000000000>; @@ -126,24 +96,34 @@ opp-microvolt = <831000>; }; - opp-1908000000 { - opp-hz = /bits/ 64 <1908000000>; - opp-microvolt = <861000>; - }; - - opp-2016000000 { - opp-hz = /bits/ 64 <2016000000>; - opp-microvolt = <911000>; - }; - - opp-2108000000 { - opp-hz = /bits/ 64 <2108000000>; - opp-microvolt = <951000>; - }; - - opp-2208000000 { - opp-hz = /bits/ 64 <2208000000>; - opp-microvolt = <1011000>; - }; + opp-1908000000 { + opp-hz = /bits/ 64 <1908000000>; + opp-microvolt = <861000>; + }; + + opp-2016000000 { + opp-hz = /bits/ 64 <2016000000>; + opp-microvolt = <911000>; + }; + + opp-2108000000 { + opp-hz = /bits/ 64 <2108000000>; + opp-microvolt = <951000>; + }; + + opp-2208000000 { + opp-hz = /bits/ 64 <2208000000>; + opp-microvolt = <1011000>; + }; + + opp-2304000000 { + opp-hz = /bits/ 64 <2304000000>; + opp-microvolt = <1022000>; + }; + + opp-2400000000 { + opp-hz = /bits/ 64 <2400000000>; + opp-microvolt = <1022000>; + }; }; }; diff -Naur a/arch/arm64/boot/dts/amlogic/meson-g12b-unionpi-tiger.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-unionpi-tiger.dts --- a/arch/arm64/boot/dts/amlogic/meson-g12b-unionpi-tiger.dts 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-unionpi-tiger.dts 2022-07-04 13:57:46.707580803 +0800 @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + */ + +/dts-v1/; + +#include "meson-g12b-a311d.dtsi" +#include "meson-unionpi-tiger.dtsi" +#include "meson-g12b-unionpi-tiger.dtsi" + +/ { + model = "UnionPi Tiger"; + compatible = "unionpi,tiger", "amlogic,a311d", "amlogic,g12b"; + amlogic-dt-id = "g12b_w400_b"; + + reserved-memory { + galcore_reserved:linux,galcore { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x1000000>; + alignment = <0x0 0x400000>; + linux,contiguous-region; + }; + + isp_cma_reserved:linux,isp_cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x10000000>; + alignment = <0x0 0x400000>; + linux,contiguous-region; + }; + + adapt_cma_reserved:linux,adapt_cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x03000000>; + alignment = <0x0 0x400000>; + linux,contiguous-region; + }; + + codec_mm_cma:linux,codec_mm_cma { + compatible = "shared-dma-pool"; + reusable; + /* ion_codec_mm max can alloc size 80M*/ + size = <0x0 0x13400000>; + alignment = <0x0 0x400000>; + linux,contiguous-region; + }; + + /* codec shared reserved */ + codec_mm_reserved:linux,codec_mm_reserved { + compatible = "amlogic, codec-mm-reserved"; + size = <0x0 0x0>; + alignment = <0x0 0x100000>; + //no-map; + }; + }; + + cpu_version { + reg=<0x0 0xff800220 0x0 0x4>; + }; + + canvas_legacy: canvas_legacy { + compatible = "amlogic, meson, canvas_legacy"; + dev_name = "amlogic-canvas"; + status = "okay"; + amlogic,canvas = <&canvas>; + }; + + media_clk { + compatible = "amlogic, media_clk"; + status = "okay"; + clocks = <&clkc CLKID_PARSER + &clkc CLKID_DEMUX + &clkc CLKID_AHB_ARB0 + &clkc CLKID_DOS + &clkc CLKID_VDEC_MUX + &clkc CLKID_HCODEC_MUX + &clkc CLKID_HEVC_MUX + &clkc CLKID_HEVCF_MUX>; + clock-names = "parser_top", + "demux", + "ahbarb0", + "vdec", + "clk_vdec_mux", + "clk_hcodec_mux", + "clk_hevc_mux", + "clk_hevcb_mux"; + }; + + codec_mm { + compatible = "amlogic, codec, mm"; + memory-region = <&codec_mm_cma &codec_mm_reserved>; + dev_name = "codec_mm"; + status = "okay"; + }; + + codec_io: codec_io { + compatible = "amlogic, codec_io"; + status = "okay"; + #address-cells=<1>; + #size-cells=<1>; + ranges; + io_cbus_base{ + reg = <0xffd00000 0x100000>; + }; + io_dos_base{ + reg = <0xff620000 0x10000>; + }; + io_hiubus_base{ + reg = <0xff63c000 0x2000>; + }; + io_aobus_base{ + reg = <0xff800000 0x10000>; + }; + io_vcbus_base{ + reg = <0xff900000 0x40000>; + }; + io_dmc_base{ + reg = <0xff638000 0x2000>; + }; + io_efuse_base{ + reg = <0xff630000 0x2000>; + }; + }; + + vdec { + compatible = "amlogic, vdec"; + dev_name = "vdec.0"; + status = "okay"; + interrupts = <0 3 1 + 0 23 1 + 0 32 1 + 0 43 1 + 0 44 1 + 0 45 1>; + interrupt-names = "vsync", + "demux", + "parser", + "mailbox_0", + "mailbox_1", + "mailbox_2"; + }; + + amvenc_avc { + compatible = "amlogic, amvenc_avc"; + dev_name = "amvenc_avc"; + status = "okay"; + interrupts = <0 45 1>; + interrupt-names = "mailbox_2"; + }; + + ge2d { + compatible = "amlogic, ge2d-g12a"; + dev_name = "ge2d"; + status = "okay"; + interrupts = ; + interrupt-names = "ge2d"; + clocks = <&clkc CLKID_VAPB>, + <&clkc CLKID_G2D>, + <&clkc CLKID_VAPB>; + clock-names = "clk_vapb_0", + "clk_ge2d", + "clk_ge2d_gate"; + reg = <0x0 0xff940000 0x0 0x10000>; + amlogic,canvas = <&canvas>; + }; + + galcore { + compatible = "amlogic, galcore"; + dev_name = "galcore"; + status = "okay"; + clocks = <&clkc CLKID_NNA_AXI_CLK>, + <&clkc CLKID_NNA_CORE_CLK>; + clock-names = "cts_vipnanoq_axi_clk_composite", + "cts_vipnanoq_core_clk_composite"; + interrupts = ; + interrupt-names = "galcore"; + reg = <0x0 0xff100000 0x0 0x800>, + <0x0 0xff000000 0x0 0x400000>, + <0x0 0xff63c10c 0x0 0x4>, + <0x0 0xff63c110 0x0 0x4>, + <0x0 0xffd01088 0x0 0x4>, + <0X0 0xff63c1c8 0X0 0x4>; + reg-names = "NN_REG","NN_SRAM","NN_MEM0", + "NN_MEM1","NN_RESET","NN_CLK"; + nn_power_version = <2>; + nn_efuse = <0xff63003c 0x20>; + + memory-region = <&galcore_reserved>; + }; + + cpu_iomap { + compatible = "amlogic, iomap"; + #address-cells=<2>; + #size-cells=<2>; + ranges; + io_cbus_base { + reg = <0x0 0xffd00000 0x0 0x26000>; + }; + io_apb_base { + reg = <0x0 0xffe01000 0x0 0x7f000>; + }; + io_aobus_base { + reg = <0x0 0xff800000 0x0 0xb000>; + }; + io_vapb_base { + reg = <0x0 0xff900000 0x0 0x50000>; + }; + io_hiu_base { + reg = <0x0 0xff63c000 0x0 0x2000>; + }; + }; + + aml_pm { + compatible = "amlogic, pm"; + status = "okay"; + device_name = "aml_pm"; + debug_reg = <0xff8000a8>; + exit_reg = <0xff80023c>; + }; + + aml_reboot{ + compatible = "amlogic, reboot"; + sys_reset = <0x84000009>; + sys_poweroff = <0x84000008>; + }; + + bluetooth{ + compatible = "amlogic, bt-dev"; + dev_name = "bluetooth"; + status = "okay"; + gpio_en = <&gpio GPIOX_16 GPIO_ACTIVE_HIGH>; + gpio_hostwake = <&gpio GPIOX_19 GPIO_ACTIVE_HIGH>; + }; + + wifi{ + compatible = "amlogic, wifi-dev"; + dev_name = "wifi"; + status = "okay"; + power_on_pin = <&gpio_ao GPIOAO_5 GPIO_ACTIVE_HIGH>; + }; + + partitions: partitions{ + parts = <14>; + part-0 = <&logo>; + part-1 = <&updater>; + part-2 = <&misc>; + part-3 = <&dto>; + part-4 = <&cri_data>; + part-5 = <¶m>; + part-6 = <&boot>; + part-7 = <&rsv>; + part-8 = <&tee>; + part-9 = <&vendor>; + part-10 = <&odm>; + part-11 = <&system>; + part-12 = <&cache>; + part-13 = <&data>; + + logo:logo{ + pname = "logo"; + size = <0x0 0x800000>; + mask = <1>; + }; + + updater:updater{ + pname = "updater"; + size = <0x0 0x1800000>; + mask = <1>; + }; + + misc:misc{ + pname = "misc"; + size = <0x0 0x800000>; + mask = <1>; + }; + + dto:dto{ + pname = "dto"; + size = <0x0 0x800000>; + mask = <1>; + }; + + cri_data:cri_data{ + pname = "cri_data"; + size = <0x0 0x800000>; + mask = <2>; + }; + + rsv:rsv{ + pname = "rsv"; + size = <0x0 0x1000000>; + mask = <1>; + }; + + param:param{ + pname = "param"; + size = <0x0 0x1000000>; + mask = <2>; + }; + + boot:boot{ + pname = "boot"; + size = <0x0 0x1000000>; + mask = <1>; + }; + + tee:tee{ + pname = "tee"; + size = <0x0 0x2000000>; + mask = <1>; + }; + + vendor:vendor{ + pname = "vendor"; + size = <0x0 0x20000000>; + mask = <1>; + }; + + odm:odm{ + pname = "odm"; + size = <0x0 0x10000000>; + mask = <1>; + }; + + system:system{ + pname = "system"; + size = <0x2 0x00000000>; + mask = <2>; + }; + + cache:cache{ + pname = "cache"; + size = <0x0 0x40000000>; + mask = <2>; + }; + + data:data{ + pname = "data"; + size = <0xffffffff 0xffffffff>; + mask = <4>; + }; + }; + + unifykey{ + compatible = "amlogic, unifykey"; + status = "ok"; + unifykey-num = <17>; + unifykey-index-0 = <&keysn_0>; + unifykey-index-1 = <&keysn_1>; + unifykey-index-2 = <&keysn_2>; + unifykey-index-3 = <&keysn_3>; + unifykey-index-4 = <&keysn_4>; + unifykey-index-5 = <&keysn_5>; + unifykey-index-6 = <&keysn_6>; + unifykey-index-7 = <&keysn_7>; + unifykey-index-8 = <&keysn_8>; + unifykey-index-9 = <&keysn_9>; + unifykey-index-10= <&keysn_10>; + unifykey-index-11= <&keysn_11>; + unifykey-index-12= <&keysn_12>; + unifykey-index-13= <&keysn_13>; + unifykey-index-14= <&keysn_14>; + unifykey-index-15= <&keysn_15>; + unifykey-index-16= <&keysn_16>; + + keysn_0: key_0{ + key-name = "usid"; + key-device = "normal"; + key-permit = "read","write","del"; + }; + keysn_1:key_1{ + key-name = "mac"; + key-device = "normal"; + key-permit = "read","write","del"; + }; + keysn_2:key_2{ + key-name = "hdcp"; + key-device = "secure"; + key-type = "sha1"; + key-permit = "read","write","del"; + }; + keysn_3:key_3{ + key-name = "secure_boot_set"; + key-device = "efuse"; + key-permit = "write"; + }; + keysn_4:key_4{ + key-name = "mac_bt"; + key-device = "normal"; + key-permit = "read","write","del"; + key-type = "mac"; + }; + keysn_5:key_5{ + key-name = "mac_wifi"; + key-device = "normal"; + key-permit = "read","write","del"; + key-type = "mac"; + }; + keysn_6:key_6{ + key-name = "hdcp2_tx"; + key-device = "normal"; + key-permit = "read","write","del"; + }; + keysn_7:key_7{ + key-name = "hdcp2_rx"; + key-device = "normal"; + key-permit = "read","write","del"; + }; + keysn_8:key_8{ + key-name = "widevinekeybox"; + key-device = "secure"; + key-permit = "read","write","del"; + }; + keysn_9:key_9{ + key-name = "deviceid"; + key-device = "normal"; + key-permit = "read","write","del"; + }; + keysn_10:key_10{ + key-name = "hdcp22_fw_private"; + key-device = "secure"; + key-permit = "read","write","del"; + }; + keysn_11:key_11{ + key-name = "PlayReadykeybox25"; + key-device = "secure"; + key-permit = "read","write","del"; + }; + keysn_12:key_12{ + key-name = "prpubkeybox";// PlayReady + key-device = "secure"; + key-permit = "read","write","del"; + }; + keysn_13:key_13{ + key-name = "prprivkeybox";// PlayReady + key-device = "secure"; + key-permit = "read","write","del"; + }; + keysn_14:key_14{ + key-name = "netflix_mgkid"; + key-device = "secure"; + key-permit = "read","write","del"; + }; + keysn_15:key_15{ + key-name = "eth_exphy_para"; + key-device = "normal"; + key-permit = "read","write","del"; + }; + keysn_16:key_16{ + key-name = "um_factory_para"; + key-device = "normal"; + key-permit = "read","write","del"; + }; + };//End unifykey + + sensor: sensor { + compatible = "soc, sensor"; + status = "okay"; + sensor-name = "imx219"; /*ov5647,imx290;os08a10;imx227;imx307;imx219*/ + pinctrl-names="default"; + clocks = <&clkc CLKID_24M>; + clock-names = "g12a_24m"; + }; + + iq: iq { + compatible = "soc, iq"; + status = "okay"; + sensor-name = "imx219"; /*ov5647,imx290;os08a10;imx227;imx307;imx219*/ + }; +}; + +&isp { + status = "okay"; + temper-line-offset = <0x1680>; + temper-buf-size = <12>; + temper-frame-num = <1>; + temper-frame-size = <0xBDD800>; + memory-region = <&isp_cma_reserved>; +}; + +&adapter { + status = "okay"; + memory-region = <&adapt_cma_reserved>; +}; diff -Naur a/arch/arm64/boot/dts/amlogic/meson-g12b-unionpi-tiger.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b-unionpi-tiger.dtsi --- a/arch/arm64/boot/dts/amlogic/meson-g12b-unionpi-tiger.dtsi 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm64/boot/dts/amlogic/meson-g12b-unionpi-tiger.dtsi 2022-05-31 11:56:47.693259679 +0800 @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + */ + +/ { + vddcpu_a: regulator-vddcpu-a { + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU_A"; + regulator-min-microvolt = <721000>; + regulator-max-microvolt = <1022000>; + regulator-ramp-delay = <10>; + + vin-supply = <&dc_in>; + + pwms = <&pwm_ab 0 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; + + vddcpu_b: regulator-vddcpu-b { + compatible = "pwm-regulator"; + + regulator-name = "VDDCPU_B"; + regulator-min-microvolt = <721000>; + regulator-max-microvolt = <1022000>; + regulator-ramp-delay = <10>; + + vin-supply = <&dc_in>; + + pwms = <&pwm_AO_cd 1 1250 0>; + pwm-dutycycle-range = <100 0>; + + regulator-boot-on; + regulator-always-on; + }; +}; + +&cpu0 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu1 { + cpu-supply = <&vddcpu_b>; + operating-points-v2 = <&cpu_opp_table_0>; + clocks = <&clkc CLKID_CPU_CLK>; + clock-latency = <50000>; +}; + +&cpu100 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu101 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu102 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&cpu103 { + cpu-supply = <&vddcpu_a>; + operating-points-v2 = <&cpub_opp_table_1>; + clocks = <&clkc CLKID_CPUB_CLK>; + clock-latency = <50000>; +}; + +&pwm_ab { + pinctrl-0 = <&pwm_a_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin0"; + status = "okay"; +}; + +&pwm_AO_cd { + pinctrl-0 = <&pwm_ao_c_6_pins>, <&pwm_ao_d_e_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin1"; + status = "okay"; +}; + diff -Naur a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi --- a/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi 2022-05-27 17:20:14.013880643 +0800 +++ b/arch/arm64/boot/dts/amlogic/meson-g12-common.dtsi 2022-06-18 13:48:23.734525427 +0800 @@ -17,6 +17,12 @@ #address-cells = <2>; #size-cells = <2>; + aliases { + mmc0 = &sd_emmc_c; /* eMMC */ + mmc1 = &sd_emmc_b; /* SD card */ + mmc2 = &sd_emmc_a; /* SDIO */ + }; + chosen { #address-cells = <2>; #size-cells = <2>; @@ -43,6 +49,10 @@ }; }; + system-suspend { + compatible = "amlogic,meson-gx-pm"; + }; + efuse: efuse { compatible = "amlogic,meson-gxbb-efuse"; clocks = <&clkc CLKID_EFUSE>; @@ -55,10 +65,6 @@ gpu_opp_table: gpu-opp-table { compatible = "operating-points-v2"; - opp-124999998 { - opp-hz = /bits/ 64 <124999998>; - opp-microvolt = <800000>; - }; opp-249999996 { opp-hz = /bits/ 64 <249999996>; opp-microvolt = <800000>; @@ -96,15 +102,19 @@ ranges; /* 3 MiB reserved for ARM Trusted Firmware (BL31) */ - secmon_reserved: secmon@5000000 { - reg = <0x0 0x05000000 0x0 0x300000>; - no-map; + secmon_reserved:linux,secmon { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 0x3400000>; + alignment = <0x0 0x400000>; + alloc-ranges = <0x0 0x05000000 0x0 0x3400000>; + clear-map; }; linux,cma { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x10000000>; + size = <0x0 0x38000000>; alignment = <0x0 0x400000>; linux,cma-default; }; @@ -113,6 +123,16 @@ sm: secure-monitor { compatible = "amlogic,meson-gxbb-sm"; }; + + secmon { + compatible = "amlogic, secmon"; + memory-region = <&secmon_reserved>; + in_base_func = <0x82000020>; + out_base_func = <0x82000021>; + inout_size_func = <0x8200002a>; + reserve_mem_size = <0x00300000>; + clear_range = <0x05100000 0x200000>; + }; soc { compatible = "simple-bus"; @@ -224,6 +244,8 @@ "timing-adjustment"; rx-fifo-depth = <4096>; tx-fifo-depth = <2048>; + resets = <&reset RESET_ETHERNET>; + reset-names = "stmmaceth"; status = "disabled"; mdio0: mdio { @@ -1681,12 +1703,31 @@ <666666666>, <0>, /* Do Nothing */ <0>, /* Do Nothing */ - <250000000>, + <500000000>, <0>; /* Do Nothing */ }; + + mipi_analog_dphy: phy { + compatible = "amlogic,g12a-mipi-dphy-analog"; + #phy-cells = <0>; + status = "disabled"; + }; }; }; + mipi_dphy: phy@44000 { + compatible = "amlogic,axg-mipi-dphy"; + reg = <0x0 0x44000 0x0 0x2000>; + clocks = <&clkc CLKID_MIPI_DSI_PHY>; + clock-names = "pclk"; + resets = <&reset RESET_MIPI_DSI_PHY>; + reset-names = "phy"; + phys = <&mipi_analog_dphy>; + phy-names = "analog"; + #phy-cells = <0>; + status = "disabled"; + }; + usb3_pcie_phy: phy@46000 { compatible = "amlogic,g12a-usb3-pcie-phy"; reg = <0x0 0x46000 0x0 0x2000>; @@ -1930,6 +1971,33 @@ }; }; + uart_ao_b_1_pins: uart-ao-b-1 { + mux { + groups = "uart_ao_b_tx_2", + "uart_ao_b_rx_3"; + function = "uart_ao_b"; + bias-disable; + }; + }; + + uart_ao_b_2_pins: uart-ao-b-2 { + mux { + groups = "uart_ao_b_tx_8", + "uart_ao_b_rx_9"; + function = "uart_ao_b"; + bias-disable; + }; + }; + + uart_ao_b_cts_rts_pins: uart-ao-b-cts-rts { + mux { + groups = "uart_ao_b_cts", + "uart_ao_b_rts"; + function = "uart_ao_b"; + bias-disable; + }; + }; + pwm_a_e_pins: pwm-a-e { mux { groups = "pwm_a_e"; @@ -2003,7 +2071,7 @@ }; }; - vrtc: rtc@0a8 { + vrtc: rtc@a8 { compatible = "amlogic,meson-vrtc"; reg = <0x0 0x000a8 0x0 0x4>; }; @@ -2144,6 +2212,15 @@ remote-endpoint = <&hdmi_tx_in>; }; }; + + /* DPI output port */ + dpi_port: port@2 { + reg = <2>; + + dpi_out: endpoint { + remote-endpoint = <&mipi_dsi_in>; + }; + }; }; gic: interrupt-controller@ffc01000 { @@ -2181,6 +2258,49 @@ amlogic,channel-interrupts = <64 65 66 67 68 69 70 71>; }; + mipi_dsi: mipi-dsi@7000 { + compatible = "amlogic,meson-g12a-dw-mipi-dsi"; + reg = <0x0 0x7000 0x0 0x1000>; + resets = <&reset RESET_MIPI_DSI_HOST>; + reset-names = "top"; + clocks = <&clkc CLKID_MIPI_DSI_HOST>, + <&clkc CLKID_MIPI_DSI_PXCLK>; + clock-names = "pclk", "px_clk"; + phys = <&mipi_dphy>; + phy-names = "dphy"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + assigned-clocks = <&clkc CLKID_MIPI_DSI_PXCLK_SEL>; + assigned-clock-parents = <&clkc CLKID_GP0_PLL>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* VPU VENC Input */ + mipi_dsi_venc_port: port@0 { + reg = <0>; + + mipi_dsi_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + /* DSI Output */ + mipi_dsi_panel_port: port@1 { + reg = <1>; + }; + }; + }; + + watchdog: wdt@f0d0 { + compatible = "amlogic,meson-gxbb-wdt"; + reg = <0x0 0xf0d0 0x0 0x10>; + clocks = <&xtal>; + }; + spicc0: spi@13000 { compatible = "amlogic,meson-g12a-spicc"; reg = <0x0 0x13000 0x0 0x44>; @@ -2305,6 +2425,7 @@ clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; clock-names = "xtal", "pclk", "baud"; status = "disabled"; + fifo-size = <128>; }; }; @@ -2400,6 +2521,62 @@ operating-points-v2 = <&gpu_opp_table>; #cooling-cells = <2>; }; + + isp_sc: isp-sc@ff655400 { + compatible = "amlogic, isp-sc"; + reg = <0x0 0xff655400 0x0 0x00001000>; + reg-names = "isp_sc"; + interrupts = <0 17 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "isp_sc"; + }; + + isp: isp@ff140000 { + compatible = "arm, isp"; + reg = <0x0 0xff140000 0x0 0x00040000>; + reg-names = "ISP"; + isp-efuse = <0xff630038 0x4000>; + interrupts = <0 142 4>; + interrupt-names = "ISP"; + temper-buf-size = <24>; + clocks = <&clkc CLKID_MIPI_ISP_CLK_COMP>, + <&clkc CLKID_MIPI_CSI_PHY_CLK0_COMP>; + clock-names = "cts_mipi_isp_clk_composite", + "cts_mipi_csi_phy_clk0_composite"; + link-device = <&isp_sc>; + }; + + adapter: isp-adapter@ff650000 { + compatible = "amlogic, isp-adapter"; + reg = <0x0 0xff650000 0x0 0x00006000>; + reg-names = "adapter"; + interrupts = <0 179 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "adapter-irq"; + mem_alloc = <48>; + }; + + phycsi: phy-csi@ff650000 { + compatible = "amlogic, phy-csi"; + reg = <0x0 0xff650000 0x0 0x00002000>, + <0x0 0xff652000 0x0 0x00002000>, + <0x0 0xff63c300 0x0 0x00000100>, + <0x0 0xff654000 0x0 0x00000100>, + <0x0 0xff654400 0x0 0x00000100>; + reg-names = "csi2_phy0", "csi2_phy1", "aphy_reg", + "csi0_host", "csi1_host"; + interrupts = <0 41 IRQ_TYPE_EDGE_RISING>, + <0 42 IRQ_TYPE_EDGE_RISING>, + <0 72 IRQ_TYPE_EDGE_RISING>, + <0 74 IRQ_TYPE_EDGE_RISING>, + <0 87 IRQ_TYPE_EDGE_RISING>, + <0 88 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "phy0-irq", + "phy1-irq", + "csi-host0-intr2", + "csi-host0-intr1", + "csi-host1-intr2", + "csi-host1-intr1"; + link-device = <&adapter>; + }; }; timer { @@ -2422,4 +2599,10 @@ #clock-cells = <0>; }; + osc8M: osc8M { + compatible = "fixed-clock"; + clock-output-names = "osc8M"; + clock-frequency = <8000000>; + #clock-cells = <0>; + }; }; diff -Naur a/arch/arm64/boot/dts/amlogic/meson-unionpi-tiger.dtsi b/arch/arm64/boot/dts/amlogic/meson-unionpi-tiger.dtsi --- a/arch/arm64/boot/dts/amlogic/meson-unionpi-tiger.dtsi 1970-01-01 08:00:00.000000000 +0800 +++ b/arch/arm64/boot/dts/amlogic/meson-unionpi-tiger.dtsi 2022-06-04 12:16:05.318220487 +0800 @@ -0,0 +1,805 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (c) 2019 Christian Hewitt + */ + +#include +#include +#include +#include +#include +#include +#include + +/ { + aliases { + serial0 = &uart_AO; + serial1 = &uart_AO_B; + serial2 = &uart_A; + i2c0 = &i2c0; + i2c1 = &i2c1; + i2c2 = &i2c2; + i2c3 = &i2c3; + i2c4 = &i2c_AO; + ethernet0 = ðmac; + rtc0 = &rtc; + rtc1 = &vrtc; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0xf0000000>; + }; + + gpio-keys-polled { + compatible = "gpio-keys-polled"; + #address-cells = <1>; + #size-cells = <0>; + poll-interval = <100>; + + power-button { + label = "power"; + linux,code = ; + gpios = <&gpio GPIOC_7 GPIO_ACTIVE_LOW>; + }; + }; + + leds { + compatible = "gpio-leds"; + + /* USB-OTG Switch GPIO */ + usb-switch { + label = "usb_switch"; + gpios = <&gpio GPIOX_7 GPIO_ACTIVE_LOW>; + default-state = "on"; + }; + }; + + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; + }; + + dc_in: regulator-dc_in { + compatible = "regulator-fixed"; + regulator-name = "DC_IN"; + regulator-min-microvolt = <12000000>; + regulator-max-microvolt = <12000000>; + regulator-always-on; + }; + + vcc_5v: regulator-vcc_5v { + compatible = "regulator-fixed"; + regulator-name = "VCC_5V"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&dc_in>; + + /* SY8113B */ + gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; + enable-active-high; + }; + + vsys_3v3: regulator-vsys_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VSYS_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&dc_in>; + regulator-always-on; + }; + + usb_pwr_en: regulator-usb-pwr-en { + compatible = "regulator-fixed"; + regulator-name = "USB_PWR_EN"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_5v>; + enable-active-high; + }; + + usb1_pow: regulator-usb1-pow { + compatible = "regulator-fixed"; + regulator-name = "USB1_POW"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_5v>; + enable-active-high; + }; + + vddao_3v3: regulator-vddao-3v3 { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&dc_in>; + regulator-always-on; + }; + + vddao_1v8: regulator-vddao_1v8 { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + vin-supply = <&vddao_3v3>; + regulator-always-on; + }; + + usb_pwr: regulator-usb_pwr { + compatible = "regulator-fixed"; + regulator-name = "USB_PWR"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + vin-supply = <&vcc_5v>; + enable-active-high; + }; + + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; + status = "okay"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&hdmi_tx_tmds_out>; + }; + }; + }; + + spdif_dit: audio-codec-1 { + #sound-dai-cells = <0>; + compatible = "linux,spdif-dit"; + status = "okay"; + sound-name-prefix = "DIT"; + }; + + sound { + compatible = "amlogic,axg-sound-card"; + model = "UNIONPI-TIGER"; + audio-widgets = "Line", "Lineout", + "Line", "Linein"; + audio-aux-devs = <&tdmout_b>, <&tdmout_c>, + <&tdmin_a>, <&tdmin_b>, <&tdmin_c>, <&tdmin_lb>; + audio-routing = "TDMOUT_B IN 0", "FRDDR_A OUT 1", + "TDMOUT_B IN 1", "FRDDR_B OUT 1", + "TDMOUT_B IN 2", "FRDDR_C OUT 1", + "TDM_B Playback", "TDMOUT_B OUT", + "TDMOUT_C IN 0", "FRDDR_A OUT 2", + "TDMOUT_C IN 1", "FRDDR_B OUT 2", + "TDMOUT_C IN 2", "FRDDR_C OUT 2", + "TDM_C Playback", "TDMOUT_C OUT", + /* for audio capture */ + "TDMIN_A IN 1", "TDM_B Capture", + "TDMIN_B IN 1", "TDM_B Capture", + "TDMIN_C IN 1", "TDM_B Capture", + "TDMIN_A IN 2", "TDM_C Capture", + "TDMIN_B IN 2", "TDM_C Capture", + "TDMIN_C IN 2", "TDM_C Capture", + "TDMIN_A IN 4", "TDM_B Loopback", + "TDMIN_B IN 4", "TDM_B Loopback", + "TDMIN_C IN 4", "TDM_B Loopback", + "TDMIN_A IN 5", "TDM_C Loopback", + "TDMIN_B IN 5", "TDM_C Loopback", + "TDMIN_C IN 5", "TDM_C Loopback", + "TDMIN_LB IN 1", "TDM_B Capture", + "TDMIN_LB IN 2", "TDM_C Capture", + "TDMIN_LB IN 4", "TDM_B Loopback", + "TDMIN_LB IN 5", "TDM_C Loopback", + /* tdmin -> toddr */ + "TODDR_A IN 0", "TDMIN_A OUT", + "TODDR_B IN 0", "TDMIN_A OUT", + "TODDR_C IN 0", "TDMIN_A OUT", + "TODDR_A IN 1", "TDMIN_B OUT", + "TODDR_B IN 1", "TDMIN_B OUT", + "TODDR_C IN 1", "TDMIN_B OUT", + "TODDR_A IN 2", "TDMIN_C OUT", + "TODDR_B IN 2", "TDMIN_C OUT", + "TODDR_C IN 2", "TDMIN_C OUT", + "TODDR_A IN 6", "TDMIN_LB OUT", + "TODDR_B IN 6", "TDMIN_LB OUT", + "TODDR_C IN 6", "TDMIN_LB OUT", + "Linein MIC1", "Linein", + "TDM_B Capture", "Linein AIFTX"; + + assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; + assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + status = "okay"; + + dai-link-0 { + sound-dai = <&frddr_a>; + }; + + dai-link-1 { + sound-dai = <&frddr_b>; + }; + + dai-link-2 { + sound-dai = <&frddr_c>; + }; + + dai-link-3 { + sound-dai = <&toddr_a>; + }; + + dai-link-4 { + sound-dai = <&toddr_b>; + }; + + dai-link-5 { + sound-dai = <&toddr_c>; + }; + + /* 8ch hdmi interface */ + dai-link-6 { + sound-dai = <&tdmif_b>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + dai-tdm-slot-rx-mask-1 = <1 1>; + dai-tdm-slot-tx-mask-2 = <1 1>; + dai-tdm-slot-tx-mask-3 = <1 1>; + mclk-fs = <256>; + + codec-0 { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_B>; + }; + + codec-1 { + sound-dai = <&toacodec TOACODEC_IN_B>; + }; + + /* audio capture */ + codec-2 { + sound-dai = <&nau8540>; + }; + }; + + /* i2s jack output interface */ + dai-link-7 { + sound-dai = <&tdmif_c>; + dai-format = "i2s"; + dai-tdm-slot-tx-mask-0 = <1 1>; + mclk-fs = <256>; + + codec-0 { + sound-dai = <&tohdmitx TOHDMITX_I2S_IN_C>; + }; + + codec-1 { + sound-dai = <&toacodec TOACODEC_IN_C>; + }; + }; + + /* hdmi glue */ + dai-link-8 { + sound-dai = <&tohdmitx TOHDMITX_I2S_OUT>; + + codec { + sound-dai = <&hdmi_tx>; + }; + }; + + /* acodec glue */ + dai-link-9 { + sound-dai = <&toacodec TOACODEC_OUT>; + + codec { + sound-dai = <&acodec>; + }; + }; + }; +}; + +&pdm { + status = "okay"; +}; + +&acodec { + AVDD-supply = <&vddao_1v8>; + status = "okay"; +}; + +&arb { + status = "okay"; +}; + +&clkc_audio { + status = "okay"; +}; + +&cec_AO { + pinctrl-0 = <&cec_ao_a_h_pins>; + pinctrl-names = "default"; + status = "disabled"; + hdmi-phandle = <&hdmi_tx>; +}; + +&cecb_AO { + pinctrl-0 = <&cec_ao_b_h_pins>; + pinctrl-names = "default"; + status = "okay"; + hdmi-phandle = <&hdmi_tx>; +}; + +&ext_mdio { + external_phy: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; + max-speed = <1000>; + reset-assert-us = <10000>; + reset-deassert-us = <80000>; + reset-gpios = <&gpio GPIOZ_15 (GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN)>; + + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_14 */ + interrupts = <26 IRQ_TYPE_LEVEL_LOW>; + }; +}; + +ðmac { + pinctrl-0 = <ð_pins>, <ð_rgmii_pins>; + pinctrl-names = "default"; + status = "okay"; + phy-mode = "rgmii"; + phy-handle = <&external_phy>; + amlogic,tx-delay-ns = <2>; +}; + +&frddr_a { + status = "okay"; +}; + +&frddr_b { + status = "okay"; +}; + +&frddr_c { + status = "okay"; +}; + +&hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; + pinctrl-names = "default"; + hdmi-supply = <&vcc_5v>; +}; + +&hdmi_tx_tmds_port { + hdmi_tx_tmds_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; +}; + +&mipi_dsi { + status = "okay"; + + assigned-clocks = <&clkc CLKID_GP0_PLL>, + <&clkc CLKID_MIPI_DSI_PXCLK_SEL>, + <&clkc CLKID_MIPI_DSI_PXCLK>; + assigned-clock-parents = <0>, + <&clkc CLKID_GP0_PLL>, + <0>; + assigned-clock-rates = <720000000>, + <0>, + <720000000>; + + panel@0 { + status = "okay"; + compatible = "chipone,icn6211"; + power-supply = <&vddao_3v3>; + /*compatible = "waveshare,tl070hdv03ct"; + power-supply = <&vcc_5v>;*/ + reg = <0>; + + port { + dsi_in_panel: endpoint { + remote-endpoint = <&dsi_out_panel>; + }; + }; + }; +}; + +&mipi_analog_dphy { + status = "okay"; +}; + +&mipi_dphy { + status = "okay"; +}; + +&mipi_dsi_panel_port { + dsi_out_panel: endpoint { + remote-endpoint = <&dsi_in_panel>; + }; +}; + +&i2c2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c2_sck_x_pins>, <&i2c2_sda_x_pins>; + clock-frequency = <100000>; /* default 100k */ +}; + +&i2c3 { + status = "okay"; + pinctrl-names="default"; + pinctrl-0 = <&i2c3_sck_a_pins>, <&i2c3_sda_a_pins>; + clock-frequency = <100000>; /* default 100k */ + + i2cmux@71 { + compatible = "nxp,pca9546"; + reg = <0x71>; + status = "okay"; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + + /*i2c and gpio_extension*/ + i2c3a: i2c3@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + status = "okay"; + }; + + i2c3b: i2c3@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + status = "okay"; + }; + + i2c3c: i2c3@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + + pca9575b: gpio@21 { + compatible = "nxp,pca9575"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <0x02>; + status = "okay"; + gpio-line-names = "WAKEUP_OUT", "PWR_ON_N", "WAKEUP_IN", "W_DISABLE_N", + "PMU_RSTIN_N", "9342_RST", "SEN-SYNC1", "", "MUTE", + "WIFI_LED", "CM_GPIO_1", "", "AMP_PWRDN", "POWER_LED", + "GPIO_18", "GPIO_17"; + }; + + pca9575a: gpio@23 { + compatible = "nxp,pca9575"; + reg = <0x23>; + gpio-controller; + #gpio-cells = <0x02>; + status = "okay"; + gpio-line-names = "GPIO_01", "GPIO_02", "GPIO_03", "GPIO_04", + "GPIO_05", "GPIO_06", "GPIO_07", "GPIO_08", "GPIO_09", + "GPIO_10", "GPIO_11", "GPIO_12", "GPIO_13", "GPIO_14", + "GPIO_15", "GPIO_16"; + }; + + es7243: es7243@11 { + compatible = "everest,es7243"; + #sound-dai-cells = <0>; + reg = <0x11>; + status = "okay"; + }; + + nau8540: nau8540@1c { + compatible = "nuvoton,nau8540"; + #sound-dai-cells = <0>; + reg = <0x1c>; + sound-name-prefix = "Linein"; + status = "okay"; + }; + + tlv320dac3101: tlv320dac3101@18 { + compatible = "ti,tlv320dac3101"; + #sound-dai-cells = <0>; + reg = <0x18>; + slot_number = <3>; + differential_pair = <1>; + status = "okay"; + }; + + ft5406: ft5406@38 { + compatible = "edt,edt-ft5406"; + reg = <0x38>; + touchscreen-size-x = < 800 >; + touchscreen-size-y = < 480 >; + touchscreen-inverted-x = < 1 >; + touchscreen-inverted-y = < 1 >; + status = "okay"; + }; + + icn6211: icn6211@45 { + compatible = "chipone,icn6211-i2c"; + status = "okay"; + reg = <0x45>; + }; + + sensor-i2c@6c { + compatible = "arm, i2c-sensor"; + reg = <0x6c>; + reg-names = "i2c-sensor"; + slave-addr = <0x6c>; + reg-type = <2>; + reg-data-type = <1>; + link-device = <&phycsi>; + }; + }; + + /*icm-20948*/ + i2c3d: i2c3@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + status = "okay"; + }; + }; +}; + +&i2c_AO { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2c_ao_sck_pins>, <&i2c_ao_sda_pins>; + clock-frequency = <400000>; + + rtc: rtc@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + status = "okay"; + wakeup-source; + }; +}; + +&pwm_ab { + status = "okay"; +}; + +&pwm_AO_ab { + status = "okay"; + pinctrl-0 = <&pwm_ao_a_pins>; + pinctrl-names = "default"; + clocks = <&xtal>; + clock-names = "clkin0"; +}; + +&saradc { + status = "okay"; + vref-supply = <&vddao_1v8>; +}; + +/* eMMC */ +&sd_emmc_c { + status = "okay"; + compatible = "amlogic,meson-axg-mmc"; + pinctrl-0 = <&emmc_ctrl_pins>, <&emmc_data_8b_pins>, <&emmc_ds_pins>; + pinctrl-1 = <&emmc_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + + bus-width = <8>; + cap-mmc-highspeed; + mmc-ddr-1_8v; + mmc-hs200-1_8v; + max-frequency = <200000000>; + disable-wp; + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddao_1v8>; +}; + +/* SD card */ +&sd_emmc_b { + status = "okay"; + compatible = "amlogic,meson-axg-mmc"; + pinctrl-0 = <&sdcard_c_pins>; + pinctrl-1 = <&sdcard_clk_gate_c_pins>; + pinctrl-names = "default", "clk-gate"; + + bus-width = <4>; + cap-sd-highspeed; + max-frequency = <50000000>; + disable-wp; + + cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddao_3v3>; +}; + +/* SDIO */ +&sd_emmc_a { + status = "okay"; + pinctrl-0 = <&sdio_pins>; + pinctrl-1 = <&sdio_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + #address-cells = <1>; + #size-cells = <0>; + + bus-width = <4>; + cap-sd-highspeed; + sd-uhs-sdr104; + max-frequency = <167000000>; + + non-removable; + disable-wp; + + /* WiFi firmware requires power to be kept while in suspend */ + keep-power-in-suspend; + + mmc-pwrseq = <&sdio_pwrseq>; + + vmmc-supply = <&vddao_3v3>; + vqmmc-supply = <&vddao_1v8>; +}; + +&tdmif_a { + status = "okay"; +}; + +&tdmif_b { + pinctrl-0 = <&tdm_b_sclk_pins>, <&tdm_b_fs_pins>, + <&tdm_b_din0_pins>, <&tdm_b_din1_pins>, <&mclk0_a_pins>; + pinctrl-names = "default"; + + assigned-clocks = <&clkc_audio AUD_CLKID_TDM_MCLK_PAD0>, + <&clkc_audio AUD_CLKID_TDM_SCLK_PAD1>, + <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD1>; + assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_B_MCLK>, + <&clkc_audio AUD_CLKID_MST_B_SCLK>, + <&clkc_audio AUD_CLKID_MST_B_LRCLK>; + assigned-clock-rates = <0>, <0>, <0>; + + status = "okay"; +}; + +&tdmif_c { + status = "okay"; +}; + +&tdmin_a { + status = "okay"; +}; + +&tdmin_b { + status = "okay"; +}; + +&tdmin_lb { + status = "okay"; +}; + +&tdmin_c { + status = "okay"; +}; + +&tdmout_a { + status = "okay"; +}; + +&tdmout_b { + status = "okay"; +}; + +&tdmout_c { + status = "okay"; +}; + +&toacodec { + status = "okay"; +}; + +&tohdmitx { + status = "okay"; +}; + +&toddr_a { + status = "okay"; +}; + +&toddr_b { + status = "okay"; +}; + +&toddr_c { + status = "okay"; +}; + +&uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; + xtal_tick_en = <2>; +}; + +&uart_AO_B { + status = "okay"; + pinctrl-0 = <&uart_ao_b_2_pins>; + pinctrl-names = "default"; +}; + +/* BT UART */ +&uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>; + pinctrl-names = "default"; +}; + +&dwc2 { + status = "okay"; +}; + +&dwc3 { + status = "okay"; +}; + +&usb2_phy0 { + status = "okay"; + phy-supply = <&usb1_pow>; +}; + +&usb2_phy1 { + status = "okay"; + phy-supply = <&usb1_pow>; +}; + +&usb3_pcie_phy { + status = "okay"; + phy-supply = <&usb_pwr>; +}; + +&usb { + status = "okay"; + dr_mode = "host"; + vbus-supply = <&usb_pwr_en>; +}; + +&spicc0 { + status = "okay"; + pinctrl-names = "default","gpio_periphs"; + pinctrl-0 = <&spicc0_x_pins>; + pinctrl-1 = <&spicc0_ss0_x_pins>; + num_chipselect = <1>; + cs-gpios = <&gpio GPIOX_10 GPIO_ACTIVE_LOW>; + + spidev@0 { + status = "okay"; + compatible = "rohm,dh2228fv"; + reg = <0>; + spi-max-frequency = <10000000>; + }; +}; + +&spicc1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&spicc1_pins>; + num_chipselect = <1>; + cs-gpios = <&gpio GPIOH_6 GPIO_ACTIVE_LOW>; + + spidev@0 { + status = "okay"; + compatible = "microchip,mcp2515"; + reg = <0>; + clocks = <&osc8M>; + spi-max-frequency = <5000000>; + interrupt-parent = <&gpio_intc>; + interrupts = <66 IRQ_TYPE_LEVEL_LOW>; + }; +}; diff -Naur a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile --- a/arch/arm64/boot/dts/Makefile 2022-05-27 17:20:14.009880591 +0800 +++ b/arch/arm64/boot/dts/Makefile 2022-05-31 11:56:47.697259643 +0800 @@ -30,3 +30,5 @@ subdir-y += toshiba subdir-y += xilinx subdir-y += zte +dtbs: $(addprefix $(obj)/, $(DTB_LIST)) +clean-files := dts/*.dtb *.dtb diff -Naur a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile --- a/arch/arm64/boot/Makefile 2022-05-27 17:20:14.009880591 +0800 +++ b/arch/arm64/boot/Makefile 2022-05-31 11:56:47.697259643 +0800 @@ -16,7 +16,20 @@ OBJCOPYFLAGS_Image :=-O binary -R .note -R .note.gnu.build-id -R .comment -S -targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo +targets := Image Image.bz2 Image.gz Image.lz4 Image.lzma Image.lzo Image.gz-dtb + +dtstree := $(srctree)/$(src)/dts + +dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(foreach d,$(dts-dirs), $(wildcard $(dtstree)/$(d)/*.dts))) + +DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE_NAMES)) +ifneq ($(DTB_NAMES),) +DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) +else +DTB_LIST := $(dtb-y) +endif + +DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST)) $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) @@ -24,6 +37,9 @@ $(obj)/Image.bz2: $(obj)/Image FORCE $(call if_changed,bzip2) +$(obj)/Image-dtb: $(obj)/Image $(DTB_OBJS) FORCE + $(call if_changed,cat) + $(obj)/Image.gz: $(obj)/Image FORCE $(call if_changed,gzip) @@ -36,10 +52,35 @@ $(obj)/Image.lzo: $(obj)/Image FORCE $(call if_changed,lzo) -install: +$(obj)/Image.gz-dtb: $(obj)/Image.gz $(DTB_OBJS) FORCE + $(call if_changed,cat) + +UIMAGE_LOADADDR=$(TEXT_OFFSET) +UIMAGE_ENTRYADDR=$(TEXT_OFFSET) +#UIMAGE_COMPRESSION = gzip +check_for_multiple_loadaddr = \ +if [ $(words $(UIMAGE_LOADADDR)) -ne 1 ]; then \ + echo 'multiple (or no) load addresses: $(UIMAGE_LOADADDR)'; \ + echo 'This is incompatible with uImages'; \ + echo 'Specify LOADADDR on the commandline to build an uImage'; \ + false; \ +fi + +rm_uimage: + @rm -f $(obj)/uImage + +$(obj)/uImage: $(obj)/Image rm_uimage FORCE + @$(check_for_multiple_loadaddr) + @dd if=$< of=$<.dd ibs=4096 conv=sync && mv $<.dd $< + $(call if_changed,uimage) + $(if $(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE),@$(kecho) ' CAT $(DTB_OBJS) to $@') + $(if $(CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE),@cat $(DTB_OBJS) >>$@,) + @$(kecho) ' Image $@ is ready' + +install:$(obj)/uImage $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ $(obj)/Image System.map "$(INSTALL_PATH)" -zinstall: +zinstall:$(obj)/uImage $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ $(obj)/Image.gz System.map "$(INSTALL_PATH)" diff -Naur a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h --- a/arch/arm64/include/asm/kernel-pgtable.h 2022-05-27 17:20:14.061881262 +0800 +++ b/arch/arm64/include/asm/kernel-pgtable.h 2022-05-31 11:56:47.705259573 +0800 @@ -86,7 +86,7 @@ + EARLY_PGDS((vstart), (vend)) /* each PGDIR needs a next level page table */ \ + EARLY_PUDS((vstart), (vend)) /* each PUD needs a next level page table */ \ + EARLY_PMDS((vstart), (vend))) /* each PMD needs a next level page table */ -#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end)) +#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR + TEXT_OFFSET, _end)) #define IDMAP_DIR_SIZE (IDMAP_PGTABLE_LEVELS * PAGE_SIZE) /* Initial memory map size */ diff -Naur a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S --- a/arch/arm64/kernel/head.S 2022-05-27 17:20:14.065881314 +0800 +++ b/arch/arm64/kernel/head.S 2022-05-31 11:56:47.705259573 +0800 @@ -36,10 +36,14 @@ #include "efi-header.S" -#define __PHYS_OFFSET KERNEL_START +#define __PHYS_OFFSET (KERNEL_START - TEXT_OFFSET) -#if (PAGE_OFFSET & 0x1fffff) != 0 +#if (TEXT_OFFSET & 0xfff) != 0 +#error TEXT_OFFSET must be at least 4KB aligned +#elif (PAGE_OFFSET & 0x1fffff) != 0 #error PAGE_OFFSET must be at least 2MB aligned +#elif TEXT_OFFSET > 0x1fffff +//#error TEXT_OFFSET must be less than 2MB #endif /* @@ -73,7 +77,7 @@ b primary_entry // branch to kernel start, magic .long 0 // reserved #endif - .quad 0 // Image load offset from start of RAM, little-endian + le64sym _kernel_offset_le // Image load offset from start of RAM, little-endian le64sym _kernel_size_le // Effective size of kernel image, little-endian le64sym _kernel_flags_le // Informative flags, little-endian .quad 0 // reserved @@ -379,7 +383,7 @@ * Map the kernel image (starting with PHYS_OFFSET). */ adrp x0, init_pg_dir - mov_q x5, KIMAGE_VADDR // compile time __va(_text) + mov_q x5, KIMAGE_VADDR + TEXT_OFFSET // compile time __va(_text) add x5, x5, x23 // add KASLR displacement mov x4, PTRS_PER_PGD adrp x6, _end // runtime __pa(_end) @@ -471,7 +475,7 @@ .pushsection ".rodata", "a" SYM_DATA_START(kimage_vaddr) - .quad _text + .quad _text - TEXT_OFFSET SYM_DATA_END(kimage_vaddr) EXPORT_SYMBOL(kimage_vaddr) .popsection diff -Naur a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h --- a/arch/arm64/kernel/image.h 2022-05-27 17:20:14.069881366 +0800 +++ b/arch/arm64/kernel/image.h 2022-05-31 11:56:47.705259573 +0800 @@ -62,6 +62,7 @@ */ #define HEAD_SYMBOLS \ DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text); \ + DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET); \ DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS); #endif /* __ARM64_KERNEL_IMAGE_H */ diff -Naur a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile --- a/arch/arm64/kernel/Makefile 2022-05-27 17:20:14.065881314 +0800 +++ b/arch/arm64/kernel/Makefile 2022-05-31 11:56:47.705259573 +0800 @@ -3,6 +3,8 @@ # Makefile for the linux kernel. # +CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) +AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) CFLAGS_armv8_deprecated.o := -I$(src) CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) diff -Naur a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S --- a/arch/arm64/kernel/vmlinux.lds.S 2022-05-27 17:20:14.073881416 +0800 +++ b/arch/arm64/kernel/vmlinux.lds.S 2022-05-31 11:56:47.705259573 +0800 @@ -115,7 +115,7 @@ *(.dynsym .dynstr .hash .gnu.hash) } - . = KIMAGE_VADDR; + . = KIMAGE_VADDR + TEXT_OFFSET; .head.text : { _text = .; @@ -305,4 +305,4 @@ /* * If padding is applied before .head.text, virt<->phys conversions will fail. */ -ASSERT(_text == KIMAGE_VADDR, "HEAD is misaligned") +ASSERT(_text == (KIMAGE_VADDR + TEXT_OFFSET), "HEAD is misaligned") diff -Naur a/arch/arm64/Makefile b/arch/arm64/Makefile --- a/arch/arm64/Makefile 2022-05-27 17:20:14.009880591 +0800 +++ b/arch/arm64/Makefile 2022-05-31 11:56:47.705259573 +0800 @@ -11,6 +11,9 @@ # Copyright (C) 1995-2001 by Russell King LDFLAGS_vmlinux :=--no-undefined -X +CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) + +OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S ifeq ($(CONFIG_RELOCATABLE), y) # Pass --no-apply-dynamic-relocs to restore pre-binutils-2.27 behaviour @@ -96,6 +99,11 @@ asm-arch := armv8.4-a endif +ifeq ($(CONFIG_AS_HAS_ARMV8_5), y) +# make sure to pass the newest target architecture to -march. +asm-arch := armv8.5-a +endif + ifdef asm-arch KBUILD_CFLAGS += -Wa,-march=$(asm-arch) \ -DARM64_ASM_ARCH='"$(asm-arch)"' @@ -134,6 +142,9 @@ # Default value head-y := arch/arm64/kernel/head.o +# The byte offset of the kernel image in RAM from the start of RAM. +TEXT_OFFSET := 0x01080000 + ifeq ($(CONFIG_KASAN_SW_TAGS), y) KASAN_SHADOW_SCALE_SHIFT := 4 else @@ -144,13 +155,15 @@ KBUILD_CPPFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) KBUILD_AFLAGS += -DKASAN_SHADOW_SCALE_SHIFT=$(KASAN_SHADOW_SCALE_SHIFT) +export TEXT_OFFSET + core-y += arch/arm64/ libs-y := arch/arm64/lib/ $(libs-y) libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a # Default target when executing plain make boot := arch/arm64/boot -KBUILD_IMAGE := $(boot)/Image.gz +KBUILD_IMAGE := $(boot)/Image all: Image.gz diff -Naur a/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c b/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c --- a/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c 2022-06-30 21:35:01.784330920 +0800 +++ b/arch/powerpc/platforms/85xx/mpc85xx_pm_ops.c 2022-05-27 17:20:14.357885080 +0800 @@ -94,8 +94,9 @@ pr_err("Could not map guts node address\n"); return -ENOMEM; } - qoriq_pm_ops = &mpc85xx_pm_ops; } + qoriq_pm_ops = &mpc85xx_pm_ops; + return 0; } diff -Naur a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h --- a/arch/x86/include/asm/page_64_types.h 2022-06-30 21:35:01.784330920 +0800 +++ b/arch/x86/include/asm/page_64_types.h 2022-05-27 17:20:14.513887093 +0800 @@ -15,7 +15,7 @@ #define THREAD_SIZE_ORDER (2 + KASAN_STACK_ORDER) #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) -#define EXCEPTION_STACK_ORDER (1 + KASAN_STACK_ORDER) +#define EXCEPTION_STACK_ORDER (0 + KASAN_STACK_ORDER) #define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER) #define IRQ_STACK_ORDER (2 + KASAN_STACK_ORDER) diff -Naur a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c --- a/arch/x86/kernel/cpu/bugs.c 2022-07-04 18:32:52.121159105 +0800 +++ b/arch/x86/kernel/cpu/bugs.c 2022-05-27 17:20:14.525887248 +0800 @@ -1091,7 +1091,6 @@ #define MDS_MSG_SMT "MDS CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html for more details.\n" #define TAA_MSG_SMT "TAA CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/tsx_async_abort.html for more details.\n" -#define MMIO_MSG_SMT "MMIO Stale Data CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/processor_mmio_stale_data.html for more details.\n" void cpu_bugs_smt_update(void) { @@ -1136,16 +1135,6 @@ break; } - switch (mmio_mitigation) { - case MMIO_MITIGATION_VERW: - case MMIO_MITIGATION_UCODE_NEEDED: - if (sched_smt_active()) - pr_warn_once(MMIO_MSG_SMT); - break; - case MMIO_MITIGATION_OFF: - break; - } - mutex_unlock(&spec_ctrl_mutex); } diff -Naur a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c --- a/arch/x86/kvm/hyperv.c 2022-07-04 18:32:52.121159105 +0800 +++ b/arch/x86/kvm/hyperv.c 2022-05-27 17:20:14.541887454 +0800 @@ -207,7 +207,7 @@ struct kvm_vcpu *vcpu = synic_to_vcpu(synic); int ret; - if (!synic->active && (!host || data)) + if (!synic->active && !host) return 1; trace_kvm_hv_synic_set_msr(vcpu->vcpu_id, msr, data, host); @@ -253,9 +253,6 @@ case HV_X64_MSR_EOM: { int i; - if (!synic->active) - break; - for (i = 0; i < ARRAY_SIZE(synic->sint); i++) kvm_hv_notify_acked_sint(vcpu, i); break; @@ -639,7 +636,7 @@ struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); - if (!synic->active && (!host || config)) + if (!synic->active && !host) return 1; trace_kvm_hv_stimer_set_config(stimer_to_vcpu(stimer)->vcpu_id, @@ -663,7 +660,7 @@ struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer); struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu); - if (!synic->active && (!host || count)) + if (!synic->active && !host) return 1; trace_kvm_hv_stimer_set_count(stimer_to_vcpu(stimer)->vcpu_id, diff -Naur a/drivers/clk/meson/clk-mux.c b/drivers/clk/meson/clk-mux.c --- a/drivers/clk/meson/clk-mux.c 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/clk/meson/clk-mux.c 2022-05-31 11:56:47.725259396 +0800 @@ -0,0 +1,214 @@ +/* + * drivers/amlogic/clk/clk-mux.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-mux.h" + + +#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) + +static inline u32 clk_mux_readl(struct clk_mux *mux) +{ + if (mux->flags & CLK_MUX_BIG_ENDIAN) + return ioread32be(mux->reg); + + return readl(mux->reg); +} + +static inline void clk_mux_writel(struct clk_mux *mux, u32 val) +{ + if (mux->flags & CLK_MUX_BIG_ENDIAN) + iowrite32be(val, mux->reg); + else + writel(val, mux->reg); +} + + +static u8 meson_clk_mux_get_parent(struct clk_hw *hw) +{ + struct clk_mux *mux = to_clk_mux(hw); + int num_parents = clk_hw_get_num_parents(hw); + u32 val; + + /* + * FIXME need a mux-specific flag to determine if val is bitwise or + * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges + * from 0x1 to 0x7 (index starts at one) + * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so + * val = 0x4 really means "bit 2, index starts at bit 0" + */ + val = clk_mux_readl(mux) >> mux->shift; + val &= mux->mask; + + if (mux->table) { + int i; + + for (i = 0; i < num_parents; i++) + if (mux->table[i] == val) + return i; + return -EINVAL; + } + + if (val && (mux->flags & CLK_MUX_INDEX_BIT)) + val = ffs(val) - 1; + + if (val && (mux->flags & CLK_MUX_INDEX_ONE)) + val--; + + if (val >= num_parents) + return -EINVAL; + + return val; +} + +static int meson_clk_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_mux *mux = to_clk_mux(hw); + u32 val; + unsigned long flags = 0; + + if (mux->table) { + index = mux->table[index]; + } else { + if (mux->flags & CLK_MUX_INDEX_BIT) + index = (1 << ffs(index)); + + if (mux->flags & CLK_MUX_INDEX_ONE) + index++; + } + + if (mux->lock) + spin_lock_irqsave(mux->lock, flags); + else + __acquire(mux->lock); + + if (mux->flags & CLK_MUX_HIWORD_MASK) { + val = mux->mask << (mux->shift + 16); + } else { + val = clk_mux_readl(mux); + val &= ~(mux->mask << mux->shift); + } + + val |= index << mux->shift; + clk_mux_writel(mux, val); + + if (mux->lock) + spin_unlock_irqrestore(mux->lock, flags); + else + __release(mux->lock); + + return 0; +} + +static unsigned long meson_clk_mux_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_hw *parent_hw; + u32 index = 0; + unsigned long new_parent_rate; + + index = meson_clk_mux_get_parent(hw); + + parent_hw = clk_hw_get_parent_by_index(hw, index); + new_parent_rate = clk_hw_get_rate(parent_hw); + if (new_parent_rate != parent_rate) + clk_set_parent(hw->clk, parent_hw->clk); + + return new_parent_rate; +} + +int meson_clk_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_hw *parent, *best_parent = NULL; + int i, num_parents, ret; + unsigned long best = 0; + struct clk_rate_request parent_req = *req; + struct clk_mux *mux = to_clk_mux(hw); + + num_parents = clk_hw_get_num_parents(hw); + + if ((num_parents == 2) && (mux->flags == CLK_PARENT_ALTERNATE)) { + i = meson_clk_mux_get_parent(hw); + i = (i + 1) % 2; + + best_parent = clk_hw_get_parent_by_index(hw, i); + best = clk_hw_get_rate(best_parent); + if (best != parent_req.rate) { + ret = clk_set_rate(best_parent->clk, parent_req.rate); + if (ret) + pr_err("Fail! Can not set to %lu, cur rate: %lu\n", + parent_req.rate, best); + else { + best = clk_hw_get_rate(best_parent); + pr_debug("success set parent %s rate to %lu\n", + clk_hw_get_name(best_parent), best); + if (!(clk_hw_get_flags(hw) & + CLK_SET_RATE_UNGATE)) { + clk_prepare(best_parent->clk); + clk_enable(best_parent->clk); + } + } + } + } else { + for (i = 0; i < num_parents; i++) { + parent = clk_hw_get_parent_by_index(hw, i); + if (!parent) + continue; + + if (mux->flags & CLK_SET_RATE_PARENT) { + parent_req = *req; + ret = __clk_determine_rate(parent, &parent_req); + if (ret) + continue; + } else { + parent_req.rate = clk_hw_get_rate(parent); + } + } + } + + if (!best_parent) + return -EINVAL; + + if (best_parent) + req->best_parent_hw = best_parent; + + req->best_parent_rate = best; + req->rate = best; + + return 0; +} + +const struct clk_ops meson_clk_mux_ops = { + .get_parent = meson_clk_mux_get_parent, + .set_parent = meson_clk_mux_set_parent, + .determine_rate = meson_clk_mux_determine_rate, + .recalc_rate = meson_clk_mux_recalc_rate, +}; + +const struct clk_ops meson_clk_mux_ro_ops = { + .get_parent = meson_clk_mux_get_parent, +}; diff -Naur a/drivers/clk/meson/clk-mux.h b/drivers/clk/meson/clk-mux.h --- a/drivers/clk/meson/clk-mux.h 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/clk/meson/clk-mux.h 2022-05-31 11:56:47.725259396 +0800 @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_CLK_MUX_H +#define __MESON_CLK_MUX_H + +#include +#include +#include "parm.h" + +#define CLK_PARENT_ALTERNATE BIT(5) + +extern const struct clk_ops meson_clk_mux_ops; + + +#endif /* __MESON_CLK_MUX_H */ diff -Naur a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c --- a/drivers/clk/meson/clk-pll.c 2022-05-27 17:20:14.749890137 +0800 +++ b/drivers/clk/meson/clk-pll.c 2022-05-31 11:56:47.725259396 +0800 @@ -283,6 +283,8 @@ delay--; } while (delay > 0); + pr_warn("%s: pll %s did not lock\n", __func__, clk_hw_get_name(hw)); + return -ETIMEDOUT; } @@ -339,6 +341,9 @@ /* Enable the pll */ meson_parm_write(clk->map, &pll->en, 1); + /* Reset delay */ + udelay(pll->rst_delay_us); + /* Take the pll out reset */ meson_parm_write(clk->map, &pll->rst, 0); diff -Naur a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h --- a/drivers/clk/meson/clk-pll.h 2022-05-27 17:20:14.749890137 +0800 +++ b/drivers/clk/meson/clk-pll.h 2022-05-31 11:56:47.725259396 +0800 @@ -41,6 +41,7 @@ const struct pll_params_table *table; const struct pll_mult_range *range; u8 flags; + u32 rst_delay_us; }; extern const struct clk_ops meson_clk_pll_ro_ops; diff -Naur a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c --- a/drivers/clk/meson/g12a.c 2022-05-27 17:20:14.749890137 +0800 +++ b/drivers/clk/meson/g12a.c 2022-05-31 11:56:47.725259396 +0800 @@ -15,6 +15,7 @@ #include #include #include +#include #include "clk-mpll.h" #include "clk-pll.h" @@ -23,8 +24,9 @@ #include "vid-pll-div.h" #include "meson-eeclk.h" #include "g12a.h" +#include "g12a-vcodec-clk.h" -static DEFINE_SPINLOCK(meson_clk_lock); +/*static*/ DEFINE_SPINLOCK(meson_clk_lock); static struct clk_regmap g12a_fixed_pll_dco = { .data = &(struct meson_clk_pll_data){ @@ -1602,20 +1604,21 @@ }; static const struct pll_mult_range g12a_gp0_pll_mult_range = { - .min = 125, - .max = 255, + .min = 132, /* Force M to 132 */ + .max = 132, }; /* * Internal gp0 pll emulation configuration parameters */ static const struct reg_sequence g12a_gp0_init_regs[] = { + { .reg = HHI_GP0_PLL_CNTL0, .def = 0x08000000 }, { .reg = HHI_GP0_PLL_CNTL1, .def = 0x00000000 }, { .reg = HHI_GP0_PLL_CNTL2, .def = 0x00000000 }, - { .reg = HHI_GP0_PLL_CNTL3, .def = 0x48681c00 }, - { .reg = HHI_GP0_PLL_CNTL4, .def = 0x33771290 }, + { .reg = HHI_GP0_PLL_CNTL3, .def = 0x6a285c00}, + { .reg = HHI_GP0_PLL_CNTL4, .def = 0x65771290}, { .reg = HHI_GP0_PLL_CNTL5, .def = 0x39272000 }, - { .reg = HHI_GP0_PLL_CNTL6, .def = 0x56540000 }, + { .reg = HHI_GP0_PLL_CNTL6, .def = 0x56540000, .delay_us = 10 }, }; static struct clk_regmap g12a_gp0_pll_dco = { @@ -1653,6 +1656,7 @@ .range = &g12a_gp0_pll_mult_range, .init_regs = g12a_gp0_init_regs, .init_count = ARRAY_SIZE(g12a_gp0_init_regs), + .rst_delay_us = 100, }, .hw.init = &(struct clk_init_data){ .name = "gp0_pll_dco", @@ -3657,6 +3661,86 @@ }, }; +/* MIPI DSI Host Clocks */ + +static const struct clk_hw *g12a_mipi_dsi_pxclk_parent_hws[] = { + &g12a_vid_pll.hw, + &g12a_gp0_pll.hw, + &g12a_hifi_pll.hw, + &g12a_mpll1.hw, + &g12a_fclk_div2.hw, + &g12a_fclk_div2p5.hw, + &g12a_fclk_div3.hw, + &g12a_fclk_div7.hw, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk_sel = { + .data = &(struct clk_regmap_mux_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .mask = 0x7, + .shift = 12, + .flags = CLK_MUX_ROUND_CLOSEST, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_dsi_pxclk_sel", + .ops = &clk_regmap_mux_ops, + .parent_hws = g12a_mipi_dsi_pxclk_parent_hws, + .num_parents = ARRAY_SIZE(g12a_mipi_dsi_pxclk_parent_hws), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk_div = { + .data = &(struct clk_regmap_div_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .shift = 0, + .width = 7, + }, + .hw.init = &(struct clk_init_data){ + .name = "mipi_dsi_pxclk_div", + .ops = &clk_regmap_divider_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mipi_dsi_pxclk_sel.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap g12a_mipi_dsi_pxclk = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_MIPIDSI_PHY_CLK_CNTL, + .bit_idx = 8, + }, + .hw.init = &(struct clk_init_data) { + .name = "mipi_dsi_pxclk", + .ops = &clk_regmap_gate_ops, + .parent_hws = (const struct clk_hw *[]) { + &g12a_mipi_dsi_pxclk_div.hw + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +/* GPIO 24M */ +static struct clk_regmap g12a_24m = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_XTAL_DIVN_CNTL, + .bit_idx = 6, + }, + .hw.init = &(struct clk_init_data){ + .name = "g12a_24m", + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "xtal" }, + .parent_data = &(const struct clk_parent_data) { + .fw_name = "xtal", + }, + .num_parents = 1, + .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), + }, +}; + /* HDMI Clocks */ static const struct clk_parent_data g12a_hdmi_parent_data[] = { @@ -4099,6 +4183,96 @@ }, }; +static const char * const media_parent_names[] = { "xtal", + "gp0_pll", "hifi_pll", "fclk_div2p5", "fclk_div3", "fclk_div4", + "fclk_div5", "fclk_div7"}; + +static const char * const media_parent_names_mipi[] = { "xtal", + "gp0_pll", "mpll1", "mpll2", "fclk_div3", "fclk_div4", + "fclk_div5", "fclk_div7"}; + +static struct clk_mux cts_mipi_isp_clk_mux = { + .reg = (void *)HHI_MIPI_ISP_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_mipi_isp_clk_mux", + .ops = &clk_mux_ops, + .parent_names = media_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider cts_mipi_isp_clk_div = { + .reg = (void *)HHI_MIPI_ISP_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_mipi_isp_clk_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "cts_mipi_isp_clk_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate cts_mipi_isp_clk_gate = { + .reg = (void *)HHI_MIPI_ISP_CLK_CNTL, + .bit_idx = 8, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "cts_mipi_isp_clk_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "cts_mipi_isp_clk_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux cts_mipi_csi_phy_clk0_mux = { + .reg = (void *)HHI_MIPI_CSI_PHY_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_mipi_csi_phy_clk0_mux", + .ops = &clk_mux_ops, + .parent_names = media_parent_names_mipi, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider cts_mipi_csi_phy_clk0_div = { + .reg = (void *)HHI_MIPI_CSI_PHY_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "cts_mipi_csi_phy_clk0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "cts_mipi_csi_phy_clk0_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate cts_mipi_csi_phy_clk0_gate = { + .reg = (void *)HHI_MIPI_CSI_PHY_CLK_CNTL, + .bit_idx = 8, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "cts_mipi_csi_phy_clk0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "cts_mipi_csi_phy_clk0_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + #define MESON_GATE(_name, _reg, _bit) \ MESON_PCLK(_name, _reg, _bit, &g12a_clk81.hw) @@ -4402,6 +4576,9 @@ [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -4657,6 +4834,10 @@ [CLKID_SPICC1_SCLK_SEL] = &g12a_spicc1_sclk_sel.hw, [CLKID_SPICC1_SCLK_DIV] = &g12a_spicc1_sclk_div.hw, [CLKID_SPICC1_SCLK] = &g12a_spicc1_sclk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, + [CLKID_24M] = &g12a_24m.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -4903,6 +5084,9 @@ [CLKID_NNA_CORE_CLK_SEL] = &sm1_nna_core_clk_sel.hw, [CLKID_NNA_CORE_CLK_DIV] = &sm1_nna_core_clk_div.hw, [CLKID_NNA_CORE_CLK] = &sm1_nna_core_clk.hw, + [CLKID_MIPI_DSI_PXCLK_SEL] = &g12a_mipi_dsi_pxclk_sel.hw, + [CLKID_MIPI_DSI_PXCLK_DIV] = &g12a_mipi_dsi_pxclk_div.hw, + [CLKID_MIPI_DSI_PXCLK] = &g12a_mipi_dsi_pxclk.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -5150,6 +5334,10 @@ &sm1_nna_core_clk_sel, &sm1_nna_core_clk_div, &sm1_nna_core_clk, + &g12a_mipi_dsi_pxclk_sel, + &g12a_mipi_dsi_pxclk_div, + &g12a_mipi_dsi_pxclk, + &g12a_24m, }; static const struct reg_sequence g12a_init_regs[] = { @@ -5196,7 +5384,58 @@ struct clk *notifier_clk; struct clk_hw *xtal; int ret; + + void __iomem *clk_base; + + clk_base = of_iomap(of_get_parent(pdev->dev.of_node), 0); + if (!clk_base) { + pr_err("%s: Unable to map clk base\n", __func__); + return -1; + } + + cts_mipi_isp_clk_mux.reg = clk_base + + (unsigned long)(cts_mipi_isp_clk_mux.reg); + cts_mipi_isp_clk_gate.reg = clk_base + + (unsigned long)(cts_mipi_isp_clk_gate.reg); + cts_mipi_isp_clk_div.reg = clk_base + + (unsigned long)(cts_mipi_isp_clk_div.reg); + + cts_mipi_csi_phy_clk0_mux.reg = clk_base + + (unsigned long)(cts_mipi_csi_phy_clk0_mux.reg); + cts_mipi_csi_phy_clk0_div.reg = clk_base + + (unsigned long)(cts_mipi_csi_phy_clk0_div.reg); + cts_mipi_csi_phy_clk0_gate.reg = clk_base + + (unsigned long)(cts_mipi_csi_phy_clk0_gate.reg); + + // register composite clks + hws[CLKID_MIPI_ISP_CLK_COMP] = clk_hw_register_composite(NULL, + "cts_mipi_isp_clk_composite", + media_parent_names, 8, + &cts_mipi_isp_clk_mux.hw, + &clk_mux_ops, + &cts_mipi_isp_clk_div.hw, + &clk_divider_ops, + &cts_mipi_isp_clk_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(hws[CLKID_MIPI_ISP_CLK_COMP])) + panic("%s: %d register cts_mipi_isp_clk_composite error\n", + __func__, __LINE__); + + hws[CLKID_MIPI_CSI_PHY_CLK0_COMP] = clk_hw_register_composite(NULL, + "cts_mipi_csi_phy_clk0_composite", + media_parent_names_mipi, 8, + &cts_mipi_csi_phy_clk0_mux.hw, + &clk_mux_ops, + &cts_mipi_csi_phy_clk0_div.hw, + &clk_divider_ops, + &cts_mipi_csi_phy_clk0_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(hws[CLKID_MIPI_CSI_PHY_CLK0_COMP])) + panic("%s: %d register cts_mipi_csi_phy_clk0_composite error\n", + __func__, __LINE__); + meson_g12a_vcodec_init(hws, clk_base); + ret = meson_g12a_dvfs_setup_common(pdev, hws); if (ret) return ret; diff -Naur a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h --- a/drivers/clk/meson/g12a.h 2022-05-27 17:20:14.749890137 +0800 +++ b/drivers/clk/meson/g12a.h 2022-05-31 11:56:47.725259396 +0800 @@ -44,6 +44,7 @@ #define HHI_PCIE_PLL_CNTL4 0x0A8 #define HHI_PCIE_PLL_CNTL5 0x0AC #define HHI_PCIE_PLL_STS 0x0B8 +#define HHI_XTAL_DIVN_CNTL 0x0BC /* 0x2f offset in data sheet */ #define HHI_HIFI_PLL_CNTL0 0x0D8 #define HHI_HIFI_PLL_CNTL1 0x0DC #define HHI_HIFI_PLL_CNTL2 0x0E0 @@ -70,6 +71,7 @@ #define HHI_MALI_CLK_CNTL 0x1b0 #define HHI_VPU_CLKC_CNTL 0x1b4 #define HHI_VPU_CLK_CNTL 0x1bC +#define HHI_MIPI_ISP_CLK_CNTL 0x1C0 /* 0x70 offset in data sheet */ #define HHI_NNA_CLK_CNTL 0x1C8 #define HHI_HDMI_CLK_CNTL 0x1CC #define HHI_VDEC_CLK_CNTL 0x1E0 @@ -117,6 +119,7 @@ #define HHI_HDMI_PLL_CNTL4 0x330 #define HHI_HDMI_PLL_CNTL5 0x334 #define HHI_HDMI_PLL_CNTL6 0x338 +#define HHI_MIPI_CSI_PHY_CLK_CNTL 0x340 /* 0xd0 offset in data sheet */ #define HHI_SPICC_CLK_CNTL 0x3dc #define HHI_SYS1_PLL_CNTL0 0x380 #define HHI_SYS1_PLL_CNTL1 0x384 @@ -264,8 +267,9 @@ #define CLKID_NNA_AXI_CLK_DIV 263 #define CLKID_NNA_CORE_CLK_SEL 265 #define CLKID_NNA_CORE_CLK_DIV 266 +#define CLKID_MIPI_DSI_PXCLK_DIV 268 -#define NR_CLKS 268 +#define NR_CLKS 286 /* include the CLKIDs that have been made part of the DT binding */ #include diff -Naur a/drivers/clk/meson/g12a-vcodec-clk.c b/drivers/clk/meson/g12a-vcodec-clk.c --- a/drivers/clk/meson/g12a-vcodec-clk.c 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/clk/meson/g12a-vcodec-clk.c 2022-05-31 11:56:47.725259396 +0800 @@ -0,0 +1,624 @@ +/* + * drivers/amlogic/clk/g12a/g12a_clk_media.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "g12a.h" +#include "clk-mux.h" +#include "g12a-vcodec-clk.h" + + +extern spinlock_t meson_clk_lock; + + +const char *g12a_dec_parent_names[] = { "fclk_div2p5", "fclk_div3", + "fclk_div4", "fclk_div5", "fclk_div7", "hifi_pll", "gp0_pll", "xtal"}; + +/* cts_vdec_clk */ +static struct clk_mux vdec_p0_mux = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p0_mux", + .ops = &clk_mux_ops, + .parent_names = g12a_dec_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider vdec_p0_div = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vdec_p0_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate vdec_p0_gate = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .bit_idx = 8, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vdec_p0_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux vdec_p1_mux = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p1_mux", + .ops = &clk_mux_ops, + .parent_names = g12a_dec_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider vdec_p1_div = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vdec_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vdec_p1_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate vdec_p1_gate = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .bit_idx = 8, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vdec_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vdec_p1_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux vdec_mux = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .mask = 0x1, + .shift = 15, + .lock = &meson_clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "vdec_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "vdec_p0_composite", + "vdec_p1_composite"}, + .num_parents = 2, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +/* cts_hcodec_clk */ +static struct clk_mux hcodec_p0_mux = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_p0_mux", + .ops = &clk_mux_ops, + .parent_names = g12a_dec_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider hcodec_p0_div = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hcodec_p0_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate hcodec_p0_gate = { + .reg = (void *)HHI_VDEC_CLK_CNTL, + .bit_idx = 24, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hcodec_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hcodec_p0_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux hcodec_p1_mux = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_p1_mux", + .ops = &clk_mux_ops, + .parent_names = g12a_dec_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider hcodec_p1_div = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hcodec_p1_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate hcodec_p1_gate = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .bit_idx = 24, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hcodec_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hcodec_p1_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux hcodec_mux = { + .reg = (void *)HHI_VDEC3_CLK_CNTL, + .mask = 0x1, + .shift = 31, + .lock = &meson_clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "hcodec_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "hcodec_p0_composite", + "hcodec_p1_composite"}, + .num_parents = 2, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +/* cts_hevcb_clk */ +static struct clk_mux hevc_p0_mux = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevc_p0_mux", + .ops = &clk_mux_ops, + .parent_names = g12a_dec_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider hevc_p0_div = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevc_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hevc_p0_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate hevc_p0_gate = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .bit_idx = 24, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hevc_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hevc_p0_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux hevc_p1_mux = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .mask = 0x7, + .shift = 25, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevc_p1_mux", + .ops = &clk_mux_ops, + .parent_names = g12a_dec_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider hevc_p1_div = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevc_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hevc_p1_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate hevc_p1_gate = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .bit_idx = 24, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hevc_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hevc_p1_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux hevc_mux = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .mask = 0x1, + .shift = 31, + .lock = &meson_clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "hevc_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "hevc_p0_composite", + "hevc_p1_composite"}, + .num_parents = 2, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +/* cts_hevcf_clk */ +static struct clk_mux hevcf_p0_mux = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_p0_mux", + .ops = &clk_mux_ops, + .parent_names = g12a_dec_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider hevcf_p0_div = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_p0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hevcf_p0_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate hevcf_p0_gate = { + .reg = (void *)HHI_VDEC2_CLK_CNTL, + .bit_idx = 8, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p0_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hevcf_p0_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux hevcf_p1_mux = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .mask = 0x7, + .shift = 9, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_p1_mux", + .ops = &clk_mux_ops, + .parent_names = g12a_dec_parent_names, + .num_parents = 8, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_divider hevcf_p1_div = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_p1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "hevcf_p1_mux" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_gate hevcf_p1_gate = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .bit_idx = 8, + .lock = &meson_clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "hevcf_p1_gate", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "hevcf_p1_div" }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_mux hevcf_mux = { + .reg = (void *)HHI_VDEC4_CLK_CNTL, + .mask = 0x1, + .shift = 15, + .lock = &meson_clk_lock, + .flags = CLK_PARENT_ALTERNATE, + .hw.init = &(struct clk_init_data){ + .name = "hevcf_mux", + .ops = &meson_clk_mux_ops, + .parent_names = (const char *[]){ "hevcf_p0_composite", + "hevcf_p1_composite"}, + .num_parents = 2, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +void meson_g12a_vcodec_init(struct clk_hw **clk_hws, void __iomem *clk_base) +{ + /* cts_vdec_clk */ + vdec_p0_mux.reg = clk_base + (unsigned long)(vdec_p0_mux.reg); + vdec_p0_div.reg = clk_base + (unsigned long)(vdec_p0_div.reg); + vdec_p0_gate.reg = clk_base + (unsigned long)(vdec_p0_gate.reg); + vdec_p1_mux.reg = clk_base + (unsigned long)(vdec_p1_mux.reg); + vdec_p1_div.reg = clk_base + (unsigned long)(vdec_p1_div.reg); + vdec_p1_gate.reg = clk_base + (unsigned long)(vdec_p1_gate.reg); + vdec_mux.reg = clk_base + (unsigned long)(vdec_mux.reg); + + /* cts_hcodec_clk */ + hcodec_p0_mux.reg = clk_base + (unsigned long)(hcodec_p0_mux.reg); + hcodec_p0_div.reg = clk_base + (unsigned long)(hcodec_p0_div.reg); + hcodec_p0_gate.reg = clk_base + (unsigned long)(hcodec_p0_gate.reg); + hcodec_p1_mux.reg = clk_base + (unsigned long)(hcodec_p1_mux.reg); + hcodec_p1_div.reg = clk_base + (unsigned long)(hcodec_p1_div.reg); + hcodec_p1_gate.reg = clk_base + (unsigned long)(hcodec_p1_gate.reg); + hcodec_mux.reg = clk_base + (unsigned long)(hcodec_mux.reg); + + /* cts_hevc_clk */ + hevc_p0_mux.reg = clk_base + (unsigned long)(hevc_p0_mux.reg); + hevc_p0_div.reg = clk_base + (unsigned long)(hevc_p0_div.reg); + hevc_p0_gate.reg = clk_base + (unsigned long)(hevc_p0_gate.reg); + hevc_p1_mux.reg = clk_base + (unsigned long)(hevc_p1_mux.reg); + hevc_p1_div.reg = clk_base + (unsigned long)(hevc_p1_div.reg); + hevc_p1_gate.reg = clk_base + (unsigned long)(hevc_p1_gate.reg); + hevc_mux.reg = clk_base + (unsigned long)(hevc_mux.reg); + + /* cts_hevcf_clk */ + hevcf_p0_mux.reg = clk_base + (unsigned long)(hevcf_p0_mux.reg); + hevcf_p0_div.reg = clk_base + (unsigned long)(hevcf_p0_div.reg); + hevcf_p0_gate.reg = clk_base + (unsigned long)(hevcf_p0_gate.reg); + hevcf_p1_mux.reg = clk_base + (unsigned long)(hevcf_p1_mux.reg); + hevcf_p1_div.reg = clk_base + (unsigned long)(hevcf_p1_div.reg); + hevcf_p1_gate.reg = clk_base + (unsigned long)(hevcf_p1_gate.reg); + hevcf_mux.reg = clk_base + (unsigned long)(hevcf_mux.reg); + + /* cts_vdec_clk */ + clk_hws[CLKID_VDEC_P0_COMP] = clk_hw_register_composite(NULL, + "vdec_p0_composite", + g12a_dec_parent_names, 8, + &vdec_p0_mux.hw, + &clk_mux_ops, + &vdec_p0_div.hw, + &clk_divider_ops, + &vdec_p0_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(clk_hws[CLKID_VDEC_P0_COMP])) + panic("%s: %d clk_hw_register_composite vdec_p0_composite error\n", + __func__, __LINE__); + + clk_hws[CLKID_VDEC_P1_COMP] = clk_hw_register_composite(NULL, + "vdec_p1_composite", + g12a_dec_parent_names, 8, + &vdec_p1_mux.hw, + &clk_mux_ops, + &vdec_p1_div.hw, + &clk_divider_ops, + &vdec_p1_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(clk_hws[CLKID_VDEC_P1_COMP])) + panic("%s: %d clk_hw_register_composite vdec_p1_composite error\n", + __func__, __LINE__); + + if (clk_hw_register(NULL, &vdec_mux.hw)) { + panic("%s: %d clk_hw_register vdec_mux error\n", + __func__, __LINE__); + } else { + clk_hws[CLKID_VDEC_MUX] = &vdec_mux.hw; + } + + if (IS_ERR(clk_hws[CLKID_VDEC_MUX])) + panic("%s: %d clk_hw_register vdec_mux error\n", + __func__, __LINE__); + + /* cts_hcodec_clk */ + clk_hws[CLKID_HCODEC_P0_COMP] = clk_hw_register_composite(NULL, + "hcodec_p0_composite", + g12a_dec_parent_names, 8, + &hcodec_p0_mux.hw, + &clk_mux_ops, + &hcodec_p0_div.hw, + &clk_divider_ops, + &hcodec_p0_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(clk_hws[CLKID_HCODEC_P0_COMP])) + panic("%s: %d clk_hw_register_composite hcodec_p0_composite error\n", + __func__, __LINE__); + + clk_hws[CLKID_HCODEC_P1_COMP] = clk_hw_register_composite(NULL, + "hcodec_p1_composite", + g12a_dec_parent_names, 8, + &hcodec_p1_mux.hw, + &clk_mux_ops, + &hcodec_p1_div.hw, + &clk_divider_ops, + &hcodec_p1_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(clk_hws[CLKID_HCODEC_P1_COMP])) + panic("%s: %d clk_hw_register_composite hcodec_p1_composite error\n", + __func__, __LINE__); + + if (clk_hw_register(NULL, &hcodec_mux.hw)) { + panic("%s: %d clk_hw_register hcodec_mux error\n", + __func__, __LINE__); + } else { + clk_hws[CLKID_HCODEC_MUX] = &hcodec_mux.hw; + } + + if (IS_ERR(clk_hws[CLKID_HCODEC_MUX])) + panic("%s: %d clk_hw_register hcodec_mux error\n", + __func__, __LINE__); + + /* cts_hevc_clk */ + clk_hws[CLKID_HEVC_P0_COMP] = clk_hw_register_composite(NULL, + "hevc_p0_composite", + g12a_dec_parent_names, 8, + &hevc_p0_mux.hw, + &clk_mux_ops, + &hevc_p0_div.hw, + &clk_divider_ops, + &hevc_p0_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(clk_hws[CLKID_HEVC_P0_COMP])) + panic("%s: %d clk_hw_register_composite hevc_p0_composite error\n", + __func__, __LINE__); + + clk_hws[CLKID_HEVC_P1_COMP] = clk_hw_register_composite(NULL, + "hevc_p1_composite", + g12a_dec_parent_names, 8, + &hevc_p1_mux.hw, + &clk_mux_ops, + &hevc_p1_div.hw, + &clk_divider_ops, + &hevc_p1_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(clk_hws[CLKID_HEVC_P1_COMP])) + panic("%s: %d clk_hw_register_composite hevc_p1_composite error\n", + __func__, __LINE__); + + if (clk_hw_register(NULL, &hevc_mux.hw)) { + panic("%s: %d clk_hw_register hcodec_mux error\n", + __func__, __LINE__); + } else { + clk_hws[CLKID_HEVC_MUX] = &hevc_mux.hw; + } + + if (IS_ERR(clk_hws[CLKID_HEVC_MUX])) + panic("%s: %d clk_hw_register hevc_mux error\n", + __func__, __LINE__); + + /* cts_hevcf_clk */ + clk_hws[CLKID_HEVCF_P0_COMP] = clk_hw_register_composite(NULL, + "hevcf_p0_composite", + g12a_dec_parent_names, 8, + &hevcf_p0_mux.hw, + &clk_mux_ops, + &hevcf_p0_div.hw, + &clk_divider_ops, + &hevcf_p0_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(clk_hws[CLKID_HEVCF_P0_COMP])) + panic("%s: %d clk_hw_register_composite hevcf_p0_composite error\n", + __func__, __LINE__); + + clk_hws[CLKID_HEVCF_P1_COMP] = clk_hw_register_composite(NULL, + "hevcf_p1_composite", + g12a_dec_parent_names, 8, + &hevcf_p1_mux.hw, + &clk_mux_ops, + &hevcf_p1_div.hw, + &clk_divider_ops, + &hevcf_p1_gate.hw, + &clk_gate_ops, 0); + if (IS_ERR(clk_hws[CLKID_HEVCF_P1_COMP])) + panic("%s: %d clk_hw_register_composite hevcf_p1_composite error\n", + __func__, __LINE__); + + if (clk_hw_register(NULL, &hevcf_mux.hw)) { + panic("%s: %d clk_hw_register hevcf_mux error\n", + __func__, __LINE__); + } else { + clk_hws[CLKID_HEVCF_MUX] = &hevcf_mux.hw; + } + + if (IS_ERR(clk_hws[CLKID_HEVCF_MUX])) + panic("%s: %d clk_hw_register hevcf_mux error\n", + __func__, __LINE__); + + pr_info("%s: register meson media clk\n", __func__); +} + diff -Naur a/drivers/clk/meson/g12a-vcodec-clk.h b/drivers/clk/meson/g12a-vcodec-clk.h --- a/drivers/clk/meson/g12a-vcodec-clk.h 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/clk/meson/g12a-vcodec-clk.h 2022-05-31 11:56:47.725259396 +0800 @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2019 BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef __G12A_VCODEC_CLK_H +#define __G12A_VCODEC_CLK_H + +extern void meson_g12a_vcodec_init(struct clk_hw **clks, void __iomem *clk_base); + +#endif /* __G12A_VCODEC_CLK_H */ diff -Naur a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile --- a/drivers/clk/meson/Makefile 2022-05-27 17:20:14.749890137 +0800 +++ b/drivers/clk/meson/Makefile 2022-05-31 11:56:47.725259396 +0800 @@ -7,7 +7,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o -obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o +obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o clk-mux.o obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o @@ -17,5 +17,5 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o -obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o +obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o g12a-vcodec-clk.o obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o diff -Naur a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c --- a/drivers/clk/meson/vid-pll-div.c 2022-05-27 17:20:14.753890189 +0800 +++ b/drivers/clk/meson/vid-pll-div.c 2022-05-31 11:56:47.725259396 +0800 @@ -39,12 +39,14 @@ } static const struct vid_pll_div vid_pll_div_table[] = { + VID_PLL_DIV(0xffff, 0, 1, 1), /* 1/1 => /1 */ VID_PLL_DIV(0x0aaa, 0, 2, 1), /* 2/1 => /2 */ VID_PLL_DIV(0x5294, 2, 5, 2), /* 5/2 => /2.5 */ VID_PLL_DIV(0x0db6, 0, 3, 1), /* 3/1 => /3 */ VID_PLL_DIV(0x36cc, 1, 7, 2), /* 7/2 => /3.5 */ VID_PLL_DIV(0x6666, 2, 15, 4), /* 15/4 => /3.75 */ VID_PLL_DIV(0x0ccc, 0, 4, 1), /* 4/1 => /4 */ + VID_PLL_DIV(0x0ccc, 1, 467, 100), /* 467/100 => /4.67 */ VID_PLL_DIV(0x739c, 2, 5, 1), /* 5/1 => /5 */ VID_PLL_DIV(0x0e38, 0, 6, 1), /* 6/1 => /6 */ VID_PLL_DIV(0x0000, 3, 25, 4), /* 25/4 => /6.25 */ diff -Naur a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c --- a/drivers/edac/sb_edac.c 2022-06-29 08:47:07.171383478 +0800 +++ b/drivers/edac/sb_edac.c 2022-05-27 17:20:14.881891840 +0800 @@ -1052,7 +1052,7 @@ pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOHM_1, ®); rc = ((reg << 6) | rc) << 26; - return rc | 0x3ffffff; + return rc | 0x1ffffff; } static u64 knl_get_tolm(struct sbridge_pvt *pvt) diff -Naur a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c --- a/drivers/firmware/efi/libstub/arm64-stub.c 2022-05-27 17:20:14.893891994 +0800 +++ b/drivers/firmware/efi/libstub/arm64-stub.c 2022-05-31 11:56:47.725259396 +0800 @@ -125,7 +125,7 @@ kernel_size = _edata - _text; kernel_memsize = kernel_size + (_end - _edata); - *reserve_size = kernel_memsize; + *reserve_size = kernel_memsize + + TEXT_OFFSET % min_kimg_align; if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) { /* @@ -141,7 +141,7 @@ if (status != EFI_SUCCESS) { if (!check_image_region((u64)_text, kernel_memsize)) { efi_err("FIRMWARE BUG: Image BSS overlaps adjacent EFI memory region\n"); - } else if (IS_ALIGNED((u64)_text, min_kimg_align)) { + } else if (IS_ALIGNED((u64)_text - TEXT_OFFSET, min_kimg_align)) { /* * Just execute from wherever we were loaded by the * UEFI PE/COFF loader if the alignment is suitable. @@ -161,7 +161,7 @@ } } - *image_addr = *reserve_addr; + *image_addr = *reserve_addr + TEXT_OFFSET % min_kimg_align; memcpy((void *)*image_addr, _text, kernel_size); return EFI_SUCCESS; diff -Naur a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile --- a/drivers/firmware/efi/libstub/Makefile 2022-05-27 17:20:14.893891994 +0800 +++ b/drivers/firmware/efi/libstub/Makefile 2022-05-31 11:56:47.725259396 +0800 @@ -69,6 +69,7 @@ lib-$(CONFIG_X86) += x86-stub.o lib-$(CONFIG_RISCV) += riscv-stub.o CFLAGS_arm32-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) +CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) # Even when -mbranch-protection=none is set, Clang will generate a # .note.gnu.property for code-less object files (like lib/ctype.c), diff -Naur a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c 2022-05-27 17:20:15.513899992 +0800 +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-ahb-audio.c 2022-05-31 11:56:47.725259396 +0800 @@ -320,13 +320,17 @@ 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; - ret = snd_pcm_hw_constraint_eld(runtime, dw->data.eld); - if (ret < 0) - return ret; + 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) diff -Naur a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h 2022-05-27 17:20:15.513899992 +0800 +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h 2022-05-31 11:56:47.725259396 +0800 @@ -9,15 +9,15 @@ void __iomem *base; int irq; struct dw_hdmi *hdmi; - u8 *eld; + u8 *(*get_eld)(struct dw_hdmi *hdmi); }; struct dw_hdmi_i2s_audio_data { struct dw_hdmi *hdmi; - u8 *eld; void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); u8 (*read)(struct dw_hdmi *hdmi, int offset); + u8 *(*get_eld)(struct dw_hdmi *hdmi); }; #endif diff -Naur a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c 2022-05-27 17:20:15.513899992 +0800 +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c 2022-05-31 11:56:47.729259361 +0800 @@ -143,6 +143,7 @@ struct dw_hdmi { struct drm_connector connector; struct drm_bridge bridge; + struct drm_bridge *next_bridge; unsigned int version; @@ -754,6 +755,19 @@ else hdmi->mc_clkdis |= HDMI_MC_CLKDIS_AUDCLK_DISABLE; hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS); + + if (enable) { + hdmi_set_cts_n(hdmi, hdmi->audio_cts, 0); + hdmi_set_cts_n(hdmi, hdmi->audio_cts, hdmi->audio_n); + } +} + +static u8 *hdmi_audio_get_eld(struct dw_hdmi *hdmi) +{ + if (!hdmi->curr_conn) + return NULL; + + return hdmi->curr_conn->eld; } static void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi) @@ -2395,21 +2409,6 @@ return ret; } -static bool hdr_metadata_equal(const struct drm_connector_state *old_state, - const struct drm_connector_state *new_state) -{ - struct drm_property_blob *old_blob = old_state->hdr_output_metadata; - struct drm_property_blob *new_blob = new_state->hdr_output_metadata; - - if (!old_blob || !new_blob) - return old_blob == new_blob; - - if (old_blob->length != new_blob->length) - return false; - - return !memcmp(old_blob->data, new_blob->data, old_blob->length); -} - static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, struct drm_atomic_state *state) { @@ -2423,7 +2422,7 @@ if (!crtc) return 0; - if (!hdr_metadata_equal(old_state, new_state)) { + if (!drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); @@ -2492,8 +2491,7 @@ drm_connector_attach_max_bpc_property(connector, 8, 16); if (hdmi->version >= 0x200a && hdmi->plat_data->use_drm_infoframe) - drm_object_attach_property(&connector->base, - connector->dev->mode_config.hdr_output_metadata_property, 0); + drm_connector_attach_hdr_output_metadata_property(connector); drm_connector_attach_encoder(connector, hdmi->bridge.encoder); @@ -2791,7 +2789,8 @@ struct dw_hdmi *hdmi = bridge->driver_private; if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) - return 0; + return drm_bridge_attach(bridge->encoder, hdmi->next_bridge, + bridge, flags); return dw_hdmi_connector_create(hdmi); } @@ -3176,6 +3175,52 @@ /* ----------------------------------------------------------------------------- * Probe/remove API, used from platforms based on the DRM bridge API. */ + +static int dw_hdmi_parse_dt(struct dw_hdmi *hdmi) +{ + struct device_node *endpoint; + struct device_node *remote; + + if (!hdmi->plat_data->output_port) + return 0; + + endpoint = of_graph_get_endpoint_by_regs(hdmi->dev->of_node, + hdmi->plat_data->output_port, + -1); + if (!endpoint) { + /* + * On platforms whose bindings don't make the output port + * mandatory (such as Rockchip) the plat_data->output_port + * field isn't set, so it's safe to make this a fatal error. + */ + dev_err(hdmi->dev, "Missing endpoint in port@%u\n", + hdmi->plat_data->output_port); + return -ENODEV; + } + + remote = of_graph_get_remote_port_parent(endpoint); + of_node_put(endpoint); + if (!remote) { + dev_err(hdmi->dev, "Endpoint in port@%u unconnected\n", + hdmi->plat_data->output_port); + return -ENODEV; + } + + if (!of_device_is_available(remote)) { + dev_err(hdmi->dev, "port@%u remote device is disabled\n", + hdmi->plat_data->output_port); + of_node_put(remote); + return -ENODEV; + } + + hdmi->next_bridge = of_drm_find_bridge(remote); + of_node_put(remote); + if (!hdmi->next_bridge) + return -EPROBE_DEFER; + + return 0; +} + struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, const struct dw_hdmi_plat_data *plat_data) { @@ -3212,6 +3257,10 @@ mutex_init(&hdmi->cec_notifier_mutex); spin_lock_init(&hdmi->audio_lock); + ret = dw_hdmi_parse_dt(hdmi); + if (ret < 0) + return ERR_PTR(ret); + ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0); if (ddc_node) { hdmi->ddc = of_get_i2c_adapter_by_node(ddc_node); @@ -3377,6 +3426,7 @@ hdmi->bridge.funcs = &dw_hdmi_bridge_funcs; hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD; + hdmi->bridge.interlace_allowed = true; #ifdef CONFIG_OF hdmi->bridge.of_node = pdev->dev.of_node; #endif @@ -3395,7 +3445,7 @@ audio.base = hdmi->regs; audio.irq = irq; audio.hdmi = hdmi; - audio.eld = hdmi->connector.eld; + audio.get_eld = hdmi_audio_get_eld; hdmi->enable_audio = dw_hdmi_ahb_audio_enable; hdmi->disable_audio = dw_hdmi_ahb_audio_disable; @@ -3408,7 +3458,7 @@ struct dw_hdmi_i2s_audio_data audio; audio.hdmi = hdmi; - audio.eld = hdmi->connector.eld; + audio.get_eld = hdmi_audio_get_eld; audio.write = hdmi_writeb; audio.read = hdmi_readb; hdmi->enable_audio = dw_hdmi_i2s_audio_enable; @@ -3421,7 +3471,7 @@ hdmi->audio = platform_device_register_full(&pdevinfo); } - if (config0 & HDMI_CONFIG0_CEC) { + if (!plat_data->disable_cec && (config0 & HDMI_CONFIG0_CEC)) { cec.hdmi = hdmi; cec.ops = &dw_hdmi_cec_ops; cec.irq = irq; @@ -3440,8 +3490,7 @@ err_iahb: clk_disable_unprepare(hdmi->iahb_clk); - if (hdmi->cec_clk) - clk_disable_unprepare(hdmi->cec_clk); + clk_disable_unprepare(hdmi->cec_clk); err_isfr: clk_disable_unprepare(hdmi->isfr_clk); err_res: @@ -3465,8 +3514,7 @@ clk_disable_unprepare(hdmi->iahb_clk); clk_disable_unprepare(hdmi->isfr_clk); - if (hdmi->cec_clk) - clk_disable_unprepare(hdmi->cec_clk); + clk_disable_unprepare(hdmi->cec_clk); if (hdmi->i2c) i2c_del_adapter(&hdmi->i2c->adap); diff -Naur a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c 2022-05-27 17:20:15.513899992 +0800 +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c 2022-05-31 11:56:47.729259361 +0800 @@ -265,11 +265,9 @@ /* override the module pointer */ cec->adap->owner = THIS_MODULE; - ret = devm_add_action(&pdev->dev, dw_hdmi_cec_del, cec); - if (ret) { - cec_delete_adapter(cec->adap); + ret = devm_add_action_or_reset(&pdev->dev, dw_hdmi_cec_del, cec); + if (ret) return ret; - } ret = devm_request_threaded_irq(&pdev->dev, cec->irq, dw_hdmi_cec_hardirq, diff -Naur a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c 2022-05-27 17:20:15.513899992 +0800 +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c 2022-05-31 11:56:47.729259361 +0800 @@ -135,8 +135,15 @@ size_t len) { struct dw_hdmi_i2s_audio_data *audio = data; + u8 *eld; + + eld = audio->get_eld(audio->hdmi); + if (eld) + memcpy(buf, eld, min_t(size_t, MAX_ELD_BYTES, len)); + else + /* Pass en empty ELD if connector not available */ + memset(buf, 0, len); - memcpy(buf, audio->eld, min_t(size_t, MAX_ELD_BYTES, len)); return 0; } @@ -170,7 +177,7 @@ return dw_hdmi_set_plugged_cb(hdmi, fn, codec_dev); } -static struct hdmi_codec_ops dw_hdmi_i2s_ops = { +static const struct hdmi_codec_ops dw_hdmi_i2s_ops = { .hw_params = dw_hdmi_i2s_hw_params, .audio_startup = dw_hdmi_i2s_audio_startup, .audio_shutdown = dw_hdmi_i2s_audio_shutdown, diff -Naur a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c 2022-05-27 17:20:15.513899992 +0800 +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c 2022-05-31 11:56:47.729259361 +0800 @@ -246,6 +246,7 @@ struct clk *pclk; + bool device_found; unsigned int lane_mbps; /* per lane */ u32 channel; u32 lanes; @@ -309,13 +310,37 @@ return readl(dsi->base + reg); } +static int dw_mipi_dsi_panel_or_bridge(struct dw_mipi_dsi *dsi, + struct device_node *node) +{ + struct drm_bridge *bridge; + struct drm_panel *panel; + int ret; + + ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge); + if (ret) + return ret; + + if (panel) { + bridge = drm_panel_bridge_add_typed(panel, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + } + + dsi->panel_bridge = bridge; + + if (!dsi->panel_bridge) + return -EPROBE_DEFER; + + return 0; +} + static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct dw_mipi_dsi *dsi = host_to_dsi(host); const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; - struct drm_bridge *bridge; - struct drm_panel *panel; int ret; if (device->lanes > dsi->plat_data->max_data_lanes) { @@ -329,22 +354,14 @@ dsi->format = device->format; dsi->mode_flags = device->mode_flags; - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, - &panel, &bridge); - if (ret) - return ret; + if (!dsi->device_found) { + ret = dw_mipi_dsi_panel_or_bridge(dsi, host->dev->of_node); + if (ret) + return ret; - if (panel) { - bridge = drm_panel_bridge_add_typed(panel, - DRM_MODE_CONNECTOR_DSI); - if (IS_ERR(bridge)) - return PTR_ERR(bridge); + dsi->device_found = true; } - dsi->panel_bridge = bridge; - - drm_bridge_add(&dsi->bridge); - if (pdata->host_ops && pdata->host_ops->attach) { ret = pdata->host_ops->attach(pdata->priv_data, device); if (ret < 0) @@ -854,7 +871,8 @@ dsi_write(dsi, DSI_INT_MSK1, 0); } -static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) +static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; @@ -961,7 +979,8 @@ dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode); } -static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) +static void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_bridge_state) { struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); @@ -981,7 +1000,10 @@ enum drm_mode_status mode_status = MODE_OK; if (pdata->mode_valid) - mode_status = pdata->mode_valid(pdata->priv_data, mode); + mode_status = pdata->mode_valid(pdata->priv_data, mode, + dsi->mode_flags, + dw_mipi_dsi_get_lanes(dsi), + dsi->format); return mode_status; } @@ -999,17 +1021,30 @@ /* Set the encoder type as caller does not know it */ bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI; + if (!dsi->device_found) { + int ret; + + ret = dw_mipi_dsi_panel_or_bridge(dsi, dsi->dev->of_node); + if (ret) + return ret; + + dsi->device_found = true; + } + /* Attach the panel-bridge to the dsi bridge */ return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge, flags); } static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = { - .mode_set = dw_mipi_dsi_bridge_mode_set, - .enable = dw_mipi_dsi_bridge_enable, - .post_disable = dw_mipi_dsi_bridge_post_disable, - .mode_valid = dw_mipi_dsi_bridge_mode_valid, - .attach = dw_mipi_dsi_bridge_attach, + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_enable = dw_mipi_dsi_bridge_atomic_enable, + .atomic_post_disable = dw_mipi_dsi_bridge_post_atomic_disable, + .mode_set = dw_mipi_dsi_bridge_mode_set, + .mode_valid = dw_mipi_dsi_bridge_mode_valid, + .attach = dw_mipi_dsi_bridge_attach, }; #ifdef CONFIG_DEBUG_FS @@ -1172,6 +1207,7 @@ ret = mipi_dsi_host_register(&dsi->dsi_host); if (ret) { dev_err(dev, "Failed to register MIPI host: %d\n", ret); + pm_runtime_disable(dev); dw_mipi_dsi_debugfs_remove(dsi); return ERR_PTR(ret); } @@ -1181,6 +1217,7 @@ #ifdef CONFIG_OF dsi->bridge.of_node = pdev->dev.of_node; #endif + drm_bridge_add(&dsi->bridge); return dsi; } @@ -1229,15 +1266,7 @@ */ int dw_mipi_dsi_bind(struct dw_mipi_dsi *dsi, struct drm_encoder *encoder) { - int ret; - - ret = drm_bridge_attach(encoder, &dsi->bridge, NULL, 0); - if (ret) { - DRM_ERROR("Failed to initialize bridge with drm\n"); - return ret; - } - - return ret; + return drm_bridge_attach(encoder, &dsi->bridge, NULL, 0); } EXPORT_SYMBOL_GPL(dw_mipi_dsi_bind); diff -Naur a/drivers/gpu/drm/drm_aperture.c b/drivers/gpu/drm/drm_aperture.c --- a/drivers/gpu/drm/drm_aperture.c 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/gpu/drm/drm_aperture.c 2022-05-31 11:56:47.729259361 +0800 @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: MIT + +#include +#include +#include +#include +#include +#include /* for firmware helpers */ +#include +#include +#include + +#include +#include +#include + +/** + * DOC: overview + * + * A graphics device might be supported by different drivers, but only one + * driver can be active at any given time. Many systems load a generic + * graphics drivers, such as EFI-GOP or VESA, early during the boot process. + * During later boot stages, they replace the generic driver with a dedicated, + * hardware-specific driver. To take over the device the dedicated driver + * first has to remove the generic driver. DRM aperture functions manage + * ownership of DRM framebuffer memory and hand-over between drivers. + * + * DRM drivers should call drm_aperture_remove_conflicting_framebuffers() + * at the top of their probe function. The function removes any generic + * driver that is currently associated with the given framebuffer memory. + * If the framebuffer is located at PCI BAR 0, the rsp code looks as in the + * example given below. + * + * .. code-block:: c + * + * static const struct drm_driver example_driver = { + * ... + * }; + * + * static int remove_conflicting_framebuffers(struct pci_dev *pdev) + * { + * bool primary = false; + * resource_size_t base, size; + * int ret; + * + * base = pci_resource_start(pdev, 0); + * size = pci_resource_len(pdev, 0); + * #ifdef CONFIG_X86 + * primary = pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW; + * #endif + * + * return drm_aperture_remove_conflicting_framebuffers(base, size, primary, + * &example_driver); + * } + * + * static int probe(struct pci_dev *pdev) + * { + * int ret; + * + * // Remove any generic drivers... + * ret = remove_conflicting_framebuffers(pdev); + * if (ret) + * return ret; + * + * // ... and initialize the hardware. + * ... + * + * drm_dev_register(); + * + * return 0; + * } + * + * PCI device drivers should call + * drm_aperture_remove_conflicting_pci_framebuffers() and let it detect the + * framebuffer apertures automatically. Device drivers without knowledge of + * the framebuffer's location shall call drm_aperture_remove_framebuffers(), + * which removes all drivers for known framebuffer. + * + * Drivers that are susceptible to being removed by other drivers, such as + * generic EFI or VESA drivers, have to register themselves as owners of their + * given framebuffer memory. Ownership of the framebuffer memory is achieved + * by calling devm_aperture_acquire_from_firmware(). On success, the driver + * is the owner of the framebuffer range. The function fails if the + * framebuffer is already by another driver. See below for an example. + * + * .. code-block:: c + * + * static int acquire_framebuffers(struct drm_device *dev, struct platform_device *pdev) + * { + * resource_size_t base, size; + * + * mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + * if (!mem) + * return -EINVAL; + * base = mem->start; + * size = resource_size(mem); + * + * return devm_acquire_aperture_from_firmware(dev, base, size); + * } + * + * static int probe(struct platform_device *pdev) + * { + * struct drm_device *dev; + * int ret; + * + * // ... Initialize the device... + * dev = devm_drm_dev_alloc(); + * ... + * + * // ... and acquire ownership of the framebuffer. + * ret = acquire_framebuffers(dev, pdev); + * if (ret) + * return ret; + * + * drm_dev_register(dev, 0); + * + * return 0; + * } + * + * The generic driver is now subject to forced removal by other drivers. This + * only works for platform drivers that support hot unplug. + * When a driver calls drm_aperture_remove_conflicting_framebuffers() et al + * for the registered framebuffer range, the aperture helpers call + * platform_device_unregister() and the generic driver unloads itself. It + * may not access the device's registers, framebuffer memory, ROM, etc + * afterwards. + */ + +struct drm_aperture { + struct drm_device *dev; + resource_size_t base; + resource_size_t size; + struct list_head lh; + void (*detach)(struct drm_device *dev); +}; + +static LIST_HEAD(drm_apertures); +static DEFINE_MUTEX(drm_apertures_lock); + +static bool overlap(resource_size_t base1, resource_size_t end1, + resource_size_t base2, resource_size_t end2) +{ + return (base1 < end2) && (end1 > base2); +} + +static void devm_aperture_acquire_release(void *data) +{ + struct drm_aperture *ap = data; + bool detached = !ap->dev; + + if (detached) + return; + + mutex_lock(&drm_apertures_lock); + list_del(&ap->lh); + mutex_unlock(&drm_apertures_lock); +} + +static int devm_aperture_acquire(struct drm_device *dev, + resource_size_t base, resource_size_t size, + void (*detach)(struct drm_device *)) +{ + size_t end = base + size; + struct list_head *pos; + struct drm_aperture *ap; + + mutex_lock(&drm_apertures_lock); + + list_for_each(pos, &drm_apertures) { + ap = container_of(pos, struct drm_aperture, lh); + if (overlap(base, end, ap->base, ap->base + ap->size)) { + mutex_unlock(&drm_apertures_lock); + return -EBUSY; + } + } + + ap = devm_kzalloc(dev->dev, sizeof(*ap), GFP_KERNEL); + if (!ap) { + mutex_unlock(&drm_apertures_lock); + return -ENOMEM; + } + + ap->dev = dev; + ap->base = base; + ap->size = size; + ap->detach = detach; + INIT_LIST_HEAD(&ap->lh); + + list_add(&ap->lh, &drm_apertures); + + mutex_unlock(&drm_apertures_lock); + + return devm_add_action_or_reset(dev->dev, devm_aperture_acquire_release, ap); +} + +static void drm_aperture_detach_firmware(struct drm_device *dev) +{ + struct platform_device *pdev = to_platform_device(dev->dev); + + /* + * Remove the device from the device hierarchy. This is the right thing + * to do for firmware-based DRM drivers, such as EFI, VESA or VGA. After + * the new driver takes over the hardware, the firmware device's state + * will be lost. + * + * For non-platform devices, a new callback would be required. + * + * If the aperture helpers ever need to handle native drivers, this call + * would only have to unplug the DRM device, so that the hardware device + * stays around after detachment. + */ + platform_device_unregister(pdev); +} + +/** + * devm_aperture_acquire_from_firmware - Acquires ownership of a firmware framebuffer + * on behalf of a DRM driver. + * @dev: the DRM device to own the framebuffer memory + * @base: the framebuffer's byte offset in physical memory + * @size: the framebuffer size in bytes + * + * Installs the given device as the new owner of the framebuffer. The function + * expects the framebuffer to be provided by a platform device that has been + * set up by firmware. Firmware can be any generic interface, such as EFI, + * VESA, VGA, etc. If the native hardware driver takes over ownership of the + * framebuffer range, the firmware state gets lost. Aperture helpers will then + * unregister the platform device automatically. Acquired apertures are + * released automatically if the underlying device goes away. + * + * The function fails if the framebuffer range, or parts of it, is currently + * owned by another driver. To evict current owners, callers should use + * drm_aperture_remove_conflicting_framebuffers() et al. before calling this + * function. The function also fails if the given device is not a platform + * device. + * + * Returns: + * 0 on success, or a negative errno value otherwise. + */ +int devm_aperture_acquire_from_firmware(struct drm_device *dev, resource_size_t base, + resource_size_t size) +{ + if (drm_WARN_ON(dev, !dev_is_platform(dev->dev))) + return -EINVAL; + + return devm_aperture_acquire(dev, base, size, drm_aperture_detach_firmware); +} +EXPORT_SYMBOL(devm_aperture_acquire_from_firmware); + +static void drm_aperture_detach_drivers(resource_size_t base, resource_size_t size) +{ + resource_size_t end = base + size; + struct list_head *pos, *n; + + mutex_lock(&drm_apertures_lock); + + list_for_each_safe(pos, n, &drm_apertures) { + struct drm_aperture *ap = + container_of(pos, struct drm_aperture, lh); + struct drm_device *dev = ap->dev; + + if (WARN_ON_ONCE(!dev)) + continue; + + if (!overlap(base, end, ap->base, ap->base + ap->size)) + continue; + + ap->dev = NULL; /* detach from device */ + list_del(&ap->lh); + + ap->detach(dev); + } + + mutex_unlock(&drm_apertures_lock); +} + +/** + * drm_aperture_remove_conflicting_framebuffers - remove existing framebuffers in the given range + * @base: the aperture's base address in physical memory + * @size: aperture size in bytes + * @primary: also kick vga16fb if present + * @req_driver: requesting DRM driver + * + * This function removes graphics device drivers which use memory range described by + * @base and @size. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +int drm_aperture_remove_conflicting_framebuffers(resource_size_t base, resource_size_t size, + bool primary, const struct drm_driver *req_driver) +{ +#if IS_REACHABLE(CONFIG_FB) + struct apertures_struct *a; + int ret; + + a = alloc_apertures(1); + if (!a) + return -ENOMEM; + + a->ranges[0].base = base; + a->ranges[0].size = size; + + ret = remove_conflicting_framebuffers(a, req_driver->name, primary); + kfree(a); + + if (ret) + return ret; +#endif + + drm_aperture_detach_drivers(base, size); + + return 0; +} +EXPORT_SYMBOL(drm_aperture_remove_conflicting_framebuffers); + +/** + * drm_aperture_remove_conflicting_pci_framebuffers - remove existing framebuffers for PCI devices + * @pdev: PCI device + * @req_driver: requesting DRM driver + * + * This function removes graphics device drivers using memory range configured + * for any of @pdev's memory bars. The function assumes that PCI device with + * shadowed ROM drives a primary display and so kicks out vga16fb. + * + * Returns: + * 0 on success, or a negative errno code otherwise + */ +int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev, + const struct drm_driver *req_driver) +{ + resource_size_t base, size; + int bar, ret = 0; + + for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) { + if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) + continue; + base = pci_resource_start(pdev, bar); + size = pci_resource_len(pdev, bar); + drm_aperture_detach_drivers(base, size); + } + + /* + * WARNING: Apparently we must kick fbdev drivers before vgacon, + * otherwise the vga fbdev driver falls over. + */ +#if IS_REACHABLE(CONFIG_FB) + ret = remove_conflicting_pci_framebuffers(pdev, req_driver->name); +#endif + if (ret == 0) + ret = vga_remove_vgacon(pdev); + return ret; +} +EXPORT_SYMBOL(drm_aperture_remove_conflicting_pci_framebuffers); diff -Naur a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c --- a/drivers/gpu/drm/drm_connector.c 2022-05-27 17:20:15.517900044 +0800 +++ b/drivers/gpu/drm/drm_connector.c 2022-05-31 11:56:47.729259361 +0800 @@ -2144,6 +2144,55 @@ EXPORT_SYMBOL(drm_connector_attach_max_bpc_property); /** + * drm_connector_attach_hdr_output_metadata_property - attach "HDR_OUTPUT_METADA" property + * @connector: connector to attach the property on. + * + * This is used to allow the userspace to send HDR Metadata to the + * driver. + * + * Returns: + * Zero on success, negative errno on failure. + */ +int drm_connector_attach_hdr_output_metadata_property(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_property *prop = dev->mode_config.hdr_output_metadata_property; + + drm_object_attach_property(&connector->base, prop, 0); + + return 0; +} +EXPORT_SYMBOL(drm_connector_attach_hdr_output_metadata_property); + +/** + * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed + * @old_state: old connector state to compare + * @new_state: new connector state to compare + * + * This is used by HDR-enabled drivers to test whether the HDR metadata + * have changed between two different connector state (and thus probably + * requires a full blown mode change). + * + * Returns: + * True if the metadata are equal, False otherwise + */ +bool drm_connector_atomic_hdr_metadata_equal(struct drm_connector_state *old_state, + struct drm_connector_state *new_state) +{ + struct drm_property_blob *old_blob = old_state->hdr_output_metadata; + struct drm_property_blob *new_blob = new_state->hdr_output_metadata; + + if (!old_blob || !new_blob) + return old_blob == new_blob; + + if (old_blob->length != new_blob->length) + return false; + + return !memcmp(old_blob->data, new_blob->data, old_blob->length); +} +EXPORT_SYMBOL(drm_connector_atomic_hdr_metadata_equal); + +/** * drm_connector_set_vrr_capable_property - sets the variable refresh rate * capable property for a connector * @connector: drm connector diff -Naur a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c --- a/drivers/gpu/drm/drm_ioctl.c 2022-05-27 17:20:15.521900096 +0800 +++ b/drivers/gpu/drm/drm_ioctl.c 2022-05-31 11:56:47.729259361 +0800 @@ -678,9 +678,9 @@ DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, 0), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_RENDER_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_RENDER_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER), diff -Naur a/drivers/gpu/drm/drm_vblank.c b/drivers/gpu/drm/drm_vblank.c --- a/drivers/gpu/drm/drm_vblank.c 2022-05-27 17:20:15.525900147 +0800 +++ b/drivers/gpu/drm/drm_vblank.c 2022-05-31 11:56:47.729259361 +0800 @@ -1725,6 +1725,15 @@ reply->tval_usec = ts.tv_nsec / 1000; } +static bool drm_wait_vblank_supported(struct drm_device *dev) +{ +#if IS_ENABLED(CONFIG_DRM_LEGACY) + if (unlikely(drm_core_check_feature(dev, DRIVER_LEGACY))) + return dev->irq_enabled; +#endif + return drm_dev_has_vblank(dev); +} + int drm_wait_vblank_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -1736,7 +1745,7 @@ unsigned int pipe_index; unsigned int flags, pipe, high_pipe; - if (!dev->irq_enabled) + if (!drm_wait_vblank_supported(dev)) return -EOPNOTSUPP; if (vblwait->request.type & _DRM_VBLANK_SIGNAL) @@ -2011,7 +2020,7 @@ if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; - if (!dev->irq_enabled) + if (!drm_dev_has_vblank(dev)) return -EOPNOTSUPP; crtc = drm_crtc_find(dev, file_priv, get_seq->crtc_id); @@ -2070,7 +2079,7 @@ if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EOPNOTSUPP; - if (!dev->irq_enabled) + if (!drm_dev_has_vblank(dev)) return -EOPNOTSUPP; crtc = drm_crtc_find(dev, file_priv, queue_seq->crtc_id); diff -Naur a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile --- a/drivers/gpu/drm/Makefile 2022-05-27 17:20:14.917892304 +0800 +++ b/drivers/gpu/drm/Makefile 2022-05-31 11:56:47.729259361 +0800 @@ -18,7 +18,7 @@ drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \ drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o \ - drm_managed.o drm_vblank_work.o + drm_managed.o drm_vblank_work.o drm_aperture.o drm-$(CONFIG_DRM_LEGACY) += drm_legacy_misc.o drm_bufs.o drm_context.o drm_dma.o drm_scatter.o drm_lock.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o diff -Naur a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig --- a/drivers/gpu/drm/meson/Kconfig 2022-05-27 17:20:15.601901127 +0800 +++ b/drivers/gpu/drm/meson/Kconfig 2022-05-31 11:56:47.729259361 +0800 @@ -6,9 +6,11 @@ select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER select DRM_GEM_CMA_HELPER + select DRM_DISPLAY_CONNECTOR select VIDEOMODE_HELPERS select REGMAP_MMIO select MESON_CANVAS + select CEC_CORE if CEC_NOTIFIER config DRM_MESON_DW_HDMI tristate "HDMI Synopsys Controller support for Amlogic Meson Display" @@ -16,3 +18,10 @@ default y if DRM_MESON select DRM_DW_HDMI imply DRM_DW_HDMI_I2S_AUDIO + +config DRM_MESON_DW_MIPI_DSI + tristate "MIPI DSI Synopsys Controller support for Amlogic Meson Display" + depends on DRM_MESON + default y if DRM_MESON + select DRM_DW_MIPI_DSI + select GENERIC_PHY_MIPI_DPHY diff -Naur a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile --- a/drivers/gpu/drm/meson/Makefile 2022-05-27 17:20:15.601901127 +0800 +++ b/drivers/gpu/drm/meson/Makefile 2022-05-31 11:56:47.729259361 +0800 @@ -1,7 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only -meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o +meson-drm-y := meson_drv.o meson_plane.o meson_cursor.o meson_crtc.o meson_encoder_cvbs.o meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o meson-drm-y += meson_rdma.o meson_osd_afbcd.o +meson-drm-y += meson_encoder_hdmi.o meson_encoder_dsi.o obj-$(CONFIG_DRM_MESON) += meson-drm.o obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o +obj-$(CONFIG_DRM_MESON_DW_MIPI_DSI) += meson_dw_mipi_dsi.o diff -Naur a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c --- a/drivers/gpu/drm/meson/meson_crtc.c 2022-05-27 17:20:15.601901127 +0800 +++ b/drivers/gpu/drm/meson/meson_crtc.c 2022-05-31 11:56:47.729259361 +0800 @@ -36,6 +36,7 @@ struct drm_pending_vblank_event *event; struct meson_drm *priv; void (*enable_osd1)(struct meson_drm *priv); + void (*enable_osd2)(struct meson_drm *priv); void (*enable_vd1)(struct meson_drm *priv); void (*enable_osd1_afbc)(struct meson_drm *priv); void (*disable_osd1_afbc)(struct meson_drm *priv); @@ -82,7 +83,7 @@ }; static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) + struct drm_crtc_state *old_crtc_state) { struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct drm_crtc_state *crtc_state = crtc->state; @@ -110,6 +111,20 @@ writel_relaxed(0 << 16 | (crtc_state->mode.vdisplay - 1), priv->io_base + _REG(VPP_OSD1_BLD_V_SCOPE)); + writel_relaxed(0 << 16 | + (crtc_state->mode.hdisplay - 1), + priv->io_base + _REG(VPP_OSD2_BLD_H_SCOPE)); + writel_relaxed(0 << 16 | + (crtc_state->mode.vdisplay - 1), + priv->io_base + _REG(VPP_OSD2_BLD_V_SCOPE)); + writel_relaxed(crtc_state->mode.hdisplay | + crtc_state->mode.vdisplay << 16, + priv->io_base + + _REG(VIU_OSD_BLEND_BLEND0_SIZE)); + writel_relaxed(crtc_state->mode.hdisplay | + crtc_state->mode.vdisplay << 16, + priv->io_base + + _REG(VIU_OSD_BLEND_BLEND1_SIZE)); writel_relaxed(crtc_state->mode.hdisplay << 16 | crtc_state->mode.vdisplay, priv->io_base + _REG(VPP_OUT_H_V_SIZE)); @@ -118,7 +133,7 @@ } static void meson_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) + struct drm_crtc_state *old_crtc_state) { struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct drm_crtc_state *crtc_state = crtc->state; @@ -146,7 +161,7 @@ } static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) + struct drm_crtc_state *old_crtc_state) { struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct meson_drm *priv = meson_crtc->priv; @@ -158,6 +173,9 @@ priv->viu.osd1_enabled = false; priv->viu.osd1_commit = false; + priv->viu.osd2_enabled = false; + priv->viu.osd2_commit = false; + priv->viu.vd1_enabled = false; priv->viu.vd1_commit = false; @@ -171,7 +189,7 @@ } static void meson_crtc_atomic_disable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) + struct drm_crtc_state *old_crtc_state) { struct meson_crtc *meson_crtc = to_meson_crtc(crtc); struct meson_drm *priv = meson_crtc->priv; @@ -183,11 +201,14 @@ priv->viu.osd1_enabled = false; priv->viu.osd1_commit = false; + priv->viu.osd2_enabled = false; + priv->viu.osd2_commit = false; + priv->viu.vd1_enabled = false; priv->viu.vd1_commit = false; /* Disable VPP Postblend */ - writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_VD1_POSTBLEND | + writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND | VPP_POSTBLEND_ENABLE, 0, priv->io_base + _REG(VPP_MISC)); @@ -201,7 +222,7 @@ } static void meson_crtc_atomic_begin(struct drm_crtc *crtc, - struct drm_crtc_state *state) + struct drm_crtc_state *old_crtc_state) { struct meson_crtc *meson_crtc = to_meson_crtc(crtc); unsigned long flags; @@ -223,6 +244,7 @@ struct meson_drm *priv = meson_crtc->priv; priv->viu.osd1_commit = true; + priv->viu.osd2_commit = true; priv->viu.vd1_commit = true; } @@ -246,6 +268,12 @@ priv->io_base + _REG(VPP_MISC)); } +static void meson_crtc_enable_osd2(struct meson_drm *priv) +{ + writel_bits_relaxed(VPP_OSD2_POSTBLEND, VPP_OSD2_POSTBLEND, + priv->io_base + _REG(VPP_MISC)); +} + static void meson_crtc_g12a_enable_osd1_afbc(struct meson_drm *priv) { writel_relaxed(priv->viu.osd1_blk2_cfg4, @@ -274,14 +302,20 @@ writel_relaxed(priv->viu.osd_blend_din0_scope_v, priv->io_base + _REG(VIU_OSD_BLEND_DIN0_SCOPE_V)); - writel_relaxed(priv->viu.osb_blend0_size, + writel_bits_relaxed(OSD_BLEND_POSTBLD_SRC_OSD1, OSD_BLEND_POSTBLD_SRC_OSD1, + priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); +} + +static void meson_g12a_crtc_enable_osd2(struct meson_drm *priv) +{ + writel_relaxed(priv->viu.osd_blend_din3_scope_h, priv->io_base + - _REG(VIU_OSD_BLEND_BLEND0_SIZE)); - writel_relaxed(priv->viu.osb_blend1_size, + _REG(VIU_OSD_BLEND_DIN1_SCOPE_H)); + writel_relaxed(priv->viu.osd_blend_din3_scope_v, priv->io_base + - _REG(VIU_OSD_BLEND_BLEND1_SIZE)); - writel_bits_relaxed(3 << 8, 3 << 8, - priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); + _REG(VIU_OSD_BLEND_DIN1_SCOPE_V)); + writel_bits_relaxed(OSD_BLEND_POSTBLD_SRC_OSD2, OSD_BLEND_POSTBLD_SRC_OSD2, + priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); } static void meson_crtc_enable_vd1(struct meson_drm *priv) @@ -388,6 +422,43 @@ priv->viu.osd1_commit = false; } + if (priv->viu.osd2_enabled && priv->viu.osd2_commit) { + writel_relaxed(priv->viu.osd2_ctrl_stat, + priv->io_base + _REG(VIU_OSD2_CTRL_STAT)); + writel_relaxed(priv->viu.osd2_ctrl_stat2, + priv->io_base + _REG(VIU_OSD2_CTRL_STAT2)); + writel_relaxed(priv->viu.osd2_blk0_cfg[0], + priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W0)); + writel_relaxed(priv->viu.osd2_blk0_cfg[1], + priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W1)); + writel_relaxed(priv->viu.osd2_blk0_cfg[2], + priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W2)); + writel_relaxed(priv->viu.osd2_blk0_cfg[3], + priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W3)); + writel_relaxed(priv->viu.osd2_blk0_cfg[4], + priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W4)); + + /* vsync forced to update INTERLACE_SEL_ODD in interlace mode */ + meson_crtc->vsync_forced = priv->viu.osd2_interlace; + + meson_canvas_config(priv->canvas, priv->canvas_id_osd2, + priv->viu.osd2_addr, + priv->viu.osd2_stride, + priv->viu.osd2_height, + MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, 0); + + /* Enable OSD2 */ + if (meson_crtc->enable_osd2) + meson_crtc->enable_osd2(priv); + + priv->viu.osd2_commit = false; + } else if (priv->viu.osd2_enabled && priv->viu.osd2_interlace) { + u32 reg = readl_relaxed(priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W0)) & ~BIT(0); + writel_relaxed(reg | meson_venci_get_field(priv) ? 1 : 0, + priv->io_base + _REG(VIU_OSD2_BLK0_CFG_W0)); + } + /* Update the VD1 registers */ if (priv->viu.vd1_enabled && priv->viu.vd1_commit) { @@ -685,7 +756,7 @@ meson_crtc->priv = priv; crtc = &meson_crtc->base; ret = drm_crtc_init_with_planes(priv->drm, crtc, - priv->primary_plane, NULL, + priv->primary_plane, priv->cursor_plane, &meson_crtc_funcs, "meson_crtc"); if (ret) { dev_err(priv->drm->dev, "Failed to init CRTC\n"); @@ -694,6 +765,7 @@ if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1; + meson_crtc->enable_osd2 = meson_g12a_crtc_enable_osd2; meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1; meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET; meson_crtc->enable_osd1_afbc = @@ -703,6 +775,7 @@ drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs); } else { meson_crtc->enable_osd1 = meson_crtc_enable_osd1; + meson_crtc->enable_osd2 = meson_crtc_enable_osd2; meson_crtc->enable_vd1 = meson_crtc_enable_vd1; if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM)) { meson_crtc->enable_osd1_afbc = diff -Naur a/drivers/gpu/drm/meson/meson_cursor.c b/drivers/gpu/drm/meson/meson_cursor.c --- a/drivers/gpu/drm/meson/meson_cursor.c 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/gpu/drm/meson/meson_cursor.c 2022-05-31 11:56:47.729259361 +0800 @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "meson_cursor.h" +#include "meson_registers.h" +#include "meson_viu.h" + +struct meson_cursor { + struct drm_plane base; + struct meson_drm *priv; +}; +#define to_meson_cursor(x) container_of(x, struct meson_cursor, base) + +static int meson_cursor_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state->state, + plane); + struct drm_crtc_state *crtc_state; + + if (!new_plane_state->crtc) + return 0; + + crtc_state = drm_atomic_get_crtc_state(state->state, + new_plane_state->crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + return drm_atomic_helper_check_plane_state(new_plane_state, + crtc_state, + DRM_PLANE_HELPER_NO_SCALING, + DRM_PLANE_HELPER_NO_SCALING, + true, true); +} + +/* Takes a fixed 16.16 number and converts it to integer. */ +static inline int64_t fixed16_to_int(int64_t value) +{ + return value >> 16; +} + +static void meson_cursor_atomic_update(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct meson_cursor *meson_cursor = to_meson_cursor(plane); + struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state->state, + plane); + struct drm_rect dest = drm_plane_state_dest(new_state); + struct meson_drm *priv = meson_cursor->priv; + struct drm_framebuffer *fb = new_state->fb; + struct drm_gem_cma_object *gem; + unsigned long flags; + int dst_w, dst_h; + + /* + * Update Coordinates + * Update Formats + * Update Buffer + * Enable Plane + */ + spin_lock_irqsave(&priv->drm->event_lock, flags); + + /* Enable OSD and BLK0, set max global alpha */ + priv->viu.osd2_ctrl_stat = OSD_ENABLE | + (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | + OSD_BLK0_ENABLE; + + priv->viu.osd2_ctrl_stat2 = readl(priv->io_base + + _REG(VIU_OSD2_CTRL_STAT2)); + + /* Set up BLK0 to point to the right canvas */ + priv->viu.osd2_blk0_cfg[0] = priv->canvas_id_osd2 << OSD_CANVAS_SEL; + priv->viu.osd2_blk0_cfg[0] |= OSD_ENDIANNESS_LE; + + /* On GXBB, Use the old non-HDR RGB2YUV converter */ + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) + priv->viu.osd2_blk0_cfg[0] |= OSD_OUTPUT_COLOR_RGB; + + switch (fb->format->format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + priv->viu.osd2_blk0_cfg[0] |= OSD_BLK_MODE_32 | + OSD_COLOR_MATRIX_32_ARGB; + break; + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_ABGR8888: + priv->viu.osd2_blk0_cfg[0] |= OSD_BLK_MODE_32 | + OSD_COLOR_MATRIX_32_ABGR; + break; + case DRM_FORMAT_RGB888: + priv->viu.osd2_blk0_cfg[0] |= OSD_BLK_MODE_24 | + OSD_COLOR_MATRIX_24_RGB; + break; + case DRM_FORMAT_RGB565: + priv->viu.osd2_blk0_cfg[0] |= OSD_BLK_MODE_16 | + OSD_COLOR_MATRIX_16_RGB565; + break; + } + + switch (fb->format->format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + /* For XRGB, replace the pixel's alpha by 0xFF */ + priv->viu.osd2_ctrl_stat2 |= OSD_REPLACE_EN; + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + /* For ARGB, use the pixel's alpha */ + priv->viu.osd2_ctrl_stat2 &= ~OSD_REPLACE_EN; + break; + } + + dst_w = new_state->crtc_w; + dst_h = new_state->crtc_h; + + if (new_state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) + priv->viu.osd2_interlace = true; + else + priv->viu.osd2_interlace = false; + + /* + * The format of these registers is (x2 << 16 | x1), + * where x2 is exclusive. + * e.g. +30x1920 would be (1919 << 16) | 30 + */ + priv->viu.osd2_blk0_cfg[1] = + ((fixed16_to_int(new_state->src.x2) - 1) << 16) | + fixed16_to_int(new_state->src.x1); + priv->viu.osd2_blk0_cfg[2] = + ((fixed16_to_int(new_state->src.y2) - 1) << 16) | + fixed16_to_int(new_state->src.y1); + priv->viu.osd2_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; + priv->viu.osd2_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; + + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + priv->viu.osd_blend_din3_scope_h = ((dest.x2 - 1) << 16) | dest.x1; + priv->viu.osd_blend_din3_scope_v = ((dest.y2 - 1) << 16) | dest.y1; + priv->viu.osb_blend1_size = dst_h << 16 | dst_w; + } + + /* Update Canvas with buffer address */ + gem = drm_fb_cma_get_gem_obj(fb, 0); + + priv->viu.osd2_addr = gem->paddr; + priv->viu.osd2_stride = fb->pitches[0]; + priv->viu.osd2_height = fb->height; + priv->viu.osd2_width = fb->width; + + /* TOFIX: Reset OSD2 before enabling it on GXL+ SoCs ? */ + + priv->viu.osd2_enabled = true; + + spin_unlock_irqrestore(&priv->drm->event_lock, flags); +} + +static void meson_cursor_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *state) +{ + struct meson_cursor *meson_cursor = to_meson_cursor(plane); + struct meson_drm *priv = meson_cursor->priv; + + /* Disable OSD2 */ + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) + writel_bits_relaxed(OSD_BLEND_POSTBLD_SRC_OSD2, 0, + priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); + else + writel_bits_relaxed(VPP_OSD2_POSTBLEND, 0, + priv->io_base + _REG(VPP_MISC)); + + priv->viu.osd2_enabled = false; +} + +static const struct drm_plane_helper_funcs meson_cursor_helper_funcs = { + .atomic_check = meson_cursor_atomic_check, + .atomic_disable = meson_cursor_atomic_disable, + .atomic_update = meson_cursor_atomic_update, +}; + +static const struct drm_plane_funcs meson_cursor_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = drm_plane_cleanup, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static const uint32_t supported_drm_formats[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, +}; + +static const uint64_t format_modifiers_default[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_INVALID, +}; + +int meson_cursor_create(struct meson_drm *priv) +{ + struct meson_cursor *meson_cursor; + struct drm_plane *cursor; + + meson_cursor = devm_kzalloc(priv->drm->dev, sizeof(*meson_cursor), + GFP_KERNEL); + if (!meson_cursor) + return -ENOMEM; + + meson_cursor->priv = priv; + cursor = &meson_cursor->base; + + drm_universal_plane_init(priv->drm, cursor, 0xFF, + &meson_cursor_funcs, + supported_drm_formats, + ARRAY_SIZE(supported_drm_formats), + format_modifiers_default, + DRM_PLANE_TYPE_CURSOR, "meson_cursor_plane"); + + drm_plane_helper_add(cursor, &meson_cursor_helper_funcs); + + /* For now, OSD Cursor is always on top of the primary plane */ + drm_plane_create_zpos_immutable_property(cursor, 2); + + priv->cursor_plane = cursor; + + return 0; +} diff -Naur a/drivers/gpu/drm/meson/meson_cursor.h b/drivers/gpu/drm/meson/meson_cursor.h --- a/drivers/gpu/drm/meson/meson_cursor.h 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/gpu/drm/meson/meson_cursor.h 2022-05-31 11:56:47.729259361 +0800 @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 BayLibre, SAS + * Author: Neil Armstrong + */ + +#ifndef __MESON_CURSOR_H +#define __MESON_CURSOR_H + +#include "meson_drv.h" + +int meson_cursor_create(struct meson_drm *priv); + +#endif /* __MESON_CURSOR_H */ diff -Naur a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c --- a/drivers/gpu/drm/meson/meson_drv.c 2022-05-27 17:20:15.601901127 +0800 +++ b/drivers/gpu/drm/meson/meson_drv.c 2022-05-31 11:56:47.729259361 +0800 @@ -15,12 +15,12 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -29,9 +29,12 @@ #include "meson_drv.h" #include "meson_overlay.h" #include "meson_plane.h" +#include "meson_cursor.h" #include "meson_osd_afbcd.h" #include "meson_registers.h" -#include "meson_venc_cvbs.h" +#include "meson_encoder_cvbs.h" +#include "meson_encoder_hdmi.h" +#include "meson_encoder_dsi.h" #include "meson_viu.h" #include "meson_vpp.h" #include "meson_rdma.h" @@ -93,9 +96,6 @@ static struct drm_driver meson_driver = { .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, - /* IRQ */ - .irq_handler = meson_irq, - /* CMA Ops */ DRM_GEM_CMA_DRIVER_OPS_WITH_DUMB_CREATE(meson_dumb_create), @@ -156,23 +156,6 @@ writel_relaxed(value, priv->io_base + _REG(VPU_WRARB_MODE_L2C1)); } -static void meson_remove_framebuffers(void) -{ - struct apertures_struct *ap; - - ap = alloc_apertures(1); - if (!ap) - return; - - /* The framebuffer can be located anywhere in RAM */ - ap->ranges[0].base = 0; - ap->ranges[0].size = ~0; - - drm_fb_helper_remove_conflicting_framebuffers(ap, "meson-drm-fb", - false); - kfree(ap); -} - struct meson_drm_soc_attr { struct meson_drm_soc_limits limits; const struct soc_device_attribute *attrs; @@ -226,8 +209,7 @@ priv->compat = match->compat; priv->afbcd.ops = match->afbcd_ops; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpu"); - regs = devm_ioremap_resource(dev, res); + regs = devm_platform_ioremap_resource_byname(pdev, "vpu"); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto free_drm; @@ -264,6 +246,9 @@ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); if (ret) goto free_drm; + ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd2); + if (ret) + goto free_drm; ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_0); if (ret) { meson_canvas_free(priv->canvas, priv->canvas_id_osd1); @@ -297,8 +282,13 @@ } } - /* Remove early framebuffers (ie. simplefb) */ - meson_remove_framebuffers(); + /* + * Remove early framebuffers (ie. simplefb). The framebuffer can be + * located anywhere in RAM + */ + ret = drm_aperture_remove_framebuffers(false, &meson_driver); + if (ret) + goto free_drm; ret = drmm_mode_config_init(drm); if (ret) @@ -322,33 +312,47 @@ /* Encoder Initialization */ - ret = meson_venc_cvbs_create(priv); + ret = meson_encoder_cvbs_init(priv); if (ret) - goto free_drm; + goto exit_afbcd; if (has_components) { ret = component_bind_all(drm->dev, drm); if (ret) { dev_err(drm->dev, "Couldn't bind all components\n"); - goto free_drm; + goto exit_afbcd; } } + ret = meson_encoder_hdmi_init(priv); + if (ret) + goto exit_afbcd; + + ret = meson_cursor_create(priv); + if (ret) + goto exit_afbcd; + + if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) { + ret = meson_encoder_dsi_init(priv); + if (ret) + goto free_drm; + } + ret = meson_plane_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; ret = meson_overlay_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; ret = meson_crtc_create(priv); if (ret) - goto free_drm; + goto exit_afbcd; - ret = drm_irq_install(drm, priv->vsync_irq); + ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm); if (ret) - goto free_drm; + goto exit_afbcd; drm_mode_config_reset(drm); @@ -365,7 +369,10 @@ return 0; uninstall_irq: - drm_irq_uninstall(drm); + free_irq(priv->vsync_irq, drm); +exit_afbcd: + if (priv->afbcd.ops) + priv->afbcd.ops->exit(priv); free_drm: drm_dev_put(drm); @@ -393,13 +400,11 @@ drm_kms_helper_poll_fini(drm); drm_atomic_helper_shutdown(drm); component_unbind_all(dev, drm); - drm_irq_uninstall(drm); + free_irq(priv->vsync_irq, drm); drm_dev_put(drm); - if (priv->afbcd.ops) { - priv->afbcd.ops->reset(priv); - meson_rdma_free(priv); - } + if (priv->afbcd.ops) + priv->afbcd.ops->exit(priv); } static const struct component_master_ops meson_drv_master_ops = { @@ -442,46 +447,6 @@ return dev->of_node == data; } -/* Possible connectors nodes to ignore */ -static const struct of_device_id connectors_match[] = { - { .compatible = "composite-video-connector" }, - { .compatible = "svideo-connector" }, - { .compatible = "hdmi-connector" }, - { .compatible = "dvi-connector" }, - {} -}; - -static int meson_probe_remote(struct platform_device *pdev, - struct component_match **match, - struct device_node *parent, - struct device_node *remote) -{ - struct device_node *ep, *remote_node; - int count = 1; - - /* If node is a connector, return and do not add to match table */ - if (of_match_node(connectors_match, remote)) - return 1; - - component_match_add(&pdev->dev, match, compare_of, remote); - - for_each_endpoint_of_node(remote, ep) { - remote_node = of_graph_get_remote_port_parent(ep); - if (!remote_node || - remote_node == parent || /* Ignore parent endpoint */ - !of_device_is_available(remote_node)) { - of_node_put(remote_node); - continue; - } - - count += meson_probe_remote(pdev, match, remote, remote_node); - - of_node_put(remote_node); - } - - return count; -} - static void meson_drv_shutdown(struct platform_device *pdev) { struct meson_drm *priv = dev_get_drvdata(&pdev->dev); @@ -493,6 +458,13 @@ drm_atomic_helper_shutdown(priv->drm); } +/* Possible connectors nodes to ignore */ +static const struct of_device_id connectors_match[] = { + { .compatible = "composite-video-connector" }, + { .compatible = "svideo-connector" }, + {} +}; + static int meson_drv_probe(struct platform_device *pdev) { struct component_match *match = NULL; @@ -507,8 +479,21 @@ continue; } - count += meson_probe_remote(pdev, &match, np, remote); + /* If an analog connector is detected, count it as an output */ + if (of_match_node(connectors_match, remote)) { + ++count; + of_node_put(remote); + continue; + } + + dev_dbg(&pdev->dev, "parent %pOF remote match add %pOF parent %s\n", + np, remote, dev_name(&pdev->dev)); + + component_match_add(&pdev->dev, &match, compare_of, remote); + of_node_put(remote); + + ++count; } if (count && !match) diff -Naur a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h --- a/drivers/gpu/drm/meson/meson_drv.h 2022-05-27 17:20:15.601901127 +0800 +++ b/drivers/gpu/drm/meson/meson_drv.h 2022-05-31 11:56:47.729259361 +0800 @@ -43,12 +43,14 @@ struct meson_canvas *canvas; u8 canvas_id_osd1; + u8 canvas_id_osd2; u8 canvas_id_vd1_0; u8 canvas_id_vd1_1; u8 canvas_id_vd1_2; struct drm_device *drm; struct drm_crtc *crtc; + struct drm_plane *cursor_plane; struct drm_plane *primary_plane; struct drm_plane *overlay_plane; @@ -82,6 +84,21 @@ uint32_t osd_blend_din0_scope_h; uint32_t osd_blend_din0_scope_v; uint32_t osb_blend0_size; + + bool osd2_enabled; + bool osd2_interlace; + bool osd2_commit; + uint32_t osd2_ctrl_stat; + uint32_t osd2_ctrl_stat2; + uint32_t osd2_blk0_cfg[5]; + uint32_t osd2_blk1_cfg4; + uint32_t osd2_blk2_cfg4; + uint32_t osd2_addr; + uint32_t osd2_stride; + uint32_t osd2_height; + uint32_t osd2_width; + uint32_t osd_blend_din3_scope_h; + uint32_t osd_blend_din3_scope_v; uint32_t osb_blend1_size; bool vd1_enabled; diff -Naur a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c 2022-05-27 17:20:15.601901127 +0800 +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c 2022-05-31 11:56:47.729259361 +0800 @@ -22,14 +22,11 @@ #include #include -#include #include #include "meson_drv.h" #include "meson_dw_hdmi.h" #include "meson_registers.h" -#include "meson_vclk.h" -#include "meson_venc.h" #define DRIVER_NAME "meson-dw-hdmi" #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver" @@ -135,8 +132,6 @@ }; struct meson_dw_hdmi { - struct drm_encoder encoder; - struct drm_bridge bridge; struct dw_hdmi_plat_data dw_plat_data; struct meson_drm *priv; struct device *dev; @@ -148,12 +143,8 @@ struct regulator *hdmi_supply; u32 irq_stat; struct dw_hdmi *hdmi; - unsigned long output_bus_fmt; + struct drm_bridge *bridge; }; -#define encoder_to_meson_dw_hdmi(x) \ - container_of(x, struct meson_dw_hdmi, encoder) -#define bridge_to_meson_dw_hdmi(x) \ - container_of(x, struct meson_dw_hdmi, bridge) static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi, const char *compat) @@ -295,14 +286,14 @@ /* Setup PHY bandwidth modes */ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, - const struct drm_display_mode *mode) + const struct drm_display_mode *mode, + bool mode_is_420) { struct meson_drm *priv = dw_hdmi->priv; unsigned int pixel_clock = mode->clock; /* For 420, pixel clock is half unlike venc clock */ - if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) - pixel_clock /= 2; + if (mode_is_420) pixel_clock /= 2; if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) { @@ -374,68 +365,25 @@ mdelay(2); } -static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, - const struct drm_display_mode *mode) -{ - struct meson_drm *priv = dw_hdmi->priv; - int vic = drm_match_cea_mode(mode); - unsigned int phy_freq; - unsigned int vclk_freq; - unsigned int venc_freq; - unsigned int hdmi_freq; - - vclk_freq = mode->clock; - - /* For 420, pixel clock is half unlike venc clock */ - if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) - vclk_freq /= 2; - - /* TMDS clock is pixel_clock * 10 */ - phy_freq = vclk_freq * 10; - - if (!vic) { - meson_vclk_setup(priv, MESON_VCLK_TARGET_DMT, phy_freq, - vclk_freq, vclk_freq, vclk_freq, false); - return; - } - - /* 480i/576i needs global pixel doubling */ - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - vclk_freq *= 2; - - venc_freq = vclk_freq; - hdmi_freq = vclk_freq; - - /* VENC double pixels for 1080i, 720p and YUV420 modes */ - if (meson_venc_hdmi_venc_repeat(vic) || - dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) - venc_freq *= 2; - - vclk_freq = max(venc_freq, hdmi_freq); - - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - venc_freq /= 2; - - DRM_DEBUG_DRIVER("vclk:%d phy=%d venc=%d hdmi=%d enci=%d\n", - phy_freq, vclk_freq, venc_freq, hdmi_freq, - priv->venc.hdmi_use_enci); - - meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq, - venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); -} - static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, const struct drm_display_info *display, const struct drm_display_mode *mode) { struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + bool is_hdmi2_sink = display->hdmi.scdc.supported; struct meson_drm *priv = dw_hdmi->priv; unsigned int wr_clk = readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING)); + bool mode_is_420 = false; DRM_DEBUG_DRIVER("\"%s\" div%d\n", mode->name, mode->clock > 340000 ? 40 : 10); + if (drm_mode_is_420_only(display, mode) || + (!is_hdmi2_sink && + drm_mode_is_420_also(display, mode))) + mode_is_420 = true; + /* Enable clocks */ regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100); @@ -457,8 +405,7 @@ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); /* TMDS pattern setup */ - if (mode->clock > 340000 && - dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_YUV8_1X24) { + if (mode->clock > 340000 && !mode_is_420) { dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0); dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, @@ -476,7 +423,7 @@ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); /* Setup PHY parameters */ - meson_hdmi_phy_setup_mode(dw_hdmi, mode); + meson_hdmi_phy_setup_mode(dw_hdmi, mode, mode_is_420); /* Setup PHY */ regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, @@ -622,214 +569,15 @@ dw_hdmi_setup_rx_sense(dw_hdmi->hdmi, hpd_connected, hpd_connected); - drm_helper_hpd_irq_event(dw_hdmi->encoder.dev); + drm_helper_hpd_irq_event(dw_hdmi->bridge->dev); + drm_bridge_hpd_notify(dw_hdmi->bridge, + hpd_connected ? connector_status_connected + : connector_status_disconnected); } return IRQ_HANDLED; } -static enum drm_mode_status -dw_hdmi_mode_valid(struct dw_hdmi *hdmi, void *data, - const struct drm_display_info *display_info, - const struct drm_display_mode *mode) -{ - struct meson_dw_hdmi *dw_hdmi = data; - struct meson_drm *priv = dw_hdmi->priv; - bool is_hdmi2_sink = display_info->hdmi.scdc.supported; - unsigned int phy_freq; - unsigned int vclk_freq; - unsigned int venc_freq; - unsigned int hdmi_freq; - int vic = drm_match_cea_mode(mode); - enum drm_mode_status status; - - DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); - - /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ - if (display_info->max_tmds_clock && - mode->clock > display_info->max_tmds_clock && - !drm_mode_is_420_only(display_info, mode) && - !drm_mode_is_420_also(display_info, mode)) - return MODE_BAD; - - /* Check against non-VIC supported modes */ - if (!vic) { - status = meson_venc_hdmi_supported_mode(mode); - if (status != MODE_OK) - return status; - - return meson_vclk_dmt_supported_freq(priv, mode->clock); - /* Check against supported VIC modes */ - } else if (!meson_venc_hdmi_supported_vic(vic)) - return MODE_BAD; - - vclk_freq = mode->clock; - - /* For 420, pixel clock is half unlike venc clock */ - if (drm_mode_is_420_only(display_info, mode) || - (!is_hdmi2_sink && - drm_mode_is_420_also(display_info, mode))) - vclk_freq /= 2; - - /* TMDS clock is pixel_clock * 10 */ - phy_freq = vclk_freq * 10; - - /* 480i/576i needs global pixel doubling */ - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - vclk_freq *= 2; - - venc_freq = vclk_freq; - hdmi_freq = vclk_freq; - - /* VENC double pixels for 1080i, 720p and YUV420 modes */ - if (meson_venc_hdmi_venc_repeat(vic) || - drm_mode_is_420_only(display_info, mode) || - (!is_hdmi2_sink && - drm_mode_is_420_also(display_info, mode))) - venc_freq *= 2; - - vclk_freq = max(venc_freq, hdmi_freq); - - if (mode->flags & DRM_MODE_FLAG_DBLCLK) - venc_freq /= 2; - - dev_dbg(dw_hdmi->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", - __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); - - return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); -} - -/* Encoder */ - -static const u32 meson_dw_hdmi_out_bus_fmts[] = { - MEDIA_BUS_FMT_YUV8_1X24, - MEDIA_BUS_FMT_UYYVYY8_0_5X24, -}; - -static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); -} - -static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = { - .destroy = meson_venc_hdmi_encoder_destroy, -}; - -static u32 * -meson_venc_hdmi_encoder_get_inp_bus_fmts(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state, - u32 output_fmt, - unsigned int *num_input_fmts) -{ - u32 *input_fmts = NULL; - int i; - - *num_input_fmts = 0; - - for (i = 0 ; i < ARRAY_SIZE(meson_dw_hdmi_out_bus_fmts) ; ++i) { - if (output_fmt == meson_dw_hdmi_out_bus_fmts[i]) { - *num_input_fmts = 1; - input_fmts = kcalloc(*num_input_fmts, - sizeof(*input_fmts), - GFP_KERNEL); - if (!input_fmts) - return NULL; - - input_fmts[0] = output_fmt; - - break; - } - } - - return input_fmts; -} - -static int meson_venc_hdmi_encoder_atomic_check(struct drm_bridge *bridge, - struct drm_bridge_state *bridge_state, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge); - - dw_hdmi->output_bus_fmt = bridge_state->output_bus_cfg.format; - - DRM_DEBUG_DRIVER("output_bus_fmt %lx\n", dw_hdmi->output_bus_fmt); - - return 0; -} - -static void meson_venc_hdmi_encoder_disable(struct drm_bridge *bridge) -{ - struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge); - struct meson_drm *priv = dw_hdmi->priv; - - DRM_DEBUG_DRIVER("\n"); - - writel_bits_relaxed(0x3, 0, - priv->io_base + _REG(VPU_HDMI_SETTING)); - - writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); - writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); -} - -static void meson_venc_hdmi_encoder_enable(struct drm_bridge *bridge) -{ - struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge); - struct meson_drm *priv = dw_hdmi->priv; - - DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP"); - - if (priv->venc.hdmi_use_enci) - writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN)); - else - writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN)); -} - -static void meson_venc_hdmi_encoder_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode) -{ - struct meson_dw_hdmi *dw_hdmi = bridge_to_meson_dw_hdmi(bridge); - struct meson_drm *priv = dw_hdmi->priv; - int vic = drm_match_cea_mode(mode); - unsigned int ycrcb_map = VPU_HDMI_OUTPUT_CBYCR; - bool yuv420_mode = false; - - DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic); - - if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { - ycrcb_map = VPU_HDMI_OUTPUT_CRYCB; - yuv420_mode = true; - } - - /* VENC + VENC-DVI Mode setup */ - meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); - - /* VCLK Set clock */ - dw_hdmi_set_vclk(dw_hdmi, mode); - - if (dw_hdmi->output_bus_fmt == MEDIA_BUS_FMT_UYYVYY8_0_5X24) - /* Setup YUV420 to HDMI-TX, no 10bit diphering */ - writel_relaxed(2 | (2 << 2), - priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); - else - /* Setup YUV444 to HDMI-TX, no 10bit diphering */ - writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); -} - -static const struct drm_bridge_funcs meson_venc_hdmi_encoder_bridge_funcs = { - .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, - .atomic_get_input_bus_fmts = meson_venc_hdmi_encoder_get_inp_bus_fmts, - .atomic_reset = drm_atomic_helper_bridge_reset, - .atomic_check = meson_venc_hdmi_encoder_atomic_check, - .enable = meson_venc_hdmi_encoder_enable, - .disable = meson_venc_hdmi_encoder_disable, - .mode_set = meson_venc_hdmi_encoder_mode_set, -}; - /* DW HDMI Regmap */ static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, @@ -876,28 +624,6 @@ .dwc_write = dw_hdmi_g12a_dwc_write, }; -static bool meson_hdmi_connector_is_available(struct device *dev) -{ - struct device_node *ep, *remote; - - /* HDMI Connector is on the second port, first endpoint */ - ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0); - if (!ep) - return false; - - /* If the endpoint node exists, consider it enabled */ - remote = of_graph_get_remote_port(ep); - if (remote) { - of_node_put(ep); - return true; - } - - of_node_put(ep); - of_node_put(remote); - - return false; -} - static void meson_dw_hdmi_init(struct meson_dw_hdmi *meson_dw_hdmi) { struct meson_drm *priv = meson_dw_hdmi->priv; @@ -976,19 +702,11 @@ struct drm_device *drm = data; struct meson_drm *priv = drm->dev_private; struct dw_hdmi_plat_data *dw_plat_data; - struct drm_bridge *next_bridge; - struct drm_encoder *encoder; - struct resource *res; int irq; int ret; DRM_DEBUG_DRIVER("\n"); - if (!meson_hdmi_connector_is_available(dev)) { - dev_info(drm->dev, "HDMI Output connector not available\n"); - return -ENODEV; - } - match = of_device_get_match_data(&pdev->dev); if (!match) { dev_err(&pdev->dev, "failed to get match data\n"); @@ -1004,7 +722,6 @@ meson_dw_hdmi->dev = dev; meson_dw_hdmi->data = match; dw_plat_data = &meson_dw_hdmi->dw_plat_data; - encoder = &meson_dw_hdmi->encoder; meson_dw_hdmi->hdmi_supply = devm_regulator_get_optional(dev, "hdmi"); if (IS_ERR(meson_dw_hdmi->hdmi_supply)) { @@ -1042,8 +759,7 @@ return PTR_ERR(meson_dw_hdmi->hdmitx_phy); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res); + meson_dw_hdmi->hdmitx = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(meson_dw_hdmi->hdmitx)) return PTR_ERR(meson_dw_hdmi->hdmitx); @@ -1076,33 +792,18 @@ return ret; } - /* Encoder */ - - ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs, - DRM_MODE_ENCODER_TMDS, "meson_hdmi"); - if (ret) { - dev_err(priv->dev, "Failed to init HDMI encoder\n"); - return ret; - } - - meson_dw_hdmi->bridge.funcs = &meson_venc_hdmi_encoder_bridge_funcs; - drm_bridge_attach(encoder, &meson_dw_hdmi->bridge, NULL, 0); - - encoder->possible_crtcs = BIT(0); - meson_dw_hdmi_init(meson_dw_hdmi); - DRM_DEBUG_DRIVER("encoder initialized\n"); - /* Bridge / Connector */ dw_plat_data->priv_data = meson_dw_hdmi; - dw_plat_data->mode_valid = dw_hdmi_mode_valid; dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops; dw_plat_data->phy_name = "meson_dw_hdmi_phy"; dw_plat_data->phy_data = meson_dw_hdmi; dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; dw_plat_data->ycbcr_420_allowed = true; + dw_plat_data->disable_cec = true; + dw_plat_data->output_port = 1; if (dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || dw_hdmi_is_compatible(meson_dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || @@ -1111,15 +812,11 @@ platform_set_drvdata(pdev, meson_dw_hdmi); - meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev, - &meson_dw_hdmi->dw_plat_data); + meson_dw_hdmi->hdmi = dw_hdmi_probe(pdev, &meson_dw_hdmi->dw_plat_data); if (IS_ERR(meson_dw_hdmi->hdmi)) return PTR_ERR(meson_dw_hdmi->hdmi); - next_bridge = of_drm_find_bridge(pdev->dev.of_node); - if (next_bridge) - drm_bridge_attach(encoder, next_bridge, - &meson_dw_hdmi->bridge, 0); + meson_dw_hdmi->bridge = of_drm_find_bridge(pdev->dev.of_node); DRM_DEBUG_DRIVER("HDMI controller initialized\n"); diff -Naur a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c --- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c 1970-01-01 08:00:00.000000000 +0800 +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c 2022-05-31 11:56:47.733259325 +0800 @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 BayLibre, SAS + * Author: Neil Armstrong + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include