From ea23f0a33d0f280b3e2a5ca14fbb2c3b6026477a Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 26 Sep 2018 06:47:36 +0400 Subject: [PATCH 01/21] project: add mainline 'Amlogic' project --- projects/Amlogic/options | 67 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 projects/Amlogic/options diff --git a/projects/Amlogic/options b/projects/Amlogic/options new file mode 100644 index 0000000000..7cf0d5fb1a --- /dev/null +++ b/projects/Amlogic/options @@ -0,0 +1,67 @@ +################################################################################ +# setup system defaults +################################################################################ + + # Bootloader to use (syslinux / u-boot / bcm2835-bootloader) + BOOTLOADER="u-boot" + + # Linux Kernel to use + LINUX="default" + +################################################################################ +# setup build defaults +################################################################################ + + # Project CFLAGS + PROJECT_CFLAGS="" + + # SquashFS compression method (gzip / lzo / xz / zstd) + SQUASHFS_COMPRESSION="zstd" + +################################################################################ +# setup project defaults +################################################################################ + + # build and install ALSA Audio support (yes / no) + ALSA_SUPPORT="yes" + + # OpenGL(X) implementation to use (no / mesa) + OPENGL="no" + + # Displayserver to use (x11 / no) + DISPLAYSERVER="no" + + # Windowmanager to use (ratpoison / fluxbox / none) + WINDOWMANAGER="none" + + # Xorg Graphic drivers to use (all / i915,i965,r200,r300,r600,nvidia) + # Space separated list is supported, + # e.g. GRAPHIC_DRIVERS="i915 i965 r300 r600 radeonsi nvidia" + GRAPHIC_DRIVERS="" + + # additional Firmware to use (dvb-firmware, misc-firmware, wlan-firmware) + FIRMWARE="brcmfmac_sdio-firmware meson-firmware" + + # build and install ATV IR remote support (yes / no) + ATVCLIENT_SUPPORT="no" + + # build and install iSCSI support - iscsistart (yes / no) + ISCSI_SUPPORT="no" + + # build with installer (yes / no) + INSTALLER_SUPPORT="no" + + # build and install driver addons (yes / no) + DRIVER_ADDONS_SUPPORT="no" + + # driver addons to install: + DRIVER_ADDONS="crazycat dvb-latest" + + # additional packages to install: + ADDITIONAL_PACKAGES="u-boot-script dtc ethmactool" + + # use the kernel CEC framework for libcec (yes / no) + CEC_FRAMEWORK_SUPPORT="yes" + + # debug tty path + DEBUG_TTY="/dev/ttyAML0" From c15f54a3f2e235f8ad56e4d531a7ed5b3d712b58 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 26 Sep 2018 06:55:12 +0400 Subject: [PATCH 02/21] project: add Kodi appliance.xml defaults --- projects/Amlogic/kodi/appliance.xml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 projects/Amlogic/kodi/appliance.xml diff --git a/projects/Amlogic/kodi/appliance.xml b/projects/Amlogic/kodi/appliance.xml new file mode 100644 index 0000000000..d5e9a32687 --- /dev/null +++ b/projects/Amlogic/kodi/appliance.xml @@ -0,0 +1,22 @@ + + + +
+ + + + true + 0192001080060.00000pstd + + + false + + + true + 3 + + + +
+ +
From ab1c5e64be1c6737fa2dcf62995de734fff2f264 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 26 Sep 2018 07:01:15 +0400 Subject: [PATCH 03/21] project: add alsa HDMI.conf --- .../filesystem/usr/share/alsa/cards/HDMI.conf | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 projects/Amlogic/filesystem/usr/share/alsa/cards/HDMI.conf diff --git a/projects/Amlogic/filesystem/usr/share/alsa/cards/HDMI.conf b/projects/Amlogic/filesystem/usr/share/alsa/cards/HDMI.conf new file mode 100644 index 0000000000..a79abf8d3e --- /dev/null +++ b/projects/Amlogic/filesystem/usr/share/alsa/cards/HDMI.conf @@ -0,0 +1,34 @@ +# +# Configuration for HDMI +# + + + +HDMI.pcm.hdmi.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { type string } + @args.AES0 { type integer } + @args.AES1 { type integer } + @args.AES2 { type integer } + @args.AES3 { type integer } + type hooks + slave.pcm { + type hw + card $CARD + device 0 + } + hooks.0 { + type ctl_elems + hook_args [ + { + interface MIXER + name "IEC958 Playback Default" + lock true + preserve true + optional true + value [ $AES0 $AES1 $AES2 $AES3 ] + } + ] + } + hint.device 0 +} From 77b1d8f0171f83e67e48f61b7e9261537123f60c Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 26 Sep 2018 07:07:23 +0400 Subject: [PATCH 04/21] project: add amlogic-boot-fip package --- .../packages/amlogic-boot-fip/package.mk | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 projects/Amlogic/packages/amlogic-boot-fip/package.mk diff --git a/projects/Amlogic/packages/amlogic-boot-fip/package.mk b/projects/Amlogic/packages/amlogic-boot-fip/package.mk new file mode 100644 index 0000000000..74c7b3a8be --- /dev/null +++ b/projects/Amlogic/packages/amlogic-boot-fip/package.mk @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2016-present Team LibreELEC (https://libreelec.tv) + +PKG_NAME="amlogic-boot-fip" +PKG_LICENSE="nonfree" +PKG_SITE="" +PKG_LONGDESC="Amlogic Boot Firmare files used to wrap U-Boot to provide a functional boot blob" +PKG_TOOLCHAIN="manual" +PKG_STAMP="$UBOOT_SYSTEM" + +case "$UBOOT_SYSTEM" in + khadas-vim*) + PKG_VERSION="20180207" + PKG_SHA256="8dfdf0a267bbedde2229f22d41f0573f67a182a2bb4852db3baae884315f5acc" + PKG_URL="https://github.com/BayLibre/u-boot/releases/download/v2017.11-libretech-cc/khadas-vim_fip_${PKG_VERSION}.tar.gz" + PKG_SOURCE_DIR="fip" + ;; + nanopi-k2|p20*) + PKG_VERSION="20170412" + PKG_SHA256="4b5778098ca2a4f7ade06db7752ec9f77775d67e438d6fba0c669a4959ff7200" + PKG_URL="https://github.com/BayLibre/u-boot/releases/download/v2017.11-libretech-cc/nanopi-k2_fip_${PKG_VERSION}.tar.gz" + PKG_SOURCE_DIR="fip" + ;; + odroid-c2) + PKG_VERSION="s905_6.0.1_v3.7" + PKG_SHA256="3ee700fd3a6439997060ac6d21217b0adba3a801876707fae70988f8ce6c3fef" + PKG_URL="https://github.com/hardkernel/u-boot/archive/${PKG_VERSION}.tar.gz" + PKG_SOURCE_DIR="u-boot-${PKG_VERSION}" + ;; + *) + PKG_VERSION="20170606" + PKG_SHA256="957c96037bcd792a4139cc33eded2f006d55a82c0c56ae69ef43bdcb76a255e2" + PKG_URL="https://github.com/BayLibre/u-boot/releases/download/v2017.11-libretech-cc/p212_fip_${PKG_VERSION}.tar.gz" + PKG_SOURCE_DIR="fip" + ;; +esac From 709a60e423318e220bf543738bc5d0ca0be69939 Mon Sep 17 00:00:00 2001 From: kszaq Date: Tue, 21 May 2019 01:43:22 +0200 Subject: [PATCH 05/21] project: add common bootloader files --- projects/Amlogic/bootloader/box.ini | 7 + projects/Amlogic/bootloader/canupdate.sh | 19 +++ projects/Amlogic/bootloader/config | 3 + projects/Amlogic/bootloader/install | 123 ++++++++++++++++++ projects/Amlogic/bootloader/mkimage | 30 +++++ projects/Amlogic/bootloader/release | 25 ++++ projects/Amlogic/bootloader/update.sh | 40 ++++++ .../bootloader/scripts/aml_autoscript.src | 11 ++ .../AMLGX/bootloader/scripts/boot.scr.src | 4 + .../bootloader/scripts/emmc_autoscript.src | 7 + .../bootloader/scripts/s905_autoscript.src | 9 ++ 11 files changed, 278 insertions(+) create mode 100644 projects/Amlogic/bootloader/box.ini create mode 100644 projects/Amlogic/bootloader/canupdate.sh create mode 100644 projects/Amlogic/bootloader/config create mode 100644 projects/Amlogic/bootloader/install create mode 100644 projects/Amlogic/bootloader/mkimage create mode 100644 projects/Amlogic/bootloader/release create mode 100644 projects/Amlogic/bootloader/update.sh create mode 100644 projects/Amlogic/devices/AMLGX/bootloader/scripts/aml_autoscript.src create mode 100644 projects/Amlogic/devices/AMLGX/bootloader/scripts/boot.scr.src create mode 100644 projects/Amlogic/devices/AMLGX/bootloader/scripts/emmc_autoscript.src create mode 100644 projects/Amlogic/devices/AMLGX/bootloader/scripts/s905_autoscript.src diff --git a/projects/Amlogic/bootloader/box.ini b/projects/Amlogic/bootloader/box.ini new file mode 100644 index 0000000000..600137995f --- /dev/null +++ b/projects/Amlogic/bootloader/box.ini @@ -0,0 +1,7 @@ +WETEK-UBOOT-CONFIG + +# This is a helper file for WeTek Hub and Play2 devices. +# It is not used and safe to delete on every other device. + +fatload mmc 0 1020000 s905_autoscript +autoscr 1020000 diff --git a/projects/Amlogic/bootloader/canupdate.sh b/projects/Amlogic/bootloader/canupdate.sh new file mode 100644 index 0000000000..a69bb605fd --- /dev/null +++ b/projects/Amlogic/bootloader/canupdate.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +# detect legacy kernel installs and abort to prevent upgrades +if [ "$(uname -r)" = "3.14.29" ]; then + echo "Update from 3.14 is not supported!" + sleep 10 + exit 1 +fi + +# allow upgrades between aarch64 and arm images +PROJECT=$("$1" | cut -d. -f1) +if [ "$1" = "${PROJECT}.aarch64" -o "$1" = "${PROJECT}.arm" ]; then + exit 0 +else + exit 1 +fi diff --git a/projects/Amlogic/bootloader/config b/projects/Amlogic/bootloader/config new file mode 100644 index 0000000000..373b083518 --- /dev/null +++ b/projects/Amlogic/bootloader/config @@ -0,0 +1,3 @@ +CONFIG_LZ4=y +CONFIG_LZO=y +CONFIG_LZMA=y diff --git a/projects/Amlogic/bootloader/install b/projects/Amlogic/bootloader/install new file mode 100644 index 0000000000..fc03c50ac5 --- /dev/null +++ b/projects/Amlogic/bootloader/install @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +echo "$BOOTLOADER: creating u-boot.bin" + +DESTDIR="$PKG_BUILD/fip" +mkdir -p $DESTDIR + +FIPDIR="$(get_build_dir amlogic-boot-fip)" + +case "${UBOOT_SYSTEM}" in + box|"") + # No-op, use vendor booloader + ;; + + odroid-c2) + FIPDIR+="/fip" + FUSEDIR="$(get_build_dir amlogic-boot-fip)/sd_fuse" + + $FIPDIR/fip_create --bl30 $FIPDIR/gxb/bl30.bin \ + --bl301 $FIPDIR/gxb/bl301.bin \ + --bl31 $FIPDIR/gxb/bl31.bin \ + --bl33 $(get_build_dir $BOOTLOADER)/u-boot.bin $DESTDIR/fip.bin + + $FIPDIR/fip_create --dump $DESTDIR/fip.bin + + cat $FIPDIR/gxb/bl2.package $DESTDIR/fip.bin > $DESTDIR/boot_new.bin + + $FIPDIR/gxb/aml_encrypt_gxb --bootsig --input $DESTDIR/boot_new.bin --output $DESTDIR/u-boot.img + + dd if=$DESTDIR/u-boot.img of=$DESTDIR/u-boot.gxbb bs=512 skip=96 + dd if=$FUSEDIR/bl1.bin.hardkernel of=$DESTDIR/u-boot.bin.sd.bin conv=fsync,notrunc bs=1 count=442 + dd if=$FUSEDIR/bl1.bin.hardkernel of=$DESTDIR/u-boot.bin.sd.bin conv=fsync,notrunc bs=512 skip=1 seek=1 + dd if=$DESTDIR/u-boot.gxbb of=$DESTDIR/u-boot.bin.sd.bin conv=fsync,notrunc bs=512 seek=97 + ;; + + nanopi-k2) + cp $FIPDIR/gxb/bl2.bin $DESTDIR/ + cp $FIPDIR/gxb/acs.bin $DESTDIR/ + cp $FIPDIR/gxb/bl21.bin $DESTDIR/ + cp $FIPDIR/gxb/bl30.bin $DESTDIR/ + cp $FIPDIR/gxb/bl301.bin $DESTDIR/ + cp $FIPDIR/gxb/bl31.img $DESTDIR/ + cp $(get_build_dir $BOOTLOADER)/u-boot.bin $DESTDIR/bl33.bin + + $FIPDIR/blx_fix.sh $DESTDIR/bl30.bin \ + $DESTDIR/zero_tmp \ + $DESTDIR/bl30_zero.bin \ + $DESTDIR/bl301.bin \ + $DESTDIR/bl301_zero.bin \ + $DESTDIR/bl30_new.bin bl30 + + $FIPDIR/fip_create --bl30 $DESTDIR/bl30_new.bin \ + --bl31 $DESTDIR/bl31.img \ + --bl33 $DESTDIR/bl33.bin \ + $DESTDIR/fip.bin + + $FIPDIR/fip_create --dump $DESTDIR/fip.bin + + python2 $FIPDIR/acs_tool.pyc $DESTDIR/bl2.bin \ + $DESTDIR/bl2_acs.bin \ + $DESTDIR/acs.bin 0 + + $FIPDIR/blx_fix.sh $DESTDIR/bl2_acs.bin \ + $DESTDIR/zero_tmp \ + $DESTDIR/bl2_zero.bin \ + $DESTDIR/bl21.bin \ + $DESTDIR/bl21_zero.bin \ + $DESTDIR/bl2_new.bin bl2 + + cat $DESTDIR/bl2_new.bin $DESTDIR/fip.bin > $DESTDIR/boot_new.bin + + $FIPDIR/gxb/aml_encrypt_gxb --bootsig --input $DESTDIR/boot_new.bin --output $DESTDIR/u-boot.bin.sd.bin + ;; + + *) + cp $FIPDIR/gxl/bl2.bin $DESTDIR/ + cp $FIPDIR/gxl/acs.bin $DESTDIR/ + cp $FIPDIR/gxl/bl21.bin $DESTDIR/ + cp $FIPDIR/gxl/bl30.bin $DESTDIR/ + cp $FIPDIR/gxl/bl301.bin $DESTDIR/ + cp $FIPDIR/gxl/bl31.img $DESTDIR/ + cp $(get_build_dir $BOOTLOADER)/u-boot.bin $DESTDIR/bl33.bin + + $FIPDIR/blx_fix.sh $DESTDIR/bl30.bin \ + $DESTDIR/zero_tmp \ + $DESTDIR/bl30_zero.bin \ + $DESTDIR/bl301.bin \ + $DESTDIR/bl301_zero.bin \ + $DESTDIR/bl30_new.bin bl30 + + python2 $FIPDIR/acs_tool.pyc $DESTDIR/bl2.bin $DESTDIR/bl2_acs.bin $DESTDIR/acs.bin 0 + + $FIPDIR/blx_fix.sh $DESTDIR/bl2_acs.bin \ + $DESTDIR/zero_tmp \ + $DESTDIR/bl2_zero.bin \ + $DESTDIR/bl21.bin \ + $DESTDIR/bl21_zero.bin \ + $DESTDIR/bl2_new.bin bl2 + + $FIPDIR/gxl/aml_encrypt_gxl --bl3enc --input $DESTDIR/bl30_new.bin + $FIPDIR/gxl/aml_encrypt_gxl --bl3enc --input $DESTDIR/bl31.img + $FIPDIR/gxl/aml_encrypt_gxl --bl3enc --input $DESTDIR/bl33.bin + $FIPDIR/gxl/aml_encrypt_gxl --bl2sig --input $DESTDIR/bl2_new.bin --output $DESTDIR/bl2.n.bin.sig + $FIPDIR/gxl/aml_encrypt_gxl --bootmk --output $DESTDIR/u-boot.bin.sd.bin --bl2 $DESTDIR/bl2.n.bin.sig --bl30 $DESTDIR/bl30_new.bin.enc --bl31 $DESTDIR/bl31.img.enc --bl33 $DESTDIR/bl33.bin.enc + ;; + +esac + +# Clean up after previous build +rm -rf $INSTALL/usr/share/bootloader/boot.ini +rm -rf $INSTALL/usr/share/bootloader/u-boot.bin.sd.bin + +mkdir -p $INSTALL/usr/share/bootloader + +if [ -f $DESTDIR/u-boot.bin.sd.bin ] ; then + cp -av $DESTDIR/u-boot.bin.sd.bin $INSTALL/usr/share/bootloader +fi + +# Install boot.ini if it exists +if find_file_path bootloader/${UBOOT_SYSTEM}.ini; then + cp -av ${FOUND_PATH} $INSTALL/usr/share/bootloader/boot.ini +fi diff --git a/projects/Amlogic/bootloader/mkimage b/projects/Amlogic/bootloader/mkimage new file mode 100644 index 0000000000..2d5b9d9694 --- /dev/null +++ b/projects/Amlogic/bootloader/mkimage @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +. config/options $1 + +case "${UBOOT_SYSTEM}" in + box|"") + DTB="@@DTB_NAME@@" + ;; + + *) + echo "image: writing u-boot to $(basename $DISK)" + dd if="$INSTALL/usr/share/bootloader/u-boot.bin.sd.bin" of="$DISK" conv=fsync,notrunc bs=1 count=112 >"$SAVE_ERROR" 2>&1 || show_error + dd if="$INSTALL/usr/share/bootloader/u-boot.bin.sd.bin" of="$DISK" conv=fsync,notrunc bs=512 skip=1 seek=1 >"$SAVE_ERROR" 2>&1 || show_error + + DTB="$(${SCRIPTS}/uboot_helper ${PROJECT} ${DEVICE} ${UBOOT_SYSTEM} dtb)" + ;; +esac + +echo "image: creating uEnv.ini" +cat << EOF > "${LE_TMP}/uEnv.ini" +dtb_name=/dtb/${DTB} +bootargs=boot=UUID=${UUID_SYSTEM} disk=UUID=${UUID_STORAGE} quiet ${EXTRA_CMDLINE} +EOF +mcopy -s "${LE_TMP}/uEnv.ini" :: + +touch "$RELEASE_DIR/3rdparty/bootloader/aml_autoscript.zip" + +echo "image: copying autoscript files and device trees" +mcopy -s ${RELEASE_DIR}/3rdparty/bootloader/* :: diff --git a/projects/Amlogic/bootloader/release b/projects/Amlogic/bootloader/release new file mode 100644 index 0000000000..3e9646b00c --- /dev/null +++ b/projects/Amlogic/bootloader/release @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +mkdir -p "$RELEASE_DIR/3rdparty/bootloader" + cp -a $(get_build_dir u-boot-script)/* $RELEASE_DIR/3rdparty/bootloader + + if find_file_path bootloader/${UBOOT_SYSTEM}.ini; then + cp -av ${FOUND_PATH} $RELEASE_DIR/3rdparty/bootloader/boot.ini + fi + +mkdir -p "$RELEASE_DIR/3rdparty/bootloader/dtb" + case ${DEVICE:-$PROJECT} in + AMLGX) + cp -a $(get_build_dir linux)/arch/$TARGET_KERNEL_ARCH/boot/dts/amlogic/*gxbb*.dtb $RELEASE_DIR/3rdparty/bootloader/dtb + cp -a $(get_build_dir linux)/arch/$TARGET_KERNEL_ARCH/boot/dts/amlogic/*gxl*.dtb $RELEASE_DIR/3rdparty/bootloader/dtb + cp -a $(get_build_dir linux)/arch/$TARGET_KERNEL_ARCH/boot/dts/amlogic/*gxm*.dtb $RELEASE_DIR/3rdparty/bootloader/dtb + ;; + AMLG12) + cp -a $(get_build_dir linux)/arch/$TARGET_KERNEL_ARCH/boot/dts/amlogic/*g12a*.dtb $RELEASE_DIR/3rdparty/bootloader/dtb + cp -a $(get_build_dir linux)/arch/$TARGET_KERNEL_ARCH/boot/dts/amlogic/*g12b*.dtb $RELEASE_DIR/3rdparty/bootloader/dtb + ;; + *) + cp -a $(get_build_dir linux)/arch/$TARGET_KERNEL_ARCH/boot/dts/amlogic/*.dtb $RELEASE_DIR/3rdparty/bootloader/dtb + ;; + esac diff --git a/projects/Amlogic/bootloader/update.sh b/projects/Amlogic/bootloader/update.sh new file mode 100644 index 0000000000..d58ec11bd8 --- /dev/null +++ b/projects/Amlogic/bootloader/update.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) + +[ -z "$SYSTEM_ROOT" ] && SYSTEM_ROOT="" +[ -z "$BOOT_ROOT" ] && BOOT_ROOT="/flash" +[ -z "$BOOT_PART" ] && BOOT_PART=$(df "$BOOT_ROOT" | tail -1 | awk {' print $1 '}) + +# identify the boot device + if [ -z "$BOOT_DISK" ]; then + case $BOOT_PART in + /dev/sd[a-z][0-9]*) + BOOT_DISK=$(echo $BOOT_PART | sed -e "s,[0-9]*,,g") + ;; + /dev/mmcblk*) + BOOT_DISK=$(echo $BOOT_PART | sed -e "s,p[0-9]*,,g") + ;; + esac + fi + +# mount $BOOT_ROOT rw + mount -o remount,rw $BOOT_ROOT + +# update device trees + for dtbfile in $BOOT_ROOT/dtb/*.dtb ; do + dtb=$(basename $dtbfile) + echo "Updating $dtb" + cp -p $SYSTEM_ROOT/usr/share/bootloader/$dtb $BOOT_ROOT/dtb/ 2>/dev/null || true + done + +# update u-boot scripts + for scriptfile in $SYSTEM_ROOT/usr/share/bootloader/*_autoscript* $SYSTEM_ROOT/usr/share/bootloader/*.scr ; do + echo "Updating $(basename $scriptfile)" + cp -p $scriptfile $BOOT_ROOT 2>/dev/null || true + done + +# mount $BOOT_ROOT ro + sync + mount -o remount,ro $BOOT_ROOT diff --git a/projects/Amlogic/devices/AMLGX/bootloader/scripts/aml_autoscript.src b/projects/Amlogic/devices/AMLGX/bootloader/scripts/aml_autoscript.src new file mode 100644 index 0000000000..92b8c80a6c --- /dev/null +++ b/projects/Amlogic/devices/AMLGX/bootloader/scripts/aml_autoscript.src @@ -0,0 +1,11 @@ +defenv +setenv bootcmd 'run start_autoscript; run storeboot' +setenv start_autoscript 'mmcinfo && run start_mmc_autoscript; usb start && run start_usb_autoscript; run start_emmc_autoscript' +setenv start_emmc_autoscript 'fatload mmc 1 1020000 emmc_autoscript && autoscr 1020000' +setenv start_mmc_autoscript 'fatload mmc 0 1020000 s905_autoscript && autoscr 1020000' +setenv start_usb_autoscript 'for usbdev in 0 1 2 3; do fatload usb ${usbdev} 1020000 s905_autoscript && autoscr 1020000; done' +setenv system_part b +setenv upgrade_step 2 +saveenv +sleep 1 +reboot diff --git a/projects/Amlogic/devices/AMLGX/bootloader/scripts/boot.scr.src b/projects/Amlogic/devices/AMLGX/bootloader/scripts/boot.scr.src new file mode 100644 index 0000000000..b4bd3fd46b --- /dev/null +++ b/projects/Amlogic/devices/AMLGX/bootloader/scripts/boot.scr.src @@ -0,0 +1,4 @@ +load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} ${prefix}uEnv.ini && env import -t ${kernel_addr_r} ${filesize} +load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} ${prefix}KERNEL +load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${dtb_name} +bootm ${kernel_addr_r} - ${fdt_addr_r} diff --git a/projects/Amlogic/devices/AMLGX/bootloader/scripts/emmc_autoscript.src b/projects/Amlogic/devices/AMLGX/bootloader/scripts/emmc_autoscript.src new file mode 100644 index 0000000000..8defda50a7 --- /dev/null +++ b/projects/Amlogic/devices/AMLGX/bootloader/scripts/emmc_autoscript.src @@ -0,0 +1,7 @@ +setenv env_addr 0x10400000 +setenv boot_start 'bootm ${loadaddr} - ${dtb_mem_addr}' +setenv addmac 'if printenv mac; then setenv bootargs ${bootargs} mac=${mac}; elif printenv eth_mac; then setenv bootargs ${bootargs} mac=${eth_mac}; fi' +setenv try_boot_start 'if fatload ${devtype} ${devnum} ${loadaddr} KERNEL; then fatload ${devtype} ${devnum} ${env_addr} uEnv.ini && env import -t ${env_addr} ${filesize} && run addmac; fatload ${devtype} ${devnum} ${dtb_mem_addr} ${dtb_name} && run boot_start; fi' +setenv devtype mmc +setenv devnum 1 +run try_boot_start diff --git a/projects/Amlogic/devices/AMLGX/bootloader/scripts/s905_autoscript.src b/projects/Amlogic/devices/AMLGX/bootloader/scripts/s905_autoscript.src new file mode 100644 index 0000000000..b62629db9c --- /dev/null +++ b/projects/Amlogic/devices/AMLGX/bootloader/scripts/s905_autoscript.src @@ -0,0 +1,9 @@ +setenv env_addr 0x10400000 +setenv boot_start 'bootm ${loadaddr} - ${dtb_mem_addr}' +setenv addmac 'if printenv mac; then setenv bootargs ${bootargs} mac=${mac}; elif printenv eth_mac; then setenv bootargs ${bootargs} mac=${eth_mac}; fi' +setenv try_boot_start 'if fatload ${devtype} ${devnum} ${loadaddr} KERNEL; then fatload ${devtype} ${devnum} ${env_addr} uEnv.ini && env import -t ${env_addr} ${filesize} && run addmac; fatload ${devtype} ${devnum} ${dtb_mem_addr} ${dtb_name} && run boot_start; fi' +setenv devtype mmc +setenv devnum 0 +run try_boot_start +setenv devtype usb +for devnum in 0 1 2 3 ; run try_boot_start ; done From 8bf5a18af52635fa471aae66a0cbca6780d34d22 Mon Sep 17 00:00:00 2001 From: chewitt Date: Sun, 6 Jan 2019 14:59:53 +0000 Subject: [PATCH 06/21] project: add cputemp script --- projects/Amlogic/filesystem/usr/bin/cputemp | 8 ++++++++ projects/Amlogic/filesystem/usr/bin/gputemp | 1 + 2 files changed, 9 insertions(+) create mode 100755 projects/Amlogic/filesystem/usr/bin/cputemp create mode 120000 projects/Amlogic/filesystem/usr/bin/gputemp diff --git a/projects/Amlogic/filesystem/usr/bin/cputemp b/projects/Amlogic/filesystem/usr/bin/cputemp new file mode 100755 index 0000000000..66e13bf88e --- /dev/null +++ b/projects/Amlogic/filesystem/usr/bin/cputemp @@ -0,0 +1,8 @@ +#!/bin/sh + +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) + +TEMP=$(cat /sys/class/hwmon/hwmon0/temp1_input) +TEMP="$(( $TEMP / 1000 ))" +echo "${TEMP} C" diff --git a/projects/Amlogic/filesystem/usr/bin/gputemp b/projects/Amlogic/filesystem/usr/bin/gputemp new file mode 120000 index 0000000000..6476b954d2 --- /dev/null +++ b/projects/Amlogic/filesystem/usr/bin/gputemp @@ -0,0 +1 @@ +cputemp \ No newline at end of file From 395db39fc14e51bdf02aca104f7efbabf02f02ca Mon Sep 17 00:00:00 2001 From: chewitt Date: Sat, 23 Mar 2019 06:55:40 +0000 Subject: [PATCH 07/21] project: add mali-bifrost package --- .../linux-drivers/mali-bifrost/package.mk | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 packages/linux-drivers/mali-bifrost/package.mk diff --git a/packages/linux-drivers/mali-bifrost/package.mk b/packages/linux-drivers/mali-bifrost/package.mk new file mode 100644 index 0000000000..47a180cf5e --- /dev/null +++ b/packages/linux-drivers/mali-bifrost/package.mk @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2019-present Team LibreELEC (https://libreelec.tv) + +PKG_NAME="mali-bifrost" +PKG_VERSION="79755036ecadecff0963cb55537d361708618122" # BX301A01B-SW-99002-r16p0-01rel0_meson-g12b +PKG_SHA256="f3d7ea0cc3a0fc215274c19ca3068f0ca0094206663497147906cde8f3671232" +PKG_ARCH="arm aarch64" +PKG_LICENSE="GPL" +PKG_SITE="https://developer.arm.com/products/software/mali-drivers/bifrost-kernel" +PKG_URL="https://github.com/LibreELEC/mali-bifrost/archive/$PKG_VERSION.tar.gz" +PKG_DEPENDS_TARGET="toolchain linux" +PKG_NEED_UNPACK="$LINUX_DEPENDS" +PKG_LONGDESC="mali-midgard: the Linux kernel driver for ARM Mali Midgard GPUs" +PKG_TOOLCHAIN="manual" +PKG_IS_KERNEL_PKG="yes" + +case $PROJECT in + Amlogic) + PKG_MALI_PLATFORM_CONFIG="config.meson-g12a" + ;; +esac + +make_target() { + kernel_make KDIR=$(kernel_path) -C $PKG_BUILD \ + CONFIG_NAME=$PKG_MALI_PLATFORM_CONFIG +} + +makeinstall_target() { + DRIVER_DIR=$PKG_BUILD/driver/product/kernel/drivers/gpu/arm/midgard/ + + mkdir -p $INSTALL/$(get_full_module_dir)/$PKG_NAME + cp $DRIVER_DIR/mali_kbase.ko $INSTALL/$(get_full_module_dir)/$PKG_NAME/ +} From f7bc3c764a863b07e87c01e009cec1c0c6755cd3 Mon Sep 17 00:00:00 2001 From: kszaq Date: Tue, 14 May 2019 23:43:09 +0200 Subject: [PATCH 08/21] project: add AMLGX device --- projects/Amlogic/devices/AMLGX/options | 49 ++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 projects/Amlogic/devices/AMLGX/options diff --git a/projects/Amlogic/devices/AMLGX/options b/projects/Amlogic/devices/AMLGX/options new file mode 100644 index 0000000000..b47d1106cf --- /dev/null +++ b/projects/Amlogic/devices/AMLGX/options @@ -0,0 +1,49 @@ +################################################################################ +# setup device defaults +################################################################################ + + # The TARGET_CPU variable controls which processor should be targeted for + # generated code. + case $TARGET_ARCH in + aarch64) + TARGET_CPU="cortex-a53" + TARGET_CPU_FLAGS="+crc+fp+simd" + TARGET_FEATURES="64bit" + ;; + arm) + TARGET_KERNEL_ARCH="arm64" + TARGET_PATCH_ARCH="aarch64" + TARGET_FLOAT=hard + TARGET_CPU="cortex-a53" + TARGET_CPU_FLAGS="+crc" + TARGET_FPU="neon-fp-armv8" + TARGET_FEATURES="32bit" + ;; + esac + + # Kernel target + KERNEL_TARGET="uImage.lzo" + + # Kernel uImage load address + KERNEL_UIMAGE_LOADADDR="0x1080000" + + # Kernel uImage entry address + KERNEL_UIMAGE_ENTRYADDR="0x1080000" + + # Additional kernel make parameters + KERNEL_MAKE_EXTRACMD="dtbs" + + # kernel serial console + EXTRA_CMDLINE="console=ttyAML0,115200n8 console=tty0" + + # OpenGL-ES implementation to use + OPENGLES="mesa" + + # Graphic drivers to use + GRAPHIC_DRIVERS="lima panfrost" + + # KODI Player implementation to use + KODIPLAYER_DRIVER="$OPENGLES" + + # Mali GPU family + MALI_FAMILY="450 t820" From 97b83a2af0a6da23689143d3fc0229346a51474a Mon Sep 17 00:00:00 2001 From: chewitt Date: Wed, 3 Apr 2019 12:45:05 +0000 Subject: [PATCH 09/21] project: add AMLG12 device --- projects/Amlogic/devices/AMLG12/bootloader | 1 + projects/Amlogic/devices/AMLG12/options | 52 ++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 120000 projects/Amlogic/devices/AMLG12/bootloader create mode 100644 projects/Amlogic/devices/AMLG12/options diff --git a/projects/Amlogic/devices/AMLG12/bootloader b/projects/Amlogic/devices/AMLG12/bootloader new file mode 120000 index 0000000000..8c1b9cac7c --- /dev/null +++ b/projects/Amlogic/devices/AMLG12/bootloader @@ -0,0 +1 @@ +../AMLGX/bootloader \ No newline at end of file diff --git a/projects/Amlogic/devices/AMLG12/options b/projects/Amlogic/devices/AMLG12/options new file mode 100644 index 0000000000..94507e51b8 --- /dev/null +++ b/projects/Amlogic/devices/AMLG12/options @@ -0,0 +1,52 @@ +################################################################################ +# setup device defaults +################################################################################ + + # The TARGET_CPU variable controls which processor should be targeted for + # generated code. + case $TARGET_ARCH in + aarch64) + TARGET_CPU="cortex-a53" + TARGET_CPU_FLAGS="+crc+fp+simd" + TARGET_FEATURES="64bit" + ;; + arm) + TARGET_KERNEL_ARCH="arm64" + TARGET_PATCH_ARCH="aarch64" + TARGET_FLOAT=hard + TARGET_CPU="cortex-a53" + TARGET_CPU_FLAGS="+crc" + TARGET_FPU="neon-fp-armv8" + TARGET_FEATURES="32bit" + ;; + esac + + # Kernel target + KERNEL_TARGET="uImage.lzo" + + # Kernel uImage load address + KERNEL_UIMAGE_LOADADDR="0x1080000" + + # Kernel uImage entry address + KERNEL_UIMAGE_ENTRYADDR="0x1080000" + + # Additional kernel make parameters + KERNEL_MAKE_EXTRACMD="dtbs" + + # kernel serial console + EXTRA_CMDLINE="console=ttyAML0,115200n8 console=tty0" + + # OpenGL-ES implementation to use + OPENGLES="libmali" + + # Graphic drivers to use + GRAPHIC_DRIVERS="" + + # KODI Player implementation to use + KODIPLAYER_DRIVER="$OPENGLES" + + # Mali GPU family + MALI_FAMILY="g31 g52" + + # additional drivers to install + ADDITIONAL_DRIVERS+=" mali-bifrost" From 15d4b2b4b0e81520231ec78055dbae096e7890be Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 26 Sep 2018 06:49:40 +0400 Subject: [PATCH 10/21] project: add linux defconfig (5.1) --- projects/Amlogic/linux/linux.aarch64.conf | 5272 +++++++++++++++++++++ 1 file changed, 5272 insertions(+) create mode 100644 projects/Amlogic/linux/linux.aarch64.conf diff --git a/projects/Amlogic/linux/linux.aarch64.conf b/projects/Amlogic/linux/linux.aarch64.conf new file mode 100644 index 0000000000..0fbb2e2e92 --- /dev/null +++ b/projects/Amlogic/linux/linux.aarch64.conf @@ -0,0 +1,5272 @@ +# +# Automatically generated file; DO NOT EDIT. +# Linux/arm64 5.1.0 Kernel Configuration +# + +# +# Compiler: aarch64-libreelec-linux-gnueabi-gcc-8.3.0 (GCC) 8.3.0 +# +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=80300 +CONFIG_CLANG_VERSION=0 +CONFIG_CC_HAS_ASM_GOTO=y +CONFIG_CC_HAS_WARN_MAYBE_UNINITIALIZED=y +CONFIG_IRQ_WORK=y +CONFIG_BUILDTIME_EXTABLE_SORT=y +CONFIG_THREAD_INFO_IN_TASK=y + +# +# General setup +# +CONFIG_INIT_ENV_ARG_LIMIT=32 +# CONFIG_COMPILE_TEST is not set +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_BUILD_SALT="" +CONFIG_DEFAULT_HOSTNAME="@DISTRONAME@" +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +CONFIG_CROSS_MEMORY_ATTACH=y +# CONFIG_USELIB is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_ARCH_AUDITSYSCALL=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_MIGRATION=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_CHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_HANDLE_DOMAIN_IRQ=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_SPARSE_IRQ=y +# CONFIG_GENERIC_IRQ_DEBUGFS is not set +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_ARCH_CLOCKSOURCE_DATA=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_ARCH_HAS_TICK_BROADCAST=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y + +# +# Timers subsystem +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ_COMMON=y +# CONFIG_HZ_PERIODIC is not set +CONFIG_NO_HZ_IDLE=y +# CONFIG_NO_HZ_FULL is not set +# CONFIG_NO_HZ is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_PREEMPT_NONE is not set +CONFIG_PREEMPT_VOLUNTARY=y +# CONFIG_PREEMPT is not set + +# +# CPU/Task time and stats accounting +# +CONFIG_TICK_CPU_ACCOUNTING=y +# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set +# CONFIG_IRQ_TIME_ACCOUNTING is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_PSI is not set +CONFIG_CPU_ISOLATION=y + +# +# RCU Subsystem +# +CONFIG_TREE_RCU=y +# CONFIG_RCU_EXPERT is not set +CONFIG_SRCU=y +CONFIG_TREE_SRCU=y +CONFIG_RCU_STALL_COMMON=y +CONFIG_RCU_NEED_SEGCBLIST=y +CONFIG_BUILD_BIN2C=y +CONFIG_IKCONFIG=m +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_LOG_CPU_MAX_BUF_SHIFT=12 +CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13 +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y +CONFIG_ARCH_SUPPORTS_INT128=y +CONFIG_CGROUPS=y +CONFIG_PAGE_COUNTER=y +CONFIG_MEMCG=y +# CONFIG_MEMCG_SWAP is not set +CONFIG_MEMCG_KMEM=y +CONFIG_BLK_CGROUP=y +# CONFIG_DEBUG_BLK_CGROUP is not set +CONFIG_CGROUP_WRITEBACK=y +CONFIG_CGROUP_SCHED=y +# CONFIG_FAIR_GROUP_SCHED is not set +# CONFIG_RT_GROUP_SCHED is not set +# CONFIG_CGROUP_PIDS is not set +# CONFIG_CGROUP_RDMA is not set +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_PROC_PID_CPUSET=y +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +# CONFIG_CGROUP_PERF is not set +CONFIG_CGROUP_BPF=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_SOCK_CGROUP_DATA=y +CONFIG_NAMESPACES=y +CONFIG_UTS_NS=y +CONFIG_IPC_NS=y +# CONFIG_USER_NS is not set +CONFIG_PID_NS=y +CONFIG_NET_NS=y +# CONFIG_CHECKPOINT_RESTORE is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_RD_GZIP is not set +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_HAVE_UID16=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +CONFIG_BPF=y +CONFIG_EXPERT=y +# CONFIG_UID16 is not set +CONFIG_MULTIUSER=y +# CONFIG_SGETMASK_SYSCALL is not set +# CONFIG_SYSFS_SYSCALL is not set +CONFIG_SYSCTL_SYSCALL=y +CONFIG_FHANDLE=y +CONFIG_POSIX_TIMERS=y +CONFIG_PRINTK=y +CONFIG_PRINTK_NMI=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_FUTEX_PI=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_AIO=y +CONFIG_IO_URING=y +CONFIG_ADVISE_SYSCALLS=y +CONFIG_MEMBARRIER=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_ALL is not set +CONFIG_KALLSYMS_BASE_RELATIVE=y +CONFIG_BPF_SYSCALL=y +# CONFIG_USERFAULTFD is not set +CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y +CONFIG_RSEQ=y +# CONFIG_DEBUG_RSEQ is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +# CONFIG_PC104 is not set + +# +# Kernel Performance Events And Counters +# +CONFIG_PERF_EVENTS=y +# CONFIG_DEBUG_PERF_USE_VMALLOC is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +# CONFIG_SLUB_MEMCG_SYSFS_ON is not set +# CONFIG_COMPAT_BRK is not set +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +CONFIG_SLAB_MERGE_DEFAULT=y +# CONFIG_SLAB_FREELIST_RANDOM is not set +# CONFIG_SLAB_FREELIST_HARDENED is not set +CONFIG_SLUB_CPU_PARTIAL=y +CONFIG_SYSTEM_DATA_VERIFICATION=y +CONFIG_PROFILING=y +CONFIG_ARM64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_ARM64_PAGE_SHIFT=12 +CONFIG_ARM64_CONT_SHIFT=4 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=33 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=11 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16 +CONFIG_NO_IOPORT_MAP=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000 +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_ZONE_DMA32=y +CONFIG_HAVE_GENERIC_GUP=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_SMP=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_PGTABLE_LEVELS=4 +CONFIG_ARCH_SUPPORTS_UPROBES=y +CONFIG_ARCH_PROC_KCORE_TEXT=y + +# +# Platform selection +# +# CONFIG_ARCH_ACTIONS is not set +# CONFIG_ARCH_SUNXI is not set +# CONFIG_ARCH_ALPINE is not set +# CONFIG_ARCH_BCM2835 is not set +# CONFIG_ARCH_BCM_IPROC is not set +# CONFIG_ARCH_BERLIN is not set +# CONFIG_ARCH_BITMAIN is not set +# CONFIG_ARCH_BRCMSTB is not set +# CONFIG_ARCH_EXYNOS is not set +# CONFIG_ARCH_K3 is not set +# CONFIG_ARCH_LAYERSCAPE is not set +# CONFIG_ARCH_LG1K is not set +# CONFIG_ARCH_HISI is not set +# CONFIG_ARCH_MEDIATEK is not set +CONFIG_ARCH_MESON=y +# CONFIG_ARCH_MVEBU is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_QCOM is not set +# CONFIG_ARCH_REALTEK is not set +# CONFIG_ARCH_RENESAS is not set +# CONFIG_ARCH_ROCKCHIP is not set +# CONFIG_ARCH_SEATTLE is not set +# CONFIG_ARCH_STRATIX10 is not set +# CONFIG_ARCH_SYNQUACER is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_SPRD is not set +# CONFIG_ARCH_THUNDER is not set +# CONFIG_ARCH_THUNDER2 is not set +# CONFIG_ARCH_UNIPHIER is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_XGENE is not set +# CONFIG_ARCH_ZX is not set +# CONFIG_ARCH_ZYNQMP is not set + +# +# Kernel Features +# + +# +# ARM errata workarounds via the alternatives framework +# +CONFIG_ARM64_WORKAROUND_CLEAN_CACHE=y +CONFIG_ARM64_ERRATUM_826319=y +CONFIG_ARM64_ERRATUM_827319=y +CONFIG_ARM64_ERRATUM_824069=y +CONFIG_ARM64_ERRATUM_819472=y +# CONFIG_ARM64_ERRATUM_832075 is not set +CONFIG_ARM64_ERRATUM_845719=y +CONFIG_ARM64_ERRATUM_843419=y +# CONFIG_ARM64_ERRATUM_1024718 is not set +# CONFIG_ARM64_ERRATUM_1188873 is not set +# CONFIG_ARM64_ERRATUM_1165522 is not set +# CONFIG_ARM64_ERRATUM_1286807 is not set +# CONFIG_CAVIUM_ERRATUM_22375 is not set +# CONFIG_CAVIUM_ERRATUM_23154 is not set +# CONFIG_CAVIUM_ERRATUM_27456 is not set +# CONFIG_CAVIUM_ERRATUM_30115 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1003 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_1009 is not set +# CONFIG_QCOM_QDF2400_ERRATUM_0065 is not set +# CONFIG_SOCIONEXT_SYNQUACER_PREITS is not set +# CONFIG_HISILICON_ERRATUM_161600802 is not set +# CONFIG_QCOM_FALKOR_ERRATUM_E1041 is not set +# CONFIG_FUJITSU_ERRATUM_010001 is not set +CONFIG_ARM64_4K_PAGES=y +# CONFIG_ARM64_16K_PAGES is not set +# CONFIG_ARM64_64K_PAGES is not set +# CONFIG_ARM64_VA_BITS_39 is not set +CONFIG_ARM64_VA_BITS_48=y +CONFIG_ARM64_VA_BITS=48 +CONFIG_ARM64_PA_BITS_48=y +CONFIG_ARM64_PA_BITS=48 +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_SCHED_MC is not set +# CONFIG_SCHED_SMT is not set +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +# CONFIG_NUMA is not set +CONFIG_HOLES_IN_ZONE=y +# CONFIG_HZ_100 is not set +# CONFIG_HZ_250 is not set +CONFIG_HZ_300=y +# CONFIG_HZ_1000 is not set +CONFIG_HZ=300 +CONFIG_SCHED_HRTICK=y +CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_FLATMEM_ENABLE=y +CONFIG_HAVE_ARCH_PFN_VALID=y +CONFIG_HW_PERF_EVENTS=y +CONFIG_SYS_SUPPORTS_HUGETLBFS=y +CONFIG_ARCH_WANT_HUGE_PMD_SHARE=y +CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y +CONFIG_SECCOMP=y +# CONFIG_PARAVIRT is not set +# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set +# CONFIG_KEXEC is not set +# CONFIG_KEXEC_FILE is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_XEN is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_UNMAP_KERNEL_AT_EL0=y +CONFIG_HARDEN_BRANCH_PREDICTOR=y +CONFIG_HARDEN_EL2_VECTORS=y +CONFIG_ARM64_SSBD=y +CONFIG_RODATA_FULL_DEFAULT_ENABLED=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_SW_TTBR0_PAN is not set + +# +# ARMv8.1 architectural features +# +# CONFIG_ARM64_HW_AFDBM is not set +# CONFIG_ARM64_PAN is not set +# CONFIG_ARM64_LSE_ATOMICS is not set +# CONFIG_ARM64_VHE is not set + +# +# ARMv8.2 architectural features +# +# CONFIG_ARM64_UAO is not set +# CONFIG_ARM64_PMEM is not set +# CONFIG_ARM64_RAS_EXTN is not set +# CONFIG_ARM64_CNP is not set + +# +# ARMv8.3 architectural features +# +# CONFIG_ARM64_PTR_AUTH is not set +CONFIG_ARM64_SVE=y +CONFIG_ARM64_MODULE_PLTS=y +# CONFIG_ARM64_PSEUDO_NMI is not set +# CONFIG_RANDOMIZE_BASE is not set + +# +# Boot options +# +CONFIG_CMDLINE="" +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_EFI is not set +CONFIG_COMPAT=y +CONFIG_SYSVIPC_COMPAT=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +# CONFIG_SUSPEND_SKIP_SYNC is not set +# CONFIG_HIBERNATION is not set +CONFIG_PM_SLEEP=y +CONFIG_PM_SLEEP_SMP=y +# CONFIG_PM_AUTOSLEEP is not set +# CONFIG_PM_WAKELOCKS is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_CLK=y +CONFIG_PM_GENERIC_DOMAINS=y +# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set +CONFIG_PM_GENERIC_DOMAINS_SLEEP=y +CONFIG_PM_GENERIC_DOMAINS_OF=y +CONFIG_CPU_PM=y +# CONFIG_ENERGY_MODEL is not set +CONFIG_ARCH_HIBERNATION_POSSIBLE=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y + +# +# CPU Power Management +# + +# +# CPU Idle +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_MULTIPLE_DRIVERS=y +# CONFIG_CPU_IDLE_GOV_LADDER is not set +CONFIG_CPU_IDLE_GOV_MENU=y +# CONFIG_CPU_IDLE_GOV_TEO is not set +CONFIG_DT_IDLE_STATES=y + +# +# ARM CPU Idle Drivers +# +CONFIG_ARM_CPUIDLE=y + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ATTR_SET=y +CONFIG_CPU_FREQ_GOV_COMMON=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_SCHEDUTIL is not set +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +# CONFIG_CPU_FREQ_GOV_USERSPACE is not set +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set +# CONFIG_CPU_FREQ_GOV_SCHEDUTIL is not set + +# +# CPU frequency scaling drivers +# +CONFIG_CPUFREQ_DT=y +CONFIG_CPUFREQ_DT_PLATDEV=y +CONFIG_ARM_SCPI_CPUFREQ=y +# CONFIG_QORIQ_CPUFREQ is not set + +# +# Firmware Drivers +# +CONFIG_ARM_PSCI_FW=y +# CONFIG_ARM_PSCI_CHECKER is not set +# CONFIG_ARM_SCMI_PROTOCOL is not set +CONFIG_ARM_SCPI_PROTOCOL=y +CONFIG_ARM_SCPI_POWER_DOMAIN=y +# CONFIG_ARM_SDE_INTERFACE is not set +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_HAVE_ARM_SMCCC=y +# CONFIG_GOOGLE_FIRMWARE is not set +CONFIG_EFI_EARLYCON=y +CONFIG_MESON_SM=y + +# +# Tegra firmware driver +# +# CONFIG_VIRTUALIZATION is not set +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA256_ARM64=y +# CONFIG_CRYPTO_SHA512_ARM64 is not set +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +# CONFIG_CRYPTO_SHA512_ARM64_CE is not set +# CONFIG_CRYPTO_SHA3_ARM64 is not set +# CONFIG_CRYPTO_SM3_ARM64_CE is not set +# CONFIG_CRYPTO_SM4_ARM64_CE is not set +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64=y +CONFIG_CRYPTO_AES_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_CRYPTO_CHACHA20_NEON=y +# CONFIG_CRYPTO_NHPOLY1305_NEON is not set +CONFIG_CRYPTO_AES_ARM64_BS=y + +# +# General architecture-dependent options +# +# CONFIG_KPROBES is not set +CONFIG_JUMP_LABEL=y +# CONFIG_STATIC_KEYS_SELFTEST is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_NMI=y +CONFIG_HAVE_ARCH_TRACEHOOK=y +CONFIG_HAVE_DMA_CONTIGUOUS=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_ARCH_HAS_FORTIFY_SOURCE=y +CONFIG_ARCH_HAS_SET_MEMORY=y +CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_RSEQ=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_HW_BREAKPOINT=y +CONFIG_HAVE_PERF_REGS=y +CONFIG_HAVE_PERF_USER_STACK_DUMP=y +CONFIG_HAVE_ARCH_JUMP_LABEL=y +CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y +CONFIG_HAVE_RCU_TABLE_FREE=y +CONFIG_HAVE_RCU_TABLE_INVALIDATE=y +CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y +CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y +CONFIG_HAVE_CMPXCHG_LOCAL=y +CONFIG_HAVE_CMPXCHG_DOUBLE=y +CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION=y +CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_SECCOMP_FILTER=y +CONFIG_HAVE_ARCH_STACKLEAK=y +CONFIG_HAVE_STACKPROTECTOR=y +CONFIG_CC_HAS_STACKPROTECTOR_NONE=y +CONFIG_STACKPROTECTOR=y +CONFIG_STACKPROTECTOR_STRONG=y +CONFIG_HAVE_CONTEXT_TRACKING=y +CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y +CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y +CONFIG_HAVE_ARCH_HUGE_VMAP=y +CONFIG_HAVE_MOD_ARCH_SPECIFIC=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_ARCH_HAS_ELF_RANDOMIZE=y +CONFIG_HAVE_ARCH_MMAP_RND_BITS=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS=y +CONFIG_ARCH_MMAP_RND_COMPAT_BITS=11 +CONFIG_CLONE_BACKWARDS=y +CONFIG_OLD_SIGSUSPEND3=y +CONFIG_COMPAT_OLD_SIGACTION=y +CONFIG_COMPAT_32BIT_TIME=y +CONFIG_HAVE_ARCH_VMAP_STACK=y +CONFIG_VMAP_STACK=y +CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y +CONFIG_STRICT_KERNEL_RWX=y +CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y +CONFIG_STRICT_MODULE_RWX=y +CONFIG_REFCOUNT_FULL=y +CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y +CONFIG_ARCH_USE_MEMREMAP_PROT=y + +# +# GCOV-based kernel profiling +# +# CONFIG_GCOV_KERNEL is not set +CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y +CONFIG_PLUGIN_HOSTCC="" +CONFIG_HAVE_GCC_PLUGINS=y +# CONFIG_GCC_PLUGINS is not set +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_FORCE_LOAD is not set +CONFIG_MODULE_UNLOAD=y +# CONFIG_MODULE_FORCE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_MODULE_SIG is not set +# CONFIG_MODULE_COMPRESS is not set +# CONFIG_TRIM_UNUSED_KSYMS is not set +CONFIG_MODULES_TREE_LOOKUP=y +CONFIG_BLOCK=y +CONFIG_BLK_SCSI_REQUEST=y +CONFIG_BLK_DEV_BSG=y +CONFIG_BLK_DEV_BSGLIB=y +# CONFIG_BLK_DEV_INTEGRITY is not set +# CONFIG_BLK_DEV_ZONED is not set +# CONFIG_BLK_DEV_THROTTLING is not set +# CONFIG_BLK_CMDLINE_PARSER is not set +# CONFIG_BLK_WBT is not set +# CONFIG_BLK_CGROUP_IOLATENCY is not set +CONFIG_BLK_DEBUG_FS=y +# CONFIG_BLK_SED_OPAL is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_AIX_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +CONFIG_MAC_PARTITION=y +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +CONFIG_LDM_PARTITION=y +# CONFIG_LDM_DEBUG is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +# CONFIG_CMDLINE_PARTITION is not set +CONFIG_BLOCK_COMPAT=y +CONFIG_BLK_PM=y + +# +# IO Schedulers +# +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_IOSCHED_BFQ=y +# CONFIG_BFQ_GROUP_IOSCHED is not set +CONFIG_PADATA=y +CONFIG_ASN1=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK=y +CONFIG_ARCH_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK=y +CONFIG_ARCH_INLINE_SPIN_LOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_BH=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_READ_LOCK=y +CONFIG_ARCH_INLINE_READ_LOCK_BH=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_READ_UNLOCK=y +CONFIG_ARCH_INLINE_READ_UNLOCK_BH=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_INLINE_WRITE_LOCK=y +CONFIG_ARCH_INLINE_WRITE_LOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_BH=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_SPIN_TRYLOCK=y +CONFIG_INLINE_SPIN_TRYLOCK_BH=y +CONFIG_INLINE_SPIN_LOCK=y +CONFIG_INLINE_SPIN_LOCK_BH=y +CONFIG_INLINE_SPIN_LOCK_IRQ=y +CONFIG_INLINE_SPIN_LOCK_IRQSAVE=y +CONFIG_INLINE_SPIN_UNLOCK_BH=y +CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_READ_LOCK=y +CONFIG_INLINE_READ_LOCK_BH=y +CONFIG_INLINE_READ_LOCK_IRQ=y +CONFIG_INLINE_READ_LOCK_IRQSAVE=y +CONFIG_INLINE_READ_UNLOCK=y +CONFIG_INLINE_READ_UNLOCK_BH=y +CONFIG_INLINE_READ_UNLOCK_IRQ=y +CONFIG_INLINE_READ_UNLOCK_IRQRESTORE=y +CONFIG_INLINE_WRITE_LOCK=y +CONFIG_INLINE_WRITE_LOCK_BH=y +CONFIG_INLINE_WRITE_LOCK_IRQ=y +CONFIG_INLINE_WRITE_LOCK_IRQSAVE=y +CONFIG_INLINE_WRITE_UNLOCK=y +CONFIG_INLINE_WRITE_UNLOCK_BH=y +CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE=y +CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y +CONFIG_QUEUED_SPINLOCKS=y +CONFIG_ARCH_USE_QUEUED_RWLOCKS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_ARCH_HAS_SYSCALL_WRAPPER=y +CONFIG_FREEZER=y + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +CONFIG_COMPAT_BINFMT_ELF=y +CONFIG_ELFCORE=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_SCRIPT=y +# CONFIG_BINFMT_MISC is not set +CONFIG_COREDUMP=y + +# +# Memory Management options +# +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSEMEM_VMEMMAP=y +CONFIG_MEMORY_ISOLATION=y +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +CONFIG_PHYS_ADDR_T_64BIT=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y +# CONFIG_MEMORY_FAILURE is not set +CONFIG_TRANSPARENT_HUGEPAGE=y +CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y +# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set +CONFIG_TRANSPARENT_HUGE_PAGECACHE=y +CONFIG_CLEANCACHE=y +CONFIG_FRONTSWAP=y +CONFIG_CMA=y +# CONFIG_CMA_DEBUG is not set +CONFIG_CMA_DEBUGFS=y +CONFIG_CMA_AREAS=7 +# CONFIG_ZSWAP is not set +# CONFIG_ZPOOL is not set +# CONFIG_ZBUD is not set +# CONFIG_ZSMALLOC is not set +CONFIG_GENERIC_EARLY_IOREMAP=y +# CONFIG_DEFERRED_STRUCT_PAGE_INIT is not set +# CONFIG_IDLE_PAGE_TRACKING is not set +CONFIG_FRAME_VECTOR=y +# CONFIG_PERCPU_STATS is not set +# CONFIG_GUP_BENCHMARK is not set +CONFIG_ARCH_HAS_PTE_SPECIAL=y +CONFIG_NET=y +CONFIG_COMPAT_NETLINK_MESSAGES=y +CONFIG_NET_INGRESS=y +CONFIG_SKB_EXTENSIONS=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_DIAG is not set +CONFIG_UNIX=y +CONFIG_UNIX_SCM=y +# CONFIG_UNIX_DIAG is not set +# CONFIG_TLS is not set +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_INTERFACE is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# CONFIG_NET_KEY is not set +# CONFIG_XDP_SOCKETS is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +CONFIG_NET_IP_TUNNEL=m +CONFIG_IP_MROUTE_COMMON=y +CONFIG_IP_MROUTE=y +# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set +# CONFIG_SYN_COOKIES is not set +CONFIG_NET_UDP_TUNNEL=m +CONFIG_NET_FOU=m +# CONFIG_NET_FOU_IP_TUNNELS is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +CONFIG_INET_TUNNEL=m +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_INET_UDP_DIAG is not set +# CONFIG_INET_RAW_DIAG is not set +# CONFIG_INET_DIAG_DESTROY is not set +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +CONFIG_TCP_CONG_CUBIC=y +# CONFIG_TCP_CONG_WESTWOOD is not set +CONFIG_TCP_CONG_HTCP=m +CONFIG_TCP_CONG_HSTCP=m +# CONFIG_TCP_CONG_HYBLA is not set +CONFIG_TCP_CONG_VEGAS=m +# CONFIG_TCP_CONG_NV is not set +CONFIG_TCP_CONG_SCALABLE=m +# CONFIG_TCP_CONG_LP is not set +CONFIG_TCP_CONG_VENO=m +CONFIG_TCP_CONG_YEAH=m +CONFIG_TCP_CONG_ILLINOIS=m +# CONFIG_TCP_CONG_DCTCP is not set +CONFIG_TCP_CONG_CDG=m +# CONFIG_TCP_CONG_BBR is not set +CONFIG_DEFAULT_CUBIC=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +# CONFIG_IPV6_ROUTER_PREF is not set +# CONFIG_IPV6_OPTIMISTIC_DAD is not set +# CONFIG_INET6_AH is not set +# CONFIG_INET6_ESP is not set +# CONFIG_INET6_IPCOMP is not set +# CONFIG_IPV6_MIP6 is not set +# CONFIG_IPV6_ILA is not set +# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET6_XFRM_MODE_TUNNEL is not set +# CONFIG_INET6_XFRM_MODE_BEET is not set +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=m +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +# CONFIG_IPV6_TUNNEL is not set +CONFIG_IPV6_FOU=m +# CONFIG_IPV6_MULTIPLE_TABLES is not set +# CONFIG_IPV6_MROUTE is not set +# CONFIG_IPV6_SEG6_LWTUNNEL is not set +# CONFIG_IPV6_SEG6_HMAC is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_ADVANCED=y +CONFIG_BRIDGE_NETFILTER=m + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_INGRESS=y +CONFIG_NETFILTER_NETLINK=m +CONFIG_NETFILTER_FAMILY_BRIDGE=y +# CONFIG_NETFILTER_NETLINK_ACCT is not set +# CONFIG_NETFILTER_NETLINK_QUEUE is not set +CONFIG_NETFILTER_NETLINK_LOG=m +# CONFIG_NETFILTER_NETLINK_OSF is not set +CONFIG_NF_CONNTRACK=m +# CONFIG_NF_LOG_NETDEV is not set +# CONFIG_NF_CONNTRACK_MARK is not set +# CONFIG_NF_CONNTRACK_ZONES is not set +CONFIG_NF_CONNTRACK_PROCFS=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMEOUT is not set +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +# CONFIG_NF_CONNTRACK_LABELS is not set +# CONFIG_NF_CT_PROTO_DCCP is not set +# CONFIG_NF_CT_PROTO_SCTP is not set +# CONFIG_NF_CT_PROTO_UDPLITE is not set +# CONFIG_NF_CONNTRACK_AMANDA is not set +CONFIG_NF_CONNTRACK_FTP=m +# CONFIG_NF_CONNTRACK_H323 is not set +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_BROADCAST=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +# CONFIG_NF_CONNTRACK_SNMP is not set +# CONFIG_NF_CONNTRACK_PPTP is not set +# CONFIG_NF_CONNTRACK_SANE is not set +CONFIG_NF_CONNTRACK_SIP=m +# CONFIG_NF_CONNTRACK_TFTP is not set +CONFIG_NF_CT_NETLINK=m +# CONFIG_NETFILTER_NETLINK_GLUE_CT is not set +CONFIG_NF_NAT=m +CONFIG_NF_NAT_NEEDED=y +CONFIG_NF_NAT_FTP=m +CONFIG_NF_NAT_IRC=m +CONFIG_NF_NAT_SIP=m +CONFIG_NF_NAT_MASQUERADE=y +# CONFIG_NF_TABLES is not set +CONFIG_NETFILTER_XTABLES=m + +# +# Xtables combined modules +# +# CONFIG_NETFILTER_XT_MARK is not set +# CONFIG_NETFILTER_XT_CONNMARK is not set + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set +# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_HMARK is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +# CONFIG_NETFILTER_XT_TARGET_LED is not set +# CONFIG_NETFILTER_XT_TARGET_LOG is not set +# CONFIG_NETFILTER_XT_TARGET_MARK is not set +CONFIG_NETFILTER_XT_NAT=m +# CONFIG_NETFILTER_XT_TARGET_NETMAP is not set +# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set +# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_REDIRECT is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +# CONFIG_NETFILTER_XT_TARGET_TPROXY is not set +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +# CONFIG_NETFILTER_XT_MATCH_BPF is not set +# CONFIG_NETFILTER_XT_MATCH_CGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLABEL is not set +# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ECN is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_HELPER is not set +# CONFIG_NETFILTER_XT_MATCH_HL is not set +# CONFIG_NETFILTER_XT_MATCH_IPCOMP is not set +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set +# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set +# CONFIG_NETFILTER_XT_MATCH_MAC is not set +# CONFIG_NETFILTER_XT_MATCH_MARK is not set +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_NFACCT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +CONFIG_NETFILTER_XT_MATCH_OWNER=m +# CONFIG_NETFILTER_XT_MATCH_POLICY is not set +# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set +# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +# CONFIG_NETFILTER_XT_MATCH_SOCKET is not set +CONFIG_NETFILTER_XT_MATCH_STATE=m +# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set +# CONFIG_NETFILTER_XT_MATCH_STRING is not set +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +# CONFIG_NETFILTER_XT_MATCH_TIME is not set +# CONFIG_NETFILTER_XT_MATCH_U32 is not set +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=m +# CONFIG_NF_SOCKET_IPV4 is not set +# CONFIG_NF_TPROXY_IPV4 is not set +# CONFIG_NF_DUP_IPV4 is not set +# CONFIG_NF_LOG_ARP is not set +# CONFIG_NF_LOG_IPV4 is not set +CONFIG_NF_REJECT_IPV4=m +CONFIG_IP_NF_IPTABLES=m +# CONFIG_IP_NF_MATCH_AH is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_RPFILTER is not set +# CONFIG_IP_NF_MATCH_TTL is not set +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +# CONFIG_IP_NF_TARGET_SYNPROXY is not set +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_REDIRECT is not set +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +# CONFIG_IP_NF_RAW is not set +# CONFIG_IP_NF_ARPTABLES is not set + +# +# IPv6: Netfilter Configuration +# +# CONFIG_NF_SOCKET_IPV6 is not set +# CONFIG_NF_TPROXY_IPV6 is not set +# CONFIG_NF_DUP_IPV6 is not set +CONFIG_NF_REJECT_IPV6=m +# CONFIG_NF_LOG_IPV6 is not set +CONFIG_IP6_NF_IPTABLES=m +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RPFILTER is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_MATCH_SRH is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +# CONFIG_IP6_NF_TARGET_SYNPROXY is not set +CONFIG_IP6_NF_MANGLE=m +# CONFIG_IP6_NF_RAW is not set +CONFIG_IP6_NF_NAT=m +# CONFIG_IP6_NF_TARGET_MASQUERADE is not set +# CONFIG_IP6_NF_TARGET_NPT is not set +CONFIG_NF_DEFRAG_IPV6=m +# CONFIG_BRIDGE_NF_EBTABLES is not set +# CONFIG_BPFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +CONFIG_STP=m +CONFIG_BRIDGE=m +CONFIG_BRIDGE_IGMP_SNOOPING=y +# CONFIG_BRIDGE_VLAN_FILTERING is not set +CONFIG_HAVE_NET_DSA=y +# CONFIG_NET_DSA is not set +CONFIG_VLAN_8021Q=m +# CONFIG_VLAN_8021Q_GVRP is not set +# CONFIG_VLAN_8021Q_MVRP is not set +# CONFIG_DECNET is not set +CONFIG_LLC=m +# CONFIG_LLC2 is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_PHONET is not set +# CONFIG_6LOWPAN is not set +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +# CONFIG_NET_SCH_SFB is not set +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_CBS is not set +# CONFIG_NET_SCH_ETF is not set +# CONFIG_NET_SCH_TAPRIO is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_SKBPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_CODEL is not set +CONFIG_NET_SCH_FQ_CODEL=y +# CONFIG_NET_SCH_CAKE is not set +# CONFIG_NET_SCH_FQ is not set +# CONFIG_NET_SCH_HHF is not set +# CONFIG_NET_SCH_PIE is not set +# CONFIG_NET_SCH_PLUG is not set +# CONFIG_NET_SCH_DEFAULT is not set + +# +# Classification +# +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +# CONFIG_NET_CLS_U32 is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +# CONFIG_NET_CLS_BPF is not set +# CONFIG_NET_CLS_FLOWER is not set +# CONFIG_NET_CLS_MATCHALL is not set +# CONFIG_NET_EMATCH is not set +# CONFIG_NET_CLS_ACT is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +CONFIG_DNS_RESOLVER=y +# CONFIG_BATMAN_ADV is not set +# CONFIG_OPENVSWITCH is not set +# CONFIG_VSOCKETS is not set +# CONFIG_NETLINK_DIAG is not set +# CONFIG_MPLS is not set +# CONFIG_NET_NSH is not set +# CONFIG_HSR is not set +# CONFIG_NET_SWITCHDEV is not set +# CONFIG_NET_L3_MASTER_DEV is not set +# CONFIG_NET_NCSI is not set +CONFIG_RPS=y +CONFIG_RFS_ACCEL=y +CONFIG_XPS=y +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set +CONFIG_NET_RX_BUSY_POLL=y +CONFIG_BQL=y +# CONFIG_BPF_JIT is not set +# CONFIG_BPF_STREAM_PARSER is not set +CONFIG_NET_FLOW_LIMIT=y + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +CONFIG_BT=m +CONFIG_BT_BREDR=y +CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM_TTY=y +# CONFIG_BT_BNEP is not set +CONFIG_BT_HIDP=m +CONFIG_BT_HS=y +CONFIG_BT_LE=y +# CONFIG_BT_LEDS is not set +# CONFIG_BT_SELFTEST is not set +# CONFIG_BT_DEBUGFS is not set + +# +# Bluetooth device drivers +# +CONFIG_BT_INTEL=m +CONFIG_BT_BCM=m +CONFIG_BT_RTL=m +CONFIG_BT_QCA=m +CONFIG_BT_HCIBTUSB=m +# CONFIG_BT_HCIBTUSB_AUTOSUSPEND is not set +CONFIG_BT_HCIBTUSB_BCM=y +CONFIG_BT_HCIBTUSB_RTL=y +CONFIG_BT_HCIBTSDIO=m +CONFIG_BT_HCIUART=m +CONFIG_BT_HCIUART_SERDEV=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_NOKIA is not set +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +# CONFIG_BT_HCIUART_LL is not set +CONFIG_BT_HCIUART_3WIRE=y +# CONFIG_BT_HCIUART_INTEL is not set +CONFIG_BT_HCIUART_BCM=y +CONFIG_BT_HCIUART_QCA=y +# CONFIG_BT_HCIUART_AG6XX is not set +# CONFIG_BT_HCIUART_MRVL is not set +CONFIG_BT_HCIBCM203X=m +# CONFIG_BT_HCIBPA10X is not set +CONFIG_BT_HCIBFUSB=m +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +CONFIG_BT_ATH3K=m +# CONFIG_BT_MTKUART is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_AF_KCM is not set +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_PRIV=y +CONFIG_CFG80211=m +# CONFIG_NL80211_TESTMODE is not set +# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set +# CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_REQUIRE_SIGNED_REGDB=y +CONFIG_CFG80211_USE_KERNEL_REGDB_KEYS=y +# CONFIG_CFG80211_DEFAULT_PS is not set +# CONFIG_CFG80211_DEBUGFS is not set +# CONFIG_CFG80211_CRDA_SUPPORT is not set +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_HAS_RC=y +CONFIG_MAC80211_RC_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y +CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" +# CONFIG_MAC80211_MESH is not set +CONFIG_MAC80211_LEDS=y +# CONFIG_MAC80211_DEBUGFS is not set +# CONFIG_MAC80211_MESSAGE_TRACING is not set +# CONFIG_MAC80211_DEBUG_MENU is not set +CONFIG_MAC80211_STA_HASH_MAX_SIZE=0 +# CONFIG_WIMAX is not set +CONFIG_RFKILL=m +CONFIG_RFKILL_LEDS=y +CONFIG_RFKILL_INPUT=y +CONFIG_RFKILL_GPIO=m +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set +# CONFIG_NFC is not set +# CONFIG_PSAMPLE is not set +# CONFIG_NET_IFE is not set +# CONFIG_LWTUNNEL is not set +CONFIG_DST_CACHE=y +CONFIG_GRO_CELLS=y +# CONFIG_NET_DEVLINK is not set +CONFIG_FAILOVER=y +CONFIG_HAVE_EBPF_JIT=y + +# +# Device Drivers +# +CONFIG_ARM_AMBA=y +CONFIG_HAVE_PCI=y +# CONFIG_PCI is not set +# CONFIG_PCCARD is not set + +# +# Generic Driver Options +# +# CONFIG_UEVENT_HELPER is not set +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y + +# +# Firmware loader +# +CONFIG_FW_LOADER=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_FW_LOADER_USER_HELPER is not set +CONFIG_WANT_DEV_COREDUMP=y +# CONFIG_ALLOW_DEV_COREDUMP is not set +# CONFIG_DEBUG_DRIVER is not set +# CONFIG_DEBUG_DEVRES is not set +# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set +# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set +CONFIG_GENERIC_CPU_AUTOPROBE=y +CONFIG_SOC_BUS=y +CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y +CONFIG_REGMAP_SPI=y +CONFIG_REGMAP_MMIO=y +CONFIG_REGMAP_IRQ=y +CONFIG_DMA_SHARED_BUFFER=y +# CONFIG_DMA_FENCE_TRACE is not set +CONFIG_GENERIC_ARCH_TOPOLOGY=y + +# +# Bus devices +# +# CONFIG_BRCMSTB_GISB_ARB is not set +# CONFIG_SIMPLE_PM_BUS is not set +# CONFIG_VEXPRESS_CONFIG is not set +# CONFIG_CONNECTOR is not set +# CONFIG_GNSS is not set +# CONFIG_MTD is not set +CONFIG_DTC=y +CONFIG_OF=y +# CONFIG_OF_UNITTEST is not set +CONFIG_OF_FLATTREE=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_KOBJ=y +CONFIG_OF_DYNAMIC=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_IRQ=y +CONFIG_OF_NET=y +CONFIG_OF_MDIO=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_OF_RESOLVE=y +CONFIG_OF_OVERLAY=y +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_NULL_BLK is not set +CONFIG_CDROM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=0 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +CONFIG_BLK_DEV_NBD=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_BLK_DEV_RBD is not set + +# +# NVME Support +# +# CONFIG_NVME_FC is not set +# CONFIG_NVME_TARGET is not set + +# +# Misc devices +# +# CONFIG_AD525X_DPOT is not set +# CONFIG_DUMMY_IRQ is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +# CONFIG_DS1682 is not set +# CONFIG_USB_SWITCH_FSA9480 is not set +# CONFIG_LATTICE_ECP3_CONFIG is not set +# CONFIG_SRAM is not set +# CONFIG_PVPANIC is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +CONFIG_EEPROM_AT25=m +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +CONFIG_EEPROM_93CX6=m +# CONFIG_EEPROM_93XX46 is not set +# CONFIG_EEPROM_IDT_89HPESX is not set +# CONFIG_EEPROM_EE1004 is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_ALTERA_STAPL is not set + +# +# Intel MIC & related support +# + +# +# Intel MIC Bus Driver +# + +# +# SCIF Bus Driver +# + +# +# VOP Bus Driver +# +# CONFIG_VOP_BUS is not set + +# +# Intel MIC Host Driver +# + +# +# Intel MIC Card Driver +# + +# +# SCIF Driver +# + +# +# Intel MIC Coprocessor State Management (COSM) Drivers +# + +# +# VOP Driver +# +# CONFIG_ECHO is not set +# CONFIG_MISC_RTSX_USB is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_PROC_FS is not set + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +CONFIG_SCSI_ISCSI_ATTRS=y +CONFIG_SCSI_SAS_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=y +CONFIG_SCSI_SAS_HOST_SMP=y +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +CONFIG_ISCSI_TCP=y +CONFIG_ISCSI_BOOT_SYSFS=y +# CONFIG_SCSI_UFSHCD is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +CONFIG_HAVE_PATA_PLATFORM=y +# CONFIG_ATA is not set +# CONFIG_MD is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_MII=y +CONFIG_NET_CORE=y +# CONFIG_BONDING is not set +# CONFIG_DUMMY is not set +# CONFIG_EQUALIZER is not set +# CONFIG_NET_TEAM is not set +CONFIG_MACVLAN=m +# CONFIG_MACVTAP is not set +# CONFIG_IPVLAN is not set +# CONFIG_VXLAN is not set +# CONFIG_GENEVE is not set +# CONFIG_GTP is not set +# CONFIG_MACSEC is not set +CONFIG_NETCONSOLE=y +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_NETPOLL=y +CONFIG_NET_POLL_CONTROLLER=y +CONFIG_TUN=y +# CONFIG_TUN_VNET_CROSS_LE is not set +CONFIG_VETH=m +# CONFIG_NLMON is not set + +# +# CAIF transport drivers +# + +# +# Distributed Switch Architecture drivers +# +CONFIG_ETHERNET=y +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_ALTERA_TSE is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_AURORA is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CADENCE is not set +# CONFIG_NET_VENDOR_CAVIUM is not set +# CONFIG_NET_VENDOR_CORTINA is not set +# CONFIG_DNET is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MICROSEMI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_NI is not set +# CONFIG_ETHOC is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_SOCIONEXT is not set +CONFIG_NET_VENDOR_STMICRO=y +CONFIG_STMMAC_ETH=y +CONFIG_STMMAC_PLATFORM=y +# CONFIG_DWMAC_DWC_QOS_ETH is not set +CONFIG_DWMAC_GENERIC=y +CONFIG_DWMAC_MESON=y +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_BUS=y +# CONFIG_MDIO_BCM_UNIMAC is not set +CONFIG_MDIO_BITBANG=y +CONFIG_MDIO_BUS_MUX=y +# CONFIG_MDIO_BUS_MUX_GPIO is not set +CONFIG_MDIO_BUS_MUX_MESON_G12A=y +CONFIG_MDIO_BUS_MUX_MMIOREG=y +# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set +# CONFIG_MDIO_GPIO is not set +# CONFIG_MDIO_HISI_FEMAC is not set +# CONFIG_MDIO_MSCC_MIIM is not set +# CONFIG_MDIO_OCTEON is not set +CONFIG_PHYLIB=y +CONFIG_SWPHY=y +# CONFIG_LED_TRIGGER_PHY is not set + +# +# MII PHY device drivers +# +# CONFIG_AMD_PHY is not set +# CONFIG_AQUANTIA_PHY is not set +# CONFIG_ASIX_PHY is not set +# CONFIG_AT803X_PHY is not set +# CONFIG_BCM7XXX_PHY is not set +# CONFIG_BCM87XX_PHY is not set +# CONFIG_BROADCOM_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_CORTINA_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_DP83822_PHY is not set +# CONFIG_DP83TC811_PHY is not set +# CONFIG_DP83848_PHY is not set +# CONFIG_DP83867_PHY is not set +CONFIG_FIXED_PHY=y +# CONFIG_ICPLUS_PHY is not set +# CONFIG_INTEL_XWAY_PHY is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_MARVELL_PHY is not set +# CONFIG_MARVELL_10G_PHY is not set +CONFIG_MESON_GXL_PHY=y +# CONFIG_MICREL_PHY is not set +CONFIG_MICROCHIP_PHY=m +# CONFIG_MICROCHIP_T1_PHY is not set +# CONFIG_MICROSEMI_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_QSEMI_PHY is not set +CONFIG_REALTEK_PHY=y +# CONFIG_RENESAS_PHY is not set +# CONFIG_ROCKCHIP_PHY is not set +# CONFIG_SMSC_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_TERANETICS_PHY is not set +# CONFIG_VITESSE_PHY is not set +# CONFIG_XILINX_GMII2RGMII is not set +# CONFIG_MICREL_KS8995MA is not set +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +# CONFIG_PPP_FILTER is not set +CONFIG_PPP_MPPE=m +# CONFIG_PPP_MULTILINK is not set +CONFIG_PPPOE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +# CONFIG_SLIP is not set +CONFIG_SLHC=m +CONFIG_USB_NET_DRIVERS=y +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +CONFIG_USB_PEGASUS=y +CONFIG_USB_RTL8150=y +CONFIG_USB_RTL8152=m +CONFIG_USB_LAN78XX=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_AX8817X=m +CONFIG_USB_NET_AX88179_178A=m +CONFIG_USB_NET_CDCETHER=m +# CONFIG_USB_NET_CDC_EEM is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_HUAWEI_CDC_NCM is not set +# CONFIG_USB_NET_CDC_MBIM is not set +CONFIG_USB_NET_DM9601=m +# CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +# CONFIG_USB_NET_GL620A is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_PLUSB is not set +CONFIG_USB_NET_MCS7830=m +CONFIG_USB_NET_RNDIS_HOST=m +# CONFIG_USB_NET_CDC_SUBSET is not set +CONFIG_USB_NET_ZAURUS=m +# CONFIG_USB_NET_CX82310_ETH is not set +# CONFIG_USB_NET_KALMIA is not set +# CONFIG_USB_NET_QMI_WWAN is not set +CONFIG_USB_HSO=m +# CONFIG_USB_NET_INT51X1 is not set +CONFIG_USB_IPHETH=m +# CONFIG_USB_SIERRA_NET is not set +# CONFIG_USB_VL600 is not set +# CONFIG_USB_NET_CH9200 is not set +# CONFIG_USB_NET_AQC111 is not set +CONFIG_WLAN=y +# CONFIG_WIRELESS_WDS is not set +CONFIG_WLAN_VENDOR_ADMTEK=y +CONFIG_ATH_COMMON=m +CONFIG_WLAN_VENDOR_ATH=y +# CONFIG_ATH_DEBUG is not set +CONFIG_ATH9K_HW=m +CONFIG_ATH9K_COMMON=m +CONFIG_ATH9K_BTCOEX_SUPPORT=y +CONFIG_ATH9K=m +# CONFIG_ATH9K_AHB is not set +# CONFIG_ATH9K_DEBUGFS is not set +# CONFIG_ATH9K_DYNACK is not set +# CONFIG_ATH9K_WOW is not set +CONFIG_ATH9K_RFKILL=y +CONFIG_ATH9K_CHANNEL_CONTEXT=y +CONFIG_ATH9K_PCOEM=y +CONFIG_ATH9K_HTC=m +# CONFIG_ATH9K_HTC_DEBUGFS is not set +CONFIG_ATH9K_HWRNG=y +CONFIG_CARL9170=m +CONFIG_CARL9170_LEDS=y +CONFIG_CARL9170_WPC=y +CONFIG_CARL9170_HWRNG=y +CONFIG_ATH6KL=m +# CONFIG_ATH6KL_SDIO is not set +CONFIG_ATH6KL_USB=m +# CONFIG_ATH6KL_DEBUG is not set +CONFIG_AR5523=m +CONFIG_ATH10K=m +CONFIG_ATH10K_CE=y +CONFIG_ATH10K_SDIO=m +CONFIG_ATH10K_USB=m +# CONFIG_ATH10K_DEBUG is not set +# CONFIG_ATH10K_DEBUGFS is not set +CONFIG_WCN36XX=m +# CONFIG_WCN36XX_DEBUGFS is not set +CONFIG_WLAN_VENDOR_ATMEL=y +# CONFIG_AT76C50X_USB is not set +CONFIG_WLAN_VENDOR_BROADCOM=y +CONFIG_B43=m +CONFIG_B43_BCMA=y +CONFIG_B43_SSB=y +CONFIG_B43_BUSES_BCMA_AND_SSB=y +# CONFIG_B43_BUSES_BCMA is not set +# CONFIG_B43_BUSES_SSB is not set +# CONFIG_B43_SDIO is not set +CONFIG_B43_BCMA_PIO=y +CONFIG_B43_PIO=y +CONFIG_B43_PHY_G=y +CONFIG_B43_PHY_N=y +CONFIG_B43_PHY_LP=y +CONFIG_B43_PHY_HT=y +CONFIG_B43_LEDS=y +CONFIG_B43_HWRNG=y +# CONFIG_B43_DEBUG is not set +# CONFIG_B43LEGACY is not set +CONFIG_BRCMUTIL=m +# CONFIG_BRCMSMAC is not set +CONFIG_BRCMFMAC=m +CONFIG_BRCMFMAC_PROTO_BCDC=y +CONFIG_BRCMFMAC_SDIO=y +CONFIG_BRCMFMAC_USB=y +# CONFIG_BRCM_TRACING is not set +# CONFIG_BRCMDBG is not set +CONFIG_WLAN_VENDOR_CISCO=y +CONFIG_WLAN_VENDOR_INTEL=y +CONFIG_WLAN_VENDOR_INTERSIL=y +# CONFIG_HOSTAP is not set +CONFIG_P54_COMMON=m +CONFIG_P54_USB=m +# CONFIG_P54_SPI is not set +CONFIG_P54_LEDS=y +CONFIG_WLAN_VENDOR_MARVELL=y +# CONFIG_LIBERTAS is not set +# CONFIG_LIBERTAS_THINFIRM is not set +# CONFIG_MWIFIEX is not set +CONFIG_WLAN_VENDOR_MEDIATEK=y +CONFIG_MT7601U=m +CONFIG_MT76_CORE=m +CONFIG_MT76_LEDS=y +CONFIG_MT76_USB=m +CONFIG_MT76x02_LIB=m +CONFIG_MT76x02_USB=m +CONFIG_MT76x0_COMMON=m +CONFIG_MT76x0U=m +CONFIG_MT76x2_COMMON=m +CONFIG_MT76x2U=m +CONFIG_WLAN_VENDOR_RALINK=y +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT33XX=y +CONFIG_RT2800USB_RT35XX=y +CONFIG_RT2800USB_RT3573=y +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RT2800_LIB=m +CONFIG_RT2X00_LIB_USB=m +CONFIG_RT2X00_LIB=m +CONFIG_RT2X00_LIB_FIRMWARE=y +CONFIG_RT2X00_LIB_CRYPTO=y +CONFIG_RT2X00_LIB_LEDS=y +# CONFIG_RT2X00_DEBUG is not set +CONFIG_WLAN_VENDOR_REALTEK=y +CONFIG_RTL8187=m +CONFIG_RTL8187_LEDS=y +CONFIG_RTL_CARDS=m +# CONFIG_RTL8192CU is not set +# CONFIG_RTL8XXXU is not set +CONFIG_WLAN_VENDOR_RSI=y +# CONFIG_RSI_91X is not set +CONFIG_WLAN_VENDOR_ST=y +# CONFIG_CW1200 is not set +CONFIG_WLAN_VENDOR_TI=y +# CONFIG_WL1251 is not set +# CONFIG_WL12XX is not set +CONFIG_WL18XX=m +CONFIG_WLCORE=m +# CONFIG_WLCORE_SPI is not set +CONFIG_WLCORE_SDIO=m +CONFIG_WILINK_PLATFORM_DATA=y +CONFIG_WLAN_VENDOR_ZYDAS=y +CONFIG_USB_ZD1201=m +CONFIG_ZD1211RW=m +# CONFIG_ZD1211RW_DEBUG is not set +# CONFIG_WLAN_VENDOR_QUANTENNA is not set +# CONFIG_MAC80211_HWSIM is not set +CONFIG_USB_NET_RNDIS_WLAN=m +# CONFIG_VIRT_WIFI is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# +# CONFIG_WAN is not set +# CONFIG_NETDEVSIM is not set +# CONFIG_NET_FAILOVER is not set +# CONFIG_ISDN is not set +# CONFIG_NVM is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_LEDS=y +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_POLLDEV=m +# CONFIG_INPUT_SPARSEKMAP is not set +# CONFIG_INPUT_MATRIXKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADC is not set +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_DLINK_DIR685 is not set +# CONFIG_KEYBOARD_LKKBD is not set +CONFIG_KEYBOARD_GPIO=m +# CONFIG_KEYBOARD_GPIO_POLLED is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_TCA8418 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_LM8323 is not set +# CONFIG_KEYBOARD_LM8333 is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_SAMSUNG is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_OMAP4 is not set +# CONFIG_KEYBOARD_TM2_TOUCHKEY is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_CROS_EC is not set +# CONFIG_KEYBOARD_CAP11XX is not set +# CONFIG_KEYBOARD_BCM is not set +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_APPLETOUCH is not set +# CONFIG_MOUSE_BCM5974 is not set +# CONFIG_MOUSE_CYAPA is not set +# CONFIG_MOUSE_ELAN_I2C is not set +# CONFIG_MOUSE_VSXXXAA is not set +# CONFIG_MOUSE_GPIO is not set +# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_MOUSE_SYNAPTICS_USB is not set +CONFIG_INPUT_JOYSTICK=y +# CONFIG_JOYSTICK_ANALOG is not set +# CONFIG_JOYSTICK_A3D is not set +# CONFIG_JOYSTICK_ADI is not set +# CONFIG_JOYSTICK_COBRA is not set +# CONFIG_JOYSTICK_GF2K is not set +# CONFIG_JOYSTICK_GRIP is not set +# CONFIG_JOYSTICK_GRIP_MP is not set +# CONFIG_JOYSTICK_GUILLEMOT is not set +# CONFIG_JOYSTICK_INTERACT is not set +# CONFIG_JOYSTICK_SIDEWINDER is not set +# CONFIG_JOYSTICK_TMDC is not set +# CONFIG_JOYSTICK_IFORCE is not set +# CONFIG_JOYSTICK_WARRIOR is not set +# CONFIG_JOYSTICK_MAGELLAN is not set +# CONFIG_JOYSTICK_SPACEORB is not set +# CONFIG_JOYSTICK_SPACEBALL is not set +# CONFIG_JOYSTICK_STINGER is not set +# CONFIG_JOYSTICK_TWIDJOY is not set +# CONFIG_JOYSTICK_ZHENHUA is not set +# CONFIG_JOYSTICK_AS5011 is not set +# CONFIG_JOYSTICK_JOYDUMP is not set +CONFIG_JOYSTICK_XPAD=m +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_JOYSTICK_PSXPAD_SPI=m +CONFIG_JOYSTICK_PSXPAD_SPI_FF=y +# CONFIG_JOYSTICK_PXRC is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ARIZONA_HAPTICS is not set +# CONFIG_INPUT_ATMEL_CAPTOUCH is not set +# CONFIG_INPUT_BMA150 is not set +# CONFIG_INPUT_E3X0_BUTTON is not set +# CONFIG_INPUT_MSM_VIBRATOR is not set +# CONFIG_INPUT_MMA8450 is not set +# CONFIG_INPUT_GP2A is not set +# CONFIG_INPUT_GPIO_BEEPER is not set +# CONFIG_INPUT_GPIO_DECODER is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_KXTJ9 is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +# CONFIG_INPUT_REGULATOR_HAPTIC is not set +CONFIG_INPUT_UINPUT=y +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_PWM_VIBRA is not set +# CONFIG_INPUT_RK805_PWRKEY is not set +CONFIG_INPUT_GPIO_ROTARY_ENCODER=m +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_IMS_PCU is not set +# CONFIG_INPUT_CMA3000 is not set +# CONFIG_INPUT_SOC_BUTTON_ARRAY is not set +# CONFIG_INPUT_DRV260X_HAPTICS is not set +# CONFIG_INPUT_DRV2665_HAPTICS is not set +# CONFIG_INPUT_DRV2667_HAPTICS is not set +CONFIG_RMI4_CORE=y +# CONFIG_RMI4_I2C is not set +# CONFIG_RMI4_SPI is not set +# CONFIG_RMI4_SMB is not set +CONFIG_RMI4_F03=y +CONFIG_RMI4_F03_SERIO=y +CONFIG_RMI4_2D_SENSOR=y +CONFIG_RMI4_F11=y +CONFIG_RMI4_F12=y +CONFIG_RMI4_F30=y +# CONFIG_RMI4_F34 is not set +# CONFIG_RMI4_F55 is not set + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +# CONFIG_SERIO_AMBAKMI is not set +# CONFIG_SERIO_LIBPS2 is not set +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO_ARC_PS2 is not set +# CONFIG_SERIO_APBPS2 is not set +# CONFIG_SERIO_OLPC_APSP is not set +# CONFIG_SERIO_GPIO_PS2 is not set +# CONFIG_USERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_TTY=y +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_VT_CONSOLE_SLEEP=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +CONFIG_UNIX98_PTYS=y +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_LDISC_AUTOLOAD=y +CONFIG_DEVMEM=y + +# +# Serial drivers +# +CONFIG_SERIAL_EARLYCON=y +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +# CONFIG_SERIAL_8250_FINTEK is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=1 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_EXTENDED=y +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_ASPEED_VUART is not set +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_RSA is not set +CONFIG_SERIAL_8250_FSL=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_RT288X is not set +CONFIG_SERIAL_OF_PLATFORM=y + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_AMBA_PL010 is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set +CONFIG_SERIAL_MESON=y +CONFIG_SERIAL_MESON_CONSOLE=y +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX310X is not set +# CONFIG_SERIAL_UARTLITE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_SCCNXP is not set +# CONFIG_SERIAL_SC16IS7XX is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_SERIAL_ARC is not set +# CONFIG_SERIAL_FSL_LPUART is not set +# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set +CONFIG_SERIAL_DEV_BUS=m +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +CONFIG_HW_RANDOM_MESON=y +CONFIG_HW_RANDOM_OPTEE=m +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_XILLYBUS is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MUX=m + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_GPMUX is not set +# CONFIG_I2C_MUX_LTC4306 is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set +# CONFIG_I2C_MUX_PINCTRL is not set +# CONFIG_I2C_MUX_REG is not set +# CONFIG_I2C_DEMUX_PINCTRL is not set +# CONFIG_I2C_MUX_MLXCPLD is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_CADENCE is not set +# CONFIG_I2C_CBUS_GPIO is not set +CONFIG_I2C_DESIGNWARE_CORE=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y +# CONFIG_I2C_DESIGNWARE_SLAVE is not set +# CONFIG_I2C_EMEV2 is not set +# CONFIG_I2C_GPIO is not set +CONFIG_I2C_MESON=y +# CONFIG_I2C_NOMADIK is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_RK3X is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_CROS_EC_TUNNEL is not set +# CONFIG_I2C_STUB is not set +CONFIG_I2C_SLAVE=y +# CONFIG_I2C_SLAVE_EEPROM is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I3C is not set +CONFIG_SPI=y +# CONFIG_SPI_DEBUG is not set +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +# CONFIG_SPI_AXI_SPI_ENGINE is not set +# CONFIG_SPI_BITBANG is not set +# CONFIG_SPI_CADENCE is not set +# CONFIG_SPI_DESIGNWARE is not set +# CONFIG_SPI_NXP_FLEXSPI is not set +# CONFIG_SPI_GPIO is not set +# CONFIG_SPI_FSL_SPI is not set +CONFIG_SPI_MESON_SPICC=y +CONFIG_SPI_MESON_SPIFC=y +# CONFIG_SPI_OC_TINY is not set +CONFIG_SPI_PL022=y +# CONFIG_SPI_ROCKCHIP is not set +# CONFIG_SPI_SC18IS602 is not set +# CONFIG_SPI_SIFIVE is not set +# CONFIG_SPI_MXIC is not set +# CONFIG_SPI_XCOMM is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_ZYNQMP_GQSPI is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=m +# CONFIG_SPI_LOOPBACK_TEST is not set +# CONFIG_SPI_TLE62X0 is not set +# CONFIG_SPI_SLAVE is not set +# CONFIG_SPMI is not set +# CONFIG_HSI is not set +CONFIG_PPS=y +# CONFIG_PPS_DEBUG is not set + +# +# PPS clients support +# +# CONFIG_PPS_CLIENT_KTIMER is not set +# CONFIG_PPS_CLIENT_LDISC is not set +# CONFIG_PPS_CLIENT_GPIO is not set + +# +# PPS generators support +# + +# +# PTP clock support +# +# CONFIG_PTP_1588_CLOCK is not set + +# +# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks. +# +CONFIG_PINCTRL=y +CONFIG_PINMUX=y +CONFIG_PINCONF=y +CONFIG_GENERIC_PINCONF=y +# CONFIG_DEBUG_PINCTRL is not set +# CONFIG_PINCTRL_AMD is not set +# CONFIG_PINCTRL_MCP23S08 is not set +# CONFIG_PINCTRL_SINGLE is not set +# CONFIG_PINCTRL_SX150X is not set +# CONFIG_PINCTRL_RK805 is not set +# CONFIG_PINCTRL_OCELOT is not set +CONFIG_PINCTRL_MESON=y +CONFIG_PINCTRL_MESON_GXBB=y +CONFIG_PINCTRL_MESON_GXL=y +CONFIG_PINCTRL_MESON8_PMX=y +CONFIG_PINCTRL_MESON_AXG=y +CONFIG_PINCTRL_MESON_AXG_PMX=y +CONFIG_PINCTRL_MESON_G12A=y +CONFIG_GPIOLIB=y +CONFIG_GPIOLIB_FASTPATH_LIMIT=512 +CONFIG_OF_GPIO=y +# CONFIG_DEBUG_GPIO is not set +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_GENERIC=y + +# +# Memory mapped GPIO drivers +# +# CONFIG_GPIO_74XX_MMIO is not set +# CONFIG_GPIO_ALTERA is not set +# CONFIG_GPIO_CADENCE is not set +CONFIG_GPIO_DWAPB=y +# CONFIG_GPIO_FTGPIO010 is not set +CONFIG_GPIO_GENERIC_PLATFORM=y +# CONFIG_GPIO_GRGPIO is not set +# CONFIG_GPIO_HLWD is not set +# CONFIG_GPIO_MB86S7X is not set +# CONFIG_GPIO_MOCKUP is not set +# CONFIG_GPIO_PL061 is not set +# CONFIG_GPIO_SAMA5D2_PIOBU is not set +# CONFIG_GPIO_SYSCON is not set +# CONFIG_GPIO_XGENE is not set +# CONFIG_GPIO_XILINX is not set +# CONFIG_GPIO_AMD_FCH is not set + +# +# I2C GPIO expanders +# +# CONFIG_GPIO_ADP5588 is not set +# CONFIG_GPIO_ADNP is not set +# CONFIG_GPIO_GW_PLD is not set +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_TPIC2810 is not set + +# +# MFD GPIO expanders +# +# CONFIG_GPIO_ARIZONA is not set + +# +# SPI GPIO expanders +# +# CONFIG_GPIO_74X164 is not set +# CONFIG_GPIO_MAX3191X is not set +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_PISOSR is not set +# CONFIG_GPIO_XRA1403 is not set + +# +# USB GPIO expanders +# +# CONFIG_W1 is not set +# CONFIG_POWER_AVS is not set +CONFIG_POWER_RESET=y +# CONFIG_POWER_RESET_BRCMSTB is not set +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_GPIO_RESTART=y +# CONFIG_POWER_RESET_LTC2952 is not set +# CONFIG_POWER_RESET_RESTART is not set +# CONFIG_POWER_RESET_XGENE is not set +CONFIG_POWER_RESET_SYSCON=y +# CONFIG_POWER_RESET_SYSCON_POWEROFF is not set +# CONFIG_SYSCON_REBOOT_MODE is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_GENERIC_ADC_BATTERY is not set +# CONFIG_TEST_POWER is not set +# CONFIG_CHARGER_ADP5061 is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2781 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_LEGO_EV3 is not set +# CONFIG_BATTERY_SBS is not set +# CONFIG_CHARGER_SBS is not set +# CONFIG_MANAGER_SBS is not set +# CONFIG_BATTERY_BQ27XXX is not set +# CONFIG_BATTERY_MAX17040 is not set +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_LP8727 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_CHARGER_MANAGER is not set +# CONFIG_CHARGER_LTC3651 is not set +# CONFIG_CHARGER_DETECTOR_MAX14656 is not set +# CONFIG_CHARGER_BQ2415X is not set +# CONFIG_CHARGER_BQ24190 is not set +# CONFIG_CHARGER_BQ24257 is not set +# CONFIG_CHARGER_BQ24735 is not set +# CONFIG_CHARGER_BQ25890 is not set +# CONFIG_CHARGER_SMB347 is not set +# CONFIG_BATTERY_GAUGE_LTC2941 is not set +# CONFIG_CHARGER_RT9455 is not set +# CONFIG_CHARGER_CROS_USBPD is not set +CONFIG_HWMON=y +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7314 is not set +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7310 is not set +# CONFIG_SENSORS_ADT7410 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +CONFIG_SENSORS_ARM_SCPI=y +# CONFIG_SENSORS_ASPEED is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS620 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_FTSTEUTATES is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_G762 is not set +CONFIG_SENSORS_GPIO_FAN=m +# CONFIG_SENSORS_HIH6130 is not set +# CONFIG_SENSORS_IIO_HWMON is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_JC42 is not set +# CONFIG_SENSORS_POWR1220 is not set +# CONFIG_SENSORS_LINEAGE is not set +# CONFIG_SENSORS_LTC2945 is not set +# CONFIG_SENSORS_LTC2990 is not set +# CONFIG_SENSORS_LTC4151 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4222 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LTC4260 is not set +# CONFIG_SENSORS_LTC4261 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX16065 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX1668 is not set +# CONFIG_SENSORS_MAX197 is not set +# CONFIG_SENSORS_MAX31722 is not set +# CONFIG_SENSORS_MAX6621 is not set +# CONFIG_SENSORS_MAX6639 is not set +# CONFIG_SENSORS_MAX6642 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_MAX6697 is not set +# CONFIG_SENSORS_MAX31790 is not set +# CONFIG_SENSORS_MCP3021 is not set +# CONFIG_SENSORS_TC654 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LM95234 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_LM95245 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_NTC_THERMISTOR is not set +# CONFIG_SENSORS_NCT6683 is not set +# CONFIG_SENSORS_NCT6775 is not set +# CONFIG_SENSORS_NCT7802 is not set +# CONFIG_SENSORS_NCT7904 is not set +# CONFIG_SENSORS_NPCM7XX is not set +# CONFIG_SENSORS_OCC_P8_I2C is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_PMBUS is not set +CONFIG_SENSORS_PWM_FAN=m +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_SHT21 is not set +# CONFIG_SENSORS_SHT3x is not set +# CONFIG_SENSORS_SHTC1 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_EMC2103 is not set +# CONFIG_SENSORS_EMC6W201 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SCH5627 is not set +# CONFIG_SENSORS_SCH5636 is not set +# CONFIG_SENSORS_STTS751 is not set +# CONFIG_SENSORS_SMM665 is not set +# CONFIG_SENSORS_ADC128D818 is not set +# CONFIG_SENSORS_ADS1015 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_INA209 is not set +# CONFIG_SENSORS_INA2XX is not set +# CONFIG_SENSORS_INA3221 is not set +# CONFIG_SENSORS_TC74 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP103 is not set +# CONFIG_SENSORS_TMP108 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83773G is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83795 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +CONFIG_THERMAL=y +# CONFIG_THERMAL_STATISTICS is not set +CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0 +CONFIG_THERMAL_HWMON=y +CONFIG_THERMAL_OF=y +# CONFIG_THERMAL_WRITABLE_TRIPS is not set +CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y +# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set +# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set +# CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR is not set +# CONFIG_THERMAL_GOV_FAIR_SHARE is not set +CONFIG_THERMAL_GOV_STEP_WISE=y +# CONFIG_THERMAL_GOV_BANG_BANG is not set +# CONFIG_THERMAL_GOV_USER_SPACE is not set +# CONFIG_THERMAL_GOV_POWER_ALLOCATOR is not set +# CONFIG_CPU_THERMAL is not set +# CONFIG_CLOCK_THERMAL is not set +# CONFIG_DEVFREQ_THERMAL is not set +# CONFIG_THERMAL_EMULATION is not set +# CONFIG_QORIQ_THERMAL is not set +# CONFIG_GENERIC_ADC_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y +# CONFIG_WATCHDOG_SYSFS is not set + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_GPIO_WATCHDOG is not set +# CONFIG_XILINX_WATCHDOG is not set +# CONFIG_ZIIRAVE_WATCHDOG is not set +# CONFIG_ARM_SP805_WATCHDOG is not set +# CONFIG_ARM_SBSA_WATCHDOG is not set +# CONFIG_CADENCE_WATCHDOG is not set +# CONFIG_DW_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +CONFIG_MESON_GXBB_WATCHDOG=y +CONFIG_MESON_WATCHDOG=y +# CONFIG_MEN_A21_WDT is not set + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set + +# +# Watchdog Pretimeout Governors +# +# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set +CONFIG_SSB_POSSIBLE=y +CONFIG_SSB=m +CONFIG_SSB_BLOCKIO=y +CONFIG_SSB_SDIOHOST_POSSIBLE=y +# CONFIG_SSB_SDIOHOST is not set +# CONFIG_SSB_DRIVER_GPIO is not set +CONFIG_BCMA_POSSIBLE=y +CONFIG_BCMA=m +CONFIG_BCMA_BLOCKIO=y +# CONFIG_BCMA_HOST_SOC is not set +# CONFIG_BCMA_DRIVER_GMAC_CMN is not set +# CONFIG_BCMA_DRIVER_GPIO is not set +# CONFIG_BCMA_DEBUG is not set + +# +# Multifunction device drivers +# +CONFIG_MFD_CORE=y +# CONFIG_MFD_ACT8945A is not set +# CONFIG_MFD_AS3711 is not set +# CONFIG_MFD_AS3722 is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_AAT2870_CORE is not set +# CONFIG_MFD_ATMEL_FLEXCOM is not set +# CONFIG_MFD_ATMEL_HLCDC is not set +# CONFIG_MFD_BCM590XX is not set +# CONFIG_MFD_BD9571MWV is not set +# CONFIG_MFD_AXP20X_I2C is not set +CONFIG_MFD_CROS_EC=y +# CONFIG_MFD_CROS_EC_CHARDEV is not set +# CONFIG_MFD_MADERA is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_MFD_DA9052_SPI is not set +# CONFIG_MFD_DA9052_I2C is not set +# CONFIG_MFD_DA9055 is not set +# CONFIG_MFD_DA9062 is not set +# CONFIG_MFD_DA9063 is not set +# CONFIG_MFD_DA9150 is not set +# CONFIG_MFD_DLN2 is not set +# CONFIG_MFD_MC13XXX_SPI is not set +# CONFIG_MFD_MC13XXX_I2C is not set +# CONFIG_MFD_HI6421_PMIC is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_MFD_KEMPLD is not set +# CONFIG_MFD_88PM800 is not set +# CONFIG_MFD_88PM805 is not set +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX14577 is not set +# CONFIG_MFD_MAX77620 is not set +# CONFIG_MFD_MAX77686 is not set +# CONFIG_MFD_MAX77693 is not set +# CONFIG_MFD_MAX77843 is not set +# CONFIG_MFD_MAX8907 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +# CONFIG_MFD_MAX8998 is not set +# CONFIG_MFD_MT6397 is not set +# CONFIG_MFD_MENF21BMC is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_CPCAP is not set +# CONFIG_MFD_VIPERBOARD is not set +# CONFIG_MFD_RETU is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_RT5033 is not set +# CONFIG_MFD_RC5T583 is not set +CONFIG_MFD_RK808=y +# CONFIG_MFD_RN5T618 is not set +CONFIG_MFD_SEC_CORE=y +# CONFIG_MFD_SI476X_CORE is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_SKY81452 is not set +# CONFIG_MFD_SMSC is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_MFD_STMPE is not set +CONFIG_MFD_SYSCON=y +# CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set +# CONFIG_MFD_LP8788 is not set +# CONFIG_MFD_TI_LMU is not set +# CONFIG_MFD_PALMAS is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS65086 is not set +# CONFIG_MFD_TPS65090 is not set +# CONFIG_MFD_TPS65217 is not set +# CONFIG_MFD_TI_LP873X is not set +# CONFIG_MFD_TI_LP87565 is not set +# CONFIG_MFD_TPS65218 is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_MFD_TPS65910 is not set +# CONFIG_MFD_TPS65912_I2C is not set +# CONFIG_MFD_TPS65912_SPI is not set +# CONFIG_MFD_TPS80031 is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_TWL6040_CORE is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_LM3533 is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TQMX86 is not set +# CONFIG_MFD_LOCHNAGAR is not set +CONFIG_MFD_ARIZONA=y +CONFIG_MFD_ARIZONA_I2C=m +CONFIG_MFD_ARIZONA_SPI=m +# CONFIG_MFD_CS47L24 is not set +CONFIG_MFD_WM5102=y +# CONFIG_MFD_WM5110 is not set +# CONFIG_MFD_WM8997 is not set +# CONFIG_MFD_WM8998 is not set +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_ROHM_BD718XX is not set +# CONFIG_MFD_STPMIC1 is not set +# CONFIG_RAVE_SP_CORE is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +CONFIG_REGULATOR_FIXED_VOLTAGE=y +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_88PG86X is not set +# CONFIG_REGULATOR_ACT8865 is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_ANATOP is not set +# CONFIG_REGULATOR_ARIZONA_LDO1 is not set +# CONFIG_REGULATOR_ARIZONA_MICSUPP is not set +# CONFIG_REGULATOR_DA9210 is not set +# CONFIG_REGULATOR_DA9211 is not set +# CONFIG_REGULATOR_FAN53555 is not set +CONFIG_REGULATOR_GPIO=y +# CONFIG_REGULATOR_ISL9305 is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_LP872X is not set +# CONFIG_REGULATOR_LP8755 is not set +# CONFIG_REGULATOR_LTC3589 is not set +# CONFIG_REGULATOR_LTC3676 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +# CONFIG_REGULATOR_MAX8952 is not set +# CONFIG_REGULATOR_MAX8973 is not set +# CONFIG_REGULATOR_MCP16502 is not set +# CONFIG_REGULATOR_MT6311 is not set +# CONFIG_REGULATOR_PFUZE100 is not set +# CONFIG_REGULATOR_PV88060 is not set +# CONFIG_REGULATOR_PV88080 is not set +# CONFIG_REGULATOR_PV88090 is not set +# CONFIG_REGULATOR_PWM is not set +# CONFIG_REGULATOR_RK808 is not set +# CONFIG_REGULATOR_S2MPA01 is not set +# CONFIG_REGULATOR_S2MPS11 is not set +# CONFIG_REGULATOR_S5M8767 is not set +# CONFIG_REGULATOR_SY8106A is not set +# CONFIG_REGULATOR_TPS51632 is not set +# CONFIG_REGULATOR_TPS62360 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_TPS65132 is not set +# CONFIG_REGULATOR_TPS6524X is not set +# CONFIG_REGULATOR_VCTRL is not set +CONFIG_CEC_CORE=y +CONFIG_CEC_NOTIFIER=y +CONFIG_RC_CORE=m +CONFIG_RC_MAP=m +CONFIG_LIRC=y +CONFIG_RC_DECODERS=y +CONFIG_IR_NEC_DECODER=m +CONFIG_IR_RC5_DECODER=m +CONFIG_IR_RC6_DECODER=m +CONFIG_IR_JVC_DECODER=m +CONFIG_IR_SONY_DECODER=m +CONFIG_IR_SANYO_DECODER=m +CONFIG_IR_SHARP_DECODER=m +CONFIG_IR_MCE_KBD_DECODER=m +CONFIG_IR_XMP_DECODER=m +CONFIG_IR_IMON_DECODER=m +CONFIG_IR_RCMM_DECODER=m +CONFIG_RC_DEVICES=y +CONFIG_RC_ATI_REMOTE=m +# CONFIG_IR_HIX5HD2 is not set +CONFIG_IR_IMON=m +CONFIG_IR_IMON_RAW=m +CONFIG_IR_MCEUSB=m +CONFIG_IR_MESON=m +CONFIG_IR_REDRAT3=m +# CONFIG_IR_SPI is not set +CONFIG_IR_STREAMZAP=m +CONFIG_IR_IGORPLUGUSB=m +CONFIG_IR_IGUANA=m +CONFIG_IR_TTUSBIR=m +# CONFIG_RC_LOOPBACK is not set +CONFIG_IR_GPIO_CIR=m +CONFIG_IR_GPIO_TX=m +CONFIG_IR_PWM_TX=m +# CONFIG_IR_SERIAL is not set +# CONFIG_IR_SIR is not set +CONFIG_RC_XBOX_DVD=m +CONFIG_MEDIA_SUPPORT=m + +# +# Multimedia core support +# +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_ANALOG_TV_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +# CONFIG_MEDIA_SDR_SUPPORT is not set +CONFIG_MEDIA_CEC_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +# CONFIG_MEDIA_CONTROLLER_DVB is not set +CONFIG_VIDEO_DEV=m +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_V4L2=m +# CONFIG_VIDEO_ADV_DEBUG is not set +# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set +CONFIG_VIDEO_TUNER=m +CONFIG_V4L2_MEM2MEM_DEV=m +CONFIG_VIDEOBUF_GEN=m +CONFIG_VIDEOBUF_VMALLOC=m +CONFIG_DVB_CORE=m +# CONFIG_DVB_MMAP is not set +CONFIG_DVB_NET=y +CONFIG_TTPCI_EEPROM=m +CONFIG_DVB_MAX_ADAPTERS=8 +# CONFIG_DVB_DYNAMIC_MINORS is not set +# CONFIG_DVB_DEMUX_SECTION_LOSS_LOG is not set +# CONFIG_DVB_ULE_DEBUG is not set + +# +# Media drivers +# +CONFIG_MEDIA_USB_SUPPORT=y + +# +# Webcam devices +# +CONFIG_USB_VIDEO_CLASS=m +# CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV is not set +# CONFIG_USB_GSPCA is not set +# CONFIG_USB_PWC is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_USB_ZR364XX is not set +# CONFIG_USB_STKWEBCAM is not set +# CONFIG_USB_S2255 is not set +CONFIG_VIDEO_USBTV=m + +# +# Analog TV USB devices +# +CONFIG_VIDEO_PVRUSB2=m +CONFIG_VIDEO_PVRUSB2_SYSFS=y +CONFIG_VIDEO_PVRUSB2_DVB=y +# CONFIG_VIDEO_PVRUSB2_DEBUGIFC is not set +CONFIG_VIDEO_HDPVR=m +CONFIG_VIDEO_USBVISION=m +CONFIG_VIDEO_STK1160_COMMON=m +CONFIG_VIDEO_STK1160=m +# CONFIG_VIDEO_GO7007 is not set + +# +# Analog/digital TV USB devices +# +CONFIG_VIDEO_AU0828=m +CONFIG_VIDEO_AU0828_V4L2=y +CONFIG_VIDEO_AU0828_RC=y +CONFIG_VIDEO_CX231XX=m +CONFIG_VIDEO_CX231XX_RC=y +# CONFIG_VIDEO_CX231XX_ALSA is not set +CONFIG_VIDEO_CX231XX_DVB=m +CONFIG_VIDEO_TM6000=m +# CONFIG_VIDEO_TM6000_ALSA is not set +CONFIG_VIDEO_TM6000_DVB=m + +# +# Digital TV USB devices +# +CONFIG_DVB_USB=m +# CONFIG_DVB_USB_DEBUG is not set +CONFIG_DVB_USB_DIB3000MC=m +CONFIG_DVB_USB_A800=m +CONFIG_DVB_USB_DIBUSB_MB=m +CONFIG_DVB_USB_DIBUSB_MB_FAULTY=y +CONFIG_DVB_USB_DIBUSB_MC=m +CONFIG_DVB_USB_DIB0700=m +CONFIG_DVB_USB_UMT_010=m +CONFIG_DVB_USB_CXUSB=m +CONFIG_DVB_USB_M920X=m +CONFIG_DVB_USB_DIGITV=m +CONFIG_DVB_USB_VP7045=m +CONFIG_DVB_USB_VP702X=m +CONFIG_DVB_USB_GP8PSK=m +CONFIG_DVB_USB_NOVA_T_USB2=m +CONFIG_DVB_USB_TTUSB2=m +CONFIG_DVB_USB_DTT200U=m +CONFIG_DVB_USB_OPERA1=m +CONFIG_DVB_USB_AF9005=m +CONFIG_DVB_USB_AF9005_REMOTE=m +CONFIG_DVB_USB_PCTV452E=m +CONFIG_DVB_USB_DW2102=m +CONFIG_DVB_USB_CINERGY_T2=m +CONFIG_DVB_USB_DTV5100=m +CONFIG_DVB_USB_AZ6027=m +CONFIG_DVB_USB_TECHNISAT_USB2=m +CONFIG_DVB_USB_V2=m +CONFIG_DVB_USB_AF9015=m +CONFIG_DVB_USB_AF9035=m +CONFIG_DVB_USB_ANYSEE=m +CONFIG_DVB_USB_AU6610=m +CONFIG_DVB_USB_AZ6007=m +CONFIG_DVB_USB_CE6230=m +CONFIG_DVB_USB_EC168=m +CONFIG_DVB_USB_GL861=m +CONFIG_DVB_USB_LME2510=m +CONFIG_DVB_USB_MXL111SF=m +CONFIG_DVB_USB_RTL28XXU=m +CONFIG_DVB_USB_DVBSKY=m +CONFIG_DVB_USB_ZD1301=m +CONFIG_SMS_USB_DRV=m +CONFIG_DVB_B2C2_FLEXCOP_USB=m +# CONFIG_DVB_B2C2_FLEXCOP_USB_DEBUG is not set +CONFIG_DVB_AS102=m + +# +# Webcam, TV (analog/digital) USB devices +# +CONFIG_VIDEO_EM28XX=m +# CONFIG_VIDEO_EM28XX_V4L2 is not set +# CONFIG_VIDEO_EM28XX_ALSA is not set +CONFIG_VIDEO_EM28XX_DVB=m +CONFIG_VIDEO_EM28XX_RC=m + +# +# USB HDMI CEC adapters +# +# CONFIG_USB_PULSE8_CEC is not set +# CONFIG_USB_RAINSHADOW_CEC is not set +# CONFIG_V4L_PLATFORM_DRIVERS is not set +CONFIG_V4L_MEM2MEM_DRIVERS=y +CONFIG_VIDEO_MEM2MEM_DEINTERLACE=m +# CONFIG_VIDEO_SH_VEU is not set +CONFIG_VIDEO_MESON_VDEC=m +# CONFIG_V4L_TEST_DRIVERS is not set +# CONFIG_DVB_PLATFORM_DRIVERS is not set +CONFIG_CEC_PLATFORM_DRIVERS=y +# CONFIG_VIDEO_CROS_EC_CEC is not set +CONFIG_VIDEO_MESON_AO_CEC=m +CONFIG_VIDEO_MESON_G12A_AO_CEC=m + +# +# Supported MMC/SDIO adapters +# +# CONFIG_SMS_SDIO_DRV is not set +# CONFIG_RADIO_ADAPTERS is not set +CONFIG_MEDIA_COMMON_OPTIONS=y + +# +# common driver options +# +CONFIG_VIDEO_CX2341X=m +CONFIG_VIDEO_TVEEPROM=m +CONFIG_CYPRESS_FIRMWARE=m +CONFIG_VIDEOBUF2_CORE=m +CONFIG_VIDEOBUF2_V4L2=m +CONFIG_VIDEOBUF2_MEMOPS=m +CONFIG_VIDEOBUF2_DMA_CONTIG=m +CONFIG_VIDEOBUF2_VMALLOC=m +CONFIG_DVB_B2C2_FLEXCOP=m +CONFIG_SMS_SIANO_MDTV=m +CONFIG_SMS_SIANO_RC=y + +# +# Media ancillary drivers (tuners, sensors, i2c, spi, frontends) +# +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_MEDIA_ATTACH=y +CONFIG_VIDEO_IR_I2C=m + +# +# Audio decoders, processors and mixers +# +CONFIG_VIDEO_MSP3400=m +CONFIG_VIDEO_CS53L32A=m +CONFIG_VIDEO_WM8775=m + +# +# RDS decoders +# + +# +# Video decoders +# +CONFIG_VIDEO_SAA711X=m + +# +# Video and audio decoders +# +CONFIG_VIDEO_CX25840=m + +# +# Video encoders +# + +# +# Camera sensor devices +# + +# +# Flash devices +# + +# +# Video improvement chips +# + +# +# Audio/Video compression chips +# + +# +# SDR tuner chips +# + +# +# Miscellaneous helper chips +# + +# +# Media SPI Adapters +# +CONFIG_CXD2880_SPI_DRV=m +CONFIG_MEDIA_TUNER=m +CONFIG_MEDIA_TUNER_SIMPLE=m +CONFIG_MEDIA_TUNER_TDA18250=m +CONFIG_MEDIA_TUNER_TDA8290=m +CONFIG_MEDIA_TUNER_TDA827X=m +CONFIG_MEDIA_TUNER_TDA18271=m +CONFIG_MEDIA_TUNER_TDA9887=m +CONFIG_MEDIA_TUNER_TEA5761=m +CONFIG_MEDIA_TUNER_TEA5767=m +CONFIG_MEDIA_TUNER_MT20XX=m +CONFIG_MEDIA_TUNER_MT2060=m +CONFIG_MEDIA_TUNER_MT2063=m +CONFIG_MEDIA_TUNER_MT2266=m +CONFIG_MEDIA_TUNER_QT1010=m +CONFIG_MEDIA_TUNER_XC2028=m +CONFIG_MEDIA_TUNER_XC5000=m +CONFIG_MEDIA_TUNER_XC4000=m +CONFIG_MEDIA_TUNER_MXL5005S=m +CONFIG_MEDIA_TUNER_MXL5007T=m +CONFIG_MEDIA_TUNER_MC44S803=m +CONFIG_MEDIA_TUNER_MAX2165=m +CONFIG_MEDIA_TUNER_TDA18218=m +CONFIG_MEDIA_TUNER_FC0011=m +CONFIG_MEDIA_TUNER_FC0012=m +CONFIG_MEDIA_TUNER_FC0013=m +CONFIG_MEDIA_TUNER_TDA18212=m +CONFIG_MEDIA_TUNER_E4000=m +CONFIG_MEDIA_TUNER_FC2580=m +CONFIG_MEDIA_TUNER_TUA9001=m +CONFIG_MEDIA_TUNER_SI2157=m +CONFIG_MEDIA_TUNER_IT913X=m +CONFIG_MEDIA_TUNER_R820T=m +CONFIG_MEDIA_TUNER_QM1D1C0042=m + +# +# Multistandard (satellite) frontends +# +CONFIG_DVB_STB0899=m +CONFIG_DVB_STB6100=m +CONFIG_DVB_STV090x=m +CONFIG_DVB_STV6110x=m +CONFIG_DVB_M88DS3103=m + +# +# Multistandard (cable + terrestrial) frontends +# +CONFIG_DVB_DRXK=m +CONFIG_DVB_TDA18271C2DD=m +CONFIG_DVB_SI2165=m +CONFIG_DVB_MN88472=m +CONFIG_DVB_MN88473=m + +# +# DVB-S (satellite) frontends +# +CONFIG_DVB_CX24123=m +CONFIG_DVB_MT312=m +CONFIG_DVB_ZL10039=m +CONFIG_DVB_S5H1420=m +CONFIG_DVB_STV0288=m +CONFIG_DVB_STB6000=m +CONFIG_DVB_STV0299=m +CONFIG_DVB_STV6110=m +CONFIG_DVB_STV0900=m +CONFIG_DVB_TDA10086=m +CONFIG_DVB_TUNER_ITD1000=m +CONFIG_DVB_TUNER_CX24113=m +CONFIG_DVB_TDA826X=m +CONFIG_DVB_CX24116=m +CONFIG_DVB_CX24120=m +CONFIG_DVB_SI21XX=m +CONFIG_DVB_TS2020=m +CONFIG_DVB_DS3000=m +CONFIG_DVB_TDA10071=m + +# +# DVB-T (terrestrial) frontends +# +CONFIG_DVB_CX22702=m +CONFIG_DVB_DRXD=m +CONFIG_DVB_TDA1004X=m +CONFIG_DVB_NXT6000=m +CONFIG_DVB_MT352=m +CONFIG_DVB_ZL10353=m +CONFIG_DVB_DIB3000MB=m +CONFIG_DVB_DIB3000MC=m +CONFIG_DVB_DIB7000M=m +CONFIG_DVB_DIB7000P=m +CONFIG_DVB_TDA10048=m +CONFIG_DVB_AF9013=m +CONFIG_DVB_EC100=m +CONFIG_DVB_CXD2820R=m +CONFIG_DVB_CXD2841ER=m +CONFIG_DVB_RTL2830=m +CONFIG_DVB_RTL2832=m +CONFIG_DVB_SI2168=m +CONFIG_DVB_AS102_FE=m +CONFIG_DVB_ZD1301_DEMOD=m +CONFIG_DVB_GP8PSK_FE=m + +# +# DVB-C (cable) frontends +# +CONFIG_DVB_TDA10023=m +CONFIG_DVB_STV0297=m + +# +# ATSC (North American/Korean Terrestrial/Cable DTV) frontends +# +CONFIG_DVB_NXT200X=m +CONFIG_DVB_BCM3510=m +CONFIG_DVB_LGDT330X=m +CONFIG_DVB_LGDT3305=m +CONFIG_DVB_LGDT3306A=m +CONFIG_DVB_LG2160=m +CONFIG_DVB_S5H1409=m +CONFIG_DVB_AU8522=m +CONFIG_DVB_AU8522_DTV=m +CONFIG_DVB_AU8522_V4L=m +CONFIG_DVB_S5H1411=m + +# +# ISDB-T (terrestrial) frontends +# +CONFIG_DVB_S921=m +CONFIG_DVB_DIB8000=m +CONFIG_DVB_MB86A20S=m + +# +# ISDB-S (satellite) & ISDB-T (terrestrial) frontends +# +CONFIG_DVB_TC90522=m + +# +# Digital terrestrial only tuners/PLL +# +CONFIG_DVB_PLL=m +CONFIG_DVB_TUNER_DIB0070=m +CONFIG_DVB_TUNER_DIB0090=m + +# +# SEC control devices for DVB-S +# +CONFIG_DVB_DRX39XYJ=m +CONFIG_DVB_LNBP21=m +CONFIG_DVB_LNBP22=m +CONFIG_DVB_ISL6421=m +CONFIG_DVB_ISL6423=m +CONFIG_DVB_A8293=m +CONFIG_DVB_LGS8GXX=m +CONFIG_DVB_ATBM8830=m +CONFIG_DVB_IX2505V=m +CONFIG_DVB_M88RS2000=m +CONFIG_DVB_AF9033=m + +# +# Common Interface (EN50221) controller drivers +# +CONFIG_DVB_SP2=m + +# +# Tools to develop new frontends +# + +# +# Graphics support +# +CONFIG_DRM=y +# CONFIG_DRM_DP_AUX_CHARDEV is not set +# CONFIG_DRM_DEBUG_MM is not set +# CONFIG_DRM_DEBUG_SELFTEST is not set +CONFIG_DRM_KMS_HELPER=y +CONFIG_DRM_KMS_FB_HELPER=y +CONFIG_DRM_FBDEV_EMULATION=y +CONFIG_DRM_FBDEV_OVERALLOC=100 +# CONFIG_DRM_FBDEV_LEAK_PHYS_SMEM is not set +CONFIG_DRM_LOAD_EDID_FIRMWARE=y +# CONFIG_DRM_DP_CEC is not set +CONFIG_DRM_GEM_CMA_HELPER=y +CONFIG_DRM_KMS_CMA_HELPER=y +CONFIG_DRM_GEM_SHMEM_HELPER=y +CONFIG_DRM_SCHED=m + +# +# I2C encoder or helper chips +# +# CONFIG_DRM_I2C_CH7006 is not set +# CONFIG_DRM_I2C_SIL164 is not set +# CONFIG_DRM_I2C_NXP_TDA998X is not set +# CONFIG_DRM_I2C_NXP_TDA9950 is not set + +# +# ARM devices +# +# CONFIG_DRM_HDLCD is not set +# CONFIG_DRM_MALI_DISPLAY is not set +# CONFIG_DRM_KOMEDA is not set + +# +# ACP (Audio CoProcessor) Configuration +# + +# +# AMD Library routines +# +# CONFIG_DRM_VGEM is not set +# CONFIG_DRM_VKMS is not set +# CONFIG_DRM_UDL is not set +# CONFIG_DRM_RCAR_DW_HDMI is not set +# CONFIG_DRM_RCAR_LVDS is not set +CONFIG_DRM_PANEL=y + +# +# Display Panels +# +# CONFIG_DRM_PANEL_ARM_VERSATILE is not set +# CONFIG_DRM_PANEL_LVDS is not set +# CONFIG_DRM_PANEL_SIMPLE is not set +# CONFIG_DRM_PANEL_ILITEK_IL9322 is not set +# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set +# CONFIG_DRM_PANEL_LG_LG4573 is not set +# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set +# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set +# CONFIG_DRM_PANEL_SEIKO_43WVF1G is not set +# CONFIG_DRM_PANEL_SITRONIX_ST7789V is not set +# CONFIG_DRM_PANEL_TPO_TPG110 is not set +CONFIG_DRM_BRIDGE=y +CONFIG_DRM_PANEL_BRIDGE=y + +# +# Display Interface Bridges +# +# CONFIG_DRM_ANALOGIX_ANX78XX is not set +# CONFIG_DRM_CDNS_DSI is not set +# CONFIG_DRM_DUMB_VGA_DAC is not set +# CONFIG_DRM_LVDS_ENCODER is not set +# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set +# CONFIG_DRM_NXP_PTN3460 is not set +# CONFIG_DRM_PARADE_PS8622 is not set +# CONFIG_DRM_SIL_SII8620 is not set +# CONFIG_DRM_SII902X is not set +# CONFIG_DRM_SII9234 is not set +# CONFIG_DRM_THINE_THC63LVD1024 is not set +# CONFIG_DRM_TOSHIBA_TC358764 is not set +# CONFIG_DRM_TOSHIBA_TC358767 is not set +# CONFIG_DRM_TI_TFP410 is not set +# CONFIG_DRM_TI_SN65DSI86 is not set +# CONFIG_DRM_I2C_ADV7511 is not set +CONFIG_DRM_DW_HDMI=y +# CONFIG_DRM_DW_HDMI_AHB_AUDIO is not set +CONFIG_DRM_DW_HDMI_I2S_AUDIO=y +# CONFIG_DRM_DW_HDMI_CEC is not set +# CONFIG_DRM_ETNAVIV is not set +# CONFIG_DRM_ARCPGU is not set +# CONFIG_DRM_HISI_KIRIN is not set +# CONFIG_DRM_MXSFB is not set +CONFIG_DRM_MESON=y +CONFIG_DRM_MESON_DW_HDMI=y +# CONFIG_DRM_TINYDRM is not set +# CONFIG_DRM_PL111 is not set +CONFIG_DRM_LIMA=m +CONFIG_DRM_PANFROST=m +# CONFIG_DRM_LEGACY is not set +CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y + +# +# Frame buffer Devices +# +CONFIG_FB_CMDLINE=y +CONFIG_FB_NOTIFY=y +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +CONFIG_FB_SYS_FILLRECT=y +CONFIG_FB_SYS_COPYAREA=y +CONFIG_FB_SYS_IMAGEBLIT=y +# CONFIG_FB_FOREIGN_ENDIAN is not set +CONFIG_FB_SYS_FOPS=y +CONFIG_FB_DEFERRED_IO=y +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +CONFIG_FB_ARMCLCD=y +# CONFIG_FB_OPENCORES is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_SMSCUFX is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_IBM_GXT4500 is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_SIMPLE is not set +# CONFIG_FB_SSD1307 is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_PM8941_WLED is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set +# CONFIG_BACKLIGHT_LM3630A is not set +# CONFIG_BACKLIGHT_LM3639 is not set +# CONFIG_BACKLIGHT_LP855X is not set +CONFIG_BACKLIGHT_GPIO=y +# CONFIG_BACKLIGHT_LV5207LP is not set +# CONFIG_BACKLIGHT_BD6107 is not set +# CONFIG_BACKLIGHT_ARCXCNN is not set +CONFIG_VIDEOMODE_HELPERS=y +CONFIG_HDMI=y + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=80 +CONFIG_DUMMY_CONSOLE_ROWS=25 +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set +# CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_PCM_ELD=y +CONFIG_SND_PCM_IEC958=y +CONFIG_SND_HWDEP=m +CONFIG_SND_RAWMIDI=m +CONFIG_SND_JACK=y +CONFIG_SND_JACK_INPUT_DEV=y +# CONFIG_SND_OSSEMUL is not set +CONFIG_SND_PCM_TIMER=y +# CONFIG_SND_HRTIMER is not set +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_MAX_CARDS=32 +# CONFIG_SND_SUPPORT_OLD_API is not set +CONFIG_SND_PROC_FS=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +CONFIG_SND_VMASTER=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_DRIVERS is not set + +# +# HD-Audio +# +CONFIG_SND_HDA_PREALLOC_SIZE=2048 +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +CONFIG_SND_USB_AUDIO=m +CONFIG_SND_USB_UA101=m +CONFIG_SND_USB_CAIAQ=m +CONFIG_SND_USB_CAIAQ_INPUT=y +CONFIG_SND_USB_6FIRE=m +CONFIG_SND_USB_HIFACE=m +CONFIG_SND_BCD2000=m +CONFIG_SND_USB_LINE6=m +CONFIG_SND_USB_POD=m +CONFIG_SND_USB_PODHD=m +CONFIG_SND_USB_TONEPORT=m +CONFIG_SND_USB_VARIAX=m +CONFIG_SND_SOC=y +# CONFIG_SND_SOC_AMD_ACP is not set +# CONFIG_SND_ATMEL_SOC is not set +# CONFIG_SND_DESIGNWARE_I2S is not set + +# +# SoC Audio for Freescale CPUs +# + +# +# Common SoC Audio options for Freescale CPUs: +# +# CONFIG_SND_SOC_FSL_ASRC is not set +# CONFIG_SND_SOC_FSL_SAI is not set +# CONFIG_SND_SOC_FSL_SSI is not set +# CONFIG_SND_SOC_FSL_SPDIF is not set +# CONFIG_SND_SOC_FSL_ESAI is not set +# CONFIG_SND_SOC_FSL_MICFIL is not set +# CONFIG_SND_SOC_IMX_AUDMUX is not set +# CONFIG_SND_I2S_HI6210_I2S is not set +# CONFIG_SND_SOC_IMG is not set +# CONFIG_SND_SOC_MTK_BTCVSD is not set + +# +# ASoC support for Amlogic platforms +# +CONFIG_SND_MESON_AXG_FIFO=m +CONFIG_SND_MESON_AXG_FRDDR=m +CONFIG_SND_MESON_AXG_TODDR=m +CONFIG_SND_MESON_AXG_TDM_FORMATTER=m +CONFIG_SND_MESON_AXG_TDM_INTERFACE=m +CONFIG_SND_MESON_AXG_TDMIN=m +CONFIG_SND_MESON_AXG_TDMOUT=m +CONFIG_SND_MESON_AXG_SOUND_CARD=m +CONFIG_SND_MESON_AXG_SPDIFOUT=m +CONFIG_SND_MESON_AXG_SPDIFIN=m +CONFIG_SND_MESON_AXG_PDM=m +CONFIG_SND_MESON_G12A_TOHDMITX=m +CONFIG_SND_SOC_MESON_GX=m +CONFIG_SND_SOC_MESON_GX_I2S=m +CONFIG_SND_SOC_MESON_GX_SPDIF=m + +# +# STMicroelectronics STM32 SOC audio support +# +# CONFIG_SND_SOC_XILINX_I2S is not set +# CONFIG_SND_SOC_XILINX_AUDIO_FORMATTER is not set +# CONFIG_SND_SOC_XILINX_SPDIF is not set +# CONFIG_SND_SOC_XTFPGA_I2S is not set +# CONFIG_ZX_TDM is not set +CONFIG_SND_SOC_I2C_AND_SPI=y + +# +# CODEC drivers +# +# CONFIG_SND_SOC_AC97_CODEC is not set +# CONFIG_SND_SOC_ADAU1701 is not set +# CONFIG_SND_SOC_ADAU1761_I2C is not set +# CONFIG_SND_SOC_ADAU1761_SPI is not set +# CONFIG_SND_SOC_ADAU7002 is not set +# CONFIG_SND_SOC_AK4104 is not set +# CONFIG_SND_SOC_AK4118 is not set +# CONFIG_SND_SOC_AK4458 is not set +# CONFIG_SND_SOC_AK4554 is not set +# CONFIG_SND_SOC_AK4613 is not set +# CONFIG_SND_SOC_AK4642 is not set +# CONFIG_SND_SOC_AK5386 is not set +# CONFIG_SND_SOC_AK5558 is not set +# CONFIG_SND_SOC_ALC5623 is not set +# CONFIG_SND_SOC_BD28623 is not set +# CONFIG_SND_SOC_BT_SCO is not set +# CONFIG_SND_SOC_CROS_EC_CODEC is not set +# CONFIG_SND_SOC_CS35L32 is not set +# CONFIG_SND_SOC_CS35L33 is not set +# CONFIG_SND_SOC_CS35L34 is not set +# CONFIG_SND_SOC_CS35L35 is not set +# CONFIG_SND_SOC_CS35L36 is not set +# CONFIG_SND_SOC_CS42L42 is not set +# CONFIG_SND_SOC_CS42L51_I2C is not set +# CONFIG_SND_SOC_CS42L52 is not set +# CONFIG_SND_SOC_CS42L56 is not set +# CONFIG_SND_SOC_CS42L73 is not set +# CONFIG_SND_SOC_CS4265 is not set +# CONFIG_SND_SOC_CS4270 is not set +# CONFIG_SND_SOC_CS4271_I2C is not set +# CONFIG_SND_SOC_CS4271_SPI is not set +# CONFIG_SND_SOC_CS42XX8_I2C is not set +# CONFIG_SND_SOC_CS43130 is not set +# CONFIG_SND_SOC_CS4341 is not set +# CONFIG_SND_SOC_CS4349 is not set +# CONFIG_SND_SOC_CS53L30 is not set +# CONFIG_SND_SOC_DMIC is not set +CONFIG_SND_SOC_HDMI_CODEC=y +CONFIG_SND_SOC_ES7134=y +# CONFIG_SND_SOC_ES7241 is not set +# CONFIG_SND_SOC_ES8316 is not set +# CONFIG_SND_SOC_ES8328_I2C is not set +# CONFIG_SND_SOC_ES8328_SPI is not set +# CONFIG_SND_SOC_GTM601 is not set +# CONFIG_SND_SOC_INNO_RK3036 is not set +# CONFIG_SND_SOC_MAX98088 is not set +CONFIG_SND_SOC_MAX98357A=m +# CONFIG_SND_SOC_MAX98504 is not set +# CONFIG_SND_SOC_MAX9867 is not set +# CONFIG_SND_SOC_MAX98927 is not set +# CONFIG_SND_SOC_MAX98373 is not set +# CONFIG_SND_SOC_MAX9860 is not set +# CONFIG_SND_SOC_MSM8916_WCD_DIGITAL is not set +# CONFIG_SND_SOC_PCM1681 is not set +# CONFIG_SND_SOC_PCM1789_I2C is not set +# CONFIG_SND_SOC_PCM179X_I2C is not set +# CONFIG_SND_SOC_PCM179X_SPI is not set +# CONFIG_SND_SOC_PCM186X_I2C is not set +# CONFIG_SND_SOC_PCM186X_SPI is not set +# CONFIG_SND_SOC_PCM3060_I2C is not set +# CONFIG_SND_SOC_PCM3060_SPI is not set +# CONFIG_SND_SOC_PCM3168A_I2C is not set +# CONFIG_SND_SOC_PCM3168A_SPI is not set +# CONFIG_SND_SOC_PCM512x_I2C is not set +# CONFIG_SND_SOC_PCM512x_SPI is not set +# CONFIG_SND_SOC_RK3328 is not set +# CONFIG_SND_SOC_RT5616 is not set +# CONFIG_SND_SOC_RT5631 is not set +# CONFIG_SND_SOC_SGTL5000 is not set +# CONFIG_SND_SOC_SIMPLE_AMPLIFIER is not set +# CONFIG_SND_SOC_SIRF_AUDIO_CODEC is not set +CONFIG_SND_SOC_SPDIF=y +# CONFIG_SND_SOC_SSM2305 is not set +# CONFIG_SND_SOC_SSM2602_SPI is not set +# CONFIG_SND_SOC_SSM2602_I2C is not set +# CONFIG_SND_SOC_SSM4567 is not set +# CONFIG_SND_SOC_STA32X is not set +# CONFIG_SND_SOC_STA350 is not set +# CONFIG_SND_SOC_STI_SAS is not set +# CONFIG_SND_SOC_TAS2552 is not set +# CONFIG_SND_SOC_TAS5086 is not set +# CONFIG_SND_SOC_TAS571X is not set +# CONFIG_SND_SOC_TAS5720 is not set +# CONFIG_SND_SOC_TAS6424 is not set +# CONFIG_SND_SOC_TDA7419 is not set +# CONFIG_SND_SOC_TFA9879 is not set +# CONFIG_SND_SOC_TLV320AIC23_I2C is not set +# CONFIG_SND_SOC_TLV320AIC23_SPI is not set +# CONFIG_SND_SOC_TLV320AIC31XX is not set +# CONFIG_SND_SOC_TLV320AIC32X4_I2C is not set +# CONFIG_SND_SOC_TLV320AIC32X4_SPI is not set +# CONFIG_SND_SOC_TLV320AIC3X is not set +# CONFIG_SND_SOC_TS3A227E is not set +# CONFIG_SND_SOC_TSCS42XX is not set +# CONFIG_SND_SOC_TSCS454 is not set +# CONFIG_SND_SOC_WM8510 is not set +# CONFIG_SND_SOC_WM8523 is not set +# CONFIG_SND_SOC_WM8524 is not set +# CONFIG_SND_SOC_WM8580 is not set +# CONFIG_SND_SOC_WM8711 is not set +# CONFIG_SND_SOC_WM8728 is not set +# CONFIG_SND_SOC_WM8731 is not set +# CONFIG_SND_SOC_WM8737 is not set +# CONFIG_SND_SOC_WM8741 is not set +# CONFIG_SND_SOC_WM8750 is not set +# CONFIG_SND_SOC_WM8753 is not set +# CONFIG_SND_SOC_WM8770 is not set +# CONFIG_SND_SOC_WM8776 is not set +# CONFIG_SND_SOC_WM8782 is not set +# CONFIG_SND_SOC_WM8804_I2C is not set +# CONFIG_SND_SOC_WM8804_SPI is not set +# CONFIG_SND_SOC_WM8903 is not set +# CONFIG_SND_SOC_WM8904 is not set +# CONFIG_SND_SOC_WM8960 is not set +# CONFIG_SND_SOC_WM8962 is not set +# CONFIG_SND_SOC_WM8974 is not set +# CONFIG_SND_SOC_WM8978 is not set +# CONFIG_SND_SOC_WM8985 is not set +# CONFIG_SND_SOC_ZX_AUD96P22 is not set +# CONFIG_SND_SOC_MAX9759 is not set +# CONFIG_SND_SOC_MT6351 is not set +# CONFIG_SND_SOC_MT6358 is not set +# CONFIG_SND_SOC_NAU8540 is not set +# CONFIG_SND_SOC_NAU8810 is not set +# CONFIG_SND_SOC_NAU8822 is not set +# CONFIG_SND_SOC_NAU8824 is not set +# CONFIG_SND_SOC_TPA6130A2 is not set +CONFIG_SND_SIMPLE_CARD_UTILS=m +CONFIG_SND_SIMPLE_CARD=m +# CONFIG_SND_AUDIO_GRAPH_CARD is not set + +# +# HID support +# +CONFIG_HID=y +# CONFIG_HID_BATTERY_STRENGTH is not set +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_GENERIC=y + +# +# Special HID drivers +# +CONFIG_HID_A4TECH=y +# CONFIG_HID_ACCUTOUCH is not set +# CONFIG_HID_ACRUX is not set +CONFIG_HID_APPLE=y +# CONFIG_HID_APPLEIR is not set +CONFIG_HID_ASUS=y +CONFIG_HID_AUREAL=y +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_BETOP_FF is not set +CONFIG_HID_BIGBEN_FF=m +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +# CONFIG_HID_CORSAIR is not set +# CONFIG_HID_COUGAR is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CMEDIA is not set +# CONFIG_HID_CP2112 is not set +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=m +CONFIG_DRAGONRISE_FF=y +# CONFIG_HID_EMS_FF is not set +# CONFIG_HID_ELAN is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_ELO is not set +CONFIG_HID_EZKEY=y +# CONFIG_HID_GEMBIRD is not set +# CONFIG_HID_GFRM is not set +# CONFIG_HID_HOLTEK is not set +# CONFIG_HID_GOOGLE_HAMMER is not set +# CONFIG_HID_GT683R is not set +# CONFIG_HID_KEYTOUCH is not set +CONFIG_HID_KYE=y +# CONFIG_HID_UCLOGIC is not set +# CONFIG_HID_WALTOP is not set +# CONFIG_HID_VIEWSONIC is not set +CONFIG_HID_GYRATION=y +# CONFIG_HID_ICADE is not set +# CONFIG_HID_ITE is not set +# CONFIG_HID_JABRA is not set +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +# CONFIG_HID_LCPOWER is not set +# CONFIG_HID_LED is not set +CONFIG_HID_LENOVO=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_HID_LOGITECH_HIDPP=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_LOGIWHEELS_FF=y +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_MALTRON is not set +# CONFIG_HID_MAYFLASH is not set +# CONFIG_HID_REDRAGON is not set +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=m +# CONFIG_HID_NTI is not set +# CONFIG_HID_NTRIG is not set +CONFIG_HID_ORTEK=y +CONFIG_HID_OUYA=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PENMOUNT=y +CONFIG_HID_PETALYNX=y +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_PLANTRONICS is not set +# CONFIG_HID_PRIMAX is not set +# CONFIG_HID_RETRODE is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_SAITEK is not set +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_SONY_FF=y +# CONFIG_HID_SPEEDLINK is not set +CONFIG_HID_STEAM=y +# CONFIG_HID_STEELSERIES is not set +CONFIG_HID_SUNPLUS=y +CONFIG_HID_RMI=y +# CONFIG_HID_GREENASIA is not set +CONFIG_HID_SMARTJOYPLUS=m +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +# CONFIG_HID_THINGM is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_UDRAW_PS3 is not set +# CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=m +CONFIG_HID_XINMO=y +# CONFIG_HID_ZEROPLUS is not set +CONFIG_HID_ZYDACRON=y +# CONFIG_HID_SENSOR_HUB is not set +# CONFIG_HID_ALPS is not set + +# +# USB HID support +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +CONFIG_USB_HIDDEV=y + +# +# I2C HID support +# +# CONFIG_I2C_HID is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +CONFIG_USB_SUPPORT=y +CONFIG_USB_COMMON=y +CONFIG_USB_ARCH_HAS_HCD=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEFAULT_PERSIST=y +# CONFIG_USB_DYNAMIC_MINORS is not set +CONFIG_USB_OTG=y +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_OTG_FSM is not set +# CONFIG_USB_LEDS_TRIGGER_USBPORT is not set +CONFIG_USB_AUTOSUSPEND_DELAY=2 +CONFIG_USB_MON=m +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_XHCI_HCD=y +# CONFIG_USB_XHCI_DBGCAP is not set +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_EHCI_TT_NEWSCHED=y +# CONFIG_USB_EHCI_FSL is not set +CONFIG_USB_EHCI_HCD_PLATFORM=y +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_FOTG210_HCD is not set +# CONFIG_USB_MAX3421_HCD is not set +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HCD_BCMA is not set +# CONFIG_USB_HCD_SSB is not set +# CONFIG_USB_HCD_TEST_MODE is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=m +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_REALTEK is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_STORAGE_ENE_UB6250 is not set +CONFIG_USB_UAS=m + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USBIP_CORE is not set +# CONFIG_USB_MUSB_HDRC is not set +CONFIG_USB_DWC3=y +# CONFIG_USB_DWC3_HOST is not set +# CONFIG_USB_DWC3_GADGET is not set +CONFIG_USB_DWC3_DUAL_ROLE=y + +# +# Platform Glue Driver Support +# +CONFIG_USB_DWC3_MESON_G12A=y +CONFIG_USB_DWC3_OF_SIMPLE=y +CONFIG_USB_DWC2=y +# CONFIG_USB_DWC2_HOST is not set + +# +# Gadget/Dual-role mode requires USB Gadget support to be enabled +# +# CONFIG_USB_DWC2_PERIPHERAL is not set +CONFIG_USB_DWC2_DUAL_ROLE=y +# CONFIG_USB_DWC2_DEBUG is not set +# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set +# CONFIG_USB_CHIPIDEA is not set +# CONFIG_USB_ISP1760 is not set + +# +# USB port drivers +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +# CONFIG_USB_SERIAL_SIMPLE is not set +# CONFIG_USB_SERIAL_AIRCABLE is not set +# CONFIG_USB_SERIAL_ARK3116 is not set +# CONFIG_USB_SERIAL_BELKIN is not set +CONFIG_USB_SERIAL_CH341=m +# CONFIG_USB_SERIAL_WHITEHEAT is not set +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +CONFIG_USB_SERIAL_CP210X=m +# CONFIG_USB_SERIAL_CYPRESS_M8 is not set +# CONFIG_USB_SERIAL_EMPEG is not set +CONFIG_USB_SERIAL_FTDI_SIO=m +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_F81232 is not set +# CONFIG_USB_SERIAL_F8153X is not set +# CONFIG_USB_SERIAL_GARMIN is not set +# CONFIG_USB_SERIAL_IPW is not set +CONFIG_USB_SERIAL_IUU=m +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_METRO is not set +# CONFIG_USB_SERIAL_MOS7720 is not set +# CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set +# CONFIG_USB_SERIAL_NAVMAN is not set +CONFIG_USB_SERIAL_PL2303=m +# CONFIG_USB_SERIAL_OTI6858 is not set +# CONFIG_USB_SERIAL_QCAUX is not set +# CONFIG_USB_SERIAL_QUALCOMM is not set +# CONFIG_USB_SERIAL_SPCP8X5 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set +# CONFIG_USB_SERIAL_SYMBOL is not set +# CONFIG_USB_SERIAL_TI is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OPTION is not set +# CONFIG_USB_SERIAL_OMNINET is not set +# CONFIG_USB_SERIAL_OPTICON is not set +# CONFIG_USB_SERIAL_XSENS_MT is not set +# CONFIG_USB_SERIAL_WISHBONE is not set +# CONFIG_USB_SERIAL_SSU100 is not set +# CONFIG_USB_SERIAL_QT2 is not set +# CONFIG_USB_SERIAL_UPD78F0730 is not set +# CONFIG_USB_SERIAL_DEBUG is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_EHSET_TEST_FIXTURE is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +# CONFIG_USB_EZUSB_FX2 is not set +# CONFIG_USB_HUB_USB251XB is not set +# CONFIG_USB_HSIC_USB3503 is not set +# CONFIG_USB_HSIC_USB4604 is not set +# CONFIG_USB_LINK_LAYER_TEST is not set +# CONFIG_USB_CHAOSKEY is not set + +# +# USB Physical Layer drivers +# +# CONFIG_NOP_USB_XCEIV is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ISP1301 is not set +CONFIG_USB_ULPI=y +CONFIG_USB_ULPI_VIEWPORT=y +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG is not set +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_VBUS_DRAW=2 +CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 + +# +# USB Peripheral Controller +# +# CONFIG_USB_FOTG210_UDC is not set +# CONFIG_USB_GR_UDC is not set +# CONFIG_USB_R8A66597 is not set +# CONFIG_USB_PXA27X is not set +# CONFIG_USB_MV_UDC is not set +# CONFIG_USB_MV_U3D is not set +# CONFIG_USB_SNP_UDC_PLAT is not set +# CONFIG_USB_M66592 is not set +# CONFIG_USB_BDC_UDC is not set +# CONFIG_USB_NET2272 is not set +# CONFIG_USB_GADGET_XILINX is not set +# CONFIG_USB_DUMMY_HCD is not set +# CONFIG_USB_CONFIGFS is not set +# CONFIG_TYPEC is not set +CONFIG_USB_ROLE_SWITCH=y +# CONFIG_USB_LED_TRIG is not set +# CONFIG_USB_ULPI_BUS is not set +# CONFIG_UWB is not set +CONFIG_MMC=y +CONFIG_PWRSEQ_EMMC=y +CONFIG_PWRSEQ_SIMPLE=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=32 +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_ARMMMCI is not set +# CONFIG_MMC_SDHCI is not set +CONFIG_MMC_MESON_GX=y +# CONFIG_MMC_MESON_MX_SDIO is not set +CONFIG_MMC_SPI=y +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MMC_USDHI6ROL0 is not set +# CONFIG_MMC_CQHCI is not set +# CONFIG_MMC_MTK is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +# CONFIG_LEDS_CLASS_FLASH is not set +# CONFIG_LEDS_BRIGHTNESS_HW_CHANGED is not set + +# +# LED drivers +# +# CONFIG_LEDS_AN30259A is not set +# CONFIG_LEDS_BCM6328 is not set +# CONFIG_LEDS_BCM6358 is not set +# CONFIG_LEDS_CR0014114 is not set +# CONFIG_LEDS_LM3530 is not set +# CONFIG_LEDS_LM3642 is not set +# CONFIG_LEDS_LM3692X is not set +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_LP3952 is not set +# CONFIG_LEDS_LP5521 is not set +# CONFIG_LEDS_LP5523 is not set +# CONFIG_LEDS_LP5562 is not set +# CONFIG_LEDS_LP8501 is not set +# CONFIG_LEDS_LP8860 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_PCA963X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_REGULATOR is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +# CONFIG_LEDS_TCA6507 is not set +# CONFIG_LEDS_TLC591XX is not set +# CONFIG_LEDS_LM355x is not set +# CONFIG_LEDS_IS31FL319X is not set +# CONFIG_LEDS_IS31FL32XX is not set + +# +# LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM) +# +# CONFIG_LEDS_BLINKM is not set +CONFIG_LEDS_SYSCON=y +# CONFIG_LEDS_MLXREG is not set +# CONFIG_LEDS_USER is not set + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGERS=y +# CONFIG_LEDS_TRIGGER_TIMER is not set +# CONFIG_LEDS_TRIGGER_ONESHOT is not set +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +CONFIG_LEDS_TRIGGER_CPU=y +# CONFIG_LEDS_TRIGGER_ACTIVITY is not set +# CONFIG_LEDS_TRIGGER_GPIO is not set +# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_LEDS_TRIGGER_TRANSIENT is not set +# CONFIG_LEDS_TRIGGER_CAMERA is not set +# CONFIG_LEDS_TRIGGER_PANIC is not set +# CONFIG_LEDS_TRIGGER_NETDEV is not set +# CONFIG_LEDS_TRIGGER_PATTERN is not set +# CONFIG_LEDS_TRIGGER_AUDIO is not set +# CONFIG_ACCESSIBILITY is not set +# CONFIG_INFINIBAND is not set +CONFIG_EDAC_SUPPORT=y +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +CONFIG_RTC_SYSTOHC=y +CONFIG_RTC_SYSTOHC_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set +CONFIG_RTC_NVMEM=y + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_ABB5ZES3 is not set +# CONFIG_RTC_DRV_ABEOZ9 is not set +# CONFIG_RTC_DRV_ABX80X is not set +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_HYM8563 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RK808 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12026 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8523 is not set +# CONFIG_RTC_DRV_PCF85063 is not set +# CONFIG_RTC_DRV_PCF85363 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8010 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3028 is not set +# CONFIG_RTC_DRV_RV8803 is not set +# CONFIG_RTC_DRV_S5M is not set +# CONFIG_RTC_DRV_SD3078 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1302 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1343 is not set +# CONFIG_RTC_DRV_DS1347 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6916 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RX4581 is not set +# CONFIG_RTC_DRV_RX6110 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_PCF2123 is not set +# CONFIG_RTC_DRV_MCP795 is not set +CONFIG_RTC_I2C_AND_SPI=y + +# +# SPI and I2C RTC drivers +# +CONFIG_RTC_DRV_DS3232=y +CONFIG_RTC_DRV_DS3232_HWMON=y +# CONFIG_RTC_DRV_PCF2127 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1685_FAMILY is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_DS2404 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set +# CONFIG_RTC_DRV_ZYNQMP is not set +# CONFIG_RTC_DRV_CROS_EC is not set + +# +# on-CPU RTC drivers +# +# CONFIG_RTC_DRV_PL030 is not set +CONFIG_RTC_DRV_PL031=y +# CONFIG_RTC_DRV_CADENCE is not set +# CONFIG_RTC_DRV_FTRTC010 is not set +# CONFIG_RTC_DRV_SNVS is not set +# CONFIG_RTC_DRV_R7301 is not set + +# +# HID Sensor RTC drivers +# +# CONFIG_DMADEVICES is not set + +# +# DMABUF options +# +CONFIG_SYNC_FILE=y +# CONFIG_SW_SYNC is not set +# CONFIG_UDMABUF is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_VFIO is not set +# CONFIG_VIRT_DRIVERS is not set +# CONFIG_VIRTIO_MENU is not set + +# +# Microsoft Hyper-V guest support +# +# CONFIG_STAGING is not set +# CONFIG_GOLDFISH is not set +CONFIG_CHROME_PLATFORMS=y +# CONFIG_CROS_EC_I2C is not set +# CONFIG_CROS_EC_SPI is not set +CONFIG_CROS_EC_PROTO=y +CONFIG_CLKDEV_LOOKUP=y +CONFIG_HAVE_CLK_PREPARE=y +CONFIG_COMMON_CLK=y + +# +# Common Clock Framework +# +CONFIG_COMMON_CLK_VERSATILE=y +CONFIG_CLK_SP810=y +# CONFIG_CLK_HSDK is not set +# CONFIG_COMMON_CLK_MAX9485 is not set +CONFIG_COMMON_CLK_RK808=y +CONFIG_COMMON_CLK_SCPI=y +# CONFIG_COMMON_CLK_SI5351 is not set +# CONFIG_COMMON_CLK_SI514 is not set +# CONFIG_COMMON_CLK_SI544 is not set +# CONFIG_COMMON_CLK_SI570 is not set +# CONFIG_COMMON_CLK_CDCE706 is not set +# CONFIG_COMMON_CLK_CDCE925 is not set +CONFIG_COMMON_CLK_CS2000_CP=y +CONFIG_COMMON_CLK_S2MPS11=y +CONFIG_CLK_QORIQ=y +CONFIG_COMMON_CLK_XGENE=y +CONFIG_COMMON_CLK_PWM=y +# CONFIG_COMMON_CLK_VC5 is not set +# CONFIG_COMMON_CLK_FIXED_MMIO is not set +CONFIG_COMMON_CLK_MESON_INPUT=y +CONFIG_COMMON_CLK_MESON_REGMAP=y +CONFIG_COMMON_CLK_MESON_DUALDIV=y +CONFIG_COMMON_CLK_MESON_MPLL=y +CONFIG_COMMON_CLK_MESON_PHASE=y +CONFIG_COMMON_CLK_MESON_PLL=y +CONFIG_COMMON_CLK_MESON_SCLK_DIV=y +CONFIG_COMMON_CLK_MESON_VID_PLL_DIV=y +CONFIG_COMMON_CLK_MESON_AO_CLKC=y +CONFIG_COMMON_CLK_MESON_EE_CLKC=y +CONFIG_COMMON_CLK_GXBB=y +CONFIG_COMMON_CLK_AXG=y +CONFIG_COMMON_CLK_AXG_AUDIO=y +CONFIG_COMMON_CLK_G12A=y +# CONFIG_HWSPINLOCK is not set + +# +# Clock Source drivers +# +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_CLKSRC_MMIO=y +CONFIG_ARM_ARCH_TIMER=y +CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y +CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND=y +CONFIG_FSL_ERRATUM_A008585=y +# CONFIG_HISILICON_ERRATUM_161010101 is not set +# CONFIG_ARM64_ERRATUM_858921 is not set +CONFIG_ARM_TIMER_SP804=y +CONFIG_MAILBOX=y +CONFIG_ARM_MHU=y +CONFIG_PLATFORM_MHU=y +# CONFIG_PL320_MBOX is not set +# CONFIG_ALTERA_MBOX is not set +# CONFIG_MAILBOX_TEST is not set +CONFIG_IOMMU_IOVA=y +CONFIG_IOMMU_API=y +CONFIG_IOMMU_SUPPORT=y + +# +# Generic IOMMU Pagetable Support +# +CONFIG_IOMMU_IO_PGTABLE=y +CONFIG_IOMMU_IO_PGTABLE_LPAE=y +# CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST is not set +# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set +CONFIG_OF_IOMMU=y +CONFIG_IOMMU_DMA=y +# CONFIG_ARM_SMMU is not set +# CONFIG_ARM_SMMU_V3 is not set + +# +# Remoteproc drivers +# +# CONFIG_REMOTEPROC is not set + +# +# Rpmsg drivers +# +# CONFIG_RPMSG_QCOM_GLINK_RPM is not set +# CONFIG_RPMSG_VIRTIO is not set +# CONFIG_SOUNDWIRE is not set + +# +# SOC (System On Chip) specific Drivers +# + +# +# Amlogic SoC drivers +# +CONFIG_MESON_CANVAS=y +CONFIG_MESON_CLK_MEASURE=y +CONFIG_MESON_GX_SOCINFO=y +CONFIG_MESON_GX_PM_DOMAINS=y +CONFIG_MESON_MX_SOCINFO=y + +# +# Broadcom SoC drivers +# +# CONFIG_SOC_BRCMSTB is not set + +# +# NXP/Freescale QorIQ SoC drivers +# + +# +# i.MX SoC drivers +# + +# +# Qualcomm SoC drivers +# +# CONFIG_SOC_TI is not set + +# +# Xilinx SoC drivers +# +# CONFIG_XILINX_VCU is not set +CONFIG_PM_DEVFREQ=y + +# +# DEVFREQ Governors +# +CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=m +CONFIG_DEVFREQ_GOV_PERFORMANCE=m +CONFIG_DEVFREQ_GOV_POWERSAVE=m +# CONFIG_DEVFREQ_GOV_USERSPACE is not set +# CONFIG_DEVFREQ_GOV_PASSIVE is not set + +# +# DEVFREQ Drivers +# +# CONFIG_PM_DEVFREQ_EVENT is not set +CONFIG_EXTCON=y + +# +# Extcon Device Drivers +# +# CONFIG_EXTCON_ADC_JACK is not set +# CONFIG_EXTCON_ARIZONA is not set +# CONFIG_EXTCON_GPIO is not set +# CONFIG_EXTCON_MAX3355 is not set +# CONFIG_EXTCON_PTN5150 is not set +# CONFIG_EXTCON_RT8973A is not set +# CONFIG_EXTCON_SM5502 is not set +CONFIG_EXTCON_USB_GPIO=y +# CONFIG_EXTCON_USBC_CROS_EC is not set +# CONFIG_MEMORY is not set +CONFIG_IIO=y +# CONFIG_IIO_BUFFER is not set +# CONFIG_IIO_CONFIGFS is not set +# CONFIG_IIO_TRIGGER is not set +# CONFIG_IIO_SW_DEVICE is not set +# CONFIG_IIO_SW_TRIGGER is not set + +# +# Accelerometers +# +# CONFIG_ADIS16201 is not set +# CONFIG_ADIS16209 is not set +# CONFIG_ADXL345_I2C is not set +# CONFIG_ADXL345_SPI is not set +# CONFIG_ADXL372_SPI is not set +# CONFIG_ADXL372_I2C is not set +# CONFIG_BMA180 is not set +# CONFIG_BMA220 is not set +# CONFIG_BMC150_ACCEL is not set +# CONFIG_DA280 is not set +# CONFIG_DA311 is not set +# CONFIG_DMARD06 is not set +# CONFIG_DMARD09 is not set +# CONFIG_DMARD10 is not set +# CONFIG_IIO_CROS_EC_ACCEL_LEGACY is not set +# CONFIG_IIO_ST_ACCEL_3AXIS is not set +# CONFIG_KXSD9 is not set +# CONFIG_KXCJK1013 is not set +# CONFIG_MC3230 is not set +# CONFIG_MMA7455_I2C is not set +# CONFIG_MMA7455_SPI is not set +# CONFIG_MMA7660 is not set +# CONFIG_MMA8452 is not set +# CONFIG_MMA9551 is not set +# CONFIG_MMA9553 is not set +# CONFIG_MXC4005 is not set +# CONFIG_MXC6255 is not set +# CONFIG_SCA3000 is not set +# CONFIG_STK8312 is not set +# CONFIG_STK8BA50 is not set + +# +# Analog to digital converters +# +# CONFIG_AD7124 is not set +# CONFIG_AD7266 is not set +# CONFIG_AD7291 is not set +# CONFIG_AD7298 is not set +# CONFIG_AD7476 is not set +# CONFIG_AD7606_IFACE_PARALLEL is not set +# CONFIG_AD7606_IFACE_SPI is not set +# CONFIG_AD7766 is not set +# CONFIG_AD7768_1 is not set +# CONFIG_AD7791 is not set +# CONFIG_AD7793 is not set +# CONFIG_AD7887 is not set +# CONFIG_AD7923 is not set +# CONFIG_AD7949 is not set +# CONFIG_AD799X is not set +# CONFIG_CC10001_ADC is not set +# CONFIG_ENVELOPE_DETECTOR is not set +# CONFIG_HI8435 is not set +# CONFIG_HX711 is not set +# CONFIG_INA2XX_ADC is not set +# CONFIG_LTC2471 is not set +# CONFIG_LTC2485 is not set +# CONFIG_LTC2497 is not set +# CONFIG_MAX1027 is not set +# CONFIG_MAX11100 is not set +# CONFIG_MAX1118 is not set +# CONFIG_MAX1363 is not set +# CONFIG_MAX9611 is not set +# CONFIG_MCP320X is not set +# CONFIG_MCP3422 is not set +# CONFIG_MCP3911 is not set +CONFIG_MESON_SARADC=y +# CONFIG_NAU7802 is not set +# CONFIG_SD_ADC_MODULATOR is not set +# CONFIG_TI_ADC081C is not set +# CONFIG_TI_ADC0832 is not set +# CONFIG_TI_ADC084S021 is not set +# CONFIG_TI_ADC12138 is not set +# CONFIG_TI_ADC108S102 is not set +# CONFIG_TI_ADC128S052 is not set +# CONFIG_TI_ADC161S626 is not set +# CONFIG_TI_ADS1015 is not set +# CONFIG_TI_ADS7950 is not set +# CONFIG_TI_ADS8688 is not set +# CONFIG_TI_ADS124S08 is not set +# CONFIG_TI_TLC4541 is not set +# CONFIG_VF610_ADC is not set + +# +# Analog Front Ends +# +# CONFIG_IIO_RESCALE is not set + +# +# Amplifiers +# +# CONFIG_AD8366 is not set + +# +# Chemical Sensors +# +# CONFIG_ATLAS_PH_SENSOR is not set +# CONFIG_BME680 is not set +# CONFIG_CCS811 is not set +# CONFIG_IAQCORE is not set +# CONFIG_PMS7003 is not set +# CONFIG_SENSIRION_SGP30 is not set +# CONFIG_SPS30 is not set +# CONFIG_VZ89X is not set +# CONFIG_IIO_CROS_EC_SENSORS_CORE is not set + +# +# Hid Sensor IIO Common +# + +# +# SSP Sensor Common +# +# CONFIG_IIO_SSP_SENSORHUB is not set + +# +# Counters +# + +# +# Digital to analog converters +# +# CONFIG_AD5064 is not set +# CONFIG_AD5360 is not set +# CONFIG_AD5380 is not set +# CONFIG_AD5421 is not set +# CONFIG_AD5446 is not set +# CONFIG_AD5449 is not set +# CONFIG_AD5592R is not set +# CONFIG_AD5593R is not set +# CONFIG_AD5504 is not set +# CONFIG_AD5624R_SPI is not set +# CONFIG_LTC1660 is not set +# CONFIG_LTC2632 is not set +# CONFIG_AD5686_SPI is not set +# CONFIG_AD5696_I2C is not set +# CONFIG_AD5755 is not set +# CONFIG_AD5758 is not set +# CONFIG_AD5761 is not set +# CONFIG_AD5764 is not set +# CONFIG_AD5791 is not set +# CONFIG_AD7303 is not set +# CONFIG_AD8801 is not set +# CONFIG_DPOT_DAC is not set +# CONFIG_DS4424 is not set +# CONFIG_M62332 is not set +# CONFIG_MAX517 is not set +# CONFIG_MAX5821 is not set +# CONFIG_MCP4725 is not set +# CONFIG_MCP4922 is not set +# CONFIG_TI_DAC082S085 is not set +# CONFIG_TI_DAC5571 is not set +# CONFIG_TI_DAC7311 is not set +# CONFIG_TI_DAC7612 is not set +# CONFIG_VF610_DAC is not set + +# +# IIO dummy driver +# + +# +# Frequency Synthesizers DDS/PLL +# + +# +# Clock Generator/Distribution +# +# CONFIG_AD9523 is not set + +# +# Phase-Locked Loop (PLL) frequency synthesizers +# +# CONFIG_ADF4350 is not set + +# +# Digital gyroscope sensors +# +# CONFIG_ADIS16080 is not set +# CONFIG_ADIS16130 is not set +# CONFIG_ADIS16136 is not set +# CONFIG_ADIS16260 is not set +# CONFIG_ADXRS450 is not set +# CONFIG_BMG160 is not set +# CONFIG_MPU3050_I2C is not set +# CONFIG_IIO_ST_GYRO_3AXIS is not set +# CONFIG_ITG3200 is not set + +# +# Health Sensors +# + +# +# Heart Rate Monitors +# +# CONFIG_AFE4403 is not set +# CONFIG_AFE4404 is not set +# CONFIG_MAX30100 is not set +# CONFIG_MAX30102 is not set + +# +# Humidity sensors +# +# CONFIG_AM2315 is not set +# CONFIG_DHT11 is not set +# CONFIG_HDC100X is not set +# CONFIG_HTS221 is not set +# CONFIG_HTU21 is not set +# CONFIG_SI7005 is not set +# CONFIG_SI7020 is not set + +# +# Inertial measurement units +# +# CONFIG_ADIS16400 is not set +# CONFIG_ADIS16480 is not set +# CONFIG_BMI160_I2C is not set +# CONFIG_BMI160_SPI is not set +# CONFIG_KMX61 is not set +# CONFIG_INV_MPU6050_I2C is not set +# CONFIG_INV_MPU6050_SPI is not set +# CONFIG_IIO_ST_LSM6DSX is not set + +# +# Light sensors +# +# CONFIG_ADJD_S311 is not set +# CONFIG_AL3320A is not set +# CONFIG_APDS9300 is not set +# CONFIG_APDS9960 is not set +# CONFIG_BH1750 is not set +# CONFIG_BH1780 is not set +# CONFIG_CM32181 is not set +# CONFIG_CM3232 is not set +# CONFIG_CM3323 is not set +# CONFIG_CM3605 is not set +# CONFIG_CM36651 is not set +# CONFIG_GP2AP020A00F is not set +# CONFIG_SENSORS_ISL29018 is not set +# CONFIG_SENSORS_ISL29028 is not set +# CONFIG_ISL29125 is not set +# CONFIG_JSA1212 is not set +# CONFIG_RPR0521 is not set +# CONFIG_LTR501 is not set +# CONFIG_LV0104CS is not set +# CONFIG_MAX44000 is not set +# CONFIG_MAX44009 is not set +# CONFIG_OPT3001 is not set +# CONFIG_PA12203001 is not set +# CONFIG_SI1133 is not set +# CONFIG_SI1145 is not set +# CONFIG_STK3310 is not set +# CONFIG_ST_UVIS25 is not set +# CONFIG_TCS3414 is not set +# CONFIG_TCS3472 is not set +# CONFIG_SENSORS_TSL2563 is not set +# CONFIG_TSL2583 is not set +# CONFIG_TSL2772 is not set +# CONFIG_TSL4531 is not set +# CONFIG_US5182D is not set +# CONFIG_VCNL4000 is not set +# CONFIG_VCNL4035 is not set +# CONFIG_VEML6070 is not set +# CONFIG_VL6180 is not set +# CONFIG_ZOPT2201 is not set + +# +# Magnetometer sensors +# +# CONFIG_AK8974 is not set +# CONFIG_AK8975 is not set +# CONFIG_AK09911 is not set +# CONFIG_BMC150_MAGN_I2C is not set +# CONFIG_BMC150_MAGN_SPI is not set +# CONFIG_MAG3110 is not set +# CONFIG_MMC35240 is not set +# CONFIG_IIO_ST_MAGN_3AXIS is not set +# CONFIG_SENSORS_HMC5843_I2C is not set +# CONFIG_SENSORS_HMC5843_SPI is not set +# CONFIG_SENSORS_RM3100_I2C is not set +# CONFIG_SENSORS_RM3100_SPI is not set + +# +# Multiplexers +# +# CONFIG_IIO_MUX is not set + +# +# Inclinometer sensors +# + +# +# Digital potentiometers +# +# CONFIG_AD5272 is not set +# CONFIG_DS1803 is not set +# CONFIG_MAX5481 is not set +# CONFIG_MAX5487 is not set +# CONFIG_MCP4018 is not set +# CONFIG_MCP4131 is not set +# CONFIG_MCP4531 is not set +# CONFIG_MCP41010 is not set +# CONFIG_TPL0102 is not set + +# +# Digital potentiostats +# +# CONFIG_LMP91000 is not set + +# +# Pressure sensors +# +# CONFIG_ABP060MG is not set +# CONFIG_BMP280 is not set +# CONFIG_HP03 is not set +# CONFIG_MPL115_I2C is not set +# CONFIG_MPL115_SPI is not set +# CONFIG_MPL3115 is not set +# CONFIG_MS5611 is not set +# CONFIG_MS5637 is not set +# CONFIG_IIO_ST_PRESS is not set +# CONFIG_T5403 is not set +# CONFIG_HP206C is not set +# CONFIG_ZPA2326 is not set + +# +# Lightning sensors +# +# CONFIG_AS3935 is not set + +# +# Proximity and distance sensors +# +# CONFIG_ISL29501 is not set +# CONFIG_LIDAR_LITE_V2 is not set +# CONFIG_RFD77402 is not set +# CONFIG_SRF04 is not set +# CONFIG_SX9500 is not set +# CONFIG_SRF08 is not set +# CONFIG_VL53L0X_I2C is not set + +# +# Resolver to digital converters +# +# CONFIG_AD2S90 is not set +# CONFIG_AD2S1200 is not set + +# +# Temperature sensors +# +# CONFIG_MAXIM_THERMOCOUPLE is not set +# CONFIG_MLX90614 is not set +# CONFIG_MLX90632 is not set +# CONFIG_TMP006 is not set +# CONFIG_TMP007 is not set +# CONFIG_TSYS01 is not set +# CONFIG_TSYS02D is not set +CONFIG_PWM=y +CONFIG_PWM_SYSFS=y +# CONFIG_PWM_CROS_EC is not set +# CONFIG_PWM_FSL_FTM is not set +CONFIG_PWM_MESON=m +# CONFIG_PWM_PCA9685 is not set + +# +# IRQ chip support +# +CONFIG_IRQCHIP=y +CONFIG_ARM_GIC=y +CONFIG_ARM_GIC_MAX_NR=1 +CONFIG_ARM_GIC_V3=y +CONFIG_ARM_GIC_V3_ITS=y +CONFIG_PARTITION_PERCPU=y +CONFIG_MESON_IRQ_GPIO=y +# CONFIG_IPACK_BUS is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_MESON=y +CONFIG_RESET_MESON_AUDIO_ARB=y +# CONFIG_RESET_TI_SYSCON is not set +# CONFIG_FMC is not set + +# +# PHY Subsystem +# +CONFIG_GENERIC_PHY=y +# CONFIG_PHY_XGENE is not set +CONFIG_PHY_MESON8B_USB2=y +CONFIG_PHY_MESON_GXL_USB2=y +CONFIG_PHY_MESON_GXL_USB3=y +CONFIG_PHY_MESON_G12A_USB2=y +CONFIG_PHY_MESON_G12A_USB3_PCIE=y +# CONFIG_BCM_KONA_USB2_PHY is not set +# CONFIG_PHY_CADENCE_DP is not set +# CONFIG_PHY_CADENCE_DPHY is not set +# CONFIG_PHY_CADENCE_SIERRA is not set +# CONFIG_PHY_FSL_IMX8MQ_USB is not set +# CONFIG_PHY_PXA_28NM_HSIC is not set +# CONFIG_PHY_PXA_28NM_USB2 is not set +# CONFIG_PHY_CPCAP_USB is not set +# CONFIG_PHY_MAPPHONE_MDM6600 is not set +# CONFIG_PHY_OCELOT_SERDES is not set +# CONFIG_PHY_SAMSUNG_USB2 is not set +# CONFIG_POWERCAP is not set +# CONFIG_MCB is not set + +# +# Performance monitor support +# +# CONFIG_ARM_CCI_PMU is not set +# CONFIG_ARM_CCN is not set +CONFIG_ARM_PMU=y +# CONFIG_ARM_DSU_PMU is not set +# CONFIG_ARM_SPE_PMU is not set +# CONFIG_RAS is not set + +# +# Android +# +# CONFIG_ANDROID is not set +# CONFIG_LIBNVDIMM is not set +# CONFIG_DAX is not set +CONFIG_NVMEM=y +CONFIG_MESON_EFUSE=y +# CONFIG_MESON_MX_EFUSE is not set + +# +# HW tracing support +# +# CONFIG_STM is not set +# CONFIG_INTEL_TH is not set +# CONFIG_FPGA is not set +# CONFIG_FSI is not set +CONFIG_TEE=y + +# +# TEE drivers +# +CONFIG_OPTEE=y +CONFIG_OPTEE_SHM_NUM_PRIV_PAGES=1 +CONFIG_PM_OPP=y +# CONFIG_SIOX is not set +# CONFIG_SLIMBUS is not set +# CONFIG_INTERCONNECT is not set + +# +# File systems +# +CONFIG_DCACHE_WORD_ACCESS=y +CONFIG_VALIDATE_FS_PARSER=y +CONFIG_FS_IOMAP=y +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT2=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_JBD2_DEBUG is not set +CONFIG_FS_MBCACHE=y +CONFIG_REISERFS_FS=m +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR is not set +CONFIG_JFS_FS=m +# CONFIG_JFS_POSIX_ACL is not set +# CONFIG_JFS_SECURITY is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +CONFIG_XFS_FS=m +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_POSIX_ACL is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_ONLINE_SCRUB is not set +# CONFIG_XFS_WARN is not set +# CONFIG_XFS_DEBUG is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +CONFIG_BTRFS_FS=m +# CONFIG_BTRFS_FS_POSIX_ACL is not set +# CONFIG_BTRFS_FS_CHECK_INTEGRITY is not set +# CONFIG_BTRFS_FS_RUN_SANITY_TESTS is not set +# CONFIG_BTRFS_DEBUG is not set +# CONFIG_BTRFS_ASSERT is not set +# CONFIG_BTRFS_FS_REF_VERIFY is not set +# CONFIG_NILFS2_FS is not set +CONFIG_F2FS_FS=m +CONFIG_F2FS_STAT_FS=y +# CONFIG_F2FS_FS_XATTR is not set +CONFIG_F2FS_CHECK_FS=y +# CONFIG_F2FS_FAULT_INJECTION is not set +# CONFIG_FS_DAX is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +# CONFIG_EXPORTFS_BLOCK_OPS is not set +CONFIG_FILE_LOCKING=y +CONFIG_MANDATORY_FILE_LOCKING=y +# CONFIG_FS_ENCRYPTION is not set +CONFIG_FSNOTIFY=y +CONFIG_DNOTIFY=y +CONFIG_INOTIFY_USER=y +CONFIG_FANOTIFY=y +# CONFIG_QUOTA is not set +CONFIG_AUTOFS4_FS=y +CONFIG_AUTOFS_FS=y +CONFIG_FUSE_FS=m +# CONFIG_CUSE is not set +CONFIG_OVERLAY_FS=m +# CONFIG_OVERLAY_FS_REDIRECT_DIR is not set +CONFIG_OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW=y +# CONFIG_OVERLAY_FS_INDEX is not set +# CONFIG_OVERLAY_FS_XINO_AUTO is not set +# CONFIG_OVERLAY_FS_METACOPY is not set + +# +# Caches +# +CONFIG_FSCACHE=y +# CONFIG_FSCACHE_STATS is not set +# CONFIG_FSCACHE_HISTOGRAM is not set +# CONFIG_FSCACHE_DEBUG is not set +# CONFIG_FSCACHE_OBJECT_LIST is not set +# CONFIG_CACHEFILES is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=m +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +# CONFIG_MSDOS_FS is not set +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="ascii" +# CONFIG_FAT_DEFAULT_UTF8 is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +# CONFIG_PROC_KCORE is not set +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +# CONFIG_PROC_CHILDREN is not set +CONFIG_KERNFS=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLBFS is not set +CONFIG_MEMFD_CREATE=y +CONFIG_ARCH_HAS_GIGANTIC_PAGE=y +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ORANGEFS_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_ECRYPT_FS is not set +CONFIG_HFS_FS=m +CONFIG_HFSPLUS_FS=m +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +CONFIG_SQUASHFS=y +# CONFIG_SQUASHFS_FILE_CACHE is not set +CONFIG_SQUASHFS_FILE_DIRECT=y +# CONFIG_SQUASHFS_DECOMP_SINGLE is not set +# CONFIG_SQUASHFS_DECOMP_MULTI is not set +CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU=y +# CONFIG_SQUASHFS_XATTR is not set +CONFIG_SQUASHFS_ZLIB=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_SQUASHFS_ZSTD=y +# CONFIG_SQUASHFS_4K_DEVBLK_SIZE is not set +# CONFIG_SQUASHFS_EMBEDDED is not set +CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3 +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX6FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V2=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +CONFIG_NFS_V4=y +# CONFIG_NFS_SWAP is not set +CONFIG_NFS_V4_1=y +CONFIG_NFS_V4_2=y +CONFIG_PNFS_FILE_LAYOUT=y +CONFIG_PNFS_FLEXFILE_LAYOUT=m +CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN="kernel.org" +CONFIG_NFS_V4_1_MIGRATION=y +CONFIG_ROOT_NFS=y +CONFIG_NFS_FSCACHE=y +# CONFIG_NFS_USE_LEGACY_DNS is not set +CONFIG_NFS_USE_KERNEL_DNS=y +# CONFIG_NFSD is not set +CONFIG_GRACE_PERIOD=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +CONFIG_SUNRPC_BACKCHANNEL=y +CONFIG_RPCSEC_GSS_KRB5=m +# CONFIG_CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES is not set +# CONFIG_SUNRPC_DEBUG is not set +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +CONFIG_CIFS_STATS2=y +CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_UPCALL is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG is not set +# CONFIG_CIFS_DFS_UPCALL is not set +CONFIG_CIFS_FSCACHE=y +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="utf-8" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_MAC_ROMAN is not set +# CONFIG_NLS_MAC_CELTIC is not set +# CONFIG_NLS_MAC_CENTEURO is not set +# CONFIG_NLS_MAC_CROATIAN is not set +# CONFIG_NLS_MAC_CYRILLIC is not set +# CONFIG_NLS_MAC_GAELIC is not set +# CONFIG_NLS_MAC_GREEK is not set +# CONFIG_NLS_MAC_ICELAND is not set +# CONFIG_NLS_MAC_INUIT is not set +# CONFIG_NLS_MAC_ROMANIAN is not set +# CONFIG_NLS_MAC_TURKISH is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Security options +# +CONFIG_KEYS=y +CONFIG_KEYS_COMPAT=y +# CONFIG_PERSISTENT_KEYRINGS is not set +# CONFIG_BIG_KEYS is not set +# CONFIG_ENCRYPTED_KEYS is not set +# CONFIG_KEY_DH_OPERATIONS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y +# CONFIG_HARDENED_USERCOPY is not set +# CONFIG_FORTIFY_SOURCE is not set +# CONFIG_STATIC_USERMODEHELPER is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_LSM="yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" +CONFIG_XOR_BLOCKS=m +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_AKCIPHER2=y +CONFIG_CRYPTO_AKCIPHER=y +CONFIG_CRYPTO_KPP2=y +CONFIG_CRYPTO_KPP=m +CONFIG_CRYPTO_ACOMP2=y +CONFIG_CRYPTO_RSA=y +# CONFIG_CRYPTO_DH is not set +CONFIG_CRYPTO_ECDH=m +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +# CONFIG_CRYPTO_USER is not set +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +CONFIG_CRYPTO_GF128MUL=y +CONFIG_CRYPTO_NULL=y +CONFIG_CRYPTO_NULL2=y +CONFIG_CRYPTO_PCRYPT=y +CONFIG_CRYPTO_WORKQUEUE=y +CONFIG_CRYPTO_CRYPTD=y +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_TEST is not set +CONFIG_CRYPTO_SIMD=y + +# +# Authenticated Encryption with Associated Data +# +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_GCM=m +# CONFIG_CRYPTO_CHACHA20POLY1305 is not set +# CONFIG_CRYPTO_AEGIS128 is not set +# CONFIG_CRYPTO_AEGIS128L is not set +# CONFIG_CRYPTO_AEGIS256 is not set +# CONFIG_CRYPTO_MORUS640 is not set +# CONFIG_CRYPTO_MORUS1280 is not set +CONFIG_CRYPTO_SEQIV=y +CONFIG_CRYPTO_ECHAINIV=m + +# +# Block modes +# +CONFIG_CRYPTO_CBC=m +CONFIG_CRYPTO_CFB=m +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_CTS=m +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_OFB is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_KEYWRAP is not set +# CONFIG_CRYPTO_ADIANTUM is not set + +# +# Hash modes +# +CONFIG_CRYPTO_CMAC=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_CRC32=y +CONFIG_CRYPTO_CRCT10DIF=y +CONFIG_CRYPTO_GHASH=m +# CONFIG_CRYPTO_POLY1305 is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +# CONFIG_CRYPTO_SHA3 is not set +# CONFIG_CRYPTO_SM3 is not set +# CONFIG_CRYPTO_STREEBOG is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_AES_TI is not set +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +CONFIG_CRYPTO_CHACHA20=y +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_SM4 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_LZO is not set +# CONFIG_CRYPTO_842 is not set +# CONFIG_CRYPTO_LZ4 is not set +# CONFIG_CRYPTO_LZ4HC is not set +# CONFIG_CRYPTO_ZSTD is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_DRBG_HMAC=y +# CONFIG_CRYPTO_DRBG_HASH is not set +# CONFIG_CRYPTO_DRBG_CTR is not set +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_JITTERENTROPY=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +# CONFIG_CRYPTO_USER_API_RNG is not set +# CONFIG_CRYPTO_USER_API_AEAD is not set +CONFIG_CRYPTO_HASH_INFO=y +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_CCP is not set +# CONFIG_CRYPTO_DEV_CCREE is not set +# CONFIG_CRYPTO_DEV_HISI_SEC is not set +CONFIG_ASYMMETRIC_KEY_TYPE=y +CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=y +CONFIG_X509_CERTIFICATE_PARSER=y +# CONFIG_PKCS8_PRIVATE_KEY_PARSER is not set +CONFIG_PKCS7_MESSAGE_PARSER=y +# CONFIG_PKCS7_TEST_KEY is not set +# CONFIG_SIGNED_PE_FILE_VERIFICATION is not set + +# +# Certificates for signature checking +# +CONFIG_SYSTEM_TRUSTED_KEYRING=y +CONFIG_SYSTEM_TRUSTED_KEYS="" +# CONFIG_SYSTEM_EXTRA_CERTIFICATE is not set +# CONFIG_SECONDARY_TRUSTED_KEYRING is not set +# CONFIG_SYSTEM_BLACKLIST_KEYRING is not set + +# +# Library routines +# +CONFIG_RAID6_PQ=m +# CONFIG_RAID6_PQ_BENCHMARK is not set +CONFIG_BITREVERSE=y +CONFIG_HAVE_ARCH_BITREVERSE=y +CONFIG_RATIONAL=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_NET_UTILS=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y +CONFIG_ARCH_HAS_FAST_MULTIPLIER=y +# CONFIG_INDIRECT_PIO is not set +CONFIG_CRC_CCITT=m +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +CONFIG_CRC_ITU_T=y +CONFIG_CRC32=y +# CONFIG_CRC32_SELFTEST is not set +CONFIG_CRC32_SLICEBY8=y +# CONFIG_CRC32_SLICEBY4 is not set +# CONFIG_CRC32_SARWATE is not set +# CONFIG_CRC32_BIT is not set +# CONFIG_CRC64 is not set +# CONFIG_CRC4 is not set +CONFIG_CRC7=y +CONFIG_LIBCRC32C=m +# CONFIG_CRC8 is not set +CONFIG_XXHASH=y +CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y +# CONFIG_RANDOM32_SELFTEST is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=m +CONFIG_LZO_COMPRESS=m +CONFIG_LZO_DECOMPRESS=y +CONFIG_LZ4_DECOMPRESS=y +CONFIG_ZSTD_COMPRESS=m +CONFIG_ZSTD_DECOMPRESS=y +CONFIG_XZ_DEC=y +# CONFIG_XZ_DEC_X86 is not set +# CONFIG_XZ_DEC_POWERPC is not set +# CONFIG_XZ_DEC_IA64 is not set +# CONFIG_XZ_DEC_ARM is not set +# CONFIG_XZ_DEC_ARMTHUMB is not set +# CONFIG_XZ_DEC_SPARC is not set +# CONFIG_XZ_DEC_TEST is not set +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_XARRAY_MULTI=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_NEED_SG_DMA_LENGTH=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_DMA_DECLARE_COHERENT=y +CONFIG_ARCH_HAS_SETUP_DMA_OPS=y +CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y +CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y +CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y +CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN=y +CONFIG_ARCH_HAS_DMA_MMAP_PGPROT=y +CONFIG_SWIOTLB=y +CONFIG_DMA_REMAP=y +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DMA_CMA=y + +# +# Default contiguous memory area size: +# +CONFIG_CMA_SIZE_MBYTES=256 +CONFIG_CMA_SIZE_SEL_MBYTES=y +# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set +# CONFIG_CMA_SIZE_SEL_MIN is not set +# CONFIG_CMA_SIZE_SEL_MAX is not set +CONFIG_CMA_ALIGNMENT=8 +# CONFIG_DMA_API_DEBUG is not set +CONFIG_SGL_ALLOC=y +CONFIG_CPU_RMAP=y +CONFIG_DQL=y +CONFIG_GLOB=y +# CONFIG_GLOB_SELFTEST is not set +CONFIG_NLATTR=y +CONFIG_CLZ_TAB=y +CONFIG_CORDIC=m +# CONFIG_DDR is not set +# CONFIG_IRQ_POLL is not set +CONFIG_MPILIB=y +CONFIG_LIBFDT=y +CONFIG_OID_REGISTRY=y +CONFIG_FONT_SUPPORT=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_SG_POOL=y +CONFIG_SBITMAP=y +# CONFIG_STRING_SELFTEST is not set + +# +# Kernel hacking +# + +# +# printk and dmesg options +# +CONFIG_PRINTK_TIME=y +# CONFIG_PRINTK_CALLER is not set +CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7 +CONFIG_CONSOLE_LOGLEVEL_QUIET=4 +CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4 +# CONFIG_BOOT_PRINTK_DELAY is not set +CONFIG_DYNAMIC_DEBUG=y + +# +# Compile-time checks and compiler options +# +# CONFIG_DEBUG_INFO is not set +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=2048 +CONFIG_STRIP_ASM_SYMS=y +# CONFIG_READABLE_ASM is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +CONFIG_SECTION_MISMATCH_WARN_ONLY=y +CONFIG_ARCH_WANT_FRAME_POINTERS=y +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1 +CONFIG_MAGIC_SYSRQ_SERIAL=y +CONFIG_DEBUG_KERNEL=y + +# +# Memory Debugging +# +# CONFIG_PAGE_EXTENSION is not set +# CONFIG_DEBUG_PAGEALLOC is not set +# CONFIG_PAGE_OWNER is not set +# CONFIG_PAGE_POISONING is not set +# CONFIG_DEBUG_RODATA_TEST is not set +# CONFIG_DEBUG_OBJECTS is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +CONFIG_HAVE_DEBUG_KMEMLEAK=y +# CONFIG_DEBUG_KMEMLEAK is not set +# CONFIG_DEBUG_STACK_USAGE is not set +# CONFIG_DEBUG_VM is not set +CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y +# CONFIG_DEBUG_VIRTUAL is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +# CONFIG_DEBUG_PER_CPU_MAPS is not set +CONFIG_HAVE_ARCH_KASAN=y +CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y +CONFIG_CC_HAS_KASAN_GENERIC=y +# CONFIG_KASAN is not set +CONFIG_KASAN_STACK=1 +CONFIG_ARCH_HAS_KCOV=y +CONFIG_CC_HAS_SANCOV_TRACE_PC=y +# CONFIG_KCOV is not set +# CONFIG_DEBUG_SHIRQ is not set + +# +# Debug Lockups and Hangs +# +# CONFIG_SOFTLOCKUP_DETECTOR is not set +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120 +# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set +CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0 +# CONFIG_WQ_WATCHDOG is not set +# CONFIG_PANIC_ON_OOPS is not set +CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_SCHEDSTATS is not set +# CONFIG_SCHED_STACK_END_CHECK is not set +# CONFIG_DEBUG_TIMEKEEPING is not set + +# +# Lock Debugging (spinlocks, mutexes, etc...) +# +CONFIG_LOCK_DEBUGGING_SUPPORT=y +# CONFIG_PROVE_LOCKING is not set +# CONFIG_LOCK_STAT is not set +# CONFIG_DEBUG_RT_MUTEXES is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_MUTEXES is not set +# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set +# CONFIG_DEBUG_RWSEMS is not set +# CONFIG_DEBUG_LOCK_ALLOC is not set +# CONFIG_DEBUG_ATOMIC_SLEEP is not set +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set +# CONFIG_LOCK_TORTURE_TEST is not set +# CONFIG_WW_MUTEX_SELFTEST is not set +# CONFIG_STACKTRACE is not set +# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set +# CONFIG_DEBUG_KOBJECT is not set +CONFIG_HAVE_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_DEBUG_LIST is not set +# CONFIG_DEBUG_PI_LIST is not set +# CONFIG_DEBUG_SG is not set +# CONFIG_DEBUG_NOTIFIERS is not set +# CONFIG_DEBUG_CREDENTIALS is not set + +# +# RCU Debugging +# +# CONFIG_RCU_PERF_TEST is not set +# CONFIG_RCU_TORTURE_TEST is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=21 +# CONFIG_RCU_TRACE is not set +# CONFIG_RCU_EQS_DEBUG is not set +# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set +# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set +# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set +# CONFIG_NOTIFIER_ERROR_INJECTION is not set +# CONFIG_FAULT_INJECTION is not set +# CONFIG_LATENCYTOP is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_SYSCALL_TRACEPOINTS=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_RUNTIME_TESTING_MENU is not set +# CONFIG_MEMTEST is not set +# CONFIG_BUG_ON_DATA_CORRUPTION is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_KGDB is not set +CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y +# CONFIG_UBSAN is not set +CONFIG_UBSAN_ALIGNMENT=y +CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_ARM64_PTDUMP_DEBUGFS is not set +# CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET is not set +# CONFIG_DEBUG_WX is not set +# CONFIG_DEBUG_ALIGN_RODATA is not set +# CONFIG_ARM64_RELOC_TEST is not set +# CONFIG_CORESIGHT is not set From 6a80fdd4db06e91d0facc91e3cdc2b589c137a72 Mon Sep 17 00:00:00 2001 From: chewitt Date: Tue, 20 Nov 2018 14:07:05 +0000 Subject: [PATCH 11/21] project: add kernel-firmware.dat file --- projects/Amlogic/firmwares/kernel-firmware.dat | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 projects/Amlogic/firmwares/kernel-firmware.dat diff --git a/projects/Amlogic/firmwares/kernel-firmware.dat b/projects/Amlogic/firmwares/kernel-firmware.dat new file mode 100644 index 0000000000..e69de29bb2 From 0be7dce87d425d7179a5856b3b743ca6981be252 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 26 Sep 2018 09:52:36 +0400 Subject: [PATCH 12/21] firmware: add meson-firmware package --- .../meson-firmware/firmwares/any.dat | 1 + .../linux-firmware/meson-firmware/package.mk | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 packages/linux-firmware/meson-firmware/firmwares/any.dat create mode 100644 packages/linux-firmware/meson-firmware/package.mk diff --git a/packages/linux-firmware/meson-firmware/firmwares/any.dat b/packages/linux-firmware/meson-firmware/firmwares/any.dat new file mode 100644 index 0000000000..1eacf246f2 --- /dev/null +++ b/packages/linux-firmware/meson-firmware/firmwares/any.dat @@ -0,0 +1 @@ +meson/* diff --git a/packages/linux-firmware/meson-firmware/package.mk b/packages/linux-firmware/meson-firmware/package.mk new file mode 100644 index 0000000000..3df2c4acb1 --- /dev/null +++ b/packages/linux-firmware/meson-firmware/package.mk @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) + +PKG_NAME="meson-firmware" +PKG_VERSION="edd24b481293b93814494508cd4952b67f15acb3" +PKG_SHA256="2092c71a5eb106725784dadcc2cfea7be60254539a41fafebf311235283259e4" +PKG_LICENSE="GPLv2" +PKG_SITE="https://github.com/LibreELEC/meson-firmware" +PKG_URL="https://github.com/LibreELEC/meson-firmware/archive/$PKG_VERSION.tar.gz" +PKG_DEPENDS_TARGET="toolchain" +PKG_LONGDESC="meson-firmware: Amlogic microcode firmware for the V4L2 mem2mem vdec driver" +PKG_TOOLCHAIN="manual" + +makeinstall_target() { + FW_TARGET_DIR=$INSTALL/$(get_full_firmware_dir) + + if find_file_path config/$PKG_NAME.dat; then + FW_LISTS="${FOUND_PATH}" + else + FW_LISTS="${PKG_DIR}/firmwares/any.dat ${PKG_DIR}/firmwares/${TARGET_ARCH}.dat" + fi + + for fwlist in ${FW_LISTS}; do + [ -f ${fwlist} ] || continue + while read -r fwline; do + [ -z "${fwline}" ] && continue + [[ ${fwline} =~ ^#.* ]] && continue + [[ ${fwline} =~ ^[[:space:]] ]] && continue + + for fwfile in $(cd ${PKG_BUILD} && eval "find ${fwline}"); do + [ -d ${PKG_BUILD}/${fwfile} ] && continue + + if [ -f ${PKG_BUILD}/${fwfile} ]; then + mkdir -p $(dirname ${FW_TARGET_DIR}/${fwfile}) + cp -Lv ${PKG_BUILD}/${fwfile} ${FW_TARGET_DIR}/${fwfile} + else + echo "ERROR: Firmware file ${fwfile} does not exist - aborting" + exit 1 + fi + done + done < ${fwlist} + done +} From 04c8342dbdc0602606a154b3b2a2a8f7e239a073 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 26 Sep 2018 10:00:51 +0400 Subject: [PATCH 13/21] u-boot: add Amlogic board devices to uboot_helper --- scripts/uboot_helper | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/uboot_helper b/scripts/uboot_helper index 8d993311c9..904f4a2302 100755 --- a/scripts/uboot_helper +++ b/scripts/uboot_helper @@ -30,6 +30,17 @@ devices = { 'pine_h64' : { 'dtb' : 'sun50i-h6-pine-h64.dtb', 'config' : 'pine_h64_defconfig' }, }, }, + 'Amlogic' : { + 'AMLGX' : { + 'box' : { 'dtb' : 'meson-gxl-s905x-p212.dtb', 'config' : 'p212_defconfig' }, + 'lepotato' : { 'dtb' : 'meson-gxl-s905x-libretech-cc.dtb', 'config' : 'libretech-cc_defconfig' }, + 'nanopi-k2' : { 'dtb' : 'meson-gxbb-nanopi-k2.dtb', 'config' : 'nanopi-k2_defconfig' }, + 'odroid-c2' : { 'dtb' : 'meson-gxbb-odroidc2.dtb', 'config' : 'odroid-c2_defconfig' }, + }, + 'AMLG12' : { + 'box' : { 'dtb' : 'meson-gxl-s905x-p212.dtb', 'config' : 'p212_defconfig' }, + }, + }, 'Rockchip' : { 'MiQi' : { 'rk3288' : { 'dtb' : 'rk3288-miqi.dtb', 'config' : 'miqi-rk3288_config' }, }, 'RK3328' : { From f80dc6402d6592fe84b0674c09c1bfc93430f482 Mon Sep 17 00:00:00 2001 From: kszaq Date: Tue, 28 May 2019 02:33:23 +0200 Subject: [PATCH 14/21] u-boot: add Amlogic dependency --- packages/tools/u-boot/package.mk | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/tools/u-boot/package.mk b/packages/tools/u-boot/package.mk index 295fd80936..18ce684aba 100644 --- a/packages/tools/u-boot/package.mk +++ b/packages/tools/u-boot/package.mk @@ -17,6 +17,12 @@ PKG_STAMP="$UBOOT_SYSTEM" PKG_NEED_UNPACK="$PROJECT_DIR/$PROJECT/bootloader" [ -n "$DEVICE" ] && PKG_NEED_UNPACK+=" $PROJECT_DIR/$PROJECT/devices/$DEVICE/bootloader" +case "$PROJECT" in + Amlogic) + PKG_DEPENDS_TARGET+=" amlogic-boot-fip" + ;; +esac + case "$PROJECT" in Rockchip) PKG_VERSION="8659d08d2b589693d121c1298484e861b7dafc4f" From 78f5c1d6b850544d3b9e940798951ac7aba1f69e Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 26 Sep 2018 08:14:25 +0400 Subject: [PATCH 15/21] ffmpeg: add WIP/PoC stateful v4l2 patch --- .../ffmpeg/ffmpeg-999-aspect-ratio.patch | 62 ++ .../ffmpeg/ffmpeg-999-lrusak-v4l2.patch | 768 ++++++++++++++++++ .../ffmpeg/ffmpeg-999-min-buffers.patch | 11 + .../patches/ffmpeg/ffmpeg-999-z-fixes.patch | 51 ++ 4 files changed, 892 insertions(+) create mode 100644 projects/Amlogic/patches/ffmpeg/ffmpeg-999-aspect-ratio.patch create mode 100644 projects/Amlogic/patches/ffmpeg/ffmpeg-999-lrusak-v4l2.patch create mode 100644 projects/Amlogic/patches/ffmpeg/ffmpeg-999-min-buffers.patch create mode 100644 projects/Amlogic/patches/ffmpeg/ffmpeg-999-z-fixes.patch diff --git a/projects/Amlogic/patches/ffmpeg/ffmpeg-999-aspect-ratio.patch b/projects/Amlogic/patches/ffmpeg/ffmpeg-999-aspect-ratio.patch new file mode 100644 index 0000000000..c7c2fbbb66 --- /dev/null +++ b/projects/Amlogic/patches/ffmpeg/ffmpeg-999-aspect-ratio.patch @@ -0,0 +1,62 @@ +From e5d21ff782977b0fe79a60796dc9d973d98e692c Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Sun, 9 Sep 2018 17:22:35 +0200 +Subject: [PATCH] avcodec: v4l2_context: set frame SAR using VIDIOC_CROPCAP + +--- + libavcodec/v4l2_context.c | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c +index efcb0426e4..8bff58ca5d 100644 +--- a/libavcodec/v4l2_context.c ++++ b/libavcodec/v4l2_context.c +@@ -501,6 +501,24 @@ static int v4l2_get_coded_format(V4L2Context* ctx, uint32_t *p) + return 0; + } + ++static AVRational v4l2_get_sar(V4L2Context* ctx) ++{ ++ struct AVRational sar = { 1, 1 }; ++ struct v4l2_cropcap cropcap; ++ int ret; ++ ++ memset(&cropcap, 0, sizeof(cropcap)); ++ cropcap.type = ctx->type; ++ ++ ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_CROPCAP, &cropcap); ++ if (ret) ++ return sar; ++ ++ sar.num = cropcap.pixelaspect.numerator; ++ sar.den = cropcap.pixelaspect.denominator; ++ return sar; ++} ++ + /***************************************************************************** + * + * V4L2 Context Interface +@@ -574,6 +592,7 @@ int ff_v4l2_context_enqueue_packet(V4L2Context* ctx, const AVPacket* pkt) + int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame) + { + V4L2Buffer* avbuf = NULL; ++ int ret; + + /* + * blocks until: +@@ -588,7 +607,12 @@ int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame) + return AVERROR(EAGAIN); + } + +- return ff_v4l2_buffer_buf_to_avframe(frame, avbuf); ++ ret = ff_v4l2_buffer_buf_to_avframe(frame, avbuf); ++ if (ret) ++ return ret; ++ ++ frame->sample_aspect_ratio = v4l2_get_sar(ctx); ++ return 0; + } + + int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt) +-- +2.18.0 diff --git a/projects/Amlogic/patches/ffmpeg/ffmpeg-999-lrusak-v4l2.patch b/projects/Amlogic/patches/ffmpeg/ffmpeg-999-lrusak-v4l2.patch new file mode 100644 index 0000000000..d95eebfc12 --- /dev/null +++ b/projects/Amlogic/patches/ffmpeg/ffmpeg-999-lrusak-v4l2.patch @@ -0,0 +1,768 @@ +From 5c80d25f8f3821118fd4050321ac89e23bbedc8e Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Tue, 24 Apr 2018 22:48:23 -0700 +Subject: [PATCH 1/6] libavcodec: v4l2m2m: fix indentation and add M2MDEC_CLASS + +--- + libavcodec/v4l2_m2m_dec.c | 44 ++++++++++++++++++++------------------- + 1 file changed, 23 insertions(+), 21 deletions(-) + +diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c +index bca45be1484..ed5193ecc17 100644 +--- a/libavcodec/v4l2_m2m_dec.c ++++ b/libavcodec/v4l2_m2m_dec.c +@@ -202,28 +202,30 @@ static const AVOption options[] = { + { NULL}, + }; + ++#define M2MDEC_CLASS(NAME) \ ++ static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \ ++ .class_name = #NAME "_v4l2_m2m_decoder", \ ++ .item_name = av_default_item_name, \ ++ .option = options, \ ++ .version = LIBAVUTIL_VERSION_INT, \ ++ }; ++ + #define M2MDEC(NAME, LONGNAME, CODEC, bsf_name) \ +-static const AVClass v4l2_m2m_ ## NAME ## _dec_class = {\ +- .class_name = #NAME "_v4l2_m2m_decoder",\ +- .item_name = av_default_item_name,\ +- .option = options,\ +- .version = LIBAVUTIL_VERSION_INT,\ +-};\ +-\ +-AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \ +- .name = #NAME "_v4l2m2m" ,\ +- .long_name = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " decoder wrapper"),\ +- .type = AVMEDIA_TYPE_VIDEO,\ +- .id = CODEC ,\ +- .priv_data_size = sizeof(V4L2m2mPriv),\ +- .priv_class = &v4l2_m2m_ ## NAME ## _dec_class,\ +- .init = v4l2_decode_init,\ +- .receive_frame = v4l2_receive_frame,\ +- .close = ff_v4l2_m2m_codec_end,\ +- .bsfs = bsf_name, \ +- .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ +- .wrapper_name = "v4l2m2m", \ +-}; ++ M2MDEC_CLASS(NAME) \ ++ AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \ ++ .name = #NAME "_v4l2m2m" , \ ++ .long_name = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " decoder wrapper"), \ ++ .type = AVMEDIA_TYPE_VIDEO, \ ++ .id = CODEC , \ ++ .priv_data_size = sizeof(V4L2m2mPriv), \ ++ .priv_class = &v4l2_m2m_ ## NAME ## _dec_class, \ ++ .init = v4l2_decode_init, \ ++ .receive_frame = v4l2_receive_frame, \ ++ .close = ff_v4l2_m2m_codec_end, \ ++ .bsfs = bsf_name, \ ++ .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ ++ .wrapper_name = "v4l2m2m", \ ++ }; + + M2MDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb"); + M2MDEC(hevc, "HEVC", AV_CODEC_ID_HEVC, "hevc_mp4toannexb"); + +From ba04ebfb7ec5df1dff44b7cd6c0daac9146dcf3a Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Tue, 24 Apr 2018 23:00:23 -0700 +Subject: [PATCH 2/6] libavcodec: v4l2m2m: output AVDRMFrameDescriptor + +--- + libavcodec/v4l2_buffers.c | 216 ++++++++++++++++++++++++++++++++------ + libavcodec/v4l2_buffers.h | 4 + + libavcodec/v4l2_context.c | 40 ++++++- + libavcodec/v4l2_m2m.c | 4 +- + libavcodec/v4l2_m2m.h | 3 + + libavcodec/v4l2_m2m_dec.c | 23 ++++ + 6 files changed, 253 insertions(+), 37 deletions(-) + +diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c +index aef911f3bbc..e5c46ac81e6 100644 +--- a/libavcodec/v4l2_buffers.c ++++ b/libavcodec/v4l2_buffers.c +@@ -21,6 +21,7 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#include + #include + #include + #include +@@ -29,6 +30,7 @@ + #include + #include "libavcodec/avcodec.h" + #include "libavcodec/internal.h" ++#include "libavutil/hwcontext.h" + #include "v4l2_context.h" + #include "v4l2_buffers.h" + #include "v4l2_m2m.h" +@@ -203,7 +205,79 @@ static enum AVColorTransferCharacteristic v4l2_get_color_trc(V4L2Buffer *buf) + return AVCOL_TRC_UNSPECIFIED; + } + +-static void v4l2_free_buffer(void *opaque, uint8_t *unused) ++static uint8_t * v4l2_get_drm_frame(V4L2Buffer *avbuf) ++{ ++ AVDRMFrameDescriptor *drm_desc = &avbuf->drm_frame; ++ AVDRMLayerDescriptor *layer; ++ ++ /* fill the DRM frame descriptor */ ++ drm_desc->nb_objects = avbuf->num_planes; ++ drm_desc->nb_layers = 1; ++ ++ layer = &drm_desc->layers[0]; ++ layer->nb_planes = avbuf->num_planes; ++ ++ for (int i = 0; i < avbuf->num_planes; i++) { ++ layer->planes[i].object_index = i; ++ layer->planes[i].offset = 0; ++ layer->planes[i].pitch = avbuf->plane_info[i].bytesperline; ++ } ++ ++ switch (avbuf->context->av_pix_fmt) { ++ case AV_PIX_FMT_YUYV422: ++ ++ layer->format = DRM_FORMAT_YUYV; ++ layer->nb_planes = 1; ++ ++ break; ++ ++ case AV_PIX_FMT_NV12: ++ case AV_PIX_FMT_NV21: ++ ++ layer->format = avbuf->context->av_pix_fmt == AV_PIX_FMT_NV12 ? ++ DRM_FORMAT_NV12 : DRM_FORMAT_NV21; ++ ++ if (avbuf->num_planes > 1) ++ break; ++ ++ layer->nb_planes = 2; ++ ++ layer->planes[1].object_index = 0; ++ layer->planes[1].offset = avbuf->plane_info[0].bytesperline * ++ avbuf->context->format.fmt.pix.height; ++ layer->planes[1].pitch = avbuf->plane_info[0].bytesperline; ++ break; ++ ++ case AV_PIX_FMT_YUV420P: ++ ++ layer->format = DRM_FORMAT_YUV420; ++ ++ if (avbuf->num_planes > 1) ++ break; ++ ++ layer->nb_planes = 3; ++ ++ layer->planes[1].object_index = 0; ++ layer->planes[1].offset = avbuf->plane_info[0].bytesperline * ++ avbuf->context->format.fmt.pix.height; ++ layer->planes[1].pitch = avbuf->plane_info[0].bytesperline >> 1; ++ ++ layer->planes[2].object_index = 0; ++ layer->planes[2].offset = layer->planes[1].offset + ++ ((avbuf->plane_info[0].bytesperline * ++ avbuf->context->format.fmt.pix.height) >> 2); ++ layer->planes[2].pitch = avbuf->plane_info[0].bytesperline >> 1; ++ break; ++ ++ default: ++ drm_desc->nb_layers = 0; ++ break; ++ } ++ ++ return (uint8_t *) drm_desc; ++} ++ ++static void v4l2_free_buffer(void *opaque, uint8_t *data) + { + V4L2Buffer* avbuf = opaque; + V4L2m2mContext *s = buf_to_m2mctx(avbuf); +@@ -227,27 +301,47 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused) + } + } + +-static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) ++static int v4l2_buffer_export_drm(V4L2Buffer* avbuf) + { +- V4L2m2mContext *s = buf_to_m2mctx(in); ++ struct v4l2_exportbuffer expbuf; ++ int i, ret; + +- if (plane >= in->num_planes) +- return AVERROR(EINVAL); ++ for (i = 0; i < avbuf->num_planes; i++) { ++ memset(&expbuf, 0, sizeof(expbuf)); + +- /* even though most encoders return 0 in data_offset encoding vp8 does require this value */ +- *buf = av_buffer_create((char *)in->plane_info[plane].mm_addr + in->planes[plane].data_offset, +- in->plane_info[plane].length, v4l2_free_buffer, in, 0); +- if (!*buf) +- return AVERROR(ENOMEM); ++ expbuf.index = avbuf->buf.index; ++ expbuf.type = avbuf->buf.type; ++ expbuf.plane = i; ++ ++ ret = ioctl(buf_to_m2mctx(avbuf)->fd, VIDIOC_EXPBUF, &expbuf); ++ if (ret < 0) ++ return AVERROR(errno); ++ ++ if (V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type)) { ++ /* drm frame */ ++ avbuf->drm_frame.objects[i].size = avbuf->buf.m.planes[i].length; ++ avbuf->drm_frame.objects[i].fd = expbuf.fd; ++ } else { ++ /* drm frame */ ++ avbuf->drm_frame.objects[0].size = avbuf->buf.length; ++ avbuf->drm_frame.objects[0].fd = expbuf.fd; ++ } ++ } ++ ++ return 0; ++} ++ ++static int v4l2_buf_increase_ref(V4L2Buffer *in) ++{ ++ V4L2m2mContext *s = buf_to_m2mctx(in); + + if (in->context_ref) + atomic_fetch_add(&in->context_refcount, 1); + else { + in->context_ref = av_buffer_ref(s->self_ref); +- if (!in->context_ref) { +- av_buffer_unref(buf); ++ if (!in->context_ref) + return AVERROR(ENOMEM); +- } ++ + in->context_refcount = 1; + } + +@@ -257,6 +351,46 @@ static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) + return 0; + } + ++static int v4l2_buf_to_bufref_drm(V4L2Buffer *in, AVBufferRef **buf) ++{ ++ int ret; ++ ++ *buf = av_buffer_create((uint8_t *) &in->drm_frame, ++ sizeof(in->drm_frame), ++ v4l2_free_buffer, ++ in, AV_BUFFER_FLAG_READONLY); ++ if (!*buf) ++ return AVERROR(ENOMEM); ++ ++ ret = v4l2_buf_increase_ref(in); ++ if (ret) ++ av_buffer_unref(buf); ++ ++ return ret; ++} ++ ++static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) ++{ ++ int ret; ++ ++ if (plane >= in->num_planes) ++ return AVERROR(EINVAL); ++ ++ /* most encoders return 0 in data_offset but vp8 does require this value */ ++ *buf = av_buffer_create((char *)in->plane_info[plane].mm_addr + in->planes[plane].data_offset, ++ in->plane_info[plane].length, ++ v4l2_free_buffer, ++ in, 0); ++ if (!*buf) ++ return AVERROR(ENOMEM); ++ ++ ret = v4l2_buf_increase_ref(in); ++ if (ret) ++ av_buffer_unref(buf); ++ ++ return ret; ++} ++ + static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, int size, AVBufferRef* bref) + { + unsigned int bytesused, length; +@@ -308,31 +442,43 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf) + + av_frame_unref(frame); + +- /* 1. get references to the actual data */ +- for (i = 0; i < avbuf->num_planes; i++) { +- ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]); ++ if (buf_to_m2mctx(avbuf)->output_drm) { ++ /* 1. get references to the actual data */ ++ ret = v4l2_buf_to_bufref_drm(avbuf, &frame->buf[0]); + if (ret) + return ret; + +- frame->linesize[i] = avbuf->plane_info[i].bytesperline; +- frame->data[i] = frame->buf[i]->data; +- } ++ frame->data[0] = (uint8_t *) v4l2_get_drm_frame(avbuf); ++ frame->format = AV_PIX_FMT_DRM_PRIME; ++ } else { ++ /* 1. get references to the actual data */ ++ for (i = 0; i < avbuf->num_planes; i++) { ++ ret = v4l2_buf_to_bufref(avbuf, i, &frame->buf[i]); ++ if (ret) ++ return ret; ++ ++ frame->linesize[i] = avbuf->plane_info[i].bytesperline; ++ frame->data[i] = frame->buf[i]->data; ++ } + +- /* 1.1 fixup special cases */ +- switch (avbuf->context->av_pix_fmt) { +- case AV_PIX_FMT_NV12: +- if (avbuf->num_planes > 1) ++ /* 1.1 fixup special cases */ ++ switch (avbuf->context->av_pix_fmt) { ++ case AV_PIX_FMT_NV12: ++ if (avbuf->num_planes > 1) ++ break; ++ frame->linesize[1] = avbuf->plane_info[0].bytesperline; ++ frame->data[1] = frame->buf[0]->data + ++ avbuf->plane_info[0].bytesperline * ++ avbuf->context->format.fmt.pix.height; + break; +- frame->linesize[1] = avbuf->plane_info[0].bytesperline; +- frame->data[1] = frame->buf[0]->data + avbuf->plane_info[0].bytesperline * avbuf->context->format.fmt.pix_mp.height; +- break; +- default: +- break; ++ default: ++ break; ++ } ++ frame->format = avbuf->context->av_pix_fmt; + } + + /* 2. get frame information */ + frame->key_frame = !!(avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME); +- frame->format = avbuf->context->av_pix_fmt; + frame->color_primaries = v4l2_get_color_primaries(avbuf); + frame->colorspace = v4l2_get_color_space(avbuf); + frame->color_range = v4l2_get_color_range(avbuf); +@@ -447,9 +593,6 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) + + avbuf->status = V4L2BUF_AVAILABLE; + +- if (V4L2_TYPE_IS_OUTPUT(ctx->type)) +- return 0; +- + if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { + avbuf->buf.m.planes = avbuf->planes; + avbuf->buf.length = avbuf->num_planes; +@@ -459,6 +602,15 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) + avbuf->buf.length = avbuf->planes[0].length; + } + ++ if (V4L2_TYPE_IS_OUTPUT(ctx->type)) ++ return 0; ++ ++ if (buf_to_m2mctx(avbuf)->output_drm) { ++ ret = v4l2_buffer_export_drm(avbuf); ++ if (ret) ++ return ret; ++ } ++ + return ff_v4l2_buffer_enqueue(avbuf); + } + +diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h +index dc5cc9e2671..a8a50ecc65f 100644 +--- a/libavcodec/v4l2_buffers.h ++++ b/libavcodec/v4l2_buffers.h +@@ -27,6 +27,7 @@ + #include + #include + ++#include "libavutil/hwcontext_drm.h" + #include "avcodec.h" + + enum V4L2Buffer_status { +@@ -42,6 +43,9 @@ typedef struct V4L2Buffer { + /* each buffer needs to have a reference to its context */ + struct V4L2Context *context; + ++ /* DRM descriptor */ ++ AVDRMFrameDescriptor drm_frame; ++ + /* This object is refcounted per-plane, so we need to keep track + * of how many context-refs we are holding. */ + AVBufferRef *context_ref; +diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c +index efcb0426e49..9457fadb1e9 100644 +--- a/libavcodec/v4l2_context.c ++++ b/libavcodec/v4l2_context.c +@@ -393,22 +393,54 @@ static int v4l2_release_buffers(V4L2Context* ctx) + struct v4l2_requestbuffers req = { + .memory = V4L2_MEMORY_MMAP, + .type = ctx->type, +- .count = 0, /* 0 -> unmaps buffers from the driver */ ++ .count = 0, /* 0 -> unmap all buffers from the driver */ + }; +- int i, j; ++ int ret, i, j; + + for (i = 0; i < ctx->num_buffers; i++) { + V4L2Buffer *buffer = &ctx->buffers[i]; + + for (j = 0; j < buffer->num_planes; j++) { + struct V4L2Plane_info *p = &buffer->plane_info[j]; ++ ++ if (V4L2_TYPE_IS_OUTPUT(ctx->type)) { ++ /* output buffers are not EXPORTED */ ++ goto unmap; ++ } ++ ++ if (ctx_to_m2mctx(ctx)->output_drm) { ++ /* use the DRM frame to close */ ++ if (buffer->drm_frame.objects[j].fd >= 0) { ++ if (close(buffer->drm_frame.objects[j].fd) < 0) { ++ av_log(logger(ctx), AV_LOG_ERROR, "%s close drm fd " ++ "[buffer=%2d, plane=%d, fd=%2d] - %s \n", ++ ctx->name, i, j, buffer->drm_frame.objects[j].fd, ++ av_err2str(AVERROR(errno))); ++ } ++ } ++ } ++unmap: + if (p->mm_addr && p->length) + if (munmap(p->mm_addr, p->length) < 0) +- av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", ctx->name, av_err2str(AVERROR(errno))); ++ av_log(logger(ctx), AV_LOG_ERROR, "%s unmap plane (%s))\n", ++ ctx->name, av_err2str(AVERROR(errno))); + } + } + +- return ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req); ++ ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_REQBUFS, &req); ++ if (ret < 0) { ++ av_log(logger(ctx), AV_LOG_ERROR, "release all %s buffers (%s)\n", ++ ctx->name, av_err2str(AVERROR(errno))); ++ ++ if (ctx_to_m2mctx(ctx)->output_drm) ++ av_log(logger(ctx), AV_LOG_ERROR, ++ "Make sure the DRM client releases all FB/GEM objects before closing the codec (ie):\n" ++ "for all buffers: \n" ++ " 1. drmModeRmFB(..)\n" ++ " 2. drmIoctl(.., DRM_IOCTL_GEM_CLOSE,... )\n"); ++ } ++ ++ return ret; + } + + static inline int v4l2_try_raw_format(V4L2Context* ctx, enum AVPixelFormat pixfmt) +diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c +index 427e165f586..7896326e808 100644 +--- a/libavcodec/v4l2_m2m.c ++++ b/libavcodec/v4l2_m2m.c +@@ -159,7 +159,9 @@ static int v4l2_configure_contexts(V4L2m2mContext* s) + goto error; + } + +- /* decoder's buffers need to be updated at a later stage */ ++ /* decoder's capture buffers are updated during v4l2_try_start once we find ++ * the valid format. ++ */ + if (!av_codec_is_decoder(s->avctx->codec)) { + ret = ff_v4l2_context_init(&s->capture); + if (ret) { +diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h +index 452bf0d9bc2..9ac5a2448da 100644 +--- a/libavcodec/v4l2_m2m.h ++++ b/libavcodec/v4l2_m2m.h +@@ -59,6 +59,9 @@ typedef struct V4L2m2mContext { + + /* Reference to self; only valid while codec is active. */ + AVBufferRef *self_ref; ++ ++ /* generate DRM frames */ ++ int output_drm; + } V4L2m2mContext; + + typedef struct V4L2m2mPriv +diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c +index ed5193ecc17..7f41e3b2121 100644 +--- a/libavcodec/v4l2_m2m_dec.c ++++ b/libavcodec/v4l2_m2m_dec.c +@@ -23,12 +23,18 @@ + + #include + #include ++ ++#include "libavutil/hwcontext.h" ++#include "libavutil/hwcontext_drm.h" + #include "libavutil/pixfmt.h" + #include "libavutil/pixdesc.h" + #include "libavutil/opt.h" + #include "libavcodec/avcodec.h" + #include "libavcodec/decode.h" + ++#include "libavcodec/hwaccel.h" ++#include "libavcodec/internal.h" ++ + #include "v4l2_context.h" + #include "v4l2_m2m.h" + #include "v4l2_fmt.h" +@@ -183,6 +189,15 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) + capture->av_codec_id = AV_CODEC_ID_RAWVIDEO; + capture->av_pix_fmt = avctx->pix_fmt; + ++ /* the client requests the codec to generate DRM frames: ++ * - data[0] will therefore point to the returned AVDRMFrameDescriptor ++ * check the ff_v4l2_buffer_to_avframe conversion function. ++ * - the DRM frame format is passed in the DRM frame descriptor layer. ++ * check the v4l2_get_drm_frame function. ++ */ ++ if (ff_get_format(avctx, avctx->codec->pix_fmts) == AV_PIX_FMT_DRM_PRIME) ++ s->output_drm = 1; ++ + ret = ff_v4l2_m2m_codec_init(avctx); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "can't configure decoder\n"); +@@ -202,6 +217,11 @@ static const AVOption options[] = { + { NULL}, + }; + ++static const AVCodecHWConfigInternal *v4l2_m2m_hw_configs[] = { ++ HW_CONFIG_INTERNAL(DRM_PRIME), ++ NULL ++}; ++ + #define M2MDEC_CLASS(NAME) \ + static const AVClass v4l2_m2m_ ## NAME ## _dec_class = { \ + .class_name = #NAME "_v4l2_m2m_decoder", \ +@@ -222,7 +242,10 @@ static const AVOption options[] = { + .init = v4l2_decode_init, \ + .receive_frame = v4l2_receive_frame, \ + .close = ff_v4l2_m2m_codec_end, \ ++ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ ++ AV_PIX_FMT_NONE}, \ + .bsfs = bsf_name, \ ++ .hw_configs = v4l2_m2m_hw_configs, \ + .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ + .wrapper_name = "v4l2m2m", \ + }; + +From 56b801661f935994d971c6b4aaf0d0ed3c4ca83f Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Tue, 8 May 2018 22:40:23 -0700 +Subject: [PATCH 3/6] libavcodec: v4l2m2m: adjust formatting + +--- + libavcodec/v4l2_buffers.c | 23 +++++++++++++++-------- + libavcodec/v4l2_buffers.h | 1 - + 2 files changed, 15 insertions(+), 9 deletions(-) + +diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c +index e5c46ac81e6..897c3c46369 100644 +--- a/libavcodec/v4l2_buffers.c ++++ b/libavcodec/v4l2_buffers.c +@@ -401,7 +401,8 @@ static int v4l2_bufref_to_buf(V4L2Buffer *out, int plane, const uint8_t* data, i + bytesused = FFMIN(size, out->plane_info[plane].length); + length = out->plane_info[plane].length; + +- memcpy(out->plane_info[plane].mm_addr, data, FFMIN(size, out->plane_info[plane].length)); ++ memcpy(out->plane_info[plane].mm_addr, data, ++ FFMIN(size, out->plane_info[plane].length)); + + if (V4L2_TYPE_IS_MULTIPLANAR(out->buf.type)) { + out->planes[plane].bytesused = bytesused; +@@ -425,7 +426,10 @@ int ff_v4l2_buffer_avframe_to_buf(const AVFrame *frame, V4L2Buffer* out) + int i, ret; + + for(i = 0; i < out->num_planes; i++) { +- ret = v4l2_bufref_to_buf(out, i, frame->buf[i]->data, frame->buf[i]->size, frame->buf[i]); ++ ret = v4l2_bufref_to_buf(out, i, ++ frame->buf[i]->data, ++ frame->buf[i]->size, ++ frame->buf[i]); + if (ret) + return ret; + } +@@ -480,8 +484,8 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *avbuf) + /* 2. get frame information */ + frame->key_frame = !!(avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME); + frame->color_primaries = v4l2_get_color_primaries(avbuf); +- frame->colorspace = v4l2_get_color_space(avbuf); + frame->color_range = v4l2_get_color_range(avbuf); ++ frame->colorspace = v4l2_get_color_space(avbuf); + frame->color_trc = v4l2_get_color_trc(avbuf); + frame->pts = v4l2_get_pts(avbuf); + +@@ -507,7 +511,8 @@ int ff_v4l2_buffer_buf_to_avpkt(AVPacket *pkt, V4L2Buffer *avbuf) + if (ret) + return ret; + +- pkt->size = V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type) ? avbuf->buf.m.planes[0].bytesused : avbuf->buf.bytesused; ++ pkt->size = V4L2_TYPE_IS_MULTIPLANAR(avbuf->buf.type) ? ++ avbuf->buf.m.planes[0].bytesused : avbuf->buf.bytesused; + pkt->data = pkt->buf->data; + + if (avbuf->buf.flags & V4L2_BUF_FLAG_KEYFRAME) +@@ -563,6 +568,7 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) + /* in MP, the V4L2 API states that buf.length means num_planes */ + if (avbuf->num_planes >= avbuf->buf.length) + break; ++ + if (avbuf->buf.m.planes[avbuf->num_planes].length) + avbuf->num_planes++; + } +@@ -579,12 +585,14 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) + avbuf->plane_info[i].length = avbuf->buf.m.planes[i].length; + avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.m.planes[i].length, + PROT_READ | PROT_WRITE, MAP_SHARED, +- buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.planes[i].m.mem_offset); ++ buf_to_m2mctx(avbuf)->fd, ++ avbuf->buf.m.planes[i].m.mem_offset); + } else { + avbuf->plane_info[i].length = avbuf->buf.length; + avbuf->plane_info[i].mm_addr = mmap(NULL, avbuf->buf.length, + PROT_READ | PROT_WRITE, MAP_SHARED, +- buf_to_m2mctx(avbuf)->fd, avbuf->buf.m.offset); ++ buf_to_m2mctx(avbuf)->fd, ++ avbuf->buf.m.offset); + } + + if (avbuf->plane_info[i].mm_addr == MAP_FAILED) +@@ -594,9 +602,8 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index) + avbuf->status = V4L2BUF_AVAILABLE; + + if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { +- avbuf->buf.m.planes = avbuf->planes; + avbuf->buf.length = avbuf->num_planes; +- ++ avbuf->buf.m.planes = avbuf->planes; + } else { + avbuf->buf.bytesused = avbuf->planes[0].bytesused; + avbuf->buf.length = avbuf->planes[0].length; +diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h +index a8a50ecc65f..c609a6c6767 100644 +--- a/libavcodec/v4l2_buffers.h ++++ b/libavcodec/v4l2_buffers.h +@@ -131,5 +131,4 @@ int ff_v4l2_buffer_initialize(V4L2Buffer* avbuf, int index); + */ + int ff_v4l2_buffer_enqueue(V4L2Buffer* avbuf); + +- + #endif // AVCODEC_V4L2_BUFFERS_H + +From 992ecd533321b876438fe3c4b7630003f260974e Mon Sep 17 00:00:00 2001 +From: Jorge Ramirez-Ortiz +Date: Sun, 6 May 2018 19:56:30 +0200 +Subject: [PATCH 4/6] libavcodec: v4l2m2m: fix error handling during buffer + init + +Signed-off-by: Jorge Ramirez-Ortiz +--- + libavcodec/v4l2_context.c | 19 ++++++++++++++++--- + libavcodec/v4l2_m2m_dec.c | 11 ++++++++--- + 2 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c +index 9457fadb1e9..fd3161ce2f5 100644 +--- a/libavcodec/v4l2_context.c ++++ b/libavcodec/v4l2_context.c +@@ -263,6 +263,12 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) + /* if we are draining and there are no more capture buffers queued in the driver we are done */ + if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx_to_m2mctx(ctx)->draining) { + for (i = 0; i < ctx->num_buffers; i++) { ++ /* catpture buffer initialization happens during decode hence ++ * detection happens at runtime ++ */ ++ if (!ctx->buffers) ++ break; ++ + if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER) + goto start; + } +@@ -724,9 +730,8 @@ int ff_v4l2_context_init(V4L2Context* ctx) + ctx->buffers[i].context = ctx; + ret = ff_v4l2_buffer_initialize(&ctx->buffers[i], i); + if (ret < 0) { +- av_log(logger(ctx), AV_LOG_ERROR, "%s buffer initialization (%s)\n", ctx->name, av_err2str(ret)); +- av_free(ctx->buffers); +- return ret; ++ av_log(logger(ctx), AV_LOG_ERROR, "%s buffer[%d] initialization (%s)\n", ctx->name, i, av_err2str(ret)); ++ goto error; + } + } + +@@ -739,4 +744,12 @@ int ff_v4l2_context_init(V4L2Context* ctx) + V4L2_TYPE_IS_MULTIPLANAR(ctx->type) ? ctx->format.fmt.pix_mp.plane_fmt[0].bytesperline : ctx->format.fmt.pix.bytesperline); + + return 0; ++ ++error: ++ v4l2_release_buffers(ctx); ++ ++ av_free(ctx->buffers); ++ ctx->buffers = NULL; ++ ++ return ret; + } +diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c +index 7f41e3b2121..d524fd29a6a 100644 +--- a/libavcodec/v4l2_m2m_dec.c ++++ b/libavcodec/v4l2_m2m_dec.c +@@ -92,8 +92,8 @@ static int v4l2_try_start(AVCodecContext *avctx) + if (!capture->buffers) { + ret = ff_v4l2_context_init(capture); + if (ret) { +- av_log(avctx, AV_LOG_DEBUG, "can't request output buffers\n"); +- return ret; ++ av_log(avctx, AV_LOG_ERROR, "can't request capture buffers\n"); ++ return AVERROR(ENOMEM); + } + } + +@@ -155,8 +155,13 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) + + if (avpkt.size) { + ret = v4l2_try_start(avctx); +- if (ret) ++ if (ret) { ++ /* cant recover */ ++ if (ret == AVERROR(ENOMEM)) ++ return ret; ++ + return 0; ++ } + } + + dequeue: + +From 98f828fcb15f2bcec11a6b8f56ae808c4c1220c2 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Sun, 17 Jun 2018 22:56:37 -0700 +Subject: [PATCH 6/6] libavcodec: v4l2m2m: make sure to unref avpkt + +--- + libavcodec/v4l2_m2m_dec.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c +index 6dd0de7ffcf..6fdbf8f16e4 100644 +--- a/libavcodec/v4l2_m2m_dec.c ++++ b/libavcodec/v4l2_m2m_dec.c +@@ -156,6 +156,7 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) + if (avpkt.size) { + ret = v4l2_try_start(avctx); + if (ret) { ++ av_packet_unref(&avpkt); + /* cant recover */ + if (ret == AVERROR(ENOMEM)) + return ret; +@@ -165,6 +166,7 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) + } + + dequeue: ++ av_packet_unref(&avpkt); + return ff_v4l2_context_dequeue_frame(capture, frame); + } + diff --git a/projects/Amlogic/patches/ffmpeg/ffmpeg-999-min-buffers.patch b/projects/Amlogic/patches/ffmpeg/ffmpeg-999-min-buffers.patch new file mode 100644 index 0000000000..c156cf69ff --- /dev/null +++ b/projects/Amlogic/patches/ffmpeg/ffmpeg-999-min-buffers.patch @@ -0,0 +1,11 @@ +--- a/libavcodec/v4l2_m2m.h 2018-07-22 11:04:44.223961230 +0100 ++++ b/libavcodec/v4l2_m2m.h 2018-07-30 18:19:54.780753049 +0100 +@@ -38,7 +38,7 @@ + + #define V4L_M2M_DEFAULT_OPTS \ + { "num_output_buffers", "Number of buffers in the output context",\ +- OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 6, INT_MAX, FLAGS } ++ OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT_MAX, FLAGS } + + typedef struct V4L2m2mContext { + char devname[PATH_MAX]; diff --git a/projects/Amlogic/patches/ffmpeg/ffmpeg-999-z-fixes.patch b/projects/Amlogic/patches/ffmpeg/ffmpeg-999-z-fixes.patch new file mode 100644 index 0000000000..7e2f74d22f --- /dev/null +++ b/projects/Amlogic/patches/ffmpeg/ffmpeg-999-z-fixes.patch @@ -0,0 +1,51 @@ +diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c +index 80a09f7a43..af65927ac3 100644 +--- a/libavcodec/v4l2_m2m_dec.c ++++ b/libavcodec/v4l2_m2m_dec.c +@@ -125,6 +125,8 @@ static int v4l2_prepare_decoder(V4L2m2mContext *s) + return 0; + } + ++static AVPacket saved_avpkt = { 0 }; ++ + static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) + { + V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; +@@ -133,9 +135,14 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) + AVPacket avpkt = {0}; + int ret; + +- ret = ff_decode_get_packet(avctx, &avpkt); +- if (ret < 0 && ret != AVERROR_EOF) +- return ret; ++ if (saved_avpkt.size) { ++ avpkt = saved_avpkt; ++ memset(&saved_avpkt, 0, sizeof(saved_avpkt)); ++ } else { ++ ret = ff_decode_get_packet(avctx, &avpkt); ++ if (ret < 0 && ret != AVERROR_EOF) ++ return ret; ++ } + + if (s->draining) + goto dequeue; +@@ -144,6 +151,8 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) + if (ret < 0) { + if (ret != AVERROR(ENOMEM)) + return ret; ++ ++ saved_avpkt = avpkt; + /* no input buffers available, continue dequeing */ + } + +@@ -156,7 +165,8 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) + } + + dequeue: +- av_packet_unref(&avpkt); ++ if (!saved_avpkt.size) ++ av_packet_unref(&avpkt); + return ff_v4l2_context_dequeue_frame(capture, frame); + } + + From a5f1eda331e9dedd8a2d5dc9fa49004159486c80 Mon Sep 17 00:00:00 2001 From: chewitt Date: Wed, 24 Oct 2018 08:48:07 +0100 Subject: [PATCH 16/21] kodi: misc patches to go upstream --- .../Amlogic/patches/kodi/kodi-PR15922.patch | 39 ++ .../Amlogic/patches/kodi/kodi-PR15928.patch | 383 ++++++++++++++++++ .../Amlogic/patches/kodi/kodi-PR15946.patch | 65 +++ .../patches/kodi/kodi-drmprime-ghetto.patch | 75 ++++ .../patches/kodi/kodi-front-buffer-lock.patch | 36 ++ .../Amlogic/patches/kodi/kodi-guisize.patch | 153 +++++++ 6 files changed, 751 insertions(+) create mode 100644 projects/Amlogic/patches/kodi/kodi-PR15922.patch create mode 100644 projects/Amlogic/patches/kodi/kodi-PR15928.patch create mode 100644 projects/Amlogic/patches/kodi/kodi-PR15946.patch create mode 100644 projects/Amlogic/patches/kodi/kodi-drmprime-ghetto.patch create mode 100644 projects/Amlogic/patches/kodi/kodi-front-buffer-lock.patch create mode 100644 projects/Amlogic/patches/kodi/kodi-guisize.patch diff --git a/projects/Amlogic/patches/kodi/kodi-PR15922.patch b/projects/Amlogic/patches/kodi/kodi-PR15922.patch new file mode 100644 index 0000000000..577fb772e1 --- /dev/null +++ b/projects/Amlogic/patches/kodi/kodi-PR15922.patch @@ -0,0 +1,39 @@ +From 4d6af620f4d6a6645229dcf3403a397dfb1a8a93 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Mon, 15 Apr 2019 16:51:09 -0700 +Subject: [PATCH] CDRMUtils: rework modifiers flag selection + +--- + xbmc/windowing/gbm/DRMUtils.cpp | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/xbmc/windowing/gbm/DRMUtils.cpp b/xbmc/windowing/gbm/DRMUtils.cpp +index df46ad4bdc25..8e1ec9d0dcb5 100644 +--- a/xbmc/windowing/gbm/DRMUtils.cpp ++++ b/xbmc/windowing/gbm/DRMUtils.cpp +@@ -109,10 +109,13 @@ drm_fb * CDRMUtils::DrmFbGetFromBo(struct gbm_bo *bo) + memset(offsets, 0, 16); + #endif + +- if (modifiers[0] == DRM_FORMAT_MOD_INVALID) +- modifiers[0] = DRM_FORMAT_MOD_LINEAR; ++ uint32_t flags = 0; + +- CLog::Log(LOGDEBUG, "CDRMUtils::%s - using modifier: %lli", __FUNCTION__, modifiers[0]); ++ if (modifiers[0] && modifiers[0] != DRM_FORMAT_MOD_INVALID) ++ { ++ flags |= DRM_MODE_FB_MODIFIERS; ++ CLog::Log(LOGDEBUG, "CDRMUtils::{} - using modifier: {:#x}", __FUNCTION__, modifiers[0]); ++ } + + auto ret = drmModeAddFB2WithModifiers(m_fd, + width, +@@ -123,7 +126,7 @@ drm_fb * CDRMUtils::DrmFbGetFromBo(struct gbm_bo *bo) + offsets, + modifiers, + &fb->fb_id, +- (modifiers[0] > 0) ? DRM_MODE_FB_MODIFIERS : 0); ++ flags); + + if(ret) + { diff --git a/projects/Amlogic/patches/kodi/kodi-PR15928.patch b/projects/Amlogic/patches/kodi/kodi-PR15928.patch new file mode 100644 index 0000000000..e1f374c713 --- /dev/null +++ b/projects/Amlogic/patches/kodi/kodi-PR15928.patch @@ -0,0 +1,383 @@ +From af01b284b158891d258b3a2617697b9779af11c5 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Thu, 7 Mar 2019 15:08:24 -0800 +Subject: [PATCH 1/4] CEGLFence: add class to help with EGL sync objects + +--- + xbmc/utils/CMakeLists.txt | 6 ++-- + xbmc/utils/EGLFence.cpp | 68 +++++++++++++++++++++++++++++++++++++++ + xbmc/utils/EGLFence.h | 32 ++++++++++++++++++ + 3 files changed, 104 insertions(+), 2 deletions(-) + create mode 100644 xbmc/utils/EGLFence.cpp + create mode 100644 xbmc/utils/EGLFence.h + +diff --git a/xbmc/utils/CMakeLists.txt b/xbmc/utils/CMakeLists.txt +index f0ce99014b84..6dbee35a1a60 100644 +--- a/xbmc/utils/CMakeLists.txt ++++ b/xbmc/utils/CMakeLists.txt +@@ -169,8 +169,10 @@ if(XSLT_FOUND) + list(APPEND HEADERS XSLTUtils.h) + endif() + if(EGL_FOUND) +- list(APPEND SOURCES EGLUtils.cpp) +- list(APPEND HEADERS EGLUtils.h) ++ list(APPEND SOURCES EGLUtils.cpp ++ EGLFence.cpp) ++ list(APPEND HEADERS EGLUtils.h ++ EGLFence.h) + endif() + + # The large map trips the clang optimizer +diff --git a/xbmc/utils/EGLFence.cpp b/xbmc/utils/EGLFence.cpp +new file mode 100644 +index 000000000000..55cc45c4282a +--- /dev/null ++++ b/xbmc/utils/EGLFence.cpp +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (C) 2017-2018 Team Kodi ++ * This file is part of Kodi - https://kodi.tv ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * See LICENSES/README.md for more information. ++ */ ++ ++#include "EGLFence.h" ++ ++#include "EGLUtils.h" ++ ++CEGLFence::CEGLFence(EGLDisplay display) : ++ m_display(display) ++{ ++ m_eglCreateSyncKHR = CEGLUtils::GetRequiredProcAddress("eglCreateSyncKHR"); ++ m_eglDestroySyncKHR = CEGLUtils::GetRequiredProcAddress("eglDestroySyncKHR"); ++ m_eglGetSyncAttribKHR = CEGLUtils::GetRequiredProcAddress("eglGetSyncAttribKHR"); ++} ++ ++bool CEGLFence::CreateFence() ++{ ++ m_fence = m_eglCreateSyncKHR(m_display, EGL_SYNC_FENCE_KHR, nullptr); ++ if (m_fence == EGL_NO_SYNC_KHR) ++ { ++ CEGLUtils::LogError("failed to create egl sync fence"); ++ return false; ++ } ++ ++ return true; ++} ++ ++void CEGLFence::DestroyFence() ++{ ++ if (m_fence == EGL_NO_SYNC_KHR) ++ { ++ return; ++ } ++ ++ if (m_eglDestroySyncKHR(m_display, m_fence) != EGL_TRUE) ++ { ++ CEGLUtils::LogError("failed to destroy egl sync fence"); ++ } ++ ++ m_fence = EGL_NO_SYNC_KHR; ++} ++ ++bool CEGLFence::IsSignaled() ++{ ++ if (m_fence == EGL_NO_SYNC_KHR) ++ { ++ return false; ++ } ++ ++ EGLint status = EGL_UNSIGNALED_KHR; ++ if (m_eglGetSyncAttribKHR(m_display, m_fence, EGL_SYNC_STATUS_KHR, &status) != EGL_TRUE) ++ { ++ CEGLUtils::LogError("failed to query egl sync fence"); ++ return false; ++ } ++ ++ if (status == EGL_SIGNALED_KHR) ++ { ++ return true; ++ } ++ ++ return false; ++} +diff --git a/xbmc/utils/EGLFence.h b/xbmc/utils/EGLFence.h +new file mode 100644 +index 000000000000..eb285ac4260e +--- /dev/null ++++ b/xbmc/utils/EGLFence.h +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (C) 2017-2018 Team Kodi ++ * This file is part of Kodi - https://kodi.tv ++ * ++ * SPDX-License-Identifier: GPL-2.0-or-later ++ * See LICENSES/README.md for more information. ++ */ ++ ++#pragma once ++ ++#include ++#include ++ ++class CEGLFence ++{ ++public: ++ explicit CEGLFence(EGLDisplay display); ++ CEGLFence(CEGLFence const& other) = delete; ++ CEGLFence& operator=(CEGLFence const& other) = delete; ++ ++ bool CreateFence(); ++ void DestroyFence(); ++ bool IsSignaled(); ++ ++private: ++ EGLDisplay m_display{nullptr}; ++ EGLSyncKHR m_fence{nullptr}; ++ ++ PFNEGLCREATESYNCKHRPROC m_eglCreateSyncKHR{nullptr}; ++ PFNEGLDESTROYSYNCKHRPROC m_eglDestroySyncKHR{nullptr}; ++ PFNEGLGETSYNCATTRIBKHRPROC m_eglGetSyncAttribKHR{nullptr}; ++}; + +From eebac4f4e456aa3eb174286bf69073b1e740e4a9 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Thu, 7 Mar 2019 18:43:15 -0800 +Subject: [PATCH 2/4] CRendererDRMPRIMEGLES: use CEGLFence to sync rendering + +--- + .../HwDecRender/RendererDRMPRIMEGLES.cpp | 23 +++++++++++++++++++ + .../HwDecRender/RendererDRMPRIMEGLES.h | 8 +++++++ + 2 files changed, 31 insertions(+) + +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp +index 330823196fbc..5b8d82c2cd2f 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp +@@ -10,6 +10,7 @@ + + #include "cores/VideoPlayer/VideoRenderers/RenderFactory.h" + #include "ServiceBroker.h" ++#include "utils/EGLFence.h" + #include "utils/log.h" + #include "windowing/gbm/WinSystemGbmGLESContext.h" + +@@ -43,15 +44,32 @@ bool CRendererDRMPRIMEGLES::Configure(const VideoPicture &picture, float fps, un + for (auto &texture : m_DRMPRIMETextures) + texture.Init(winSystem->GetEGLDisplay()); + ++ for (auto& fence : m_fences) ++ { ++ fence.reset(new CEGLFence(winSystem->GetEGLDisplay())); ++ } ++ + return CLinuxRendererGLES::Configure(picture, fps, orientation); + } + + void CRendererDRMPRIMEGLES::ReleaseBuffer(int index) + { ++ m_fences[index]->DestroyFence(); ++ + m_DRMPRIMETextures[index].Unmap(); + CLinuxRendererGLES::ReleaseBuffer(index); + } + ++bool CRendererDRMPRIMEGLES::NeedBuffer(int index) ++{ ++ if (m_fences[index]->IsSignaled()) ++ { ++ return false; ++ } ++ ++ return true; ++} ++ + bool CRendererDRMPRIMEGLES::CreateTexture(int index) + { + CPictureBuffer &buf = m_buffers[index]; +@@ -188,3 +206,8 @@ bool CRendererDRMPRIMEGLES::RenderHook(int index) + + return true; + } ++ ++void CRendererDRMPRIMEGLES::AfterRenderHook(int index) ++{ ++ m_fences[index]->CreateFence(); ++} +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.h +index f879b6cf5a38..1666f70443ac 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.h ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.h +@@ -11,6 +11,11 @@ + #include "cores/VideoPlayer/VideoRenderers/LinuxRendererGLES.h" + #include "DRMPRIMEEGL.h" + ++#include ++#include ++ ++class CEGLFence; ++ + class CRendererDRMPRIMEGLES : public CLinuxRendererGLES + { + public: +@@ -24,14 +29,17 @@ class CRendererDRMPRIMEGLES : public CLinuxRendererGLES + // CLinuxRendererGLES overrides + bool Configure(const VideoPicture &picture, float fps, unsigned int orientation) override; + void ReleaseBuffer(int index) override; ++ bool NeedBuffer(int index) override; + + protected: + // CLinuxRendererGLES overrides + bool LoadShadersHook() override; + bool RenderHook(int index) override; ++ void AfterRenderHook(int index) override; + bool UploadTexture(int index) override; + void DeleteTexture(int index) override; + bool CreateTexture(int index) override; + ++ std::array, NUM_BUFFERS> m_fences; + CDRMPRIMETexture m_DRMPRIMETextures[NUM_BUFFERS]; + }; + +From 86d11125437086b290ec380cbe200acd96e76475 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Mon, 18 Feb 2019 19:18:39 -0800 +Subject: [PATCH 3/4] CRendererDRMPRIMEGLES: update VBO's to be similar to + CLinuxRendererGL + +--- + .../HwDecRender/RendererDRMPRIMEGLES.cpp | 48 ++++++++++++------- + 1 file changed, 32 insertions(+), 16 deletions(-) + +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp +index 5b8d82c2cd2f..1f3176422885 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp +@@ -157,28 +157,44 @@ bool CRendererDRMPRIMEGLES::RenderHook(int index) + { + float x, y, z; + float u1, v1; +- } vertex[4]; ++ }; ++ ++ std::array vertex; + + GLint vertLoc = renderSystem->GUIShaderGetPos(); + GLint loc = renderSystem->GUIShaderGetCoord0(); + +- for (unsigned int i = 0; i < 4; i++) +- { +- // Setup vertex position values +- vertex[i].x = m_rotatedDestCoords[i].x; +- vertex[i].y = m_rotatedDestCoords[i].y; +- vertex[i].z = 0.0f; +- } +- +- // Setup texture coordinates +- vertex[0].u1 = vertex[3].u1 = plane.rect.x1; +- vertex[0].v1 = vertex[1].v1 = plane.rect.y1; +- vertex[1].u1 = vertex[2].u1 = plane.rect.x2; +- vertex[2].v1 = vertex[3].v1 = plane.rect.y2; ++ // top left ++ vertex[0].x = m_rotatedDestCoords[0].x; ++ vertex[0].y = m_rotatedDestCoords[0].y; ++ vertex[0].z = 0.0f; ++ vertex[0].u1 = plane.rect.x1; ++ vertex[0].v1 = plane.rect.y1; ++ ++ // top right ++ vertex[1].x = m_rotatedDestCoords[1].x; ++ vertex[1].y = m_rotatedDestCoords[1].y; ++ vertex[1].z = 0.0f; ++ vertex[1].u1 = plane.rect.x2; ++ vertex[1].v1 = plane.rect.y1; ++ ++ // bottom right ++ vertex[2].x = m_rotatedDestCoords[2].x; ++ vertex[2].y = m_rotatedDestCoords[2].y; ++ vertex[2].z = 0.0f; ++ vertex[2].u1 = plane.rect.x2; ++ vertex[2].v1 = plane.rect.y2; ++ ++ // bottom left ++ vertex[3].x = m_rotatedDestCoords[3].x; ++ vertex[3].y = m_rotatedDestCoords[3].y; ++ vertex[3].z = 0.0f; ++ vertex[3].u1 = plane.rect.x1; ++ vertex[3].v1 = plane.rect.y2;; + + glGenBuffers(1, &vertexVBO); + glBindBuffer(GL_ARRAY_BUFFER, vertexVBO); +- glBufferData(GL_ARRAY_BUFFER, sizeof(PackedVertex)*4, &vertex[0], GL_STATIC_DRAW); ++ glBufferData(GL_ARRAY_BUFFER, sizeof(PackedVertex) * vertex.size(), vertex.data(), GL_STATIC_DRAW); + + glVertexAttribPointer(vertLoc, 3, GL_FLOAT, 0, sizeof(PackedVertex), reinterpret_cast(offsetof(PackedVertex, x))); + glVertexAttribPointer(loc, 2, GL_FLOAT, 0, sizeof(PackedVertex), reinterpret_cast(offsetof(PackedVertex, u1))); +@@ -188,7 +204,7 @@ bool CRendererDRMPRIMEGLES::RenderHook(int index) + + glGenBuffers(1, &indexVBO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexVBO); +- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte)*4, idx, GL_STATIC_DRAW); ++ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * 4, idx, GL_STATIC_DRAW); + + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, 0); + + +From 8d4e4760cb92c90b56aa28a9260d364cd40e0245 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Mon, 18 Feb 2019 19:20:11 -0800 +Subject: [PATCH 4/4] CRendererDRMPRIMEGLES: add override methods for + ERENDERFEATURE and ESCALINGMETHOD + +--- + .../HwDecRender/RendererDRMPRIMEGLES.cpp | 24 +++++++++++++++++++ + .../HwDecRender/RendererDRMPRIMEGLES.h | 3 +++ + 2 files changed, 27 insertions(+) + +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp +index 1f3176422885..ac01d52c10d7 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.cpp +@@ -227,3 +227,27 @@ void CRendererDRMPRIMEGLES::AfterRenderHook(int index) + { + m_fences[index]->CreateFence(); + } ++ ++bool CRendererDRMPRIMEGLES::Supports(ERENDERFEATURE feature) ++{ ++ if (feature == RENDERFEATURE_STRETCH || ++ feature == RENDERFEATURE_ZOOM || ++ feature == RENDERFEATURE_VERTICAL_SHIFT || ++ feature == RENDERFEATURE_PIXEL_RATIO || ++ feature == RENDERFEATURE_ROTATION) ++ { ++ return true; ++ } ++ ++ return false; ++} ++ ++bool CRendererDRMPRIMEGLES::Supports(ESCALINGMETHOD method) ++{ ++ if (method == VS_SCALINGMETHOD_LINEAR) ++ { ++ return true; ++ } ++ ++ return false; ++} +diff --git a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.h b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.h +index 1666f70443ac..4e9ae779daf8 100644 +--- a/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.h ++++ b/xbmc/cores/VideoPlayer/VideoRenderers/HwDecRender/RendererDRMPRIMEGLES.h +@@ -31,6 +31,9 @@ class CRendererDRMPRIMEGLES : public CLinuxRendererGLES + void ReleaseBuffer(int index) override; + bool NeedBuffer(int index) override; + ++ bool Supports(ERENDERFEATURE feature) override; ++ bool Supports(ESCALINGMETHOD method) override; ++ + protected: + // CLinuxRendererGLES overrides + bool LoadShadersHook() override; diff --git a/projects/Amlogic/patches/kodi/kodi-PR15946.patch b/projects/Amlogic/patches/kodi/kodi-PR15946.patch new file mode 100644 index 0000000000..127bafb8ef --- /dev/null +++ b/projects/Amlogic/patches/kodi/kodi-PR15946.patch @@ -0,0 +1,65 @@ +From 2104dbd5e263b9f83c0e6cd451a486d6f3046f83 Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Sat, 20 Apr 2019 12:01:19 -0700 +Subject: [PATCH] CDRMUtils: fallback to drmModeAddFB2 if + drmModeAddFB2WithModifiers fails + +--- + xbmc/windowing/gbm/DRMUtils.cpp | 43 +++++++++++++++++++++------------ + 1 file changed, 28 insertions(+), 15 deletions(-) + +diff --git a/xbmc/windowing/gbm/DRMUtils.cpp b/xbmc/windowing/gbm/DRMUtils.cpp +index 8e1ec9d0dcb5..6cae2176296f 100644 +--- a/xbmc/windowing/gbm/DRMUtils.cpp ++++ b/xbmc/windowing/gbm/DRMUtils.cpp +@@ -117,22 +117,35 @@ drm_fb * CDRMUtils::DrmFbGetFromBo(struct gbm_bo *bo) + CLog::Log(LOGDEBUG, "CDRMUtils::{} - using modifier: {:#x}", __FUNCTION__, modifiers[0]); + } + +- auto ret = drmModeAddFB2WithModifiers(m_fd, +- width, +- height, +- fb->format, +- handles, +- strides, +- offsets, +- modifiers, +- &fb->fb_id, +- flags); ++ int ret = drmModeAddFB2WithModifiers(m_fd, ++ width, ++ height, ++ fb->format, ++ handles, ++ strides, ++ offsets, ++ modifiers, ++ &fb->fb_id, ++ flags); ++ ++ if(ret < 0) ++ { ++ ret = drmModeAddFB2(m_fd, ++ width, ++ height, ++ fb->format, ++ handles, ++ strides, ++ offsets, ++ &fb->fb_id, ++ flags); + +- if(ret) +- { +- delete (fb); +- CLog::Log(LOGDEBUG, "CDRMUtils::%s - failed to add framebuffer", __FUNCTION__); +- return nullptr; ++ if (ret < 0) ++ { ++ delete (fb); ++ CLog::Log(LOGDEBUG, "CDRMUtils::{} - failed to add framebuffer: {} ({})", __FUNCTION__, strerror(errno), errno); ++ return nullptr; ++ } + } + + gbm_bo_set_user_data(bo, fb, DrmFbDestroyCallback); diff --git a/projects/Amlogic/patches/kodi/kodi-drmprime-ghetto.patch b/projects/Amlogic/patches/kodi/kodi-drmprime-ghetto.patch new file mode 100644 index 0000000000..1b6a8fc485 --- /dev/null +++ b/projects/Amlogic/patches/kodi/kodi-drmprime-ghetto.patch @@ -0,0 +1,75 @@ +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +index e04c3c6ff6..dcf97af4ef 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.cpp +@@ -156,7 +156,7 @@ void CVideoBufferPoolDRMPRIME::Return(int id) + //------------------------------------------------------------------------------ + + CDVDVideoCodecDRMPRIME::CDVDVideoCodecDRMPRIME(CProcessInfo& processInfo) +- : CDVDVideoCodec(processInfo) ++ : CDVDVideoCodec(processInfo), m_prevTime(0), m_seeking(false) + { + m_pFrame = av_frame_alloc(); + m_videoBufferPool = std::make_shared(); +@@ -406,6 +406,20 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecDRMPRIME::GetPicture(VideoPicture* pVideo + return VC_ERROR; + } + ++ if (m_prevTime && std::abs(m_prevTime - m_processInfo.GetTime()) >= 5000) ++ m_seeking = true; ++ ++ m_prevTime = m_processInfo.GetTime(); ++ ++ // Drop frames too far away from the target time ++ if (m_seeking && std::abs(m_pFrame->pts/1000 - m_processInfo.GetTime()) >= 5000) { ++ CLog::Log(LOGDEBUG, "CDVDVideoCodecDRMPRIME::%s - Dropping pts %llu time %lld", __FUNCTION__, m_pFrame->pts/1000, m_processInfo.GetTime()); ++ av_frame_unref(m_pFrame); ++ return VC_BUFFER; ++ } ++ ++ m_seeking = false; ++ + if (pVideoPicture->videoBuffer) + pVideoPicture->videoBuffer->Release(); + pVideoPicture->videoBuffer = nullptr; +diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +index ffcdf1a7b6..4455280e38 100644 +--- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h ++++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecDRMPRIME.h +@@ -79,4 +79,6 @@ protected: + AVCodecContext* m_pCodecContext = nullptr; + AVFrame* m_pFrame = nullptr; + std::shared_ptr m_videoBufferPool; ++ int64_t m_prevTime; ++ bool m_seeking; + }; +diff --git a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp +index e8d9023a9f..4299894c00 100644 +--- a/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp ++++ b/xbmc/cores/VideoPlayer/Process/ProcessInfo.cpp +@@ -635,6 +635,13 @@ bool CProcessInfo::GetVideoRender() + return m_renderVideoLayer; + } + ++int64_t CProcessInfo::GetTime() ++{ ++ CSingleLock lock(m_stateSection); ++ ++ return m_time; ++} ++ + void CProcessInfo::SetPlayTimes(time_t start, int64_t current, int64_t min, int64_t max) + { + CSingleLock lock(m_stateSection); +diff --git a/xbmc/cores/VideoPlayer/Process/ProcessInfo.h b/xbmc/cores/VideoPlayer/Process/ProcessInfo.h +index e8042c2bc2..5b4aea9b9d 100644 +--- a/xbmc/cores/VideoPlayer/Process/ProcessInfo.h ++++ b/xbmc/cores/VideoPlayer/Process/ProcessInfo.h +@@ -101,6 +101,7 @@ public: + bool GetGuiRender(); + void SetVideoRender(bool video); + bool GetVideoRender(); ++ int64_t GetTime(); + + void SetPlayTimes(time_t start, int64_t current, int64_t min, int64_t max); + int64_t GetMaxTime(); diff --git a/projects/Amlogic/patches/kodi/kodi-front-buffer-lock.patch b/projects/Amlogic/patches/kodi/kodi-front-buffer-lock.patch new file mode 100644 index 0000000000..6eafb34858 --- /dev/null +++ b/projects/Amlogic/patches/kodi/kodi-front-buffer-lock.patch @@ -0,0 +1,36 @@ +From 1667f2b95424f7c42fbd5b30aaadef53ab76e3ad Mon Sep 17 00:00:00 2001 +From: Lukas Rusak +Date: Fri, 12 Apr 2019 22:22:34 -0700 +Subject: [PATCH] CWinSystemGbm: only lock the front buffer if something is + rendered + +--- + xbmc/windowing/gbm/WinSystemGbm.cpp | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/xbmc/windowing/gbm/WinSystemGbm.cpp b/xbmc/windowing/gbm/WinSystemGbm.cpp +index 4a3291a55045..5cee802be2de 100644 +--- a/xbmc/windowing/gbm/WinSystemGbm.cpp ++++ b/xbmc/windowing/gbm/WinSystemGbm.cpp +@@ -207,11 +207,19 @@ void CWinSystemGbm::FlipPage(bool rendered, bool videoLayer) + m_videoLayerBridge->Disable(); + } + +- struct gbm_bo *bo = m_GBM->LockFrontBuffer(); ++ struct gbm_bo *bo = nullptr; ++ ++ if (rendered) ++ { ++ bo = m_GBM->LockFrontBuffer(); ++ } + + m_DRM->FlipPage(bo, rendered, videoLayer); + +- m_GBM->ReleaseBuffer(); ++ if (rendered) ++ { ++ m_GBM->ReleaseBuffer(); ++ } + + if (m_videoLayerBridge && !videoLayer) + { diff --git a/projects/Amlogic/patches/kodi/kodi-guisize.patch b/projects/Amlogic/patches/kodi/kodi-guisize.patch new file mode 100644 index 0000000000..c421f5969f --- /dev/null +++ b/projects/Amlogic/patches/kodi/kodi-guisize.patch @@ -0,0 +1,153 @@ +From 7a88b0ad7a90a8ac2266f87ccb08dca5df0c0867 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 14 Oct 2018 14:20:03 +0200 +Subject: [PATCH] WIP: windowing/gbm: add option to limit gui size + +--- + .../resources/strings.po | 52 ++++++++++++++++++- + system/settings/gbm.xml | 15 ++++++ + xbmc/windowing/gbm/DRMUtils.cpp | 28 ++++++++++ + 3 files changed, 94 insertions(+), 1 deletion(-) + +diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po +index 97211d3b718a..eaa5b3fed759 100644 +--- a/addons/resource.language.en_gb/resources/strings.po ++++ b/addons/resource.language.en_gb/resources/strings.po +@@ -7256,7 +7256,57 @@ msgctxt "#13465" + msgid "EGL" + msgstr "" + +-#empty strings from id 13466 to 13504 ++#empty strings from id 13466 to 13485 ++ ++#. String for options 3 of setting with label #13482 "HDMI Quantization Range" ++#: system/settings/gbm.xml ++msgctxt "#13486" ++msgid "Limited" ++msgstr "" ++ ++#. Option for setting Limit GUI Size ++#: system/settings/gbm.xml ++msgctxt "#13487" ++msgid "Limit GUI Size" ++msgstr "" ++ ++#. Description of setting with label #13487 "Limit GUI Size" ++#: system/settings/gbm.xml ++msgctxt "#13488" ++msgid "This option limits GUI size for screen resolutions above 1080p. Requires restart." ++msgstr "" ++ ++#. String for options 1 of setting with label #13487 "Limit GUI Size" ++#: system/settings/gbm.xml ++msgctxt "#13489" ++msgid "No limit" ++msgstr "" ++ ++#. String for options 2 of setting with label #13487 "Limit GUI Size" ++#: system/settings/gbm.xml ++msgctxt "#13490" ++msgid "720p" ++msgstr "" ++ ++#. String for options 3 of setting with label #13487 "Limit GUI Size" ++#: system/settings/gbm.xml ++msgctxt "#13491" ++msgid "1080p / 720p (>30hz)" ++msgstr "" ++ ++#. String for options 4 of setting with label #13487 "Limit GUI Size" ++#: system/settings/gbm.xml ++msgctxt "#13492" ++msgid "1080p" ++msgstr "" ++ ++#. String for options 5 of setting with label #13487 "Limit GUI Size" ++#: system/settings/gbm.xml ++msgctxt "#13493" ++msgid "No limit / 1080p (>30hz)" ++msgstr "" ++ ++#empty strings from id 13494 to 13504 + + #: system/settings/settings.xml + msgctxt "#13505" +diff --git a/system/settings/gbm.xml b/system/settings/gbm.xml +index c5e4d98e0bef..830576c156a6 100644 +--- a/system/settings/gbm.xml ++++ b/system/settings/gbm.xml +@@ -41,6 +41,21 @@ + + false + ++ ++ false ++ 3 ++ 0 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + 3 + false +diff --git a/xbmc/windowing/gbm/DRMUtils.cpp b/xbmc/windowing/gbm/DRMUtils.cpp +index fceaf770d363..21a6f8f1b926 100644 +--- a/xbmc/windowing/gbm/DRMUtils.cpp ++++ b/xbmc/windowing/gbm/DRMUtils.cpp +@@ -17,6 +17,8 @@ + #include + + #include "platform/linux/XTimeUtils.h" ++#include "settings/Settings.h" ++#include "settings/SettingsComponent.h" + #include "utils/log.h" + #include "utils/StringUtils.h" + #include "windowing/GraphicContext.h" +@@ -25,6 +27,8 @@ + + using namespace KODI::WINDOWING::GBM; + ++const std::string SETTING_VIDEOSCREEN_LIMITGUISIZE = "videoscreen.limitguisize"; ++ + CDRMUtils::CDRMUtils() + : m_connector(new connector) + , m_encoder(new encoder) +@@ -731,6 +735,30 @@ RESOLUTION_INFO CDRMUtils::GetResolutionInfo(drmModeModeInfoPtr mode) + res.iWidth = res.iScreenWidth; + res.iHeight = res.iScreenHeight; + ++ int limit = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(SETTING_VIDEOSCREEN_LIMITGUISIZE); ++ if (limit > 0 && res.iScreenWidth > 1920 && res.iScreenHeight > 1080) ++ { ++ switch (limit) ++ { ++ case 1: ++ res.iWidth = 1280; ++ res.iHeight = 720; ++ break; ++ case 2: ++ res.iWidth = mode->vrefresh > 30 ? 1280 : 1920; ++ res.iHeight = mode->vrefresh > 30 ? 720 : 1080; ++ break; ++ case 3: ++ res.iWidth = 1920; ++ res.iHeight = 1080; ++ break; ++ case 4: ++ res.iWidth = mode->vrefresh > 30 ? 1920 : res.iScreenWidth; ++ res.iHeight = mode->vrefresh > 30 ? 1080 : res.iScreenHeight; ++ break; ++ } ++ } ++ + if (mode->clock % 5 != 0) + res.fRefreshRate = static_cast(mode->vrefresh) * (1000.0f/1001.0f); + else From ecd87898a57040c2d477933e5f1c04250ae283da Mon Sep 17 00:00:00 2001 From: chewitt Date: Sat, 20 Apr 2019 22:02:39 +0000 Subject: [PATCH 17/21] busybox: add dtsoc helper script --- packages/sysutils/busybox/package.mk | 1 + packages/sysutils/busybox/scripts/dtsoc | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100755 packages/sysutils/busybox/scripts/dtsoc diff --git a/packages/sysutils/busybox/package.mk b/packages/sysutils/busybox/package.mk index 48b2cfe232..79239064f3 100644 --- a/packages/sysutils/busybox/package.mk +++ b/packages/sysutils/busybox/package.mk @@ -126,6 +126,7 @@ makeinstall_target() { cp $PKG_DIR/scripts/createlog $INSTALL/usr/bin/ cp $PKG_DIR/scripts/dtfile $INSTALL/usr/bin cp $PKG_DIR/scripts/dtname $INSTALL/usr/bin + cp $PKG_DIR/scripts/dtsoc $INSTALL/usr/bin cp $PKG_DIR/scripts/lsb_release $INSTALL/usr/bin/ cp $PKG_DIR/scripts/apt-get $INSTALL/usr/bin/ cp $PKG_DIR/scripts/sudo $INSTALL/usr/bin/ diff --git a/packages/sysutils/busybox/scripts/dtsoc b/packages/sysutils/busybox/scripts/dtsoc new file mode 100755 index 0000000000..f853e10158 --- /dev/null +++ b/packages/sysutils/busybox/scripts/dtsoc @@ -0,0 +1,11 @@ +#!/bin/bash + +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) + +COMPATIBLE=$(cat /proc/device-tree/compatible 2>/dev/null | tr -d '\000' | sed -n -e 's/.*\(allwinner\|amlogic\|rockchip\).*/\1/p') + +if [ -n "$COMPATIBLE" ]; then + DTNAME=$(cat /proc/device-tree/compatible | cut -f1,2 -d',' | tail -n 1) + echo "$DTNAME" +fi From 7a8b27fbcc5690d9d1b8ec7cb5a6879f86d109d1 Mon Sep 17 00:00:00 2001 From: kszaq Date: Tue, 28 May 2019 00:32:07 +0200 Subject: [PATCH 18/21] mesa: use mesa master if device uses Lima or Panfrost --- packages/graphics/mesa/package.mk | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/graphics/mesa/package.mk b/packages/graphics/mesa/package.mk index 7e334fa639..2dc9c56a32 100644 --- a/packages/graphics/mesa/package.mk +++ b/packages/graphics/mesa/package.mk @@ -13,6 +13,12 @@ PKG_LONGDESC="Mesa is a 3-D graphics library with an API." PKG_TOOLCHAIN="meson" PKG_BUILD_FLAGS="+lto" +if listcontains "${GRAPHIC_DRIVERS}" "(lima|panfrost)"; then + PKG_VERSION="659aa3dd6519f64379e91ca97fe184434fd7fdee" # master-19.2 + PKG_SHA256="7152dd8c780e47c4e5e18ebaa47fd4f8fe116b43012affda2f964ae23b324d34" + PKG_URL="https://gitlab.freedesktop.org/mesa/mesa/-/archive/$PKG_VERSION/mesa-$PKG_VERSION.tar.gz" +fi + get_graphicdrivers PKG_MESON_OPTS_TARGET="-Ddri-drivers=${DRI_DRIVERS// /,} \ @@ -90,6 +96,21 @@ pre_configure_target() { if [ "$DISPLAYSERVER" = "x11" ]; then export LIBS="-lxcb-dri3 -lxcb-dri2 -lxcb-xfixes -lxcb-present -lxcb-sync -lxshmfence -lz" fi + + # Temporary hack (until panfrost evolves) to use 64-bit pointers in structs passed to GPU + # even if userspace is 32-bit. This is required for Mali-T8xx to work with mesa built for + # arm userspace. The hack does not affect building for aarch64. + if [[ "${MALI_FAMILY}" = *t8* ]]; then + ( + cd "$PKG_BUILD/src/gallium/drivers/panfrost" + sed -i 's/uintptr_t/uint64_t/g' include/panfrost-job.h \ + include/panfrost-misc.h \ + pan_context.c \ + pandecode/decode.c + + find -type f -exec sed -i 's/ndef __LP64__/ 0/g; s/def __LP64__/ 1/g' {} +; + ) + fi } post_makeinstall_target() { From 38c8a0915f526c92637ba64f560af8c479bdbf6d Mon Sep 17 00:00:00 2001 From: chewitt Date: Sun, 21 Apr 2019 05:56:06 +0000 Subject: [PATCH 19/21] v4l-utils: disable multimap if device tree map is present --- packages/sysutils/v4l-utils/package.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sysutils/v4l-utils/package.mk b/packages/sysutils/v4l-utils/package.mk index 84495dfe29..10e967b077 100644 --- a/packages/sysutils/v4l-utils/package.mk +++ b/packages/sysutils/v4l-utils/package.mk @@ -99,7 +99,7 @@ post_makeinstall_target() { # table for Xbox DVD Playback Kit * rc-xbox-dvd xbox_dvd # multi-table for amlogic devices -meson-ir * libreelec_multi +meson-ir rc-empty libreelec_multi EOF fi From 847be426c7b6588098f508515d49610b08d5c54b Mon Sep 17 00:00:00 2001 From: kszaq Date: Tue, 7 May 2019 21:32:33 +0200 Subject: [PATCH 20/21] project: add linux patchset --- projects/Amlogic/patches/linux/README.md | 11 + .../Amlogic/patches/linux/a-meson-integ.patch | 47535 ++++++++++++++++ .../patches/linux/c-hdmi-audio-and-cec.patch | 1150 + .../e-0001-HACK-set-cma-pool-to-896MB.patch | 28 + ...ACK-fix-Kodi-sysinfo-CPU-information.patch | 31 + ...-silence-meson-ir-warn-once-log-spam.patch | 29 + ...e-0005-HACK-silence-hrtimer-log-spam.patch | 28 + ...Bluetooth-Fix-spurious-error-message.patch | 37 + ...gxbb-vega-s95-update-dtsi-with-many-.patch | 255 + ...son-gxbb-wetek.dtsi-enable-bluetooth.patch | 50 + ...n-gxbb-wetek.dtsi-enable-saradc-node.patch | 43 + ...meson-gxbb-odroid-set-blue-led-to-on.patch | 30 + ...-gxbb-odroid-set-rc-odroid-ir-keymap.patch | 25 + ...gxbb-vega-s95-set-rc-vega-s95-ir-key.patch | 26 + ...gxbb-wetek-hub-set-rc-wetek-hub-ir-k.patch | 26 + ...gxbb-wetek-play2-set-rc-wetek-play2-.patch | 26 + ...gxl-s905x-khadas-vim-use-rc-khadas-r.patch | 34 + ...gxl-s905x-khadas-vim-fix-address-siz.patch | 33 + ...gxl-s905w-tx3-mini-set-rc-tx3mini-ir.patch | 26 + ...gxm-khadas-vim2-set-eee-broken-1000t.patch | 25 + ...gxm-khadas-vim2-fix-address-size-cel.patch | 33 + ...on-gxm-khadas-vim2-set-bt-compatible.patch | 33 + ...gxm-vega-s96-set-rc-vega-s95-ir-keym.patch | 31 + ...-keymap-for-HardKernel-ODROID-remote.patch | 100 + ...dd-keymap-for-Khadas-VIM-EDGE-remote.patch | 111 + ...dia-rc-add-keymap-for-KHAMSIN-remote.patch | 100 + ...-add-keymap-for-Philips-RC242-remote.patch | 141 + ...add-keymap-for-Tanix-TX3-mini-remote.patch | 128 + ...a-rc-add-keymap-for-WeTek-Hub-remote.patch | 104 + ...c-add-keymap-for-WeTeK-Play-2-remote.patch | 141 + ...SoC-meson-correct-i2s-error-messages.patch | 35 + ...-Add-vendor-prefix-for-SmartLabs-LLC.patch | 28 + ...amlogic-Add-support-for-the-SmartLab.patch | 44 + ...gxl-Add-support-for-the-SmartLabs-SM.patch | 334 + ...gx-add-ATF-BL32-reserved-memory-regi.patch | 36 + ...keymap-for-Amediatech-X96-MAX-remote.patch | 134 + ...g12b-odroid-n2-add-rc-odroid-ir-keym.patch | 25 + ...g12a-x96-max-add-rc-x96max-ir-keymap.patch | 25 + ...-dts-add-meson-g12a-x96-max-rmii-dts.patch | 332 + 39 files changed, 51363 insertions(+) create mode 100644 projects/Amlogic/patches/linux/README.md create mode 100644 projects/Amlogic/patches/linux/a-meson-integ.patch create mode 100644 projects/Amlogic/patches/linux/c-hdmi-audio-and-cec.patch create mode 100644 projects/Amlogic/patches/linux/e-0001-HACK-set-cma-pool-to-896MB.patch create mode 100644 projects/Amlogic/patches/linux/e-0002-HACK-fix-Kodi-sysinfo-CPU-information.patch create mode 100644 projects/Amlogic/patches/linux/e-0004-HACK-silence-meson-ir-warn-once-log-spam.patch create mode 100644 projects/Amlogic/patches/linux/e-0005-HACK-silence-hrtimer-log-spam.patch create mode 100644 projects/Amlogic/patches/linux/e-0006-HACK-Bluetooth-Fix-spurious-error-message.patch create mode 100644 projects/Amlogic/patches/linux/e-0011-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-many-.patch create mode 100644 projects/Amlogic/patches/linux/e-0012-arm64-dts-meson-gxbb-wetek.dtsi-enable-bluetooth.patch create mode 100644 projects/Amlogic/patches/linux/e-0013-arm64-dts-meson-gxbb-wetek.dtsi-enable-saradc-node.patch create mode 100644 projects/Amlogic/patches/linux/e-0015-arm64-dts-meson-gxbb-odroid-set-blue-led-to-on.patch create mode 100644 projects/Amlogic/patches/linux/e-0016-arm64-dts-meson-gxbb-odroid-set-rc-odroid-ir-keymap.patch create mode 100644 projects/Amlogic/patches/linux/e-0017-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir-key.patch create mode 100644 projects/Amlogic/patches/linux/e-0018-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-hub-ir-k.patch create mode 100644 projects/Amlogic/patches/linux/e-0019-arm64-dts-meson-gxbb-wetek-play2-set-rc-wetek-play2-.patch create mode 100644 projects/Amlogic/patches/linux/e-0020-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-khadas-r.patch create mode 100644 projects/Amlogic/patches/linux/e-0021-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address-siz.patch create mode 100644 projects/Amlogic/patches/linux/e-0022-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx3mini-ir.patch create mode 100644 projects/Amlogic/patches/linux/e-0023-arm64-dts-meson-gxm-khadas-vim2-set-eee-broken-1000t.patch create mode 100644 projects/Amlogic/patches/linux/e-0024-arm64-dts-meson-gxm-khadas-vim2-fix-address-size-cel.patch create mode 100644 projects/Amlogic/patches/linux/e-0025-arm64-dts-meson-gxm-khadas-vim2-set-bt-compatible.patch create mode 100644 projects/Amlogic/patches/linux/e-0026-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-keym.patch create mode 100644 projects/Amlogic/patches/linux/e-0027-media-rc-add-keymap-for-HardKernel-ODROID-remote.patch create mode 100644 projects/Amlogic/patches/linux/e-0028-media-rc-add-keymap-for-Khadas-VIM-EDGE-remote.patch create mode 100644 projects/Amlogic/patches/linux/e-0029-media-rc-add-keymap-for-KHAMSIN-remote.patch create mode 100644 projects/Amlogic/patches/linux/e-0030-media-rc-add-keymap-for-Philips-RC242-remote.patch create mode 100644 projects/Amlogic/patches/linux/e-0031-media-rc-add-keymap-for-Tanix-TX3-mini-remote.patch create mode 100644 projects/Amlogic/patches/linux/e-0032-media-rc-add-keymap-for-WeTek-Hub-remote.patch create mode 100644 projects/Amlogic/patches/linux/e-0033-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch create mode 100644 projects/Amlogic/patches/linux/e-0034-ASoC-meson-correct-i2s-error-messages.patch create mode 100644 projects/Amlogic/patches/linux/e-0035-dt-bindings-Add-vendor-prefix-for-SmartLabs-LLC.patch create mode 100644 projects/Amlogic/patches/linux/e-0036-dt-bindings-arm-amlogic-Add-support-for-the-SmartLab.patch create mode 100644 projects/Amlogic/patches/linux/e-0037-ARM64-dts-meson-gxl-Add-support-for-the-SmartLabs-SM.patch create mode 100644 projects/Amlogic/patches/linux/f-0001-ARM64-dts-meson-gx-add-ATF-BL32-reserved-memory-regi.patch create mode 100644 projects/Amlogic/patches/linux/f-0002-media-rc-add-keymap-for-Amediatech-X96-MAX-remote.patch create mode 100644 projects/Amlogic/patches/linux/f-0003-arm64-dts-meson-g12b-odroid-n2-add-rc-odroid-ir-keym.patch create mode 100644 projects/Amlogic/patches/linux/f-0004-arm64-dts-meson-g12a-x96-max-add-rc-x96max-ir-keymap.patch create mode 100644 projects/Amlogic/patches/linux/f-0005-arm64-dts-add-meson-g12a-x96-max-rmii-dts.patch diff --git a/projects/Amlogic/patches/linux/README.md b/projects/Amlogic/patches/linux/README.md new file mode 100644 index 0000000000..f300c25f23 --- /dev/null +++ b/projects/Amlogic/patches/linux/README.md @@ -0,0 +1,11 @@ +### A + +https://github.com/torvalds/linux/compare/v5.1...superna9999:linux-5.1-le-amlogic-v2.patch + +### C +** from rockchip-5.1-patches-for-libreelec-v5.1 branch, remove 09/16 ** + +https://github.com/Kwiboo/linux-rockchip/compare/43e542a1432b200f589e589320a885b5640d1f45...d6b6f0ca3df105f4d84b7cbaca8e5a3cfbf2ad42 + +### E-F +** misc patches to go upstream ** diff --git a/projects/Amlogic/patches/linux/a-meson-integ.patch b/projects/Amlogic/patches/linux/a-meson-integ.patch new file mode 100644 index 0000000000..fb543745af --- /dev/null +++ b/projects/Amlogic/patches/linux/a-meson-integ.patch @@ -0,0 +1,47535 @@ +From 57a9585034000d61b241d87855d6895011da9b2c Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 12 Feb 2019 15:02:58 +0100 +Subject: [PATCH 001/249] FROMGIT: vendor-prefixes: Add prefix for Shenzhen SEI + Robotics Co., Ltd + +Add vendor prefix for the Shenzhen SEI Robotics Co., Ltd, a chinese ODM +specialized in Android TV HDMI Stick, OTT Box, Hybrid STB, +Smart Home Gateway & more. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 6917de8a6c4d05737dded7053a66be3c7e6779c2 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +Signed-off-by: Neil Armstrong +--- + Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt +index 8162b0eb4b506..bb6f6e8a2eeea 100644 +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -353,6 +353,7 @@ sandisk Sandisk Corporation + sbs Smart Battery System + schindler Schindler + seagate Seagate Technology PLC ++seirobotics Shenzhen SEI Robotics Co., Ltd + semtech Semtech Corporation + sensirion Sensirion AG + sff Small Form Factor Committee + +From 7732905e42684a6214ddde58f9eb6f5d0975faae Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 12 Feb 2019 15:02:59 +0100 +Subject: [PATCH 002/249] FROMGIT: arm64: dts: Add SEI Robotics SEI510 Board + +The SEI Robotics SEI510 Board is based on the Amlogic G12A S905X2 +and has the following features : +- Amlogic G12A S905X2 SoC +- 10/100 Ethernet +- USB2 + USB3 ports +- Micro SDCard Port +- Audio + CVBS AV Jack port +- HDMI 2.1 + CEC Port +- ADC Touch Button +- Far-Field Microphone Array + Mono HP +- IR Sensor +- IR Emmiter LED Array +- RGB Led + +Signed-off-by: Neil Armstrong +[khilman: sorted Makefile entry alphabetcially] +Signed-off-by: Kevin Hilman +(cherry picked from commit b7be144932a8376fbb886115ce908a1a1818940b + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +Signed-off-by: Neil Armstrong +--- + .../devicetree/bindings/arm/amlogic.txt | 1 + + arch/arm64/boot/dts/amlogic/Makefile | 1 + + .../boot/dts/amlogic/meson-g12a-sei510.dts | 38 +++++++++++++++++++ + 3 files changed, 40 insertions(+) + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt +index 7f40cb5f490bd..061f7b98a07f1 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.txt ++++ b/Documentation/devicetree/bindings/arm/amlogic.txt +@@ -110,6 +110,7 @@ Board compatible values (alphabetically, grouped by SoC): + + - "amlogic,u200" (Meson g12a s905d2) + - "amediatech,x96-max" (Meson g12a s905x2) ++ - "seirobotics,sei510" (Meson g12a s905x2) + + Amlogic Meson Firmware registers Interface + ------------------------------------------ +diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile +index 0821fed4c0749..e129c03ced140 100644 +--- a/arch/arm64/boot/dts/amlogic/Makefile ++++ b/arch/arm64/boot/dts/amlogic/Makefile +@@ -1,5 +1,6 @@ + # 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-gxbb-nanopi-k2.dtb +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +new file mode 100644 +index 0000000000000..6a7c3241862af +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre SAS. All rights reserved. ++ */ ++ ++/dts-v1/; ++ ++#include "meson-g12a.dtsi" ++ ++/ { ++ compatible = "seirobotics,sei510", "amlogic,g12a"; ++ model = "SEI Robotics SEI510"; ++ ++ aliases { ++ serial0 = &uart_AO; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x40000000>; ++ }; ++ ++ reserved-memory { ++ /* TEE Reserved Memory */ ++ bl32_reserved: bl32@5000000 { ++ reg = <0x0 0x05300000 0x0 0x2000000>; ++ no-map; ++ }; ++ }; ++}; ++ ++&uart_AO { ++ status = "okay"; ++}; + +From 4d4ca52f504bb200ff243b8a945f7da066a0d028 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 7 Mar 2019 15:01:47 +0100 +Subject: [PATCH 003/249] FROMGIT: arm64: dts: meson-g12a: Add AO Secure node + +This adds the Always-On ao-secure system control registers node, +which is used by the meson-gx-socinfo driver to detect the SoC IDs. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 0fa724c51e31cc814af9e44c019fb4d570422b02 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 17c6217f8a849..31ddf9444b3e3 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -122,6 +122,12 @@ + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>; + ++ sec_AO: ao-secure@140 { ++ compatible = "amlogic,meson-gx-ao-secure", "syscon"; ++ reg = <0x0 0x140 0x0 0x140>; ++ amlogic,has-chip-id; ++ }; ++ + uart_AO: serial@3000 { + compatible = "amlogic,meson-gx-uart", + "amlogic,meson-ao-uart"; + +From caa45a70bd62537de06587db18fa4b805cd06079 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 15 Mar 2019 14:42:43 +0100 +Subject: [PATCH 004/249] FROMGIT: arm64: dts: meson: g12a: add secure monitor + +Add the interface to the secure monitor on g12a + +Signed-off-by: Jerome Brunet +Signed-off-by: Kevin Hilman +(cherry picked from commit bd39515284120fc806fd0bea86fecd39908e18dc + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 31ddf9444b3e3..92ee8c895ba68 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -72,6 +72,10 @@ + }; + }; + ++ sm: secure-monitor { ++ compatible = "amlogic,meson-gxbb-sm"; ++ }; ++ + soc { + compatible = "simple-bus"; + #address-cells = <2>; + +From 345369aee7b3c60ee88a835362ca5d09cc5de6fe Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 15 Mar 2019 14:42:44 +0100 +Subject: [PATCH 005/249] FROMGIT: arm64: dts: meson: g12a: add efuse + +Add the g12a SoC efuse device + +Signed-off-by: Jerome Brunet +Signed-off-by: Kevin Hilman +(cherry picked from commit 965c827ac37e71f76d3ac55c75ac08909f2a4eed + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 92ee8c895ba68..dcc821cf35bb8 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -4,6 +4,7 @@ + */ + + #include ++#include + #include + #include + +@@ -55,6 +56,14 @@ + }; + }; + ++ efuse: efuse { ++ compatible = "amlogic,meson-gxbb-efuse"; ++ clocks = <&clkc CLKID_EFUSE>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ read-only; ++ }; ++ + psci { + compatible = "arm,psci-1.0"; + method = "smc"; + +From cca0a2b4f97728bf46ab8d3c95c4c29f1f4f9c34 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 18 Mar 2019 10:58:44 +0100 +Subject: [PATCH 006/249] FROMGIT: arm64: dts: meson: g12a: Add AO Clock + + Reset Controller support + +Add nodes and properties for the AO Clocks and Resets. + +Signed-off-by: Neil Armstrong +Signed-off-by: Jerome Brunet +Signed-off-by: Kevin Hilman +(cherry picked from commit b019f4a4199f865b054262ff78f606ca70f7b981 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index dcc821cf35bb8..abfa167751afc 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -135,6 +135,23 @@ + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xff800000 0x0 0x100000>; + ++ rti: sys-ctrl@0 { ++ compatible = "amlogic,meson-gx-ao-sysctrl", ++ "simple-mfd", "syscon"; ++ reg = <0x0 0x0 0x0 0x100>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x0 0x0 0x100>; ++ ++ clkc_AO: clock-controller { ++ compatible = "amlogic,meson-g12a-aoclkc"; ++ #clock-cells = <1>; ++ #reset-cells = <1>; ++ clocks = <&xtal>, <&clkc CLKID_CLK81>; ++ clock-names = "xtal", "mpeg-clk"; ++ }; ++ }; ++ + sec_AO: ao-secure@140 { + compatible = "amlogic,meson-gx-ao-secure", "syscon"; + reg = <0x0 0x140 0x0 0x140>; + +From e93e552de459029885814f21f55bb428d429ec0d Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 18 Mar 2019 10:58:45 +0100 +Subject: [PATCH 007/249] FROMGIT: arm64: dts: meson: g12a: add pinctrl support + controllers + +Add the peripheral and always-on pinctrl controllers to the g12a soc. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 11a7bea17c9e0a36daab934d83e15a760f402147 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 42 +++++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index abfa167751afc..5e07e4ca3f4bb 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -104,6 +104,29 @@ + #address-cells = <2>; + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0x34400 0x0 0x400>; ++ ++ periphs_pinctrl: pinctrl@40 { ++ compatible = "amlogic,meson-g12a-periphs-pinctrl"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gpio: bank@40 { ++ reg = <0x0 0x40 0x0 0x4c>, ++ <0x0 0xe8 0x0 0x18>, ++ <0x0 0x120 0x0 0x18>, ++ <0x0 0x2c0 0x0 0x40>, ++ <0x0 0x340 0x0 0x1c>; ++ reg-names = "gpio", ++ "pull", ++ "pull-enable", ++ "mux", ++ "ds"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&periphs_pinctrl 0 0 86>; ++ }; ++ }; + }; + + hiu: bus@3c000 { +@@ -150,6 +173,25 @@ + clocks = <&xtal>, <&clkc CLKID_CLK81>; + clock-names = "xtal", "mpeg-clk"; + }; ++ ++ ao_pinctrl: pinctrl@14 { ++ compatible = "amlogic,meson-g12a-aobus-pinctrl"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ gpio_ao: bank@14 { ++ reg = <0x0 0x14 0x0 0x8>, ++ <0x0 0x1c 0x0 0x8>, ++ <0x0 0x24 0x0 0x14>; ++ reg-names = "mux", ++ "ds", ++ "gpio"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-ranges = <&ao_pinctrl 0 0 15>; ++ }; ++ }; + }; + + sec_AO: ao-secure@140 { + +From c1204940694189c11ec4de20a4201666ce9603df Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 18 Mar 2019 10:58:46 +0100 +Subject: [PATCH 008/249] FROMGIT: arm64: dts: meson: g12a: add uart_ao_a + pinctrl + +Add the always on UART pinctrl setting to the g12a soc DT. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit e92546c226ec16005994d2798c8ad6470bcda1b1 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 5e07e4ca3f4bb..3784b94c5df7d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -191,6 +191,24 @@ + #gpio-cells = <2>; + gpio-ranges = <&ao_pinctrl 0 0 15>; + }; ++ ++ uart_ao_a_pins: uart-a-ao { ++ mux { ++ groups = "uart_ao_a_tx", ++ "uart_ao_a_rx"; ++ function = "uart_ao_a"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_ao_a_cts_rts_pins: uart-ao-a-cts-rts { ++ mux { ++ groups = "uart_ao_a_cts", ++ "uart_ao_a_rts"; ++ function = "uart_ao_a"; ++ bias-disable; ++ }; ++ }; + }; + }; + + +From 969c73356f29fa0f0d004ddb51e89a5ad65aa32a Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 18 Mar 2019 10:58:47 +0100 +Subject: [PATCH 009/249] FROMGIT: arm64: dts: meson: g12a: add reset + controller + +Add the reset controller device of g12a SoC family + +Signed-off-by: Jerome Brunet +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 7ab41c4741253f8f33a1af60b9839cfcd62ee455 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 3784b94c5df7d..1d3e5083c4411 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -259,6 +259,13 @@ + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xffd00000 0x0 0x100000>; + ++ reset: reset-controller@1004 { ++ compatible = "amlogic,meson-g12a-reset", ++ "amlogic,meson-axg-reset"; ++ reg = <0x0 0x1004 0x0 0x9c>; ++ #reset-cells = <1>; ++ }; ++ + clk_msr: clock-measure@18000 { + compatible = "amlogic,meson-g12a-clk-measure"; + reg = <0x0 0x18000 0x0 0x10>; + +From 5da88cae989eae6e3d9844d466db673304068857 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 18 Mar 2019 10:58:48 +0100 +Subject: [PATCH 010/249] FROMGIT: arm64: dts: meson: g12a: Add UART A, B & C + nodes and pins + +This patch adds the 3 UART nodes in the EE power domain with the corresponding +pinctrl nodes. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit ff4f8b6cab5885ebc2c6b21fd058db8544e2eebb + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 72 +++++++++++++++++++++ + 1 file changed, 72 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 1d3e5083c4411..4d04742b05c2c 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -126,6 +126,51 @@ + #gpio-cells = <2>; + gpio-ranges = <&periphs_pinctrl 0 0 86>; + }; ++ ++ uart_a_pins: uart-a { ++ mux { ++ groups = "uart_a_tx", ++ "uart_a_rx"; ++ function = "uart_a"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_a_cts_rts_pins: uart-a-cts-rts { ++ mux { ++ groups = "uart_a_cts", ++ "uart_a_rts"; ++ function = "uart_a"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_b_pins: uart-b { ++ mux { ++ groups = "uart_b_tx", ++ "uart_b_rx"; ++ function = "uart_b"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_c_pins: uart-c { ++ mux { ++ groups = "uart_c_tx", ++ "uart_c_rx"; ++ function = "uart_c"; ++ bias-disable; ++ }; ++ }; ++ ++ uart_c_cts_rts_pins: uart-c-cts-rts { ++ mux { ++ groups = "uart_c_cts", ++ "uart_c_rts"; ++ function = "uart_c"; ++ bias-disable; ++ }; ++ }; + }; + }; + +@@ -270,6 +315,33 @@ + compatible = "amlogic,meson-g12a-clk-measure"; + reg = <0x0 0x18000 0x0 0x10>; + }; ++ ++ uart_C: serial@22000 { ++ compatible = "amlogic,meson-gx-uart"; ++ reg = <0x0 0x22000 0x0 0x18>; ++ interrupts = ; ++ clocks = <&xtal>, <&clkc CLKID_UART2>, <&xtal>; ++ clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; ++ }; ++ ++ uart_B: serial@23000 { ++ compatible = "amlogic,meson-gx-uart"; ++ reg = <0x0 0x23000 0x0 0x18>; ++ interrupts = ; ++ clocks = <&xtal>, <&clkc CLKID_UART1>, <&xtal>; ++ clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; ++ }; ++ ++ uart_A: serial@24000 { ++ compatible = "amlogic,meson-gx-uart"; ++ reg = <0x0 0x24000 0x0 0x18>; ++ interrupts = ; ++ clocks = <&xtal>, <&clkc CLKID_UART0>, <&xtal>; ++ clock-names = "xtal", "pclk", "baud"; ++ status = "disabled"; ++ }; + }; + }; + + +From 83acbbf7e77041d36765a2900074ebafe8282aed Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 18 Mar 2019 11:04:48 +0100 +Subject: [PATCH 011/249] FROMGIT: arm64: dts: meson-g12a-u200: add uart_AO + pinctrl + +Add pinctrl on the always-enabled debug UART AO. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 638914212ace84264accaa41578cf80a18797d91 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index c44dbdddf2cf6..f2afd0bf3e28b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -25,5 +25,7 @@ + + &uart_AO { + status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; + }; + + +From bc35401805db14683fc99a8954c51ce7bc6db8f1 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 18 Mar 2019 11:04:49 +0100 +Subject: [PATCH 012/249] FROMGIT: arm64: dts: meson-g12a-sei510: add uart_AO + pinctrl + +Add pinctrl on the always-enabled debug UART AO. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 51d215c14341a1e769828f9f1ff14f95c7ad35e3 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 6a7c3241862af..63c515fe49966 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -35,4 +35,6 @@ + + &uart_AO { + status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; + }; + +From 292328f856c04b213d9cf7d5ec3fdc70f8245cb9 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 18 Mar 2019 11:04:50 +0100 +Subject: [PATCH 013/249] FROMGIT: arm64: dts: meson-g12a-x96-max: add uart_AO + pinctrl + +Add pinctrl on the always-enabled debug UART AO. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 0b7aed337ff0f4ff82c3d920a9d022a34c246b6f + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index c62d3d5706ff1..0edbd00b358fd 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -25,4 +25,6 @@ + + &uart_AO { + status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; + }; + +From e5d7028bff190d70d74bcf372d2bdb7f9abf7d2d Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 18 Mar 2019 11:04:52 +0100 +Subject: [PATCH 014/249] FROMGIT: arm64: dts: meson-g12a-sei510: add + regulators + +Add some regulators. Still missing +* VDD_EE (0.8V - PWM controlled) +* VDD_CPU(PWM controlled) +* VDDQ1_5 + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +Acked-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 2297c33c19af6a90a03c5144836c2a088e74c7b3 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 57 +++++++++++++++++++ + 1 file changed, 57 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 63c515fe49966..43d57e20294a0 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -6,6 +6,8 @@ + /dts-v1/; + + #include "meson-g12a.dtsi" ++#include ++#include + + / { + compatible = "seirobotics,sei510", "amlogic,g12a"; +@@ -15,10 +17,36 @@ + serial0 = &uart_AO; + }; + ++ ao_5v: regulator-ao_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "AO_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&dc_in>; ++ regulator-always-on; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; + ++ dc_in: regulator-dc_in { ++ compatible = "regulator-fixed"; ++ regulator-name = "DC_IN"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ emmc_1v8: regulator-emmc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "EMMC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ }; ++ + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; +@@ -31,6 +59,35 @@ + no-map; + }; + }; ++ ++ 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_3v3_t: regultor-vddao_3v3_t { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_3V3_T"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vddao_3v3>; ++ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; ++ enable-active-high; ++ }; ++ ++ vddio_ao1v8: regulator-vddio_ao1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_AO1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ }; ++ + }; + + &uart_AO { + +From 5c6544d93c8f1a0ba0d074e01881d584b010c2f7 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Mon, 25 Mar 2019 11:14:48 +0100 +Subject: [PATCH 015/249] FROMGIT: arm64: dts: meson-g12a-x96-max: add + regulators + +Add system regulators for the X96 Max Set-Top-Box. + +Still missing +* VDD_EE (0.8V - PWM controlled) +* VDD_CPU (PWM controlled) + +Signed-off-by: Guillaume La Roque +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit c9206b42ccbe339e1c72481cf9fefd3b26d79345 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + .../boot/dts/amlogic/meson-g12a-x96-max.dts | 67 +++++++++++++++++++ + 1 file changed, 67 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 0edbd00b358fd..0ba28491e2b0b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -6,6 +6,8 @@ + /dts-v1/; + + #include "meson-g12a.dtsi" ++#include ++#include + + / { + compatible = "amediatech,x96-max", "amlogic,u200", "amlogic,g12a"; +@@ -21,6 +23,71 @@ + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; + }; ++ ++ flash_1v8: regulator-flash_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "FLASH_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ dc_in: regulator-dc_in { ++ compatible = "regulator-fixed"; ++ regulator-name = "DC_IN"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vcc_1v8: regulator-vcc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ /* FIXME: actually controlled by VDDCPU_B_EN */ ++ }; ++ ++ vcc_5v: regulator-vcc_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&dc_in>; ++ ++ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; ++ enable-active-low; ++ }; ++ ++ 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; ++ }; ++ ++ 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; ++ }; + }; + + &uart_AO { + +From 36fe8d6ff81eb295457b58a57cd39a8816d8a278 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 11:14:49 +0100 +Subject: [PATCH 016/249] FROMGIT: arm64: dts: meson-g12a-x96-max: Enable BT + Module + +Enable the Bluetooth Module on the X96 Max Set-Top-Box. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit c5c9c7cff2692d75a24761b081d717a78ad535c8 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 0ba28491e2b0b..0a6919523ba94 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -90,6 +90,18 @@ + }; + }; + ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + +From f278831ec5fc28f19d1f00370d6b2ff91818a9f9 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 27 Mar 2019 11:21:57 +0100 +Subject: [PATCH 017/249] FROMGIT: arm64: dts: meson-g12a: Add CMA reserved + memory + +In order to handle Video Output and later on Video decoding, +add a reserved CMA pool with a similar 256MiB size as other SoCs. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit e2cffeb398f4830b004774444809ee256b9bc653 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 4d04742b05c2c..d6ca0bbd8f74a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -79,6 +79,14 @@ + reg = <0x0 0x05000000 0x0 0x300000>; + no-map; + }; ++ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; ++ size = <0x0 0x10000000>; ++ alignment = <0x0 0x400000>; ++ linux,cma-default; ++ }; + }; + + sm: secure-monitor { + +From 2de04645e134d5c2456144677f065b56e90a3991 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 7 Mar 2019 15:01:45 +0100 +Subject: [PATCH 018/249] FROMGIT: soc: amlogic: gx-socinfo: Add mask for each + SoC packages + +When updated IDs on f842c41adc04 ("amlogic: meson-gx-socinfo: Update soc ids") +we introduced packages ids using the full 8bit value, but in the function +socinfo_to_package_id() the id was filtered with the 0xf0 mask. + +While the 0xf0 mask is valid for most board, it filters out the lower +4 bits which encodes some characteristics of the chip. + +This patch moves the mask into the meson_gx_package_id table to be applied +on each package name independently and add the correct mask for some +specific entries. + +An example is the S905, in the vendor code the S905 is package_id +different from 0x20, and S905M is exactly 0x20. + +Another example are the The Wetek Hub & Play2 boards using a S905-H +variant, which is the S905 SoC with some licence bits enabled. +These licence bits are encoded in the lower 4bits, so to detect +the -H variant, we must detect the id == 0x3 with the 0xf mask. + +Fixes: f842c41adc04 ("amlogic: meson-gx-socinfo: Update soc ids") +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit dce47aed20c7de3ee2011b7a63e67f08e9dcfb5e + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) +--- + drivers/soc/amlogic/meson-gx-socinfo.c | 32 ++++++++++++++------------ + 1 file changed, 17 insertions(+), 15 deletions(-) + +diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c +index 37ea0a1c24c82..1ae339f5eadbd 100644 +--- a/drivers/soc/amlogic/meson-gx-socinfo.c ++++ b/drivers/soc/amlogic/meson-gx-socinfo.c +@@ -43,20 +43,21 @@ static const struct meson_gx_package_id { + const char *name; + unsigned int major_id; + unsigned int pack_id; ++ unsigned int pack_mask; + } soc_packages[] = { +- { "S905", 0x1f, 0 }, +- { "S905H", 0x1f, 0x13 }, +- { "S905M", 0x1f, 0x20 }, +- { "S905D", 0x21, 0 }, +- { "S905X", 0x21, 0x80 }, +- { "S905W", 0x21, 0xa0 }, +- { "S905L", 0x21, 0xc0 }, +- { "S905M2", 0x21, 0xe0 }, +- { "S912", 0x22, 0 }, +- { "962X", 0x24, 0x10 }, +- { "962E", 0x24, 0x20 }, +- { "A113X", 0x25, 0x37 }, +- { "A113D", 0x25, 0x22 }, ++ { "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */ ++ { "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */ ++ { "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */ ++ { "S905D", 0x21, 0, 0xf0 }, ++ { "S905X", 0x21, 0x80, 0xf0 }, ++ { "S905W", 0x21, 0xa0, 0xf0 }, ++ { "S905L", 0x21, 0xc0, 0xf0 }, ++ { "S905M2", 0x21, 0xe0, 0xf0 }, ++ { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */ ++ { "962X", 0x24, 0x10, 0xf0 }, ++ { "962E", 0x24, 0x20, 0xf0 }, ++ { "A113X", 0x25, 0x37, 0xff }, ++ { "A113D", 0x25, 0x22, 0xff }, + }; + + static inline unsigned int socinfo_to_major(u32 socinfo) +@@ -81,13 +82,14 @@ static inline unsigned int socinfo_to_misc(u32 socinfo) + + static const char *socinfo_to_package_id(u32 socinfo) + { +- unsigned int pack = socinfo_to_pack(socinfo) & 0xf0; ++ unsigned int pack = socinfo_to_pack(socinfo); + unsigned int major = socinfo_to_major(socinfo); + int i; + + for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) { + if (soc_packages[i].major_id == major && +- soc_packages[i].pack_id == pack) ++ soc_packages[i].pack_id == ++ (pack & soc_packages[i].pack_mask)) + return soc_packages[i].name; + } + + +From 0a8f350d721f0261d337b5ed8673066b90874372 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 7 Mar 2019 15:01:46 +0100 +Subject: [PATCH 019/249] FROMGIT: soc: amlogic: gx-socinfo: Add new SoC IDs + and Packages IDs + +This adds the: +- G12A SoC ID and S905X2, S905D2 package IDs, found booting the + X96 Max and U200 Reference Board +- G12B SoC ID and S922X package ID, found booting the Odroid-N2 +- S805X, S805Y package IDs found in the vendor U-Boot source + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 65f80df58eb770b2b687c35142c113d1ad6fa415 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) +--- + drivers/soc/amlogic/meson-gx-socinfo.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c +index 1ae339f5eadbd..c8d138d85f34b 100644 +--- a/drivers/soc/amlogic/meson-gx-socinfo.c ++++ b/drivers/soc/amlogic/meson-gx-socinfo.c +@@ -37,6 +37,8 @@ static const struct meson_gx_soc_id { + { "AXG", 0x25 }, + { "GXLX", 0x26 }, + { "TXHD", 0x27 }, ++ { "G12A", 0x28 }, ++ { "G12B", 0x29 }, + }; + + static const struct meson_gx_package_id { +@@ -53,11 +55,16 @@ static const struct meson_gx_package_id { + { "S905W", 0x21, 0xa0, 0xf0 }, + { "S905L", 0x21, 0xc0, 0xf0 }, + { "S905M2", 0x21, 0xe0, 0xf0 }, ++ { "S805X", 0x21, 0x30, 0xf0 }, ++ { "S805Y", 0x21, 0xb0, 0xf0 }, + { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */ + { "962X", 0x24, 0x10, 0xf0 }, + { "962E", 0x24, 0x20, 0xf0 }, + { "A113X", 0x25, 0x37, 0xff }, + { "A113D", 0x25, 0x22, 0xff }, ++ { "S905D2", 0x28, 0x10, 0xf0 }, ++ { "S905X2", 0x28, 0x40, 0xf0 }, ++ { "S922X", 0x29, 0x40, 0xf0 }, + }; + + static inline unsigned int socinfo_to_major(u32 socinfo) + +From 235e355fc478c0d52b745d843dd60255e51bdbfa Mon Sep 17 00:00:00 2001 +From: Julia Lawall +Date: Sat, 23 Feb 2019 14:20:40 +0100 +Subject: [PATCH 020/249] FROMGIT: meson-gx-socinfo: add missing of_node_put + after of_device_is_available + +Add an of_node_put when a tested device node is not available. + +The semantic patch that fixes this problem is as follows +(http://coccinelle.lip6.fr): + +// +@@ +identifier f; +local idexpression e; +expression x; +@@ + +e = f(...); +... when != of_node_put(e) + when != x = e + when != e = x + when any +if (<+...of_device_is_available(e)...+>) { + ... when != of_node_put(e) +( + return e; +| ++ of_node_put(e); + return ...; +) +} +// + +Fixes: a9daaba2965e8 ("soc: Add Amlogic SoC Information driver") +Signed-off-by: Julia Lawall +Signed-off-by: Kevin Hilman +(cherry picked from commit fdda0a6adc33536ad468f07db27325423703c5bc + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) +Signed-off-by: Neil Armstrong +--- + drivers/soc/amlogic/meson-gx-socinfo.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c +index c8d138d85f34b..bca34954518ec 100644 +--- a/drivers/soc/amlogic/meson-gx-socinfo.c ++++ b/drivers/soc/amlogic/meson-gx-socinfo.c +@@ -132,8 +132,10 @@ static int __init meson_gx_socinfo_init(void) + return -ENODEV; + + /* check if interface is enabled */ +- if (!of_device_is_available(np)) ++ if (!of_device_is_available(np)) { ++ of_node_put(np); + return -ENODEV; ++ } + + /* check if chip-id is available */ + if (!of_property_read_bool(np, "amlogic,has-chip-id")) + +From b3352f1172cce07aac6be6c6fbd7d966d5630687 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 4 Mar 2019 12:12:16 +0100 +Subject: [PATCH 021/249] FROMGIT: dt-bindings: iio: adc: document the Meson + G12A support + +Update the documentation to explicitly support the Meson-G12A SoC. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Jonathan Cameron +(cherry picked from commit a29b8657d322daef2b9fd3fd7c03f5f5bebfde86 + git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git iio-for-5.2a-2) +--- + .../devicetree/bindings/iio/adc/amlogic,meson-saradc.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt +index 75c7759541024..d57e9df25f4fa 100644 +--- a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt ++++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt +@@ -9,6 +9,7 @@ Required properties: + - "amlogic,meson-gxl-saradc" for GXL + - "amlogic,meson-gxm-saradc" for GXM + - "amlogic,meson-axg-saradc" for AXG ++ - "amlogic,meson-g12a-saradc" for AXG + along with the generic "amlogic,meson-saradc" + - reg: the physical base address and length of the registers + - interrupts: the interrupt indicating end of sampling + +From a7e431394ee50de7f4c3ee054d8d078511c914b0 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 4 Mar 2019 12:12:17 +0100 +Subject: [PATCH 022/249] FROMGIT: iio: adc: meson-saradc: add support for + Meson G12A + +Add the SAR ADC driver for the Amlogic Meson-G12A SoC. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Jonathan Cameron +(cherry picked from commit e415a1659ec9f04cda81875cd7e7acb73da16e89 + git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git iio-for-5.2a-2) +--- + drivers/iio/adc/meson_saradc.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c +index f8600fbcdfe37..510d8b7ef3a06 100644 +--- a/drivers/iio/adc/meson_saradc.c ++++ b/drivers/iio/adc/meson_saradc.c +@@ -1150,6 +1150,11 @@ static const struct meson_sar_adc_data meson_sar_adc_axg_data = { + .name = "meson-axg-saradc", + }; + ++static const struct meson_sar_adc_data meson_sar_adc_g12a_data = { ++ .param = &meson_sar_adc_gxl_param, ++ .name = "meson-g12a-saradc", ++}; ++ + static const struct of_device_id meson_sar_adc_of_match[] = { + { + .compatible = "amlogic,meson8-saradc", +@@ -1175,6 +1180,9 @@ static const struct of_device_id meson_sar_adc_of_match[] = { + }, { + .compatible = "amlogic,meson-axg-saradc", + .data = &meson_sar_adc_axg_data, ++ }, { ++ .compatible = "amlogic,meson-g12a-saradc", ++ .data = &meson_sar_adc_g12a_data, + }, + {}, + }; + +From d9c37fc7244d366d55fd6b5b9a47d1b8e006f569 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 4 Mar 2019 14:11:28 +0100 +Subject: [PATCH 023/249] FROMGIT: clk: meson-g12a: add cpu clock bindings + +Add Amlogic G12A Family CPU clocks bindings, only export CPU_CLK since +it should be the only ID used. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Reviewed-by: Rob Herring +Acked-by: Jerome Brunet +Link: https://lkml.kernel.org/r/20190304131129.7762-2-narmstrong@baylibre.com +(cherry picked from commit 58b5c8acba12fdf375dd30074c07730e67b97c3f + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + include/dt-bindings/clock/g12a-clkc.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h +index 83b657038d1ea..d7bf0830c87df 100644 +--- a/include/dt-bindings/clock/g12a-clkc.h ++++ b/include/dt-bindings/clock/g12a-clkc.h +@@ -131,5 +131,6 @@ + #define CLKID_MALI_1 174 + #define CLKID_MALI 175 + #define CLKID_MPLL_5OM 177 ++#define CLKID_CPU_CLK 187 + + #endif /* __G12A_CLKC_H */ + +From 96591cc2644b1f13ee7d58c2e161708b59feea25 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 4 Mar 2019 11:53:58 +0100 +Subject: [PATCH 024/249] FROMGIT: clk: g12a-aoclk: re-export + CLKID_AO_SAR_ADC_SEL clock id + +When submitted v2 of the G12A AO-CLK IDs, the SAR_ADC_SEL ID was moved +to the internal non-exported bindings, but this clock is necessary and +mandatory for the SAR ADC bindings. + +Export it back to the public bindings. + +Fixes: be3d960b0aeb ("dt-bindings: clk: add G12A AO Clock and Reset Bindings") +Signed-off-by: Neil Armstrong +Acked-by: Jerome Brunet +Link: https://lkml.kernel.org/r/20190304105358.4987-1-narmstrong@baylibre.com +(cherry picked from commit dc6276f57617344c9e78332c682ea1e982527e09 + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/g12a-aoclk.h | 1 - + include/dt-bindings/clock/g12a-aoclkc.h | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a-aoclk.h b/drivers/clk/meson/g12a-aoclk.h +index 04b0d55066412..666b4493822cc 100644 +--- a/drivers/clk/meson/g12a-aoclk.h ++++ b/drivers/clk/meson/g12a-aoclk.h +@@ -16,7 +16,6 @@ + * to expose, such as the internal muxes and dividers of composite clocks, + * will remain defined here. + */ +-#define CLKID_AO_SAR_ADC_SEL 16 + #define CLKID_AO_SAR_ADC_DIV 17 + #define CLKID_AO_CTS_OSCIN 19 + #define CLKID_AO_32K_PRE 20 +diff --git a/include/dt-bindings/clock/g12a-aoclkc.h b/include/dt-bindings/clock/g12a-aoclkc.h +index 8db01ffbeb063..5ac66a2eee0f7 100644 +--- a/include/dt-bindings/clock/g12a-aoclkc.h ++++ b/include/dt-bindings/clock/g12a-aoclkc.h +@@ -26,6 +26,7 @@ + #define CLKID_AO_M4_FCLK 13 + #define CLKID_AO_M4_HCLK 14 + #define CLKID_AO_CLK81 15 ++#define CLKID_AO_SAR_ADC_SEL 16 + #define CLKID_AO_SAR_ADC_CLK 18 + #define CLKID_AO_32K 23 + #define CLKID_AO_CEC 27 + +From 4b6fc482482f7c4e3fc73e871eabde1f7ec6b1eb Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 7 Mar 2019 15:14:54 +0100 +Subject: [PATCH 025/249] FROMGIT: dt-bindings: clk: g12a-clkc: add PCIE PLL + clock ID + +Add a clock ID for the reference clock feeding the USB3+PCIe Combo PHY. + +Signed-off-by: Neil Armstrong +Acked-by: Jerome Brunet +Link: https://lkml.kernel.org/r/20190307141455.23879-3-narmstrong@baylibre.com +(cherry picked from commit 17750f5218764a06172a294b23275a950e2adce9 + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + include/dt-bindings/clock/g12a-clkc.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h +index d7bf0830c87df..30303728fe096 100644 +--- a/include/dt-bindings/clock/g12a-clkc.h ++++ b/include/dt-bindings/clock/g12a-clkc.h +@@ -132,5 +132,6 @@ + #define CLKID_MALI 175 + #define CLKID_MPLL_5OM 177 + #define CLKID_CPU_CLK 187 ++#define CLKID_PCIE_PLL 201 + + #endif /* __G12A_CLKC_H */ + +From 302a43357dc8cade7480508aefc3dd30a1133842 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Wed, 13 Feb 2019 10:58:35 +0100 +Subject: [PATCH 026/249] FROMGIT: dt-bindings: clock: axg-audio: unexpose + controller inputs + +Remove the bindings ID of the clock input of the controller. These +clocks are purely internal to the controller, exposing them was a +mistake. Actually, these should not even be in the provider and have +IDs to begin with. + +Unexpose these IDs before: + * someone starts using them (even if there no valid reason to do so) + * the actual clocks are removed. The fact that they exist is just the + result of an ugly hack. This will be resolved in CCF when we can + reference DT directly in parent table. + +Signed-off-by: Jerome Brunet +Acked-by: Maxime Jourdan +Reviewed-by: Rob Herring +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190213095835.17448-1-jbrunet@baylibre.com +(cherry picked from commit e4c1e95facf9ddf70bb1a737f8ab1c7d38acd234 + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/axg-audio.h | 20 ++++++++++++++++++++ + include/dt-bindings/clock/axg-audio-clkc.h | 20 -------------------- + 2 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h +index 7191b39c9d650..644f0b0fddf25 100644 +--- a/drivers/clk/meson/axg-audio.h ++++ b/drivers/clk/meson/axg-audio.h +@@ -60,6 +60,26 @@ + #define AUD_CLKID_MST5 6 + #define AUD_CLKID_MST6 7 + #define AUD_CLKID_MST7 8 ++#define AUD_CLKID_SLV_SCLK0 9 ++#define AUD_CLKID_SLV_SCLK1 10 ++#define AUD_CLKID_SLV_SCLK2 11 ++#define AUD_CLKID_SLV_SCLK3 12 ++#define AUD_CLKID_SLV_SCLK4 13 ++#define AUD_CLKID_SLV_SCLK5 14 ++#define AUD_CLKID_SLV_SCLK6 15 ++#define AUD_CLKID_SLV_SCLK7 16 ++#define AUD_CLKID_SLV_SCLK8 17 ++#define AUD_CLKID_SLV_SCLK9 18 ++#define AUD_CLKID_SLV_LRCLK0 19 ++#define AUD_CLKID_SLV_LRCLK1 20 ++#define AUD_CLKID_SLV_LRCLK2 21 ++#define AUD_CLKID_SLV_LRCLK3 22 ++#define AUD_CLKID_SLV_LRCLK4 23 ++#define AUD_CLKID_SLV_LRCLK5 24 ++#define AUD_CLKID_SLV_LRCLK6 25 ++#define AUD_CLKID_SLV_LRCLK7 26 ++#define AUD_CLKID_SLV_LRCLK8 27 ++#define AUD_CLKID_SLV_LRCLK9 28 + #define AUD_CLKID_MST_A_MCLK_SEL 59 + #define AUD_CLKID_MST_B_MCLK_SEL 60 + #define AUD_CLKID_MST_C_MCLK_SEL 61 +diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h +index fd9c362099d9b..eafb0de8466bb 100644 +--- a/include/dt-bindings/clock/axg-audio-clkc.h ++++ b/include/dt-bindings/clock/axg-audio-clkc.h +@@ -7,26 +7,6 @@ + #ifndef __AXG_AUDIO_CLKC_BINDINGS_H + #define __AXG_AUDIO_CLKC_BINDINGS_H + +-#define AUD_CLKID_SLV_SCLK0 9 +-#define AUD_CLKID_SLV_SCLK1 10 +-#define AUD_CLKID_SLV_SCLK2 11 +-#define AUD_CLKID_SLV_SCLK3 12 +-#define AUD_CLKID_SLV_SCLK4 13 +-#define AUD_CLKID_SLV_SCLK5 14 +-#define AUD_CLKID_SLV_SCLK6 15 +-#define AUD_CLKID_SLV_SCLK7 16 +-#define AUD_CLKID_SLV_SCLK8 17 +-#define AUD_CLKID_SLV_SCLK9 18 +-#define AUD_CLKID_SLV_LRCLK0 19 +-#define AUD_CLKID_SLV_LRCLK1 20 +-#define AUD_CLKID_SLV_LRCLK2 21 +-#define AUD_CLKID_SLV_LRCLK3 22 +-#define AUD_CLKID_SLV_LRCLK4 23 +-#define AUD_CLKID_SLV_LRCLK5 24 +-#define AUD_CLKID_SLV_LRCLK6 25 +-#define AUD_CLKID_SLV_LRCLK7 26 +-#define AUD_CLKID_SLV_LRCLK8 27 +-#define AUD_CLKID_SLV_LRCLK9 28 + #define AUD_CLKID_DDR_ARB 29 + #define AUD_CLKID_PDM 30 + #define AUD_CLKID_TDMIN_A 31 + +From 2a66552919d35e5abad8ba9ff4b6670538af6dde Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Tue, 19 Mar 2019 11:11:37 +0100 +Subject: [PATCH 027/249] FROMGIT: dt-bindings: clk: g12a-clkc: add VDEC clock + IDs + +Expose the three clocks related to the video decoder. + +Signed-off-by: Maxime Jourdan +Reviewed-by: Rob Herring +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190319101138.27520-2-mjourdan@baylibre.com +(cherry picked from commit 19478907951afef2249506acc8afec89c3133d9d + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + include/dt-bindings/clock/g12a-clkc.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h +index 30303728fe096..82c9e0c020b21 100644 +--- a/include/dt-bindings/clock/g12a-clkc.h ++++ b/include/dt-bindings/clock/g12a-clkc.h +@@ -133,5 +133,8 @@ + #define CLKID_MPLL_5OM 177 + #define CLKID_CPU_CLK 187 + #define CLKID_PCIE_PLL 201 ++#define CLKID_VDEC_1 204 ++#define CLKID_VDEC_HEVC 207 ++#define CLKID_VDEC_HEVCF 210 + + #endif /* __G12A_CLKC_H */ + +From 24c6f2bd0a457a79ff09e41d1ba6dc828f3a627a Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 4 Mar 2019 14:11:29 +0100 +Subject: [PATCH 028/249] FROMGIT: clk: meson: g12a: add cpu clocks + +Add the Amlogic G12A Family CPU Clock tree in read/only for now. + +The CPU clock can either use the SYS_PLL for > 1GHz frequencies or +use a couple of div+mux from 1GHz/667MHz/24MHz source with 2 non-glitch +muxes. + +Proper DVFS support will come in a second time. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Acked-by: Jerome Brunet +[narmstrong: fixed cpu clocks namings] +Link: https://lkml.kernel.org/r/20190304131129.7762-3-narmstrong@baylibre.com +(cherry picked from commit 370294e2667fa1648eb05aab6c4657419634ff83 + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/g12a.c | 350 +++++++++++++++++++++++++++++++++++++++ + drivers/clk/meson/g12a.h | 22 ++- + 2 files changed, 371 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index f7b11e1eeebe8..292ccb1f7c79d 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -150,6 +150,318 @@ static struct clk_regmap g12a_sys_pll = { + }, + }; + ++static struct clk_regmap g12a_sys_pll_div16_en = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .bit_idx = 24, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "sys_pll_div16_en", ++ .ops = &clk_regmap_gate_ro_ops, ++ .parent_names = (const char *[]){ "sys_pll" }, ++ .num_parents = 1, ++ /* ++ * This clock is used to debug the sys_pll range ++ * Linux should not change it at runtime ++ */ ++ }, ++}; ++ ++static struct clk_fixed_factor g12a_sys_pll_div16 = { ++ .mult = 1, ++ .div = 16, ++ .hw.init = &(struct clk_init_data){ ++ .name = "sys_pll_div16", ++ .ops = &clk_fixed_factor_ops, ++ .parent_names = (const char *[]){ "sys_pll_div16_en" }, ++ .num_parents = 1, ++ }, ++}; ++ ++/* Datasheet names this field as "premux0" */ ++static struct clk_regmap g12a_cpu_clk_premux0 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .mask = 0x3, ++ .shift = 0, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_dyn0_sel", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ IN_PREFIX "xtal", ++ "fclk_div2", ++ "fclk_div3" }, ++ .num_parents = 3, ++ }, ++}; ++ ++/* Datasheet names this field as "mux0_divn_tcnt" */ ++static struct clk_regmap g12a_cpu_clk_mux0_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .shift = 4, ++ .width = 6, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_dyn0_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_dyn0_sel" }, ++ .num_parents = 1, ++ }, ++}; ++ ++/* Datasheet names this field as "postmux0" */ ++static struct clk_regmap g12a_cpu_clk_postmux0 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .mask = 0x1, ++ .shift = 2, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_dyn0", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_dyn0_sel", ++ "cpu_clk_dyn0_div" }, ++ .num_parents = 2, ++ }, ++}; ++ ++/* Datasheet names this field as "premux1" */ ++static struct clk_regmap g12a_cpu_clk_premux1 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .mask = 0x3, ++ .shift = 16, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_dyn1_sel", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ IN_PREFIX "xtal", ++ "fclk_div2", ++ "fclk_div3" }, ++ .num_parents = 3, ++ }, ++}; ++ ++/* Datasheet names this field as "Mux1_divn_tcnt" */ ++static struct clk_regmap g12a_cpu_clk_mux1_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .shift = 20, ++ .width = 6, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_dyn1_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_dyn1_sel" }, ++ .num_parents = 1, ++ }, ++}; ++ ++/* Datasheet names this field as "postmux1" */ ++static struct clk_regmap g12a_cpu_clk_postmux1 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .mask = 0x1, ++ .shift = 18, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_dyn1", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_dyn1_sel", ++ "cpu_clk_dyn1_div" }, ++ .num_parents = 2, ++ }, ++}; ++ ++/* Datasheet names this field as "Final_dyn_mux_sel" */ ++static struct clk_regmap g12a_cpu_clk_dyn = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .mask = 0x1, ++ .shift = 10, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_dyn", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_dyn0", ++ "cpu_clk_dyn1" }, ++ .num_parents = 2, ++ }, ++}; ++ ++/* Datasheet names this field as "Final_mux_sel" */ ++static struct clk_regmap g12a_cpu_clk = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .mask = 0x1, ++ .shift = 11, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_dyn", ++ "sys_pll" }, ++ .num_parents = 2, ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_div16_en = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .bit_idx = 1, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "cpu_clk_div16_en", ++ .ops = &clk_regmap_gate_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk" }, ++ .num_parents = 1, ++ /* ++ * This clock is used to debug the cpu_clk range ++ * Linux should not change it at runtime ++ */ ++ }, ++}; ++ ++static struct clk_fixed_factor g12a_cpu_clk_div16 = { ++ .mult = 1, ++ .div = 16, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_div16", ++ .ops = &clk_fixed_factor_ops, ++ .parent_names = (const char *[]){ "cpu_clk_div16_en" }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_apb_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .shift = 3, ++ .width = 3, ++ .flags = CLK_DIVIDER_POWER_OF_TWO, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_apb_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk" }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_apb = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .bit_idx = 1, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "cpu_clk_apb", ++ .ops = &clk_regmap_gate_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_apb_div" }, ++ .num_parents = 1, ++ /* ++ * This clock is set by the ROM monitor code, ++ * Linux should not change it at runtime ++ */ ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_atb_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .shift = 6, ++ .width = 3, ++ .flags = CLK_DIVIDER_POWER_OF_TWO, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_atb_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk" }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_atb = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .bit_idx = 17, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "cpu_clk_atb", ++ .ops = &clk_regmap_gate_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_atb_div" }, ++ .num_parents = 1, ++ /* ++ * This clock is set by the ROM monitor code, ++ * Linux should not change it at runtime ++ */ ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_axi_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .shift = 9, ++ .width = 3, ++ .flags = CLK_DIVIDER_POWER_OF_TWO, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_axi_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk" }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_axi = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .bit_idx = 18, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "cpu_clk_axi", ++ .ops = &clk_regmap_gate_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_axi_div" }, ++ .num_parents = 1, ++ /* ++ * This clock is set by the ROM monitor code, ++ * Linux should not change it at runtime ++ */ ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_trace_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .shift = 20, ++ .width = 3, ++ .flags = CLK_DIVIDER_POWER_OF_TWO, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk_trace_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk" }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_regmap g12a_cpu_clk_trace = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL1, ++ .bit_idx = 23, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "cpu_clk_trace", ++ .ops = &clk_regmap_gate_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_trace_div" }, ++ .num_parents = 1, ++ /* ++ * This clock is set by the ROM monitor code, ++ * Linux should not change it at runtime ++ */ ++ }, ++}; ++ + static const struct pll_mult_range g12a_gp0_pll_mult_range = { + .min = 55, + .max = 255, +@@ -2167,6 +2479,26 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { + [CLKID_MALI] = &g12a_mali.hw, + [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw, + [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw, ++ [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, ++ [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, ++ [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, ++ [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw, ++ [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw, ++ [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw, ++ [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw, ++ [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw, ++ [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, ++ [CLKID_CPU_CLK] = &g12a_cpu_clk.hw, ++ [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, ++ [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw, ++ [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw, ++ [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw, ++ [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw, ++ [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw, ++ [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw, ++ [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, ++ [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, ++ [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, +@@ -2335,6 +2667,24 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { + &g12a_mali_1, + &g12a_mali, + &g12a_mpll_50m, ++ &g12a_sys_pll_div16_en, ++ &g12a_cpu_clk_premux0, ++ &g12a_cpu_clk_mux0_div, ++ &g12a_cpu_clk_postmux0, ++ &g12a_cpu_clk_premux1, ++ &g12a_cpu_clk_mux1_div, ++ &g12a_cpu_clk_postmux1, ++ &g12a_cpu_clk_dyn, ++ &g12a_cpu_clk, ++ &g12a_cpu_clk_div16_en, ++ &g12a_cpu_clk_apb_div, ++ &g12a_cpu_clk_apb, ++ &g12a_cpu_clk_atb_div, ++ &g12a_cpu_clk_atb, ++ &g12a_cpu_clk_axi_div, ++ &g12a_cpu_clk_axi, ++ &g12a_cpu_clk_trace_div, ++ &g12a_cpu_clk_trace, + }; + + static const struct meson_eeclkc_data g12a_clkc_data = { +diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h +index f399dfe1401cd..70aa469ca1cfc 100644 +--- a/drivers/clk/meson/g12a.h ++++ b/drivers/clk/meson/g12a.h +@@ -50,6 +50,7 @@ + #define HHI_GCLK_MPEG2 0x148 + #define HHI_GCLK_OTHER 0x150 + #define HHI_GCLK_OTHER2 0x154 ++#define HHI_SYS_CPU_CLK_CNTL1 0x15c + #define HHI_VID_CLK_DIV 0x164 + #define HHI_MPEG_CLK_CNTL 0x174 + #define HHI_AUD_CLK_CNTL 0x178 +@@ -166,8 +167,27 @@ + #define CLKID_MALI_0_DIV 170 + #define CLKID_MALI_1_DIV 173 + #define CLKID_MPLL_5OM_DIV 176 ++#define CLKID_SYS_PLL_DIV16_EN 178 ++#define CLKID_SYS_PLL_DIV16 179 ++#define CLKID_CPU_CLK_DYN0_SEL 180 ++#define CLKID_CPU_CLK_DYN0_DIV 181 ++#define CLKID_CPU_CLK_DYN0 182 ++#define CLKID_CPU_CLK_DYN1_SEL 183 ++#define CLKID_CPU_CLK_DYN1_DIV 184 ++#define CLKID_CPU_CLK_DYN1 185 ++#define CLKID_CPU_CLK_DYN 186 ++#define CLKID_CPU_CLK_DIV16_EN 188 ++#define CLKID_CPU_CLK_DIV16 189 ++#define CLKID_CPU_CLK_APB_DIV 190 ++#define CLKID_CPU_CLK_APB 191 ++#define CLKID_CPU_CLK_ATB_DIV 192 ++#define CLKID_CPU_CLK_ATB 193 ++#define CLKID_CPU_CLK_AXI_DIV 194 ++#define CLKID_CPU_CLK_AXI 195 ++#define CLKID_CPU_CLK_TRACE_DIV 196 ++#define CLKID_CPU_CLK_TRACE 197 + +-#define NR_CLKS 178 ++#define NR_CLKS 198 + + /* include the CLKIDs that have been made part of the DT binding */ + #include + +From 9c1d0c7fa83a3d2ecd5bf41f0568153541994ed8 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 7 Mar 2019 15:14:53 +0100 +Subject: [PATCH 029/249] FROMGIT: clk: meson-pll: add reduced specific clk_ops + for G12A PCIe PLL + +The Meson G12A PCIE PLL is fined tuned to deliver a very precise +100MHz reference clock for the PCIe Analog PHY, and thus requires +a strict register sequence to enable the PLL. +To simplify, use the _init() op to enable the PLL and keep +the other ops except set_rate since the rate is fixed. + +Signed-off-by: Neil Armstrong +Acked-by: Jerome Brunet +Link: https://lkml.kernel.org/r/20190307141455.23879-2-narmstrong@baylibre.com +(cherry picked from commit 39b8500283b45252e2f9ad9d60992f2c0d3a1659 + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/clk-pll.c | 26 ++++++++++++++++++++++++++ + drivers/clk/meson/clk-pll.h | 1 + + 2 files changed, 27 insertions(+) + +diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c +index 7a14ac9b2fecf..ddb1e56347395 100644 +--- a/drivers/clk/meson/clk-pll.c ++++ b/drivers/clk/meson/clk-pll.c +@@ -303,6 +303,16 @@ static int meson_clk_pll_is_enabled(struct clk_hw *hw) + return 1; + } + ++static int meson_clk_pcie_pll_enable(struct clk_hw *hw) ++{ ++ meson_clk_pll_init(hw); ++ ++ if (meson_clk_pll_wait_lock(hw)) ++ return -EIO; ++ ++ return 0; ++} ++ + static int meson_clk_pll_enable(struct clk_hw *hw) + { + struct clk_regmap *clk = to_clk_regmap(hw); +@@ -387,6 +397,22 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + return 0; + } + ++/* ++ * The Meson G12A PCIE PLL is fined tuned to deliver a very precise ++ * 100MHz reference clock for the PCIe Analog PHY, and thus requires ++ * a strict register sequence to enable the PLL. ++ * To simplify, re-use the _init() op to enable the PLL and keep ++ * the other ops except set_rate since the rate is fixed. ++ */ ++const struct clk_ops meson_clk_pcie_pll_ops = { ++ .recalc_rate = meson_clk_pll_recalc_rate, ++ .round_rate = meson_clk_pll_round_rate, ++ .is_enabled = meson_clk_pll_is_enabled, ++ .enable = meson_clk_pcie_pll_enable, ++ .disable = meson_clk_pll_disable ++}; ++EXPORT_SYMBOL_GPL(meson_clk_pcie_pll_ops); ++ + const struct clk_ops meson_clk_pll_ops = { + .init = meson_clk_pll_init, + .recalc_rate = meson_clk_pll_recalc_rate, +diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h +index 55af2e285b1b0..367efd0f6410c 100644 +--- a/drivers/clk/meson/clk-pll.h ++++ b/drivers/clk/meson/clk-pll.h +@@ -45,5 +45,6 @@ struct meson_clk_pll_data { + + extern const struct clk_ops meson_clk_pll_ro_ops; + extern const struct clk_ops meson_clk_pll_ops; ++extern const struct clk_ops meson_clk_pcie_pll_ops; + + #endif /* __MESON_CLK_PLL_H */ + +From 62980b27c3547abe86ea616b4d57bd46f674b5a8 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 21 Mar 2019 10:20:10 +0100 +Subject: [PATCH 030/249] FROMGIT: dt-bindings: clock: g12a-aoclk: expose + CLKID_AO_CTS_OSCIN + +When submitted v2 of the G12A AO-CLK IDs, the CLKID_AO_CTS_OSCIN was moved +to the internal non-exported bindings, but this clock is necessary for +the second AO-CEC-B module since it embeds the 32768Hz dual-divider +clock generator unlike the AO-CEC-A module. + +Export it back to the public bindings. + +Fixes: be3d960b0aeb ("dt-bindings: clk: add G12A AO Clock and Reset Bindings") +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Link: https://lkml.kernel.org/r/20190321092010.14382-1-narmstrong@baylibre.com +(cherry picked from commit 133bb341b99d096d332108f412234d0cf641c15d + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/g12a-aoclk.h | 1 - + include/dt-bindings/clock/g12a-aoclkc.h | 1 + + 2 files changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a-aoclk.h b/drivers/clk/meson/g12a-aoclk.h +index 666b4493822cc..a67c8a7cd7c47 100644 +--- a/drivers/clk/meson/g12a-aoclk.h ++++ b/drivers/clk/meson/g12a-aoclk.h +@@ -17,7 +17,6 @@ + * will remain defined here. + */ + #define CLKID_AO_SAR_ADC_DIV 17 +-#define CLKID_AO_CTS_OSCIN 19 + #define CLKID_AO_32K_PRE 20 + #define CLKID_AO_32K_DIV 21 + #define CLKID_AO_32K_SEL 22 +diff --git a/include/dt-bindings/clock/g12a-aoclkc.h b/include/dt-bindings/clock/g12a-aoclkc.h +index 5ac66a2eee0f7..e916e49ff2884 100644 +--- a/include/dt-bindings/clock/g12a-aoclkc.h ++++ b/include/dt-bindings/clock/g12a-aoclkc.h +@@ -28,6 +28,7 @@ + #define CLKID_AO_CLK81 15 + #define CLKID_AO_SAR_ADC_SEL 16 + #define CLKID_AO_SAR_ADC_CLK 18 ++#define CLKID_AO_CTS_OSCIN 19 + #define CLKID_AO_32K 23 + #define CLKID_AO_CEC 27 + #define CLKID_AO_CTS_RTC_OSCIN 28 + +From ae5582ebc4391e414246889312963d6756fd1f65 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 7 Mar 2019 15:14:55 +0100 +Subject: [PATCH 031/249] FROMGIT: clk: meson-g12a: add PCIE PLL clocks + +Add the PCIe reference clock feeding the USB3 + PCIE combo PHY. + +This PLL needs a very precise register sequence to permit to be locked, +thus using the specific clk-pll pcie ops. + +The PLL is then followed by : +- a fixed /2 divider +- a 5-bit 1-based divider +- a final /2 divider + +This reference clock is fixed to 100MHz, thus only a single PLL setup +is added. + +Signed-off-by: Neil Armstrong +Acked-by: Jerome Brunet +Link: https://lkml.kernel.org/r/20190307141455.23879-4-narmstrong@baylibre.com +(cherry picked from commit 34775209ba37bff3b4e60ddee0a2d69966146a5d + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/g12a.c | 118 +++++++++++++++++++++++++++++++++++++++ + drivers/clk/meson/g12a.h | 5 +- + 2 files changed, 122 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index 292ccb1f7c79d..ecbfd4f38a255 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -614,6 +614,118 @@ static struct clk_regmap g12a_hifi_pll = { + }, + }; + ++/* ++ * The Meson G12A PCIE PLL is fined tuned to deliver a very precise ++ * 100MHz reference clock for the PCIe Analog PHY, and thus requires ++ * a strict register sequence to enable the PLL. ++ */ ++static const struct reg_sequence g12a_pcie_pll_init_regs[] = { ++ { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x20090496 }, ++ { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x30090496 }, ++ { .reg = HHI_PCIE_PLL_CNTL1, .def = 0x00000000 }, ++ { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001100 }, ++ { .reg = HHI_PCIE_PLL_CNTL3, .def = 0x10058e00 }, ++ { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x000100c0 }, ++ { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000048 }, ++ { .reg = HHI_PCIE_PLL_CNTL5, .def = 0x68000068, .delay_us = 20 }, ++ { .reg = HHI_PCIE_PLL_CNTL4, .def = 0x008100c0, .delay_us = 10 }, ++ { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x34090496 }, ++ { .reg = HHI_PCIE_PLL_CNTL0, .def = 0x14090496, .delay_us = 10 }, ++ { .reg = HHI_PCIE_PLL_CNTL2, .def = 0x00001000 }, ++}; ++ ++/* Keep a single entry table for recalc/round_rate() ops */ ++static const struct pll_params_table g12a_pcie_pll_table[] = { ++ PLL_PARAMS(150, 1), ++ {0, 0}, ++}; ++ ++static struct clk_regmap g12a_pcie_pll_dco = { ++ .data = &(struct meson_clk_pll_data){ ++ .en = { ++ .reg_off = HHI_PCIE_PLL_CNTL0, ++ .shift = 28, ++ .width = 1, ++ }, ++ .m = { ++ .reg_off = HHI_PCIE_PLL_CNTL0, ++ .shift = 0, ++ .width = 8, ++ }, ++ .n = { ++ .reg_off = HHI_PCIE_PLL_CNTL0, ++ .shift = 10, ++ .width = 5, ++ }, ++ .frac = { ++ .reg_off = HHI_PCIE_PLL_CNTL1, ++ .shift = 0, ++ .width = 12, ++ }, ++ .l = { ++ .reg_off = HHI_PCIE_PLL_CNTL0, ++ .shift = 31, ++ .width = 1, ++ }, ++ .rst = { ++ .reg_off = HHI_PCIE_PLL_CNTL0, ++ .shift = 29, ++ .width = 1, ++ }, ++ .table = g12a_pcie_pll_table, ++ .init_regs = g12a_pcie_pll_init_regs, ++ .init_count = ARRAY_SIZE(g12a_pcie_pll_init_regs), ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "pcie_pll_dco", ++ .ops = &meson_clk_pcie_pll_ops, ++ .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_fixed_factor g12a_pcie_pll_dco_div2 = { ++ .mult = 1, ++ .div = 2, ++ .hw.init = &(struct clk_init_data){ ++ .name = "pcie_pll_dco_div2", ++ .ops = &clk_fixed_factor_ops, ++ .parent_names = (const char *[]){ "pcie_pll_dco" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_pcie_pll_od = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_PCIE_PLL_CNTL0, ++ .shift = 16, ++ .width = 5, ++ .flags = CLK_DIVIDER_ROUND_CLOSEST | ++ CLK_DIVIDER_ONE_BASED | ++ CLK_DIVIDER_ALLOW_ZERO, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "pcie_pll_od", ++ .ops = &clk_regmap_divider_ops, ++ .parent_names = (const char *[]){ "pcie_pll_dco_div2" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_fixed_factor g12a_pcie_pll = { ++ .mult = 1, ++ .div = 2, ++ .hw.init = &(struct clk_init_data){ ++ .name = "pcie_pll_pll", ++ .ops = &clk_fixed_factor_ops, ++ .parent_names = (const char *[]){ "pcie_pll_od" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ + static struct clk_regmap g12a_hdmi_pll_dco = { + .data = &(struct meson_clk_pll_data){ + .en = { +@@ -2499,6 +2611,10 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { + [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, + [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, + [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, ++ [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw, ++ [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, ++ [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, ++ [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, +@@ -2685,6 +2801,8 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { + &g12a_cpu_clk_axi, + &g12a_cpu_clk_trace_div, + &g12a_cpu_clk_trace, ++ &g12a_pcie_pll_od, ++ &g12a_pcie_pll_dco, + }; + + static const struct meson_eeclkc_data g12a_clkc_data = { +diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h +index 70aa469ca1cfc..1393a09730a6b 100644 +--- a/drivers/clk/meson/g12a.h ++++ b/drivers/clk/meson/g12a.h +@@ -186,8 +186,11 @@ + #define CLKID_CPU_CLK_AXI 195 + #define CLKID_CPU_CLK_TRACE_DIV 196 + #define CLKID_CPU_CLK_TRACE 197 ++#define CLKID_PCIE_PLL_DCO 198 ++#define CLKID_PCIE_PLL_DCO_DIV2 199 ++#define CLKID_PCIE_PLL_OD 200 + +-#define NR_CLKS 198 ++#define NR_CLKS 202 + + /* include the CLKIDs that have been made part of the DT binding */ + #include + +From 6c9abc2a14e119cb48a26869f3e2093bff6c801b Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Tue, 19 Mar 2019 11:11:38 +0100 +Subject: [PATCH 032/249] FROMGIT: clk: meson-g12a: add video decoder clocks + +Add the necessary clock parts for: + + - VDEC_1: used to feed VDEC_1 + - VDEC_HEVC: the "back" part of the VDEC_HEVC block + - VDEC_HEVCF: the "front" part of the VDEC_HEVC block + +In previous SoC generations (GXL, GXBB), there was only one VDEC_HEVC +clock, which got split in two parts for G12A. + +Signed-off-by: Maxime Jourdan +Acked-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190319101138.27520-2-mjourdan@baylibre.com +(cherry picked from commit 4b0f73055acaced436d5de909b26d001ea7f667c + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/g12a.c | 163 +++++++++++++++++++++++++++++++++++++++ + drivers/clk/meson/g12a.h | 8 +- + 2 files changed, 170 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index ecbfd4f38a255..739f64fdf1e3b 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -1495,6 +1495,151 @@ static struct clk_regmap g12a_vpu = { + }, + }; + ++/* VDEC clocks */ ++ ++static const char * const g12a_vdec_parent_names[] = { ++ "fclk_div2p5", "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7", ++ "hifi_pll", "gp0_pll", ++}; ++ ++static struct clk_regmap g12a_vdec_1_sel = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_VDEC_CLK_CNTL, ++ .mask = 0x7, ++ .shift = 9, ++ .flags = CLK_MUX_ROUND_CLOSEST, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "vdec_1_sel", ++ .ops = &clk_regmap_mux_ops, ++ .parent_names = g12a_vdec_parent_names, ++ .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_vdec_1_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_VDEC_CLK_CNTL, ++ .shift = 0, ++ .width = 7, ++ .flags = CLK_DIVIDER_ROUND_CLOSEST, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "vdec_1_div", ++ .ops = &clk_regmap_divider_ops, ++ .parent_names = (const char *[]){ "vdec_1_sel" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_vdec_1 = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_VDEC_CLK_CNTL, ++ .bit_idx = 8, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "vdec_1", ++ .ops = &clk_regmap_gate_ops, ++ .parent_names = (const char *[]){ "vdec_1_div" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_vdec_hevcf_sel = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_VDEC2_CLK_CNTL, ++ .mask = 0x7, ++ .shift = 9, ++ .flags = CLK_MUX_ROUND_CLOSEST, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "vdec_hevcf_sel", ++ .ops = &clk_regmap_mux_ops, ++ .parent_names = g12a_vdec_parent_names, ++ .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_vdec_hevcf_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_VDEC2_CLK_CNTL, ++ .shift = 0, ++ .width = 7, ++ .flags = CLK_DIVIDER_ROUND_CLOSEST, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "vdec_hevcf_div", ++ .ops = &clk_regmap_divider_ops, ++ .parent_names = (const char *[]){ "vdec_hevcf_sel" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_vdec_hevcf = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_VDEC2_CLK_CNTL, ++ .bit_idx = 8, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "vdec_hevcf", ++ .ops = &clk_regmap_gate_ops, ++ .parent_names = (const char *[]){ "vdec_hevcf_div" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_vdec_hevc_sel = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_VDEC2_CLK_CNTL, ++ .mask = 0x7, ++ .shift = 25, ++ .flags = CLK_MUX_ROUND_CLOSEST, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "vdec_hevc_sel", ++ .ops = &clk_regmap_mux_ops, ++ .parent_names = g12a_vdec_parent_names, ++ .num_parents = ARRAY_SIZE(g12a_vdec_parent_names), ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_vdec_hevc_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_VDEC2_CLK_CNTL, ++ .shift = 16, ++ .width = 7, ++ .flags = CLK_DIVIDER_ROUND_CLOSEST, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "vdec_hevc_div", ++ .ops = &clk_regmap_divider_ops, ++ .parent_names = (const char *[]){ "vdec_hevc_sel" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ ++static struct clk_regmap g12a_vdec_hevc = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_VDEC2_CLK_CNTL, ++ .bit_idx = 24, ++ }, ++ .hw.init = &(struct clk_init_data) { ++ .name = "vdec_hevc", ++ .ops = &clk_regmap_gate_ops, ++ .parent_names = (const char *[]){ "vdec_hevc_div" }, ++ .num_parents = 1, ++ .flags = CLK_SET_RATE_PARENT, ++ }, ++}; ++ + /* VAPB Clock */ + + static const char * const g12a_vapb_parent_names[] = { +@@ -2615,6 +2760,15 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { + [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, + [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, + [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, ++ [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw, ++ [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw, ++ [CLKID_VDEC_1] = &g12a_vdec_1.hw, ++ [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw, ++ [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw, ++ [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw, ++ [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, ++ [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, ++ [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, +@@ -2803,6 +2957,15 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { + &g12a_cpu_clk_trace, + &g12a_pcie_pll_od, + &g12a_pcie_pll_dco, ++ &g12a_vdec_1_sel, ++ &g12a_vdec_1_div, ++ &g12a_vdec_1, ++ &g12a_vdec_hevc_sel, ++ &g12a_vdec_hevc_div, ++ &g12a_vdec_hevc, ++ &g12a_vdec_hevcf_sel, ++ &g12a_vdec_hevcf_div, ++ &g12a_vdec_hevcf, + }; + + static const struct meson_eeclkc_data g12a_clkc_data = { +diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h +index 1393a09730a6b..39c41af708044 100644 +--- a/drivers/clk/meson/g12a.h ++++ b/drivers/clk/meson/g12a.h +@@ -189,8 +189,14 @@ + #define CLKID_PCIE_PLL_DCO 198 + #define CLKID_PCIE_PLL_DCO_DIV2 199 + #define CLKID_PCIE_PLL_OD 200 ++#define CLKID_VDEC_1_SEL 202 ++#define CLKID_VDEC_1_DIV 203 ++#define CLKID_VDEC_HEVC_SEL 205 ++#define CLKID_VDEC_HEVC_DIV 206 ++#define CLKID_VDEC_HEVCF_SEL 208 ++#define CLKID_VDEC_HEVCF_DIV 209 + +-#define NR_CLKS 202 ++#define NR_CLKS 211 + + /* include the CLKIDs that have been made part of the DT binding */ + #include + +From b2508cc758bbc0513d7c9181d910de12f2c0bb07 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 29 Mar 2019 17:06:46 +0100 +Subject: [PATCH 033/249] FROMGIT: dt-bindings: clk: axg-audio: add g12a + support + +Add a new compatible string and additional clock ids for audio clock +controller of the g12a SoC family. + +Signed-off-by: Jerome Brunet +Reviewed-by: Rob Herring +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190329160649.31603-2-jbrunet@baylibre.com +(cherry picked from commit 8554926b3fcb703a788018d5eba0ddd377abeecd + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + .../bindings/clock/amlogic,axg-audio-clkc.txt | 3 ++- + include/dt-bindings/clock/axg-audio-clkc.h | 10 ++++++++++ + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt +index 61777ad24f61c..0f777749f4f1e 100644 +--- a/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt ++++ b/Documentation/devicetree/bindings/clock/amlogic,axg-audio-clkc.txt +@@ -6,7 +6,8 @@ devices. + + Required Properties: + +-- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D ++- compatible : should be "amlogic,axg-audio-clkc" for the A113X and A113D, ++ "amlogic,g12a-audio-clkc" for G12A. + - reg : physical base address of the clock controller and length of + memory mapped region. + - clocks : a list of phandle + clock-specifier pairs for the clocks listed +diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h +index eafb0de8466bb..75901c636893c 100644 +--- a/include/dt-bindings/clock/axg-audio-clkc.h ++++ b/include/dt-bindings/clock/axg-audio-clkc.h +@@ -70,5 +70,15 @@ + #define AUD_CLKID_TDMOUT_A_LRCLK 134 + #define AUD_CLKID_TDMOUT_B_LRCLK 135 + #define AUD_CLKID_TDMOUT_C_LRCLK 136 ++#define AUD_CLKID_SPDIFOUT_B 151 ++#define AUD_CLKID_SPDIFOUT_B_CLK 152 ++#define AUD_CLKID_TDM_MCLK_PAD0 155 ++#define AUD_CLKID_TDM_MCLK_PAD1 156 ++#define AUD_CLKID_TDM_LRCLK_PAD0 157 ++#define AUD_CLKID_TDM_LRCLK_PAD1 158 ++#define AUD_CLKID_TDM_LRCLK_PAD2 159 ++#define AUD_CLKID_TDM_SCLK_PAD0 160 ++#define AUD_CLKID_TDM_SCLK_PAD1 161 ++#define AUD_CLKID_TDM_SCLK_PAD2 162 + + #endif /* __AXG_AUDIO_CLKC_BINDINGS_H */ + +From 6167833a050ffb1ba90cfe109721eacb70b64596 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 29 Mar 2019 17:06:47 +0100 +Subject: [PATCH 034/249] FROMGIT: clk: meson: axg_audio: replace prefix axg by + aud + +The audio clock controller is compatible with axg and g12a SoC family. +Having each clock name prefixed with "axg_" looks weird on the g12a. +This change replace the "axg_" by "aud_" in fron the clock names. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190329160649.31603-3-jbrunet@baylibre.com +(cherry picked from commit b18819c4acf16ac3273192b79c53f3b833b9a1f8 + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/axg-audio.c | 964 +++++++++++++++++----------------- + 1 file changed, 482 insertions(+), 482 deletions(-) + +diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c +index 7ab200b6c3bff..38fccffc171ea 100644 +--- a/drivers/clk/meson/axg-audio.c ++++ b/drivers/clk/meson/axg-audio.c +@@ -20,18 +20,18 @@ + #include "clk-phase.h" + #include "sclk-div.h" + +-#define AXG_MST_IN_COUNT 8 +-#define AXG_SLV_SCLK_COUNT 10 +-#define AXG_SLV_LRCLK_COUNT 10 ++#define AUD_MST_IN_COUNT 8 ++#define AUD_SLV_SCLK_COUNT 10 ++#define AUD_SLV_LRCLK_COUNT 10 + +-#define AXG_AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ +-struct clk_regmap axg_##_name = { \ ++#define AUD_GATE(_name, _reg, _bit, _pname, _iflags) \ ++struct clk_regmap aud_##_name = { \ + .data = &(struct clk_regmap_gate_data){ \ + .offset = (_reg), \ + .bit_idx = (_bit), \ + }, \ + .hw.init = &(struct clk_init_data) { \ +- .name = "axg_"#_name, \ ++ .name = "aud_"#_name, \ + .ops = &clk_regmap_gate_ops, \ + .parent_names = (const char *[]){ _pname }, \ + .num_parents = 1, \ +@@ -39,8 +39,8 @@ struct clk_regmap axg_##_name = { \ + }, \ + } + +-#define AXG_AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ +-struct clk_regmap axg_##_name = { \ ++#define AUD_MUX(_name, _reg, _mask, _shift, _dflags, _pnames, _iflags) \ ++struct clk_regmap aud_##_name = { \ + .data = &(struct clk_regmap_mux_data){ \ + .offset = (_reg), \ + .mask = (_mask), \ +@@ -48,7 +48,7 @@ struct clk_regmap axg_##_name = { \ + .flags = (_dflags), \ + }, \ + .hw.init = &(struct clk_init_data){ \ +- .name = "axg_"#_name, \ ++ .name = "aud_"#_name, \ + .ops = &clk_regmap_mux_ops, \ + .parent_names = (_pnames), \ + .num_parents = ARRAY_SIZE(_pnames), \ +@@ -56,8 +56,8 @@ struct clk_regmap axg_##_name = { \ + }, \ + } + +-#define AXG_AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ +-struct clk_regmap axg_##_name = { \ ++#define AUD_DIV(_name, _reg, _shift, _width, _dflags, _pname, _iflags) \ ++struct clk_regmap aud_##_name = { \ + .data = &(struct clk_regmap_div_data){ \ + .offset = (_reg), \ + .shift = (_shift), \ +@@ -65,7 +65,7 @@ struct clk_regmap axg_##_name = { \ + .flags = (_dflags), \ + }, \ + .hw.init = &(struct clk_init_data){ \ +- .name = "axg_"#_name, \ ++ .name = "aud_"#_name, \ + .ops = &clk_regmap_divider_ops, \ + .parent_names = (const char *[]) { _pname }, \ + .num_parents = 1, \ +@@ -73,109 +73,109 @@ struct clk_regmap axg_##_name = { \ + }, \ + } + +-#define AXG_PCLK_GATE(_name, _bit) \ +- AXG_AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "axg_audio_pclk", 0) ++#define AUD_PCLK_GATE(_name, _bit) \ ++ AUD_GATE(_name, AUDIO_CLK_GATE_EN, _bit, "audio_pclk", 0) + + /* Audio peripheral clocks */ +-static AXG_PCLK_GATE(ddr_arb, 0); +-static AXG_PCLK_GATE(pdm, 1); +-static AXG_PCLK_GATE(tdmin_a, 2); +-static AXG_PCLK_GATE(tdmin_b, 3); +-static AXG_PCLK_GATE(tdmin_c, 4); +-static AXG_PCLK_GATE(tdmin_lb, 5); +-static AXG_PCLK_GATE(tdmout_a, 6); +-static AXG_PCLK_GATE(tdmout_b, 7); +-static AXG_PCLK_GATE(tdmout_c, 8); +-static AXG_PCLK_GATE(frddr_a, 9); +-static AXG_PCLK_GATE(frddr_b, 10); +-static AXG_PCLK_GATE(frddr_c, 11); +-static AXG_PCLK_GATE(toddr_a, 12); +-static AXG_PCLK_GATE(toddr_b, 13); +-static AXG_PCLK_GATE(toddr_c, 14); +-static AXG_PCLK_GATE(loopback, 15); +-static AXG_PCLK_GATE(spdifin, 16); +-static AXG_PCLK_GATE(spdifout, 17); +-static AXG_PCLK_GATE(resample, 18); +-static AXG_PCLK_GATE(power_detect, 19); ++static AUD_PCLK_GATE(ddr_arb, 0); ++static AUD_PCLK_GATE(pdm, 1); ++static AUD_PCLK_GATE(tdmin_a, 2); ++static AUD_PCLK_GATE(tdmin_b, 3); ++static AUD_PCLK_GATE(tdmin_c, 4); ++static AUD_PCLK_GATE(tdmin_lb, 5); ++static AUD_PCLK_GATE(tdmout_a, 6); ++static AUD_PCLK_GATE(tdmout_b, 7); ++static AUD_PCLK_GATE(tdmout_c, 8); ++static AUD_PCLK_GATE(frddr_a, 9); ++static AUD_PCLK_GATE(frddr_b, 10); ++static AUD_PCLK_GATE(frddr_c, 11); ++static AUD_PCLK_GATE(toddr_a, 12); ++static AUD_PCLK_GATE(toddr_b, 13); ++static AUD_PCLK_GATE(toddr_c, 14); ++static AUD_PCLK_GATE(loopback, 15); ++static AUD_PCLK_GATE(spdifin, 16); ++static AUD_PCLK_GATE(spdifout, 17); ++static AUD_PCLK_GATE(resample, 18); ++static AUD_PCLK_GATE(power_detect, 19); + + /* Audio Master Clocks */ + static const char * const mst_mux_parent_names[] = { +- "axg_mst_in0", "axg_mst_in1", "axg_mst_in2", "axg_mst_in3", +- "axg_mst_in4", "axg_mst_in5", "axg_mst_in6", "axg_mst_in7", ++ "aud_mst_in0", "aud_mst_in1", "aud_mst_in2", "aud_mst_in3", ++ "aud_mst_in4", "aud_mst_in5", "aud_mst_in6", "aud_mst_in7", + }; + +-#define AXG_MST_MUX(_name, _reg, _flag) \ +- AXG_AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ +- mst_mux_parent_names, CLK_SET_RATE_PARENT) +- +-#define AXG_MST_MCLK_MUX(_name, _reg) \ +- AXG_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) +- +-#define AXG_MST_SYS_MUX(_name, _reg) \ +- AXG_MST_MUX(_name, _reg, 0) +- +-static AXG_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); +-static AXG_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); +-static AXG_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); +-static AXG_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); +-static AXG_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); +-static AXG_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); +-static AXG_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +-static AXG_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +-static AXG_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +-static AXG_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +- +-#define AXG_MST_DIV(_name, _reg, _flag) \ +- AXG_AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ +- "axg_"#_name"_sel", CLK_SET_RATE_PARENT) \ +- +-#define AXG_MST_MCLK_DIV(_name, _reg) \ +- AXG_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) +- +-#define AXG_MST_SYS_DIV(_name, _reg) \ +- AXG_MST_DIV(_name, _reg, 0) +- +-static AXG_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); +-static AXG_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); +-static AXG_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); +-static AXG_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); +-static AXG_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); +-static AXG_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); +-static AXG_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +-static AXG_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +-static AXG_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +-static AXG_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); +- +-#define AXG_MST_MCLK_GATE(_name, _reg) \ +- AXG_AUD_GATE(_name, _reg, 31, "axg_"#_name"_div", \ +- CLK_SET_RATE_PARENT) +- +-static AXG_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); +-static AXG_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); +-static AXG_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); +-static AXG_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); +-static AXG_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); +-static AXG_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); +-static AXG_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); +-static AXG_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); +-static AXG_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); +-static AXG_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); ++#define AUD_MST_MUX(_name, _reg, _flag) \ ++ AUD_MUX(_name##_sel, _reg, 0x7, 24, _flag, \ ++ mst_mux_parent_names, CLK_SET_RATE_PARENT) ++ ++#define AUD_MST_MCLK_MUX(_name, _reg) \ ++ AUD_MST_MUX(_name, _reg, CLK_MUX_ROUND_CLOSEST) ++ ++#define AUD_MST_SYS_MUX(_name, _reg) \ ++ AUD_MST_MUX(_name, _reg, 0) ++ ++static AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_MCLK_A_CTRL); ++static AUD_MST_MCLK_MUX(mst_b_mclk, AUDIO_MCLK_B_CTRL); ++static AUD_MST_MCLK_MUX(mst_c_mclk, AUDIO_MCLK_C_CTRL); ++static AUD_MST_MCLK_MUX(mst_d_mclk, AUDIO_MCLK_D_CTRL); ++static AUD_MST_MCLK_MUX(mst_e_mclk, AUDIO_MCLK_E_CTRL); ++static AUD_MST_MCLK_MUX(mst_f_mclk, AUDIO_MCLK_F_CTRL); ++static AUD_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); ++static AUD_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); ++static AUD_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); ++static AUD_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); ++ ++#define AUD_MST_DIV(_name, _reg, _flag) \ ++ AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ ++ "aud_"#_name"_sel", CLK_SET_RATE_PARENT) \ ++ ++#define AUD_MST_MCLK_DIV(_name, _reg) \ ++ AUD_MST_DIV(_name, _reg, CLK_DIVIDER_ROUND_CLOSEST) ++ ++#define AUD_MST_SYS_DIV(_name, _reg) \ ++ AUD_MST_DIV(_name, _reg, 0) ++ ++static AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_MCLK_A_CTRL); ++static AUD_MST_MCLK_DIV(mst_b_mclk, AUDIO_MCLK_B_CTRL); ++static AUD_MST_MCLK_DIV(mst_c_mclk, AUDIO_MCLK_C_CTRL); ++static AUD_MST_MCLK_DIV(mst_d_mclk, AUDIO_MCLK_D_CTRL); ++static AUD_MST_MCLK_DIV(mst_e_mclk, AUDIO_MCLK_E_CTRL); ++static AUD_MST_MCLK_DIV(mst_f_mclk, AUDIO_MCLK_F_CTRL); ++static AUD_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); ++static AUD_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); ++static AUD_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); ++static AUD_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); ++ ++#define AUD_MST_MCLK_GATE(_name, _reg) \ ++ AUD_GATE(_name, _reg, 31, "aud_"#_name"_div", \ ++ CLK_SET_RATE_PARENT) ++ ++static AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_MCLK_A_CTRL); ++static AUD_MST_MCLK_GATE(mst_b_mclk, AUDIO_MCLK_B_CTRL); ++static AUD_MST_MCLK_GATE(mst_c_mclk, AUDIO_MCLK_C_CTRL); ++static AUD_MST_MCLK_GATE(mst_d_mclk, AUDIO_MCLK_D_CTRL); ++static AUD_MST_MCLK_GATE(mst_e_mclk, AUDIO_MCLK_E_CTRL); ++static AUD_MST_MCLK_GATE(mst_f_mclk, AUDIO_MCLK_F_CTRL); ++static AUD_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); ++static AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); ++static AUD_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); ++static AUD_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); + + /* Sample Clocks */ +-#define AXG_MST_SCLK_PRE_EN(_name, _reg) \ +- AXG_AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ +- "axg_mst_"#_name"_mclk", 0) +- +-static AXG_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); +-static AXG_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); +-static AXG_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); +-static AXG_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); +-static AXG_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); +-static AXG_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); +- +-#define AXG_AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ ++#define AUD_MST_SCLK_PRE_EN(_name, _reg) \ ++ AUD_GATE(mst_##_name##_sclk_pre_en, _reg, 31, \ ++ "aud_mst_"#_name"_mclk", 0) ++ ++static AUD_MST_SCLK_PRE_EN(a, AUDIO_MST_A_SCLK_CTRL0); ++static AUD_MST_SCLK_PRE_EN(b, AUDIO_MST_B_SCLK_CTRL0); ++static AUD_MST_SCLK_PRE_EN(c, AUDIO_MST_C_SCLK_CTRL0); ++static AUD_MST_SCLK_PRE_EN(d, AUDIO_MST_D_SCLK_CTRL0); ++static AUD_MST_SCLK_PRE_EN(e, AUDIO_MST_E_SCLK_CTRL0); ++static AUD_MST_SCLK_PRE_EN(f, AUDIO_MST_F_SCLK_CTRL0); ++ ++#define AUD_SCLK_DIV(_name, _reg, _div_shift, _div_width, \ + _hi_shift, _hi_width, _pname, _iflags) \ +-struct clk_regmap axg_##_name = { \ ++struct clk_regmap aud_##_name = { \ + .data = &(struct meson_sclk_div_data) { \ + .div = { \ + .reg_off = (_reg), \ +@@ -189,7 +189,7 @@ struct clk_regmap axg_##_name = { \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ +- .name = "axg_"#_name, \ ++ .name = "aud_"#_name, \ + .ops = &meson_sclk_div_ops, \ + .parent_names = (const char *[]) { _pname }, \ + .num_parents = 1, \ +@@ -197,32 +197,32 @@ struct clk_regmap axg_##_name = { \ + }, \ + } + +-#define AXG_MST_SCLK_DIV(_name, _reg) \ +- AXG_AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ +- "axg_mst_"#_name"_sclk_pre_en", \ +- CLK_SET_RATE_PARENT) +- +-static AXG_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +-static AXG_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +-static AXG_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); +-static AXG_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); +-static AXG_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); +-static AXG_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); +- +-#define AXG_MST_SCLK_POST_EN(_name, _reg) \ +- AXG_AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ +- "axg_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) +- +-static AXG_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); +-static AXG_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); +-static AXG_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); +-static AXG_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); +-static AXG_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); +-static AXG_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); +- +-#define AXG_AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ ++#define AUD_MST_SCLK_DIV(_name, _reg) \ ++ AUD_SCLK_DIV(mst_##_name##_sclk_div, _reg, 20, 10, 0, 0, \ ++ "aud_mst_"#_name"_sclk_pre_en", \ ++ CLK_SET_RATE_PARENT) ++ ++static AUD_MST_SCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); ++static AUD_MST_SCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); ++static AUD_MST_SCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); ++static AUD_MST_SCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); ++static AUD_MST_SCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); ++static AUD_MST_SCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); ++ ++#define AUD_MST_SCLK_POST_EN(_name, _reg) \ ++ AUD_GATE(mst_##_name##_sclk_post_en, _reg, 30, \ ++ "aud_mst_"#_name"_sclk_div", CLK_SET_RATE_PARENT) ++ ++static AUD_MST_SCLK_POST_EN(a, AUDIO_MST_A_SCLK_CTRL0); ++static AUD_MST_SCLK_POST_EN(b, AUDIO_MST_B_SCLK_CTRL0); ++static AUD_MST_SCLK_POST_EN(c, AUDIO_MST_C_SCLK_CTRL0); ++static AUD_MST_SCLK_POST_EN(d, AUDIO_MST_D_SCLK_CTRL0); ++static AUD_MST_SCLK_POST_EN(e, AUDIO_MST_E_SCLK_CTRL0); ++static AUD_MST_SCLK_POST_EN(f, AUDIO_MST_F_SCLK_CTRL0); ++ ++#define AUD_TRIPHASE(_name, _reg, _width, _shift0, _shift1, _shift2, \ + _pname, _iflags) \ +-struct clk_regmap axg_##_name = { \ ++struct clk_regmap aud_##_name = { \ + .data = &(struct meson_clk_triphase_data) { \ + .ph0 = { \ + .reg_off = (_reg), \ +@@ -241,7 +241,7 @@ struct clk_regmap axg_##_name = { \ + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ +- .name = "axg_"#_name, \ ++ .name = "aud_"#_name, \ + .ops = &meson_clk_triphase_ops, \ + .parent_names = (const char *[]) { _pname }, \ + .num_parents = 1, \ +@@ -249,87 +249,87 @@ struct clk_regmap axg_##_name = { \ + }, \ + } + +-#define AXG_MST_SCLK(_name, _reg) \ +- AXG_AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ +- "axg_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) +- +-static AXG_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); +-static AXG_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); +-static AXG_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); +-static AXG_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); +-static AXG_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); +-static AXG_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); +- +-#define AXG_MST_LRCLK_DIV(_name, _reg) \ +- AXG_AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ +- "axg_mst_"#_name"_sclk_post_en", 0) \ +- +-static AXG_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); +-static AXG_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); +-static AXG_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); +-static AXG_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); +-static AXG_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); +-static AXG_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); +- +-#define AXG_MST_LRCLK(_name, _reg) \ +- AXG_AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ +- "axg_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) +- +-static AXG_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); +-static AXG_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); +-static AXG_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); +-static AXG_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); +-static AXG_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); +-static AXG_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); ++#define AUD_MST_SCLK(_name, _reg) \ ++ AUD_TRIPHASE(mst_##_name##_sclk, _reg, 1, 0, 2, 4, \ ++ "aud_mst_"#_name"_sclk_post_en", CLK_SET_RATE_PARENT) ++ ++static AUD_MST_SCLK(a, AUDIO_MST_A_SCLK_CTRL1); ++static AUD_MST_SCLK(b, AUDIO_MST_B_SCLK_CTRL1); ++static AUD_MST_SCLK(c, AUDIO_MST_C_SCLK_CTRL1); ++static AUD_MST_SCLK(d, AUDIO_MST_D_SCLK_CTRL1); ++static AUD_MST_SCLK(e, AUDIO_MST_E_SCLK_CTRL1); ++static AUD_MST_SCLK(f, AUDIO_MST_F_SCLK_CTRL1); ++ ++#define AUD_MST_LRCLK_DIV(_name, _reg) \ ++ AUD_SCLK_DIV(mst_##_name##_lrclk_div, _reg, 0, 10, 10, 10, \ ++ "aud_mst_"#_name"_sclk_post_en", 0) \ ++ ++static AUD_MST_LRCLK_DIV(a, AUDIO_MST_A_SCLK_CTRL0); ++static AUD_MST_LRCLK_DIV(b, AUDIO_MST_B_SCLK_CTRL0); ++static AUD_MST_LRCLK_DIV(c, AUDIO_MST_C_SCLK_CTRL0); ++static AUD_MST_LRCLK_DIV(d, AUDIO_MST_D_SCLK_CTRL0); ++static AUD_MST_LRCLK_DIV(e, AUDIO_MST_E_SCLK_CTRL0); ++static AUD_MST_LRCLK_DIV(f, AUDIO_MST_F_SCLK_CTRL0); ++ ++#define AUD_MST_LRCLK(_name, _reg) \ ++ AUD_TRIPHASE(mst_##_name##_lrclk, _reg, 1, 1, 3, 5, \ ++ "aud_mst_"#_name"_lrclk_div", CLK_SET_RATE_PARENT) ++ ++static AUD_MST_LRCLK(a, AUDIO_MST_A_SCLK_CTRL1); ++static AUD_MST_LRCLK(b, AUDIO_MST_B_SCLK_CTRL1); ++static AUD_MST_LRCLK(c, AUDIO_MST_C_SCLK_CTRL1); ++static AUD_MST_LRCLK(d, AUDIO_MST_D_SCLK_CTRL1); ++static AUD_MST_LRCLK(e, AUDIO_MST_E_SCLK_CTRL1); ++static AUD_MST_LRCLK(f, AUDIO_MST_F_SCLK_CTRL1); + + static const char * const tdm_sclk_parent_names[] = { +- "axg_mst_a_sclk", "axg_mst_b_sclk", "axg_mst_c_sclk", +- "axg_mst_d_sclk", "axg_mst_e_sclk", "axg_mst_f_sclk", +- "axg_slv_sclk0", "axg_slv_sclk1", "axg_slv_sclk2", +- "axg_slv_sclk3", "axg_slv_sclk4", "axg_slv_sclk5", +- "axg_slv_sclk6", "axg_slv_sclk7", "axg_slv_sclk8", +- "axg_slv_sclk9" ++ "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", ++ "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", ++ "aud_slv_sclk0", "aud_slv_sclk1", "aud_slv_sclk2", ++ "aud_slv_sclk3", "aud_slv_sclk4", "aud_slv_sclk5", ++ "aud_slv_sclk6", "aud_slv_sclk7", "aud_slv_sclk8", ++ "aud_slv_sclk9" + }; + +-#define AXG_TDM_SCLK_MUX(_name, _reg) \ +- AXG_AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ ++#define AUD_TDM_SCLK_MUX(_name, _reg) \ ++ AUD_MUX(tdm##_name##_sclk_sel, _reg, 0xf, 24, \ + CLK_MUX_ROUND_CLOSEST, \ + tdm_sclk_parent_names, 0) + +-static AXG_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); +-static AXG_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); +-static AXG_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); +-static AXG_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +-static AXG_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +-static AXG_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +-static AXG_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); +- +-#define AXG_TDM_SCLK_PRE_EN(_name, _reg) \ +- AXG_AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ +- "axg_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) +- +-static AXG_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); +-static AXG_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +-static AXG_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); +-static AXG_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +-static AXG_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +-static AXG_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +-static AXG_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); +- +-#define AXG_TDM_SCLK_POST_EN(_name, _reg) \ +- AXG_AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ +- "axg_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) +- +-static AXG_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); +-static AXG_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); +-static AXG_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); +-static AXG_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +-static AXG_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +-static AXG_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +-static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); +- +-#define AXG_TDM_SCLK(_name, _reg) \ +- struct clk_regmap axg_tdm##_name##_sclk = { \ ++static AUD_TDM_SCLK_MUX(in_a, AUDIO_CLK_TDMIN_A_CTRL); ++static AUD_TDM_SCLK_MUX(in_b, AUDIO_CLK_TDMIN_B_CTRL); ++static AUD_TDM_SCLK_MUX(in_c, AUDIO_CLK_TDMIN_C_CTRL); ++static AUD_TDM_SCLK_MUX(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); ++static AUD_TDM_SCLK_MUX(out_a, AUDIO_CLK_TDMOUT_A_CTRL); ++static AUD_TDM_SCLK_MUX(out_b, AUDIO_CLK_TDMOUT_B_CTRL); ++static AUD_TDM_SCLK_MUX(out_c, AUDIO_CLK_TDMOUT_C_CTRL); ++ ++#define AUD_TDM_SCLK_PRE_EN(_name, _reg) \ ++ AUD_GATE(tdm##_name##_sclk_pre_en, _reg, 31, \ ++ "aud_tdm"#_name"_sclk_sel", CLK_SET_RATE_PARENT) ++ ++static AUD_TDM_SCLK_PRE_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); ++static AUD_TDM_SCLK_PRE_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); ++static AUD_TDM_SCLK_PRE_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); ++static AUD_TDM_SCLK_PRE_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); ++static AUD_TDM_SCLK_PRE_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); ++static AUD_TDM_SCLK_PRE_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); ++static AUD_TDM_SCLK_PRE_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); ++ ++#define AUD_TDM_SCLK_POST_EN(_name, _reg) \ ++ AUD_GATE(tdm##_name##_sclk_post_en, _reg, 30, \ ++ "aud_tdm"#_name"_sclk_pre_en", CLK_SET_RATE_PARENT) ++ ++static AUD_TDM_SCLK_POST_EN(in_a, AUDIO_CLK_TDMIN_A_CTRL); ++static AUD_TDM_SCLK_POST_EN(in_b, AUDIO_CLK_TDMIN_B_CTRL); ++static AUD_TDM_SCLK_POST_EN(in_c, AUDIO_CLK_TDMIN_C_CTRL); ++static AUD_TDM_SCLK_POST_EN(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); ++static AUD_TDM_SCLK_POST_EN(out_a, AUDIO_CLK_TDMOUT_A_CTRL); ++static AUD_TDM_SCLK_POST_EN(out_b, AUDIO_CLK_TDMOUT_B_CTRL); ++static AUD_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); ++ ++#define AUD_TDM_SCLK(_name, _reg) \ ++ struct clk_regmap aud_tdm##_name##_sclk = { \ + .data = &(struct meson_clk_phase_data) { \ + .ph = { \ + .reg_off = (_reg), \ +@@ -338,44 +338,44 @@ static AXG_TDM_SCLK_POST_EN(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + }, \ + }, \ + .hw.init = &(struct clk_init_data) { \ +- .name = "axg_tdm"#_name"_sclk", \ ++ .name = "aud_tdm"#_name"_sclk", \ + .ops = &meson_clk_phase_ops, \ + .parent_names = (const char *[]) \ +- { "axg_tdm"#_name"_sclk_post_en" }, \ ++ { "aud_tdm"#_name"_sclk_post_en" }, \ + .num_parents = 1, \ + .flags = CLK_DUTY_CYCLE_PARENT | CLK_SET_RATE_PARENT, \ + }, \ + } + +-static AXG_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); +-static AXG_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +-static AXG_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); +-static AXG_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +-static AXG_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +-static AXG_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +-static AXG_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); ++static AUD_TDM_SCLK(in_a, AUDIO_CLK_TDMIN_A_CTRL); ++static AUD_TDM_SCLK(in_b, AUDIO_CLK_TDMIN_B_CTRL); ++static AUD_TDM_SCLK(in_c, AUDIO_CLK_TDMIN_C_CTRL); ++static AUD_TDM_SCLK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); ++static AUD_TDM_SCLK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); ++static AUD_TDM_SCLK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); ++static AUD_TDM_SCLK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + + static const char * const tdm_lrclk_parent_names[] = { +- "axg_mst_a_lrclk", "axg_mst_b_lrclk", "axg_mst_c_lrclk", +- "axg_mst_d_lrclk", "axg_mst_e_lrclk", "axg_mst_f_lrclk", +- "axg_slv_lrclk0", "axg_slv_lrclk1", "axg_slv_lrclk2", +- "axg_slv_lrclk3", "axg_slv_lrclk4", "axg_slv_lrclk5", +- "axg_slv_lrclk6", "axg_slv_lrclk7", "axg_slv_lrclk8", +- "axg_slv_lrclk9" ++ "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", ++ "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", ++ "aud_slv_lrclk0", "aud_slv_lrclk1", "aud_slv_lrclk2", ++ "aud_slv_lrclk3", "aud_slv_lrclk4", "aud_slv_lrclk5", ++ "aud_slv_lrclk6", "aud_slv_lrclk7", "aud_slv_lrclk8", ++ "aud_slv_lrclk9" + }; + +-#define AXG_TDM_LRLCK(_name, _reg) \ +- AXG_AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ +- CLK_MUX_ROUND_CLOSEST, \ +- tdm_lrclk_parent_names, 0) ++#define AUD_TDM_LRLCK(_name, _reg) \ ++ AUD_MUX(tdm##_name##_lrclk, _reg, 0xf, 20, \ ++ CLK_MUX_ROUND_CLOSEST, \ ++ tdm_lrclk_parent_names, 0) + +-static AXG_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); +-static AXG_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); +-static AXG_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); +-static AXG_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); +-static AXG_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); +-static AXG_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); +-static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); ++static AUD_TDM_LRLCK(in_a, AUDIO_CLK_TDMIN_A_CTRL); ++static AUD_TDM_LRLCK(in_b, AUDIO_CLK_TDMIN_B_CTRL); ++static AUD_TDM_LRLCK(in_c, AUDIO_CLK_TDMIN_C_CTRL); ++static AUD_TDM_LRLCK(in_lb, AUDIO_CLK_TDMIN_LB_CTRL); ++static AUD_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); ++static AUD_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); ++static AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + + /* + * Array of all clocks provided by this provider +@@ -383,255 +383,255 @@ static AXG_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + */ + static struct clk_hw_onecell_data axg_audio_hw_onecell_data = { + .hws = { +- [AUD_CLKID_DDR_ARB] = &axg_ddr_arb.hw, +- [AUD_CLKID_PDM] = &axg_pdm.hw, +- [AUD_CLKID_TDMIN_A] = &axg_tdmin_a.hw, +- [AUD_CLKID_TDMIN_B] = &axg_tdmin_b.hw, +- [AUD_CLKID_TDMIN_C] = &axg_tdmin_c.hw, +- [AUD_CLKID_TDMIN_LB] = &axg_tdmin_lb.hw, +- [AUD_CLKID_TDMOUT_A] = &axg_tdmout_a.hw, +- [AUD_CLKID_TDMOUT_B] = &axg_tdmout_b.hw, +- [AUD_CLKID_TDMOUT_C] = &axg_tdmout_c.hw, +- [AUD_CLKID_FRDDR_A] = &axg_frddr_a.hw, +- [AUD_CLKID_FRDDR_B] = &axg_frddr_b.hw, +- [AUD_CLKID_FRDDR_C] = &axg_frddr_c.hw, +- [AUD_CLKID_TODDR_A] = &axg_toddr_a.hw, +- [AUD_CLKID_TODDR_B] = &axg_toddr_b.hw, +- [AUD_CLKID_TODDR_C] = &axg_toddr_c.hw, +- [AUD_CLKID_LOOPBACK] = &axg_loopback.hw, +- [AUD_CLKID_SPDIFIN] = &axg_spdifin.hw, +- [AUD_CLKID_SPDIFOUT] = &axg_spdifout.hw, +- [AUD_CLKID_RESAMPLE] = &axg_resample.hw, +- [AUD_CLKID_POWER_DETECT] = &axg_power_detect.hw, +- [AUD_CLKID_MST_A_MCLK_SEL] = &axg_mst_a_mclk_sel.hw, +- [AUD_CLKID_MST_B_MCLK_SEL] = &axg_mst_b_mclk_sel.hw, +- [AUD_CLKID_MST_C_MCLK_SEL] = &axg_mst_c_mclk_sel.hw, +- [AUD_CLKID_MST_D_MCLK_SEL] = &axg_mst_d_mclk_sel.hw, +- [AUD_CLKID_MST_E_MCLK_SEL] = &axg_mst_e_mclk_sel.hw, +- [AUD_CLKID_MST_F_MCLK_SEL] = &axg_mst_f_mclk_sel.hw, +- [AUD_CLKID_MST_A_MCLK_DIV] = &axg_mst_a_mclk_div.hw, +- [AUD_CLKID_MST_B_MCLK_DIV] = &axg_mst_b_mclk_div.hw, +- [AUD_CLKID_MST_C_MCLK_DIV] = &axg_mst_c_mclk_div.hw, +- [AUD_CLKID_MST_D_MCLK_DIV] = &axg_mst_d_mclk_div.hw, +- [AUD_CLKID_MST_E_MCLK_DIV] = &axg_mst_e_mclk_div.hw, +- [AUD_CLKID_MST_F_MCLK_DIV] = &axg_mst_f_mclk_div.hw, +- [AUD_CLKID_MST_A_MCLK] = &axg_mst_a_mclk.hw, +- [AUD_CLKID_MST_B_MCLK] = &axg_mst_b_mclk.hw, +- [AUD_CLKID_MST_C_MCLK] = &axg_mst_c_mclk.hw, +- [AUD_CLKID_MST_D_MCLK] = &axg_mst_d_mclk.hw, +- [AUD_CLKID_MST_E_MCLK] = &axg_mst_e_mclk.hw, +- [AUD_CLKID_MST_F_MCLK] = &axg_mst_f_mclk.hw, +- [AUD_CLKID_SPDIFOUT_CLK_SEL] = &axg_spdifout_clk_sel.hw, +- [AUD_CLKID_SPDIFOUT_CLK_DIV] = &axg_spdifout_clk_div.hw, +- [AUD_CLKID_SPDIFOUT_CLK] = &axg_spdifout_clk.hw, +- [AUD_CLKID_SPDIFIN_CLK_SEL] = &axg_spdifin_clk_sel.hw, +- [AUD_CLKID_SPDIFIN_CLK_DIV] = &axg_spdifin_clk_div.hw, +- [AUD_CLKID_SPDIFIN_CLK] = &axg_spdifin_clk.hw, +- [AUD_CLKID_PDM_DCLK_SEL] = &axg_pdm_dclk_sel.hw, +- [AUD_CLKID_PDM_DCLK_DIV] = &axg_pdm_dclk_div.hw, +- [AUD_CLKID_PDM_DCLK] = &axg_pdm_dclk.hw, +- [AUD_CLKID_PDM_SYSCLK_SEL] = &axg_pdm_sysclk_sel.hw, +- [AUD_CLKID_PDM_SYSCLK_DIV] = &axg_pdm_sysclk_div.hw, +- [AUD_CLKID_PDM_SYSCLK] = &axg_pdm_sysclk.hw, +- [AUD_CLKID_MST_A_SCLK_PRE_EN] = &axg_mst_a_sclk_pre_en.hw, +- [AUD_CLKID_MST_B_SCLK_PRE_EN] = &axg_mst_b_sclk_pre_en.hw, +- [AUD_CLKID_MST_C_SCLK_PRE_EN] = &axg_mst_c_sclk_pre_en.hw, +- [AUD_CLKID_MST_D_SCLK_PRE_EN] = &axg_mst_d_sclk_pre_en.hw, +- [AUD_CLKID_MST_E_SCLK_PRE_EN] = &axg_mst_e_sclk_pre_en.hw, +- [AUD_CLKID_MST_F_SCLK_PRE_EN] = &axg_mst_f_sclk_pre_en.hw, +- [AUD_CLKID_MST_A_SCLK_DIV] = &axg_mst_a_sclk_div.hw, +- [AUD_CLKID_MST_B_SCLK_DIV] = &axg_mst_b_sclk_div.hw, +- [AUD_CLKID_MST_C_SCLK_DIV] = &axg_mst_c_sclk_div.hw, +- [AUD_CLKID_MST_D_SCLK_DIV] = &axg_mst_d_sclk_div.hw, +- [AUD_CLKID_MST_E_SCLK_DIV] = &axg_mst_e_sclk_div.hw, +- [AUD_CLKID_MST_F_SCLK_DIV] = &axg_mst_f_sclk_div.hw, +- [AUD_CLKID_MST_A_SCLK_POST_EN] = &axg_mst_a_sclk_post_en.hw, +- [AUD_CLKID_MST_B_SCLK_POST_EN] = &axg_mst_b_sclk_post_en.hw, +- [AUD_CLKID_MST_C_SCLK_POST_EN] = &axg_mst_c_sclk_post_en.hw, +- [AUD_CLKID_MST_D_SCLK_POST_EN] = &axg_mst_d_sclk_post_en.hw, +- [AUD_CLKID_MST_E_SCLK_POST_EN] = &axg_mst_e_sclk_post_en.hw, +- [AUD_CLKID_MST_F_SCLK_POST_EN] = &axg_mst_f_sclk_post_en.hw, +- [AUD_CLKID_MST_A_SCLK] = &axg_mst_a_sclk.hw, +- [AUD_CLKID_MST_B_SCLK] = &axg_mst_b_sclk.hw, +- [AUD_CLKID_MST_C_SCLK] = &axg_mst_c_sclk.hw, +- [AUD_CLKID_MST_D_SCLK] = &axg_mst_d_sclk.hw, +- [AUD_CLKID_MST_E_SCLK] = &axg_mst_e_sclk.hw, +- [AUD_CLKID_MST_F_SCLK] = &axg_mst_f_sclk.hw, +- [AUD_CLKID_MST_A_LRCLK_DIV] = &axg_mst_a_lrclk_div.hw, +- [AUD_CLKID_MST_B_LRCLK_DIV] = &axg_mst_b_lrclk_div.hw, +- [AUD_CLKID_MST_C_LRCLK_DIV] = &axg_mst_c_lrclk_div.hw, +- [AUD_CLKID_MST_D_LRCLK_DIV] = &axg_mst_d_lrclk_div.hw, +- [AUD_CLKID_MST_E_LRCLK_DIV] = &axg_mst_e_lrclk_div.hw, +- [AUD_CLKID_MST_F_LRCLK_DIV] = &axg_mst_f_lrclk_div.hw, +- [AUD_CLKID_MST_A_LRCLK] = &axg_mst_a_lrclk.hw, +- [AUD_CLKID_MST_B_LRCLK] = &axg_mst_b_lrclk.hw, +- [AUD_CLKID_MST_C_LRCLK] = &axg_mst_c_lrclk.hw, +- [AUD_CLKID_MST_D_LRCLK] = &axg_mst_d_lrclk.hw, +- [AUD_CLKID_MST_E_LRCLK] = &axg_mst_e_lrclk.hw, +- [AUD_CLKID_MST_F_LRCLK] = &axg_mst_f_lrclk.hw, +- [AUD_CLKID_TDMIN_A_SCLK_SEL] = &axg_tdmin_a_sclk_sel.hw, +- [AUD_CLKID_TDMIN_B_SCLK_SEL] = &axg_tdmin_b_sclk_sel.hw, +- [AUD_CLKID_TDMIN_C_SCLK_SEL] = &axg_tdmin_c_sclk_sel.hw, +- [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &axg_tdmin_lb_sclk_sel.hw, +- [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &axg_tdmout_a_sclk_sel.hw, +- [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &axg_tdmout_b_sclk_sel.hw, +- [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &axg_tdmout_c_sclk_sel.hw, +- [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &axg_tdmin_a_sclk_pre_en.hw, +- [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &axg_tdmin_b_sclk_pre_en.hw, +- [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &axg_tdmin_c_sclk_pre_en.hw, +- [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &axg_tdmin_lb_sclk_pre_en.hw, +- [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &axg_tdmout_a_sclk_pre_en.hw, +- [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &axg_tdmout_b_sclk_pre_en.hw, +- [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &axg_tdmout_c_sclk_pre_en.hw, +- [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &axg_tdmin_a_sclk_post_en.hw, +- [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &axg_tdmin_b_sclk_post_en.hw, +- [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &axg_tdmin_c_sclk_post_en.hw, +- [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &axg_tdmin_lb_sclk_post_en.hw, +- [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &axg_tdmout_a_sclk_post_en.hw, +- [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &axg_tdmout_b_sclk_post_en.hw, +- [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &axg_tdmout_c_sclk_post_en.hw, +- [AUD_CLKID_TDMIN_A_SCLK] = &axg_tdmin_a_sclk.hw, +- [AUD_CLKID_TDMIN_B_SCLK] = &axg_tdmin_b_sclk.hw, +- [AUD_CLKID_TDMIN_C_SCLK] = &axg_tdmin_c_sclk.hw, +- [AUD_CLKID_TDMIN_LB_SCLK] = &axg_tdmin_lb_sclk.hw, +- [AUD_CLKID_TDMOUT_A_SCLK] = &axg_tdmout_a_sclk.hw, +- [AUD_CLKID_TDMOUT_B_SCLK] = &axg_tdmout_b_sclk.hw, +- [AUD_CLKID_TDMOUT_C_SCLK] = &axg_tdmout_c_sclk.hw, +- [AUD_CLKID_TDMIN_A_LRCLK] = &axg_tdmin_a_lrclk.hw, +- [AUD_CLKID_TDMIN_B_LRCLK] = &axg_tdmin_b_lrclk.hw, +- [AUD_CLKID_TDMIN_C_LRCLK] = &axg_tdmin_c_lrclk.hw, +- [AUD_CLKID_TDMIN_LB_LRCLK] = &axg_tdmin_lb_lrclk.hw, +- [AUD_CLKID_TDMOUT_A_LRCLK] = &axg_tdmout_a_lrclk.hw, +- [AUD_CLKID_TDMOUT_B_LRCLK] = &axg_tdmout_b_lrclk.hw, +- [AUD_CLKID_TDMOUT_C_LRCLK] = &axg_tdmout_c_lrclk.hw, ++ [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw, ++ [AUD_CLKID_PDM] = &aud_pdm.hw, ++ [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw, ++ [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw, ++ [AUD_CLKID_TDMIN_C] = &aud_tdmin_c.hw, ++ [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw, ++ [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw, ++ [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw, ++ [AUD_CLKID_TDMOUT_C] = &aud_tdmout_c.hw, ++ [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw, ++ [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw, ++ [AUD_CLKID_FRDDR_C] = &aud_frddr_c.hw, ++ [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw, ++ [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw, ++ [AUD_CLKID_TODDR_C] = &aud_toddr_c.hw, ++ [AUD_CLKID_LOOPBACK] = &aud_loopback.hw, ++ [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw, ++ [AUD_CLKID_SPDIFOUT] = &aud_spdifout.hw, ++ [AUD_CLKID_RESAMPLE] = &aud_resample.hw, ++ [AUD_CLKID_POWER_DETECT] = &aud_power_detect.hw, ++ [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw, ++ [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw, ++ [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw, ++ [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw, ++ [AUD_CLKID_MST_E_MCLK_SEL] = &aud_mst_e_mclk_sel.hw, ++ [AUD_CLKID_MST_F_MCLK_SEL] = &aud_mst_f_mclk_sel.hw, ++ [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw, ++ [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw, ++ [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw, ++ [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw, ++ [AUD_CLKID_MST_E_MCLK_DIV] = &aud_mst_e_mclk_div.hw, ++ [AUD_CLKID_MST_F_MCLK_DIV] = &aud_mst_f_mclk_div.hw, ++ [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw, ++ [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw, ++ [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw, ++ [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw, ++ [AUD_CLKID_MST_E_MCLK] = &aud_mst_e_mclk.hw, ++ [AUD_CLKID_MST_F_MCLK] = &aud_mst_f_mclk.hw, ++ [AUD_CLKID_SPDIFOUT_CLK_SEL] = &aud_spdifout_clk_sel.hw, ++ [AUD_CLKID_SPDIFOUT_CLK_DIV] = &aud_spdifout_clk_div.hw, ++ [AUD_CLKID_SPDIFOUT_CLK] = &aud_spdifout_clk.hw, ++ [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw, ++ [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw, ++ [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw, ++ [AUD_CLKID_PDM_DCLK_SEL] = &aud_pdm_dclk_sel.hw, ++ [AUD_CLKID_PDM_DCLK_DIV] = &aud_pdm_dclk_div.hw, ++ [AUD_CLKID_PDM_DCLK] = &aud_pdm_dclk.hw, ++ [AUD_CLKID_PDM_SYSCLK_SEL] = &aud_pdm_sysclk_sel.hw, ++ [AUD_CLKID_PDM_SYSCLK_DIV] = &aud_pdm_sysclk_div.hw, ++ [AUD_CLKID_PDM_SYSCLK] = &aud_pdm_sysclk.hw, ++ [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw, ++ [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw, ++ [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw, ++ [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw, ++ [AUD_CLKID_MST_E_SCLK_PRE_EN] = &aud_mst_e_sclk_pre_en.hw, ++ [AUD_CLKID_MST_F_SCLK_PRE_EN] = &aud_mst_f_sclk_pre_en.hw, ++ [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw, ++ [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw, ++ [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw, ++ [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw, ++ [AUD_CLKID_MST_E_SCLK_DIV] = &aud_mst_e_sclk_div.hw, ++ [AUD_CLKID_MST_F_SCLK_DIV] = &aud_mst_f_sclk_div.hw, ++ [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw, ++ [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw, ++ [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw, ++ [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw, ++ [AUD_CLKID_MST_E_SCLK_POST_EN] = &aud_mst_e_sclk_post_en.hw, ++ [AUD_CLKID_MST_F_SCLK_POST_EN] = &aud_mst_f_sclk_post_en.hw, ++ [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw, ++ [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw, ++ [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw, ++ [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw, ++ [AUD_CLKID_MST_E_SCLK] = &aud_mst_e_sclk.hw, ++ [AUD_CLKID_MST_F_SCLK] = &aud_mst_f_sclk.hw, ++ [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw, ++ [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw, ++ [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw, ++ [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw, ++ [AUD_CLKID_MST_E_LRCLK_DIV] = &aud_mst_e_lrclk_div.hw, ++ [AUD_CLKID_MST_F_LRCLK_DIV] = &aud_mst_f_lrclk_div.hw, ++ [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw, ++ [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw, ++ [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw, ++ [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw, ++ [AUD_CLKID_MST_E_LRCLK] = &aud_mst_e_lrclk.hw, ++ [AUD_CLKID_MST_F_LRCLK] = &aud_mst_f_lrclk.hw, ++ [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw, ++ [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw, ++ [AUD_CLKID_TDMIN_C_SCLK_SEL] = &aud_tdmin_c_sclk_sel.hw, ++ [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw, ++ [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw, ++ [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw, ++ [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &aud_tdmout_c_sclk_sel.hw, ++ [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw, ++ [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw, ++ [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &aud_tdmin_c_sclk_pre_en.hw, ++ [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw, ++ [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw, ++ [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw, ++ [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &aud_tdmout_c_sclk_pre_en.hw, ++ [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw, ++ [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw, ++ [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &aud_tdmin_c_sclk_post_en.hw, ++ [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw, ++ [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw, ++ [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw, ++ [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &aud_tdmout_c_sclk_post_en.hw, ++ [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw, ++ [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw, ++ [AUD_CLKID_TDMIN_C_SCLK] = &aud_tdmin_c_sclk.hw, ++ [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw, ++ [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw, ++ [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw, ++ [AUD_CLKID_TDMOUT_C_SCLK] = &aud_tdmout_c_sclk.hw, ++ [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw, ++ [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw, ++ [AUD_CLKID_TDMIN_C_LRCLK] = &aud_tdmin_c_lrclk.hw, ++ [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw, ++ [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw, ++ [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw, ++ [AUD_CLKID_TDMOUT_C_LRCLK] = &aud_tdmout_c_lrclk.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, + }; + + /* Convenience table to populate regmap in .probe() */ +-static struct clk_regmap *const axg_audio_clk_regmaps[] = { +- &axg_ddr_arb, +- &axg_pdm, +- &axg_tdmin_a, +- &axg_tdmin_b, +- &axg_tdmin_c, +- &axg_tdmin_lb, +- &axg_tdmout_a, +- &axg_tdmout_b, +- &axg_tdmout_c, +- &axg_frddr_a, +- &axg_frddr_b, +- &axg_frddr_c, +- &axg_toddr_a, +- &axg_toddr_b, +- &axg_toddr_c, +- &axg_loopback, +- &axg_spdifin, +- &axg_spdifout, +- &axg_resample, +- &axg_power_detect, +- &axg_mst_a_mclk_sel, +- &axg_mst_b_mclk_sel, +- &axg_mst_c_mclk_sel, +- &axg_mst_d_mclk_sel, +- &axg_mst_e_mclk_sel, +- &axg_mst_f_mclk_sel, +- &axg_mst_a_mclk_div, +- &axg_mst_b_mclk_div, +- &axg_mst_c_mclk_div, +- &axg_mst_d_mclk_div, +- &axg_mst_e_mclk_div, +- &axg_mst_f_mclk_div, +- &axg_mst_a_mclk, +- &axg_mst_b_mclk, +- &axg_mst_c_mclk, +- &axg_mst_d_mclk, +- &axg_mst_e_mclk, +- &axg_mst_f_mclk, +- &axg_spdifout_clk_sel, +- &axg_spdifout_clk_div, +- &axg_spdifout_clk, +- &axg_spdifin_clk_sel, +- &axg_spdifin_clk_div, +- &axg_spdifin_clk, +- &axg_pdm_dclk_sel, +- &axg_pdm_dclk_div, +- &axg_pdm_dclk, +- &axg_pdm_sysclk_sel, +- &axg_pdm_sysclk_div, +- &axg_pdm_sysclk, +- &axg_mst_a_sclk_pre_en, +- &axg_mst_b_sclk_pre_en, +- &axg_mst_c_sclk_pre_en, +- &axg_mst_d_sclk_pre_en, +- &axg_mst_e_sclk_pre_en, +- &axg_mst_f_sclk_pre_en, +- &axg_mst_a_sclk_div, +- &axg_mst_b_sclk_div, +- &axg_mst_c_sclk_div, +- &axg_mst_d_sclk_div, +- &axg_mst_e_sclk_div, +- &axg_mst_f_sclk_div, +- &axg_mst_a_sclk_post_en, +- &axg_mst_b_sclk_post_en, +- &axg_mst_c_sclk_post_en, +- &axg_mst_d_sclk_post_en, +- &axg_mst_e_sclk_post_en, +- &axg_mst_f_sclk_post_en, +- &axg_mst_a_sclk, +- &axg_mst_b_sclk, +- &axg_mst_c_sclk, +- &axg_mst_d_sclk, +- &axg_mst_e_sclk, +- &axg_mst_f_sclk, +- &axg_mst_a_lrclk_div, +- &axg_mst_b_lrclk_div, +- &axg_mst_c_lrclk_div, +- &axg_mst_d_lrclk_div, +- &axg_mst_e_lrclk_div, +- &axg_mst_f_lrclk_div, +- &axg_mst_a_lrclk, +- &axg_mst_b_lrclk, +- &axg_mst_c_lrclk, +- &axg_mst_d_lrclk, +- &axg_mst_e_lrclk, +- &axg_mst_f_lrclk, +- &axg_tdmin_a_sclk_sel, +- &axg_tdmin_b_sclk_sel, +- &axg_tdmin_c_sclk_sel, +- &axg_tdmin_lb_sclk_sel, +- &axg_tdmout_a_sclk_sel, +- &axg_tdmout_b_sclk_sel, +- &axg_tdmout_c_sclk_sel, +- &axg_tdmin_a_sclk_pre_en, +- &axg_tdmin_b_sclk_pre_en, +- &axg_tdmin_c_sclk_pre_en, +- &axg_tdmin_lb_sclk_pre_en, +- &axg_tdmout_a_sclk_pre_en, +- &axg_tdmout_b_sclk_pre_en, +- &axg_tdmout_c_sclk_pre_en, +- &axg_tdmin_a_sclk_post_en, +- &axg_tdmin_b_sclk_post_en, +- &axg_tdmin_c_sclk_post_en, +- &axg_tdmin_lb_sclk_post_en, +- &axg_tdmout_a_sclk_post_en, +- &axg_tdmout_b_sclk_post_en, +- &axg_tdmout_c_sclk_post_en, +- &axg_tdmin_a_sclk, +- &axg_tdmin_b_sclk, +- &axg_tdmin_c_sclk, +- &axg_tdmin_lb_sclk, +- &axg_tdmout_a_sclk, +- &axg_tdmout_b_sclk, +- &axg_tdmout_c_sclk, +- &axg_tdmin_a_lrclk, +- &axg_tdmin_b_lrclk, +- &axg_tdmin_c_lrclk, +- &axg_tdmin_lb_lrclk, +- &axg_tdmout_a_lrclk, +- &axg_tdmout_b_lrclk, +- &axg_tdmout_c_lrclk, ++static struct clk_regmap *const aud_clk_regmaps[] = { ++ &aud_ddr_arb, ++ &aud_pdm, ++ &aud_tdmin_a, ++ &aud_tdmin_b, ++ &aud_tdmin_c, ++ &aud_tdmin_lb, ++ &aud_tdmout_a, ++ &aud_tdmout_b, ++ &aud_tdmout_c, ++ &aud_frddr_a, ++ &aud_frddr_b, ++ &aud_frddr_c, ++ &aud_toddr_a, ++ &aud_toddr_b, ++ &aud_toddr_c, ++ &aud_loopback, ++ &aud_spdifin, ++ &aud_spdifout, ++ &aud_resample, ++ &aud_power_detect, ++ &aud_mst_a_mclk_sel, ++ &aud_mst_b_mclk_sel, ++ &aud_mst_c_mclk_sel, ++ &aud_mst_d_mclk_sel, ++ &aud_mst_e_mclk_sel, ++ &aud_mst_f_mclk_sel, ++ &aud_mst_a_mclk_div, ++ &aud_mst_b_mclk_div, ++ &aud_mst_c_mclk_div, ++ &aud_mst_d_mclk_div, ++ &aud_mst_e_mclk_div, ++ &aud_mst_f_mclk_div, ++ &aud_mst_a_mclk, ++ &aud_mst_b_mclk, ++ &aud_mst_c_mclk, ++ &aud_mst_d_mclk, ++ &aud_mst_e_mclk, ++ &aud_mst_f_mclk, ++ &aud_spdifout_clk_sel, ++ &aud_spdifout_clk_div, ++ &aud_spdifout_clk, ++ &aud_spdifin_clk_sel, ++ &aud_spdifin_clk_div, ++ &aud_spdifin_clk, ++ &aud_pdm_dclk_sel, ++ &aud_pdm_dclk_div, ++ &aud_pdm_dclk, ++ &aud_pdm_sysclk_sel, ++ &aud_pdm_sysclk_div, ++ &aud_pdm_sysclk, ++ &aud_mst_a_sclk_pre_en, ++ &aud_mst_b_sclk_pre_en, ++ &aud_mst_c_sclk_pre_en, ++ &aud_mst_d_sclk_pre_en, ++ &aud_mst_e_sclk_pre_en, ++ &aud_mst_f_sclk_pre_en, ++ &aud_mst_a_sclk_div, ++ &aud_mst_b_sclk_div, ++ &aud_mst_c_sclk_div, ++ &aud_mst_d_sclk_div, ++ &aud_mst_e_sclk_div, ++ &aud_mst_f_sclk_div, ++ &aud_mst_a_sclk_post_en, ++ &aud_mst_b_sclk_post_en, ++ &aud_mst_c_sclk_post_en, ++ &aud_mst_d_sclk_post_en, ++ &aud_mst_e_sclk_post_en, ++ &aud_mst_f_sclk_post_en, ++ &aud_mst_a_sclk, ++ &aud_mst_b_sclk, ++ &aud_mst_c_sclk, ++ &aud_mst_d_sclk, ++ &aud_mst_e_sclk, ++ &aud_mst_f_sclk, ++ &aud_mst_a_lrclk_div, ++ &aud_mst_b_lrclk_div, ++ &aud_mst_c_lrclk_div, ++ &aud_mst_d_lrclk_div, ++ &aud_mst_e_lrclk_div, ++ &aud_mst_f_lrclk_div, ++ &aud_mst_a_lrclk, ++ &aud_mst_b_lrclk, ++ &aud_mst_c_lrclk, ++ &aud_mst_d_lrclk, ++ &aud_mst_e_lrclk, ++ &aud_mst_f_lrclk, ++ &aud_tdmin_a_sclk_sel, ++ &aud_tdmin_b_sclk_sel, ++ &aud_tdmin_c_sclk_sel, ++ &aud_tdmin_lb_sclk_sel, ++ &aud_tdmout_a_sclk_sel, ++ &aud_tdmout_b_sclk_sel, ++ &aud_tdmout_c_sclk_sel, ++ &aud_tdmin_a_sclk_pre_en, ++ &aud_tdmin_b_sclk_pre_en, ++ &aud_tdmin_c_sclk_pre_en, ++ &aud_tdmin_lb_sclk_pre_en, ++ &aud_tdmout_a_sclk_pre_en, ++ &aud_tdmout_b_sclk_pre_en, ++ &aud_tdmout_c_sclk_pre_en, ++ &aud_tdmin_a_sclk_post_en, ++ &aud_tdmin_b_sclk_post_en, ++ &aud_tdmin_c_sclk_post_en, ++ &aud_tdmin_lb_sclk_post_en, ++ &aud_tdmout_a_sclk_post_en, ++ &aud_tdmout_b_sclk_post_en, ++ &aud_tdmout_c_sclk_post_en, ++ &aud_tdmin_a_sclk, ++ &aud_tdmin_b_sclk, ++ &aud_tdmin_c_sclk, ++ &aud_tdmin_lb_sclk, ++ &aud_tdmout_a_sclk, ++ &aud_tdmout_b_sclk, ++ &aud_tdmout_c_sclk, ++ &aud_tdmin_a_lrclk, ++ &aud_tdmin_b_lrclk, ++ &aud_tdmin_c_lrclk, ++ &aud_tdmin_lb_lrclk, ++ &aud_tdmout_a_lrclk, ++ &aud_tdmout_b_lrclk, ++ &aud_tdmout_c_lrclk, + }; + + static int devm_clk_get_enable(struct device *dev, char *id) +@@ -672,7 +672,7 @@ static int axg_register_clk_hw_input(struct device *dev, + struct clk_hw *hw; + int err = 0; + +- clk_name = kasprintf(GFP_KERNEL, "axg_%s", name); ++ clk_name = kasprintf(GFP_KERNEL, "aud_%s", name); + if (!clk_name) + return -ENOMEM; + +@@ -755,7 +755,7 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) + } + + /* Register the peripheral input clock */ +- hw = meson_clk_hw_register_input(dev, "pclk", "axg_audio_pclk", 0); ++ hw = meson_clk_hw_register_input(dev, "pclk", "audio_pclk", 0); + if (IS_ERR(hw)) + return PTR_ERR(hw); + +@@ -763,28 +763,28 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) + + /* Register optional input master clocks */ + ret = axg_register_clk_hw_inputs(dev, "mst_in", +- AXG_MST_IN_COUNT, ++ AUD_MST_IN_COUNT, + AUD_CLKID_MST0); + if (ret) + return ret; + + /* Register optional input slave sclks */ + ret = axg_register_clk_hw_inputs(dev, "slv_sclk", +- AXG_SLV_SCLK_COUNT, ++ AUD_SLV_SCLK_COUNT, + AUD_CLKID_SLV_SCLK0); + if (ret) + return ret; + + /* Register optional input slave lrclks */ + ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", +- AXG_SLV_LRCLK_COUNT, ++ AUD_SLV_LRCLK_COUNT, + AUD_CLKID_SLV_LRCLK0); + if (ret) + return ret; + + /* Populate regmap for the regmap backed clocks */ +- for (i = 0; i < ARRAY_SIZE(axg_audio_clk_regmaps); i++) +- axg_audio_clk_regmaps[i]->map = map; ++ for (i = 0; i < ARRAY_SIZE(aud_clk_regmaps); i++) ++ aud_clk_regmaps[i]->map = map; + + /* Take care to skip the registered input clocks */ + for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) { + +From 1d83a59947004b402cb632893dd8f1e449d4a6bc Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 29 Mar 2019 17:06:48 +0100 +Subject: [PATCH 035/249] FROMGIT: clk: meson: axg-audio: don't register inputs + in the onecell data + +Clock inputs should not be exported outside the controller. It is a hack +to have a stable global clock name within the clock controller, even for +clocks external to the controller. + +There is an ongoing effort to replace this hack with something better. +The first step is to not register those clocks in the provider anymore, +so we can completely remove them later on. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190329160649.31603-4-jbrunet@baylibre.com +(cherry picked from commit 6d6d2a24b2c7a717a75f4e5f3a0e2ebd35ae5573 + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/axg-audio.c | 21 ++++++--------------- + drivers/clk/meson/axg-audio.h | 29 ----------------------------- + 2 files changed, 6 insertions(+), 44 deletions(-) + +diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c +index 38fccffc171ea..e8516f9c03d31 100644 +--- a/drivers/clk/meson/axg-audio.c ++++ b/drivers/clk/meson/axg-audio.c +@@ -665,8 +665,7 @@ static int devm_clk_get_enable(struct device *dev, char *id) + } + + static int axg_register_clk_hw_input(struct device *dev, +- const char *name, +- unsigned int clkid) ++ const char *name) + { + char *clk_name; + struct clk_hw *hw; +@@ -686,8 +685,6 @@ static int axg_register_clk_hw_input(struct device *dev, + if (err != -EPROBE_DEFER) + dev_err(dev, "failed to get %s clock", name); + } +- } else { +- axg_audio_hw_onecell_data.hws[clkid] = hw; + } + + kfree(clk_name); +@@ -696,8 +693,7 @@ static int axg_register_clk_hw_input(struct device *dev, + + static int axg_register_clk_hw_inputs(struct device *dev, + const char *basename, +- unsigned int count, +- unsigned int clkid) ++ unsigned int count) + { + char *name; + int i, ret; +@@ -707,7 +703,7 @@ static int axg_register_clk_hw_inputs(struct device *dev, + if (!name) + return -ENOMEM; + +- ret = axg_register_clk_hw_input(dev, name, clkid + i); ++ ret = axg_register_clk_hw_input(dev, name); + kfree(name); + if (ret) + return ret; +@@ -759,26 +755,21 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) + if (IS_ERR(hw)) + return PTR_ERR(hw); + +- axg_audio_hw_onecell_data.hws[AUD_CLKID_PCLK] = hw; +- + /* Register optional input master clocks */ + ret = axg_register_clk_hw_inputs(dev, "mst_in", +- AUD_MST_IN_COUNT, +- AUD_CLKID_MST0); ++ AUD_MST_IN_COUNT); + if (ret) + return ret; + + /* Register optional input slave sclks */ + ret = axg_register_clk_hw_inputs(dev, "slv_sclk", +- AUD_SLV_SCLK_COUNT, +- AUD_CLKID_SLV_SCLK0); ++ AUD_SLV_SCLK_COUNT); + if (ret) + return ret; + + /* Register optional input slave lrclks */ + ret = axg_register_clk_hw_inputs(dev, "slv_lrclk", +- AUD_SLV_LRCLK_COUNT, +- AUD_CLKID_SLV_LRCLK0); ++ AUD_SLV_LRCLK_COUNT); + if (ret) + return ret; + +diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h +index 644f0b0fddf25..9644c2ff0b3b6 100644 +--- a/drivers/clk/meson/axg-audio.h ++++ b/drivers/clk/meson/axg-audio.h +@@ -51,35 +51,6 @@ + * These indices are entirely contrived and do not map onto the hardware. + */ + +-#define AUD_CLKID_PCLK 0 +-#define AUD_CLKID_MST0 1 +-#define AUD_CLKID_MST1 2 +-#define AUD_CLKID_MST2 3 +-#define AUD_CLKID_MST3 4 +-#define AUD_CLKID_MST4 5 +-#define AUD_CLKID_MST5 6 +-#define AUD_CLKID_MST6 7 +-#define AUD_CLKID_MST7 8 +-#define AUD_CLKID_SLV_SCLK0 9 +-#define AUD_CLKID_SLV_SCLK1 10 +-#define AUD_CLKID_SLV_SCLK2 11 +-#define AUD_CLKID_SLV_SCLK3 12 +-#define AUD_CLKID_SLV_SCLK4 13 +-#define AUD_CLKID_SLV_SCLK5 14 +-#define AUD_CLKID_SLV_SCLK6 15 +-#define AUD_CLKID_SLV_SCLK7 16 +-#define AUD_CLKID_SLV_SCLK8 17 +-#define AUD_CLKID_SLV_SCLK9 18 +-#define AUD_CLKID_SLV_LRCLK0 19 +-#define AUD_CLKID_SLV_LRCLK1 20 +-#define AUD_CLKID_SLV_LRCLK2 21 +-#define AUD_CLKID_SLV_LRCLK3 22 +-#define AUD_CLKID_SLV_LRCLK4 23 +-#define AUD_CLKID_SLV_LRCLK5 24 +-#define AUD_CLKID_SLV_LRCLK6 25 +-#define AUD_CLKID_SLV_LRCLK7 26 +-#define AUD_CLKID_SLV_LRCLK8 27 +-#define AUD_CLKID_SLV_LRCLK9 28 + #define AUD_CLKID_MST_A_MCLK_SEL 59 + #define AUD_CLKID_MST_B_MCLK_SEL 60 + #define AUD_CLKID_MST_C_MCLK_SEL 61 + +From 046266fc6983d305c06f8e52d5df3f60a1007858 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Fri, 29 Mar 2019 17:06:49 +0100 +Subject: [PATCH 036/249] FROMGIT: clk: meson: axg-audio: add g12a support + +The g12a audio clock controller is largely similar to the existing axg +controller, with the addition of the spdif output B and TDM pad clocks. + +This commit extends the existing axg audio clock controller driver +to work with multiple compatibles and add the g12a specific clocks + +Signed-off-by: Maxime Jourdan +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190329160649.31603-5-jbrunet@baylibre.com +(cherry picked from commit 075001385c66a00fba9810b9ecb88d644384df88 + https://github.com/BayLibre/clk-meson/ next/drivers) +--- + drivers/clk/meson/axg-audio.c | 240 +++++++++++++++++++++++++++++++++- + drivers/clk/meson/axg-audio.h | 7 +- + 2 files changed, 239 insertions(+), 8 deletions(-) + +diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c +index e8516f9c03d31..8028ff6f66107 100644 +--- a/drivers/clk/meson/axg-audio.c ++++ b/drivers/clk/meson/axg-audio.c +@@ -97,6 +97,7 @@ static AUD_PCLK_GATE(spdifin, 16); + static AUD_PCLK_GATE(spdifout, 17); + static AUD_PCLK_GATE(resample, 18); + static AUD_PCLK_GATE(power_detect, 19); ++static AUD_PCLK_GATE(spdifout_b, 21); + + /* Audio Master Clocks */ + static const char * const mst_mux_parent_names[] = { +@@ -124,6 +125,7 @@ static AUD_MST_MCLK_MUX(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); + static AUD_MST_MCLK_MUX(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); + static AUD_MST_SYS_MUX(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); + static AUD_MST_SYS_MUX(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); ++static AUD_MST_MCLK_MUX(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + + #define AUD_MST_DIV(_name, _reg, _flag) \ + AUD_DIV(_name##_div, _reg, 0, 16, _flag, \ +@@ -145,6 +147,7 @@ static AUD_MST_MCLK_DIV(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); + static AUD_MST_MCLK_DIV(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); + static AUD_MST_SYS_DIV(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); + static AUD_MST_SYS_DIV(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); ++static AUD_MST_MCLK_DIV(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + + #define AUD_MST_MCLK_GATE(_name, _reg) \ + AUD_GATE(_name, _reg, 31, "aud_"#_name"_div", \ +@@ -160,6 +163,7 @@ static AUD_MST_MCLK_GATE(spdifout_clk, AUDIO_CLK_SPDIFOUT_CTRL); + static AUD_MST_MCLK_GATE(spdifin_clk, AUDIO_CLK_SPDIFIN_CTRL); + static AUD_MST_MCLK_GATE(pdm_dclk, AUDIO_CLK_PDMIN_CTRL0); + static AUD_MST_MCLK_GATE(pdm_sysclk, AUDIO_CLK_PDMIN_CTRL1); ++static AUD_MST_MCLK_GATE(spdifout_b_clk, AUDIO_CLK_SPDIFOUT_B_CTRL); + + /* Sample Clocks */ + #define AUD_MST_SCLK_PRE_EN(_name, _reg) \ +@@ -377,6 +381,45 @@ static AUD_TDM_LRLCK(out_a, AUDIO_CLK_TDMOUT_A_CTRL); + static AUD_TDM_LRLCK(out_b, AUDIO_CLK_TDMOUT_B_CTRL); + static AUD_TDM_LRLCK(out_c, AUDIO_CLK_TDMOUT_C_CTRL); + ++/* G12a Pad control */ ++#define AUD_TDM_PAD_CTRL(_name, _reg, _shift, _parents) \ ++ AUD_MUX(tdm_##_name, _reg, 0x7, _shift, 0, _parents, \ ++ CLK_SET_RATE_NO_REPARENT) ++ ++static const char * const mclk_pad_ctrl_parent_names[] = { ++ "aud_mst_a_mclk", "aud_mst_b_mclk", "aud_mst_c_mclk", ++ "aud_mst_d_mclk", "aud_mst_e_mclk", "aud_mst_f_mclk", ++}; ++ ++static AUD_TDM_PAD_CTRL(mclk_pad_0, AUDIO_MST_PAD_CTRL0, 0, ++ mclk_pad_ctrl_parent_names); ++static AUD_TDM_PAD_CTRL(mclk_pad_1, AUDIO_MST_PAD_CTRL0, 4, ++ mclk_pad_ctrl_parent_names); ++ ++static const char * const lrclk_pad_ctrl_parent_names[] = { ++ "aud_mst_a_lrclk", "aud_mst_b_lrclk", "aud_mst_c_lrclk", ++ "aud_mst_d_lrclk", "aud_mst_e_lrclk", "aud_mst_f_lrclk", ++}; ++ ++static AUD_TDM_PAD_CTRL(lrclk_pad_0, AUDIO_MST_PAD_CTRL1, 16, ++ lrclk_pad_ctrl_parent_names); ++static AUD_TDM_PAD_CTRL(lrclk_pad_1, AUDIO_MST_PAD_CTRL1, 20, ++ lrclk_pad_ctrl_parent_names); ++static AUD_TDM_PAD_CTRL(lrclk_pad_2, AUDIO_MST_PAD_CTRL1, 24, ++ lrclk_pad_ctrl_parent_names); ++ ++static const char * const sclk_pad_ctrl_parent_names[] = { ++ "aud_mst_a_sclk", "aud_mst_b_sclk", "aud_mst_c_sclk", ++ "aud_mst_d_sclk", "aud_mst_e_sclk", "aud_mst_f_sclk", ++}; ++ ++static AUD_TDM_PAD_CTRL(sclk_pad_0, AUDIO_MST_PAD_CTRL1, 0, ++ sclk_pad_ctrl_parent_names); ++static AUD_TDM_PAD_CTRL(sclk_pad_1, AUDIO_MST_PAD_CTRL1, 4, ++ sclk_pad_ctrl_parent_names); ++static AUD_TDM_PAD_CTRL(sclk_pad_2, AUDIO_MST_PAD_CTRL1, 8, ++ sclk_pad_ctrl_parent_names); ++ + /* + * Array of all clocks provided by this provider + * The input clocks of the controller will be populated at runtime +@@ -509,7 +552,156 @@ static struct clk_hw_onecell_data axg_audio_hw_onecell_data = { + .num = NR_CLKS, + }; + +-/* Convenience table to populate regmap in .probe() */ ++/* ++ * Array of all G12A clocks provided by this provider ++ * The input clocks of the controller will be populated at runtime ++ */ ++static struct clk_hw_onecell_data g12a_audio_hw_onecell_data = { ++ .hws = { ++ [AUD_CLKID_DDR_ARB] = &aud_ddr_arb.hw, ++ [AUD_CLKID_PDM] = &aud_pdm.hw, ++ [AUD_CLKID_TDMIN_A] = &aud_tdmin_a.hw, ++ [AUD_CLKID_TDMIN_B] = &aud_tdmin_b.hw, ++ [AUD_CLKID_TDMIN_C] = &aud_tdmin_c.hw, ++ [AUD_CLKID_TDMIN_LB] = &aud_tdmin_lb.hw, ++ [AUD_CLKID_TDMOUT_A] = &aud_tdmout_a.hw, ++ [AUD_CLKID_TDMOUT_B] = &aud_tdmout_b.hw, ++ [AUD_CLKID_TDMOUT_C] = &aud_tdmout_c.hw, ++ [AUD_CLKID_FRDDR_A] = &aud_frddr_a.hw, ++ [AUD_CLKID_FRDDR_B] = &aud_frddr_b.hw, ++ [AUD_CLKID_FRDDR_C] = &aud_frddr_c.hw, ++ [AUD_CLKID_TODDR_A] = &aud_toddr_a.hw, ++ [AUD_CLKID_TODDR_B] = &aud_toddr_b.hw, ++ [AUD_CLKID_TODDR_C] = &aud_toddr_c.hw, ++ [AUD_CLKID_LOOPBACK] = &aud_loopback.hw, ++ [AUD_CLKID_SPDIFIN] = &aud_spdifin.hw, ++ [AUD_CLKID_SPDIFOUT] = &aud_spdifout.hw, ++ [AUD_CLKID_RESAMPLE] = &aud_resample.hw, ++ [AUD_CLKID_POWER_DETECT] = &aud_power_detect.hw, ++ [AUD_CLKID_SPDIFOUT_B] = &aud_spdifout_b.hw, ++ [AUD_CLKID_MST_A_MCLK_SEL] = &aud_mst_a_mclk_sel.hw, ++ [AUD_CLKID_MST_B_MCLK_SEL] = &aud_mst_b_mclk_sel.hw, ++ [AUD_CLKID_MST_C_MCLK_SEL] = &aud_mst_c_mclk_sel.hw, ++ [AUD_CLKID_MST_D_MCLK_SEL] = &aud_mst_d_mclk_sel.hw, ++ [AUD_CLKID_MST_E_MCLK_SEL] = &aud_mst_e_mclk_sel.hw, ++ [AUD_CLKID_MST_F_MCLK_SEL] = &aud_mst_f_mclk_sel.hw, ++ [AUD_CLKID_MST_A_MCLK_DIV] = &aud_mst_a_mclk_div.hw, ++ [AUD_CLKID_MST_B_MCLK_DIV] = &aud_mst_b_mclk_div.hw, ++ [AUD_CLKID_MST_C_MCLK_DIV] = &aud_mst_c_mclk_div.hw, ++ [AUD_CLKID_MST_D_MCLK_DIV] = &aud_mst_d_mclk_div.hw, ++ [AUD_CLKID_MST_E_MCLK_DIV] = &aud_mst_e_mclk_div.hw, ++ [AUD_CLKID_MST_F_MCLK_DIV] = &aud_mst_f_mclk_div.hw, ++ [AUD_CLKID_MST_A_MCLK] = &aud_mst_a_mclk.hw, ++ [AUD_CLKID_MST_B_MCLK] = &aud_mst_b_mclk.hw, ++ [AUD_CLKID_MST_C_MCLK] = &aud_mst_c_mclk.hw, ++ [AUD_CLKID_MST_D_MCLK] = &aud_mst_d_mclk.hw, ++ [AUD_CLKID_MST_E_MCLK] = &aud_mst_e_mclk.hw, ++ [AUD_CLKID_MST_F_MCLK] = &aud_mst_f_mclk.hw, ++ [AUD_CLKID_SPDIFOUT_CLK_SEL] = &aud_spdifout_clk_sel.hw, ++ [AUD_CLKID_SPDIFOUT_CLK_DIV] = &aud_spdifout_clk_div.hw, ++ [AUD_CLKID_SPDIFOUT_CLK] = &aud_spdifout_clk.hw, ++ [AUD_CLKID_SPDIFOUT_B_CLK_SEL] = &aud_spdifout_b_clk_sel.hw, ++ [AUD_CLKID_SPDIFOUT_B_CLK_DIV] = &aud_spdifout_b_clk_div.hw, ++ [AUD_CLKID_SPDIFOUT_B_CLK] = &aud_spdifout_b_clk.hw, ++ [AUD_CLKID_SPDIFIN_CLK_SEL] = &aud_spdifin_clk_sel.hw, ++ [AUD_CLKID_SPDIFIN_CLK_DIV] = &aud_spdifin_clk_div.hw, ++ [AUD_CLKID_SPDIFIN_CLK] = &aud_spdifin_clk.hw, ++ [AUD_CLKID_PDM_DCLK_SEL] = &aud_pdm_dclk_sel.hw, ++ [AUD_CLKID_PDM_DCLK_DIV] = &aud_pdm_dclk_div.hw, ++ [AUD_CLKID_PDM_DCLK] = &aud_pdm_dclk.hw, ++ [AUD_CLKID_PDM_SYSCLK_SEL] = &aud_pdm_sysclk_sel.hw, ++ [AUD_CLKID_PDM_SYSCLK_DIV] = &aud_pdm_sysclk_div.hw, ++ [AUD_CLKID_PDM_SYSCLK] = &aud_pdm_sysclk.hw, ++ [AUD_CLKID_MST_A_SCLK_PRE_EN] = &aud_mst_a_sclk_pre_en.hw, ++ [AUD_CLKID_MST_B_SCLK_PRE_EN] = &aud_mst_b_sclk_pre_en.hw, ++ [AUD_CLKID_MST_C_SCLK_PRE_EN] = &aud_mst_c_sclk_pre_en.hw, ++ [AUD_CLKID_MST_D_SCLK_PRE_EN] = &aud_mst_d_sclk_pre_en.hw, ++ [AUD_CLKID_MST_E_SCLK_PRE_EN] = &aud_mst_e_sclk_pre_en.hw, ++ [AUD_CLKID_MST_F_SCLK_PRE_EN] = &aud_mst_f_sclk_pre_en.hw, ++ [AUD_CLKID_MST_A_SCLK_DIV] = &aud_mst_a_sclk_div.hw, ++ [AUD_CLKID_MST_B_SCLK_DIV] = &aud_mst_b_sclk_div.hw, ++ [AUD_CLKID_MST_C_SCLK_DIV] = &aud_mst_c_sclk_div.hw, ++ [AUD_CLKID_MST_D_SCLK_DIV] = &aud_mst_d_sclk_div.hw, ++ [AUD_CLKID_MST_E_SCLK_DIV] = &aud_mst_e_sclk_div.hw, ++ [AUD_CLKID_MST_F_SCLK_DIV] = &aud_mst_f_sclk_div.hw, ++ [AUD_CLKID_MST_A_SCLK_POST_EN] = &aud_mst_a_sclk_post_en.hw, ++ [AUD_CLKID_MST_B_SCLK_POST_EN] = &aud_mst_b_sclk_post_en.hw, ++ [AUD_CLKID_MST_C_SCLK_POST_EN] = &aud_mst_c_sclk_post_en.hw, ++ [AUD_CLKID_MST_D_SCLK_POST_EN] = &aud_mst_d_sclk_post_en.hw, ++ [AUD_CLKID_MST_E_SCLK_POST_EN] = &aud_mst_e_sclk_post_en.hw, ++ [AUD_CLKID_MST_F_SCLK_POST_EN] = &aud_mst_f_sclk_post_en.hw, ++ [AUD_CLKID_MST_A_SCLK] = &aud_mst_a_sclk.hw, ++ [AUD_CLKID_MST_B_SCLK] = &aud_mst_b_sclk.hw, ++ [AUD_CLKID_MST_C_SCLK] = &aud_mst_c_sclk.hw, ++ [AUD_CLKID_MST_D_SCLK] = &aud_mst_d_sclk.hw, ++ [AUD_CLKID_MST_E_SCLK] = &aud_mst_e_sclk.hw, ++ [AUD_CLKID_MST_F_SCLK] = &aud_mst_f_sclk.hw, ++ [AUD_CLKID_MST_A_LRCLK_DIV] = &aud_mst_a_lrclk_div.hw, ++ [AUD_CLKID_MST_B_LRCLK_DIV] = &aud_mst_b_lrclk_div.hw, ++ [AUD_CLKID_MST_C_LRCLK_DIV] = &aud_mst_c_lrclk_div.hw, ++ [AUD_CLKID_MST_D_LRCLK_DIV] = &aud_mst_d_lrclk_div.hw, ++ [AUD_CLKID_MST_E_LRCLK_DIV] = &aud_mst_e_lrclk_div.hw, ++ [AUD_CLKID_MST_F_LRCLK_DIV] = &aud_mst_f_lrclk_div.hw, ++ [AUD_CLKID_MST_A_LRCLK] = &aud_mst_a_lrclk.hw, ++ [AUD_CLKID_MST_B_LRCLK] = &aud_mst_b_lrclk.hw, ++ [AUD_CLKID_MST_C_LRCLK] = &aud_mst_c_lrclk.hw, ++ [AUD_CLKID_MST_D_LRCLK] = &aud_mst_d_lrclk.hw, ++ [AUD_CLKID_MST_E_LRCLK] = &aud_mst_e_lrclk.hw, ++ [AUD_CLKID_MST_F_LRCLK] = &aud_mst_f_lrclk.hw, ++ [AUD_CLKID_TDMIN_A_SCLK_SEL] = &aud_tdmin_a_sclk_sel.hw, ++ [AUD_CLKID_TDMIN_B_SCLK_SEL] = &aud_tdmin_b_sclk_sel.hw, ++ [AUD_CLKID_TDMIN_C_SCLK_SEL] = &aud_tdmin_c_sclk_sel.hw, ++ [AUD_CLKID_TDMIN_LB_SCLK_SEL] = &aud_tdmin_lb_sclk_sel.hw, ++ [AUD_CLKID_TDMOUT_A_SCLK_SEL] = &aud_tdmout_a_sclk_sel.hw, ++ [AUD_CLKID_TDMOUT_B_SCLK_SEL] = &aud_tdmout_b_sclk_sel.hw, ++ [AUD_CLKID_TDMOUT_C_SCLK_SEL] = &aud_tdmout_c_sclk_sel.hw, ++ [AUD_CLKID_TDMIN_A_SCLK_PRE_EN] = &aud_tdmin_a_sclk_pre_en.hw, ++ [AUD_CLKID_TDMIN_B_SCLK_PRE_EN] = &aud_tdmin_b_sclk_pre_en.hw, ++ [AUD_CLKID_TDMIN_C_SCLK_PRE_EN] = &aud_tdmin_c_sclk_pre_en.hw, ++ [AUD_CLKID_TDMIN_LB_SCLK_PRE_EN] = &aud_tdmin_lb_sclk_pre_en.hw, ++ [AUD_CLKID_TDMOUT_A_SCLK_PRE_EN] = &aud_tdmout_a_sclk_pre_en.hw, ++ [AUD_CLKID_TDMOUT_B_SCLK_PRE_EN] = &aud_tdmout_b_sclk_pre_en.hw, ++ [AUD_CLKID_TDMOUT_C_SCLK_PRE_EN] = &aud_tdmout_c_sclk_pre_en.hw, ++ [AUD_CLKID_TDMIN_A_SCLK_POST_EN] = &aud_tdmin_a_sclk_post_en.hw, ++ [AUD_CLKID_TDMIN_B_SCLK_POST_EN] = &aud_tdmin_b_sclk_post_en.hw, ++ [AUD_CLKID_TDMIN_C_SCLK_POST_EN] = &aud_tdmin_c_sclk_post_en.hw, ++ [AUD_CLKID_TDMIN_LB_SCLK_POST_EN] = &aud_tdmin_lb_sclk_post_en.hw, ++ [AUD_CLKID_TDMOUT_A_SCLK_POST_EN] = &aud_tdmout_a_sclk_post_en.hw, ++ [AUD_CLKID_TDMOUT_B_SCLK_POST_EN] = &aud_tdmout_b_sclk_post_en.hw, ++ [AUD_CLKID_TDMOUT_C_SCLK_POST_EN] = &aud_tdmout_c_sclk_post_en.hw, ++ [AUD_CLKID_TDMIN_A_SCLK] = &aud_tdmin_a_sclk.hw, ++ [AUD_CLKID_TDMIN_B_SCLK] = &aud_tdmin_b_sclk.hw, ++ [AUD_CLKID_TDMIN_C_SCLK] = &aud_tdmin_c_sclk.hw, ++ [AUD_CLKID_TDMIN_LB_SCLK] = &aud_tdmin_lb_sclk.hw, ++ [AUD_CLKID_TDMOUT_A_SCLK] = &aud_tdmout_a_sclk.hw, ++ [AUD_CLKID_TDMOUT_B_SCLK] = &aud_tdmout_b_sclk.hw, ++ [AUD_CLKID_TDMOUT_C_SCLK] = &aud_tdmout_c_sclk.hw, ++ [AUD_CLKID_TDMIN_A_LRCLK] = &aud_tdmin_a_lrclk.hw, ++ [AUD_CLKID_TDMIN_B_LRCLK] = &aud_tdmin_b_lrclk.hw, ++ [AUD_CLKID_TDMIN_C_LRCLK] = &aud_tdmin_c_lrclk.hw, ++ [AUD_CLKID_TDMIN_LB_LRCLK] = &aud_tdmin_lb_lrclk.hw, ++ [AUD_CLKID_TDMOUT_A_LRCLK] = &aud_tdmout_a_lrclk.hw, ++ [AUD_CLKID_TDMOUT_B_LRCLK] = &aud_tdmout_b_lrclk.hw, ++ [AUD_CLKID_TDMOUT_C_LRCLK] = &aud_tdmout_c_lrclk.hw, ++ [AUD_CLKID_TDM_MCLK_PAD0] = &aud_tdm_mclk_pad_0.hw, ++ [AUD_CLKID_TDM_MCLK_PAD1] = &aud_tdm_mclk_pad_1.hw, ++ [AUD_CLKID_TDM_LRCLK_PAD0] = &aud_tdm_lrclk_pad_0.hw, ++ [AUD_CLKID_TDM_LRCLK_PAD1] = &aud_tdm_lrclk_pad_1.hw, ++ [AUD_CLKID_TDM_LRCLK_PAD2] = &aud_tdm_lrclk_pad_2.hw, ++ [AUD_CLKID_TDM_SCLK_PAD0] = &aud_tdm_sclk_pad_0.hw, ++ [AUD_CLKID_TDM_SCLK_PAD1] = &aud_tdm_sclk_pad_1.hw, ++ [AUD_CLKID_TDM_SCLK_PAD2] = &aud_tdm_sclk_pad_2.hw, ++ [NR_CLKS] = NULL, ++ }, ++ .num = NR_CLKS, ++}; ++ ++/* Convenience table to populate regmap in .probe() ++ * Note that this table is shared between both AXG and G12A, ++ * with spdifout_b clocks being exclusive to G12A. Since those ++ * clocks are not declared within the AXG onecell table, we do not ++ * feel the need to have separate AXG/G12A regmap tables. ++ */ + static struct clk_regmap *const aud_clk_regmaps[] = { + &aud_ddr_arb, + &aud_pdm, +@@ -531,6 +723,7 @@ static struct clk_regmap *const aud_clk_regmaps[] = { + &aud_spdifout, + &aud_resample, + &aud_power_detect, ++ &aud_spdifout_b, + &aud_mst_a_mclk_sel, + &aud_mst_b_mclk_sel, + &aud_mst_c_mclk_sel, +@@ -632,6 +825,17 @@ static struct clk_regmap *const aud_clk_regmaps[] = { + &aud_tdmout_a_lrclk, + &aud_tdmout_b_lrclk, + &aud_tdmout_c_lrclk, ++ &aud_spdifout_b_clk_sel, ++ &aud_spdifout_b_clk_div, ++ &aud_spdifout_b_clk, ++ &aud_tdm_mclk_pad_0, ++ &aud_tdm_mclk_pad_1, ++ &aud_tdm_lrclk_pad_0, ++ &aud_tdm_lrclk_pad_1, ++ &aud_tdm_lrclk_pad_2, ++ &aud_tdm_sclk_pad_0, ++ &aud_tdm_sclk_pad_1, ++ &aud_tdm_sclk_pad_2, + }; + + static int devm_clk_get_enable(struct device *dev, char *id) +@@ -719,15 +923,24 @@ static const struct regmap_config axg_audio_regmap_cfg = { + .max_register = AUDIO_CLK_PDMIN_CTRL1, + }; + ++struct audioclk_data { ++ struct clk_hw_onecell_data *hw_onecell_data; ++}; ++ + static int axg_audio_clkc_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ const struct audioclk_data *data; + struct regmap *map; + struct resource *res; + void __iomem *regs; + struct clk_hw *hw; + int ret, i; + ++ data = of_device_get_match_data(dev); ++ if (!data) ++ return -EINVAL; ++ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(dev, res); + if (IS_ERR(regs)) +@@ -778,8 +991,8 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) + aud_clk_regmaps[i]->map = map; + + /* Take care to skip the registered input clocks */ +- for (i = AUD_CLKID_DDR_ARB; i < axg_audio_hw_onecell_data.num; i++) { +- hw = axg_audio_hw_onecell_data.hws[i]; ++ for (i = AUD_CLKID_DDR_ARB; i < data->hw_onecell_data->num; i++) { ++ hw = data->hw_onecell_data->hws[i]; + /* array might be sparse */ + if (!hw) + continue; +@@ -793,12 +1006,25 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, +- &axg_audio_hw_onecell_data); ++ data->hw_onecell_data); + } + ++static const struct audioclk_data axg_audioclk_data = { ++ .hw_onecell_data = &axg_audio_hw_onecell_data, ++}; ++ ++static const struct audioclk_data g12a_audioclk_data = { ++ .hw_onecell_data = &g12a_audio_hw_onecell_data, ++}; ++ + static const struct of_device_id clkc_match_table[] = { +- { .compatible = "amlogic,axg-audio-clkc" }, +- {} ++ { ++ .compatible = "amlogic,axg-audio-clkc", ++ .data = &axg_audioclk_data ++ }, { ++ .compatible = "amlogic,g12a-audio-clkc", ++ .data = &g12a_audioclk_data ++ }, {} + }; + MODULE_DEVICE_TABLE(of, clkc_match_table); + +@@ -811,6 +1037,6 @@ static struct platform_driver axg_audio_driver = { + }; + module_platform_driver(axg_audio_driver); + +-MODULE_DESCRIPTION("Amlogic A113x Audio Clock driver"); ++MODULE_DESCRIPTION("Amlogic AXG/G12A Audio Clock driver"); + MODULE_AUTHOR("Jerome Brunet "); + MODULE_LICENSE("GPL v2"); +diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h +index 9644c2ff0b3b6..5d972d55d6c74 100644 +--- a/drivers/clk/meson/axg-audio.h ++++ b/drivers/clk/meson/axg-audio.h +@@ -20,6 +20,8 @@ + #define AUDIO_MCLK_D_CTRL 0x010 + #define AUDIO_MCLK_E_CTRL 0x014 + #define AUDIO_MCLK_F_CTRL 0x018 ++#define AUDIO_MST_PAD_CTRL0 0x01c ++#define AUDIO_MST_PAD_CTRL1 0x020 + #define AUDIO_MST_A_SCLK_CTRL0 0x040 + #define AUDIO_MST_A_SCLK_CTRL1 0x044 + #define AUDIO_MST_B_SCLK_CTRL0 0x048 +@@ -45,6 +47,7 @@ + #define AUDIO_CLK_LOCKER_CTRL 0x0A8 + #define AUDIO_CLK_PDMIN_CTRL0 0x0AC + #define AUDIO_CLK_PDMIN_CTRL1 0x0B0 ++#define AUDIO_CLK_SPDIFOUT_B_CTRL 0x0B4 + + /* + * CLKID index values +@@ -109,10 +112,12 @@ + #define AUD_CLKID_TDMOUT_A_SCLK_POST_EN 148 + #define AUD_CLKID_TDMOUT_B_SCLK_POST_EN 149 + #define AUD_CLKID_TDMOUT_C_SCLK_POST_EN 150 ++#define AUD_CLKID_SPDIFOUT_B_CLK_SEL 153 ++#define AUD_CLKID_SPDIFOUT_B_CLK_DIV 154 + + /* include the CLKIDs which are part of the DT bindings */ + #include + +-#define NR_CLKS 151 ++#define NR_CLKS 163 + + #endif /*__AXG_AUDIO_CLKC_H */ + +From ef3250f3d0571d3266e40989d4a399e6395580cb Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Mon, 11 Mar 2019 11:51:44 +0100 +Subject: [PATCH 037/249] FROMGIT: drm/meson: exclusively use the canvas + provider module + +Now that the DMC register range is no longer in the bindings, remove any +mention towards it and exclusively use the meson-canvas module. + +Signed-off-by: Maxime Jourdan +Acked-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20190311105144.7276-3-mjourdan@baylibre.com +(cherry picked from commit 2bf6b5b0e374fccda724ca208e8d5433b869246a + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/Makefile | 2 +- + drivers/gpu/drm/meson/meson_canvas.c | 73 ----------------------- + drivers/gpu/drm/meson/meson_canvas.h | 51 ---------------- + drivers/gpu/drm/meson/meson_crtc.c | 84 ++++++++------------------- + drivers/gpu/drm/meson/meson_drv.c | 68 ++++++++-------------- + drivers/gpu/drm/meson/meson_drv.h | 1 - + drivers/gpu/drm/meson/meson_overlay.c | 8 --- + drivers/gpu/drm/meson/meson_plane.c | 6 +- + drivers/gpu/drm/meson/meson_viu.c | 1 - + 9 files changed, 51 insertions(+), 243 deletions(-) + delete mode 100644 drivers/gpu/drm/meson/meson_canvas.c + delete mode 100644 drivers/gpu/drm/meson/meson_canvas.h + +diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile +index 7709f2fbb9f77..d4ea82fc493b6 100644 +--- a/drivers/gpu/drm/meson/Makefile ++++ b/drivers/gpu/drm/meson/Makefile +@@ -1,5 +1,5 @@ + meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o +-meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o meson_overlay.o ++meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_overlay.o + + obj-$(CONFIG_DRM_MESON) += meson-drm.o + obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o +diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c +deleted file mode 100644 +index 5de11aa7c775e..0000000000000 +--- a/drivers/gpu/drm/meson/meson_canvas.c ++++ /dev/null +@@ -1,73 +0,0 @@ +-/* +- * Copyright (C) 2016 BayLibre, SAS +- * Author: Neil Armstrong +- * Copyright (C) 2015 Amlogic, Inc. All rights reserved. +- * Copyright (C) 2014 Endless Mobile +- * +- * 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. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, see . +- */ +- +-#include +-#include +-#include "meson_drv.h" +-#include "meson_canvas.h" +-#include "meson_registers.h" +- +-/** +- * DOC: Canvas +- * +- * CANVAS is a memory zone where physical memory frames information +- * are stored for the VIU to scanout. +- */ +- +-/* DMC Registers */ +-#define DMC_CAV_LUT_DATAL 0x48 /* 0x12 offset in data sheet */ +-#define CANVAS_WIDTH_LBIT 29 +-#define CANVAS_WIDTH_LWID 3 +-#define DMC_CAV_LUT_DATAH 0x4c /* 0x13 offset in data sheet */ +-#define CANVAS_WIDTH_HBIT 0 +-#define CANVAS_HEIGHT_BIT 9 +-#define CANVAS_BLKMODE_BIT 24 +-#define CANVAS_ENDIAN_BIT 26 +-#define DMC_CAV_LUT_ADDR 0x50 /* 0x14 offset in data sheet */ +-#define CANVAS_LUT_WR_EN (0x2 << 8) +-#define CANVAS_LUT_RD_EN (0x1 << 8) +- +-void meson_canvas_setup(struct meson_drm *priv, +- uint32_t canvas_index, uint32_t addr, +- uint32_t stride, uint32_t height, +- unsigned int wrap, +- unsigned int blkmode, +- unsigned int endian) +-{ +- unsigned int val; +- +- regmap_write(priv->dmc, DMC_CAV_LUT_DATAL, +- (((addr + 7) >> 3)) | +- (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT)); +- +- regmap_write(priv->dmc, DMC_CAV_LUT_DATAH, +- ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) << +- CANVAS_WIDTH_HBIT) | +- (height << CANVAS_HEIGHT_BIT) | +- (wrap << 22) | +- (blkmode << CANVAS_BLKMODE_BIT) | +- (endian << CANVAS_ENDIAN_BIT)); +- +- regmap_write(priv->dmc, DMC_CAV_LUT_ADDR, +- CANVAS_LUT_WR_EN | canvas_index); +- +- /* Force a read-back to make sure everything is flushed. */ +- regmap_read(priv->dmc, DMC_CAV_LUT_DATAH, &val); +-} +diff --git a/drivers/gpu/drm/meson/meson_canvas.h b/drivers/gpu/drm/meson/meson_canvas.h +deleted file mode 100644 +index 85dbf26e2826a..0000000000000 +--- a/drivers/gpu/drm/meson/meson_canvas.h ++++ /dev/null +@@ -1,51 +0,0 @@ +-/* +- * Copyright (C) 2016 BayLibre, SAS +- * Author: Neil Armstrong +- * Copyright (C) 2014 Endless Mobile +- * +- * 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. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, see . +- */ +- +-/* Canvas LUT Memory */ +- +-#ifndef __MESON_CANVAS_H +-#define __MESON_CANVAS_H +- +-#define MESON_CANVAS_ID_OSD1 0x4e +-#define MESON_CANVAS_ID_VD1_0 0x60 +-#define MESON_CANVAS_ID_VD1_1 0x61 +-#define MESON_CANVAS_ID_VD1_2 0x62 +- +-/* Canvas configuration. */ +-#define MESON_CANVAS_WRAP_NONE 0x00 +-#define MESON_CANVAS_WRAP_X 0x01 +-#define MESON_CANVAS_WRAP_Y 0x02 +- +-#define MESON_CANVAS_BLKMODE_LINEAR 0x00 +-#define MESON_CANVAS_BLKMODE_32x32 0x01 +-#define MESON_CANVAS_BLKMODE_64x64 0x02 +- +-#define MESON_CANVAS_ENDIAN_SWAP16 0x1 +-#define MESON_CANVAS_ENDIAN_SWAP32 0x3 +-#define MESON_CANVAS_ENDIAN_SWAP64 0x7 +-#define MESON_CANVAS_ENDIAN_SWAP128 0xf +- +-void meson_canvas_setup(struct meson_drm *priv, +- uint32_t canvas_index, uint32_t addr, +- uint32_t stride, uint32_t height, +- unsigned int wrap, +- unsigned int blkmode, +- unsigned int endian); +- +-#endif /* __MESON_CANVAS_H */ +diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c +index 43e29984f8b17..6d9311e254efc 100644 +--- a/drivers/gpu/drm/meson/meson_crtc.c ++++ b/drivers/gpu/drm/meson/meson_crtc.c +@@ -37,7 +37,6 @@ + #include "meson_venc.h" + #include "meson_vpp.h" + #include "meson_viu.h" +-#include "meson_canvas.h" + #include "meson_registers.h" + + /* CRTC definition */ +@@ -214,13 +213,7 @@ void meson_crtc_irq(struct meson_drm *priv) + writel_relaxed(priv->viu.osd_sc_v_ctrl0, + priv->io_base + _REG(VPP_OSD_VSC_CTRL0)); + +- if (priv->canvas) +- meson_canvas_config(priv->canvas, priv->canvas_id_osd1, +- priv->viu.osd1_addr, priv->viu.osd1_stride, +- priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, +- MESON_CANVAS_BLKMODE_LINEAR, 0); +- else +- meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1, ++ meson_canvas_config(priv->canvas, priv->canvas_id_osd1, + priv->viu.osd1_addr, priv->viu.osd1_stride, + priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE, + MESON_CANVAS_BLKMODE_LINEAR, 0); +@@ -237,61 +230,34 @@ void meson_crtc_irq(struct meson_drm *priv) + + switch (priv->viu.vd1_planes) { + case 3: +- if (priv->canvas) +- meson_canvas_config(priv->canvas, +- priv->canvas_id_vd1_2, +- priv->viu.vd1_addr2, +- priv->viu.vd1_stride2, +- priv->viu.vd1_height2, +- MESON_CANVAS_WRAP_NONE, +- MESON_CANVAS_BLKMODE_LINEAR, +- MESON_CANVAS_ENDIAN_SWAP64); +- else +- meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_2, +- priv->viu.vd1_addr2, +- priv->viu.vd1_stride2, +- priv->viu.vd1_height2, +- MESON_CANVAS_WRAP_NONE, +- MESON_CANVAS_BLKMODE_LINEAR, +- MESON_CANVAS_ENDIAN_SWAP64); ++ meson_canvas_config(priv->canvas, ++ priv->canvas_id_vd1_2, ++ priv->viu.vd1_addr2, ++ priv->viu.vd1_stride2, ++ priv->viu.vd1_height2, ++ MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR, ++ MESON_CANVAS_ENDIAN_SWAP64); + /* fallthrough */ + case 2: +- if (priv->canvas) +- meson_canvas_config(priv->canvas, +- priv->canvas_id_vd1_1, +- priv->viu.vd1_addr1, +- priv->viu.vd1_stride1, +- priv->viu.vd1_height1, +- MESON_CANVAS_WRAP_NONE, +- MESON_CANVAS_BLKMODE_LINEAR, +- MESON_CANVAS_ENDIAN_SWAP64); +- else +- meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_1, +- priv->viu.vd1_addr2, +- priv->viu.vd1_stride2, +- priv->viu.vd1_height2, +- MESON_CANVAS_WRAP_NONE, +- MESON_CANVAS_BLKMODE_LINEAR, +- MESON_CANVAS_ENDIAN_SWAP64); ++ meson_canvas_config(priv->canvas, ++ priv->canvas_id_vd1_1, ++ priv->viu.vd1_addr1, ++ priv->viu.vd1_stride1, ++ priv->viu.vd1_height1, ++ MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR, ++ MESON_CANVAS_ENDIAN_SWAP64); + /* fallthrough */ + case 1: +- if (priv->canvas) +- meson_canvas_config(priv->canvas, +- priv->canvas_id_vd1_0, +- priv->viu.vd1_addr0, +- priv->viu.vd1_stride0, +- priv->viu.vd1_height0, +- MESON_CANVAS_WRAP_NONE, +- MESON_CANVAS_BLKMODE_LINEAR, +- MESON_CANVAS_ENDIAN_SWAP64); +- else +- meson_canvas_setup(priv, MESON_CANVAS_ID_VD1_0, +- priv->viu.vd1_addr2, +- priv->viu.vd1_stride2, +- priv->viu.vd1_height2, +- MESON_CANVAS_WRAP_NONE, +- MESON_CANVAS_BLKMODE_LINEAR, +- MESON_CANVAS_ENDIAN_SWAP64); ++ meson_canvas_config(priv->canvas, ++ priv->canvas_id_vd1_0, ++ priv->viu.vd1_addr0, ++ priv->viu.vd1_stride0, ++ priv->viu.vd1_height0, ++ MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR, ++ MESON_CANVAS_ENDIAN_SWAP64); + }; + + writel_relaxed(priv->viu.vd1_if0_gen_reg, +diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c +index 8a4ebcb6405ce..079d22299d789 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -48,7 +48,6 @@ + #include "meson_vpp.h" + #include "meson_viu.h" + #include "meson_venc.h" +-#include "meson_canvas.h" + #include "meson_registers.h" + + #define DRIVER_NAME "meson" +@@ -231,50 +230,31 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) + } + + priv->canvas = meson_canvas_get(dev); +- if (!IS_ERR(priv->canvas)) { +- ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); +- 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); +- goto free_drm; +- } +- ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); +- if (ret) { +- meson_canvas_free(priv->canvas, priv->canvas_id_osd1); +- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); +- goto free_drm; +- } +- ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); +- if (ret) { +- meson_canvas_free(priv->canvas, priv->canvas_id_osd1); +- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); +- meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); +- goto free_drm; +- } +- } else { +- priv->canvas = NULL; +- +- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dmc"); +- if (!res) { +- ret = -EINVAL; +- goto free_drm; +- } +- /* Simply ioremap since it may be a shared register zone */ +- regs = devm_ioremap(dev, res->start, resource_size(res)); +- if (!regs) { +- ret = -EADDRNOTAVAIL; +- goto free_drm; +- } ++ if (IS_ERR(priv->canvas)) { ++ ret = PTR_ERR(priv->canvas); ++ goto free_drm; ++ } + +- priv->dmc = devm_regmap_init_mmio(dev, regs, +- &meson_regmap_config); +- if (IS_ERR(priv->dmc)) { +- dev_err(&pdev->dev, "Couldn't create the DMC regmap\n"); +- ret = PTR_ERR(priv->dmc); +- goto free_drm; +- } ++ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_osd1); ++ 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); ++ goto free_drm; ++ } ++ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_1); ++ if (ret) { ++ meson_canvas_free(priv->canvas, priv->canvas_id_osd1); ++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); ++ goto free_drm; ++ } ++ ret = meson_canvas_alloc(priv->canvas, &priv->canvas_id_vd1_2); ++ if (ret) { ++ meson_canvas_free(priv->canvas, priv->canvas_id_osd1); ++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_0); ++ meson_canvas_free(priv->canvas, priv->canvas_id_vd1_1); ++ goto free_drm; + } + + priv->vsync_irq = platform_get_irq(pdev, 0); +diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h +index 4dccf4cd042a5..214a7cb18ce27 100644 +--- a/drivers/gpu/drm/meson/meson_drv.h ++++ b/drivers/gpu/drm/meson/meson_drv.h +@@ -29,7 +29,6 @@ struct meson_drm { + struct device *dev; + void __iomem *io_base; + struct regmap *hhi; +- struct regmap *dmc; + int vsync_irq; + + struct meson_canvas *canvas; +diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c +index 691a9fd16b366..b54a22e483b92 100644 +--- a/drivers/gpu/drm/meson/meson_overlay.c ++++ b/drivers/gpu/drm/meson/meson_overlay.c +@@ -22,7 +22,6 @@ + #include "meson_overlay.h" + #include "meson_vpp.h" + #include "meson_viu.h" +-#include "meson_canvas.h" + #include "meson_registers.h" + + /* VD1_IF0_GEN_REG */ +@@ -350,13 +349,6 @@ static void meson_overlay_atomic_update(struct drm_plane *plane, + + DRM_DEBUG_DRIVER("\n"); + +- /* Fallback is canvas provider is not available */ +- if (!priv->canvas) { +- priv->canvas_id_vd1_0 = MESON_CANVAS_ID_VD1_0; +- priv->canvas_id_vd1_1 = MESON_CANVAS_ID_VD1_1; +- priv->canvas_id_vd1_2 = MESON_CANVAS_ID_VD1_2; +- } +- + interlace_mode = state->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE; + + spin_lock_irqsave(&priv->drm->event_lock, flags); +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index 6119a02242788..b7786218cb10a 100644 +--- a/drivers/gpu/drm/meson/meson_plane.c ++++ b/drivers/gpu/drm/meson/meson_plane.c +@@ -38,7 +38,6 @@ + #include "meson_plane.h" + #include "meson_vpp.h" + #include "meson_viu.h" +-#include "meson_canvas.h" + #include "meson_registers.h" + + /* OSD_SCI_WH_M1 */ +@@ -148,10 +147,7 @@ static void meson_plane_atomic_update(struct drm_plane *plane, + (0xFF << OSD_GLOBAL_ALPHA_SHIFT) | + OSD_BLK0_ENABLE; + +- if (priv->canvas) +- canvas_id_osd1 = priv->canvas_id_osd1; +- else +- canvas_id_osd1 = MESON_CANVAS_ID_OSD1; ++ canvas_id_osd1 = priv->canvas_id_osd1; + + /* Set up BLK0 to point to the right canvas */ + priv->viu.osd1_blk0_cfg[0] = ((canvas_id_osd1 << OSD_CANVAS_SEL) | +diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c +index e46e05f50bad7..ac0f3687e09a3 100644 +--- a/drivers/gpu/drm/meson/meson_viu.c ++++ b/drivers/gpu/drm/meson/meson_viu.c +@@ -25,7 +25,6 @@ + #include "meson_viu.h" + #include "meson_vpp.h" + #include "meson_venc.h" +-#include "meson_canvas.h" + #include "meson_registers.h" + + /** + +From d3f3465466dd0ff8b456d5202443dc27ea2d8e66 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 1 Apr 2019 10:09:49 +0200 +Subject: [PATCH 038/249] FROMGIT: dt-bindings: gpu: add bindings for the ARM + Mali Bifrost GPU + +Add the bindings for the Bifrost family of ARM Mali GPUs. + +The Bifrost GPU architecture is similar to the Midgard family, +but with a different Shader Core & Execution Engine structures. + +Bindings are based on the Midgard family bindings, but the inner +architectural changes makes it a separate family needing separate +bindings. + +The Bifrost GPUs are present in a number of recent SoCs, like the +Amlogic G12A Family, and many other vendors. +The Amlogic vendor specific compatible is added to handle the +specific IP integration differences and dependencies. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +[narmstrong: fixed small typo in compatible description] +Link: https://patchwork.freedesktop.org/patch/msgid/20190401080949.14550-1-narmstrong@baylibre.com +(cherry picked from commit ebc41018d84bc526e9f873a80228aba24c9f9189 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + .../bindings/gpu/arm,mali-bifrost.txt | 92 +++++++++++++++++++ + 1 file changed, 92 insertions(+) + create mode 100644 Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt + +diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt +new file mode 100644 +index 0000000000000..b8be9dbc68b4c +--- /dev/null ++++ b/Documentation/devicetree/bindings/gpu/arm,mali-bifrost.txt +@@ -0,0 +1,92 @@ ++ARM Mali Bifrost GPU ++==================== ++ ++Required properties: ++ ++- compatible : ++ * Since Mali Bifrost GPU model/revision is fully discoverable by reading ++ some determined registers, must contain the following: ++ + "arm,mali-bifrost" ++ * which must be preceded by one of the following vendor specifics: ++ + "amlogic,meson-g12a-mali" ++ ++- reg : Physical base address of the device and length of the register area. ++ ++- interrupts : Contains the three IRQ lines required by Mali Bifrost devices, ++ in the following defined order. ++ ++- interrupt-names : Contains the names of IRQ resources in this exact defined ++ order: "job", "mmu", "gpu". ++ ++Optional properties: ++ ++- clocks : Phandle to clock for the Mali Bifrost device. ++ ++- mali-supply : Phandle to regulator for the Mali device. Refer to ++ Documentation/devicetree/bindings/regulator/regulator.txt for details. ++ ++- operating-points-v2 : Refer to Documentation/devicetree/bindings/opp/opp.txt ++ for details. ++ ++- resets : Phandle of the GPU reset line. ++ ++Vendor-specific bindings ++------------------------ ++ ++The Mali GPU is integrated very differently from one SoC to ++another. In order to accommodate those differences, you have the option ++to specify one more vendor-specific compatible, among: ++ ++- "amlogic,meson-g12a-mali" ++ Required properties: ++ - resets : Should contain phandles of : ++ + GPU reset line ++ + GPU APB glue reset line ++ ++Example for a Mali-G31: ++ ++gpu@ffa30000 { ++ compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; ++ reg = <0xffe40000 0x10000>; ++ interrupts = , ++ , ++ ; ++ interrupt-names = "job", "mmu", "gpu"; ++ clocks = <&clk CLKID_MALI>; ++ mali-supply = <&vdd_gpu>; ++ operating-points-v2 = <&gpu_opp_table>; ++ resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; ++}; ++ ++gpu_opp_table: opp_table0 { ++ compatible = "operating-points-v2"; ++ ++ opp@533000000 { ++ opp-hz = /bits/ 64 <533000000>; ++ opp-microvolt = <1250000>; ++ }; ++ opp@450000000 { ++ opp-hz = /bits/ 64 <450000000>; ++ opp-microvolt = <1150000>; ++ }; ++ opp@400000000 { ++ opp-hz = /bits/ 64 <400000000>; ++ opp-microvolt = <1125000>; ++ }; ++ opp@350000000 { ++ opp-hz = /bits/ 64 <350000000>; ++ opp-microvolt = <1075000>; ++ }; ++ opp@266000000 { ++ opp-hz = /bits/ 64 <266000000>; ++ opp-microvolt = <1025000>; ++ }; ++ opp@160000000 { ++ opp-hz = /bits/ 64 <160000000>; ++ opp-microvolt = <925000>; ++ }; ++ opp@100000000 { ++ opp-hz = /bits/ 64 <100000000>; ++ opp-microvolt = <912500>; ++ }; ++}; + +From 186dc507a63f4d775bd989481bb231609b3970cb Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 13 Mar 2019 15:10:28 +0100 +Subject: [PATCH 039/249] FROMGIT: dt-bindings: display: amlogic, meson-vpu: + Add G12A compatible and ports + +The Amlogic G12A VPU is very similar to the Amlogic GXM VPU but with : +- an enhanced plane blender, with up to 3 OSD planes +- support for AFBC 1.2 decoder (for Bifrost GPU) +- support display mode up to 4k60@75Hz + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20190313141030.5958-2-narmstrong@baylibre.com +(cherry picked from commit 71bfbaa47b6ddf267ee383350f96cf3d3401bdc5 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + .../devicetree/bindings/display/amlogic,meson-vpu.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt +index c65fd7a7467c0..8041283a4cafa 100644 +--- a/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt ++++ b/Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt +@@ -57,6 +57,7 @@ Required properties: + - GXL (S905X, S905D) : "amlogic,meson-gxl-vpu" + - GXM (S912) : "amlogic,meson-gxm-vpu" + followed by the common "amlogic,meson-gx-vpu" ++ - G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-vpu" + - reg: base address and size of he following memory-mapped regions : + - vpu + - hhi +@@ -84,6 +85,9 @@ corresponding to each VPU output. + S905X (GXL) CVBS VDAC HDMI-TX + S905D (GXL) CVBS VDAC HDMI-TX + S912 (GXM) CVBS VDAC HDMI-TX ++ S905X2 (G12A) CVBS VDAC HDMI-TX ++ S905Y2 (G12A) CVBS VDAC HDMI-TX ++ S905D2 (G12A) CVBS VDAC HDMI-TX + + Example: + + +From 361720b6086f2f6030ed1847210ed8fb6a163b34 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 13 Mar 2019 15:10:29 +0100 +Subject: [PATCH 040/249] FROMGIT: dt-bindings: display: amlogic, + meson-dw-hdmi: Add G12A compatible and ports + +The Amlogic G12A SoC has a slighly modified DW-HDMI Glue with +support for HDMI 2.1 and a different DW-HDMI register access. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20190313141030.5958-3-narmstrong@baylibre.com +(cherry picked from commit 6c28dca669c6ee3377a9e52ed9432c0158d43ed6 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + .../devicetree/bindings/display/amlogic,meson-dw-hdmi.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt +index bf4a18047309a..3a50a7862cf3f 100644 +--- a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt ++++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt +@@ -37,6 +37,7 @@ Required properties: + - GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi" + - GXM (S912) : "amlogic,meson-gxm-dw-hdmi" + followed by the common "amlogic,meson-gx-dw-hdmi" ++ - G12A (S905X2, S905Y2, S905D2) : "amlogic,meson-g12a-dw-hdmi" + - reg: Physical base address and length of the controller's registers. + - interrupts: The HDMI interrupt number + - clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks, +@@ -66,6 +67,9 @@ corresponding to each HDMI output and input. + S905X (GXL) VENC Input TMDS Output + S905D (GXL) VENC Input TMDS Output + S912 (GXM) VENC Input TMDS Output ++ S905X2 (G12A) VENC Input TMDS Output ++ S905Y2 (G12A) VENC Input TMDS Output ++ S905D2 (G12A) VENC Input TMDS Output + + Example: + + +From be774f8725e8e5fdf9608cdcf78448afa6b2f418 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:14 +0100 +Subject: [PATCH 041/249] FROMGIT: drm/meson: Switch PLL to 5.94GHz base for + 297Mhz pixel clock + +On Amlogic G12A SoC, the 2,97GHz PLL frequency is not stable enough +to provide a correct 297MHz pixel clock, so switch the PLL base +frequency with a /2 OD when the 297MHz pixel clock is requested. + +This solves the issue on G12A and also works fine on GXBB, GXL & GXM. + +Signed-off-by: Neil Armstrong +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-2-narmstrong@baylibre.com +(cherry picked from commit 61af6e22ec265849133bdfc4058bf0f1b28c5c24 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_vclk.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index f6ba35a405f8d..c15a5a5df6331 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -396,8 +396,8 @@ struct meson_vclk_params { + }, + [MESON_VCLK_HDMI_297000] = { + .pixel_freq = 297000, +- .pll_base_freq = 2970000, +- .pll_od1 = 1, ++ .pll_base_freq = 5940000, ++ .pll_od1 = 2, + .pll_od2 = 1, + .pll_od3 = 1, + .vid_pll_div = VID_PLL_DIV_5, + +From 7f4fa153c248e0f05b4de87c02abf9779ed1261d Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:15 +0100 +Subject: [PATCH 042/249] FROMGIT: drm/meson: Add registers for G12A SoC + +This patch adds the new VPU registers added since the +Amlogic GXM SoCs. + +Signed-off-by: Neil Armstrong +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-3-narmstrong@baylibre.com +(cherry picked from commit b93a66faeea9ddf3dd00c51af0f13a65d3c18cd1 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_registers.h | 247 ++++++++++++++++++++++++ + 1 file changed, 247 insertions(+) + +diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h +index 5c7e02c703bc7..cfaf90501bb17 100644 +--- a/drivers/gpu/drm/meson/meson_registers.h ++++ b/drivers/gpu/drm/meson/meson_registers.h +@@ -216,6 +216,29 @@ + #define VIU_OSD2_FIFO_CTRL_STAT 0x1a4b + #define VIU_OSD2_TEST_RDDATA 0x1a4c + #define VIU_OSD2_PROT_CTRL 0x1a4e ++#define VIU_OSD2_MALI_UNPACK_CTRL 0x1abd ++#define VIU_OSD2_DIMM_CTRL 0x1acf ++ ++#define VIU_OSD3_CTRL_STAT 0x3d80 ++#define VIU_OSD3_CTRL_STAT2 0x3d81 ++#define VIU_OSD3_COLOR_ADDR 0x3d82 ++#define VIU_OSD3_COLOR 0x3d83 ++#define VIU_OSD3_TCOLOR_AG0 0x3d84 ++#define VIU_OSD3_TCOLOR_AG1 0x3d85 ++#define VIU_OSD3_TCOLOR_AG2 0x3d86 ++#define VIU_OSD3_TCOLOR_AG3 0x3d87 ++#define VIU_OSD3_BLK0_CFG_W0 0x3d88 ++#define VIU_OSD3_BLK0_CFG_W1 0x3d8c ++#define VIU_OSD3_BLK0_CFG_W2 0x3d90 ++#define VIU_OSD3_BLK0_CFG_W3 0x3d94 ++#define VIU_OSD3_BLK0_CFG_W4 0x3d98 ++#define VIU_OSD3_BLK1_CFG_W4 0x3d99 ++#define VIU_OSD3_BLK2_CFG_W4 0x3d9a ++#define VIU_OSD3_FIFO_CTRL_STAT 0x3d9c ++#define VIU_OSD3_TEST_RDDATA 0x3d9d ++#define VIU_OSD3_PROT_CTRL 0x3d9e ++#define VIU_OSD3_MALI_UNPACK_CTRL 0x3d9f ++#define VIU_OSD3_DIMM_CTRL 0x3da0 + + #define VD1_IF0_GEN_REG 0x1a50 + #define VD1_IF0_CANVAS0 0x1a51 +@@ -287,6 +310,27 @@ + #define VIU_OSD1_MATRIX_COEF31_32 0x1a9e + #define VIU_OSD1_MATRIX_COEF40_41 0x1a9f + #define VD1_IF0_GEN_REG3 0x1aa7 ++ ++#define VIU_OSD_BLENDO_H_START_END 0x1aa9 ++#define VIU_OSD_BLENDO_V_START_END 0x1aaa ++#define VIU_OSD_BLEND_GEN_CTRL0 0x1aab ++#define VIU_OSD_BLEND_GEN_CTRL1 0x1aac ++#define VIU_OSD_BLEND_DUMMY_DATA 0x1aad ++#define VIU_OSD_BLEND_CURRENT_XY 0x1aae ++ ++#define VIU_OSD2_MATRIX_CTRL 0x1ab0 ++#define VIU_OSD2_MATRIX_COEF00_01 0x1ab1 ++#define VIU_OSD2_MATRIX_COEF02_10 0x1ab2 ++#define VIU_OSD2_MATRIX_COEF11_12 0x1ab3 ++#define VIU_OSD2_MATRIX_COEF20_21 0x1ab4 ++#define VIU_OSD2_MATRIX_COEF22 0x1ab5 ++#define VIU_OSD2_MATRIX_OFFSET0_1 0x1ab6 ++#define VIU_OSD2_MATRIX_OFFSET2 0x1ab7 ++#define VIU_OSD2_MATRIX_PRE_OFFSET0_1 0x1ab8 ++#define VIU_OSD2_MATRIX_PRE_OFFSET2 0x1ab9 ++#define VIU_OSD2_MATRIX_PROBE_COLOR 0x1aba ++#define VIU_OSD2_MATRIX_HL_COLOR 0x1abb ++#define VIU_OSD2_MATRIX_PROBE_POS 0x1abc + #define VIU_OSD1_EOTF_CTL 0x1ad4 + #define VIU_OSD1_EOTF_COEF00_01 0x1ad5 + #define VIU_OSD1_EOTF_COEF02_10 0x1ad6 +@@ -481,6 +525,82 @@ + #define VPP_OSD_SCALE_COEF 0x1dcd + #define VPP_INT_LINE_NUM 0x1dce + ++#define VPP_WRAP_OSD1_MATRIX_COEF00_01 0x3d60 ++#define VPP_WRAP_OSD1_MATRIX_COEF02_10 0x3d61 ++#define VPP_WRAP_OSD1_MATRIX_COEF11_12 0x3d62 ++#define VPP_WRAP_OSD1_MATRIX_COEF20_21 0x3d63 ++#define VPP_WRAP_OSD1_MATRIX_COEF22 0x3d64 ++#define VPP_WRAP_OSD1_MATRIX_COEF13_14 0x3d65 ++#define VPP_WRAP_OSD1_MATRIX_COEF23_24 0x3d66 ++#define VPP_WRAP_OSD1_MATRIX_COEF15_25 0x3d67 ++#define VPP_WRAP_OSD1_MATRIX_CLIP 0x3d68 ++#define VPP_WRAP_OSD1_MATRIX_OFFSET0_1 0x3d69 ++#define VPP_WRAP_OSD1_MATRIX_OFFSET2 0x3d6a ++#define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1 0x3d6b ++#define VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2 0x3d6c ++#define VPP_WRAP_OSD1_MATRIX_EN_CTRL 0x3d6d ++ ++#define VPP_WRAP_OSD2_MATRIX_COEF00_01 0x3d70 ++#define VPP_WRAP_OSD2_MATRIX_COEF02_10 0x3d71 ++#define VPP_WRAP_OSD2_MATRIX_COEF11_12 0x3d72 ++#define VPP_WRAP_OSD2_MATRIX_COEF20_21 0x3d73 ++#define VPP_WRAP_OSD2_MATRIX_COEF22 0x3d74 ++#define VPP_WRAP_OSD2_MATRIX_COEF13_14 0x3d75 ++#define VPP_WRAP_OSD2_MATRIX_COEF23_24 0x3d76 ++#define VPP_WRAP_OSD2_MATRIX_COEF15_25 0x3d77 ++#define VPP_WRAP_OSD2_MATRIX_CLIP 0x3d78 ++#define VPP_WRAP_OSD2_MATRIX_OFFSET0_1 0x3d79 ++#define VPP_WRAP_OSD2_MATRIX_OFFSET2 0x3d7a ++#define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET0_1 0x3d7b ++#define VPP_WRAP_OSD2_MATRIX_PRE_OFFSET2 0x3d7c ++#define VPP_WRAP_OSD2_MATRIX_EN_CTRL 0x3d7d ++ ++#define VPP_WRAP_OSD3_MATRIX_COEF00_01 0x3db0 ++#define VPP_WRAP_OSD3_MATRIX_COEF02_10 0x3db1 ++#define VPP_WRAP_OSD3_MATRIX_COEF11_12 0x3db2 ++#define VPP_WRAP_OSD3_MATRIX_COEF20_21 0x3db3 ++#define VPP_WRAP_OSD3_MATRIX_COEF22 0x3db4 ++#define VPP_WRAP_OSD3_MATRIX_COEF13_14 0x3db5 ++#define VPP_WRAP_OSD3_MATRIX_COEF23_24 0x3db6 ++#define VPP_WRAP_OSD3_MATRIX_COEF15_25 0x3db7 ++#define VPP_WRAP_OSD3_MATRIX_CLIP 0x3db8 ++#define VPP_WRAP_OSD3_MATRIX_OFFSET0_1 0x3db9 ++#define VPP_WRAP_OSD3_MATRIX_OFFSET2 0x3dba ++#define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET0_1 0x3dbb ++#define VPP_WRAP_OSD3_MATRIX_PRE_OFFSET2 0x3dbc ++#define VPP_WRAP_OSD3_MATRIX_EN_CTRL 0x3dbd ++ ++/* osd2 scaler */ ++#define OSD2_VSC_PHASE_STEP 0x3d00 ++#define OSD2_VSC_INI_PHASE 0x3d01 ++#define OSD2_VSC_CTRL0 0x3d02 ++#define OSD2_HSC_PHASE_STEP 0x3d03 ++#define OSD2_HSC_INI_PHASE 0x3d04 ++#define OSD2_HSC_CTRL0 0x3d05 ++#define OSD2_HSC_INI_PAT_CTRL 0x3d06 ++#define OSD2_SC_DUMMY_DATA 0x3d07 ++#define OSD2_SC_CTRL0 0x3d08 ++#define OSD2_SCI_WH_M1 0x3d09 ++#define OSD2_SCO_H_START_END 0x3d0a ++#define OSD2_SCO_V_START_END 0x3d0b ++#define OSD2_SCALE_COEF_IDX 0x3d18 ++#define OSD2_SCALE_COEF 0x3d19 ++ ++/* osd34 scaler */ ++#define OSD34_SCALE_COEF_IDX 0x3d1e ++#define OSD34_SCALE_COEF 0x3d1f ++#define OSD34_VSC_PHASE_STEP 0x3d20 ++#define OSD34_VSC_INI_PHASE 0x3d21 ++#define OSD34_VSC_CTRL0 0x3d22 ++#define OSD34_HSC_PHASE_STEP 0x3d23 ++#define OSD34_HSC_INI_PHASE 0x3d24 ++#define OSD34_HSC_CTRL0 0x3d25 ++#define OSD34_HSC_INI_PAT_CTRL 0x3d26 ++#define OSD34_SC_DUMMY_DATA 0x3d27 ++#define OSD34_SC_CTRL0 0x3d28 ++#define OSD34_SCI_WH_M1 0x3d29 ++#define OSD34_SCO_H_START_END 0x3d2a ++#define OSD34_SCO_V_START_END 0x3d2b + /* viu2 */ + #define VIU2_ADDR_START 0x1e00 + #define VIU2_ADDR_END 0x1eff +@@ -1400,4 +1520,131 @@ + #define OSDSR_YBIC_VCOEF0 0x3149 + #define OSDSR_CBIC_VCOEF0 0x314a + ++/* osd afbcd on gxtvbb */ ++#define OSD1_AFBCD_ENABLE 0x31a0 ++#define OSD1_AFBCD_MODE 0x31a1 ++#define OSD1_AFBCD_SIZE_IN 0x31a2 ++#define OSD1_AFBCD_HDR_PTR 0x31a3 ++#define OSD1_AFBCD_FRAME_PTR 0x31a4 ++#define OSD1_AFBCD_CHROMA_PTR 0x31a5 ++#define OSD1_AFBCD_CONV_CTRL 0x31a6 ++#define OSD1_AFBCD_STATUS 0x31a8 ++#define OSD1_AFBCD_PIXEL_HSCOPE 0x31a9 ++#define OSD1_AFBCD_PIXEL_VSCOPE 0x31aa ++#define VIU_MISC_CTRL1 0x1a07 ++ ++/* add for gxm and 962e dv core2 */ ++#define DOLBY_CORE2A_SWAP_CTRL1 0x3434 ++#define DOLBY_CORE2A_SWAP_CTRL2 0x3435 ++ ++/* osd afbc on g12a */ ++#define VPU_MAFBC_BLOCK_ID 0x3a00 ++#define VPU_MAFBC_IRQ_RAW_STATUS 0x3a01 ++#define VPU_MAFBC_IRQ_CLEAR 0x3a02 ++#define VPU_MAFBC_IRQ_MASK 0x3a03 ++#define VPU_MAFBC_IRQ_STATUS 0x3a04 ++#define VPU_MAFBC_COMMAND 0x3a05 ++#define VPU_MAFBC_STATUS 0x3a06 ++#define VPU_MAFBC_SURFACE_CFG 0x3a07 ++ ++/* osd afbc on g12a */ ++#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S0 0x3a10 ++#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S0 0x3a11 ++#define VPU_MAFBC_FORMAT_SPECIFIER_S0 0x3a12 ++#define VPU_MAFBC_BUFFER_WIDTH_S0 0x3a13 ++#define VPU_MAFBC_BUFFER_HEIGHT_S0 0x3a14 ++#define VPU_MAFBC_BOUNDING_BOX_X_START_S0 0x3a15 ++#define VPU_MAFBC_BOUNDING_BOX_X_END_S0 0x3a16 ++#define VPU_MAFBC_BOUNDING_BOX_Y_START_S0 0x3a17 ++#define VPU_MAFBC_BOUNDING_BOX_Y_END_S0 0x3a18 ++#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S0 0x3a19 ++#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S0 0x3a1a ++#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S0 0x3a1b ++#define VPU_MAFBC_PREFETCH_CFG_S0 0x3a1c ++ ++#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S1 0x3a30 ++#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S1 0x3a31 ++#define VPU_MAFBC_FORMAT_SPECIFIER_S1 0x3a32 ++#define VPU_MAFBC_BUFFER_WIDTH_S1 0x3a33 ++#define VPU_MAFBC_BUFFER_HEIGHT_S1 0x3a34 ++#define VPU_MAFBC_BOUNDING_BOX_X_START_S1 0x3a35 ++#define VPU_MAFBC_BOUNDING_BOX_X_END_S1 0x3a36 ++#define VPU_MAFBC_BOUNDING_BOX_Y_START_S1 0x3a37 ++#define VPU_MAFBC_BOUNDING_BOX_Y_END_S1 0x3a38 ++#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S1 0x3a39 ++#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S1 0x3a3a ++#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S1 0x3a3b ++#define VPU_MAFBC_PREFETCH_CFG_S1 0x3a3c ++ ++#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S2 0x3a50 ++#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S2 0x3a51 ++#define VPU_MAFBC_FORMAT_SPECIFIER_S2 0x3a52 ++#define VPU_MAFBC_BUFFER_WIDTH_S2 0x3a53 ++#define VPU_MAFBC_BUFFER_HEIGHT_S2 0x3a54 ++#define VPU_MAFBC_BOUNDING_BOX_X_START_S2 0x3a55 ++#define VPU_MAFBC_BOUNDING_BOX_X_END_S2 0x3a56 ++#define VPU_MAFBC_BOUNDING_BOX_Y_START_S2 0x3a57 ++#define VPU_MAFBC_BOUNDING_BOX_Y_END_S2 0x3a58 ++#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S2 0x3a59 ++#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S2 0x3a5a ++#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S2 0x3a5b ++#define VPU_MAFBC_PREFETCH_CFG_S2 0x3a5c ++ ++#define VPU_MAFBC_HEADER_BUF_ADDR_LOW_S3 0x3a70 ++#define VPU_MAFBC_HEADER_BUF_ADDR_HIGH_S3 0x3a71 ++#define VPU_MAFBC_FORMAT_SPECIFIER_S3 0x3a72 ++#define VPU_MAFBC_BUFFER_WIDTH_S3 0x3a73 ++#define VPU_MAFBC_BUFFER_HEIGHT_S3 0x3a74 ++#define VPU_MAFBC_BOUNDING_BOX_X_START_S3 0x3a75 ++#define VPU_MAFBC_BOUNDING_BOX_X_END_S3 0x3a76 ++#define VPU_MAFBC_BOUNDING_BOX_Y_START_S3 0x3a77 ++#define VPU_MAFBC_BOUNDING_BOX_Y_END_S3 0x3a78 ++#define VPU_MAFBC_OUTPUT_BUF_ADDR_LOW_S3 0x3a79 ++#define VPU_MAFBC_OUTPUT_BUF_ADDR_HIGH_S3 0x3a7a ++#define VPU_MAFBC_OUTPUT_BUF_STRIDE_S3 0x3a7b ++#define VPU_MAFBC_PREFETCH_CFG_S3 0x3a7c ++ ++#define DOLBY_PATH_CTRL 0x1a0c ++#define OSD_PATH_MISC_CTRL 0x1a0e ++#define MALI_AFBCD_TOP_CTRL 0x1a0f ++ ++#define VIU_OSD_BLEND_CTRL 0x39b0 ++#define VIU_OSD_BLEND_CTRL1 0x39c0 ++#define VIU_OSD_BLEND_DIN0_SCOPE_H 0x39b1 ++#define VIU_OSD_BLEND_DIN0_SCOPE_V 0x39b2 ++#define VIU_OSD_BLEND_DIN1_SCOPE_H 0x39b3 ++#define VIU_OSD_BLEND_DIN1_SCOPE_V 0x39b4 ++#define VIU_OSD_BLEND_DIN2_SCOPE_H 0x39b5 ++#define VIU_OSD_BLEND_DIN2_SCOPE_V 0x39b6 ++#define VIU_OSD_BLEND_DIN3_SCOPE_H 0x39b7 ++#define VIU_OSD_BLEND_DIN3_SCOPE_V 0x39b8 ++#define VIU_OSD_BLEND_DUMMY_DATA0 0x39b9 ++#define VIU_OSD_BLEND_DUMMY_ALPHA 0x39ba ++#define VIU_OSD_BLEND_BLEND0_SIZE 0x39bb ++#define VIU_OSD_BLEND_BLEND1_SIZE 0x39bc ++#define VIU_OSD_BLEND_RO_CURRENT_XY 0x39bf ++ ++#define VPP_OUT_H_V_SIZE 0x1da5 ++ ++#define VPP_VD2_HDR_IN_SIZE 0x1df0 ++#define VPP_OSD1_IN_SIZE 0x1df1 ++#define VPP_GCLK_CTRL2 0x1df2 ++#define VD2_PPS_DUMMY_DATA 0x1df4 ++#define VPP_OSD1_BLD_H_SCOPE 0x1df5 ++#define VPP_OSD1_BLD_V_SCOPE 0x1df6 ++#define VPP_OSD2_BLD_H_SCOPE 0x1df7 ++#define VPP_OSD2_BLD_V_SCOPE 0x1df8 ++#define VPP_WRBAK_CTRL 0x1df9 ++#define VPP_SLEEP_CTRL 0x1dfa ++#define VD1_BLEND_SRC_CTRL 0x1dfb ++#define VD2_BLEND_SRC_CTRL 0x1dfc ++#define OSD1_BLEND_SRC_CTRL 0x1dfd ++#define OSD2_BLEND_SRC_CTRL 0x1dfe ++ ++#define VPP_POST_BLEND_BLEND_DUMMY_DATA 0x3968 ++#define VPP_POST_BLEND_DUMMY_ALPHA 0x3969 ++#define VPP_RDARB_MODE 0x3978 ++#define VPP_RDARB_REQEN_SLV 0x3979 ++#define VPU_RDARB_MODE_L2C1 0x279d ++ + #endif /* __MESON_REGISTERS_H */ + +From 4c74bd81938dcef24a848f9721df38ac7e889e71 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:16 +0100 +Subject: [PATCH 043/249] FROMGIT: drm/meson: Add G12A Support for VPP setup + +Amlogic G12A needs a different VPP setup code, handle it here. + +Signed-off-by: Neil Armstrong +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-4-narmstrong@baylibre.com +(cherry picked from commit e4d1ae1fa3603614ed9799b4407a8d09a796fb0b + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_vpp.c | 51 ++++++++++++++++++------------- + 1 file changed, 29 insertions(+), 22 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c +index f9efb431e9535..8c52a3455ef47 100644 +--- a/drivers/gpu/drm/meson/meson_vpp.c ++++ b/drivers/gpu/drm/meson/meson_vpp.c +@@ -112,32 +112,39 @@ void meson_vpp_init(struct meson_drm *priv) + writel_relaxed(0x20000, priv->io_base + _REG(VPP_DOLBY_CTRL)); + writel_relaxed(0x1020080, + priv->io_base + _REG(VPP_DUMMY_DATA1)); +- } ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ writel_relaxed(0xf, priv->io_base + _REG(DOLBY_PATH_CTRL)); + + /* Initialize vpu fifo control registers */ +- writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | +- 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ writel_relaxed(0xfff << 20 | 0x1000, ++ priv->io_base + _REG(VPP_OFIFO_SIZE)); ++ else ++ writel_relaxed(readl_relaxed(priv->io_base + _REG(VPP_OFIFO_SIZE)) | ++ 0x77f, priv->io_base + _REG(VPP_OFIFO_SIZE)); + writel_relaxed(0x08080808, priv->io_base + _REG(VPP_HOLD_LINES)); + +- /* Turn off preblend */ +- writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0, +- priv->io_base + _REG(VPP_MISC)); +- +- /* Turn off POSTBLEND */ +- writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, +- priv->io_base + _REG(VPP_MISC)); +- +- /* Force all planes off */ +- writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | +- VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND | +- VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0, +- priv->io_base + _REG(VPP_MISC)); +- +- /* Setup default VD settings */ +- writel_relaxed(4096, +- priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END)); +- writel_relaxed(4096, +- priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); ++ if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ /* Turn off preblend */ ++ writel_bits_relaxed(VPP_PREBLEND_ENABLE, 0, ++ priv->io_base + _REG(VPP_MISC)); ++ ++ /* Turn off POSTBLEND */ ++ writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0, ++ priv->io_base + _REG(VPP_MISC)); ++ ++ /* Force all planes off */ ++ writel_bits_relaxed(VPP_OSD1_POSTBLEND | VPP_OSD2_POSTBLEND | ++ VPP_VD1_POSTBLEND | VPP_VD2_POSTBLEND | ++ VPP_VD1_PREBLEND | VPP_VD2_PREBLEND, 0, ++ priv->io_base + _REG(VPP_MISC)); ++ ++ /* Setup default VD settings */ ++ writel_relaxed(4096, ++ priv->io_base + _REG(VPP_PREBLEND_VD1_H_START_END)); ++ writel_relaxed(4096, ++ priv->io_base + _REG(VPP_BLEND_VD2_H_START_END)); ++ } + + /* Disable Scalers */ + writel_relaxed(0, priv->io_base + _REG(VPP_OSD_SC_CTRL0)); + +From 2953e224163700e393ac626a42c54f08155c403f Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:17 +0100 +Subject: [PATCH 044/249] FROMGIT: drm/meson: Add G12A Support for VIU setup + +Amlogic G12A SoC needs a different VIU setup code, +handle it. + +Signed-off-by: Neil Armstrong +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-5-narmstrong@baylibre.com +(cherry picked from commit 728883948b0d3c01492c1f83d505645aa2ca09d0 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_viu.c | 72 ++++++++++++++++++++++++++++--- + 1 file changed, 67 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c +index ac0f3687e09a3..0169c98b01c94 100644 +--- a/drivers/gpu/drm/meson/meson_viu.c ++++ b/drivers/gpu/drm/meson/meson_viu.c +@@ -90,6 +90,34 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { + EOTF_COEFF_RIGHTSHIFT /* right shift */ + }; + ++void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, int *m, ++ bool csc_on) ++{ ++ /* VPP WRAP OSD1 matrix */ ++ writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET0_1)); ++ writel(m[2] & 0xfff, ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_PRE_OFFSET2)); ++ writel(((m[3] & 0x1fff) << 16) | (m[4] & 0x1fff), ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF00_01)); ++ writel(((m[5] & 0x1fff) << 16) | (m[6] & 0x1fff), ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF02_10)); ++ writel(((m[7] & 0x1fff) << 16) | (m[8] & 0x1fff), ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF11_12)); ++ writel(((m[9] & 0x1fff) << 16) | (m[10] & 0x1fff), ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF20_21)); ++ writel((m[11] & 0x1fff) << 16, ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_COEF22)); ++ ++ writel(((m[18] & 0xfff) << 16) | (m[19] & 0xfff), ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET0_1)); ++ writel(m[20] & 0xfff, ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_OFFSET2)); ++ ++ writel_bits_relaxed(BIT(0), csc_on ? BIT(0) : 0, ++ priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); ++} ++ + void meson_viu_set_osd_matrix(struct meson_drm *priv, + enum viu_matrix_sel_e m_select, + int *m, bool csc_on) +@@ -336,14 +364,24 @@ void meson_viu_init(struct meson_drm *priv) + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + meson_viu_load_matrix(priv); ++ else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ meson_viu_set_g12a_osd1_matrix(priv, RGB709_to_YUV709l_coeff, ++ true); + + /* Initialize OSD1 fifo control register */ + reg = BIT(0) | /* Urgent DDR request priority */ +- (4 << 5) | /* hold_fifo_lines */ +- (3 << 10) | /* burst length 64 */ +- (32 << 12) | /* fifo_depth_val: 32*8=256 */ +- (2 << 22) | /* 4 words in 1 burst */ +- (2 << 24); ++ (4 << 5); /* hold_fifo_lines */ ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ reg |= (1 << 10) | /* burst length 32 */ ++ (32 << 12) | /* fifo_depth_val: 32*8=256 */ ++ (2 << 22) | /* 4 words in 1 burst */ ++ (2 << 24) | ++ (1 << 31); ++ else ++ reg |= (3 << 10) | /* burst length 64 */ ++ (32 << 12) | /* fifo_depth_val: 32*8=256 */ ++ (2 << 22) | /* 4 words in 1 burst */ ++ (2 << 24); + writel_relaxed(reg, priv->io_base + _REG(VIU_OSD1_FIFO_CTRL_STAT)); + writel_relaxed(reg, priv->io_base + _REG(VIU_OSD2_FIFO_CTRL_STAT)); + +@@ -369,6 +407,30 @@ void meson_viu_init(struct meson_drm *priv) + writel_relaxed(0x00FF00C0, + priv->io_base + _REG(VD2_IF0_LUMA_FIFO_SIZE)); + ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ writel_relaxed(4 << 29 | ++ 1 << 27 | ++ 1 << 26 | /* blend_din0 input to blend0 */ ++ 1 << 25 | /* blend1_dout to blend2 */ ++ 1 << 24 | /* blend1_din3 input to blend1 */ ++ 1 << 20 | ++ 0 << 16 | ++ 1, ++ priv->io_base + _REG(VIU_OSD_BLEND_CTRL)); ++ writel_relaxed(3 << 8 | ++ 1 << 20, ++ priv->io_base + _REG(OSD1_BLEND_SRC_CTRL)); ++ writel_relaxed(1 << 20, ++ priv->io_base + _REG(OSD2_BLEND_SRC_CTRL)); ++ writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); ++ writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); ++ writel_relaxed(0, ++ priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_DATA0)); ++ writel_relaxed(0, ++ priv->io_base + _REG(VIU_OSD_BLEND_DUMMY_ALPHA)); ++ writel_bits_relaxed(0x3 << 2, 0x3 << 2, ++ priv->io_base + _REG(DOLBY_PATH_CTRL)); ++ } + + priv->viu.osd1_enabled = false; + priv->viu.osd1_commit = false; + +From 2b0b206f454e1ac5293598b47a863b4745de2493 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:18 +0100 +Subject: [PATCH 045/249] FROMGIT: drm/meson: Add G12A support for OSD1 Plane + +Amlogic G12A SoC supports now up to 3 OSD planes (1 more than the +previous SoCs) and a brand new OSD plane blender module. + +This patch uses the same OSD1 plane for G12A, using the exact same scaler +and OSD1 setup registers, except using the new blender register to +disable the plane. + +Signed-off-by: Neil Armstrong +[narmstrong: fixed typo in commit log] +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-6-narmstrong@baylibre.com +(cherry picked from commit 490f50c109d1178aae4124cd9138b231d030e554 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_plane.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index b7786218cb10a..bf8f1fab63aa9 100644 +--- a/drivers/gpu/drm/meson/meson_plane.c ++++ b/drivers/gpu/drm/meson/meson_plane.c +@@ -294,6 +294,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, + priv->viu.osd1_blk0_cfg[3] = ((dest.x2 - 1) << 16) | dest.x1; + priv->viu.osd1_blk0_cfg[4] = ((dest.y2 - 1) << 16) | dest.y1; + ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ priv->viu.osd_blend_din0_scope_h = ((dest.x2 - 1) << 16) | dest.x1; ++ priv->viu.osd_blend_din0_scope_v = ((dest.y2 - 1) << 16) | dest.y1; ++ priv->viu.osb_blend0_size = dst_h << 16 | dst_w; ++ priv->viu.osb_blend1_size = dst_h << 16 | dst_w; ++ } ++ + /* Update Canvas with buffer address */ + gem = drm_fb_cma_get_gem_obj(fb, 0); + +@@ -320,8 +327,12 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, + struct meson_drm *priv = meson_plane->priv; + + /* Disable OSD1 */ +- writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, +- priv->io_base + _REG(VPP_MISC)); ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ writel_bits_relaxed(BIT(0) | BIT(21), 0, ++ priv->io_base + _REG(VIU_OSD1_CTRL_STAT)); ++ else ++ writel_bits_relaxed(VPP_OSD1_POSTBLEND, 0, ++ priv->io_base + _REG(VPP_MISC)); + + meson_plane->enabled = false; + + +From 427d164c3823ebab6fd0c3f7c2f058eef3c0ff42 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:19 +0100 +Subject: [PATCH 046/249] FROMGIT: drm/meson: Add G12A Support for the Overlay + video plane + +Amlogic G12A SoC supports the same set of Video Planes, but now +are handled by the new OSD plane blender module. + +This patch uses the same VD1 plane for G12A, using the exact same scaler +and VD1 setup registers, except using the new blender register to +disable the plane. + +Signed-off-by: Neil Armstrong +[narmstrong: fix typo in commit log] +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-7-narmstrong@baylibre.com +(cherry picked from commit 11c2d4c751e5b339f8a3c6b9f19120bb331af0ef + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_overlay.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c +index b54a22e483b92..bdbf925ff3e85 100644 +--- a/drivers/gpu/drm/meson/meson_overlay.c ++++ b/drivers/gpu/drm/meson/meson_overlay.c +@@ -516,8 +516,14 @@ static void meson_overlay_atomic_disable(struct drm_plane *plane, + priv->viu.vd1_enabled = false; + + /* Disable VD1 */ +- writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, +- priv->io_base + _REG(VPP_MISC)); ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ writel_relaxed(0, priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); ++ writel_relaxed(0, priv->io_base + _REG(VD2_BLEND_SRC_CTRL)); ++ writel_relaxed(0, priv->io_base + _REG(VD1_IF0_GEN_REG + 0x17b0)); ++ writel_relaxed(0, priv->io_base + _REG(VD2_IF0_GEN_REG + 0x17b0)); ++ } else ++ writel_bits_relaxed(VPP_VD1_POSTBLEND | VPP_VD1_PREBLEND, 0, ++ priv->io_base + _REG(VPP_MISC)); + + } + + +From 15a35f845c1c1b3995d522a3b7540d63f594b21e Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:20 +0100 +Subject: [PATCH 047/249] FROMGIT: drm/meson: Add G12A support for plane + handling in CRTC driver + +This patch adds support for the new OSD+VD Plane blending module +in the CRTC code by adding the G12A code to manage the blending +module and setting the right OSD1 & VD1 plane registers. + +Signed-off-by: Neil Armstrong +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-8-narmstrong@baylibre.com +(cherry picked from commit 68679d41a3d6d7e55ed49b4e5688d1089de7c5a7 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_crtc.c | 269 +++++++++++++++++++++++------ + drivers/gpu/drm/meson/meson_drv.h | 4 + + 2 files changed, 221 insertions(+), 52 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c +index 6d9311e254efc..5579f8ac3e3f7 100644 +--- a/drivers/gpu/drm/meson/meson_crtc.c ++++ b/drivers/gpu/drm/meson/meson_crtc.c +@@ -39,12 +39,17 @@ + #include "meson_viu.h" + #include "meson_registers.h" + ++#define MESON_G12A_VIU_OFFSET 0x5ec0 ++ + /* CRTC definition */ + + struct meson_crtc { + struct drm_crtc base; + struct drm_pending_vblank_event *event; + struct meson_drm *priv; ++ void (*enable_osd1)(struct meson_drm *priv); ++ void (*enable_vd1)(struct meson_drm *priv); ++ unsigned int viu_offset; + }; + #define to_meson_crtc(x) container_of(x, struct meson_crtc, base) + +@@ -80,6 +85,44 @@ static const struct drm_crtc_funcs meson_crtc_funcs = { + + }; + ++static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, ++ struct drm_crtc_state *old_state) ++{ ++ struct meson_crtc *meson_crtc = to_meson_crtc(crtc); ++ struct drm_crtc_state *crtc_state = crtc->state; ++ struct meson_drm *priv = meson_crtc->priv; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ if (!crtc_state) { ++ DRM_ERROR("Invalid crtc_state\n"); ++ return; ++ } ++ ++ /* VD1 Preblend vertical start/end */ ++ writel(FIELD_PREP(GENMASK(11, 0), 2303), ++ priv->io_base + _REG(VPP_PREBLEND_VD1_V_START_END)); ++ ++ /* Setup Blender */ ++ writel(crtc_state->mode.hdisplay | ++ crtc_state->mode.vdisplay << 16, ++ priv->io_base + _REG(VPP_POSTBLEND_H_SIZE)); ++ ++ writel_relaxed(0 << 16 | ++ (crtc_state->mode.hdisplay - 1), ++ priv->io_base + _REG(VPP_OSD1_BLD_H_SCOPE)); ++ writel_relaxed(0 << 16 | ++ (crtc_state->mode.vdisplay - 1), ++ priv->io_base + _REG(VPP_OSD1_BLD_V_SCOPE)); ++ writel_relaxed(crtc_state->mode.hdisplay << 16 | ++ crtc_state->mode.vdisplay, ++ priv->io_base + _REG(VPP_OUT_H_V_SIZE)); ++ ++ drm_crtc_vblank_on(crtc); ++ ++ priv->viu.osd1_enabled = true; ++} ++ + static void meson_crtc_atomic_enable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) + { +@@ -110,6 +153,31 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc, + priv->viu.osd1_enabled = true; + } + ++static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, ++ struct drm_crtc_state *old_state) ++{ ++ struct meson_crtc *meson_crtc = to_meson_crtc(crtc); ++ struct meson_drm *priv = meson_crtc->priv; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ drm_crtc_vblank_off(crtc); ++ ++ priv->viu.osd1_enabled = false; ++ priv->viu.osd1_commit = false; ++ ++ priv->viu.vd1_enabled = false; ++ priv->viu.vd1_commit = false; ++ ++ if (crtc->state->event && !crtc->state->active) { ++ spin_lock_irq(&crtc->dev->event_lock); ++ drm_crtc_send_vblank_event(crtc, crtc->state->event); ++ spin_unlock_irq(&crtc->dev->event_lock); ++ ++ crtc->state->event = NULL; ++ } ++} ++ + static void meson_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) + { +@@ -173,6 +241,53 @@ static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = { + .atomic_disable = meson_crtc_atomic_disable, + }; + ++static const struct drm_crtc_helper_funcs meson_g12a_crtc_helper_funcs = { ++ .atomic_begin = meson_crtc_atomic_begin, ++ .atomic_flush = meson_crtc_atomic_flush, ++ .atomic_enable = meson_g12a_crtc_atomic_enable, ++ .atomic_disable = meson_g12a_crtc_atomic_disable, ++}; ++ ++static void meson_crtc_enable_osd1(struct meson_drm *priv) ++{ ++ writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, ++ priv->io_base + _REG(VPP_MISC)); ++} ++ ++static void meson_g12a_crtc_enable_osd1(struct meson_drm *priv) ++{ ++ writel_relaxed(priv->viu.osd_blend_din0_scope_h, ++ priv->io_base + ++ _REG(VIU_OSD_BLEND_DIN0_SCOPE_H)); ++ 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, ++ priv->io_base + ++ _REG(VIU_OSD_BLEND_BLEND0_SIZE)); ++ writel_relaxed(priv->viu.osb_blend1_size, ++ priv->io_base + ++ _REG(VIU_OSD_BLEND_BLEND1_SIZE)); ++} ++ ++static void meson_crtc_enable_vd1(struct meson_drm *priv) ++{ ++ writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | ++ VPP_COLOR_MNG_ENABLE, ++ VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | ++ VPP_COLOR_MNG_ENABLE, ++ priv->io_base + _REG(VPP_MISC)); ++} ++ ++static void meson_g12a_crtc_enable_vd1(struct meson_drm *priv) ++{ ++ writel_relaxed(((1 << 16) | /* post bld premult*/ ++ (1 << 8) | /* post src */ ++ (1 << 4) | /* pre bld premult*/ ++ (1 << 0)), ++ priv->io_base + _REG(VD1_BLEND_SRC_CTRL)); ++} ++ + void meson_crtc_irq(struct meson_drm *priv) + { + struct meson_crtc *meson_crtc = to_meson_crtc(priv->crtc); +@@ -219,8 +334,8 @@ void meson_crtc_irq(struct meson_drm *priv) + MESON_CANVAS_BLKMODE_LINEAR, 0); + + /* Enable OSD1 */ +- writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND, +- priv->io_base + _REG(VPP_MISC)); ++ if (meson_crtc->enable_osd1) ++ meson_crtc->enable_osd1(priv); + + priv->viu.osd1_commit = false; + } +@@ -261,89 +376,133 @@ void meson_crtc_irq(struct meson_drm *priv) + }; + + writel_relaxed(priv->viu.vd1_if0_gen_reg, +- priv->io_base + _REG(VD1_IF0_GEN_REG)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_GEN_REG)); + writel_relaxed(priv->viu.vd1_if0_gen_reg, +- priv->io_base + _REG(VD2_IF0_GEN_REG)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_GEN_REG)); + writel_relaxed(priv->viu.vd1_if0_gen_reg2, +- priv->io_base + _REG(VD1_IF0_GEN_REG2)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_GEN_REG2)); + writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, +- priv->io_base + _REG(VIU_VD1_FMT_CTRL)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VIU_VD1_FMT_CTRL)); + writel_relaxed(priv->viu.viu_vd1_fmt_ctrl, +- priv->io_base + _REG(VIU_VD2_FMT_CTRL)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VIU_VD2_FMT_CTRL)); + writel_relaxed(priv->viu.viu_vd1_fmt_w, +- priv->io_base + _REG(VIU_VD1_FMT_W)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VIU_VD1_FMT_W)); + writel_relaxed(priv->viu.viu_vd1_fmt_w, +- priv->io_base + _REG(VIU_VD2_FMT_W)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VIU_VD2_FMT_W)); + writel_relaxed(priv->viu.vd1_if0_canvas0, +- priv->io_base + _REG(VD1_IF0_CANVAS0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CANVAS0)); + writel_relaxed(priv->viu.vd1_if0_canvas0, +- priv->io_base + _REG(VD1_IF0_CANVAS1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CANVAS1)); + writel_relaxed(priv->viu.vd1_if0_canvas0, +- priv->io_base + _REG(VD2_IF0_CANVAS0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CANVAS0)); + writel_relaxed(priv->viu.vd1_if0_canvas0, +- priv->io_base + _REG(VD2_IF0_CANVAS1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CANVAS1)); + writel_relaxed(priv->viu.vd1_if0_luma_x0, +- priv->io_base + _REG(VD1_IF0_LUMA_X0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_LUMA_X0)); + writel_relaxed(priv->viu.vd1_if0_luma_x0, +- priv->io_base + _REG(VD1_IF0_LUMA_X1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_LUMA_X1)); + writel_relaxed(priv->viu.vd1_if0_luma_x0, +- priv->io_base + _REG(VD2_IF0_LUMA_X0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_LUMA_X0)); + writel_relaxed(priv->viu.vd1_if0_luma_x0, +- priv->io_base + _REG(VD2_IF0_LUMA_X1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_LUMA_X1)); + writel_relaxed(priv->viu.vd1_if0_luma_y0, +- priv->io_base + _REG(VD1_IF0_LUMA_Y0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_LUMA_Y0)); + writel_relaxed(priv->viu.vd1_if0_luma_y0, +- priv->io_base + _REG(VD1_IF0_LUMA_Y1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_LUMA_Y1)); + writel_relaxed(priv->viu.vd1_if0_luma_y0, +- priv->io_base + _REG(VD2_IF0_LUMA_Y0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_LUMA_Y0)); + writel_relaxed(priv->viu.vd1_if0_luma_y0, +- priv->io_base + _REG(VD2_IF0_LUMA_Y1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_LUMA_Y1)); + writel_relaxed(priv->viu.vd1_if0_chroma_x0, +- priv->io_base + _REG(VD1_IF0_CHROMA_X0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CHROMA_X0)); + writel_relaxed(priv->viu.vd1_if0_chroma_x0, +- priv->io_base + _REG(VD1_IF0_CHROMA_X1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CHROMA_X1)); + writel_relaxed(priv->viu.vd1_if0_chroma_x0, +- priv->io_base + _REG(VD2_IF0_CHROMA_X0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CHROMA_X0)); + writel_relaxed(priv->viu.vd1_if0_chroma_x0, +- priv->io_base + _REG(VD2_IF0_CHROMA_X1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CHROMA_X1)); + writel_relaxed(priv->viu.vd1_if0_chroma_y0, +- priv->io_base + _REG(VD1_IF0_CHROMA_Y0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CHROMA_Y0)); + writel_relaxed(priv->viu.vd1_if0_chroma_y0, +- priv->io_base + _REG(VD1_IF0_CHROMA_Y1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CHROMA_Y1)); + writel_relaxed(priv->viu.vd1_if0_chroma_y0, +- priv->io_base + _REG(VD2_IF0_CHROMA_Y0)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CHROMA_Y0)); + writel_relaxed(priv->viu.vd1_if0_chroma_y0, +- priv->io_base + _REG(VD2_IF0_CHROMA_Y1)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CHROMA_Y1)); + writel_relaxed(priv->viu.vd1_if0_repeat_loop, +- priv->io_base + _REG(VD1_IF0_RPT_LOOP)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_RPT_LOOP)); + writel_relaxed(priv->viu.vd1_if0_repeat_loop, +- priv->io_base + _REG(VD2_IF0_RPT_LOOP)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_RPT_LOOP)); + writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, +- priv->io_base + _REG(VD1_IF0_LUMA0_RPT_PAT)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_LUMA0_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, +- priv->io_base + _REG(VD2_IF0_LUMA0_RPT_PAT)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_LUMA0_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, +- priv->io_base + _REG(VD1_IF0_LUMA1_RPT_PAT)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_LUMA1_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_luma0_rpt_pat, +- priv->io_base + _REG(VD2_IF0_LUMA1_RPT_PAT)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_LUMA1_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, +- priv->io_base + _REG(VD1_IF0_CHROMA0_RPT_PAT)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CHROMA0_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, +- priv->io_base + _REG(VD2_IF0_CHROMA0_RPT_PAT)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CHROMA0_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, +- priv->io_base + _REG(VD1_IF0_CHROMA1_RPT_PAT)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CHROMA1_RPT_PAT)); + writel_relaxed(priv->viu.vd1_if0_chroma0_rpt_pat, +- priv->io_base + _REG(VD2_IF0_CHROMA1_RPT_PAT)); +- writel_relaxed(0, priv->io_base + _REG(VD1_IF0_LUMA_PSEL)); +- writel_relaxed(0, priv->io_base + _REG(VD1_IF0_CHROMA_PSEL)); +- writel_relaxed(0, priv->io_base + _REG(VD2_IF0_LUMA_PSEL)); +- writel_relaxed(0, priv->io_base + _REG(VD2_IF0_CHROMA_PSEL)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CHROMA1_RPT_PAT)); ++ writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_LUMA_PSEL)); ++ writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_CHROMA_PSEL)); ++ writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_LUMA_PSEL)); ++ writel_relaxed(0, priv->io_base + meson_crtc->viu_offset + ++ _REG(VD2_IF0_CHROMA_PSEL)); + writel_relaxed(priv->viu.vd1_range_map_y, +- priv->io_base + _REG(VD1_IF0_RANGE_MAP_Y)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_RANGE_MAP_Y)); + writel_relaxed(priv->viu.vd1_range_map_cb, +- priv->io_base + _REG(VD1_IF0_RANGE_MAP_CB)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_RANGE_MAP_CB)); + writel_relaxed(priv->viu.vd1_range_map_cr, +- priv->io_base + _REG(VD1_IF0_RANGE_MAP_CR)); ++ priv->io_base + meson_crtc->viu_offset + ++ _REG(VD1_IF0_RANGE_MAP_CR)); + writel_relaxed(0x78404, + priv->io_base + _REG(VPP_SC_MISC)); + writel_relaxed(priv->viu.vpp_pic_in_height, +@@ -389,11 +548,8 @@ void meson_crtc_irq(struct meson_drm *priv) + writel_relaxed(0x42, priv->io_base + _REG(VPP_SCALE_COEF_IDX)); + + /* Enable VD1 */ +- writel_bits_relaxed(VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | +- VPP_COLOR_MNG_ENABLE, +- VPP_VD1_PREBLEND | VPP_VD1_POSTBLEND | +- VPP_COLOR_MNG_ENABLE, +- priv->io_base + _REG(VPP_MISC)); ++ if (meson_crtc->enable_vd1) ++ meson_crtc->enable_vd1(priv); + + priv->viu.vd1_commit = false; + } +@@ -430,7 +586,16 @@ int meson_crtc_create(struct meson_drm *priv) + return ret; + } + +- drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ meson_crtc->enable_osd1 = meson_g12a_crtc_enable_osd1; ++ meson_crtc->enable_vd1 = meson_g12a_crtc_enable_vd1; ++ meson_crtc->viu_offset = MESON_G12A_VIU_OFFSET; ++ drm_crtc_helper_add(crtc, &meson_g12a_crtc_helper_funcs); ++ } else { ++ meson_crtc->enable_osd1 = meson_crtc_enable_osd1; ++ meson_crtc->enable_vd1 = meson_crtc_enable_vd1; ++ drm_crtc_helper_add(crtc, &meson_crtc_helper_funcs); ++ } + + priv->crtc = crtc; + +diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h +index 214a7cb18ce27..9614baa836b92 100644 +--- a/drivers/gpu/drm/meson/meson_drv.h ++++ b/drivers/gpu/drm/meson/meson_drv.h +@@ -62,6 +62,10 @@ struct meson_drm { + uint32_t osd_sc_h_phase_step; + uint32_t osd_sc_h_ctrl0; + uint32_t osd_sc_v_ctrl0; ++ uint32_t osd_blend_din0_scope_h; ++ uint32_t osd_blend_din0_scope_v; ++ uint32_t osb_blend0_size; ++ uint32_t osb_blend1_size; + + bool vd1_enabled; + bool vd1_commit; + +From 52fccfa8527daecd653a114798899e00bd10f087 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:21 +0100 +Subject: [PATCH 048/249] FROMGIT: drm/meson: Add G12A support for CVBS Encoder + +The Meson G12A SoCs uses the exact same CVBS encoder except a simple +CVBS DAC register offset and settings delta. + +Signed-off-by: Neil Armstrong +[narmstrong: fixed subject typo] +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-9-narmstrong@baylibre.com +(cherry picked from commit 64d598a106c3d6c06071fd66780d3d7d7d15251a + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_venc.c | 11 +++++++++-- + drivers/gpu/drm/meson/meson_venc_cvbs.c | 25 ++++++++++++++++++------- + 2 files changed, 27 insertions(+), 9 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c +index 66d73a932d193..6faca7313339e 100644 +--- a/drivers/gpu/drm/meson/meson_venc.c ++++ b/drivers/gpu/drm/meson/meson_venc.c +@@ -73,7 +73,9 @@ + /* HHI Registers */ + #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ + #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ ++#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ + #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ ++#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ + #define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ + + struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { +@@ -1675,8 +1677,13 @@ void meson_venc_disable_vsync(struct meson_drm *priv) + void meson_venc_init(struct meson_drm *priv) + { + /* Disable CVBS VDAC */ +- regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); +- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0); ++ regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 8); ++ } else { ++ regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); ++ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); ++ } + + /* Power Down Dacs */ + writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING)); +diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c +index d622d817b6df1..2c5341c881c47 100644 +--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c ++++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c +@@ -37,7 +37,9 @@ + + /* HHI VDAC Registers */ + #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ ++#define HHI_VDAC_CNTL0_G12A 0x2EC /* 0xbd offset in data sheet */ + #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ ++#define HHI_VDAC_CNTL1_G12A 0x2F0 /* 0xbe offset in data sheet */ + + struct meson_venc_cvbs { + struct drm_encoder encoder; +@@ -166,8 +168,13 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder) + struct meson_drm *priv = meson_venc_cvbs->priv; + + /* Disable CVBS VDAC */ +- regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); +- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0); ++ regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0); ++ } else { ++ regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); ++ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); ++ } + } + + static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) +@@ -179,13 +186,17 @@ static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) + /* VDAC0 source is not from ATV */ + writel_bits_relaxed(BIT(5), 0, priv->io_base + _REG(VENC_VDAC_DACSEL0)); + +- if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) { + regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1); +- else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) ++ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001); +- +- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); ++ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001); ++ regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0); ++ } + } + + static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, + +From 69f6ae40245b7d26374cd8c8ca7f23b529e0a627 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:22 +0100 +Subject: [PATCH 049/249] FROMGIT: drm/meson: Add G12A Video Clock setup + +While switching to the Common Clock Framework is still Work In Progress, +this patch adds the corresponding G12A HDMI PLL setup to be on-par +with the other SoCs support. + +The G12A has only a single tweak about the high frequency setup, +where the HDMI PLL needs a specific setup to handle correctly the +5.94GHz DCO frequency. + +Apart that, it handls ecorrectly all the other HDMI frequencies +and can achieve even better DMT clock frequency precision with +the larger fractional dividier width. + +Signed-off-by: Neil Armstrong +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-10-narmstrong@baylibre.com +(cherry picked from commit 202b9808f8edc8508f34f99a96c6cbe88042aff1 + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_vclk.c | 119 ++++++++++++++++++++++++++--- + 1 file changed, 108 insertions(+), 11 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index c15a5a5df6331..b39034745444a 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -113,9 +113,12 @@ + #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ + #define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ + #define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ ++#define HHI_HDMI_PLL_CNTL7 0x338 /* 0xce offset in data sheet */ + + #define HDMI_PLL_RESET BIT(28) ++#define HDMI_PLL_RESET_G12A BIT(29) + #define HDMI_PLL_LOCK BIT(31) ++#define HDMI_PLL_LOCK_G12A (3 << 30) + + #define FREQ_1000_1001(_freq) DIV_ROUND_CLOSEST(_freq * 1000, 1001) + +@@ -257,6 +260,10 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55); + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4800023d); ++ ++ /* Poll for lock bit */ ++ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, ++ (val & HDMI_PLL_LOCK), 10, 0); + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || + meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { + regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b); +@@ -271,11 +278,26 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) + HDMI_PLL_RESET, HDMI_PLL_RESET); + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, + HDMI_PLL_RESET, 0); +- } + +- /* Poll for lock bit */ +- regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, +- (val & HDMI_PLL_LOCK), 10, 0); ++ /* Poll for lock bit */ ++ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, ++ (val & HDMI_PLL_LOCK), 10, 0); ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00010000); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x6a28dc00); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x56540000); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x3a0504f7); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x1a0504f7); ++ ++ /* Poll for lock bit */ ++ regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, ++ ((val & HDMI_PLL_LOCK_G12A) == HDMI_PLL_LOCK_G12A), ++ 10, 0); ++ } + + /* Disable VCLK2 */ + regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0); +@@ -288,8 +310,13 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv) + VCLK2_DIV_MASK, (55 - 1)); + + /* select vid_pll for vclk2 */ +- regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, +- VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, ++ VCLK2_SEL_MASK, (0 << VCLK2_SEL_SHIFT)); ++ else ++ regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, ++ VCLK2_SEL_MASK, (4 << VCLK2_SEL_SHIFT)); ++ + /* enable vclk2 gate */ + regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, VCLK2_EN); + +@@ -476,32 +503,80 @@ void meson_hdmi_pll_set_params(struct meson_drm *priv, unsigned int m, + /* Poll for lock bit */ + regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val, + (val & HDMI_PLL_LOCK), 10, 0); ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x0b3a0400 | m); ++ ++ /* Enable and reset */ ++ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, ++ 0x3 << 28, 0x3 << 28); ++ ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, frac); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x00000000); ++ ++ /* G12A HDMI PLL Needs specific parameters for 5.4GHz */ ++ if (m >= 0xf7) { ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0xea68dc00); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x65771290); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39272000); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x55540000); ++ } else { ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0a691c00); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x33771290); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x39270000); ++ regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL7, 0x50540000); ++ } ++ ++ do { ++ /* Reset PLL */ ++ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, ++ HDMI_PLL_RESET_G12A, HDMI_PLL_RESET_G12A); ++ ++ /* UN-Reset PLL */ ++ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, ++ HDMI_PLL_RESET_G12A, 0); ++ ++ /* Poll for lock bits */ ++ if (!regmap_read_poll_timeout(priv->hhi, ++ HHI_HDMI_PLL_CNTL, val, ++ ((val & HDMI_PLL_LOCK_G12A) ++ == HDMI_PLL_LOCK_G12A), ++ 10, 100)) ++ break; ++ } while(1); + } + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 3 << 16, pll_od_to_reg(od1) << 16); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, + 3 << 21, pll_od_to_reg(od1) << 21); ++ else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, ++ 3 << 16, pll_od_to_reg(od1) << 16); + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 3 << 22, pll_od_to_reg(od2) << 22); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, + 3 << 23, pll_od_to_reg(od2) << 23); ++ else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, ++ 3 << 18, pll_od_to_reg(od2) << 18); + + if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2, + 3 << 18, pll_od_to_reg(od3) << 18); + else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) + regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3, + 3 << 19, pll_od_to_reg(od3) << 19); +- ++ else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL, ++ 3 << 20, pll_od_to_reg(od3) << 20); + } + + #define XTAL_FREQ 24000 +@@ -518,6 +593,7 @@ static unsigned int meson_hdmi_pll_get_m(struct meson_drm *priv, + + #define HDMI_FRAC_MAX_GXBB 4096 + #define HDMI_FRAC_MAX_GXL 1024 ++#define HDMI_FRAC_MAX_G12A 131072 + + static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, + unsigned int m, +@@ -534,6 +610,9 @@ static unsigned int meson_hdmi_pll_get_frac(struct meson_drm *priv, + parent_freq *= 2; + } + ++ if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) ++ frac_max = HDMI_FRAC_MAX_G12A; ++ + /* We can have a perfect match !*/ + if (pll_freq / m == parent_freq && + pll_freq % m == 0) +@@ -559,7 +638,8 @@ static bool meson_hdmi_pll_validate_params(struct meson_drm *priv, + if (frac >= HDMI_FRAC_MAX_GXBB) + return false; + } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") || +- meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) { ++ meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu") || ++ meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { + /* Empiric supported min/max dividers */ + if (m < 106 || m > 247) + return false; +@@ -713,6 +793,23 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, + break; + } + ++ meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); ++ } else if (meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ switch (pll_base_freq) { ++ case 2970000: ++ m = 0x7b; ++ frac = vic_alternate_clock ? 0x140b4 : 0x18000; ++ break; ++ case 4320000: ++ m = vic_alternate_clock ? 0xb3 : 0xb4; ++ frac = vic_alternate_clock ? 0x1a3ee : 0; ++ break; ++ case 5940000: ++ m = 0xf7; ++ frac = vic_alternate_clock ? 0x8148 : 0x10000; ++ break; ++ } ++ + meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3); + } + + +From 2f0d9002b9e49e6b942101393006f22a20bf35fc Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:23 +0100 +Subject: [PATCH 050/249] FROMGIT: drm/meson: Add G12A compatible + +Finally add the Amlogic G12A SoC compatible for the VPU driver. + +Signed-off-by: Neil Armstrong +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-11-narmstrong@baylibre.com +(cherry picked from commit 4deb190aa3551dfb2b7508960dc217702cb7278d + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_drv.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c +index 079d22299d789..faf1b1b0357cd 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -447,6 +447,7 @@ static const struct of_device_id dt_match[] = { + { .compatible = "amlogic,meson-gxbb-vpu" }, + { .compatible = "amlogic,meson-gxl-vpu" }, + { .compatible = "amlogic,meson-gxm-vpu" }, ++ { .compatible = "amlogic,meson-g12a-vpu" }, + {} + }; + MODULE_DEVICE_TABLE(of, dt_match); + +From 93c59c97a0f0952e960e5d00a870630a54d23336 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 15:18:24 +0100 +Subject: [PATCH 051/249] FROMGIT: drm/meson: Add G12A support for the DW-HDMI + Glue + +The Amlogic G12A embeds the same Synopsys DW-HDMI Controller, +but with : +- a "backport" of the HDR signaling registers from more recent + DW-HDMI controllers, this will need a tweak since it's not + normally present on this version of the DW-HDMI controller +- A direct mapping of TOP and DW-HDMI registers instead of an + internal bus accessed using read/write registers +- Support for RX-SENSE, but not yet implemented +- Support for HDMI 2.1 Dynamic HDR, but not yet implemented +- Different registers mapping for the HDMI PHY setup + +This patchs adds support for these changes while providing exact +same support as the previous GXBB, GXL & GXM SoCs. + +Signed-off-by: Neil Armstrong +Tested-by: Jerome Brunet +Reviewed-by: Jerome Brunet +Link: https://patchwork.freedesktop.org/patch/msgid/20190325141824.21259-12-narmstrong@baylibre.com +(cherry picked from commit 3b7c1237a72a970daca99a6dc30f980f8bbaa34c + git://anongit.freedesktop.org/drm/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 163 ++++++++++++++++++++------ + drivers/gpu/drm/meson/meson_dw_hdmi.h | 32 ++++- + 2 files changed, 157 insertions(+), 38 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 563953ec6ad03..779da21143b9b 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -105,6 +106,7 @@ + #define HDMITX_TOP_ADDR_REG 0x0 + #define HDMITX_TOP_DATA_REG 0x4 + #define HDMITX_TOP_CTRL_REG 0x8 ++#define HDMITX_TOP_G12A_OFFSET 0x8000 + + /* Controller Communication Channel */ + #define HDMITX_DWC_ADDR_REG 0x10 +@@ -118,6 +120,8 @@ + #define HHI_HDMI_PHY_CNTL1 0x3a4 /* 0xe9 */ + #define HHI_HDMI_PHY_CNTL2 0x3a8 /* 0xea */ + #define HHI_HDMI_PHY_CNTL3 0x3ac /* 0xeb */ ++#define HHI_HDMI_PHY_CNTL4 0x3b0 /* 0xec */ ++#define HHI_HDMI_PHY_CNTL5 0x3b4 /* 0xed */ + + static DEFINE_SPINLOCK(reg_lock); + +@@ -127,12 +131,26 @@ enum meson_venc_source { + MESON_VENC_SOURCE_ENCP = 2, + }; + ++struct meson_dw_hdmi; ++ ++struct meson_dw_hdmi_data { ++ unsigned int (*top_read)(struct meson_dw_hdmi *dw_hdmi, ++ unsigned int addr); ++ void (*top_write)(struct meson_dw_hdmi *dw_hdmi, ++ unsigned int addr, unsigned int data); ++ unsigned int (*dwc_read)(struct meson_dw_hdmi *dw_hdmi, ++ unsigned int addr); ++ void (*dwc_write)(struct meson_dw_hdmi *dw_hdmi, ++ unsigned int addr, unsigned int data); ++}; ++ + struct meson_dw_hdmi { + struct drm_encoder encoder; + struct dw_hdmi_plat_data dw_plat_data; + struct meson_drm *priv; + struct device *dev; + void __iomem *hdmitx; ++ const struct meson_dw_hdmi_data *data; + struct reset_control *hdmitx_apb; + struct reset_control *hdmitx_ctrl; + struct reset_control *hdmitx_phy; +@@ -174,6 +192,12 @@ static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi, + return data; + } + ++static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi, ++ unsigned int addr) ++{ ++ return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); ++} ++ + static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data) + { +@@ -191,18 +215,24 @@ static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi, + spin_unlock_irqrestore(®_lock, flags); + } + ++static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi, ++ unsigned int addr, unsigned int data) ++{ ++ writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2)); ++} ++ + /* Helper to change specific bits in PHY registers */ + static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, + unsigned int mask, + unsigned int val) + { +- unsigned int data = dw_hdmi_top_read(dw_hdmi, addr); ++ unsigned int data = dw_hdmi->data->top_read(dw_hdmi, addr); + + data &= ~mask; + data |= val; + +- dw_hdmi_top_write(dw_hdmi, addr, data); ++ dw_hdmi->data->top_write(dw_hdmi, addr, data); + } + + static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, +@@ -226,6 +256,12 @@ static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi, + return data; + } + ++static unsigned int dw_hdmi_g12a_dwc_read(struct meson_dw_hdmi *dw_hdmi, ++ unsigned int addr) ++{ ++ return readb(dw_hdmi->hdmitx + addr); ++} ++ + static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, unsigned int data) + { +@@ -243,18 +279,24 @@ static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi, + spin_unlock_irqrestore(®_lock, flags); + } + ++static inline void dw_hdmi_g12a_dwc_write(struct meson_dw_hdmi *dw_hdmi, ++ unsigned int addr, unsigned int data) ++{ ++ writeb(data, dw_hdmi->hdmitx + addr); ++} ++ + /* Helper to change specific bits in controller registers */ + static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi, + unsigned int addr, + unsigned int mask, + unsigned int val) + { +- unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr); ++ unsigned int data = dw_hdmi->data->dwc_read(dw_hdmi, addr); + + data &= ~mask; + data |= val; + +- dw_hdmi_dwc_write(dw_hdmi, addr, data); ++ dw_hdmi->data->dwc_write(dw_hdmi, addr, data); + } + + /* Bridge */ +@@ -300,6 +342,24 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122); + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b); + } ++ } else if (dw_hdmi_is_compatible(dw_hdmi, ++ "amlogic,meson-g12a-dw-hdmi")) { ++ if (pixel_clock >= 371250) { ++ /* 5.94Gbps, 3.7125Gbps */ ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x37eb65c4); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x0000080b); ++ } else if (pixel_clock >= 297000) { ++ /* 2.97Gbps */ ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb6262); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); ++ } else { ++ /* 1.485Gbps, and below */ ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33eb4242); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2ab0ff3b); ++ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL5, 0x00000003); ++ } + } + } + +@@ -375,7 +435,7 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0); + + /* Bring out of reset */ +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); ++ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_SW_RESET, 0); + + /* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */ + dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL, +@@ -384,24 +444,25 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + 0x3 << 4, 0x3 << 4); + + /* Enable normal output to PHY */ +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); ++ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); + + /* TMDS pattern setup (TOFIX Handle the YUV420 case) */ + if (mode->clock > 340000) { +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0); +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, ++ 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, + 0x03ff03ff); + } else { +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, ++ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, + 0x001f001f); +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, ++ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, + 0x001f001f); + } + + /* Load TMDS pattern */ +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); ++ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1); + msleep(20); +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2); ++ 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); +@@ -412,7 +473,8 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + + /* BIT_INVERT */ + if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") || +- dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) ++ dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi") || ++ dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-g12a-dw-hdmi")) + regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, + BIT(17), 0); + else +@@ -480,7 +542,7 @@ static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi, + { + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + +- return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ? ++ return !!dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_STAT0) ? + connector_status_connected : connector_status_disconnected; + } + +@@ -490,11 +552,11 @@ static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi, + struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; + + /* Setup HPD Filter */ +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, ++ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER, + (0xa << 12) | 0xa0); + + /* Clear interrupts */ +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, ++ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, + HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL); + + /* Unmask interrupts */ +@@ -515,8 +577,8 @@ static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id) + struct meson_dw_hdmi *dw_hdmi = dev_id; + u32 stat; + +- stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); +- dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); ++ stat = dw_hdmi->data->top_read(dw_hdmi, HDMITX_TOP_INTR_STAT); ++ dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat); + + /* HPD Events, handle in the threaded interrupt handler */ + if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) { +@@ -686,7 +748,9 @@ static const struct drm_encoder_helper_funcs + static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, + unsigned int *result) + { +- *result = dw_hdmi_dwc_read(context, reg); ++ struct meson_dw_hdmi *dw_hdmi = context; ++ ++ *result = dw_hdmi->data->dwc_read(dw_hdmi, reg); + + return 0; + +@@ -695,7 +759,9 @@ static int meson_dw_hdmi_reg_read(void *context, unsigned int reg, + static int meson_dw_hdmi_reg_write(void *context, unsigned int reg, + unsigned int val) + { +- dw_hdmi_dwc_write(context, reg, val); ++ struct meson_dw_hdmi *dw_hdmi = context; ++ ++ dw_hdmi->data->dwc_write(dw_hdmi, reg, val); + + return 0; + } +@@ -709,6 +775,20 @@ static const struct regmap_config meson_dw_hdmi_regmap_config = { + .fast_io = true, + }; + ++static const struct meson_dw_hdmi_data meson_dw_hdmi_gx_data = { ++ .top_read = dw_hdmi_top_read, ++ .top_write = dw_hdmi_top_write, ++ .dwc_read = dw_hdmi_dwc_read, ++ .dwc_write = dw_hdmi_dwc_write, ++}; ++ ++static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { ++ .top_read = dw_hdmi_g12a_top_read, ++ .top_write = dw_hdmi_g12a_top_write, ++ .dwc_read = dw_hdmi_g12a_dwc_read, ++ .dwc_write = dw_hdmi_g12a_dwc_write, ++}; ++ + static bool meson_hdmi_connector_is_available(struct device *dev) + { + struct device_node *ep, *remote; +@@ -735,6 +815,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, + void *data) + { + struct platform_device *pdev = to_platform_device(dev); ++ const struct meson_dw_hdmi_data *match; + struct meson_dw_hdmi *meson_dw_hdmi; + struct drm_device *drm = data; + struct meson_drm *priv = drm->dev_private; +@@ -751,6 +832,12 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, + return -ENODEV; + } + ++ match = of_device_get_match_data(&pdev->dev); ++ if (!match) { ++ dev_err(&pdev->dev, "failed to get match data\n"); ++ return -ENODEV; ++ } ++ + meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi), + GFP_KERNEL); + if (!meson_dw_hdmi) +@@ -758,6 +845,7 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, + + meson_dw_hdmi->priv = priv; + meson_dw_hdmi->dev = dev; ++ meson_dw_hdmi->data = match; + dw_plat_data = &meson_dw_hdmi->dw_plat_data; + encoder = &meson_dw_hdmi->encoder; + +@@ -858,24 +946,28 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, + reset_control_reset(meson_dw_hdmi->hdmitx_phy); + + /* Enable APB3 fail on error */ +- writel_bits_relaxed(BIT(15), BIT(15), +- meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); +- writel_bits_relaxed(BIT(15), BIT(15), +- meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); ++ if (!meson_vpu_is_compatible(priv, "amlogic,meson-g12a-vpu")) { ++ writel_bits_relaxed(BIT(15), BIT(15), ++ meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG); ++ writel_bits_relaxed(BIT(15), BIT(15), ++ meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG); ++ } + + /* Bring out of reset */ +- dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET, 0); ++ meson_dw_hdmi->data->top_write(meson_dw_hdmi, ++ HDMITX_TOP_SW_RESET, 0); + + msleep(20); + +- dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff); ++ meson_dw_hdmi->data->top_write(meson_dw_hdmi, ++ HDMITX_TOP_CLK_CNTL, 0xff); + + /* Enable HDMI-TX Interrupt */ +- dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, +- HDMITX_TOP_INTR_CORE); ++ meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, ++ HDMITX_TOP_INTR_CORE); + +- dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, +- HDMITX_TOP_INTR_CORE); ++ meson_dw_hdmi->data->top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN, ++ HDMITX_TOP_INTR_CORE); + + /* Bridge / Connector */ + +@@ -924,9 +1016,14 @@ static int meson_dw_hdmi_remove(struct platform_device *pdev) + } + + static const struct of_device_id meson_dw_hdmi_of_table[] = { +- { .compatible = "amlogic,meson-gxbb-dw-hdmi" }, +- { .compatible = "amlogic,meson-gxl-dw-hdmi" }, +- { .compatible = "amlogic,meson-gxm-dw-hdmi" }, ++ { .compatible = "amlogic,meson-gxbb-dw-hdmi", ++ .data = &meson_dw_hdmi_gx_data }, ++ { .compatible = "amlogic,meson-gxl-dw-hdmi", ++ .data = &meson_dw_hdmi_gx_data }, ++ { .compatible = "amlogic,meson-gxm-dw-hdmi", ++ .data = &meson_dw_hdmi_gx_data }, ++ { .compatible = "amlogic,meson-g12a-dw-hdmi", ++ .data = &meson_dw_hdmi_g12a_data }, + { } + }; + MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table); +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.h b/drivers/gpu/drm/meson/meson_dw_hdmi.h +index 0b81183125e33..03e2f0c1a2d50 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.h ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.h +@@ -21,9 +21,12 @@ + #define __MESON_DW_HDMI_H + + /* +- * Bit 7 RW Reserved. Default 1. +- * Bit 6 RW Reserved. Default 1. +- * Bit 5 RW Reserved. Default 1. ++ * Bit 15-10: RW Reserved. Default 1 starting from G12A ++ * Bit 9 RW sw_reset_i2c starting from G12A ++ * Bit 8 RW sw_reset_axiarb starting from G12A ++ * Bit 7 RW Reserved. Default 1, sw_reset_emp starting from G12A ++ * Bit 6 RW Reserved. Default 1, sw_reset_flt starting from G12A ++ * Bit 5 RW Reserved. Default 1, sw_reset_hdcp22 starting from G12A + * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset. + * Default 1. + * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset; +@@ -39,12 +42,16 @@ + #define HDMITX_TOP_SW_RESET (0x000) + + /* ++ * Bit 31 RW free_clk_en: 0=Enable clock gating for power saving; 1= Disable + * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0. + * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0. + * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0. + * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0. + * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0. +- * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. ++ * Bit 7 RW hdcp22_skpclk_en: starting from G12A, 1=enable; 0=disable ++ * Bit 6 RW hdcp22_esmclk_en: starting from G12A, 1=enable; 0=disable ++ * Bit 5 RW hdcp22_tmdsclk_en: starting from G12A, 1=enable; 0=disable ++ * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0. Reserved for G12A + * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0. + * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0. + * Bit 1 RW tmds_clk_en: 1=enable tmds_clk; 0=disable. Default 0. +@@ -53,6 +60,8 @@ + #define HDMITX_TOP_CLK_CNTL (0x001) + + /* ++ * Bit 31:28 RW rxsense_glitch_width: starting from G12A ++ * Bit 27:16 RW rxsense_valid_width: starting from G12A + * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024. Default 0. + * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N. Default 0. + */ +@@ -61,6 +70,9 @@ + /* + * intr_maskn: MASK_N, one bit per interrupt source. + * 1=Enable interrupt source; 0=Disable interrupt source. Default 0. ++ * [ 7] rxsense_fall starting from G12A ++ * [ 6] rxsense_rise starting from G12A ++ * [ 5] err_i2c_timeout starting from G12A + * [ 4] hdcp22_rndnum_err + * [ 3] nonce_rfrsh_rise + * [ 2] hpd_fall_intr +@@ -73,6 +85,9 @@ + * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt + * bit, read back the interrupt status. + * Bit 31 R IP interrupt status ++ * Bit 7 RW rxsense_fall starting from G12A ++ * Bit 6 RW rxsense_rise starting from G12A ++ * Bit 5 RW err_i2c_timeout starting from G12A + * Bit 2 RW hpd_fall + * Bit 1 RW hpd_rise + * Bit 0 RW IP interrupt +@@ -80,6 +95,9 @@ + #define HDMITX_TOP_INTR_STAT (0x004) + + /* ++ * [7] rxsense_fall starting from G12A ++ * [6] rxsense_rise starting from G12A ++ * [5] err_i2c_timeout starting from G12A + * [4] hdcp22_rndnum_err + * [3] nonce_rfrsh_rise + * [2] hpd_fall +@@ -91,6 +109,8 @@ + #define HDMITX_TOP_INTR_CORE BIT(0) + #define HDMITX_TOP_INTR_HPD_RISE BIT(1) + #define HDMITX_TOP_INTR_HPD_FALL BIT(2) ++#define HDMITX_TOP_INTR_RXSENSE_RISE BIT(6) ++#define HDMITX_TOP_INTR_RXSENSE_FALL BIT(7) + + /* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data; + * 3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0. +@@ -140,7 +160,9 @@ + */ + #define HDMITX_TOP_REVOCMEM_STAT (0x00D) + +-/* Bit 0 R filtered HPD status. */ ++/* Bit 1 R filtered RxSense status ++ * Bit 0 R filtered HPD status. ++ */ + #define HDMITX_TOP_STAT0 (0x00E) + + #endif /* __MESON_DW_HDMI_H */ + +From f49c47fd4696e1f2b33c80ca45f8765a650740d2 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 10:39:36 +0100 +Subject: [PATCH 052/249] UPSTREAM: dt-bindings: phy: Add Amlogic G12A USB2 PHY + Bindings + +Add the Amlogic G12A Family USB2 OTG PHY Bindings + +The PHY can work in host or peripheral modes depending on it's position. +Configuration of the mode is part of the USBCTRL registers which are +outside of the PHY registers. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Reviewed-by: Rob Herring +Signed-off-by: Kishon Vijay Abraham I +(cherry picked from commit 7609db4e846b26bab1c259fb025c56f4c262a21a) +--- + .../bindings/phy/meson-g12a-usb2-phy.txt | 22 +++++++++++++++++++ + 1 file changed, 22 insertions(+) + create mode 100644 Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt + +diff --git a/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt +new file mode 100644 +index 0000000000000..a6ebc3dea159f +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt +@@ -0,0 +1,22 @@ ++* Amlogic G12A USB2 PHY binding ++ ++Required properties: ++- compatible: Should be "amlogic,meson-g12a-usb2-phy" ++- reg: The base address and length of the registers ++- #phys-cells: must be 0 (see phy-bindings.txt in this directory) ++- clocks: a phandle to the clock of this PHY ++- clock-names: must be "xtal" ++- resets: a phandle to the reset line of this PHY ++- reset-names: must be "phy" ++- phy-supply: see phy-bindings.txt in this directory ++ ++Example: ++ usb2_phy0: phy@36000 { ++ compatible = "amlogic,g12a-usb2-phy"; ++ reg = <0x0 0x36000 0x0 0x2000>; ++ clocks = <&xtal>; ++ clock-names = "xtal"; ++ resets = <&reset RESET_USB_PHY21>; ++ reset-names = "phy"; ++ #phy-cells = <0>; ++ }; + +From b9c670240de8260212a7833bdaae470486e492ec Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 10:39:37 +0100 +Subject: [PATCH 053/249] UPSTREAM: dt-bindings: phy: Add Amlogic G12A + USB3+PCIE Combo PHY Bindings + +Add the Amlogic G12A Family USB3 + PCIE Combo PHY Bindings. + +This PHY can provide exclusively USB3 or PCIE support on shared I/Os. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Reviewed-by: Rob Herring +Signed-off-by: Kishon Vijay Abraham I +(cherry picked from commit ab6dbeb24d1a93425b2d1d91b17a7bce79dba41b) +--- + .../bindings/phy/meson-g12a-usb3-pcie-phy.txt | 22 +++++++++++++++++++ + 1 file changed, 22 insertions(+) + create mode 100644 Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt + +diff --git a/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt b/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt +new file mode 100644 +index 0000000000000..7cfc17e2df315 +--- /dev/null ++++ b/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt +@@ -0,0 +1,22 @@ ++* Amlogic G12A USB3 + PCIE Combo PHY binding ++ ++Required properties: ++- compatible: Should be "amlogic,meson-g12a-usb3-pcie-phy" ++- #phys-cells: must be 1. The cell number is used to select the phy mode ++ as defined in between PHY_TYPE_USB3 and PHY_TYPE_PCIE ++- reg: The base address and length of the registers ++- clocks: a phandle to the 100MHz reference clock of this PHY ++- clock-names: must be "ref_clk" ++- resets: phandle to the reset lines for the PHY control ++- reset-names: must be "phy" ++ ++Example: ++ usb3_pcie_phy: phy@46000 { ++ compatible = "amlogic,g12a-usb3-pcie-phy"; ++ reg = <0x0 0x46000 0x0 0x2000>; ++ clocks = <&clkc CLKID_PCIE_PLL>; ++ clock-names = "ref_clk"; ++ resets = <&reset RESET_PCIE_PHY>; ++ reset-names = "phy"; ++ #phy-cells = <1>; ++ }; + +From 8735a1a320370afadec8eb5489f8152e78454ce0 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 10:39:40 +0100 +Subject: [PATCH 054/249] UPSTREAM: phy: amlogic: add Amlogic G12A USB2 PHY + Driver + +This adds support for the USB2 PHY found in the Amlogic G12A SoC Family. + +It supports Host and/or Peripheral mode, depending on it's position. +The first PHY is only used as Host, but the second supports Dual modes +defined by the USB Control Glue HW in front of the USB Controllers. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kishon Vijay Abraham I +(cherry picked from commit 16df8bcb672c45e69a7bf4b37bb6de12c705e195) +Signed-off-by: Neil Armstrong +--- + drivers/phy/amlogic/Kconfig | 11 + + drivers/phy/amlogic/Makefile | 1 + + drivers/phy/amlogic/phy-meson-g12a-usb2.c | 341 ++++++++++++++++++++++ + 3 files changed, 353 insertions(+) + create mode 100644 drivers/phy/amlogic/phy-meson-g12a-usb2.c + +diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig +index 23fe1cda2f70d..560ff0f1ed4c1 100644 +--- a/drivers/phy/amlogic/Kconfig ++++ b/drivers/phy/amlogic/Kconfig +@@ -36,3 +36,14 @@ config PHY_MESON_GXL_USB3 + Enable this to support the Meson USB3 PHY and OTG detection + IP block found in Meson GXL and GXM SoCs. + If unsure, say N. ++ ++config PHY_MESON_G12A_USB2 ++ tristate "Meson G12A USB2 PHY driver" ++ default ARCH_MESON ++ depends on OF && (ARCH_MESON || COMPILE_TEST) ++ select GENERIC_PHY ++ select REGMAP_MMIO ++ help ++ Enable this to support the Meson USB2 PHYs found in Meson ++ G12A SoCs. ++ If unsure, say N. +diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile +index 4fd8848c194d6..7d4d10f5a6b3a 100644 +--- a/drivers/phy/amlogic/Makefile ++++ b/drivers/phy/amlogic/Makefile +@@ -1,3 +1,4 @@ + obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o + obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o ++obj-$(CONFIG_PHY_MESON_G12A_USB2) += phy-meson-g12a-usb2.o + obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o +diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb2.c b/drivers/phy/amlogic/phy-meson-g12a-usb2.c +new file mode 100644 +index 0000000000000..9065ffc85eb47 +--- /dev/null ++++ b/drivers/phy/amlogic/phy-meson-g12a-usb2.c +@@ -0,0 +1,341 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Meson G12A USB2 PHY driver ++ * ++ * Copyright (C) 2017 Martin Blumenstingl ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved ++ * Copyright (C) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PHY_CTRL_R0 0x0 ++#define PHY_CTRL_R1 0x4 ++#define PHY_CTRL_R2 0x8 ++#define PHY_CTRL_R3 0xc ++ #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0) ++ #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2) ++ #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4) ++ ++#define PHY_CTRL_R4 0x10 ++ #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0) ++ #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8) ++ #define PHY_CTRL_R4_CALIB_CODE_23_16 GENMASK(23, 16) ++ #define PHY_CTRL_R4_I_C2L_CAL_EN BIT(24) ++ #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25) ++ #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26) ++ #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27) ++ #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28) ++ #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30) ++ ++#define PHY_CTRL_R5 0x14 ++#define PHY_CTRL_R6 0x18 ++#define PHY_CTRL_R7 0x1c ++#define PHY_CTRL_R8 0x20 ++#define PHY_CTRL_R9 0x24 ++#define PHY_CTRL_R10 0x28 ++#define PHY_CTRL_R11 0x2c ++#define PHY_CTRL_R12 0x30 ++#define PHY_CTRL_R13 0x34 ++ #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0) ++ #define PHY_CTRL_R13_LOAD_STAT BIT(14) ++ #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15) ++ #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16) ++ #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21) ++ #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22) ++ #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23) ++ #define PHY_CTRL_R13_I_C2L_HS_EN BIT(24) ++ #define PHY_CTRL_R13_I_C2L_FS_EN BIT(25) ++ #define PHY_CTRL_R13_I_C2L_LS_EN BIT(26) ++ #define PHY_CTRL_R13_I_C2L_HS_OE BIT(27) ++ #define PHY_CTRL_R13_I_C2L_FS_OE BIT(28) ++ #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29) ++ #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30) ++ ++#define PHY_CTRL_R14 0x38 ++ #define PHY_CTRL_R14_I_RDP_EN BIT(0) ++ #define PHY_CTRL_R14_I_RPU_SW1_EN BIT(1) ++ #define PHY_CTRL_R14_I_RPU_SW2_EN GENMASK(2, 3) ++ #define PHY_CTRL_R14_PG_RSTN BIT(4) ++ #define PHY_CTRL_R14_I_C2L_DATA_16_8 BIT(5) ++ #define PHY_CTRL_R14_I_C2L_ASSERT_SINGLE_EN_ZERO BIT(6) ++ #define PHY_CTRL_R14_BYPASS_CTRL_7_0 GENMASK(15, 8) ++ #define PHY_CTRL_R14_BYPASS_CTRL_15_8 GENMASK(23, 16) ++ ++#define PHY_CTRL_R15 0x3c ++#define PHY_CTRL_R16 0x40 ++ #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0) ++ #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10) ++ #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20) ++ #define PHY_CTRL_R16_MPLL_SDM_EN BIT(21) ++ #define PHY_CTRL_R16_MPLL_LOAD BIT(22) ++ #define PHY_CTRL_R16_MPLL_DCO_SDM_EN BIT(23) ++ #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24) ++ #define PHY_CTRL_R16_MPLL_LOCK_F BIT(26) ++ #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27) ++ #define PHY_CTRL_R16_MPLL_EN BIT(28) ++ #define PHY_CTRL_R16_MPLL_RESET BIT(29) ++ #define PHY_CTRL_R16_MPLL_LOCK BIT(30) ++ #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31) ++ ++#define PHY_CTRL_R17 0x44 ++ #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0) ++ #define PHY_CTRL_R17_MPLL_FIX_EN BIT(16) ++ #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17) ++ #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20) ++ #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23) ++ #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24) ++ #define PHY_CTRL_R17_MPLL_FILTER_PVT1 GENMASK(31, 28) ++ ++#define PHY_CTRL_R18 0x48 ++ #define PHY_CTRL_R18_MPLL_LKW_SEL GENMASK(1, 0) ++ #define PHY_CTRL_R18_MPLL_LK_W GENMASK(5, 2) ++ #define PHY_CTRL_R18_MPLL_LK_S GENMASK(11, 6) ++ #define PHY_CTRL_R18_MPLL_DCO_M_EN BIT(12) ++ #define PHY_CTRL_R18_MPLL_DCO_CLK_SEL BIT(13) ++ #define PHY_CTRL_R18_MPLL_PFD_GAIN GENMASK(15, 14) ++ #define PHY_CTRL_R18_MPLL_ROU GENMASK(18, 16) ++ #define PHY_CTRL_R18_MPLL_DATA_SEL GENMASK(21, 19) ++ #define PHY_CTRL_R18_MPLL_BIAS_ADJ GENMASK(23, 22) ++ #define PHY_CTRL_R18_MPLL_BB_MODE GENMASK(25, 24) ++ #define PHY_CTRL_R18_MPLL_ALPHA GENMASK(28, 26) ++ #define PHY_CTRL_R18_MPLL_ADJ_LDO GENMASK(30, 29) ++ #define PHY_CTRL_R18_MPLL_ACG_RANGE BIT(31) ++ ++#define PHY_CTRL_R19 0x4c ++#define PHY_CTRL_R20 0x50 ++ #define PHY_CTRL_R20_USB2_IDDET_EN BIT(0) ++ #define PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0 GENMASK(3, 1) ++ #define PHY_CTRL_R20_USB2_OTG_VBUSDET_EN BIT(4) ++ #define PHY_CTRL_R20_USB2_AMON_EN BIT(5) ++ #define PHY_CTRL_R20_USB2_CAL_CODE_R5 BIT(6) ++ #define PHY_CTRL_R20_BYPASS_OTG_DET BIT(7) ++ #define PHY_CTRL_R20_USB2_DMON_EN BIT(8) ++ #define PHY_CTRL_R20_USB2_DMON_SEL_3_0 GENMASK(12, 9) ++ #define PHY_CTRL_R20_USB2_EDGE_DRV_EN BIT(13) ++ #define PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0 GENMASK(15, 14) ++ #define PHY_CTRL_R20_USB2_BGR_ADJ_4_0 GENMASK(20, 16) ++ #define PHY_CTRL_R20_USB2_BGR_START BIT(21) ++ #define PHY_CTRL_R20_USB2_BGR_VREF_4_0 GENMASK(28, 24) ++ #define PHY_CTRL_R20_USB2_BGR_DBG_1_0 GENMASK(30, 29) ++ #define PHY_CTRL_R20_BYPASS_CAL_DONE_R5 BIT(31) ++ ++#define PHY_CTRL_R21 0x54 ++ #define PHY_CTRL_R21_USB2_BGR_FORCE BIT(0) ++ #define PHY_CTRL_R21_USB2_CAL_ACK_EN BIT(1) ++ #define PHY_CTRL_R21_USB2_OTG_ACA_EN BIT(2) ++ #define PHY_CTRL_R21_USB2_TX_STRG_PD BIT(3) ++ #define PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0 GENMASK(5, 4) ++ #define PHY_CTRL_R21_BYPASS_UTMI_CNTR GENMASK(15, 6) ++ #define PHY_CTRL_R21_BYPASS_UTMI_REG GENMASK(25, 20) ++ ++#define PHY_CTRL_R22 0x58 ++#define PHY_CTRL_R23 0x5c ++ ++#define RESET_COMPLETE_TIME 1000 ++#define PLL_RESET_COMPLETE_TIME 100 ++ ++struct phy_meson_g12a_usb2_priv { ++ struct device *dev; ++ struct regmap *regmap; ++ struct clk *clk; ++ struct reset_control *reset; ++}; ++ ++static const struct regmap_config phy_meson_g12a_usb2_regmap_conf = { ++ .reg_bits = 8, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = PHY_CTRL_R23, ++}; ++ ++static int phy_meson_g12a_usb2_init(struct phy *phy) ++{ ++ struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy); ++ int ret; ++ ++ ret = reset_control_reset(priv->reset); ++ if (ret) ++ return ret; ++ ++ udelay(RESET_COMPLETE_TIME); ++ ++ /* usb2_otg_aca_en == 0 */ ++ regmap_update_bits(priv->regmap, PHY_CTRL_R21, ++ PHY_CTRL_R21_USB2_OTG_ACA_EN, 0); ++ ++ /* PLL Setup : 24MHz * 20 / 1 = 480MHz */ ++ regmap_write(priv->regmap, PHY_CTRL_R16, ++ FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) | ++ FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) | ++ PHY_CTRL_R16_MPLL_LOAD | ++ FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) | ++ PHY_CTRL_R16_MPLL_FAST_LOCK | ++ PHY_CTRL_R16_MPLL_EN | ++ PHY_CTRL_R16_MPLL_RESET); ++ ++ regmap_write(priv->regmap, PHY_CTRL_R17, ++ FIELD_PREP(PHY_CTRL_R17_MPLL_FRAC_IN, 0) | ++ FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA1, 7) | ++ FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA0, 7) | ++ FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | ++ FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9)); ++ ++ regmap_write(priv->regmap, PHY_CTRL_R18, ++ FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) | ++ FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | ++ PHY_CTRL_R18_MPLL_ACG_RANGE); ++ ++ udelay(PLL_RESET_COMPLETE_TIME); ++ ++ /* UnReset PLL */ ++ regmap_write(priv->regmap, PHY_CTRL_R16, ++ FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) | ++ FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) | ++ PHY_CTRL_R16_MPLL_LOAD | ++ FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) | ++ PHY_CTRL_R16_MPLL_FAST_LOCK | ++ PHY_CTRL_R16_MPLL_EN); ++ ++ /* PHY Tuning */ ++ regmap_write(priv->regmap, PHY_CTRL_R20, ++ FIELD_PREP(PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0, 4) | ++ PHY_CTRL_R20_USB2_OTG_VBUSDET_EN | ++ FIELD_PREP(PHY_CTRL_R20_USB2_DMON_SEL_3_0, 15) | ++ PHY_CTRL_R20_USB2_EDGE_DRV_EN | ++ FIELD_PREP(PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0, 3) | ++ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_ADJ_4_0, 0) | ++ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | ++ FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0)); ++ ++ regmap_write(priv->regmap, PHY_CTRL_R4, ++ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | ++ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | ++ FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | ++ PHY_CTRL_R4_TEST_BYPASS_MODE_EN | ++ FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | ++ FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); ++ ++ /* Tuning Disconnect Threshold */ ++ regmap_write(priv->regmap, PHY_CTRL_R3, ++ FIELD_PREP(PHY_CTRL_R3_SQUELCH_REF, 0) | ++ FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) | ++ FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3)); ++ ++ /* Analog Settings */ ++ regmap_write(priv->regmap, PHY_CTRL_R14, 0); ++ regmap_write(priv->regmap, PHY_CTRL_R13, ++ PHY_CTRL_R13_UPDATE_PMA_SIGNALS | ++ FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); ++ ++ return 0; ++} ++ ++static int phy_meson_g12a_usb2_exit(struct phy *phy) ++{ ++ struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy); ++ ++ return reset_control_reset(priv->reset); ++} ++ ++/* set_mode is not needed, mode setting is handled via the UTMI bus */ ++static const struct phy_ops phy_meson_g12a_usb2_ops = { ++ .init = phy_meson_g12a_usb2_init, ++ .exit = phy_meson_g12a_usb2_exit, ++ .owner = THIS_MODULE, ++}; ++ ++static int phy_meson_g12a_usb2_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct phy_provider *phy_provider; ++ struct resource *res; ++ struct phy_meson_g12a_usb2_priv *priv; ++ struct phy *phy; ++ void __iomem *base; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = dev; ++ platform_set_drvdata(pdev, priv); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ priv->regmap = devm_regmap_init_mmio(dev, base, ++ &phy_meson_g12a_usb2_regmap_conf); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ priv->clk = devm_clk_get(dev, "xtal"); ++ if (IS_ERR(priv->clk)) ++ return PTR_ERR(priv->clk); ++ ++ priv->reset = devm_reset_control_get(dev, "phy"); ++ if (IS_ERR(priv->reset)) ++ return PTR_ERR(priv->reset); ++ ++ ret = reset_control_deassert(priv->reset); ++ if (ret) ++ return ret; ++ ++ phy = devm_phy_create(dev, NULL, &phy_meson_g12a_usb2_ops); ++ if (IS_ERR(phy)) { ++ ret = PTR_ERR(phy); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to create PHY\n"); ++ ++ return ret; ++ } ++ ++ phy_set_bus_width(phy, 8); ++ phy_set_drvdata(phy, priv); ++ ++ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++} ++ ++static const struct of_device_id phy_meson_g12a_usb2_of_match[] = { ++ { .compatible = "amlogic,g12a-usb2-phy", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, phy_meson_g12a_usb2_of_match); ++ ++static struct platform_driver phy_meson_g12a_usb2_driver = { ++ .probe = phy_meson_g12a_usb2_probe, ++ .driver = { ++ .name = "phy-meson-g12a-usb2", ++ .of_match_table = phy_meson_g12a_usb2_of_match, ++ }, ++}; ++module_platform_driver(phy_meson_g12a_usb2_driver); ++ ++MODULE_AUTHOR("Martin Blumenstingl "); ++MODULE_AUTHOR("Neil Armstrong "); ++MODULE_DESCRIPTION("Meson G12A USB2 PHY driver"); ++MODULE_LICENSE("GPL v2"); + +From 0a20d973f2620cee04b7003d908192c5917a08a9 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 10:39:41 +0100 +Subject: [PATCH 055/249] UPSTREAM: phy: amlogic: Add Amlogic G12A USB3 + PCIE + Combo PHY Driver + +This adds support for the shared USB3 + PCIE PHY found in the +Amlogic G12A SoC Family. + +It supports USB3 Host mode or PCIE 2.0 mode, depending on the layout of +the board. + +Selection is done by the #phy-cells, making the mode static and exclusive. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kishon Vijay Abraham I +(cherry picked from commit 36077e16c050d1b063cdfec8c1d38d51d112f86d) +--- + drivers/phy/amlogic/Kconfig | 11 + + drivers/phy/amlogic/Makefile | 1 + + .../phy/amlogic/phy-meson-g12a-usb3-pcie.c | 413 ++++++++++++++++++ + 3 files changed, 425 insertions(+) + create mode 100644 drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c + +diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig +index 560ff0f1ed4c1..4c08c1ccdd049 100644 +--- a/drivers/phy/amlogic/Kconfig ++++ b/drivers/phy/amlogic/Kconfig +@@ -47,3 +47,14 @@ config PHY_MESON_G12A_USB2 + Enable this to support the Meson USB2 PHYs found in Meson + G12A SoCs. + If unsure, say N. ++ ++config PHY_MESON_G12A_USB3_PCIE ++ tristate "Meson G12A USB3+PCIE Combo PHY driver" ++ default ARCH_MESON ++ depends on OF && (ARCH_MESON || COMPILE_TEST) ++ select GENERIC_PHY ++ select REGMAP_MMIO ++ help ++ Enable this to support the Meson USB3 + PCIE Combo PHY found ++ in Meson G12A SoCs. ++ If unsure, say N. +diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile +index 7d4d10f5a6b3a..fdd008e1b19b6 100644 +--- a/drivers/phy/amlogic/Makefile ++++ b/drivers/phy/amlogic/Makefile +@@ -2,3 +2,4 @@ obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o + obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o + obj-$(CONFIG_PHY_MESON_G12A_USB2) += phy-meson-g12a-usb2.o + obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o ++obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE) += phy-meson-g12a-usb3-pcie.o +diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c +new file mode 100644 +index 0000000000000..6233a7979a931 +--- /dev/null ++++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c +@@ -0,0 +1,413 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Amlogic G12A USB3 + PCIE Combo PHY driver ++ * ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved ++ * Copyright (C) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define PHY_R0 0x00 ++ #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0) ++ #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5) ++ ++#define PHY_R1 0x04 ++ #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0) ++ #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5) ++ #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10) ++ #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13) ++ #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16) ++ #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21) ++ #define PHY_R1_PHY_REF_CLKDIV2 BIT(24) ++ #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25) ++ ++#define PHY_R2 0x08 ++ #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0) ++ #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6) ++ #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12) ++ #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18) ++ ++#define PHY_R4 0x10 ++ #define PHY_R4_PHY_CR_WRITE BIT(0) ++ #define PHY_R4_PHY_CR_READ BIT(1) ++ #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2) ++ #define PHY_R4_PHY_CR_CAP_DATA BIT(18) ++ #define PHY_R4_PHY_CR_CAP_ADDR BIT(19) ++ ++#define PHY_R5 0x14 ++ #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0) ++ #define PHY_R5_PHY_CR_ACK BIT(16) ++ #define PHY_R5_PHY_BS_OUT BIT(17) ++ ++struct phy_g12a_usb3_pcie_priv { ++ struct regmap *regmap; ++ struct regmap *regmap_cr; ++ struct clk *clk_ref; ++ struct reset_control *reset; ++ struct phy *phy; ++ unsigned int mode; ++}; ++ ++static const struct regmap_config phy_g12a_usb3_pcie_regmap_conf = { ++ .reg_bits = 8, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = PHY_R5, ++}; ++ ++static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv, ++ unsigned int addr) ++{ ++ unsigned int val, reg; ++ int ret; ++ ++ reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr); ++ ++ regmap_write(priv->regmap, PHY_R4, reg); ++ regmap_write(priv->regmap, PHY_R4, reg); ++ ++ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, ++ (val & PHY_R5_PHY_CR_ACK), ++ 5, 1000); ++ if (ret) ++ return ret; ++ ++ regmap_write(priv->regmap, PHY_R4, reg); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, ++ !(val & PHY_R5_PHY_CR_ACK), ++ 5, 1000); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int phy_g12a_usb3_pcie_cr_bus_read(void *context, unsigned int addr, ++ unsigned int *data) ++{ ++ struct phy_g12a_usb3_pcie_priv *priv = context; ++ unsigned int val; ++ int ret; ++ ++ ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); ++ if (ret) ++ return ret; ++ ++ regmap_write(priv->regmap, PHY_R4, 0); ++ regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, ++ (val & PHY_R5_PHY_CR_ACK), ++ 5, 1000); ++ if (ret) ++ return ret; ++ ++ *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val); ++ ++ regmap_write(priv->regmap, PHY_R4, 0); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, ++ !(val & PHY_R5_PHY_CR_ACK), ++ 5, 1000); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int phy_g12a_usb3_pcie_cr_bus_write(void *context, unsigned int addr, ++ unsigned int data) ++{ ++ struct phy_g12a_usb3_pcie_priv *priv = context; ++ unsigned int val, reg; ++ int ret; ++ ++ ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); ++ if (ret) ++ return ret; ++ ++ reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data); ++ ++ regmap_write(priv->regmap, PHY_R4, reg); ++ regmap_write(priv->regmap, PHY_R4, reg); ++ ++ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, ++ (val & PHY_R5_PHY_CR_ACK), ++ 5, 1000); ++ if (ret) ++ return ret; ++ ++ regmap_write(priv->regmap, PHY_R4, reg); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, ++ (val & PHY_R5_PHY_CR_ACK) == 0, ++ 5, 1000); ++ if (ret) ++ return ret; ++ ++ regmap_write(priv->regmap, PHY_R4, reg); ++ ++ regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, ++ (val & PHY_R5_PHY_CR_ACK), ++ 5, 1000); ++ if (ret) ++ return ret; ++ ++ regmap_write(priv->regmap, PHY_R4, reg); ++ ++ ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, ++ (val & PHY_R5_PHY_CR_ACK) == 0, ++ 5, 1000); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = { ++ .reg_bits = 16, ++ .val_bits = 16, ++ .reg_read = phy_g12a_usb3_pcie_cr_bus_read, ++ .reg_write = phy_g12a_usb3_pcie_cr_bus_write, ++ .max_register = 0xffff, ++ .fast_io = true, ++}; ++ ++static int phy_g12a_usb3_init(struct phy *phy) ++{ ++ struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); ++ int data, ret; ++ ++ /* Switch PHY to USB3 */ ++ /* TODO figure out how to handle when PCIe was set in the bootloader */ ++ regmap_update_bits(priv->regmap, PHY_R0, ++ PHY_R0_PCIE_USB3_SWITCH, ++ PHY_R0_PCIE_USB3_SWITCH); ++ ++ /* ++ * WORKAROUND: There is SSPHY suspend bug due to ++ * which USB enumerates ++ * in HS mode instead of SS mode. Workaround it by asserting ++ * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus ++ * mode ++ */ ++ ret = regmap_update_bits(priv->regmap_cr, 0x102d, BIT(7), BIT(7)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(priv->regmap_cr, 0x1010, 0xff0, 20); ++ if (ret) ++ return ret; ++ ++ /* ++ * Fix RX Equalization setting as follows ++ * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 ++ * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 ++ * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 ++ * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 ++ */ ++ ret = regmap_read(priv->regmap_cr, 0x1006, &data); ++ if (ret) ++ return ret; ++ ++ data &= ~BIT(6); ++ data |= BIT(7); ++ data &= ~(0x7 << 8); ++ data |= (0x3 << 8); ++ data |= (1 << 11); ++ ret = regmap_write(priv->regmap_cr, 0x1006, data); ++ if (ret) ++ return ret; ++ ++ /* ++ * Set EQ and TX launch amplitudes as follows ++ * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 ++ * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 ++ * LANE0.TX_OVRD_DRV_LO.EN set to 1. ++ */ ++ ret = regmap_read(priv->regmap_cr, 0x1002, &data); ++ if (ret) ++ return ret; ++ ++ data &= ~0x3f80; ++ data |= (0x16 << 7); ++ data &= ~0x7f; ++ data |= (0x7f | BIT(14)); ++ ret = regmap_write(priv->regmap_cr, 0x1002, data); ++ if (ret) ++ return ret; ++ ++ /* MPLL_LOOP_CTL.PROP_CNTRL = 8 */ ++ ret = regmap_update_bits(priv->regmap_cr, 0x30, 0xf << 4, 8 << 4); ++ if (ret) ++ return ret; ++ ++ regmap_update_bits(priv->regmap, PHY_R2, ++ PHY_R2_PHY_TX_VBOOST_LVL, ++ FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4)); ++ ++ regmap_update_bits(priv->regmap, PHY_R1, ++ PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL, ++ FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) | ++ FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9)); ++ ++ return 0; ++} ++ ++static int phy_g12a_usb3_pcie_init(struct phy *phy) ++{ ++ struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); ++ int ret; ++ ++ ret = reset_control_reset(priv->reset); ++ if (ret) ++ return ret; ++ ++ if (priv->mode == PHY_TYPE_USB3) ++ return phy_g12a_usb3_init(phy); ++ ++ /* Power UP PCIE */ ++ /* TODO figure out when the bootloader has set USB3 mode before */ ++ regmap_update_bits(priv->regmap, PHY_R0, ++ PHY_R0_PCIE_POWER_STATE, ++ FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c)); ++ ++ return 0; ++} ++ ++static int phy_g12a_usb3_pcie_exit(struct phy *phy) ++{ ++ struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); ++ ++ return reset_control_reset(priv->reset); ++} ++ ++static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, ++ struct of_phandle_args *args) ++{ ++ struct phy_g12a_usb3_pcie_priv *priv = dev_get_drvdata(dev); ++ unsigned int mode; ++ ++ if (args->args_count < 1) { ++ dev_err(dev, "invalid number of arguments\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ mode = args->args[0]; ++ ++ if (mode != PHY_TYPE_USB3 && mode != PHY_TYPE_PCIE) { ++ dev_err(dev, "invalid phy mode select argument\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ priv->mode = mode; ++ ++ return priv->phy; ++} ++ ++static const struct phy_ops phy_g12a_usb3_pcie_ops = { ++ .init = phy_g12a_usb3_pcie_init, ++ .exit = phy_g12a_usb3_pcie_exit, ++ .owner = THIS_MODULE, ++}; ++ ++static int phy_g12a_usb3_pcie_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct phy_g12a_usb3_pcie_priv *priv; ++ struct resource *res; ++ struct phy_provider *phy_provider; ++ void __iomem *base; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ priv->regmap = devm_regmap_init_mmio(dev, base, ++ &phy_g12a_usb3_pcie_regmap_conf); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ priv->regmap_cr = devm_regmap_init(dev, NULL, priv, ++ &phy_g12a_usb3_pcie_cr_regmap_conf); ++ if (IS_ERR(priv->regmap_cr)) ++ return PTR_ERR(priv->regmap_cr); ++ ++ priv->clk_ref = devm_clk_get(dev, "ref_clk"); ++ if (IS_ERR(priv->clk_ref)) ++ return PTR_ERR(priv->clk_ref); ++ ++ ret = clk_prepare_enable(priv->clk_ref); ++ if (ret) ++ goto err_disable_clk_ref; ++ ++ priv->reset = devm_reset_control_array_get(dev, false, false); ++ if (IS_ERR(priv->reset)) ++ return PTR_ERR(priv->reset); ++ ++ priv->phy = devm_phy_create(dev, np, &phy_g12a_usb3_pcie_ops); ++ if (IS_ERR(priv->phy)) { ++ ret = PTR_ERR(priv->phy); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to create PHY\n"); ++ ++ return ret; ++ } ++ ++ phy_set_drvdata(priv->phy, priv); ++ dev_set_drvdata(dev, priv); ++ ++ phy_provider = devm_of_phy_provider_register(dev, ++ phy_g12a_usb3_pcie_xlate); ++ ++ return PTR_ERR_OR_ZERO(phy_provider); ++ ++err_disable_clk_ref: ++ clk_disable_unprepare(priv->clk_ref); ++ ++ return ret; ++} ++ ++static const struct of_device_id phy_g12a_usb3_pcie_of_match[] = { ++ { .compatible = "amlogic,g12a-usb3-pcie-phy", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(of, phy_g12a_usb3_pcie_of_match); ++ ++static struct platform_driver phy_g12a_usb3_pcie_driver = { ++ .probe = phy_g12a_usb3_pcie_probe, ++ .driver = { ++ .name = "phy-g12a-usb3-pcie", ++ .of_match_table = phy_g12a_usb3_pcie_of_match, ++ }, ++}; ++module_platform_driver(phy_g12a_usb3_pcie_driver); ++ ++MODULE_AUTHOR("Neil Armstrong "); ++MODULE_DESCRIPTION("Amlogic G12A USB3 + PCIE Combo PHY driver"); ++MODULE_LICENSE("GPL v2"); + +From 9db5bf0097baa3fa7f555124e37c0ecdd753e9bc Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 23 Apr 2019 10:51:24 +0200 +Subject: [PATCH 056/249] UPSTREAM: dt-bindings: usb: dwc2: Add Amlogic G12A + DWC2 Compatible + +Adds the specific compatible string for the DWC2 IP found in the +Amlogic G12A SoC Family. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Reviewed-by: Rob Herring +Signed-off-by: Felipe Balbi +(cherry picked from commit 7a76b97325c2cc6c6599a2b3b15d32aebf2f48ee) +--- + Documentation/devicetree/bindings/usb/dwc2.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt +index 6dc3c4a344830..e150b7b227c9e 100644 +--- a/Documentation/devicetree/bindings/usb/dwc2.txt ++++ b/Documentation/devicetree/bindings/usb/dwc2.txt +@@ -14,6 +14,7 @@ Required properties: + - "amlogic,meson8-usb": The DWC2 USB controller instance in Amlogic Meson8 SoCs; + - "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs; + - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs; ++ - "amlogic,meson-g12a-usb": The DWC2 USB controller instance in Amlogic G12A SoCs; + - "amcc,dwc-otg": The DWC2 USB controller instance in AMCC Canyonlands 460EX SoCs; + - snps,dwc2: A generic DWC2 USB controller with default parameters. + - "st,stm32f4x9-fsotg": The DWC2 USB FS/HS controller instance in STM32F4x9 SoCs + +From e5bf510e9ea3fd8f36b9279506829c601d6882df Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 23 Apr 2019 10:51:25 +0200 +Subject: [PATCH 057/249] UPSTREAM: dt-bindings: usb: dwc3: Add Amlogic G12A + DWC3 Glue Bindings + +Adds the bindings for the Amlogic G12A USB Glue HW. + +The Amlogic G12A SoC Family embeds 2 USB Controllers : +- a DWC3 IP configured as Host for USB2 and USB3 +- a DWC2 IP configured as Peripheral USB2 Only + +A glue connects these both controllers to 2 USB2 PHYs, +and optionnally to an USB3+PCIE Combo PHY shared with the PCIE controller. + +The Glue configures the UTMI 8bit interfaces for the USB2 PHYs, including +routing of the OTG PHY between the DWC3 and DWC2 controllers, and +setups the on-chip OTG mode selection for this PHY. + +The PHYs phandles are passed to the Glue node since the Glue controls the +interface with the PHY, not the DWC3 controller. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Reviewed-by: Rob Herring +Signed-off-by: Felipe Balbi +(cherry picked from commit e8c77fa091808c7e27ad15c7256743b6c2406b02) +--- + .../devicetree/bindings/usb/amlogic,dwc3.txt | 88 +++++++++++++++++++ + 1 file changed, 88 insertions(+) + +diff --git a/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt b/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt +index 9a8b631904fd6..b9f04e617eb77 100644 +--- a/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt ++++ b/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt +@@ -40,3 +40,91 @@ Example device nodes: + phy-names = "usb2-phy", "usb3-phy"; + }; + }; ++ ++Amlogic Meson G12A DWC3 USB SoC Controller Glue ++ ++The Amlogic G12A embeds a DWC3 USB IP Core configured for USB2 and USB3 ++in host-only mode, and a DWC2 IP Core configured for USB2 peripheral mode ++only. ++ ++A glue connects the DWC3 core to USB2 PHYs and optionnaly to an USB3 PHY. ++ ++One of the USB2 PHY can be re-routed in peripheral mode to a DWC2 USB IP. ++ ++The DWC3 Glue controls the PHY routing and power, an interrupt line is ++connected to the Glue to serve as OTG ID change detection. ++ ++Required properties: ++- compatible: Should be "amlogic,meson-g12a-usb-ctrl" ++- clocks: a handle for the "USB" clock ++- resets: a handle for the shared "USB" reset line ++- reg: The base address and length of the registers ++- interrupts: the interrupt specifier for the OTG detection ++- phys: handle to used PHYs on the system ++ - a <0> phandle can be used if a PHY is not used ++- phy-names: names of the used PHYs on the system : ++ - "usb2-phy0" for USB2 PHY0 if USBHOST_A port is used ++ - "usb2-phy1" for USB2 PHY1 if USBOTG_B port is used ++ - "usb3-phy0" for USB3 PHY if USB3_0 is used ++- dr_mode: should be "host", "peripheral", or "otg" depending on ++ the usage and configuration of the OTG Capable port. ++ - "host" and "peripheral" means a fixed Host or Device only connection ++ - "otg" means the port can be used as both Host or Device and ++ be switched automatically using the OTG ID pin. ++ ++Optional properties: ++- vbus-supply: should be a phandle to the regulator controlling the VBUS ++ power supply when used in OTG switchable mode ++ ++Required child nodes: ++ ++A child node must exist to represent the core DWC3 IP block. The name of ++the node is not important. The content of the node is defined in dwc3.txt. ++ ++A child node must exist to represent the core DWC2 IP block. The name of ++the node is not important. The content of the node is defined in dwc2.txt. ++ ++PHY documentation is provided in the following places: ++- Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt ++- Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt ++ ++Example device nodes: ++ usb: usb@ffe09000 { ++ compatible = "amlogic,meson-g12a-usb-ctrl"; ++ reg = <0x0 0xffe09000 0x0 0xa0>; ++ interrupts = ; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ clocks = <&clkc CLKID_USB>; ++ resets = <&reset RESET_USB>; ++ ++ dr_mode = "otg"; ++ ++ phys = <&usb2_phy0>, <&usb2_phy1>, ++ <&usb3_pcie_phy PHY_TYPE_USB3>; ++ phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; ++ ++ dwc2: usb@ff400000 { ++ compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; ++ reg = <0x0 0xff400000 0x0 0x40000>; ++ interrupts = ; ++ clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; ++ clock-names = "ddr"; ++ phys = <&usb2_phy1>; ++ dr_mode = "peripheral"; ++ g-rx-fifo-size = <192>; ++ g-np-tx-fifo-size = <128>; ++ g-tx-fifo-size = <128 128 16 16 16>; ++ }; ++ ++ dwc3: usb@ff500000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0xff500000 0x0 0x100000>; ++ interrupts = ; ++ dr_mode = "host"; ++ snps,dis_u2_susphy_quirk; ++ snps,quirk-frame-length-adjustment; ++ }; ++ }; + +From cca7872a15fdb519d0e332d28eaf56440447978b Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 23 Apr 2019 10:51:26 +0200 +Subject: [PATCH 058/249] UPSTREAM: usb: dwc2: Add Amlogic G12A DWC2 Params + +This patchs sets the params for the DWC2 Controller found in the +Amlogic G12A SoC family. + +It mainly sets the settings reported incorrect by the driver, +leaving the remaining detected automatically by the driver and +provided by the DT node. + +Signed-off-by: Neil Armstrong +Acked-by: Minas Harutyunyan +Signed-off-by: Felipe Balbi +(cherry picked from commit fc4e326ee72cc36c942333c65d851247b31c567b) +--- + drivers/usb/dwc2/params.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c +index 24ff5f21cb25d..442113246cba6 100644 +--- a/drivers/usb/dwc2/params.c ++++ b/drivers/usb/dwc2/params.c +@@ -121,6 +121,16 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg) + p->power_down = DWC2_POWER_DOWN_PARAM_NONE; + } + ++static void dwc2_set_amlogic_g12a_params(struct dwc2_hsotg *hsotg) ++{ ++ struct dwc2_core_params *p = &hsotg->params; ++ ++ p->lpm = false; ++ p->lpm_clock_gating = false; ++ p->besl = false; ++ p->hird_threshold_en = false; ++} ++ + static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) + { + struct dwc2_core_params *p = &hsotg->params; +@@ -167,6 +177,8 @@ const struct of_device_id dwc2_of_match_table[] = { + .data = dwc2_set_amlogic_params }, + { .compatible = "amlogic,meson-gxbb-usb", + .data = dwc2_set_amlogic_params }, ++ { .compatible = "amlogic,meson-g12a-usb", ++ .data = dwc2_set_amlogic_g12a_params }, + { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, + { .compatible = "st,stm32f4x9-fsotg", + .data = dwc2_set_stm32f4x9_fsotg_params }, + +From 80ef089553065260869056a4ed3e9351c127cab0 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 23 Apr 2019 10:51:27 +0200 +Subject: [PATCH 059/249] UPSTREAM: usb: dwc3: Add Amlogic G12A DWC3 glue + +Adds support for Amlogic G12A USB Control Glue HW. + +The Amlogic G12A SoC Family embeds 2 USB Controllers : +- a DWC3 IP configured as Host for USB2 and USB3 +- a DWC2 IP configured as Peripheral USB2 Only + +A glue connects these both controllers to 2 USB2 PHYs, and optionnally +to an USB3+PCIE Combo PHY shared with the PCIE controller. + +The Glue configures the UTMI 8bit interfaces for the USB2 PHYs, including +routing of the OTG PHY between the DWC3 and DWC2 controllers, and +setups the on-chip OTG mode selection for this PHY. + +This drivers supports the on-probe setup of the OTG mode, and manually +via a debugfs interface. The IRQ mode change detect is yet to be added +in a future patchset, mainly due to lack of hardware to validate on. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Felipe Balbi +(cherry picked from commit c99993376f72ca3dcc989813512607c6435cbed8) +--- + drivers/usb/dwc3/Kconfig | 10 + + drivers/usb/dwc3/Makefile | 1 + + drivers/usb/dwc3/dwc3-meson-g12a.c | 604 +++++++++++++++++++++++++++++ + 3 files changed, 615 insertions(+) + create mode 100644 drivers/usb/dwc3/dwc3-meson-g12a.c + +diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig +index 2b1494460d0cb..d2ea9670563cb 100644 +--- a/drivers/usb/dwc3/Kconfig ++++ b/drivers/usb/dwc3/Kconfig +@@ -95,6 +95,16 @@ config USB_DWC3_KEYSTONE + Support of USB2/3 functionality in TI Keystone2 and AM654 platforms. + Say 'Y' or 'M' here if you have one such device + ++config USB_DWC3_MESON_G12A ++ tristate "Amlogic Meson G12A Platforms" ++ depends on OF && COMMON_CLK ++ depends on ARCH_MESON || COMPILE_TEST ++ default USB_DWC3 ++ select USB_ROLE_SWITCH ++ help ++ Support USB2/3 functionality in Amlogic G12A platforms. ++ Say 'Y' or 'M' if you have one such device. ++ + config USB_DWC3_OF_SIMPLE + tristate "Generic OF Simple Glue Layer" + depends on OF && COMMON_CLK +diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile +index 6e3ef6144e5d9..ae86da0dc5bd1 100644 +--- a/drivers/usb/dwc3/Makefile ++++ b/drivers/usb/dwc3/Makefile +@@ -47,6 +47,7 @@ obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o + obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o + obj-$(CONFIG_USB_DWC3_HAPS) += dwc3-haps.o + obj-$(CONFIG_USB_DWC3_KEYSTONE) += dwc3-keystone.o ++obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o + obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o + obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o + obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o +diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c +new file mode 100644 +index 0000000000000..2aec31a2eacbd +--- /dev/null ++++ b/drivers/usb/dwc3/dwc3-meson-g12a.c +@@ -0,0 +1,604 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * USB Glue for Amlogic G12A SoCs ++ * ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ */ ++ ++/* ++ * The USB is organized with a glue around the DWC3 Controller IP as : ++ * - Control registers for each USB2 Ports ++ * - Control registers for the USB PHY layer ++ * - SuperSpeed PHY can be enabled only if port is used ++ * ++ * TOFIX: ++ * - Add dynamic OTG switching with ID change interrupt ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* USB2 Ports Control Registers */ ++ ++#define U2P_REG_SIZE 0x20 ++ ++#define U2P_R0 0x0 ++ #define U2P_R0_HOST_DEVICE BIT(0) ++ #define U2P_R0_POWER_OK BIT(1) ++ #define U2P_R0_HAST_MODE BIT(2) ++ #define U2P_R0_POWER_ON_RESET BIT(3) ++ #define U2P_R0_ID_PULLUP BIT(4) ++ #define U2P_R0_DRV_VBUS BIT(5) ++ ++#define U2P_R1 0x4 ++ #define U2P_R1_PHY_READY BIT(0) ++ #define U2P_R1_ID_DIG BIT(1) ++ #define U2P_R1_OTG_SESSION_VALID BIT(2) ++ #define U2P_R1_VBUS_VALID BIT(3) ++ ++/* USB Glue Control Registers */ ++ ++#define USB_R0 0x80 ++ #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17) ++ #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18) ++ #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19) ++ #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29) ++ #define USB_R0_U2D_ACT BIT(31) ++ ++#define USB_R1 0x84 ++ #define USB_R1_U3H_BIGENDIAN_GS BIT(0) ++ #define USB_R1_U3H_PME_ENABLE BIT(1) ++ #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(4, 2) ++ #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7) ++ #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 12) ++ #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16) ++ #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17) ++ #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18) ++ #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19) ++ #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25) ++ ++#define USB_R2 0x88 ++ #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20) ++ #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26) ++ ++#define USB_R3 0x8c ++ #define USB_R3_P30_SSC_ENABLE BIT(0) ++ #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1) ++ #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4) ++ #define USB_R3_P30_REF_SSP_EN BIT(13) ++ ++#define USB_R4 0x90 ++ #define USB_R4_P21_PORT_RESET_0 BIT(0) ++ #define USB_R4_P21_SLEEP_M0 BIT(1) ++ #define USB_R4_MEM_PD_MASK GENMASK(3, 2) ++ #define USB_R4_P21_ONLY BIT(4) ++ ++#define USB_R5 0x94 ++ #define USB_R5_ID_DIG_SYNC BIT(0) ++ #define USB_R5_ID_DIG_REG BIT(1) ++ #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2) ++ #define USB_R5_ID_DIG_EN_0 BIT(4) ++ #define USB_R5_ID_DIG_EN_1 BIT(5) ++ #define USB_R5_ID_DIG_CURR BIT(6) ++ #define USB_R5_ID_DIG_IRQ BIT(7) ++ #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8) ++ #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16) ++ ++enum { ++ USB2_HOST_PHY = 0, ++ USB2_OTG_PHY, ++ USB3_HOST_PHY, ++ PHY_COUNT, ++}; ++ ++static const char *phy_names[PHY_COUNT] = { ++ "usb2-phy0", "usb2-phy1", "usb3-phy0", ++}; ++ ++struct dwc3_meson_g12a { ++ struct device *dev; ++ struct regmap *regmap; ++ struct clk *clk; ++ struct reset_control *reset; ++ struct phy *phys[PHY_COUNT]; ++ enum usb_dr_mode otg_mode; ++ enum phy_mode otg_phy_mode; ++ unsigned int usb2_ports; ++ unsigned int usb3_ports; ++ struct regulator *vbus; ++ struct usb_role_switch_desc switch_desc; ++ struct usb_role_switch *role_switch; ++}; ++ ++static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv, ++ int i, enum phy_mode mode) ++{ ++ if (mode == PHY_MODE_USB_HOST) ++ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), ++ U2P_R0_HOST_DEVICE, ++ U2P_R0_HOST_DEVICE); ++ else ++ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), ++ U2P_R0_HOST_DEVICE, 0); ++} ++ ++static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv) ++{ ++ int i; ++ ++ if (priv->otg_mode == USB_DR_MODE_PERIPHERAL) ++ priv->otg_phy_mode = PHY_MODE_USB_DEVICE; ++ else ++ priv->otg_phy_mode = PHY_MODE_USB_HOST; ++ ++ for (i = 0 ; i < USB3_HOST_PHY ; ++i) { ++ if (!priv->phys[i]) ++ continue; ++ ++ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), ++ U2P_R0_POWER_ON_RESET, ++ U2P_R0_POWER_ON_RESET); ++ ++ if (i == USB2_OTG_PHY) { ++ regmap_update_bits(priv->regmap, ++ U2P_R0 + (U2P_REG_SIZE * i), ++ U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, ++ U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS); ++ ++ dwc3_meson_g12a_usb2_set_mode(priv, i, ++ priv->otg_phy_mode); ++ } else ++ dwc3_meson_g12a_usb2_set_mode(priv, i, ++ PHY_MODE_USB_HOST); ++ ++ regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), ++ U2P_R0_POWER_ON_RESET, 0); ++ } ++ ++ return 0; ++} ++ ++static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv) ++{ ++ regmap_update_bits(priv->regmap, USB_R3, ++ USB_R3_P30_SSC_RANGE_MASK | ++ USB_R3_P30_REF_SSP_EN, ++ USB_R3_P30_SSC_ENABLE | ++ FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) | ++ USB_R3_P30_REF_SSP_EN); ++ udelay(2); ++ ++ regmap_update_bits(priv->regmap, USB_R2, ++ USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, ++ FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15)); ++ ++ regmap_update_bits(priv->regmap, USB_R2, ++ USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, ++ FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20)); ++ ++ udelay(2); ++ ++ regmap_update_bits(priv->regmap, USB_R1, ++ USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT, ++ USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT); ++ ++ regmap_update_bits(priv->regmap, USB_R1, ++ USB_R1_P30_PCS_TX_SWING_FULL_MASK, ++ FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127)); ++} ++ ++static void dwc3_meson_g12a_usb_otg_apply_mode(struct dwc3_meson_g12a *priv) ++{ ++ if (priv->otg_phy_mode == PHY_MODE_USB_DEVICE) { ++ regmap_update_bits(priv->regmap, USB_R0, ++ USB_R0_U2D_ACT, USB_R0_U2D_ACT); ++ regmap_update_bits(priv->regmap, USB_R0, ++ USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0); ++ regmap_update_bits(priv->regmap, USB_R4, ++ USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0); ++ } else { ++ regmap_update_bits(priv->regmap, USB_R0, ++ USB_R0_U2D_ACT, 0); ++ regmap_update_bits(priv->regmap, USB_R4, ++ USB_R4_P21_SLEEP_M0, 0); ++ } ++} ++ ++static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv) ++{ ++ int ret; ++ ++ ret = dwc3_meson_g12a_usb2_init(priv); ++ if (ret) ++ return ret; ++ ++ regmap_update_bits(priv->regmap, USB_R1, ++ USB_R1_U3H_FLADJ_30MHZ_REG_MASK, ++ FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20)); ++ ++ regmap_update_bits(priv->regmap, USB_R5, ++ USB_R5_ID_DIG_EN_0, ++ USB_R5_ID_DIG_EN_0); ++ regmap_update_bits(priv->regmap, USB_R5, ++ USB_R5_ID_DIG_EN_1, ++ USB_R5_ID_DIG_EN_1); ++ regmap_update_bits(priv->regmap, USB_R5, ++ USB_R5_ID_DIG_TH_MASK, ++ FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff)); ++ ++ /* If we have an actual SuperSpeed port, initialize it */ ++ if (priv->usb3_ports) ++ dwc3_meson_g12a_usb3_init(priv); ++ ++ dwc3_meson_g12a_usb_otg_apply_mode(priv); ++ ++ return 0; ++} ++ ++static const struct regmap_config phy_meson_g12a_usb3_regmap_conf = { ++ .reg_bits = 8, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = USB_R5, ++}; ++ ++static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) ++{ ++ int i; ++ ++ for (i = 0 ; i < PHY_COUNT ; ++i) { ++ priv->phys[i] = devm_phy_optional_get(priv->dev, phy_names[i]); ++ if (!priv->phys[i]) ++ continue; ++ ++ if (IS_ERR(priv->phys[i])) ++ return PTR_ERR(priv->phys[i]); ++ ++ if (i == USB3_HOST_PHY) ++ priv->usb3_ports++; ++ else ++ priv->usb2_ports++; ++ } ++ ++ dev_info(priv->dev, "USB2 ports: %d\n", priv->usb2_ports); ++ dev_info(priv->dev, "USB3 ports: %d\n", priv->usb3_ports); ++ ++ return 0; ++} ++ ++static enum phy_mode dwc3_meson_g12a_get_id(struct dwc3_meson_g12a *priv) ++{ ++ u32 reg; ++ ++ regmap_read(priv->regmap, USB_R5, ®); ++ ++ if (reg & (USB_R5_ID_DIG_SYNC | USB_R5_ID_DIG_REG)) ++ return PHY_MODE_USB_DEVICE; ++ ++ return PHY_MODE_USB_HOST; ++} ++ ++static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv, ++ enum phy_mode mode) ++{ ++ int ret; ++ ++ if (!priv->phys[USB2_OTG_PHY]) ++ return -EINVAL; ++ ++ if (mode == PHY_MODE_USB_HOST) ++ dev_info(priv->dev, "switching to Host Mode\n"); ++ else ++ dev_info(priv->dev, "switching to Device Mode\n"); ++ ++ if (priv->vbus) { ++ if (mode == PHY_MODE_USB_DEVICE) ++ ret = regulator_disable(priv->vbus); ++ else ++ ret = regulator_enable(priv->vbus); ++ if (ret) ++ return ret; ++ } ++ ++ priv->otg_phy_mode = mode; ++ ++ dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode); ++ ++ dwc3_meson_g12a_usb_otg_apply_mode(priv); ++ ++ return 0; ++} ++ ++static int dwc3_meson_g12a_role_set(struct device *dev, enum usb_role role) ++{ ++ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); ++ enum phy_mode mode; ++ ++ if (role == USB_ROLE_NONE) ++ return 0; ++ ++ mode = (role == USB_ROLE_HOST) ? PHY_MODE_USB_HOST ++ : PHY_MODE_USB_DEVICE; ++ ++ if (mode == priv->otg_phy_mode) ++ return 0; ++ ++ return dwc3_meson_g12a_otg_mode_set(priv, mode); ++} ++ ++static enum usb_role dwc3_meson_g12a_role_get(struct device *dev) ++{ ++ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); ++ ++ return priv->otg_phy_mode == PHY_MODE_USB_HOST ? ++ USB_ROLE_HOST : USB_ROLE_DEVICE; ++} ++ ++static struct device *dwc3_meson_g12_find_child(struct device *dev, ++ const char *compatible) ++{ ++ struct platform_device *pdev; ++ struct device_node *np; ++ ++ np = of_get_compatible_child(dev->of_node, compatible); ++ if (!np) ++ return NULL; ++ ++ pdev = of_find_device_by_node(np); ++ of_node_put(np); ++ if (!pdev) ++ return NULL; ++ ++ return &pdev->dev; ++} ++ ++static int dwc3_meson_g12a_probe(struct platform_device *pdev) ++{ ++ struct dwc3_meson_g12a *priv; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ void __iomem *base; ++ struct resource *res; ++ enum phy_mode otg_id; ++ int ret, i; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ priv->regmap = devm_regmap_init_mmio(dev, base, ++ &phy_meson_g12a_usb3_regmap_conf); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ priv->vbus = devm_regulator_get_optional(dev, "vbus"); ++ if (IS_ERR(priv->vbus)) { ++ if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) ++ return PTR_ERR(priv->vbus); ++ priv->vbus = NULL; ++ } ++ ++ priv->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(priv->clk)) ++ return PTR_ERR(priv->clk); ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) ++ return ret; ++ ++ devm_add_action_or_reset(dev, ++ (void(*)(void *))clk_disable_unprepare, ++ priv->clk); ++ ++ platform_set_drvdata(pdev, priv); ++ priv->dev = dev; ++ ++ priv->reset = devm_reset_control_get(dev, NULL); ++ if (IS_ERR(priv->reset)) { ++ ret = PTR_ERR(priv->reset); ++ dev_err(dev, "failed to get device reset, err=%d\n", ret); ++ return ret; ++ } ++ ++ ret = reset_control_reset(priv->reset); ++ if (ret) ++ return ret; ++ ++ ret = dwc3_meson_g12a_get_phys(priv); ++ if (ret) ++ return ret; ++ ++ if (priv->vbus) { ++ ret = regulator_enable(priv->vbus); ++ if (ret) ++ return ret; ++ } ++ ++ /* Get dr_mode */ ++ priv->otg_mode = usb_get_dr_mode(dev); ++ ++ dwc3_meson_g12a_usb_init(priv); ++ ++ /* Init PHYs */ ++ for (i = 0 ; i < PHY_COUNT ; ++i) { ++ ret = phy_init(priv->phys[i]); ++ if (ret) ++ return ret; ++ } ++ ++ /* Set PHY Power */ ++ for (i = 0 ; i < PHY_COUNT ; ++i) { ++ ret = phy_power_on(priv->phys[i]); ++ if (ret) ++ goto err_phys_exit; ++ } ++ ++ ret = of_platform_populate(np, NULL, NULL, dev); ++ if (ret) { ++ clk_disable_unprepare(priv->clk); ++ goto err_phys_power; ++ } ++ ++ /* Setup OTG mode corresponding to the ID pin */ ++ if (priv->otg_mode == USB_DR_MODE_OTG) { ++ /* TOFIX Handle ID mode toggling via IRQ */ ++ otg_id = dwc3_meson_g12a_get_id(priv); ++ if (otg_id != priv->otg_phy_mode) { ++ if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) ++ dev_warn(dev, "Failed to switch OTG mode\n"); ++ } ++ } ++ ++ /* Setup role switcher */ ++ priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, ++ "snps,dwc3"); ++ priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2"); ++ priv->switch_desc.allow_userspace_control = true; ++ priv->switch_desc.set = dwc3_meson_g12a_role_set; ++ priv->switch_desc.get = dwc3_meson_g12a_role_get; ++ ++ priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc); ++ if (IS_ERR(priv->role_switch)) ++ dev_warn(dev, "Unable to register Role Switch\n"); ++ ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_get_sync(dev); ++ ++ return 0; ++ ++err_phys_power: ++ for (i = 0 ; i < PHY_COUNT ; ++i) ++ phy_power_off(priv->phys[i]); ++ ++err_phys_exit: ++ for (i = 0 ; i < PHY_COUNT ; ++i) ++ phy_exit(priv->phys[i]); ++ ++ return ret; ++} ++ ++static int dwc3_meson_g12a_remove(struct platform_device *pdev) ++{ ++ struct dwc3_meson_g12a *priv = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ int i; ++ ++ usb_role_switch_unregister(priv->role_switch); ++ ++ of_platform_depopulate(dev); ++ ++ for (i = 0 ; i < PHY_COUNT ; ++i) { ++ phy_power_off(priv->phys[i]); ++ phy_exit(priv->phys[i]); ++ } ++ ++ pm_runtime_disable(dev); ++ pm_runtime_put_noidle(dev); ++ pm_runtime_set_suspended(dev); ++ ++ return 0; ++} ++ ++static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev) ++{ ++ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); ++ ++ clk_disable(priv->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev) ++{ ++ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); ++ ++ return clk_enable(priv->clk); ++} ++ ++static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) ++{ ++ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); ++ int i; ++ ++ for (i = 0 ; i < PHY_COUNT ; ++i) { ++ phy_power_off(priv->phys[i]); ++ phy_exit(priv->phys[i]); ++ } ++ ++ reset_control_assert(priv->reset); ++ ++ return 0; ++} ++ ++static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev) ++{ ++ struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); ++ int i, ret; ++ ++ reset_control_deassert(priv->reset); ++ ++ dwc3_meson_g12a_usb_init(priv); ++ ++ /* Init PHYs */ ++ for (i = 0 ; i < PHY_COUNT ; ++i) { ++ ret = phy_init(priv->phys[i]); ++ if (ret) ++ return ret; ++ } ++ ++ /* Set PHY Power */ ++ for (i = 0 ; i < PHY_COUNT ; ++i) { ++ ret = phy_power_on(priv->phys[i]); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend, dwc3_meson_g12a_resume) ++ SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend, ++ dwc3_meson_g12a_runtime_resume, NULL) ++}; ++ ++static const struct of_device_id dwc3_meson_g12a_match[] = { ++ { .compatible = "amlogic,meson-g12a-usb-ctrl" }, ++ { /* Sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match); ++ ++static struct platform_driver dwc3_meson_g12a_driver = { ++ .probe = dwc3_meson_g12a_probe, ++ .remove = dwc3_meson_g12a_remove, ++ .driver = { ++ .name = "dwc3-meson-g12a", ++ .of_match_table = dwc3_meson_g12a_match, ++ .pm = &dwc3_meson_g12a_dev_pm_ops, ++ }, ++}; ++ ++module_platform_driver(dwc3_meson_g12a_driver); ++MODULE_LICENSE("GPL v2"); ++MODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer"); ++MODULE_AUTHOR("Neil Armstrong "); + +From 22eb5e142c7c3e8b0ba84075c9a65aed68cda145 Mon Sep 17 00:00:00 2001 +From: Colin Ian King +Date: Wed, 17 Apr 2019 17:26:28 +0100 +Subject: [PATCH 060/249] UPSTREAM: ASoC: hdmi-codec: fix spelling mistake + "plalform" -> "platform" + +There is a spelling mistake in a dev_err message. Fix it. + +Signed-off-by: Colin Ian King +Signed-off-by: Mark Brown +(cherry picked from commit 7b6531c5054e7804ccce25f389a2d4810357f5c9) +Signed-off-by: Neil Armstrong +--- + sound/soc/codecs/hdmi-codec.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 35df73e42cbc5..b9d9dde9fbaf4 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -757,7 +757,7 @@ static int hdmi_codec_probe(struct platform_device *pdev) + dev_dbg(dev, "%s()\n", __func__); + + if (!hcd) { +- dev_err(dev, "%s: No plalform data\n", __func__); ++ dev_err(dev, "%s: No platform data\n", __func__); + return -EINVAL; + } + + +From e595b9b55d362f9699dc404dd926258dd7c18faa Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 29 Apr 2019 15:29:39 +0200 +Subject: [PATCH 061/249] UPSTREAM: ASoC: hdmi-codec: unlock the device on + startup errors + +If the hdmi codec startup fails, it should clear the current_substream +pointer to free the device. This is properly done for the audio_startup() +callback but for snd_pcm_hw_constraint_eld(). + +Make sure the pointer cleared if an error is reported. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 30180e8436046344b12813dc954b2e01dfdcd22d) +Signed-off-by: Neil Armstrong +--- + sound/soc/codecs/hdmi-codec.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index b9d9dde9fbaf4..720de0a53c799 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -439,8 +439,12 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, + if (!ret) { + ret = snd_pcm_hw_constraint_eld(substream->runtime, + hcp->eld); +- if (ret) ++ if (ret) { ++ mutex_lock(&hcp->current_stream_lock); ++ hcp->current_stream = NULL; ++ mutex_unlock(&hcp->current_stream_lock); + return ret; ++ } + } + /* Select chmap supported */ + hdmi_codec_eld_chmap(hcp); + +From a6118030ab40baa635a596af19136dd0039ebd8f Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 29 Apr 2019 15:29:40 +0200 +Subject: [PATCH 062/249] UPSTREAM: ASoC: hdmi-codec: stream is already locked + in hw_params + +startup() should have run before hw_params() is called, so the +current_substream pointer should already be properly set. There +is no reason to call hdmi_codec_new_stream() again in the +hw_params() callback + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 726fc60babe4a46e946e69a9dbd3e21aaec4d58e) +Signed-off-by: Neil Armstrong +--- + sound/soc/codecs/hdmi-codec.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 720de0a53c799..39caf19abb0bc 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -496,10 +496,6 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, + return ret; + } + +- ret = hdmi_codec_new_stream(substream, dai); +- if (ret) +- return ret; +- + hdmi_audio_infoframe_init(&hp.cea); + hp.cea.channels = params_channels(params); + hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; + +From 9c4008d852ccf0ecd0029f1849e1203042883ce1 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 6 May 2019 11:58:12 +0200 +Subject: [PATCH 063/249] UPSTREAM: ASoC: hdmi-codec: remove function name + debug traces + +Remove the debug traces only showing the function name on entry. +The same can be obtained using ftrace. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 900e5daf7034cf65ce4072b86f297c42f9042433) +Signed-off-by: Neil Armstrong +--- + sound/soc/codecs/hdmi-codec.c | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 39caf19abb0bc..eb31d7eddcbf8 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -416,8 +416,6 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + int ret = 0; + +- dev_dbg(dai->dev, "%s()\n", __func__); +- + ret = hdmi_codec_new_stream(substream, dai); + if (ret) + return ret; +@@ -457,8 +455,6 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, + { + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + +- dev_dbg(dai->dev, "%s()\n", __func__); +- + WARN_ON(hcp->current_stream != substream); + + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; +@@ -527,8 +523,6 @@ static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + struct hdmi_codec_daifmt cf = { 0 }; + +- dev_dbg(dai->dev, "%s()\n", __func__); +- + if (dai->id == DAI_ID_SPDIF) + return 0; + +@@ -597,8 +591,6 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) + { + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + +- dev_dbg(dai->dev, "%s()\n", __func__); +- + if (hcp->hcd.ops->digital_mute) + return hcp->hcd.ops->digital_mute(dai->dev->parent, + hcp->hcd.data, mute); +@@ -656,8 +648,6 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, + }; + int ret; + +- dev_dbg(dai->dev, "%s()\n", __func__); +- + ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, + NULL, drv->playback.channels_max, 0, + &hcp->chmap_info); +@@ -754,8 +744,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) + int dai_count, i = 0; + int ret; + +- dev_dbg(dev, "%s()\n", __func__); +- + if (!hcd) { + dev_err(dev, "%s: No platform data\n", __func__); + return -EINVAL; + +From f27a8c03d6dca2faacc22c0385667faf70c36cea Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 6 May 2019 11:58:13 +0200 +Subject: [PATCH 064/249] UPSTREAM: ASoC: hdmi-codec: remove reference to the + current substream + +If the hdmi-codec is on a codec-to-codec link, the substream pointer +it receives is completely made up by snd_soc_dai_link_event(). +The pointer will be different between startup() and shutdown(). + +The hdmi-codec complains when this happens even if it is not really a +problem. The current_substream pointer is not used for anything useful +apart from getting the exclusive ownership of the device. + +Remove current_substream pointer and replace the exclusive locking +mechanism with a simple variable and some atomic operations. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 3fcf94ef4d418668fa66e33ce9aabb05689b55f6) +Signed-off-by: Neil Armstrong +--- + sound/soc/codecs/hdmi-codec.c | 58 ++++++++++------------------------- + 1 file changed, 16 insertions(+), 42 deletions(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index eb31d7eddcbf8..4d32f93f6be68 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -280,11 +280,10 @@ struct hdmi_codec_priv { + struct hdmi_codec_pdata hcd; + struct snd_soc_dai_driver *daidrv; + struct hdmi_codec_daifmt daifmt[2]; +- struct mutex current_stream_lock; +- struct snd_pcm_substream *current_stream; + uint8_t eld[MAX_ELD_BYTES]; + struct snd_pcm_chmap *chmap_info; + unsigned int chmap_idx; ++ unsigned long busy; + }; + + static const struct snd_soc_dapm_widget hdmi_widgets[] = { +@@ -392,42 +391,22 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, + return 0; + } + +-static int hdmi_codec_new_stream(struct snd_pcm_substream *substream, +- struct snd_soc_dai *dai) +-{ +- struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); +- int ret = 0; +- +- mutex_lock(&hcp->current_stream_lock); +- if (!hcp->current_stream) { +- hcp->current_stream = substream; +- } else if (hcp->current_stream != substream) { +- dev_err(dai->dev, "Only one simultaneous stream supported!\n"); +- ret = -EINVAL; +- } +- mutex_unlock(&hcp->current_stream_lock); +- +- return ret; +-} +- + static int hdmi_codec_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + int ret = 0; + +- ret = hdmi_codec_new_stream(substream, dai); +- if (ret) +- return ret; ++ ret = test_and_set_bit(0, &hcp->busy); ++ if (ret) { ++ dev_err(dai->dev, "Only one simultaneous stream supported!\n"); ++ return -EINVAL; ++ } + + if (hcp->hcd.ops->audio_startup) { + ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data); +- if (ret) { +- mutex_lock(&hcp->current_stream_lock); +- hcp->current_stream = NULL; +- mutex_unlock(&hcp->current_stream_lock); +- return ret; +- } ++ if (ret) ++ goto err; + } + + if (hcp->hcd.ops->get_eld) { +@@ -437,17 +416,18 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, + if (!ret) { + ret = snd_pcm_hw_constraint_eld(substream->runtime, + hcp->eld); +- if (ret) { +- mutex_lock(&hcp->current_stream_lock); +- hcp->current_stream = NULL; +- mutex_unlock(&hcp->current_stream_lock); +- return ret; +- } ++ if (ret) ++ goto err; + } + /* Select chmap supported */ + hdmi_codec_eld_chmap(hcp); + } + return 0; ++ ++err: ++ /* Release the exclusive lock on error */ ++ clear_bit(0, &hcp->busy); ++ return ret; + } + + static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, +@@ -455,14 +435,10 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, + { + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + +- WARN_ON(hcp->current_stream != substream); +- + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); + +- mutex_lock(&hcp->current_stream_lock); +- hcp->current_stream = NULL; +- mutex_unlock(&hcp->current_stream_lock); ++ clear_bit(0, &hcp->busy); + } + + static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, +@@ -761,8 +737,6 @@ static int hdmi_codec_probe(struct platform_device *pdev) + return -ENOMEM; + + hcp->hcd = *hcd; +- mutex_init(&hcp->current_stream_lock); +- + hcp->daidrv = devm_kcalloc(dev, dai_count, sizeof(*hcp->daidrv), + GFP_KERNEL); + if (!hcp->daidrv) + +From 138b08265088ba3a0356bfdb9dcfeddd8913f5ca Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 6 May 2019 11:58:14 +0200 +Subject: [PATCH 065/249] UPSTREAM: ASoC: hdmi-codec: remove reference to the + dai drivers in the private data + +Keeping the a pointer to the dai drivers is not necessary. It is not used +by the hdmi_codec after the probe. + +Even if it was used, the 'struct snd_soc_dai_driver' can accessed through +the 'struct snd_soc_dai' so keeping the pointer in the private data +structure is not useful. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 1de005d47d90343666c5cc50a50929e05e52baac) +Signed-off-by: Neil Armstrong +--- + sound/soc/codecs/hdmi-codec.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 4d32f93f6be68..9408e6bc4d3e5 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -278,7 +278,6 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { + + struct hdmi_codec_priv { + struct hdmi_codec_pdata hcd; +- struct snd_soc_dai_driver *daidrv; + struct hdmi_codec_daifmt daifmt[2]; + uint8_t eld[MAX_ELD_BYTES]; + struct snd_pcm_chmap *chmap_info; +@@ -715,6 +714,7 @@ static const struct snd_soc_component_driver hdmi_driver = { + static int hdmi_codec_probe(struct platform_device *pdev) + { + struct hdmi_codec_pdata *hcd = pdev->dev.platform_data; ++ struct snd_soc_dai_driver *daidrv; + struct device *dev = &pdev->dev; + struct hdmi_codec_priv *hcp; + int dai_count, i = 0; +@@ -737,27 +737,25 @@ static int hdmi_codec_probe(struct platform_device *pdev) + return -ENOMEM; + + hcp->hcd = *hcd; +- hcp->daidrv = devm_kcalloc(dev, dai_count, sizeof(*hcp->daidrv), +- GFP_KERNEL); +- if (!hcp->daidrv) ++ daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); ++ if (!daidrv) + return -ENOMEM; + + if (hcd->i2s) { +- hcp->daidrv[i] = hdmi_i2s_dai; +- hcp->daidrv[i].playback.channels_max = +- hcd->max_i2s_channels; ++ daidrv[i] = hdmi_i2s_dai; ++ daidrv[i].playback.channels_max = hcd->max_i2s_channels; + i++; + } + + if (hcd->spdif) { +- hcp->daidrv[i] = hdmi_spdif_dai; ++ daidrv[i] = hdmi_spdif_dai; + hcp->daifmt[DAI_ID_SPDIF].fmt = HDMI_SPDIF; + } + + dev_set_drvdata(dev, hcp); + +- ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv, +- dai_count); ++ ret = devm_snd_soc_register_component(dev, &hdmi_driver, daidrv, ++ dai_count); + if (ret) { + dev_err(dev, "%s: snd_soc_register_component() failed (%d)\n", + __func__, ret); + +From 82dc0a826a10bacacb3cca8e955b599acd7b1253 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 6 May 2019 11:58:15 +0200 +Subject: [PATCH 066/249] UPSTREAM: ASoC: hdmi-codec: remove ops dependency on + the dai id + +The dependency on the dai_id can be removed by setting different ops +for the i2s and spdif dai and storing the dai format information in +each dai structure. It simplies the code a bit. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 0cf4610b9f297e570da4d98514b310f076ecc8ab) +Signed-off-by: Neil Armstrong +--- + sound/soc/codecs/hdmi-codec.c | 100 +++++++++++++++++++++++----------- + 1 file changed, 67 insertions(+), 33 deletions(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 9408e6bc4d3e5..90a8927666259 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -278,7 +278,6 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { + + struct hdmi_codec_priv { + struct hdmi_codec_pdata hcd; +- struct hdmi_codec_daifmt daifmt[2]; + uint8_t eld[MAX_ELD_BYTES]; + struct snd_pcm_chmap *chmap_info; + unsigned int chmap_idx; +@@ -445,6 +444,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) + { + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); ++ struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + struct hdmi_codec_params hp = { + .iec = { + .status = { 0 }, +@@ -489,28 +489,27 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, + hp.channels = params_channels(params); + + return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, +- &hcp->daifmt[dai->id], &hp); ++ cf, &hp); + } + +-static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, +- unsigned int fmt) ++static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, ++ unsigned int fmt) + { +- struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); +- struct hdmi_codec_daifmt cf = { 0 }; ++ struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + +- if (dai->id == DAI_ID_SPDIF) +- return 0; ++ /* Reset daifmt */ ++ memset(cf, 0, sizeof(*cf)); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: +- cf.bit_clk_master = 1; +- cf.frame_clk_master = 1; ++ cf->bit_clk_master = 1; ++ cf->frame_clk_master = 1; + break; + case SND_SOC_DAIFMT_CBS_CFM: +- cf.frame_clk_master = 1; ++ cf->frame_clk_master = 1; + break; + case SND_SOC_DAIFMT_CBM_CFS: +- cf.bit_clk_master = 1; ++ cf->bit_clk_master = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + break; +@@ -522,43 +521,41 @@ static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: +- cf.frame_clk_inv = 1; ++ cf->frame_clk_inv = 1; + break; + case SND_SOC_DAIFMT_IB_NF: +- cf.bit_clk_inv = 1; ++ cf->bit_clk_inv = 1; + break; + case SND_SOC_DAIFMT_IB_IF: +- cf.frame_clk_inv = 1; +- cf.bit_clk_inv = 1; ++ cf->frame_clk_inv = 1; ++ cf->bit_clk_inv = 1; + break; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: +- cf.fmt = HDMI_I2S; ++ cf->fmt = HDMI_I2S; + break; + case SND_SOC_DAIFMT_DSP_A: +- cf.fmt = HDMI_DSP_A; ++ cf->fmt = HDMI_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: +- cf.fmt = HDMI_DSP_B; ++ cf->fmt = HDMI_DSP_B; + break; + case SND_SOC_DAIFMT_RIGHT_J: +- cf.fmt = HDMI_RIGHT_J; ++ cf->fmt = HDMI_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: +- cf.fmt = HDMI_LEFT_J; ++ cf->fmt = HDMI_LEFT_J; + break; + case SND_SOC_DAIFMT_AC97: +- cf.fmt = HDMI_AC97; ++ cf->fmt = HDMI_AC97; + break; + default: + dev_err(dai->dev, "Invalid DAI interface format\n"); + return -EINVAL; + } + +- hcp->daifmt[dai->id] = cf; +- + return 0; + } + +@@ -573,14 +570,20 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) + return 0; + } + +-static const struct snd_soc_dai_ops hdmi_dai_ops = { ++static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, +- .set_fmt = hdmi_codec_set_fmt, ++ .set_fmt = hdmi_codec_i2s_set_fmt, + .digital_mute = hdmi_codec_digital_mute, + }; + ++static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { ++ .startup = hdmi_codec_startup, ++ .shutdown = hdmi_codec_shutdown, ++ .hw_params = hdmi_codec_hw_params, ++ .digital_mute = hdmi_codec_digital_mute, ++}; + + #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ +@@ -648,20 +651,52 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, + static int hdmi_dai_probe(struct snd_soc_dai *dai) + { + struct snd_soc_dapm_context *dapm; ++ struct hdmi_codec_daifmt *daifmt; + struct snd_soc_dapm_route route = { + .sink = "TX", + .source = dai->driver->playback.stream_name, + }; ++ int ret; + + dapm = snd_soc_component_get_dapm(dai->component); ++ ret = snd_soc_dapm_add_routes(dapm, &route, 1); ++ if (ret) ++ return ret; ++ ++ daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL); ++ if (!daifmt) ++ return -ENOMEM; + +- return snd_soc_dapm_add_routes(dapm, &route, 1); ++ dai->playback_dma_data = daifmt; ++ return 0; ++} ++ ++static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) ++{ ++ struct hdmi_codec_daifmt *cf = dai->playback_dma_data; ++ int ret; ++ ++ ret = hdmi_dai_probe(dai); ++ if (ret) ++ return ret; ++ ++ cf = dai->playback_dma_data; ++ cf->fmt = HDMI_SPDIF; ++ ++ return 0; ++} ++ ++static int hdmi_codec_dai_remove(struct snd_soc_dai *dai) ++{ ++ kfree(dai->playback_dma_data); ++ return 0; + } + + static const struct snd_soc_dai_driver hdmi_i2s_dai = { + .name = "i2s-hifi", + .id = DAI_ID_I2S, + .probe = hdmi_dai_probe, ++ .remove = hdmi_codec_dai_remove, + .playback = { + .stream_name = "I2S Playback", + .channels_min = 2, +@@ -670,14 +705,15 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { + .formats = I2S_FORMATS, + .sig_bits = 24, + }, +- .ops = &hdmi_dai_ops, ++ .ops = &hdmi_codec_i2s_dai_ops, + .pcm_new = hdmi_codec_pcm_new, + }; + + static const struct snd_soc_dai_driver hdmi_spdif_dai = { + .name = "spdif-hifi", + .id = DAI_ID_SPDIF, +- .probe = hdmi_dai_probe, ++ .probe = hdmi_dai_spdif_probe, ++ .remove = hdmi_codec_dai_remove, + .playback = { + .stream_name = "SPDIF Playback", + .channels_min = 2, +@@ -685,7 +721,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { + .rates = HDMI_RATES, + .formats = SPDIF_FORMATS, + }, +- .ops = &hdmi_dai_ops, ++ .ops = &hdmi_codec_spdif_dai_ops, + .pcm_new = hdmi_codec_pcm_new, + }; + +@@ -747,10 +783,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) + i++; + } + +- if (hcd->spdif) { ++ if (hcd->spdif) + daidrv[i] = hdmi_spdif_dai; +- hcp->daifmt[DAI_ID_SPDIF].fmt = HDMI_SPDIF; +- } + + dev_set_drvdata(dev, hcp); + + +From 9dc13d7c0233a8cb6b242846a7371bdfefc654b3 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 29 Apr 2019 11:47:49 +0200 +Subject: [PATCH 067/249] UPSTREAM: ASoC: fix valid stream condition + +A stream may specify a rate range using 'rate_min' and 'rate_max', so a +stream may be valid and not specify any rates. However, as stream cannot +be valid and not have any channel. Let's use this condition instead to +determine if a stream is valid or not. + +Fixes: cde79035c6cf ("ASoC: Handle multiple codecs with split playback / capture") +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 6a7c59c6d9f3b280e81d7a04bbe4e55e90152dce) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-pcm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index be80a12fba27c..c4e5d292a0d76 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -43,8 +43,8 @@ static bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream) + else + codec_stream = &dai->driver->capture; + +- /* If the codec specifies any rate at all, it supports the stream. */ +- return codec_stream->rates; ++ /* If the codec specifies any channels at all, it supports the stream */ ++ return codec_stream->channels_min; + } + + /** + +From 6d486503dc795f8a989150c95eccc267dcffe39f Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 29 Apr 2019 11:47:50 +0200 +Subject: [PATCH 068/249] UPSTREAM: ASoC: skip hw_free on codec dai for which + the stream is invalid + +Like for hw_params, hw_free should not be called on codec dai for +which the current stream is invalid. + +Fixes: cde79035c6cf ("ASoC: Handle multiple codecs with split playback / capture") +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit f47b9ad927c6370b80922af434dda98764a43804) +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-pcm.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index c4e5d292a0d76..69ea962de5856 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -1033,6 +1033,9 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, + + codec_err: + for_each_rtd_codec_dai_rollback(rtd, i, codec_dai) { ++ if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) ++ continue; ++ + if (codec_dai->driver->ops->hw_free) + codec_dai->driver->ops->hw_free(substream, codec_dai); + codec_dai->rate = 0; +@@ -1090,6 +1093,9 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) + + /* now free hw params for the DAIs */ + for_each_rtd_codec_dai(rtd, i, codec_dai) { ++ if (!snd_soc_dai_stream_valid(codec_dai, substream->stream)) ++ continue; ++ + if (codec_dai->driver->ops->hw_free) + codec_dai->driver->ops->hw_free(substream, codec_dai); + } + +From a94cd4dd33fa0bc465f8540ca30c882a8154c01d Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 13:50:15 +0200 +Subject: [PATCH 069/249] FROMGIT: ASoC: max98357a: add missing supported rates + +According the publicly available datasheet (and some test) the max98357a +also supports 32, 44.1 and 88.2 kHz sample rate. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit fdf34366d3242d5eeffa1b4d9a3497ebf30a4ecb + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) +Signed-off-by: Neil Armstrong +--- + sound/soc/codecs/max98357a.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c +index d469576b5a7bb..d037a3e4d3232 100644 +--- a/sound/soc/codecs/max98357a.c ++++ b/sound/soc/codecs/max98357a.c +@@ -97,7 +97,10 @@ static struct snd_soc_dai_driver max98357a_dai_driver = { + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | ++ SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + +From a8790dfb8563038dc3832a4eac59af56e708650b Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 13:17:28 +0200 +Subject: [PATCH 070/249] FROMGIT: ASoC: meson: add g12a compatibles + +Add new compatible strings for the g12a devices. +Audio wise, the g12a is fairly to close to the axg, yet some differences +need to be handled. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 679f4e6cfd45bcc14bb563576e419ac9e43fad7c + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) +Signed-off-by: Neil Armstrong +--- + Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt | 4 +++- + Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt | 3 ++- + .../devicetree/bindings/sound/amlogic,axg-spdifin.txt | 3 ++- + .../devicetree/bindings/sound/amlogic,axg-spdifout.txt | 3 ++- + .../devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt | 4 +++- + 5 files changed, 12 insertions(+), 5 deletions(-) + +diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt +index 3dfc2515e5c67..4330fc9dca6d8 100644 +--- a/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt ++++ b/Documentation/devicetree/bindings/sound/amlogic,axg-fifo.txt +@@ -2,7 +2,9 @@ + + Required properties: + - compatible: 'amlogic,axg-toddr' or +- 'amlogic,axg-frddr' ++ 'amlogic,axg-toddr' or ++ 'amlogic,g12a-frddr' or ++ 'amlogic,g12a-toddr' + - reg: physical base address of the controller and length of memory + mapped region. + - interrupts: interrupt specifier for the fifo. +diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt +index 5672d0bc5b166..73f473a9365f7 100644 +--- a/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt ++++ b/Documentation/devicetree/bindings/sound/amlogic,axg-pdm.txt +@@ -1,7 +1,8 @@ + * Amlogic Audio PDM input + + Required properties: +-- compatible: 'amlogic,axg-pdm' ++- compatible: 'amlogic,axg-pdm' or ++ 'amlogic,g12a-pdm' + - reg: physical base address of the controller and length of memory + mapped region. + - clocks: list of clock phandle, one for each entry clock-names. +diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt +index 2e6cb7d9b2029..0b82504fa4190 100644 +--- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt ++++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifin.txt +@@ -1,7 +1,8 @@ + * Amlogic Audio SPDIF Input + + Required properties: +-- compatible: 'amlogic,axg-spdifin' ++- compatible: 'amlogic,axg-spdifin' or ++ 'amlogic,g12a-spdifin' + - interrupts: interrupt specifier for the spdif input. + - clocks: list of clock phandle, one for each entry clock-names. + - clock-names: should contain the following: +diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt +index 521c38ad89e71..826152730508e 100644 +--- a/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt ++++ b/Documentation/devicetree/bindings/sound/amlogic,axg-spdifout.txt +@@ -1,7 +1,8 @@ + * Amlogic Audio SPDIF Output + + Required properties: +-- compatible: 'amlogic,axg-spdifout' ++- compatible: 'amlogic,axg-spdifout' or ++ 'amlogic,g12a-spdifout' + - clocks: list of clock phandle, one for each entry clock-names. + - clock-names: should contain the following: + * "pclk" : peripheral clock. +diff --git a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt +index 1c1b7490554ea..3b94a715a0b9b 100644 +--- a/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt ++++ b/Documentation/devicetree/bindings/sound/amlogic,axg-tdm-formatters.txt +@@ -2,7 +2,9 @@ + + Required properties: + - compatible: 'amlogic,axg-tdmin' or +- 'amlogic,axg-tdmout' ++ 'amlogic,axg-tdmout' or ++ 'amlogic,g12a-tdmin' or ++ 'amlogic,g12a-tdmout' + - reg: physical base address of the controller and length of memory + mapped region. + - clocks: list of clock phandle, one for each entry clock-names. + +From 7291779c68c58785c107307a4a00a466dab8bc9d Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 13:17:29 +0200 +Subject: [PATCH 071/249] FROMGIT: ASoC: meson: axg-fifo: add g12a support + +The g12a fifos gained the ability to set the initial address of the +pointer within the buffer, instead of defaulting to the buffer start +address. + +It is not very useful to us (yet) but we need to put a copy the buffer +start address in the related register for the fifo to work properly on the +g12a SoC family + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit 7c02509a8a9981fb2c16b75904423e7ab2f9f43a + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/axg-fifo.c | 34 +++++++++++++++++++++++++++++++--- + sound/soc/meson/axg-fifo.h | 2 ++ + 2 files changed, 33 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c +index 75e5e480fda28..01c1c7db25100 100644 +--- a/sound/soc/meson/axg-fifo.c ++++ b/sound/soc/meson/axg-fifo.c +@@ -19,7 +19,7 @@ + * This file implements the platform operations common to the playback and + * capture frontend DAI. The logic behind this two types of fifo is very + * similar but some difference exist. +- * These differences the respective DAI drivers ++ * These differences are handled in the respective DAI drivers + */ + + static struct snd_pcm_hardware axg_fifo_hw = { +@@ -133,6 +133,23 @@ static int axg_fifo_pcm_hw_params(struct snd_pcm_substream *ss, + return 0; + } + ++static int g12a_fifo_pcm_hw_params(struct snd_pcm_substream *ss, ++ struct snd_pcm_hw_params *params) ++{ ++ struct axg_fifo *fifo = axg_fifo_data(ss); ++ struct snd_pcm_runtime *runtime = ss->runtime; ++ int ret; ++ ++ ret = axg_fifo_pcm_hw_params(ss, params); ++ if (ret) ++ return ret; ++ ++ /* Set the initial memory address of the DMA */ ++ regmap_write(fifo->map, FIFO_INIT_ADDR, runtime->dma_addr); ++ ++ return 0; ++} ++ + static int axg_fifo_pcm_hw_free(struct snd_pcm_substream *ss) + { + struct axg_fifo *fifo = axg_fifo_data(ss); +@@ -262,6 +279,17 @@ const struct snd_pcm_ops axg_fifo_pcm_ops = { + }; + EXPORT_SYMBOL_GPL(axg_fifo_pcm_ops); + ++const struct snd_pcm_ops g12a_fifo_pcm_ops = { ++ .open = axg_fifo_pcm_open, ++ .close = axg_fifo_pcm_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = g12a_fifo_pcm_hw_params, ++ .hw_free = axg_fifo_pcm_hw_free, ++ .pointer = axg_fifo_pcm_pointer, ++ .trigger = axg_fifo_pcm_trigger, ++}; ++EXPORT_SYMBOL_GPL(g12a_fifo_pcm_ops); ++ + int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type) + { + struct snd_card *card = rtd->card->snd_card; +@@ -278,7 +306,7 @@ static const struct regmap_config axg_fifo_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +- .max_register = FIFO_STATUS2, ++ .max_register = FIFO_INIT_ADDR, + }; + + int axg_fifo_probe(struct platform_device *pdev) +@@ -339,6 +367,6 @@ int axg_fifo_probe(struct platform_device *pdev) + } + EXPORT_SYMBOL_GPL(axg_fifo_probe); + +-MODULE_DESCRIPTION("Amlogic AXG fifo driver"); ++MODULE_DESCRIPTION("Amlogic AXG/G12A fifo driver"); + MODULE_AUTHOR("Jerome Brunet "); + MODULE_LICENSE("GPL v2"); +diff --git a/sound/soc/meson/axg-fifo.h b/sound/soc/meson/axg-fifo.h +index d9f516cfbeda2..5caf81241dfee 100644 +--- a/sound/soc/meson/axg-fifo.h ++++ b/sound/soc/meson/axg-fifo.h +@@ -60,6 +60,7 @@ struct snd_soc_pcm_runtime; + #define FIFO_STATUS1 0x14 + #define STATUS1_INT_STS(x) ((x) << 0) + #define FIFO_STATUS2 0x18 ++#define FIFO_INIT_ADDR 0x24 + + struct axg_fifo { + struct regmap *map; +@@ -74,6 +75,7 @@ struct axg_fifo_match_data { + }; + + extern const struct snd_pcm_ops axg_fifo_pcm_ops; ++extern const struct snd_pcm_ops g12a_fifo_pcm_ops; + + int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type); + int axg_fifo_probe(struct platform_device *pdev); + +From 9c274e6acdf442bb173a2b124a9fc5d07e13feeb Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 13:17:30 +0200 +Subject: [PATCH 072/249] FROMGIT: ASoC: meson: axg-toddr: add g12a support + +Since the g12a SoC fifo can set the fifo initial start address, we must +make sure to actually reset the write pointer to this address when +starting a capture. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit a3c23a8ad4dc07100d916d75ca30c982288b868d + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/axg-toddr.c | 53 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 53 insertions(+) + +diff --git a/sound/soc/meson/axg-toddr.c b/sound/soc/meson/axg-toddr.c +index 0e9ca3882ae5c..4f63e434fad4b 100644 +--- a/sound/soc/meson/axg-toddr.c ++++ b/sound/soc/meson/axg-toddr.c +@@ -24,6 +24,7 @@ + #define CTRL0_TODDR_MSB_POS(x) ((x) << 8) + #define CTRL0_TODDR_LSB_POS_MASK GENMASK(7, 3) + #define CTRL0_TODDR_LSB_POS(x) ((x) << 3) ++#define CTRL1_TODDR_FORCE_FINISH BIT(25) + + #define TODDR_MSB_POS 31 + +@@ -33,6 +34,22 @@ static int axg_toddr_pcm_new(struct snd_soc_pcm_runtime *rtd, + return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_CAPTURE); + } + ++static int g12a_toddr_dai_prepare(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); ++ ++ /* Reset the write pointer to the FIFO_INIT_ADDR */ ++ regmap_update_bits(fifo->map, FIFO_CTRL1, ++ CTRL1_TODDR_FORCE_FINISH, 0); ++ regmap_update_bits(fifo->map, FIFO_CTRL1, ++ CTRL1_TODDR_FORCE_FINISH, CTRL1_TODDR_FORCE_FINISH); ++ regmap_update_bits(fifo->map, FIFO_CTRL1, ++ CTRL1_TODDR_FORCE_FINISH, 0); ++ ++ return 0; ++} ++ + static int axg_toddr_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +@@ -172,10 +189,46 @@ static const struct axg_fifo_match_data axg_toddr_match_data = { + .dai_drv = &axg_toddr_dai_drv + }; + ++static const struct snd_soc_dai_ops g12a_toddr_ops = { ++ .prepare = g12a_toddr_dai_prepare, ++ .hw_params = axg_toddr_dai_hw_params, ++ .startup = axg_toddr_dai_startup, ++ .shutdown = axg_toddr_dai_shutdown, ++}; ++ ++static struct snd_soc_dai_driver g12a_toddr_dai_drv = { ++ .name = "TODDR", ++ .capture = { ++ .stream_name = "Capture", ++ .channels_min = 1, ++ .channels_max = AXG_FIFO_CH_MAX, ++ .rates = AXG_FIFO_RATES, ++ .formats = AXG_FIFO_FORMATS, ++ }, ++ .ops = &g12a_toddr_ops, ++ .pcm_new = axg_toddr_pcm_new, ++}; ++ ++static const struct snd_soc_component_driver g12a_toddr_component_drv = { ++ .dapm_widgets = axg_toddr_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(axg_toddr_dapm_widgets), ++ .dapm_routes = axg_toddr_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(axg_toddr_dapm_routes), ++ .ops = &g12a_fifo_pcm_ops ++}; ++ ++static const struct axg_fifo_match_data g12a_toddr_match_data = { ++ .component_drv = &g12a_toddr_component_drv, ++ .dai_drv = &g12a_toddr_dai_drv ++}; ++ + static const struct of_device_id axg_toddr_of_match[] = { + { + .compatible = "amlogic,axg-toddr", + .data = &axg_toddr_match_data, ++ }, { ++ .compatible = "amlogic,g12a-toddr", ++ .data = &g12a_toddr_match_data, + }, {} + }; + MODULE_DEVICE_TABLE(of, axg_toddr_of_match); + +From 24e5a97911389c4ee6712aceb956d8013f420e7f Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 13:17:31 +0200 +Subject: [PATCH 073/249] FROMGIT: ASoC: meson: axg-frddr: add g12a support + +On the axg, frddr could only be connected to 1 downstream element, so the +playback was possible on 1 interface only at a time. + +On the g12a, the frddr may connect and wait for the request of up to 3 +downstream elements. With this, it possible for single playback to be +played on several interfaces at the same time. + +Like the toddr fifo, the g12a frddr also need to take care of resetting +the read pointer to the initial fifo address when preparing a playback. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit fcced66f208d778aa2dea05910161689503c16bf + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/axg-frddr.c | 143 +++++++++++++++++++++++++++++++++++- + 1 file changed, 140 insertions(+), 3 deletions(-) + +diff --git a/sound/soc/meson/axg-frddr.c b/sound/soc/meson/axg-frddr.c +index a6f6f6a2eca80..2b8807737b2be 100644 +--- a/sound/soc/meson/axg-frddr.c ++++ b/sound/soc/meson/axg-frddr.c +@@ -3,7 +3,9 @@ + // Copyright (c) 2018 BayLibre, SAS. + // Author: Jerome Brunet + +-/* This driver implements the frontend playback DAI of AXG based SoCs */ ++/* ++ * This driver implements the frontend playback DAI of AXG and G12A based SoCs ++ */ + + #include + #include +@@ -14,7 +16,29 @@ + + #include "axg-fifo.h" + +-#define CTRL0_FRDDR_PP_MODE BIT(30) ++#define CTRL0_FRDDR_PP_MODE BIT(30) ++#define CTRL0_SEL1_EN_SHIFT 3 ++#define CTRL0_SEL2_SHIFT 4 ++#define CTRL0_SEL2_EN_SHIFT 7 ++#define CTRL0_SEL3_SHIFT 8 ++#define CTRL0_SEL3_EN_SHIFT 11 ++#define CTRL1_FRDDR_FORCE_FINISH BIT(12) ++ ++static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai); ++ ++ /* Reset the read pointer to the FIFO_INIT_ADDR */ ++ regmap_update_bits(fifo->map, FIFO_CTRL1, ++ CTRL1_FRDDR_FORCE_FINISH, 0); ++ regmap_update_bits(fifo->map, FIFO_CTRL1, ++ CTRL1_FRDDR_FORCE_FINISH, CTRL1_FRDDR_FORCE_FINISH); ++ regmap_update_bits(fifo->map, FIFO_CTRL1, ++ CTRL1_FRDDR_FORCE_FINISH, 0); ++ ++ return 0; ++} + + static int axg_frddr_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +@@ -119,10 +143,123 @@ static const struct axg_fifo_match_data axg_frddr_match_data = { + .dai_drv = &axg_frddr_dai_drv + }; + ++static const struct snd_soc_dai_ops g12a_frddr_ops = { ++ .prepare = g12a_frddr_dai_prepare, ++ .startup = axg_frddr_dai_startup, ++ .shutdown = axg_frddr_dai_shutdown, ++}; ++ ++static struct snd_soc_dai_driver g12a_frddr_dai_drv = { ++ .name = "FRDDR", ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 1, ++ .channels_max = AXG_FIFO_CH_MAX, ++ .rates = AXG_FIFO_RATES, ++ .formats = AXG_FIFO_FORMATS, ++ }, ++ .ops = &g12a_frddr_ops, ++ .pcm_new = axg_frddr_pcm_new, ++}; ++ ++static const char * const g12a_frddr_sel_texts[] = { ++ "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", ++}; ++ ++static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT, ++ g12a_frddr_sel_texts); ++static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT, ++ g12a_frddr_sel_texts); ++static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT, ++ g12a_frddr_sel_texts); ++ ++static const struct snd_kcontrol_new g12a_frddr_out1_demux = ++ SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum); ++static const struct snd_kcontrol_new g12a_frddr_out2_demux = ++ SOC_DAPM_ENUM("Output Src 2", g12a_frddr_sel2_enum); ++static const struct snd_kcontrol_new g12a_frddr_out3_demux = ++ SOC_DAPM_ENUM("Output Src 3", g12a_frddr_sel3_enum); ++ ++static const struct snd_kcontrol_new g12a_frddr_out1_enable = ++ SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, ++ CTRL0_SEL1_EN_SHIFT, 1, 0); ++static const struct snd_kcontrol_new g12a_frddr_out2_enable = ++ SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, ++ CTRL0_SEL2_EN_SHIFT, 1, 0); ++static const struct snd_kcontrol_new g12a_frddr_out3_enable = ++ SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0, ++ CTRL0_SEL3_EN_SHIFT, 1, 0); ++ ++static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = { ++ SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0, ++ &g12a_frddr_out1_enable), ++ SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0, ++ &g12a_frddr_out2_enable), ++ SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0, ++ &g12a_frddr_out3_enable), ++ SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0, ++ &g12a_frddr_out1_demux), ++ SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0, ++ &g12a_frddr_out2_demux), ++ SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0, ++ &g12a_frddr_out3_demux), ++ SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0), ++ SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0), ++}; ++ ++static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = { ++ { "SRC 1", NULL, "Playback" }, ++ { "SRC 2", NULL, "Playback" }, ++ { "SRC 3", NULL, "Playback" }, ++ { "SRC 1 EN", "Switch", "SRC 1" }, ++ { "SRC 2 EN", "Switch", "SRC 2" }, ++ { "SRC 3 EN", "Switch", "SRC 3" }, ++ { "SINK 1 SEL", NULL, "SRC 1 EN" }, ++ { "SINK 2 SEL", NULL, "SRC 2 EN" }, ++ { "SINK 3 SEL", NULL, "SRC 3 EN" }, ++ { "OUT 0", "OUT 0", "SINK 1 SEL" }, ++ { "OUT 1", "OUT 1", "SINK 1 SEL" }, ++ { "OUT 2", "OUT 2", "SINK 1 SEL" }, ++ { "OUT 3", "OUT 3", "SINK 1 SEL" }, ++ { "OUT 4", "OUT 4", "SINK 1 SEL" }, ++ { "OUT 0", "OUT 0", "SINK 2 SEL" }, ++ { "OUT 1", "OUT 1", "SINK 2 SEL" }, ++ { "OUT 2", "OUT 2", "SINK 2 SEL" }, ++ { "OUT 3", "OUT 3", "SINK 2 SEL" }, ++ { "OUT 4", "OUT 4", "SINK 2 SEL" }, ++ { "OUT 0", "OUT 0", "SINK 3 SEL" }, ++ { "OUT 1", "OUT 1", "SINK 3 SEL" }, ++ { "OUT 2", "OUT 2", "SINK 3 SEL" }, ++ { "OUT 3", "OUT 3", "SINK 3 SEL" }, ++ { "OUT 4", "OUT 4", "SINK 3 SEL" }, ++}; ++ ++static const struct snd_soc_component_driver g12a_frddr_component_drv = { ++ .dapm_widgets = g12a_frddr_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(g12a_frddr_dapm_widgets), ++ .dapm_routes = g12a_frddr_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes), ++ .ops = &g12a_fifo_pcm_ops ++}; ++ ++static const struct axg_fifo_match_data g12a_frddr_match_data = { ++ .component_drv = &g12a_frddr_component_drv, ++ .dai_drv = &g12a_frddr_dai_drv ++}; ++ + static const struct of_device_id axg_frddr_of_match[] = { + { + .compatible = "amlogic,axg-frddr", + .data = &axg_frddr_match_data, ++ }, { ++ .compatible = "amlogic,g12a-frddr", ++ .data = &g12a_frddr_match_data, + }, {} + }; + MODULE_DEVICE_TABLE(of, axg_frddr_of_match); +@@ -136,6 +273,6 @@ static struct platform_driver axg_frddr_pdrv = { + }; + module_platform_driver(axg_frddr_pdrv); + +-MODULE_DESCRIPTION("Amlogic AXG playback fifo driver"); ++MODULE_DESCRIPTION("Amlogic AXG/G12A playback fifo driver"); + MODULE_AUTHOR("Jerome Brunet "); + MODULE_LICENSE("GPL v2"); + +From 26d9868563f2192ab78f2ab9cb3e7455e2aa537e Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 13:17:32 +0200 +Subject: [PATCH 074/249] FROMGIT: ASoC: meson: axg-tdm-formatter: rework + quirks settings + +The g12a tdmout requires a different signal skew offset than the axg. +With this change, the skew offset is added as a parameter of the tdm +formatters to prepare the addition of the g12a support. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit f01bc67f58fde599b48d2dde5d0f48dccd84c4f1 + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/axg-tdm-formatter.c | 6 ++++-- + sound/soc/meson/axg-tdm-formatter.h | 11 +++++++++-- + sound/soc/meson/axg-tdmin.c | 16 +++++++++++----- + sound/soc/meson/axg-tdmout.c | 16 +++++++++++----- + 4 files changed, 35 insertions(+), 14 deletions(-) + +diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c +index 43e390f9358a4..0c6cce5c57732 100644 +--- a/sound/soc/meson/axg-tdm-formatter.c ++++ b/sound/soc/meson/axg-tdm-formatter.c +@@ -68,7 +68,7 @@ EXPORT_SYMBOL_GPL(axg_tdm_formatter_set_channel_masks); + static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter) + { + struct axg_tdm_stream *ts = formatter->stream; +- bool invert = formatter->drv->invert_sclk; ++ bool invert = formatter->drv->quirks->invert_sclk; + int ret; + + /* Do nothing if the formatter is already enabled */ +@@ -85,7 +85,9 @@ static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter) + return ret; + + /* Setup the stream parameter in the formatter */ +- ret = formatter->drv->ops->prepare(formatter->map, formatter->stream); ++ ret = formatter->drv->ops->prepare(formatter->map, ++ formatter->drv->quirks, ++ formatter->stream); + if (ret) + return ret; + +diff --git a/sound/soc/meson/axg-tdm-formatter.h b/sound/soc/meson/axg-tdm-formatter.h +index cf947caf3cb15..9ef98e955cb27 100644 +--- a/sound/soc/meson/axg-tdm-formatter.h ++++ b/sound/soc/meson/axg-tdm-formatter.h +@@ -14,18 +14,25 @@ struct regmap; + struct snd_soc_dapm_widget; + struct snd_kcontrol; + ++struct axg_tdm_formatter_hw { ++ unsigned int skew_offset; ++ bool invert_sclk; ++}; ++ + struct axg_tdm_formatter_ops { + struct axg_tdm_stream *(*get_stream)(struct snd_soc_dapm_widget *w); + void (*enable)(struct regmap *map); + void (*disable)(struct regmap *map); +- int (*prepare)(struct regmap *map, struct axg_tdm_stream *ts); ++ int (*prepare)(struct regmap *map, ++ const struct axg_tdm_formatter_hw *quirks, ++ struct axg_tdm_stream *ts); + }; + + struct axg_tdm_formatter_driver { + const struct snd_soc_component_driver *component_drv; + const struct regmap_config *regmap_cfg; + const struct axg_tdm_formatter_ops *ops; +- bool invert_sclk; ++ const struct axg_tdm_formatter_hw *quirks; + }; + + int axg_tdm_formatter_set_channel_masks(struct regmap *map, +diff --git a/sound/soc/meson/axg-tdmin.c b/sound/soc/meson/axg-tdmin.c +index bbac44c816886..a790f925a4ef3 100644 +--- a/sound/soc/meson/axg-tdmin.c ++++ b/sound/soc/meson/axg-tdmin.c +@@ -107,21 +107,22 @@ static void axg_tdmin_disable(struct regmap *map) + regmap_update_bits(map, TDMIN_CTRL, TDMIN_CTRL_ENABLE, 0); + } + +-static int axg_tdmin_prepare(struct regmap *map, struct axg_tdm_stream *ts) ++static int axg_tdmin_prepare(struct regmap *map, ++ const struct axg_tdm_formatter_hw *quirks, ++ struct axg_tdm_stream *ts) + { +- unsigned int val = 0; ++ unsigned int val, skew = quirks->skew_offset; + + /* Set stream skew */ + switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_DSP_A: +- val |= TDMIN_CTRL_IN_BIT_SKEW(3); ++ skew += 1; + break; + + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_DSP_B: +- val = TDMIN_CTRL_IN_BIT_SKEW(2); + break; + + default: +@@ -130,6 +131,8 @@ static int axg_tdmin_prepare(struct regmap *map, struct axg_tdm_stream *ts) + return -EINVAL; + } + ++ val = TDMIN_CTRL_IN_BIT_SKEW(skew); ++ + /* Set stream format mode */ + switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: +@@ -204,7 +207,10 @@ static const struct axg_tdm_formatter_driver axg_tdmin_drv = { + .component_drv = &axg_tdmin_component_drv, + .regmap_cfg = &axg_tdmin_regmap_cfg, + .ops = &axg_tdmin_ops, +- .invert_sclk = false, ++ .quirks = &(const struct axg_tdm_formatter_hw) { ++ .invert_sclk = false, ++ .skew_offset = 2, ++ }, + }; + + static const struct of_device_id axg_tdmin_of_match[] = { +diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c +index f73368ee1088f..3984818e2a7cf 100644 +--- a/sound/soc/meson/axg-tdmout.c ++++ b/sound/soc/meson/axg-tdmout.c +@@ -124,21 +124,22 @@ static void axg_tdmout_disable(struct regmap *map) + regmap_update_bits(map, TDMOUT_CTRL0, TDMOUT_CTRL0_ENABLE, 0); + } + +-static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts) ++static int axg_tdmout_prepare(struct regmap *map, ++ const struct axg_tdm_formatter_hw *quirks, ++ struct axg_tdm_stream *ts) + { +- unsigned int val = 0; ++ unsigned int val, skew = quirks->skew_offset; + + /* Set the stream skew */ + switch (ts->iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_DSP_A: +- val |= TDMOUT_CTRL0_INIT_BITNUM(1); + break; + + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + case SND_SOC_DAIFMT_DSP_B: +- val |= TDMOUT_CTRL0_INIT_BITNUM(2); ++ skew += 1; + break; + + default: +@@ -147,6 +148,8 @@ static int axg_tdmout_prepare(struct regmap *map, struct axg_tdm_stream *ts) + return -EINVAL; + } + ++ val = TDMOUT_CTRL0_INIT_BITNUM(skew); ++ + /* Set the slot width */ + val |= TDMOUT_CTRL0_BITNUM(ts->iface->slot_width - 1); + +@@ -234,7 +237,10 @@ static const struct axg_tdm_formatter_driver axg_tdmout_drv = { + .component_drv = &axg_tdmout_component_drv, + .regmap_cfg = &axg_tdmout_regmap_cfg, + .ops = &axg_tdmout_ops, +- .invert_sclk = true, ++ .quirks = &(const struct axg_tdm_formatter_hw) { ++ .invert_sclk = true, ++ .skew_offset = 1, ++ }, + }; + + static const struct of_device_id axg_tdmout_of_match[] = { + +From a100d9ea2b2aaaaf8c8a16582472fd0caf9c0c2e Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 13:17:33 +0200 +Subject: [PATCH 075/249] FROMGIT: ASoC: meson: axg-tdmout: add g12a support + +The axg tdmout driver just need a different skew offset to operate +correctly on the g12a SoC family. + +Signed-off-by: Jerome Brunet +Signed-off-by: Mark Brown +(cherry picked from commit aa191a37b801be6c5abebe77e67dcec7c5c0faee + git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-5.2) +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/axg-tdmout.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/sound/soc/meson/axg-tdmout.c b/sound/soc/meson/axg-tdmout.c +index 3984818e2a7cf..527bfc4487e02 100644 +--- a/sound/soc/meson/axg-tdmout.c ++++ b/sound/soc/meson/axg-tdmout.c +@@ -243,10 +243,23 @@ static const struct axg_tdm_formatter_driver axg_tdmout_drv = { + }, + }; + ++static const struct axg_tdm_formatter_driver g12a_tdmout_drv = { ++ .component_drv = &axg_tdmout_component_drv, ++ .regmap_cfg = &axg_tdmout_regmap_cfg, ++ .ops = &axg_tdmout_ops, ++ .quirks = &(const struct axg_tdm_formatter_hw) { ++ .invert_sclk = true, ++ .skew_offset = 2, ++ }, ++}; ++ + static const struct of_device_id axg_tdmout_of_match[] = { + { + .compatible = "amlogic,axg-tdmout", + .data = &axg_tdmout_drv, ++ }, { ++ .compatible = "amlogic,g12a-tdmout", ++ .data = &g12a_tdmout_drv, + }, {} + }; + MODULE_DEVICE_TABLE(of, axg_tdmout_of_match); + +From ddeda41714235e1959a77f2effd9550f5e8f058c Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 13 Mar 2019 15:10:30 +0100 +Subject: [PATCH 076/249] FROMGIT: dt-bindings: power: amlogic, meson-gx-pwrc: + Add G12A compatible + +The Amlogic G12A has a slighly different Power Control, but uses the +same address space and sysctrl registers. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Signed-off-by: Kevin Hilman +(cherry picked from commit 55d76e83a39d2cba7ed686327498efb386b7e8f7 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + .../devicetree/bindings/power/amlogic,meson-gx-pwrc.txt | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt b/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt +index 1cd050b4054ca..0fdc3dd1125e8 100644 +--- a/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt ++++ b/Documentation/devicetree/bindings/power/amlogic,meson-gx-pwrc.txt +@@ -16,7 +16,9 @@ Device Tree Bindings: + --------------------- + + Required properties: +-- compatible: should be "amlogic,meson-gx-pwrc-vpu" for the Meson GX SoCs ++- compatible: should be one of the following : ++ - "amlogic,meson-gx-pwrc-vpu" for the Meson GX SoCs ++ - "amlogic,meson-g12a-pwrc-vpu" for the Meson G12A SoCs + - #power-domain-cells: should be 0 + - amlogic,hhi-sysctrl: phandle to the HHI sysctrl node + - resets: phandles to the reset lines needed for this power demain sequence + +From 90afb116135299eb312c812307ddbb6b3c8dd9d6 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 11:03:37 +0100 +Subject: [PATCH 077/249] FROMGIT: arm64: dts: meson: g12a: Add SAR ADC node + +This patch adds the SAR ADC controller node. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 820873cf38daaf965b37018028c5cc7015735745 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index d6ca0bbd8f74a..9c666e2a45b0a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -5,6 +5,7 @@ + + #include + #include ++#include + #include + #include + +@@ -290,6 +291,20 @@ + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; ++ ++ saradc: adc@9000 { ++ compatible = "amlogic,meson-g12a-saradc", ++ "amlogic,meson-saradc"; ++ reg = <0x0 0x9000 0x0 0x48>; ++ #io-channel-cells = <1>; ++ interrupts = ; ++ clocks = <&xtal>, ++ <&clkc_AO CLKID_AO_SAR_ADC>, ++ <&clkc_AO CLKID_AO_SAR_ADC_CLK>, ++ <&clkc_AO CLKID_AO_SAR_ADC_SEL>; ++ clock-names = "clkin", "core", "adc_clk", "adc_sel"; ++ status = "disabled"; ++ }; + }; + + gic: interrupt-controller@ffc01000 { + +From 45d610803e08336acf7f831114714cc8b363b0d9 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 11:03:38 +0100 +Subject: [PATCH 078/249] FROMGIT: arm64: dts: meson: g12a: Add G12A USB nodes + +This patch adds the nodes for the USB Complex found in the Amlogic +G12A SoC. + +It includes the : +- 2 USB2 PHYs +- 1 USB3 + PCIE Combo PHY +- the USB Glue with it's DWC2 and DWC3 sub-nodes + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 9baf7d6be730cbd996eb56d6047ff1d5147cbff0 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 75 +++++++++++++++++++++ + 1 file changed, 75 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 9c666e2a45b0a..d4dc1a6caab50 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -3,11 +3,13 @@ + * Copyright (c) 2018 Amlogic, Inc. All rights reserved. + */ + ++#include + #include + #include + #include + #include + #include ++#include + + / { + compatible = "amlogic,g12a"; +@@ -183,6 +185,26 @@ + }; + }; + ++ usb2_phy0: phy@36000 { ++ compatible = "amlogic,g12a-usb2-phy"; ++ reg = <0x0 0x36000 0x0 0x2000>; ++ clocks = <&xtal>; ++ clock-names = "xtal"; ++ resets = <&reset RESET_USB_PHY20>; ++ reset-names = "phy"; ++ #phy-cells = <0>; ++ }; ++ ++ usb2_phy1: phy@3a000 { ++ compatible = "amlogic,g12a-usb2-phy"; ++ reg = <0x0 0x3a000 0x0 0x2000>; ++ clocks = <&xtal>; ++ clock-names = "xtal"; ++ resets = <&reset RESET_USB_PHY21>; ++ reset-names = "phy"; ++ #phy-cells = <0>; ++ }; ++ + hiu: bus@3c000 { + compatible = "simple-bus"; + reg = <0x0 0x3c000 0x0 0x1400>; +@@ -203,6 +225,18 @@ + }; + }; + }; ++ ++ usb3_pcie_phy: phy@46000 { ++ compatible = "amlogic,g12a-usb3-pcie-phy"; ++ reg = <0x0 0x46000 0x0 0x2000>; ++ clocks = <&clkc CLKID_PCIE_PLL>; ++ clock-names = "ref_clk"; ++ resets = <&reset RESET_PCIE_PHY>; ++ reset-names = "phy"; ++ assigned-clocks = <&clkc CLKID_PCIE_PLL>; ++ assigned-clock-rates = <100000000>; ++ #phy-cells = <1>; ++ }; + }; + + aobus: bus@ff800000 { +@@ -366,6 +400,47 @@ + status = "disabled"; + }; + }; ++ ++ usb: usb@ffe09000 { ++ status = "disabled"; ++ compatible = "amlogic,meson-g12a-usb-ctrl"; ++ reg = <0x0 0xffe09000 0x0 0xa0>; ++ interrupts = ; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ clocks = <&clkc CLKID_USB>; ++ resets = <&reset RESET_USB>; ++ ++ dr_mode = "otg"; ++ ++ phys = <&usb2_phy0>, <&usb2_phy1>, ++ <&usb3_pcie_phy PHY_TYPE_USB3>; ++ phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; ++ ++ dwc2: usb@ff400000 { ++ compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; ++ reg = <0x0 0xff400000 0x0 0x40000>; ++ interrupts = ; ++ clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; ++ clock-names = "ddr"; ++ phys = <&usb2_phy1>; ++ dr_mode = "peripheral"; ++ g-rx-fifo-size = <192>; ++ g-np-tx-fifo-size = <128>; ++ g-tx-fifo-size = <128 128 16 16 16>; ++ }; ++ ++ dwc3: usb@ff500000 { ++ compatible = "snps,dwc3"; ++ reg = <0x0 0xff500000 0x0 0x100000>; ++ interrupts = ; ++ dr_mode = "host"; ++ snps,dis_u2_susphy_quirk; ++ snps,quirk-frame-length-adjustment; ++ }; ++ }; + }; + + timer { + +From e32830e48024d722be800777e6d3a83c6e636da6 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 11:03:39 +0100 +Subject: [PATCH 079/249] FROMGIT: arm64: dts: meson: g12a: Add mali-g31 gpu + node + +This patch adds the ARM Mali G31 GPU node. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 2607fd087370777fd2ae2ff7c1681fe1fb02566d + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 27 +++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index d4dc1a6caab50..858ddd68665c9 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -441,6 +441,33 @@ + snps,quirk-frame-length-adjustment; + }; + }; ++ ++ mali: gpu@ffe40000 { ++ compatible = "amlogic,meson-g12a-mali", "arm,mali-bifrost"; ++ reg = <0x0 0xffe40000 0x0 0x40000>; ++ interrupt-parent = <&gic>; ++ interrupts = , ++ , ++ ; ++ interrupt-names = "gpu", "mmu", "job"; ++ clocks = <&clkc CLKID_MALI>; ++ resets = <&reset RESET_DVALIN_CAPB3>, <&reset RESET_DVALIN>; ++ ++ /* ++ * Mali clocking is provided by two identical clock paths ++ * MALI_0 and MALI_1 muxed to a single clock by a glitch ++ * free mux to safely change frequency while running. ++ */ ++ assigned-clocks = <&clkc CLKID_MALI_0_SEL>, ++ <&clkc CLKID_MALI_0>, ++ <&clkc CLKID_MALI>; /* Glitch free mux */ ++ assigned-clock-parents = <&clkc CLKID_FCLK_DIV2P5>, ++ <0>, /* Do Nothing */ ++ <&clkc CLKID_MALI_0>; ++ assigned-clock-rates = <0>, /* Do Nothing */ ++ <800000000>, ++ <0>; /* Do Nothing */ ++ }; + }; + + timer { + +From d8aea2c7f9f8400f299ea9d81defc796e17cf542 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 18 Mar 2019 11:04:51 +0100 +Subject: [PATCH 080/249] FROMGIT: arm64: dts: meson-g12a-u200: add regulators + +Add system regulators for the S905D U200 reference design. + +Add some regulators. Still missing +* VDD_EE (0.8V - PWM controlled) +* VDD_CPU (PWM controlled) + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +Acked-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit aa77657b018fbd0eebfc78ee3f8b07fec4f5cda7 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + .../boot/dts/amlogic/meson-g12a-u200.dts | 79 +++++++++++++++++++ + 1 file changed, 79 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index f2afd0bf3e28b..c69328d163337 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -6,6 +6,8 @@ + /dts-v1/; + + #include "meson-g12a.dtsi" ++#include ++#include + + / { + compatible = "amlogic,u200", "amlogic,g12a"; +@@ -21,6 +23,83 @@ + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; + }; ++ ++ flash_1v8: regulator-flash_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "FLASH_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ main_12v: regulator-main_12v { ++ compatible = "regulator-fixed"; ++ regulator-name = "12V"; ++ regulator-min-microvolt = <12000000>; ++ regulator-max-microvolt = <12000000>; ++ regulator-always-on; ++ }; ++ ++ vcc_1v8: regulator-vcc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ /* FIXME: actually controlled by VDDCPU_B_EN */ ++ }; ++ ++ vcc_5v: regulator-vcc_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&main_12v>; ++ ++ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; ++ enable-active-high; ++ }; ++ ++ 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>; ++ ++ gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ 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; ++ }; ++ ++ vddao_3v3: regulator-vddao_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&main_12v>; ++ regulator-always-on; ++ }; ++ + }; + + &uart_AO { + +From f3888b33e14cfb4c288f096cf45a30a656d17e15 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 11:14:50 +0100 +Subject: [PATCH 081/249] FROMGIT: arm64: dts: meson-g12a-sei510: Add ADC Key + and BT support + +Add support for the : +- ADC Touch key +- Bluetooth Module on UART A + +Signed-off-by: Neil Armstrong +Acked-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit d1c023af198835833203f64160d3aefe1fbb45e8 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 30 +++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 43d57e20294a0..ebdad5a192f1c 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -7,6 +7,7 @@ + + #include "meson-g12a.dtsi" + #include ++#include + #include + + / { +@@ -17,6 +18,19 @@ + serial0 = &uart_AO; + }; + ++ adc_keys { ++ compatible = "adc-keys"; ++ io-channels = <&saradc 0>; ++ io-channel-names = "buttons"; ++ keyup-threshold-microvolt = <1800000>; ++ ++ button-onoff { ++ label = "On/Off"; ++ linux,code = ; ++ press-threshold-microvolt = <1700000>; ++ }; ++ }; ++ + ao_5v: regulator-ao_5v { + compatible = "regulator-fixed"; + regulator-name = "AO_5V"; +@@ -87,7 +101,23 @@ + vin-supply = <&vddao_3v3>; + regulator-always-on; + }; ++}; ++ ++&saradc { ++ status = "okay"; ++ vref-supply = <&vddio_ao1v8>; ++}; ++ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; + ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ }; + }; + + &uart_AO { + +From 81bdbeb60217f55e1996331909b01bb53d26db0b Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 11:14:51 +0100 +Subject: [PATCH 082/249] FROMGIT: arm64: dts: meson-g12a-sei510: Enable USB + +Enable the USB2 and USB3 Host ports on the SEI520 Set-Top-Box. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 41cc4551f45470c6052c84615af81873122cf158 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index ebdad5a192f1c..c350a0165d447 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -125,3 +125,8 @@ + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; + }; ++ ++&usb { ++ status = "okay"; ++ dr_mode = "host"; ++}; + +From 97b5ad85d2c4b2209423e7dc7187855fc3155dd7 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 11:14:52 +0100 +Subject: [PATCH 083/249] FROMGIT: arm64: dts: meson-g12a-u200: Enable USB + +Enable the USB2 OTG and USB3 Host ports on the S905D2 Reference Design. + +Signed-off-by: Neil Armstrong +Acked-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 8ad7624453cf1c6788b726e51727a2c7c4f7abd3 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index c69328d163337..2240e365af27e 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -108,3 +108,15 @@ + pinctrl-names = "default"; + }; + ++&usb { ++ status = "okay"; ++ vbus-supply = <&usb_pwr_en>; ++}; ++ ++&usb2_phy0 { ++ phy-supply = <&vcc_5v>; ++}; ++ ++&usb2_phy1 { ++ phy-supply = <&vcc_5v>; ++}; + +From 8427322c45ac90aa04a8c5fbed25dcd6a9e98b08 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 25 Mar 2019 11:14:53 +0100 +Subject: [PATCH 084/249] FROMGIT: arm64: dts: meson-g12a-x96-max: Enable USB + +Enable the USB2 and USB3 Host ports on the X96 Max Set-Top-Box. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Kevin Hilman +(cherry picked from commit 45b72126022923ebdcd9f9b58af1ff47f73452fa + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 0a6919523ba94..b5b88262c06a3 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -107,3 +107,8 @@ + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; + }; ++ ++&usb { ++ status = "okay"; ++ dr_mode = "host"; ++}; + +From 5863c32f2d98803eecb3d386f392300ddb061e3b Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 8 Apr 2019 11:31:35 +0200 +Subject: [PATCH 085/249] FROMGIT: arm64: dts: meson-g12a: Add VPU and HDMI + related nodes + +Add VPU and HDMI display support. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 083feecd854833dcee8f1e98d7197195f5fd3649 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 131 ++++++++++++++++++++ + 1 file changed, 131 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 858ddd68665c9..a696612f8f442 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -109,6 +109,37 @@ + #size-cells = <2>; + ranges = <0x0 0x0 0x0 0xff600000 0x0 0x200000>; + ++ hdmi_tx: hdmi-tx@0 { ++ compatible = "amlogic,meson-g12a-dw-hdmi"; ++ reg = <0x0 0x0 0x0 0x10000>; ++ interrupts = ; ++ resets = <&reset RESET_HDMITX_CAPB3>, ++ <&reset RESET_HDMITX_PHY>, ++ <&reset RESET_HDMITX>; ++ reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy"; ++ clocks = <&clkc CLKID_HDMI>, ++ <&clkc CLKID_HTX_PCLK>, ++ <&clkc CLKID_VPU_INTR>; ++ clock-names = "isfr", "iahb", "venci"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "disabled"; ++ ++ /* VPU VENC Input */ ++ hdmi_tx_venc_port: port@0 { ++ reg = <0>; ++ ++ hdmi_tx_in: endpoint { ++ remote-endpoint = <&hdmi_tx_out>; ++ }; ++ }; ++ ++ /* TMDS Output */ ++ hdmi_tx_tmds_port: port@1 { ++ reg = <1>; ++ }; ++ }; ++ + periphs: bus@34400 { + compatible = "simple-bus"; + reg = <0x0 0x34400 0x0 0x400>; +@@ -138,6 +169,23 @@ + gpio-ranges = <&periphs_pinctrl 0 0 86>; + }; + ++ hdmitx_ddc_pins: hdmitx_ddc { ++ mux { ++ groups = "hdmitx_sda", ++ "hdmitx_sck"; ++ function = "hdmitx"; ++ bias-disable; ++ }; ++ }; ++ ++ hdmitx_hpd_pins: hdmitx_hpd { ++ mux { ++ groups = "hdmitx_hpd_in"; ++ function = "hdmitx"; ++ bias-disable; ++ }; ++ }; ++ + uart_a_pins: uart-a { + mux { + groups = "uart_a_tx", +@@ -195,6 +243,19 @@ + #phy-cells = <0>; + }; + ++ dmc: bus@38000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0x38000 0x0 0x400>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x38000 0x0 0x400>; ++ ++ canvas: video-lut@48 { ++ compatible = "amlogic,canvas"; ++ reg = <0x0 0x48 0x0 0x14>; ++ }; ++ }; ++ + usb2_phy1: phy@3a000 { + compatible = "amlogic,g12a-usb2-phy"; + reg = <0x0 0x3a000 0x0 0x2000>; +@@ -262,6 +323,50 @@ + clock-names = "xtal", "mpeg-clk"; + }; + ++ pwrc_vpu: power-controller-vpu { ++ compatible = "amlogic,meson-g12a-pwrc-vpu"; ++ #power-domain-cells = <0>; ++ amlogic,hhi-sysctrl = <&hhi>; ++ resets = <&reset RESET_VIU>, ++ <&reset RESET_VENC>, ++ <&reset RESET_VCBUS>, ++ <&reset RESET_BT656>, ++ <&reset RESET_RDMA>, ++ <&reset RESET_VENCI>, ++ <&reset RESET_VENCP>, ++ <&reset RESET_VDAC>, ++ <&reset RESET_VDI6>, ++ <&reset RESET_VENCL>, ++ <&reset RESET_VID_LOCK>; ++ clocks = <&clkc CLKID_VPU>, ++ <&clkc CLKID_VAPB>; ++ clock-names = "vpu", "vapb"; ++ /* ++ * VPU clocking is provided by two identical clock paths ++ * VPU_0 and VPU_1 muxed to a single clock by a glitch ++ * free mux to safely change frequency while running. ++ * Same for VAPB but with a final gate after the glitch free mux. ++ */ ++ assigned-clocks = <&clkc CLKID_VPU_0_SEL>, ++ <&clkc CLKID_VPU_0>, ++ <&clkc CLKID_VPU>, /* Glitch free mux */ ++ <&clkc CLKID_VAPB_0_SEL>, ++ <&clkc CLKID_VAPB_0>, ++ <&clkc CLKID_VAPB_SEL>; /* Glitch free mux */ ++ assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, ++ <0>, /* Do Nothing */ ++ <&clkc CLKID_VPU_0>, ++ <&clkc CLKID_FCLK_DIV4>, ++ <0>, /* Do Nothing */ ++ <&clkc CLKID_VAPB_0>; ++ assigned-clock-rates = <0>, /* Do Nothing */ ++ <666666666>, ++ <0>, /* Do Nothing */ ++ <0>, /* Do Nothing */ ++ <250000000>, ++ <0>; /* Do Nothing */ ++ }; ++ + ao_pinctrl: pinctrl@14 { + compatible = "amlogic,meson-g12a-aobus-pinctrl"; + #address-cells = <2>; +@@ -341,6 +446,32 @@ + }; + }; + ++ vpu: vpu@ff900000 { ++ compatible = "amlogic,meson-g12a-vpu"; ++ reg = <0x0 0xff900000 0x0 0x100000>, ++ <0x0 0xff63c000 0x0 0x1000>; ++ reg-names = "vpu", "hhi"; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ amlogic,canvas = <&canvas>; ++ power-domains = <&pwrc_vpu>; ++ ++ /* CVBS VDAC output port */ ++ cvbs_vdac_port: port@0 { ++ reg = <0>; ++ }; ++ ++ /* HDMI-TX output port */ ++ hdmi_tx_port: port@1 { ++ reg = <1>; ++ ++ hdmi_tx_out: endpoint { ++ remote-endpoint = <&hdmi_tx_in>; ++ }; ++ }; ++ }; ++ + gic: interrupt-controller@ffc01000 { + compatible = "arm,gic-400"; + reg = <0x0 0xffc01000 0 0x1000>, + +From 625b73d78138030e6fbb84f2595ec4c4b90e2212 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 8 Apr 2019 11:31:36 +0200 +Subject: [PATCH 086/249] FROMGIT: arm64: dts: meson-g12a: Add AO-CEC nodes + +Amlogic G12A embeds 2 CEC controllers : +- AO-CEC-A the same controller as in GXBB, GXL & GXM SoCs +- AO-CEC-B is a new controller + +Note, the two controller can work simultanously since 2 Pads can +handle CEC, thus this SoC can handle 2 distinct CEC busses. + +This patch adds the nodes for the AO-CEC-A and AO-CEC-B controllers. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 91516e5419cf91947213b4d9c62b4728701063e9 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 34 +++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index a696612f8f442..9f72396ba7103 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -169,6 +169,22 @@ + gpio-ranges = <&periphs_pinctrl 0 0 86>; + }; + ++ cec_ao_a_h_pins: cec_ao_a_h { ++ mux { ++ groups = "cec_ao_a_h"; ++ function = "cec_ao_a_h"; ++ bias-disable; ++ }; ++ }; ++ ++ cec_ao_b_h_pins: cec_ao_b_h { ++ mux { ++ groups = "cec_ao_b_h"; ++ function = "cec_ao_b_h"; ++ bias-disable; ++ }; ++ }; ++ + hdmitx_ddc_pins: hdmitx_ddc { + mux { + groups = "hdmitx_sda", +@@ -405,12 +421,30 @@ + }; + }; + ++ cec_AO: cec@100 { ++ compatible = "amlogic,meson-gx-ao-cec"; ++ reg = <0x0 0x00100 0x0 0x14>; ++ interrupts = ; ++ clocks = <&clkc_AO CLKID_AO_CEC>; ++ clock-names = "core"; ++ status = "disabled"; ++ }; ++ + sec_AO: ao-secure@140 { + compatible = "amlogic,meson-gx-ao-secure", "syscon"; + reg = <0x0 0x140 0x0 0x140>; + amlogic,has-chip-id; + }; + ++ cecb_AO: cec@280 { ++ compatible = "amlogic,meson-g12a-ao-cec"; ++ reg = <0x0 0x00280 0x0 0x1c>; ++ interrupts = ; ++ clocks = <&clkc_AO CLKID_AO_CTS_OSCIN>; ++ clock-names = "oscin"; ++ status = "disabled"; ++ }; ++ + uart_AO: serial@3000 { + compatible = "amlogic,meson-gx-uart", + "amlogic,meson-ao-uart"; + +From ea29362ac5d2a99cb60dc4712049052c206044ba Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 8 Apr 2019 11:31:37 +0200 +Subject: [PATCH 087/249] FROMGIT: arm64: dts: meson-g12a-x96-max: Add support + for Video Display + +This patch adds the HDMI, CVBS and CEC attributes and nodes to support +full display on the X96 Max STB. + +AO-CEC-B is used by default and AO-CEC-A is disabled. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit b0be96160a55701af4748bcebbe0cd5fb7aec697 + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + .../boot/dts/amlogic/meson-g12a-x96-max.dts | 54 +++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index b5b88262c06a3..b3d913f28f121 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -24,6 +24,27 @@ + reg = <0x0 0x0 0x0 0x40000000>; + }; + ++ cvbs-connector { ++ compatible = "composite-video-connector"; ++ ++ port { ++ cvbs_connector_in: endpoint { ++ remote-endpoint = <&cvbs_vdac_out>; ++ }; ++ }; ++ }; ++ ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ + flash_1v8: regulator-flash_1v8 { + compatible = "regulator-fixed"; + regulator-name = "FLASH_1V8"; +@@ -90,6 +111,39 @@ + }; + }; + ++&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>; ++}; ++ ++&cvbs_vdac_port { ++ cvbs_vdac_out: endpoint { ++ remote-endpoint = <&cvbs_connector_in>; ++ }; ++}; ++ ++&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>; ++ }; ++}; ++ + &uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + +From f0cf87ede64f379eb27d5a8cb6db7cca1692fcd6 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 8 Apr 2019 11:31:38 +0200 +Subject: [PATCH 088/249] FROMGIT: arm64: dts: meson-g12a-sei510: Add support + for Video Display + +This patch adds the HDMI, CVBS and CEC attributes and nodes to support +full display on the SEI510 STB. + +AO-CEC-B is used by default and AO-CEC-A is disabled. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 912a3395df3a80fe789ebc406e595314ebefc45e + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 53 +++++++++++++++++++ + 1 file changed, 53 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index c350a0165d447..34b40587e5ef1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -44,6 +44,16 @@ + stdout-path = "serial0:115200n8"; + }; + ++ cvbs-connector { ++ compatible = "composite-video-connector"; ++ ++ port { ++ cvbs_connector_in: endpoint { ++ remote-endpoint = <&cvbs_vdac_out>; ++ }; ++ }; ++ }; ++ + dc_in: regulator-dc_in { + compatible = "regulator-fixed"; + regulator-name = "DC_IN"; +@@ -61,6 +71,17 @@ + regulator-always-on; + }; + ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ + memory@0 { + device_type = "memory"; + reg = <0x0 0x0 0x0 0x40000000>; +@@ -103,6 +124,26 @@ + }; + }; + ++&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>; ++}; ++ ++&cvbs_vdac_port { ++ cvbs_vdac_out: endpoint { ++ remote-endpoint = <&cvbs_connector_in>; ++ }; ++}; ++ + &saradc { + status = "okay"; + vref-supply = <&vddio_ao1v8>; +@@ -120,6 +161,18 @@ + }; + }; + ++&hdmi_tx { ++ status = "okay"; ++ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&hdmi_tx_tmds_port { ++ hdmi_tx_tmds_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++}; ++ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + +From 68e5a972d2af554c10e53515e70d804e4f34ebfb Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 8 Apr 2019 11:31:39 +0200 +Subject: [PATCH 089/249] FROMGIT: arm64: dts: meson-g12a-u200: Add support for + Video Display + +This patch adds the HDMI, CVBS and CEC attributes and nodes to support +full display on the U200 Reference Design. + +AO-CEC-B is used by default and AO-CEC-A is disabled. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 659f2563d323b09ca12b0e70bb6a50c1b25af3ee + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/dt64) +--- + .../boot/dts/amlogic/meson-g12a-u200.dts | 54 +++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index 2240e365af27e..0e8045b8a9158 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -24,6 +24,16 @@ + reg = <0x0 0x0 0x0 0x40000000>; + }; + ++ cvbs-connector { ++ compatible = "composite-video-connector"; ++ ++ port { ++ cvbs_connector_in: endpoint { ++ remote-endpoint = <&cvbs_vdac_out>; ++ }; ++ }; ++ }; ++ + flash_1v8: regulator-flash_1v8 { + compatible = "regulator-fixed"; + regulator-name = "FLASH_1V8"; +@@ -33,6 +43,17 @@ + regulator-always-on; + }; + ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ + main_12v: regulator-main_12v { + compatible = "regulator-fixed"; + regulator-name = "12V"; +@@ -102,6 +123,39 @@ + + }; + ++&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>; ++}; ++ ++&cvbs_vdac_port { ++ cvbs_vdac_out: endpoint { ++ remote-endpoint = <&cvbs_connector_in>; ++ }; ++}; ++ ++&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>; ++ }; ++}; ++ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + +From 39bfd6c05de42e7a941e0363361aca9e34056d3d Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 1 Apr 2019 09:48:01 +0200 +Subject: [PATCH 090/249] FROMGIT: soc: amlogic: meson-gx-pwrc-vpu: Fix power + on/off register bitmask + +The register bitmask to power on/off the VPU memories was incorectly set +to 0x2 instead of 0x3. While still working, let's use the recommended +vendor value instead. + +Fixes: 75fcb5ca4b46 ("soc: amlogic: add Meson GX VPU Domains driver") +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit 2fe3b4bbc93ec30a173ebae7d2b8c530416df3af + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) +--- + drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +index 6289965c42e98..05421d029dff9 100644 +--- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c ++++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +@@ -54,12 +54,12 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) + /* Power Down Memories */ + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, +- 0x2 << i, 0x3 << i); ++ 0x3 << i, 0x3 << i); + udelay(5); + } + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, +- 0x2 << i, 0x3 << i); ++ 0x3 << i, 0x3 << i); + udelay(5); + } + for (i = 8; i < 16; i++) { +@@ -108,13 +108,13 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) + /* Power Up Memories */ + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, +- 0x2 << i, 0); ++ 0x3 << i, 0); + udelay(5); + } + + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, +- 0x2 << i, 0); ++ 0x3 << i, 0); + udelay(5); + } + + +From 67456f6b7894b0a9a6c1b430349c88787391be28 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 1 Apr 2019 09:52:58 +0200 +Subject: [PATCH 091/249] FROMGIT: soc: amlogic: meson-gx-pwrc-vpu: Add support + for G12A + +The Amlogic G12A SoC has a very similar VPU Power Controller setup +than the older GXBB, GXL & GXm SoCs. + +This patch adds the variant support for G12A. + +Signed-off-by: Neil Armstrong +Signed-off-by: Kevin Hilman +(cherry picked from commit bb1dca3a3900a00b881286c96340d6ab85eafe0c + git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git v5.2/drivers) +--- + drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 152 ++++++++++++++++++++++-- + 1 file changed, 140 insertions(+), 12 deletions(-) + +diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +index 05421d029dff9..511b6856225d6 100644 +--- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c ++++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -26,6 +27,7 @@ + #define HHI_MEM_PD_REG0 (0x40 << 2) + #define HHI_VPU_MEM_PD_REG0 (0x41 << 2) + #define HHI_VPU_MEM_PD_REG1 (0x42 << 2) ++#define HHI_VPU_MEM_PD_REG2 (0x4d << 2) + + struct meson_gx_pwrc_vpu { + struct generic_pm_domain genpd; +@@ -80,6 +82,49 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) + return 0; + } + ++static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd) ++{ ++ struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); ++ int i; ++ ++ regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); ++ udelay(20); ++ ++ /* Power Down Memories */ ++ for (i = 0; i < 32; i += 2) { ++ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, ++ 0x3 << i, 0x3 << i); ++ udelay(5); ++ } ++ for (i = 0; i < 32; i += 2) { ++ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, ++ 0x3 << i, 0x3 << i); ++ udelay(5); ++ } ++ for (i = 0; i < 32; i += 2) { ++ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, ++ 0x3 << i, 0x3 << i); ++ udelay(5); ++ } ++ for (i = 8; i < 16; i++) { ++ regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, ++ BIT(i), BIT(i)); ++ udelay(5); ++ } ++ udelay(20); ++ ++ regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); ++ ++ msleep(20); ++ ++ clk_disable_unprepare(pd->vpu_clk); ++ clk_disable_unprepare(pd->vapb_clk); ++ ++ return 0; ++} ++ + static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd) + { + int ret; +@@ -143,6 +188,60 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) + return 0; + } + ++static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd) ++{ ++ struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); ++ int ret; ++ int i; ++ ++ regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VPU_HDMI, 0); ++ udelay(20); ++ ++ /* Power Up Memories */ ++ for (i = 0; i < 32; i += 2) { ++ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, ++ 0x3 << i, 0); ++ udelay(5); ++ } ++ ++ for (i = 0; i < 32; i += 2) { ++ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, ++ 0x3 << i, 0); ++ udelay(5); ++ } ++ ++ for (i = 0; i < 32; i += 2) { ++ regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, ++ 0x3 << i, 0); ++ udelay(5); ++ } ++ ++ for (i = 8; i < 16; i++) { ++ regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, ++ BIT(i), 0); ++ udelay(5); ++ } ++ udelay(20); ++ ++ ret = reset_control_assert(pd->rstc); ++ if (ret) ++ return ret; ++ ++ regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VPU_HDMI_ISO, 0); ++ ++ ret = reset_control_deassert(pd->rstc); ++ if (ret) ++ return ret; ++ ++ ret = meson_gx_pwrc_vpu_setup_clk(pd); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ + static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd) + { + u32 reg; +@@ -160,15 +259,37 @@ static struct meson_gx_pwrc_vpu vpu_hdmi_pd = { + }, + }; + ++static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = { ++ .genpd = { ++ .name = "vpu_hdmi", ++ .power_off = meson_g12a_pwrc_vpu_power_off, ++ .power_on = meson_g12a_pwrc_vpu_power_on, ++ }, ++}; ++ + static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) + { ++ const struct meson_gx_pwrc_vpu *vpu_pd_match; + struct regmap *regmap_ao, *regmap_hhi; ++ struct meson_gx_pwrc_vpu *vpu_pd; + struct reset_control *rstc; + struct clk *vpu_clk; + struct clk *vapb_clk; + bool powered_off; + int ret; + ++ vpu_pd_match = of_device_get_match_data(&pdev->dev); ++ if (!vpu_pd_match) { ++ dev_err(&pdev->dev, "failed to get match data\n"); ++ return -ENODEV; ++ } ++ ++ vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL); ++ if (!vpu_pd) ++ return -ENOMEM; ++ ++ memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd)); ++ + regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node)); + if (IS_ERR(regmap_ao)) { + dev_err(&pdev->dev, "failed to get regmap\n"); +@@ -201,39 +322,46 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) + return PTR_ERR(vapb_clk); + } + +- vpu_hdmi_pd.regmap_ao = regmap_ao; +- vpu_hdmi_pd.regmap_hhi = regmap_hhi; +- vpu_hdmi_pd.rstc = rstc; +- vpu_hdmi_pd.vpu_clk = vpu_clk; +- vpu_hdmi_pd.vapb_clk = vapb_clk; ++ vpu_pd->regmap_ao = regmap_ao; ++ vpu_pd->regmap_hhi = regmap_hhi; ++ vpu_pd->rstc = rstc; ++ vpu_pd->vpu_clk = vpu_clk; ++ vpu_pd->vapb_clk = vapb_clk; ++ ++ platform_set_drvdata(pdev, vpu_pd); + +- powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd); ++ powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); + + /* If already powered, sync the clock states */ + if (!powered_off) { +- ret = meson_gx_pwrc_vpu_setup_clk(&vpu_hdmi_pd); ++ ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd); + if (ret) + return ret; + } + +- pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov, ++ pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov, + powered_off); + + return of_genpd_add_provider_simple(pdev->dev.of_node, +- &vpu_hdmi_pd.genpd); ++ &vpu_pd->genpd); + } + + static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev) + { ++ struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev); + bool powered_off; + +- powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd); ++ powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); + if (!powered_off) +- meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd); ++ vpu_pd->genpd.power_off(&vpu_pd->genpd); + } + + static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = { +- { .compatible = "amlogic,meson-gx-pwrc-vpu" }, ++ { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd }, ++ { ++ .compatible = "amlogic,meson-g12a-pwrc-vpu", ++ .data = &vpu_hdmi_pd_g12a ++ }, + { /* sentinel */ } + }; + + +From d860e5a85b15d603d5bba033246e7e2ef46cd56f Mon Sep 17 00:00:00 2001 +From: Hans Verkuil +Date: Wed, 10 Apr 2019 05:13:28 -0400 +Subject: [PATCH 092/249] FROMGIT: media: cec-notifier: add + cec_notifier_parse_hdmi_phandle helper + +Add helper function to parse the DT for the hdmi-phandle property +and return the corresponding struct device pointer. + +It takes care to avoid increasing the device refcount since all +we need is the device pointer. This pointer is used in the +notifier list as a key, but it is never accessed by the CEC driver. + +Signed-off-by: Hans Verkuil +Reported-by: Wen Yang +Acked-by: Wen Yang +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit fbbd403b3286b4467f8b755efa0f10819cef9bba + git://linuxtv.org/media_tree.git master) +--- + drivers/media/cec/cec-notifier.c | 30 ++++++++++++++++++++++++++++++ + include/media/cec-notifier.h | 19 ++++++++++++++++++- + 2 files changed, 48 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c +index dd2078b27a419..9598c7778871a 100644 +--- a/drivers/media/cec/cec-notifier.c ++++ b/drivers/media/cec/cec-notifier.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -127,3 +128,32 @@ void cec_notifier_unregister(struct cec_notifier *n) + cec_notifier_put(n); + } + EXPORT_SYMBOL_GPL(cec_notifier_unregister); ++ ++struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) ++{ ++ struct platform_device *hdmi_pdev; ++ struct device *hdmi_dev = NULL; ++ struct device_node *np; ++ ++ np = of_parse_phandle(dev->of_node, "hdmi-phandle", 0); ++ ++ if (!np) { ++ dev_err(dev, "Failed to find HDMI node in device tree\n"); ++ return ERR_PTR(-ENODEV); ++ } ++ hdmi_pdev = of_find_device_by_node(np); ++ of_node_put(np); ++ if (hdmi_pdev) { ++ hdmi_dev = &hdmi_pdev->dev; ++ /* ++ * Note that the device struct is only used as a key into the ++ * cec_notifiers list, it is never actually accessed. ++ * So we decrement the reference here so we don't leak ++ * memory. ++ */ ++ put_device(hdmi_dev); ++ return hdmi_dev; ++ } ++ return ERR_PTR(-EPROBE_DEFER); ++} ++EXPORT_SYMBOL_GPL(cec_notifier_parse_hdmi_phandle); +diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h +index 814eeef35a5cf..57b3a9f6ea1d5 100644 +--- a/include/media/cec-notifier.h ++++ b/include/media/cec-notifier.h +@@ -9,7 +9,7 @@ + #ifndef LINUX_CEC_NOTIFIER_H + #define LINUX_CEC_NOTIFIER_H + +-#include ++#include + #include + + struct device; +@@ -87,6 +87,17 @@ void cec_notifier_unregister(struct cec_notifier *n); + void cec_register_cec_notifier(struct cec_adapter *adap, + struct cec_notifier *notifier); + ++/** ++ * cec_notifier_parse_hdmi_phandle - find the hdmi device from "hdmi-phandle" ++ * @dev: the device with the "hdmi-phandle" device tree property ++ * ++ * Returns the device pointer referenced by the "hdmi-phandle" property. ++ * Note that the refcount of the returned device is not incremented. ++ * This device pointer is only used as a key value in the notifier ++ * list, but it is never accessed by the CEC driver. ++ */ ++struct device *cec_notifier_parse_hdmi_phandle(struct device *dev); ++ + #else + static inline struct cec_notifier *cec_notifier_get_conn(struct device *dev, + const char *conn) +@@ -122,6 +133,12 @@ static inline void cec_register_cec_notifier(struct cec_adapter *adap, + struct cec_notifier *notifier) + { + } ++ ++static inline struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) ++{ ++ return ERR_PTR(-ENODEV); ++} ++ + #endif + + /** + +From 8d922af065e8a8cfcb67308276b4def00177c3d4 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 12 Apr 2019 04:30:58 -0400 +Subject: [PATCH 093/249] FROMGIT: media: dt-bindings: media: meson-ao-cec: Add + G12A AO-CEC-B Compatible + +The Amlogic G12A embeds a second CEC controller named AO-CEC-B, and +the other one is AO-CEC-A described by the current bindings. + +The register interface is very close but the internal architecture +is totally different. + +The other difference is the clock source, the AO-CEC-B takes the +"oscin", the Always-On Oscillator clock, as input and embeds a +dual-divider clock divider to provide the precise 32768Hz base +clock for CEC communication. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 3473ba384de7cf5df33f0ea3650aa4c7aaf1c995 + git://linuxtv.org/media_tree.git master) +--- + .../devicetree/bindings/media/meson-ao-cec.txt | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/Documentation/devicetree/bindings/media/meson-ao-cec.txt b/Documentation/devicetree/bindings/media/meson-ao-cec.txt +index 8671bdb08080e..c67fc41d4aa23 100644 +--- a/Documentation/devicetree/bindings/media/meson-ao-cec.txt ++++ b/Documentation/devicetree/bindings/media/meson-ao-cec.txt +@@ -4,16 +4,23 @@ The Amlogic Meson AO-CEC module is present is Amlogic SoCs and its purpose is + to handle communication between HDMI connected devices over the CEC bus. + + Required properties: +- - compatible : value should be following ++ - compatible : value should be following depending on the SoC : ++ For GXBB, GXL, GXM and G12A (AO_CEC_A module) : + "amlogic,meson-gx-ao-cec" ++ For G12A (AO_CEC_B module) : ++ "amlogic,meson-g12a-ao-cec" + + - reg : Physical base address of the IP registers and length of memory + mapped region. + + - interrupts : AO-CEC interrupt number to the CPU. + - clocks : from common clock binding: handle to AO-CEC clock. +- - clock-names : from common clock binding: must contain "core", +- corresponding to entry in the clocks property. ++ - clock-names : from common clock binding, must contain : ++ For GXBB, GXL, GXM and G12A (AO_CEC_A module) : ++ - "core" ++ For G12A (AO_CEC_B module) : ++ - "oscin" ++ corresponding to entry in the clocks property. + - hdmi-phandle: phandle to the HDMI controller + + Example: + +From 64ebd1eed771d48cb81357a8ae3977978f342e81 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 12 Apr 2019 04:30:59 -0400 +Subject: [PATCH 094/249] FROMGIT: media: platform: meson: Add Amlogic Meson + G12A AO CEC Controller driver + +The Amlogic G12A SoC embeds a second CEC controller with a totally +different design. + +The two controller can work in the same time since the CEC line can +be set to two different pins on the two controllers. + +This second CEC controller is documented as "AO-CEC-B", thus the +registers will be named "CECB_" to differentiate with the other +AO-CEC driver. + +Unlike the other AO-CEC controller, this one takes the Oscillator +clock as input and embeds a dual-divider to provide a precise +32768Hz clock for communication. This is handled by registering +a clock in the driver. + +Unlike the other AO-CEC controller, this controller supports setting +up to 15 logical addresses and supports the signal_free_time settings +in the transmit function. + +Unfortunately, this controller does not support "monitor" mode. + +Signed-off-by: Neil Armstrong +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit b7778c46683ce468f49141a18d984f6f13c6c5d2 + git://linuxtv.org/media_tree.git master) +--- + drivers/media/platform/Kconfig | 16 + + drivers/media/platform/meson/Makefile | 1 + + drivers/media/platform/meson/ao-cec-g12a.c | 779 +++++++++++++++++++++ + 3 files changed, 796 insertions(+) + create mode 100644 drivers/media/platform/meson/ao-cec-g12a.c + +diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig +index 4acbed1896449..ea3a65e1ddbcd 100644 +--- a/drivers/media/platform/Kconfig ++++ b/drivers/media/platform/Kconfig +@@ -578,6 +578,22 @@ config VIDEO_MESON_AO_CEC + generic CEC framework interface. + CEC bus is present in the HDMI connector and enables communication + ++config VIDEO_MESON_G12A_AO_CEC ++ tristate "Amlogic Meson G12A AO CEC driver" ++ depends on ARCH_MESON || COMPILE_TEST ++ depends on COMMON_CLK && OF ++ select REGMAP ++ select REGMAP_MMIO ++ select CEC_CORE ++ select CEC_NOTIFIER ++ ---help--- ++ This is a driver for Amlogic Meson G12A SoCs AO CEC interface. ++ This driver if for the new AO-CEC module found in G12A SoCs, ++ usually named AO_CEC_B in documentation. ++ It uses the generic CEC framework interface. ++ CEC bus is present in the HDMI connector and enables communication ++ between compatible devices. ++ + config CEC_GPIO + tristate "Generic GPIO-based CEC driver" + depends on PREEMPT || COMPILE_TEST +diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile +index 597beb8f34d15..f611c23c37180 100644 +--- a/drivers/media/platform/meson/Makefile ++++ b/drivers/media/platform/meson/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o ++obj-$(CONFIG_VIDEO_MESON_G12A_AO_CEC) += ao-cec-g12a.o +diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c +new file mode 100644 +index 0000000000000..3620a1e310f52 +--- /dev/null ++++ b/drivers/media/platform/meson/ao-cec-g12a.c +@@ -0,0 +1,779 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Driver for Amlogic Meson AO CEC G12A Controller ++ * ++ * Copyright (C) 2017 Amlogic, Inc. All rights reserved ++ * Copyright (C) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* CEC Registers */ ++ ++#define CECB_CLK_CNTL_REG0 0x00 ++ ++#define CECB_CLK_CNTL_N1 GENMASK(11, 0) ++#define CECB_CLK_CNTL_N2 GENMASK(23, 12) ++#define CECB_CLK_CNTL_DUAL_EN BIT(28) ++#define CECB_CLK_CNTL_OUTPUT_EN BIT(30) ++#define CECB_CLK_CNTL_INPUT_EN BIT(31) ++ ++#define CECB_CLK_CNTL_REG1 0x04 ++ ++#define CECB_CLK_CNTL_M1 GENMASK(11, 0) ++#define CECB_CLK_CNTL_M2 GENMASK(23, 12) ++#define CECB_CLK_CNTL_BYPASS_EN BIT(24) ++ ++/* ++ * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal ++ * change pulse width < filter_del * T(filter_tick) * 3. ++ * [9:8] Filter_tick_sel: Select which periodical pulse for ++ * glitch-filtering CEC line signal. ++ * - 0=Use T(xtal)*3 = 125ns; ++ * - 1=Use once-per-1us pulse; ++ * - 2=Use once-per-10us pulse; ++ * - 3=Use once-per-100us pulse. ++ * [3] Sysclk_en. 0=Disable system clock; 1=Enable system clock. ++ * [2:1] cntl_clk ++ * - 0 = Disable clk (Power-off mode) ++ * - 1 = Enable gated clock (Normal mode) ++ * - 2 = Enable free-run clk (Debug mode) ++ * [0] SW_RESET 1=Apply reset; 0=No reset. ++ */ ++#define CECB_GEN_CNTL_REG 0x08 ++ ++#define CECB_GEN_CNTL_RESET BIT(0) ++#define CECB_GEN_CNTL_CLK_DISABLE 0 ++#define CECB_GEN_CNTL_CLK_ENABLE 1 ++#define CECB_GEN_CNTL_CLK_ENABLE_DBG 2 ++#define CECB_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1) ++#define CECB_GEN_CNTL_SYS_CLK_EN BIT(3) ++#define CECB_GEN_CNTL_FILTER_TICK_125NS 0 ++#define CECB_GEN_CNTL_FILTER_TICK_1US 1 ++#define CECB_GEN_CNTL_FILTER_TICK_10US 2 ++#define CECB_GEN_CNTL_FILTER_TICK_100US 3 ++#define CECB_GEN_CNTL_FILTER_TICK_SEL GENMASK(9, 8) ++#define CECB_GEN_CNTL_FILTER_DEL GENMASK(14, 12) ++ ++/* ++ * [7:0] cec_reg_addr ++ * [15:8] cec_reg_wrdata ++ * [16] cec_reg_wr ++ * - 0 = Read ++ * - 1 = Write ++ * [31:24] cec_reg_rddata ++ */ ++#define CECB_RW_REG 0x0c ++ ++#define CECB_RW_ADDR GENMASK(7, 0) ++#define CECB_RW_WR_DATA GENMASK(15, 8) ++#define CECB_RW_WRITE_EN BIT(16) ++#define CECB_RW_BUS_BUSY BIT(23) ++#define CECB_RW_RD_DATA GENMASK(31, 24) ++ ++/* ++ * [0] DONE Interrupt ++ * [1] End Of Message Interrupt ++ * [2] Not Acknowlegde Interrupt ++ * [3] Arbitration Loss Interrupt ++ * [4] Initiator Error Interrupt ++ * [5] Follower Error Interrupt ++ * [6] Wake-Up Interrupt ++ */ ++#define CECB_INTR_MASKN_REG 0x10 ++#define CECB_INTR_CLR_REG 0x14 ++#define CECB_INTR_STAT_REG 0x18 ++ ++#define CECB_INTR_DONE BIT(0) ++#define CECB_INTR_EOM BIT(1) ++#define CECB_INTR_NACK BIT(2) ++#define CECB_INTR_ARB_LOSS BIT(3) ++#define CECB_INTR_INITIATOR_ERR BIT(4) ++#define CECB_INTR_FOLLOWER_ERR BIT(5) ++#define CECB_INTR_WAKE_UP BIT(6) ++ ++/* CEC Commands */ ++ ++#define CECB_CTRL 0x00 ++ ++#define CECB_CTRL_SEND BIT(0) ++#define CECB_CTRL_TYPE GENMASK(2, 1) ++#define CECB_CTRL_TYPE_RETRY 0 ++#define CECB_CTRL_TYPE_NEW 1 ++#define CECB_CTRL_TYPE_NEXT 2 ++ ++#define CECB_CTRL2 0x01 ++#define CECB_INTR_MASK 0x02 ++#define CECB_LADD_LOW 0x05 ++#define CECB_LADD_HIGH 0x06 ++#define CECB_TX_CNT 0x07 ++#define CECB_RX_CNT 0x08 ++#define CECB_STAT0 0x09 ++#define CECB_TX_DATA00 0x10 ++#define CECB_TX_DATA01 0x11 ++#define CECB_TX_DATA02 0x12 ++#define CECB_TX_DATA03 0x13 ++#define CECB_TX_DATA04 0x14 ++#define CECB_TX_DATA05 0x15 ++#define CECB_TX_DATA06 0x16 ++#define CECB_TX_DATA07 0x17 ++#define CECB_TX_DATA08 0x18 ++#define CECB_TX_DATA09 0x19 ++#define CECB_TX_DATA10 0x1A ++#define CECB_TX_DATA11 0x1B ++#define CECB_TX_DATA12 0x1C ++#define CECB_TX_DATA13 0x1D ++#define CECB_TX_DATA14 0x1E ++#define CECB_TX_DATA15 0x1F ++#define CECB_RX_DATA00 0x20 ++#define CECB_RX_DATA01 0x21 ++#define CECB_RX_DATA02 0x22 ++#define CECB_RX_DATA03 0x23 ++#define CECB_RX_DATA04 0x24 ++#define CECB_RX_DATA05 0x25 ++#define CECB_RX_DATA06 0x26 ++#define CECB_RX_DATA07 0x27 ++#define CECB_RX_DATA08 0x28 ++#define CECB_RX_DATA09 0x29 ++#define CECB_RX_DATA10 0x2A ++#define CECB_RX_DATA11 0x2B ++#define CECB_RX_DATA12 0x2C ++#define CECB_RX_DATA13 0x2D ++#define CECB_RX_DATA14 0x2E ++#define CECB_RX_DATA15 0x2F ++#define CECB_LOCK_BUF 0x30 ++ ++#define CECB_LOCK_BUF_EN BIT(0) ++ ++#define CECB_WAKEUPCTRL 0x31 ++ ++struct meson_ao_cec_g12a_device { ++ struct platform_device *pdev; ++ struct regmap *regmap; ++ struct regmap *regmap_cec; ++ spinlock_t cec_reg_lock; ++ struct cec_notifier *notify; ++ struct cec_adapter *adap; ++ struct cec_msg rx_msg; ++ struct clk *oscin; ++ struct clk *core; ++}; ++ ++static const struct regmap_config meson_ao_cec_g12a_regmap_conf = { ++ .reg_bits = 8, ++ .val_bits = 32, ++ .reg_stride = 4, ++ .max_register = CECB_INTR_STAT_REG, ++}; ++ ++/* ++ * The AO-CECB embeds a dual/divider to generate a more precise ++ * 32,768KHz clock for CEC core clock. ++ * ______ ______ ++ * | | | | ++ * ______ | Div1 |-| Cnt1 | ______ ++ * | | /|______| |______|\ | | ++ * Xtal-->| Gate |---| ______ ______ X-X--| Gate |--> ++ * |______| | \| | | |/ | |______| ++ * | | Div2 |-| Cnt2 | | ++ * | |______| |______| | ++ * |_______________________| ++ * ++ * The dividing can be switched to single or dual, with a counter ++ * for each divider to set when the switching is done. ++ * The entire dividing mechanism can be also bypassed. ++ */ ++ ++struct meson_ao_cec_g12a_dualdiv_clk { ++ struct clk_hw hw; ++ struct regmap *regmap; ++}; ++ ++#define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \ ++ container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \ ++ ++static unsigned long ++meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = ++ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); ++ unsigned long n1; ++ u32 reg0, reg1; ++ ++ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®0); ++ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®1); ++ ++ if (reg1 & CECB_CLK_CNTL_BYPASS_EN) ++ return parent_rate; ++ ++ if (reg0 & CECB_CLK_CNTL_DUAL_EN) { ++ unsigned long n2, m1, m2, f1, f2, p1, p2; ++ ++ n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; ++ n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1; ++ ++ m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; ++ m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; ++ ++ f1 = DIV_ROUND_CLOSEST(parent_rate, n1); ++ f2 = DIV_ROUND_CLOSEST(parent_rate, n2); ++ ++ p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2)); ++ p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2)); ++ ++ return DIV_ROUND_UP(100000000, p1 + p2); ++ } ++ ++ n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; ++ ++ return DIV_ROUND_CLOSEST(parent_rate, n1); ++} ++ ++static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw) ++{ ++ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = ++ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); ++ ++ ++ /* Disable Input & Output */ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ++ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, ++ 0); ++ ++ /* Set N1 & N2 */ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ++ CECB_CLK_CNTL_N1, ++ FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1)); ++ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ++ CECB_CLK_CNTL_N2, ++ FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1)); ++ ++ /* Set M1 & M2 */ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, ++ CECB_CLK_CNTL_M1, ++ FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1)); ++ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, ++ CECB_CLK_CNTL_M2, ++ FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1)); ++ ++ /* Enable Dual divisor */ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ++ CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN); ++ ++ /* Disable divisor bypass */ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, ++ CECB_CLK_CNTL_BYPASS_EN, 0); ++ ++ /* Enable Input & Output */ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ++ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, ++ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN); ++ ++ return 0; ++} ++ ++static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw) ++{ ++ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = ++ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); ++ ++ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ++ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, ++ 0); ++} ++ ++static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw) ++{ ++ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = ++ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); ++ int val; ++ ++ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val); ++ ++ return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN)); ++} ++ ++static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = { ++ .recalc_rate = meson_ao_cec_g12a_dualdiv_clk_recalc_rate, ++ .is_enabled = meson_ao_cec_g12a_dualdiv_clk_is_enabled, ++ .enable = meson_ao_cec_g12a_dualdiv_clk_enable, ++ .disable = meson_ao_cec_g12a_dualdiv_clk_disable, ++}; ++ ++static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec) ++{ ++ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk; ++ struct device *dev = &ao_cec->pdev->dev; ++ struct clk_init_data init; ++ const char *parent_name; ++ struct clk *clk; ++ char *name; ++ ++ dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL); ++ if (!dualdiv_clk) ++ return -ENOMEM; ++ ++ name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev)); ++ if (!name) ++ return -ENOMEM; ++ ++ parent_name = __clk_get_name(ao_cec->oscin); ++ ++ init.name = name; ++ init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops; ++ init.flags = 0; ++ init.parent_names = &parent_name; ++ init.num_parents = 1; ++ dualdiv_clk->regmap = ao_cec->regmap; ++ dualdiv_clk->hw.init = &init; ++ ++ clk = devm_clk_register(dev, &dualdiv_clk->hw); ++ kfree(name); ++ if (IS_ERR(clk)) { ++ dev_err(dev, "failed to register clock\n"); ++ return PTR_ERR(clk); ++ } ++ ++ ao_cec->core = clk; ++ ++ return 0; ++} ++ ++static int meson_ao_cec_g12a_read(void *context, unsigned int addr, ++ unsigned int *data) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec = context; ++ u32 reg = FIELD_PREP(CECB_RW_ADDR, addr); ++ unsigned long flags; ++ int ret = 0; ++ ++ spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); ++ ++ ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); ++ if (ret) ++ goto read_out; ++ ++ ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, ++ !(reg & CECB_RW_BUS_BUSY), ++ 5, 1000); ++ if (ret) ++ goto read_out; ++ ++ ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®); ++ ++ *data = FIELD_GET(CECB_RW_RD_DATA, reg); ++ ++read_out: ++ spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); ++ ++ return ret; ++} ++ ++static int meson_ao_cec_g12a_write(void *context, unsigned int addr, ++ unsigned int data) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec = context; ++ unsigned long flags; ++ u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) | ++ FIELD_PREP(CECB_RW_WR_DATA, data) | ++ CECB_RW_WRITE_EN; ++ int ret = 0; ++ ++ spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); ++ ++ ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); ++ ++ spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); ++ ++ return ret; ++} ++ ++static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .reg_read = meson_ao_cec_g12a_read, ++ .reg_write = meson_ao_cec_g12a_write, ++ .max_register = 0xffff, ++ .fast_io = true, ++}; ++ ++static inline void ++meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec, ++ bool enable) ++{ ++ u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK | ++ CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR | ++ CECB_INTR_FOLLOWER_ERR; ++ ++ regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG, ++ enable ? cfg : 0); ++} ++ ++static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec) ++{ ++ int i, ret = 0; ++ u32 val; ++ ++ ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val); ++ ++ ao_cec->rx_msg.len = val; ++ if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) ++ ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; ++ ++ for (i = 0; i < ao_cec->rx_msg.len; i++) { ++ ret |= regmap_read(ao_cec->regmap_cec, ++ CECB_RX_DATA00 + i, &val); ++ ++ ao_cec->rx_msg.msg[i] = val & 0xff; ++ } ++ ++ ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); ++ if (ret) ++ return; ++ ++ cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); ++} ++ ++static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec = data; ++ u32 stat; ++ ++ regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); ++ if (stat) ++ return IRQ_WAKE_THREAD; ++ ++ return IRQ_NONE; ++} ++ ++static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec = data; ++ u32 stat; ++ ++ regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); ++ regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat); ++ ++ if (stat & CECB_INTR_DONE) ++ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK); ++ ++ if (stat & CECB_INTR_EOM) ++ meson_ao_cec_g12a_irq_rx(ao_cec); ++ ++ if (stat & CECB_INTR_NACK) ++ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK); ++ ++ if (stat & CECB_INTR_ARB_LOSS) { ++ regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0); ++ regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, ++ CECB_CTRL_SEND | CECB_CTRL_TYPE, 0); ++ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST); ++ } ++ ++ /* Initiator reports an error on the CEC bus */ ++ if (stat & CECB_INTR_INITIATOR_ERR) ++ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); ++ ++ /* Follower reports a receive error, just reset RX buffer */ ++ if (stat & CECB_INTR_FOLLOWER_ERR) ++ regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); ++ ++ return IRQ_HANDLED; ++} ++ ++static int ++meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec = adap->priv; ++ int ret = 0; ++ ++ if (logical_addr == CEC_LOG_ADDR_INVALID) { ++ /* Assume this will allways succeed */ ++ regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0); ++ regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0); ++ ++ return 0; ++ } else if (logical_addr < 8) { ++ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW, ++ BIT(logical_addr), ++ BIT(logical_addr)); ++ } else { ++ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, ++ BIT(logical_addr - 8), ++ BIT(logical_addr - 8)); ++ } ++ ++ /* Always set Broadcast/Unregistered 15 address */ ++ ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, ++ BIT(CEC_LOG_ADDR_UNREGISTERED - 8), ++ BIT(CEC_LOG_ADDR_UNREGISTERED - 8)); ++ ++ return ret ? -EIO : 0; ++} ++ ++static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts, ++ u32 signal_free_time, struct cec_msg *msg) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec = adap->priv; ++ unsigned int type; ++ int ret = 0; ++ u32 val; ++ int i; ++ ++ /* Check if RX is in progress */ ++ ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val); ++ if (ret) ++ return ret; ++ if (val & CECB_LOCK_BUF_EN) ++ return -EBUSY; ++ ++ /* Check if TX Busy */ ++ ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val); ++ if (ret) ++ return ret; ++ if (val & CECB_CTRL_SEND) ++ return -EBUSY; ++ ++ switch (signal_free_time) { ++ case CEC_SIGNAL_FREE_TIME_RETRY: ++ type = CECB_CTRL_TYPE_RETRY; ++ break; ++ case CEC_SIGNAL_FREE_TIME_NEXT_XFER: ++ type = CECB_CTRL_TYPE_NEXT; ++ break; ++ case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR: ++ default: ++ type = CECB_CTRL_TYPE_NEW; ++ break; ++ } ++ ++ for (i = 0; i < msg->len; i++) ++ ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i, ++ msg->msg[i]); ++ ++ ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len); ++ if (ret) ++ return -EIO; ++ ++ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, ++ CECB_CTRL_SEND | ++ CECB_CTRL_TYPE, ++ CECB_CTRL_SEND | ++ FIELD_PREP(CECB_CTRL_TYPE, type)); ++ ++ return ret; ++} ++ ++static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec = adap->priv; ++ ++ meson_ao_cec_g12a_irq_setup(ao_cec, false); ++ ++ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, ++ CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET); ++ ++ if (!enable) ++ return 0; ++ ++ /* Setup Filter */ ++ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, ++ CECB_GEN_CNTL_FILTER_TICK_SEL | ++ CECB_GEN_CNTL_FILTER_DEL, ++ FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL, ++ CECB_GEN_CNTL_FILTER_TICK_1US) | ++ FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7)); ++ ++ /* Enable System Clock */ ++ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, ++ CECB_GEN_CNTL_SYS_CLK_EN, ++ CECB_GEN_CNTL_SYS_CLK_EN); ++ ++ /* Enable gated clock (Normal mode). */ ++ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, ++ CECB_GEN_CNTL_CLK_CTRL_MASK, ++ FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK, ++ CECB_GEN_CNTL_CLK_ENABLE)); ++ ++ /* Release Reset */ ++ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, ++ CECB_GEN_CNTL_RESET, 0); ++ ++ meson_ao_cec_g12a_irq_setup(ao_cec, true); ++ ++ return 0; ++} ++ ++static const struct cec_adap_ops meson_ao_cec_g12a_ops = { ++ .adap_enable = meson_ao_cec_g12a_adap_enable, ++ .adap_log_addr = meson_ao_cec_g12a_set_log_addr, ++ .adap_transmit = meson_ao_cec_g12a_transmit, ++}; ++ ++static int meson_ao_cec_g12a_probe(struct platform_device *pdev) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec; ++ struct device *hdmi_dev; ++ struct resource *res; ++ void __iomem *base; ++ int ret, irq; ++ ++ hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); ++ if (IS_ERR(hdmi_dev)) ++ return PTR_ERR(hdmi_dev); ++ ++ ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); ++ if (!ao_cec) ++ return -ENOMEM; ++ ++ spin_lock_init(&ao_cec->cec_reg_lock); ++ ao_cec->pdev = pdev; ++ ++ ao_cec->notify = cec_notifier_get(hdmi_dev); ++ if (!ao_cec->notify) ++ return -ENOMEM; ++ ++ ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, ++ "meson_g12a_ao_cec", ++ CEC_CAP_DEFAULTS, ++ CEC_MAX_LOG_ADDRS); ++ if (IS_ERR(ao_cec->adap)) { ++ ret = PTR_ERR(ao_cec->adap); ++ goto out_probe_notify; ++ } ++ ++ ao_cec->adap->owner = THIS_MODULE; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(base)) { ++ ret = PTR_ERR(base); ++ goto out_probe_adapter; ++ } ++ ++ ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, ++ &meson_ao_cec_g12a_regmap_conf); ++ if (IS_ERR(ao_cec->regmap)) { ++ ret = PTR_ERR(ao_cec->regmap); ++ goto out_probe_adapter; ++ } ++ ++ ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, ++ &meson_ao_cec_g12a_cec_regmap_conf); ++ if (IS_ERR(ao_cec->regmap_cec)) { ++ ret = PTR_ERR(ao_cec->regmap_cec); ++ goto out_probe_adapter; ++ } ++ ++ irq = platform_get_irq(pdev, 0); ++ ret = devm_request_threaded_irq(&pdev->dev, irq, ++ meson_ao_cec_g12a_irq, ++ meson_ao_cec_g12a_irq_thread, ++ 0, NULL, ao_cec); ++ if (ret) { ++ dev_err(&pdev->dev, "irq request failed\n"); ++ goto out_probe_adapter; ++ } ++ ++ ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); ++ if (IS_ERR(ao_cec->oscin)) { ++ dev_err(&pdev->dev, "oscin clock request failed\n"); ++ ret = PTR_ERR(ao_cec->oscin); ++ goto out_probe_adapter; ++ } ++ ++ ret = meson_ao_cec_g12a_setup_clk(ao_cec); ++ if (ret) ++ goto out_probe_adapter; ++ ++ ret = clk_prepare_enable(ao_cec->core); ++ if (ret) { ++ dev_err(&pdev->dev, "core clock enable failed\n"); ++ goto out_probe_adapter; ++ } ++ ++ device_reset_optional(&pdev->dev); ++ ++ platform_set_drvdata(pdev, ao_cec); ++ ++ ret = cec_register_adapter(ao_cec->adap, &pdev->dev); ++ if (ret < 0) { ++ cec_notifier_put(ao_cec->notify); ++ goto out_probe_core_clk; ++ } ++ ++ /* Setup Hardware */ ++ regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); ++ ++ cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); ++ ++ return 0; ++ ++out_probe_core_clk: ++ clk_disable_unprepare(ao_cec->core); ++ ++out_probe_adapter: ++ cec_delete_adapter(ao_cec->adap); ++ ++out_probe_notify: ++ cec_notifier_put(ao_cec->notify); ++ ++ dev_err(&pdev->dev, "CEC controller registration failed\n"); ++ ++ return ret; ++} ++ ++static int meson_ao_cec_g12a_remove(struct platform_device *pdev) ++{ ++ struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(ao_cec->core); ++ ++ cec_unregister_adapter(ao_cec->adap); ++ ++ cec_notifier_put(ao_cec->notify); ++ ++ return 0; ++} ++ ++static const struct of_device_id meson_ao_cec_g12a_of_match[] = { ++ { .compatible = "amlogic,meson-g12a-ao-cec", }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); ++ ++static struct platform_driver meson_ao_cec_g12a_driver = { ++ .probe = meson_ao_cec_g12a_probe, ++ .remove = meson_ao_cec_g12a_remove, ++ .driver = { ++ .name = "meson-ao-cec-g12a", ++ .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), ++ }, ++}; ++ ++module_platform_driver(meson_ao_cec_g12a_driver); ++ ++MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver"); ++MODULE_AUTHOR("Neil Armstrong "); ++MODULE_LICENSE("GPL"); + +From 27529762e1b4f4d3d80541474c76afeb9b1e4b58 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 12 Apr 2019 04:31:00 -0400 +Subject: [PATCH 095/249] FROMGIT: media: MAINTAINERS: Update AO CEC with + ao-cec-g12a driver + +Update the MAINTAINERS entry with the new AO-CEC driver for G12A. + +Signed-off-by: Neil Armstrong +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit a4dfc8a24796ff312d1d307e11f26f8ca466e938 + git://linuxtv.org/media_tree.git master) +--- + MAINTAINERS | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 2c2fce72e694f..ddc31a0716ab8 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -10057,6 +10057,7 @@ L: linux-amlogic@lists.infradead.org + W: http://linux-meson.com/ + S: Supported + F: drivers/media/platform/meson/ao-cec.c ++F: drivers/media/platform/meson/ao-cec-g12a.c + F: Documentation/devicetree/bindings/media/meson-ao-cec.txt + T: git git://linuxtv.org/media_tree.git + + +From 8a1ac659c340c5614d4d8295a823e51cf26e3303 Mon Sep 17 00:00:00 2001 +From: YueHaibing +Date: Sat, 13 Apr 2019 22:14:55 +0800 +Subject: [PATCH 096/249] FROMGIT: drm/meson: Make some functions static + +Fix sparse warnings: + +drivers/gpu/drm/meson/meson_viu.c:93:6: warning: symbol 'meson_viu_set_g12a_osd1_matrix' was not declared. Should it be static? +drivers/gpu/drm/meson/meson_viu.c:121:6: warning: symbol 'meson_viu_set_osd_matrix' was not declared. Should it be static? +drivers/gpu/drm/meson/meson_viu.c:190:6: warning: symbol 'meson_viu_set_osd_lut' was not declared. Should it be static? + +Signed-off-by: YueHaibing +Acked-by: Neil Armstrong +Signed-off-by: Neil Armstrong +Link: https://patchwork.freedesktop.org/patch/msgid/20190413141455.34020-1-yuehaibing@huawei.com +(cherry picked from commit 2ccb8433ebe8dc99ed7cd0e3b8ff6976dcc05e3d + https://github.com/freedesktop/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_viu.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c +index 0169c98b01c94..b59072342cae7 100644 +--- a/drivers/gpu/drm/meson/meson_viu.c ++++ b/drivers/gpu/drm/meson/meson_viu.c +@@ -90,8 +90,8 @@ static int eotf_bypass_coeff[EOTF_COEFF_SIZE] = { + EOTF_COEFF_RIGHTSHIFT /* right shift */ + }; + +-void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, int *m, +- bool csc_on) ++static void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, ++ int *m, bool csc_on) + { + /* VPP WRAP OSD1 matrix */ + writel(((m[0] & 0xfff) << 16) | (m[1] & 0xfff), +@@ -118,8 +118,8 @@ void meson_viu_set_g12a_osd1_matrix(struct meson_drm *priv, int *m, + priv->io_base + _REG(VPP_WRAP_OSD1_MATRIX_EN_CTRL)); + } + +-void meson_viu_set_osd_matrix(struct meson_drm *priv, +- enum viu_matrix_sel_e m_select, ++static void meson_viu_set_osd_matrix(struct meson_drm *priv, ++ enum viu_matrix_sel_e m_select, + int *m, bool csc_on) + { + if (m_select == VIU_MATRIX_OSD) { +@@ -187,10 +187,10 @@ void meson_viu_set_osd_matrix(struct meson_drm *priv, + #define OSD_EOTF_LUT_SIZE 33 + #define OSD_OETF_LUT_SIZE 41 + +-void meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, +- unsigned int *r_map, unsigned int *g_map, +- unsigned int *b_map, +- bool csc_on) ++static void ++meson_viu_set_osd_lut(struct meson_drm *priv, enum viu_lut_sel_e lut_sel, ++ unsigned int *r_map, unsigned int *g_map, ++ unsigned int *b_map, bool csc_on) + { + unsigned int addr_port; + unsigned int data_port; + +From 51bbd9e7fe83cf7faa77fe360b47817c56ca6a58 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 8 Apr 2019 11:01:37 +0200 +Subject: [PATCH 097/249] FROMGIT: drm/meson: add size and alignment + requirements for dumb buffers + +The Amlogic SoCs Canvas buffers stride must be aligned on 64bytes +and overall size should be aligned on PAGE width. + +Adds a custom dumb_create op to adds these requirements. + +Fixes: bbbe775ec5b5 ("drm: Add support for Amlogic Meson Graphic Controller") +Suggested-by: Sky Zhou +Signed-off-by: Neil Armstrong +Reviewed-by: Sky Zhou +Link: https://patchwork.freedesktop.org/patch/msgid/20190408090137.2402-1-narmstrong@baylibre.com +(cherry picked from commit 852ce7285c99e3f7b56e76511e1b33c645a2b648 + https://github.com/freedesktop/drm-misc drm-misc-next) +--- + drivers/gpu/drm/meson/meson_drv.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c +index faf1b1b0357cd..72b01e6be0d9d 100644 +--- a/drivers/gpu/drm/meson/meson_drv.c ++++ b/drivers/gpu/drm/meson/meson_drv.c +@@ -90,6 +90,18 @@ static irqreturn_t meson_irq(int irq, void *arg) + return IRQ_HANDLED; + } + ++static int meson_dumb_create(struct drm_file *file, struct drm_device *dev, ++ struct drm_mode_create_dumb *args) ++{ ++ /* ++ * We need 64bytes aligned stride, and PAGE aligned size ++ */ ++ args->pitch = ALIGN(DIV_ROUND_UP(args->width * args->bpp, 8), SZ_64); ++ args->size = PAGE_ALIGN(args->pitch * args->height); ++ ++ return drm_gem_cma_dumb_create_internal(file, dev, args); ++} ++ + DEFINE_DRM_GEM_CMA_FOPS(fops); + + static struct drm_driver meson_driver = { +@@ -112,7 +124,7 @@ static struct drm_driver meson_driver = { + .gem_prime_mmap = drm_gem_cma_prime_mmap, + + /* GEM Ops */ +- .dumb_create = drm_gem_cma_dumb_create, ++ .dumb_create = meson_dumb_create, + .gem_free_object_unlocked = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + + +From 587d6fd2663ba72cdcb2bed109a2c56950f2080c Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 15:11:44 +0200 +Subject: [PATCH 098/249] FROMGIT: dt-bindings: net: phy: add g12a mdio mux + documentation + +Add documentation for the device tree bindings of the MDIO mux of Amlogic +g12a SoC family + +Reviewed-by: Rob Herring +Signed-off-by: Jerome Brunet +Signed-off-by: David S. Miller +(cherry picked from commit 867934e9c9babe9192797726f6910554bbdc28ce + git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master) +Signed-off-by: Neil Armstrong +--- + .../bindings/net/mdio-mux-meson-g12a.txt | 48 +++++++++++++++++++ + 1 file changed, 48 insertions(+) + create mode 100644 Documentation/devicetree/bindings/net/mdio-mux-meson-g12a.txt + +diff --git a/Documentation/devicetree/bindings/net/mdio-mux-meson-g12a.txt b/Documentation/devicetree/bindings/net/mdio-mux-meson-g12a.txt +new file mode 100644 +index 0000000000000..3a96cbed92947 +--- /dev/null ++++ b/Documentation/devicetree/bindings/net/mdio-mux-meson-g12a.txt +@@ -0,0 +1,48 @@ ++Properties for the MDIO bus multiplexer/glue of Amlogic G12a SoC family. ++ ++This is a special case of a MDIO bus multiplexer. It allows to choose between ++the internal mdio bus leading to the embedded 10/100 PHY or the external ++MDIO bus. ++ ++Required properties in addition to the generic multiplexer properties: ++- compatible : amlogic,g12a-mdio-mux ++- reg: physical address and length of the multiplexer/glue registers ++- clocks: list of clock phandle, one for each entry clock-names. ++- clock-names: should contain the following: ++ * "pclk" : peripheral clock. ++ * "clkin0" : platform crytal ++ * "clkin1" : SoC 50MHz MPLL ++ ++Example : ++ ++mdio_mux: mdio-multiplexer@4c000 { ++ compatible = "amlogic,g12a-mdio-mux"; ++ reg = <0x0 0x4c000 0x0 0xa4>; ++ clocks = <&clkc CLKID_ETH_PHY>, ++ <&xtal>, ++ <&clkc CLKID_MPLL_5OM>; ++ clock-names = "pclk", "clkin0", "clkin1"; ++ mdio-parent-bus = <&mdio0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ext_mdio: mdio@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ int_mdio: mdio@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ internal_ephy: ethernet-phy@8 { ++ compatible = "ethernet-phy-id0180.3301", ++ "ethernet-phy-ieee802.3-c22"; ++ interrupts = ; ++ reg = <8>; ++ max-speed = <100>; ++ }; ++ }; ++}; + +From 4eeb71337c6dfb38c327b6f4728cc168ff913294 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 15:11:45 +0200 +Subject: [PATCH 099/249] FROMGIT: net: phy: add amlogic g12a mdio mux support + +Add support for the mdio mux and internal phy glue of the g12a SoC family + +Reviewed-by: Neil Armstrong # clk parts +Signed-off-by: Jerome Brunet +Signed-off-by: David S. Miller +(cherry picked from commit 7090425104dbd87959bd424e9bd5a8711fde0986 + git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master) +Signed-off-by: Neil Armstrong +--- + drivers/net/phy/Kconfig | 11 + + drivers/net/phy/Makefile | 1 + + drivers/net/phy/mdio-mux-meson-g12a.c | 380 ++++++++++++++++++++++++++ + 3 files changed, 392 insertions(+) + create mode 100644 drivers/net/phy/mdio-mux-meson-g12a.c + +diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig +index 520657945b827..1b04004e1f379 100644 +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -76,6 +76,17 @@ config MDIO_BUS_MUX_GPIO + several child MDIO busses to a parent bus. Child bus + selection is under the control of GPIO lines. + ++config MDIO_BUS_MUX_MESON_G12A ++ tristate "Amlogic G12a based MDIO bus multiplexer" ++ depends on ARCH_MESON || COMPILE_TEST ++ depends on OF_MDIO && HAS_IOMEM && COMMON_CLK ++ select MDIO_BUS_MUX ++ default m if ARCH_MESON ++ help ++ This module provides a driver for the MDIO multiplexer/glue of ++ the amlogic g12a SoC. The multiplexers connects either the external ++ or the internal MDIO bus to the parent bus. ++ + config MDIO_BUS_MUX_MMIOREG + tristate "MMIO device-controlled MDIO bus multiplexers" + depends on OF_MDIO && HAS_IOMEM +diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile +index ece5dae67174f..27d7f9f3b0de4 100644 +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o + obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o + obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC) += mdio-mux-bcm-iproc.o + obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o ++obj-$(CONFIG_MDIO_BUS_MUX_MESON_G12A) += mdio-mux-meson-g12a.o + obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o + obj-$(CONFIG_MDIO_BUS_MUX_MULTIPLEXER) += mdio-mux-multiplexer.o + obj-$(CONFIG_MDIO_CAVIUM) += mdio-cavium.o +diff --git a/drivers/net/phy/mdio-mux-meson-g12a.c b/drivers/net/phy/mdio-mux-meson-g12a.c +new file mode 100644 +index 0000000000000..6fa29ea8e2a36 +--- /dev/null ++++ b/drivers/net/phy/mdio-mux-meson-g12a.c +@@ -0,0 +1,380 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright (c) 2019 Baylibre, SAS. ++ * Author: Jerome Brunet ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define ETH_PLL_STS 0x40 ++#define ETH_PLL_CTL0 0x44 ++#define PLL_CTL0_LOCK_DIG BIT(30) ++#define PLL_CTL0_RST BIT(29) ++#define PLL_CTL0_EN BIT(28) ++#define PLL_CTL0_SEL BIT(23) ++#define PLL_CTL0_N GENMASK(14, 10) ++#define PLL_CTL0_M GENMASK(8, 0) ++#define PLL_LOCK_TIMEOUT 1000000 ++#define PLL_MUX_NUM_PARENT 2 ++#define ETH_PLL_CTL1 0x48 ++#define ETH_PLL_CTL2 0x4c ++#define ETH_PLL_CTL3 0x50 ++#define ETH_PLL_CTL4 0x54 ++#define ETH_PLL_CTL5 0x58 ++#define ETH_PLL_CTL6 0x5c ++#define ETH_PLL_CTL7 0x60 ++ ++#define ETH_PHY_CNTL0 0x80 ++#define EPHY_G12A_ID 0x33000180 ++#define ETH_PHY_CNTL1 0x84 ++#define PHY_CNTL1_ST_MODE GENMASK(2, 0) ++#define PHY_CNTL1_ST_PHYADD GENMASK(7, 3) ++#define EPHY_DFLT_ADD 8 ++#define PHY_CNTL1_MII_MODE GENMASK(15, 14) ++#define EPHY_MODE_RMII 0x1 ++#define PHY_CNTL1_CLK_EN BIT(16) ++#define PHY_CNTL1_CLKFREQ BIT(17) ++#define PHY_CNTL1_PHY_ENB BIT(18) ++#define ETH_PHY_CNTL2 0x88 ++#define PHY_CNTL2_USE_INTERNAL BIT(5) ++#define PHY_CNTL2_SMI_SRC_MAC BIT(6) ++#define PHY_CNTL2_RX_CLK_EPHY BIT(9) ++ ++#define MESON_G12A_MDIO_EXTERNAL_ID 0 ++#define MESON_G12A_MDIO_INTERNAL_ID 1 ++ ++struct g12a_mdio_mux { ++ bool pll_is_enabled; ++ void __iomem *regs; ++ void *mux_handle; ++ struct clk *pclk; ++ struct clk *pll; ++}; ++ ++struct g12a_ephy_pll { ++ void __iomem *base; ++ struct clk_hw hw; ++}; ++ ++#define g12a_ephy_pll_to_dev(_hw) \ ++ container_of(_hw, struct g12a_ephy_pll, hw) ++ ++static unsigned long g12a_ephy_pll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); ++ u32 val, m, n; ++ ++ val = readl(pll->base + ETH_PLL_CTL0); ++ m = FIELD_GET(PLL_CTL0_M, val); ++ n = FIELD_GET(PLL_CTL0_N, val); ++ ++ return parent_rate * m / n; ++} ++ ++static int g12a_ephy_pll_enable(struct clk_hw *hw) ++{ ++ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); ++ u32 val = readl(pll->base + ETH_PLL_CTL0); ++ ++ /* Apply both enable an reset */ ++ val |= PLL_CTL0_RST | PLL_CTL0_EN; ++ writel(val, pll->base + ETH_PLL_CTL0); ++ ++ /* Clear the reset to let PLL lock */ ++ val &= ~PLL_CTL0_RST; ++ writel(val, pll->base + ETH_PLL_CTL0); ++ ++ /* Poll on the digital lock instead of the usual analog lock ++ * This is done because bit 31 is unreliable on some SoC. Bit ++ * 31 may indicate that the PLL is not lock eventhough the clock ++ * is actually running ++ */ ++ return readl_poll_timeout(pll->base + ETH_PLL_CTL0, val, ++ val & PLL_CTL0_LOCK_DIG, 0, PLL_LOCK_TIMEOUT); ++} ++ ++static void g12a_ephy_pll_disable(struct clk_hw *hw) ++{ ++ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); ++ u32 val; ++ ++ val = readl(pll->base + ETH_PLL_CTL0); ++ val &= ~PLL_CTL0_EN; ++ val |= PLL_CTL0_RST; ++ writel(val, pll->base + ETH_PLL_CTL0); ++} ++ ++static int g12a_ephy_pll_is_enabled(struct clk_hw *hw) ++{ ++ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); ++ unsigned int val; ++ ++ val = readl(pll->base + ETH_PLL_CTL0); ++ ++ return (val & PLL_CTL0_LOCK_DIG) ? 1 : 0; ++} ++ ++static void g12a_ephy_pll_init(struct clk_hw *hw) ++{ ++ struct g12a_ephy_pll *pll = g12a_ephy_pll_to_dev(hw); ++ ++ /* Apply PLL HW settings */ ++ writel(0x29c0040a, pll->base + ETH_PLL_CTL0); ++ writel(0x927e0000, pll->base + ETH_PLL_CTL1); ++ writel(0xac5f49e5, pll->base + ETH_PLL_CTL2); ++ writel(0x00000000, pll->base + ETH_PLL_CTL3); ++ writel(0x00000000, pll->base + ETH_PLL_CTL4); ++ writel(0x20200000, pll->base + ETH_PLL_CTL5); ++ writel(0x0000c002, pll->base + ETH_PLL_CTL6); ++ writel(0x00000023, pll->base + ETH_PLL_CTL7); ++} ++ ++static const struct clk_ops g12a_ephy_pll_ops = { ++ .recalc_rate = g12a_ephy_pll_recalc_rate, ++ .is_enabled = g12a_ephy_pll_is_enabled, ++ .enable = g12a_ephy_pll_enable, ++ .disable = g12a_ephy_pll_disable, ++ .init = g12a_ephy_pll_init, ++}; ++ ++static int g12a_enable_internal_mdio(struct g12a_mdio_mux *priv) ++{ ++ int ret; ++ ++ /* Enable the phy clock */ ++ if (!priv->pll_is_enabled) { ++ ret = clk_prepare_enable(priv->pll); ++ if (ret) ++ return ret; ++ } ++ ++ priv->pll_is_enabled = true; ++ ++ /* Initialize ephy control */ ++ writel(EPHY_G12A_ID, priv->regs + ETH_PHY_CNTL0); ++ writel(FIELD_PREP(PHY_CNTL1_ST_MODE, 3) | ++ FIELD_PREP(PHY_CNTL1_ST_PHYADD, EPHY_DFLT_ADD) | ++ FIELD_PREP(PHY_CNTL1_MII_MODE, EPHY_MODE_RMII) | ++ PHY_CNTL1_CLK_EN | ++ PHY_CNTL1_CLKFREQ | ++ PHY_CNTL1_PHY_ENB, ++ priv->regs + ETH_PHY_CNTL1); ++ writel(PHY_CNTL2_USE_INTERNAL | ++ PHY_CNTL2_SMI_SRC_MAC | ++ PHY_CNTL2_RX_CLK_EPHY, ++ priv->regs + ETH_PHY_CNTL2); ++ ++ return 0; ++} ++ ++static int g12a_enable_external_mdio(struct g12a_mdio_mux *priv) ++{ ++ /* Reset the mdio bus mux */ ++ writel_relaxed(0x0, priv->regs + ETH_PHY_CNTL2); ++ ++ /* Disable the phy clock if enabled */ ++ if (priv->pll_is_enabled) { ++ clk_disable_unprepare(priv->pll); ++ priv->pll_is_enabled = false; ++ } ++ ++ return 0; ++} ++ ++static int g12a_mdio_switch_fn(int current_child, int desired_child, ++ void *data) ++{ ++ struct g12a_mdio_mux *priv = dev_get_drvdata(data); ++ ++ if (current_child == desired_child) ++ return 0; ++ ++ switch (desired_child) { ++ case MESON_G12A_MDIO_EXTERNAL_ID: ++ return g12a_enable_external_mdio(priv); ++ case MESON_G12A_MDIO_INTERNAL_ID: ++ return g12a_enable_internal_mdio(priv); ++ default: ++ return -EINVAL; ++ } ++} ++ ++static const struct of_device_id g12a_mdio_mux_match[] = { ++ { .compatible = "amlogic,g12a-mdio-mux", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, g12a_mdio_mux_match); ++ ++static int g12a_ephy_glue_clk_register(struct device *dev) ++{ ++ struct g12a_mdio_mux *priv = dev_get_drvdata(dev); ++ const char *parent_names[PLL_MUX_NUM_PARENT]; ++ struct clk_init_data init; ++ struct g12a_ephy_pll *pll; ++ struct clk_mux *mux; ++ struct clk *clk; ++ char *name; ++ int i; ++ ++ /* get the mux parents */ ++ for (i = 0; i < PLL_MUX_NUM_PARENT; i++) { ++ char in_name[8]; ++ ++ snprintf(in_name, sizeof(in_name), "clkin%d", i); ++ clk = devm_clk_get(dev, in_name); ++ if (IS_ERR(clk)) { ++ if (PTR_ERR(clk) != -EPROBE_DEFER) ++ dev_err(dev, "Missing clock %s\n", in_name); ++ return PTR_ERR(clk); ++ } ++ ++ parent_names[i] = __clk_get_name(clk); ++ } ++ ++ /* create the input mux */ ++ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); ++ if (!mux) ++ return -ENOMEM; ++ ++ name = kasprintf(GFP_KERNEL, "%s#mux", dev_name(dev)); ++ if (!name) ++ return -ENOMEM; ++ ++ init.name = name; ++ init.ops = &clk_mux_ro_ops; ++ init.flags = 0; ++ init.parent_names = parent_names; ++ init.num_parents = PLL_MUX_NUM_PARENT; ++ ++ mux->reg = priv->regs + ETH_PLL_CTL0; ++ mux->shift = __ffs(PLL_CTL0_SEL); ++ mux->mask = PLL_CTL0_SEL >> mux->shift; ++ mux->hw.init = &init; ++ ++ clk = devm_clk_register(dev, &mux->hw); ++ kfree(name); ++ if (IS_ERR(clk)) { ++ dev_err(dev, "failed to register input mux\n"); ++ return PTR_ERR(clk); ++ } ++ ++ /* create the pll */ ++ pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); ++ if (!pll) ++ return -ENOMEM; ++ ++ name = kasprintf(GFP_KERNEL, "%s#pll", dev_name(dev)); ++ if (!name) ++ return -ENOMEM; ++ ++ init.name = name; ++ init.ops = &g12a_ephy_pll_ops; ++ init.flags = 0; ++ parent_names[0] = __clk_get_name(clk); ++ init.parent_names = parent_names; ++ init.num_parents = 1; ++ ++ pll->base = priv->regs; ++ pll->hw.init = &init; ++ ++ clk = devm_clk_register(dev, &pll->hw); ++ kfree(name); ++ if (IS_ERR(clk)) { ++ dev_err(dev, "failed to register input mux\n"); ++ return PTR_ERR(clk); ++ } ++ ++ priv->pll = clk; ++ ++ return 0; ++} ++ ++static int g12a_mdio_mux_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct g12a_mdio_mux *priv; ++ struct resource *res; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, priv); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ priv->regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(priv->regs)) ++ return PTR_ERR(priv->regs); ++ ++ priv->pclk = devm_clk_get(dev, "pclk"); ++ if (IS_ERR(priv->pclk)) { ++ ret = PTR_ERR(priv->pclk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to get peripheral clock\n"); ++ return ret; ++ } ++ ++ /* Make sure the device registers are clocked */ ++ ret = clk_prepare_enable(priv->pclk); ++ if (ret) { ++ dev_err(dev, "failed to enable peripheral clock"); ++ return ret; ++ } ++ ++ /* Register PLL in CCF */ ++ ret = g12a_ephy_glue_clk_register(dev); ++ if (ret) ++ goto err; ++ ++ ret = mdio_mux_init(dev, dev->of_node, g12a_mdio_switch_fn, ++ &priv->mux_handle, dev, NULL); ++ if (ret) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "mdio multiplexer init failed: %d", ret); ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ clk_disable_unprepare(priv->pclk); ++ return ret; ++} ++ ++static int g12a_mdio_mux_remove(struct platform_device *pdev) ++{ ++ struct g12a_mdio_mux *priv = platform_get_drvdata(pdev); ++ ++ mdio_mux_uninit(priv->mux_handle); ++ ++ if (priv->pll_is_enabled) ++ clk_disable_unprepare(priv->pll); ++ ++ clk_disable_unprepare(priv->pclk); ++ ++ return 0; ++} ++ ++static struct platform_driver g12a_mdio_mux_driver = { ++ .probe = g12a_mdio_mux_probe, ++ .remove = g12a_mdio_mux_remove, ++ .driver = { ++ .name = "g12a-mdio_mux", ++ .of_match_table = g12a_mdio_mux_match, ++ }, ++}; ++module_platform_driver(g12a_mdio_mux_driver); ++ ++MODULE_DESCRIPTION("Amlogic G12a MDIO multiplexer driver"); ++MODULE_AUTHOR("Jerome Brunet "); ++MODULE_LICENSE("GPL v2"); + +From 8d2e275796d61e5c54bb4296886725ff6ad1d779 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 15:11:46 +0200 +Subject: [PATCH 100/249] FROMGIT: net: phy: meson-gxl: add g12a support + +The g12a SoC family uses the type of internal PHY that was used on the +gxl family. The quirks of gxl family, like the LPA register corruption, +appear to have been resolved on this new SoC generation. + +Signed-off-by: Jerome Brunet +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +(cherry picked from commit 5c3407abb3382fb0621a503662d00495f7ab65c4 + git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master) +Signed-off-by: Neil Armstrong +--- + drivers/net/phy/meson-gxl.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c +index 0eec2913c289b..2033c93a46ca8 100644 +--- a/drivers/net/phy/meson-gxl.c ++++ b/drivers/net/phy/meson-gxl.c +@@ -237,11 +237,22 @@ static struct phy_driver meson_gxl_phy[] = { + .config_intr = meson_gxl_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, ++ }, { ++ PHY_ID_MATCH_EXACT(0x01803301), ++ .name = "Meson G12A Internal PHY", ++ .features = PHY_BASIC_FEATURES, ++ .flags = PHY_IS_INTERNAL, ++ .soft_reset = genphy_soft_reset, ++ .ack_interrupt = meson_gxl_ack_interrupt, ++ .config_intr = meson_gxl_config_intr, ++ .suspend = genphy_suspend, ++ .resume = genphy_resume, + }, + }; + + static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = { + { 0x01814400, 0xfffffff0 }, ++ { PHY_ID_MATCH_VENDOR(0x01803301) }, + { } + }; + + +From 8d275e2172f69a82526b980d041bf7ee76855340 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 4 Apr 2019 15:11:47 +0200 +Subject: [PATCH 101/249] FROMGIT: net: phy: meson-gxl: clean-up gxl variant + driver + +The purpose of this change is to align the gxl and g12a driver +declaration. + +Like on the g12a variant, remove genphy_aneg_done() from the driver +declaration as the net phy framework will default to it anyway. + +Also, the gxl phy id should be an exact match as well, so let's change +this and use the macro provided. + +Signed-off-by: Jerome Brunet +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +(cherry picked from commit fad137c4ef073c45fe7696680a555262d48319db + git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master) +Signed-off-by: Neil Armstrong +--- + drivers/net/phy/meson-gxl.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c +index 2033c93a46ca8..6d4a8c508ec0c 100644 +--- a/drivers/net/phy/meson-gxl.c ++++ b/drivers/net/phy/meson-gxl.c +@@ -224,14 +224,12 @@ static int meson_gxl_config_intr(struct phy_device *phydev) + + static struct phy_driver meson_gxl_phy[] = { + { +- .phy_id = 0x01814400, +- .phy_id_mask = 0xfffffff0, ++ PHY_ID_MATCH_EXACT(0x01814400), + .name = "Meson GXL Internal PHY", + .features = PHY_BASIC_FEATURES, + .flags = PHY_IS_INTERNAL, + .soft_reset = genphy_soft_reset, + .config_init = meson_gxl_config_init, +- .aneg_done = genphy_aneg_done, + .read_status = meson_gxl_read_status, + .ack_interrupt = meson_gxl_ack_interrupt, + .config_intr = meson_gxl_config_intr, +@@ -251,7 +249,7 @@ static struct phy_driver meson_gxl_phy[] = { + }; + + static struct mdio_device_id __maybe_unused meson_gxl_tbl[] = { +- { 0x01814400, 0xfffffff0 }, ++ { PHY_ID_MATCH_VENDOR(0x01814400) }, + { PHY_ID_MATCH_VENDOR(0x01803301) }, + { } + }; + +From 0e4b883ac1f54130d46554898d7949b87a346fbb Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Mon, 1 Apr 2019 20:18:16 +0200 +Subject: [PATCH 102/249] UPSTREAM: pwm: meson: Consider 128 a valid + pre-divider +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The pre-divider allows configuring longer PWM periods compared to using +the input clock directly. The pre-divider is 7 bit wide, meaning it's +maximum value is 128 (the register value is off-by-one: 0x7f or 127). + +Change the loop to also allow for the maximum possible value to be +considered valid. + +Fixes: 211ed630753d2f ("pwm: Add support for Meson PWM Controller") +Signed-off-by: Martin Blumenstingl +Acked-by: Uwe Kleine-König +Reviewed-by: Neil Armstrong +Signed-off-by: Thierry Reding +(cherry picked from commit 51496e4446875726d50a5617a6e0e0dabbc2e6da) +--- + drivers/pwm/pwm-meson.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c +index c1ed641b3e266..aaae48ab484ef 100644 +--- a/drivers/pwm/pwm-meson.c ++++ b/drivers/pwm/pwm-meson.c +@@ -184,7 +184,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, + do_div(fin_ps, fin_freq); + + /* Calc pre_div with the period */ +- for (pre_div = 0; pre_div < MISC_CLK_DIV_MASK; pre_div++) { ++ for (pre_div = 0; pre_div <= MISC_CLK_DIV_MASK; pre_div++) { + cnt = DIV_ROUND_CLOSEST_ULL((u64)period * 1000, + fin_ps * (pre_div + 1)); + dev_dbg(meson->chip.dev, "fin_ps=%llu pre_div=%u cnt=%u\n", +@@ -193,7 +193,7 @@ static int meson_pwm_calc(struct meson_pwm *meson, + break; + } + +- if (pre_div == MISC_CLK_DIV_MASK) { ++ if (pre_div > MISC_CLK_DIV_MASK) { + dev_err(meson->chip.dev, "unable to get period pre_div\n"); + return -EINVAL; + } + +From b05b882710e729104362dcc5537c8882478b5f43 Mon Sep 17 00:00:00 2001 +From: Bichao Zheng +Date: Mon, 1 Apr 2019 20:18:17 +0200 +Subject: [PATCH 103/249] UPSTREAM: pwm: meson: Don't disable PWM when setting + duty repeatedly + +There is an abnormally low about 20ms,when setting duty repeatedly. +Because setting the duty will disable PWM and then enable. Delete +this operation now. + +Fixes: 211ed630753d2f ("pwm: Add support for Meson PWM Controller") +Signed-off-by: Bichao Zheng +[ Dropped code instead of hiding it behind a comment ] +Signed-off-by: Martin Blumenstingl +Reviewed-by: Neil Armstrong +Signed-off-by: Thierry Reding +(cherry picked from commit a279345807e1e0ae79567a52cfdd9d30c9174a3c) +Signed-off-by: Neil Armstrong +--- + drivers/pwm/pwm-meson.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c +index aaae48ab484ef..2ab3d216b35a7 100644 +--- a/drivers/pwm/pwm-meson.c ++++ b/drivers/pwm/pwm-meson.c +@@ -314,11 +314,6 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + if (state->period != channel->state.period || + state->duty_cycle != channel->state.duty_cycle || + state->polarity != channel->state.polarity) { +- if (channel->state.enabled) { +- meson_pwm_disable(meson, pwm->hwpwm); +- channel->state.enabled = false; +- } +- + if (state->polarity != channel->state.polarity) { + if (state->polarity == PWM_POLARITY_NORMAL) + meson->inverter_mask |= BIT(pwm->hwpwm); + +From 099f5fac8ef04d59ccd148a843c9054da83a82fd Mon Sep 17 00:00:00 2001 +From: Martin Blumenstingl +Date: Mon, 1 Apr 2019 19:57:48 +0200 +Subject: [PATCH 104/249] UPSTREAM: pwm: meson: Use the spin-lock only to + protect register modifications +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Holding the spin-lock for all of the code in meson_pwm_apply() can +result in a "BUG: scheduling while atomic". This can happen because +clk_get_rate() (which is called from meson_pwm_calc()) may sleep. +Only hold the spin-lock when modifying registers to solve this. + +The reason why we need a spin-lock in the driver is because the +REG_MISC_AB register is shared between the two channels provided by one +PWM controller. The only functions where REG_MISC_AB is modified are +meson_pwm_enable() and meson_pwm_disable() so the register reads/writes +in there need to be protected by the spin-lock. + +The original code also used the spin-lock to protect the values in +struct meson_pwm_channel. This could be necessary if two consumers can +use the same PWM channel. However, PWM core doesn't allow this so we +don't need to protect the values in struct meson_pwm_channel with a +lock. + +Fixes: 211ed630753d2f ("pwm: Add support for Meson PWM Controller") +Signed-off-by: Martin Blumenstingl +Reviewed-by: Uwe Kleine-König +Reviewed-by: Neil Armstrong +Signed-off-by: Thierry Reding +(cherry picked from commit f173747fffdf037c791405ab4f1ec0eb392fc48e) +Signed-off-by: Neil Armstrong +--- + drivers/pwm/pwm-meson.c | 25 +++++++++++++++++-------- + 1 file changed, 17 insertions(+), 8 deletions(-) + +diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c +index 2ab3d216b35a7..e247ab632530b 100644 +--- a/drivers/pwm/pwm-meson.c ++++ b/drivers/pwm/pwm-meson.c +@@ -111,6 +111,10 @@ struct meson_pwm { + const struct meson_pwm_data *data; + void __iomem *base; + u8 inverter_mask; ++ /* ++ * Protects register (write) access to the REG_MISC_AB register ++ * that is shared between the two PWMs. ++ */ + spinlock_t lock; + }; + +@@ -235,6 +239,7 @@ static void meson_pwm_enable(struct meson_pwm *meson, + { + u32 value, clk_shift, clk_enable, enable; + unsigned int offset; ++ unsigned long flags; + + switch (id) { + case 0: +@@ -255,6 +260,8 @@ static void meson_pwm_enable(struct meson_pwm *meson, + return; + } + ++ spin_lock_irqsave(&meson->lock, flags); ++ + value = readl(meson->base + REG_MISC_AB); + value &= ~(MISC_CLK_DIV_MASK << clk_shift); + value |= channel->pre_div << clk_shift; +@@ -267,11 +274,14 @@ static void meson_pwm_enable(struct meson_pwm *meson, + value = readl(meson->base + REG_MISC_AB); + value |= enable; + writel(value, meson->base + REG_MISC_AB); ++ ++ spin_unlock_irqrestore(&meson->lock, flags); + } + + static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id) + { + u32 value, enable; ++ unsigned long flags; + + switch (id) { + case 0: +@@ -286,9 +296,13 @@ static void meson_pwm_disable(struct meson_pwm *meson, unsigned int id) + return; + } + ++ spin_lock_irqsave(&meson->lock, flags); ++ + value = readl(meson->base + REG_MISC_AB); + value &= ~enable; + writel(value, meson->base + REG_MISC_AB); ++ ++ spin_unlock_irqrestore(&meson->lock, flags); + } + + static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, +@@ -296,19 +310,16 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + { + struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); + struct meson_pwm *meson = to_meson_pwm(chip); +- unsigned long flags; + int err = 0; + + if (!state) + return -EINVAL; + +- spin_lock_irqsave(&meson->lock, flags); +- + if (!state->enabled) { + meson_pwm_disable(meson, pwm->hwpwm); + channel->state.enabled = false; + +- goto unlock; ++ return 0; + } + + if (state->period != channel->state.period || +@@ -324,7 +335,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + err = meson_pwm_calc(meson, channel, pwm->hwpwm, + state->duty_cycle, state->period); + if (err < 0) +- goto unlock; ++ return err; + + channel->state.polarity = state->polarity; + channel->state.period = state->period; +@@ -336,9 +347,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + channel->state.enabled = true; + } + +-unlock: +- spin_unlock_irqrestore(&meson->lock, flags); +- return err; ++ return 0; + } + + static void meson_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + +From 8851941f3d6c6857d72a612e5966a6f93faa5158 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 23 Apr 2019 15:36:44 +0200 +Subject: [PATCH 105/249] UPSTREAM: dt-bindings: pwm: Update bindings for the + Meson G12A Family + +Update the doc to explicitly support Meson G12A Family. +The 2 first (A & B) AO PWM uses different clock source than the last 2 +(C & D) AO PWM modules, thus we need to differentiate them. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Reviewed-by: Rob Herring +Signed-off-by: Thierry Reding +(cherry picked from commit ad36cb9186bc805b8fd0b9908469e29617211658) +--- + Documentation/devicetree/bindings/pwm/pwm-meson.txt | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Documentation/devicetree/bindings/pwm/pwm-meson.txt b/Documentation/devicetree/bindings/pwm/pwm-meson.txt +index 1fa3f71821334..8916323540652 100644 +--- a/Documentation/devicetree/bindings/pwm/pwm-meson.txt ++++ b/Documentation/devicetree/bindings/pwm/pwm-meson.txt +@@ -7,6 +7,9 @@ Required properties: + or "amlogic,meson-gxbb-ao-pwm" + or "amlogic,meson-axg-ee-pwm" + or "amlogic,meson-axg-ao-pwm" ++ or "amlogic,meson-g12a-ee-pwm" ++ or "amlogic,meson-g12a-ao-pwm-ab" ++ or "amlogic,meson-g12a-ao-pwm-cd" + - #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. + + +From 816a0e0c017cf15e5b4b13cc63b80724762a5289 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 23 Apr 2019 15:36:45 +0200 +Subject: [PATCH 106/249] UPSTREAM: pwm: meson: Add clock source configuration + for Meson G12A + +For the PWM controller in the Meson G12A SoC, the EE domain and AO domain +have different clock sources. This patch tries to describe them in the +DT compatible data. The two AO PWM controller has different clock source, +but the first AO controller (A & B) can reuse the AXG parents name. + +Signed-off-by: Neil Armstrong +Reviewed-by: Martin Blumenstingl +Signed-off-by: Thierry Reding +(cherry picked from commit f41efceb46e697a750e93c19e4579dc50697effe) +--- + drivers/pwm/pwm-meson.c | 30 ++++++++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c +index e247ab632530b..ba748027ecbf1 100644 +--- a/drivers/pwm/pwm-meson.c ++++ b/drivers/pwm/pwm-meson.c +@@ -433,6 +433,24 @@ static const struct meson_pwm_data pwm_axg_ao_data = { + .num_parents = ARRAY_SIZE(pwm_axg_ao_parent_names), + }; + ++static const char * const pwm_g12a_ao_cd_parent_names[] = { ++ "aoclk81", "xtal", ++}; ++ ++static const struct meson_pwm_data pwm_g12a_ao_cd_data = { ++ .parent_names = pwm_g12a_ao_cd_parent_names, ++ .num_parents = ARRAY_SIZE(pwm_g12a_ao_cd_parent_names), ++}; ++ ++static const char * const pwm_g12a_ee_parent_names[] = { ++ "xtal", "hdmi_pll", "fclk_div4", "fclk_div3" ++}; ++ ++static const struct meson_pwm_data pwm_g12a_ee_data = { ++ .parent_names = pwm_g12a_ee_parent_names, ++ .num_parents = ARRAY_SIZE(pwm_g12a_ee_parent_names), ++}; ++ + static const struct of_device_id meson_pwm_matches[] = { + { + .compatible = "amlogic,meson8b-pwm", +@@ -454,6 +472,18 @@ static const struct of_device_id meson_pwm_matches[] = { + .compatible = "amlogic,meson-axg-ao-pwm", + .data = &pwm_axg_ao_data + }, ++ { ++ .compatible = "amlogic,meson-g12a-ee-pwm", ++ .data = &pwm_g12a_ee_data ++ }, ++ { ++ .compatible = "amlogic,meson-g12a-ao-pwm-ab", ++ .data = &pwm_axg_ao_data ++ }, ++ { ++ .compatible = "amlogic,meson-g12a-ao-pwm-cd", ++ .data = &pwm_g12a_ao_cd_data ++ }, + {}, + }; + MODULE_DEVICE_TABLE(of, meson_pwm_matches); + +From 6094f4aeb36b06313fe8dd456a0f8ced3f9889d4 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 23 Apr 2019 11:02:29 +0200 +Subject: [PATCH 107/249] UPSTREAM: mmc: meson-gx: remove open coded read with + timeout + +There is already a function available to poll a register until a +condition is met. Let's use it instead of open coding it. + +Reviewed-by: Martin Blumenstingl +Signed-off-by: Jerome Brunet +Reviewed-by: Kevin Hilman +Signed-off-by: Ulf Hansson +(cherry picked from commit 98849da63fffdc010dca6e6f6785c2e2ff34e807) +Signed-off-by: Neil Armstrong +--- + drivers/mmc/host/meson-gx-mmc.c | 18 ++++-------------- + 1 file changed, 4 insertions(+), 14 deletions(-) + +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index 2eba507790e49..2deeacc051b1c 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1100,7 +1101,6 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) + + static int meson_mmc_wait_desc_stop(struct meson_host *host) + { +- int loop; + u32 status; + + /* +@@ -1110,20 +1110,10 @@ static int meson_mmc_wait_desc_stop(struct meson_host *host) + * If we don't confirm the descriptor is stopped, it might raise new + * IRQs after we have called mmc_request_done() which is bad. + */ +- for (loop = 50; loop; loop--) { +- status = readl(host->regs + SD_EMMC_STATUS); +- if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) +- udelay(100); +- else +- break; +- } + +- if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) { +- dev_err(host->dev, "Timed out waiting for host to stop\n"); +- return -ETIMEDOUT; +- } +- +- return 0; ++ return readl_poll_timeout(host->regs + SD_EMMC_STATUS, status, ++ !(status & (STATUS_BUSY | STATUS_DESC_BUSY)), ++ 100, 5000); + } + + static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) + +From 5d5e8be448e8a093bf1de6c5f7b7e159f91f50dc Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 23 Apr 2019 11:02:30 +0200 +Subject: [PATCH 108/249] UPSTREAM: mmc: meson-gx: ack only raised irq + +This is merely a clean up. It makes sense to only ack raised irqs +instead of acking everything all the time. + +Signed-off-by: Jerome Brunet +Acked-by: Martin Blumenstingl +Reviewed-by: Kevin Hilman +Signed-off-by: Ulf Hansson +(cherry picked from commit 9c5fdb07a28d730d4907d48905f06680691851e8) +Signed-off-by: Neil Armstrong +--- + drivers/mmc/host/meson-gx-mmc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index 2deeacc051b1c..8b690ecde4c5f 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -1082,9 +1082,6 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) + } + + out: +- /* ack all enabled interrupts */ +- writel(irq_en, host->regs + SD_EMMC_STATUS); +- + if (cmd->error) { + /* Stop desc in case of errors */ + u32 start = readl(host->regs + SD_EMMC_START); +@@ -1096,6 +1093,9 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) + if (ret == IRQ_HANDLED) + meson_mmc_request_done(host->mmc, cmd->mrq); + ++ /* ack all raised interrupts */ ++ writel(status, host->regs + SD_EMMC_STATUS); ++ + return ret; + } + + +From 97267342fd64e62dc931f55679480c84e7cfcb8c Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 23 Apr 2019 11:02:31 +0200 +Subject: [PATCH 109/249] UPSTREAM: mmc: meson-gx: correct irq flag + +There is no reason for another device to request the MMC irq. It should +only be used the MMC device, so remove IRQ_SHARED and replace by +IRQ_ONESHOT as we don't the irq to fire again until the irq thread is +done + +Signed-off-by: Jerome Brunet +Reviewed-by: Martin Blumenstingl +Reviewed-by: Kevin Hilman +Signed-off-by: Ulf Hansson +(cherry picked from commit eb4d811277465784e2d25d74c19183295d4499ab) +Signed-off-by: Neil Armstrong +--- + drivers/mmc/host/meson-gx-mmc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index 8b690ecde4c5f..3df50b53f8341 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -1328,7 +1328,7 @@ static int meson_mmc_probe(struct platform_device *pdev) + host->regs + SD_EMMC_IRQ_EN); + + ret = request_threaded_irq(host->irq, meson_mmc_irq, +- meson_mmc_irq_thread, IRQF_SHARED, ++ meson_mmc_irq_thread, IRQF_ONESHOT, + dev_name(&pdev->dev), host); + if (ret) + goto err_init_clk; + +From d764d585346e1d74f66d530133fa38954fc808b3 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 23 Apr 2019 11:02:32 +0200 +Subject: [PATCH 110/249] UPSTREAM: mmc: meson-gx: disable HS400 + +At the moment, all our attempts to enable HS400 on Amlogic chipsets have +been unsuccessful or unreliable. Until we can figure out how to enable this +mode safely and reliably, let's force it off. + +Signed-off-by: Jerome Brunet +Acked-by: Martin Blumenstingl +Reviewed-by: Kevin Hilman +Signed-off-by: Ulf Hansson +(cherry picked from commit d5f758f2df8015b8dcf47b6403cc192e4cef734d) +Signed-off-by: Neil Armstrong +--- + drivers/mmc/host/meson-gx-mmc.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index 3df50b53f8341..118f09da8dfbc 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -823,10 +823,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + if (meson_mmc_timing_is_ddr(ios)) + val |= CFG_DDR; + +- val &= ~CFG_CHK_DS; +- if (ios->timing == MMC_TIMING_MMC_HS400) +- val |= CFG_CHK_DS; +- + err = meson_mmc_clk_set(host, ios); + if (err) + dev_err(host->dev, "Failed to set clock: %d\n,", err); +@@ -1339,6 +1335,13 @@ static int meson_mmc_probe(struct platform_device *pdev) + mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc); + mmc->max_seg_size = mmc->max_req_size; + ++ /* ++ * At the moment, we don't know how to reliably enable HS400. ++ * From the different datasheets, it is not even clear if this mode ++ * is officially supported by any of the SoCs ++ */ ++ mmc->caps2 &= ~MMC_CAP2_HS400; ++ + /* data bounce buffer */ + host->bounce_buf_size = mmc->max_req_size; + host->bounce_buf = + +From b1330d44e875c09c8209816151ef96c9f115fdbb Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 23 Apr 2019 11:02:33 +0200 +Subject: [PATCH 111/249] UPSTREAM: mmc: meson-gx: avoid clock glitch when + switching to DDR modes + +Activating DDR in the Amlogic mmc controller, among other things, will +divide the output clock by 2. So by activating it with clock on, we are +creating a glitch on the output. + +Instead, let's deal with DDR when the clock output is off, when setting +the clock. + +Signed-off-by: Jerome Brunet +Tested-by: Martin Blumenstingl +Reviewed-by: Kevin Hilman +Signed-off-by: Ulf Hansson +(cherry picked from commit dc38ac8141a664f4cc96306e6de85f68bbee92b9) +Signed-off-by: Neil Armstrong +--- + drivers/mmc/host/meson-gx-mmc.c | 73 +++++++++++++++++++-------------- + 1 file changed, 43 insertions(+), 30 deletions(-) + +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index 118f09da8dfbc..0454021c9ff5e 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -169,6 +169,7 @@ struct meson_host { + struct clk *rx_clk; + struct clk *tx_clk; + unsigned long req_rate; ++ bool ddr; + + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; +@@ -384,16 +385,6 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, + mmc_get_dma_dir(data)); + } + +-static bool meson_mmc_timing_is_ddr(struct mmc_ios *ios) +-{ +- if (ios->timing == MMC_TIMING_MMC_DDR52 || +- ios->timing == MMC_TIMING_UHS_DDR50 || +- ios->timing == MMC_TIMING_MMC_HS400) +- return true; +- +- return false; +-} +- + /* + * Gating the clock on this controller is tricky. It seems the mmc clock + * is also used by the controller. It may crash during some operation if the +@@ -430,36 +421,41 @@ static void meson_mmc_clk_ungate(struct meson_host *host) + writel(cfg, host->regs + SD_EMMC_CFG); + } + +-static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) ++static int meson_mmc_clk_set(struct meson_host *host, unsigned long rate, ++ bool ddr) + { + struct mmc_host *mmc = host->mmc; +- unsigned long rate = ios->clock; + int ret; + u32 cfg; + +- /* DDR modes require higher module clock */ +- if (meson_mmc_timing_is_ddr(ios)) +- rate <<= 1; +- + /* Same request - bail-out */ +- if (host->req_rate == rate) ++ if (host->ddr == ddr && host->req_rate == rate) + return 0; + + /* stop clock */ + meson_mmc_clk_gate(host); + host->req_rate = 0; ++ mmc->actual_clock = 0; + +- if (!rate) { +- mmc->actual_clock = 0; +- /* return with clock being stopped */ ++ /* return with clock being stopped */ ++ if (!rate) + return 0; +- } + + /* Stop the clock during rate change to avoid glitches */ + cfg = readl(host->regs + SD_EMMC_CFG); + cfg |= CFG_STOP_CLOCK; + writel(cfg, host->regs + SD_EMMC_CFG); + ++ if (ddr) { ++ /* DDR modes require higher module clock */ ++ rate <<= 1; ++ cfg |= CFG_DDR; ++ } else { ++ cfg &= ~CFG_DDR; ++ } ++ writel(cfg, host->regs + SD_EMMC_CFG); ++ host->ddr = ddr; ++ + ret = clk_set_rate(host->mmc_clk, rate); + if (ret) { + dev_err(host->dev, "Unable to set cfg_div_clk to %lu. ret=%d\n", +@@ -471,12 +467,14 @@ static int meson_mmc_clk_set(struct meson_host *host, struct mmc_ios *ios) + mmc->actual_clock = clk_get_rate(host->mmc_clk); + + /* We should report the real output frequency of the controller */ +- if (meson_mmc_timing_is_ddr(ios)) ++ if (ddr) { ++ host->req_rate >>= 1; + mmc->actual_clock >>= 1; ++ } + + dev_dbg(host->dev, "clk rate: %u Hz\n", mmc->actual_clock); +- if (ios->clock != mmc->actual_clock) +- dev_dbg(host->dev, "requested rate was %u\n", ios->clock); ++ if (rate != mmc->actual_clock) ++ dev_dbg(host->dev, "requested rate was %lu\n", rate); + + /* (re)start clock */ + meson_mmc_clk_ungate(host); +@@ -750,6 +748,25 @@ static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) + return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); + } + ++static int meson_mmc_prepare_ios_clock(struct meson_host *host, ++ struct mmc_ios *ios) ++{ ++ bool ddr; ++ ++ switch (ios->timing) { ++ case MMC_TIMING_MMC_DDR52: ++ case MMC_TIMING_UHS_DDR50: ++ ddr = true; ++ break; ++ ++ default: ++ ddr = false; ++ break; ++ } ++ ++ return meson_mmc_clk_set(host, ios->clock, ddr); ++} ++ + static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + { + struct meson_host *host = mmc_priv(mmc); +@@ -818,16 +835,12 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + val = readl(host->regs + SD_EMMC_CFG); + val &= ~CFG_BUS_WIDTH_MASK; + val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width); ++ writel(val, host->regs + SD_EMMC_CFG); + +- val &= ~CFG_DDR; +- if (meson_mmc_timing_is_ddr(ios)) +- val |= CFG_DDR; +- +- err = meson_mmc_clk_set(host, ios); ++ err = meson_mmc_prepare_ios_clock(host, ios); + if (err) + dev_err(host->dev, "Failed to set clock: %d\n,", err); + +- writel(val, host->regs + SD_EMMC_CFG); + dev_dbg(host->dev, "SD_EMMC_CFG: 0x%08x\n", val); + } + + +From 387ac95ff367eeef80c061632b6b1622531aed85 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 23 Apr 2019 11:02:34 +0200 +Subject: [PATCH 112/249] UPSTREAM: mmc: meson-gx: remove Rx phase tuning + +This remove all the code related to phase settings. Using the Rx phase +for tuning has not been reliable. We had several issues over the past +months, on both v2 and v3 mmc chips After discussing the issue matter +with Amlogic, They suggested to set a phase shift of 180 between Core and +Tx and use signal resampling for the tuning. + +Since we won't be playing with the phase anymore, let's remove all the +clock code related to it and set the appropriate value on init. + +Signed-off-by: Jerome Brunet +Tested-by: Martin Blumenstingl +Reviewed-by: Kevin Hilman +Signed-off-by: Ulf Hansson +(cherry picked from commit 5e6f75f42393d1619ca426a4909df963cc814fbc) +Signed-off-by: Neil Armstrong +--- + drivers/mmc/host/meson-gx-mmc.c | 290 ++------------------------------ + 1 file changed, 13 insertions(+), 277 deletions(-) + +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index 0454021c9ff5e..acdc5520d02cc 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -49,6 +49,8 @@ + #define CLK_CORE_PHASE_MASK GENMASK(9, 8) + #define CLK_TX_PHASE_MASK GENMASK(11, 10) + #define CLK_RX_PHASE_MASK GENMASK(13, 12) ++#define CLK_PHASE_0 0 ++#define CLK_PHASE_180 2 + #define CLK_V2_TX_DELAY_MASK GENMASK(19, 16) + #define CLK_V2_RX_DELAY_MASK GENMASK(23, 20) + #define CLK_V2_ALWAYS_ON BIT(24) +@@ -57,10 +59,6 @@ + #define CLK_V3_RX_DELAY_MASK GENMASK(27, 22) + #define CLK_V3_ALWAYS_ON BIT(28) + +-#define CLK_DELAY_STEP_PS 200 +-#define CLK_PHASE_STEP 30 +-#define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP) +- + #define CLK_TX_DELAY_MASK(h) (h->data->tx_delay_mask) + #define CLK_RX_DELAY_MASK(h) (h->data->rx_delay_mask) + #define CLK_ALWAYS_ON(h) (h->data->always_on) +@@ -165,9 +163,8 @@ struct meson_host { + + void __iomem *regs; + struct clk *core_clk; ++ struct clk *mux_clk; + struct clk *mmc_clk; +- struct clk *rx_clk; +- struct clk *tx_clk; + unsigned long req_rate; + bool ddr; + +@@ -209,90 +206,6 @@ struct meson_host { + #define CMD_RESP_MASK GENMASK(31, 1) + #define CMD_RESP_SRAM BIT(0) + +-struct meson_mmc_phase { +- struct clk_hw hw; +- void __iomem *reg; +- unsigned long phase_mask; +- unsigned long delay_mask; +- unsigned int delay_step_ps; +-}; +- +-#define to_meson_mmc_phase(_hw) container_of(_hw, struct meson_mmc_phase, hw) +- +-static int meson_mmc_clk_get_phase(struct clk_hw *hw) +-{ +- struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); +- unsigned int phase_num = 1 << hweight_long(mmc->phase_mask); +- unsigned long period_ps, p, d; +- int degrees; +- u32 val; +- +- val = readl(mmc->reg); +- p = (val & mmc->phase_mask) >> __ffs(mmc->phase_mask); +- degrees = p * 360 / phase_num; +- +- if (mmc->delay_mask) { +- period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, +- clk_get_rate(hw->clk)); +- d = (val & mmc->delay_mask) >> __ffs(mmc->delay_mask); +- degrees += d * mmc->delay_step_ps * 360 / period_ps; +- degrees %= 360; +- } +- +- return degrees; +-} +- +-static void meson_mmc_apply_phase_delay(struct meson_mmc_phase *mmc, +- unsigned int phase, +- unsigned int delay) +-{ +- u32 val; +- +- val = readl(mmc->reg); +- val &= ~mmc->phase_mask; +- val |= phase << __ffs(mmc->phase_mask); +- +- if (mmc->delay_mask) { +- val &= ~mmc->delay_mask; +- val |= delay << __ffs(mmc->delay_mask); +- } +- +- writel(val, mmc->reg); +-} +- +-static int meson_mmc_clk_set_phase(struct clk_hw *hw, int degrees) +-{ +- struct meson_mmc_phase *mmc = to_meson_mmc_phase(hw); +- unsigned int phase_num = 1 << hweight_long(mmc->phase_mask); +- unsigned long period_ps, d = 0, r; +- uint64_t p; +- +- p = degrees % 360; +- +- if (!mmc->delay_mask) { +- p = DIV_ROUND_CLOSEST_ULL(p, 360 / phase_num); +- } else { +- period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, +- clk_get_rate(hw->clk)); +- +- /* First compute the phase index (p), the remainder (r) is the +- * part we'll try to acheive using the delays (d). +- */ +- r = do_div(p, 360 / phase_num); +- d = DIV_ROUND_CLOSEST(r * period_ps, +- 360 * mmc->delay_step_ps); +- d = min(d, mmc->delay_mask >> __ffs(mmc->delay_mask)); +- } +- +- meson_mmc_apply_phase_delay(mmc, p, d); +- return 0; +-} +- +-static const struct clk_ops meson_mmc_clk_phase_ops = { +- .get_phase = meson_mmc_clk_get_phase, +- .set_phase = meson_mmc_clk_set_phase, +-}; +- + static unsigned int meson_mmc_get_timeout_msecs(struct mmc_data *data) + { + unsigned int timeout = data->timeout_ns / NSEC_PER_MSEC; +@@ -492,8 +405,6 @@ static int meson_mmc_clk_init(struct meson_host *host) + struct clk_init_data init; + struct clk_mux *mux; + struct clk_divider *div; +- struct meson_mmc_phase *core, *tx, *rx; +- struct clk *clk; + char clk_name[32]; + int i, ret = 0; + const char *mux_parent_names[MUX_CLK_NUM_PARENTS]; +@@ -501,9 +412,11 @@ static int meson_mmc_clk_init(struct meson_host *host) + u32 clk_reg; + + /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ +- clk_reg = 0; +- clk_reg |= CLK_ALWAYS_ON(host); ++ clk_reg = CLK_ALWAYS_ON(host); + clk_reg |= CLK_DIV_MASK; ++ clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180); ++ clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_0); ++ clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0); + writel(clk_reg, host->regs + SD_EMMC_CLOCK); + + /* get the mux parents */ +@@ -539,9 +452,9 @@ static int meson_mmc_clk_init(struct meson_host *host) + mux->mask = CLK_SRC_MASK >> mux->shift; + mux->hw.init = &init; + +- clk = devm_clk_register(host->dev, &mux->hw); +- if (WARN_ON(IS_ERR(clk))) +- return PTR_ERR(clk); ++ host->mux_clk = devm_clk_register(host->dev, &mux->hw); ++ if (WARN_ON(IS_ERR(host->mux_clk))) ++ return PTR_ERR(host->mux_clk); + + /* create the divider */ + div = devm_kzalloc(host->dev, sizeof(*div), GFP_KERNEL); +@@ -552,7 +465,7 @@ static int meson_mmc_clk_init(struct meson_host *host) + init.name = clk_name; + init.ops = &clk_divider_ops; + init.flags = CLK_SET_RATE_PARENT; +- clk_parent[0] = __clk_get_name(clk); ++ clk_parent[0] = __clk_get_name(host->mux_clk); + init.parent_names = clk_parent; + init.num_parents = 1; + +@@ -562,192 +475,19 @@ static int meson_mmc_clk_init(struct meson_host *host) + div->hw.init = &init; + div->flags = CLK_DIVIDER_ONE_BASED; + +- clk = devm_clk_register(host->dev, &div->hw); +- if (WARN_ON(IS_ERR(clk))) +- return PTR_ERR(clk); +- +- /* create the mmc core clock */ +- core = devm_kzalloc(host->dev, sizeof(*core), GFP_KERNEL); +- if (!core) +- return -ENOMEM; +- +- snprintf(clk_name, sizeof(clk_name), "%s#core", dev_name(host->dev)); +- init.name = clk_name; +- init.ops = &meson_mmc_clk_phase_ops; +- init.flags = CLK_SET_RATE_PARENT; +- clk_parent[0] = __clk_get_name(clk); +- init.parent_names = clk_parent; +- init.num_parents = 1; +- +- core->reg = host->regs + SD_EMMC_CLOCK; +- core->phase_mask = CLK_CORE_PHASE_MASK; +- core->hw.init = &init; +- +- host->mmc_clk = devm_clk_register(host->dev, &core->hw); +- if (WARN_ON(PTR_ERR_OR_ZERO(host->mmc_clk))) ++ host->mmc_clk = devm_clk_register(host->dev, &div->hw); ++ if (WARN_ON(IS_ERR(host->mmc_clk))) + return PTR_ERR(host->mmc_clk); + +- /* create the mmc tx clock */ +- tx = devm_kzalloc(host->dev, sizeof(*tx), GFP_KERNEL); +- if (!tx) +- return -ENOMEM; +- +- snprintf(clk_name, sizeof(clk_name), "%s#tx", dev_name(host->dev)); +- init.name = clk_name; +- init.ops = &meson_mmc_clk_phase_ops; +- init.flags = 0; +- clk_parent[0] = __clk_get_name(host->mmc_clk); +- init.parent_names = clk_parent; +- init.num_parents = 1; +- +- tx->reg = host->regs + SD_EMMC_CLOCK; +- tx->phase_mask = CLK_TX_PHASE_MASK; +- tx->delay_mask = CLK_TX_DELAY_MASK(host); +- tx->delay_step_ps = CLK_DELAY_STEP_PS; +- tx->hw.init = &init; +- +- host->tx_clk = devm_clk_register(host->dev, &tx->hw); +- if (WARN_ON(PTR_ERR_OR_ZERO(host->tx_clk))) +- return PTR_ERR(host->tx_clk); +- +- /* create the mmc rx clock */ +- rx = devm_kzalloc(host->dev, sizeof(*rx), GFP_KERNEL); +- if (!rx) +- return -ENOMEM; +- +- snprintf(clk_name, sizeof(clk_name), "%s#rx", dev_name(host->dev)); +- init.name = clk_name; +- init.ops = &meson_mmc_clk_phase_ops; +- init.flags = 0; +- clk_parent[0] = __clk_get_name(host->mmc_clk); +- init.parent_names = clk_parent; +- init.num_parents = 1; +- +- rx->reg = host->regs + SD_EMMC_CLOCK; +- rx->phase_mask = CLK_RX_PHASE_MASK; +- rx->delay_mask = CLK_RX_DELAY_MASK(host); +- rx->delay_step_ps = CLK_DELAY_STEP_PS; +- rx->hw.init = &init; +- +- host->rx_clk = devm_clk_register(host->dev, &rx->hw); +- if (WARN_ON(PTR_ERR_OR_ZERO(host->rx_clk))) +- return PTR_ERR(host->rx_clk); +- + /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ + host->mmc->f_min = clk_round_rate(host->mmc_clk, 400000); + ret = clk_set_rate(host->mmc_clk, host->mmc->f_min); + if (ret) + return ret; + +- clk_set_phase(host->mmc_clk, 180); +- clk_set_phase(host->tx_clk, 0); +- clk_set_phase(host->rx_clk, 0); +- + return clk_prepare_enable(host->mmc_clk); + } + +-static void meson_mmc_shift_map(unsigned long *map, unsigned long shift) +-{ +- DECLARE_BITMAP(left, CLK_PHASE_POINT_NUM); +- DECLARE_BITMAP(right, CLK_PHASE_POINT_NUM); +- +- /* +- * shift the bitmap right and reintroduce the dropped bits on the left +- * of the bitmap +- */ +- bitmap_shift_right(right, map, shift, CLK_PHASE_POINT_NUM); +- bitmap_shift_left(left, map, CLK_PHASE_POINT_NUM - shift, +- CLK_PHASE_POINT_NUM); +- bitmap_or(map, left, right, CLK_PHASE_POINT_NUM); +-} +- +-static void meson_mmc_find_next_region(unsigned long *map, +- unsigned long *start, +- unsigned long *stop) +-{ +- *start = find_next_bit(map, CLK_PHASE_POINT_NUM, *start); +- *stop = find_next_zero_bit(map, CLK_PHASE_POINT_NUM, *start); +-} +- +-static int meson_mmc_find_tuning_point(unsigned long *test) +-{ +- unsigned long shift, stop, offset = 0, start = 0, size = 0; +- +- /* Get the all good/all bad situation out the way */ +- if (bitmap_full(test, CLK_PHASE_POINT_NUM)) +- return 0; /* All points are good so point 0 will do */ +- else if (bitmap_empty(test, CLK_PHASE_POINT_NUM)) +- return -EIO; /* No successful tuning point */ +- +- /* +- * Now we know there is a least one region find. Make sure it does +- * not wrap by the shifting the bitmap if necessary +- */ +- shift = find_first_zero_bit(test, CLK_PHASE_POINT_NUM); +- if (shift != 0) +- meson_mmc_shift_map(test, shift); +- +- while (start < CLK_PHASE_POINT_NUM) { +- meson_mmc_find_next_region(test, &start, &stop); +- +- if ((stop - start) > size) { +- offset = start; +- size = stop - start; +- } +- +- start = stop; +- } +- +- /* Get the center point of the region */ +- offset += (size / 2); +- +- /* Shift the result back */ +- offset = (offset + shift) % CLK_PHASE_POINT_NUM; +- +- return offset; +-} +- +-static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode, +- struct clk *clk) +-{ +- int point, ret; +- DECLARE_BITMAP(test, CLK_PHASE_POINT_NUM); +- +- dev_dbg(mmc_dev(mmc), "%s phase/delay tunning...\n", +- __clk_get_name(clk)); +- bitmap_zero(test, CLK_PHASE_POINT_NUM); +- +- /* Explore tuning points */ +- for (point = 0; point < CLK_PHASE_POINT_NUM; point++) { +- clk_set_phase(clk, point * CLK_PHASE_STEP); +- ret = mmc_send_tuning(mmc, opcode, NULL); +- if (!ret) +- set_bit(point, test); +- } +- +- /* Find the optimal tuning point and apply it */ +- point = meson_mmc_find_tuning_point(test); +- if (point < 0) +- return point; /* tuning failed */ +- +- clk_set_phase(clk, point * CLK_PHASE_STEP); +- dev_dbg(mmc_dev(mmc), "success with phase: %d\n", +- clk_get_phase(clk)); +- return 0; +-} +- +-static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +-{ +- struct meson_host *host = mmc_priv(mmc); +- int adj = 0; +- +- /* enable signal resampling w/o delay */ +- adj = ADJUST_ADJ_EN; +- writel(adj, host->regs + host->data->adjust); +- +- return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk); +-} +- + static int meson_mmc_prepare_ios_clock(struct meson_host *host, + struct mmc_ios *ios) + { +@@ -796,9 +536,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + /* disable signal resampling */ + writel(0, host->regs + host->data->adjust); + +- /* Reset rx phase */ +- clk_set_phase(host->rx_clk, 0); +- + break; + + case MMC_POWER_ON: +@@ -1226,7 +963,6 @@ static const struct mmc_host_ops meson_mmc_ops = { + .get_cd = meson_mmc_get_cd, + .pre_req = meson_mmc_pre_req, + .post_req = meson_mmc_post_req, +- .execute_tuning = meson_mmc_execute_tuning, + .card_busy = meson_mmc_card_busy, + .start_signal_voltage_switch = meson_mmc_voltage_switch, + }; + +From c71c4edd8d6b76ca10e523f12848cd2985868284 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 23 Apr 2019 11:02:35 +0200 +Subject: [PATCH 113/249] UPSTREAM: mmc: meson-gx: add signal resampling tuning + +Use signal resampling tuning for the UHS and HS200 modes. +Instead of trying to get the *best* resampling setting with complex +window calculation, we just stop on the first working setting. + +If the tuning setting later proves unstable, we will just continue the +tuning where we left it. + +Signed-off-by: Jerome Brunet +Tested-by: Martin Blumenstingl +Reviewed-by: Kevin Hilman +Signed-off-by: Ulf Hansson +(cherry picked from commit f50b7ac5e4ed33f5d2095bfecf48e0671289d188) +Signed-off-by: Neil Armstrong +--- + drivers/mmc/host/meson-gx-mmc.c | 73 +++++++++++++++++++++++++++++++-- + 1 file changed, 70 insertions(+), 3 deletions(-) + +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index acdc5520d02cc..c5a8af4ca76b2 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -488,6 +488,61 @@ static int meson_mmc_clk_init(struct meson_host *host) + return clk_prepare_enable(host->mmc_clk); + } + ++static void meson_mmc_disable_resampling(struct meson_host *host) ++{ ++ unsigned int val = readl(host->regs + host->data->adjust); ++ ++ val &= ~ADJUST_ADJ_EN; ++ writel(val, host->regs + host->data->adjust); ++} ++ ++static void meson_mmc_reset_resampling(struct meson_host *host) ++{ ++ unsigned int val; ++ ++ meson_mmc_disable_resampling(host); ++ ++ val = readl(host->regs + host->data->adjust); ++ val &= ~ADJUST_ADJ_DELAY_MASK; ++ writel(val, host->regs + host->data->adjust); ++} ++ ++static int meson_mmc_resampling_tuning(struct mmc_host *mmc, u32 opcode) ++{ ++ struct meson_host *host = mmc_priv(mmc); ++ unsigned int val, dly, max_dly, i; ++ int ret; ++ ++ /* Resampling is done using the source clock */ ++ max_dly = DIV_ROUND_UP(clk_get_rate(host->mux_clk), ++ clk_get_rate(host->mmc_clk)); ++ ++ val = readl(host->regs + host->data->adjust); ++ val |= ADJUST_ADJ_EN; ++ writel(val, host->regs + host->data->adjust); ++ ++ if (mmc->doing_retune) ++ dly = FIELD_GET(ADJUST_ADJ_DELAY_MASK, val) + 1; ++ else ++ dly = 0; ++ ++ for (i = 0; i < max_dly; i++) { ++ val &= ~ADJUST_ADJ_DELAY_MASK; ++ val |= FIELD_PREP(ADJUST_ADJ_DELAY_MASK, (dly + i) % max_dly); ++ writel(val, host->regs + host->data->adjust); ++ ++ ret = mmc_send_tuning(mmc, opcode, NULL); ++ if (!ret) { ++ dev_dbg(mmc_dev(mmc), "resampling delay: %u\n", ++ (dly + i) % max_dly); ++ return 0; ++ } ++ } ++ ++ meson_mmc_reset_resampling(host); ++ return -EIO; ++} ++ + static int meson_mmc_prepare_ios_clock(struct meson_host *host, + struct mmc_ios *ios) + { +@@ -507,6 +562,19 @@ static int meson_mmc_prepare_ios_clock(struct meson_host *host, + return meson_mmc_clk_set(host, ios->clock, ddr); + } + ++static void meson_mmc_check_resampling(struct meson_host *host, ++ struct mmc_ios *ios) ++{ ++ switch (ios->timing) { ++ case MMC_TIMING_LEGACY: ++ case MMC_TIMING_MMC_HS: ++ case MMC_TIMING_SD_HS: ++ case MMC_TIMING_MMC_DDR52: ++ meson_mmc_disable_resampling(host); ++ break; ++ } ++} ++ + static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + { + struct meson_host *host = mmc_priv(mmc); +@@ -533,9 +601,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); + +- /* disable signal resampling */ +- writel(0, host->regs + host->data->adjust); +- + break; + + case MMC_POWER_ON: +@@ -574,6 +639,7 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + val |= FIELD_PREP(CFG_BUS_WIDTH_MASK, bus_width); + writel(val, host->regs + SD_EMMC_CFG); + ++ meson_mmc_check_resampling(host, ios); + err = meson_mmc_prepare_ios_clock(host, ios); + if (err) + dev_err(host->dev, "Failed to set clock: %d\n,", err); +@@ -963,6 +1029,7 @@ static const struct mmc_host_ops meson_mmc_ops = { + .get_cd = meson_mmc_get_cd, + .pre_req = meson_mmc_pre_req, + .post_req = meson_mmc_post_req, ++ .execute_tuning = meson_mmc_resampling_tuning, + .card_busy = meson_mmc_card_busy, + .start_signal_voltage_switch = meson_mmc_voltage_switch, + }; + +From 4bfdc07be57722cdad3a17d174d2d1d2f4653ce1 Mon Sep 17 00:00:00 2001 +From: Hans Verkuil +Date: Wed, 10 Apr 2019 05:13:29 -0400 +Subject: [PATCH 114/249] UPSTREAM: media: meson: ao-cec: use new + cec_notifier_parse_hdmi_phandle helper + +The meson CEC driver increased the HDMI device refcount when +it shouldn't. Use the new helper function to ensure that that +doesn't happen and to simplify the driver code. + +Signed-off-by: Hans Verkuil +Acked-by: Neil Armstrong +Signed-off-by: Mauro Carvalho Chehab +(cherry picked from commit 6bc37729df640748ed1718e3f150d63cbff1dc7e) +Signed-off-by: Neil Armstrong +--- + drivers/media/platform/meson/ao-cec.c | 16 +++++----------- + 1 file changed, 5 insertions(+), 11 deletions(-) + +diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c +index cd4be38ab5acc..facf9b029e797 100644 +--- a/drivers/media/platform/meson/ao-cec.c ++++ b/drivers/media/platform/meson/ao-cec.c +@@ -601,20 +601,14 @@ static const struct cec_adap_ops meson_ao_cec_ops = { + static int meson_ao_cec_probe(struct platform_device *pdev) + { + struct meson_ao_cec_device *ao_cec; +- struct platform_device *hdmi_dev; +- struct device_node *np; ++ struct device *hdmi_dev; + struct resource *res; + int ret, irq; + +- np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); +- if (!np) { +- dev_err(&pdev->dev, "Failed to find hdmi node\n"); +- return -ENODEV; +- } ++ hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); + +- hdmi_dev = of_find_device_by_node(np); +- if (hdmi_dev == NULL) +- return -EPROBE_DEFER; ++ if (IS_ERR(hdmi_dev)) ++ return PTR_ERR(hdmi_dev); + + ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); + if (!ao_cec) +@@ -622,7 +616,7 @@ static int meson_ao_cec_probe(struct platform_device *pdev) + + spin_lock_init(&ao_cec->cec_reg_lock); + +- ao_cec->notify = cec_notifier_get(&hdmi_dev->dev); ++ ao_cec->notify = cec_notifier_get(hdmi_dev); + if (!ao_cec->notify) + return -ENOMEM; + + +From 63e581a76dc7cf1cbd4390ba0d5c59fa114c068d Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Sun, 12 May 2019 22:57:43 +0200 +Subject: [PATCH 115/249] FROMLIST: clk: meson: fix MPLL 50M binding id typo + +MPLL_5OM (the capital letter o) should indeed be MPLL_50M (the number) +Fix this before it gets used. + +Reported-by: Martin Blumenstingl +Fixes: 25db146aa726 ("dt-bindings: clk: meson: add g12a periph clock controller bindings") +Signed-off-by: Jerome Brunet +Acked-by: Neil Armstrong +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 4 ++-- + drivers/clk/meson/g12a.h | 2 +- + include/dt-bindings/clock/g12a-clkc.h | 2 +- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index 739f64fdf1e3b..206fafd299ea6 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -2734,8 +2734,8 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { + [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, + [CLKID_MALI_1] = &g12a_mali_1.hw, + [CLKID_MALI] = &g12a_mali.hw, +- [CLKID_MPLL_5OM_DIV] = &g12a_mpll_50m_div.hw, +- [CLKID_MPLL_5OM] = &g12a_mpll_50m.hw, ++ [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw, ++ [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, + [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, + [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, + [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, +diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h +index 39c41af708044..bcc05cd9882f0 100644 +--- a/drivers/clk/meson/g12a.h ++++ b/drivers/clk/meson/g12a.h +@@ -166,7 +166,7 @@ + #define CLKID_HDMI_DIV 167 + #define CLKID_MALI_0_DIV 170 + #define CLKID_MALI_1_DIV 173 +-#define CLKID_MPLL_5OM_DIV 176 ++#define CLKID_MPLL_50M_DIV 176 + #define CLKID_SYS_PLL_DIV16_EN 178 + #define CLKID_SYS_PLL_DIV16 179 + #define CLKID_CPU_CLK_DYN0_SEL 180 +diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h +index 82c9e0c020b21..e10470ed7c4f1 100644 +--- a/include/dt-bindings/clock/g12a-clkc.h ++++ b/include/dt-bindings/clock/g12a-clkc.h +@@ -130,7 +130,7 @@ + #define CLKID_MALI_1_SEL 172 + #define CLKID_MALI_1 174 + #define CLKID_MALI 175 +-#define CLKID_MPLL_5OM 177 ++#define CLKID_MPLL_50M 177 + #define CLKID_CPU_CLK 187 + #define CLKID_PCIE_PLL 201 + #define CLKID_VDEC_1 204 + +From 589f53ff8c99f92174d3ff072062b58a8ec2e619 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:45:31 +0200 +Subject: [PATCH 116/249] FROMLIST: clk: meson: g12a: fix gp0 and hifi ranges + +While some SoC samples are able to lock with a PLL factor of 55, others +samples can't. ATM, a minimum of 60 appears to work on all the samples +I have tried. + +Even with 60, it sometimes takes a long time for the PLL to eventually +lock. The documentation says that the minimum rate of these PLLs DCO +should be 3GHz, a factor of 125. Let's use that to be on the safe side. + +With factor range changed, the PLL seems to lock quickly (enough) so far. +It is still unclear if the range was the only reason for the delay. + +Fixes: 085a4ea93d54 ("clk: meson: g12a: add peripheral clock controller") +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index 206fafd299ea6..d11606d5ddbd6 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -463,7 +463,7 @@ static struct clk_regmap g12a_cpu_clk_trace = { + }; + + static const struct pll_mult_range g12a_gp0_pll_mult_range = { +- .min = 55, ++ .min = 125, + .max = 255, + }; + + +From d0b436a7fe01aeb89d2264ae7b019cf68bddf5ae Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:31:09 +0200 +Subject: [PATCH 117/249] FROMLIST: clk: meson: mpll: properly handle spread + spectrum + +The bit 'SSEN' available on some MPLL DSS outputs is not related to the +fractional part of the divider but to the function called +'Spread Spectrum'. + +This function might be used to solve EM issues by adding a jitter on +clock signal. This widens the signal spectrum and weakens the peaks in it. + +While spread spectrum might be useful for some application, it is +problematic for others, such as audio. + +This patch introduce a new flag to the MPLL driver to enable (or not) the +spread spectrum function. + +Fixes: 1f737ffa13ef ("clk: meson: mpll: fix mpll0 fractional part ignored") +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/clk-mpll.c | 9 ++++++--- + drivers/clk/meson/clk-mpll.h | 1 + + 2 files changed, 7 insertions(+), 3 deletions(-) + +diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c +index f76850d99e591..d3f42e0864313 100644 +--- a/drivers/clk/meson/clk-mpll.c ++++ b/drivers/clk/meson/clk-mpll.c +@@ -119,9 +119,12 @@ static int mpll_set_rate(struct clk_hw *hw, + meson_parm_write(clk->map, &mpll->sdm, sdm); + meson_parm_write(clk->map, &mpll->sdm_en, 1); + +- /* Set additional fractional part enable if required */ +- if (MESON_PARM_APPLICABLE(&mpll->ssen)) +- meson_parm_write(clk->map, &mpll->ssen, 1); ++ /* Set spread spectrum if possible */ ++ if (MESON_PARM_APPLICABLE(&mpll->ssen)) { ++ unsigned int ss = ++ mpll->flags & CLK_MESON_MPLL_SPREAD_SPECTRUM ? 1 : 0; ++ meson_parm_write(clk->map, &mpll->ssen, ss); ++ } + + /* Set the integer divider part */ + meson_parm_write(clk->map, &mpll->n2, n2); +diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h +index cf79340006dd7..0f948430fed48 100644 +--- a/drivers/clk/meson/clk-mpll.h ++++ b/drivers/clk/meson/clk-mpll.h +@@ -23,6 +23,7 @@ struct meson_clk_mpll_data { + }; + + #define CLK_MESON_MPLL_ROUND_CLOSEST BIT(0) ++#define CLK_MESON_MPLL_SPREAD_SPECTRUM BIT(1) + + extern const struct clk_ops meson_clk_mpll_ro_ops; + extern const struct clk_ops meson_clk_mpll_ops; + +From 5b3d82d3de68220a8b8d8e1e7ba0922e124296ca Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:31:10 +0200 +Subject: [PATCH 118/249] FROMLIST: clk: meson: gxbb: no spread spectrum on + mpll0 + +The documentation says there is an SSEN bit on mpll0 but, after testing +it, no spread spectrum function appears to be enabled by this bit on any +of the MPLLs. + +Let's remove it until we know more + +Fixes: 1f737ffa13ef ("clk: meson: mpll: fix mpll0 fractional part ignored") +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/gxbb.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c +index 29ffb4fde7145..dab16d9b1af8b 100644 +--- a/drivers/clk/meson/gxbb.c ++++ b/drivers/clk/meson/gxbb.c +@@ -679,11 +679,6 @@ static struct clk_regmap gxbb_mpll0_div = { + .shift = 16, + .width = 9, + }, +- .ssen = { +- .reg_off = HHI_MPLL_CNTL, +- .shift = 25, +- .width = 1, +- }, + .lock = &meson_clk_lock, + }, + .hw.init = &(struct clk_init_data){ + +From 4e091b46ecd6d09322b9c19ff791a5eb69f4ffed Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:31:11 +0200 +Subject: [PATCH 119/249] FROMLIST: clk: meson: axg: spread spectrum is on + mpll2 + +After testing, it appears that the SSEN bit controls the spread +spectrum function on MPLL2, not MPLL0. + +Fixes: 78b4af312f91 ("clk: meson-axg: add clock controller drivers") +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/axg.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c +index 7a8ef80e5f2cb..3ddd0efc9ee0b 100644 +--- a/drivers/clk/meson/axg.c ++++ b/drivers/clk/meson/axg.c +@@ -469,11 +469,6 @@ static struct clk_regmap axg_mpll0_div = { + .shift = 16, + .width = 9, + }, +- .ssen = { +- .reg_off = HHI_MPLL_CNTL, +- .shift = 25, +- .width = 1, +- }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 0, +@@ -568,6 +563,11 @@ static struct clk_regmap axg_mpll2_div = { + .shift = 16, + .width = 9, + }, ++ .ssen = { ++ .reg_off = HHI_MPLL_CNTL, ++ .shift = 25, ++ .width = 1, ++ }, + .misc = { + .reg_off = HHI_PLL_TOP_MISC, + .shift = 2, + +From 7fb2041c723972b7ab631af3d5e2aac145a3a23a Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:31:12 +0200 +Subject: [PATCH 120/249] FROMLIST: clk: meson: mpll: add init callback and + regs + +Until now (gx and axg), the mpll setting on boot (whatever the +bootloader) was good enough to generate a clean fractional division. + +It is not the case on the g12a. While moving away from the vendor u-boot, +it was noticed the fractional part of the divider was no longer applied. +Like on the pll, some magic settings need to applied on the mpll +register. + +This change adds the ability to do that on the mpll driver. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/clk-mpll.c | 35 ++++++++++++++++++++++++----------- + drivers/clk/meson/clk-mpll.h | 2 ++ + 2 files changed, 26 insertions(+), 11 deletions(-) + +diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c +index d3f42e0864313..2d39a8bc367c3 100644 +--- a/drivers/clk/meson/clk-mpll.c ++++ b/drivers/clk/meson/clk-mpll.c +@@ -115,8 +115,30 @@ static int mpll_set_rate(struct clk_hw *hw, + else + __acquire(mpll->lock); + +- /* Enable and set the fractional part */ ++ /* Set the fractional part */ + meson_parm_write(clk->map, &mpll->sdm, sdm); ++ ++ /* Set the integer divider part */ ++ meson_parm_write(clk->map, &mpll->n2, n2); ++ ++ if (mpll->lock) ++ spin_unlock_irqrestore(mpll->lock, flags); ++ else ++ __release(mpll->lock); ++ ++ return 0; ++} ++ ++static void mpll_init(struct clk_hw *hw) ++{ ++ struct clk_regmap *clk = to_clk_regmap(hw); ++ struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk); ++ ++ if (mpll->init_count) ++ regmap_multi_reg_write(clk->map, mpll->init_regs, ++ mpll->init_count); ++ ++ /* Enable the fractional part */ + meson_parm_write(clk->map, &mpll->sdm_en, 1); + + /* Set spread spectrum if possible */ +@@ -126,19 +148,9 @@ static int mpll_set_rate(struct clk_hw *hw, + meson_parm_write(clk->map, &mpll->ssen, ss); + } + +- /* Set the integer divider part */ +- meson_parm_write(clk->map, &mpll->n2, n2); +- + /* Set the magic misc bit if required */ + if (MESON_PARM_APPLICABLE(&mpll->misc)) + meson_parm_write(clk->map, &mpll->misc, 1); +- +- if (mpll->lock) +- spin_unlock_irqrestore(mpll->lock, flags); +- else +- __release(mpll->lock); +- +- return 0; + } + + const struct clk_ops meson_clk_mpll_ro_ops = { +@@ -151,6 +163,7 @@ const struct clk_ops meson_clk_mpll_ops = { + .recalc_rate = mpll_recalc_rate, + .round_rate = mpll_round_rate, + .set_rate = mpll_set_rate, ++ .init = mpll_init, + }; + EXPORT_SYMBOL_GPL(meson_clk_mpll_ops); + +diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h +index 0f948430fed48..a991d568c43ae 100644 +--- a/drivers/clk/meson/clk-mpll.h ++++ b/drivers/clk/meson/clk-mpll.h +@@ -18,6 +18,8 @@ struct meson_clk_mpll_data { + struct parm n2; + struct parm ssen; + struct parm misc; ++ const struct reg_sequence *init_regs; ++ unsigned int init_count; + spinlock_t *lock; + u8 flags; + }; + +From 2bb779d258c73f180152ec74ddd4c3b51ed4a205 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:31:13 +0200 +Subject: [PATCH 121/249] FROMLIST: clk: meson: g12a: add mpll register init + sequences + +Add the required init of each MPLL of the g12a. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index d11606d5ddbd6..ef1d2e4c8fd28 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -1001,6 +1001,10 @@ static struct clk_fixed_factor g12a_mpll_prediv = { + }, + }; + ++static const struct reg_sequence g12a_mpll0_init_regs[] = { ++ { .reg = HHI_MPLL_CNTL2, .def = 0x40000033 }, ++}; ++ + static struct clk_regmap g12a_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { +@@ -1024,6 +1028,8 @@ static struct clk_regmap g12a_mpll0_div = { + .width = 1, + }, + .lock = &meson_clk_lock, ++ .init_regs = g12a_mpll0_init_regs, ++ .init_count = ARRAY_SIZE(g12a_mpll0_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", +@@ -1047,6 +1053,10 @@ static struct clk_regmap g12a_mpll0 = { + }, + }; + ++static const struct reg_sequence g12a_mpll1_init_regs[] = { ++ { .reg = HHI_MPLL_CNTL4, .def = 0x40000033 }, ++}; ++ + static struct clk_regmap g12a_mpll1_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { +@@ -1070,6 +1080,8 @@ static struct clk_regmap g12a_mpll1_div = { + .width = 1, + }, + .lock = &meson_clk_lock, ++ .init_regs = g12a_mpll1_init_regs, ++ .init_count = ARRAY_SIZE(g12a_mpll1_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll1_div", +@@ -1093,6 +1105,10 @@ static struct clk_regmap g12a_mpll1 = { + }, + }; + ++static const struct reg_sequence g12a_mpll2_init_regs[] = { ++ { .reg = HHI_MPLL_CNTL6, .def = 0x40000033 }, ++}; ++ + static struct clk_regmap g12a_mpll2_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { +@@ -1116,6 +1132,8 @@ static struct clk_regmap g12a_mpll2_div = { + .width = 1, + }, + .lock = &meson_clk_lock, ++ .init_regs = g12a_mpll2_init_regs, ++ .init_count = ARRAY_SIZE(g12a_mpll2_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll2_div", +@@ -1139,6 +1157,10 @@ static struct clk_regmap g12a_mpll2 = { + }, + }; + ++static const struct reg_sequence g12a_mpll3_init_regs[] = { ++ { .reg = HHI_MPLL_CNTL8, .def = 0x40000033 }, ++}; ++ + static struct clk_regmap g12a_mpll3_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { +@@ -1162,6 +1184,8 @@ static struct clk_regmap g12a_mpll3_div = { + .width = 1, + }, + .lock = &meson_clk_lock, ++ .init_regs = g12a_mpll3_init_regs, ++ .init_count = ARRAY_SIZE(g12a_mpll3_init_regs), + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll3_div", + +From 4d87e27519b27bacd736e5ed46bc0f952ecf5819 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:31:14 +0200 +Subject: [PATCH 122/249] FROMLIST: clk: meson: eeclk: add init regs + +Like the PLL and MPLL, the controller may require some magic setting to +be applied on startup. + +This is needed when the initial setting is not applied by the boot ROM. +The controller need to do it when the setting applies to several clock, +like all the MPLLs in the case of g12a. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/meson-eeclk.c | 3 +++ + drivers/clk/meson/meson-eeclk.h | 2 ++ + 2 files changed, 5 insertions(+) + +diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c +index 37a34c9c3885e..6ba2094be2577 100644 +--- a/drivers/clk/meson/meson-eeclk.c ++++ b/drivers/clk/meson/meson-eeclk.c +@@ -34,6 +34,9 @@ int meson_eeclkc_probe(struct platform_device *pdev) + return PTR_ERR(map); + } + ++ if (data->init_count) ++ regmap_multi_reg_write(map, data->init_regs, data->init_count); ++ + input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0); + if (IS_ERR(input)) { + ret = PTR_ERR(input); +diff --git a/drivers/clk/meson/meson-eeclk.h b/drivers/clk/meson/meson-eeclk.h +index 1b809b1419fe0..9ab5d6fa7ccb2 100644 +--- a/drivers/clk/meson/meson-eeclk.h ++++ b/drivers/clk/meson/meson-eeclk.h +@@ -17,6 +17,8 @@ struct platform_device; + struct meson_eeclkc_data { + struct clk_regmap *const *regmap_clks; + unsigned int regmap_clk_num; ++ const struct reg_sequence *init_regs; ++ unsigned int init_count; + struct clk_hw_onecell_data *hw_onecell_data; + }; + + +From aa923cd99d1ffd071e7db0319162e0905b0800ac Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 May 2019 14:31:15 +0200 +Subject: [PATCH 123/249] FROMLIST: clk: meson: g12a: add controller register + init + +Add the MPLL common register initial setting + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index ef1d2e4c8fd28..d5aceb79a91a8 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -2992,10 +2992,16 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { + &g12a_vdec_hevcf, + }; + ++static const struct reg_sequence g12a_init_regs[] = { ++ { .reg = HHI_MPLL_CNTL0, .def = 0x00000543 }, ++}; ++ + static const struct meson_eeclkc_data g12a_clkc_data = { + .regmap_clks = g12a_clk_regmaps, + .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), +- .hw_onecell_data = &g12a_hw_onecell_data ++ .hw_onecell_data = &g12a_hw_onecell_data, ++ .init_regs = g12a_init_regs, ++ .init_count = ARRAY_SIZE(g12a_init_regs), + }; + + static const struct of_device_id clkc_match_table[] = { + +From 428bbcedc99fd5b073aab2c775cfd9f78fa78ce9 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Fri, 10 May 2019 10:23:19 +0200 +Subject: [PATCH 124/249] FROMLIST: dt-bindings: pinctrl: add a + 'drive-strength-microamp' property + +This property allow drive-strength parameter in uA instead of mA. + +Signed-off-by: Guillaume La Roque +Reviewed-by: Martin Blumenstingl +Reviewed-by: Rob Herring +Signed-off-by: Neil Armstrong +--- + Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +index cef2b5855d60f..fcd37e93ed4da 100644 +--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt ++++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +@@ -258,6 +258,7 @@ drive-push-pull - drive actively high and low + drive-open-drain - drive with open drain + drive-open-source - drive with open source + drive-strength - sink or source at most X mA ++drive-strength-microamp - sink or source at most X uA + input-enable - enable input on pin (no effect on output, such as + enabling an input buffer) + input-disable - disable input on pin (no effect on output, such as +@@ -326,6 +327,8 @@ arguments are described below. + + - drive-strength takes as argument the target strength in mA. + ++- drive-strength-microamp takes as argument the target strength in uA. ++ + - input-debounce takes the debounce time in usec as argument + or 0 to disable debouncing + + +From 0e9d1f0da2925ab28e8ab022c0cd9621ef99abaf Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Fri, 10 May 2019 10:23:20 +0200 +Subject: [PATCH 125/249] FROMLIST: pinctrl: generic: add new + 'drive-strength-microamp' property support + +Add drive-strength-microamp property support to allow drive strength in uA + +Signed-off-by: Guillaume La Roque +Signed-off-by: Neil Armstrong +--- + drivers/pinctrl/pinconf-generic.c | 2 ++ + include/linux/pinctrl/pinconf-generic.h | 3 +++ + 2 files changed, 5 insertions(+) + +diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c +index b4f7f8a458eaf..d0cbdb1ad76a9 100644 +--- a/drivers/pinctrl/pinconf-generic.c ++++ b/drivers/pinctrl/pinconf-generic.c +@@ -39,6 +39,7 @@ static const struct pin_config_item conf_items[] = { + PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false), + PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false), + PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true), ++ PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true), + PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true), + PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false), + PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false), +@@ -167,6 +168,7 @@ static const struct pinconf_generic_params dt_params[] = { + { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, + { "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, ++ { "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 }, + { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, +diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h +index 6c06806411084..72d06d6a30996 100644 +--- a/include/linux/pinctrl/pinconf-generic.h ++++ b/include/linux/pinctrl/pinconf-generic.h +@@ -55,6 +55,8 @@ + * push-pull mode, the argument is ignored. + * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current + * passed as argument. The argument is in mA. ++ * @PIN_CONFIG_DRIVE_STRENGTH_UA: the pin will sink or source at most the current ++ * passed as argument. The argument is in uA. + * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode, + * which means it will wait for signals to settle when reading inputs. The + * argument gives the debounce time in usecs. Setting the +@@ -112,6 +114,7 @@ enum pin_config_param { + PIN_CONFIG_DRIVE_OPEN_SOURCE, + PIN_CONFIG_DRIVE_PUSH_PULL, + PIN_CONFIG_DRIVE_STRENGTH, ++ PIN_CONFIG_DRIVE_STRENGTH_UA, + PIN_CONFIG_INPUT_DEBOUNCE, + PIN_CONFIG_INPUT_ENABLE, + PIN_CONFIG_INPUT_SCHMITT, + +From de9a915165524d151dd47bf21b8151e7ac064e7b Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Fri, 10 May 2019 10:23:21 +0200 +Subject: [PATCH 126/249] FROMLIST: dt-bindings: pinctrl: meson: Add + drive-strength-microamp property + +Add optional drive-strength-microamp property + +Signed-off-by: Guillaume La Roque +Reviewed-by: Martin Blumenstingl +Reviewed-by: Rob Herring +Signed-off-by: Neil Armstrong +--- + Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt +index a47dd990a8d3a..a7618605bf1ef 100644 +--- a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt ++++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt +@@ -51,6 +51,10 @@ Configuration nodes support the generic properties "bias-disable", + "bias-pull-up" and "bias-pull-down", described in file + pinctrl-bindings.txt + ++Optional properties : ++ - drive-strength-microamp: Drive strength for the specified pins in uA. ++ This property is only valid for G12A and newer. ++ + === Example === + + pinctrl: pinctrl@c1109880 { + +From 7ed2690c52c38d99e53111045774987dd4dc0a37 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Fri, 10 May 2019 10:23:22 +0200 +Subject: [PATCH 127/249] FROMLIST: pinctrl: meson: Rework enable/disable bias + part + +rework bias enable/disable part to prepare drive-strength integration +no functional changes + +Signed-off-by: Guillaume La Roque +Reviewed-by: Martin Blumenstingl +Tested-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +--- + drivers/pinctrl/meson/pinctrl-meson.c | 85 +++++++++++++++------------ + 1 file changed, 49 insertions(+), 36 deletions(-) + +diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c +index 96a4a72708e49..8ea5c1527064c 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson.c ++++ b/drivers/pinctrl/meson/pinctrl-meson.c +@@ -174,62 +174,75 @@ int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector, + return 0; + } + +-static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, +- unsigned long *configs, unsigned num_configs) ++static int meson_pinconf_disable_bias(struct meson_pinctrl *pc, ++ unsigned int pin) + { +- struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + struct meson_bank *bank; +- enum pin_config_param param; +- unsigned int reg, bit; +- int i, ret; ++ unsigned int reg, bit = 0; ++ int ret; + + ret = meson_get_bank(pc, pin, &bank); + if (ret) + return ret; + ++ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); ++ ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), 0); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin, ++ bool pull_up) ++{ ++ struct meson_bank *bank; ++ unsigned int reg, bit, val = 0; ++ int ret; ++ ++ ret = meson_get_bank(pc, pin, &bank); ++ if (ret) ++ return ret; ++ ++ meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); ++ if (pull_up) ++ val = BIT(bit); ++ ++ ret = regmap_update_bits(pc->reg_pull, reg, BIT(bit), val); ++ if (ret) ++ return ret; ++ ++ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, &bit); ++ ret = regmap_update_bits(pc->reg_pullen, reg, BIT(bit), BIT(bit)); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, ++ unsigned long *configs, unsigned num_configs) ++{ ++ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); ++ enum pin_config_param param; ++ int i, ret; ++ + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: +- dev_dbg(pc->dev, "pin %u: disable bias\n", pin); +- +- meson_calc_reg_and_bit(bank, pin, REG_PULLEN, ®, +- &bit); +- ret = regmap_update_bits(pc->reg_pullen, reg, +- BIT(bit), 0); ++ ret = meson_pinconf_disable_bias(pc, pin); + if (ret) + return ret; + break; + case PIN_CONFIG_BIAS_PULL_UP: +- dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin); +- +- meson_calc_reg_and_bit(bank, pin, REG_PULLEN, +- ®, &bit); +- ret = regmap_update_bits(pc->reg_pullen, reg, +- BIT(bit), BIT(bit)); +- if (ret) +- return ret; +- +- meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); +- ret = regmap_update_bits(pc->reg_pull, reg, +- BIT(bit), BIT(bit)); ++ ret = meson_pinconf_enable_bias(pc, pin, true); + if (ret) + return ret; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: +- dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin); +- +- meson_calc_reg_and_bit(bank, pin, REG_PULLEN, +- ®, &bit); +- ret = regmap_update_bits(pc->reg_pullen, reg, +- BIT(bit), BIT(bit)); +- if (ret) +- return ret; +- +- meson_calc_reg_and_bit(bank, pin, REG_PULL, ®, &bit); +- ret = regmap_update_bits(pc->reg_pull, reg, +- BIT(bit), 0); ++ ret = meson_pinconf_enable_bias(pc, pin, false); + if (ret) + return ret; + break; + +From 68c85a8e2e96de2ca61723034539f136f5e8cba4 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Fri, 10 May 2019 10:23:23 +0200 +Subject: [PATCH 128/249] FROMLIST: pinctrl: meson: add support of + drive-strength-microamp + +drive-strength-microamp is a new feature needed for G12A SoC. +the default DS setting after boot is usually 500uA and it is not enough for +many functions. We need to be able to set the drive strength to reliably +enable things like MMC, I2C, etc ... + +Signed-off-by: Guillaume La Roque +Reviewed-by: Martin Blumenstingl +Tested-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +--- + drivers/pinctrl/meson/pinctrl-meson.c | 99 +++++++++++++++++++++++++++ + drivers/pinctrl/meson/pinctrl-meson.h | 18 ++++- + 2 files changed, 116 insertions(+), 1 deletion(-) + +diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c +index 8ea5c1527064c..33b4b141baac6 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson.c ++++ b/drivers/pinctrl/meson/pinctrl-meson.c +@@ -220,11 +220,54 @@ static int meson_pinconf_enable_bias(struct meson_pinctrl *pc, unsigned int pin, + return 0; + } + ++static int meson_pinconf_set_drive_strength(struct meson_pinctrl *pc, ++ unsigned int pin, ++ u16 drive_strength_ua) ++{ ++ struct meson_bank *bank; ++ unsigned int reg, bit, ds_val; ++ int ret; ++ ++ if (!pc->reg_ds) { ++ dev_err(pc->dev, "drive-strength not supported\n"); ++ return -ENOTSUPP; ++ } ++ ++ ret = meson_get_bank(pc, pin, &bank); ++ if (ret) ++ return ret; ++ ++ meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit); ++ bit = bit << 1; ++ ++ if (drive_strength_ua <= 500) { ++ ds_val = MESON_PINCONF_DRV_500UA; ++ } else if (drive_strength_ua <= 2500) { ++ ds_val = MESON_PINCONF_DRV_2500UA; ++ } else if (drive_strength_ua <= 3000) { ++ ds_val = MESON_PINCONF_DRV_3000UA; ++ } else if (drive_strength_ua <= 4000) { ++ ds_val = MESON_PINCONF_DRV_4000UA; ++ } else { ++ dev_warn_once(pc->dev, ++ "pin %u: invalid drive-strength : %d , default to 4mA\n", ++ pin, drive_strength_ua); ++ ds_val = MESON_PINCONF_DRV_4000UA; ++ } ++ ++ ret = regmap_update_bits(pc->reg_ds, reg, 0x3 << bit, ds_val << bit); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ + static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *configs, unsigned num_configs) + { + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param; ++ unsigned int drive_strength_ua; + int i, ret; + + for (i = 0; i < num_configs; i++) { +@@ -246,6 +289,14 @@ static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin, + if (ret) + return ret; + break; ++ case PIN_CONFIG_DRIVE_STRENGTH_UA: ++ drive_strength_ua = ++ pinconf_to_config_argument(configs[i]); ++ ret = meson_pinconf_set_drive_strength ++ (pc, pin, drive_strength_ua); ++ if (ret) ++ return ret; ++ break; + default: + return -ENOTSUPP; + } +@@ -288,12 +339,55 @@ static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin) + return conf; + } + ++static int meson_pinconf_get_drive_strength(struct meson_pinctrl *pc, ++ unsigned int pin, ++ u16 *drive_strength_ua) ++{ ++ struct meson_bank *bank; ++ unsigned int reg, bit; ++ unsigned int val; ++ int ret; ++ ++ if (!pc->reg_ds) ++ return -ENOTSUPP; ++ ++ ret = meson_get_bank(pc, pin, &bank); ++ if (ret) ++ return ret; ++ ++ meson_calc_reg_and_bit(bank, pin, REG_DS, ®, &bit); ++ ++ ret = regmap_read(pc->reg_ds, reg, &val); ++ if (ret) ++ return ret; ++ ++ switch ((val >> bit) & 0x3) { ++ case MESON_PINCONF_DRV_500UA: ++ *drive_strength_ua = 500; ++ break; ++ case MESON_PINCONF_DRV_2500UA: ++ *drive_strength_ua = 2500; ++ break; ++ case MESON_PINCONF_DRV_3000UA: ++ *drive_strength_ua = 3000; ++ break; ++ case MESON_PINCONF_DRV_4000UA: ++ *drive_strength_ua = 4000; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ + static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, + unsigned long *config) + { + struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); + enum pin_config_param param = pinconf_to_config_param(*config); + u16 arg; ++ int ret; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: +@@ -304,6 +398,11 @@ static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin, + else + return -EINVAL; + break; ++ case PIN_CONFIG_DRIVE_STRENGTH_UA: ++ ret = meson_pinconf_get_drive_strength(pc, pin, &arg); ++ if (ret) ++ return ret; ++ break; + default: + return -ENOTSUPP; + } +diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h +index 5eaab925f427f..cd955fb7c2ce3 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson.h ++++ b/drivers/pinctrl/meson/pinctrl-meson.h +@@ -71,9 +71,20 @@ enum meson_reg_type { + REG_DIR, + REG_OUT, + REG_IN, ++ REG_DS, + NUM_REG, + }; + ++/** ++ * enum meson_pinconf_drv - value of drive-strength supported ++ */ ++enum meson_pinconf_drv { ++ MESON_PINCONF_DRV_500UA, ++ MESON_PINCONF_DRV_2500UA, ++ MESON_PINCONF_DRV_3000UA, ++ MESON_PINCONF_DRV_4000UA, ++}; ++ + /** + * struct meson bank + * +@@ -132,7 +143,8 @@ struct meson_pinctrl { + .num_groups = ARRAY_SIZE(fn ## _groups), \ + } + +-#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ ++#define BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, \ ++ dsr, dsb) \ + { \ + .name = n, \ + .first = f, \ +@@ -145,9 +157,13 @@ struct meson_pinctrl { + [REG_DIR] = { dr, db }, \ + [REG_OUT] = { or, ob }, \ + [REG_IN] = { ir, ib }, \ ++ [REG_DS] = { dsr, dsb }, \ + }, \ + } + ++#define BANK(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib) \ ++ BANK_DS(n, f, l, fi, li, per, peb, pr, pb, dr, db, or, ob, ir, ib, 0, 0) ++ + #define MESON_PIN(x) PINCTRL_PIN(x, #x) + + /* Common pmx functions */ + +From aff7a16af9e128cd7f1a7ddc01e60b55775abdfc Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Fri, 10 May 2019 10:23:24 +0200 +Subject: [PATCH 129/249] FROMLIST: pinctrl: meson: g12a: add DS bank value + +add drive-strength bank regiter and bit value for G12A SoC + +Signed-off-by: Guillaume La Roque +Reviewed-by: Martin Blumenstingl +Signed-off-by: Neil Armstrong +--- + drivers/pinctrl/meson/pinctrl-meson-g12a.c | 36 +++++++++++----------- + 1 file changed, 18 insertions(+), 18 deletions(-) + +diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c +index d494492e98e9c..3475cd7bd2af3 100644 +--- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c ++++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c +@@ -1304,28 +1304,28 @@ static struct meson_pmx_func meson_g12a_aobus_functions[] = { + }; + + static struct meson_bank meson_g12a_periphs_banks[] = { +- /* name first last irq pullen pull dir out in */ +- BANK("Z", GPIOZ_0, GPIOZ_15, 12, 27, +- 4, 0, 4, 0, 12, 0, 13, 0, 14, 0), +- BANK("H", GPIOH_0, GPIOH_8, 28, 36, +- 3, 0, 3, 0, 9, 0, 10, 0, 11, 0), +- BANK("BOOT", BOOT_0, BOOT_15, 37, 52, +- 0, 0, 0, 0, 0, 0, 1, 0, 2, 0), +- BANK("C", GPIOC_0, GPIOC_7, 53, 60, +- 1, 0, 1, 0, 3, 0, 4, 0, 5, 0), +- BANK("A", GPIOA_0, GPIOA_15, 61, 76, +- 5, 0, 5, 0, 16, 0, 17, 0, 18, 0), +- BANK("X", GPIOX_0, GPIOX_19, 77, 96, +- 2, 0, 2, 0, 6, 0, 7, 0, 8, 0), ++ /* name first last irq pullen pull dir out in ds */ ++ BANK_DS("Z", GPIOZ_0, GPIOZ_15, 12, 27, ++ 4, 0, 4, 0, 12, 0, 13, 0, 14, 0, 5, 0), ++ BANK_DS("H", GPIOH_0, GPIOH_8, 28, 36, ++ 3, 0, 3, 0, 9, 0, 10, 0, 11, 0, 4, 0), ++ BANK_DS("BOOT", BOOT_0, BOOT_15, 37, 52, ++ 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0), ++ BANK_DS("C", GPIOC_0, GPIOC_7, 53, 60, ++ 1, 0, 1, 0, 3, 0, 4, 0, 5, 0, 1, 0), ++ BANK_DS("A", GPIOA_0, GPIOA_15, 61, 76, ++ 5, 0, 5, 0, 16, 0, 17, 0, 18, 0, 6, 0), ++ BANK_DS("X", GPIOX_0, GPIOX_19, 77, 96, ++ 2, 0, 2, 0, 6, 0, 7, 0, 8, 0, 2, 0), + }; + + static struct meson_bank meson_g12a_aobus_banks[] = { +- /* name first last irq pullen pull dir out in */ +- BANK("AO", GPIOAO_0, GPIOAO_11, 0, 11, +- 3, 0, 2, 0, 0, 0, 4, 0, 1, 0), ++ /* name first last irq pullen pull dir out in ds */ ++ BANK_DS("AO", GPIOAO_0, GPIOAO_11, 0, 11, 3, 0, 2, 0, 0, 0, 4, 0, 1, 0, ++ 0, 0), + /* GPIOE actually located in the AO bank */ +- BANK("E", GPIOE_0, GPIOE_2, 97, 99, +- 3, 16, 2, 16, 0, 16, 4, 16, 1, 16), ++ BANK_DS("E", GPIOE_0, GPIOE_2, 97, 99, 3, 16, 2, 16, 0, 16, 4, 16, 1, ++ 16, 1, 0), + }; + + static struct meson_pmx_bank meson_g12a_periphs_pmx_banks[] = { + +From 952c6cf49de885601bc897b6bdf79ec2db2c4483 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 10 May 2019 17:53:26 +0200 +Subject: [PATCH 130/249] FROMLIST: arm64: dts: meson: sei510: consistently + order nodes + +Like order boards, order nodes by address then node names then aliases. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 92 +++++++++---------- + 1 file changed, 46 insertions(+), 46 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 34b40587e5ef1..61fb30047d7fc 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -14,10 +14,6 @@ + compatible = "seirobotics,sei510", "amlogic,g12a"; + model = "SEI Robotics SEI510"; + +- aliases { +- serial0 = &uart_AO; +- }; +- + adc_keys { + compatible = "adc-keys"; + io-channels = <&saradc 0>; +@@ -31,13 +27,8 @@ + }; + }; + +- ao_5v: regulator-ao_5v { +- compatible = "regulator-fixed"; +- regulator-name = "AO_5V"; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- vin-supply = <&dc_in>; +- regulator-always-on; ++ aliases { ++ serial0 = &uart_AO; + }; + + chosen { +@@ -54,23 +45,6 @@ + }; + }; + +- dc_in: regulator-dc_in { +- compatible = "regulator-fixed"; +- regulator-name = "DC_IN"; +- regulator-min-microvolt = <5000000>; +- regulator-max-microvolt = <5000000>; +- regulator-always-on; +- }; +- +- emmc_1v8: regulator-emmc_1v8 { +- compatible = "regulator-fixed"; +- regulator-name = "EMMC_1V8"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- vin-supply = <&vddao_3v3>; +- regulator-always-on; +- }; +- + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; +@@ -87,12 +61,30 @@ + reg = <0x0 0x0 0x0 0x40000000>; + }; + +- reserved-memory { +- /* TEE Reserved Memory */ +- bl32_reserved: bl32@5000000 { +- reg = <0x0 0x05300000 0x0 0x2000000>; +- no-map; +- }; ++ ao_5v: regulator-ao_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "AO_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&dc_in>; ++ regulator-always-on; ++ }; ++ ++ dc_in: regulator-dc_in { ++ compatible = "regulator-fixed"; ++ regulator-name = "DC_IN"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ emmc_1v8: regulator-emmc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "EMMC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; + }; + + vddao_3v3: regulator-vddao_3v3 { +@@ -122,6 +114,14 @@ + vin-supply = <&vddao_3v3>; + regulator-always-on; + }; ++ ++ reserved-memory { ++ /* TEE Reserved Memory */ ++ bl32_reserved: bl32@5000000 { ++ reg = <0x0 0x05300000 0x0 0x2000000>; ++ no-map; ++ }; ++ }; + }; + + &cec_AO { +@@ -144,6 +144,18 @@ + }; + }; + ++&hdmi_tx { ++ status = "okay"; ++ pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&hdmi_tx_tmds_port { ++ hdmi_tx_tmds_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++}; ++ + &saradc { + status = "okay"; + vref-supply = <&vddio_ao1v8>; +@@ -161,18 +173,6 @@ + }; + }; + +-&hdmi_tx { +- status = "okay"; +- pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; +- pinctrl-names = "default"; +-}; +- +-&hdmi_tx_tmds_port { +- hdmi_tx_tmds_out: endpoint { +- remote-endpoint = <&hdmi_connector_in>; +- }; +-}; +- + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + +From 5c90a99c8894a78c50ea33ca287c868081eba99a Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 10 May 2019 17:53:27 +0200 +Subject: [PATCH 131/249] FROMLIST: arm64: dts: meson: u200: consistently order + nodes + +Like order boards, order nodes by address then node names then aliases. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12a-u200.dts | 50 ++++++++++--------- + 1 file changed, 26 insertions(+), 24 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index 0e8045b8a9158..79c70c04ccd19 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -16,13 +16,10 @@ + aliases { + serial0 = &uart_AO; + }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +- memory@0 { +- device_type = "memory"; +- reg = <0x0 0x0 0x0 0x40000000>; +- }; + + cvbs-connector { + compatible = "composite-video-connector"; +@@ -34,15 +31,6 @@ + }; + }; + +- flash_1v8: regulator-flash_1v8 { +- compatible = "regulator-fixed"; +- regulator-name = "FLASH_1V8"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- vin-supply = <&vcc_3v3>; +- regulator-always-on; +- }; +- + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; +@@ -54,6 +42,20 @@ + }; + }; + ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x40000000>; ++ }; ++ ++ flash_1v8: regulator-flash_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "FLASH_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ + main_12v: regulator-main_12v { + compatible = "regulator-fixed"; + regulator-name = "12V"; +@@ -62,6 +64,17 @@ + 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>; ++ ++ gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ + vcc_1v8: regulator-vcc_1v8 { + compatible = "regulator-fixed"; + regulator-name = "VCC_1V8"; +@@ -92,17 +105,6 @@ + enable-active-high; + }; + +- 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>; +- +- gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; +- enable-active-high; +- }; +- + vddao_1v8: regulator-vddao_1v8 { + compatible = "regulator-fixed"; + regulator-name = "VDDAO_1V8"; + +From 886ed10475ae22e15ce16977e6c26cb40d3fc37b Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 10 May 2019 18:49:36 +0200 +Subject: [PATCH 132/249] FROMLIST: arm64: dts: meson: g12a: add ethernet mac + controller + +Add the synopsys ethernet mac controller embedded in the g12a SoC family. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 9f72396ba7103..2034e9d51ad8f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -102,6 +102,27 @@ + #size-cells = <2>; + ranges; + ++ ethmac: ethernet@ff3f0000 { ++ compatible = "amlogic,meson-axg-dwmac", ++ "snps,dwmac-3.70a", ++ "snps,dwmac"; ++ reg = <0x0 0xff3f0000 0x0 0x10000 ++ 0x0 0xff634540 0x0 0x8>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ clocks = <&clkc CLKID_ETH>, ++ <&clkc CLKID_FCLK_DIV2>, ++ <&clkc CLKID_MPLL2>; ++ clock-names = "stmmaceth", "clkin0", "clkin1"; ++ status = "disabled"; ++ ++ mdio0: mdio { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "snps,dwmac-mdio"; ++ }; ++ }; ++ + apb: bus@ff600000 { + compatible = "simple-bus"; + reg = <0x0 0xff600000 0x0 0x200000>; + +From 15ac466d12398b5816c854c5bb32c83e74d8e299 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 10 May 2019 18:49:37 +0200 +Subject: [PATCH 133/249] FROMLIST: arm64: dts: meson: g12a: add ethernet + pinctrl definitions + +Add the ethernet pinctrl settings for RMII, RGMII and internal phy leds + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 37 +++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 2034e9d51ad8f..b26da285ad929 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -206,6 +206,43 @@ + }; + }; + ++ eth_leds_pins: eth-leds { ++ mux { ++ groups = "eth_link_led", ++ "eth_act_led"; ++ function = "eth"; ++ bias-disable; ++ }; ++ }; ++ ++ eth_rmii_pins: eth-rmii { ++ mux { ++ groups = "eth_mdio", ++ "eth_mdc", ++ "eth_rgmii_rx_clk", ++ "eth_rx_dv", ++ "eth_rxd0", ++ "eth_rxd1", ++ "eth_txen", ++ "eth_txd0", ++ "eth_txd1"; ++ function = "eth"; ++ bias-disable; ++ }; ++ }; ++ ++ eth_rgmii_pins: eth-rgmii { ++ mux { ++ groups = "eth_rxd2_rgmii", ++ "eth_rxd3_rgmii", ++ "eth_rgmii_tx_clk", ++ "eth_txd2_rgmii", ++ "eth_txd3_rgmii"; ++ function = "eth"; ++ bias-disable; ++ }; ++ }; ++ + hdmitx_ddc_pins: hdmitx_ddc { + mux { + groups = "hdmitx_sda", + +From aadc5e1356bb4f26e76a307ecc7e58b4528d9688 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 10 May 2019 18:49:38 +0200 +Subject: [PATCH 134/249] FROMLIST: arm64: dts: meson: g12a: add mdio + multiplexer + +Add the g12a mdio multiplexer which allows to connect to either +an external phy through the SoC pins or the internal 10/100 phy + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +[narmstrong: fixed CLKID_MPLL_50M] +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 32 +++++++++++++++++++++ + 1 file changed, 32 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index b26da285ad929..2ab39f39f679f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -372,6 +372,38 @@ + assigned-clock-rates = <100000000>; + #phy-cells = <1>; + }; ++ ++ eth_phy: mdio-multiplexer@4c000 { ++ compatible = "amlogic,g12a-mdio-mux"; ++ reg = <0x0 0x4c000 0x0 0xa4>; ++ clocks = <&clkc CLKID_ETH_PHY>, ++ <&xtal>, ++ <&clkc CLKID_MPLL_50M>; ++ clock-names = "pclk", "clkin0", "clkin1"; ++ mdio-parent-bus = <&mdio0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ext_mdio: mdio@0 { ++ reg = <0>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ }; ++ ++ int_mdio: mdio@1 { ++ reg = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ internal_ephy: ethernet_phy@8 { ++ compatible = "ethernet-phy-id0180.3301", ++ "ethernet-phy-ieee802.3-c22"; ++ interrupts = ; ++ reg = <8>; ++ max-speed = <100>; ++ }; ++ }; ++ }; + }; + + aobus: bus@ff800000 { + +From 99ae6ee90cd8bff09da4f094c963a0552f66f145 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 10 May 2019 18:49:39 +0200 +Subject: [PATCH 135/249] FROMLIST: arm64: dts: meson: u200: add internal + network + +The u200 is the main mother board for the S905D2. It can provide +both the internal and external network. However, by default the +resistance required for the external RGMII bus are not fitted, so +enable the internal PHY. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index 79c70c04ccd19..f1cb02567a130 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -15,6 +15,7 @@ + + aliases { + serial0 = &uart_AO; ++ ethernet0 = ðmac; + }; + + chosen { +@@ -145,6 +146,12 @@ + }; + }; + ++ðmac { ++ status = "okay"; ++ phy-handle = <&internal_ephy>; ++ phy-mode = "rmii"; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; + +From 43d2941fab29f9d4cc12cef8f513dc199ce7c50a Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 10 May 2019 18:49:40 +0200 +Subject: [PATCH 136/249] FROMLIST: arm64: dts: meson: sei510: add network + support + +Enable the network interface of the SEI510 which use the internal PHY. + +Signed-off-by: Jerome Brunet +Tested-by: Kevin Hilman +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 61fb30047d7fc..4a785b17c1af7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -29,6 +29,7 @@ + + aliases { + serial0 = &uart_AO; ++ ethernet0 = ðmac; + }; + + chosen { +@@ -144,6 +145,12 @@ + }; + }; + ++ðmac { ++ status = "okay"; ++ phy-handle = <&internal_ephy>; ++ phy-mode = "rmii"; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; + +From 671da6b5f5c9f385b8a5c04787b9febe0f3e5caf Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Sun, 12 May 2019 23:12:37 +0200 +Subject: [PATCH 137/249] FROMLIST: net: meson: fixup g12a glue ephy id + +The phy id chosen by Amlogic is incorrectly set in the mdio mux and +does not match the phy driver. + +It was not detected before because DT forces the use the correct driver +for the internal PHY. + +Fixes: 7090425104db ("net: phy: add amlogic g12a mdio mux support") +Reported-by: Qi Duan +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/net/phy/mdio-mux-meson-g12a.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/phy/mdio-mux-meson-g12a.c b/drivers/net/phy/mdio-mux-meson-g12a.c +index 6fa29ea8e2a36..6644762ff2abb 100644 +--- a/drivers/net/phy/mdio-mux-meson-g12a.c ++++ b/drivers/net/phy/mdio-mux-meson-g12a.c +@@ -33,7 +33,7 @@ + #define ETH_PLL_CTL7 0x60 + + #define ETH_PHY_CNTL0 0x80 +-#define EPHY_G12A_ID 0x33000180 ++#define EPHY_G12A_ID 0x33010180 + #define ETH_PHY_CNTL1 0x84 + #define PHY_CNTL1_ST_MODE GENMASK(2, 0) + #define PHY_CNTL1_ST_PHYADD GENMASK(7, 3) + +From b499c275a5a1857f45c92cf68fe554d11c419678 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Fri, 12 Apr 2019 12:02:20 +0200 +Subject: [PATCH 138/249] FROMLIST: dt-bindings: clk: g12a-clkc: add + Temperature Sensor clock ID + +Add clock id used by temperature sensor for G12A Socs + +Signed-off-by: Guillaume La Roque +Reviewed-by: Martin Blumenstingl +--- + include/dt-bindings/clock/g12a-clkc.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h +index e10470ed7c4f1..b6b127e456345 100644 +--- a/include/dt-bindings/clock/g12a-clkc.h ++++ b/include/dt-bindings/clock/g12a-clkc.h +@@ -136,5 +136,6 @@ + #define CLKID_VDEC_1 204 + #define CLKID_VDEC_HEVC 207 + #define CLKID_VDEC_HEVCF 210 ++#define CLKID_TS 212 + + #endif /* __G12A_CLKC_H */ + +From fa512588c07fbd208365f7a80088723b5bef4303 Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Fri, 12 Apr 2019 12:02:21 +0200 +Subject: [PATCH 139/249] FROMLIST: clk: meson-g12a: Add Temperature Sensor + clock + +Add TS clock used by two temperature sensor + +Signed-off-by: Guillaume La Roque +Reviewed-by: Martin Blumenstingl +--- + drivers/clk/meson/g12a.c | 31 +++++++++++++++++++++++++++++++ + drivers/clk/meson/g12a.h | 3 ++- + 2 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index d5aceb79a91a8..a7b621bebb7e2 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -2504,6 +2504,33 @@ static struct clk_regmap g12a_mali = { + }, + }; + ++static struct clk_regmap g12a_ts_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_TS_CLK_CNTL, ++ .shift = 0, ++ .width = 8, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "ts_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "xtal" }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_regmap g12a_ts = { ++ .data = &(struct clk_regmap_gate_data){ ++ .offset = HHI_TS_CLK_CNTL, ++ .bit_idx = 8, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "ts", ++ .ops = &clk_regmap_gate_ops, ++ .parent_names = (const char *[]){ "ts_div" }, ++ .num_parents = 1, ++ }, ++}; ++ + /* Everything Else (EE) domain gates */ + static MESON_GATE(g12a_ddr, HHI_GCLK_MPEG0, 0); + static MESON_GATE(g12a_dos, HHI_GCLK_MPEG0, 1); +@@ -2793,6 +2820,8 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { + [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, + [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, + [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, ++ [CLKID_TS_DIV] = &g12a_ts_div.hw, ++ [CLKID_TS] = &g12a_ts.hw, + [NR_CLKS] = NULL, + }, + .num = NR_CLKS, +@@ -2990,6 +3019,8 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { + &g12a_vdec_hevcf_sel, + &g12a_vdec_hevcf_div, + &g12a_vdec_hevcf, ++ &g12a_ts_div, ++ &g12a_ts, + }; + + static const struct reg_sequence g12a_init_regs[] = { +diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h +index bcc05cd9882f0..bda1501ba671e 100644 +--- a/drivers/clk/meson/g12a.h ++++ b/drivers/clk/meson/g12a.h +@@ -195,8 +195,9 @@ + #define CLKID_VDEC_HEVC_DIV 206 + #define CLKID_VDEC_HEVCF_SEL 208 + #define CLKID_VDEC_HEVCF_DIV 209 ++#define CLKID_TS_DIV 211 + +-#define NR_CLKS 211 ++#define NR_CLKS 213 + + /* include the CLKIDs that have been made part of the DT binding */ + #include + +From c574de0f772993aa0cbc7534c1c3a2cf5e362b28 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 14 Mar 2019 14:50:42 +0100 +Subject: [PATCH 140/249] FROMLIST: dt-bindings: clk: meson: add g12b periph + clock controller bindings + +This patch adds the specific Amlogic G12B clock driver compatible. + +G12B clock driver is very close, the main differences are : +- the clock tree is duplicated for the both clusters, and the + SYS_PLL are swapped between the clusters +- G12A has additional clocks like for CSI an other components + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +--- + Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt +index 5c8b105be4d66..6eaa520923139 100644 +--- a/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt ++++ b/Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt +@@ -10,6 +10,7 @@ Required Properties: + "amlogic,gxl-clkc" for GXL and GXM SoC, + "amlogic,axg-clkc" for AXG SoC. + "amlogic,g12a-clkc" for G12A SoC. ++ "amlogic,g12b-clkc" for G12B SoC. + - clocks : list of clock phandle, one for each entry clock-names. + - clock-names : should contain the following: + * "xtal": the platform xtal + +From 09393a868c0527f8855db18384bd946574f48b83 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 14 Mar 2019 14:51:18 +0100 +Subject: [PATCH 141/249] FROMLIST: clk: meson: g12a: Add support for G12B CPUB + clocks + +This patch support for the specific Amlogic G12B clocks. + +G12B clock driver is very close, the main differences are : +- the clock tree is duplicated for the both clusters, and the + SYS_PLL are swapped between the clusters +- G12A has additional clocks like for CSI an other components + +Here only the cpu clock tree is handled. + +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 443 +++++++++++++++++++++++++++++++++++++++ + drivers/clk/meson/g12a.h | 20 +- + 2 files changed, 462 insertions(+), 1 deletion(-) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index a7b621bebb7e2..bbd67e9be3ddc 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -150,6 +150,57 @@ static struct clk_regmap g12a_sys_pll = { + }, + }; + ++static struct clk_regmap g12b_sys1_pll_dco = { ++ .data = &(struct meson_clk_pll_data){ ++ .en = { ++ .reg_off = HHI_SYS1_PLL_CNTL0, ++ .shift = 28, ++ .width = 1, ++ }, ++ .m = { ++ .reg_off = HHI_SYS1_PLL_CNTL0, ++ .shift = 0, ++ .width = 8, ++ }, ++ .n = { ++ .reg_off = HHI_SYS1_PLL_CNTL0, ++ .shift = 10, ++ .width = 5, ++ }, ++ .l = { ++ .reg_off = HHI_SYS1_PLL_CNTL0, ++ .shift = 31, ++ .width = 1, ++ }, ++ .rst = { ++ .reg_off = HHI_SYS1_PLL_CNTL0, ++ .shift = 29, ++ .width = 1, ++ }, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "sys1_pll_dco", ++ .ops = &meson_clk_pll_ro_ops, ++ .parent_names = (const char *[]){ IN_PREFIX "xtal" }, ++ .num_parents = 1, ++ }, ++}; ++ ++static struct clk_regmap g12b_sys1_pll = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS1_PLL_CNTL0, ++ .shift = 16, ++ .width = 3, ++ .flags = CLK_DIVIDER_POWER_OF_TWO, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "sys1_pll", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "sys1_pll_dco" }, ++ .num_parents = 1, ++ }, ++}; ++ + static struct clk_regmap g12a_sys_pll_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, +@@ -306,6 +357,150 @@ static struct clk_regmap g12a_cpu_clk = { + }, + }; + ++/* Datasheet names this field as "Final_mux_sel" */ ++static struct clk_regmap g12b_cpu_clk = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPU_CLK_CNTL0, ++ .mask = 0x1, ++ .shift = 11, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpu_clk", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpu_clk_dyn", ++ "sys1_pll" }, ++ .num_parents = 2, ++ }, ++}; ++ ++/* Datasheet names this field as "premux0" */ ++static struct clk_regmap g12b_cpub_clk_premux0 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPUB_CLK_CNTL, ++ .mask = 0x3, ++ .shift = 0, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpub_clk_dyn0_sel", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ IN_PREFIX "xtal", ++ "fclk_div2", ++ "fclk_div3" }, ++ .num_parents = 3, ++ }, ++}; ++ ++/* Datasheet names this field as "mux0_divn_tcnt" */ ++static struct clk_regmap g12b_cpub_clk_mux0_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS_CPUB_CLK_CNTL, ++ .shift = 4, ++ .width = 6, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpub_clk_dyn0_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "cpub_clk_dyn0_sel" }, ++ .num_parents = 1, ++ }, ++}; ++ ++/* Datasheet names this field as "postmux0" */ ++static struct clk_regmap g12b_cpub_clk_postmux0 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPUB_CLK_CNTL, ++ .mask = 0x1, ++ .shift = 2, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpub_clk_dyn0", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpub_clk_dyn0_sel", ++ "cpub_clk_dyn0_div" }, ++ .num_parents = 2, ++ }, ++}; ++ ++/* Datasheet names this field as "premux1" */ ++static struct clk_regmap g12b_cpub_clk_premux1 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPUB_CLK_CNTL, ++ .mask = 0x3, ++ .shift = 16, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpub_clk_dyn1_sel", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ IN_PREFIX "xtal", ++ "fclk_div2", ++ "fclk_div3" }, ++ .num_parents = 3, ++ }, ++}; ++ ++/* Datasheet names this field as "Mux1_divn_tcnt" */ ++static struct clk_regmap g12b_cpub_clk_mux1_div = { ++ .data = &(struct clk_regmap_div_data){ ++ .offset = HHI_SYS_CPUB_CLK_CNTL, ++ .shift = 20, ++ .width = 6, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpub_clk_dyn1_div", ++ .ops = &clk_regmap_divider_ro_ops, ++ .parent_names = (const char *[]){ "cpub_clk_dyn1_sel" }, ++ .num_parents = 1, ++ }, ++}; ++ ++/* Datasheet names this field as "postmux1" */ ++static struct clk_regmap g12b_cpub_clk_postmux1 = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPUB_CLK_CNTL, ++ .mask = 0x1, ++ .shift = 18, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpub_clk_dyn1", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpub_clk_dyn1_sel", ++ "cpub_clk_dyn1_div" }, ++ .num_parents = 2, ++ }, ++}; ++ ++/* Datasheet names this field as "Final_dyn_mux_sel" */ ++static struct clk_regmap g12b_cpub_clk_dyn = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPUB_CLK_CNTL, ++ .mask = 0x1, ++ .shift = 10, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpub_clk_dyn", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpub_clk_dyn0", ++ "cpub_clk_dyn1" }, ++ .num_parents = 2, ++ }, ++}; ++ ++/* Datasheet names this field as "Final_mux_sel" */ ++static struct clk_regmap g12b_cpub_clk = { ++ .data = &(struct clk_regmap_mux_data){ ++ .offset = HHI_SYS_CPUB_CLK_CNTL, ++ .mask = 0x1, ++ .shift = 11, ++ }, ++ .hw.init = &(struct clk_init_data){ ++ .name = "cpub_clk", ++ .ops = &clk_regmap_mux_ro_ops, ++ .parent_names = (const char *[]){ "cpub_clk_dyn", ++ "sys_pll" }, ++ .num_parents = 2, ++ }, ++}; ++ + static struct clk_regmap g12a_cpu_clk_div16_en = { + .data = &(struct clk_regmap_gate_data){ + .offset = HHI_SYS_CPU_CLK_CNTL1, +@@ -2827,6 +3022,236 @@ static struct clk_hw_onecell_data g12a_hw_onecell_data = { + .num = NR_CLKS, + }; + ++static struct clk_hw_onecell_data g12b_hw_onecell_data = { ++ .hws = { ++ [CLKID_SYS_PLL] = &g12a_sys_pll.hw, ++ [CLKID_FIXED_PLL] = &g12a_fixed_pll.hw, ++ [CLKID_FCLK_DIV2] = &g12a_fclk_div2.hw, ++ [CLKID_FCLK_DIV3] = &g12a_fclk_div3.hw, ++ [CLKID_FCLK_DIV4] = &g12a_fclk_div4.hw, ++ [CLKID_FCLK_DIV5] = &g12a_fclk_div5.hw, ++ [CLKID_FCLK_DIV7] = &g12a_fclk_div7.hw, ++ [CLKID_FCLK_DIV2P5] = &g12a_fclk_div2p5.hw, ++ [CLKID_GP0_PLL] = &g12a_gp0_pll.hw, ++ [CLKID_MPEG_SEL] = &g12a_mpeg_clk_sel.hw, ++ [CLKID_MPEG_DIV] = &g12a_mpeg_clk_div.hw, ++ [CLKID_CLK81] = &g12a_clk81.hw, ++ [CLKID_MPLL0] = &g12a_mpll0.hw, ++ [CLKID_MPLL1] = &g12a_mpll1.hw, ++ [CLKID_MPLL2] = &g12a_mpll2.hw, ++ [CLKID_MPLL3] = &g12a_mpll3.hw, ++ [CLKID_DDR] = &g12a_ddr.hw, ++ [CLKID_DOS] = &g12a_dos.hw, ++ [CLKID_AUDIO_LOCKER] = &g12a_audio_locker.hw, ++ [CLKID_MIPI_DSI_HOST] = &g12a_mipi_dsi_host.hw, ++ [CLKID_ETH_PHY] = &g12a_eth_phy.hw, ++ [CLKID_ISA] = &g12a_isa.hw, ++ [CLKID_PL301] = &g12a_pl301.hw, ++ [CLKID_PERIPHS] = &g12a_periphs.hw, ++ [CLKID_SPICC0] = &g12a_spicc_0.hw, ++ [CLKID_I2C] = &g12a_i2c.hw, ++ [CLKID_SANA] = &g12a_sana.hw, ++ [CLKID_SD] = &g12a_sd.hw, ++ [CLKID_RNG0] = &g12a_rng0.hw, ++ [CLKID_UART0] = &g12a_uart0.hw, ++ [CLKID_SPICC1] = &g12a_spicc_1.hw, ++ [CLKID_HIU_IFACE] = &g12a_hiu_reg.hw, ++ [CLKID_MIPI_DSI_PHY] = &g12a_mipi_dsi_phy.hw, ++ [CLKID_ASSIST_MISC] = &g12a_assist_misc.hw, ++ [CLKID_SD_EMMC_A] = &g12a_emmc_a.hw, ++ [CLKID_SD_EMMC_B] = &g12a_emmc_b.hw, ++ [CLKID_SD_EMMC_C] = &g12a_emmc_c.hw, ++ [CLKID_AUDIO_CODEC] = &g12a_audio_codec.hw, ++ [CLKID_AUDIO] = &g12a_audio.hw, ++ [CLKID_ETH] = &g12a_eth_core.hw, ++ [CLKID_DEMUX] = &g12a_demux.hw, ++ [CLKID_AUDIO_IFIFO] = &g12a_audio_ififo.hw, ++ [CLKID_ADC] = &g12a_adc.hw, ++ [CLKID_UART1] = &g12a_uart1.hw, ++ [CLKID_G2D] = &g12a_g2d.hw, ++ [CLKID_RESET] = &g12a_reset.hw, ++ [CLKID_PCIE_COMB] = &g12a_pcie_comb.hw, ++ [CLKID_PARSER] = &g12a_parser.hw, ++ [CLKID_USB] = &g12a_usb_general.hw, ++ [CLKID_PCIE_PHY] = &g12a_pcie_phy.hw, ++ [CLKID_AHB_ARB0] = &g12a_ahb_arb0.hw, ++ [CLKID_AHB_DATA_BUS] = &g12a_ahb_data_bus.hw, ++ [CLKID_AHB_CTRL_BUS] = &g12a_ahb_ctrl_bus.hw, ++ [CLKID_HTX_HDCP22] = &g12a_htx_hdcp22.hw, ++ [CLKID_HTX_PCLK] = &g12a_htx_pclk.hw, ++ [CLKID_BT656] = &g12a_bt656.hw, ++ [CLKID_USB1_DDR_BRIDGE] = &g12a_usb1_to_ddr.hw, ++ [CLKID_MMC_PCLK] = &g12a_mmc_pclk.hw, ++ [CLKID_UART2] = &g12a_uart2.hw, ++ [CLKID_VPU_INTR] = &g12a_vpu_intr.hw, ++ [CLKID_GIC] = &g12a_gic.hw, ++ [CLKID_SD_EMMC_A_CLK0_SEL] = &g12a_sd_emmc_a_clk0_sel.hw, ++ [CLKID_SD_EMMC_A_CLK0_DIV] = &g12a_sd_emmc_a_clk0_div.hw, ++ [CLKID_SD_EMMC_A_CLK0] = &g12a_sd_emmc_a_clk0.hw, ++ [CLKID_SD_EMMC_B_CLK0_SEL] = &g12a_sd_emmc_b_clk0_sel.hw, ++ [CLKID_SD_EMMC_B_CLK0_DIV] = &g12a_sd_emmc_b_clk0_div.hw, ++ [CLKID_SD_EMMC_B_CLK0] = &g12a_sd_emmc_b_clk0.hw, ++ [CLKID_SD_EMMC_C_CLK0_SEL] = &g12a_sd_emmc_c_clk0_sel.hw, ++ [CLKID_SD_EMMC_C_CLK0_DIV] = &g12a_sd_emmc_c_clk0_div.hw, ++ [CLKID_SD_EMMC_C_CLK0] = &g12a_sd_emmc_c_clk0.hw, ++ [CLKID_MPLL0_DIV] = &g12a_mpll0_div.hw, ++ [CLKID_MPLL1_DIV] = &g12a_mpll1_div.hw, ++ [CLKID_MPLL2_DIV] = &g12a_mpll2_div.hw, ++ [CLKID_MPLL3_DIV] = &g12a_mpll3_div.hw, ++ [CLKID_FCLK_DIV2_DIV] = &g12a_fclk_div2_div.hw, ++ [CLKID_FCLK_DIV3_DIV] = &g12a_fclk_div3_div.hw, ++ [CLKID_FCLK_DIV4_DIV] = &g12a_fclk_div4_div.hw, ++ [CLKID_FCLK_DIV5_DIV] = &g12a_fclk_div5_div.hw, ++ [CLKID_FCLK_DIV7_DIV] = &g12a_fclk_div7_div.hw, ++ [CLKID_FCLK_DIV2P5_DIV] = &g12a_fclk_div2p5_div.hw, ++ [CLKID_HIFI_PLL] = &g12a_hifi_pll.hw, ++ [CLKID_VCLK2_VENCI0] = &g12a_vclk2_venci0.hw, ++ [CLKID_VCLK2_VENCI1] = &g12a_vclk2_venci1.hw, ++ [CLKID_VCLK2_VENCP0] = &g12a_vclk2_vencp0.hw, ++ [CLKID_VCLK2_VENCP1] = &g12a_vclk2_vencp1.hw, ++ [CLKID_VCLK2_VENCT0] = &g12a_vclk2_venct0.hw, ++ [CLKID_VCLK2_VENCT1] = &g12a_vclk2_venct1.hw, ++ [CLKID_VCLK2_OTHER] = &g12a_vclk2_other.hw, ++ [CLKID_VCLK2_ENCI] = &g12a_vclk2_enci.hw, ++ [CLKID_VCLK2_ENCP] = &g12a_vclk2_encp.hw, ++ [CLKID_DAC_CLK] = &g12a_dac_clk.hw, ++ [CLKID_AOCLK] = &g12a_aoclk_gate.hw, ++ [CLKID_IEC958] = &g12a_iec958_gate.hw, ++ [CLKID_ENC480P] = &g12a_enc480p.hw, ++ [CLKID_RNG1] = &g12a_rng1.hw, ++ [CLKID_VCLK2_ENCT] = &g12a_vclk2_enct.hw, ++ [CLKID_VCLK2_ENCL] = &g12a_vclk2_encl.hw, ++ [CLKID_VCLK2_VENCLMMC] = &g12a_vclk2_venclmmc.hw, ++ [CLKID_VCLK2_VENCL] = &g12a_vclk2_vencl.hw, ++ [CLKID_VCLK2_OTHER1] = &g12a_vclk2_other1.hw, ++ [CLKID_FIXED_PLL_DCO] = &g12a_fixed_pll_dco.hw, ++ [CLKID_SYS_PLL_DCO] = &g12a_sys_pll_dco.hw, ++ [CLKID_GP0_PLL_DCO] = &g12a_gp0_pll_dco.hw, ++ [CLKID_HIFI_PLL_DCO] = &g12a_hifi_pll_dco.hw, ++ [CLKID_DMA] = &g12a_dma.hw, ++ [CLKID_EFUSE] = &g12a_efuse.hw, ++ [CLKID_ROM_BOOT] = &g12a_rom_boot.hw, ++ [CLKID_RESET_SEC] = &g12a_reset_sec.hw, ++ [CLKID_SEC_AHB_APB3] = &g12a_sec_ahb_apb3.hw, ++ [CLKID_MPLL_PREDIV] = &g12a_mpll_prediv.hw, ++ [CLKID_VPU_0_SEL] = &g12a_vpu_0_sel.hw, ++ [CLKID_VPU_0_DIV] = &g12a_vpu_0_div.hw, ++ [CLKID_VPU_0] = &g12a_vpu_0.hw, ++ [CLKID_VPU_1_SEL] = &g12a_vpu_1_sel.hw, ++ [CLKID_VPU_1_DIV] = &g12a_vpu_1_div.hw, ++ [CLKID_VPU_1] = &g12a_vpu_1.hw, ++ [CLKID_VPU] = &g12a_vpu.hw, ++ [CLKID_VAPB_0_SEL] = &g12a_vapb_0_sel.hw, ++ [CLKID_VAPB_0_DIV] = &g12a_vapb_0_div.hw, ++ [CLKID_VAPB_0] = &g12a_vapb_0.hw, ++ [CLKID_VAPB_1_SEL] = &g12a_vapb_1_sel.hw, ++ [CLKID_VAPB_1_DIV] = &g12a_vapb_1_div.hw, ++ [CLKID_VAPB_1] = &g12a_vapb_1.hw, ++ [CLKID_VAPB_SEL] = &g12a_vapb_sel.hw, ++ [CLKID_VAPB] = &g12a_vapb.hw, ++ [CLKID_HDMI_PLL_DCO] = &g12a_hdmi_pll_dco.hw, ++ [CLKID_HDMI_PLL_OD] = &g12a_hdmi_pll_od.hw, ++ [CLKID_HDMI_PLL_OD2] = &g12a_hdmi_pll_od2.hw, ++ [CLKID_HDMI_PLL] = &g12a_hdmi_pll.hw, ++ [CLKID_VID_PLL] = &g12a_vid_pll_div.hw, ++ [CLKID_VID_PLL_SEL] = &g12a_vid_pll_sel.hw, ++ [CLKID_VID_PLL_DIV] = &g12a_vid_pll.hw, ++ [CLKID_VCLK_SEL] = &g12a_vclk_sel.hw, ++ [CLKID_VCLK2_SEL] = &g12a_vclk2_sel.hw, ++ [CLKID_VCLK_INPUT] = &g12a_vclk_input.hw, ++ [CLKID_VCLK2_INPUT] = &g12a_vclk2_input.hw, ++ [CLKID_VCLK_DIV] = &g12a_vclk_div.hw, ++ [CLKID_VCLK2_DIV] = &g12a_vclk2_div.hw, ++ [CLKID_VCLK] = &g12a_vclk.hw, ++ [CLKID_VCLK2] = &g12a_vclk2.hw, ++ [CLKID_VCLK_DIV1] = &g12a_vclk_div1.hw, ++ [CLKID_VCLK_DIV2_EN] = &g12a_vclk_div2_en.hw, ++ [CLKID_VCLK_DIV4_EN] = &g12a_vclk_div4_en.hw, ++ [CLKID_VCLK_DIV6_EN] = &g12a_vclk_div6_en.hw, ++ [CLKID_VCLK_DIV12_EN] = &g12a_vclk_div12_en.hw, ++ [CLKID_VCLK2_DIV1] = &g12a_vclk2_div1.hw, ++ [CLKID_VCLK2_DIV2_EN] = &g12a_vclk2_div2_en.hw, ++ [CLKID_VCLK2_DIV4_EN] = &g12a_vclk2_div4_en.hw, ++ [CLKID_VCLK2_DIV6_EN] = &g12a_vclk2_div6_en.hw, ++ [CLKID_VCLK2_DIV12_EN] = &g12a_vclk2_div12_en.hw, ++ [CLKID_VCLK_DIV2] = &g12a_vclk_div2.hw, ++ [CLKID_VCLK_DIV4] = &g12a_vclk_div4.hw, ++ [CLKID_VCLK_DIV6] = &g12a_vclk_div6.hw, ++ [CLKID_VCLK_DIV12] = &g12a_vclk_div12.hw, ++ [CLKID_VCLK2_DIV2] = &g12a_vclk2_div2.hw, ++ [CLKID_VCLK2_DIV4] = &g12a_vclk2_div4.hw, ++ [CLKID_VCLK2_DIV6] = &g12a_vclk2_div6.hw, ++ [CLKID_VCLK2_DIV12] = &g12a_vclk2_div12.hw, ++ [CLKID_CTS_ENCI_SEL] = &g12a_cts_enci_sel.hw, ++ [CLKID_CTS_ENCP_SEL] = &g12a_cts_encp_sel.hw, ++ [CLKID_CTS_VDAC_SEL] = &g12a_cts_vdac_sel.hw, ++ [CLKID_HDMI_TX_SEL] = &g12a_hdmi_tx_sel.hw, ++ [CLKID_CTS_ENCI] = &g12a_cts_enci.hw, ++ [CLKID_CTS_ENCP] = &g12a_cts_encp.hw, ++ [CLKID_CTS_VDAC] = &g12a_cts_vdac.hw, ++ [CLKID_HDMI_TX] = &g12a_hdmi_tx.hw, ++ [CLKID_HDMI_SEL] = &g12a_hdmi_sel.hw, ++ [CLKID_HDMI_DIV] = &g12a_hdmi_div.hw, ++ [CLKID_HDMI] = &g12a_hdmi.hw, ++ [CLKID_MALI_0_SEL] = &g12a_mali_0_sel.hw, ++ [CLKID_MALI_0_DIV] = &g12a_mali_0_div.hw, ++ [CLKID_MALI_0] = &g12a_mali_0.hw, ++ [CLKID_MALI_1_SEL] = &g12a_mali_1_sel.hw, ++ [CLKID_MALI_1_DIV] = &g12a_mali_1_div.hw, ++ [CLKID_MALI_1] = &g12a_mali_1.hw, ++ [CLKID_MALI] = &g12a_mali.hw, ++ [CLKID_MPLL_50M_DIV] = &g12a_mpll_50m_div.hw, ++ [CLKID_MPLL_50M] = &g12a_mpll_50m.hw, ++ [CLKID_SYS_PLL_DIV16_EN] = &g12a_sys_pll_div16_en.hw, ++ [CLKID_SYS_PLL_DIV16] = &g12a_sys_pll_div16.hw, ++ [CLKID_CPU_CLK_DYN0_SEL] = &g12a_cpu_clk_premux0.hw, ++ [CLKID_CPU_CLK_DYN0_DIV] = &g12a_cpu_clk_mux0_div.hw, ++ [CLKID_CPU_CLK_DYN0] = &g12a_cpu_clk_postmux0.hw, ++ [CLKID_CPU_CLK_DYN1_SEL] = &g12a_cpu_clk_premux1.hw, ++ [CLKID_CPU_CLK_DYN1_DIV] = &g12a_cpu_clk_mux1_div.hw, ++ [CLKID_CPU_CLK_DYN1] = &g12a_cpu_clk_postmux1.hw, ++ [CLKID_CPU_CLK_DYN] = &g12a_cpu_clk_dyn.hw, ++ [CLKID_CPU_CLK] = &g12b_cpu_clk.hw, ++ [CLKID_CPU_CLK_DIV16_EN] = &g12a_cpu_clk_div16_en.hw, ++ [CLKID_CPU_CLK_DIV16] = &g12a_cpu_clk_div16.hw, ++ [CLKID_CPU_CLK_APB_DIV] = &g12a_cpu_clk_apb_div.hw, ++ [CLKID_CPU_CLK_APB] = &g12a_cpu_clk_apb.hw, ++ [CLKID_CPU_CLK_ATB_DIV] = &g12a_cpu_clk_atb_div.hw, ++ [CLKID_CPU_CLK_ATB] = &g12a_cpu_clk_atb.hw, ++ [CLKID_CPU_CLK_AXI_DIV] = &g12a_cpu_clk_axi_div.hw, ++ [CLKID_CPU_CLK_AXI] = &g12a_cpu_clk_axi.hw, ++ [CLKID_CPU_CLK_TRACE_DIV] = &g12a_cpu_clk_trace_div.hw, ++ [CLKID_CPU_CLK_TRACE] = &g12a_cpu_clk_trace.hw, ++ [CLKID_PCIE_PLL_DCO] = &g12a_pcie_pll_dco.hw, ++ [CLKID_PCIE_PLL_DCO_DIV2] = &g12a_pcie_pll_dco_div2.hw, ++ [CLKID_PCIE_PLL_OD] = &g12a_pcie_pll_od.hw, ++ [CLKID_PCIE_PLL] = &g12a_pcie_pll.hw, ++ [CLKID_VDEC_1_SEL] = &g12a_vdec_1_sel.hw, ++ [CLKID_VDEC_1_DIV] = &g12a_vdec_1_div.hw, ++ [CLKID_VDEC_1] = &g12a_vdec_1.hw, ++ [CLKID_VDEC_HEVC_SEL] = &g12a_vdec_hevc_sel.hw, ++ [CLKID_VDEC_HEVC_DIV] = &g12a_vdec_hevc_div.hw, ++ [CLKID_VDEC_HEVC] = &g12a_vdec_hevc.hw, ++ [CLKID_VDEC_HEVCF_SEL] = &g12a_vdec_hevcf_sel.hw, ++ [CLKID_VDEC_HEVCF_DIV] = &g12a_vdec_hevcf_div.hw, ++ [CLKID_VDEC_HEVCF] = &g12a_vdec_hevcf.hw, ++ [CLKID_TS_DIV] = &g12a_ts_div.hw, ++ [CLKID_TS] = &g12a_ts.hw, ++ [CLKID_SYS1_PLL_DCO] = &g12b_sys1_pll_dco.hw, ++ [CLKID_SYS1_PLL] = &g12b_sys1_pll.hw, ++ [CLKID_CPUB_CLK_DYN0_SEL] = &g12b_cpub_clk_premux0.hw, ++ [CLKID_CPUB_CLK_DYN0_DIV] = &g12b_cpub_clk_mux0_div.hw, ++ [CLKID_CPUB_CLK_DYN0] = &g12b_cpub_clk_postmux0.hw, ++ [CLKID_CPUB_CLK_DYN1_SEL] = &g12b_cpub_clk_premux1.hw, ++ [CLKID_CPUB_CLK_DYN1_DIV] = &g12b_cpub_clk_mux1_div.hw, ++ [CLKID_CPUB_CLK_DYN1] = &g12b_cpub_clk_postmux1.hw, ++ [CLKID_CPUB_CLK_DYN] = &g12b_cpub_clk_dyn.hw, ++ [CLKID_CPUB_CLK] = &g12b_cpub_clk.hw, ++ [NR_CLKS] = NULL, ++ }, ++ .num = NR_CLKS, ++}; ++ + /* Convenience table to populate regmap in .probe */ + static struct clk_regmap *const g12a_clk_regmaps[] = { + &g12a_clk81, +@@ -3021,6 +3446,17 @@ static struct clk_regmap *const g12a_clk_regmaps[] = { + &g12a_vdec_hevcf, + &g12a_ts_div, + &g12a_ts, ++ &g12b_cpu_clk, ++ &g12b_sys1_pll_dco, ++ &g12b_sys1_pll, ++ &g12b_cpub_clk_premux0, ++ &g12b_cpub_clk_mux0_div, ++ &g12b_cpub_clk_postmux0, ++ &g12b_cpub_clk_premux1, ++ &g12b_cpub_clk_mux1_div, ++ &g12b_cpub_clk_postmux1, ++ &g12b_cpub_clk_dyn, ++ &g12b_cpub_clk, + }; + + static const struct reg_sequence g12a_init_regs[] = { +@@ -3035,8 +3471,15 @@ static const struct meson_eeclkc_data g12a_clkc_data = { + .init_count = ARRAY_SIZE(g12a_init_regs), + }; + ++static const struct meson_eeclkc_data g12b_clkc_data = { ++ .regmap_clks = g12a_clk_regmaps, ++ .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps), ++ .hw_onecell_data = &g12b_hw_onecell_data ++}; ++ + static const struct of_device_id clkc_match_table[] = { + { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data }, ++ { .compatible = "amlogic,g12b-clkc", .data = &g12b_clkc_data }, + {} + }; + +diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h +index bda1501ba671e..d2f9a657e1499 100644 +--- a/drivers/clk/meson/g12a.h ++++ b/drivers/clk/meson/g12a.h +@@ -69,6 +69,7 @@ + #define HHI_VDEC4_CLK_CNTL 0x1EC + #define HHI_HDCP22_CLK_CNTL 0x1F0 + #define HHI_VAPBCLK_CNTL 0x1F4 ++#define HHI_SYS_CPUB_CLK_CNTL 0x208 + #define HHI_VPU_CLKB_CNTL 0x20C + #define HHI_GEN_CLK_CNTL 0x228 + #define HHI_VDIN_MEAS_CLK_CNTL 0x250 +@@ -102,6 +103,13 @@ + #define HHI_HDMI_PLL_CNTL5 0x334 + #define HHI_HDMI_PLL_CNTL6 0x338 + #define HHI_SPICC_CLK_CNTL 0x3dc ++#define HHI_SYS1_PLL_CNTL0 0x380 ++#define HHI_SYS1_PLL_CNTL1 0x384 ++#define HHI_SYS1_PLL_CNTL2 0x388 ++#define HHI_SYS1_PLL_CNTL3 0x38c ++#define HHI_SYS1_PLL_CNTL4 0x390 ++#define HHI_SYS1_PLL_CNTL5 0x394 ++#define HHI_SYS1_PLL_CNTL6 0x398 + + /* + * CLKID index values +@@ -196,8 +204,18 @@ + #define CLKID_VDEC_HEVCF_SEL 208 + #define CLKID_VDEC_HEVCF_DIV 209 + #define CLKID_TS_DIV 211 ++#define CLKID_SYS1_PLL_DCO 213 ++#define CLKID_SYS1_PLL 214 ++#define CLKID_CPUB_CLK_DYN0_SEL 215 ++#define CLKID_CPUB_CLK_DYN0_DIV 216 ++#define CLKID_CPUB_CLK_DYN0 217 ++#define CLKID_CPUB_CLK_DYN1_SEL 218 ++#define CLKID_CPUB_CLK_DYN1_DIV 219 ++#define CLKID_CPUB_CLK_DYN1 220 ++#define CLKID_CPUB_CLK_DYN 221 ++#define CLKID_CPUB_CLK 222 + +-#define NR_CLKS 213 ++#define NR_CLKS 223 + + /* include the CLKIDs that have been made part of the DT binding */ + #include + +From a60b44654f9a38216f263140703beffcb22ef096 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 14 Mar 2019 15:58:19 +0100 +Subject: [PATCH 142/249] FROMLIST: clk: meson: g12a: mark fclk_div3 as + critical + +On Amlogic Meson G12b platform, the fclk_div3 seems to be necessary for +the system to operate correctly. + +Disabling it cause the entire system to freeze, including peripherals. + +This patch patch marks this clock as critical, fixing boot on G12b platforms. + +Signed-off-by: Neil Armstrong +--- + drivers/clk/meson/g12a.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c +index bbd67e9be3ddc..268e8a5cfbd62 100644 +--- a/drivers/clk/meson/g12a.c ++++ b/drivers/clk/meson/g12a.c +@@ -1060,6 +1060,16 @@ static struct clk_regmap g12a_fclk_div3 = { + .ops = &clk_regmap_gate_ops, + .parent_names = (const char *[]){ "fclk_div3_div" }, + .num_parents = 1, ++ /* ++ * This clock is used by the resident firmware and is required ++ * by the platform to operate correctly. ++ * Until the following condition are met, we need this clock to ++ * be marked as critical: ++ * a) Mark the clock used by a firmware resource, if possible ++ * b) CCF has a clock hand-off mechanism to make the sure the ++ * clock stays on until the proper driver comes along ++ */ ++ .flags = CLK_IS_CRITICAL, + }, + }; + + +From d4ac66449d518261daf0d2eb970a956812199d71 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 14 Mar 2019 10:05:19 +0100 +Subject: [PATCH 143/249] FROMLIST: dt-bindings: arm: amlogic: add G12B + bindings + +Add compatible for the Amlogic G12B SoC, sharing most of the +features and architecture with the G12A SoC. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +--- + Documentation/devicetree/bindings/arm/amlogic.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt +index 061f7b98a07f1..94bbcc646e105 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.txt ++++ b/Documentation/devicetree/bindings/arm/amlogic.txt +@@ -61,6 +61,10 @@ Boards with the Amlogic Meson G12A S905D2 SoC shall have the following propertie + Required root node property: + compatible: "amlogic,g12a"; + ++Boards with the Amlogic Meson G12B S922X SoC shall have the following properties: ++ Required root node property: ++ compatible: "amlogic,g12b"; ++ + Board compatible values (alphabetically, grouped by SoC): + + - "geniatech,atv1200" (Meson6) + +From ccc06c35562d484c711ea9a203588e67b89668d0 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 14 Mar 2019 10:22:07 +0100 +Subject: [PATCH 144/249] FROMLIST: dt-bindings: arm: amlogic: add Odroid-N2 + binding + +Add compatible for the Amlogic G12B (S922X) SoC based Odroid-N2 SBC +from HardKernel. + +Signed-off-by: Neil Armstrong +Reviewed-by: Rob Herring +--- + Documentation/devicetree/bindings/arm/amlogic.txt | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt +index 94bbcc646e105..eff41128268eb 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.txt ++++ b/Documentation/devicetree/bindings/arm/amlogic.txt +@@ -116,6 +116,8 @@ Board compatible values (alphabetically, grouped by SoC): + - "amediatech,x96-max" (Meson g12a s905x2) + - "seirobotics,sei510" (Meson g12a s905x2) + ++ - "hardkernel,odroid-n2" (Meson g12b s922x) ++ + Amlogic Meson Firmware registers Interface + ------------------------------------------ + + +From f9913b0420698dbda91f69adb90085c967601081 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 14 Mar 2019 10:21:12 +0100 +Subject: [PATCH 145/249] FROMLIST: arm64: dts: meson: Add minimal support for + Odroid-N2 + +This patch adds basic support for : +- Amlogic G12B, which is very similar to G12A +- The HardKernel Odroid-N2 based on the S922X SoC + +The Amlogic G12B SoC is very similar with the G12A SoC, sharing +most of the features and architecture, but with these differences : +- The first CPU cluster only has 2xCortex-A53 instead of 4 +- G12B has a second cluster of 4xCortex-A73 +- Both cluster can achieve 2GHz instead of 1,8GHz for G12A +- CPU Clock architecture is difference, thus needing a different + compatible to handle this slight difference +- Supports a MIPI CSI input +- Embeds a Mali-G52 instead of a Mali-G31, but integration is the same + +Actual support is done in the same way as for the GXM support, including +the G12A dtsi and redefining the CPU clusters. +Unlike GXM, the first cluster is different, thus needing to remove +the last 2 cpu nodes of the first cluster. + +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/Makefile | 1 + + .../boot/dts/amlogic/meson-g12b-odroid-n2.dts | 185 ++++++++++++++++++ + arch/arm64/boot/dts/amlogic/meson-g12b.dtsi | 82 ++++++++ + 3 files changed, 268 insertions(+) + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12b.dtsi + +diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile +index e129c03ced140..07b861fe5fa5f 100644 +--- a/arch/arm64/boot/dts/amlogic/Makefile ++++ b/arch/arm64/boot/dts/amlogic/Makefile +@@ -3,6 +3,7 @@ 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-odroid-n2.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 +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +new file mode 100644 +index 0000000000000..0541fe0bbaea9 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -0,0 +1,185 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ */ ++ ++/dts-v1/; ++ ++#include "meson-g12b.dtsi" ++#include ++#include ++ ++/ { ++ compatible = "hardkernel,odroid-n2", "amlogic,g12b"; ++ model = "Hardkernel ODROID-N2"; ++ ++ aliases { ++ serial0 = &uart_AO; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x40000000>; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ blue { ++ label = "n2:blue"; ++ gpios = <&gpio_ao GPIOAO_11 GPIO_ACTIVE_HIGH>; ++ linux,default-trigger = "heartbeat"; ++ }; ++ }; ++ ++ main_12v: regulator-main_12v { ++ compatible = "regulator-fixed"; ++ regulator-name = "12V"; ++ regulator-min-microvolt = <12000000>; ++ regulator-max-microvolt = <12000000>; ++ regulator-always-on; ++ }; ++ ++ vcc_5v: regulator-vcc_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vcc_1v8: regulator-vcc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ /* FIXME: actually controlled by VDDCPU_B_EN */ ++ }; ++ ++ hub_5v: regulator-hub_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "HUB_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&vcc_5v>; ++ ++ gpio = <&gpio GPIOH_5 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ 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 = <&hub_5v>; ++ ++ gpio = <&gpio GPIOH_6 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ 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; ++ }; ++ ++ vddao_3v3: regulator-vddao_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&main_12v>; ++ regulator-always-on; ++ }; ++ ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++}; ++ ++&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>; ++}; ++ ++&gpio { ++ /* ++ * WARNING: The USB Hub on the Odroid-N2 needs a reset signal ++ * to be turned high in order to be detected by the USB Controller ++ * This signal should be handled by a USB specific power sequence ++ * in order to reset the Hub when USB bus is powered down. ++ */ ++ usb-hub { ++ gpio-hog; ++ gpios = ; ++ output-high; ++ line-name = "usb-hub-reset"; ++ }; ++}; ++ ++&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>; ++ }; ++}; ++ ++&uart_AO { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&usb { ++ status = "okay"; ++}; ++ ++&usb2_phy0 { ++ phy-supply = <&usb_pwr_en>; ++}; ++ ++&usb2_phy1 { ++ phy-supply = <&vcc_5v>; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +new file mode 100644 +index 0000000000000..0359539ba8840 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b.dtsi +@@ -0,0 +1,82 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2019 BayLibre, SAS ++ * Author: Neil Armstrong ++ */ ++ ++#include "meson-g12a.dtsi" ++ ++/ { ++ compatible = "amlogic,g12b"; ++ ++ cpus { ++ cpu-map { ++ cluster0 { ++ core0 { ++ cpu = <&cpu0>; ++ }; ++ ++ core1 { ++ cpu = <&cpu1>; ++ }; ++ }; ++ ++ cluster1 { ++ core0 { ++ cpu = <&cpu100>; ++ }; ++ ++ core1 { ++ cpu = <&cpu101>; ++ }; ++ ++ core2 { ++ cpu = <&cpu102>; ++ }; ++ ++ core3 { ++ cpu = <&cpu103>; ++ }; ++ }; ++ }; ++ ++ /delete-node/ cpu@2; ++ /delete-node/ cpu@3; ++ ++ cpu100: cpu@100 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a73", "arm,armv8"; ++ reg = <0x0 0x100>; ++ enable-method = "psci"; ++ next-level-cache = <&l2>; ++ }; ++ ++ cpu101: cpu@101 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a73", "arm,armv8"; ++ reg = <0x0 0x101>; ++ enable-method = "psci"; ++ next-level-cache = <&l2>; ++ }; ++ ++ cpu102: cpu@102 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a73", "arm,armv8"; ++ reg = <0x0 0x102>; ++ enable-method = "psci"; ++ next-level-cache = <&l2>; ++ }; ++ ++ cpu103: cpu@103 { ++ device_type = "cpu"; ++ compatible = "arm,cortex-a73", "arm,armv8"; ++ reg = <0x0 0x103>; ++ enable-method = "psci"; ++ next-level-cache = <&l2>; ++ }; ++ }; ++}; ++ ++&clkc { ++ compatible = "amlogic,g12b-clkc"; ++}; + +From 2a1175fe774426d5303821b1c2f3200a59b02f9c Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 12 Apr 2019 11:23:37 +0200 +Subject: [PATCH 146/249] FROMLIST: arm64: dts: meson-g12a: Add PWM nodes + +This adds the EE and AO PWM nodes and the possible pinctrl settings. + +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 179 ++++++++++++++++++++ + 1 file changed, 179 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 2ab39f39f679f..4f4355322673f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -260,6 +260,94 @@ + }; + }; + ++ pwm_a_pins: pwm-a { ++ mux { ++ groups = "pwm_a"; ++ function = "pwm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_b_x7_pins: pwm-b-x7 { ++ mux { ++ groups = "pwm_b_x7"; ++ function = "pwm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_b_x19_pins: pwm-b-x19 { ++ mux { ++ groups = "pwm_b_x19"; ++ function = "pwm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_c_c_pins: pwm-c-c { ++ mux { ++ groups = "pwm_c_c"; ++ function = "pwm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_c_x5_pins: pwm-c-x5 { ++ mux { ++ groups = "pwm_c_x5"; ++ function = "pwm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_c_x8_pins: pwm-c-x8 { ++ mux { ++ groups = "pwm_c_x8"; ++ function = "pwm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_d_x3_pins: pwm-d-x3 { ++ mux { ++ groups = "pwm_d_x3"; ++ function = "pwm_d"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_d_x6_pins: pwm-d-x6 { ++ mux { ++ groups = "pwm_d_x6"; ++ function = "pwm_d"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_e_pins: pwm-e { ++ mux { ++ groups = "pwm_e"; ++ function = "pwm_e"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_f_x_pins: pwm-f-x { ++ mux { ++ groups = "pwm_f_x"; ++ function = "pwm_f"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_f_h_pins: pwm-f-h { ++ mux { ++ groups = "pwm_f_h"; ++ function = "pwm_f"; ++ bias-disable; ++ }; ++ }; ++ + uart_a_pins: uart-a { + mux { + groups = "uart_a_tx", +@@ -508,6 +596,62 @@ + bias-disable; + }; + }; ++ ++ pwm_ao_a_pins: pwm-ao-a { ++ mux { ++ groups = "pwm_ao_a"; ++ function = "pwm_ao_a"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_b_pins: pwm-ao-b { ++ mux { ++ groups = "pwm_ao_b"; ++ function = "pwm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_c_4_pins: pwm-ao-c-4 { ++ mux { ++ groups = "pwm_ao_c_4"; ++ function = "pwm_ao_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_c_6_pins: pwm-ao-c-6 { ++ mux { ++ groups = "pwm_ao_c_6"; ++ function = "pwm_ao_c"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_d_5_pins: pwm-ao-d-5 { ++ mux { ++ groups = "pwm_ao_d_5"; ++ function = "pwm_ao_d"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_d_10_pins: pwm-ao-d-10 { ++ mux { ++ groups = "pwm_ao_d_10"; ++ function = "pwm_ao_d"; ++ bias-disable; ++ }; ++ }; ++ ++ pwm_ao_d_e_pins: pwm-ao-d-e { ++ mux { ++ groups = "pwm_ao_d_e"; ++ function = "pwm_ao_d"; ++ bias-disable; ++ }; ++ }; + }; + }; + +@@ -535,6 +679,13 @@ + status = "disabled"; + }; + ++ pwm_AO_cd: pwm@2000 { ++ compatible = "amlogic,meson-g12a-ao-pwm-cd"; ++ reg = <0x0 0x2000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ + uart_AO: serial@3000 { + compatible = "amlogic,meson-gx-uart", + "amlogic,meson-ao-uart"; +@@ -555,6 +706,13 @@ + status = "disabled"; + }; + ++ pwm_AO_ab: pwm@7000 { ++ compatible = "amlogic,meson-g12a-ao-pwm-ab"; ++ reg = <0x0 0x7000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ + saradc: adc@9000 { + compatible = "amlogic,meson-g12a-saradc", + "amlogic,meson-saradc"; +@@ -623,6 +781,27 @@ + #reset-cells = <1>; + }; + ++ pwm_ef: pwm@19000 { ++ compatible = "amlogic,meson-g12a-ee-pwm"; ++ reg = <0x0 0x19000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ pwm_cd: pwm@1a000 { ++ compatible = "amlogic,meson-g12a-ee-pwm"; ++ reg = <0x0 0x1a000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ ++ pwm_ab: pwm@1b000 { ++ compatible = "amlogic,meson-g12a-ee-pwm"; ++ reg = <0x0 0x1b000 0x0 0x20>; ++ #pwm-cells = <3>; ++ status = "disabled"; ++ }; ++ + clk_msr: clock-measure@18000 { + compatible = "amlogic,meson-g12a-clk-measure"; + reg = <0x0 0x18000 0x0 0x10>; + +From afa93eb97486e10f45d09dc5d0af8b2c8b3d8c31 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 4 Feb 2019 15:45:34 +0100 +Subject: [PATCH 147/249] FROMLIST: arm64: dts: meson-g12a: Add IR nodes + +Amlogic G12A SoCs uses the exact same IR decoder as previous +families, add the IR node and the pintctrl setting. + +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 4f4355322673f..ee713693be777 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -649,6 +649,13 @@ + mux { + groups = "pwm_ao_d_e"; + function = "pwm_ao_d"; ++ }; ++ }; ++ ++ remote_input_ao_pins: remote-input-ao { ++ mux { ++ groups = "remote_ao_input"; ++ function = "remote_ao_input"; + bias-disable; + }; + }; +@@ -713,6 +720,13 @@ + status = "disabled"; + }; + ++ ir: ir@8000 { ++ compatible = "amlogic,meson-gxbb-ir"; ++ reg = <0x0 0x8000 0x0 0x20>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ + saradc: adc@9000 { + compatible = "amlogic,meson-g12a-saradc", + "amlogic,meson-saradc"; + +From 2be6ee97eda8f4fca30f02db1e222434e1fbff09 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 11 Apr 2019 16:02:16 +0200 +Subject: [PATCH 148/249] FROMLIST: arm64: dts: meson-g12a-x96-max: enable IR + decoder + +Add support for the IR decoder input on the X96 Max board. + +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index b3d913f28f121..5cdc263b03e67 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -144,6 +144,12 @@ + }; + }; + ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++}; ++ + &uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + +From 4ed272775f97e7a842530561f63336a2cbeb6904 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 11 Apr 2019 16:03:03 +0200 +Subject: [PATCH 149/249] FROMLIST: arm64: dts: meson-g12a-u200: enable IR + decoder + +Add support for the IR decoder input on the U200 Reference Design board. + +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index f1cb02567a130..c2221eb4549e2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -165,6 +165,12 @@ + }; + }; + ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++}; ++ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + +From 7c0cd2a31134d9a93749c044c8ff4451ccbbbe6c Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 25 Apr 2019 15:20:10 +0000 +Subject: [PATCH 150/249] FROMLIST: drm/meson: Add support for XBGR8888 & + ABGR8888 formats + +Add missing XBGR8888 & ABGR8888 formats variants from the primary plane. + +Fixes: bbbe775ec5b5 ("drm: Add support for Amlogic Meson Graphic Controller") +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190429075238.7884-1-narmstrong@baylibre.com +--- + drivers/gpu/drm/meson/meson_plane.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index bf8f1fab63aa9..b8f6b08a89a67 100644 +--- a/drivers/gpu/drm/meson/meson_plane.c ++++ b/drivers/gpu/drm/meson/meson_plane.c +@@ -165,6 +165,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | + OSD_COLOR_MATRIX_32_ARGB; + break; ++ case DRM_FORMAT_XBGR8888: ++ /* For XRGB, replace the pixel's alpha by 0xFF */ ++ writel_bits_relaxed(OSD_REPLACE_EN, OSD_REPLACE_EN, ++ priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); ++ priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | ++ OSD_COLOR_MATRIX_32_ABGR; ++ break; + case DRM_FORMAT_ARGB8888: + /* For ARGB, use the pixel's alpha */ + writel_bits_relaxed(OSD_REPLACE_EN, 0, +@@ -172,6 +179,13 @@ static void meson_plane_atomic_update(struct drm_plane *plane, + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | + OSD_COLOR_MATRIX_32_ARGB; + break; ++ case DRM_FORMAT_ABGR8888: ++ /* For ARGB, use the pixel's alpha */ ++ writel_bits_relaxed(OSD_REPLACE_EN, 0, ++ priv->io_base + _REG(VIU_OSD1_CTRL_STAT2)); ++ priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_32 | ++ OSD_COLOR_MATRIX_32_ABGR; ++ break; + case DRM_FORMAT_RGB888: + priv->viu.osd1_blk0_cfg[0] |= OSD_BLK_MODE_24 | + OSD_COLOR_MATRIX_24_RGB; +@@ -356,7 +370,9 @@ static const struct drm_plane_funcs meson_plane_funcs = { + + 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, + }; + +From 601b2ce79fa9a0a8e2e7de739a49e5f156648395 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 26 Apr 2019 10:13:23 +0000 +Subject: [PATCH 151/249] FROMLIST: drm/meson: Add zpos immutable property to + planes + +Add immutable zpos property to primary and overlay planes to specify +the current fixed zpos position. + +Fixes: f9a2348196d1 ("drm/meson: Support Overlay plane for video rendering") +Signed-off-by: Neil Armstrong +Link: https://lkml.kernel.org/r/20190429075247.7946-1-narmstrong@baylibre.com +--- + drivers/gpu/drm/meson/meson_overlay.c | 3 +++ + drivers/gpu/drm/meson/meson_plane.c | 3 +++ + 2 files changed, 6 insertions(+) + +diff --git a/drivers/gpu/drm/meson/meson_overlay.c b/drivers/gpu/drm/meson/meson_overlay.c +index bdbf925ff3e85..dceb3df5e6526 100644 +--- a/drivers/gpu/drm/meson/meson_overlay.c ++++ b/drivers/gpu/drm/meson/meson_overlay.c +@@ -578,6 +578,9 @@ int meson_overlay_create(struct meson_drm *priv) + + drm_plane_helper_add(plane, &meson_overlay_helper_funcs); + ++ /* For now, VD Overlay plane is always on the back */ ++ drm_plane_create_zpos_immutable_property(plane, 0); ++ + priv->overlay_plane = plane; + + DRM_DEBUG_DRIVER("\n"); +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index b8f6b08a89a67..2f7f4dfce45be 100644 +--- a/drivers/gpu/drm/meson/meson_plane.c ++++ b/drivers/gpu/drm/meson/meson_plane.c +@@ -399,6 +399,9 @@ int meson_plane_create(struct meson_drm *priv) + + drm_plane_helper_add(plane, &meson_plane_helper_funcs); + ++ /* For now, OSD Primary plane is always on the front */ ++ drm_plane_create_zpos_immutable_property(plane, 1); ++ + priv->primary_plane = plane; + + return 0; + +From d297597f9a3a1f89d4db70383a105c43e55983b8 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 29 Apr 2019 12:23:25 +0200 +Subject: [PATCH 152/249] FROMLIST: drm/meson: imply dw-hdmi i2s audio for + meson hdmi + +Imply the i2s part of the Synopsys HDMI driver for Amlogic SoCs. +This will enable the i2s part by default when meson hdmi driver +is enable but let platforms not supported by the audio subsystem +disable it if necessary. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/meson/Kconfig | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig +index c28b69f485555..a480e4a80beab 100644 +--- a/drivers/gpu/drm/meson/Kconfig ++++ b/drivers/gpu/drm/meson/Kconfig +@@ -14,3 +14,4 @@ config DRM_MESON_DW_HDMI + depends on DRM_MESON + default y if DRM_MESON + select DRM_DW_HDMI ++ imply DRM_DW_HDMI_I2S_AUDIO + +From 57c04b9c5bec28d82b26f918a1c77822ed55081f Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 11:16:09 +0200 +Subject: [PATCH 153/249] FROMLIST: arm64: dts: meson: g12a: add mmc nodes + +Add port B (sdcard) and port C (eMMC) pinctrl and controllers nodes to +the g12a DT. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 124 ++++++++++++++++++++ + 1 file changed, 124 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index ee713693be777..b5f145a5a08dd 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -243,6 +243,48 @@ + }; + }; + ++ emmc_pins: emmc { ++ mux-0 { ++ groups = "emmc_nand_d0", ++ "emmc_nand_d1", ++ "emmc_nand_d2", ++ "emmc_nand_d3", ++ "emmc_nand_d4", ++ "emmc_nand_d5", ++ "emmc_nand_d6", ++ "emmc_nand_d7", ++ "emmc_cmd"; ++ function = "emmc"; ++ bias-pull-up; ++ drive-strength-microamp = <4000>; ++ }; ++ ++ mux-1 { ++ groups = "emmc_clk"; ++ function = "emmc"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ emmc_ds_pins: emmc-ds { ++ mux { ++ groups = "emmc_nand_ds"; ++ function = "emmc"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ emmc_clk_gate_pins: emmc_clk_gate { ++ mux { ++ groups = "BOOT_8"; ++ function = "gpio_periphs"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ + hdmitx_ddc_pins: hdmitx_ddc { + mux { + groups = "hdmitx_sda", +@@ -348,6 +390,64 @@ + }; + }; + ++ sdcard_c_pins: sdcard_c { ++ mux-0 { ++ groups = "sdcard_d0_c", ++ "sdcard_d1_c", ++ "sdcard_d2_c", ++ "sdcard_d3_c", ++ "sdcard_cmd_c"; ++ function = "sdcard"; ++ bias-pull-up; ++ drive-strength-microamp = <4000>; ++ }; ++ ++ mux-1 { ++ groups = "sdcard_clk_c"; ++ function = "sdcard"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdcard_clk_gate_c_pins: sdcard_clk_gate_c { ++ mux { ++ groups = "GPIOC_4"; ++ function = "gpio_periphs"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdcard_z_pins: sdcard_z { ++ mux-0 { ++ groups = "sdcard_d0_z", ++ "sdcard_d1_z", ++ "sdcard_d2_z", ++ "sdcard_d3_z", ++ "sdcard_cmd_z"; ++ function = "sdcard"; ++ bias-pull-up; ++ drive-strength-microamp = <4000>; ++ }; ++ ++ mux-1 { ++ groups = "sdcard_clk_z"; ++ function = "sdcard"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdcard_clk_gate_z_pins: sdcard_clk_gate_z { ++ mux { ++ groups = "GPIOZ_6"; ++ function = "gpio_periphs"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ + uart_a_pins: uart-a { + mux { + groups = "uart_a_tx", +@@ -849,6 +949,30 @@ + }; + }; + ++ sd_emmc_b: sd@ffe05000 { ++ compatible = "amlogic,meson-axg-mmc"; ++ reg = <0x0 0xffe05000 0x0 0x800>; ++ interrupts = ; ++ status = "disabled"; ++ clocks = <&clkc CLKID_SD_EMMC_B>, ++ <&clkc CLKID_SD_EMMC_B_CLK0>, ++ <&clkc CLKID_FCLK_DIV2>; ++ clock-names = "core", "clkin0", "clkin1"; ++ resets = <&reset RESET_SD_EMMC_B>; ++ }; ++ ++ sd_emmc_c: mmc@ffe07000 { ++ compatible = "amlogic,meson-axg-mmc"; ++ reg = <0x0 0xffe07000 0x0 0x800>; ++ interrupts = ; ++ status = "disabled"; ++ clocks = <&clkc CLKID_SD_EMMC_C>, ++ <&clkc CLKID_SD_EMMC_C_CLK0>, ++ <&clkc CLKID_FCLK_DIV2>; ++ clock-names = "core", "clkin0", "clkin1"; ++ resets = <&reset RESET_SD_EMMC_C>; ++ }; ++ + usb: usb@ffe09000 { + status = "disabled"; + compatible = "amlogic,meson-g12a-usb-ctrl"; + +From 66a03968735669560fb291f1097b610efda8afe2 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 11:16:10 +0200 +Subject: [PATCH 154/249] FROMLIST: arm64: dts: meson: u200: add sd and emmc + +Enable eMMC and SDCard on the g12a u200 board + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12a-u200.dts | 42 +++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index c2221eb4549e2..2b6c2cd41aa68 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -32,6 +32,11 @@ + }; + }; + ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; ++ }; ++ + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; +@@ -171,6 +176,43 @@ + pinctrl-names = "default"; + }; + ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ 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>; ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_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>; ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vcc_3v3>; ++ vqmmc-supply = <&flash_1v8>; ++}; ++ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + +From 8f465d7c9306498f7874b1f1ba61944ba18aaa19 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 11:16:11 +0200 +Subject: [PATCH 155/249] FROMLIST: arm64: dts: meson: sei510: add sd and emmc + +Enable eMMC and SDCard on the g12a sei510 board + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 42 +++++++++++++++++++ + 1 file changed, 42 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 4a785b17c1af7..4376d9378908c 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -46,6 +46,11 @@ + }; + }; + ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; ++ }; ++ + hdmi-connector { + compatible = "hdmi-connector"; + type = "a"; +@@ -168,6 +173,43 @@ + vref-supply = <&vddio_ao1v8>; + }; + ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ 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>; ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_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>; ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&emmc_1v8>; ++}; ++ + &uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + +From 885394afbaed6b22aa985b96289821f8ee3cfbea Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 11:45:37 +0200 +Subject: [PATCH 156/249] FROMLIST: arm64: dts: meson: g12a: set uart_ao clocks + +Now that the AO clock controller is available, make the uarts of the +always-on domain claim the appropriate peripheral clock. + +Signed-off-by: Jerome Brunet +Reviewed-by: Neil Armstrong +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index b5f145a5a08dd..7b95d91d08255 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -798,7 +798,7 @@ + "amlogic,meson-ao-uart"; + reg = <0x0 0x3000 0x0 0x18>; + interrupts = ; +- clocks = <&xtal>, <&xtal>, <&xtal>; ++ clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; +@@ -808,7 +808,7 @@ + "amlogic,meson-ao-uart"; + reg = <0x0 0x4000 0x0 0x18>; + interrupts = ; +- clocks = <&xtal>, <&xtal>, <&xtal>; ++ clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; + status = "disabled"; + }; + +From 8c51017d1eb954dddf0ef151ba3ede002785ba0f Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Tue, 14 May 2019 12:12:35 +0200 +Subject: [PATCH 157/249] FROMLIST: arm64: dts: meson: g12a: add i2c nodes + +Add pinctrl and nodes for i2c support on amlogic g12a + +Signed-off-by: Guillaume La Roque +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 268 ++++++++++++++++++++ + 1 file changed, 268 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 7b95d91d08255..05fcaf73203bf 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -302,6 +302,188 @@ + }; + }; + ++ ++ i2c0_sda_c_pins: i2c0-sda-c { ++ mux { ++ groups = "i2c0_sda_c"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ ++ }; ++ }; ++ ++ i2c0_sck_c_pins: i2c0-sck-c { ++ mux { ++ groups = "i2c0_sck_c"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c0_sda_z0_pins: i2c0-sda-z0 { ++ mux { ++ groups = "i2c0_sda_z0"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c0_sck_z1_pins: i2c0-sck-z1 { ++ mux { ++ groups = "i2c0_sck_z1"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c0_sda_z7_pins: i2c0-sda-z7 { ++ mux { ++ groups = "i2c0_sda_z7"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c0_sda_z8_pins: i2c0-sda-z8 { ++ mux { ++ groups = "i2c0_sda_z8"; ++ function = "i2c0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sda_x_pins: i2c1-sda-x { ++ mux { ++ groups = "i2c1_sda_x"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sck_x_pins: i2c1-sck-x { ++ mux { ++ groups = "i2c1_sck_x"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sda_h2_pins: i2c1-sda-h2 { ++ mux { ++ groups = "i2c1_sda_h2"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sck_h3_pins: i2c1-sck-h3 { ++ mux { ++ groups = "i2c1_sck_h3"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sda_h6_pins: i2c1-sda-h6 { ++ mux { ++ groups = "i2c1_sda_h6"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c1_sck_h7_pins: i2c1-sck-h7 { ++ mux { ++ groups = "i2c1_sck_h7"; ++ function = "i2c1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c2_sda_x_pins: i2c2-sda-x { ++ mux { ++ groups = "i2c2_sda_x"; ++ function = "i2c2"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c2_sck_x_pins: i2c2-sck-x { ++ mux { ++ groups = "i2c2_sck_x"; ++ function = "i2c2"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c2_sda_z_pins: i2c2-sda-z { ++ mux { ++ groups = "i2c2_sda_z"; ++ function = "i2c2"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c2_sck_z_pins: i2c2-sck-z { ++ mux { ++ groups = "i2c2_sck_z"; ++ function = "i2c2"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c3_sda_h_pins: i2c3-sda-h { ++ mux { ++ groups = "i2c3_sda_h"; ++ function = "i2c3"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c3_sck_h_pins: i2c3-sck-h { ++ mux { ++ groups = "i2c3_sck_h"; ++ function = "i2c3"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c3_sda_a_pins: i2c3-sda-a { ++ mux { ++ groups = "i2c3_sda_a"; ++ function = "i2c3"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c3_sck_a_pins: i2c3-sck-a { ++ mux { ++ groups = "i2c3_sck_a"; ++ function = "i2c3"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ + pwm_a_pins: pwm-a { + mux { + groups = "pwm_a"; +@@ -679,6 +861,42 @@ + gpio-ranges = <&ao_pinctrl 0 0 15>; + }; + ++ i2c_ao_sck_pins: i2c_ao_sck_pins { ++ mux { ++ groups = "i2c_ao_sck"; ++ function = "i2c_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c_ao_sda_pins: i2c_ao_sda { ++ mux { ++ groups = "i2c_ao_sda"; ++ function = "i2c_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c_ao_sck_e_pins: i2c_ao_sck_e { ++ mux { ++ groups = "i2c_ao_sck_e"; ++ function = "i2c_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ i2c_ao_sda_e_pins: i2c_ao_sda_e { ++ mux { ++ groups = "i2c_ao_sda_e"; ++ function = "i2c_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ + uart_ao_a_pins: uart-a-ao { + mux { + groups = "uart_ao_a_tx", +@@ -813,6 +1031,16 @@ + status = "disabled"; + }; + ++ i2c_AO: i2c@5000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x05000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ + pwm_AO_ab: pwm@7000 { + compatible = "amlogic,meson-g12a-ao-pwm-ab"; + reg = <0x0 0x7000 0x0 0x20>; +@@ -916,6 +1144,46 @@ + status = "disabled"; + }; + ++ i2c3: i2c@1c000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x1c000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ ++ i2c2: i2c@1d000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x1d000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ ++ i2c1: i2c@1e000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x1e000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ ++ i2c0: i2c@1f000 { ++ compatible = "amlogic,meson-axg-i2c"; ++ status = "disabled"; ++ reg = <0x0 0x1f000 0x0 0x20>; ++ interrupts = ; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clkc CLKID_I2C>; ++ }; ++ + clk_msr: clock-measure@18000 { + compatible = "amlogic,meson-g12a-clk-measure"; + reg = <0x0 0x18000 0x0 0x10>; + +From 00515ec7e1bbd92e715e46b8582c50045b3b2d91 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 12:12:36 +0200 +Subject: [PATCH 158/249] FROMLIST: arm64: dts: meson: u200: enable i2c busses + +Add the 3 i2c busses present on the u200 reference design. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12a-u200.dts | 21 +++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index 2b6c2cd41aa68..8551fbd4a488c 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -176,6 +176,27 @@ + pinctrl-names = "default"; + }; + ++/* i2c Touch */ ++&i2c0 { ++ status = "okay"; ++ pinctrl-0 = <&i2c0_sda_z0_pins>, <&i2c0_sck_z1_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/* i2c CM */ ++&i2c2 { ++ status = "okay"; ++ pinctrl-0 = <&i2c2_sda_z_pins>, <&i2c2_sck_z_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/* i2c Audio */ ++&i2c3 { ++ status = "okay"; ++ pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>; ++ pinctrl-names = "default"; ++}; ++ + /* SD card */ + &sd_emmc_b { + status = "okay"; + +From c251d749b39eeee2b3330a9fefee0e15a61880ed Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 12:12:37 +0200 +Subject: [PATCH 159/249] FROMLIST: arm64: dts: meson: sei510: enable i2c3 + +Add the i2c bus used for RGB led controller. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 4376d9378908c..9f0b8005877ae 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -168,6 +168,12 @@ + }; + }; + ++&i2c3 { ++ status = "okay"; ++ pinctrl-0 = <&i2c3_sda_a_pins>, <&i2c3_sck_a_pins>; ++ pinctrl-names = "default"; ++}; ++ + &saradc { + status = "okay"; + vref-supply = <&vddio_ao1v8>; + +From 26f252d4fcecb7af98ea4ef610a7ade7b8f6e731 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 13:15:03 +0200 +Subject: [PATCH 160/249] FROMLIST: arm64: dts: meson: g12a: add audio clock + controller + +Add the g12a clock controller dedicated to audio. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 36 +++++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 05fcaf73203bf..b67bdcbc16a31 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -731,6 +731,42 @@ + }; + }; + ++ audio: bus@42000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0x42000 0x0 0x2000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x42000 0x0 0x2000>; ++ ++ clkc_audio: clock-controller@0 { ++ status = "disabled"; ++ compatible = "amlogic,g12a-audio-clkc"; ++ reg = <0x0 0x0 0x0 0xb4>; ++ #clock-cells = <1>; ++ ++ clocks = <&clkc CLKID_AUDIO>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>, ++ <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL3>, ++ <&clkc CLKID_HIFI_PLL>, ++ <&clkc CLKID_FCLK_DIV3>, ++ <&clkc CLKID_FCLK_DIV4>, ++ <&clkc CLKID_GP0_PLL>; ++ clock-names = "pclk", ++ "mst_in0", ++ "mst_in1", ++ "mst_in2", ++ "mst_in3", ++ "mst_in4", ++ "mst_in5", ++ "mst_in6", ++ "mst_in7"; ++ ++ resets = <&reset RESET_AUDIO>; ++ }; ++ }; ++ + usb3_pcie_phy: phy@46000 { + compatible = "amlogic,g12a-usb3-pcie-phy"; + reg = <0x0 0x46000 0x0 0x2000>; + +From 43bf187e1732fac571d216f220abaf4972a3a63d Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 13:15:04 +0200 +Subject: [PATCH 161/249] FROMLIST: arm64: dts: meson: g12a: add audio memory + arbitrer + +Add the audio DDR memory arbitrer of the g12a SoC family. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index b67bdcbc16a31..668f43fad57e5 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -5,6 +5,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -765,6 +766,14 @@ + + resets = <&reset RESET_AUDIO>; + }; ++ ++ arb: reset-controller@280 { ++ status = "disabled"; ++ compatible = "amlogic,meson-axg-audio-arb"; ++ reg = <0x0 0x280 0x0 0x4>; ++ #reset-cells = <1>; ++ clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; ++ }; + }; + + usb3_pcie_phy: phy@46000 { + +From c104488a20d9a6a188b8603e02fa3810156ea263 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 13:15:05 +0200 +Subject: [PATCH 162/249] FROMLIST: arm64: dts: meson: g12a: add audio fifos + +Add the playback and capture memory interfaces of the g12a SoC family. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 67 +++++++++++++++++++++ + 1 file changed, 67 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 668f43fad57e5..7f382f59b2ef8 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + + / { +@@ -767,6 +768,72 @@ + resets = <&reset RESET_AUDIO>; + }; + ++ toddr_a: audio-controller@100 { ++ compatible = "amlogic,g12a-toddr"; ++ reg = <0x0 0x100 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TODDR_A"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_TODDR_A>; ++ resets = <&arb AXG_ARB_TODDR_A>; ++ status = "disabled"; ++ }; ++ ++ toddr_b: audio-controller@140 { ++ compatible = "amlogic,g12a-toddr"; ++ reg = <0x0 0x140 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TODDR_B"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_TODDR_B>; ++ resets = <&arb AXG_ARB_TODDR_B>; ++ status = "disabled"; ++ }; ++ ++ toddr_c: audio-controller@180 { ++ compatible = "amlogic,g12a-toddr"; ++ reg = <0x0 0x180 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TODDR_C"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_TODDR_C>; ++ resets = <&arb AXG_ARB_TODDR_C>; ++ status = "disabled"; ++ }; ++ ++ frddr_a: audio-controller@1c0 { ++ compatible = "amlogic,g12a-frddr"; ++ reg = <0x0 0x1c0 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "FRDDR_A"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_FRDDR_A>; ++ resets = <&arb AXG_ARB_FRDDR_A>; ++ status = "disabled"; ++ }; ++ ++ frddr_b: audio-controller@200 { ++ compatible = "amlogic,g12a-frddr"; ++ reg = <0x0 0x200 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "FRDDR_B"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_FRDDR_B>; ++ resets = <&arb AXG_ARB_FRDDR_B>; ++ status = "disabled"; ++ }; ++ ++ frddr_c: audio-controller@240 { ++ compatible = "amlogic,g12a-frddr"; ++ reg = <0x0 0x240 0x0 0x1c>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "FRDDR_C"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_FRDDR_C>; ++ resets = <&arb AXG_ARB_FRDDR_C>; ++ status = "disabled"; ++ }; ++ + arb: reset-controller@280 { + status = "disabled"; + compatible = "amlogic,meson-axg-audio-arb"; + +From 540d0eddb18133b1ff75d9a9acadf4866584aa58 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 13:15:06 +0200 +Subject: [PATCH 163/249] FROMLIST: arm64: dts: meson: g12a: add tdm + +Add the devices and pinctrl definitions for the tdm interfaces of +the g12a SoC family. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 658 ++++++++++++++++++++ + 1 file changed, 658 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 7f382f59b2ef8..73aa3025b50a2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -20,6 +20,39 @@ + #address-cells = <2>; + #size-cells = <2>; + ++ tdmif_a: audio-controller-0 { ++ compatible = "amlogic,axg-tdm-iface"; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TDM_A"; ++ clocks = <&clkc_audio AUD_CLKID_MST_A_MCLK>, ++ <&clkc_audio AUD_CLKID_MST_A_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_A_LRCLK>; ++ clock-names = "mclk", "sclk", "lrclk"; ++ status = "disabled"; ++ }; ++ ++ tdmif_b: audio-controller-1 { ++ compatible = "amlogic,axg-tdm-iface"; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TDM_B"; ++ clocks = <&clkc_audio AUD_CLKID_MST_B_MCLK>, ++ <&clkc_audio AUD_CLKID_MST_B_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_B_LRCLK>; ++ clock-names = "mclk", "sclk", "lrclk"; ++ status = "disabled"; ++ }; ++ ++ tdmif_c: audio-controller-2 { ++ compatible = "amlogic,axg-tdm-iface"; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "TDM_C"; ++ clocks = <&clkc_audio AUD_CLKID_MST_C_MCLK>, ++ <&clkc_audio AUD_CLKID_MST_C_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_C_LRCLK>; ++ clock-names = "mclk", "sclk", "lrclk"; ++ status = "disabled"; ++ }; ++ + cpus { + #address-cells = <0x2>; + #size-cells = <0x0>; +@@ -486,6 +519,42 @@ + }; + }; + ++ mclk0_a_pins: mclk0_a { ++ mux { ++ groups = "mclk0_a"; ++ function = "mclk0"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ mclk1_a_pins: mclk1_a { ++ mux { ++ groups = "mclk1_a"; ++ function = "mclk1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ mclk1_x_pins: mclk1_x { ++ mux { ++ groups = "mclk1_x"; ++ function = "mclk1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ mclk1_z_pins: mclk1_z { ++ mux { ++ groups = "mclk1_z"; ++ function = "mclk1"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ + pwm_a_pins: pwm-a { + mux { + groups = "pwm_a"; +@@ -632,6 +701,399 @@ + }; + }; + ++ tdm_a_din0_pins: tdm-a-din0 { ++ mux { ++ groups = "tdm_a_din0"; ++ function = "tdm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ ++ tdm_a_din1_pins: tdm-a-din1 { ++ mux { ++ groups = "tdm_a_din1"; ++ function = "tdm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_a_dout0_pins: tdm-a-dout0 { ++ mux { ++ groups = "tdm_a_dout0"; ++ function = "tdm_a"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_a_dout1_pins: tdm-a-dout1 { ++ mux { ++ groups = "tdm_a_dout1"; ++ function = "tdm_a"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_a_fs_pins: tdm-a-fs { ++ mux { ++ groups = "tdm_a_fs"; ++ function = "tdm_a"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_a_sclk_pins: tdm-a-sclk { ++ mux { ++ groups = "tdm_a_sclk"; ++ function = "tdm_a"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_a_slv_fs_pins: tdm-a-slv-fs { ++ mux { ++ groups = "tdm_a_slv_fs"; ++ function = "tdm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ ++ tdm_a_slv_sclk_pins: tdm-a-slv-sclk { ++ mux { ++ groups = "tdm_a_slv_sclk"; ++ function = "tdm_a"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din0_pins: tdm-b-din0 { ++ mux { ++ groups = "tdm_b_din0"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din1_pins: tdm-b-din1 { ++ mux { ++ groups = "tdm_b_din1"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din2_pins: tdm-b-din2 { ++ mux { ++ groups = "tdm_b_din2"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din3_a_pins: tdm-b-din3-a { ++ mux { ++ groups = "tdm_b_din3_a"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_din3_h_pins: tdm-b-din3-h { ++ mux { ++ groups = "tdm_b_din3_h"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_dout0_pins: tdm-b-dout0 { ++ mux { ++ groups = "tdm_b_dout0"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_dout1_pins: tdm-b-dout1 { ++ mux { ++ groups = "tdm_b_dout1"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_dout2_pins: tdm-b-dout2 { ++ mux { ++ groups = "tdm_b_dout2"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_dout3_a_pins: tdm-b-dout3-a { ++ mux { ++ groups = "tdm_b_dout3_a"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_dout3_h_pins: tdm-b-dout3-h { ++ mux { ++ groups = "tdm_b_dout3_h"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_fs_pins: tdm-b-fs { ++ mux { ++ groups = "tdm_b_fs"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_sclk_pins: tdm-b-sclk { ++ mux { ++ groups = "tdm_b_sclk"; ++ function = "tdm_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_b_slv_fs_pins: tdm-b-slv-fs { ++ mux { ++ groups = "tdm_b_slv_fs"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_b_slv_sclk_pins: tdm-b-slv-sclk { ++ mux { ++ groups = "tdm_b_slv_sclk"; ++ function = "tdm_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din0_a_pins: tdm-c-din0-a { ++ mux { ++ groups = "tdm_c_din0_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din0_z_pins: tdm-c-din0-z { ++ mux { ++ groups = "tdm_c_din0_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din1_a_pins: tdm-c-din1-a { ++ mux { ++ groups = "tdm_c_din1_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din1_z_pins: tdm-c-din1-z { ++ mux { ++ groups = "tdm_c_din1_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din2_a_pins: tdm-c-din2-a { ++ mux { ++ groups = "tdm_c_din2_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din2_z_pins: tdm-c-din2-z { ++ mux { ++ groups = "tdm_c_din2_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din3_a_pins: tdm-c-din3-a { ++ mux { ++ groups = "tdm_c_din3_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_din3_z_pins: tdm-c-din3-z { ++ mux { ++ groups = "tdm_c_din3_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_dout0_a_pins: tdm-c-dout0-a { ++ mux { ++ groups = "tdm_c_dout0_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout0_z_pins: tdm-c-dout0-z { ++ mux { ++ groups = "tdm_c_dout0_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout1_a_pins: tdm-c-dout1-a { ++ mux { ++ groups = "tdm_c_dout1_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout1_z_pins: tdm-c-dout1-z { ++ mux { ++ groups = "tdm_c_dout1_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout2_a_pins: tdm-c-dout2-a { ++ mux { ++ groups = "tdm_c_dout2_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout2_z_pins: tdm-c-dout2-z { ++ mux { ++ groups = "tdm_c_dout2_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout3_a_pins: tdm-c-dout3-a { ++ mux { ++ groups = "tdm_c_dout3_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_dout3_z_pins: tdm-c-dout3-z { ++ mux { ++ groups = "tdm_c_dout3_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_fs_a_pins: tdm-c-fs-a { ++ mux { ++ groups = "tdm_c_fs_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_fs_z_pins: tdm-c-fs-z { ++ mux { ++ groups = "tdm_c_fs_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_sclk_a_pins: tdm-c-sclk-a { ++ mux { ++ groups = "tdm_c_sclk_a"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_sclk_z_pins: tdm-c-sclk-z { ++ mux { ++ groups = "tdm_c_sclk_z"; ++ function = "tdm_c"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_c_slv_fs_a_pins: tdm-c-slv-fs-a { ++ mux { ++ groups = "tdm_c_slv_fs_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_slv_fs_z_pins: tdm-c-slv-fs-z { ++ mux { ++ groups = "tdm_c_slv_fs_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_slv_sclk_a_pins: tdm-c-slv-sclk-a { ++ mux { ++ groups = "tdm_c_slv_sclk_a"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_c_slv_sclk_z_pins: tdm-c-slv-sclk-z { ++ mux { ++ groups = "tdm_c_slv_sclk_z"; ++ function = "tdm_c"; ++ bias-disable; ++ }; ++ }; ++ + uart_a_pins: uart-a { + mux { + groups = "uart_a_tx", +@@ -841,6 +1303,108 @@ + #reset-cells = <1>; + clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; + }; ++ ++ tdmin_a: audio-controller@300 { ++ compatible = "amlogic,g12a-tdmin", ++ "amlogic,axg-tdmin"; ++ reg = <0x0 0x300 0x0 0x40>; ++ sound-name-prefix = "TDMIN_A"; ++ clocks = <&clkc_audio AUD_CLKID_TDMIN_A>, ++ <&clkc_audio AUD_CLKID_TDMIN_A_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_A_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_A_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmin_b: audio-controller@340 { ++ compatible = "amlogic,g12a-tdmin", ++ "amlogic,axg-tdmin"; ++ reg = <0x0 0x340 0x0 0x40>; ++ sound-name-prefix = "TDMIN_B"; ++ clocks = <&clkc_audio AUD_CLKID_TDMIN_B>, ++ <&clkc_audio AUD_CLKID_TDMIN_B_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_B_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_B_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmin_c: audio-controller@380 { ++ compatible = "amlogic,g12a-tdmin", ++ "amlogic,axg-tdmin"; ++ reg = <0x0 0x380 0x0 0x40>; ++ sound-name-prefix = "TDMIN_C"; ++ clocks = <&clkc_audio AUD_CLKID_TDMIN_C>, ++ <&clkc_audio AUD_CLKID_TDMIN_C_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_C_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_C_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmin_lb: audio-controller@3c0 { ++ compatible = "amlogic,g12a-tdmin", ++ "amlogic,axg-tdmin"; ++ reg = <0x0 0x3c0 0x0 0x40>; ++ sound-name-prefix = "TDMIN_LB"; ++ clocks = <&clkc_audio AUD_CLKID_TDMIN_LB>, ++ <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_LB_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMIN_LB_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmout_a: audio-controller@500 { ++ compatible = "amlogic,g12a-tdmout"; ++ reg = <0x0 0x500 0x0 0x40>; ++ sound-name-prefix = "TDMOUT_A"; ++ clocks = <&clkc_audio AUD_CLKID_TDMOUT_A>, ++ <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_A_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_A_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmout_b: audio-controller@540 { ++ compatible = "amlogic,g12a-tdmout"; ++ reg = <0x0 0x540 0x0 0x40>; ++ sound-name-prefix = "TDMOUT_B"; ++ clocks = <&clkc_audio AUD_CLKID_TDMOUT_B>, ++ <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_B_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_B_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; ++ ++ tdmout_c: audio-controller@580 { ++ compatible = "amlogic,g12a-tdmout"; ++ reg = <0x0 0x580 0x0 0x40>; ++ sound-name-prefix = "TDMOUT_C"; ++ clocks = <&clkc_audio AUD_CLKID_TDMOUT_C>, ++ <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_C_SCLK_SEL>, ++ <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>, ++ <&clkc_audio AUD_CLKID_TDMOUT_C_LRCLK>; ++ clock-names = "pclk", "sclk", "sclk_sel", ++ "lrclk", "lrclk_sel"; ++ status = "disabled"; ++ }; + }; + + usb3_pcie_phy: phy@46000 { +@@ -1009,6 +1573,100 @@ + }; + }; + ++ mclk0_ao_pins: mclk0-ao { ++ mux { ++ groups = "mclk0_ao"; ++ function = "mclk0_ao"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_din0_pins: tdm-ao-b-din0 { ++ mux { ++ groups = "tdm_ao_b_din0"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_ao_b_din1_pins: tdm-ao-b-din1 { ++ mux { ++ groups = "tdm_ao_b_din1"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_ao_b_din2_pins: tdm-ao-b-din2 { ++ mux { ++ groups = "tdm_ao_b_din2"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_ao_b_dout0_pins: tdm-ao-b-dout0 { ++ mux { ++ groups = "tdm_ao_b_dout0"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_dout1_pins: tdm-ao-b-dout1 { ++ mux { ++ groups = "tdm_ao_b_dout1"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_dout2_pins: tdm-ao-b-dout2 { ++ mux { ++ groups = "tdm_ao_b_dout2"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_fs_pins: tdm-ao-b-fs { ++ mux { ++ groups = "tdm_ao_b_fs"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_sclk_pins: tdm-ao-b-sclk { ++ mux { ++ groups = "tdm_ao_b_sclk"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ drive-strength-microamp = <3000>; ++ }; ++ }; ++ ++ tdm_ao_b_slv_fs_pins: tdm-ao-b-slv-fs { ++ mux { ++ groups = "tdm_ao_b_slv_fs"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ ++ tdm_ao_b_slv_sclk_pins: tdm-ao-b-slv-sclk { ++ mux { ++ groups = "tdm_ao_b_slv_sclk"; ++ function = "tdm_ao_b"; ++ bias-disable; ++ }; ++ }; ++ + uart_ao_a_pins: uart-a-ao { + mux { + groups = "uart_ao_a_tx", + +From fc0995a2c81aa81181c862ca5fe785d338628263 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 13:15:07 +0200 +Subject: [PATCH 164/249] FROMLIST: arm64: dts: meson: g12a: add spdifouts + +Add the devices nodes and pinctrl definitions for the spdif outputs of +the g12a SoC family + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 60 +++++++++++++++++++++ + 1 file changed, 60 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 73aa3025b50a2..0cb04f83c5213 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -701,6 +701,33 @@ + }; + }; + ++ spdif_out_h_pins: spdif-out-h { ++ mux { ++ groups = "spdif_out_h"; ++ function = "spdif_out"; ++ drive-strength-microamp = <500>; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_out_a11_pins: spdif-out-a11 { ++ mux { ++ groups = "spdif_out_a11"; ++ function = "spdif_out"; ++ drive-strength-microamp = <500>; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_out_a13_pins: spdif-out-a13 { ++ mux { ++ groups = "spdif_out_a13"; ++ function = "spdif_out"; ++ drive-strength-microamp = <500>; ++ bias-disable; ++ }; ++ }; ++ + tdm_a_din0_pins: tdm-a-din0 { + mux { + groups = "tdm_a_din0"; +@@ -1364,6 +1391,18 @@ + status = "disabled"; + }; + ++ spdifout: audio-controller@480 { ++ compatible = "amlogic,g12a-spdifout", ++ "amlogic,axg-spdifout"; ++ reg = <0x0 0x480 0x0 0x50>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "SPDIFOUT"; ++ clocks = <&clkc_audio AUD_CLKID_SPDIFOUT>, ++ <&clkc_audio AUD_CLKID_SPDIFOUT_CLK>; ++ clock-names = "pclk", "mclk"; ++ status = "disabled"; ++ }; ++ + tdmout_a: audio-controller@500 { + compatible = "amlogic,g12a-tdmout"; + reg = <0x0 0x500 0x0 0x40>; +@@ -1405,6 +1444,18 @@ + "lrclk", "lrclk_sel"; + status = "disabled"; + }; ++ ++ spdifout_b: audio-controller@680 { ++ compatible = "amlogic,g12a-spdifout", ++ "amlogic,axg-spdifout"; ++ reg = <0x0 0x680 0x0 0x50>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "SPDIFOUT_B"; ++ clocks = <&clkc_audio AUD_CLKID_SPDIFOUT_B>, ++ <&clkc_audio AUD_CLKID_SPDIFOUT_B_CLK>; ++ clock-names = "pclk", "mclk"; ++ status = "disabled"; ++ }; + }; + + usb3_pcie_phy: phy@46000 { +@@ -1590,6 +1641,15 @@ + }; + }; + ++ spdif_ao_out_pins: spdif_ao_out { ++ mux { ++ groups = "spdif_ao_out"; ++ function = "spdif_ao_out"; ++ drive-strength-microamp = <500>; ++ bias-disable; ++ }; ++ }; ++ + tdm_ao_b_din1_pins: tdm-ao-b-din1 { + mux { + groups = "tdm_ao_b_din1"; + +From d040122987c72bda00023d06f569c32b4985f601 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 13:15:08 +0200 +Subject: [PATCH 165/249] FROMLIST: arm64: dts: meson: g12a: add pdm + +Add the pdm device node and the pinctrl definition for this capture +interface g12a SoC family + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 177 ++++++++++++++++++++ + 1 file changed, 177 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 0cb04f83c5213..42292d3992338 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -555,6 +555,170 @@ + }; + }; + ++ pdm_din0_a_pins: pdm_din0_a { ++ mux { ++ groups = "pdm_din0_a"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din0_c_pins: pdm_din0_c { ++ mux { ++ groups = "pdm_din0_c"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din0_x_pins: pdm_din0_x { ++ mux { ++ groups = "pdm_din0_x"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din0_z_pins: pdm_din0_z { ++ mux { ++ groups = "pdm_din0_z"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din1_a_pins: pdm_din1_a { ++ mux { ++ groups = "pdm_din1_a"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din1_c_pins: pdm_din1_c { ++ mux { ++ groups = "pdm_din1_c"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din1_x_pins: pdm_din1_x { ++ mux { ++ groups = "pdm_din1_x"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din1_z_pins: pdm_din1_z { ++ mux { ++ groups = "pdm_din1_z"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din2_a_pins: pdm_din2_a { ++ mux { ++ groups = "pdm_din2_a"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din2_c_pins: pdm_din2_c { ++ mux { ++ groups = "pdm_din2_c"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din2_x_pins: pdm_din2_x { ++ mux { ++ groups = "pdm_din2_x"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din2_z_pins: pdm_din2_z { ++ mux { ++ groups = "pdm_din2_z"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din3_a_pins: pdm_din3_a { ++ mux { ++ groups = "pdm_din3_a"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din3_c_pins: pdm_din3_c { ++ mux { ++ groups = "pdm_din3_c"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din3_x_pins: pdm_din3_x { ++ mux { ++ groups = "pdm_din3_x"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_din3_z_pins: pdm_din3_z { ++ mux { ++ groups = "pdm_din3_z"; ++ function = "pdm"; ++ bias-disable; ++ }; ++ }; ++ ++ pdm_dclk_a_pins: pdm_dclk_a { ++ mux { ++ groups = "pdm_dclk_a"; ++ function = "pdm"; ++ bias-disable; ++ drive-strength-microamp = <500>; ++ }; ++ }; ++ ++ pdm_dclk_c_pins: pdm_dclk_c { ++ mux { ++ groups = "pdm_dclk_c"; ++ function = "pdm"; ++ bias-disable; ++ drive-strength-microamp = <500>; ++ }; ++ }; ++ ++ pdm_dclk_x_pins: pdm_dclk_x { ++ mux { ++ groups = "pdm_dclk_x"; ++ function = "pdm"; ++ bias-disable; ++ drive-strength-microamp = <500>; ++ }; ++ }; ++ ++ pdm_dclk_z_pins: pdm_dclk_z { ++ mux { ++ groups = "pdm_dclk_z"; ++ function = "pdm"; ++ bias-disable; ++ drive-strength-microamp = <500>; ++ }; ++ }; ++ + pwm_a_pins: pwm-a { + mux { + groups = "pwm_a"; +@@ -1222,6 +1386,19 @@ + }; + }; + ++ pdm: audio-controller@40000 { ++ compatible = "amlogic,g12a-pdm", ++ "amlogic,axg-pdm"; ++ reg = <0x0 0x40000 0x0 0x34>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "PDM"; ++ clocks = <&clkc_audio AUD_CLKID_PDM>, ++ <&clkc_audio AUD_CLKID_PDM_DCLK>, ++ <&clkc_audio AUD_CLKID_PDM_SYSCLK>; ++ clock-names = "pclk", "dclk", "sysclk"; ++ status = "disabled"; ++ }; ++ + audio: bus@42000 { + compatible = "simple-bus"; + reg = <0x0 0x42000 0x0 0x2000>; + +From 955d6af8987bd39aa651aa3decfd005340acab54 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 13:15:09 +0200 +Subject: [PATCH 166/249] FROMLIST: arm64: dts: meson: g12a: add spdifin + +Add the spdif input device node and the pinctrl definition for +this capture interface g12a SoC family + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 37 +++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 42292d3992338..40cdab068577d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -865,6 +865,30 @@ + }; + }; + ++ spdif_in_a10_pins: spdif-in-a10 { ++ mux { ++ groups = "spdif_in_a10"; ++ function = "spdif_in"; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_in_a12_pins: spdif-in-a12 { ++ mux { ++ groups = "spdif_in_a12"; ++ function = "spdif_in"; ++ bias-disable; ++ }; ++ }; ++ ++ spdif_in_h_pins: spdif-in-h { ++ mux { ++ groups = "spdif_in_h"; ++ function = "spdif_in"; ++ bias-disable; ++ }; ++ }; ++ + spdif_out_h_pins: spdif-out-h { + mux { + groups = "spdif_out_h"; +@@ -1568,6 +1592,19 @@ + status = "disabled"; + }; + ++ spdifin: audio-controller@400 { ++ compatible = "amlogic,g12a-spdifin", ++ "amlogic,axg-spdifin"; ++ reg = <0x0 0x400 0x0 0x30>; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "SPDIFIN"; ++ interrupts = ; ++ clocks = <&clkc_audio AUD_CLKID_SPDIFIN>, ++ <&clkc_audio AUD_CLKID_SPDIFIN_CLK>; ++ clock-names = "pclk", "refclk"; ++ status = "disabled"; ++ }; ++ + spdifout: audio-controller@480 { + compatible = "amlogic,g12a-spdifout", + "amlogic,axg-spdifout"; + +From 22df6e84290731863bd4b40560609c4492155cd1 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 14 May 2019 13:15:10 +0200 +Subject: [PATCH 167/249] FROMLIST: arm64: dts: meson: g12a: enable hdmi_tx + sound dai provider + +At the moment the sysnopsys hdmi i2s driver provides a single playback +DAI. Add the corresponding sound-dai-cell to the hdmi device node. + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 40cdab068577d..8822acab23315 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -179,6 +179,7 @@ + clock-names = "isfr", "iahb", "venci"; + #address-cells = <1>; + #size-cells = <0>; ++ #sound-dai-cells = <0>; + status = "disabled"; + + /* VPU VENC Input */ + +From f5ee2d03881853eb3425aefa150de1be2a3eeae3 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 13 May 2019 11:15:46 +0200 +Subject: [PATCH 168/249] FROMLIST: dt-bindings: mmc: meson-gx: add + ddr-access-quirk property + +On the Amlogic G12A SoC family, (only) the SDIO controller has a bug which +makes any DDR access from the MMC controller fail. + +Add the amlogic,ddr-access-quirk property so signal this particular +controller has this bug and needs a quirk to work properly. + +Signed-off-by: Neil Armstrong +--- + Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt +index 13e70409e8ac6..f8914dab06c60 100644 +--- a/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt ++++ b/Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt +@@ -22,6 +22,10 @@ Required properties: + clock rate requested by the MMC core. + - resets : phandle of the internal reset line + ++Optional properties: ++- amlogic,ddr-access-quirk: set when HW cannot access the DDR memory, like on ++ the G12A SDIO controller. ++ + Example: + + sd_emmc_a: mmc@70000 { + +From 8e7e969c288262fa5dc3e5b4bbf77b8cd7ad9bc0 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 13 May 2019 11:15:47 +0200 +Subject: [PATCH 169/249] FROMLIST: mmc: meson-gx: add ddr-access-quirk + +On the Amlogic G12A SoC family, (only) the SDIO controller fails to access +the data from DDR, leading to a broken controller. + +But each MMC controller has 1,5KiB of SRAM after the registers, that can +be used as bounce buffer to avoid direct DDR access from the integrated +DMAs (this SRAM may be used by the boot ROM when DDR is not yet initialized). + +The quirk is to disable the chained descriptor for this controller, and +use this SRAM memory zone as buffer for the bounce buffer fallback mode. + +The performance hit hasn't been evaluated, but the fix has been tested +using a WiFi AP6398S SDIO module, and the iperf3 Bandwidth measurement gave +55.2 Mbits/sec over a 63 Hours long test, with the SDIO ios set as High-Speed +at 50MHz clock. It gave 170 Mbits/sec as SDR104 and 200MHz clock. + +Signed-off-by: Neil Armstrong +Reviewed-by: Kevin Hilman +Signed-off-by: Neil Armstrong +--- + drivers/mmc/host/meson-gx-mmc.c | 65 ++++++++++++++++++++++++++------- + 1 file changed, 52 insertions(+), 13 deletions(-) + +diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c +index c5a8af4ca76b2..6ef4653040526 100644 +--- a/drivers/mmc/host/meson-gx-mmc.c ++++ b/drivers/mmc/host/meson-gx-mmc.c +@@ -129,6 +129,9 @@ + #define SD_EMMC_TXD 0x94 + #define SD_EMMC_LAST_REG SD_EMMC_TXD + ++#define SD_EMMC_SRAM_DATA_BUF_LEN 1536 ++#define SD_EMMC_SRAM_DATA_BUF_OFF 0x200 ++ + #define SD_EMMC_CFG_BLK_SIZE 512 /* internal buffer max: 512 bytes */ + #define SD_EMMC_CFG_RESP_TIMEOUT 256 /* in clock cycles */ + #define SD_EMMC_CMD_TIMEOUT 1024 /* in ms */ +@@ -168,6 +171,8 @@ struct meson_host { + unsigned long req_rate; + bool ddr; + ++ bool ddr_access_quirk; ++ + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_clk_gate; +@@ -232,11 +237,20 @@ static struct mmc_command *meson_mmc_get_next_command(struct mmc_command *cmd) + static void meson_mmc_get_transfer_mode(struct mmc_host *mmc, + struct mmc_request *mrq) + { ++ struct meson_host *host = mmc_priv(mmc); + struct mmc_data *data = mrq->data; + struct scatterlist *sg; + int i; + bool use_desc_chain_mode = true; + ++ /* ++ * When Controller DMA cannot directly access DDR memory, disable ++ * support for Chain Mode to directly use the internal SRAM using ++ * the bounce buffer mode. ++ */ ++ if (host->ddr_access_quirk) ++ return; ++ + /* + * Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been + * reported. For some strange reason this occurs in descriptor +@@ -1049,6 +1063,10 @@ static int meson_mmc_probe(struct platform_device *pdev) + host->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, host); + ++ /* The G12A SDIO Controller needs an SRAM bounce buffer */ ++ host->ddr_access_quirk = device_property_read_bool(&pdev->dev, ++ "amlogic,ddr-access-quirk"); ++ + /* Get regulators and the supported OCR mask */ + host->vqmmc_enabled = false; + ret = mmc_regulator_get_supply(mmc); +@@ -1146,9 +1164,16 @@ static int meson_mmc_probe(struct platform_device *pdev) + goto err_init_clk; + + mmc->caps |= MMC_CAP_CMD23; +- mmc->max_blk_count = CMD_CFG_LENGTH_MASK; ++ if (host->ddr_access_quirk) { ++ /* Limit to the available sram memory */ ++ mmc->max_segs = SD_EMMC_SRAM_DATA_BUF_LEN / mmc->max_blk_size; ++ mmc->max_blk_count = mmc->max_segs; ++ } else { ++ mmc->max_blk_count = CMD_CFG_LENGTH_MASK; ++ mmc->max_segs = SD_EMMC_DESC_BUF_LEN / ++ sizeof(struct sd_emmc_desc); ++ } + mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; +- mmc->max_segs = SD_EMMC_DESC_BUF_LEN / sizeof(struct sd_emmc_desc); + mmc->max_seg_size = mmc->max_req_size; + + /* +@@ -1158,15 +1183,27 @@ static int meson_mmc_probe(struct platform_device *pdev) + */ + mmc->caps2 &= ~MMC_CAP2_HS400; + +- /* data bounce buffer */ +- host->bounce_buf_size = mmc->max_req_size; +- host->bounce_buf = +- dma_alloc_coherent(host->dev, host->bounce_buf_size, +- &host->bounce_dma_addr, GFP_KERNEL); +- if (host->bounce_buf == NULL) { +- dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n"); +- ret = -ENOMEM; +- goto err_free_irq; ++ if (host->ddr_access_quirk) { ++ /* ++ * The MMC Controller embeds 1,5KiB of internal SRAM ++ * that can be used to be used as bounce buffer. ++ * In the case of the G12A SDIO controller, use these ++ * instead of the DDR memory ++ */ ++ host->bounce_buf_size = SD_EMMC_SRAM_DATA_BUF_LEN; ++ host->bounce_buf = host->regs + SD_EMMC_SRAM_DATA_BUF_OFF; ++ host->bounce_dma_addr = res->start + SD_EMMC_SRAM_DATA_BUF_OFF; ++ } else { ++ /* data bounce buffer */ ++ host->bounce_buf_size = mmc->max_req_size; ++ host->bounce_buf = ++ dma_alloc_coherent(host->dev, host->bounce_buf_size, ++ &host->bounce_dma_addr, GFP_KERNEL); ++ if (host->bounce_buf == NULL) { ++ dev_err(host->dev, "Unable to map allocate DMA bounce buffer.\n"); ++ ret = -ENOMEM; ++ goto err_free_irq; ++ } + } + + host->descs = dma_alloc_coherent(host->dev, SD_EMMC_DESC_BUF_LEN, +@@ -1208,8 +1245,10 @@ static int meson_mmc_remove(struct platform_device *pdev) + + dma_free_coherent(host->dev, SD_EMMC_DESC_BUF_LEN, + host->descs, host->descs_dma_addr); +- dma_free_coherent(host->dev, host->bounce_buf_size, +- host->bounce_buf, host->bounce_dma_addr); ++ ++ if (!host->ddr_access_quirk) ++ dma_free_coherent(host->dev, host->bounce_buf_size, ++ host->bounce_buf, host->bounce_dma_addr); + + clk_disable_unprepare(host->mmc_clk); + clk_disable_unprepare(host->core_clk); + +From 2bccc28e7190cb1ea0c6ce556de880c1a04c2726 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 26 Apr 2019 17:55:24 +0200 +Subject: [PATCH 170/249] WIP: ASoC: dapm: let mux force a disconnect during + power update + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + sound/soc/soc-dapm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c +index 0382a47b30bd8..0e3bda80f5319 100644 +--- a/sound/soc/soc-dapm.c ++++ b/sound/soc/soc-dapm.c +@@ -2244,7 +2244,7 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, + dapm_kcontrol_for_each_path(path, kcontrol) { + found = 1; + /* we now need to match the string in the enum to the path */ +- if (!(strcmp(path->name, e->texts[mux]))) ++ if (e && !(strcmp(path->name, e->texts[mux]))) + connect = true; + else + connect = false; + +From 16f03e497af82f68fed2cdfe482f1c24f917c96b Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 12 Apr 2019 14:15:32 +0200 +Subject: [PATCH 171/249] WIP: ASoC: meson: axg-card: set link name based on + link node name + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/axg-card.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c +index aa54d2c612c98..5c8deee8d512d 100644 +--- a/sound/soc/meson/axg-card.c ++++ b/sound/soc/meson/axg-card.c +@@ -80,10 +80,11 @@ static int axg_card_parse_dai(struct snd_soc_card *card, + + static int axg_card_set_link_name(struct snd_soc_card *card, + struct snd_soc_dai_link *link, ++ struct device_node *node, + const char *prefix) + { + char *name = devm_kasprintf(card->dev, GFP_KERNEL, "%s.%s", +- prefix, link->cpu_of_node->full_name); ++ prefix, node->full_name); + if (!name) + return -ENOMEM; + +@@ -474,7 +475,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card, + codec++; + } + +- ret = axg_card_set_link_name(card, link, "be"); ++ ret = axg_card_set_link_name(card, link, node, "be"); + if (ret) + dev_err(card->dev, "error setting %pOFn link name\n", np); + +@@ -483,6 +484,7 @@ static int axg_card_set_be_link(struct snd_soc_card *card, + + static int axg_card_set_fe_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link, ++ struct device_node *node, + bool is_playback) + { + link->dynamic = 1; +@@ -497,7 +499,7 @@ static int axg_card_set_fe_link(struct snd_soc_card *card, + else + link->dpcm_capture = 1; + +- return axg_card_set_link_name(card, link, "fe"); ++ return axg_card_set_link_name(card, link, node, "fe"); + } + + static int axg_card_cpu_is_capture_fe(struct device_node *np) +@@ -527,9 +529,9 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, + return ret; + + if (axg_card_cpu_is_playback_fe(dai_link->cpu_of_node)) +- ret = axg_card_set_fe_link(card, dai_link, true); ++ ret = axg_card_set_fe_link(card, dai_link, np, true); + else if (axg_card_cpu_is_capture_fe(dai_link->cpu_of_node)) +- ret = axg_card_set_fe_link(card, dai_link, false); ++ ret = axg_card_set_fe_link(card, dai_link, np, false); + else + ret = axg_card_set_be_link(card, dai_link, np); + + +From 0781679d344e5749e23f89f2b20cd4b362904ad2 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 16 Apr 2019 10:36:53 +0200 +Subject: [PATCH 172/249] WIP: ASoC: meson: add tohdmitx support in axg-card + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/axg-card.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/sound/soc/meson/axg-card.c b/sound/soc/meson/axg-card.c +index 5c8deee8d512d..6c5181c988287 100644 +--- a/sound/soc/meson/axg-card.c ++++ b/sound/soc/meson/axg-card.c +@@ -29,6 +29,15 @@ struct axg_dai_link_tdm_data { + struct axg_dai_link_tdm_mask *codec_masks; + }; + ++/* Base params for the HDMI codec to codec link */ ++static const struct snd_soc_pcm_stream hdmi_codec_params = { ++ .formats = SNDRV_PCM_FMTBIT_S24_LE, ++ .rate_min = 8000, ++ .rate_max = 192000, ++ .channels_min = 2, ++ .channels_max = 8, ++}; ++ + #define PREFIX "amlogic," + + static int axg_card_reallocate_links(struct axg_card *priv, +@@ -517,6 +526,11 @@ static int axg_card_cpu_is_tdm_iface(struct device_node *np) + return of_device_is_compatible(np, PREFIX "axg-tdm-iface"); + } + ++static int g12a_card_is_hdmi_codec(struct device_node *np) ++{ ++ return of_device_is_compatible(np, PREFIX "g12a-tohdmitx"); ++} ++ + static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, + int *index) + { +@@ -540,6 +554,8 @@ static int axg_card_add_link(struct snd_soc_card *card, struct device_node *np, + + if (axg_card_cpu_is_tdm_iface(dai_link->cpu_of_node)) + ret = axg_card_parse_tdm(card, np, index); ++ else if (g12a_card_is_hdmi_codec(dai_link->cpu_of_node)) ++ dai_link->params = &hdmi_codec_params; + + return ret; + } + +From 0003d9d433211507354950cff9c5a01fde316c17 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 16 Apr 2019 10:36:19 +0200 +Subject: [PATCH 173/249] WIP: ASoC: meson: add g12a tohdmitx control + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + sound/soc/meson/Kconfig | 7 + + sound/soc/meson/Makefile | 2 + + sound/soc/meson/g12a-tohdmitx.c | 439 ++++++++++++++++++++++++++++++++ + 3 files changed, 448 insertions(+) + create mode 100644 sound/soc/meson/g12a-tohdmitx.c + +diff --git a/sound/soc/meson/Kconfig b/sound/soc/meson/Kconfig +index 8779fe23671d6..6ffaa85df70ca 100644 +--- a/sound/soc/meson/Kconfig ++++ b/sound/soc/meson/Kconfig +@@ -82,4 +82,11 @@ config SND_MESON_AXG_PDM + help + Select Y or M to add support for PDM input embedded + in the Amlogic AXG SoC family ++ ++config SND_MESON_G12A_TOHDMITX ++ tristate "Amlogic G12A To HDMI TX Control Support" ++ imply SND_SOC_HDMI_CODEC ++ help ++ Select Y or M to add support for HDMI audio on the g12a SoC ++ family + endmenu +diff --git a/sound/soc/meson/Makefile b/sound/soc/meson/Makefile +index b45dfb9e2f888..1a8b1470ed843 100644 +--- a/sound/soc/meson/Makefile ++++ b/sound/soc/meson/Makefile +@@ -11,6 +11,7 @@ snd-soc-meson-axg-sound-card-objs := axg-card.o + snd-soc-meson-axg-spdifin-objs := axg-spdifin.o + snd-soc-meson-axg-spdifout-objs := axg-spdifout.o + snd-soc-meson-axg-pdm-objs := axg-pdm.o ++snd-soc-meson-g12a-tohdmitx-objs := g12a-tohdmitx.o + + obj-$(CONFIG_SND_MESON_AXG_FIFO) += snd-soc-meson-axg-fifo.o + obj-$(CONFIG_SND_MESON_AXG_FRDDR) += snd-soc-meson-axg-frddr.o +@@ -23,3 +24,4 @@ obj-$(CONFIG_SND_MESON_AXG_SOUND_CARD) += snd-soc-meson-axg-sound-card.o + obj-$(CONFIG_SND_MESON_AXG_SPDIFIN) += snd-soc-meson-axg-spdifin.o + obj-$(CONFIG_SND_MESON_AXG_SPDIFOUT) += snd-soc-meson-axg-spdifout.o + obj-$(CONFIG_SND_MESON_AXG_PDM) += snd-soc-meson-axg-pdm.o ++obj-$(CONFIG_SND_MESON_G12A_TOHDMITX) += snd-soc-meson-g12a-tohdmitx.o +diff --git a/sound/soc/meson/g12a-tohdmitx.c b/sound/soc/meson/g12a-tohdmitx.c +new file mode 100644 +index 0000000000000..e49d6c8306838 +--- /dev/null ++++ b/sound/soc/meson/g12a-tohdmitx.c +@@ -0,0 +1,439 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// ++// Copyright (c) 2019 BayLibre, SAS. ++// Author: Jerome Brunet ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define G12A_TOHDMITX_DRV_NAME "g12a-tohdmitx" ++ ++#define TOHDMITX_CTRL0 0x0 ++#define CTRL0_ENABLE_SHIFT 31 ++#define CTRL0_I2S_DAT_SEL GENMASK(13, 12) ++#define CTRL0_I2S_LRCLK_SEL GENMASK(9, 8) ++#define CTRL0_I2S_BLK_CAP_INV BIT(7) ++#define CTRL0_I2S_BCLK_O_INV BIT(6) ++#define CTRL0_I2S_BCLK_SEL GENMASK(5, 4) ++#define CTRL0_SPDIF_CLK_CAP_INV BIT(3) ++#define CTRL0_SPDIF_CLK_O_INV BIT(2) ++#define CTRL0_SPDIF_SEL BIT(1) ++#define CTRL0_SPDIF_CLK_SEL BIT(0) ++ ++struct g12a_tohdmitx { ++ struct regmap *map; ++}; ++ ++struct g12a_tohdmitx_input { ++ struct snd_pcm_hw_params params; ++ unsigned int fmt; ++}; ++ ++static struct snd_soc_dapm_widget * ++g12a_tohdmitx_get_input(struct snd_soc_dapm_widget *w) ++{ ++ struct snd_soc_dapm_path *p = NULL; ++ struct snd_soc_dapm_widget *in; ++ ++ snd_soc_dapm_widget_for_each_source_path(w, p) { ++ if (!p->connect) ++ continue; ++ ++ /* Check that we still are in the same component */ ++ if (snd_soc_dapm_to_component(w->dapm) != ++ snd_soc_dapm_to_component(p->source->dapm)) ++ continue; ++ ++ if (p->source->id == snd_soc_dapm_dai_in) ++ return p->source; ++ ++ in = g12a_tohdmitx_get_input(p->source); ++ if (in) ++ return in; ++ } ++ ++ return NULL; ++} ++ ++static struct g12a_tohdmitx_input * ++g12a_tohdmitx_get_input_data(struct snd_soc_dapm_widget *w) ++{ ++ struct snd_soc_dapm_widget *in = ++ g12a_tohdmitx_get_input(w); ++ struct snd_soc_dai *dai; ++ ++ if (WARN_ON(!in)) ++ return NULL; ++ ++ dai = in->priv; ++ ++ return dai->playback_dma_data; ++} ++ ++static const char * const g12a_tohdmitx_i2s_mux_texts[] = { ++ "I2S A", "I2S B", "I2S C", ++}; ++ ++static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_i2s_mux_enum, ++ g12a_tohdmitx_i2s_mux_texts); ++ ++static int g12a_tohdmitx_get_input_val(struct g12a_tohdmitx *priv, ++ unsigned int mask) ++{ ++ unsigned int val; ++ ++ regmap_read(priv->map, TOHDMITX_CTRL0, &val); ++ return (val & mask) >> __ffs(mask); ++} ++ ++static int g12a_tohdmitx_i2s_mux_get_enum(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_dapm_kcontrol_component(kcontrol); ++ struct g12a_tohdmitx *priv = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.enumerated.item[0] = ++ g12a_tohdmitx_get_input_val(priv, CTRL0_I2S_DAT_SEL); ++ ++ return 0; ++} ++ ++static int g12a_tohdmitx_i2s_mux_put_enum(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_dapm_kcontrol_component(kcontrol); ++ struct snd_soc_dapm_context *dapm = ++ snd_soc_dapm_kcontrol_dapm(kcontrol); ++ struct g12a_tohdmitx *priv = snd_soc_component_get_drvdata(component); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int mux = ucontrol->value.enumerated.item[0]; ++ unsigned int val = g12a_tohdmitx_get_input_val(priv, CTRL0_I2S_DAT_SEL); ++ ++ /* Force disconnect of the mux while updating */ ++ if (val != mux) ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); ++ ++ regmap_update_bits(priv->map, TOHDMITX_CTRL0, ++ CTRL0_I2S_DAT_SEL | ++ CTRL0_I2S_LRCLK_SEL | ++ CTRL0_I2S_BCLK_SEL, ++ FIELD_PREP(CTRL0_I2S_DAT_SEL, mux) | ++ FIELD_PREP(CTRL0_I2S_LRCLK_SEL, mux) | ++ FIELD_PREP(CTRL0_I2S_BCLK_SEL, mux)); ++ ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); ++ ++ return 0; ++} ++ ++static const struct snd_kcontrol_new g12a_tohdmitx_i2s_mux = ++ SOC_DAPM_ENUM_EXT("I2S Source", g12a_tohdmitx_i2s_mux_enum, ++ g12a_tohdmitx_i2s_mux_get_enum, ++ g12a_tohdmitx_i2s_mux_put_enum); ++ ++static const char * const g12a_tohdmitx_spdif_mux_texts[] = { ++ "SPDIF A", "SPDIF B", ++}; ++ ++static SOC_ENUM_SINGLE_EXT_DECL(g12a_tohdmitx_spdif_mux_enum, ++ g12a_tohdmitx_spdif_mux_texts); ++ ++static int g12a_tohdmitx_spdif_mux_get_enum(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_dapm_kcontrol_component(kcontrol); ++ struct g12a_tohdmitx *priv = snd_soc_component_get_drvdata(component); ++ ++ ucontrol->value.enumerated.item[0] = ++ g12a_tohdmitx_get_input_val(priv, CTRL0_SPDIF_SEL); ++ ++ return 0; ++} ++ ++static int g12a_tohdmitx_spdif_mux_put_enum(struct snd_kcontrol *kcontrol, ++ struct snd_ctl_elem_value *ucontrol) ++{ ++ struct snd_soc_component *component = ++ snd_soc_dapm_kcontrol_component(kcontrol); ++ struct snd_soc_dapm_context *dapm = ++ snd_soc_dapm_kcontrol_dapm(kcontrol); ++ struct g12a_tohdmitx *priv = snd_soc_component_get_drvdata(component); ++ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; ++ unsigned int mux = ucontrol->value.enumerated.item[0]; ++ unsigned int val = g12a_tohdmitx_get_input_val(priv, CTRL0_SPDIF_SEL); ++ ++ /* Force disconnect of the mux while updating */ ++ if (val != mux) ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, 0, NULL, NULL); ++ ++ regmap_update_bits(priv->map, TOHDMITX_CTRL0, ++ CTRL0_SPDIF_SEL | ++ CTRL0_SPDIF_CLK_SEL, ++ FIELD_PREP(CTRL0_SPDIF_SEL, mux) | ++ FIELD_PREP(CTRL0_SPDIF_CLK_SEL, mux)); ++ ++ snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL); ++ ++ return 0; ++} ++ ++static const struct snd_kcontrol_new g12a_tohdmitx_spdif_mux = ++ SOC_DAPM_ENUM_EXT("SPDIF Source", g12a_tohdmitx_spdif_mux_enum, ++ g12a_tohdmitx_spdif_mux_get_enum, ++ g12a_tohdmitx_spdif_mux_put_enum); ++ ++static const struct snd_kcontrol_new g12a_tohdmitx_out_enable = ++ SOC_DAPM_SINGLE_AUTODISABLE("Switch", TOHDMITX_CTRL0, ++ CTRL0_ENABLE_SHIFT, 1, 0); ++ ++static const struct snd_soc_dapm_widget g12a_tohdmitx_widgets[] = { ++ SND_SOC_DAPM_MUX("I2S SRC", SND_SOC_NOPM, 0, 0, ++ &g12a_tohdmitx_i2s_mux), ++ SND_SOC_DAPM_SWITCH("I2S OUT EN", SND_SOC_NOPM, 0, 0, ++ &g12a_tohdmitx_out_enable), ++ SND_SOC_DAPM_MUX("SPDIF SRC", SND_SOC_NOPM, 0, 0, ++ &g12a_tohdmitx_spdif_mux), ++ SND_SOC_DAPM_SWITCH("SPDIF OUT EN", SND_SOC_NOPM, 0, 0, ++ &g12a_tohdmitx_out_enable), ++}; ++ ++static int g12a_tohdmitx_input_probe(struct snd_soc_dai *dai) ++{ ++ struct g12a_tohdmitx_input *data; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ dai->playback_dma_data = data; ++ return 0; ++} ++ ++static int g12a_tohdmitx_input_remove(struct snd_soc_dai *dai) ++{ ++ kfree(dai->playback_dma_data); ++ return 0; ++} ++ ++static int g12a_tohdmitx_input_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct g12a_tohdmitx_input *data = dai->playback_dma_data; ++ ++ /* Save the stream params for the downstream link */ ++ memcpy(&data->params, params, sizeof(*params)); ++ ++ return 0; ++} ++ ++static int g12a_tohdmitx_output_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct g12a_tohdmitx_input *in_data = ++ g12a_tohdmitx_get_input_data(dai->capture_widget); ++ ++ if (!in_data) ++ return -ENODEV; ++ ++ memcpy(params, &in_data->params, sizeof(*params)); ++ ++ return 0; ++} ++ ++static int g12a_tohdmitx_input_set_fmt(struct snd_soc_dai *dai, ++ unsigned int fmt) ++{ ++ struct g12a_tohdmitx_input *data = dai->playback_dma_data; ++ ++ /* Save the source stream format for the downstream link */ ++ data->fmt = fmt; ++ return 0; ++} ++ ++static int g12a_tohdmitx_output_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++ struct g12a_tohdmitx_input *in_data = ++ g12a_tohdmitx_get_input_data(dai->capture_widget); ++ ++ if (!in_data) ++ return -ENODEV; ++ ++ if (!in_data->fmt) ++ return 0; ++ ++ return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt); ++} ++ ++static const struct snd_soc_dai_ops g12a_tohdmitx_input_ops = { ++ .hw_params = g12a_tohdmitx_input_hw_params, ++ .set_fmt = g12a_tohdmitx_input_set_fmt, ++}; ++ ++static const struct snd_soc_dai_ops g12a_tohdmitx_output_ops = { ++ .hw_params = g12a_tohdmitx_output_hw_params, ++ .startup = g12a_tohdmitx_output_startup, ++}; ++ ++#define TOHDMITX_SPDIF_FORMATS \ ++ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ ++ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) ++ ++#define TOHDMITX_I2S_FORMATS \ ++ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ ++ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ ++ SNDRV_PCM_FMTBIT_S32_LE) ++ ++#define TOHDMITX_IN(_name, _fmt, _chmax) { \ ++ .name = _name, \ ++ .playback = { \ ++ .stream_name = _name " Playback", \ ++ .channels_min = 1, \ ++ .channels_max = (_chmax), \ ++ .rate_min = 8000, \ ++ .rate_max = 192000, \ ++ .formats = (_fmt), \ ++ }, \ ++ .ops = &g12a_tohdmitx_input_ops, \ ++ .probe = g12a_tohdmitx_input_probe, \ ++ .remove = g12a_tohdmitx_input_remove, \ ++} ++ ++#define TOHDMITX_OUT(_name, _fmt, _chmax) { \ ++ .name = _name, \ ++ .capture = { \ ++ .stream_name = _name " Capture", \ ++ .channels_min = 1, \ ++ .channels_max = (_chmax), \ ++ .rate_min = 8000, \ ++ .rate_max = 192000, \ ++ .formats = (_fmt), \ ++ }, \ ++ .ops = &g12a_tohdmitx_output_ops, \ ++} ++ ++static struct snd_soc_dai_driver g12a_tohdmitx_dai_drv[] = { ++ TOHDMITX_IN("I2S IN A", TOHDMITX_I2S_FORMATS, 8), ++ TOHDMITX_IN("I2S IN B", TOHDMITX_I2S_FORMATS, 8), ++ TOHDMITX_IN("I2S IN C", TOHDMITX_I2S_FORMATS, 8), ++ TOHDMITX_OUT("I2S OUT", TOHDMITX_I2S_FORMATS, 8), ++ TOHDMITX_IN("SPDIF IN A", TOHDMITX_SPDIF_FORMATS, 2), ++ TOHDMITX_IN("SPDIF IN B", TOHDMITX_SPDIF_FORMATS, 2), ++ TOHDMITX_OUT("SPDIF OUT", TOHDMITX_SPDIF_FORMATS, 2), ++}; ++ ++static const struct snd_soc_dapm_route g12a_tohdmitx_routes[] = { ++ { "I2S SRC", "I2S A", "I2S IN A Playback" }, ++ { "I2S SRC", "I2S B", "I2S IN B Playback" }, ++ { "I2S SRC", "I2S C", "I2S IN C Playback" }, ++ { "I2S OUT EN", "Switch", "I2S SRC" }, ++ { "I2S OUT Capture", NULL, "I2S OUT EN" }, ++ { "SPDIF SRC", "SPDIF A", "SPDIF IN A Playback" }, ++ { "SPDIF SRC", "SPDIF B", "SPDIF IN B Playback" }, ++ { "SPDIF OUT EN", "Switch", "SPDIF SRC" }, ++ { "SPDIF OUT Capture", NULL, "SPDIF OUT EN" }, ++}; ++ ++static const struct snd_soc_component_driver g12a_tohdmitx_component_drv = { ++ .dapm_widgets = g12a_tohdmitx_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(g12a_tohdmitx_widgets), ++ .dapm_routes = g12a_tohdmitx_routes, ++ .num_dapm_routes = ARRAY_SIZE(g12a_tohdmitx_routes), ++ .endianness = 1, ++ .non_legacy_dai_naming = 1, ++}; ++ ++static const struct regmap_config g12a_tohdmitx_regmap_cfg = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++}; ++ ++static const struct of_device_id g12a_tohdmitx_of_match[] = { ++ { .compatible = "amlogic,g12a-tohdmitx", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, g12a_tohdmitx_of_match); ++ ++static int g12a_tohdmitx_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct g12a_tohdmitx *priv; ++ struct resource *res; ++ void __iomem *regs; ++ struct clk *pclk; ++ int ret; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, priv); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ pclk = devm_clk_get(dev, NULL); ++ if (IS_ERR(pclk)) { ++ ret = PTR_ERR(pclk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "failed to get pclk\n"); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(pclk); ++ if (ret) { ++ dev_err(dev, "pclk enable failed\n"); ++ return ret; ++ } ++ ++ ret = devm_add_action_or_reset(dev, ++ (void(*)(void *))clk_disable_unprepare, ++ pclk); ++ if (ret) { ++ dev_err(dev, "failed to add pclk reset aciton\n"); ++ clk_disable_unprepare(pclk); ++ return ret; ++ } ++ ++ /* Enable the clock here */ ++ priv->map = devm_regmap_init_mmio(dev, regs, &g12a_tohdmitx_regmap_cfg); ++ if (IS_ERR(priv->map)) { ++ dev_err(dev, "failed to init regmap: %ld\n", ++ PTR_ERR(priv->map)); ++ return PTR_ERR(priv->map); ++ } ++ ++ /* Initialize the static clock parameters */ ++ regmap_write(priv->map, TOHDMITX_CTRL0, ++ CTRL0_I2S_BLK_CAP_INV | CTRL0_SPDIF_CLK_CAP_INV); ++ ++ return devm_snd_soc_register_component(dev, ++ &g12a_tohdmitx_component_drv, g12a_tohdmitx_dai_drv, ++ ARRAY_SIZE(g12a_tohdmitx_dai_drv)); ++} ++ ++static struct platform_driver g12a_tohdmitx_pdrv = { ++ .driver = { ++ .name = G12A_TOHDMITX_DRV_NAME, ++ .of_match_table = g12a_tohdmitx_of_match, ++ }, ++ .probe = g12a_tohdmitx_probe, ++}; ++module_platform_driver(g12a_tohdmitx_pdrv); ++ ++MODULE_AUTHOR("Jerome Brunet "); ++MODULE_DESCRIPTION("Amlogic G12a To HDMI Tx Control Codec Driver"); ++MODULE_LICENSE("GPL v2"); + +From c753955463b03c766f02dc94d87cfa56828ec8db Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 14 Feb 2019 14:11:58 +0100 +Subject: [PATCH 174/249] WIP: ASoC: max98357a: add Kconfig name + +Allows the module to be built on its own +--- + sound/soc/codecs/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index 667fc1d59e189..1d3f2ee159316 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -699,7 +699,7 @@ config SND_SOC_MAX98095 + tristate + + config SND_SOC_MAX98357A +- tristate ++ tristate "Maxim MAX98357A" + + config SND_SOC_MAX98371 + tristate + +From 57a92dec4917797644b96a07603e2ede90ad3d6e Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Sun, 12 May 2019 22:12:52 +0200 +Subject: [PATCH 175/249] WIP: ASoC: hdmi-codec: re-introduce mutex locking + +Replace the bit atomic operations by a mutex to ensure only one dai +at a time is active on the hdmi codec. + +This is a follow up on change: +3fcf94ef4d41 ("ASoC: hdmi-codec: remove reference to the current substream") + +Suggested-by: Mark Brown +Signed-off-by: Jerome Brunet +--- + sound/soc/codecs/hdmi-codec.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 90a8927666259..6a0cc8d7e1412 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -281,7 +281,7 @@ struct hdmi_codec_priv { + uint8_t eld[MAX_ELD_BYTES]; + struct snd_pcm_chmap *chmap_info; + unsigned int chmap_idx; +- unsigned long busy; ++ struct mutex lock; + }; + + static const struct snd_soc_dapm_widget hdmi_widgets[] = { +@@ -395,8 +395,8 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + int ret = 0; + +- ret = test_and_set_bit(0, &hcp->busy); +- if (ret) { ++ ret = mutex_trylock(&hcp->lock); ++ if (!ret) { + dev_err(dai->dev, "Only one simultaneous stream supported!\n"); + return -EINVAL; + } +@@ -424,7 +424,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, + + err: + /* Release the exclusive lock on error */ +- clear_bit(0, &hcp->busy); ++ mutex_unlock(&hcp->lock); + return ret; + } + +@@ -436,7 +436,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); + +- clear_bit(0, &hcp->busy); ++ mutex_unlock(&hcp->lock); + } + + static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, +@@ -773,6 +773,8 @@ static int hdmi_codec_probe(struct platform_device *pdev) + return -ENOMEM; + + hcp->hcd = *hcd; ++ mutex_init(&hcp->lock); ++ + daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); + if (!daidrv) + return -ENOMEM; + +From f2e2fdf50f201f7dac844d78be70d94457c4b3af Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Wed, 3 Apr 2019 10:25:55 +0200 +Subject: [PATCH 176/249] WIP: drm: dw-hdmi-i2s: support more i2s modes + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 26 ++++++++++++++++--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 6 +++-- + 2 files changed, 27 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 5cbb71a866d54..2b624cff541d7 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -44,9 +44,8 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + u8 inputclkfs = 0; + + /* it cares I2S only */ +- if ((fmt->fmt != HDMI_I2S) || +- (fmt->bit_clk_master | fmt->frame_clk_master)) { +- dev_err(dev, "unsupported format/settings\n"); ++ if (fmt->bit_clk_master | fmt->frame_clk_master) { ++ dev_err(dev, "unsupported clock settings\n"); + return -EINVAL; + } + +@@ -63,6 +62,27 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + break; + } + ++ switch (fmt->fmt) { ++ case HDMI_I2S: ++ conf1 |= HDMI_AUD_CONF1_MODE_I2S; ++ break; ++ case HDMI_RIGHT_J: ++ conf1 |= HDMI_AUD_CONF1_MODE_RIGHT_J; ++ break; ++ case HDMI_LEFT_J: ++ conf1 |= HDMI_AUD_CONF1_MODE_LEFT_J; ++ break; ++ case HDMI_DSP_A: ++ conf1 |= HDMI_AUD_CONF1_MODE_BURST_1; ++ break; ++ case HDMI_DSP_B: ++ conf1 |= HDMI_AUD_CONF1_MODE_BURST_2; ++ break; ++ default: ++ dev_err(dev, "unsupported format\n"); ++ return -EINVAL; ++ } ++ + dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); + + hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +index 3f3c616eba97b..6ff14dcfc6842 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +@@ -873,8 +873,10 @@ enum { + + /* AUD_CONF1 field values */ + HDMI_AUD_CONF1_MODE_I2S = 0x00, +- HDMI_AUD_CONF1_MODE_RIGHT_J = 0x02, +- HDMI_AUD_CONF1_MODE_LEFT_J = 0x04, ++ HDMI_AUD_CONF1_MODE_RIGHT_J = 0x20, ++ HDMI_AUD_CONF1_MODE_LEFT_J = 0x40, ++ HDMI_AUD_CONF1_MODE_BURST_1 = 0x60, ++ HDMI_AUD_CONF1_MODE_BURST_2 = 0x80, + HDMI_AUD_CONF1_WIDTH_16 = 0x10, + HDMI_AUD_CONF1_WIDTH_24 = 0x18, + + +From aae89bc725a9b97722704df5ac9aadcee8793d68 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Wed, 3 Apr 2019 10:28:57 +0200 +Subject: [PATCH 177/249] WIP: drm: dw-hdmi-i2s: support 4*2 channels + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 2b624cff541d7..cdb1480f5975f 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -139,7 +139,7 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) + + pdata.ops = &dw_hdmi_i2s_ops; + pdata.i2s = 1; +- pdata.max_i2s_channels = 6; ++ pdata.max_i2s_channels = 8; + pdata.data = audio; + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + +From 4c4ad3a418008b1f1f011994333348eec4d541d3 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 17 Jan 2019 19:16:42 +0100 +Subject: [PATCH 178/249] WIP: arm64: dts: meson: g12a: add mhu mailboxes + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 8822acab23315..8d10c8da37359 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -1409,6 +1409,16 @@ + clock-names = "xtal"; + }; + }; ++ ++ mailbox: mailbox@404 { ++ compatible = "amlogic,meson-gx-mhu", ++ "amlogic,meson-gxbb-mhu"; ++ reg = <0 0x404 0 0x4c>; ++ interrupts = , ++ , ++ ; ++ #mbox-cells = <1>; ++ }; + }; + + pdm: audio-controller@40000 { + +From 6ca47184cad55333fad80ebdd32b4a7d22918f1a Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 17 Jan 2019 19:17:25 +0100 +Subject: [PATCH 179/249] WIP: arm64: dts: meson: g12a: add sram shared memory + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 8d10c8da37359..02596a5e10ac2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -2151,6 +2151,24 @@ + }; + }; + ++ sram: sram@fffc0000 { ++ compatible = "mmio-sram"; ++ reg = <0x0 0xfffc0000 0x0 0x20000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0 0x0 0xfffc0000 0x20000>; ++ ++ cpu_scp_lpri: scp-shmem@13000 { ++ compatible = "amlogic,meson-axg-scp-shmem"; ++ reg = <0x13000 0x400>; ++ }; ++ ++ cpu_scp_hpri: scp-shmem@13400 { ++ compatible = "amlogic,meson-axg-scp-shmem"; ++ reg = <0x13400 0x400>; ++ }; ++ }; ++ + gic: interrupt-controller@ffc01000 { + compatible = "arm,gic-400"; + reg = <0x0 0xffc01000 0 0x1000>, + +From 393b7130d5109f7aea9bf7ea1403d5a91c7915c7 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Wed, 5 Sep 2018 10:58:27 +0200 +Subject: [PATCH 180/249] WIP: arm64: dts: meson: add dwmac-3.710 to ethmac + compatible list + +Adding snps,dwmac-3.710 will trigger some needed work around in the driver + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 3 ++- + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +index 34704fecf7566..c71c0e5834c61 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-axg.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-axg.dtsi +@@ -171,7 +171,8 @@ + ranges; + + ethmac: ethernet@ff3f0000 { +- compatible = "amlogic,meson-axg-dwmac", "snps,dwmac"; ++ compatible = "amlogic,meson-axg-dwmac", "snps,dwmac-3.710", ++ "snps,dwmac"; + reg = <0x0 0xff3f0000 0x0 0x10000 + 0x0 0xff634540 0x0 0x8>; + interrupts = ; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index 6772709b9e195..b7240ec8a4f5b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -486,7 +486,7 @@ + }; + + ethmac: ethernet@c9410000 { +- compatible = "amlogic,meson-gx-dwmac", "amlogic,meson-gxbb-dwmac", "snps,dwmac"; ++ compatible = "amlogic,meson-gxbb-dwmac", "snps,dwmac-3.710", "snps,dwmac"; + reg = <0x0 0xc9410000 0x0 0x10000 + 0x0 0xc8834540 0x0 0x4>; + interrupts = ; + +From 2a7e1811c77f83c881828b67cdfd027af5d92e88 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 29 Jan 2019 16:19:53 +0100 +Subject: [PATCH 181/249] WIP: arm64: dts: g12a: add mailbox clock gate + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 02596a5e10ac2..f39314960c9d5 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -1417,6 +1417,8 @@ + interrupts = , + , + ; ++ clocks = <&clkc_AO CLKID_AO_MAILBOX>; ++ clock-names = "pclk"; + #mbox-cells = <1>; + }; + }; + +From 8464c72157428ce1eaeffe514edc0e080698e476 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 29 Jan 2019 16:24:34 +0100 +Subject: [PATCH 182/249] WIP: arm64: dts: meson: g12a: add uart_ao reset + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index f39314960c9d5..ea71fbe3928c4 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2075,6 +2076,7 @@ + interrupts = ; + clocks = <&xtal>, <&clkc_AO CLKID_AO_UART>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; ++ reset = <&clkc_AO RESET_AO_UART>; + status = "disabled"; + }; + +@@ -2085,6 +2087,7 @@ + interrupts = ; + clocks = <&xtal>, <&clkc_AO CLKID_AO_UART2>, <&xtal>; + clock-names = "xtal", "pclk", "baud"; ++ reset = <&clkc_AO RESET_AO_UART2>; + status = "disabled"; + }; + + +From 806e7edd91c5f5fafde071a17b7c62ae2302741f Mon Sep 17 00:00:00 2001 +From: Zheng Yang +Date: Tue, 27 Jun 2017 16:22:01 +0800 +Subject: [PATCH 183/249] WIP: drm/bridge: dw-hdmi: support dynamically get + input/out color info + +To get input/output bus_format/enc_format dynamically, this patch +introduce following functions in plat_data: + - get_input_bus_format + - get_output_bus_format + - get_enc_in_encoding + - get_enc_out_encoding + +Signed-off-by: Zheng Yang +Signed-off-by: Neil Armstrong +Tested-by: Heiko Stuebner +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 +++++++++++++++++------ + include/drm/bridge/dw_hdmi.h | 5 ++++ + 2 files changed, 26 insertions(+), 7 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index ab7968c8f6a29..6fe73f1669734 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -1841,6 +1841,7 @@ static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi) + static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) + { + int ret; ++ void *data = hdmi->plat_data->phy_data; + + hdmi_disable_overflow_interrupts(hdmi); + +@@ -1852,10 +1853,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) + dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic); + } + +- if ((hdmi->vic == 6) || (hdmi->vic == 7) || +- (hdmi->vic == 21) || (hdmi->vic == 22) || +- (hdmi->vic == 2) || (hdmi->vic == 3) || +- (hdmi->vic == 17) || (hdmi->vic == 18)) ++ if (hdmi->plat_data->get_enc_out_encoding) ++ hdmi->hdmi_data.enc_out_encoding = ++ hdmi->plat_data->get_enc_out_encoding(data); ++ else if ((hdmi->vic == 6) || (hdmi->vic == 7) || ++ (hdmi->vic == 21) || (hdmi->vic == 22) || ++ (hdmi->vic == 2) || (hdmi->vic == 3) || ++ (hdmi->vic == 17) || (hdmi->vic == 18)) + hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_601; + else + hdmi->hdmi_data.enc_out_encoding = V4L2_YCBCR_ENC_709; +@@ -1864,21 +1868,31 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode) + hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; + + /* TOFIX: Get input format from plat data or fallback to RGB888 */ +- if (hdmi->plat_data->input_bus_format) ++ if (hdmi->plat_data->get_input_bus_format) ++ hdmi->hdmi_data.enc_in_bus_format = ++ hdmi->plat_data->get_input_bus_format(data); ++ else if (hdmi->plat_data->input_bus_format) + hdmi->hdmi_data.enc_in_bus_format = + hdmi->plat_data->input_bus_format; + else + hdmi->hdmi_data.enc_in_bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + /* TOFIX: Get input encoding from plat data or fallback to none */ +- if (hdmi->plat_data->input_bus_encoding) ++ if (hdmi->plat_data->get_enc_in_encoding) ++ hdmi->hdmi_data.enc_in_encoding = ++ hdmi->plat_data->get_enc_in_encoding(data); ++ else if (hdmi->plat_data->input_bus_encoding) + hdmi->hdmi_data.enc_in_encoding = + hdmi->plat_data->input_bus_encoding; + else + hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT; + + /* TOFIX: Default to RGB888 output format */ +- hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; ++ if (hdmi->plat_data->get_output_bus_format) ++ hdmi->hdmi_data.enc_out_bus_format = ++ hdmi->plat_data->get_output_bus_format(data); ++ else ++ hdmi->hdmi_data.enc_out_bus_format = MEDIA_BUS_FMT_RGB888_1X24; + + hdmi->hdmi_data.pix_repet_factor = 0; + hdmi->hdmi_data.hdcp_enable = 0; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index 66e70770cce5d..d506df2382de6 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -144,6 +144,11 @@ struct dw_hdmi_plat_data { + int (*configure_phy)(struct dw_hdmi *hdmi, + const struct dw_hdmi_plat_data *pdata, + unsigned long mpixelclock); ++ ++ unsigned long (*get_input_bus_format)(void *data); ++ unsigned long (*get_output_bus_format)(void *data); ++ unsigned long (*get_enc_in_encoding)(void *data); ++ unsigned long (*get_enc_out_encoding)(void *data); + }; + + struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev, + +From 7305124553c8448bd76a2b5a6add3792831af27c Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 14 Nov 2018 17:39:46 +0100 +Subject: [PATCH 184/249] WIP: drm/bridge: dw-hdmi: allow ycbcr420 modes for >= + 0x200a + +Now the DW-HDMI Controller supports the HDMI2.0 modes, enable support +for these modes in the connector if the platform supports them. +We limit these modes to DW-HDMI IP version >= 0x200a which +are designed to support HDMI2.0 display modes. + +Signed-off-by: Neil Armstrong +Tested-by: Heiko Stuebner +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 6 ++++++ + include/drm/bridge/dw_hdmi.h | 1 + + 2 files changed, 7 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6fe73f1669734..c68b6ed1bb35e 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2643,6 +2643,12 @@ __dw_hdmi_probe(struct platform_device *pdev, + if (hdmi->phy.ops->setup_hpd) + hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data); + ++ if (hdmi->version >= 0x200a) ++ hdmi->connector.ycbcr_420_allowed = ++ hdmi->plat_data->ycbcr_420_allowed; ++ else ++ hdmi->connector.ycbcr_420_allowed = false; ++ + memset(&pdevinfo, 0, sizeof(pdevinfo)); + pdevinfo.parent = dev; + pdevinfo.id = PLATFORM_DEVID_AUTO; +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index d506df2382de6..ede8bff9fffc5 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -130,6 +130,7 @@ struct dw_hdmi_plat_data { + const struct drm_display_mode *mode); + unsigned long input_bus_format; + unsigned long input_bus_encoding; ++ bool ycbcr_420_allowed; + + /* Vendor PHY support */ + const struct dw_hdmi_phy_ops *phy_ops; + +From 581841d4b664a7d7cd7ded52f409a6c2dcf8cb1b Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 15 Nov 2018 16:41:23 +0100 +Subject: [PATCH 185/249] WIP: drm/meson: Add YUV420 output support + +This patch adds support for the YUV420 output from the Amlogic Meson SoCs +Video Processing Unit to the HDMI Controller. + +The YUV420 is obtained by generating a YUV444 pixel stream like +the classic HDMI display modes, but then the Video Encoder output +can be configured to down-sample the YUV444 pixel stream to a YUV420 +stream. +In addition if pixel stream down-sampling, the Y Cb Cr components must +also be mapped differently to align with the HDMI2.0 specifications. + +This mode needs a different clock generation scheme since the TMDS PHY +clock must match the 10x ration with the YUV420 pixel clock, but +the video encoder must run at 2x the pixel clock. + +This patch adds the TMDS PHY clock value in all the video clock setup +in order to better support these specific uses cases and switch +to the Common Clock framework for clocks handling in the future. + +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 114 ++++++++++++++++++++---- + drivers/gpu/drm/meson/meson_vclk.c | 93 ++++++++++++++----- + drivers/gpu/drm/meson/meson_vclk.h | 7 +- + drivers/gpu/drm/meson/meson_venc.c | 6 +- + drivers/gpu/drm/meson/meson_venc.h | 11 +++ + drivers/gpu/drm/meson/meson_venc_cvbs.c | 3 +- + 6 files changed, 188 insertions(+), 46 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 779da21143b9b..0d09f067d689a 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -159,6 +159,8 @@ struct meson_dw_hdmi { + struct regulator *hdmi_supply; + u32 irq_stat; + struct dw_hdmi *hdmi; ++ unsigned long input_bus_format; ++ unsigned long output_bus_format; + }; + #define encoder_to_meson_dw_hdmi(x) \ + container_of(x, struct meson_dw_hdmi, encoder) +@@ -308,6 +310,10 @@ static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi, + 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->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) ++ 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")) { + if (pixel_clock >= 371250) { +@@ -383,25 +389,36 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, + { + 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->input_bus_format == 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, vclk_freq, +- vclk_freq, vclk_freq, false); ++ 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; + +- if (meson_venc_hdmi_venc_repeat(vic)) ++ /* VENC double pixels for 1080i, 720p and YUV420 modes */ ++ if (meson_venc_hdmi_venc_repeat(vic) || ++ dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) + venc_freq *= 2; + + vclk_freq = max(venc_freq, hdmi_freq); +@@ -409,11 +426,11 @@ static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi, + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + venc_freq /= 2; + +- DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n", +- vclk_freq, venc_freq, hdmi_freq, ++ 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, vclk_freq, ++ meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, phy_freq, vclk_freq, + venc_freq, hdmi_freq, priv->venc.hdmi_use_enci); + } + +@@ -446,8 +463,9 @@ static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data, + /* Enable normal output to PHY */ + dw_hdmi->data->top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12)); + +- /* TMDS pattern setup (TOFIX Handle the YUV420 case) */ +- if (mode->clock > 340000) { ++ /* TMDS pattern setup */ ++ if (mode->clock > 340000 && ++ dw_hdmi->input_bus_format == MEDIA_BUS_FMT_YUV8_1X24) { + 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, +@@ -622,6 +640,8 @@ dw_hdmi_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) + { + struct meson_drm *priv = connector->dev->dev_private; ++ bool is_hdmi2_sink = connector->display_info.hdmi.scdc.supported; ++ unsigned int phy_freq; + unsigned int vclk_freq; + unsigned int venc_freq; + unsigned int hdmi_freq; +@@ -630,9 +650,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, + + DRM_DEBUG_DRIVER("Modeline " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); + +- /* If sink max TMDS clock, we reject the mode */ ++ /* If sink does not support 540MHz, reject the non-420 HDMI2 modes */ + if (connector->display_info.max_tmds_clock && +- mode->clock > connector->display_info.max_tmds_clock) ++ mode->clock > connector->display_info.max_tmds_clock && ++ !drm_mode_is_420_only(&connector->display_info, mode) && ++ !drm_mode_is_420_also(&connector->display_info, mode)) + return MODE_BAD; + + /* Check against non-VIC supported modes */ +@@ -648,6 +670,15 @@ dw_hdmi_mode_valid(struct drm_connector *connector, + + vclk_freq = mode->clock; + ++ /* For 420, pixel clock is half unlike venc clock */ ++ if (drm_mode_is_420_only(&connector->display_info, mode) || ++ (!is_hdmi2_sink && ++ drm_mode_is_420_also(&connector->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; +@@ -655,8 +686,11 @@ dw_hdmi_mode_valid(struct drm_connector *connector, + venc_freq = vclk_freq; + hdmi_freq = vclk_freq; + +- /* VENC double pixels for 1080i and 720p modes */ +- if (meson_venc_hdmi_venc_repeat(vic)) ++ /* VENC double pixels for 1080i, 720p and YUV420 modes */ ++ if (meson_venc_hdmi_venc_repeat(vic) || ++ drm_mode_is_420_only(&connector->display_info, mode) || ++ (!is_hdmi2_sink && ++ drm_mode_is_420_also(&connector->display_info, mode))) + venc_freq *= 2; + + vclk_freq = max(venc_freq, hdmi_freq); +@@ -664,10 +698,10 @@ dw_hdmi_mode_valid(struct drm_connector *connector, + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + venc_freq /= 2; + +- dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__, +- vclk_freq, venc_freq, hdmi_freq); ++ dev_dbg(connector->dev->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(vclk_freq); ++ return meson_vclk_vic_supported_freq(phy_freq, vclk_freq); + } + + /* Encoder */ +@@ -685,6 +719,21 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) + { ++ struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); ++ struct drm_display_info *info = &conn_state->connector->display_info; ++ struct drm_display_mode *mode = &crtc_state->mode; ++ bool is_hdmi2_sink = ++ conn_state->connector->display_info.hdmi.scdc.supported; ++ ++ if (drm_mode_is_420_only(info, mode) || ++ (!is_hdmi2_sink && drm_mode_is_420_also(info, mode))) { ++ dw_hdmi->input_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; ++ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; ++ } else { ++ dw_hdmi->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; ++ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24; ++ } ++ + return 0; + } + +@@ -722,17 +771,29 @@ static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder, + struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder); + struct meson_drm *priv = dw_hdmi->priv; + int vic = drm_match_cea_mode(mode); ++ unsigned int ycrcb_map = MESON_VENC_MAP_CB_Y_CR; ++ bool yuv420_mode = false; + + DRM_DEBUG_DRIVER("\"%s\" vic %d\n", mode->name, vic); + ++ if (dw_hdmi->input_bus_format == MEDIA_BUS_FMT_UYYVYY8_0_5X24) { ++ ycrcb_map = MESON_VENC_MAP_CR_Y_CB; ++ yuv420_mode = true; ++ } ++ + /* VENC + VENC-DVI Mode setup */ +- meson_venc_hdmi_mode_set(priv, vic, mode); ++ meson_venc_hdmi_mode_set(priv, vic, ycrcb_map, yuv420_mode, mode); + + /* VCLK Set clock */ + dw_hdmi_set_vclk(dw_hdmi, mode); + +- /* Setup YUV444 to HDMI-TX, no 10bit diphering */ +- writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL)); ++ if (dw_hdmi->input_bus_format == 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_encoder_helper_funcs +@@ -789,6 +850,20 @@ static const struct meson_dw_hdmi_data meson_dw_hdmi_g12a_data = { + .dwc_write = dw_hdmi_g12a_dwc_write, + }; + ++static unsigned long meson_dw_hdmi_get_in_bus_format(void *data) ++{ ++ struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; ++ ++ return dw_hdmi->input_bus_format; ++} ++ ++static unsigned long meson_dw_hdmi_get_out_bus_format(void *data) ++{ ++ struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data; ++ ++ return dw_hdmi->output_bus_format; ++} ++ + static bool meson_hdmi_connector_is_available(struct device *dev) + { + struct device_node *ep, *remote; +@@ -977,6 +1052,9 @@ static int meson_dw_hdmi_bind(struct device *dev, struct device *master, + dw_plat_data->phy_data = meson_dw_hdmi; + dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; + dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709; ++ dw_plat_data->get_input_bus_format = meson_dw_hdmi_get_in_bus_format; ++ dw_plat_data->get_output_bus_format = meson_dw_hdmi_get_out_bus_format; ++ dw_plat_data->ycbcr_420_allowed = true; + + platform_set_drvdata(pdev, meson_dw_hdmi); + +diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c +index b39034745444a..44250eff8a3f4 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.c ++++ b/drivers/gpu/drm/meson/meson_vclk.c +@@ -364,12 +364,17 @@ enum { + /* 2970 /1 /1 /1 /5 /2 => /1 /1 */ + MESON_VCLK_HDMI_297000, + /* 5940 /1 /1 /2 /5 /1 => /1 /1 */ +- MESON_VCLK_HDMI_594000 ++ MESON_VCLK_HDMI_594000, ++/* 2970 /1 /1 /1 /5 /1 => /1 /2 */ ++ MESON_VCLK_HDMI_594000_YUV420, + }; + + struct meson_vclk_params { ++ unsigned int pll_freq; ++ unsigned int phy_freq; ++ unsigned int vclk_freq; ++ unsigned int venc_freq; + unsigned int pixel_freq; +- unsigned int pll_base_freq; + unsigned int pll_od1; + unsigned int pll_od2; + unsigned int pll_od3; +@@ -377,8 +382,11 @@ struct meson_vclk_params { + unsigned int vclk_div; + } params[] = { + [MESON_VCLK_HDMI_ENCI_54000] = { ++ .pll_freq = 4320000, ++ .phy_freq = 270000, ++ .vclk_freq = 54000, ++ .venc_freq = 54000, + .pixel_freq = 54000, +- .pll_base_freq = 4320000, + .pll_od1 = 4, + .pll_od2 = 4, + .pll_od3 = 1, +@@ -386,8 +394,11 @@ struct meson_vclk_params { + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_DDR_54000] = { +- .pixel_freq = 54000, +- .pll_base_freq = 4320000, ++ .pll_freq = 4320000, ++ .phy_freq = 270000, ++ .vclk_freq = 54000, ++ .venc_freq = 54000, ++ .pixel_freq = 27000, + .pll_od1 = 4, + .pll_od2 = 4, + .pll_od3 = 1, +@@ -395,8 +406,11 @@ struct meson_vclk_params { + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_DDR_148500] = { +- .pixel_freq = 148500, +- .pll_base_freq = 2970000, ++ .pll_freq = 2970000, ++ .phy_freq = 742500, ++ .vclk_freq = 148500, ++ .venc_freq = 148500, ++ .pixel_freq = 74250, + .pll_od1 = 4, + .pll_od2 = 1, + .pll_od3 = 1, +@@ -404,8 +418,11 @@ struct meson_vclk_params { + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_74250] = { ++ .pll_freq = 2970000, ++ .phy_freq = 742500, ++ .vclk_freq = 74250, ++ .venc_freq = 74250, + .pixel_freq = 74250, +- .pll_base_freq = 2970000, + .pll_od1 = 2, + .pll_od2 = 2, + .pll_od3 = 2, +@@ -413,8 +430,11 @@ struct meson_vclk_params { + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_148500] = { ++ .pll_freq = 2970000, ++ .phy_freq = 1485000, ++ .vclk_freq = 148500, ++ .venc_freq = 148500, + .pixel_freq = 148500, +- .pll_base_freq = 2970000, + .pll_od1 = 1, + .pll_od2 = 2, + .pll_od3 = 2, +@@ -422,8 +442,11 @@ struct meson_vclk_params { + .vclk_div = 1, + }, + [MESON_VCLK_HDMI_297000] = { ++ .pll_freq = 5940000, ++ .phy_freq = 2970000, ++ .venc_freq = 297000, ++ .vclk_freq = 297000, + .pixel_freq = 297000, +- .pll_base_freq = 5940000, + .pll_od1 = 2, + .pll_od2 = 1, + .pll_od3 = 1, +@@ -431,14 +454,29 @@ struct meson_vclk_params { + .vclk_div = 2, + }, + [MESON_VCLK_HDMI_594000] = { ++ .pll_freq = 5940000, ++ .phy_freq = 5940000, ++ .venc_freq = 594000, ++ .vclk_freq = 594000, + .pixel_freq = 594000, +- .pll_base_freq = 5940000, + .pll_od1 = 1, + .pll_od2 = 1, + .pll_od3 = 2, + .vid_pll_div = VID_PLL_DIV_5, + .vclk_div = 1, + }, ++ [MESON_VCLK_HDMI_594000_YUV420] = { ++ .pll_freq = 5940000, ++ .phy_freq = 2970000, ++ .venc_freq = 594000, ++ .vclk_freq = 594000, ++ .pixel_freq = 297000, ++ .pll_od1 = 2, ++ .pll_od2 = 1, ++ .pll_od3 = 1, ++ .vid_pll_div = VID_PLL_DIV_5, ++ .vclk_div = 1, ++ }, + { /* sentinel */ }, + }; + +@@ -696,6 +734,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv, + unsigned int od, m, frac, od1, od2, od3; + + if (meson_hdmi_pll_find_params(priv, pll_freq, &m, &frac, &od)) { ++ /* OD2 goes to the PHY, and needs to be *10, so keep OD3=1 */ + od3 = 1; + if (od < 4) { + od1 = 2; +@@ -718,21 +757,28 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv, + } + + enum drm_mode_status +-meson_vclk_vic_supported_freq(unsigned int freq) ++meson_vclk_vic_supported_freq(unsigned int phy_freq, ++ unsigned int vclk_freq) + { + int i; + +- DRM_DEBUG_DRIVER("freq = %d\n", freq); ++ DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n", ++ phy_freq, vclk_freq); + + for (i = 0 ; params[i].pixel_freq ; ++i) { + DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n", + i, params[i].pixel_freq, + FREQ_1000_1001(params[i].pixel_freq)); ++ DRM_DEBUG_DRIVER("i = %d phy_freq = %d alt = %d\n", ++ i, params[i].phy_freq, ++ FREQ_1000_1001(params[i].phy_freq/10)*10); + /* Match strict frequency */ +- if (freq == params[i].pixel_freq) ++ if (phy_freq == params[i].phy_freq && ++ vclk_freq == params[i].vclk_freq) + return MODE_OK; + /* Match 1000/1001 variant */ +- if (freq == FREQ_1000_1001(params[i].pixel_freq)) ++ if (phy_freq == (FREQ_1000_1001(params[i].phy_freq/10)*10) && ++ vclk_freq == FREQ_1000_1001(params[i].vclk_freq)) + return MODE_OK; + } + +@@ -960,8 +1006,9 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq, + } + + void meson_vclk_setup(struct meson_drm *priv, unsigned int target, +- unsigned int vclk_freq, unsigned int venc_freq, +- unsigned int dac_freq, bool hdmi_use_enci) ++ unsigned int phy_freq, unsigned int vclk_freq, ++ unsigned int venc_freq, unsigned int dac_freq, ++ bool hdmi_use_enci) + { + bool vic_alternate_clock = false; + unsigned int freq; +@@ -980,7 +1027,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + * - venc_div = 1 + * - encp encoder + */ +- meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0, ++ meson_vclk_set(priv, phy_freq, 0, 0, 0, + VID_PLL_DIV_5, 2, 1, 1, false, false); + return; + } +@@ -1002,9 +1049,11 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + } + + for (freq = 0 ; params[freq].pixel_freq ; ++freq) { +- if (vclk_freq == params[freq].pixel_freq || +- vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) { +- if (vclk_freq != params[freq].pixel_freq) ++ if ((phy_freq == params[freq].phy_freq || ++ phy_freq == FREQ_1000_1001(params[freq].phy_freq/10)*10) && ++ (vclk_freq == params[freq].vclk_freq || ++ vclk_freq == FREQ_1000_1001(params[freq].vclk_freq))) { ++ if (vclk_freq != params[freq].vclk_freq) + vic_alternate_clock = true; + else + vic_alternate_clock = false; +@@ -1033,7 +1082,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target, + return; + } + +- meson_vclk_set(priv, params[freq].pll_base_freq, ++ meson_vclk_set(priv, params[freq].pll_freq, + params[freq].pll_od1, params[freq].pll_od2, + params[freq].pll_od3, params[freq].vid_pll_div, + params[freq].vclk_div, hdmi_tx_div, venc_div, +diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h +index 4bd8752da02ab..c4d19ddfcd790 100644 +--- a/drivers/gpu/drm/meson/meson_vclk.h ++++ b/drivers/gpu/drm/meson/meson_vclk.h +@@ -33,10 +33,11 @@ enum { + enum drm_mode_status + meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); + enum drm_mode_status +-meson_vclk_vic_supported_freq(unsigned int freq); ++meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq); + + void meson_vclk_setup(struct meson_drm *priv, unsigned int target, +- unsigned int vclk_freq, unsigned int venc_freq, +- unsigned int dac_freq, bool hdmi_use_enci); ++ unsigned int phy_freq, unsigned int vclk_freq, ++ unsigned int venc_freq, unsigned int dac_freq, ++ bool hdmi_use_enci); + + #endif /* __MESON_VCLK_H */ +diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c +index 6faca7313339e..5460c4439612c 100644 +--- a/drivers/gpu/drm/meson/meson_venc.c ++++ b/drivers/gpu/drm/meson/meson_venc.c +@@ -958,6 +958,8 @@ bool meson_venc_hdmi_venc_repeat(int vic) + EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat); + + void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, ++ unsigned int ycrcb_map, ++ bool yuv420_mode, + struct drm_display_mode *mode) + { + union meson_hdmi_venc_mode *vmode = NULL; +@@ -1508,8 +1510,8 @@ void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, + writel_relaxed((use_enci ? 1 : 2) | + (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) | + (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) | +- 4 << 5 | +- (venc_repeat ? 1 << 8 : 0) | ++ (ycrcb_map << 5) | ++ (venc_repeat || yuv420_mode ? 1 << 8 : 0) | + (hdmi_repeat ? 1 << 12 : 0), + priv->io_base + _REG(VPU_HDMI_SETTING)); + +diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h +index 97eaebbfa0c4a..5580bf38e3812 100644 +--- a/drivers/gpu/drm/meson/meson_venc.h ++++ b/drivers/gpu/drm/meson/meson_venc.h +@@ -33,6 +33,15 @@ enum { + MESON_VENC_MODE_HDMI, + }; + ++enum { ++ MESON_VENC_MAP_CR_Y_CB = 0, ++ MESON_VENC_MAP_Y_CB_CR, ++ MESON_VENC_MAP_Y_CR_CB, ++ MESON_VENC_MAP_CB_CR_Y, ++ MESON_VENC_MAP_CB_Y_CR, ++ MESON_VENC_MAP_CR_CB_Y, ++}; ++ + struct meson_cvbs_enci_mode { + unsigned int mode_tag; + unsigned int hso_begin; /* HSO begin position */ +@@ -70,6 +79,8 @@ extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc; + void meson_venci_cvbs_mode_set(struct meson_drm *priv, + struct meson_cvbs_enci_mode *mode); + void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic, ++ unsigned int ycrcb_map, ++ bool yuv420_mode, + struct drm_display_mode *mode); + unsigned int meson_venci_get_field(struct meson_drm *priv); + +diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c +index 2c5341c881c47..c1bbc601cf132 100644 +--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c ++++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c +@@ -218,7 +218,8 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder, + /* Setup 27MHz vclk2 for ENCI and VDAC */ + meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, + MESON_VCLK_CVBS, MESON_VCLK_CVBS, +- MESON_VCLK_CVBS, true); ++ MESON_VCLK_CVBS, MESON_VCLK_CVBS, ++ true); + break; + } + } + +From 2cec5da66ce308bdaf1c9aef4c13df56857e281e Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Sun, 18 Nov 2018 14:06:11 +0100 +Subject: [PATCH 186/249] WIP: drm/meson: Output in YUV444 if sink supports it + +With the YUV420 handling, we can dynamically setup the HDMI output +pixel format depending on the mode and connector info. +So now, we can output in YUV444, which is the native video pipeline +format, directly to the HDMI Sink if it's supported without +necessarily involving the HDMI Controller CSC. + +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/meson/meson_dw_hdmi.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c +index 0d09f067d689a..feafb896ecaee 100644 +--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c ++++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c +@@ -731,7 +731,10 @@ static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder, + dw_hdmi->output_bus_format = MEDIA_BUS_FMT_UYYVYY8_0_5X24; + } else { + dw_hdmi->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24; +- dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24; ++ if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) ++ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_YUV8_1X24; ++ else ++ dw_hdmi->output_bus_format = MEDIA_BUS_FMT_RGB888_1X24; + } + + return 0; + +From f0ab196aa42e72addba4db147c842ba3d4381548 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 17 Jan 2019 19:00:11 +0100 +Subject: [PATCH 187/249] WIP: arm64: dts: meson: g12a: add SDIO pins + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 23 +++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index ea71fbe3928c4..b2f9087ab1c7b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -867,6 +867,29 @@ + }; + }; + ++ sdio_pins: sdio { ++ mux { ++ groups = "sdio_d0", ++ "sdio_d1", ++ "sdio_d2", ++ "sdio_d3", ++ "sdio_cmd", ++ "sdio_clk"; ++ function = "sdio"; ++ bias-disable; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ ++ sdio_clk_gate_pins: sdio_clk_gate { ++ mux { ++ groups = "GPIOX_4"; ++ function = "gpio_periphs"; ++ bias-pull-down; ++ drive-strength-microamp = <4000>; ++ }; ++ }; ++ + spdif_in_a10_pins: spdif-in-a10 { + mux { + groups = "spdif_in_a10"; + +From 66f026a11e8c8e3777bc44b876d0bf45a34f4ba6 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 21 Jan 2019 21:37:52 +0100 +Subject: [PATCH 188/249] WIP: arm64: dts: meson: g12a: add SDIO controller + +The Amlogic G12A SDIO Controller has a bug preventing direct DDR access, +mark this specific controller with the amlogic,ddr-access-quirk property. + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index b2f9087ab1c7b..600f7ce6b8c76 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -2318,6 +2318,19 @@ + }; + }; + ++ sd_emmc_a: sd@ffe03000 { ++ compatible = "amlogic,meson-axg-mmc"; ++ reg = <0x0 0xffe03000 0x0 0x800>; ++ interrupts = ; ++ status = "disabled"; ++ clocks = <&clkc CLKID_SD_EMMC_A>, ++ <&clkc CLKID_SD_EMMC_A_CLK0>, ++ <&clkc CLKID_FCLK_DIV2>; ++ clock-names = "core", "clkin0", "clkin1"; ++ resets = <&reset RESET_SD_EMMC_A>; ++ amlogic,ddr-access-quirk; ++ }; ++ + sd_emmc_b: sd@ffe05000 { + compatible = "amlogic,meson-axg-mmc"; + reg = <0x0 0xffe05000 0x0 0x800>; + +From f457f2387361601ed1da1a2f622af6ae397390bd Mon Sep 17 00:00:00 2001 +From: Guillaume La Roque +Date: Mon, 28 Jan 2019 15:45:37 +0000 +Subject: [PATCH 189/249] WIP: arm64: dts: meson: x96: add sd and emmc + +Signed-off-by: Guillaume La Roque +--- + .../boot/dts/amlogic/meson-g12a-x96-max.dts | 40 +++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 5cdc263b03e67..69aae6c03dc55 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -45,6 +45,11 @@ + }; + }; + ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; ++ }; ++ + flash_1v8: regulator-flash_1v8 { + compatible = "regulator-fixed"; + regulator-name = "FLASH_1V8"; +@@ -172,3 +177,38 @@ + status = "okay"; + dr_mode = "host"; + }; ++ ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ 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 = <100000000>; ++ disable-wp; ++ ++ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddao_3v3>; ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; ++ pinctrl-1 = <&emmc_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ max-frequency = <100000000>; ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vcc_3v3>; ++ vqmmc-supply = <&flash_1v8>; ++}; + +From fc11f8b165ab91f60345f4c047083cdab84ca7f7 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 8 Feb 2019 14:53:35 +0100 +Subject: [PATCH 190/249] WIP: arm64: dts: meson-g12a-x96-max: Enable Wifi SDIO + Module + +--- + .../boot/dts/amlogic/meson-g12a-x96-max.dts | 48 +++++++++++++++++++ + 1 file changed, 48 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 69aae6c03dc55..8b263ec1e7a2a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -50,6 +50,13 @@ + reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; + }; + ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; ++ clocks = <&wifi32k>; ++ clock-names = "ext_clock"; ++ }; ++ + flash_1v8: regulator-flash_1v8 { + compatible = "regulator-fixed"; + regulator-name = "FLASH_1V8"; +@@ -114,6 +121,13 @@ + vin-supply = <&dc_in>; + regulator-always-on; + }; ++ ++ wifi32k: wifi32k { ++ compatible = "pwm-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ ++ }; + }; + + &cec_AO { +@@ -155,6 +169,12 @@ + pinctrl-names = "default"; + }; + ++&pwm_ef { ++ status = "okay"; ++ pinctrl-0 = <&pwm_e_pins>; ++ pinctrl-names = "default"; ++}; ++ + &uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; +@@ -178,6 +198,34 @@ + dr_mode = "host"; + }; + ++/* 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-sdr50; ++ max-frequency = <100000000>; ++ ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&sdio_pwrseq>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddao_1v8>; ++ ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ }; ++}; ++ + /* SD card */ + &sd_emmc_b { + status = "okay"; + +From 23aaa150078b4bf95bf223c7f46ba78650632fb9 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 8 Feb 2019 15:41:15 +0100 +Subject: [PATCH 191/249] WIP: arm64: dts: meson-g12a-x96-max: Add Gigabit + Ethernet Support + +--- + .../boot/dts/amlogic/meson-g12a-x96-max.dts | 22 +++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 8b263ec1e7a2a..648b7deed22d7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -15,6 +15,7 @@ + + aliases { + serial0 = &uart_AO; ++ ethernet0 = ðmac; + }; + chosen { + stdout-path = "serial0:115200n8"; +@@ -169,6 +170,27 @@ + pinctrl-names = "default"; + }; + ++&ext_mdio { ++ external_phy: ethernet-phy@0 { ++ compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ max-speed = <1000>; ++ eee-broken-1000t; ++ }; ++}; ++ ++ðmac { ++ pinctrl-0 = <ð_rmii_pins>, <ð_rgmii_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ phy-mode = "rgmii"; ++ phy-handle = <&external_phy>; ++ amlogic,tx-delay-ns = <2>; ++ snps,reset-gpio = <&gpio GPIOZ_14 0>; ++ snps,reset-delays-us = <0 10000 1000000>; ++ snps,reset-active-low; ++}; ++ + &pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; + +From 960ae664cc478ceb5268d059595ea6217d802587 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 12 Feb 2019 11:56:58 +0100 +Subject: [PATCH 192/249] WIP: arm64: dts: meson-g12a-sei510: Add base + peripherals + +* SDIO + WiFi +* IR +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 54 +++++++++++++++++++ + 1 file changed, 54 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 9f0b8005877ae..530c601fc9cb4 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -128,6 +128,20 @@ + no-map; + }; + }; ++ ++ sdio_pwrseq: sdio-pwrseq { ++ compatible = "mmc-pwrseq-simple"; ++ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; ++ clocks = <&wifi32k>; ++ clock-names = "ext_clock"; ++ }; ++ ++ wifi32k: wifi32k { ++ compatible = "pwm-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ ++ }; + }; + + &cec_AO { +@@ -174,11 +188,51 @@ + pinctrl-names = "default"; + }; + ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&pwm_ef { ++ status = "okay"; ++ pinctrl-0 = <&pwm_e_pins>; ++ pinctrl-names = "default"; ++}; ++ + &saradc { + status = "okay"; + vref-supply = <&vddio_ao1v8>; + }; + ++/* 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-sdr50; ++ max-frequency = <100000000>; ++ ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&sdio_pwrseq>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddio_ao1v8>; ++ ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ }; ++}; ++ + /* SD card */ + &sd_emmc_b { + status = "okay"; + +From 204117d03f17338f984722a64d420106f8db38f8 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 26 Feb 2019 11:21:41 +0100 +Subject: [PATCH 193/249] WIP: arm64: dts: meson-g12a: add missing + drive-strength hdmi ddc + +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 600f7ce6b8c76..51d2b2ac2acf4 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -328,6 +328,7 @@ + "hdmitx_sck"; + function = "hdmitx"; + bias-disable; ++ drive-strength-microamp = <4000>; + }; + }; + + +From 358c41ce27d41cf63d59beb0617c6979b1bcf518 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 12 Mar 2019 16:50:21 +0100 +Subject: [PATCH 194/249] WIP: arm64: dts: meson: g12a: add drive strength for + eth pins + +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 51d2b2ac2acf4..9fc47fd76c180 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -264,6 +264,7 @@ + "eth_txd0", + "eth_txd1"; + function = "eth"; ++ drive-strength-microamp = <4000>; + bias-disable; + }; + }; +@@ -276,6 +277,7 @@ + "eth_txd2_rgmii", + "eth_txd3_rgmii"; + function = "eth"; ++ drive-strength-microamp = <4000>; + bias-disable; + }; + }; + +From c6998477efba1921e0fbdf24ae5c2aad5289ca78 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 22 Feb 2019 16:39:33 +0100 +Subject: [PATCH 195/249] WIP: arm64: dts: meson-g12b-odroid-n2: Add + peripherals + +Add Ethernet, MMC, SDCard, IR & AO-CEC-B nodes. + +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12b-odroid-n2.dts | 101 ++++++++++++++++++ + 1 file changed, 101 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +index 0541fe0bbaea9..380b5cebb21df 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -16,6 +16,7 @@ + + aliases { + serial0 = &uart_AO; ++ ethernet0 = ðmac; + }; + + chosen { +@@ -27,6 +28,11 @@ + reg = <0x0 0x0 0x0 0x40000000>; + }; + ++ emmc_pwrseq: emmc-pwrseq { ++ compatible = "mmc-pwrseq-emmc"; ++ reset-gpios = <&gpio BOOT_12 GPIO_ACTIVE_LOW>; ++ }; ++ + leds { + compatible = "gpio-leds"; + +@@ -37,6 +43,40 @@ + }; + }; + ++ tflash_vdd: regulator-tflash_vdd { ++ compatible = "regulator-fixed"; ++ ++ regulator-name = "TFLASH_VDD"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpio = <&gpio_ao GPIOAO_8 GPIO_ACTIVE_HIGH>; ++ enable-active-high; ++ }; ++ ++ tf_io: gpio-regulator-tf_io { ++ compatible = "regulator-gpio"; ++ ++ regulator-name = "TF_IO"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <3300000>; ++ ++ gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>; ++ gpios-states = <0>; ++ ++ states = <3300000 0 ++ 1800000 1>; ++ }; ++ ++ flash_1v8: regulator-flash_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "FLASH_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ + main_12v: regulator-main_12v { + compatible = "regulator-fixed"; + regulator-name = "12V"; +@@ -138,6 +178,24 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&ext_mdio { ++ external_phy: ethernet-phy@0 { ++ compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ max-speed = <1000>; ++ eee-broken-1000t; ++ }; ++}; ++ ++ðmac { ++ pinctrl-0 = <ð_rmii_pins>, <ð_rgmii_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ phy-mode = "rgmii"; ++ phy-handle = <&external_phy>; ++ amlogic,tx-delay-ns = <2>; ++}; ++ + &gpio { + /* + * WARNING: The USB Hub on the Odroid-N2 needs a reset signal +@@ -166,6 +224,49 @@ + }; + }; + ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++}; ++ ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ 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 = <&tflash_vdd>; ++ vqmmc-supply = <&tf_io>; ++ ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_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 = <&vcc_3v3>; ++ vqmmc-supply = <&flash_1v8>; ++}; ++ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + +From d814c70104c2d107794e1afde2c052b806c2fc31 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 13 Feb 2019 17:21:26 +0100 +Subject: [PATCH 196/249] WIP: arm64: dts: meson-g12a-sei510: add max98357a DAC + +The SEI510 board features a max98357a audio codec + +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 530c601fc9cb4..50d8ac55eed8a 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -32,6 +32,13 @@ + ethernet0 = ðmac; + }; + ++ mono_dac: audio-codec { ++ compatible = "maxim,max98357a"; ++ #sound-dai-cells = <0>; ++ sound-name-prefix = "U16"; ++ sdmode-gpios = <&gpio GPIOX_8 GPIO_ACTIVE_HIGH>; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; + +From dba98c740ece82f04e0a3a672a053a3c6a30422b Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Tue, 16 Apr 2019 10:35:09 +0200 +Subject: [PATCH 197/249] WIP: arm64: dts: meson: g12a: add tohdmitx + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 9fc47fd76c180..9fa4ef37d6243 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -1710,6 +1710,15 @@ + clock-names = "pclk", "mclk"; + status = "disabled"; + }; ++ ++ tohdmitx: audio-controller@744 { ++ compatible = "amlogic,g12a-tohdmitx"; ++ reg = <0x0 0x744 0x0 0x4>; ++ #sound-dai-cells = <1>; ++ sound-name-prefix = "TOHDMITX"; ++ clocks = <&clkc_audio AUD_CLKID_DDR_ARB>; /* FIXME */ ++ status = "disabled"; ++ }; + }; + + usb3_pcie_phy: phy@46000 { + +From 4aa9ffaea6621ecd747118d1c502704c69a72fe2 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 18 Mar 2019 13:46:06 +0100 +Subject: [PATCH 198/249] WIP: arm64: dts: meson: u200: add audio support + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12a-u200.dts | 244 ++++++++++++++++++ + 1 file changed, 244 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +index 8551fbd4a488c..332a4b27174be 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-u200.dts +@@ -18,6 +18,13 @@ + ethernet0 = ðmac; + }; + ++ spdif_dit: audio-codec-1 { ++ #sound-dai-cells = <0>; ++ compatible = "linux,spdif-dit"; ++ status = "okay"; ++ sound-name-prefix = "DIT"; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -129,6 +136,155 @@ + regulator-always-on; + }; + ++ sound { ++ compatible = "amlogic,axg-sound-card"; ++ model = "G12A-U200"; ++ audio-aux-devs = <&tdmout_a>, <&tdmout_b>, <&tdmout_c>, ++ <&tdmin_a>, <&tdmin_b>, <&tdmin_c>, ++ <&tdmin_lb>; ++ audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", ++ "TDMOUT_A IN 1", "FRDDR_B OUT 0", ++ "TDMOUT_A IN 2", "FRDDR_C OUT 0", ++ "TDM_A Playback", "TDMOUT_A OUT", ++ "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", ++ "SPDIFOUT IN 0", "FRDDR_A OUT 3", ++ "SPDIFOUT IN 1", "FRDDR_B OUT 3", ++ "SPDIFOUT IN 2", "FRDDR_C OUT 3", ++ "TDMIN_A IN 0", "TDM_A Capture", ++ "TDMIN_A IN 1", "TDM_B Capture", ++ "TDMIN_A IN 3", "TDM_A Loopback", ++ "TDMIN_A IN 4", "TDM_B Loopback", ++ "TDMIN_B IN 0", "TDM_A Capture", ++ "TDMIN_B IN 1", "TDM_B Capture", ++ "TDMIN_B IN 3", "TDM_A Loopback", ++ "TDMIN_B IN 4", "TDM_B Loopback", ++ "TDMIN_C IN 0", "TDM_A Capture", ++ "TDMIN_C IN 1", "TDM_B Capture", ++ "TDMIN_C IN 3", "TDM_A Loopback", ++ "TDMIN_C IN 4", "TDM_B Loopback", ++ "TDMIN_LB IN 3", "TDM_A Capture", ++ "TDMIN_LB IN 4", "TDM_B Capture", ++ "TDMIN_LB IN 0", "TDM_A Loopback", ++ "TDMIN_LB IN 1", "TDM_B Loopback", ++ "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"; ++ ++ assigned-clocks = <&clkc CLKID_HIFI_PLL>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <589824000>, ++ <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>; ++ }; ++ ++ dai-link-6 { ++ sound-dai = <&tdmif_b>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec@1 { ++ sound-dai = <&tohdmitx 1>; ++ }; ++ }; ++ ++ dai-link-7 { ++ sound-dai = <&tdmif_a>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec@1 { ++ sound-dai = <&tohdmitx 0>; ++ }; ++ }; ++ ++ dai-link-8 { ++ sound-dai = <&tdmif_c>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec@1 { ++ sound-dai = <&tohdmitx 2>; ++ }; ++ }; ++ ++ dai-link-9 { ++ sound-dai = <&spdifout>; ++ ++ codec@0 { ++ sound-dai = <&spdif_dit>; ++ }; ++ ++ codec@1 { ++ sound-dai = <&tohdmitx 4>; ++ }; ++ }; ++ ++ dai-link-10 { ++ sound-dai = <&spdifout_b>; ++ ++ codec { ++ sound-dai = <&tohdmitx 5>; ++ }; ++ }; ++ ++ dai-link-11 { ++ sound-dai = <&tohdmitx 3>; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++}; ++ ++&arb { ++ status = "okay"; + }; + + &cec_AO { +@@ -145,6 +301,10 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&clkc_audio { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +@@ -157,6 +317,18 @@ + phy-mode = "rmii"; + }; + ++&frddr_a { ++ status = "okay"; ++}; ++ ++&frddr_b { ++ status = "okay"; ++}; ++ ++&frddr_c { ++ status = "okay"; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; +@@ -234,6 +406,78 @@ + vqmmc-supply = <&flash_1v8>; + }; + ++&spdifout { ++ pinctrl-0 = <&spdif_ao_out_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&spdifout_b { ++ status = "okay"; ++}; ++ ++&tdmif_a { ++ pinctrl-0 = <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>, <&tdm_a_dout0_pins> ; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&tdmif_b { ++ pinctrl-0 = <&mclk0_a_pins>, <&tdm_b_fs_pins>, <&tdm_b_sclk_pins>, ++ <&tdm_b_dout0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&tdmif_c { ++ status = "okay"; ++}; ++ ++&tdmin_a { ++ inctrl-0 = <&tdm_a_dout0_pins>, <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>; ++ status = "okay"; ++}; ++ ++&tdmin_b { ++ status = "okay"; ++}; ++ ++&tdmin_c { ++ status = "okay"; ++}; ++ ++&tdmin_lb { ++ status = "okay"; ++}; ++ ++&tdmout_a { ++ status = "okay"; ++}; ++ ++&tdmout_b { ++ status = "okay"; ++}; ++ ++&tdmout_c { ++ status = "okay"; ++}; ++ ++&toddr_a { ++ status = "okay"; ++}; ++ ++&toddr_b { ++ status = "okay"; ++}; ++ ++&toddr_c { ++ status = "okay"; ++}; ++ ++&tohdmitx { ++ status = "okay"; ++}; ++ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; + +From a0933fc9008daf4ad9038c3cd32df5f0e9029727 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 18 Mar 2019 13:45:39 +0100 +Subject: [PATCH 199/249] WIP: arm64: dts: meson: sei510: enable audio + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-g12a-sei510.dts | 246 +++++++++++++++++- + 1 file changed, 245 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index 50d8ac55eed8a..a497add0907af 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -32,13 +32,22 @@ + ethernet0 = ðmac; + }; + +- mono_dac: audio-codec { ++ mono_dac: audio-codec-0 { + compatible = "maxim,max98357a"; + #sound-dai-cells = <0>; + sound-name-prefix = "U16"; + sdmode-gpios = <&gpio GPIOX_8 GPIO_ACTIVE_HIGH>; + }; + ++ dmics: audio-codec-1 { ++ #sound-dai-cells = <0>; ++ compatible = "dmic-codec"; ++ num-channels = <2>; ++ wakeup-delay-ms = <50>; ++ status = "okay"; ++ sound-name-prefix = "MIC"; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -143,6 +152,133 @@ + clock-names = "ext_clock"; + }; + ++ sound { ++ compatible = "amlogic,axg-sound-card"; ++ model = "G12A-SEI510"; ++ audio-aux-devs = <&tdmout_a>, <&tdmout_b>, <&tdmout_c>, ++ <&tdmin_a>, <&tdmin_b>, <&tdmin_c>, ++ <&tdmin_lb>; ++ audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", ++ "TDMOUT_A IN 1", "FRDDR_B OUT 0", ++ "TDMOUT_A IN 2", "FRDDR_C OUT 0", ++ "TDM_A Playback", "TDMOUT_A OUT", ++ "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", ++ "TODDR_A IN 4", "PDM Capture", ++ "TODDR_B IN 4", "PDM Capture", ++ "TODDR_C IN 4", "PDM Capture", ++ "TDMIN_A IN 0", "TDM_A Capture", ++ "TDMIN_A IN 3", "TDM_A Loopback", ++ "TDMIN_B IN 0", "TDM_A Capture", ++ "TDMIN_B IN 3", "TDM_A Loopback", ++ "TDMIN_C IN 0", "TDM_A Capture", ++ "TDMIN_C IN 3", "TDM_A Loopback", ++ "TDMIN_LB IN 3", "TDM_A Capture", ++ "TDMIN_LB IN 0", "TDM_A Loopback", ++ "TDMIN_A IN 1", "TDM_B Capture", ++ "TDMIN_A IN 4", "TDM_B Loopback", ++ "TDMIN_B IN 1", "TDM_B Capture", ++ "TDMIN_B IN 4", "TDM_B Loopback", ++ "TDMIN_C IN 1", "TDM_B Capture", ++ "TDMIN_C IN 4", "TDM_B Loopback", ++ "TDMIN_LB IN 4", "TDM_B Capture", ++ "TDMIN_LB IN 1", "TDM_B Loopback", ++ "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"; ++ ++ /* FIXME */ ++ assigned-clocks = <&clkc CLKID_HIFI_PLL>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <589824000>, ++ <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>; ++ }; ++ ++ dai-link-6 { ++ sound-dai = <&tdmif_a>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec-0 { ++ sound-dai = <&mono_dac>; ++ }; ++ ++ codec-1 { ++ sound-dai = <&tohdmitx 0>; ++ }; ++ }; ++ ++ dai-link-7 { ++ sound-dai = <&pdm>; ++ ++ codec { ++ sound-dai = <&dmics>; ++ }; ++ }; ++ ++ dai-link-8 { ++ sound-dai = <&tdmif_b>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ dai-tdm-slot-tx-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 1>; ++ }; ++ }; ++ ++ dai-link-9 { ++ sound-dai = <&tohdmitx 3>; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + wifi32k: wifi32k { + compatible = "pwm-clock"; + #clock-cells = <0>; +@@ -151,6 +287,10 @@ + }; + }; + ++&arb { ++ status = "okay"; ++}; ++ + &cec_AO { + pinctrl-0 = <&cec_ao_a_h_pins>; + pinctrl-names = "default"; +@@ -165,6 +305,10 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&clkc_audio { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +@@ -177,6 +321,18 @@ + phy-mode = "rmii"; + }; + ++&frddr_a { ++ status = "okay"; ++}; ++ ++&frddr_b { ++ status = "okay"; ++}; ++ ++&frddr_c { ++ status = "okay"; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; +@@ -201,6 +357,14 @@ + pinctrl-names = "default"; + }; + ++&pdm { ++ pinctrl-0 = <&pdm_din0_z_pins>, <&pdm_din1_z_pins>, ++ <&pdm_din2_z_pins>, <&pdm_din3_z_pins>, ++ <&pdm_dclk_z_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ + &pwm_ef { + status = "okay"; + pinctrl-0 = <&pwm_e_pins>; +@@ -277,6 +441,86 @@ + vqmmc-supply = <&emmc_1v8>; + }; + ++&tdmif_a { ++ pinctrl-0 = <&tdm_a_dout0_pins>, <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD0>, ++ <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD0>; ++ assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_A_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_A_LRCLK>; ++ assigned-clock-rates = <0>, <0>; ++}; ++ ++&tdmif_b { ++ status = "okay"; ++ ++ assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD1>, ++ <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD1>, ++ <&clkc_audio AUD_CLKID_TDM_MCLK_PAD0>; ++ assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_B_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_B_LRCLK>, ++ <&clkc_audio AUD_CLKID_MST_B_MCLK>; ++ assigned-clock-rates = <0>, <0>, <0>; ++}; ++ ++&tdmif_c { ++ status = "okay"; ++ ++ assigned-clocks = <&clkc_audio AUD_CLKID_TDM_SCLK_PAD2>, ++ <&clkc_audio AUD_CLKID_TDM_LRCLK_PAD2>, ++ <&clkc_audio AUD_CLKID_TDM_MCLK_PAD1>; ++ assigned-clock-parents = <&clkc_audio AUD_CLKID_MST_C_SCLK>, ++ <&clkc_audio AUD_CLKID_MST_C_LRCLK>, ++ <&clkc_audio AUD_CLKID_MST_C_MCLK>; ++ assigned-clock-rates = <0>, <0>, <0>; ++}; ++ ++&tdmin_a { ++ status = "okay"; ++}; ++ ++&tdmin_b { ++ status = "okay"; ++}; ++ ++&tdmin_c { ++ status = "okay"; ++}; ++ ++&tdmin_lb { ++ status = "okay"; ++}; ++ ++&tdmout_a { ++ status = "okay"; ++}; ++ ++&tdmout_b { ++ status = "okay"; ++}; ++ ++&tdmout_c { ++ status = "okay"; ++}; ++ ++&toddr_a { ++ status = "okay"; ++}; ++ ++&toddr_b { ++ status = "okay"; ++}; ++ ++&toddr_c { ++ status = "okay"; ++}; ++ ++&tohdmitx { ++ status = "okay"; ++}; ++ + &uart_A { + status = "okay"; + pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + +From 7c3d9ce2a78fa344d701894e7fc0bea185213563 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 14 May 2019 10:00:52 +0200 +Subject: [PATCH 200/249] WIP: Bluetooth: btbcm: Add entry for BCM4359C0 UART + bluetooth + +--- + drivers/bluetooth/btbcm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c +index d5d6e6e5da3bf..b9eac94c503d2 100644 +--- a/drivers/bluetooth/btbcm.c ++++ b/drivers/bluetooth/btbcm.c +@@ -342,6 +342,7 @@ static const struct bcm_subver_table bcm_uart_subver_table[] = { + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x4217, "BCM4329B1" }, /* 002.002.023 */ ++ { 0x6106, "BCM4359C0" }, /* 003.001.006 */ + { } + }; + + +From 39082908e3a2b38f9f787fa1d80d924227c3d180 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 14 May 2019 13:38:14 +0200 +Subject: [PATCH 201/249] WIP: arm64: dts: meson-g12a-sei510: Switch sound card + to MPPL2 instead of HIFI_PLL + +--- + arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +index a497add0907af..1b535b9ed1c51 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-sei510.dts +@@ -199,11 +199,11 @@ + "TODDR_C IN 6", "TDMIN_LB OUT"; + + /* FIXME */ +- assigned-clocks = <&clkc CLKID_HIFI_PLL>, ++ assigned-clocks = <&clkc CLKID_MPLL2>, + <&clkc CLKID_MPLL0>, + <&clkc CLKID_MPLL1>; + assigned-clock-parents = <0>, <0>, <0>; +- assigned-clock-rates = <589824000>, ++ assigned-clock-rates = <294912000>, + <270950400>, + <393216000>; + + +From 18e1f337541ad76b8756c887f310cd1c72f0d71b Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Tue, 14 May 2019 14:51:26 +0200 +Subject: [PATCH 202/249] fixup! FROMLIST: arm64: dts: meson: g12a: add audio + fifos + +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 9fa4ef37d6243..29db6ce2ccbb2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -1499,7 +1499,7 @@ + }; + + toddr_a: audio-controller@100 { +- compatible = "amlogic,g12a-toddr"; ++ compatible = "amlogic,g12a-toddr", "amlogic,axg-toddr"; + reg = <0x0 0x100 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "TODDR_A"; +@@ -1510,7 +1510,7 @@ + }; + + toddr_b: audio-controller@140 { +- compatible = "amlogic,g12a-toddr"; ++ compatible = "amlogic,g12a-toddr", "amlogic,axg-toddr"; + reg = <0x0 0x140 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "TODDR_B"; +@@ -1521,7 +1521,7 @@ + }; + + toddr_c: audio-controller@180 { +- compatible = "amlogic,g12a-toddr"; ++ compatible = "amlogic,g12a-toddr", "amlogic,axg-toddr"; + reg = <0x0 0x180 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "TODDR_C"; +@@ -1532,7 +1532,7 @@ + }; + + frddr_a: audio-controller@1c0 { +- compatible = "amlogic,g12a-frddr"; ++ compatible = "amlogic,g12a-frddr", "amlogic,axg-frddr"; + reg = <0x0 0x1c0 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "FRDDR_A"; +@@ -1543,7 +1543,7 @@ + }; + + frddr_b: audio-controller@200 { +- compatible = "amlogic,g12a-frddr"; ++ compatible = "amlogic,g12a-frddr", "amlogic,axg-frddr"; + reg = <0x0 0x200 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "FRDDR_B"; +@@ -1554,7 +1554,7 @@ + }; + + frddr_c: audio-controller@240 { +- compatible = "amlogic,g12a-frddr"; ++ compatible = "amlogic,g12a-frddr", "amlogic,axg-frddr"; + reg = <0x0 0x240 0x0 0x1c>; + #sound-dai-cells = <0>; + sound-name-prefix = "FRDDR_C"; + +From 793cc3405b4bf1b744ca91eb701547ace14c48cb Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 15:05:05 +0200 +Subject: [PATCH 203/249] WIP: dt-bindings: media: add Amlogic Video Decoder + Bindings + +Add documentation for the meson vdec dts node. + +Signed-off-by: Maxime Jourdan +Reviewed-by: Rob Herring +--- + .../bindings/media/amlogic,vdec.txt | 71 +++++++++++++++++++ + 1 file changed, 71 insertions(+) + create mode 100644 Documentation/devicetree/bindings/media/amlogic,vdec.txt + +diff --git a/Documentation/devicetree/bindings/media/amlogic,vdec.txt b/Documentation/devicetree/bindings/media/amlogic,vdec.txt +new file mode 100644 +index 0000000000000..aabdd01bcf32b +--- /dev/null ++++ b/Documentation/devicetree/bindings/media/amlogic,vdec.txt +@@ -0,0 +1,71 @@ ++Amlogic Video Decoder ++================================ ++ ++The video decoding IP lies within the DOS memory region, ++except for the hardware bitstream parser that makes use of an undocumented ++region. ++ ++It makes use of the following blocks: ++ ++- ESPARSER is a bitstream parser that outputs to a VIFIFO. Further VDEC blocks ++then feed from this VIFIFO. ++- VDEC_1 can decode MPEG-1, MPEG-2, MPEG-4 part 2, MJPEG, H.263, H.264, VC-1. ++- VDEC_HEVC can decode HEVC and VP9. ++ ++Both VDEC_1 and VDEC_HEVC share the "vdec" IRQ and as such cannot run ++concurrently. ++ ++Device Tree Bindings: ++--------------------- ++ ++VDEC: Video Decoder ++-------------------------- ++ ++Required properties: ++- compatible: value should be different for each SoC family as : ++ - GXBB (S905) : "amlogic,gxbb-vdec" ++ - GXL (S905X, S905D) : "amlogic,gxl-vdec" ++ - GXM (S912) : "amlogic,gxm-vdec" ++- reg: base address and size of he following memory-mapped regions : ++ - dos ++ - esparser ++- reg-names: should contain the names of the previous memory regions ++- interrupts: should contain the following IRQs: ++ - vdec ++ - esparser ++- interrupt-names: should contain the names of the previous interrupts ++- amlogic,ao-sysctrl: should point to the AOBUS sysctrl node ++- amlogic,canvas: should point to a canvas provider node ++- clocks: should contain the following clocks : ++ - dos_parser ++ - dos ++ - vdec_1 ++ - vdec_hevc ++- clock-names: should contain the names of the previous clocks ++- resets: should contain the parser reset ++- reset-names: should be "esparser" ++ ++Example: ++ ++vdec: video-decoder@c8820000 { ++ compatible = "amlogic,gxbb-vdec"; ++ reg = <0x0 0xc8820000 0x0 0x10000>, ++ <0x0 0xc110a580 0x0 0xe4>; ++ reg-names = "dos", "esparser"; ++ ++ interrupts = , ++ ; ++ interrupt-names = "vdec", "esparser"; ++ ++ amlogic,ao-sysctrl = <&sysctrl_AO>; ++ amlogic,canvas = <&canvas>; ++ ++ clocks = <&clkc CLKID_DOS_PARSER>, ++ <&clkc CLKID_DOS>, ++ <&clkc CLKID_VDEC_1>, ++ <&clkc CLKID_VDEC_HEVC>; ++ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; ++ ++ resets = <&reset RESET_PARSER>; ++ reset-names = "esparser"; ++}; + +From f3c22a1ed164e7a74a574dd40abbb9d2e2a11582 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 4 Oct 2018 15:37:39 +0200 +Subject: [PATCH 204/249] WIP: media: videodev2: add + V4L2_FMT_FLAG_FIXED_RESOLUTION + +When a v4l2 driver exposes V4L2_EVENT_SOURCE_CHANGE, some (usually +OUTPUT) formats may not be able to trigger this event. + +For instance, MPEG2 on Amlogic hardware does not support resolution +switching on the fly, and a decode session must operate at a set +resolution defined before the decoding start. + +Add a enum_fmt format flag to tag those specific formats. + +Signed-off-by: Maxime Jourdan +--- + Documentation/media/uapi/v4l/vidioc-enum-fmt.rst | 6 ++++++ + include/uapi/linux/videodev2.h | 5 +++-- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst b/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst +index 822d6730e7d2c..b11448a1848b2 100644 +--- a/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst ++++ b/Documentation/media/uapi/v4l/vidioc-enum-fmt.rst +@@ -127,6 +127,12 @@ one until ``EINVAL`` is returned. + - This format is not native to the device but emulated through + software (usually libv4l2), where possible try to use a native + format instead for better performance. ++ * - ``V4L2_FMT_FLAG_FIXED_RESOLUTION`` ++ - 0x0004 ++ - Dynamic resolution switching is not supported for this format, ++ even if the event ``V4L2_EVENT_SOURCE_CHANGE`` is supported by ++ the device. ++ + + + Return Value +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index 1db220da3bccd..9c8a2d2e7bc62 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -751,8 +751,9 @@ struct v4l2_fmtdesc { + __u32 reserved[4]; + }; + +-#define V4L2_FMT_FLAG_COMPRESSED 0x0001 +-#define V4L2_FMT_FLAG_EMULATED 0x0002 ++#define V4L2_FMT_FLAG_COMPRESSED 0x0001 ++#define V4L2_FMT_FLAG_EMULATED 0x0002 ++#define V4L2_FMT_FLAG_FIXED_RESOLUTION 0x0004 + + /* Frame Size and frame rate enumeration */ + /* + +From ce61c43ac2da5510a5faea890111c6e11c66a2c8 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 15:17:22 +0200 +Subject: [PATCH 205/249] WIP: media: meson: add v4l2 m2m video decoder driver + +Amlogic SoCs feature a powerful video decoder unit able to +decode many formats, with a performance of usually up to 4k60. + +This is a driver for this IP that is based around the v4l2 m2m framework. + +It features decoding for: +- MPEG 1 +- MPEG 2 + +Supported SoCs are: GXBB (S905), GXL (S905X/W/D), GXM (S912) + +There is also a hardware bitstream parser (ESPARSER) that is handled here. + +Signed-off-by: Maxime Jourdan +--- + drivers/media/platform/Kconfig | 10 + + drivers/media/platform/meson/Makefile | 1 + + drivers/media/platform/meson/vdec/Makefile | 8 + + .../media/platform/meson/vdec/codec_mpeg12.c | 209 ++++ + .../media/platform/meson/vdec/codec_mpeg12.h | 14 + + drivers/media/platform/meson/vdec/dos_regs.h | 98 ++ + drivers/media/platform/meson/vdec/esparser.c | 323 +++++ + drivers/media/platform/meson/vdec/esparser.h | 32 + + drivers/media/platform/meson/vdec/vdec.c | 1071 +++++++++++++++++ + drivers/media/platform/meson/vdec/vdec.h | 265 ++++ + drivers/media/platform/meson/vdec/vdec_1.c | 229 ++++ + drivers/media/platform/meson/vdec/vdec_1.h | 14 + + .../media/platform/meson/vdec/vdec_ctrls.c | 51 + + .../media/platform/meson/vdec/vdec_ctrls.h | 14 + + .../media/platform/meson/vdec/vdec_helpers.c | 441 +++++++ + .../media/platform/meson/vdec/vdec_helpers.h | 80 ++ + .../media/platform/meson/vdec/vdec_platform.c | 107 ++ + .../media/platform/meson/vdec/vdec_platform.h | 30 + + 18 files changed, 2997 insertions(+) + create mode 100644 drivers/media/platform/meson/vdec/Makefile + create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg12.c + create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg12.h + create mode 100644 drivers/media/platform/meson/vdec/dos_regs.h + create mode 100644 drivers/media/platform/meson/vdec/esparser.c + create mode 100644 drivers/media/platform/meson/vdec/esparser.h + create mode 100644 drivers/media/platform/meson/vdec/vdec.c + create mode 100644 drivers/media/platform/meson/vdec/vdec.h + create mode 100644 drivers/media/platform/meson/vdec/vdec_1.c + create mode 100644 drivers/media/platform/meson/vdec/vdec_1.h + create mode 100644 drivers/media/platform/meson/vdec/vdec_ctrls.c + create mode 100644 drivers/media/platform/meson/vdec/vdec_ctrls.h + create mode 100644 drivers/media/platform/meson/vdec/vdec_helpers.c + create mode 100644 drivers/media/platform/meson/vdec/vdec_helpers.h + create mode 100644 drivers/media/platform/meson/vdec/vdec_platform.c + create mode 100644 drivers/media/platform/meson/vdec/vdec_platform.h + +diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig +index ea3a65e1ddbcd..82cefe97018e4 100644 +--- a/drivers/media/platform/Kconfig ++++ b/drivers/media/platform/Kconfig +@@ -501,6 +501,16 @@ config VIDEO_QCOM_VENUS + on various Qualcomm SoCs. + To compile this driver as a module choose m here. + ++config VIDEO_MESON_VDEC ++ tristate "Amlogic video decoder driver" ++ depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA ++ depends on ARCH_MESON || COMPILE_TEST ++ select VIDEOBUF2_DMA_CONTIG ++ select V4L2_MEM2MEM_DEV ++ select MESON_CANVAS ++ help ++ Support for the video decoder found in gxbb/gxl/gxm chips. ++ + endif # V4L_MEM2MEM_DRIVERS + + # TI VIDEO PORT Helper Modules +diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile +index f611c23c37180..2fc34afb70d19 100644 +--- a/drivers/media/platform/meson/Makefile ++++ b/drivers/media/platform/meson/Makefile +@@ -1,2 +1,3 @@ + obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o + obj-$(CONFIG_VIDEO_MESON_G12A_AO_CEC) += ao-cec-g12a.o ++obj-$(CONFIG_VIDEO_MESON_VDEC) += vdec/ +diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile +new file mode 100644 +index 0000000000000..eba86083aadb4 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# Makefile for Amlogic meson video decoder driver ++ ++meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o ++meson-vdec-objs += vdec_1.o ++meson-vdec-objs += codec_mpeg12.o ++ ++obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/media/platform/meson/vdec/codec_mpeg12.c b/drivers/media/platform/meson/vdec/codec_mpeg12.c +new file mode 100644 +index 0000000000000..d88530a7b81ae +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_mpeg12.c +@@ -0,0 +1,209 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "vdec_helpers.h" ++#include "dos_regs.h" ++ ++#define SIZE_WORKSPACE SZ_128K ++/* Offset substracted by the firmware from the workspace paddr */ ++#define WORKSPACE_OFFSET (5 * SZ_1K) ++ ++/* map firmware registers to known MPEG1/2 functions */ ++#define MREG_SEQ_INFO AV_SCRATCH_4 ++ #define MPEG2_SEQ_DAR_MASK GENMASK(3, 0) ++ #define MPEG2_DAR_4_3 2 ++ #define MPEG2_DAR_16_9 3 ++ #define MPEG2_DAR_221_100 4 ++#define MREG_PIC_INFO AV_SCRATCH_5 ++#define MREG_PIC_WIDTH AV_SCRATCH_6 ++#define MREG_PIC_HEIGHT AV_SCRATCH_7 ++#define MREG_BUFFERIN AV_SCRATCH_8 ++#define MREG_BUFFEROUT AV_SCRATCH_9 ++#define MREG_CMD AV_SCRATCH_A ++#define MREG_CO_MV_START AV_SCRATCH_B ++#define MREG_ERROR_COUNT AV_SCRATCH_C ++#define MREG_FRAME_OFFSET AV_SCRATCH_D ++#define MREG_WAIT_BUFFER AV_SCRATCH_E ++#define MREG_FATAL_ERROR AV_SCRATCH_F ++ ++#define PICINFO_PROG 0x00008000 ++#define PICINFO_TOP_FIRST 0x00002000 ++ ++struct codec_mpeg12 { ++ /* Buffer for the MPEG1/2 Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++}; ++ ++static const u8 eos_sequence[SZ_1K] = { 0x00, 0x00, 0x01, 0xB7 }; ++ ++static const u8 *codec_mpeg12_eos_sequence(u32 *len) ++{ ++ *len = ARRAY_SIZE(eos_sequence); ++ return eos_sequence; ++} ++ ++static int codec_mpeg12_can_recycle(struct amvdec_core *core) ++{ ++ return !amvdec_read_dos(core, MREG_BUFFERIN); ++} ++ ++static void codec_mpeg12_recycle(struct amvdec_core *core, u32 buf_idx) ++{ ++ amvdec_write_dos(core, MREG_BUFFERIN, buf_idx + 1); ++} ++ ++static int codec_mpeg12_start(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_mpeg12 *mpeg12 = sess->priv; ++ int ret; ++ ++ mpeg12 = kzalloc(sizeof(*mpeg12), GFP_KERNEL); ++ if (!mpeg12) ++ return -ENOMEM; ++ ++ /* Allocate some memory for the MPEG1/2 decoder's state */ ++ mpeg12->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &mpeg12->workspace_paddr, ++ GFP_KERNEL); ++ if (!mpeg12->workspace_vaddr) { ++ dev_err(core->dev, "Failed to request MPEG 1/2 Workspace\n"); ++ ret = -ENOMEM; ++ goto free_mpeg12; ++ } ++ ++ ret = amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, 0 }, ++ (u32[]){ 8, 0 }); ++ if (ret) ++ goto free_workspace; ++ ++ amvdec_write_dos(core, POWER_CTL_VLD, BIT(4)); ++ amvdec_write_dos(core, MREG_CO_MV_START, ++ mpeg12->workspace_paddr + WORKSPACE_OFFSET); ++ ++ amvdec_write_dos(core, MPEG1_2_REG, 0); ++ amvdec_write_dos(core, PSCALE_CTRL, 0); ++ amvdec_write_dos(core, PIC_HEAD_INFO, 0x380); ++ amvdec_write_dos(core, M4_CONTROL_REG, 0); ++ amvdec_write_dos(core, MREG_BUFFERIN, 0); ++ amvdec_write_dos(core, MREG_BUFFEROUT, 0); ++ amvdec_write_dos(core, MREG_CMD, (sess->width << 16) | sess->height); ++ amvdec_write_dos(core, MREG_ERROR_COUNT, 0); ++ amvdec_write_dos(core, MREG_FATAL_ERROR, 0); ++ amvdec_write_dos(core, MREG_WAIT_BUFFER, 0); ++ ++ sess->keyframe_found = 1; ++ sess->priv = mpeg12; ++ ++ return 0; ++ ++free_workspace: ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg12->workspace_vaddr, ++ mpeg12->workspace_paddr); ++free_mpeg12: ++ kfree(mpeg12); ++ ++ return ret; ++} ++ ++static int codec_mpeg12_stop(struct amvdec_session *sess) ++{ ++ struct codec_mpeg12 *mpeg12 = sess->priv; ++ struct amvdec_core *core = sess->core; ++ ++ if (mpeg12->workspace_vaddr) ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ mpeg12->workspace_vaddr, ++ mpeg12->workspace_paddr); ++ ++ return 0; ++} ++ ++static void codec_mpeg12_update_dar(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 seq = amvdec_read_dos(core, MREG_SEQ_INFO); ++ u32 ar = seq & MPEG2_SEQ_DAR_MASK; ++ ++ switch (ar) { ++ case MPEG2_DAR_4_3: ++ amvdec_set_par_from_dar(sess, 4, 3); ++ break; ++ case MPEG2_DAR_16_9: ++ amvdec_set_par_from_dar(sess, 16, 9); ++ break; ++ case MPEG2_DAR_221_100: ++ amvdec_set_par_from_dar(sess, 221, 100); ++ break; ++ default: ++ sess->pixelaspect.numerator = 1; ++ sess->pixelaspect.denominator = 1; ++ break; ++ } ++} ++ ++static irqreturn_t codec_mpeg12_threaded_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 reg; ++ u32 pic_info; ++ u32 is_progressive; ++ u32 buffer_index; ++ u32 field = V4L2_FIELD_NONE; ++ u32 offset; ++ ++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); ++ reg = amvdec_read_dos(core, MREG_FATAL_ERROR); ++ if (reg == 1) { ++ dev_err(core->dev, "MPEG1/2 fatal error\n"); ++ amvdec_abort(sess); ++ return IRQ_HANDLED; ++ } ++ ++ reg = amvdec_read_dos(core, MREG_BUFFEROUT); ++ if (!reg) ++ return IRQ_HANDLED; ++ ++ /* Unclear what this means */ ++ if ((reg & GENMASK(23, 17)) == GENMASK(23, 17)) ++ goto end; ++ ++ pic_info = amvdec_read_dos(core, MREG_PIC_INFO); ++ is_progressive = pic_info & PICINFO_PROG; ++ ++ if (!is_progressive) ++ field = (pic_info & PICINFO_TOP_FIRST) ? ++ V4L2_FIELD_INTERLACED_TB : ++ V4L2_FIELD_INTERLACED_BT; ++ ++ codec_mpeg12_update_dar(sess); ++ buffer_index = ((reg & 0xf) - 1) & 7; ++ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET); ++ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field); ++ ++end: ++ amvdec_write_dos(core, MREG_BUFFEROUT, 0); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t codec_mpeg12_isr(struct amvdec_session *sess) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++struct amvdec_codec_ops codec_mpeg12_ops = { ++ .start = codec_mpeg12_start, ++ .stop = codec_mpeg12_stop, ++ .isr = codec_mpeg12_isr, ++ .threaded_isr = codec_mpeg12_threaded_isr, ++ .can_recycle = codec_mpeg12_can_recycle, ++ .recycle = codec_mpeg12_recycle, ++ .eos_sequence = codec_mpeg12_eos_sequence, ++}; +diff --git a/drivers/media/platform/meson/vdec/codec_mpeg12.h b/drivers/media/platform/meson/vdec/codec_mpeg12.h +new file mode 100644 +index 0000000000000..43cab5f39ca05 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_mpeg12.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_MPEG12_H_ ++#define __MESON_VDEC_CODEC_MPEG12_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_mpeg12_ops; ++ ++#endif +diff --git a/drivers/media/platform/meson/vdec/dos_regs.h b/drivers/media/platform/meson/vdec/dos_regs.h +new file mode 100644 +index 0000000000000..abd810542dbb5 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/dos_regs.h +@@ -0,0 +1,98 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_DOS_REGS_H_ ++#define __MESON_VDEC_DOS_REGS_H_ ++ ++/* DOS registers */ ++#define VDEC_ASSIST_AMR1_INT8 0x00b4 ++ ++#define ASSIST_MBOX1_CLR_REG 0x01d4 ++#define ASSIST_MBOX1_MASK 0x01d8 ++ ++#define MPSR 0x0c04 ++#define MCPU_INTR_MSK 0x0c10 ++#define CPSR 0x0c84 ++ ++#define IMEM_DMA_CTRL 0x0d00 ++#define IMEM_DMA_ADR 0x0d04 ++#define IMEM_DMA_COUNT 0x0d08 ++#define LMEM_DMA_CTRL 0x0d40 ++ ++#define MC_STATUS0 0x2424 ++#define MC_CTRL1 0x242c ++ ++#define PSCALE_RST 0x2440 ++#define PSCALE_CTRL 0x2444 ++#define PSCALE_BMEM_ADDR 0x247c ++#define PSCALE_BMEM_DAT 0x2480 ++ ++#define DBLK_CTRL 0x2544 ++#define DBLK_STATUS 0x254c ++ ++#define GCLK_EN 0x260c ++#define MDEC_PIC_DC_CTRL 0x2638 ++#define MDEC_PIC_DC_STATUS 0x263c ++#define ANC0_CANVAS_ADDR 0x2640 ++#define MDEC_PIC_DC_THRESH 0x26e0 ++ ++/* Firmware interface registers */ ++#define AV_SCRATCH_0 0x2700 ++#define AV_SCRATCH_1 0x2704 ++#define AV_SCRATCH_2 0x2708 ++#define AV_SCRATCH_3 0x270c ++#define AV_SCRATCH_4 0x2710 ++#define AV_SCRATCH_5 0x2714 ++#define AV_SCRATCH_6 0x2718 ++#define AV_SCRATCH_7 0x271c ++#define AV_SCRATCH_8 0x2720 ++#define AV_SCRATCH_9 0x2724 ++#define AV_SCRATCH_A 0x2728 ++#define AV_SCRATCH_B 0x272c ++#define AV_SCRATCH_C 0x2730 ++#define AV_SCRATCH_D 0x2734 ++#define AV_SCRATCH_E 0x2738 ++#define AV_SCRATCH_F 0x273c ++#define AV_SCRATCH_G 0x2740 ++#define AV_SCRATCH_H 0x2744 ++#define AV_SCRATCH_I 0x2748 ++#define AV_SCRATCH_J 0x274c ++#define AV_SCRATCH_K 0x2750 ++#define AV_SCRATCH_L 0x2754 ++ ++#define MPEG1_2_REG 0x3004 ++#define PIC_HEAD_INFO 0x300c ++#define POWER_CTL_VLD 0x3020 ++#define M4_CONTROL_REG 0x30a4 ++ ++/* Stream Buffer (stbuf) regs */ ++#define VLD_MEM_VIFIFO_START_PTR 0x3100 ++#define VLD_MEM_VIFIFO_CURR_PTR 0x3104 ++#define VLD_MEM_VIFIFO_END_PTR 0x3108 ++#define VLD_MEM_VIFIFO_CONTROL 0x3110 ++ #define MEM_FIFO_CNT_BIT 16 ++ #define MEM_FILL_ON_LEVEL BIT(10) ++ #define MEM_CTRL_EMPTY_EN BIT(2) ++ #define MEM_CTRL_FILL_EN BIT(1) ++#define VLD_MEM_VIFIFO_WP 0x3114 ++#define VLD_MEM_VIFIFO_RP 0x3118 ++#define VLD_MEM_VIFIFO_LEVEL 0x311c ++#define VLD_MEM_VIFIFO_BUF_CNTL 0x3120 ++ #define MEM_BUFCTRL_MANUAL BIT(1) ++#define VLD_MEM_VIFIFO_WRAP_COUNT 0x3144 ++ ++#define DCAC_DMA_CTRL 0x3848 ++ ++#define DOS_SW_RESET0 0xfc00 ++#define DOS_GCLK_EN0 0xfc04 ++#define DOS_GEN_CTRL0 0xfc08 ++#define DOS_MEM_PD_VDEC 0xfcc0 ++#define DOS_MEM_PD_HEVC 0xfccc ++#define DOS_SW_RESET3 0xfcd0 ++#define DOS_GCLK_EN3 0xfcd4 ++#define DOS_VDEC_MCRCC_STALL_CTRL 0xfd00 ++ ++#endif +diff --git a/drivers/media/platform/meson/vdec/esparser.c b/drivers/media/platform/meson/vdec/esparser.c +new file mode 100644 +index 0000000000000..24e08b01c88a1 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/esparser.c +@@ -0,0 +1,323 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ * ++ * The Elementary Stream Parser is a HW bitstream parser. ++ * It reads bitstream buffers and feeds them to the VIFIFO ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "dos_regs.h" ++#include "esparser.h" ++#include "vdec_helpers.h" ++ ++/* PARSER REGS (CBUS) */ ++#define PARSER_CONTROL 0x00 ++ #define ES_PACK_SIZE_BIT 8 ++ #define ES_WRITE BIT(5) ++ #define ES_SEARCH BIT(1) ++ #define ES_PARSER_START BIT(0) ++#define PARSER_FETCH_ADDR 0x4 ++#define PARSER_FETCH_CMD 0x8 ++#define PARSER_CONFIG 0x14 ++ #define PS_CFG_MAX_FETCH_CYCLE_BIT 0 ++ #define PS_CFG_STARTCODE_WID_24_BIT 10 ++ #define PS_CFG_MAX_ES_WR_CYCLE_BIT 12 ++ #define PS_CFG_PFIFO_EMPTY_CNT_BIT 16 ++#define PFIFO_WR_PTR 0x18 ++#define PFIFO_RD_PTR 0x1c ++#define PARSER_SEARCH_PATTERN 0x24 ++ #define ES_START_CODE_PATTERN 0x00000100 ++#define PARSER_SEARCH_MASK 0x28 ++ #define ES_START_CODE_MASK 0xffffff00 ++ #define FETCH_ENDIAN_BIT 27 ++#define PARSER_INT_ENABLE 0x2c ++ #define PARSER_INT_HOST_EN_BIT 8 ++#define PARSER_INT_STATUS 0x30 ++ #define PARSER_INTSTAT_SC_FOUND 1 ++#define PARSER_ES_CONTROL 0x5c ++#define PARSER_VIDEO_START_PTR 0x80 ++#define PARSER_VIDEO_END_PTR 0x84 ++#define PARSER_VIDEO_WP 0x88 ++#define PARSER_VIDEO_HOLE 0x90 ++ ++#define SEARCH_PATTERN_LEN 512 ++ ++static DECLARE_WAIT_QUEUE_HEAD(wq); ++static int search_done; ++ ++static irqreturn_t esparser_isr(int irq, void *dev) ++{ ++ int int_status; ++ struct amvdec_core *core = dev; ++ ++ int_status = amvdec_read_parser(core, PARSER_INT_STATUS); ++ amvdec_write_parser(core, PARSER_INT_STATUS, int_status); ++ ++ if (int_status & PARSER_INTSTAT_SC_FOUND) { ++ amvdec_write_parser(core, PFIFO_RD_PTR, 0); ++ amvdec_write_parser(core, PFIFO_WR_PTR, 0); ++ search_done = 1; ++ wake_up_interruptible(&wq); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger ++ * ISRs. ++ * Also append a start code 000001ff at the end to trigger ++ * the ESPARSER interrupt. ++ */ ++static u32 esparser_pad_start_code(struct vb2_buffer *vb) ++{ ++ u32 payload_size = vb2_get_plane_payload(vb, 0); ++ u32 pad_size = 0; ++ u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size; ++ ++ if (payload_size < ESPARSER_MIN_PACKET_SIZE) { ++ pad_size = ESPARSER_MIN_PACKET_SIZE - payload_size; ++ memset(vaddr, 0, pad_size); ++ } ++ ++ memset(vaddr + pad_size, 0, SEARCH_PATTERN_LEN); ++ vaddr[pad_size] = 0x00; ++ vaddr[pad_size + 1] = 0x00; ++ vaddr[pad_size + 2] = 0x01; ++ vaddr[pad_size + 3] = 0xff; ++ ++ return pad_size; ++} ++ ++static int ++esparser_write_data(struct amvdec_core *core, dma_addr_t addr, u32 size) ++{ ++ amvdec_write_parser(core, PFIFO_RD_PTR, 0); ++ amvdec_write_parser(core, PFIFO_WR_PTR, 0); ++ amvdec_write_parser(core, PARSER_CONTROL, ++ ES_WRITE | ++ ES_PARSER_START | ++ ES_SEARCH | ++ (size << ES_PACK_SIZE_BIT)); ++ ++ amvdec_write_parser(core, PARSER_FETCH_ADDR, addr); ++ amvdec_write_parser(core, PARSER_FETCH_CMD, ++ (7 << FETCH_ENDIAN_BIT) | ++ (size + SEARCH_PATTERN_LEN)); ++ ++ search_done = 0; ++ return wait_event_interruptible_timeout(wq, search_done, (HZ / 5)); ++} ++ ++static u32 esparser_vififo_get_free_space(struct amvdec_session *sess) ++{ ++ u32 vififo_usage; ++ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; ++ struct amvdec_core *core = sess->core; ++ ++ vififo_usage = vdec_ops->vififo_level(sess); ++ vififo_usage += amvdec_read_parser(core, PARSER_VIDEO_HOLE); ++ vififo_usage += (6 * SZ_1K); // 6 KiB internal fifo ++ ++ if (vififo_usage > sess->vififo_size) { ++ dev_warn(sess->core->dev, ++ "VIFIFO usage (%u) > VIFIFO size (%u)\n", ++ vififo_usage, sess->vififo_size); ++ return 0; ++ } ++ ++ return sess->vififo_size - vififo_usage; ++} ++ ++int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len) ++{ ++ struct device *dev = core->dev; ++ void *eos_vaddr; ++ dma_addr_t eos_paddr; ++ int ret; ++ ++ eos_vaddr = dma_alloc_coherent(dev, len + SEARCH_PATTERN_LEN, ++ &eos_paddr, GFP_KERNEL); ++ if (!eos_vaddr) ++ return -ENOMEM; ++ ++ memcpy(eos_vaddr, data, len); ++ ret = esparser_write_data(core, eos_paddr, len); ++ dma_free_coherent(dev, len + SEARCH_PATTERN_LEN, ++ eos_vaddr, eos_paddr); ++ ++ return ret; ++} ++ ++static u32 esparser_get_offset(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 offset = amvdec_read_parser(core, PARSER_VIDEO_WP) - ++ sess->vififo_paddr; ++ ++ if (offset < sess->last_offset) ++ sess->wrap_count++; ++ ++ sess->last_offset = offset; ++ offset += (sess->wrap_count * sess->vififo_size); ++ ++ return offset; ++} ++ ++static int ++esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) ++{ ++ int ret; ++ struct vb2_buffer *vb = &vbuf->vb2_buf; ++ struct amvdec_core *core = sess->core; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ u32 num_dst_bufs = 0; ++ u32 payload_size = vb2_get_plane_payload(vb, 0); ++ dma_addr_t phy = vb2_dma_contig_plane_dma_addr(vb, 0); ++ u32 offset; ++ u32 pad_size; ++ ++ if (codec_ops->num_pending_bufs) ++ num_dst_bufs = codec_ops->num_pending_bufs(sess); ++ ++ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ ++ if (esparser_vififo_get_free_space(sess) < payload_size || ++ atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) ++ return -EAGAIN; ++ ++ v4l2_m2m_src_buf_remove_by_buf(sess->m2m_ctx, vbuf); ++ ++ offset = esparser_get_offset(sess); ++ ++ amvdec_add_ts_reorder(sess, vb->timestamp, offset); ++ dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n", ++ vb->timestamp, payload_size, offset); ++ ++ pad_size = esparser_pad_start_code(vb); ++ ret = esparser_write_data(core, phy, payload_size + pad_size); ++ ++ if (ret <= 0) { ++ dev_warn(core->dev, "esparser: input parsing error\n"); ++ amvdec_remove_ts(sess, vb->timestamp); ++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); ++ amvdec_write_parser(core, PARSER_FETCH_CMD, 0); ++ ++ return 0; ++ } ++ ++ /* We need to wait until we parse the first keyframe. ++ * All buffers prior to the first keyframe must be dropped. ++ */ ++ if (!sess->keyframe_found) ++ usleep_range(1000, 2000); ++ ++ if (sess->keyframe_found) ++ atomic_inc(&sess->esparser_queued_bufs); ++ else ++ amvdec_remove_ts(sess, vb->timestamp); ++ ++ vbuf->flags = 0; ++ vbuf->field = V4L2_FIELD_NONE; ++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); ++ ++ return 0; ++} ++ ++void esparser_queue_all_src(struct work_struct *work) ++{ ++ struct v4l2_m2m_buffer *buf, *n; ++ struct amvdec_session *sess = ++ container_of(work, struct amvdec_session, esparser_queue_work); ++ ++ mutex_lock(&sess->lock); ++ v4l2_m2m_for_each_src_buf_safe(sess->m2m_ctx, buf, n) { ++ if (sess->should_stop) ++ break; ++ ++ if (esparser_queue(sess, &buf->vb) < 0) ++ break; ++ } ++ mutex_unlock(&sess->lock); ++} ++ ++int esparser_power_up(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; ++ ++ reset_control_reset(core->esparser_reset); ++ amvdec_write_parser(core, PARSER_CONFIG, ++ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) | ++ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) | ++ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT)); ++ ++ amvdec_write_parser(core, PFIFO_RD_PTR, 0); ++ amvdec_write_parser(core, PFIFO_WR_PTR, 0); ++ ++ amvdec_write_parser(core, PARSER_SEARCH_PATTERN, ++ ES_START_CODE_PATTERN); ++ amvdec_write_parser(core, PARSER_SEARCH_MASK, ES_START_CODE_MASK); ++ ++ amvdec_write_parser(core, PARSER_CONFIG, ++ (10 << PS_CFG_PFIFO_EMPTY_CNT_BIT) | ++ (1 << PS_CFG_MAX_ES_WR_CYCLE_BIT) | ++ (16 << PS_CFG_MAX_FETCH_CYCLE_BIT) | ++ (2 << PS_CFG_STARTCODE_WID_24_BIT)); ++ ++ amvdec_write_parser(core, PARSER_CONTROL, ++ (ES_SEARCH | ES_PARSER_START)); ++ ++ amvdec_write_parser(core, PARSER_VIDEO_START_PTR, sess->vififo_paddr); ++ amvdec_write_parser(core, PARSER_VIDEO_END_PTR, ++ sess->vififo_paddr + sess->vififo_size - 8); ++ amvdec_write_parser(core, PARSER_ES_CONTROL, ++ amvdec_read_parser(core, PARSER_ES_CONTROL) & ~1); ++ ++ if (vdec_ops->conf_esparser) ++ vdec_ops->conf_esparser(sess); ++ ++ amvdec_write_parser(core, PARSER_INT_STATUS, 0xffff); ++ amvdec_write_parser(core, PARSER_INT_ENABLE, ++ BIT(PARSER_INT_HOST_EN_BIT)); ++ ++ return 0; ++} ++ ++int esparser_init(struct platform_device *pdev, struct amvdec_core *core) ++{ ++ struct device *dev = &pdev->dev; ++ int ret; ++ int irq; ++ ++ irq = platform_get_irq_byname(pdev, "esparser"); ++ if (irq < 0) { ++ dev_err(dev, "Failed getting ESPARSER IRQ from dtb\n"); ++ return irq; ++ } ++ ++ ret = devm_request_irq(dev, irq, esparser_isr, IRQF_SHARED, ++ "esparserirq", core); ++ if (ret) { ++ dev_err(dev, "Failed requesting ESPARSER IRQ\n"); ++ return ret; ++ } ++ ++ core->esparser_reset = ++ devm_reset_control_get_exclusive(dev, "esparser"); ++ if (IS_ERR(core->esparser_reset)) { ++ dev_err(dev, "Failed to get esparser_reset\n"); ++ return PTR_ERR(core->esparser_reset); ++ } ++ ++ return 0; ++} +diff --git a/drivers/media/platform/meson/vdec/esparser.h b/drivers/media/platform/meson/vdec/esparser.h +new file mode 100644 +index 0000000000000..ff51fe7fda664 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/esparser.h +@@ -0,0 +1,32 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_ESPARSER_H_ ++#define __MESON_VDEC_ESPARSER_H_ ++ ++#include ++ ++#include "vdec.h" ++ ++int esparser_init(struct platform_device *pdev, struct amvdec_core *core); ++int esparser_power_up(struct amvdec_session *sess); ++ ++/** ++ * esparser_queue_eos() - write End Of Stream sequence to the ESPARSER ++ * ++ * @core vdec core struct ++ */ ++int esparser_queue_eos(struct amvdec_core *core, const u8 *data, u32 len); ++ ++/** ++ * esparser_queue_all_src() - work handler that writes as many src buffers ++ * as possible to the ESPARSER ++ */ ++void esparser_queue_all_src(struct work_struct *work); ++ ++#define ESPARSER_MIN_PACKET_SIZE SZ_4K ++ ++#endif +diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c +new file mode 100644 +index 0000000000000..da96a788ee5c6 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec.c +@@ -0,0 +1,1071 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vdec.h" ++#include "esparser.h" ++#include "vdec_helpers.h" ++#include "vdec_ctrls.h" ++ ++struct dummy_buf { ++ struct vb2_v4l2_buffer vb; ++ struct list_head list; ++}; ++ ++/* 16 MiB for parsed bitstream swap exchange */ ++#define SIZE_VIFIFO SZ_16M ++ ++static u32 get_output_size(u32 width, u32 height) ++{ ++ return ALIGN(width * height, SZ_64K); ++} ++ ++u32 amvdec_get_output_size(struct amvdec_session *sess) ++{ ++ return get_output_size(sess->width, sess->height); ++} ++EXPORT_SYMBOL_GPL(amvdec_get_output_size); ++ ++static int vdec_codec_needs_recycle(struct amvdec_session *sess) ++{ ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ ++ return codec_ops->can_recycle && codec_ops->recycle; ++} ++ ++static int vdec_recycle_thread(void *data) ++{ ++ struct amvdec_session *sess = data; ++ struct amvdec_core *core = sess->core; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ struct amvdec_buffer *tmp, *n; ++ ++ while (!kthread_should_stop()) { ++ mutex_lock(&sess->bufs_recycle_lock); ++ list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) { ++ if (!codec_ops->can_recycle(core)) ++ break; ++ ++ codec_ops->recycle(core, tmp->vb->index); ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++ mutex_unlock(&sess->bufs_recycle_lock); ++ ++ usleep_range(5000, 10000); ++ } ++ ++ return 0; ++} ++ ++static int vdec_poweron(struct amvdec_session *sess) ++{ ++ int ret; ++ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; ++ ++ ret = clk_prepare_enable(sess->core->dos_parser_clk); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(sess->core->dos_clk); ++ if (ret) ++ goto disable_dos_parser; ++ ++ ret = vdec_ops->start(sess); ++ if (ret) ++ goto disable_dos; ++ ++ esparser_power_up(sess); ++ ++ return 0; ++ ++disable_dos: ++ clk_disable_unprepare(sess->core->dos_clk); ++disable_dos_parser: ++ clk_disable_unprepare(sess->core->dos_parser_clk); ++ ++ return ret; ++} ++ ++static void vdec_wait_inactive(struct amvdec_session *sess) ++{ ++ /* We consider 50ms with no IRQ to be inactive. */ ++ while (time_is_after_jiffies64(sess->last_irq_jiffies + ++ msecs_to_jiffies(50))) ++ msleep(25); ++} ++ ++static void vdec_poweroff(struct amvdec_session *sess) ++{ ++ struct amvdec_ops *vdec_ops = sess->fmt_out->vdec_ops; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ ++ sess->should_stop = 1; ++ vdec_wait_inactive(sess); ++ if (codec_ops->drain) ++ codec_ops->drain(sess); ++ ++ vdec_ops->stop(sess); ++ clk_disable_unprepare(sess->core->dos_clk); ++ clk_disable_unprepare(sess->core->dos_parser_clk); ++} ++ ++static void ++vdec_queue_recycle(struct amvdec_session *sess, struct vb2_buffer *vb) ++{ ++ struct amvdec_buffer *new_buf; ++ ++ new_buf = kmalloc(sizeof(*new_buf), GFP_KERNEL); ++ new_buf->vb = vb; ++ ++ mutex_lock(&sess->bufs_recycle_lock); ++ list_add_tail(&new_buf->list, &sess->bufs_recycle); ++ mutex_unlock(&sess->bufs_recycle_lock); ++} ++ ++static void vdec_m2m_device_run(void *priv) ++{ ++ struct amvdec_session *sess = priv; ++ ++ schedule_work(&sess->esparser_queue_work); ++} ++ ++static void vdec_m2m_job_abort(void *priv) ++{ ++ struct amvdec_session *sess = priv; ++ ++ v4l2_m2m_job_finish(sess->m2m_dev, sess->m2m_ctx); ++} ++ ++static const struct v4l2_m2m_ops vdec_m2m_ops = { ++ .device_run = vdec_m2m_device_run, ++ .job_abort = vdec_m2m_job_abort, ++}; ++ ++static void process_num_buffers(struct vb2_queue *q, ++ struct amvdec_session *sess, ++ unsigned int *num_buffers, ++ bool is_reqbufs) ++{ ++ const struct amvdec_format *fmt_out = sess->fmt_out; ++ unsigned int buffers_total = q->num_buffers + *num_buffers; ++ ++ if (is_reqbufs && buffers_total < fmt_out->min_buffers) ++ *num_buffers = fmt_out->min_buffers - q->num_buffers; ++ if (buffers_total > fmt_out->max_buffers) ++ *num_buffers = fmt_out->max_buffers - q->num_buffers; ++ ++ /* We need to program the complete CAPTURE buffer list ++ * in registers during start_streaming, and the firmwares ++ * are free to choose any of them to write frames to. As such, ++ * we need all of them to be queued into the driver ++ */ ++ sess->num_dst_bufs = q->num_buffers + *num_buffers; ++ q->min_buffers_needed = max(fmt_out->min_buffers, sess->num_dst_bufs); ++} ++ ++static int vdec_queue_setup(struct vb2_queue *q, ++ unsigned int *num_buffers, unsigned int *num_planes, ++ unsigned int sizes[], struct device *alloc_devs[]) ++{ ++ struct amvdec_session *sess = vb2_get_drv_priv(q); ++ u32 output_size = amvdec_get_output_size(sess); ++ ++ if (*num_planes) { ++ switch (q->type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: ++ if (*num_planes != 1 || sizes[0] < output_size) ++ return -EINVAL; ++ break; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: ++ switch (sess->pixfmt_cap) { ++ case V4L2_PIX_FMT_NV12M: ++ if (*num_planes != 2 || ++ sizes[0] < output_size || ++ sizes[1] < output_size / 2) ++ return -EINVAL; ++ break; ++ case V4L2_PIX_FMT_YUV420M: ++ if (*num_planes != 3 || ++ sizes[0] < output_size || ++ sizes[1] < output_size / 4 || ++ sizes[2] < output_size / 4) ++ return -EINVAL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ process_num_buffers(q, sess, num_buffers, false); ++ break; ++ } ++ ++ return 0; ++ } ++ ++ switch (q->type) { ++ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: ++ sizes[0] = amvdec_get_output_size(sess); ++ *num_planes = 1; ++ break; ++ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: ++ switch (sess->pixfmt_cap) { ++ case V4L2_PIX_FMT_NV12M: ++ sizes[0] = output_size; ++ sizes[1] = output_size / 2; ++ *num_planes = 2; ++ break; ++ case V4L2_PIX_FMT_YUV420M: ++ sizes[0] = output_size; ++ sizes[1] = output_size / 4; ++ sizes[2] = output_size / 4; ++ *num_planes = 3; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ process_num_buffers(q, sess, num_buffers, true); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void vdec_vb2_buf_queue(struct vb2_buffer *vb) ++{ ++ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); ++ struct amvdec_session *sess = vb2_get_drv_priv(vb->vb2_queue); ++ struct v4l2_m2m_ctx *m2m_ctx = sess->m2m_ctx; ++ ++ v4l2_m2m_buf_queue(m2m_ctx, vbuf); ++ ++ if (!sess->streamon_out || !sess->streamon_cap) ++ return; ++ ++ if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && ++ vdec_codec_needs_recycle(sess)) ++ vdec_queue_recycle(sess, vb); ++ ++ schedule_work(&sess->esparser_queue_work); ++} ++ ++static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) ++{ ++ struct amvdec_session *sess = vb2_get_drv_priv(q); ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ struct amvdec_core *core = sess->core; ++ struct vb2_v4l2_buffer *buf; ++ int ret; ++ ++ if (core->cur_sess && core->cur_sess != sess) { ++ ret = -EBUSY; ++ goto bufs_done; ++ } ++ ++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ++ sess->streamon_out = 1; ++ else ++ sess->streamon_cap = 1; ++ ++ if (!sess->streamon_out || !sess->streamon_cap) ++ return 0; ++ ++ if (sess->status == STATUS_NEEDS_RESUME && ++ q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ codec_ops->resume(sess); ++ sess->status = STATUS_RUNNING; ++ return 0; ++ } ++ ++ sess->vififo_size = SIZE_VIFIFO; ++ sess->vififo_vaddr = ++ dma_alloc_coherent(sess->core->dev, sess->vififo_size, ++ &sess->vififo_paddr, GFP_KERNEL); ++ if (!sess->vififo_vaddr) { ++ dev_err(sess->core->dev, "Failed to request VIFIFO buffer\n"); ++ ret = -ENOMEM; ++ goto bufs_done; ++ } ++ ++ sess->should_stop = 0; ++ sess->keyframe_found = 0; ++ sess->last_offset = 0; ++ sess->wrap_count = 0; ++ sess->dpb_size = 1; ++ sess->pixelaspect.numerator = 1; ++ sess->pixelaspect.denominator = 1; ++ atomic_set(&sess->esparser_queued_bufs, 0); ++ ++ ret = vdec_poweron(sess); ++ if (ret) ++ goto vififo_free; ++ ++ sess->sequence_cap = 0; ++ if (vdec_codec_needs_recycle(sess)) ++ sess->recycle_thread = kthread_run(vdec_recycle_thread, sess, ++ "vdec_recycle"); ++ ++ sess->status = STATUS_RUNNING; ++ core->cur_sess = sess; ++ ++ return 0; ++ ++vififo_free: ++ dma_free_coherent(sess->core->dev, sess->vififo_size, ++ sess->vififo_vaddr, sess->vififo_paddr); ++bufs_done: ++ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx))) ++ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); ++ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx))) ++ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED); ++ ++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ++ sess->streamon_out = 0; ++ else ++ sess->streamon_cap = 0; ++ ++ return ret; ++} ++ ++static void vdec_free_canvas(struct amvdec_session *sess) ++{ ++ int i; ++ ++ for (i = 0; i < sess->canvas_num; ++i) ++ meson_canvas_free(sess->core->canvas, sess->canvas_alloc[i]); ++ ++ sess->canvas_num = 0; ++} ++ ++static void vdec_reset_timestamps(struct amvdec_session *sess) ++{ ++ struct amvdec_timestamp *tmp, *n; ++ ++ list_for_each_entry_safe(tmp, n, &sess->timestamps, list) { ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++} ++ ++static void vdec_reset_bufs_recycle(struct amvdec_session *sess) ++{ ++ struct amvdec_buffer *tmp, *n; ++ ++ list_for_each_entry_safe(tmp, n, &sess->bufs_recycle, list) { ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++} ++ ++static void vdec_stop_streaming(struct vb2_queue *q) ++{ ++ struct amvdec_session *sess = vb2_get_drv_priv(q); ++ struct amvdec_core *core = sess->core; ++ struct vb2_v4l2_buffer *buf; ++ ++ if (sess->status == STATUS_RUNNING || ++ (sess->status == STATUS_NEEDS_RESUME && ++ (!sess->streamon_out || !sess->streamon_cap))) { ++ if (vdec_codec_needs_recycle(sess)) ++ kthread_stop(sess->recycle_thread); ++ ++ vdec_poweroff(sess); ++ vdec_free_canvas(sess); ++ dma_free_coherent(sess->core->dev, sess->vififo_size, ++ sess->vififo_vaddr, sess->vififo_paddr); ++ vdec_reset_timestamps(sess); ++ vdec_reset_bufs_recycle(sess); ++ kfree(sess->priv); ++ sess->priv = NULL; ++ core->cur_sess = NULL; ++ sess->status = STATUS_STOPPED; ++ } ++ ++ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ++ while ((buf = v4l2_m2m_src_buf_remove(sess->m2m_ctx))) ++ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); ++ ++ sess->streamon_out = 0; ++ } else { ++ while ((buf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx))) ++ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); ++ ++ sess->streamon_cap = 0; ++ } ++} ++ ++static const struct vb2_ops vdec_vb2_ops = { ++ .queue_setup = vdec_queue_setup, ++ .start_streaming = vdec_start_streaming, ++ .stop_streaming = vdec_stop_streaming, ++ .buf_queue = vdec_vb2_buf_queue, ++ .wait_prepare = vb2_ops_wait_prepare, ++ .wait_finish = vb2_ops_wait_finish, ++}; ++ ++static int ++vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) ++{ ++ strscpy(cap->driver, "meson-vdec", sizeof(cap->driver)); ++ strscpy(cap->card, "Amlogic Video Decoder", sizeof(cap->card)); ++ strscpy(cap->bus_info, "platform:meson-vdec", sizeof(cap->bus_info)); ++ ++ return 0; ++} ++ ++static const struct amvdec_format * ++find_format(const struct amvdec_format *fmts, u32 size, u32 pixfmt) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < size; i++) { ++ if (fmts[i].pixfmt == pixfmt) ++ return &fmts[i]; ++ } ++ ++ return NULL; ++} ++ ++static unsigned int ++vdec_supports_pixfmt_cap(const struct amvdec_format *fmt_out, u32 pixfmt_cap) ++{ ++ int i; ++ ++ for (i = 0; fmt_out->pixfmts_cap[i]; i++) ++ if (fmt_out->pixfmts_cap[i] == pixfmt_cap) ++ return 1; ++ ++ return 0; ++} ++ ++static const struct amvdec_format * ++vdec_try_fmt_common(struct amvdec_session *sess, u32 size, ++ struct v4l2_format *f) ++{ ++ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; ++ struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt; ++ const struct amvdec_format *fmts = sess->core->platform->formats; ++ const struct amvdec_format *fmt_out; ++ ++ memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); ++ memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); ++ ++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ++ fmt_out = find_format(fmts, size, pixmp->pixelformat); ++ if (!fmt_out) { ++ pixmp->pixelformat = V4L2_PIX_FMT_MPEG2; ++ fmt_out = find_format(fmts, size, pixmp->pixelformat); ++ } ++ ++ pfmt[0].sizeimage = ++ get_output_size(pixmp->width, pixmp->height); ++ pfmt[0].bytesperline = 0; ++ pixmp->num_planes = 1; ++ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ fmt_out = sess->fmt_out; ++ if (!vdec_supports_pixfmt_cap(fmt_out, pixmp->pixelformat)) ++ pixmp->pixelformat = fmt_out->pixfmts_cap[0]; ++ ++ memset(pfmt[1].reserved, 0, sizeof(pfmt[1].reserved)); ++ if (pixmp->pixelformat == V4L2_PIX_FMT_NV12M) { ++ pfmt[0].sizeimage = ++ get_output_size(pixmp->width, pixmp->height); ++ pfmt[0].bytesperline = ALIGN(pixmp->width, 64); ++ ++ pfmt[1].sizeimage = ++ get_output_size(pixmp->width, pixmp->height) / 2; ++ pfmt[1].bytesperline = ALIGN(pixmp->width, 64); ++ pixmp->num_planes = 2; ++ } else if (pixmp->pixelformat == V4L2_PIX_FMT_YUV420M) { ++ pfmt[0].sizeimage = ++ get_output_size(pixmp->width, pixmp->height); ++ pfmt[0].bytesperline = ALIGN(pixmp->width, 64); ++ ++ pfmt[1].sizeimage = ++ get_output_size(pixmp->width, pixmp->height) / 4; ++ pfmt[1].bytesperline = ALIGN(pixmp->width, 64) / 2; ++ ++ pfmt[2].sizeimage = ++ get_output_size(pixmp->width, pixmp->height) / 4; ++ pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2; ++ pixmp->num_planes = 3; ++ } ++ } else { ++ return NULL; ++ } ++ ++ pixmp->width = clamp(pixmp->width, (u32)256, fmt_out->max_width); ++ pixmp->height = clamp(pixmp->height, (u32)144, fmt_out->max_height); ++ ++ if (pixmp->field == V4L2_FIELD_ANY) ++ pixmp->field = V4L2_FIELD_NONE; ++ ++ return fmt_out; ++} ++ ++static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) ++{ ++ struct amvdec_session *sess = ++ container_of(file->private_data, struct amvdec_session, fh); ++ ++ vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); ++ ++ return 0; ++} ++ ++static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) ++{ ++ struct amvdec_session *sess = ++ container_of(file->private_data, struct amvdec_session, fh); ++ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; ++ ++ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ pixmp->pixelformat = sess->pixfmt_cap; ++ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ++ pixmp->pixelformat = sess->fmt_out->pixfmt; ++ ++ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ pixmp->width = sess->width; ++ pixmp->height = sess->height; ++ pixmp->colorspace = sess->colorspace; ++ pixmp->ycbcr_enc = sess->ycbcr_enc; ++ pixmp->quantization = sess->quantization; ++ pixmp->xfer_func = sess->xfer_func; ++ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ++ pixmp->width = sess->width; ++ pixmp->height = sess->height; ++ } ++ ++ vdec_try_fmt_common(sess, sess->core->platform->num_formats, f); ++ ++ return 0; ++} ++ ++static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) ++{ ++ struct amvdec_session *sess = ++ container_of(file->private_data, struct amvdec_session, fh); ++ struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; ++ u32 num_formats = sess->core->platform->num_formats; ++ const struct amvdec_format *fmt_out; ++ struct v4l2_pix_format_mplane orig_pixmp; ++ struct v4l2_format format; ++ u32 pixfmt_out = 0, pixfmt_cap = 0; ++ ++ orig_pixmp = *pixmp; ++ ++ fmt_out = vdec_try_fmt_common(sess, num_formats, f); ++ ++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ++ pixfmt_out = pixmp->pixelformat; ++ pixfmt_cap = sess->pixfmt_cap; ++ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ pixfmt_cap = pixmp->pixelformat; ++ pixfmt_out = sess->fmt_out->pixfmt; ++ } ++ ++ memset(&format, 0, sizeof(format)); ++ ++ format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ++ format.fmt.pix_mp.pixelformat = pixfmt_out; ++ format.fmt.pix_mp.width = orig_pixmp.width; ++ format.fmt.pix_mp.height = orig_pixmp.height; ++ vdec_try_fmt_common(sess, num_formats, &format); ++ ++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ++ sess->width = format.fmt.pix_mp.width; ++ sess->height = format.fmt.pix_mp.height; ++ sess->colorspace = pixmp->colorspace; ++ sess->ycbcr_enc = pixmp->ycbcr_enc; ++ sess->quantization = pixmp->quantization; ++ sess->xfer_func = pixmp->xfer_func; ++ } ++ ++ memset(&format, 0, sizeof(format)); ++ ++ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ format.fmt.pix_mp.pixelformat = pixfmt_cap; ++ format.fmt.pix_mp.width = orig_pixmp.width; ++ format.fmt.pix_mp.height = orig_pixmp.height; ++ vdec_try_fmt_common(sess, num_formats, &format); ++ ++ sess->width = format.fmt.pix_mp.width; ++ sess->height = format.fmt.pix_mp.height; ++ ++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ++ sess->fmt_out = fmt_out; ++ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ sess->pixfmt_cap = format.fmt.pix_mp.pixelformat; ++ ++ return 0; ++} ++ ++static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) ++{ ++ struct amvdec_session *sess = ++ container_of(file->private_data, struct amvdec_session, fh); ++ const struct vdec_platform *platform = sess->core->platform; ++ const struct amvdec_format *fmt_out; ++ ++ memset(f->reserved, 0, sizeof(f->reserved)); ++ ++ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ++ if (f->index >= platform->num_formats) ++ return -EINVAL; ++ ++ fmt_out = &platform->formats[f->index]; ++ f->pixelformat = fmt_out->pixfmt; ++ f->flags = fmt_out->flags; ++ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { ++ fmt_out = sess->fmt_out; ++ if (f->index >= 4 || !fmt_out->pixfmts_cap[f->index]) ++ return -EINVAL; ++ ++ f->pixelformat = fmt_out->pixfmts_cap[f->index]; ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int vdec_enum_framesizes(struct file *file, void *fh, ++ struct v4l2_frmsizeenum *fsize) ++{ ++ struct amvdec_session *sess = ++ container_of(file->private_data, struct amvdec_session, fh); ++ const struct amvdec_format *formats = sess->core->platform->formats; ++ const struct amvdec_format *fmt; ++ u32 num_formats = sess->core->platform->num_formats; ++ ++ fmt = find_format(formats, num_formats, fsize->pixel_format); ++ if (!fmt || fsize->index) ++ return -EINVAL; ++ ++ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; ++ ++ fsize->stepwise.min_width = 256; ++ fsize->stepwise.max_width = fmt->max_width; ++ fsize->stepwise.step_width = 1; ++ fsize->stepwise.min_height = 144; ++ fsize->stepwise.max_height = fmt->max_height; ++ fsize->stepwise.step_height = 1; ++ ++ return 0; ++} ++ ++static int ++vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) ++{ ++ switch (cmd->cmd) { ++ case V4L2_DEC_CMD_STOP: ++ if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) ++ return -EINVAL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) ++{ ++ struct amvdec_session *sess = ++ container_of(file->private_data, struct amvdec_session, fh); ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ struct device *dev = sess->core->dev; ++ int ret; ++ ++ ret = vdec_try_decoder_cmd(file, fh, cmd); ++ if (ret) ++ return ret; ++ ++ if (!(sess->streamon_out & sess->streamon_cap)) ++ return 0; ++ ++ dev_dbg(dev, "Received V4L2_DEC_CMD_STOP\n"); ++ sess->should_stop = 1; ++ ++ vdec_wait_inactive(sess); ++ ++ if (codec_ops->drain) { ++ codec_ops->drain(sess); ++ } else if (codec_ops->eos_sequence) { ++ u32 len; ++ const u8 *data = codec_ops->eos_sequence(&len); ++ ++ esparser_queue_eos(sess->core, data, len); ++ } ++ ++ return ret; ++} ++ ++static int vdec_subscribe_event(struct v4l2_fh *fh, ++ const struct v4l2_event_subscription *sub) ++{ ++ switch (sub->type) { ++ case V4L2_EVENT_EOS: ++ return v4l2_event_subscribe(fh, sub, 2, NULL); ++ case V4L2_EVENT_SOURCE_CHANGE: ++ return v4l2_src_change_event_subscribe(fh, sub); ++ case V4L2_EVENT_CTRL: ++ return v4l2_ctrl_subscribe_event(fh, sub); ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int vdec_g_pixelaspect(struct file *file, void *fh, int type, ++ struct v4l2_fract *f) ++{ ++ struct amvdec_session *sess = ++ container_of(file->private_data, struct amvdec_session, fh); ++ ++ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ++ return -EINVAL; ++ ++ *f = sess->pixelaspect; ++ return 0; ++} ++ ++static const struct v4l2_ioctl_ops vdec_ioctl_ops = { ++ .vidioc_querycap = vdec_querycap, ++ .vidioc_enum_fmt_vid_cap_mplane = vdec_enum_fmt, ++ .vidioc_enum_fmt_vid_out_mplane = vdec_enum_fmt, ++ .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt, ++ .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt, ++ .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt, ++ .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt, ++ .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt, ++ .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt, ++ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, ++ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, ++ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, ++ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, ++ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, ++ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, ++ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, ++ .vidioc_streamon = v4l2_m2m_ioctl_streamon, ++ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, ++ .vidioc_enum_framesizes = vdec_enum_framesizes, ++ .vidioc_subscribe_event = vdec_subscribe_event, ++ .vidioc_unsubscribe_event = v4l2_event_unsubscribe, ++ .vidioc_try_decoder_cmd = vdec_try_decoder_cmd, ++ .vidioc_decoder_cmd = vdec_decoder_cmd, ++ .vidioc_g_pixelaspect = vdec_g_pixelaspect, ++}; ++ ++static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, ++ struct vb2_queue *dst_vq) ++{ ++ struct amvdec_session *sess = priv; ++ int ret; ++ ++ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ++ src_vq->io_modes = VB2_MMAP | VB2_DMABUF; ++ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ src_vq->ops = &vdec_vb2_ops; ++ src_vq->mem_ops = &vb2_dma_contig_memops; ++ src_vq->drv_priv = sess; ++ src_vq->buf_struct_size = sizeof(struct dummy_buf); ++ src_vq->min_buffers_needed = 1; ++ src_vq->dev = sess->core->dev; ++ src_vq->lock = &sess->lock; ++ ret = vb2_queue_init(src_vq); ++ if (ret) ++ return ret; ++ ++ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; ++ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; ++ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ++ dst_vq->ops = &vdec_vb2_ops; ++ dst_vq->mem_ops = &vb2_dma_contig_memops; ++ dst_vq->drv_priv = sess; ++ dst_vq->buf_struct_size = sizeof(struct dummy_buf); ++ dst_vq->min_buffers_needed = 1; ++ dst_vq->dev = sess->core->dev; ++ dst_vq->lock = &sess->lock; ++ ret = vb2_queue_init(dst_vq); ++ if (ret) { ++ vb2_queue_release(src_vq); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int vdec_open(struct file *file) ++{ ++ struct amvdec_core *core = video_drvdata(file); ++ struct device *dev = core->dev; ++ const struct amvdec_format *formats = core->platform->formats; ++ struct amvdec_session *sess; ++ int ret; ++ ++ sess = kzalloc(sizeof(*sess), GFP_KERNEL); ++ if (!sess) ++ return -ENOMEM; ++ ++ sess->core = core; ++ ++ sess->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops); ++ if (IS_ERR(sess->m2m_dev)) { ++ dev_err(dev, "Fail to v4l2_m2m_init\n"); ++ ret = PTR_ERR(sess->m2m_dev); ++ goto err_free_sess; ++ } ++ ++ sess->m2m_ctx = v4l2_m2m_ctx_init(sess->m2m_dev, sess, m2m_queue_init); ++ if (IS_ERR(sess->m2m_ctx)) { ++ dev_err(dev, "Fail to v4l2_m2m_ctx_init\n"); ++ ret = PTR_ERR(sess->m2m_ctx); ++ goto err_m2m_release; ++ } ++ ++ ret = amvdec_init_ctrls(&sess->ctrl_handler); ++ if (ret) ++ goto err_m2m_release; ++ ++ sess->pixfmt_cap = formats[0].pixfmts_cap[0]; ++ sess->fmt_out = &formats[0]; ++ sess->width = 1280; ++ sess->height = 720; ++ sess->pixelaspect.numerator = 1; ++ sess->pixelaspect.denominator = 1; ++ sess->dpb_size = 1; ++ ++ INIT_LIST_HEAD(&sess->timestamps); ++ INIT_LIST_HEAD(&sess->bufs_recycle); ++ INIT_WORK(&sess->esparser_queue_work, esparser_queue_all_src); ++ mutex_init(&sess->lock); ++ mutex_init(&sess->bufs_recycle_lock); ++ spin_lock_init(&sess->ts_spinlock); ++ ++ v4l2_fh_init(&sess->fh, core->vdev_dec); ++ sess->fh.ctrl_handler = &sess->ctrl_handler; ++ v4l2_fh_add(&sess->fh); ++ sess->fh.m2m_ctx = sess->m2m_ctx; ++ file->private_data = &sess->fh; ++ ++ return 0; ++ ++err_m2m_release: ++ v4l2_m2m_release(sess->m2m_dev); ++err_free_sess: ++ kfree(sess); ++ return ret; ++} ++ ++static int vdec_close(struct file *file) ++{ ++ struct amvdec_session *sess = ++ container_of(file->private_data, struct amvdec_session, fh); ++ ++ v4l2_m2m_ctx_release(sess->m2m_ctx); ++ v4l2_m2m_release(sess->m2m_dev); ++ v4l2_fh_del(&sess->fh); ++ v4l2_fh_exit(&sess->fh); ++ ++ mutex_destroy(&sess->lock); ++ mutex_destroy(&sess->bufs_recycle_lock); ++ ++ kfree(sess); ++ ++ return 0; ++} ++ ++static const struct v4l2_file_operations vdec_fops = { ++ .owner = THIS_MODULE, ++ .open = vdec_open, ++ .release = vdec_close, ++ .unlocked_ioctl = video_ioctl2, ++ .poll = v4l2_m2m_fop_poll, ++ .mmap = v4l2_m2m_fop_mmap, ++}; ++ ++static irqreturn_t vdec_isr(int irq, void *data) ++{ ++ struct amvdec_core *core = data; ++ struct amvdec_session *sess = core->cur_sess; ++ ++ sess->last_irq_jiffies = get_jiffies_64(); ++ ++ return sess->fmt_out->codec_ops->isr(sess); ++} ++ ++static irqreturn_t vdec_threaded_isr(int irq, void *data) ++{ ++ struct amvdec_core *core = data; ++ struct amvdec_session *sess = core->cur_sess; ++ ++ return sess->fmt_out->codec_ops->threaded_isr(sess); ++} ++ ++static const struct of_device_id vdec_dt_match[] = { ++ { .compatible = "amlogic,gxbb-vdec", ++ .data = &vdec_platform_gxbb }, ++ { .compatible = "amlogic,gxm-vdec", ++ .data = &vdec_platform_gxm }, ++ { .compatible = "amlogic,gxl-vdec", ++ .data = &vdec_platform_gxl }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, vdec_dt_match); ++ ++static int vdec_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct video_device *vdev; ++ struct amvdec_core *core; ++ struct resource *r; ++ const struct of_device_id *of_id; ++ int irq; ++ int ret; ++ ++ core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); ++ if (!core) ++ return -ENOMEM; ++ ++ core->dev = dev; ++ platform_set_drvdata(pdev, core); ++ ++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dos"); ++ core->dos_base = devm_ioremap_resource(dev, r); ++ if (IS_ERR(core->dos_base)) { ++ dev_err(dev, "Couldn't remap DOS memory\n"); ++ return PTR_ERR(core->dos_base); ++ } ++ ++ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "esparser"); ++ core->esparser_base = devm_ioremap_resource(dev, r); ++ if (IS_ERR(core->esparser_base)) { ++ dev_err(dev, "Couldn't remap ESPARSER memory\n"); ++ return PTR_ERR(core->esparser_base); ++ } ++ ++ core->regmap_ao = syscon_regmap_lookup_by_phandle(dev->of_node, ++ "amlogic,ao-sysctrl"); ++ if (IS_ERR(core->regmap_ao)) { ++ dev_err(dev, "Couldn't regmap AO sysctrl\n"); ++ return PTR_ERR(core->regmap_ao); ++ } ++ ++ core->canvas = meson_canvas_get(dev); ++ if (!core->canvas) ++ return PTR_ERR(core->canvas); ++ ++ core->dos_parser_clk = devm_clk_get(dev, "dos_parser"); ++ if (IS_ERR(core->dos_parser_clk)) ++ return -EPROBE_DEFER; ++ ++ core->dos_clk = devm_clk_get(dev, "dos"); ++ if (IS_ERR(core->dos_clk)) ++ return -EPROBE_DEFER; ++ ++ core->vdec_1_clk = devm_clk_get(dev, "vdec_1"); ++ if (IS_ERR(core->vdec_1_clk)) ++ return -EPROBE_DEFER; ++ ++ core->vdec_hevc_clk = devm_clk_get(dev, "vdec_hevc"); ++ if (IS_ERR(core->vdec_hevc_clk)) ++ return -EPROBE_DEFER; ++ ++ irq = platform_get_irq_byname(pdev, "vdec"); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_threaded_irq(core->dev, irq, vdec_isr, ++ vdec_threaded_isr, IRQF_ONESHOT, ++ "vdec", core); ++ if (ret) ++ return ret; ++ ++ ret = esparser_init(pdev, core); ++ if (ret) ++ return ret; ++ ++ ret = v4l2_device_register(dev, &core->v4l2_dev); ++ if (ret) { ++ dev_err(dev, "Couldn't register v4l2 device\n"); ++ return -ENOMEM; ++ } ++ ++ vdev = video_device_alloc(); ++ if (!vdev) { ++ ret = -ENOMEM; ++ goto err_vdev_release; ++ } ++ ++ of_id = of_match_node(vdec_dt_match, dev->of_node); ++ core->platform = of_id->data; ++ core->vdev_dec = vdev; ++ core->dev_dec = dev; ++ mutex_init(&core->lock); ++ ++ strscpy(vdev->name, "meson-video-decoder", sizeof(vdev->name)); ++ vdev->release = video_device_release; ++ vdev->fops = &vdec_fops; ++ vdev->ioctl_ops = &vdec_ioctl_ops; ++ vdev->vfl_dir = VFL_DIR_M2M; ++ vdev->v4l2_dev = &core->v4l2_dev; ++ vdev->lock = &core->lock; ++ vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; ++ ++ video_set_drvdata(vdev, core); ++ ++ ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); ++ if (ret) { ++ dev_err(dev, "Failed registering video device\n"); ++ goto err_vdev_release; ++ } ++ ++ return 0; ++ ++err_vdev_release: ++ video_device_release(vdev); ++ return ret; ++} ++ ++static int vdec_remove(struct platform_device *pdev) ++{ ++ struct amvdec_core *core = platform_get_drvdata(pdev); ++ ++ video_unregister_device(core->vdev_dec); ++ ++ return 0; ++} ++ ++static struct platform_driver meson_vdec_driver = { ++ .probe = vdec_probe, ++ .remove = vdec_remove, ++ .driver = { ++ .name = "meson-vdec", ++ .of_match_table = vdec_dt_match, ++ }, ++}; ++module_platform_driver(meson_vdec_driver); ++ ++MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM"); ++MODULE_AUTHOR("Maxime Jourdan "); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h +new file mode 100644 +index 0000000000000..9f1e307057220 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec.h +@@ -0,0 +1,265 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CORE_H_ ++#define __MESON_VDEC_CORE_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "vdec_platform.h" ++ ++/* 32 buffers in 3-plane YUV420 */ ++#define MAX_CANVAS (32 * 3) ++ ++struct amvdec_buffer { ++ struct list_head list; ++ struct vb2_buffer *vb; ++}; ++ ++/** ++ * struct amvdec_timestamp - stores a src timestamp along with a VIFIFO offset ++ * ++ * @list: used to make lists out of this struct ++ * @ts: timestamp ++ * @offset: offset in the VIFIFO where the associated packet was written ++ */ ++struct amvdec_timestamp { ++ struct list_head list; ++ u64 ts; ++ u32 offset; ++}; ++ ++struct amvdec_session; ++ ++/** ++ * struct amvdec_core - device parameters, singleton ++ * ++ * @dos_base: DOS memory base address ++ * @esparser_base: PARSER memory base address ++ * @regmap_ao: regmap for the AO bus ++ * @dev: core device ++ * @dev_dec: decoder device ++ * @platform: platform-specific data ++ * @canvas: canvas provider reference ++ * @dos_parser_clk: DOS_PARSER clock ++ * @dos_clk: DOS clock ++ * @vdec_1_clk: VDEC_1 clock ++ * @vdec_hevc_clk: VDEC_HEVC clock ++ * @esparser_reset: RESET for the PARSER ++ * @vdec_dec: video device for the decoder ++ * @v4l2_dev: v4l2 device ++ * @cur_sess: current decoding session ++ * @lock: lock for this structure ++ */ ++struct amvdec_core { ++ void __iomem *dos_base; ++ void __iomem *esparser_base; ++ struct regmap *regmap_ao; ++ ++ struct device *dev; ++ struct device *dev_dec; ++ const struct vdec_platform *platform; ++ ++ struct meson_canvas *canvas; ++ ++ struct clk *dos_parser_clk; ++ struct clk *dos_clk; ++ struct clk *vdec_1_clk; ++ struct clk *vdec_hevc_clk; ++ ++ struct reset_control *esparser_reset; ++ ++ struct video_device *vdev_dec; ++ struct v4l2_device v4l2_dev; ++ ++ struct amvdec_session *cur_sess; ++ struct mutex lock; ++}; ++ ++/** ++ * struct amvdec_ops - vdec operations ++ * ++ * @start: mandatory call when the vdec needs to initialize ++ * @stop: mandatory call when the vdec needs to stop ++ * @conf_esparser: mandatory call to let the vdec configure the ESPARSER ++ * @vififo_level: mandatory call to get the current amount of data ++ * in the VIFIFO ++ * @use_offsets: mandatory call. Returns 1 if the VDEC supports vififo offsets ++ */ ++struct amvdec_ops { ++ int (*start)(struct amvdec_session *sess); ++ int (*stop)(struct amvdec_session *sess); ++ void (*conf_esparser)(struct amvdec_session *sess); ++ u32 (*vififo_level)(struct amvdec_session *sess); ++}; ++ ++/** ++ * struct amvdec_codec_ops - codec operations ++ * ++ * @start: mandatory call when the codec needs to initialize ++ * @stop: mandatory call when the codec needs to stop ++ * @load_extended_firmware: optional call to load additional firmware bits ++ * @num_pending_bufs: optional call to get the number of dst buffers on hold ++ * @can_recycle: optional call to know if the codec is ready to recycle ++ * a dst buffer ++ * @recycle: optional call to tell the codec to recycle a dst buffer. Must go ++ * in pair with @can_recycle ++ * @drain: optional call if the codec has a custom way of draining ++ * @eos_sequence: optional call to get an end sequence to send to esparser ++ * for flush. Mutually exclusive with @drain. ++ * @isr: mandatory call when the ISR triggers ++ * @threaded_isr: mandatory call for the threaded ISR ++ */ ++struct amvdec_codec_ops { ++ int (*start)(struct amvdec_session *sess); ++ int (*stop)(struct amvdec_session *sess); ++ int (*load_extended_firmware)(struct amvdec_session *sess, ++ const u8 *data, u32 len); ++ u32 (*num_pending_bufs)(struct amvdec_session *sess); ++ int (*can_recycle)(struct amvdec_core *core); ++ void (*recycle)(struct amvdec_core *core, u32 buf_idx); ++ void (*drain)(struct amvdec_session *sess); ++ void (*resume)(struct amvdec_session *sess); ++ const u8 * (*eos_sequence)(u32 *len); ++ irqreturn_t (*isr)(struct amvdec_session *sess); ++ irqreturn_t (*threaded_isr)(struct amvdec_session *sess); ++}; ++ ++/** ++ * struct amvdec_format - describes one of the OUTPUT (src) format supported ++ * ++ * @pixfmt: V4L2 pixel format ++ * @min_buffers: minimum amount of CAPTURE (dst) buffers ++ * @max_buffers: maximum amount of CAPTURE (dst) buffers ++ * @max_width: maximum picture width supported ++ * @max_height: maximum picture height supported ++ * @flags: enum flags associated with this pixfmt ++ * @vdec_ops: the VDEC operations that support this format ++ * @codec_ops: the codec operations that support this format ++ * @firmware_path: Path to the firmware that supports this format ++ * @pixfmts_cap: list of CAPTURE pixel formats available with pixfmt ++ */ ++struct amvdec_format { ++ u32 pixfmt; ++ u32 min_buffers; ++ u32 max_buffers; ++ u32 max_width; ++ u32 max_height; ++ u32 flags; ++ ++ struct amvdec_ops *vdec_ops; ++ struct amvdec_codec_ops *codec_ops; ++ ++ char *firmware_path; ++ u32 pixfmts_cap[4]; ++}; ++ ++enum amvdec_status { ++ STATUS_STOPPED, ++ STATUS_RUNNING, ++ STATUS_NEEDS_RESUME, ++}; ++ ++/** ++ * struct amvdec_session - decoding session parameters ++ * ++ * @core: reference to the vdec core struct ++ * @fh: v4l2 file handle ++ * @m2m_dev: v4l2 m2m device ++ * @m2m_ctx: v4l2 m2m context ++ * @lock: session lock ++ * @fmt_out: vdec pixel format for the OUTPUT queue ++ * @pixfmt_cap: V4L2 pixel format for the CAPTURE queue ++ * @width: current picture width ++ * @height: current picture height ++ * @colorspace: current colorspace ++ * @ycbcr_enc: current ycbcr_enc ++ * @quantization: current quantization ++ * @xfer_func: current transfer function ++ * @pixelaspect: Pixel Aspect Ratio reported by the decoder ++ * @esparser_queued_bufs: number of buffers currently queued into ESPARSER ++ * @esparser_queue_work: work struct for the ESPARSER to process src buffers ++ * @streamon_cap: stream on flag for capture queue ++ * @streamon_out: stream on flag for output queue ++ * @sequence_cap: capture sequence counter ++ * @should_stop: flag set if userspace signaled EOS via command ++ * or empty buffer ++ * @keyframe_found: flag set once a keyframe has been parsed ++ * @canvas_alloc: array of all the canvas IDs allocated ++ * @canvas_num: number of canvas IDs allocated ++ * @vififo_vaddr: virtual address for the VIFIFO ++ * @vififo_paddr: physical address for the VIFIFO ++ * @vififo_size: size of the VIFIFO dma alloc ++ * @bufs_recycle: list of buffers that need to be recycled ++ * @bufs_recycle_lock: lock for the bufs_recycle list ++ * @recycle_thread: task struct for the recycling thread ++ * @timestamps: chronological list of src timestamps ++ * @ts_spinlock: spinlock for the timestamps list ++ * @last_irq_jiffies: tracks last time the vdec triggered an IRQ ++ * @status: current decoding status ++ * @priv: codec private data ++ */ ++struct amvdec_session { ++ struct amvdec_core *core; ++ ++ struct v4l2_fh fh; ++ struct v4l2_m2m_dev *m2m_dev; ++ struct v4l2_m2m_ctx *m2m_ctx; ++ struct v4l2_ctrl_handler ctrl_handler; ++ struct mutex lock; ++ ++ const struct amvdec_format *fmt_out; ++ u32 pixfmt_cap; ++ ++ u32 width; ++ u32 height; ++ u32 colorspace; ++ u8 ycbcr_enc; ++ u8 quantization; ++ u8 xfer_func; ++ ++ struct v4l2_fract pixelaspect; ++ ++ atomic_t esparser_queued_bufs; ++ struct work_struct esparser_queue_work; ++ ++ unsigned int streamon_cap, streamon_out; ++ unsigned int sequence_cap; ++ unsigned int should_stop; ++ unsigned int keyframe_found; ++ unsigned int num_dst_bufs; ++ ++ u8 canvas_alloc[MAX_CANVAS]; ++ u32 canvas_num; ++ ++ void *vififo_vaddr; ++ dma_addr_t vififo_paddr; ++ u32 vififo_size; ++ ++ struct list_head bufs_recycle; ++ struct mutex bufs_recycle_lock; ++ struct task_struct *recycle_thread; ++ ++ struct list_head timestamps; ++ spinlock_t ts_spinlock; ++ ++ u64 last_irq_jiffies; ++ u32 last_offset; ++ u32 wrap_count; ++ u32 dpb_size; ++ ++ enum amvdec_status status; ++ void *priv; ++}; ++ ++u32 amvdec_get_output_size(struct amvdec_session *sess); ++ ++#endif +diff --git a/drivers/media/platform/meson/vdec/vdec_1.c b/drivers/media/platform/meson/vdec/vdec_1.c +new file mode 100644 +index 0000000000000..074767d4cb2c2 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_1.c +@@ -0,0 +1,229 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ * ++ * VDEC_1 is a video decoding block that allows decoding of ++ * MPEG 1/2/4, H.263, H.264, MJPEG, VC1 ++ */ ++ ++#include ++#include ++ ++#include "vdec_1.h" ++#include "vdec_helpers.h" ++#include "dos_regs.h" ++ ++/* AO Registers */ ++#define AO_RTI_GEN_PWR_SLEEP0 0xe8 ++#define AO_RTI_GEN_PWR_ISO0 0xec ++ #define GEN_PWR_VDEC_1 (BIT(3) | BIT(2)) ++ ++#define MC_SIZE (4096 * 4) ++ ++static int ++vdec_1_load_firmware(struct amvdec_session *sess, const char *fwname) ++{ ++ const struct firmware *fw; ++ struct amvdec_core *core = sess->core; ++ struct device *dev = core->dev_dec; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ static void *mc_addr; ++ static dma_addr_t mc_addr_map; ++ int ret; ++ u32 i = 1000; ++ ++ ret = request_firmware(&fw, fwname, dev); ++ if (ret < 0) ++ return -EINVAL; ++ ++ if (fw->size < MC_SIZE) { ++ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", ++ fw->size, MC_SIZE); ++ ret = -EINVAL; ++ goto release_firmware; ++ } ++ ++ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, ++ &mc_addr_map, GFP_KERNEL); ++ if (!mc_addr) { ++ ret = -ENOMEM; ++ goto release_firmware; ++ } ++ ++ memcpy(mc_addr, fw->data, MC_SIZE); ++ ++ amvdec_write_dos(core, MPSR, 0); ++ amvdec_write_dos(core, CPSR, 0); ++ ++ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31)); ++ ++ amvdec_write_dos(core, IMEM_DMA_ADR, mc_addr_map); ++ amvdec_write_dos(core, IMEM_DMA_COUNT, MC_SIZE / 4); ++ amvdec_write_dos(core, IMEM_DMA_CTRL, (0x8000 | (7 << 16))); ++ ++ while (--i && amvdec_read_dos(core, IMEM_DMA_CTRL) & 0x8000); ++ ++ if (i == 0) { ++ dev_err(dev, "Firmware load fail (DMA hang?)\n"); ++ ret = -EINVAL; ++ goto free_mc; ++ } ++ ++ if (codec_ops->load_extended_firmware) ++ ret = codec_ops->load_extended_firmware(sess, ++ fw->data + MC_SIZE, ++ fw->size - MC_SIZE); ++ ++free_mc: ++ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); ++release_firmware: ++ release_firmware(fw); ++ return ret; ++} ++ ++int vdec_1_stbuf_power_up(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ amvdec_write_dos(core, VLD_MEM_VIFIFO_CONTROL, 0); ++ amvdec_write_dos(core, VLD_MEM_VIFIFO_WRAP_COUNT, 0); ++ amvdec_write_dos(core, POWER_CTL_VLD, BIT(4)); ++ ++ amvdec_write_dos(core, VLD_MEM_VIFIFO_START_PTR, sess->vififo_paddr); ++ amvdec_write_dos(core, VLD_MEM_VIFIFO_CURR_PTR, sess->vififo_paddr); ++ amvdec_write_dos(core, VLD_MEM_VIFIFO_END_PTR, ++ sess->vififo_paddr + sess->vififo_size - 8); ++ ++ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1); ++ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1); ++ ++ amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL); ++ amvdec_write_dos(core, VLD_MEM_VIFIFO_WP, sess->vififo_paddr); ++ ++ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); ++ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); ++ ++ amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, ++ (0x11 << MEM_FIFO_CNT_BIT) | MEM_FILL_ON_LEVEL | ++ MEM_CTRL_FILL_EN | MEM_CTRL_EMPTY_EN); ++ ++ return 0; ++} ++ ++static void vdec_1_conf_esparser(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ /* VDEC_1 specific ESPARSER stuff */ ++ amvdec_write_dos(core, DOS_GEN_CTRL0, 0); ++ amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); ++ amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); ++} ++ ++static u32 vdec_1_vififo_level(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ return amvdec_read_dos(core, VLD_MEM_VIFIFO_LEVEL); ++} ++ ++static int vdec_1_stop(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ ++ amvdec_write_dos(core, MPSR, 0); ++ amvdec_write_dos(core, CPSR, 0); ++ amvdec_write_dos(core, ASSIST_MBOX1_MASK, 0); ++ ++ amvdec_write_dos(core, DOS_SW_RESET0, BIT(12) | BIT(11)); ++ amvdec_write_dos(core, DOS_SW_RESET0, 0); ++ amvdec_read_dos(core, DOS_SW_RESET0); ++ ++ /* enable vdec1 isolation */ ++ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc0); ++ /* power off vdec1 memories */ ++ amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0xffffffff); ++ /* power off vdec1 */ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VDEC_1, GEN_PWR_VDEC_1); ++ ++ clk_disable_unprepare(core->vdec_1_clk); ++ ++ if (sess->priv) ++ codec_ops->stop(sess); ++ ++ return 0; ++} ++ ++static int vdec_1_start(struct amvdec_session *sess) ++{ ++ int ret; ++ struct amvdec_core *core = sess->core; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ ++ /* Configure the vdec clk to the maximum available */ ++ clk_set_rate(core->vdec_1_clk, 666666666); ++ ret = clk_prepare_enable(core->vdec_1_clk); ++ if (ret) ++ return ret; ++ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VDEC_1, 0); ++ udelay(10); ++ ++ /* Reset VDEC1 */ ++ amvdec_write_dos(core, DOS_SW_RESET0, 0xfffffffc); ++ amvdec_write_dos(core, DOS_SW_RESET0, 0x00000000); ++ ++ amvdec_write_dos(core, DOS_GCLK_EN0, 0x3ff); ++ ++ /* enable VDEC Memories */ ++ amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0); ++ /* Remove VDEC1 Isolation */ ++ regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0); ++ /* Reset DOS top registers */ ++ amvdec_write_dos(core, DOS_VDEC_MCRCC_STALL_CTRL, 0); ++ ++ amvdec_write_dos(core, GCLK_EN, 0x3ff); ++ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31)); ++ ++ vdec_1_stbuf_power_up(sess); ++ ++ ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path); ++ if (ret) ++ goto stop; ++ ++ ret = codec_ops->start(sess); ++ if (ret) ++ goto stop; ++ ++ /* Enable IRQ */ ++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); ++ amvdec_write_dos(core, ASSIST_MBOX1_MASK, 1); ++ ++ /* Enable 2-plane output */ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) ++ amvdec_write_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17)); ++ else ++ amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17)); ++ ++ /* Enable firmware processor */ ++ amvdec_write_dos(core, MPSR, 1); ++ /* Let the firmware settle */ ++ udelay(10); ++ ++ return 0; ++ ++stop: ++ vdec_1_stop(sess); ++ return ret; ++} ++ ++struct amvdec_ops vdec_1_ops = { ++ .start = vdec_1_start, ++ .stop = vdec_1_stop, ++ .conf_esparser = vdec_1_conf_esparser, ++ .vififo_level = vdec_1_vififo_level, ++}; +diff --git a/drivers/media/platform/meson/vdec/vdec_1.h b/drivers/media/platform/meson/vdec/vdec_1.h +new file mode 100644 +index 0000000000000..042d930c40d77 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_1.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_VDEC_1_H_ ++#define __MESON_VDEC_VDEC_1_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_ops vdec_1_ops; ++ ++#endif +diff --git a/drivers/media/platform/meson/vdec/vdec_ctrls.c b/drivers/media/platform/meson/vdec/vdec_ctrls.c +new file mode 100644 +index 0000000000000..d5d6b1b97aa54 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_ctrls.c +@@ -0,0 +1,51 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#include "vdec_ctrls.h" ++ ++static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct amvdec_session *sess = ++ container_of(ctrl->handler, struct amvdec_session, ctrl_handler); ++ ++ switch (ctrl->id) { ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ctrl->val = sess->dpb_size; ++ break; ++ default: ++ return -EINVAL; ++ }; ++ ++ return 0; ++} ++ ++static const struct v4l2_ctrl_ops vdec_ctrl_ops = { ++ .g_volatile_ctrl = vdec_op_g_volatile_ctrl, ++}; ++ ++int amvdec_init_ctrls(struct v4l2_ctrl_handler *ctrl_handler) ++{ ++ int ret; ++ struct v4l2_ctrl *ctrl; ++ ++ ret = v4l2_ctrl_handler_init(ctrl_handler, 1); ++ if (ret) ++ return ret; ++ ++ ctrl = v4l2_ctrl_new_std(ctrl_handler, &vdec_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1); ++ if (ctrl) ++ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; ++ ++ ret = ctrl_handler->error; ++ if (ret) { ++ v4l2_ctrl_handler_free(ctrl_handler); ++ return ret; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(amvdec_init_ctrls); +diff --git a/drivers/media/platform/meson/vdec/vdec_ctrls.h b/drivers/media/platform/meson/vdec/vdec_ctrls.h +new file mode 100644 +index 0000000000000..91bf0aabc17e4 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_ctrls.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CTRLS_H_ ++#define __MESON_VDEC_CTRLS_H_ ++ ++#include "vdec.h" ++ ++int amvdec_init_ctrls(struct v4l2_ctrl_handler *ctrl_handler); ++ ++#endif +diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c +new file mode 100644 +index 0000000000000..5adf9a378b32c +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_helpers.c +@@ -0,0 +1,441 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "vdec_helpers.h" ++ ++#define NUM_CANVAS_NV12 2 ++#define NUM_CANVAS_YUV420 3 ++ ++u32 amvdec_read_dos(struct amvdec_core *core, u32 reg) ++{ ++ return readl_relaxed(core->dos_base + reg); ++} ++EXPORT_SYMBOL_GPL(amvdec_read_dos); ++ ++void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val) ++{ ++ writel_relaxed(val, core->dos_base + reg); ++} ++EXPORT_SYMBOL_GPL(amvdec_write_dos); ++ ++void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val) ++{ ++ amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) | val); ++} ++EXPORT_SYMBOL_GPL(amvdec_write_dos_bits); ++ ++void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val) ++{ ++ amvdec_write_dos(core, reg, amvdec_read_dos(core, reg) & ~val); ++} ++EXPORT_SYMBOL_GPL(amvdec_clear_dos_bits); ++ ++u32 amvdec_read_parser(struct amvdec_core *core, u32 reg) ++{ ++ return readl_relaxed(core->esparser_base + reg); ++} ++EXPORT_SYMBOL_GPL(amvdec_read_parser); ++ ++void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val) ++{ ++ writel_relaxed(val, core->esparser_base + reg); ++} ++EXPORT_SYMBOL_GPL(amvdec_write_parser); ++ ++static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id) ++{ ++ int ret; ++ ++ if (sess->canvas_num >= MAX_CANVAS) { ++ dev_err(sess->core->dev, "Reached max number of canvas\n"); ++ return -ENOMEM; ++ } ++ ++ ret = meson_canvas_alloc(sess->core->canvas, canvas_id); ++ if (ret) ++ return ret; ++ ++ sess->canvas_alloc[sess->canvas_num++] = *canvas_id; ++ return 0; ++} ++ ++static int set_canvas_yuv420m(struct amvdec_session *sess, ++ struct vb2_buffer *vb, u32 width, ++ u32 height, u32 reg) ++{ ++ struct amvdec_core *core = sess->core; ++ u8 canvas_id[NUM_CANVAS_YUV420]; /* Y U V */ ++ dma_addr_t buf_paddr[NUM_CANVAS_YUV420]; /* Y U V */ ++ int ret, i; ++ ++ for (i = 0; i < NUM_CANVAS_YUV420; ++i) { ++ ret = canvas_alloc(sess, &canvas_id[i]); ++ if (ret) ++ return ret; ++ ++ buf_paddr[i] = ++ vb2_dma_contig_plane_dma_addr(vb, i); ++ } ++ ++ /* Y plane */ ++ meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0], ++ width, height, MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR, ++ MESON_CANVAS_ENDIAN_SWAP64); ++ ++ /* U plane */ ++ meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1], ++ width / 2, height / 2, MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR, ++ MESON_CANVAS_ENDIAN_SWAP64); ++ ++ /* V plane */ ++ meson_canvas_config(core->canvas, canvas_id[2], buf_paddr[2], ++ width / 2, height / 2, MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR, ++ MESON_CANVAS_ENDIAN_SWAP64); ++ ++ amvdec_write_dos(core, reg, ++ ((canvas_id[2]) << 16) | ++ ((canvas_id[1]) << 8) | ++ (canvas_id[0])); ++ ++ return 0; ++} ++ ++static int set_canvas_nv12m(struct amvdec_session *sess, ++ struct vb2_buffer *vb, u32 width, ++ u32 height, u32 reg) ++{ ++ struct amvdec_core *core = sess->core; ++ u8 canvas_id[NUM_CANVAS_NV12]; /* Y U/V */ ++ dma_addr_t buf_paddr[NUM_CANVAS_NV12]; /* Y U/V */ ++ int ret, i; ++ ++ for (i = 0; i < NUM_CANVAS_NV12; ++i) { ++ ret = canvas_alloc(sess, &canvas_id[i]); ++ if (ret) ++ return ret; ++ ++ buf_paddr[i] = ++ vb2_dma_contig_plane_dma_addr(vb, i); ++ } ++ ++ /* Y plane */ ++ meson_canvas_config(core->canvas, canvas_id[0], buf_paddr[0], ++ width, height, MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR, ++ MESON_CANVAS_ENDIAN_SWAP64); ++ ++ /* U/V plane */ ++ meson_canvas_config(core->canvas, canvas_id[1], buf_paddr[1], ++ width, height / 2, MESON_CANVAS_WRAP_NONE, ++ MESON_CANVAS_BLKMODE_LINEAR, ++ MESON_CANVAS_ENDIAN_SWAP64); ++ ++ amvdec_write_dos(core, reg, ++ ((canvas_id[1]) << 16) | ++ ((canvas_id[1]) << 8) | ++ (canvas_id[0])); ++ ++ return 0; ++} ++ ++int amvdec_set_canvases(struct amvdec_session *sess, ++ u32 reg_base[], u32 reg_num[]) ++{ ++ struct v4l2_m2m_buffer *buf; ++ u32 pixfmt = sess->pixfmt_cap; ++ u32 width = ALIGN(sess->width, 64); ++ u32 height = ALIGN(sess->height, 64); ++ u32 reg_cur = reg_base[0]; ++ u32 reg_num_cur = 0; ++ u32 reg_base_cur = 0; ++ int ret; ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ if (!reg_base[reg_base_cur]) ++ return -EINVAL; ++ ++ reg_cur = reg_base[reg_base_cur] + reg_num_cur * 4; ++ ++ switch (pixfmt) { ++ case V4L2_PIX_FMT_NV12M: ++ ret = set_canvas_nv12m(sess, &buf->vb.vb2_buf, width, ++ height, reg_cur); ++ if (ret) ++ return ret; ++ break; ++ case V4L2_PIX_FMT_YUV420M: ++ ret = set_canvas_yuv420m(sess, &buf->vb.vb2_buf, width, ++ height, reg_cur); ++ if (ret) ++ return ret; ++ break; ++ default: ++ dev_err(sess->core->dev, "Unsupported pixfmt %08X\n", ++ pixfmt); ++ return -EINVAL; ++ } ++ ++ reg_num_cur++; ++ if (reg_num_cur >= reg_num[reg_base_cur]) { ++ reg_base_cur++; ++ reg_num_cur = 0; ++ } ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(amvdec_set_canvases); ++ ++void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset) ++{ ++ struct amvdec_timestamp *new_ts, *tmp; ++ unsigned long flags; ++ ++ new_ts = kmalloc(sizeof(*new_ts), GFP_KERNEL); ++ new_ts->ts = ts; ++ new_ts->offset = offset; ++ ++ spin_lock_irqsave(&sess->ts_spinlock, flags); ++ ++ if (list_empty(&sess->timestamps)) ++ goto add_tail; ++ ++ list_for_each_entry(tmp, &sess->timestamps, list) { ++ if (ts <= tmp->ts) { ++ list_add_tail(&new_ts->list, &tmp->list); ++ goto unlock; ++ } ++ } ++ ++add_tail: ++ list_add_tail(&new_ts->list, &sess->timestamps); ++unlock: ++ spin_unlock_irqrestore(&sess->ts_spinlock, flags); ++} ++EXPORT_SYMBOL_GPL(amvdec_add_ts_reorder); ++ ++void amvdec_remove_ts(struct amvdec_session *sess, u64 ts) ++{ ++ struct amvdec_timestamp *tmp; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sess->ts_spinlock, flags); ++ list_for_each_entry(tmp, &sess->timestamps, list) { ++ if (tmp->ts == ts) { ++ list_del(&tmp->list); ++ kfree(tmp); ++ goto unlock; ++ } ++ } ++ dev_warn(sess->core->dev_dec, ++ "Couldn't remove buffer with timestamp %llu from list\n", ts); ++ ++unlock: ++ spin_unlock_irqrestore(&sess->ts_spinlock, flags); ++} ++EXPORT_SYMBOL_GPL(amvdec_remove_ts); ++ ++static void dst_buf_done(struct amvdec_session *sess, ++ struct vb2_v4l2_buffer *vbuf, ++ u32 field, ++ u64 timestamp) ++{ ++ struct device *dev = sess->core->dev_dec; ++ u32 output_size = amvdec_get_output_size(sess); ++ ++ switch (sess->pixfmt_cap) { ++ case V4L2_PIX_FMT_NV12M: ++ vbuf->vb2_buf.planes[0].bytesused = output_size; ++ vbuf->vb2_buf.planes[1].bytesused = output_size / 2; ++ break; ++ case V4L2_PIX_FMT_YUV420M: ++ vbuf->vb2_buf.planes[0].bytesused = output_size; ++ vbuf->vb2_buf.planes[1].bytesused = output_size / 4; ++ vbuf->vb2_buf.planes[2].bytesused = output_size / 4; ++ break; ++ } ++ ++ vbuf->vb2_buf.timestamp = timestamp; ++ vbuf->sequence = sess->sequence_cap++; ++ ++ if (sess->should_stop && ++ atomic_read(&sess->esparser_queued_bufs) <= 2) { ++ const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; ++ ++ dev_dbg(dev, "Signaling EOS\n"); ++ v4l2_event_queue_fh(&sess->fh, &ev); ++ vbuf->flags |= V4L2_BUF_FLAG_LAST; ++ } else if (sess->should_stop) ++ dev_dbg(dev, "should_stop, %u bufs remain\n", ++ atomic_read(&sess->esparser_queued_bufs)); ++ ++ dev_dbg(dev, "Buffer %u done\n", vbuf->vb2_buf.index); ++ vbuf->field = field; ++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); ++ ++ /* Buffer done probably means the vififo got freed */ ++ schedule_work(&sess->esparser_queue_work); ++} ++ ++void amvdec_dst_buf_done(struct amvdec_session *sess, ++ struct vb2_v4l2_buffer *vbuf, u32 field) ++{ ++ struct device *dev = sess->core->dev_dec; ++ struct amvdec_timestamp *tmp; ++ struct list_head *timestamps = &sess->timestamps; ++ u64 timestamp; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sess->ts_spinlock, flags); ++ if (list_empty(timestamps)) { ++ dev_err(dev, "Buffer %u done but list is empty\n", ++ vbuf->vb2_buf.index); ++ ++ v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); ++ spin_unlock_irqrestore(&sess->ts_spinlock, flags); ++ return; ++ } ++ ++ tmp = list_first_entry(timestamps, struct amvdec_timestamp, list); ++ timestamp = tmp->ts; ++ list_del(&tmp->list); ++ kfree(tmp); ++ spin_unlock_irqrestore(&sess->ts_spinlock, flags); ++ ++ dst_buf_done(sess, vbuf, field, timestamp); ++ atomic_dec(&sess->esparser_queued_bufs); ++} ++EXPORT_SYMBOL_GPL(amvdec_dst_buf_done); ++ ++static void amvdec_dst_buf_done_offset(struct amvdec_session *sess, ++ struct vb2_v4l2_buffer *vbuf, ++ u32 offset, ++ u32 field) ++{ ++ struct device *dev = sess->core->dev_dec; ++ struct amvdec_timestamp *match = NULL; ++ struct amvdec_timestamp *tmp, *n; ++ u64 timestamp = 0; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&sess->ts_spinlock, flags); ++ ++ /* Look for our vififo offset to get the corresponding timestamp. */ ++ list_for_each_entry_safe(tmp, n, &sess->timestamps, list) { ++ s64 delta = (s64)offset - tmp->offset; ++ ++ /* Offsets reported by codecs usually differ slightly, ++ * so we need some wiggle room. ++ * 4KiB being the minimum packet size, there is no risk here. ++ */ ++ if (delta > (-1 * (s32)SZ_4K) && delta < SZ_4K) { ++ match = tmp; ++ break; ++ } ++ ++ /* Delete any timestamp entry that appears before our target ++ * (not all src packets/timestamps lead to a frame) ++ */ ++ if (delta > 0 || delta < -1 * (s32)sess->vififo_size) { ++ atomic_dec(&sess->esparser_queued_bufs); ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++ } ++ ++ if (!match) { ++ dev_dbg(dev, "Buffer %u done but can't match offset (%08X)\n", ++ vbuf->vb2_buf.index, offset); ++ } else { ++ timestamp = match->ts; ++ list_del(&match->list); ++ kfree(match); ++ } ++ spin_unlock_irqrestore(&sess->ts_spinlock, flags); ++ ++ dst_buf_done(sess, vbuf, field, timestamp); ++ if (match) ++ atomic_dec(&sess->esparser_queued_bufs); ++} ++ ++void amvdec_dst_buf_done_idx(struct amvdec_session *sess, ++ u32 buf_idx, u32 offset, u32 field) ++{ ++ struct vb2_v4l2_buffer *vbuf; ++ struct device *dev = sess->core->dev_dec; ++ ++ vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, buf_idx); ++ if (!vbuf) { ++ dev_err(dev, ++ "Buffer %u done but it doesn't exist in m2m_ctx\n", ++ buf_idx); ++ return; ++ } ++ ++ if (offset != -1) ++ amvdec_dst_buf_done_offset(sess, vbuf, offset, field); ++ else ++ amvdec_dst_buf_done(sess, vbuf, field); ++} ++EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_idx); ++ ++void amvdec_set_par_from_dar(struct amvdec_session *sess, ++ u32 dar_num, u32 dar_den) ++{ ++ u32 div; ++ ++ sess->pixelaspect.numerator = sess->height * dar_num; ++ sess->pixelaspect.denominator = sess->width * dar_den; ++ div = gcd(sess->pixelaspect.numerator, sess->pixelaspect.denominator); ++ sess->pixelaspect.numerator /= div; ++ sess->pixelaspect.denominator /= div; ++} ++EXPORT_SYMBOL_GPL(amvdec_set_par_from_dar); ++ ++void amvdec_src_change(struct amvdec_session *sess, u32 width, ++ u32 height, u32 dpb_size) ++{ ++ static const struct v4l2_event ev = { ++ .type = V4L2_EVENT_SOURCE_CHANGE, ++ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION }; ++ ++ sess->dpb_size = dpb_size; ++ ++ /* Check if the capture queue is already configured well for our ++ * usecase. If so, keep decoding with it and do not send the event ++ */ ++ if (sess->width == width && ++ sess->height == height && ++ dpb_size <= sess->num_dst_bufs) { ++ sess->fmt_out->codec_ops->resume(sess); ++ return; ++ } ++ ++ sess->width = width; ++ sess->height = height; ++ sess->status = STATUS_NEEDS_RESUME; ++ ++ dev_dbg(sess->core->dev, "Res. changed (%ux%u), DPB size %u\n", ++ width, height, dpb_size); ++ v4l2_event_queue_fh(&sess->fh, &ev); ++} ++EXPORT_SYMBOL_GPL(amvdec_src_change); ++ ++void amvdec_abort(struct amvdec_session *sess) ++{ ++ dev_info(sess->core->dev, "Aborting decoding session!\n"); ++ vb2_queue_error(&sess->m2m_ctx->cap_q_ctx.q); ++ vb2_queue_error(&sess->m2m_ctx->out_q_ctx.q); ++} ++EXPORT_SYMBOL_GPL(amvdec_abort); +diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h +new file mode 100644 +index 0000000000000..87b39e048a0fc +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_helpers.h +@@ -0,0 +1,80 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_HELPERS_H_ ++#define __MESON_VDEC_HELPERS_H_ ++ ++#include "vdec.h" ++ ++/** ++ * amvdec_set_canvases() - Map VB2 buffers to canvases ++ * ++ * @sess: current session ++ * @reg_base: Registry bases of where to write the canvas indexes ++ * @reg_num: number of contiguous registers after each reg_base (including it) ++ */ ++int amvdec_set_canvases(struct amvdec_session *sess, ++ u32 reg_base[], u32 reg_num[]); ++ ++/* Helpers to read/write to the various IPs (DOS, PARSER) */ ++u32 amvdec_read_dos(struct amvdec_core *core, u32 reg); ++void amvdec_write_dos(struct amvdec_core *core, u32 reg, u32 val); ++void amvdec_write_dos_bits(struct amvdec_core *core, u32 reg, u32 val); ++void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val); ++u32 amvdec_read_parser(struct amvdec_core *core, u32 reg); ++void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val); ++ ++/** ++ * amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding ++ * ++ * @sess: current session ++ * @buf_idx: hardware buffer index ++ * @offset: VIFIFO bitstream offset corresponding to the buffer ++ * @field: V4L2 interlaced field ++ */ ++void amvdec_dst_buf_done_idx(struct amvdec_session *sess, u32 buf_idx, ++ u32 offset, u32 field); ++void amvdec_dst_buf_done(struct amvdec_session *sess, ++ struct vb2_v4l2_buffer *vbuf, u32 field); ++ ++/** ++ * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order ++ * ++ * @sess: current session ++ * @ts: timestamp to add ++ * @offset: offset in the VIFIFO where the associated packet was written ++ */ ++void amvdec_add_ts_reorder(struct amvdec_session *sess, u64 ts, u32 offset); ++void amvdec_remove_ts(struct amvdec_session *sess, u64 ts); ++ ++/** ++ * amvdec_set_par_from_dar() - Set Pixel Aspect Ratio from Display Aspect Ratio ++ * ++ * @sess: current session ++ * @dar_num: numerator of the DAR ++ * @dar_den: denominator of the DAR ++ */ ++void amvdec_set_par_from_dar(struct amvdec_session *sess, ++ u32 dar_num, u32 dar_den); ++ ++/** ++ * amvdec_src_change() - Notify new resolution/DPB size to the core ++ * ++ * @sess: current session ++ * @width: picture width detected by the hardware ++ * @height: picture height detected by the hardware ++ * @dpb_size: Decoded Picture Buffer size (= amount of buffers for decoding) ++ */ ++void amvdec_src_change(struct amvdec_session *sess, u32 width, ++ u32 height, u32 dpb_size); ++ ++/** ++ * amvdec_abort() - Abort the current decoding session ++ * ++ * @sess: current session ++ */ ++void amvdec_abort(struct amvdec_session *sess); ++#endif +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c +new file mode 100644 +index 0000000000000..bb8016266ab20 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_platform.c +@@ -0,0 +1,107 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#include "vdec_platform.h" ++#include "vdec.h" ++ ++#include "vdec_1.h" ++#include "codec_mpeg12.h" ++ ++static const struct amvdec_format vdec_formats_gxbb[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_MPEG1, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG2, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, ++}; ++ ++static const struct amvdec_format vdec_formats_gxl[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_MPEG1, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG2, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, ++}; ++ ++static const struct amvdec_format vdec_formats_gxm[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_MPEG1, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG2, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, ++}; ++ ++const struct vdec_platform vdec_platform_gxbb = { ++ .formats = vdec_formats_gxbb, ++ .num_formats = ARRAY_SIZE(vdec_formats_gxbb), ++ .revision = VDEC_REVISION_GXBB, ++}; ++ ++const struct vdec_platform vdec_platform_gxl = { ++ .formats = vdec_formats_gxl, ++ .num_formats = ARRAY_SIZE(vdec_formats_gxl), ++ .revision = VDEC_REVISION_GXL, ++}; ++ ++const struct vdec_platform vdec_platform_gxm = { ++ .formats = vdec_formats_gxm, ++ .num_formats = ARRAY_SIZE(vdec_formats_gxm), ++ .revision = VDEC_REVISION_GXM, ++}; +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.h b/drivers/media/platform/meson/vdec/vdec_platform.h +new file mode 100644 +index 0000000000000..f6025326db1d6 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_platform.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_PLATFORM_H_ ++#define __MESON_VDEC_PLATFORM_H_ ++ ++#include "vdec.h" ++ ++struct amvdec_format; ++ ++enum vdec_revision { ++ VDEC_REVISION_GXBB, ++ VDEC_REVISION_GXL, ++ VDEC_REVISION_GXM, ++}; ++ ++struct vdec_platform { ++ const struct amvdec_format *formats; ++ const u32 num_formats; ++ enum vdec_revision revision; ++}; ++ ++extern const struct vdec_platform vdec_platform_gxbb; ++extern const struct vdec_platform vdec_platform_gxm; ++extern const struct vdec_platform vdec_platform_gxl; ++ ++#endif + +From d4c918a591d5cc7a7941d20d53e76b7043246485 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Mon, 25 Mar 2019 10:14:41 +0100 +Subject: [PATCH 206/249] WIP: MAINTAINERS: Add meson video decoder + +Add an entry for the meson video decoder for amlogic SoCs. + +Signed-off-by: Maxime Jourdan +--- + MAINTAINERS | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index ddc31a0716ab8..f620e30ba67cb 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -10068,6 +10068,14 @@ S: Maintained + F: drivers/mtd/nand/raw/meson_* + F: Documentation/devicetree/bindings/mtd/amlogic,meson-nand.txt + ++MESON VIDEO DECODER DRIVER FOR AMLOGIC SOCS ++M: Maxime Jourdan ++L: linux-media@lists.freedesktop.org ++L: linux-amlogic@lists.infradead.org ++S: Supported ++F: drivers/media/platform/meson/vdec/ ++T: git git://linuxtv.org/media_tree.git ++ + METHODE UDPU SUPPORT + M: Vladimir Vid + S: Maintained + +From 2f282c662b80bd2910b0186c5d82373f9b805ffe Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 15:24:02 +0200 +Subject: [PATCH 207/249] WIP: arm64: dts: meson-gx: add vdec entry + +Add the video decoder dts entry + +Signed-off-by: Maxime Jourdan +--- + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index b7240ec8a4f5b..be7096869b2e7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -437,6 +437,20 @@ + }; + }; + ++ vdec: video-decoder@c8820000 { ++ compatible = "amlogic,gx-vdec"; ++ reg = <0x0 0xc8820000 0x0 0x10000>, ++ <0x0 0xc110a580 0x0 0xe4>; ++ reg-names = "dos", "esparser"; ++ ++ interrupts = , ++ ; ++ interrupt-names = "vdec", "esparser"; ++ ++ amlogic,ao-sysctrl = <&sysctrl_AO>; ++ amlogic,canvas = <&canvas>; ++ }; ++ + periphs: periphs@c8834000 { + compatible = "simple-bus"; + reg = <0x0 0xc8834000 0x0 0x2000>; + +From 5de4d34650c1555c88ac01ae36f3e14e3ca00731 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 15:24:22 +0200 +Subject: [PATCH 208/249] WIP: arm64: dts: meson: add vdec entries + +This enables the video decoder for gxbb, gxl and gxm chips + +Signed-off-by: Maxime Jourdan +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 11 +++++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 11 +++++++++++ + arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 4 ++++ + 3 files changed, 26 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index a60d3652beee1..e900a93960fb6 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -830,3 +830,14 @@ + compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu"; + power-domains = <&pwrc_vpu>; + }; ++ ++&vdec { ++ compatible = "amlogic,gxbb-vdec"; ++ clocks = <&clkc CLKID_DOS_PARSER>, ++ <&clkc CLKID_DOS>, ++ <&clkc CLKID_VDEC_1>, ++ <&clkc CLKID_VDEC_HEVC>; ++ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; ++ resets = <&reset RESET_PARSER>; ++ reset-names = "esparser"; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index 3093ae421b177..1d105047661ed 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -833,3 +833,14 @@ + compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu"; + power-domains = <&pwrc_vpu>; + }; ++ ++&vdec { ++ compatible = "amlogic,gxl-vdec"; ++ clocks = <&clkc CLKID_DOS_PARSER>, ++ <&clkc CLKID_DOS>, ++ <&clkc CLKID_VDEC_1>, ++ <&clkc CLKID_VDEC_HEVC>; ++ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc"; ++ resets = <&reset RESET_PARSER>; ++ reset-names = "esparser"; ++}; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi +index ed3a3d5adf316..d74cb4993bae2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi +@@ -117,3 +117,7 @@ + &dwc3 { + phys = <&usb3_phy>, <&usb2_phy0>, <&usb2_phy1>, <&usb2_phy2>; + }; ++ ++&vdec { ++ compatible = "amlogic,gxm-vdec"; ++}; + +From 8d98a30268b99d94ae7affdb58f0b561cb9ec562 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 15:42:56 +0200 +Subject: [PATCH 209/249] WIP: media: meson: vdec: add H.264 decoding support + +Add support for V4L2_PIX_FMT_H264 +--- + drivers/media/platform/meson/vdec/Makefile | 2 +- + .../media/platform/meson/vdec/codec_h264.c | 478 ++++++++++++++++++ + .../media/platform/meson/vdec/codec_h264.h | 13 + + .../media/platform/meson/vdec/vdec_platform.c | 31 ++ + 4 files changed, 523 insertions(+), 1 deletion(-) + create mode 100644 drivers/media/platform/meson/vdec/codec_h264.c + create mode 100644 drivers/media/platform/meson/vdec/codec_h264.h + +diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile +index eba86083aadb4..01dc9603abdd7 100644 +--- a/drivers/media/platform/meson/vdec/Makefile ++++ b/drivers/media/platform/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o +-meson-vdec-objs += codec_mpeg12.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/media/platform/meson/vdec/codec_h264.c b/drivers/media/platform/meson/vdec/codec_h264.c +new file mode 100644 +index 0000000000000..6ac0115afaa35 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_h264.c +@@ -0,0 +1,478 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "vdec_helpers.h" ++#include "dos_regs.h" ++ ++#define SIZE_EXT_FW (20 * SZ_1K) ++#define SIZE_WORKSPACE 0x1ee000 ++#define SIZE_SEI (8 * SZ_1K) ++ ++/* Offset added by the firmware which must be substracted ++ * from the workspace phyaddr ++ */ ++#define WORKSPACE_BUF_OFFSET 0x1000000 ++ ++/* ISR status */ ++#define CMD_MASK GENMASK(7, 0) ++#define CMD_SRC_CHANGE 1 ++#define CMD_FRAMES_READY 2 ++#define CMD_FATAL_ERROR 6 ++#define CMD_BAD_WIDTH 7 ++#define CMD_BAD_HEIGHT 8 ++ ++#define SEI_DATA_READY BIT(15) ++ ++/* Picture type */ ++#define PIC_TOP_BOT 5 ++#define PIC_BOT_TOP 6 ++ ++/* Size of Motion Vector per macroblock */ ++#define MB_MV_SIZE 96 ++ ++/* Frame status data */ ++#define PIC_STRUCT_BIT 5 ++#define PIC_STRUCT_MASK GENMASK(2, 0) ++#define BUF_IDX_MASK GENMASK(4, 0) ++#define ERROR_FLAG BIT(9) ++#define OFFSET_BIT 16 ++#define OFFSET_MASK GENMASK(15, 0) ++ ++/* Bitstream parsed data */ ++#define MB_TOTAL_BIT 8 ++#define MB_TOTAL_MASK GENMASK(15, 0) ++#define MB_WIDTH_MASK GENMASK(7, 0) ++#define MAX_REF_BIT 24 ++#define MAX_REF_MASK GENMASK(6, 0) ++#define AR_IDC_BIT 16 ++#define AR_IDC_MASK GENMASK(7, 0) ++#define AR_PRESENT_FLAG BIT(0) ++#define AR_EXTEND 0xff ++ ++/* Buffer to send to the ESPARSER to signal End Of Stream for H.264. ++ * This is a 16x16 encoded picture that will trigger drain firmware-side. ++ * There is no known alternative. ++ */ ++static const u8 eos_sequence[SZ_1K] = { ++ 0x00, 0x00, 0x00, 0x01, 0x06, 0x05, 0xff, 0xe4, 0xdc, 0x45, 0xe9, 0xbd, ++ 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef, ++ 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, 0x65, 0x20, ++ 0x36, 0x37, 0x20, 0x72, 0x31, 0x31, 0x33, 0x30, 0x20, 0x38, 0x34, 0x37, ++ 0x35, 0x39, 0x37, 0x37, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, ++ 0x2f, 0x4d, 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, ++ 0x63, 0x6f, 0x64, 0x65, 0x63, 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, ++ 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, 0x33, 0x2d, 0x32, 0x30, ++ 0x30, 0x39, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, ++ 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, ++ 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, ++ 0x6d, 0x6c, 0x20, 0x2d, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, ++ 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, 0x31, 0x20, 0x72, 0x65, ++ 0x66, 0x3d, 0x31, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3d, ++ 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, ++ 0x65, 0x3d, 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, ++ 0x6d, 0x65, 0x3d, 0x68, 0x65, 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, ++ 0x3d, 0x36, 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, ++ 0x30, 0x3a, 0x30, 0x2e, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, ++ 0x72, 0x65, 0x66, 0x3d, 0x30, 0x20, 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, ++ 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, ++ 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, ++ 0x73, 0x3d, 0x30, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, ++ 0x20, 0x63, 0x71, 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, ++ 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, 0x2c, 0x31, 0x31, 0x20, 0x63, 0x68, ++ 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, 0x73, ++ 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, ++ 0x73, 0x3d, 0x31, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x63, ++ 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x6d, 0x62, 0x61, 0x66, ++ 0x66, 0x3d, 0x30, 0x20, 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, ++ 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, ++ 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, ++ 0x32, 0x35, 0x20, 0x73, 0x63, 0x65, 0x6e, 0x65, 0x63, 0x75, 0x74, 0x3d, ++ 0x34, 0x30, 0x20, 0x72, 0x63, 0x3d, 0x61, 0x62, 0x72, 0x20, 0x62, 0x69, ++ 0x74, 0x72, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x30, 0x20, 0x72, 0x61, 0x74, ++ 0x65, 0x74, 0x6f, 0x6c, 0x3d, 0x31, 0x2e, 0x30, 0x20, 0x71, 0x63, 0x6f, ++ 0x6d, 0x70, 0x3d, 0x30, 0x2e, 0x36, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x69, ++ 0x6e, 0x3d, 0x31, 0x30, 0x20, 0x71, 0x70, 0x6d, 0x61, 0x78, 0x3d, 0x35, ++ 0x31, 0x20, 0x71, 0x70, 0x73, 0x74, 0x65, 0x70, 0x3d, 0x34, 0x20, 0x69, ++ 0x70, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x3d, 0x31, 0x2e, 0x34, 0x30, ++ 0x20, 0x61, 0x71, 0x3d, 0x31, 0x3a, 0x31, 0x2e, 0x30, 0x30, 0x00, 0x80, ++ 0x00, 0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0a, 0x9a, 0x74, 0xf4, 0x20, ++ 0x00, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x06, 0x51, 0xe2, 0x44, 0xd4, ++ 0x00, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x00, 0x01, ++ 0x65, 0x88, 0x80, 0x20, 0x00, 0x08, 0x7f, 0xea, 0x6a, 0xe2, 0x99, 0xb6, ++ 0x57, 0xae, 0x49, 0x30, 0xf5, 0xfe, 0x5e, 0x46, 0x0b, 0x72, 0x44, 0xc4, ++ 0xe1, 0xfc, 0x62, 0xda, 0xf1, 0xfb, 0xa2, 0xdb, 0xd6, 0xbe, 0x5c, 0xd7, ++ 0x24, 0xa3, 0xf5, 0xb9, 0x2f, 0x57, 0x16, 0x49, 0x75, 0x47, 0x77, 0x09, ++ 0x5c, 0xa1, 0xb4, 0xc3, 0x4f, 0x60, 0x2b, 0xb0, 0x0c, 0xc8, 0xd6, 0x66, ++ 0xba, 0x9b, 0x82, 0x29, 0x33, 0x92, 0x26, 0x99, 0x31, 0x1c, 0x7f, 0x9b ++}; ++ ++static const u8 *codec_h264_eos_sequence(u32 *len) ++{ ++ *len = ARRAY_SIZE(eos_sequence); ++ return eos_sequence; ++} ++ ++struct codec_h264 { ++ /* H.264 decoder requires an extended firmware */ ++ void *ext_fw_vaddr; ++ dma_addr_t ext_fw_paddr; ++ ++ /* Buffer for the H.264 Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++ ++ /* Buffer for the H.264 references MV */ ++ void *ref_vaddr; ++ dma_addr_t ref_paddr; ++ u32 ref_size; ++ ++ /* Buffer for parsed SEI data */ ++ void *sei_vaddr; ++ dma_addr_t sei_paddr; ++ ++ u32 mb_width; ++ u32 mb_height; ++ u32 max_refs; ++}; ++ ++static int codec_h264_can_recycle(struct amvdec_core *core) ++{ ++ return !amvdec_read_dos(core, AV_SCRATCH_7) || ++ !amvdec_read_dos(core, AV_SCRATCH_8); ++} ++ ++static void codec_h264_recycle(struct amvdec_core *core, u32 buf_idx) ++{ ++ /* Tell the decoder he can recycle this buffer. ++ * AV_SCRATCH_8 serves the same purpose. ++ */ ++ if (!amvdec_read_dos(core, AV_SCRATCH_7)) ++ amvdec_write_dos(core, AV_SCRATCH_7, buf_idx + 1); ++ else ++ amvdec_write_dos(core, AV_SCRATCH_8, buf_idx + 1); ++} ++ ++static int codec_h264_start(struct amvdec_session *sess) { ++ u32 workspace_offset; ++ struct amvdec_core *core = sess->core; ++ struct codec_h264 *h264 = sess->priv; ++ ++ /* Allocate some memory for the H.264 decoder's state */ ++ h264->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &h264->workspace_paddr, GFP_KERNEL); ++ if (!h264->workspace_vaddr) { ++ dev_err(core->dev, "Failed to alloc H.264 Workspace\n"); ++ return -ENOMEM; ++ } ++ ++ /* Allocate some memory for the H.264 SEI dump */ ++ h264->sei_vaddr = dma_alloc_coherent(core->dev, SIZE_SEI, ++ &h264->sei_paddr, GFP_KERNEL); ++ if (!h264->sei_vaddr) { ++ dev_err(core->dev, "Failed to alloc H.264 SEI\n"); ++ return -ENOMEM; ++ } ++ ++ amvdec_write_dos_bits(core, POWER_CTL_VLD, BIT(9) | BIT(6)); ++ ++ workspace_offset = h264->workspace_paddr - WORKSPACE_BUF_OFFSET; ++ amvdec_write_dos(core, AV_SCRATCH_1, workspace_offset); ++ amvdec_write_dos(core, AV_SCRATCH_G, h264->ext_fw_paddr); ++ amvdec_write_dos(core, AV_SCRATCH_I, h264->sei_paddr - workspace_offset); ++ ++ /* Enable "error correction" */ ++ amvdec_write_dos(core, AV_SCRATCH_F, ++ (amvdec_read_dos(core, AV_SCRATCH_F) & 0xffffffc3) | ++ BIT(4) | BIT(7)); ++ ++ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa); ++ ++ return 0; ++} ++ ++static int codec_h264_stop(struct amvdec_session *sess) ++{ ++ struct codec_h264 *h264 = sess->priv; ++ struct amvdec_core *core = sess->core; ++ ++ if (h264->ext_fw_vaddr) ++ dma_free_coherent(core->dev, SIZE_EXT_FW, ++ h264->ext_fw_vaddr, h264->ext_fw_paddr); ++ ++ if (h264->workspace_vaddr) ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ h264->workspace_vaddr, h264->workspace_paddr); ++ ++ if (h264->ref_vaddr) ++ dma_free_coherent(core->dev, h264->ref_size, ++ h264->ref_vaddr, h264->ref_paddr); ++ ++ if (h264->sei_vaddr) ++ dma_free_coherent(core->dev, SIZE_SEI, ++ h264->sei_vaddr, h264->sei_paddr); ++ ++ return 0; ++} ++ ++static int codec_h264_load_extended_firmware(struct amvdec_session *sess, ++ const u8 *data, u32 len) ++{ ++ struct codec_h264 *h264; ++ struct amvdec_core *core = sess->core; ++ ++ if (len < SIZE_EXT_FW) ++ return -EINVAL; ++ ++ h264 = kzalloc(sizeof(*h264), GFP_KERNEL); ++ if (!h264) ++ return -ENOMEM; ++ ++ h264->ext_fw_vaddr = dma_alloc_coherent(core->dev, SIZE_EXT_FW, ++ &h264->ext_fw_paddr, GFP_KERNEL); ++ if (!h264->ext_fw_vaddr) { ++ dev_err(core->dev, "Failed to alloc H.264 extended fw\n"); ++ kfree(h264); ++ return -ENOMEM; ++ } ++ ++ memcpy(h264->ext_fw_vaddr, data, SIZE_EXT_FW); ++ sess->priv = h264; ++ ++ return 0; ++} ++ ++static const struct v4l2_fract par_table[] = { ++ { 1, 1 }, { 1, 1 }, { 12, 11 }, { 10, 11 }, ++ { 16, 11 }, { 40, 33 }, { 24, 11 }, { 20, 11 }, ++ { 32, 11 }, { 80, 33 }, { 18, 11 }, { 15, 11 }, ++ { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 }, ++ { 2, 1 } ++}; ++ ++static void codec_h264_set_par(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 seq_info = amvdec_read_dos(core, AV_SCRATCH_2); ++ u32 ar_idc = (seq_info >> AR_IDC_BIT) & AR_IDC_MASK; ++ ++ if (!(seq_info & AR_PRESENT_FLAG)) ++ return; ++ ++ if (ar_idc == AR_EXTEND) { ++ u32 ar_info = amvdec_read_dos(core, AV_SCRATCH_3); ++ sess->pixelaspect.numerator = ar_info & 0xffff; ++ sess->pixelaspect.denominator = (ar_info >> 16) & 0xffff; ++ return; ++ } ++ ++ if (ar_idc >= ARRAY_SIZE(par_table)) ++ return; ++ ++ sess->pixelaspect = par_table[ar_idc]; ++} ++ ++static void codec_h264_resume(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_h264 *h264 = sess->priv; ++ u32 mb_width, mb_height, mb_total; ++ ++ amvdec_set_canvases(sess, (u32[]){ ANC0_CANVAS_ADDR, 0 }, ++ (u32[]){ 24, 0 }); ++ ++ dev_dbg(core->dev, ++ "max_refs = %u; actual_dpb_size = %u\n", ++ h264->max_refs, sess->num_dst_bufs); ++ ++ /* Align to a multiple of 4 macroblocks */ ++ mb_width = ALIGN(h264->mb_width, 4); ++ mb_height = ALIGN(h264->mb_height, 4); ++ mb_total = mb_width * mb_height; ++ ++ h264->ref_size = mb_total * MB_MV_SIZE * h264->max_refs; ++ h264->ref_vaddr = dma_alloc_coherent(core->dev, h264->ref_size, ++ &h264->ref_paddr, GFP_KERNEL); ++ if (!h264->ref_vaddr) { ++ dev_err(core->dev, "Failed to alloc refs (%u)\n", ++ h264->ref_size); ++ amvdec_abort(sess); ++ return; ++ } ++ ++ /* Address to store the references' MVs */ ++ amvdec_write_dos(core, AV_SCRATCH_1, h264->ref_paddr); ++ /* End of ref MV */ ++ amvdec_write_dos(core, AV_SCRATCH_4, h264->ref_paddr + h264->ref_size); ++ ++ amvdec_write_dos(core, AV_SCRATCH_0, (h264->max_refs << 24) | ++ (sess->num_dst_bufs << 16) | ++ ((h264->max_refs - 1) << 8)); ++} ++ ++/* Configure the H.264 decoder when the parser detected a parameter set change ++ */ ++static void codec_h264_src_change(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_h264 *h264 = sess->priv; ++ u32 parsed_info, mb_total; ++ u32 crop_infor, crop_bottom, crop_right; ++ u32 frame_width, frame_height; ++ ++ sess->keyframe_found = 1; ++ ++ parsed_info = amvdec_read_dos(core, AV_SCRATCH_1); ++ ++ /* Total number of 16x16 macroblocks */ ++ mb_total = (parsed_info >> MB_TOTAL_BIT) & MB_TOTAL_MASK; ++ /* Number of macroblocks per line */ ++ h264->mb_width = parsed_info & MB_WIDTH_MASK; ++ /* Number of macroblock lines */ ++ h264->mb_height = mb_total / h264->mb_width; ++ ++ h264->max_refs = ((parsed_info >> MAX_REF_BIT) & MAX_REF_MASK) + 1; ++ ++ crop_infor = amvdec_read_dos(core, AV_SCRATCH_6); ++ crop_bottom = (crop_infor & 0xff); ++ crop_right = (crop_infor >> 16) & 0xff; ++ ++ frame_width = h264->mb_width * 16 - crop_right; ++ frame_height = h264->mb_height * 16 - crop_bottom; ++ ++ dev_info(core->dev, "frame: %ux%u; crop: %u %u\n", ++ frame_width, frame_height, crop_right, crop_bottom); ++ ++ codec_h264_set_par(sess); ++ amvdec_src_change(sess, frame_width, frame_height, h264->max_refs + 5); ++} ++ ++/** ++ * The offset is split in half in 2 different registers ++ */ ++static u32 get_offset_msb(struct amvdec_core *core, int frame_num) ++{ ++ int take_msb = frame_num % 2; ++ int reg_offset = (frame_num / 2) * 4; ++ u32 offset_msb = amvdec_read_dos(core, AV_SCRATCH_A + reg_offset); ++ ++ if (take_msb) ++ return offset_msb & 0xffff0000; ++ ++ return (offset_msb & 0x0000ffff) << 16; ++} ++ ++static void codec_h264_frames_ready(struct amvdec_session *sess, u32 status) ++{ ++ struct amvdec_core *core = sess->core; ++ int error_count; ++ int num_frames; ++ int i; ++ ++ error_count = amvdec_read_dos(core, AV_SCRATCH_D); ++ num_frames = (status >> 8) & 0xff; ++ if (error_count) { ++ dev_warn(core->dev, ++ "decoder error(s) happened, count %d\n", error_count); ++ amvdec_write_dos(core, AV_SCRATCH_D, 0); ++ } ++ ++ for (i = 0; i < num_frames; i++) { ++ u32 frame_status = amvdec_read_dos(core, AV_SCRATCH_1 + i * 4); ++ u32 buffer_index = frame_status & BUF_IDX_MASK; ++ u32 pic_struct = (frame_status >> PIC_STRUCT_BIT) & ++ PIC_STRUCT_MASK; ++ u32 offset = (frame_status >> OFFSET_BIT) & OFFSET_MASK; ++ u32 field = V4L2_FIELD_NONE; ++ ++ /* A buffer decode error means it was decoded, ++ * but part of the picture will have artifacts. ++ * Typical reason is a temporarily corrupted bitstream ++ */ ++ if (frame_status & ERROR_FLAG) ++ dev_dbg(core->dev, "Buffer %d decode error\n", ++ buffer_index); ++ ++ if (pic_struct == PIC_TOP_BOT) ++ field = V4L2_FIELD_INTERLACED_TB; ++ else if (pic_struct == PIC_BOT_TOP) ++ field = V4L2_FIELD_INTERLACED_BT; ++ ++ offset |= get_offset_msb(core, i); ++ amvdec_dst_buf_done_idx(sess, buffer_index, offset, field); ++ } ++} ++ ++static irqreturn_t codec_h264_threaded_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 status; ++ u32 size; ++ u8 cmd; ++ ++ status = amvdec_read_dos(core, AV_SCRATCH_0); ++ cmd = status & CMD_MASK; ++ ++ switch (cmd) { ++ case CMD_SRC_CHANGE: ++ codec_h264_src_change(sess); ++ break; ++ case CMD_FRAMES_READY: ++ codec_h264_frames_ready(sess, status); ++ break; ++ case CMD_FATAL_ERROR: ++ dev_err(core->dev, "H.264 decoder fatal error\n"); ++ goto abort; ++ case CMD_BAD_WIDTH: ++ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16; ++ dev_err(core->dev, "Unsupported video width: %u\n", size); ++ goto abort; ++ case CMD_BAD_HEIGHT: ++ size = (amvdec_read_dos(core, AV_SCRATCH_1) + 1) * 16; ++ dev_err(core->dev, "Unsupported video height: %u\n", size); ++ goto abort; ++ case 0: /* Unused but not worth printing for */ ++ case 9: ++ break; ++ default: ++ dev_info(core->dev, "Unexpected H264 ISR: %08X\n", cmd); ++ break; ++ } ++ ++ if (cmd && cmd != CMD_SRC_CHANGE) ++ amvdec_write_dos(core, AV_SCRATCH_0, 0); ++ ++ /* Decoder has some SEI data for us ; ignore */ ++ if (amvdec_read_dos(core, AV_SCRATCH_J) & SEI_DATA_READY) ++ amvdec_write_dos(core, AV_SCRATCH_J, 0); ++ ++ return IRQ_HANDLED; ++abort: ++ amvdec_abort(sess); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t codec_h264_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); ++ ++ return IRQ_WAKE_THREAD; ++} ++ ++struct amvdec_codec_ops codec_h264_ops = { ++ .start = codec_h264_start, ++ .stop = codec_h264_stop, ++ .load_extended_firmware = codec_h264_load_extended_firmware, ++ .isr = codec_h264_isr, ++ .threaded_isr = codec_h264_threaded_isr, ++ .can_recycle = codec_h264_can_recycle, ++ .recycle = codec_h264_recycle, ++ .eos_sequence = codec_h264_eos_sequence, ++ .resume = codec_h264_resume, ++}; +diff --git a/drivers/media/platform/meson/vdec/codec_h264.h b/drivers/media/platform/meson/vdec/codec_h264.h +new file mode 100644 +index 0000000000000..7a1597611faff +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_h264.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_H264_H_ ++#define __MESON_VDEC_CODEC_H264_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_h264_ops; ++ ++#endif +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c +index bb8016266ab20..2f25e14bdbad2 100644 +--- a/drivers/media/platform/meson/vdec/vdec_platform.c ++++ b/drivers/media/platform/meson/vdec/vdec_platform.c +@@ -9,9 +9,20 @@ + + #include "vdec_1.h" + #include "codec_mpeg12.h" ++#include "codec_h264.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { ++ .pixfmt = V4L2_PIX_FMT_H264, ++ .min_buffers = 2, ++ .max_buffers = 24, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_h264_ops, ++ .firmware_path = "meson/gxbb/vh264_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, +@@ -38,6 +49,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + + static const struct amvdec_format vdec_formats_gxl[] = { + { ++ .pixfmt = V4L2_PIX_FMT_H264, ++ .min_buffers = 2, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_h264_ops, ++ .firmware_path = "meson/gxl/vh264_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, +@@ -64,6 +85,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { + + static const struct amvdec_format vdec_formats_gxm[] = { + { ++ .pixfmt = V4L2_PIX_FMT_H264, ++ .min_buffers = 2, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_h264_ops, ++ .firmware_path = "meson/gxm/vh264_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, + +From 0451e4b83f7a114f508c257c65d53cbd6664226e Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 16:01:55 +0200 +Subject: [PATCH 210/249] WIP: media: meson: vdec: add MPEG4 decoding support + +Add support for V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_XVID and +V4L2_PIX_FMT_H.263 +--- + drivers/media/platform/meson/vdec/Makefile | 2 +- + .../media/platform/meson/vdec/codec_mpeg4.c | 139 ++++++++++++++++++ + .../media/platform/meson/vdec/codec_mpeg4.h | 13 ++ + .../media/platform/meson/vdec/vdec_platform.c | 91 ++++++++++++ + 4 files changed, 244 insertions(+), 1 deletion(-) + create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.c + create mode 100644 drivers/media/platform/meson/vdec/codec_mpeg4.h + +diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile +index 01dc9603abdd7..bb7a134e27280 100644 +--- a/drivers/media/platform/meson/vdec/Makefile ++++ b/drivers/media/platform/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.c b/drivers/media/platform/meson/vdec/codec_mpeg4.c +new file mode 100644 +index 0000000000000..1d574e5761125 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_mpeg4.c +@@ -0,0 +1,139 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "vdec_helpers.h" ++#include "dos_regs.h" ++ ++#define SIZE_WORKSPACE SZ_1M ++/* Offset added by firmware, to substract from workspace paddr */ ++#define DCAC_BUFF_START_IP 0x02b00000 ++ ++/* map firmware registers to known MPEG4 functions */ ++#define MREG_BUFFERIN AV_SCRATCH_8 ++#define MREG_BUFFEROUT AV_SCRATCH_9 ++#define MP4_NOT_CODED_CNT AV_SCRATCH_A ++#define MP4_OFFSET_REG AV_SCRATCH_C ++#define MEM_OFFSET_REG AV_SCRATCH_F ++#define MREG_FATAL_ERROR AV_SCRATCH_L ++ ++#define BUF_IDX_MASK GENMASK(2, 0) ++#define INTERLACE_FLAG BIT(7) ++#define TOP_FIELD_FIRST_FLAG BIT(6) ++ ++struct codec_mpeg4 { ++ /* Buffer for the MPEG4 Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++}; ++ ++static int codec_mpeg4_can_recycle(struct amvdec_core *core) ++{ ++ return !amvdec_read_dos(core, MREG_BUFFERIN); ++} ++ ++static void codec_mpeg4_recycle(struct amvdec_core *core, u32 buf_idx) ++{ ++ amvdec_write_dos(core, MREG_BUFFERIN, ~BIT(buf_idx)); ++} ++ ++static int codec_mpeg4_start(struct amvdec_session *sess) { ++ struct amvdec_core *core = sess->core; ++ struct codec_mpeg4 *mpeg4 = sess->priv; ++ int ret; ++ ++ mpeg4 = kzalloc(sizeof(*mpeg4), GFP_KERNEL); ++ if (!mpeg4) ++ return -ENOMEM; ++ ++ /* Allocate some memory for the MPEG4 decoder's state */ ++ mpeg4->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &mpeg4->workspace_paddr, ++ GFP_KERNEL); ++ if (!mpeg4->workspace_vaddr) { ++ dev_err(core->dev, "Failed to request MPEG4 Workspace\n"); ++ ret = -ENOMEM; ++ goto free_mpeg4; ++ } ++ ++ /* Canvas regs: AV_SCRATCH_0-AV_SCRATCH_4;AV_SCRATCH_G-AV_SCRATCH_J */ ++ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, AV_SCRATCH_G, 0 }, ++ (u32[]){ 4, 4, 0 }); ++ ++ amvdec_write_dos(core, MEM_OFFSET_REG, ++ mpeg4->workspace_paddr - DCAC_BUFF_START_IP); ++ amvdec_write_dos(core, PSCALE_CTRL, 0); ++ amvdec_write_dos(core, MP4_NOT_CODED_CNT, 0); ++ amvdec_write_dos(core, MREG_BUFFERIN, 0); ++ amvdec_write_dos(core, MREG_BUFFEROUT, 0); ++ amvdec_write_dos(core, MREG_FATAL_ERROR, 0); ++ amvdec_write_dos(core, MDEC_PIC_DC_THRESH, 0x404038aa); ++ ++ sess->keyframe_found = 1; ++ sess->priv = mpeg4; ++ ++ return 0; ++ ++free_mpeg4: ++ kfree(mpeg4); ++ return ret; ++} ++ ++static int codec_mpeg4_stop(struct amvdec_session *sess) ++{ ++ struct codec_mpeg4 *mpeg4 = sess->priv; ++ struct amvdec_core *core = sess->core; ++ ++ if (mpeg4->workspace_vaddr) { ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ mpeg4->workspace_vaddr, ++ mpeg4->workspace_paddr); ++ mpeg4->workspace_vaddr = 0; ++ } ++ ++ return 0; ++} ++ ++static irqreturn_t codec_mpeg4_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 reg; ++ u32 buffer_index; ++ u32 field = V4L2_FIELD_NONE; ++ ++ reg = amvdec_read_dos(core, MREG_FATAL_ERROR); ++ if (reg == 1) { ++ dev_err(core->dev, "mpeg4 fatal error\n"); ++ amvdec_abort(sess); ++ return IRQ_HANDLED; ++ } ++ ++ reg = amvdec_read_dos(core, MREG_BUFFEROUT); ++ if (!reg) ++ goto end; ++ ++ buffer_index = reg & BUF_IDX_MASK; ++ if (reg & INTERLACE_FLAG) ++ field = (reg & TOP_FIELD_FIRST_FLAG) ? ++ V4L2_FIELD_INTERLACED_TB : ++ V4L2_FIELD_INTERLACED_BT; ++ ++ amvdec_dst_buf_done_idx(sess, buffer_index, -1, field); ++ amvdec_write_dos(core, MREG_BUFFEROUT, 0); ++ ++end: ++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); ++ return IRQ_HANDLED; ++} ++ ++struct amvdec_codec_ops codec_mpeg4_ops = { ++ .start = codec_mpeg4_start, ++ .stop = codec_mpeg4_stop, ++ .isr = codec_mpeg4_isr, ++ .can_recycle = codec_mpeg4_can_recycle, ++ .recycle = codec_mpeg4_recycle, ++}; +diff --git a/drivers/media/platform/meson/vdec/codec_mpeg4.h b/drivers/media/platform/meson/vdec/codec_mpeg4.h +new file mode 100644 +index 0000000000000..b91b264131854 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_mpeg4.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_MPEG4_H_ ++#define __MESON_VDEC_CODEC_MPEG4_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_mpeg4_ops; ++ ++#endif +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c +index 2f25e14bdbad2..e1ab1914ddad9 100644 +--- a/drivers/media/platform/meson/vdec/vdec_platform.c ++++ b/drivers/media/platform/meson/vdec/vdec_platform.c +@@ -10,9 +10,40 @@ + #include "vdec_1.h" + #include "codec_mpeg12.h" + #include "codec_h264.h" ++#include "codec_mpeg4.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MPEG4, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H263, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/h263_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_XVID, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_H264, + .min_buffers = 2, + .max_buffers = 24, +@@ -49,6 +80,36 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + + static const struct amvdec_format vdec_formats_gxl[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MPEG4, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H263, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/h263_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_XVID, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_H264, + .min_buffers = 2, + .max_buffers = 24, +@@ -85,6 +146,36 @@ static const struct amvdec_format vdec_formats_gxl[] = { + + static const struct amvdec_format vdec_formats_gxm[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MPEG4, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H263, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/h263_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_XVID, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/gx/vmpeg4_mc_5", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_H264, + .min_buffers = 2, + .max_buffers = 24, + +From 48544ff3f04e1102e51288a62f90f893becf308c Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Sun, 21 Oct 2018 15:14:27 +0200 +Subject: [PATCH 211/249] WIP: media: meson: vdec: add MJPEG decoding support + +Add support for V4L2_PIX_FMT_MJPEG +--- + drivers/media/platform/meson/vdec/Makefile | 2 +- + .../media/platform/meson/vdec/codec_mjpeg.c | 140 ++++++++++++++++++ + .../media/platform/meson/vdec/codec_mjpeg.h | 13 ++ + .../media/platform/meson/vdec/vdec_platform.c | 31 ++++ + 4 files changed, 185 insertions(+), 1 deletion(-) + create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.c + create mode 100644 drivers/media/platform/meson/vdec/codec_mjpeg.h + +diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile +index bb7a134e27280..acf07f3c3dac6 100644 +--- a/drivers/media/platform/meson/vdec/Makefile ++++ b/drivers/media/platform/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.c b/drivers/media/platform/meson/vdec/codec_mjpeg.c +new file mode 100644 +index 0000000000000..abea9e3f944c2 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_mjpeg.c +@@ -0,0 +1,140 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "vdec_helpers.h" ++#include "dos_regs.h" ++ ++/* map FW registers to known MJPEG functions */ ++#define MREG_DECODE_PARAM AV_SCRATCH_2 ++#define MREG_TO_AMRISC AV_SCRATCH_8 ++#define MREG_FROM_AMRISC AV_SCRATCH_9 ++#define MREG_FRAME_OFFSET AV_SCRATCH_A ++ ++static int codec_mjpeg_can_recycle(struct amvdec_core *core) ++{ ++ return !amvdec_read_dos(core, MREG_TO_AMRISC); ++} ++ ++static void codec_mjpeg_recycle(struct amvdec_core *core, u32 buf_idx) ++{ ++ amvdec_write_dos(core, MREG_TO_AMRISC, buf_idx + 1); ++} ++ ++/* 4 point triangle */ ++static const uint32_t filt_coef[] = { ++ 0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101, ++ 0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303, ++ 0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505, ++ 0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707, ++ 0x18382808, 0x18382808, 0x17372909, 0x17372909, ++ 0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b, ++ 0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d, ++ 0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f, ++ 0x10303010 ++}; ++ ++static void codec_mjpeg_init_scaler(struct amvdec_core *core) ++{ ++ int i; ++ ++ /* PSCALE cbus bmem enable */ ++ amvdec_write_dos(core, PSCALE_CTRL, 0xc000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 0); ++ for (i = 0; i < ARRAY_SIZE(filt_coef); ++i) { ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, filt_coef[i]); ++ } ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 74); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 82); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 78); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 86); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x0008); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x60000000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 73); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 81); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); ++ ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 77); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); ++ amvdec_write_dos(core, PSCALE_BMEM_ADDR, 85); ++ amvdec_write_dos(core, PSCALE_BMEM_DAT, 0x10000); ++ ++ amvdec_write_dos(core, PSCALE_RST, 0x7); ++ amvdec_write_dos(core, PSCALE_RST, 0); ++} ++ ++static int codec_mjpeg_start(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ amvdec_write_dos(core, AV_SCRATCH_0, 12); ++ amvdec_write_dos(core, AV_SCRATCH_1, 0x031a); ++ ++ amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_4, 0 }, ++ (u32[]){ 4, 0 }); ++ codec_mjpeg_init_scaler(core); ++ ++ amvdec_write_dos(core, MREG_TO_AMRISC, 0); ++ amvdec_write_dos(core, MREG_FROM_AMRISC, 0); ++ amvdec_write_dos(core, MCPU_INTR_MSK, 0xffff); ++ amvdec_write_dos(core, MREG_DECODE_PARAM, ++ (sess->height << 4) | 0x8000); ++ amvdec_write_dos(core, VDEC_ASSIST_AMR1_INT8, 8); ++ ++ /* Intra-only codec */ ++ sess->keyframe_found = 1; ++ ++ return 0; ++} ++ ++static int codec_mjpeg_stop(struct amvdec_session *sess) ++{ ++ return 0; ++} ++ ++static irqreturn_t codec_mjpeg_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 reg; ++ u32 buffer_index; ++ u32 offset; ++ ++ amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); ++ ++ reg = amvdec_read_dos(core, MREG_FROM_AMRISC); ++ if (!(reg & 0x7)) ++ return IRQ_HANDLED; ++ ++ buffer_index = ((reg & 0x7) - 1) & 3; ++ offset = amvdec_read_dos(core, MREG_FRAME_OFFSET); ++ amvdec_dst_buf_done_idx(sess, buffer_index, offset, V4L2_FIELD_NONE); ++ ++ amvdec_write_dos(core, MREG_FROM_AMRISC, 0); ++ return IRQ_HANDLED; ++} ++ ++struct amvdec_codec_ops codec_mjpeg_ops = { ++ .start = codec_mjpeg_start, ++ .stop = codec_mjpeg_stop, ++ .isr = codec_mjpeg_isr, ++ .can_recycle = codec_mjpeg_can_recycle, ++ .recycle = codec_mjpeg_recycle, ++}; +diff --git a/drivers/media/platform/meson/vdec/codec_mjpeg.h b/drivers/media/platform/meson/vdec/codec_mjpeg.h +new file mode 100644 +index 0000000000000..cc1cf731050d1 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_mjpeg.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_MJPEG_H_ ++#define __MESON_VDEC_CODEC_MJPEG_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_mjpeg_ops; ++ ++#endif +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c +index e1ab1914ddad9..9cf978e9050d3 100644 +--- a/drivers/media/platform/meson/vdec/vdec_platform.c ++++ b/drivers/media/platform/meson/vdec/vdec_platform.c +@@ -11,9 +11,20 @@ + #include "codec_mpeg12.h" + #include "codec_h264.h" + #include "codec_mpeg4.h" ++#include "codec_mjpeg.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MJPEG, ++ .min_buffers = 4, ++ .max_buffers = 4, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mjpeg_ops, ++ .firmware_path = "meson/gx/vmjpeg_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .min_buffers = 8, + .max_buffers = 8, +@@ -80,6 +91,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + + static const struct amvdec_format vdec_formats_gxl[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MJPEG, ++ .min_buffers = 4, ++ .max_buffers = 4, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mjpeg_ops, ++ .firmware_path = "meson/gx/vmjpeg_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .min_buffers = 8, + .max_buffers = 8, +@@ -146,6 +167,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { + + static const struct amvdec_format vdec_formats_gxm[] = { + { ++ .pixfmt = V4L2_PIX_FMT_MJPEG, ++ .min_buffers = 4, ++ .max_buffers = 4, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mjpeg_ops, ++ .firmware_path = "meson/gx/vmjpeg_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .min_buffers = 8, + .max_buffers = 8, + +From 8737e27bae7e539ab69d24f8523a980c3dfc6941 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Sun, 21 Oct 2018 15:14:49 +0200 +Subject: [PATCH 212/249] WIP: media: videodev2.h: Add Amlogic compressed + format + +Add V4L2_PIX_FMT_AM21C which is a lossless, compressed framebuffer +format. + +It is used by the video decoding and the display IP on many Amlogic +SoCs. +--- + drivers/media/v4l2-core/v4l2-ioctl.c | 1 + + include/uapi/linux/videodev2.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c +index f6d663934648a..5148b0539c363 100644 +--- a/drivers/media/v4l2-core/v4l2-ioctl.c ++++ b/drivers/media/v4l2-core/v4l2-ioctl.c +@@ -1357,6 +1357,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) + case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; + case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; + case V4L2_PIX_FMT_SUNXI_TILED_NV12: descr = "Sunxi Tiled NV12 Format"; break; ++ case V4L2_PIX_FMT_AM21C: descr = "Amlogic Compressed Format"; break; + default: + if (fmt->description[0]) + return; +diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h +index 9c8a2d2e7bc62..aab7ec92b9f27 100644 +--- a/include/uapi/linux/videodev2.h ++++ b/include/uapi/linux/videodev2.h +@@ -701,6 +701,7 @@ struct v4l2_pix_format { + #define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */ + #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */ + #define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */ ++#define V4L2_PIX_FMT_AM21C v4l2_fourcc('A', 'M', '2', '1') /* Amlogic compressed block mode */ + #define V4L2_PIX_FMT_INZI v4l2_fourcc('I', 'N', 'Z', 'I') /* Intel Planar Greyscale 10-bit and Depth 16-bit */ + #define V4L2_PIX_FMT_SUNXI_TILED_NV12 v4l2_fourcc('S', 'T', '1', '2') /* Sunxi Tiled NV12 Format */ + #define V4L2_PIX_FMT_CNF4 v4l2_fourcc('C', 'N', 'F', '4') /* Intel 4-bit packed depth confidence information */ + +From dbecbb71cf8bb2b0f9eb91fc1bda12394d4a5452 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Sun, 21 Oct 2018 15:15:26 +0200 +Subject: [PATCH 213/249] WIP: media: meson: vdec: add support for + V4L2_PIX_FMT_AM21C + +Support the lossless framebuffer compression format. +--- + drivers/media/platform/meson/vdec/vdec.c | 12 +++++++ + .../media/platform/meson/vdec/vdec_helpers.c | 31 +++++++++++++++++++ + .../media/platform/meson/vdec/vdec_helpers.h | 4 +++ + 3 files changed, 47 insertions(+) + +diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c +index da96a788ee5c6..dd5e6864fbdaa 100644 +--- a/drivers/media/platform/meson/vdec/vdec.c ++++ b/drivers/media/platform/meson/vdec/vdec.c +@@ -186,6 +186,7 @@ static int vdec_queue_setup(struct vb2_queue *q, + { + struct amvdec_session *sess = vb2_get_drv_priv(q); + u32 output_size = amvdec_get_output_size(sess); ++ u32 am21c_size = amvdec_am21c_size(sess->width, sess->height); + + if (*num_planes) { + switch (q->type) { +@@ -208,6 +209,10 @@ static int vdec_queue_setup(struct vb2_queue *q, + sizes[2] < output_size / 4) + return -EINVAL; + break; ++ case V4L2_PIX_FMT_AM21C: ++ if (*num_planes != 1 || sizes[0] < am21c_size) ++ return -EINVAL; ++ break; + default: + return -EINVAL; + } +@@ -237,6 +242,9 @@ static int vdec_queue_setup(struct vb2_queue *q, + sizes[2] = output_size / 4; + *num_planes = 3; + break; ++ case V4L2_PIX_FMT_AM21C: ++ sizes[0] = am21c_size; ++ *num_planes = 1; + default: + return -EINVAL; + } +@@ -508,6 +516,10 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size, + get_output_size(pixmp->width, pixmp->height) / 4; + pfmt[2].bytesperline = ALIGN(pixmp->width, 64) / 2; + pixmp->num_planes = 3; ++ } else if (pixmp->pixelformat == V4L2_PIX_FMT_AM21C) { ++ pfmt[0].sizeimage = ++ amvdec_am21c_size(pixmp->width, pixmp->height); ++ pfmt[0].bytesperline = 0; + } + } else { + return NULL; +diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c +index 5adf9a378b32c..c57391421c301 100644 +--- a/drivers/media/platform/meson/vdec/vdec_helpers.c ++++ b/drivers/media/platform/meson/vdec/vdec_helpers.c +@@ -50,6 +50,33 @@ void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val) + } + EXPORT_SYMBOL_GPL(amvdec_write_parser); + ++/* 4 KiB per 64x32 block */ ++u32 amvdec_am21c_body_size(u32 width, u32 height) ++{ ++ u32 width_64 = ALIGN(width, 64) / 64; ++ u32 height_32 = ALIGN(height, 32) / 32; ++ ++ return SZ_4K * width_64 * height_32; ++} ++EXPORT_SYMBOL_GPL(amvdec_am21c_body_size); ++ ++/* 32 bytes per 128x64 block */ ++u32 amvdec_am21c_head_size(u32 width, u32 height) ++{ ++ u32 width_128 = ALIGN(width, 128) / 128; ++ u32 height_64 = ALIGN(height, 64) / 64; ++ ++ return 32 * width_128 * height_64; ++} ++EXPORT_SYMBOL_GPL(amvdec_am21c_head_size); ++ ++u32 amvdec_am21c_size(u32 width, u32 height) ++{ ++ return ALIGN(amvdec_am21c_body_size(width, height) + ++ amvdec_am21c_head_size(width, height), SZ_64K); ++} ++EXPORT_SYMBOL_GPL(amvdec_am21c_size); ++ + static int canvas_alloc(struct amvdec_session *sess, u8 *canvas_id) + { + int ret; +@@ -264,6 +291,10 @@ static void dst_buf_done(struct amvdec_session *sess, + vbuf->vb2_buf.planes[1].bytesused = output_size / 4; + vbuf->vb2_buf.planes[2].bytesused = output_size / 4; + break; ++ case V4L2_PIX_FMT_AM21C: ++ vbuf->vb2_buf.planes[0].bytesused = ++ amvdec_am21c_size(sess->width, sess->height); ++ break; + } + + vbuf->vb2_buf.timestamp = timestamp; +diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h +index 87b39e048a0fc..f1dee9e3447bd 100644 +--- a/drivers/media/platform/meson/vdec/vdec_helpers.h ++++ b/drivers/media/platform/meson/vdec/vdec_helpers.h +@@ -27,6 +27,10 @@ void amvdec_clear_dos_bits(struct amvdec_core *core, u32 reg, u32 val); + u32 amvdec_read_parser(struct amvdec_core *core, u32 reg); + void amvdec_write_parser(struct amvdec_core *core, u32 reg, u32 val); + ++u32 amvdec_am21c_body_size(u32 width, u32 height); ++u32 amvdec_am21c_head_size(u32 width, u32 height); ++u32 amvdec_am21c_size(u32 width, u32 height); ++ + /** + * amvdec_dst_buf_done_idx() - Signal that a buffer is done decoding + * + +From 89cd932da66a841641045631cc34c2d2744c32d0 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Tue, 13 Nov 2018 10:13:02 +0100 +Subject: [PATCH 214/249] WIP: meson: vdec: make amvdec_dst_buf_done_offset + public + +Needed for future commit +--- + drivers/media/platform/meson/vdec/vdec_helpers.c | 13 ++++++++----- + drivers/media/platform/meson/vdec/vdec_helpers.h | 3 +++ + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c +index c57391421c301..7bb7a6dad5874 100644 +--- a/drivers/media/platform/meson/vdec/vdec_helpers.c ++++ b/drivers/media/platform/meson/vdec/vdec_helpers.c +@@ -349,10 +349,9 @@ void amvdec_dst_buf_done(struct amvdec_session *sess, + } + EXPORT_SYMBOL_GPL(amvdec_dst_buf_done); + +-static void amvdec_dst_buf_done_offset(struct amvdec_session *sess, +- struct vb2_v4l2_buffer *vbuf, +- u32 offset, +- u32 field) ++void amvdec_dst_buf_done_offset(struct amvdec_session *sess, ++ struct vb2_v4l2_buffer *vbuf, ++ u32 offset, u32 field, bool allow_drop) + { + struct device *dev = sess->core->dev_dec; + struct amvdec_timestamp *match = NULL; +@@ -375,6 +374,9 @@ static void amvdec_dst_buf_done_offset(struct amvdec_session *sess, + break; + } + ++ if (!allow_drop) ++ continue; ++ + /* Delete any timestamp entry that appears before our target + * (not all src packets/timestamps lead to a frame) + */ +@@ -399,6 +401,7 @@ static void amvdec_dst_buf_done_offset(struct amvdec_session *sess, + if (match) + atomic_dec(&sess->esparser_queued_bufs); + } ++EXPORT_SYMBOL_GPL(amvdec_dst_buf_done_offset); + + void amvdec_dst_buf_done_idx(struct amvdec_session *sess, + u32 buf_idx, u32 offset, u32 field) +@@ -415,7 +418,7 @@ void amvdec_dst_buf_done_idx(struct amvdec_session *sess, + } + + if (offset != -1) +- amvdec_dst_buf_done_offset(sess, vbuf, offset, field); ++ amvdec_dst_buf_done_offset(sess, vbuf, offset, field, true); + else + amvdec_dst_buf_done(sess, vbuf, field); + } +diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.h b/drivers/media/platform/meson/vdec/vdec_helpers.h +index f1dee9e3447bd..94d2c1ecfe149 100644 +--- a/drivers/media/platform/meson/vdec/vdec_helpers.h ++++ b/drivers/media/platform/meson/vdec/vdec_helpers.h +@@ -43,6 +43,9 @@ void amvdec_dst_buf_done_idx(struct amvdec_session *sess, u32 buf_idx, + u32 offset, u32 field); + void amvdec_dst_buf_done(struct amvdec_session *sess, + struct vb2_v4l2_buffer *vbuf, u32 field); ++void amvdec_dst_buf_done_offset(struct amvdec_session *sess, ++ struct vb2_v4l2_buffer *vbuf, ++ u32 offset, u32 field, bool allow_drop); + + /** + * amvdec_add_ts_reorder() - Add a timestamp to the list in chronological order + +From 4496f9d0499ced7f88510d6d9b39a73e4d46b087 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Wed, 29 Aug 2018 18:48:35 +0200 +Subject: [PATCH 215/249] WIP: media: meson: vdec: add HEVC decoding support + +Add support for V4L2_PIX_FMT_HEVC +--- + drivers/media/platform/meson/vdec/Makefile | 4 +- + .../media/platform/meson/vdec/codec_hevc.c | 1564 +++++++++++++++++ + .../media/platform/meson/vdec/codec_hevc.h | 13 + + drivers/media/platform/meson/vdec/hevc_regs.h | 205 +++ + drivers/media/platform/meson/vdec/vdec_hevc.c | 191 ++ + drivers/media/platform/meson/vdec/vdec_hevc.h | 22 + + .../media/platform/meson/vdec/vdec_platform.c | 32 + + 7 files changed, 2029 insertions(+), 2 deletions(-) + create mode 100644 drivers/media/platform/meson/vdec/codec_hevc.c + create mode 100644 drivers/media/platform/meson/vdec/codec_hevc.h + create mode 100644 drivers/media/platform/meson/vdec/hevc_regs.h + create mode 100644 drivers/media/platform/meson/vdec/vdec_hevc.c + create mode 100644 drivers/media/platform/meson/vdec/vdec_hevc.h + +diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile +index acf07f3c3dac6..ddcf38a7c3e65 100644 +--- a/drivers/media/platform/meson/vdec/Makefile ++++ b/drivers/media/platform/meson/vdec/Makefile +@@ -2,7 +2,7 @@ + # Makefile for Amlogic meson video decoder driver + + meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o +-meson-vdec-objs += vdec_1.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o ++meson-vdec-objs += vdec_1.o vdec_hevc.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c +new file mode 100644 +index 0000000000000..116e9ffc4560d +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_hevc.c +@@ -0,0 +1,1564 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. ++ */ ++ ++#include ++#include ++ ++#include "codec_hevc.h" ++#include "dos_regs.h" ++#include "hevc_regs.h" ++#include "vdec_helpers.h" ++ ++/* HEVC reg mapping */ ++#define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 ++ #define HEVC_ACTION_DONE 0xff ++#define HEVC_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 ++#define HEVC_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2 ++#define HEVC_VPS_BUFFER HEVC_ASSIST_SCRATCH_3 ++#define HEVC_SPS_BUFFER HEVC_ASSIST_SCRATCH_4 ++#define HEVC_PPS_BUFFER HEVC_ASSIST_SCRATCH_5 ++#define HEVC_SAO_UP HEVC_ASSIST_SCRATCH_6 ++#define HEVC_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 ++#define H265_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_7 ++#define HEVC_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8 ++#define HEVC_sao_mem_unit HEVC_ASSIST_SCRATCH_9 ++#define HEVC_SAO_ABV HEVC_ASSIST_SCRATCH_A ++#define HEVC_sao_vb_size HEVC_ASSIST_SCRATCH_B ++#define HEVC_SAO_VB HEVC_ASSIST_SCRATCH_C ++#define HEVC_SCALELUT HEVC_ASSIST_SCRATCH_D ++#define HEVC_WAIT_FLAG HEVC_ASSIST_SCRATCH_E ++#define RPM_CMD_REG HEVC_ASSIST_SCRATCH_F ++#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F ++#define DEBUG_REG1 HEVC_ASSIST_SCRATCH_G ++#define HEVC_DECODE_MODE2 HEVC_ASSIST_SCRATCH_H ++#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I ++#define HEVC_DECODE_MODE HEVC_ASSIST_SCRATCH_J ++ #define DECODE_MODE_SINGLE 0 ++#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K ++#define HEVC_AUX_ADR HEVC_ASSIST_SCRATCH_L ++#define HEVC_AUX_DATA_SIZE HEVC_ASSIST_SCRATCH_M ++#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N ++ ++#define AMRISC_MAIN_REQ 0x04 ++ ++/* HEVC Constants */ ++#define MAX_REF_PIC_NUM 24 ++#define MAX_REF_ACTIVE 16 ++#define MAX_TILE_COL_NUM 10 ++#define MAX_TILE_ROW_NUM 20 ++#define MAX_SLICE_NUM 800 ++#define INVALID_POC 0x80000000 ++ ++/* HEVC Workspace layout */ ++#define MPRED_MV_BUF_SIZE 0x120000 ++ ++#define IPP_SIZE 0x4000 ++#define SAO_ABV_SIZE 0x30000 ++#define SAO_VB_SIZE 0x30000 ++#define SH_TM_RPS_SIZE 0x800 ++#define VPS_SIZE 0x800 ++#define SPS_SIZE 0x800 ++#define PPS_SIZE 0x2000 ++#define SAO_UP_SIZE 0x2800 ++#define SWAP_BUF_SIZE 0x800 ++#define SWAP_BUF2_SIZE 0x800 ++#define SCALELUT_SIZE 0x8000 ++#define DBLK_PARA_SIZE 0x20000 ++#define DBLK_DATA_SIZE 0x40000 ++#define MMU_VBH_SIZE 0x5000 ++#define MPRED_ABV_SIZE 0x8000 ++#define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) ++#define RPM_BUF_SIZE 0x100 ++#define LMEM_SIZE 0xA00 ++ ++#define IPP_OFFSET 0x00 ++#define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) ++#define SAO_VB_OFFSET (SAO_ABV_OFFSET + SAO_ABV_SIZE) ++#define SH_TM_RPS_OFFSET (SAO_VB_OFFSET + SAO_VB_SIZE) ++#define VPS_OFFSET (SH_TM_RPS_OFFSET + SH_TM_RPS_SIZE) ++#define SPS_OFFSET (VPS_OFFSET + VPS_SIZE) ++#define PPS_OFFSET (SPS_OFFSET + SPS_SIZE) ++#define SAO_UP_OFFSET (PPS_OFFSET + PPS_SIZE) ++#define SWAP_BUF_OFFSET (SAO_UP_OFFSET + SAO_UP_SIZE) ++#define SWAP_BUF2_OFFSET (SWAP_BUF_OFFSET + SWAP_BUF_SIZE) ++#define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) ++#define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) ++#define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) ++#define MMU_VBH_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) ++#define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) ++#define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) ++#define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) ++#define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) ++ ++/* ISR decode status */ ++#define HEVC_DEC_IDLE 0x0 ++#define HEVC_NAL_UNIT_VPS 0x1 ++#define HEVC_NAL_UNIT_SPS 0x2 ++#define HEVC_NAL_UNIT_PPS 0x3 ++#define HEVC_NAL_UNIT_CODED_SLICE_SEGMENT 0x4 ++#define HEVC_CODED_SLICE_SEGMENT_DAT 0x5 ++#define HEVC_SLICE_DECODING 0x6 ++#define HEVC_NAL_UNIT_SEI 0x7 ++#define HEVC_SLICE_SEGMENT_DONE 0x8 ++#define HEVC_NAL_SEARCH_DONE 0x9 ++#define HEVC_DECPIC_DATA_DONE 0xa ++#define HEVC_DECPIC_DATA_ERROR 0xb ++#define HEVC_SEI_DAT 0xc ++#define HEVC_SEI_DAT_DONE 0xd ++ ++/* RPM misc_flag0 */ ++#define PCM_LOOP_FILTER_DISABLED_FLAG_BIT 0 ++#define PCM_ENABLE_FLAG_BIT 1 ++#define LOOP_FILER_ACROSS_TILES_ENABLED_FLAG_BIT 2 ++#define PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 3 ++#define DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT 4 ++#define PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 5 ++#define DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT 6 ++#define SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT 7 ++#define SLICE_SAO_LUMA_FLAG_BIT 8 ++#define SLICE_SAO_CHROMA_FLAG_BIT 9 ++#define SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT 10 ++ ++/* Constants for HEVC_MPRED_CTRL1 */ ++#define AMVP_MAX_NUM_CANDS_MEM 3 ++#define AMVP_MAX_NUM_CANDS 2 ++#define NUM_CHROMA_MODE 5 ++#define DM_CHROMA_IDX 36 ++ ++/* Buffer sizes */ ++#define SIZE_WORKSPACE ALIGN(LMEM_OFFSET + LMEM_SIZE, 64 * SZ_1K) ++#define SIZE_AUX (SZ_1K * 16) ++#define SIZE_FRAME_MMU (0x1200 * 4) ++#define RPM_SIZE 0x80 ++#define RPS_USED_BIT 14 ++ ++#define PARSER_CMD_SKIP_CFG_0 0x0000090b ++#define PARSER_CMD_SKIP_CFG_1 0x1b14140f ++#define PARSER_CMD_SKIP_CFG_2 0x001b1910 ++static const u16 parser_cmd[] = { ++ 0x0401, 0x8401, 0x0800, 0x0402, ++ 0x9002, 0x1423, 0x8CC3, 0x1423, ++ 0x8804, 0x9825, 0x0800, 0x04FE, ++ 0x8406, 0x8411, 0x1800, 0x8408, ++ 0x8409, 0x8C2A, 0x9C2B, 0x1C00, ++ 0x840F, 0x8407, 0x8000, 0x8408, ++ 0x2000, 0xA800, 0x8410, 0x04DE, ++ 0x840C, 0x840D, 0xAC00, 0xA000, ++ 0x08C0, 0x08E0, 0xA40E, 0xFC00, ++ 0x7C00 ++}; ++ ++/* Data received from the HW in this form, do not rearrange */ ++union rpm_param { ++ struct { ++ u16 data[RPM_SIZE]; ++ } l; ++ struct { ++ u16 CUR_RPS[MAX_REF_ACTIVE]; ++ u16 num_ref_idx_l0_active; ++ u16 num_ref_idx_l1_active; ++ u16 slice_type; ++ u16 slice_temporal_mvp_enable_flag; ++ u16 dependent_slice_segment_flag; ++ u16 slice_segment_address; ++ u16 num_title_rows_minus1; ++ u16 pic_width_in_luma_samples; ++ u16 pic_height_in_luma_samples; ++ u16 log2_min_coding_block_size_minus3; ++ u16 log2_diff_max_min_coding_block_size; ++ u16 log2_max_pic_order_cnt_lsb_minus4; ++ u16 POClsb; ++ u16 collocated_from_l0_flag; ++ u16 collocated_ref_idx; ++ u16 log2_parallel_merge_level; ++ u16 five_minus_max_num_merge_cand; ++ u16 sps_num_reorder_pics_0; ++ u16 modification_flag; ++ u16 tiles_flags; ++ u16 num_tile_columns_minus1; ++ u16 num_tile_rows_minus1; ++ u16 tile_width[8]; ++ u16 tile_height[8]; ++ u16 misc_flag0; ++ u16 pps_beta_offset_div2; ++ u16 pps_tc_offset_div2; ++ u16 slice_beta_offset_div2; ++ u16 slice_tc_offset_div2; ++ u16 pps_cb_qp_offset; ++ u16 pps_cr_qp_offset; ++ u16 first_slice_segment_in_pic_flag; ++ u16 m_temporalId; ++ u16 m_nalUnitType; ++ u16 vui_num_units_in_tick_hi; ++ u16 vui_num_units_in_tick_lo; ++ u16 vui_time_scale_hi; ++ u16 vui_time_scale_lo; ++ u16 bit_depth; ++ u16 profile_etc; ++ u16 sei_frame_field_info; ++ u16 video_signal_type; ++ u16 modification_list[0x20]; ++ u16 conformance_window_flag; ++ u16 conf_win_left_offset; ++ u16 conf_win_right_offset; ++ u16 conf_win_top_offset; ++ u16 conf_win_bottom_offset; ++ u16 chroma_format_idc; ++ u16 color_description; ++ u16 aspect_ratio_idc; ++ u16 sar_width; ++ u16 sar_height; ++ } p; ++}; ++ ++enum nal_unit_type { ++ NAL_UNIT_CODED_SLICE_BLA = 16, ++ NAL_UNIT_CODED_SLICE_BLANT = 17, ++ NAL_UNIT_CODED_SLICE_BLA_N_LP = 18, ++ NAL_UNIT_CODED_SLICE_IDR = 19, ++ NAL_UNIT_CODED_SLICE_IDR_N_LP = 20, ++}; ++ ++enum slice_type { ++ B_SLICE = 0, ++ P_SLICE = 1, ++ I_SLICE = 2, ++}; ++ ++/* A frame being decoded */ ++struct hevc_frame { ++ struct list_head list; ++ struct vb2_v4l2_buffer *vbuf; ++ u32 offset; ++ u32 poc; ++ ++ int referenced; ++ u32 num_reorder_pic; ++ ++ u32 cur_slice_idx; ++ u32 cur_slice_type; ++ ++ /* 2 lists (L0/L1) ; 800 slices ; 16 refs */ ++ u32 ref_poc_list[2][MAX_SLICE_NUM][MAX_REF_ACTIVE]; ++ u32 ref_num[2]; ++}; ++ ++struct codec_hevc { ++ struct mutex lock; ++ ++ /* Buffer for the HEVC Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++ ++ /* AUX buffer */ ++ void *aux_vaddr; ++ dma_addr_t aux_paddr; ++ ++ /* Contains many information parsed from the bitstream */ ++ union rpm_param rpm_param; ++ ++ /* Information computed from the RPM */ ++ u32 lcu_size; // Largest Coding Unit ++ u32 lcu_x_num; ++ u32 lcu_y_num; ++ u32 lcu_total; ++ ++ /* Current Frame being handled */ ++ struct hevc_frame *cur_frame; ++ u32 curr_poc; ++ /* Collocated Reference Picture */ ++ struct hevc_frame *col_frame; ++ u32 col_poc; ++ ++ /* All ref frames used by the HW at a given time */ ++ struct list_head ref_frames_list; ++ u32 frames_num; ++ ++ /* Coded resolution reported by the hardware */ ++ u32 width, height; ++ /* Resolution minus the conformance window offsets */ ++ u32 dst_width, dst_height; ++ ++ u32 prev_tid0_poc; ++ u32 slice_segment_addr; ++ u32 slice_addr; ++ u32 ldc_flag; ++ ++ /* Whether we detected the bitstream as 10-bit */ ++ int is_10bit; ++ ++ /* In case of downsampling (decoding with FBC but outputting in NV12M), ++ * we need to allocate additional buffers for FBC. ++ */ ++ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; ++}; ++ ++/* Returns 1 if we must use framebuffer compression */ ++static int codec_hevc_use_fbc(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ return sess->pixfmt_cap == V4L2_PIX_FMT_AM21C || hevc->is_10bit; ++} ++ ++/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */ ++static int codec_hevc_use_downsample(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ return sess->pixfmt_cap == V4L2_PIX_FMT_NV12M && hevc->is_10bit; ++} ++ ++static u32 codec_hevc_num_pending_bufs(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc; ++ u32 ret; ++ ++ hevc = sess->priv; ++ if (!hevc) ++ return 0; ++ ++ mutex_lock(&hevc->lock); ++ ret = hevc->frames_num; ++ mutex_unlock(&hevc->lock); ++ ++ return ret; ++} ++ ++/* Update the L0 and L1 reference lists for a given frame */ ++static void codec_hevc_update_frame_refs(struct amvdec_session *sess, struct hevc_frame *frame) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ union rpm_param *params = &hevc->rpm_param; ++ int i; ++ int num_neg = 0; ++ int num_pos = 0; ++ int total_num; ++ int num_ref_idx_l0_active = ++ (params->p.num_ref_idx_l0_active > MAX_REF_ACTIVE) ? ++ MAX_REF_ACTIVE : params->p.num_ref_idx_l0_active; ++ int num_ref_idx_l1_active = ++ (params->p.num_ref_idx_l1_active > MAX_REF_ACTIVE) ? ++ MAX_REF_ACTIVE : params->p.num_ref_idx_l1_active; ++ int ref_picset0[MAX_REF_ACTIVE] = { 0 }; ++ int ref_picset1[MAX_REF_ACTIVE] = { 0 }; ++ ++ for (i = 0; i < MAX_REF_ACTIVE; i++) { ++ frame->ref_poc_list[0][frame->cur_slice_idx][i] = 0; ++ frame->ref_poc_list[1][frame->cur_slice_idx][i] = 0; ++ } ++ ++ for (i = 0; i < MAX_REF_ACTIVE; i++) { ++ u16 cur_rps = params->p.CUR_RPS[i]; ++ int delt = cur_rps & ((1 << (RPS_USED_BIT - 1)) - 1); ++ ++ if (cur_rps & 0x8000) ++ break; ++ ++ if (!((cur_rps >> RPS_USED_BIT) & 1)) ++ continue; ++ ++ if ((cur_rps >> (RPS_USED_BIT - 1)) & 1) { ++ ref_picset0[num_neg] = ++ frame->poc - ((1 << (RPS_USED_BIT - 1)) - delt); ++ num_neg++; ++ } else { ++ ref_picset1[num_pos] = frame->poc + delt; ++ num_pos++; ++ } ++ } ++ ++ total_num = num_neg + num_pos; ++ ++ if (total_num <= 0) ++ goto end; ++ ++ for (i = 0; i < num_ref_idx_l0_active; i++) { ++ int cidx; ++ if (params->p.modification_flag & 0x1) ++ cidx = params->p.modification_list[i]; ++ else ++ cidx = i % total_num; ++ ++ frame->ref_poc_list[0][frame->cur_slice_idx][i] = ++ cidx >= num_neg ? ref_picset1[cidx - num_neg] : ++ ref_picset0[cidx]; ++ } ++ ++ if (params->p.slice_type != B_SLICE) ++ goto end; ++ ++ if (params->p.modification_flag & 0x2) { ++ for (i = 0; i < num_ref_idx_l1_active; i++) { ++ int cidx; ++ if (params->p.modification_flag & 0x1) ++ cidx = ++ params->p.modification_list[num_ref_idx_l0_active + i]; ++ else ++ cidx = params->p.modification_list[i]; ++ ++ frame->ref_poc_list[1][frame->cur_slice_idx][i] = ++ (cidx >= num_pos) ? ref_picset0[cidx - num_pos] ++ : ref_picset1[cidx]; ++ } ++ } else { ++ for (i = 0; i < num_ref_idx_l1_active; i++) { ++ int cidx = i % total_num; ++ frame->ref_poc_list[1][frame->cur_slice_idx][i] = ++ cidx >= num_pos ? ref_picset0[cidx - num_pos] : ++ ref_picset1[cidx]; ++ } ++ } ++ ++end: ++ frame->ref_num[0] = num_ref_idx_l0_active; ++ frame->ref_num[1] = num_ref_idx_l1_active; ++ ++ dev_dbg(sess->core->dev, ++ "Frame %u; slice %u; slice_type %u; num_l0 %u; num_l1 %u\n", ++ frame->poc, frame->cur_slice_idx, params->p.slice_type, ++ frame->ref_num[0], frame->ref_num[1]); ++} ++ ++static void codec_hevc_update_ldc_flag(struct codec_hevc *hevc) ++{ ++ struct hevc_frame *frame = hevc->cur_frame; ++ u32 slice_type = frame->cur_slice_type; ++ u32 slice_idx = frame->cur_slice_idx; ++ int i; ++ ++ hevc->ldc_flag = 0; ++ ++ if (slice_type == I_SLICE) ++ return; ++ ++ hevc->ldc_flag = 1; ++ for (i = 0; (i < frame->ref_num[0]) && hevc->ldc_flag; i++) { ++ if (frame->ref_poc_list[0][slice_idx][i] > frame->poc) { ++ hevc->ldc_flag = 0; ++ break; ++ } ++ } ++ ++ if (slice_type == P_SLICE) ++ return; ++ ++ for (i = 0; (i < frame->ref_num[1]) && hevc->ldc_flag; i++) { ++ if (frame->ref_poc_list[1][slice_idx][i] > frame->poc) { ++ hevc->ldc_flag = 0; ++ break; ++ } ++ } ++} ++ ++/* Tag "old" frames that are no longer referenced */ ++static void codec_hevc_update_referenced(struct codec_hevc *hevc) ++{ ++ union rpm_param *param = &hevc->rpm_param; ++ struct hevc_frame *frame; ++ int i; ++ u32 curr_poc = hevc->curr_poc; ++ ++ list_for_each_entry(frame, &hevc->ref_frames_list, list) { ++ int is_referenced = 0; ++ u32 poc_tmp; ++ ++ if (!frame->referenced) ++ continue; ++ ++ for (i = 0; i < MAX_REF_ACTIVE; i++) { ++ int delt; ++ if (param->p.CUR_RPS[i] & 0x8000) ++ break; ++ ++ delt = param->p.CUR_RPS[i] & ((1 << (RPS_USED_BIT - 1)) - 1); ++ if (param->p.CUR_RPS[i] & (1 << (RPS_USED_BIT - 1))) { ++ poc_tmp = curr_poc - ((1 << (RPS_USED_BIT - 1)) - delt); ++ } else ++ poc_tmp = curr_poc + delt; ++ if (poc_tmp == frame->poc) { ++ is_referenced = 1; ++ break; ++ } ++ } ++ ++ frame->referenced = is_referenced; ++ } ++} ++ ++static struct hevc_frame * ++codec_hevc_get_lowest_poc_frame(struct codec_hevc *hevc) ++{ ++ struct hevc_frame *tmp, *ret = NULL; ++ u32 poc = INT_MAX; ++ ++ list_for_each_entry(tmp, &hevc->ref_frames_list, list) { ++ if (tmp->poc < poc) { ++ ret = tmp; ++ poc = tmp->poc; ++ } ++ } ++ ++ return ret; ++} ++ ++/* Try to output as many frames as possible */ ++static void codec_hevc_output_frames(struct amvdec_session *sess) ++{ ++ struct hevc_frame *tmp; ++ struct codec_hevc *hevc = sess->priv; ++ ++ while ((tmp = codec_hevc_get_lowest_poc_frame(hevc))) { ++ if (hevc->curr_poc && ++ (tmp->referenced || ++ tmp->num_reorder_pic >= hevc->frames_num)) ++ break; ++ ++ dev_dbg(sess->core->dev, "DONE frame poc %u; vbuf %u\n", ++ tmp->poc, tmp->vbuf->vb2_buf.index); ++ amvdec_dst_buf_done_offset(sess, tmp->vbuf, tmp->offset, ++ V4L2_FIELD_NONE, false); ++ list_del(&tmp->list); ++ kfree(tmp); ++ hevc->frames_num--; ++ } ++} ++ ++/* Configure decode head read mode */ ++static void codec_hevc_setup_decode_head(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); ++ u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); ++ ++ if (!codec_hevc_use_fbc(sess)) { ++ /* Enable 2-plane reference read mode */ ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); ++ return; ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); ++ amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); ++ amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); ++ amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); ++} ++ ++static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ struct v4l2_m2m_buffer *buf; ++ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ dma_addr_t buf_y_paddr = 0; ++ dma_addr_t buf_uv_paddr = 0; ++ u32 idx = 0; ++ u32 val; ++ int i; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ idx = buf->vb.vb2_buf.index; ++ ++ if (codec_hevc_use_downsample(sess)) ++ buf_y_paddr = hevc->fbc_buffer_paddr[idx]; ++ else ++ buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ ++ if (codec_hevc_use_fbc(sess)) { ++ val = buf_y_paddr | (idx << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ } else { ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ val = buf_y_paddr | ((idx * 2) << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ } ++ } ++ ++ if (codec_hevc_use_fbc(sess)) ++ val = buf_y_paddr | (idx << 8) | 1; ++ else ++ val = buf_y_paddr | ((idx * 2) << 8) | 1; ++ ++ /* Fill the remaining unused slots with the last buffer's Y addr */ ++ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ for (i = 0; i < 32; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); ++} ++ ++static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ struct v4l2_m2m_buffer *buf; ++ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ dma_addr_t buf_y_paddr = 0; ++ dma_addr_t buf_uv_paddr = 0; ++ int i; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, ++ BIT(2) | BIT(1)); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ u32 idx = buf->vb.vb2_buf.index; ++ ++ if (codec_hevc_use_downsample(sess)) ++ buf_y_paddr = hevc->fbc_buffer_paddr[idx]; ++ else ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_y_paddr >> 5); ++ if (!codec_hevc_use_fbc(sess)) { ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_uv_paddr >> 5); ++ } ++ } ++ ++ /* Fill the remaining unused slots with the last buffer's Y addr */ ++ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_y_paddr >> 5); ++ if (!codec_hevc_use_fbc(sess)) ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_uv_paddr >> 5); ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ for (i = 0; i < 32; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); ++} ++ ++static void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct device *dev = sess->core->dev; ++ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); ++ int i; ++ ++ for (i = 0; i < MAX_REF_PIC_NUM; ++i) { ++ if (hevc->fbc_buffer_vaddr[i]) { ++ dma_free_coherent(dev, am21_size, ++ hevc->fbc_buffer_vaddr[i], ++ hevc->fbc_buffer_paddr[i]); ++ hevc->fbc_buffer_vaddr[i] = NULL; ++ } ++ } ++} ++ ++static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct device *dev = sess->core->dev; ++ struct v4l2_m2m_buffer *buf; ++ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ u32 idx = buf->vb.vb2_buf.index; ++ dma_addr_t paddr; ++ void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, ++ GFP_KERNEL); ++ if (!vaddr) { ++ dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); ++ codec_hevc_free_fbc_buffers(sess); ++ return -ENOMEM; ++ } ++ ++ hevc->fbc_buffer_vaddr[idx] = vaddr; ++ hevc->fbc_buffer_paddr[idx] = paddr; ++ } ++ ++ return 0; ++} ++ ++static int codec_hevc_setup_buffers(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ int ret; ++ ++ if (codec_hevc_use_downsample(sess)) { ++ ret = codec_hevc_alloc_fbc_buffers(sess); ++ if (ret) ++ return ret; ++ } ++ ++ if (core->platform->revision == VDEC_REVISION_GXBB) ++ codec_hevc_setup_buffers_gxbb(sess); ++ else ++ codec_hevc_setup_buffers_gxl(sess); ++ ++ return 0; ++} ++ ++static int ++codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) ++{ ++ dma_addr_t wkaddr; ++ ++ /* Allocate some memory for the HEVC decoder's state */ ++ hevc->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &wkaddr, GFP_KERNEL); ++ if (!hevc->workspace_vaddr) { ++ dev_err(core->dev, "Failed to allocate HEVC Workspace\n"); ++ return -ENOMEM; ++ } ++ ++ hevc->workspace_paddr = wkaddr; ++ ++ amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); ++ amvdec_write_dos(core, HEVC_RPM_BUFFER, wkaddr + RPM_OFFSET); ++ amvdec_write_dos(core, HEVC_SHORT_TERM_RPS, wkaddr + SH_TM_RPS_OFFSET); ++ amvdec_write_dos(core, HEVC_VPS_BUFFER, wkaddr + VPS_OFFSET); ++ amvdec_write_dos(core, HEVC_SPS_BUFFER, wkaddr + SPS_OFFSET); ++ amvdec_write_dos(core, HEVC_PPS_BUFFER, wkaddr + PPS_OFFSET); ++ amvdec_write_dos(core, HEVC_SAO_UP, wkaddr + SAO_UP_OFFSET); ++ ++ /* No MMU */ ++ amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, ++ wkaddr + SWAP_BUF_OFFSET); ++ amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2, ++ wkaddr + SWAP_BUF2_OFFSET); ++ amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); ++ ++ return 0; ++} ++ ++static int codec_hevc_start(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc; ++ u32 val; ++ int i; ++ int ret; ++ ++ hevc = kzalloc(sizeof(*hevc), GFP_KERNEL); ++ if (!hevc) ++ return -ENOMEM; ++ ++ INIT_LIST_HEAD(&hevc->ref_frames_list); ++ hevc->curr_poc = INVALID_POC; ++ ++ ret = codec_hevc_setup_workspace(core, hevc); ++ if (ret) ++ goto free_hevc; ++ ++ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); ++ ++ val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; ++ val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | ++ BIT(0); ++ amvdec_write_dos(core, HEVC_PARSER_INT_CONTROL, val); ++ amvdec_write_dos_bits(core, HEVC_SHIFT_STATUS, BIT(1) | BIT(0)); ++ amvdec_write_dos(core, HEVC_SHIFT_CONTROL, ++ (3 << 6) | BIT(5) | BIT(2) | BIT(0)); ++ amvdec_write_dos(core, HEVC_CABAC_CONTROL, 1); ++ amvdec_write_dos(core, HEVC_PARSER_CORE_CONTROL, 1); ++ amvdec_write_dos(core, HEVC_DEC_STATUS_REG, 0); ++ ++ amvdec_write_dos(core, HEVC_IQIT_SCALELUT_WR_ADDR, 0); ++ for (i = 0; i < 1024; ++i) ++ amvdec_write_dos(core, HEVC_IQIT_SCALELUT_DATA, 0); ++ ++ amvdec_write_dos(core, HEVC_DECODE_SIZE, 0); ++ ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16)); ++ for (i = 0; i < ARRAY_SIZE(parser_cmd); ++i) ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, parser_cmd[i]); ++ ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2); ++ amvdec_write_dos(core, HEVC_PARSER_IF_CONTROL, ++ BIT(5) | BIT(2) | BIT(0)); ++ ++ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(0)); ++ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(1)); ++ ++ amvdec_write_dos(core, HEVC_WAIT_FLAG, 1); ++ ++ /* clear mailbox interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_CLR_REG, 1); ++ /* enable mailbox interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 1); ++ /* disable PSCALE for hardware sharing */ ++ amvdec_write_dos(core, HEVC_PSCALE_CTRL, 0); ++ /* Let the uCode do all the parsing */ ++ amvdec_write_dos(core, NAL_SEARCH_CTL, 0xc); ++ ++ amvdec_write_dos(core, DECODE_STOP_POS, 0); ++ amvdec_write_dos(core, HEVC_DECODE_MODE, DECODE_MODE_SINGLE); ++ amvdec_write_dos(core, HEVC_DECODE_MODE2, 0); ++ ++ /* AUX buffers */ ++ hevc->aux_vaddr = dma_alloc_coherent(core->dev, SIZE_AUX, ++ &hevc->aux_paddr, GFP_KERNEL); ++ if (!hevc->aux_vaddr) { ++ dev_err(core->dev, "Failed to request HEVC AUX\n"); ++ ret = -ENOMEM; ++ goto free_hevc; ++ } ++ ++ amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); ++ amvdec_write_dos(core, HEVC_AUX_DATA_SIZE, ++ (((SIZE_AUX) >> 4) << 16) | 0); ++ mutex_init(&hevc->lock); ++ sess->priv = hevc; ++ ++ return 0; ++ ++free_hevc: ++ kfree(hevc); ++ return ret; ++} ++ ++static void codec_hevc_flush_output(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct hevc_frame *tmp; ++ ++ while (!list_empty(&hevc->ref_frames_list)) { ++ tmp = codec_hevc_get_lowest_poc_frame(hevc); ++ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); ++ list_del(&tmp->list); ++ kfree(tmp); ++ hevc->frames_num--; ++ } ++} ++ ++static int codec_hevc_stop(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct amvdec_core *core = sess->core; ++ ++ mutex_lock(&hevc->lock); ++ codec_hevc_flush_output(sess); ++ ++ if (hevc->workspace_vaddr) ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ hevc->workspace_vaddr, ++ hevc->workspace_paddr); ++ ++ if (hevc->aux_vaddr) ++ dma_free_coherent(core->dev, SIZE_AUX, ++ hevc->aux_vaddr, hevc->aux_paddr); ++ ++ codec_hevc_free_fbc_buffers(sess); ++ mutex_unlock(&hevc->lock); ++ mutex_destroy(&hevc->lock); ++ ++ return 0; ++} ++ ++static struct hevc_frame * ++codec_hevc_get_frame_by_poc(struct codec_hevc *hevc, u32 poc) ++{ ++ struct hevc_frame *tmp; ++ ++ list_for_each_entry(tmp, &hevc->ref_frames_list, list) { ++ if (tmp->poc == poc) ++ return tmp; ++ } ++ ++ return NULL; ++} ++ ++static struct hevc_frame * ++codec_hevc_prepare_new_frame(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct hevc_frame *new_frame = NULL; ++ struct codec_hevc *hevc = sess->priv; ++ struct vb2_v4l2_buffer *vbuf; ++ union rpm_param *params = &hevc->rpm_param; ++ ++ new_frame = kzalloc(sizeof(*new_frame), GFP_KERNEL); ++ if (!new_frame) ++ return NULL; ++ ++ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); ++ if (!vbuf) { ++ dev_err(sess->core->dev, "No dst buffer available\n"); ++ return NULL; ++ } ++ ++ new_frame->vbuf = vbuf; ++ new_frame->referenced = 1; ++ new_frame->poc = hevc->curr_poc; ++ new_frame->cur_slice_type = params->p.slice_type; ++ new_frame->num_reorder_pic = params->p.sps_num_reorder_pics_0; ++ new_frame->offset = amvdec_read_dos(core, HEVC_SHIFT_BYTE_COUNT); ++ ++ list_add_tail(&new_frame->list, &hevc->ref_frames_list); ++ hevc->frames_num++; ++ ++ return new_frame; ++} ++ ++static void ++codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ union rpm_param *param = &hevc->rpm_param; ++ u32 pic_height_cu = ++ (hevc->height + hevc->lcu_size - 1) / hevc->lcu_size; ++ u32 sao_mem_unit = (hevc->lcu_size == 16 ? 9 : ++ hevc->lcu_size == 32 ? 14 : 24) << 4; ++ u32 sao_vb_size = (sao_mem_unit + (2 << 4)) * pic_height_cu; ++ u32 misc_flag0 = param->p.misc_flag0; ++ dma_addr_t buf_y_paddr; ++ dma_addr_t buf_u_v_paddr; ++ u32 slice_deblocking_filter_disabled_flag; ++ u32 val, val_2; ++ ++ val = (amvdec_read_dos(core, HEVC_SAO_CTRL0) & ~0xf) | ++ ilog2(hevc->lcu_size); ++ amvdec_write_dos(core, HEVC_SAO_CTRL0, val); ++ ++ amvdec_write_dos(core, HEVC_SAO_PIC_SIZE, ++ hevc->width | (hevc->height << 16)); ++ amvdec_write_dos(core, HEVC_SAO_PIC_SIZE_LCU, ++ (hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16); ++ ++ if (codec_hevc_use_downsample(sess)) ++ buf_y_paddr = ++ hevc->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; ++ else ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); ++ ++ if (codec_hevc_use_fbc(sess)) { ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; ++ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); ++ amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); ++ } ++ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); ++ buf_u_v_paddr = ++ vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 1); ++ amvdec_write_dos(core, HEVC_SAO_Y_START_ADDR, buf_y_paddr); ++ amvdec_write_dos(core, HEVC_SAO_C_START_ADDR, buf_u_v_paddr); ++ amvdec_write_dos(core, HEVC_SAO_Y_WPTR, buf_y_paddr); ++ amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); ++ } ++ ++ amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, ++ amvdec_get_output_size(sess)); ++ amvdec_write_dos(core, HEVC_SAO_C_LENGTH, ++ (amvdec_get_output_size(sess) / 2)); ++ ++ if (frame->cur_slice_idx == 0) { ++ amvdec_write_dos(core, HEVC_DBLK_CFG2, ++ hevc->width | (hevc->height << 16)); ++ ++ val = 0; ++ if ((misc_flag0 >> PCM_ENABLE_FLAG_BIT) & 0x1) ++ val |= ((misc_flag0 >> PCM_LOOP_FILTER_DISABLED_FLAG_BIT) & 0x1) << 3; ++ ++ val |= (param->p.pps_cb_qp_offset & 0x1f) << 4; ++ val |= (param->p.pps_cr_qp_offset & 0x1f) << 9; ++ val |= (hevc->lcu_size == 64) ? 0 : ((hevc->lcu_size == 32) ? 1 : 2); ++ amvdec_write_dos(core, HEVC_DBLK_CFG1, val); ++ } ++ ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; ++ val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ ++ if (!codec_hevc_use_fbc(sess)) ++ val |= BIT(0); /* disable cm compression */ ++ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) ++ val |= BIT(1); /* Disable double write */ ++ ++ amvdec_write_dos(core, HEVC_SAO_CTRL1, val); ++ ++ if (!codec_hevc_use_fbc(sess)) { ++ /* no downscale for NV12 */ ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000; ++ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); ++ } ++ ++ val = amvdec_read_dos(core, HEVCD_IPP_AXIIF_CONFIG) & ~0x30; ++ val |= 0xf; ++ amvdec_write_dos(core, HEVCD_IPP_AXIIF_CONFIG, val); ++ ++ val = 0; ++ val_2 = amvdec_read_dos(core, HEVC_SAO_CTRL0); ++ val_2 &= (~0x300); ++ ++ slice_deblocking_filter_disabled_flag = (misc_flag0 >> ++ SLICE_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & 0x1; ++ if ((misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG_BIT)) ++ && (misc_flag0 & (1 << DEBLOCKING_FILTER_OVERRIDE_FLAG_BIT))) { ++ val |= slice_deblocking_filter_disabled_flag << 2; ++ ++ if (!slice_deblocking_filter_disabled_flag) { ++ val |= (param->p.slice_beta_offset_div2 & 0xf) << 3; ++ val |= (param->p.slice_tc_offset_div2 & 0xf) << 7; ++ } ++ } else { ++ val |= ++ ((misc_flag0 >> ++ PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & 0x1) << 2; ++ ++ if (((misc_flag0 >> PPS_DEBLOCKING_FILTER_DISABLED_FLAG_BIT) & ++ 0x1) == 0) { ++ val |= (param->p.pps_beta_offset_div2 & 0xf) << 3; ++ val |= (param->p.pps_tc_offset_div2 & 0xf) << 7; ++ } ++ } ++ if ((misc_flag0 & (1 << PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT)) ++ && ((misc_flag0 & (1 << SLICE_SAO_LUMA_FLAG_BIT)) ++ || (misc_flag0 & (1 << SLICE_SAO_CHROMA_FLAG_BIT)) ++ || (!slice_deblocking_filter_disabled_flag))) { ++ val |= ++ ((misc_flag0 >> ++ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) ++ & 0x1) << 1; ++ val_2 |= ++ ((misc_flag0 >> ++ SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) ++ & 0x1) << 9; ++ } else { ++ val |= ++ ((misc_flag0 >> ++ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) ++ & 0x1) << 1; ++ val_2 |= ++ ((misc_flag0 >> ++ PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG_BIT) ++ & 0x1) << 9; ++ } ++ ++ amvdec_write_dos(core, HEVC_DBLK_CFG9, val); ++ amvdec_write_dos(core, HEVC_SAO_CTRL0, val_2); ++ ++ amvdec_write_dos(core, HEVC_sao_mem_unit, sao_mem_unit); ++ amvdec_write_dos(core, HEVC_SAO_ABV, ++ hevc->workspace_paddr + SAO_ABV_OFFSET); ++ amvdec_write_dos(core, HEVC_sao_vb_size, sao_vb_size); ++ amvdec_write_dos(core, HEVC_SAO_VB, ++ hevc->workspace_paddr + SAO_VB_OFFSET); ++} ++ ++static dma_addr_t codec_hevc_get_frame_mv_paddr(struct codec_hevc *hevc, ++ struct hevc_frame *frame) ++{ ++ return hevc->workspace_paddr + MPRED_MV_OFFSET + ++ (frame->vbuf->vb2_buf.index * MPRED_MV_BUF_SIZE); ++} ++ ++static void ++codec_hevc_set_mpred_ctrl(struct amvdec_core *core, struct codec_hevc *hevc) ++{ ++ union rpm_param *param = &hevc->rpm_param; ++ u32 slice_type = param->p.slice_type; ++ u32 lcu_size_log2 = ilog2(hevc->lcu_size); ++ u32 val; ++ ++ val = slice_type | ++ MPRED_CTRL0_ABOVE_EN | ++ MPRED_CTRL0_MV_WR_EN | ++ MPRED_CTRL0_BUF_LINEAR | ++ (lcu_size_log2 << 16) | ++ (3 << 20) | /* cu_size_log2 */ ++ (param->p.log2_parallel_merge_level << 24); ++ ++ if (slice_type != I_SLICE) ++ val |= MPRED_CTRL0_MV_RD_EN; ++ ++ if (param->p.collocated_from_l0_flag) ++ val |= MPRED_CTRL0_COL_FROM_L0; ++ ++ if (param->p.slice_temporal_mvp_enable_flag) ++ val |= MPRED_CTRL0_TMVP; ++ ++ if (hevc->ldc_flag) ++ val |= MPRED_CTRL0_LDC; ++ ++ if (param->p.dependent_slice_segment_flag) ++ val |= MPRED_CTRL0_NEW_SLI_SEG; ++ ++ if (param->p.slice_segment_address == 0) ++ val |= MPRED_CTRL0_NEW_PIC | ++ MPRED_CTRL0_NEW_TILE; ++ ++ amvdec_write_dos(core, HEVC_MPRED_CTRL0, val); ++ ++ val = (5 - param->p.five_minus_max_num_merge_cand) | ++ (AMVP_MAX_NUM_CANDS << 4) | ++ (AMVP_MAX_NUM_CANDS_MEM << 8) | ++ (NUM_CHROMA_MODE << 12) | ++ (DM_CHROMA_IDX << 16); ++ amvdec_write_dos(core, HEVC_MPRED_CTRL1, val); ++} ++ ++static void codec_hevc_set_mpred_mv(struct amvdec_core *core, ++ struct codec_hevc *hevc, ++ struct hevc_frame *frame, ++ struct hevc_frame *col_frame) ++{ ++ union rpm_param *param = &hevc->rpm_param; ++ u32 lcu_size_log2 = ilog2(hevc->lcu_size); ++ u32 mv_mem_unit = lcu_size_log2 == 6 ? 0x200 : ++ lcu_size_log2 == 5 ? 0x80 : 0x20; ++ dma_addr_t col_mv_rd_start_addr, col_mv_rd_ptr, col_mv_rd_end_addr; ++ dma_addr_t mpred_mv_wr_ptr; ++ u32 val; ++ ++ val = amvdec_read_dos(core, HEVC_MPRED_CURR_LCU); ++ ++ col_mv_rd_start_addr = codec_hevc_get_frame_mv_paddr(hevc, col_frame); ++ mpred_mv_wr_ptr = codec_hevc_get_frame_mv_paddr(hevc, frame) + ++ (hevc->slice_addr * mv_mem_unit); ++ col_mv_rd_ptr = col_mv_rd_start_addr + ++ (hevc->slice_addr * mv_mem_unit); ++ col_mv_rd_end_addr = col_mv_rd_start_addr + ++ (hevc->lcu_total * mv_mem_unit); ++ ++ amvdec_write_dos(core, HEVC_MPRED_MV_WR_START_ADDR, ++ codec_hevc_get_frame_mv_paddr(hevc, frame)); ++ amvdec_write_dos(core, HEVC_MPRED_MV_RD_START_ADDR, ++ col_mv_rd_start_addr); ++ ++ if (param->p.slice_segment_address == 0) { ++ amvdec_write_dos(core, HEVC_MPRED_ABV_START_ADDR, ++ hevc->workspace_paddr + MPRED_ABV_OFFSET); ++ amvdec_write_dos(core, HEVC_MPRED_MV_WPTR, mpred_mv_wr_ptr); ++ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, ++ col_mv_rd_start_addr); ++ } else { ++ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, col_mv_rd_ptr); ++ } ++ ++ amvdec_write_dos(core, HEVC_MPRED_MV_RD_END_ADDR, col_mv_rd_end_addr); ++} ++ ++/* Update motion prediction with the current slice */ ++static void codec_hevc_set_mpred(struct amvdec_session *sess, ++ struct hevc_frame *frame, ++ struct hevc_frame *col_frame) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ u32 *ref_num = frame->ref_num; ++ u32 *ref_poc_l0 = frame->ref_poc_list[0][frame->cur_slice_idx]; ++ u32 *ref_poc_l1 = frame->ref_poc_list[1][frame->cur_slice_idx]; ++ u32 val; ++ int i; ++ ++ codec_hevc_set_mpred_ctrl(core, hevc); ++ codec_hevc_set_mpred_mv(core, hevc, frame, col_frame); ++ ++ amvdec_write_dos(core, HEVC_MPRED_PIC_SIZE, ++ hevc->width | (hevc->height << 16)); ++ ++ val = ((hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16); ++ amvdec_write_dos(core, HEVC_MPRED_PIC_SIZE_LCU, val); ++ ++ amvdec_write_dos(core, HEVC_MPRED_REF_NUM, ++ (ref_num[1] << 8) | ref_num[0]); ++ amvdec_write_dos(core, HEVC_MPRED_REF_EN_L0, (1 << ref_num[0]) - 1); ++ amvdec_write_dos(core, HEVC_MPRED_REF_EN_L1, (1 << ref_num[1]) - 1); ++ ++ amvdec_write_dos(core, HEVC_MPRED_CUR_POC, hevc->curr_poc); ++ amvdec_write_dos(core, HEVC_MPRED_COL_POC, hevc->col_poc); ++ ++ for (i = 0; i < MAX_REF_ACTIVE; ++i) { ++ amvdec_write_dos(core, HEVC_MPRED_L0_REF00_POC + i * 4, ++ ref_poc_l0[i]); ++ amvdec_write_dos(core, HEVC_MPRED_L1_REF00_POC + i * 4, ++ ref_poc_l1[i]); ++ } ++} ++ ++/* motion compensation reference cache controller */ ++static void codec_hevc_set_mcrcc(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ u32 val, val_2; ++ int l0_cnt = 0; ++ int l1_cnt = 0x7fff; ++ ++ if (!codec_hevc_use_fbc(sess)) { ++ l0_cnt = hevc->cur_frame->ref_num[0]; ++ l1_cnt = hevc->cur_frame->ref_num[1]; ++ } ++ ++ if (hevc->cur_frame->cur_slice_type == I_SLICE) { ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL1, 0); ++ return; ++ } ++ ++ if (hevc->cur_frame->cur_slice_type == P_SLICE) { ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, ++ BIT(1)); ++ val = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val &= 0xffff; ++ val |= (val << 16); ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL2, val); ++ ++ if (l0_cnt == 1) { ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); ++ } else { ++ val = amvdec_read_dos(core, ++ HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val &= 0xffff; ++ val |= (val << 16); ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); ++ } ++ } else { /* B_SLICE */ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 0); ++ val = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val &= 0xffff; ++ val |= (val << 16); ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL2, val); ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, ++ BIT(12) | BIT(1)); ++ val_2 = amvdec_read_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val_2 &= 0xffff; ++ val_2 |= (val_2 << 16); ++ if (val == val_2 && l1_cnt > 1) { ++ val_2 = amvdec_read_dos(core, ++ HEVCD_MPP_ANC_CANVAS_DATA_ADDR); ++ val_2 &= 0xffff; ++ val_2 |= (val_2 << 16); ++ } ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL3, val); ++ } ++ ++ /* enable mcrcc progressive-mode */ ++ amvdec_write_dos(core, HEVCD_MCRCC_CTL1, 0xff0); ++} ++ ++static void codec_hevc_set_ref_list(struct amvdec_session *sess, ++ u32 ref_num, u32 *ref_poc_list) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct hevc_frame *ref_frame; ++ struct amvdec_core *core = sess->core; ++ int i; ++ u32 buf_id_y; ++ u32 buf_id_uv; ++ ++ for (i = 0; i < ref_num; i++) { ++ ref_frame = codec_hevc_get_frame_by_poc(hevc, ref_poc_list[i]); ++ ++ if (!ref_frame) { ++ dev_warn(core->dev, "Couldn't find ref. frame %u\n", ++ ref_poc_list[i]); ++ continue; ++ } ++ ++ if (codec_hevc_use_fbc(sess)) { ++ buf_id_y = buf_id_uv = ref_frame->vbuf->vb2_buf.index; ++ } else { ++ buf_id_y = ref_frame->vbuf->vb2_buf.index * 2; ++ buf_id_uv = buf_id_y + 1; ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, ++ (buf_id_uv << 16) | ++ (buf_id_uv << 8) | ++ buf_id_y); ++ } ++} ++ ++static void codec_hevc_set_mc(struct amvdec_session *sess, struct hevc_frame *frame) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ if (frame->cur_slice_type == I_SLICE) ++ return; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ codec_hevc_set_ref_list(sess, frame->ref_num[0], ++ frame->ref_poc_list[0][frame->cur_slice_idx]); ++ ++ if (frame->cur_slice_type == P_SLICE) ++ return; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, ++ BIT(12) | BIT(0)); ++ codec_hevc_set_ref_list(sess, frame->ref_num[1], ++ frame->ref_poc_list[1][frame->cur_slice_idx]); ++} ++ ++static void codec_hevc_update_col_frame(struct codec_hevc *hevc) ++{ ++ struct hevc_frame *cur_frame = hevc->cur_frame; ++ union rpm_param *param = &hevc->rpm_param; ++ u32 list_no = 0; ++ u32 col_ref = param->p.collocated_ref_idx; ++ u32 col_from_l0 = param->p.collocated_from_l0_flag; ++ ++ if (cur_frame->cur_slice_type == B_SLICE) ++ list_no = 1 - col_from_l0; ++ ++ if (col_ref >= cur_frame->ref_num[list_no]) ++ hevc->col_poc = INVALID_POC; ++ else ++ hevc->col_poc = cur_frame->ref_poc_list[list_no][cur_frame->cur_slice_idx][col_ref]; ++ ++ if (cur_frame->cur_slice_type == I_SLICE) ++ goto end; ++ ++ if (hevc->col_poc != INVALID_POC) ++ hevc->col_frame = codec_hevc_get_frame_by_poc(hevc, hevc->col_poc); ++ else ++ hevc->col_frame = hevc->cur_frame; ++ ++end: ++ if (!hevc->col_frame) ++ hevc->col_frame = hevc->cur_frame; ++} ++ ++static void codec_hevc_update_pocs(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ union rpm_param *param = &hevc->rpm_param; ++ u32 nal_unit_type = param->p.m_nalUnitType; ++ u32 temporal_id = param->p.m_temporalId & 0x7; ++ int max_poc_lsb = ++ 1 << (param->p.log2_max_pic_order_cnt_lsb_minus4 + 4); ++ int prev_poc_lsb; ++ int prev_poc_msb; ++ int poc_msb; ++ int poc_lsb = param->p.POClsb; ++ ++ if (nal_unit_type == NAL_UNIT_CODED_SLICE_IDR || ++ nal_unit_type == NAL_UNIT_CODED_SLICE_IDR_N_LP) { ++ hevc->curr_poc = 0; ++ if ((temporal_id - 1) == 0) ++ hevc->prev_tid0_poc = hevc->curr_poc; ++ ++ return; ++ } ++ ++ prev_poc_lsb = hevc->prev_tid0_poc % max_poc_lsb; ++ prev_poc_msb = hevc->prev_tid0_poc - prev_poc_lsb; ++ ++ if ((poc_lsb < prev_poc_lsb) && ++ ((prev_poc_lsb - poc_lsb) >= (max_poc_lsb / 2))) ++ poc_msb = prev_poc_msb + max_poc_lsb; ++ else if ((poc_lsb > prev_poc_lsb) && ++ ((poc_lsb - prev_poc_lsb) > (max_poc_lsb / 2))) ++ poc_msb = prev_poc_msb - max_poc_lsb; ++ else ++ poc_msb = prev_poc_msb; ++ ++ if (nal_unit_type == NAL_UNIT_CODED_SLICE_BLA || ++ nal_unit_type == NAL_UNIT_CODED_SLICE_BLANT || ++ nal_unit_type == NAL_UNIT_CODED_SLICE_BLA_N_LP) ++ poc_msb = 0; ++ ++ hevc->curr_poc = (poc_msb + poc_lsb); ++ if ((temporal_id - 1) == 0) ++ hevc->prev_tid0_poc = hevc->curr_poc; ++} ++ ++static void codec_hevc_process_segment_header(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ union rpm_param *param = &hevc->rpm_param; ++ ++ if (param->p.first_slice_segment_in_pic_flag == 0) { ++ hevc->slice_segment_addr = param->p.slice_segment_address; ++ if (!param->p.dependent_slice_segment_flag) ++ hevc->slice_addr = hevc->slice_segment_addr; ++ } else { ++ hevc->slice_segment_addr = 0; ++ hevc->slice_addr = 0; ++ } ++ ++ codec_hevc_update_pocs(sess); ++} ++ ++static int codec_hevc_process_segment(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ struct amvdec_core *core = sess->core; ++ union rpm_param *param = &hevc->rpm_param; ++ u32 slice_segment_address = param->p.slice_segment_address; ++ ++ /* First slice: new frame */ ++ if (slice_segment_address == 0) { ++ codec_hevc_update_referenced(hevc); ++ codec_hevc_output_frames(sess); ++ ++ hevc->cur_frame = codec_hevc_prepare_new_frame(sess); ++ if (!hevc->cur_frame) ++ return -1; ++ } else { ++ hevc->cur_frame->cur_slice_idx++; ++ } ++ ++ codec_hevc_update_frame_refs(sess, hevc->cur_frame); ++ codec_hevc_update_col_frame(hevc); ++ codec_hevc_update_ldc_flag(hevc); ++ codec_hevc_set_mc(sess, hevc->cur_frame); ++ codec_hevc_set_mcrcc(sess); ++ codec_hevc_set_mpred(sess, hevc->cur_frame, hevc->col_frame); ++ codec_hevc_set_sao(sess, hevc->cur_frame); ++ ++ amvdec_write_dos_bits(core, HEVC_WAIT_FLAG, BIT(1)); ++ amvdec_write_dos(core, HEVC_DEC_STATUS_REG, ++ HEVC_CODED_SLICE_SEGMENT_DAT); ++ ++ /* Interrupt the firmware's processor */ ++ amvdec_write_dos(core, HEVC_MCPU_INTR_REQ, AMRISC_MAIN_REQ); ++ ++ return 0; ++} ++ ++static int codec_hevc_process_rpm(struct codec_hevc *hevc) ++{ ++ union rpm_param *param = &hevc->rpm_param; ++ int src_changed = 0; ++ u32 dst_width, dst_height; ++ u32 lcu_size; ++ u32 is_10bit; ++ ++ if (param->p.slice_segment_address || ++ !param->p.pic_width_in_luma_samples || ++ !param->p.pic_height_in_luma_samples) ++ return 0; ++ ++ if (param->p.bit_depth) ++ is_10bit = 1; ++ ++ hevc->width = param->p.pic_width_in_luma_samples; ++ hevc->height = param->p.pic_height_in_luma_samples; ++ dst_width = hevc->width; ++ dst_height = hevc->height; ++ ++ lcu_size = 1 << (param->p.log2_min_coding_block_size_minus3 + ++ 3 + param->p.log2_diff_max_min_coding_block_size); ++ ++ hevc->lcu_x_num = (hevc->width + lcu_size - 1) / lcu_size; ++ hevc->lcu_y_num = (hevc->height + lcu_size - 1) / lcu_size; ++ hevc->lcu_total = hevc->lcu_x_num * hevc->lcu_y_num; ++ ++ if (param->p.conformance_window_flag) { ++ u32 sub_width = 1, sub_height = 1; ++ ++ switch (param->p.chroma_format_idc) { ++ case 1: ++ sub_height = 2; ++ case 2: ++ sub_width = 2; ++ break; ++ } ++ ++ dst_width -= sub_width * ++ (param->p.conf_win_left_offset + ++ param->p.conf_win_right_offset); ++ dst_height -= sub_height * ++ (param->p.conf_win_top_offset + ++ param->p.conf_win_bottom_offset); ++ } ++ ++ if (dst_width != hevc->dst_width || ++ dst_height != hevc->dst_height || ++ lcu_size != hevc->lcu_size || ++ is_10bit != hevc->is_10bit) ++ src_changed = 1; ++ ++ hevc->dst_width = dst_width; ++ hevc->dst_height = dst_height; ++ hevc->lcu_size = lcu_size; ++ hevc->is_10bit = is_10bit; ++ ++ return src_changed; ++} ++ ++/* The RPM section within the workspace contains ++ * many information regarding the parsed bitstream ++ */ ++static void codec_hevc_fetch_rpm(struct amvdec_session *sess) ++{ ++ struct codec_hevc *hevc = sess->priv; ++ u16 *rpm_vaddr = hevc->workspace_vaddr + RPM_OFFSET; ++ int i, j; ++ ++ for (i = 0; i < RPM_SIZE; i += 4) ++ for (j = 0; j < 4; j++) ++ hevc->rpm_param.l.data[i + j] = rpm_vaddr[i + 3 - j]; ++} ++ ++static void codec_hevc_resume(struct amvdec_session *sess) ++{ ++ if (codec_hevc_setup_buffers(sess)) { ++ amvdec_abort(sess); ++ return; ++ } ++ ++ codec_hevc_setup_decode_head(sess); ++ codec_hevc_process_segment_header(sess); ++ if (codec_hevc_process_segment(sess)) ++ amvdec_abort(sess); ++} ++ ++static irqreturn_t codec_hevc_threaded_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_hevc *hevc = sess->priv; ++ u32 dec_status = amvdec_read_dos(core, HEVC_DEC_STATUS_REG); ++ ++ if (!hevc) ++ return IRQ_HANDLED; ++ ++ mutex_lock(&hevc->lock); ++ if (dec_status != HEVC_SLICE_SEGMENT_DONE) { ++ dev_err(core->dev_dec, "Unrecognized dec_status: %08X\n", ++ dec_status); ++ amvdec_abort(sess); ++ goto unlock; ++ } ++ ++ sess->keyframe_found = 1; ++ codec_hevc_fetch_rpm(sess); ++ if (codec_hevc_process_rpm(hevc)) { ++ amvdec_src_change(sess, hevc->dst_width, hevc->dst_height, 16); ++ goto unlock; ++ } ++ ++ codec_hevc_process_segment_header(sess); ++ if (codec_hevc_process_segment(sess)) ++ amvdec_abort(sess); ++ ++unlock: ++ mutex_unlock(&hevc->lock); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t codec_hevc_isr(struct amvdec_session *sess) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++struct amvdec_codec_ops codec_hevc_ops = { ++ .start = codec_hevc_start, ++ .stop = codec_hevc_stop, ++ .isr = codec_hevc_isr, ++ .threaded_isr = codec_hevc_threaded_isr, ++ .num_pending_bufs = codec_hevc_num_pending_bufs, ++ .drain = codec_hevc_flush_output, ++ .resume = codec_hevc_resume, ++}; +diff --git a/drivers/media/platform/meson/vdec/codec_hevc.h b/drivers/media/platform/meson/vdec/codec_hevc.h +new file mode 100644 +index 0000000000000..5017e874e3ddc +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_hevc.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_HEVC_H_ ++#define __MESON_VDEC_CODEC_HEVC_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_hevc_ops; ++ ++#endif +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h +new file mode 100644 +index 0000000000000..ba49f906be5a9 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/hevc_regs.h +@@ -0,0 +1,205 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. ++ */ ++ ++#ifndef __MESON_VDEC_HEVC_REGS_H_ ++#define __MESON_VDEC_HEVC_REGS_H_ ++ ++#define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4 ++#define HEVC_ASSIST_MBOX1_MASK 0xc1d8 ++ ++#define HEVC_ASSIST_SCRATCH_0 0xc300 ++#define HEVC_ASSIST_SCRATCH_1 0xc304 ++#define HEVC_ASSIST_SCRATCH_2 0xc308 ++#define HEVC_ASSIST_SCRATCH_3 0xc30c ++#define HEVC_ASSIST_SCRATCH_4 0xc310 ++#define HEVC_ASSIST_SCRATCH_5 0xc314 ++#define HEVC_ASSIST_SCRATCH_6 0xc318 ++#define HEVC_ASSIST_SCRATCH_7 0xc31c ++#define HEVC_ASSIST_SCRATCH_8 0xc320 ++#define HEVC_ASSIST_SCRATCH_9 0xc324 ++#define HEVC_ASSIST_SCRATCH_A 0xc328 ++#define HEVC_ASSIST_SCRATCH_B 0xc32c ++#define HEVC_ASSIST_SCRATCH_C 0xc330 ++#define HEVC_ASSIST_SCRATCH_D 0xc334 ++#define HEVC_ASSIST_SCRATCH_E 0xc338 ++#define HEVC_ASSIST_SCRATCH_F 0xc33c ++#define HEVC_ASSIST_SCRATCH_G 0xc340 ++#define HEVC_ASSIST_SCRATCH_H 0xc344 ++#define HEVC_ASSIST_SCRATCH_I 0xc348 ++#define HEVC_ASSIST_SCRATCH_J 0xc34c ++#define HEVC_ASSIST_SCRATCH_K 0xc350 ++#define HEVC_ASSIST_SCRATCH_L 0xc354 ++#define HEVC_ASSIST_SCRATCH_M 0xc358 ++#define HEVC_ASSIST_SCRATCH_N 0xc35c ++ ++#define HEVC_PARSER_VERSION 0xc400 ++#define HEVC_STREAM_CONTROL 0xc404 ++#define HEVC_STREAM_START_ADDR 0xc408 ++#define HEVC_STREAM_END_ADDR 0xc40c ++#define HEVC_STREAM_WR_PTR 0xc410 ++#define HEVC_STREAM_RD_PTR 0xc414 ++#define HEVC_STREAM_LEVEL 0xc418 ++#define HEVC_STREAM_FIFO_CTL 0xc41c ++#define HEVC_SHIFT_CONTROL 0xc420 ++#define HEVC_SHIFT_STARTCODE 0xc424 ++#define HEVC_SHIFT_EMULATECODE 0xc428 ++#define HEVC_SHIFT_STATUS 0xc42c ++#define HEVC_SHIFTED_DATA 0xc430 ++#define HEVC_SHIFT_BYTE_COUNT 0xc434 ++#define HEVC_SHIFT_COMMAND 0xc438 ++#define HEVC_ELEMENT_RESULT 0xc43c ++#define HEVC_CABAC_CONTROL 0xc440 ++#define HEVC_PARSER_SLICE_INFO 0xc444 ++#define HEVC_PARSER_CMD_WRITE 0xc448 ++#define HEVC_PARSER_CORE_CONTROL 0xc44c ++#define HEVC_PARSER_CMD_FETCH 0xc450 ++#define HEVC_PARSER_CMD_STATUS 0xc454 ++#define HEVC_PARSER_LCU_INFO 0xc458 ++#define HEVC_PARSER_HEADER_INFO 0xc45c ++#define HEVC_PARSER_INT_CONTROL 0xc480 ++#define HEVC_PARSER_INT_STATUS 0xc484 ++#define HEVC_PARSER_IF_CONTROL 0xc488 ++#define HEVC_PARSER_PICTURE_SIZE 0xc48c ++#define HEVC_PARSER_LCU_START 0xc490 ++#define HEVC_PARSER_HEADER_INFO2 0xc494 ++#define HEVC_PARSER_QUANT_READ 0xc498 ++#define HEVC_PARSER_RESERVED_27 0xc49c ++#define HEVC_PARSER_CMD_SKIP_0 0xc4a0 ++#define HEVC_PARSER_CMD_SKIP_1 0xc4a4 ++#define HEVC_PARSER_CMD_SKIP_2 0xc4a8 ++#define HEVC_SAO_IF_STATUS 0xc4c0 ++#define HEVC_SAO_IF_DATA_Y 0xc4c4 ++#define HEVC_SAO_IF_DATA_U 0xc4c8 ++#define HEVC_SAO_IF_DATA_V 0xc4cc ++#define HEVC_STREAM_SWAP_ADDR 0xc4d0 ++#define HEVC_STREAM_SWAP_CTRL 0xc4d4 ++#define HEVC_IQIT_IF_WAIT_CNT 0xc4d8 ++#define HEVC_MPRED_IF_WAIT_CNT 0xc4dc ++#define HEVC_SAO_IF_WAIT_CNT 0xc4e0 ++ ++#define HEVC_MPRED_VERSION 0xc800 ++#define HEVC_MPRED_CTRL0 0xc804 ++ #define MPRED_CTRL0_NEW_PIC BIT(2) ++ #define MPRED_CTRL0_NEW_TILE BIT(3) ++ #define MPRED_CTRL0_NEW_SLI_SEG BIT(4) ++ #define MPRED_CTRL0_TMVP BIT(5) ++ #define MPRED_CTRL0_LDC BIT(6) ++ #define MPRED_CTRL0_COL_FROM_L0 BIT(7) ++ #define MPRED_CTRL0_ABOVE_EN BIT(9) ++ #define MPRED_CTRL0_MV_WR_EN BIT(10) ++ #define MPRED_CTRL0_MV_RD_EN BIT(11) ++ #define MPRED_CTRL0_BUF_LINEAR BIT(13) ++#define HEVC_MPRED_CTRL1 0xc808 ++#define HEVC_MPRED_INT_EN 0xc80c ++#define HEVC_MPRED_INT_STATUS 0xc810 ++#define HEVC_MPRED_PIC_SIZE 0xc814 ++#define HEVC_MPRED_PIC_SIZE_LCU 0xc818 ++#define HEVC_MPRED_TILE_START 0xc81c ++#define HEVC_MPRED_TILE_SIZE_LCU 0xc820 ++#define HEVC_MPRED_REF_NUM 0xc824 ++#define HEVC_MPRED_REF_EN_L0 0xc830 ++#define HEVC_MPRED_REF_EN_L1 0xc834 ++#define HEVC_MPRED_COLREF_EN_L0 0xc838 ++#define HEVC_MPRED_COLREF_EN_L1 0xc83c ++#define HEVC_MPRED_AXI_WCTRL 0xc840 ++#define HEVC_MPRED_AXI_RCTRL 0xc844 ++#define HEVC_MPRED_ABV_START_ADDR 0xc848 ++#define HEVC_MPRED_MV_WR_START_ADDR 0xc84c ++#define HEVC_MPRED_MV_RD_START_ADDR 0xc850 ++#define HEVC_MPRED_MV_WPTR 0xc854 ++#define HEVC_MPRED_MV_RPTR 0xc858 ++#define HEVC_MPRED_MV_WR_ROW_JUMP 0xc85c ++#define HEVC_MPRED_MV_RD_ROW_JUMP 0xc860 ++#define HEVC_MPRED_CURR_LCU 0xc864 ++#define HEVC_MPRED_ABV_WPTR 0xc868 ++#define HEVC_MPRED_ABV_RPTR 0xc86c ++#define HEVC_MPRED_CTRL2 0xc870 ++#define HEVC_MPRED_CTRL3 0xc874 ++#define HEVC_MPRED_L0_REF00_POC 0xc880 ++#define HEVC_MPRED_L1_REF00_POC 0xc8c0 ++ ++#define HEVC_MPRED_CUR_POC 0xc980 ++#define HEVC_MPRED_COL_POC 0xc984 ++#define HEVC_MPRED_MV_RD_END_ADDR 0xc988 ++ ++#define HEVC_MSP 0xcc00 ++#define HEVC_MPSR 0xcc04 ++#define HEVC_MCPU_INTR_MSK 0xcc10 ++#define HEVC_MCPU_INTR_REQ 0xcc14 ++#define HEVC_CPSR 0xcc84 ++ ++#define HEVC_IMEM_DMA_CTRL 0xcd00 ++#define HEVC_IMEM_DMA_ADR 0xcd04 ++#define HEVC_IMEM_DMA_COUNT 0xcd08 ++ ++#define HEVCD_IPP_TOP_CNTL 0xd000 ++#define HEVCD_IPP_LINEBUFF_BASE 0xd024 ++#define HEVCD_IPP_AXIIF_CONFIG 0xd02c ++ ++#define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180 ++#define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184 ++#define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190 ++ ++#define HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR 0xd300 ++#define HEVCD_MPP_ANC_CANVAS_DATA_ADDR 0xd304 ++#define HEVCD_MPP_DECOMP_CTL1 0xd308 ++#define HEVCD_MPP_DECOMP_CTL2 0xd30c ++#define HEVCD_MCRCC_CTL1 0xd3c0 ++#define HEVCD_MCRCC_CTL2 0xd3c4 ++#define HEVCD_MCRCC_CTL3 0xd3c8 ++ ++#define HEVC_DBLK_CFG0 0xd400 ++#define HEVC_DBLK_CFG1 0xd404 ++#define HEVC_DBLK_CFG2 0xd408 ++#define HEVC_DBLK_CFG3 0xd40c ++#define HEVC_DBLK_CFG4 0xd410 ++#define HEVC_DBLK_CFG5 0xd414 ++#define HEVC_DBLK_CFG6 0xd418 ++#define HEVC_DBLK_CFG7 0xd41c ++#define HEVC_DBLK_CFG8 0xd420 ++#define HEVC_DBLK_CFG9 0xd424 ++#define HEVC_DBLK_CFGA 0xd428 ++#define HEVC_DBLK_STS0 0xd42c ++#define HEVC_DBLK_STS1 0xd430 ++ ++#define HEVC_SAO_VERSION 0xd800 ++#define HEVC_SAO_CTRL0 0xd804 ++#define HEVC_SAO_CTRL1 0xd808 ++#define HEVC_SAO_PIC_SIZE 0xd814 ++#define HEVC_SAO_PIC_SIZE_LCU 0xd818 ++#define HEVC_SAO_TILE_START 0xd81c ++#define HEVC_SAO_TILE_SIZE_LCU 0xd820 ++#define HEVC_SAO_Y_START_ADDR 0xd82c ++#define HEVC_SAO_Y_LENGTH 0xd830 ++#define HEVC_SAO_C_START_ADDR 0xd834 ++#define HEVC_SAO_C_LENGTH 0xd838 ++#define HEVC_SAO_Y_WPTR 0xd83c ++#define HEVC_SAO_C_WPTR 0xd840 ++#define HEVC_SAO_ABV_START_ADDR 0xd844 ++#define HEVC_SAO_VB_WR_START_ADDR 0xd848 ++#define HEVC_SAO_VB_RD_START_ADDR 0xd84c ++#define HEVC_SAO_ABV_WPTR 0xd850 ++#define HEVC_SAO_ABV_RPTR 0xd854 ++#define HEVC_SAO_VB_WPTR 0xd858 ++#define HEVC_SAO_VB_RPTR 0xd85c ++#define HEVC_SAO_CTRL2 0xd880 ++#define HEVC_SAO_CTRL3 0xd884 ++#define HEVC_SAO_CTRL4 0xd888 ++#define HEVC_SAO_CTRL5 0xd88c ++#define HEVC_SAO_CTRL6 0xd890 ++#define HEVC_SAO_CTRL7 0xd894 ++#define HEVC_CM_BODY_START_ADDR 0xd898 ++#define HEVC_CM_BODY_LENGTH 0xd89c ++#define HEVC_CM_HEADER_LENGTH 0xd8a4 ++#define HEVC_CM_HEADER_OFFSET 0xd8ac ++ ++#define HEVC_IQIT_CLK_RST_CTRL 0xdc00 ++#define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08 ++#define HEVC_IQIT_SCALELUT_RD_ADDR 0xdc0c ++#define HEVC_IQIT_SCALELUT_DATA 0xdc10 ++ ++#define HEVC_PSCALE_CTRL 0xe444 ++ ++#endif +diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.c b/drivers/media/platform/meson/vdec/vdec_hevc.c +new file mode 100644 +index 0000000000000..8872f58d39fea +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_hevc.c +@@ -0,0 +1,191 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ * ++ * VDEC_HEVC is a video decoding block that allows decoding of ++ * HEVC, VP9 ++ */ ++ ++#include ++#include ++ ++#include "vdec_1.h" ++#include "vdec_helpers.h" ++#include "hevc_regs.h" ++#include "dos_regs.h" ++ ++/* AO Registers */ ++#define AO_RTI_GEN_PWR_SLEEP0 0xe8 ++#define AO_RTI_GEN_PWR_ISO0 0xec ++ #define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6)) ++ ++#define MC_SIZE (4096 * 4) ++ ++static int vdec_hevc_load_firmware(struct amvdec_session *sess, const char* fwname) ++{ ++ struct amvdec_core *core = sess->core; ++ struct device *dev = core->dev_dec; ++ const struct firmware *fw; ++ static void *mc_addr; ++ static dma_addr_t mc_addr_map; ++ int ret; ++ u32 i = 100; ++ ++ ret = request_firmware(&fw, fwname, dev); ++ if (ret < 0) { ++ dev_err(dev, "Unable to request firmware %s\n", fwname); ++ return ret; ++ } ++ ++ if (fw->size < MC_SIZE) { ++ dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", ++ fw->size, MC_SIZE); ++ ret = -EINVAL; ++ goto release_firmware; ++ } ++ ++ mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map, GFP_KERNEL); ++ if (!mc_addr) { ++ dev_err(dev, "Failed allocating memory for firmware loading\n"); ++ ret = -ENOMEM; ++ goto release_firmware; ++ } ++ ++ memcpy(mc_addr, fw->data, MC_SIZE); ++ ++ amvdec_write_dos(core, HEVC_MPSR, 0); ++ amvdec_write_dos(core, HEVC_CPSR, 0); ++ ++ amvdec_write_dos(core, HEVC_IMEM_DMA_ADR, mc_addr_map); ++ amvdec_write_dos(core, HEVC_IMEM_DMA_COUNT, MC_SIZE / 4); ++ amvdec_write_dos(core, HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); ++ ++ while (--i && readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000) { } ++ ++ if (i == 0) { ++ dev_err(dev, "Firmware load fail (DMA hang?)\n"); ++ ret = -ENODEV; ++ } ++ ++ dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); ++release_firmware: ++ release_firmware(fw); ++ return ret; ++} ++ ++static void vdec_hevc_stbuf_init(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) & ~1); ++ amvdec_write_dos(core, HEVC_STREAM_START_ADDR, sess->vififo_paddr); ++ amvdec_write_dos(core, HEVC_STREAM_END_ADDR, sess->vififo_paddr + sess->vififo_size); ++ amvdec_write_dos(core, HEVC_STREAM_RD_PTR, sess->vififo_paddr); ++ amvdec_write_dos(core, HEVC_STREAM_WR_PTR, sess->vififo_paddr); ++} ++ ++/* VDEC_HEVC specific ESPARSER configuration */ ++static void vdec_hevc_conf_esparser(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ ++ /* set vififo_vbuf_rp_sel=>vdec_hevc */ ++ amvdec_write_dos(core, DOS_GEN_CTRL0, 3 << 1); ++ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) | BIT(3)); ++ amvdec_write_dos(core, HEVC_STREAM_CONTROL, amvdec_read_dos(core, HEVC_STREAM_CONTROL) | 1); ++ amvdec_write_dos(core, HEVC_STREAM_FIFO_CTL, amvdec_read_dos(core, HEVC_STREAM_FIFO_CTL) | BIT(29)); ++} ++ ++static u32 vdec_hevc_vififo_level(struct amvdec_session *sess) ++{ ++ return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL); ++} ++ ++static int vdec_hevc_stop(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ ++ /* Disable interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 0); ++ /* Disable firmware processor */ ++ amvdec_write_dos(core, HEVC_MPSR, 0); ++ ++ if (sess->priv) ++ codec_ops->stop(sess); ++ ++ /* Enable VDEC_HEVC Isolation */ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc00, 0xc00); ++ ++ /* VDEC_HEVC Memories */ ++ amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0xffffffffUL); ++ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); ++ ++ clk_disable_unprepare(core->vdec_hevc_clk); ++ ++ return 0; ++} ++ ++static int vdec_hevc_start(struct amvdec_session *sess) ++{ ++ int ret; ++ struct amvdec_core *core = sess->core; ++ struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; ++ ++ clk_set_rate(core->vdec_hevc_clk, 666666666); ++ ret = clk_prepare_enable(core->vdec_hevc_clk); ++ if (ret) ++ return ret; ++ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, ++ GEN_PWR_VDEC_HEVC, 0); ++ udelay(10); ++ ++ /* Reset VDEC_HEVC*/ ++ amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); ++ amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); ++ ++ amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff); ++ ++ /* VDEC_HEVC Memories */ ++ amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000); ++ ++ /* Remove VDEC_HEVC Isolation */ ++ regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc00, 0); ++ ++ amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); ++ amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); ++ ++ vdec_hevc_stbuf_init(sess); ++ ++ ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path); ++ if (ret) ++ goto stop; ++ ++ ret = codec_ops->start(sess); ++ if (ret) ++ goto stop; ++ ++ amvdec_write_dos(core, DOS_SW_RESET3, BIT(12)|BIT(11)); ++ amvdec_write_dos(core, DOS_SW_RESET3, 0); ++ amvdec_read_dos(core, DOS_SW_RESET3); ++ ++ amvdec_write_dos(core, HEVC_MPSR, 1); ++ /* Let the firmware settle */ ++ udelay(10); ++ ++ return 0; ++ ++stop: ++ vdec_hevc_stop(sess); ++ return ret; ++} ++ ++struct amvdec_ops vdec_hevc_ops = { ++ .start = vdec_hevc_start, ++ .stop = vdec_hevc_stop, ++ .conf_esparser = vdec_hevc_conf_esparser, ++ .vififo_level = vdec_hevc_vififo_level, ++}; +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.h b/drivers/media/platform/meson/vdec/vdec_hevc.h +new file mode 100644 +index 0000000000000..f1ccad7d5f949 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/vdec_hevc.h +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 and ++ * only version 2 as published by the Free Software Foundation. ++ * ++ * 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. ++ * ++ */ ++ ++#ifndef __MESON_VDEC_VDEC_HEVC_H_ ++#define __MESON_VDEC_VDEC_HEVC_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_ops vdec_hevc_ops; ++ ++#endif +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c +index 9cf978e9050d3..8a76518cdcde7 100644 +--- a/drivers/media/platform/meson/vdec/vdec_platform.c ++++ b/drivers/media/platform/meson/vdec/vdec_platform.c +@@ -8,13 +8,25 @@ + #include "vdec.h" + + #include "vdec_1.h" ++#include "vdec_hevc.h" + #include "codec_mpeg12.h" + #include "codec_h264.h" + #include "codec_mpeg4.h" + #include "codec_mjpeg.h" ++#include "codec_hevc.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { ++ .pixfmt = V4L2_PIX_FMT_HEVC, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_hevc_ops, ++ .firmware_path = "meson/gx/vh265_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MJPEG, + .min_buffers = 4, + .max_buffers = 4, +@@ -91,6 +103,16 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + + static const struct amvdec_format vdec_formats_gxl[] = { + { ++ .pixfmt = V4L2_PIX_FMT_HEVC, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_hevc_ops, ++ .firmware_path = "meson/gx/vh265_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MJPEG, + .min_buffers = 4, + .max_buffers = 4, +@@ -167,6 +189,16 @@ static const struct amvdec_format vdec_formats_gxl[] = { + + static const struct amvdec_format vdec_formats_gxm[] = { + { ++ .pixfmt = V4L2_PIX_FMT_HEVC, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_hevc_ops, ++ .firmware_path = "meson/gx/vh265_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, { + .pixfmt = V4L2_PIX_FMT_MJPEG, + .min_buffers = 4, + .max_buffers = 4, + +From e7ad26a92d8e44a13848a89830ec6f264cd9d5be Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Mon, 3 Dec 2018 10:25:00 +0100 +Subject: [PATCH 216/249] WIP: meson: vdec: Map the Firmware buf idx <-> VB2 + buf idx + +The current code assumes the vb2 indexes are in order (0 -> n) when +iterating over them. This is very wrong and, in the case where they are +not in the perfect order, will generate mismatches between the firmware +internal buffer indexes and the VB2 ones. + +This fixes this bad assumption by explicitely mapping the buffer index. +--- + drivers/media/platform/meson/vdec/vdec.h | 1 + + drivers/media/platform/meson/vdec/vdec_helpers.c | 7 ++++++- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h +index 9f1e307057220..6597e26cc855e 100644 +--- a/drivers/media/platform/meson/vdec/vdec.h ++++ b/drivers/media/platform/meson/vdec/vdec.h +@@ -255,6 +255,7 @@ struct amvdec_session { + u32 last_offset; + u32 wrap_count; + u32 dpb_size; ++ u32 fw_idx_to_vb2_idx[32]; + + enum amvdec_status status; + void *priv; +diff --git a/drivers/media/platform/meson/vdec/vdec_helpers.c b/drivers/media/platform/meson/vdec/vdec_helpers.c +index 7bb7a6dad5874..0c233fd3b77d1 100644 +--- a/drivers/media/platform/meson/vdec/vdec_helpers.c ++++ b/drivers/media/platform/meson/vdec/vdec_helpers.c +@@ -186,6 +186,7 @@ int amvdec_set_canvases(struct amvdec_session *sess, + u32 reg_cur = reg_base[0]; + u32 reg_num_cur = 0; + u32 reg_base_cur = 0; ++ int i = 0; + int ret; + + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { +@@ -218,6 +219,8 @@ int amvdec_set_canvases(struct amvdec_session *sess, + reg_base_cur++; + reg_num_cur = 0; + } ++ ++ sess->fw_idx_to_vb2_idx[i++] = buf->vb.vb2_buf.index; + } + + return 0; +@@ -409,7 +412,9 @@ void amvdec_dst_buf_done_idx(struct amvdec_session *sess, + struct vb2_v4l2_buffer *vbuf; + struct device *dev = sess->core->dev_dec; + +- vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, buf_idx); ++ vbuf = v4l2_m2m_dst_buf_remove_by_idx(sess->m2m_ctx, ++ sess->fw_idx_to_vb2_idx[buf_idx]); ++ + if (!vbuf) { + dev_err(dev, + "Buffer %u done but it doesn't exist in m2m_ctx\n", + +From 3a03e68b4abd1676af681a4986b68ad05de1450d Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 17 Jan 2019 16:58:29 +0100 +Subject: [PATCH 217/249] WIP: media: meson: vdec: commonize some HEVC code + +Will be shared with the VP9 codebase. +--- + drivers/media/platform/meson/vdec/Makefile | 2 +- + .../media/platform/meson/vdec/codec_hevc.c | 239 ++---------------- + .../platform/meson/vdec/codec_hevc_common.c | 188 ++++++++++++++ + .../platform/meson/vdec/codec_hevc_common.h | 49 ++++ + drivers/media/platform/meson/vdec/vdec.h | 7 +- + 5 files changed, 260 insertions(+), 225 deletions(-) + create mode 100644 drivers/media/platform/meson/vdec/codec_hevc_common.c + create mode 100644 drivers/media/platform/meson/vdec/codec_hevc_common.h + +diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile +index ddcf38a7c3e65..4fba9e052f14f 100644 +--- a/drivers/media/platform/meson/vdec/Makefile ++++ b/drivers/media/platform/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o vdec_hevc.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c +index 116e9ffc4560d..03f00f969f025 100644 +--- a/drivers/media/platform/meson/vdec/codec_hevc.c ++++ b/drivers/media/platform/meson/vdec/codec_hevc.c +@@ -1,6 +1,6 @@ + // SPDX-License-Identifier: GPL-2.0+ + /* +- * Copyright (C) 2018 Maxime Jourdan ++ * Copyright (C) 2018 Maxime Jourdan + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. + */ + +@@ -11,6 +11,7 @@ + #include "dos_regs.h" + #include "hevc_regs.h" + #include "vdec_helpers.h" ++#include "codec_hevc_common.h" + + /* HEVC reg mapping */ + #define HEVC_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 +@@ -135,22 +136,6 @@ + #define RPM_SIZE 0x80 + #define RPS_USED_BIT 14 + +-#define PARSER_CMD_SKIP_CFG_0 0x0000090b +-#define PARSER_CMD_SKIP_CFG_1 0x1b14140f +-#define PARSER_CMD_SKIP_CFG_2 0x001b1910 +-static const u16 parser_cmd[] = { +- 0x0401, 0x8401, 0x0800, 0x0402, +- 0x9002, 0x1423, 0x8CC3, 0x1423, +- 0x8804, 0x9825, 0x0800, 0x04FE, +- 0x8406, 0x8411, 0x1800, 0x8408, +- 0x8409, 0x8C2A, 0x9C2B, 0x1C00, +- 0x840F, 0x8407, 0x8000, 0x8408, +- 0x2000, 0xA800, 0x8410, 0x04DE, +- 0x840C, 0x840D, 0xAC00, 0xA000, +- 0x08C0, 0x08E0, 0xA40E, 0xFC00, +- 0x7C00 +-}; +- + /* Data received from the HW in this form, do not rearrange */ + union rpm_param { + struct { +@@ -289,28 +274,8 @@ struct codec_hevc { + + /* Whether we detected the bitstream as 10-bit */ + int is_10bit; +- +- /* In case of downsampling (decoding with FBC but outputting in NV12M), +- * we need to allocate additional buffers for FBC. +- */ +- void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; +- dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; + }; + +-/* Returns 1 if we must use framebuffer compression */ +-static int codec_hevc_use_fbc(struct amvdec_session *sess) +-{ +- struct codec_hevc *hevc = sess->priv; +- return sess->pixfmt_cap == V4L2_PIX_FMT_AM21C || hevc->is_10bit; +-} +- +-/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */ +-static int codec_hevc_use_downsample(struct amvdec_session *sess) +-{ +- struct codec_hevc *hevc = sess->priv; +- return sess->pixfmt_cap == V4L2_PIX_FMT_NV12M && hevc->is_10bit; +-} +- + static u32 codec_hevc_num_pending_bufs(struct amvdec_session *sess) + { + struct codec_hevc *hevc; +@@ -526,181 +491,6 @@ static void codec_hevc_output_frames(struct amvdec_session *sess) + } + } + +-/* Configure decode head read mode */ +-static void codec_hevc_setup_decode_head(struct amvdec_session *sess) +-{ +- struct amvdec_core *core = sess->core; +- u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); +- u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); +- +- if (!codec_hevc_use_fbc(sess)) { +- /* Enable 2-plane reference read mode */ +- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); +- return; +- } +- +- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); +- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); +- amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); +- amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); +- amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); +-} +- +-static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess) +-{ +- struct amvdec_core *core = sess->core; +- struct codec_hevc *hevc = sess->priv; +- struct v4l2_m2m_buffer *buf; +- u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); +- dma_addr_t buf_y_paddr = 0; +- dma_addr_t buf_uv_paddr = 0; +- u32 idx = 0; +- u32 val; +- int i; +- +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); +- +- v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { +- idx = buf->vb.vb2_buf.index; +- +- if (codec_hevc_use_downsample(sess)) +- buf_y_paddr = hevc->fbc_buffer_paddr[idx]; +- else +- buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); +- +- if (codec_hevc_use_fbc(sess)) { +- val = buf_y_paddr | (idx << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); +- } else { +- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); +- val = buf_y_paddr | ((idx * 2) << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); +- val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); +- } +- } +- +- if (codec_hevc_use_fbc(sess)) +- val = buf_y_paddr | (idx << 8) | 1; +- else +- val = buf_y_paddr | ((idx * 2) << 8) | 1; +- +- /* Fill the remaining unused slots with the last buffer's Y addr */ +- for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); +- +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); +- amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); +- for (i = 0; i < 32; ++i) +- amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); +-} +- +-static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess) +-{ +- struct amvdec_core *core = sess->core; +- struct codec_hevc *hevc = sess->priv; +- struct v4l2_m2m_buffer *buf; +- u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); +- dma_addr_t buf_y_paddr = 0; +- dma_addr_t buf_uv_paddr = 0; +- int i; +- +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, +- BIT(2) | BIT(1)); +- +- v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { +- u32 idx = buf->vb.vb2_buf.index; +- +- if (codec_hevc_use_downsample(sess)) +- buf_y_paddr = hevc->fbc_buffer_paddr[idx]; +- else +- buf_y_paddr = +- vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); +- +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, +- buf_y_paddr >> 5); +- if (!codec_hevc_use_fbc(sess)) { +- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, +- buf_uv_paddr >> 5); +- } +- } +- +- /* Fill the remaining unused slots with the last buffer's Y addr */ +- for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, +- buf_y_paddr >> 5); +- if (!codec_hevc_use_fbc(sess)) +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, +- buf_uv_paddr >> 5); +- } +- +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); +- amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); +- for (i = 0; i < 32; ++i) +- amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); +-} +- +-static void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) +-{ +- struct codec_hevc *hevc = sess->priv; +- struct device *dev = sess->core->dev; +- u32 am21_size = amvdec_am21c_size(sess->width, sess->height); +- int i; +- +- for (i = 0; i < MAX_REF_PIC_NUM; ++i) { +- if (hevc->fbc_buffer_vaddr[i]) { +- dma_free_coherent(dev, am21_size, +- hevc->fbc_buffer_vaddr[i], +- hevc->fbc_buffer_paddr[i]); +- hevc->fbc_buffer_vaddr[i] = NULL; +- } +- } +-} +- +-static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) +-{ +- struct codec_hevc *hevc = sess->priv; +- struct device *dev = sess->core->dev; +- struct v4l2_m2m_buffer *buf; +- u32 am21_size = amvdec_am21c_size(sess->width, sess->height); +- +- v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { +- u32 idx = buf->vb.vb2_buf.index; +- dma_addr_t paddr; +- void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, +- GFP_KERNEL); +- if (!vaddr) { +- dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); +- codec_hevc_free_fbc_buffers(sess); +- return -ENOMEM; +- } +- +- hevc->fbc_buffer_vaddr[idx] = vaddr; +- hevc->fbc_buffer_paddr[idx] = paddr; +- } +- +- return 0; +-} +- +-static int codec_hevc_setup_buffers(struct amvdec_session *sess) +-{ +- struct amvdec_core *core = sess->core; +- int ret; +- +- if (codec_hevc_use_downsample(sess)) { +- ret = codec_hevc_alloc_fbc_buffers(sess); +- if (ret) +- return ret; +- } +- +- if (core->platform->revision == VDEC_REVISION_GXBB) +- codec_hevc_setup_buffers_gxbb(sess); +- else +- codec_hevc_setup_buffers_gxl(sess); +- +- return 0; +-} + + static int + codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) +@@ -776,8 +566,9 @@ static int codec_hevc_start(struct amvdec_session *sess) + amvdec_write_dos(core, HEVC_DECODE_SIZE, 0); + + amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16)); +- for (i = 0; i < ARRAY_SIZE(parser_cmd); ++i) +- amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, parser_cmd[i]); ++ for (i = 0; i < ARRAY_SIZE(vdec_hevc_parser_cmd); ++i) ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, ++ vdec_hevc_parser_cmd[i]); + + amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); + amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); +@@ -934,14 +725,14 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + amvdec_write_dos(core, HEVC_SAO_PIC_SIZE_LCU, + (hevc->lcu_x_num - 1) | (hevc->lcu_y_num - 1) << 16); + +- if (codec_hevc_use_downsample(sess)) ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, hevc->is_10bit)) + buf_y_paddr = +- hevc->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; ++ sess->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; + else + buf_y_paddr = + vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); + +- if (codec_hevc_use_fbc(sess)) { ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { + val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; + amvdec_write_dos(core, HEVC_SAO_CTRL5, val); + amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); +@@ -979,14 +770,14 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + + val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; + val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ +- if (!codec_hevc_use_fbc(sess)) ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) + val |= BIT(0); /* disable cm compression */ + else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) + val |= BIT(1); /* Disable double write */ + + amvdec_write_dos(core, HEVC_SAO_CTRL1, val); + +- if (!codec_hevc_use_fbc(sess)) { ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { + /* no downscale for NV12 */ + val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000; + amvdec_write_dos(core, HEVC_SAO_CTRL5, val); +@@ -1195,7 +986,7 @@ static void codec_hevc_set_mcrcc(struct amvdec_session *sess) + int l0_cnt = 0; + int l1_cnt = 0x7fff; + +- if (!codec_hevc_use_fbc(sess)) { ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { + l0_cnt = hevc->cur_frame->ref_num[0]; + l1_cnt = hevc->cur_frame->ref_num[1]; + } +@@ -1266,7 +1057,7 @@ static void codec_hevc_set_ref_list(struct amvdec_session *sess, + continue; + } + +- if (codec_hevc_use_fbc(sess)) { ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) { + buf_id_y = buf_id_uv = ref_frame->vbuf->vb2_buf.index; + } else { + buf_id_y = ref_frame->vbuf->vb2_buf.index * 2; +@@ -1504,12 +1295,14 @@ static void codec_hevc_fetch_rpm(struct amvdec_session *sess) + + static void codec_hevc_resume(struct amvdec_session *sess) + { +- if (codec_hevc_setup_buffers(sess)) { ++ struct codec_hevc *hevc = sess->priv; ++ ++ if (codec_hevc_setup_buffers(sess, hevc->is_10bit)) { + amvdec_abort(sess); + return; + } + +- codec_hevc_setup_decode_head(sess); ++ codec_hevc_setup_decode_head(sess, hevc->is_10bit); + codec_hevc_process_segment_header(sess); + if (codec_hevc_process_segment(sess)) + amvdec_abort(sess); +diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.c b/drivers/media/platform/meson/vdec/codec_hevc_common.c +new file mode 100644 +index 0000000000000..2b296beb5d88a +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_hevc_common.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#include ++#include ++ ++#include "codec_hevc_common.h" ++#include "vdec_helpers.h" ++#include "hevc_regs.h" ++ ++/* Configure decode head read mode */ ++void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); ++ u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); ++ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { ++ /* Enable 2-plane reference read mode */ ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); ++ return; ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); ++ amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); ++ amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); ++ amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); ++} ++EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head); ++ ++static void ++codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) ++{ ++ struct amvdec_core *core = sess->core; ++ struct v4l2_m2m_buffer *buf; ++ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ dma_addr_t buf_y_paddr = 0; ++ dma_addr_t buf_uv_paddr = 0; ++ u32 idx = 0; ++ u32 val; ++ int i; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ idx = buf->vb.vb2_buf.index; ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) ++ buf_y_paddr = sess->fbc_buffer_paddr[idx]; ++ else ++ buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { ++ val = buf_y_paddr | (idx << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ } else { ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ val = buf_y_paddr | ((idx * 2) << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ } ++ } ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) ++ val = buf_y_paddr | (idx << 8) | 1; ++ else ++ val = buf_y_paddr | ((idx * 2) << 8) | 1; ++ ++ /* Fill the remaining unused slots with the last buffer's Y addr */ ++ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ for (i = 0; i < 32; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); ++} ++ ++static void ++codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) ++{ ++ struct amvdec_core *core = sess->core; ++ struct v4l2_m2m_buffer *buf; ++ u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ dma_addr_t buf_y_paddr = 0; ++ dma_addr_t buf_uv_paddr = 0; ++ int i; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, ++ BIT(2) | BIT(1)); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ u32 idx = buf->vb.vb2_buf.index; ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) ++ buf_y_paddr = sess->fbc_buffer_paddr[idx]; ++ else ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_y_paddr >> 5); ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_uv_paddr >> 5); ++ } ++ } ++ ++ /* Fill the remaining unused slots with the last buffer's Y addr */ ++ for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_y_paddr >> 5); ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, ++ buf_uv_paddr >> 5); ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ for (i = 0; i < 32; ++i) ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); ++} ++ ++void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) ++{ ++ struct device *dev = sess->core->dev; ++ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); ++ int i; ++ ++ for (i = 0; i < MAX_REF_PIC_NUM; ++i) { ++ if (sess->fbc_buffer_vaddr[i]) { ++ dma_free_coherent(dev, am21_size, ++ sess->fbc_buffer_vaddr[i], ++ sess->fbc_buffer_paddr[i]); ++ sess->fbc_buffer_vaddr[i] = NULL; ++ } ++ } ++} ++EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers); ++ ++static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) ++{ ++ struct device *dev = sess->core->dev; ++ struct v4l2_m2m_buffer *buf; ++ u32 am21_size = amvdec_am21c_size(sess->width, sess->height); ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ u32 idx = buf->vb.vb2_buf.index; ++ dma_addr_t paddr; ++ void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, ++ GFP_KERNEL); ++ if (!vaddr) { ++ dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); ++ codec_hevc_free_fbc_buffers(sess); ++ return -ENOMEM; ++ } ++ ++ sess->fbc_buffer_vaddr[idx] = vaddr; ++ sess->fbc_buffer_paddr[idx] = paddr; ++ } ++ ++ return 0; ++} ++ ++int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit) ++{ ++ struct amvdec_core *core = sess->core; ++ int ret; ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) { ++ ret = codec_hevc_alloc_fbc_buffers(sess); ++ if (ret) ++ return ret; ++ } ++ ++ if (core->platform->revision == VDEC_REVISION_GXBB) ++ codec_hevc_setup_buffers_gxbb(sess, is_10bit); ++ else ++ codec_hevc_setup_buffers_gxl(sess, is_10bit); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.h b/drivers/media/platform/meson/vdec/codec_hevc_common.h +new file mode 100644 +index 0000000000000..96493f9fe6995 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_hevc_common.h +@@ -0,0 +1,49 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 BayLibre, SAS ++ * Author: Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_HEVC_COMMON_H_ ++#define __MESON_VDEC_HEVC_COMMON_H_ ++ ++#include "vdec.h" ++ ++#define PARSER_CMD_SKIP_CFG_0 0x0000090b ++#define PARSER_CMD_SKIP_CFG_1 0x1b14140f ++#define PARSER_CMD_SKIP_CFG_2 0x001b1910 ++static const u16 vdec_hevc_parser_cmd[] = { ++ 0x0401, 0x8401, 0x0800, 0x0402, ++ 0x9002, 0x1423, 0x8CC3, 0x1423, ++ 0x8804, 0x9825, 0x0800, 0x04FE, ++ 0x8406, 0x8411, 0x1800, 0x8408, ++ 0x8409, 0x8C2A, 0x9C2B, 0x1C00, ++ 0x840F, 0x8407, 0x8000, 0x8408, ++ 0x2000, 0xA800, 0x8410, 0x04DE, ++ 0x840C, 0x840D, 0xAC00, 0xA000, ++ 0x08C0, 0x08E0, 0xA40E, 0xFC00, ++ 0x7C00 ++}; ++ ++/* Returns 1 if we must use framebuffer compression */ ++static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit) ++{ ++ return pixfmt == V4L2_PIX_FMT_AM21C || is_10bit; ++} ++ ++/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */ ++static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit) ++{ ++ return pixfmt == V4L2_PIX_FMT_NV12M && is_10bit; ++} ++ ++/** ++ * Configure decode head read mode ++ */ ++void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit); ++ ++void codec_hevc_free_fbc_buffers(struct amvdec_session *sess); ++ ++int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit); ++ ++#endif +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h +index 6597e26cc855e..885777e48142a 100644 +--- a/drivers/media/platform/meson/vdec/vdec.h ++++ b/drivers/media/platform/meson/vdec/vdec.h +@@ -17,7 +17,9 @@ + #include "vdec_platform.h" + + /* 32 buffers in 3-plane YUV420 */ +-#define MAX_CANVAS (32 * 3) ++#define MAX_CANVAS (32 * 3) ++ ++#define MAX_REF_PIC_NUM 24 + + struct amvdec_buffer { + struct list_head list; +@@ -257,6 +259,9 @@ struct amvdec_session { + u32 dpb_size; + u32 fw_idx_to_vb2_idx[32]; + ++ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; ++ + enum amvdec_status status; + void *priv; + }; + +From dd53ac3d055fccf7652483eacb5bf9e6e6a9602c Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 17 Jan 2019 16:59:11 +0100 +Subject: [PATCH 218/249] WIP: media: meson: vdec: add VP9 input support + +Amlogic VP9 decoder requires an additional 16-byte payload before every +frame header. +--- + drivers/media/platform/meson/vdec/esparser.c | 101 ++++++++++++++++++- + 1 file changed, 97 insertions(+), 4 deletions(-) + +diff --git a/drivers/media/platform/meson/vdec/esparser.c b/drivers/media/platform/meson/vdec/esparser.c +index 24e08b01c88a1..d7ac51e08730d 100644 +--- a/drivers/media/platform/meson/vdec/esparser.c ++++ b/drivers/media/platform/meson/vdec/esparser.c +@@ -51,6 +51,7 @@ + #define PARSER_VIDEO_HOLE 0x90 + + #define SEARCH_PATTERN_LEN 512 ++#define VP9_HEADER_SIZE 16 + + static DECLARE_WAIT_QUEUE_HEAD(wq); + static int search_done; +@@ -73,14 +74,103 @@ static irqreturn_t esparser_isr(int irq, void *dev) + return IRQ_HANDLED; + } + ++/** ++ * VP9 frame headers need to be appended by a 16-byte long ++ * Amlogic custom header ++ */ ++static int vp9_update_header(struct vb2_buffer *buf) ++{ ++ uint8_t *dp; ++ uint8_t marker; ++ int dsize; ++ int num_frames, cur_frame; ++ int cur_mag, mag, mag_ptr; ++ int frame_size[8], tot_frame_size[8]; ++ int total_datasize = 0; ++ int new_frame_size; ++ unsigned char *old_header = NULL; ++ ++ dp = (uint8_t *) vb2_plane_vaddr(buf, 0); ++ dsize = vb2_get_plane_payload(buf, 0); ++ ++ marker = dp[dsize - 1]; ++ if ((marker & 0xe0) == 0xc0) { ++ num_frames = (marker & 0x7) + 1; ++ mag = ((marker >> 3) & 0x3) + 1; ++ mag_ptr = dsize - mag * num_frames - 2; ++ if (dp[mag_ptr] != marker) { ++ return 0; ++ } ++ mag_ptr++; ++ for (cur_frame = 0; cur_frame < num_frames; cur_frame++) { ++ frame_size[cur_frame] = 0; ++ for (cur_mag = 0; cur_mag < mag; cur_mag++) { ++ frame_size[cur_frame] |= (dp[mag_ptr] << (cur_mag * 8)); ++ mag_ptr++; ++ } ++ if (cur_frame == 0) ++ tot_frame_size[cur_frame] = frame_size[cur_frame]; ++ else ++ tot_frame_size[cur_frame] = tot_frame_size[cur_frame - 1] + frame_size[cur_frame]; ++ total_datasize += frame_size[cur_frame]; ++ } ++ } else { ++ num_frames = 1; ++ frame_size[0] = dsize; ++ tot_frame_size[0] = dsize; ++ total_datasize = dsize; ++ } ++ ++ new_frame_size = total_datasize + num_frames * VP9_HEADER_SIZE; ++ ++ for (cur_frame = num_frames - 1; cur_frame >= 0; cur_frame--) { ++ int framesize = frame_size[cur_frame]; ++ int framesize_header = framesize + 4; ++ int oldframeoff = tot_frame_size[cur_frame] - framesize; ++ int outheaderoff = oldframeoff + cur_frame * VP9_HEADER_SIZE; ++ uint8_t *fdata = dp + outheaderoff; ++ uint8_t *old_framedata = dp + oldframeoff; ++ ++ memmove(fdata + VP9_HEADER_SIZE, old_framedata, framesize); ++ ++ fdata[0] = (framesize_header >> 24) & 0xff; ++ fdata[1] = (framesize_header >> 16) & 0xff; ++ fdata[2] = (framesize_header >> 8) & 0xff; ++ fdata[3] = (framesize_header >> 0) & 0xff; ++ fdata[4] = ((framesize_header >> 24) & 0xff) ^0xff; ++ fdata[5] = ((framesize_header >> 16) & 0xff) ^0xff; ++ fdata[6] = ((framesize_header >> 8) & 0xff) ^0xff; ++ fdata[7] = ((framesize_header >> 0) & 0xff) ^0xff; ++ fdata[8] = 0; ++ fdata[9] = 0; ++ fdata[10] = 0; ++ fdata[11] = 1; ++ fdata[12] = 'A'; ++ fdata[13] = 'M'; ++ fdata[14] = 'L'; ++ fdata[15] = 'V'; ++ ++ if (!old_header) { ++ /* nothing */ ++ } else if (old_header > fdata + 16 + framesize) { ++ printk("data has gaps, setting to 0\n"); ++ memset(fdata + 16 + framesize, 0, (old_header - fdata + 16 + framesize)); ++ } else if (old_header < fdata + 16 + framesize) { ++ printk("data overwritten\n"); ++ } ++ old_header = fdata; ++ } ++ ++ return new_frame_size; ++} ++ + /* Pad the packet to at least 4KiB bytes otherwise the VDEC unit won't trigger + * ISRs. + * Also append a start code 000001ff at the end to trigger + * the ESPARSER interrupt. + */ +-static u32 esparser_pad_start_code(struct vb2_buffer *vb) ++static u32 esparser_pad_start_code(struct vb2_buffer *vb, u32 payload_size) + { +- u32 payload_size = vb2_get_plane_payload(vb, 0); + u32 pad_size = 0; + u8 *vaddr = vb2_plane_vaddr(vb, 0) + payload_size; + +@@ -189,7 +279,7 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) + if (codec_ops->num_pending_bufs) + num_dst_bufs = codec_ops->num_pending_bufs(sess); + +- num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx) - 1; + + if (esparser_vififo_get_free_space(sess) < payload_size || + atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) +@@ -203,7 +293,10 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) + dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X\n", + vb->timestamp, payload_size, offset); + +- pad_size = esparser_pad_start_code(vb); ++ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) ++ payload_size = vp9_update_header(vb); ++ ++ pad_size = esparser_pad_start_code(vb, payload_size); + ret = esparser_write_data(core, phy, payload_size + pad_size); + + if (ret <= 0) { + +From f90e2c84b8c4a1cd6cb4524fc3c2027888c0b915 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 17 Jan 2019 17:00:11 +0100 +Subject: [PATCH 219/249] WIP: media: meson: vdec: add VP9 support + +--- + drivers/media/platform/meson/vdec/Makefile | 2 +- + drivers/media/platform/meson/vdec/codec_vp9.c | 1083 +++++++++++++++++ + drivers/media/platform/meson/vdec/codec_vp9.h | 13 + + drivers/media/platform/meson/vdec/esparser.c | 4 +- + drivers/media/platform/meson/vdec/hevc_regs.h | 7 + + .../media/platform/meson/vdec/vdec_platform.c | 23 + + 6 files changed, 1130 insertions(+), 2 deletions(-) + create mode 100644 drivers/media/platform/meson/vdec/codec_vp9.c + create mode 100644 drivers/media/platform/meson/vdec/codec_vp9.h + +diff --git a/drivers/media/platform/meson/vdec/Makefile b/drivers/media/platform/meson/vdec/Makefile +index 4fba9e052f14f..c6b0c299c0377 100644 +--- a/drivers/media/platform/meson/vdec/Makefile ++++ b/drivers/media/platform/meson/vdec/Makefile +@@ -3,6 +3,6 @@ + + meson-vdec-objs = esparser.o vdec.o vdec_ctrls.o vdec_helpers.o vdec_platform.o + meson-vdec-objs += vdec_1.o vdec_hevc.o +-meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o ++meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_mpeg4.o codec_mjpeg.o codec_hevc_common.o codec_hevc.o codec_vp9.o + + obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o +diff --git a/drivers/media/platform/meson/vdec/codec_vp9.c b/drivers/media/platform/meson/vdec/codec_vp9.c +new file mode 100644 +index 0000000000000..731119b9ee17a +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_vp9.c +@@ -0,0 +1,1083 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ * Copyright (C) 2015 Amlogic, Inc. All rights reserved. ++ */ ++ ++#include ++#include ++ ++#include "codec_hevc.h" ++#include "dos_regs.h" ++#include "hevc_regs.h" ++#include "vdec_helpers.h" ++#include "codec_hevc_common.h" ++ ++/* HEVC reg mapping */ ++#define VP9_DEC_STATUS_REG HEVC_ASSIST_SCRATCH_0 ++ #define VP9_10B_DECODE_SLICE 5 ++ #define VP9_HEAD_PARSER_DONE 0xf0 ++#define VP9_RPM_BUFFER HEVC_ASSIST_SCRATCH_1 ++#define VP9_SHORT_TERM_RPS HEVC_ASSIST_SCRATCH_2 ++#define VP9_ADAPT_PROB_REG HEVC_ASSIST_SCRATCH_3 ++#define VP9_MMU_MAP_BUFFER HEVC_ASSIST_SCRATCH_4 ++#define VP9_PPS_BUFFER HEVC_ASSIST_SCRATCH_5 ++#define VP9_SAO_UP HEVC_ASSIST_SCRATCH_6 ++#define VP9_STREAM_SWAP_BUFFER HEVC_ASSIST_SCRATCH_7 ++#define VP9_STREAM_SWAP_BUFFER2 HEVC_ASSIST_SCRATCH_8 ++#define VP9_PROB_SWAP_BUFFER HEVC_ASSIST_SCRATCH_9 ++#define VP9_COUNT_SWAP_BUFFER HEVC_ASSIST_SCRATCH_A ++#define VP9_SEG_MAP_BUFFER HEVC_ASSIST_SCRATCH_B ++#define VP9_SCALELUT HEVC_ASSIST_SCRATCH_D ++#define VP9_WAIT_FLAG HEVC_ASSIST_SCRATCH_E ++#define LMEM_DUMP_ADR HEVC_ASSIST_SCRATCH_F ++#define NAL_SEARCH_CTL HEVC_ASSIST_SCRATCH_I ++#define VP9_DECODE_MODE HEVC_ASSIST_SCRATCH_J ++ #define DECODE_MODE_SINGLE 0 ++#define DECODE_STOP_POS HEVC_ASSIST_SCRATCH_K ++#define HEVC_DECODE_COUNT HEVC_ASSIST_SCRATCH_M ++#define HEVC_DECODE_SIZE HEVC_ASSIST_SCRATCH_N ++ ++/* VP9 Constants */ ++#define LCU_SIZE 64 ++#define MAX_REF_PIC_NUM 24 ++#define REFS_PER_FRAME 3 ++#define REF_FRAMES 8 ++#define MV_MEM_UNIT 0x240 ++ ++enum FRAME_TYPE { ++ KEY_FRAME = 0, ++ INTER_FRAME = 1, ++ FRAME_TYPES, ++}; ++ ++/* VP9 Workspace layout */ ++#define MPRED_MV_BUF_SIZE 0x120000 ++ ++#define IPP_SIZE 0x4000 ++#define SAO_ABV_SIZE 0x30000 ++#define SAO_VB_SIZE 0x30000 ++#define SH_TM_RPS_SIZE 0x800 ++#define VPS_SIZE 0x800 ++#define SPS_SIZE 0x800 ++#define PPS_SIZE 0x2000 ++#define SAO_UP_SIZE 0x2800 ++#define SWAP_BUF_SIZE 0x800 ++#define SWAP_BUF2_SIZE 0x800 ++#define SCALELUT_SIZE 0x8000 ++#define DBLK_PARA_SIZE 0x80000 ++#define DBLK_DATA_SIZE 0x80000 ++#define SEG_MAP_SIZE 0xd800 ++#define PROB_SIZE 0x5000 ++#define COUNT_SIZE 0x3000 ++#define MMU_VBH_SIZE 0x5000 ++#define MPRED_ABV_SIZE 0x10000 ++#define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) ++#define RPM_BUF_SIZE 0x100 ++#define LMEM_SIZE 0x800 ++ ++#define IPP_OFFSET 0x00 ++#define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) ++#define SAO_VB_OFFSET (SAO_ABV_OFFSET + SAO_ABV_SIZE) ++#define SH_TM_RPS_OFFSET (SAO_VB_OFFSET + SAO_VB_SIZE) ++#define VPS_OFFSET (SH_TM_RPS_OFFSET + SH_TM_RPS_SIZE) ++#define SPS_OFFSET (VPS_OFFSET + VPS_SIZE) ++#define PPS_OFFSET (SPS_OFFSET + SPS_SIZE) ++#define SAO_UP_OFFSET (PPS_OFFSET + PPS_SIZE) ++#define SWAP_BUF_OFFSET (SAO_UP_OFFSET + SAO_UP_SIZE) ++#define SWAP_BUF2_OFFSET (SWAP_BUF_OFFSET + SWAP_BUF_SIZE) ++#define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) ++#define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) ++#define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) ++#define SEG_MAP_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) ++#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) ++#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) ++#define MMU_VBH_OFFSET (COUNT_OFFSET + COUNT_SIZE) ++#define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) ++#define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) ++#define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) ++#define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) ++ ++#define SIZE_WORKSPACE ALIGN(LMEM_OFFSET + LMEM_SIZE, 64 * SZ_1K) ++ ++#define NONE -1 ++#define INTRA_FRAME 0 ++#define LAST_FRAME 1 ++#define GOLDEN_FRAME 2 ++#define ALTREF_FRAME 3 ++#define MAX_REF_FRAMES 4 ++ ++/* ++ * Defines, declarations, sub-functions for vp9 de-block loop ++ filter Thr/Lvl table update ++ * - struct segmentation is for loop filter only (removed something) ++ * - function "vp9_loop_filter_init" and "vp9_loop_filter_frame_init" will ++ be instantiated in C_Entry ++ * - vp9_loop_filter_init run once before decoding start ++ * - vp9_loop_filter_frame_init run before every frame decoding start ++ * - set video format to VP9 is in vp9_loop_filter_init ++ */ ++#define MAX_LOOP_FILTER 63 ++#define MAX_REF_LF_DELTAS 4 ++#define MAX_MODE_LF_DELTAS 2 ++#define SEGMENT_DELTADATA 0 ++#define SEGMENT_ABSDATA 1 ++#define MAX_SEGMENTS 8 ++ ++union rpm_param { ++ struct { ++ u16 data[RPM_BUF_SIZE]; ++ } l; ++ struct { ++ u16 profile; ++ u16 show_existing_frame; ++ u16 frame_to_show_idx; ++ u16 frame_type; /*1 bit*/ ++ u16 show_frame; /*1 bit*/ ++ u16 error_resilient_mode; /*1 bit*/ ++ u16 intra_only; /*1 bit*/ ++ u16 display_size_present; /*1 bit*/ ++ u16 reset_frame_context; ++ u16 refresh_frame_flags; ++ u16 width; ++ u16 height; ++ u16 display_width; ++ u16 display_height; ++ u16 ref_info; ++ u16 same_frame_size; ++ u16 mode_ref_delta_enabled; ++ u16 ref_deltas[4]; ++ u16 mode_deltas[2]; ++ u16 filter_level; ++ u16 sharpness_level; ++ u16 bit_depth; ++ u16 seg_quant_info[8]; ++ u16 seg_enabled; ++ u16 seg_abs_delta; ++ /* bit 15: feature enabled; bit 8, sign; bit[5:0], data */ ++ u16 seg_lf_info[8]; ++ } p; ++}; ++ ++enum SEG_LVL_FEATURES { ++ SEG_LVL_ALT_Q = 0, /* Use alternate Quantizer */ ++ SEG_LVL_ALT_LF = 1, /* Use alternate loop filter value */ ++ SEG_LVL_REF_FRAME = 2, /* Optional Segment reference frame */ ++ SEG_LVL_SKIP = 3, /* Optional Segment (0,0) + skip mode */ ++ SEG_LVL_MAX = 4 /* Number of features supported */ ++}; ++ ++struct segmentation { ++ uint8_t enabled; ++ uint8_t update_map; ++ uint8_t update_data; ++ uint8_t abs_delta; ++ uint8_t temporal_update; ++ int16_t feature_data[MAX_SEGMENTS][SEG_LVL_MAX]; ++ unsigned int feature_mask[MAX_SEGMENTS]; ++}; ++ ++struct loop_filter_thresh { ++ uint8_t mblim; ++ uint8_t lim; ++ uint8_t hev_thr; ++}; ++ ++struct loop_filter_info_n { ++ struct loop_filter_thresh lfthr[MAX_LOOP_FILTER + 1]; ++ uint8_t lvl[MAX_SEGMENTS][MAX_REF_FRAMES][MAX_MODE_LF_DELTAS]; ++}; ++ ++struct loopfilter { ++ int filter_level; ++ ++ int sharpness_level; ++ int last_sharpness_level; ++ ++ uint8_t mode_ref_delta_enabled; ++ uint8_t mode_ref_delta_update; ++ ++ /*0 = Intra, Last, GF, ARF*/ ++ signed char ref_deltas[MAX_REF_LF_DELTAS]; ++ signed char last_ref_deltas[MAX_REF_LF_DELTAS]; ++ ++ /*0 = ZERO_MV, MV*/ ++ signed char mode_deltas[MAX_MODE_LF_DELTAS]; ++ signed char last_mode_deltas[MAX_MODE_LF_DELTAS]; ++}; ++ ++struct vp9_frame { ++ struct list_head list; ++ struct vb2_v4l2_buffer *vbuf; ++ int index; ++ int intra_only; ++ int show; ++ int type; ++ int done; ++}; ++ ++struct codec_vp9 { ++ struct mutex lock; ++ ++ /* Buffer for the VP9 Workspace */ ++ void *workspace_vaddr; ++ dma_addr_t workspace_paddr; ++ ++ /* Contains many information parsed from the bitstream */ ++ union rpm_param rpm_param; ++ ++ /* Whether we detected the bitstream as 10-bit */ ++ int is_10bit; ++ ++ /* Coded resolution reported by the hardware */ ++ u32 width, height; ++ ++ /* All ref frames used by the HW at a given time */ ++ struct list_head ref_frames_list; ++ u32 frames_num; ++ ++ /* In case of downsampling (decoding with FBC but outputting in NV12M), ++ * we need to allocate additional buffers for FBC. ++ */ ++ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; ++ ++ int ref_frame_map[REF_FRAMES]; ++ int next_ref_frame_map[REF_FRAMES]; ++ struct vp9_frame* frame_refs[REFS_PER_FRAME]; ++ ++ u32 lcu_total; ++ ++ /* loop filter */ ++ int default_filt_lvl; ++ struct loop_filter_info_n lfi; ++ struct loopfilter lf; ++ struct segmentation seg_4lf; ++ ++ struct vp9_frame *cur_frame; ++ struct vp9_frame *prev_frame; ++}; ++ ++static int vp9_clamp(int value, int low, int high) ++{ ++ return value < low ? low : (value > high ? high : value); ++} ++ ++static int segfeature_active(struct segmentation *seg, ++ int segment_id, ++ enum SEG_LVL_FEATURES feature_id) ++{ ++ return seg->enabled && ++ (seg->feature_mask[segment_id] & (1 << feature_id)); ++} ++ ++static int get_segdata(struct segmentation *seg, int segment_id, ++ enum SEG_LVL_FEATURES feature_id) ++{ ++ return seg->feature_data[segment_id][feature_id]; ++} ++ ++static void vp9_update_sharpness(struct loop_filter_info_n *lfi, ++ int sharpness_lvl) ++{ ++ int lvl; ++ /*For each possible value for the loop filter fill out limits*/ ++ for (lvl = 0; lvl <= MAX_LOOP_FILTER; lvl++) { ++ /*Set loop filter parameters that control sharpness.*/ ++ int block_inside_limit = lvl >> ((sharpness_lvl > 0) + ++ (sharpness_lvl > 4)); ++ ++ if (sharpness_lvl > 0) { ++ if (block_inside_limit > (9 - sharpness_lvl)) ++ block_inside_limit = (9 - sharpness_lvl); ++ } ++ ++ if (block_inside_limit < 1) ++ block_inside_limit = 1; ++ ++ lfi->lfthr[lvl].lim = (uint8_t)block_inside_limit; ++ lfi->lfthr[lvl].mblim = (uint8_t)(2 * (lvl + 2) + ++ block_inside_limit); ++ } ++} ++ ++/*instantiate this function once when decode is started*/ ++static void ++vp9_loop_filter_init(struct amvdec_core *core, struct codec_vp9 *vp9) ++{ ++ struct loop_filter_info_n *lfi = &vp9->lfi; ++ struct loopfilter *lf = &vp9->lf; ++ struct segmentation *seg_4lf = &vp9->seg_4lf; ++ int i; ++ ++ memset(lfi, 0, sizeof(struct loop_filter_info_n)); ++ memset(lf, 0, sizeof(struct loopfilter)); ++ memset(seg_4lf, 0, sizeof(struct segmentation)); ++ lf->sharpness_level = 0; ++ vp9_update_sharpness(lfi, lf->sharpness_level); ++ lf->last_sharpness_level = lf->sharpness_level; ++ ++ for (i = 0; i < 32; i++) { ++ unsigned int thr; ++ thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f)<<8) | ++ (lfi->lfthr[i * 2 + 1].mblim & 0xff); ++ thr = (thr<<16) | ((lfi->lfthr[i*2].lim & 0x3f)<<8) | ++ (lfi->lfthr[i * 2].mblim & 0xff); ++ amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); ++ } ++ ++ amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); ++} ++ ++static void ++vp9_loop_filter_frame_init(struct amvdec_core *core, struct segmentation *seg, ++ struct loop_filter_info_n *lfi, ++ struct loopfilter *lf, int default_filt_lvl) ++{ ++ int i; ++ int seg_id; ++ /*n_shift is the multiplier for lf_deltas ++ the multiplier is 1 for when filter_lvl is between 0 and 31; ++ 2 when filter_lvl is between 32 and 63*/ ++ const int scale = 1 << (default_filt_lvl >> 5); ++ ++ /*update limits if sharpness has changed*/ ++ if (lf->last_sharpness_level != lf->sharpness_level) { ++ vp9_update_sharpness(lfi, lf->sharpness_level); ++ lf->last_sharpness_level = lf->sharpness_level; ++ ++ /*Write to register*/ ++ for (i = 0; i < 32; i++) { ++ unsigned int thr; ++ thr = ((lfi->lfthr[i * 2 + 1].lim & 0x3f) << 8) ++ | (lfi->lfthr[i * 2 + 1].mblim & 0xff); ++ thr = (thr << 16) | ((lfi->lfthr[i * 2].lim & 0x3f) << 8) ++ | (lfi->lfthr[i * 2].mblim & 0xff); ++ amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); ++ } ++ } ++ ++ for (seg_id = 0; seg_id < MAX_SEGMENTS; seg_id++) {/*MAX_SEGMENTS = 8*/ ++ int lvl_seg = default_filt_lvl; ++ if (segfeature_active(seg, seg_id, SEG_LVL_ALT_LF)) { ++ const int data = get_segdata(seg, seg_id, ++ SEG_LVL_ALT_LF); ++ lvl_seg = vp9_clamp(seg->abs_delta == SEGMENT_ABSDATA ? ++ data : default_filt_lvl + data, ++ 0, MAX_LOOP_FILTER); ++ } ++ ++ if (!lf->mode_ref_delta_enabled) { ++ /*we could get rid of this if we assume that deltas are set to ++ zero when not in use; encoder always uses deltas*/ ++ memset(lfi->lvl[seg_id], lvl_seg, sizeof(lfi->lvl[seg_id])); ++ } else { ++ int ref, mode; ++ const int intra_lvl = lvl_seg + lf->ref_deltas[INTRA_FRAME] ++ * scale; ++ lfi->lvl[seg_id][INTRA_FRAME][0] = ++ vp9_clamp(intra_lvl, 0, MAX_LOOP_FILTER); ++ ++ for (ref = LAST_FRAME; ref < MAX_REF_FRAMES; ++ref) { ++ /* LAST_FRAME = 1, MAX_REF_FRAMES = 4*/ ++ for (mode = 0; mode < MAX_MODE_LF_DELTAS; ++mode) { ++ /*MAX_MODE_LF_DELTAS = 2*/ ++ const int inter_lvl = ++ lvl_seg + lf->ref_deltas[ref] * scale ++ + lf->mode_deltas[mode] * scale; ++ lfi->lvl[seg_id][ref][mode] = ++ vp9_clamp(inter_lvl, 0, ++ MAX_LOOP_FILTER); ++ } ++ } ++ } ++ } ++ ++ for (i = 0; i < 16; i++) { ++ unsigned int level; ++ level = ((lfi->lvl[i >> 1][3][i & 1] & 0x3f) << 24) | ++ ((lfi->lvl[i >> 1][2][i & 1] & 0x3f) << 16) | ++ ((lfi->lvl[i >> 1][1][i & 1] & 0x3f) << 8) | ++ (lfi->lvl[i >> 1][0][i & 1] & 0x3f); ++ if (!default_filt_lvl) ++ level = 0; ++ amvdec_write_dos(core, HEVC_DBLK_CFGA, level); ++ } ++} ++ ++static void codec_vp9_flush_output(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ struct vp9_frame *tmp, *n; ++ ++ list_for_each_entry_safe(tmp, n, &vp9->ref_frames_list, list) { ++ if (!tmp->done) { ++ if (tmp->show) ++ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); ++ else ++ v4l2_m2m_buf_queue(sess->m2m_ctx, tmp->vbuf); ++ vp9->frames_num--; ++ } ++ ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++} ++ ++static u32 codec_vp9_num_pending_bufs(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ ++ if (!vp9) ++ return 0; ++ ++ return vp9->frames_num; ++} ++ ++static int ++codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) ++{ ++ dma_addr_t wkaddr; ++ ++ /* Allocate some memory for the VP9 decoder's state */ ++ vp9->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, ++ &wkaddr, GFP_KERNEL); ++ if (!vp9->workspace_vaddr) { ++ dev_err(core->dev, "Failed to allocate VP9 Workspace\n"); ++ return -ENOMEM; ++ } ++ ++ vp9->workspace_paddr = wkaddr; ++ ++ amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); ++ amvdec_write_dos(core, VP9_RPM_BUFFER, wkaddr + RPM_OFFSET); ++ amvdec_write_dos(core, VP9_SHORT_TERM_RPS, wkaddr + SH_TM_RPS_OFFSET); ++ amvdec_write_dos(core, VP9_PPS_BUFFER, wkaddr + PPS_OFFSET); ++ amvdec_write_dos(core, VP9_SAO_UP, wkaddr + SAO_UP_OFFSET); ++ ++ /* No MMU */ ++ amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER, ++ wkaddr + SWAP_BUF_OFFSET); ++ amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, ++ wkaddr + SWAP_BUF2_OFFSET); ++ amvdec_write_dos(core, VP9_SCALELUT, wkaddr + SCALELUT_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); ++ amvdec_write_dos(core, VP9_SEG_MAP_BUFFER, wkaddr + SEG_MAP_OFFSET); ++ amvdec_write_dos(core, VP9_PROB_SWAP_BUFFER, wkaddr + PROB_OFFSET); ++ amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); ++ ++ return 0; ++} ++ ++static int codec_vp9_start(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9; ++ u32 val; ++ int i; ++ int ret; ++ ++ vp9 = kzalloc(sizeof(*vp9), GFP_KERNEL); ++ if (!vp9) ++ return -ENOMEM; ++ ++ ret = codec_vp9_setup_workspace(core, vp9); ++ if (ret) ++ goto free_vp9; ++ ++ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); ++ ++ val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x7fffffff; ++ val |= (3 << 29) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | BIT(0); ++ amvdec_write_dos(core, HEVC_PARSER_INT_CONTROL, val); ++ amvdec_write_dos_bits(core, HEVC_SHIFT_STATUS, BIT(0)); ++ amvdec_write_dos(core, HEVC_SHIFT_CONTROL, BIT(10) | BIT(9) | ++ (3 << 6) | BIT(5) | BIT(2) | BIT(1) | BIT(0)); ++ amvdec_write_dos(core, HEVC_CABAC_CONTROL, BIT(0)); ++ amvdec_write_dos(core, HEVC_PARSER_CORE_CONTROL, BIT(0)); ++ amvdec_write_dos(core, HEVC_SHIFT_STARTCODE, 0x00000001); ++ ++ amvdec_write_dos(core, VP9_DEC_STATUS_REG, 0); ++ ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, BIT(16)); ++ for (i = 0; i < ARRAY_SIZE(vdec_hevc_parser_cmd); ++i) ++ amvdec_write_dos(core, HEVC_PARSER_CMD_WRITE, ++ vdec_hevc_parser_cmd[i]); ++ ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_0, PARSER_CMD_SKIP_CFG_0); ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_1, PARSER_CMD_SKIP_CFG_1); ++ amvdec_write_dos(core, HEVC_PARSER_CMD_SKIP_2, PARSER_CMD_SKIP_CFG_2); ++ amvdec_write_dos(core, HEVC_PARSER_IF_CONTROL, ++ BIT(5) | BIT(2) | BIT(0)); ++ ++ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(0)); ++ amvdec_write_dos(core, HEVCD_IPP_TOP_CNTL, BIT(1)); ++ ++ amvdec_write_dos(core, VP9_WAIT_FLAG, 1); ++ ++ /* clear mailbox interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_CLR_REG, 1); ++ /* enable mailbox interrupt */ ++ amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 1); ++ /* disable PSCALE for hardware sharing */ ++ amvdec_write_dos(core, HEVC_PSCALE_CTRL, 0); ++ /* Let the uCode do all the parsing */ ++ amvdec_write_dos(core, NAL_SEARCH_CTL, 0x8); ++ ++ amvdec_write_dos(core, DECODE_STOP_POS, 0); ++ amvdec_write_dos(core, VP9_DECODE_MODE, DECODE_MODE_SINGLE); ++ ++ printk("decode_count: %u; decode_size: %u\n", amvdec_read_dos(core, HEVC_DECODE_COUNT), amvdec_read_dos(core, HEVC_DECODE_SIZE)); ++ ++ vp9_loop_filter_init(core, vp9); ++ ++ INIT_LIST_HEAD(&vp9->ref_frames_list); ++ mutex_init(&vp9->lock); ++ memset(&vp9->ref_frame_map, -1, sizeof(vp9->ref_frame_map)); ++ memset(&vp9->next_ref_frame_map, -1, sizeof(vp9->next_ref_frame_map)); ++ sess->priv = vp9; ++ ++ return 0; ++ ++free_vp9: ++ kfree(vp9); ++ return ret; ++} ++ ++static int codec_vp9_stop(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9 = sess->priv; ++ ++ if (vp9->workspace_vaddr) ++ dma_free_coherent(core->dev, SIZE_WORKSPACE, ++ vp9->workspace_vaddr, ++ vp9->workspace_paddr); ++ ++ codec_hevc_free_fbc_buffers(sess); ++ return 0; ++} ++ ++static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9 = sess->priv; ++ ++ dma_addr_t buf_y_paddr; ++ dma_addr_t buf_u_v_paddr; ++ u32 val; ++ ++ if (codec_hevc_use_downsample(sess->pixfmt_cap, vp9->is_10bit)) ++ buf_y_paddr = ++ sess->fbc_buffer_paddr[vb->index]; ++ else ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(vb, 0); ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0200; ++ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); ++ amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); ++ } ++ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { ++ buf_y_paddr = ++ vb2_dma_contig_plane_dma_addr(vb, 0); ++ buf_u_v_paddr = ++ vb2_dma_contig_plane_dma_addr(vb, 1); ++ amvdec_write_dos(core, HEVC_SAO_Y_START_ADDR, buf_y_paddr); ++ amvdec_write_dos(core, HEVC_SAO_C_START_ADDR, buf_u_v_paddr); ++ amvdec_write_dos(core, HEVC_SAO_Y_WPTR, buf_y_paddr); ++ amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); ++ } ++ ++ amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, ++ amvdec_get_output_size(sess)); ++ amvdec_write_dos(core, HEVC_SAO_C_LENGTH, ++ (amvdec_get_output_size(sess) / 2)); ++ ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; ++ val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) ++ val |= BIT(0); /* disable cm compression */ ++ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) ++ val |= BIT(1); /* Disable double write */ ++ ++ amvdec_write_dos(core, HEVC_SAO_CTRL1, val); ++ ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { ++ /* no downscale for NV12 */ ++ val = amvdec_read_dos(core, HEVC_SAO_CTRL5) & ~0xff0000; ++ amvdec_write_dos(core, HEVC_SAO_CTRL5, val); ++ } ++ ++ val = amvdec_read_dos(core, HEVCD_IPP_AXIIF_CONFIG) & ~0x30; ++ val |= 0xf; ++ amvdec_write_dos(core, HEVCD_IPP_AXIIF_CONFIG, val); ++} ++ ++static dma_addr_t codec_vp9_get_frame_mv_paddr(struct codec_vp9 *vp9, ++ struct vp9_frame *frame) ++{ ++ return vp9->workspace_paddr + MPRED_MV_OFFSET + ++ (frame->index * MPRED_MV_BUF_SIZE); ++} ++ ++static void codec_vp9_set_mpred_mv(struct amvdec_core *core, ++ struct codec_vp9 *vp9) ++{ ++ int mpred_mv_rd_end_addr; ++ int use_prev_frame_mvs = !vp9->prev_frame->intra_only && ++ vp9->prev_frame->show && ++ vp9->prev_frame->type != KEY_FRAME; ++ ++ amvdec_write_dos(core, HEVC_MPRED_CTRL3, 0x24122412); ++ amvdec_write_dos(core, HEVC_MPRED_ABV_START_ADDR, ++ vp9->workspace_paddr + MPRED_ABV_OFFSET); ++ ++ amvdec_clear_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); ++ if (use_prev_frame_mvs) ++ amvdec_write_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); ++ ++ amvdec_write_dos(core, HEVC_MPRED_MV_WR_START_ADDR, ++ codec_vp9_get_frame_mv_paddr(vp9, vp9->cur_frame)); ++ amvdec_write_dos(core, HEVC_MPRED_MV_WPTR, ++ codec_vp9_get_frame_mv_paddr(vp9, vp9->cur_frame)); ++ ++ amvdec_write_dos(core, HEVC_MPRED_MV_RD_START_ADDR, ++ codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame)); ++ amvdec_write_dos(core, HEVC_MPRED_MV_RPTR, ++ codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame)); ++ ++ mpred_mv_rd_end_addr = codec_vp9_get_frame_mv_paddr(vp9, vp9->prev_frame) ++ + (vp9->lcu_total * MV_MEM_UNIT); ++ amvdec_write_dos(core, HEVC_MPRED_MV_RD_END_ADDR, mpred_mv_rd_end_addr); ++} ++ ++static void codec_vp9_update_next_ref(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ u32 buf_idx = vp9->cur_frame->index; ++ int ref_index = 0; ++ int refresh_frame_flags; ++ int mask; ++ ++ refresh_frame_flags = vp9->cur_frame->type == KEY_FRAME ? 0xff : ++ param->p.refresh_frame_flags; ++ ++ for (mask = refresh_frame_flags; mask; mask >>= 1) { ++ //printk("mask=%08X; ref_index=%d\n", mask, ref_index); ++ if (mask & 1) ++ vp9->next_ref_frame_map[ref_index] = buf_idx; ++ else ++ vp9->next_ref_frame_map[ref_index] = ++ vp9->ref_frame_map[ref_index]; ++ ++ ++ref_index; ++ } ++ ++ for (; ref_index < REF_FRAMES; ++ref_index) ++ vp9->next_ref_frame_map[ref_index] = ++ vp9->ref_frame_map[ref_index]; ++} ++ ++static void codec_vp9_update_ref(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ int ref_index = 0; ++ int mask; ++ int refresh_frame_flags; ++ ++ if (!vp9->cur_frame) ++ return; ++ ++ refresh_frame_flags = vp9->cur_frame->type == KEY_FRAME ? ++ 0xff : ++ param->p.refresh_frame_flags; ++ ++ for (mask = refresh_frame_flags; mask; mask >>= 1) { ++ vp9->ref_frame_map[ref_index] = ++ vp9->next_ref_frame_map[ref_index]; ++ ++ref_index; ++ } ++ ++ if (param->p.show_existing_frame) ++ return; ++ ++ for (; ref_index < REF_FRAMES; ++ref_index) ++ vp9->ref_frame_map[ref_index] = ++ vp9->next_ref_frame_map[ref_index]; ++} ++ ++static struct vp9_frame * codec_vp9_get_frame_by_idx(struct codec_vp9 *vp9, int idx) ++{ ++ struct vp9_frame *frame; ++ ++ list_for_each_entry(frame, &vp9->ref_frames_list, list) { ++ if (frame->index == idx) ++ return frame; ++ } ++ ++ return NULL; ++} ++ ++static void codec_vp9_sync_ref(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ int i; ++ ++ for (i = 0; i < REFS_PER_FRAME; ++i) { ++ const int ref = (param->p.ref_info >> ++ (((REFS_PER_FRAME-i-1)*4)+1)) & 0x7; ++ const int idx = vp9->ref_frame_map[ref]; ++ ++ vp9->frame_refs[i] = codec_vp9_get_frame_by_idx(vp9, idx); ++ } ++} ++ ++static void codec_vp9_set_refs(struct amvdec_session *sess, ++ struct codec_vp9 *vp9) ++{ ++ struct amvdec_core *core = sess->core; ++ int i; ++ ++ for (i = 0; i < REFS_PER_FRAME; ++i) { ++ struct vp9_frame *frame = vp9->frame_refs[i]; ++ int id_y; ++ int id_u_v; ++ ++ if (!frame) ++ continue; ++ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { ++ id_y = frame->index; ++ id_u_v = id_y; ++ } else { ++ id_y = frame->index * 2; ++ id_u_v = id_y + 1; ++ } ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, ++ (id_u_v << 16) | (id_u_v << 8) | id_y); ++ } ++} ++ ++static void codec_vp9_set_mc(struct amvdec_session *sess, ++ struct codec_vp9 *vp9) ++{ ++ struct amvdec_core *core = sess->core; ++ int i; ++ ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); ++ codec_vp9_set_refs(sess, vp9); ++ amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, (16 << 8) | 1); ++ codec_vp9_set_refs(sess, vp9); ++ ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_TBL_ACCCONFIG, BIT(2)); ++ for (i = 0; i < REFS_PER_FRAME; ++i) { ++ if (!vp9->frame_refs[i]) ++ continue; ++ ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, vp9->width); ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, vp9->height); ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, ++ (vp9->width << 14) / vp9->width); ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, ++ (vp9->height << 14) / vp9->height); ++ amvdec_write_dos(core, VP9D_MPP_REFINFO_DATA, ++ amvdec_am21c_body_size(vp9->width, vp9->height) >> 5); ++ } ++ ++ amvdec_write_dos(core, VP9D_MPP_REF_SCALE_ENBL, 0); ++} ++ ++static struct vp9_frame *codec_vp9_get_new_frame(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ union rpm_param *param = &vp9->rpm_param; ++ struct vb2_v4l2_buffer *vbuf; ++ struct vp9_frame *new_frame; ++ ++ new_frame = kzalloc(sizeof(*new_frame), GFP_KERNEL); ++ if (!new_frame) ++ return NULL; ++ ++ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); ++ if (!vbuf) { ++ dev_err(sess->core->dev, "No dst buffer available\n"); ++ kfree(new_frame); ++ return NULL; ++ } ++ ++ while (codec_vp9_get_frame_by_idx(vp9, vbuf->vb2_buf.index)) { ++ struct vb2_v4l2_buffer *old_vbuf = vbuf; ++ vbuf = v4l2_m2m_dst_buf_remove(sess->m2m_ctx); ++ v4l2_m2m_buf_queue(sess->m2m_ctx, old_vbuf); ++ if (!vbuf) { ++ dev_err(sess->core->dev, "No dst buffer available\n"); ++ kfree(new_frame); ++ return NULL; ++ } ++ } ++ ++ new_frame->vbuf = vbuf; ++ new_frame->index = vbuf->vb2_buf.index; ++ new_frame->intra_only = param->p.intra_only; ++ new_frame->show = param->p.show_frame; ++ new_frame->type = param->p.frame_type; ++ list_add_tail(&new_frame->list, &vp9->ref_frames_list); ++ vp9->frames_num++; ++ ++ return new_frame; ++} ++ ++static void codec_vp9_show_existing_frame(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ ++ if (!param->p.show_existing_frame) ++ return; ++ ++ printk("showing frame %u\n", param->p.frame_to_show_idx); ++} ++ ++static void codec_vp9_rm_noshow_frame(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ struct vp9_frame *tmp; ++ ++ list_for_each_entry(tmp, &vp9->ref_frames_list, list) { ++ if (tmp->show) ++ continue; ++ ++ printk("rm noshow: %u\n", tmp->index); ++ v4l2_m2m_buf_queue(sess->m2m_ctx, tmp->vbuf); ++ list_del(&tmp->list); ++ kfree(tmp); ++ vp9->frames_num--; ++ return; ++ } ++} ++ ++static void codec_vp9_process_frame(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9 = sess->priv; ++ union rpm_param *param = &vp9->rpm_param; ++ int intra_only; ++ ++ if (!param->p.show_frame) ++ codec_vp9_rm_noshow_frame(sess); ++ ++ vp9->cur_frame = codec_vp9_get_new_frame(sess); ++ if (!vp9->cur_frame) ++ return; ++ ++ printk("frame type: %08X; show_exist: %u; show: %u, intra_only: %u\n", param->p.frame_type, param->p.show_existing_frame, param->p.show_frame, param->p.intra_only); ++ codec_vp9_sync_ref(vp9); ++ codec_vp9_update_next_ref(vp9); ++ codec_vp9_show_existing_frame(vp9); ++ ++ intra_only = param->p.show_frame ? 0 : param->p.intra_only; ++ /* clear mpred (for keyframe only) */ ++ if (param->p.frame_type != KEY_FRAME && !intra_only) { ++ codec_vp9_set_mc(sess, vp9); ++ codec_vp9_set_mpred_mv(core, vp9); ++ } else { ++ amvdec_clear_dos_bits(core, HEVC_MPRED_CTRL4, BIT(6)); ++ } ++ ++ amvdec_write_dos(core, HEVC_PARSER_PICTURE_SIZE, ++ (vp9->height << 16) | vp9->width); ++ codec_vp9_set_sao(sess, &vp9->cur_frame->vbuf->vb2_buf); ++ ++ vp9_loop_filter_frame_init(core, &vp9->seg_4lf, ++ &vp9->lfi, &vp9->lf, vp9->default_filt_lvl); ++ ++ /* ask uCode to start decoding */ ++ amvdec_write_dos(core, VP9_DEC_STATUS_REG, VP9_10B_DECODE_SLICE); ++} ++ ++static void codec_vp9_process_lf(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ int i; ++ ++ vp9->lf.mode_ref_delta_enabled = param->p.mode_ref_delta_enabled; ++ vp9->lf.sharpness_level = param->p.sharpness_level; ++ vp9->default_filt_lvl = param->p.filter_level; ++ vp9->seg_4lf.enabled = param->p.seg_enabled; ++ vp9->seg_4lf.abs_delta = param->p.seg_abs_delta; ++ ++ for (i = 0; i < 4; i++) ++ vp9->lf.ref_deltas[i] = param->p.ref_deltas[i]; ++ ++ for (i = 0; i < 2; i++) ++ vp9->lf.mode_deltas[i] = param->p.mode_deltas[i]; ++ ++ for (i = 0; i < MAX_SEGMENTS; i++) ++ vp9->seg_4lf.feature_mask[i] = (param->p.seg_lf_info[i] & ++ 0x8000) ? (1 << SEG_LVL_ALT_LF) : 0; ++ ++ for (i = 0; i < MAX_SEGMENTS; i++) ++ vp9->seg_4lf.feature_data[i][SEG_LVL_ALT_LF] ++ = (param->p.seg_lf_info[i] ++ & 0x100) ? -(param->p.seg_lf_info[i] ++ & 0x3f) : (param->p.seg_lf_info[i] & 0x3f); ++} ++ ++static void codec_vp9_resume(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ ++ if (codec_hevc_setup_buffers(sess, vp9->is_10bit)) { ++ amvdec_abort(sess); ++ return; ++ } ++ ++ codec_hevc_setup_decode_head(sess, vp9->is_10bit); ++ codec_vp9_process_lf(vp9); ++ codec_vp9_process_frame(sess); ++} ++ ++/** ++ * The RPM section within the workspace contains ++ * many information regarding the parsed bitstream ++ */ ++static void codec_vp9_fetch_rpm(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ u16 *rpm_vaddr = vp9->workspace_vaddr + RPM_OFFSET; ++ int i, j; ++ ++ for (i = 0; i < RPM_BUF_SIZE; i += 4) ++ for (j = 0; j < 4; j++) ++ vp9->rpm_param.l.data[i + j] = rpm_vaddr[i + 3 - j]; ++} ++ ++static int codec_vp9_process_rpm(struct codec_vp9 *vp9) ++{ ++ union rpm_param *param = &vp9->rpm_param; ++ int src_changed = 0; ++ int is_10bit = 0; ++ int pic_width_64 = ALIGN(param->p.width, 64); ++ int pic_height_32 = ALIGN(param->p.height, 32); ++ int pic_width_lcu = (pic_width_64 % LCU_SIZE) ? ++ pic_width_64 / LCU_SIZE + 1 ++ : pic_width_64 / LCU_SIZE; ++ int pic_height_lcu = (pic_height_32 % LCU_SIZE) ? ++ pic_height_32 / LCU_SIZE + 1 ++ : pic_height_32 / LCU_SIZE; ++ vp9->lcu_total = pic_width_lcu * pic_height_lcu; ++ ++ if (param->p.bit_depth == 10) ++ is_10bit = 1; ++ ++ if (vp9->width != param->p.width || ++ vp9->height != param->p.height || ++ vp9->is_10bit != is_10bit) ++ src_changed = 1; ++ ++ vp9->width = param->p.width; ++ vp9->height = param->p.height; ++ vp9->is_10bit = is_10bit; ++ ++ printk("width: %u; height: %u; is_10bit: %d; src_changed: %d\n", vp9->width, vp9->height, is_10bit, src_changed); ++ return src_changed; ++} ++ ++static bool codec_vp9_is_ref(struct codec_vp9 *vp9, struct vp9_frame *frame) ++{ ++ int i; ++ ++ for (i = 0; i < REFS_PER_FRAME; ++i) ++ if (vp9->frame_refs[i] == frame) ++ return true; ++ ++ return false; ++} ++ ++static void codec_vp9_show_frame(struct amvdec_session *sess) ++{ ++ struct codec_vp9 *vp9 = sess->priv; ++ struct vp9_frame *tmp, *n; ++ ++ list_for_each_entry_safe(tmp, n, &vp9->ref_frames_list, list) { ++ if (!tmp->show || tmp == vp9->cur_frame) ++ continue; ++ ++ if (!tmp->done) { ++ printk("Doning %u\n", tmp->index); ++ amvdec_dst_buf_done(sess, tmp->vbuf, V4L2_FIELD_NONE); ++ tmp->done = 1; ++ vp9->frames_num--; ++ } ++ ++ if (codec_vp9_is_ref(vp9, tmp)) ++ continue; ++ ++ printk("deleting %d\n", tmp->index); ++ list_del(&tmp->list); ++ kfree(tmp); ++ } ++} ++ ++static irqreturn_t codec_vp9_threaded_isr(struct amvdec_session *sess) ++{ ++ struct amvdec_core *core = sess->core; ++ struct codec_vp9 *vp9 = sess->priv; ++ u32 dec_status = amvdec_read_dos(core, VP9_DEC_STATUS_REG); ++ u32 prob_status = amvdec_read_dos(core, VP9_ADAPT_PROB_REG); ++ int i; ++ ++ if (!vp9) ++ return IRQ_HANDLED; ++ ++ mutex_lock(&vp9->lock); ++ if (dec_status != VP9_HEAD_PARSER_DONE) { ++ dev_err(core->dev_dec, "Unrecognized dec_status: %08X\n", ++ dec_status); ++ amvdec_abort(sess); ++ goto unlock; ++ } ++ ++ printk("ISR: %08X;%08X\n", dec_status, prob_status); ++ sess->keyframe_found = 1; ++ ++ /* Invalidate first 3 refs */ ++ for (i = 0; i < 3; ++i) ++ vp9->frame_refs[i] = NULL; ++ ++ vp9->prev_frame = vp9->cur_frame; ++ codec_vp9_update_ref(vp9); ++ ++ codec_vp9_fetch_rpm(sess); ++ if (codec_vp9_process_rpm(vp9)) { ++ amvdec_src_change(sess, vp9->width, vp9->height, 16); ++ goto unlock; ++ } ++ ++ codec_vp9_process_lf(vp9); ++ codec_vp9_process_frame(sess); ++ codec_vp9_show_frame(sess); ++ ++unlock: ++ mutex_unlock(&vp9->lock); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t codec_vp9_isr(struct amvdec_session *sess) ++{ ++ return IRQ_WAKE_THREAD; ++} ++ ++struct amvdec_codec_ops codec_vp9_ops = { ++ .start = codec_vp9_start, ++ .stop = codec_vp9_stop, ++ .isr = codec_vp9_isr, ++ .threaded_isr = codec_vp9_threaded_isr, ++ .num_pending_bufs = codec_vp9_num_pending_bufs, ++ .drain = codec_vp9_flush_output, ++ .resume = codec_vp9_resume, ++}; +diff --git a/drivers/media/platform/meson/vdec/codec_vp9.h b/drivers/media/platform/meson/vdec/codec_vp9.h +new file mode 100644 +index 0000000000000..641cd75e323b8 +--- /dev/null ++++ b/drivers/media/platform/meson/vdec/codec_vp9.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * Copyright (C) 2018 Maxime Jourdan ++ */ ++ ++#ifndef __MESON_VDEC_CODEC_VP9_H_ ++#define __MESON_VDEC_CODEC_VP9_H_ ++ ++#include "vdec.h" ++ ++extern struct amvdec_codec_ops codec_vp9_ops; ++ ++#endif +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/esparser.c b/drivers/media/platform/meson/vdec/esparser.c +index d7ac51e08730d..535015f1be5e1 100644 +--- a/drivers/media/platform/meson/vdec/esparser.c ++++ b/drivers/media/platform/meson/vdec/esparser.c +@@ -279,7 +279,9 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) + if (codec_ops->num_pending_bufs) + num_dst_bufs = codec_ops->num_pending_bufs(sess); + +- num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx) - 1; ++ num_dst_bufs += v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); ++ if (sess->fmt_out->pixfmt == V4L2_PIX_FMT_VP9) ++ num_dst_bufs -= 2; + + if (esparser_vififo_get_free_space(sess) < payload_size || + atomic_read(&sess->esparser_queued_bufs) >= num_dst_bufs) +diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h +index ba49f906be5a9..c80479d7c9c3b 100644 +--- a/drivers/media/platform/meson/vdec/hevc_regs.h ++++ b/drivers/media/platform/meson/vdec/hevc_regs.h +@@ -120,6 +120,8 @@ + #define HEVC_MPRED_L0_REF00_POC 0xc880 + #define HEVC_MPRED_L1_REF00_POC 0xc8c0 + ++#define HEVC_MPRED_CTRL4 0xc930 ++ + #define HEVC_MPRED_CUR_POC 0xc980 + #define HEVC_MPRED_COL_POC 0xc984 + #define HEVC_MPRED_MV_RD_END_ADDR 0xc988 +@@ -138,6 +140,10 @@ + #define HEVCD_IPP_LINEBUFF_BASE 0xd024 + #define HEVCD_IPP_AXIIF_CONFIG 0xd02c + ++#define VP9D_MPP_REF_SCALE_ENBL 0xd104 ++#define VP9D_MPP_REFINFO_TBL_ACCCONFIG 0xd108 ++#define VP9D_MPP_REFINFO_DATA 0xd10c ++ + #define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180 + #define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184 + #define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190 +@@ -162,6 +168,7 @@ + #define HEVC_DBLK_CFG9 0xd424 + #define HEVC_DBLK_CFGA 0xd428 + #define HEVC_DBLK_STS0 0xd42c ++#define HEVC_DBLK_CFGB 0xd42c + #define HEVC_DBLK_STS1 0xd430 + + #define HEVC_SAO_VERSION 0xd800 +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c +index 8a76518cdcde7..cca7c369c2588 100644 +--- a/drivers/media/platform/meson/vdec/vdec_platform.c ++++ b/drivers/media/platform/meson/vdec/vdec_platform.c +@@ -14,6 +14,7 @@ + #include "codec_mpeg4.h" + #include "codec_mjpeg.h" + #include "codec_hevc.h" ++#include "codec_vp9.h" + + static const struct amvdec_format vdec_formats_gxbb[] = { + { +@@ -102,6 +103,17 @@ static const struct amvdec_format vdec_formats_gxbb[] = { + }; + + static const struct amvdec_format vdec_formats_gxl[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_VP9, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_vp9_ops, ++ .firmware_path = "meson/gx/vvp9_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, + { + .pixfmt = V4L2_PIX_FMT_HEVC, + .min_buffers = 16, +@@ -188,6 +200,17 @@ static const struct amvdec_format vdec_formats_gxl[] = { + }; + + static const struct amvdec_format vdec_formats_gxm[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_VP9, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_vp9_ops, ++ .firmware_path = "meson/gx/vvp9_mc", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, + { + .pixfmt = V4L2_PIX_FMT_HEVC, + .min_buffers = 16, + +From ab712fac73f943456eb82c37ac126861ca9f1e93 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Thu, 7 Feb 2019 17:37:34 +0100 +Subject: [PATCH 220/249] WIP: media: meson: vdec: add g12a platform + +--- + .../media/platform/meson/vdec/codec_hevc.c | 38 ++++++- + .../platform/meson/vdec/codec_hevc_common.c | 9 -- + drivers/media/platform/meson/vdec/codec_vp9.c | 54 +++++++-- + drivers/media/platform/meson/vdec/hevc_regs.h | 1 + + drivers/media/platform/meson/vdec/vdec.c | 13 ++- + drivers/media/platform/meson/vdec/vdec.h | 1 + + drivers/media/platform/meson/vdec/vdec_hevc.c | 9 ++ + .../media/platform/meson/vdec/vdec_platform.c | 103 ++++++++++++++++++ + .../media/platform/meson/vdec/vdec_platform.h | 2 + + 9 files changed, 206 insertions(+), 24 deletions(-) + +diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c +index 03f00f969f025..e16e937d56e85 100644 +--- a/drivers/media/platform/meson/vdec/codec_hevc.c ++++ b/drivers/media/platform/meson/vdec/codec_hevc.c +@@ -68,7 +68,8 @@ + #define SWAP_BUF2_SIZE 0x800 + #define SCALELUT_SIZE 0x8000 + #define DBLK_PARA_SIZE 0x20000 +-#define DBLK_DATA_SIZE 0x40000 ++#define DBLK_DATA_SIZE 0x80000 ++#define DBLK_DATA2_SIZE 0x80000 + #define MMU_VBH_SIZE 0x5000 + #define MPRED_ABV_SIZE 0x8000 + #define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) +@@ -88,7 +89,8 @@ + #define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) + #define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) + #define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) +-#define MMU_VBH_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) ++#define DBLK_DATA2_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) ++#define MMU_VBH_OFFSET (DBLK_DATA2_OFFSET + DBLK_DATA2_SIZE) + #define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) + #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) + #define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) +@@ -523,6 +525,7 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) + amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); ++ amvdec_write_dos(core, HEVC_DBLK_CFGE, wkaddr + DBLK_DATA2_OFFSET); + + return 0; + } +@@ -547,6 +550,8 @@ static int codec_hevc_start(struct amvdec_session *sess) + goto free_hevc; + + amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, (0xf << 25)); + + val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; + val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | +@@ -755,6 +760,25 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + (amvdec_get_output_size(sess) / 2)); + + if (frame->cur_slice_idx == 0) { ++ if (core->platform->revision >= VDEC_REVISION_G12A) { ++ val = 0x54 << 8; ++ ++ /* enable first, compressed write */ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) ++ val |= BIT(8); ++ ++ /* enable second, uncompressed write */ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) ++ val |= BIT(9); ++ ++ /* dblk pipeline mode=1 for performance */ ++ if (hevc->width >= 1280) ++ val |= BIT(4); ++ ++ amvdec_write_dos(core, HEVC_DBLK_CFGB, val); ++ amvdec_write_dos(core, HEVC_DBLK_STS1 + 4, BIT(28)); ++ } ++ + amvdec_write_dos(core, HEVC_DBLK_CFG2, + hevc->width | (hevc->height << 16)); + +@@ -770,10 +794,12 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + + val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; + val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ +- if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) +- val |= BIT(0); /* disable cm compression */ +- else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) +- val |= BIT(1); /* Disable double write */ ++ if (core->platform->revision < VDEC_REVISION_G12A) { ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) ++ val |= BIT(0); /* disable cm compression */ ++ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) ++ val |= BIT(1); /* Disable double write */ ++ } + + amvdec_write_dos(core, HEVC_SAO_CTRL1, val); + +diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.c b/drivers/media/platform/meson/vdec/codec_hevc_common.c +index 2b296beb5d88a..5c372a9b0f03c 100644 +--- a/drivers/media/platform/meson/vdec/codec_hevc_common.c ++++ b/drivers/media/platform/meson/vdec/codec_hevc_common.c +@@ -111,15 +111,6 @@ codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) + } + } + +- /* Fill the remaining unused slots with the last buffer's Y addr */ +- for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, +- buf_y_paddr >> 5); +- if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, +- buf_uv_paddr >> 5); +- } +- + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); + for (i = 0; i < 32; ++i) +diff --git a/drivers/media/platform/meson/vdec/codec_vp9.c b/drivers/media/platform/meson/vdec/codec_vp9.c +index 731119b9ee17a..39e8eb5937bf0 100644 +--- a/drivers/media/platform/meson/vdec/codec_vp9.c ++++ b/drivers/media/platform/meson/vdec/codec_vp9.c +@@ -90,8 +90,8 @@ enum FRAME_TYPE { + #define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) + #define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) + #define SEG_MAP_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) +-#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) +-#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) ++#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) ++#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) + #define MMU_VBH_OFFSET (COUNT_OFFSET + COUNT_SIZE) + #define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) + #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) +@@ -326,7 +326,11 @@ vp9_loop_filter_init(struct amvdec_core *core, struct codec_vp9 *vp9) + amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); + } + +- amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ /* VP9 video format */ ++ amvdec_write_dos(core, HEVC_DBLK_CFGB, (0x54 << 8) | BIT(0)); ++ else ++ amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); + } + + static void +@@ -447,6 +451,13 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) + return -ENOMEM; + } + ++ memset(vp9->workspace_vaddr + DBLK_PARA_OFFSET, 0, DBLK_PARA_SIZE); ++ memset(vp9->workspace_vaddr + COUNT_OFFSET, 0, COUNT_SIZE); ++ memset(vp9->workspace_vaddr + PROB_OFFSET, 0, PROB_SIZE); ++ ++ printk("Workspace: %08X-%08X\n", wkaddr, wkaddr + SIZE_WORKSPACE); ++ printk("DBLK_PARA: %08X\n", wkaddr + DBLK_PARA_OFFSET); ++ + vp9->workspace_paddr = wkaddr; + + amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); +@@ -461,11 +472,17 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) + amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, + wkaddr + SWAP_BUF2_OFFSET); + amvdec_write_dos(core, VP9_SCALELUT, wkaddr + SCALELUT_OFFSET); ++ ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ amvdec_write_dos(core, HEVC_DBLK_CFGE, ++ wkaddr + DBLK_PARA_OFFSET); ++ + amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); + amvdec_write_dos(core, VP9_SEG_MAP_BUFFER, wkaddr + SEG_MAP_OFFSET); + amvdec_write_dos(core, VP9_PROB_SWAP_BUFFER, wkaddr + PROB_OFFSET); + amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); ++ amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); + + return 0; + } +@@ -487,6 +504,9 @@ static int codec_vp9_start(struct amvdec_session *sess) + goto free_vp9; + + amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); ++ // stream_fifo_hole ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ amvdec_write_dos_bits(core, HEVC_STREAM_FIFO_CTL, BIT(29)); + + val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x7fffffff; + val |= (3 << 29) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | BIT(0); +@@ -597,14 +617,34 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + amvdec_write_dos(core, HEVC_SAO_C_LENGTH, + (amvdec_get_output_size(sess) / 2)); + ++ if (core->platform->revision >= VDEC_REVISION_G12A) { ++ amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, BIT(4) | BIT(5) | BIT(8) | BIT(9)); ++ /* enable first, compressed write */ ++ if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) ++ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(8)); ++ ++ /* enable second, uncompressed write */ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) ++ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(9)); ++ ++ /* dblk pipeline mode=1 for performance */ ++ if (sess->width >= 1280) ++ amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(4)); ++ ++ printk("HEVC_DBLK_CFGB: %08X\n", amvdec_read_dos(core, HEVC_DBLK_CFGB)); ++ } ++ + val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; + val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ +- if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) +- val |= BIT(0); /* disable cm compression */ +- else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) +- val |= BIT(1); /* Disable double write */ ++ if (core->platform->revision < VDEC_REVISION_G12A) { ++ if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) ++ val |= BIT(0); /* disable cm compression */ ++ else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) ++ val |= BIT(1); /* Disable double write */ ++ } + + amvdec_write_dos(core, HEVC_SAO_CTRL1, val); ++ printk("HEVC_SAO_CTRL1: %08X\n", val); + + if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { + /* no downscale for NV12 */ +diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h +index c80479d7c9c3b..dc2c2e085b051 100644 +--- a/drivers/media/platform/meson/vdec/hevc_regs.h ++++ b/drivers/media/platform/meson/vdec/hevc_regs.h +@@ -170,6 +170,7 @@ + #define HEVC_DBLK_STS0 0xd42c + #define HEVC_DBLK_CFGB 0xd42c + #define HEVC_DBLK_STS1 0xd430 ++#define HEVC_DBLK_CFGE 0xd438 + + #define HEVC_SAO_VERSION 0xd800 + #define HEVC_SAO_CTRL0 0xd804 +diff --git a/drivers/media/platform/meson/vdec/vdec.c b/drivers/media/platform/meson/vdec/vdec.c +index dd5e6864fbdaa..233604d322356 100644 +--- a/drivers/media/platform/meson/vdec/vdec.c ++++ b/drivers/media/platform/meson/vdec/vdec.c +@@ -941,6 +941,8 @@ static const struct of_device_id vdec_dt_match[] = { + .data = &vdec_platform_gxm }, + { .compatible = "amlogic,gxl-vdec", + .data = &vdec_platform_gxl }, ++ { .compatible = "amlogic,g12a-vdec", ++ .data = &vdec_platform_g12a }, + {} + }; + MODULE_DEVICE_TABLE(of, vdec_dt_match); +@@ -987,6 +989,15 @@ static int vdec_probe(struct platform_device *pdev) + if (!core->canvas) + return PTR_ERR(core->canvas); + ++ of_id = of_match_node(vdec_dt_match, dev->of_node); ++ core->platform = of_id->data; ++ ++ if (core->platform->revision == VDEC_REVISION_G12A) { ++ core->vdec_hevcf_clk = devm_clk_get(dev, "vdec_hevcf"); ++ if (IS_ERR(core->vdec_hevcf_clk)) ++ return -EPROBE_DEFER; ++ } ++ + core->dos_parser_clk = devm_clk_get(dev, "dos_parser"); + if (IS_ERR(core->dos_parser_clk)) + return -EPROBE_DEFER; +@@ -1029,8 +1040,6 @@ static int vdec_probe(struct platform_device *pdev) + goto err_vdev_release; + } + +- of_id = of_match_node(vdec_dt_match, dev->of_node); +- core->platform = of_id->data; + core->vdev_dec = vdev; + core->dev_dec = dev; + mutex_init(&core->lock); +diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h +index 885777e48142a..69a5f82ae80f2 100644 +--- a/drivers/media/platform/meson/vdec/vdec.h ++++ b/drivers/media/platform/meson/vdec/vdec.h +@@ -76,6 +76,7 @@ struct amvdec_core { + struct clk *dos_clk; + struct clk *vdec_1_clk; + struct clk *vdec_hevc_clk; ++ struct clk *vdec_hevcf_clk; + + struct reset_control *esparser_reset; + +diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.c b/drivers/media/platform/meson/vdec/vdec_hevc.c +index 8872f58d39fea..a706dbf3ae8c4 100644 +--- a/drivers/media/platform/meson/vdec/vdec_hevc.c ++++ b/drivers/media/platform/meson/vdec/vdec_hevc.c +@@ -123,6 +123,8 @@ static int vdec_hevc_stop(struct amvdec_session *sess) + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); + ++ if (core->platform->revision == VDEC_REVISION_G12A) ++ clk_disable_unprepare(core->vdec_hevcf_clk); + clk_disable_unprepare(core->vdec_hevc_clk); + + return 0; +@@ -139,6 +141,13 @@ static int vdec_hevc_start(struct amvdec_session *sess) + if (ret) + return ret; + ++ if (core->platform->revision == VDEC_REVISION_G12A) { ++ clk_set_rate(core->vdec_hevcf_clk, 666666666); ++ ret = clk_prepare_enable(core->vdec_hevcf_clk); ++ if (ret) ++ return ret; ++ } ++ + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_HEVC, 0); + udelay(10); +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.c b/drivers/media/platform/meson/vdec/vdec_platform.c +index cca7c369c2588..79ee96638552b 100644 +--- a/drivers/media/platform/meson/vdec/vdec_platform.c ++++ b/drivers/media/platform/meson/vdec/vdec_platform.c +@@ -296,6 +296,103 @@ static const struct amvdec_format vdec_formats_gxm[] = { + }, + }; + ++static const struct amvdec_format vdec_formats_g12a[] = { ++ { ++ .pixfmt = V4L2_PIX_FMT_VP9, ++ .min_buffers = 4, ++ .max_buffers = 16, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_vp9_ops, ++ .firmware_path = "meson/vdec/g12a_vp9.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, ++ { ++ .pixfmt = V4L2_PIX_FMT_HEVC, ++ .min_buffers = 16, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_hevc_ops, ++ .codec_ops = &codec_hevc_ops, ++ .firmware_path = "meson/vdec/g12a_hevc.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MJPEG, ++ .min_buffers = 4, ++ .max_buffers = 4, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mjpeg_ops, ++ .firmware_path = "meson/vdec/gxl_mjpeg.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG4, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg4_5.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H263, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/vdec/gxl_h263.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_XVID, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg4_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg4_5.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_H264, ++ .min_buffers = 2, ++ .max_buffers = 24, ++ .max_width = 3840, ++ .max_height = 2160, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_h264_ops, ++ .firmware_path = "meson/vdec/g12a_h264.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG1, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, { ++ .pixfmt = V4L2_PIX_FMT_MPEG2, ++ .min_buffers = 8, ++ .max_buffers = 8, ++ .max_width = 1920, ++ .max_height = 1080, ++ .flags = V4L2_FMT_FLAG_FIXED_RESOLUTION, ++ .vdec_ops = &vdec_1_ops, ++ .codec_ops = &codec_mpeg12_ops, ++ .firmware_path = "meson/vdec/gxl_mpeg12.bin", ++ .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, ++ }, ++}; ++ + const struct vdec_platform vdec_platform_gxbb = { + .formats = vdec_formats_gxbb, + .num_formats = ARRAY_SIZE(vdec_formats_gxbb), +@@ -313,3 +410,9 @@ const struct vdec_platform vdec_platform_gxm = { + .num_formats = ARRAY_SIZE(vdec_formats_gxm), + .revision = VDEC_REVISION_GXM, + }; ++ ++const struct vdec_platform vdec_platform_g12a = { ++ .formats = vdec_formats_g12a, ++ .num_formats = ARRAY_SIZE(vdec_formats_g12a), ++ .revision = VDEC_REVISION_G12A, ++}; +diff --git a/drivers/media/platform/meson/vdec/vdec_platform.h b/drivers/media/platform/meson/vdec/vdec_platform.h +index f6025326db1d6..7c61b941b39f4 100644 +--- a/drivers/media/platform/meson/vdec/vdec_platform.h ++++ b/drivers/media/platform/meson/vdec/vdec_platform.h +@@ -15,6 +15,7 @@ enum vdec_revision { + VDEC_REVISION_GXBB, + VDEC_REVISION_GXL, + VDEC_REVISION_GXM, ++ VDEC_REVISION_G12A, + }; + + struct vdec_platform { +@@ -26,5 +27,6 @@ struct vdec_platform { + extern const struct vdec_platform vdec_platform_gxbb; + extern const struct vdec_platform vdec_platform_gxm; + extern const struct vdec_platform vdec_platform_gxl; ++extern const struct vdec_platform vdec_platform_g12a; + + #endif + +From e88e2fbf6b08d6d7d4702306878bbe7b503cda3c Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Fri, 1 Mar 2019 12:41:03 +0100 +Subject: [PATCH 221/249] WIP: media: meson: vp9: add IOMMU support + +Starting with GXL (S905X), the HEVC/VP9 decoder hardware supports an +IOMMU to access the decoded frames. This IOMMU is controlled by writing +the buffer's page IDs to the firmware, which then does the actual work. + +This commit adds support for using the IOMMU with VP9/HEVC on G12A, the +first SoC on which it becomes mandatory. +--- + .../media/platform/meson/vdec/codec_hevc.c | 35 ++-- + .../platform/meson/vdec/codec_hevc_common.c | 177 ++++++++++++++---- + .../platform/meson/vdec/codec_hevc_common.h | 31 ++- + drivers/media/platform/meson/vdec/codec_vp9.c | 71 ++++--- + drivers/media/platform/meson/vdec/hevc_regs.h | 5 + + drivers/media/platform/meson/vdec/vdec.h | 5 - + drivers/media/platform/meson/vdec/vdec_hevc.c | 14 +- + 7 files changed, 255 insertions(+), 83 deletions(-) + +diff --git a/drivers/media/platform/meson/vdec/codec_hevc.c b/drivers/media/platform/meson/vdec/codec_hevc.c +index e16e937d56e85..65d2ad4d83459 100644 +--- a/drivers/media/platform/meson/vdec/codec_hevc.c ++++ b/drivers/media/platform/meson/vdec/codec_hevc.c +@@ -75,6 +75,7 @@ + #define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) + #define RPM_BUF_SIZE 0x100 + #define LMEM_SIZE 0xA00 ++#define MMU_MAP_SIZE 0x4800 + + #define IPP_OFFSET 0x00 + #define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE) +@@ -95,6 +96,7 @@ + #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) + #define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) + #define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE) ++#define MMU_MAP_OFFSET (LMEM_OFFSET + LMEM_SIZE) + + /* ISR decode status */ + #define HEVC_DEC_IDLE 0x0 +@@ -236,6 +238,9 @@ struct hevc_frame { + struct codec_hevc { + struct mutex lock; + ++ /* Common part of the HEVC decoder */ ++ struct codec_hevc_common common; ++ + /* Buffer for the HEVC Workspace */ + void *workspace_vaddr; + dma_addr_t workspace_paddr; +@@ -517,15 +522,20 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) + amvdec_write_dos(core, HEVC_PPS_BUFFER, wkaddr + PPS_OFFSET); + amvdec_write_dos(core, HEVC_SAO_UP, wkaddr + SAO_UP_OFFSET); + ++ if (core->platform->revision >= VDEC_REVISION_G12A) ++ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR, ++ wkaddr + MMU_MAP_OFFSET); ++ + /* No MMU */ +- amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, ++ /*amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER, + wkaddr + SWAP_BUF_OFFSET); + amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2, +- wkaddr + SWAP_BUF2_OFFSET); ++ wkaddr + SWAP_BUF2_OFFSET);*/ + amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFGE, wkaddr + DBLK_DATA2_OFFSET); ++ amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); + + return 0; + } +@@ -549,9 +559,10 @@ static int codec_hevc_start(struct amvdec_session *sess) + if (ret) + goto free_hevc; + +- amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); +- if (core->platform->revision == VDEC_REVISION_G12A) +- amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, (0xf << 25)); ++ val = BIT(0); /* stream_fetch_enable */ ++ if (core->platform->revision >= VDEC_REVISION_G12A) ++ val |= (0xf << 25); /* arwlen_axi_max */ ++ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, val); + + val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; + val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | +@@ -608,9 +619,9 @@ static int codec_hevc_start(struct amvdec_session *sess) + goto free_hevc; + } + +- amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); ++ /*amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr); + amvdec_write_dos(core, HEVC_AUX_DATA_SIZE, +- (((SIZE_AUX) >> 4) << 16) | 0); ++ (((SIZE_AUX) >> 4) << 16) | 0);*/ + mutex_init(&hevc->lock); + sess->priv = hevc; + +@@ -652,7 +663,7 @@ static int codec_hevc_stop(struct amvdec_session *sess) + dma_free_coherent(core->dev, SIZE_AUX, + hevc->aux_vaddr, hevc->aux_paddr); + +- codec_hevc_free_fbc_buffers(sess); ++ codec_hevc_free_fbc_buffers(sess, &hevc->common); + mutex_unlock(&hevc->lock); + mutex_destroy(&hevc->lock); + +@@ -732,7 +743,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + + if (codec_hevc_use_downsample(sess->pixfmt_cap, hevc->is_10bit)) + buf_y_paddr = +- sess->fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; ++ hevc->common.fbc_buffer_paddr[frame->vbuf->vb2_buf.index]; + else + buf_y_paddr = + vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0); +@@ -776,7 +787,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) + val |= BIT(4); + + amvdec_write_dos(core, HEVC_DBLK_CFGB, val); +- amvdec_write_dos(core, HEVC_DBLK_STS1 + 4, BIT(28)); ++ amvdec_write_dos(core, HEVC_DBLK_STS1 + 16, BIT(28)); + } + + amvdec_write_dos(core, HEVC_DBLK_CFG2, +@@ -1323,7 +1334,7 @@ static void codec_hevc_resume(struct amvdec_session *sess) + { + struct codec_hevc *hevc = sess->priv; + +- if (codec_hevc_setup_buffers(sess, hevc->is_10bit)) { ++ if (codec_hevc_setup_buffers(sess, &hevc->common, hevc->is_10bit)) { + amvdec_abort(sess); + return; + } +@@ -1340,6 +1351,8 @@ static irqreturn_t codec_hevc_threaded_isr(struct amvdec_session *sess) + struct codec_hevc *hevc = sess->priv; + u32 dec_status = amvdec_read_dos(core, HEVC_DEC_STATUS_REG); + ++ printk("ISR!\n"); ++ + if (!hevc) + return IRQ_HANDLED; + +diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.c b/drivers/media/platform/meson/vdec/codec_hevc_common.c +index 5c372a9b0f03c..de7eb6cfbe858 100644 +--- a/drivers/media/platform/meson/vdec/codec_hevc_common.c ++++ b/drivers/media/platform/meson/vdec/codec_hevc_common.c +@@ -10,6 +10,9 @@ + #include "vdec_helpers.h" + #include "hevc_regs.h" + ++#define MMU_COMPRESS_HEADER_SIZE 0x48000 ++#define MMU_MAP_SIZE 0x4800 ++ + /* Configure decode head read mode */ + void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) + { +@@ -23,7 +26,12 @@ void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) + return; + } + +- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); ++ if (codec_hevc_use_mmu(core->platform->revision, ++ sess->pixfmt_cap, is_10bit)) ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(4)); ++ else ++ amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); ++ + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); + amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); + amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); +@@ -31,8 +39,9 @@ void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) + } + EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head); + +-static void +-codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) ++static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ int is_10bit) + { + struct amvdec_core *core = sess->core; + struct v4l2_m2m_buffer *buf; +@@ -46,22 +55,26 @@ codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); + + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { +- idx = buf->vb.vb2_buf.index; ++ struct vb2_buffer *vb = &buf->vb.vb2_buf; ++ idx = vb->index; + + if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) +- buf_y_paddr = sess->fbc_buffer_paddr[idx]; ++ buf_y_paddr = comm->fbc_buffer_paddr[idx]; + else +- buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); + + if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { + val = buf_y_paddr | (idx << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, ++ val); + } else { +- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); + val = buf_y_paddr | ((idx * 2) << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, ++ val); + val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; +- amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, val); ++ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, ++ val); + } + } + +@@ -80,32 +93,37 @@ codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit) + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); + } + +-static void +-codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) ++static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ int is_10bit) + { + struct amvdec_core *core = sess->core; + struct v4l2_m2m_buffer *buf; +- u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); +- dma_addr_t buf_y_paddr = 0; +- dma_addr_t buf_uv_paddr = 0; ++ u32 revision = core->platform->revision; ++ u32 pixfmt_cap = sess->pixfmt_cap; + int i; + + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, + BIT(2) | BIT(1)); + + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { +- u32 idx = buf->vb.vb2_buf.index; ++ struct vb2_buffer *vb = &buf->vb.vb2_buf; ++ dma_addr_t buf_y_paddr = 0; ++ dma_addr_t buf_uv_paddr = 0; ++ u32 idx = vb->index; + +- if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) +- buf_y_paddr = sess->fbc_buffer_paddr[idx]; ++ if (codec_hevc_use_mmu(revision, pixfmt_cap, is_10bit)) ++ buf_y_paddr = comm->mmu_header_paddr[idx]; ++ else if (codec_hevc_use_downsample(pixfmt_cap, is_10bit)) ++ buf_y_paddr = comm->fbc_buffer_paddr[idx]; + else +- buf_y_paddr = +- vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); ++ buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); + + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, + buf_y_paddr >> 5); +- if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { +- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); ++ ++ if (!codec_hevc_use_fbc(pixfmt_cap, is_10bit)) { ++ buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, + buf_uv_paddr >> 5); + } +@@ -117,24 +135,26 @@ codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); + } + +-void codec_hevc_free_fbc_buffers(struct amvdec_session *sess) ++void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm) + { + struct device *dev = sess->core->dev; + u32 am21_size = amvdec_am21c_size(sess->width, sess->height); + int i; + + for (i = 0; i < MAX_REF_PIC_NUM; ++i) { +- if (sess->fbc_buffer_vaddr[i]) { ++ if (comm->fbc_buffer_vaddr[i]) { + dma_free_coherent(dev, am21_size, +- sess->fbc_buffer_vaddr[i], +- sess->fbc_buffer_paddr[i]); +- sess->fbc_buffer_vaddr[i] = NULL; ++ comm->fbc_buffer_vaddr[i], ++ comm->fbc_buffer_paddr[i]); ++ comm->fbc_buffer_vaddr[i] = NULL; + } + } + } + EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers); + +-static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) ++static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm) + { + struct device *dev = sess->core->dev; + struct v4l2_m2m_buffer *buf; +@@ -147,33 +167,118 @@ static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess) + GFP_KERNEL); + if (!vaddr) { + dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); +- codec_hevc_free_fbc_buffers(sess); ++ codec_hevc_free_fbc_buffers(sess, comm); ++ return -ENOMEM; ++ } ++ ++ comm->fbc_buffer_vaddr[idx] = vaddr; ++ comm->fbc_buffer_paddr[idx] = paddr; ++ } ++ ++ return 0; ++} ++ ++void codec_hevc_free_mmu_headers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm) ++{ ++ struct device *dev = sess->core->dev; ++ int i; ++ ++ for (i = 0; i < MAX_REF_PIC_NUM; ++i) { ++ if (comm->mmu_header_vaddr[i]) { ++ dma_free_coherent(dev, MMU_COMPRESS_HEADER_SIZE, ++ comm->mmu_header_vaddr[i], ++ comm->mmu_header_paddr[i]); ++ comm->mmu_header_vaddr[i] = NULL; ++ } ++ } ++ ++ if (comm->mmu_map_vaddr) { ++ dma_free_coherent(dev, MMU_MAP_SIZE, ++ comm->mmu_map_vaddr, ++ comm->mmu_map_paddr); ++ comm->mmu_map_vaddr = NULL; ++ } ++} ++EXPORT_SYMBOL_GPL(codec_hevc_free_mmu_headers); ++ ++static int codec_hevc_alloc_mmu_headers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm) ++{ ++ struct device *dev = sess->core->dev; ++ struct v4l2_m2m_buffer *buf; ++ ++ comm->mmu_map_vaddr = dma_alloc_coherent(dev, MMU_MAP_SIZE, ++ &comm->mmu_map_paddr, ++ GFP_KERNEL); ++ if (!comm->mmu_map_vaddr) ++ return -ENOMEM; ++ ++ v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { ++ u32 idx = buf->vb.vb2_buf.index; ++ dma_addr_t paddr; ++ void *vaddr = dma_alloc_coherent(dev, MMU_COMPRESS_HEADER_SIZE, ++ &paddr, GFP_KERNEL); ++ if (!vaddr) { ++ dev_err(dev, "Couldn't allocate MMU header %u\n", idx); ++ codec_hevc_free_mmu_headers(sess, comm); + return -ENOMEM; + } + +- sess->fbc_buffer_vaddr[idx] = vaddr; +- sess->fbc_buffer_paddr[idx] = paddr; ++ comm->mmu_header_vaddr[idx] = vaddr; ++ comm->mmu_header_paddr[idx] = paddr; + } + + return 0; + } + +-int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit) ++int codec_hevc_setup_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ int is_10bit) + { + struct amvdec_core *core = sess->core; + int ret; + + if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) { +- ret = codec_hevc_alloc_fbc_buffers(sess); ++ ret = codec_hevc_alloc_fbc_buffers(sess, comm); + if (ret) + return ret; + } + ++ if (codec_hevc_use_mmu(core->platform->revision, ++ sess->pixfmt_cap, is_10bit)) { ++ ret = codec_hevc_alloc_mmu_headers(sess, comm); ++ if (ret) { ++ codec_hevc_free_fbc_buffers(sess, comm); ++ return ret; ++ } ++ } ++ + if (core->platform->revision == VDEC_REVISION_GXBB) +- codec_hevc_setup_buffers_gxbb(sess, is_10bit); ++ codec_hevc_setup_buffers_gxbb(sess, comm, is_10bit); + else +- codec_hevc_setup_buffers_gxl(sess, is_10bit); ++ codec_hevc_setup_buffers_gxl(sess, comm, is_10bit); + + return 0; + } +-EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); +\ No newline at end of file ++EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); ++ ++void codec_hevc_fill_mmu_map(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ struct vb2_buffer *vb) ++{ ++ u32 size = amvdec_am21c_size(sess->width, sess->height); ++ u32 nb_pages = size / PAGE_SIZE; ++ u32 *mmu_map = comm->mmu_map_vaddr; ++ u32 first_page; ++ u32 i; ++ ++ if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) ++ first_page = comm->fbc_buffer_paddr[vb->index] >> PAGE_SHIFT; ++ else ++ first_page = vb2_dma_contig_plane_dma_addr(vb, 0) >> PAGE_SHIFT; ++ ++ for (i = 0; i < nb_pages; ++i) ++ mmu_map[i] = first_page + i; ++} ++EXPORT_SYMBOL_GPL(codec_hevc_fill_mmu_map); +diff --git a/drivers/media/platform/meson/vdec/codec_hevc_common.h b/drivers/media/platform/meson/vdec/codec_hevc_common.h +index 96493f9fe6995..e31aed5ee7b85 100644 +--- a/drivers/media/platform/meson/vdec/codec_hevc_common.h ++++ b/drivers/media/platform/meson/vdec/codec_hevc_common.h +@@ -25,6 +25,19 @@ static const u16 vdec_hevc_parser_cmd[] = { + 0x7C00 + }; + ++#define MAX_REF_PIC_NUM 24 ++ ++struct codec_hevc_common { ++ void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; ++ ++ void *mmu_header_vaddr[MAX_REF_PIC_NUM]; ++ dma_addr_t mmu_header_paddr[MAX_REF_PIC_NUM]; ++ ++ void *mmu_map_vaddr; ++ dma_addr_t mmu_map_paddr; ++}; ++ + /* Returns 1 if we must use framebuffer compression */ + static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit) + { +@@ -37,13 +50,27 @@ static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit) + return pixfmt == V4L2_PIX_FMT_NV12M && is_10bit; + } + ++/* Returns 1 if we are decoding using the IOMMU */ ++static inline int codec_hevc_use_mmu(u32 revision, u32 pixfmt, int is_10bit) ++{ ++ return revision >= VDEC_REVISION_G12A && ++ codec_hevc_use_fbc(pixfmt, is_10bit); ++} ++ + /** + * Configure decode head read mode + */ + void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit); + +-void codec_hevc_free_fbc_buffers(struct amvdec_session *sess); ++void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm); ++ ++int codec_hevc_setup_buffers(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ int is_10bit); + +-int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit); ++void codec_hevc_fill_mmu_map(struct amvdec_session *sess, ++ struct codec_hevc_common *comm, ++ struct vb2_buffer *vb); + + #endif +\ No newline at end of file +diff --git a/drivers/media/platform/meson/vdec/codec_vp9.c b/drivers/media/platform/meson/vdec/codec_vp9.c +index 39e8eb5937bf0..b1643cc01f684 100644 +--- a/drivers/media/platform/meson/vdec/codec_vp9.c ++++ b/drivers/media/platform/meson/vdec/codec_vp9.c +@@ -219,6 +219,9 @@ struct vp9_frame { + struct codec_vp9 { + struct mutex lock; + ++ /* Common part with the HEVC decoder */ ++ struct codec_hevc_common common; ++ + /* Buffer for the VP9 Workspace */ + void *workspace_vaddr; + dma_addr_t workspace_paddr; +@@ -438,27 +441,26 @@ static u32 codec_vp9_num_pending_bufs(struct amvdec_session *sess) + return vp9->frames_num; + } + +-static int +-codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) ++static int codec_vp9_alloc_workspace(struct amvdec_core *core, ++ struct codec_vp9 *vp9) + { +- dma_addr_t wkaddr; +- + /* Allocate some memory for the VP9 decoder's state */ + vp9->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE, +- &wkaddr, GFP_KERNEL); ++ &vp9->workspace_paddr, GFP_KERNEL); + if (!vp9->workspace_vaddr) { + dev_err(core->dev, "Failed to allocate VP9 Workspace\n"); + return -ENOMEM; + } + +- memset(vp9->workspace_vaddr + DBLK_PARA_OFFSET, 0, DBLK_PARA_SIZE); +- memset(vp9->workspace_vaddr + COUNT_OFFSET, 0, COUNT_SIZE); +- memset(vp9->workspace_vaddr + PROB_OFFSET, 0, PROB_SIZE); +- +- printk("Workspace: %08X-%08X\n", wkaddr, wkaddr + SIZE_WORKSPACE); +- printk("DBLK_PARA: %08X\n", wkaddr + DBLK_PARA_OFFSET); ++ return 0; ++} + +- vp9->workspace_paddr = wkaddr; ++static void codec_vp9_setup_workspace(struct amvdec_session *sess, ++ struct codec_vp9 *vp9) ++{ ++ struct amvdec_core *core = sess->core; ++ u32 revision = core->platform->revision; ++ dma_addr_t wkaddr = vp9->workspace_paddr; + + amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); + amvdec_write_dos(core, VP9_RPM_BUFFER, wkaddr + RPM_OFFSET); +@@ -466,7 +468,6 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) + amvdec_write_dos(core, VP9_PPS_BUFFER, wkaddr + PPS_OFFSET); + amvdec_write_dos(core, VP9_SAO_UP, wkaddr + SAO_UP_OFFSET); + +- /* No MMU */ + amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER, + wkaddr + SWAP_BUF_OFFSET); + amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, +@@ -484,7 +485,19 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) + amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); + amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); + +- return 0; ++ if (codec_hevc_use_mmu(revision, sess->pixfmt_cap, vp9->is_10bit)) { ++ amvdec_write_dos(core, HEVC_SAO_MMU_VH0_ADDR, ++ wkaddr + MMU_VBH_OFFSET); ++ amvdec_write_dos(core, HEVC_SAO_MMU_VH1_ADDR, ++ wkaddr + MMU_VBH_OFFSET + (MMU_VBH_SIZE / 2)); ++ ++ if (revision >= VDEC_REVISION_G12A) ++ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR, ++ vp9->common.mmu_map_paddr); ++ else ++ amvdec_write_dos(core, VP9_MMU_MAP_BUFFER, ++ vp9->common.mmu_map_paddr); ++ } + } + + static int codec_vp9_start(struct amvdec_session *sess) +@@ -499,10 +512,11 @@ static int codec_vp9_start(struct amvdec_session *sess) + if (!vp9) + return -ENOMEM; + +- ret = codec_vp9_setup_workspace(core, vp9); ++ ret = codec_vp9_alloc_workspace(core, vp9); + if (ret) + goto free_vp9; + ++ codec_vp9_setup_workspace(sess, vp9); + amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); + // stream_fifo_hole + if (core->platform->revision == VDEC_REVISION_G12A) +@@ -575,7 +589,7 @@ static int codec_vp9_stop(struct amvdec_session *sess) + vp9->workspace_vaddr, + vp9->workspace_paddr); + +- codec_hevc_free_fbc_buffers(sess); ++ codec_hevc_free_fbc_buffers(sess, &vp9->common); + return 0; + } + +@@ -590,7 +604,7 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + + if (codec_hevc_use_downsample(sess->pixfmt_cap, vp9->is_10bit)) + buf_y_paddr = +- sess->fbc_buffer_paddr[vb->index]; ++ vp9->common.fbc_buffer_paddr[vb->index]; + else + buf_y_paddr = + vb2_dma_contig_plane_dma_addr(vb, 0); +@@ -601,6 +615,7 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr); + } + ++ + if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) { + buf_y_paddr = + vb2_dma_contig_plane_dma_addr(vb, 0); +@@ -612,13 +627,22 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr); + } + ++ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap, ++ vp9->is_10bit)) { ++ amvdec_write_dos(core, HEVC_CM_HEADER_START_ADDR, ++ vp9->common.mmu_header_paddr[vb->index]); ++ /* use HEVC_CM_HEADER_START_ADDR */ ++ amvdec_write_dos_bits(core, HEVC_SAO_CTRL5, BIT(10)); ++ } ++ + amvdec_write_dos(core, HEVC_SAO_Y_LENGTH, + amvdec_get_output_size(sess)); + amvdec_write_dos(core, HEVC_SAO_C_LENGTH, + (amvdec_get_output_size(sess) / 2)); + + if (core->platform->revision >= VDEC_REVISION_G12A) { +- amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, BIT(4) | BIT(5) | BIT(8) | BIT(9)); ++ amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, ++ BIT(4) | BIT(5) | BIT(8) | BIT(9)); + /* enable first, compressed write */ + if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) + amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(8)); +@@ -630,8 +654,6 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + /* dblk pipeline mode=1 for performance */ + if (sess->width >= 1280) + amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(4)); +- +- printk("HEVC_DBLK_CFGB: %08X\n", amvdec_read_dos(core, HEVC_DBLK_CFGB)); + } + + val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; +@@ -644,7 +666,6 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb + } + + amvdec_write_dos(core, HEVC_SAO_CTRL1, val); +- printk("HEVC_SAO_CTRL1: %08X\n", val); + + if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { + /* no downscale for NV12 */ +@@ -919,6 +940,11 @@ static void codec_vp9_process_frame(struct amvdec_session *sess) + codec_vp9_update_next_ref(vp9); + codec_vp9_show_existing_frame(vp9); + ++ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap, ++ vp9->is_10bit)) ++ codec_hevc_fill_mmu_map(sess, &vp9->common, ++ &vp9->cur_frame->vbuf->vb2_buf); ++ + intra_only = param->p.show_frame ? 0 : param->p.intra_only; + /* clear mpred (for keyframe only) */ + if (param->p.frame_type != KEY_FRAME && !intra_only) { +@@ -971,11 +997,12 @@ static void codec_vp9_resume(struct amvdec_session *sess) + { + struct codec_vp9 *vp9 = sess->priv; + +- if (codec_hevc_setup_buffers(sess, vp9->is_10bit)) { ++ if (codec_hevc_setup_buffers(sess, &vp9->common, vp9->is_10bit)) { + amvdec_abort(sess); + return; + } + ++ codec_vp9_setup_workspace(sess, vp9); + codec_hevc_setup_decode_head(sess, vp9->is_10bit); + codec_vp9_process_lf(vp9); + codec_vp9_process_frame(sess); +diff --git a/drivers/media/platform/meson/vdec/hevc_regs.h b/drivers/media/platform/meson/vdec/hevc_regs.h +index dc2c2e085b051..0392f41a1eed5 100644 +--- a/drivers/media/platform/meson/vdec/hevc_regs.h ++++ b/drivers/media/platform/meson/vdec/hevc_regs.h +@@ -6,6 +6,8 @@ + #ifndef __MESON_VDEC_HEVC_REGS_H_ + #define __MESON_VDEC_HEVC_REGS_H_ + ++#define HEVC_ASSIST_MMU_MAP_ADDR 0xc024 ++ + #define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4 + #define HEVC_ASSIST_MBOX1_MASK 0xc1d8 + +@@ -200,8 +202,11 @@ + #define HEVC_SAO_CTRL7 0xd894 + #define HEVC_CM_BODY_START_ADDR 0xd898 + #define HEVC_CM_BODY_LENGTH 0xd89c ++#define HEVC_CM_HEADER_START_ADDR 0xd8a0 + #define HEVC_CM_HEADER_LENGTH 0xd8a4 + #define HEVC_CM_HEADER_OFFSET 0xd8ac ++#define HEVC_SAO_MMU_VH0_ADDR 0xd8e8 ++#define HEVC_SAO_MMU_VH1_ADDR 0xd8ec + + #define HEVC_IQIT_CLK_RST_CTRL 0xdc00 + #define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08 +diff --git a/drivers/media/platform/meson/vdec/vdec.h b/drivers/media/platform/meson/vdec/vdec.h +index 69a5f82ae80f2..4d156159541f1 100644 +--- a/drivers/media/platform/meson/vdec/vdec.h ++++ b/drivers/media/platform/meson/vdec/vdec.h +@@ -19,8 +19,6 @@ + /* 32 buffers in 3-plane YUV420 */ + #define MAX_CANVAS (32 * 3) + +-#define MAX_REF_PIC_NUM 24 +- + struct amvdec_buffer { + struct list_head list; + struct vb2_buffer *vb; +@@ -260,9 +258,6 @@ struct amvdec_session { + u32 dpb_size; + u32 fw_idx_to_vb2_idx[32]; + +- void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; +- dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; +- + enum amvdec_status status; + void *priv; + }; +diff --git a/drivers/media/platform/meson/vdec/vdec_hevc.c b/drivers/media/platform/meson/vdec/vdec_hevc.c +index a706dbf3ae8c4..a26e9a02e0f55 100644 +--- a/drivers/media/platform/meson/vdec/vdec_hevc.c ++++ b/drivers/media/platform/meson/vdec/vdec_hevc.c +@@ -123,9 +123,9 @@ static int vdec_hevc_stop(struct amvdec_session *sess) + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); + ++ clk_disable_unprepare(core->vdec_hevc_clk); + if (core->platform->revision == VDEC_REVISION_G12A) + clk_disable_unprepare(core->vdec_hevcf_clk); +- clk_disable_unprepare(core->vdec_hevc_clk); + + return 0; + } +@@ -136,11 +136,6 @@ static int vdec_hevc_start(struct amvdec_session *sess) + struct amvdec_core *core = sess->core; + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; + +- clk_set_rate(core->vdec_hevc_clk, 666666666); +- ret = clk_prepare_enable(core->vdec_hevc_clk); +- if (ret) +- return ret; +- + if (core->platform->revision == VDEC_REVISION_G12A) { + clk_set_rate(core->vdec_hevcf_clk, 666666666); + ret = clk_prepare_enable(core->vdec_hevcf_clk); +@@ -148,6 +143,11 @@ static int vdec_hevc_start(struct amvdec_session *sess) + return ret; + } + ++ clk_set_rate(core->vdec_hevc_clk, 666666666); ++ ret = clk_prepare_enable(core->vdec_hevc_clk); ++ if (ret) ++ return ret; ++ + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VDEC_HEVC, 0); + udelay(10); +@@ -177,7 +177,7 @@ static int vdec_hevc_start(struct amvdec_session *sess) + if (ret) + goto stop; + +- amvdec_write_dos(core, DOS_SW_RESET3, BIT(12)|BIT(11)); ++ amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11)); + amvdec_write_dos(core, DOS_SW_RESET3, 0); + amvdec_read_dos(core, DOS_SW_RESET3); + + +From 493a663243f42b86374cbd61cdcd9344f1a863b0 Mon Sep 17 00:00:00 2001 +From: Maxime Jourdan +Date: Tue, 5 Feb 2019 14:34:45 +0100 +Subject: [PATCH 222/249] WIP: arm64: dts: meson-g12a: add video decoder node + +Signed-off-by: Maxime Jourdan +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 23 +++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index 29db6ce2ccbb2..f57beffac1486 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -2165,6 +2165,29 @@ + }; + }; + ++ vdec: video-decoder@ff620000 { ++ compatible = "amlogic,g12a-vdec"; ++ reg = <0x0 0xff620000 0x0 0x10000>, ++ <0x0 0xffd0e180 0x0 0xe4>; ++ reg-names = "dos", "esparser"; ++ ++ interrupts = , ++ ; ++ interrupt-names = "vdec", "esparser"; ++ ++ amlogic,ao-sysctrl = <&rti>; ++ amlogic,canvas = <&canvas>; ++ ++ clocks = <&clkc CLKID_PARSER>, ++ <&clkc CLKID_DOS>, ++ <&clkc CLKID_VDEC_1>, ++ <&clkc CLKID_VDEC_HEVC>, ++ <&clkc CLKID_VDEC_HEVCF>; ++ clock-names = "dos_parser", "dos", "vdec_1", "vdec_hevc", "vdec_hevcf"; ++ resets = <&reset RESET_PARSER>; ++ reset-names = "esparser"; ++ }; ++ + vpu: vpu@ff900000 { + compatible = "amlogic,meson-g12a-vpu"; + reg = <0x0 0xff900000 0x0 0x100000>, + +From 8e35d74a7a0b3c6d855627b637ef773f6ccc7299 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 16 May 2019 15:25:03 +0200 +Subject: [PATCH 223/249] WIP: arm64: dts: meson-g12a-x96-max: add Audio nodes + for HDMI and S/PDIF + +--- + .../boot/dts/amlogic/meson-g12a-x96-max.dts | 164 ++++++++++++++++++ + 1 file changed, 164 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 648b7deed22d7..5776db88aa94b 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -17,6 +17,14 @@ + serial0 = &uart_AO; + ethernet0 = ðmac; + }; ++ ++ spdif_dit: audio-codec-1 { ++ #sound-dai-cells = <0>; ++ compatible = "linux,spdif-dit"; ++ status = "okay"; ++ sound-name-prefix = "DIT"; ++ }; ++ + chosen { + stdout-path = "serial0:115200n8"; + }; +@@ -123,6 +131,99 @@ + regulator-always-on; + }; + ++ sound { ++ compatible = "amlogic,axg-sound-card"; ++ model = "G12A-X96-MAX"; ++ audio-aux-devs = <&tdmout_a>, <&tdmout_b>, <&tdmout_c>; ++ audio-routing = "TDMOUT_A IN 0", "FRDDR_A OUT 0", ++ "TDMOUT_A IN 1", "FRDDR_B OUT 0", ++ "TDMOUT_A IN 2", "FRDDR_C OUT 0", ++ "TDM_A Playback", "TDMOUT_A OUT", ++ "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", ++ "SPDIFOUT IN 0", "FRDDR_A OUT 3", ++ "SPDIFOUT IN 1", "FRDDR_B OUT 3", ++ "SPDIFOUT IN 2", "FRDDR_C OUT 3"; ++ ++ assigned-clocks = <&clkc CLKID_HIFI_PLL>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <589824000>, ++ <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 = <&tdmif_a>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec@1 { ++ sound-dai = <&tohdmitx 0>; ++ }; ++ }; ++ ++ dai-link-4 { ++ sound-dai = <&tdmif_b>; ++ dai-format = "i2s"; ++ dai-tdm-slot-tx-mask-0 = <1 1>; ++ mclk-fs = <256>; ++ ++ codec@1 { ++ sound-dai = <&tohdmitx 1>; ++ }; ++ }; ++ ++ dai-link-5 { ++ sound-dai = <&spdifout>; ++ ++ codec@0 { ++ sound-dai = <&spdif_dit>; ++ }; ++ ++ codec@1 { ++ sound-dai = <&tohdmitx 4>; ++ }; ++ }; ++ ++ dai-link-6 { ++ sound-dai = <&spdifout_b>; ++ ++ codec { ++ sound-dai = <&tohdmitx 5>; ++ }; ++ }; ++ ++ dai-link-7 { ++ sound-dai = <&tohdmitx 3>; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + wifi32k: wifi32k { + compatible = "pwm-clock"; + #clock-cells = <0>; +@@ -131,6 +232,10 @@ + }; + }; + ++&arb { ++ status = "okay"; ++}; ++ + &cec_AO { + pinctrl-0 = <&cec_ao_a_h_pins>; + pinctrl-names = "default"; +@@ -145,12 +250,28 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&clkc_audio { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; + }; + }; + ++&frddr_a { ++ status = "okay"; ++}; ++ ++&frddr_b { ++ status = "okay"; ++}; ++ ++&frddr_c { ++ status = "okay"; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmitx_hpd_pins>, <&hdmitx_ddc_pins>; +@@ -282,3 +403,46 @@ + vmmc-supply = <&vcc_3v3>; + vqmmc-supply = <&flash_1v8>; + }; ++ ++&spdifout { ++ pinctrl-0 = <&spdif_out_h_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&spdifout_b { ++ status = "okay"; ++}; ++ ++&tdmif_a { ++ pinctrl-0 = <&tdm_a_fs_pins>, <&tdm_a_sclk_pins>, <&tdm_a_dout0_pins> ; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&tdmif_b { ++ pinctrl-0 = <&mclk0_a_pins>, <&tdm_b_fs_pins>, <&tdm_b_sclk_pins>, ++ <&tdm_b_dout0_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++}; ++ ++&tdmif_c { ++ status = "okay"; ++}; ++ ++&tdmout_a { ++ status = "okay"; ++}; ++ ++&tdmout_b { ++ status = "okay"; ++}; ++ ++&tdmout_c { ++ status = "okay"; ++}; ++ ++&tohdmitx { ++ status = "okay"; ++}; + +From be17028cf3bfa6b3a5ec8c4cf958a5178460b303 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 16 May 2019 17:04:21 +0200 +Subject: [PATCH 224/249] WIP: dts: meson: g12a: Add hwrng node + +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index f57beffac1486..c734324069e4f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -198,6 +198,19 @@ + }; + }; + ++ apb_efuse: bus@30000 { ++ compatible = "simple-bus"; ++ reg = <0x0 0x30000 0x0 0x1000>; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges = <0x0 0x0 0x0 0x30000 0x0 0x1000>; ++ ++ hwrng: rng { ++ compatible = "amlogic,meson-rng"; ++ reg = <0x0 0x218 0x0 0x4>; ++ }; ++ }; ++ + periphs: bus@34400 { + compatible = "simple-bus"; + reg = <0x0 0x34400 0x0 0x400>; + +From 6d1fae305d2b70e389eabaef0a0c71cd11ba4d67 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 16 May 2019 17:34:22 +0200 +Subject: [PATCH 225/249] WIP: drm/meson: fix primary plane disabling + +--- + drivers/gpu/drm/meson/meson_crtc.c | 4 ---- + drivers/gpu/drm/meson/meson_plane.c | 4 +++- + 2 files changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c +index 5579f8ac3e3f7..58f7abdc2299f 100644 +--- a/drivers/gpu/drm/meson/meson_crtc.c ++++ b/drivers/gpu/drm/meson/meson_crtc.c +@@ -119,8 +119,6 @@ static void meson_g12a_crtc_atomic_enable(struct drm_crtc *crtc, + priv->io_base + _REG(VPP_OUT_H_V_SIZE)); + + drm_crtc_vblank_on(crtc); +- +- priv->viu.osd1_enabled = true; + } + + static void meson_crtc_atomic_enable(struct drm_crtc *crtc, +@@ -149,8 +147,6 @@ static void meson_crtc_atomic_enable(struct drm_crtc *crtc, + priv->io_base + _REG(VPP_MISC)); + + drm_crtc_vblank_on(crtc); +- +- priv->viu.osd1_enabled = true; + } + + static void meson_g12a_crtc_atomic_disable(struct drm_crtc *crtc, +diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c +index 2f7f4dfce45be..9c3e522d31840 100644 +--- a/drivers/gpu/drm/meson/meson_plane.c ++++ b/drivers/gpu/drm/meson/meson_plane.c +@@ -331,6 +331,8 @@ static void meson_plane_atomic_update(struct drm_plane *plane, + meson_plane->enabled = true; + } + ++ priv->viu.osd1_enabled = true; ++ + spin_unlock_irqrestore(&priv->drm->event_lock, flags); + } + +@@ -349,7 +351,7 @@ static void meson_plane_atomic_disable(struct drm_plane *plane, + priv->io_base + _REG(VPP_MISC)); + + meson_plane->enabled = false; +- ++ priv->viu.osd1_enabled = false; + } + + static const struct drm_plane_helper_funcs meson_plane_helper_funcs = { + +From d6aa8bfca2a4fc3c36b1343aa53f4fb7a5377a83 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Fri, 17 May 2019 11:38:01 +0200 +Subject: [PATCH 226/249] HACK: arm64: dts: : g12a: set cma pool to 896MB + +--- + arch/arm64/boot/dts/amlogic/meson-g12a.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +index c734324069e4f..bd85b604c78e7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a.dtsi +@@ -122,7 +122,7 @@ + linux,cma { + compatible = "shared-dma-pool"; + reusable; +- size = <0x0 0x10000000>; ++ size = <0x0 0x38000000>; + alignment = <0x0 0x400000>; + linux,cma-default; + }; + +From 6bd2d756676ab2103be444ecbc459a7ba120f13b Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Mon, 13 Nov 2017 12:09:40 +0100 +Subject: [PATCH 227/249] ARM64: defconfig: enable CEC support + +Turn on CONFIG_CEC_SUPPORT and CONFIG_CEC_PLATFORM_DRIVERS +Turn on CONFIG_VIDEO_MESON_AO_CEC as module +Turn on CONFIG_DRM_DW_HDMI_CEC as module + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + arch/arm64/configs/defconfig | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig +index 2d9c39033c1aa..552868cb15ae5 100644 +--- a/arch/arm64/configs/defconfig ++++ b/arch/arm64/configs/defconfig +@@ -469,6 +469,7 @@ CONFIG_MEDIA_SUPPORT=m + CONFIG_MEDIA_CAMERA_SUPPORT=y + CONFIG_MEDIA_ANALOG_TV_SUPPORT=y + CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y ++CONFIG_MEDIA_CEC_SUPPORT=y + CONFIG_MEDIA_CONTROLLER=y + CONFIG_VIDEO_V4L2_SUBDEV_API=y + # CONFIG_DVB_NET is not set +@@ -482,6 +483,8 @@ CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m + CONFIG_VIDEO_SUN6I_CSI=m + CONFIG_VIDEO_RENESAS_FCP=m + CONFIG_VIDEO_RENESAS_VSP1=m ++CONFIG_CEC_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_MESON_AO_CEC=m + CONFIG_DRM=m + CONFIG_DRM_NOUVEAU=m + CONFIG_DRM_EXYNOS=m +@@ -506,6 +509,7 @@ CONFIG_DRM_TEGRA=m + CONFIG_DRM_PANEL_SIMPLE=m + CONFIG_DRM_SII902X=m + CONFIG_DRM_I2C_ADV7511=m ++CONFIG_DRM_DW_HDMI_CEC=m + CONFIG_DRM_VC4=m + CONFIG_DRM_HISI_HIBMC=m + CONFIG_DRM_HISI_KIRIN=m + +From 55b9d37fe09e6608a53083a87b8c77dc678ee53c Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 11:49:55 +0200 +Subject: [PATCH 228/249] ASoC: meson: add meson audio core driver + +This patch adds support for the audio core driver for the Amlogic Meson SoC +family. The purpose of this driver is to properly reset the audio block and +provide register access for the different devices scattered in this address +space. This includes output and input DMAs, pcm, i2s and spdif dai, card +level routing, internal codec for the gxl variant + +For more information, please refer to the section 5 of the public datasheet +of the S905 (gxbb). This datasheet is available here: [0]. + +[0]: http://dn.odroid.com/S905/DataSheet/S905_Public_Datasheet_V1.1.4.pdf + +Signed-off-by: Jerome Brunet +--- + sound/soc/Kconfig | 1 + + sound/soc/Makefile | 1 + + sound/soc/meson-gx/Kconfig | 11 ++ + sound/soc/meson-gx/Makefile | 3 + + sound/soc/meson-gx/audio-core.c | 180 ++++++++++++++++++++++++++++++++ + sound/soc/meson-gx/audio-core.h | 28 +++++ + 6 files changed, 224 insertions(+) + create mode 100644 sound/soc/meson-gx/Kconfig + create mode 100644 sound/soc/meson-gx/Makefile + create mode 100644 sound/soc/meson-gx/audio-core.c + create mode 100644 sound/soc/meson-gx/audio-core.h + +diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig +index aa35940f5c50b..06040d2db0ae6 100644 +--- a/sound/soc/Kconfig ++++ b/sound/soc/Kconfig +@@ -56,6 +56,7 @@ source "sound/soc/img/Kconfig" + source "sound/soc/intel/Kconfig" + source "sound/soc/mediatek/Kconfig" + source "sound/soc/meson/Kconfig" ++source "sound/soc/meson-gx/Kconfig" + source "sound/soc/mxs/Kconfig" + source "sound/soc/pxa/Kconfig" + source "sound/soc/qcom/Kconfig" +diff --git a/sound/soc/Makefile b/sound/soc/Makefile +index 974fb9821e172..9cd12249b0e87 100644 +--- a/sound/soc/Makefile ++++ b/sound/soc/Makefile +@@ -38,6 +38,7 @@ obj-$(CONFIG_SND_SOC) += img/ + obj-$(CONFIG_SND_SOC) += intel/ + obj-$(CONFIG_SND_SOC) += mediatek/ + obj-$(CONFIG_SND_SOC) += meson/ ++obj-$(CONFIG_SND_SOC) += meson-gx/ + obj-$(CONFIG_SND_SOC) += mxs/ + obj-$(CONFIG_SND_SOC) += nuc900/ + obj-$(CONFIG_SND_SOC) += kirkwood/ +diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig +new file mode 100644 +index 0000000000000..280e49e7c16fe +--- /dev/null ++++ b/sound/soc/meson-gx/Kconfig +@@ -0,0 +1,11 @@ ++menuconfig SND_SOC_MESON_GX ++ tristate "ASoC WIP support for Amlogic GX SoCs" ++ depends on ARCH_MESON ++ select MFD_CORE ++ select REGMAP_MMIO ++ help ++ Say Y or M if you want to add support for codecs attached to ++ the Amlogic Meson SoCs Audio interfaces. You will also need to ++ select the audio interfaces to support below. This WIP drivers ++ are kept separated from the actual upstream amlogic ASoC driver ++ to minimize conflicts until support is submitted and merged +diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile +new file mode 100644 +index 0000000000000..6f124c31a85cc +--- /dev/null ++++ b/sound/soc/meson-gx/Makefile +@@ -0,0 +1,3 @@ ++snd-soc-meson-audio-core-objs := audio-core.o ++ ++obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o +diff --git a/sound/soc/meson-gx/audio-core.c b/sound/soc/meson-gx/audio-core.c +new file mode 100644 +index 0000000000000..68f7e0e58f5f2 +--- /dev/null ++++ b/sound/soc/meson-gx/audio-core.c +@@ -0,0 +1,180 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "audio-core.h" ++ ++#define DRV_NAME "meson-gx-audio-core" ++ ++static const char * const acore_clock_names[] = { "aiu_top", ++ "aiu_glue", ++ "audin" }; ++ ++static int meson_acore_init_clocks(struct device *dev) ++{ ++ struct clk *clock; ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(acore_clock_names); i++) { ++ clock = devm_clk_get(dev, acore_clock_names[i]); ++ if (IS_ERR(clock)) { ++ if (PTR_ERR(clock) != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get %s clock\n", ++ acore_clock_names[i]); ++ return PTR_ERR(clock); ++ } ++ ++ ret = clk_prepare_enable(clock); ++ if (ret) { ++ dev_err(dev, "Failed to enable %s clock\n", ++ acore_clock_names[i]); ++ return ret; ++ } ++ ++ ret = devm_add_action_or_reset(dev, ++ (void(*)(void *))clk_disable_unprepare, ++ clock); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static const char * const acore_reset_names[] = { "aiu", ++ "audin" }; ++ ++static int meson_acore_init_resets(struct device *dev) ++{ ++ struct reset_control *reset; ++ int i, ret; ++ ++ for (i = 0; i < ARRAY_SIZE(acore_reset_names); i++) { ++ reset = devm_reset_control_get_exclusive(dev, ++ acore_reset_names[i]); ++ if (IS_ERR(reset)) { ++ if (PTR_ERR(reset) != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get %s reset\n", ++ acore_reset_names[i]); ++ return PTR_ERR(reset); ++ } ++ ++ ret = reset_control_reset(reset); ++ if (ret) { ++ dev_err(dev, "Failed to pulse %s reset\n", ++ acore_reset_names[i]); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct regmap_config meson_acore_regmap_config = { ++ .reg_bits = 32, ++ .val_bits = 32, ++ .reg_stride = 4, ++}; ++ ++static const struct mfd_cell meson_acore_devs[] = { ++ { ++ .name = "meson-aiu-i2s", ++ .of_compatible = "amlogic,meson-aiu-i2s", ++ }, ++ { ++ .name = "meson-aiu-spdif", ++ .of_compatible = "amlogic,meson-aiu-spdif", ++ }, ++}; ++ ++static int meson_acore_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct meson_audio_core_data *data; ++ struct resource *res; ++ void __iomem *regs; ++ int ret; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, data); ++ ++ ret = meson_acore_init_clocks(dev); ++ if (ret) ++ return ret; ++ ++ ret = meson_acore_init_resets(dev); ++ if (ret) ++ return ret; ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aiu"); ++ regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ data->aiu = devm_regmap_init_mmio(dev, regs, ++ &meson_acore_regmap_config); ++ if (IS_ERR(data->aiu)) { ++ dev_err(dev, "Couldn't create the AIU regmap\n"); ++ return PTR_ERR(data->aiu); ++ } ++ ++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "audin"); ++ regs = devm_ioremap_resource(dev, res); ++ if (IS_ERR(regs)) ++ return PTR_ERR(regs); ++ ++ data->audin = devm_regmap_init_mmio(dev, regs, ++ &meson_acore_regmap_config); ++ if (IS_ERR(data->audin)) { ++ dev_err(dev, "Couldn't create the AUDIN regmap\n"); ++ return PTR_ERR(data->audin); ++ } ++ ++ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, meson_acore_devs, ++ ARRAY_SIZE(meson_acore_devs), NULL, 0, ++ NULL); ++} ++ ++static const struct of_device_id meson_acore_of_match[] = { ++ { .compatible = "amlogic,meson-gx-audio-core", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, meson_acore_of_match); ++ ++static struct platform_driver meson_acore_pdrv = { ++ .probe = meson_acore_probe, ++ .driver = { ++ .name = DRV_NAME, ++ .of_match_table = meson_acore_of_match, ++ }, ++}; ++module_platform_driver(meson_acore_pdrv); ++ ++MODULE_DESCRIPTION("Meson Audio Core Driver"); ++MODULE_AUTHOR("Jerome Brunet "); ++MODULE_LICENSE("GPL v2"); +diff --git a/sound/soc/meson-gx/audio-core.h b/sound/soc/meson-gx/audio-core.h +new file mode 100644 +index 0000000000000..6e7a24cdc4a96 +--- /dev/null ++++ b/sound/soc/meson-gx/audio-core.h +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#ifndef _MESON_AUDIO_CORE_H_ ++#define _MESON_AUDIO_CORE_H_ ++ ++struct meson_audio_core_data { ++ struct regmap *aiu; ++ struct regmap *audin; ++}; ++ ++#endif /* _MESON_AUDIO_CORE_H_ */ + +From 057449a391589c802de24317d461e0a8ac61c7d1 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 12:00:10 +0200 +Subject: [PATCH 229/249] ASoC: meson: add register definitions + +Add the register definition for the AIU and AUDIN blocks + +Signed-off-by: Jerome Brunet +--- + sound/soc/meson-gx/aiu-regs.h | 182 ++++++++++++++++++++++++++++++++ + sound/soc/meson-gx/audin-regs.h | 148 ++++++++++++++++++++++++++ + 2 files changed, 330 insertions(+) + create mode 100644 sound/soc/meson-gx/aiu-regs.h + create mode 100644 sound/soc/meson-gx/audin-regs.h + +diff --git a/sound/soc/meson-gx/aiu-regs.h b/sound/soc/meson-gx/aiu-regs.h +new file mode 100644 +index 0000000000000..67391e64fe1c2 +--- /dev/null ++++ b/sound/soc/meson-gx/aiu-regs.h +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#ifndef _AIU_REGS_H_ ++#define _AIU_REGS_H_ ++ ++#define AIU_958_BPF 0x000 ++#define AIU_958_BRST 0x004 ++#define AIU_958_LENGTH 0x008 ++#define AIU_958_PADDSIZE 0x00C ++#define AIU_958_MISC 0x010 ++#define AIU_958_FORCE_LEFT 0x014 /* Unknown */ ++#define AIU_958_DISCARD_NUM 0x018 ++#define AIU_958_DCU_FF_CTRL 0x01C ++#define AIU_958_CHSTAT_L0 0x020 ++#define AIU_958_CHSTAT_L1 0x024 ++#define AIU_958_CTRL 0x028 ++#define AIU_958_RPT 0x02C ++#define AIU_I2S_MUTE_SWAP 0x030 ++#define AIU_I2S_SOURCE_DESC 0x034 ++#define AIU_I2S_MED_CTRL 0x038 ++#define AIU_I2S_MED_THRESH 0x03C ++#define AIU_I2S_DAC_CFG 0x040 ++#define AIU_I2S_SYNC 0x044 /* Unknown */ ++#define AIU_I2S_MISC 0x048 ++#define AIU_I2S_OUT_CFG 0x04C ++#define AIU_I2S_FF_CTRL 0x050 /* Unknown */ ++#define AIU_RST_SOFT 0x054 ++#define AIU_CLK_CTRL 0x058 ++#define AIU_MIX_ADCCFG 0x05C ++#define AIU_MIX_CTRL 0x060 ++#define AIU_CLK_CTRL_MORE 0x064 ++#define AIU_958_POP 0x068 ++#define AIU_MIX_GAIN 0x06C ++#define AIU_958_SYNWORD1 0x070 ++#define AIU_958_SYNWORD2 0x074 ++#define AIU_958_SYNWORD3 0x078 ++#define AIU_958_SYNWORD1_MASK 0x07C ++#define AIU_958_SYNWORD2_MASK 0x080 ++#define AIU_958_SYNWORD3_MASK 0x084 ++#define AIU_958_FFRDOUT_THD 0x088 ++#define AIU_958_LENGTH_PER_PAUSE 0x08C ++#define AIU_958_PAUSE_NUM 0x090 ++#define AIU_958_PAUSE_PAYLOAD 0x094 ++#define AIU_958_AUTO_PAUSE 0x098 ++#define AIU_958_PAUSE_PD_LENGTH 0x09C ++#define AIU_CODEC_DAC_LRCLK_CTRL 0x0A0 ++#define AIU_CODEC_ADC_LRCLK_CTRL 0x0A4 ++#define AIU_HDMI_CLK_DATA_CTRL 0x0A8 ++#define AIU_CODEC_CLK_DATA_CTRL 0x0AC ++#define AIU_ACODEC_CTRL 0x0B0 ++#define AIU_958_CHSTAT_R0 0x0C0 ++#define AIU_958_CHSTAT_R1 0x0C4 ++#define AIU_958_VALID_CTRL 0x0C8 ++#define AIU_AUDIO_AMP_REG0 0x0F0 /* Unknown */ ++#define AIU_AUDIO_AMP_REG1 0x0F4 /* Unknown */ ++#define AIU_AUDIO_AMP_REG2 0x0F8 /* Unknown */ ++#define AIU_AUDIO_AMP_REG3 0x0FC /* Unknown */ ++#define AIU_AIFIFO2_CTRL 0x100 ++#define AIU_AIFIFO2_STATUS 0x104 ++#define AIU_AIFIFO2_GBIT 0x108 ++#define AIU_AIFIFO2_CLB 0x10C ++#define AIU_CRC_CTRL 0x110 ++#define AIU_CRC_STATUS 0x114 ++#define AIU_CRC_SHIFT_REG 0x118 ++#define AIU_CRC_IREG 0x11C ++#define AIU_CRC_CAL_REG1 0x120 ++#define AIU_CRC_CAL_REG0 0x124 ++#define AIU_CRC_POLY_COEF1 0x128 ++#define AIU_CRC_POLY_COEF0 0x12C ++#define AIU_CRC_BIT_SIZE1 0x130 ++#define AIU_CRC_BIT_SIZE0 0x134 ++#define AIU_CRC_BIT_CNT1 0x138 ++#define AIU_CRC_BIT_CNT0 0x13C ++#define AIU_AMCLK_GATE_HI 0x140 ++#define AIU_AMCLK_GATE_LO 0x144 ++#define AIU_AMCLK_MSR 0x148 ++#define AIU_AUDAC_CTRL0 0x14C /* Unknown */ ++#define AIU_DELTA_SIGMA0 0x154 /* Unknown */ ++#define AIU_DELTA_SIGMA1 0x158 /* Unknown */ ++#define AIU_DELTA_SIGMA2 0x15C /* Unknown */ ++#define AIU_DELTA_SIGMA3 0x160 /* Unknown */ ++#define AIU_DELTA_SIGMA4 0x164 /* Unknown */ ++#define AIU_DELTA_SIGMA5 0x168 /* Unknown */ ++#define AIU_DELTA_SIGMA6 0x16C /* Unknown */ ++#define AIU_DELTA_SIGMA7 0x170 /* Unknown */ ++#define AIU_DELTA_SIGMA_LCNTS 0x174 /* Unknown */ ++#define AIU_DELTA_SIGMA_RCNTS 0x178 /* Unknown */ ++#define AIU_MEM_I2S_START_PTR 0x180 ++#define AIU_MEM_I2S_RD_PTR 0x184 ++#define AIU_MEM_I2S_END_PTR 0x188 ++#define AIU_MEM_I2S_MASKS 0x18C ++#define AIU_MEM_I2S_CONTROL 0x190 ++#define AIU_MEM_IEC958_START_PTR 0x194 ++#define AIU_MEM_IEC958_RD_PTR 0x198 ++#define AIU_MEM_IEC958_END_PTR 0x19C ++#define AIU_MEM_IEC958_MASKS 0x1A0 ++#define AIU_MEM_IEC958_CONTROL 0x1A4 ++#define AIU_MEM_AIFIFO2_START_PTR 0x1A8 ++#define AIU_MEM_AIFIFO2_CURR_PTR 0x1AC ++#define AIU_MEM_AIFIFO2_END_PTR 0x1B0 ++#define AIU_MEM_AIFIFO2_BYTES_AVAIL 0x1B4 ++#define AIU_MEM_AIFIFO2_CONTROL 0x1B8 ++#define AIU_MEM_AIFIFO2_MAN_WP 0x1BC ++#define AIU_MEM_AIFIFO2_MAN_RP 0x1C0 ++#define AIU_MEM_AIFIFO2_LEVEL 0x1C4 ++#define AIU_MEM_AIFIFO2_BUF_CNTL 0x1C8 ++#define AIU_MEM_I2S_MAN_WP 0x1CC ++#define AIU_MEM_I2S_MAN_RP 0x1D0 ++#define AIU_MEM_I2S_LEVEL 0x1D4 ++#define AIU_MEM_I2S_BUF_CNTL 0x1D8 ++#define AIU_MEM_I2S_BUF_WRAP_COUNT 0x1DC ++#define AIU_MEM_I2S_MEM_CTL 0x1E0 ++#define AIU_MEM_IEC958_MEM_CTL 0x1E4 ++#define AIU_MEM_IEC958_WRAP_COUNT 0x1E8 ++#define AIU_MEM_IEC958_IRQ_LEVEL 0x1EC ++#define AIU_MEM_IEC958_MAN_WP 0x1F0 ++#define AIU_MEM_IEC958_MAN_RP 0x1F4 ++#define AIU_MEM_IEC958_LEVEL 0x1F8 ++#define AIU_MEM_IEC958_BUF_CNTL 0x1FC ++#define AIU_AIFIFO_CTRL 0x200 ++#define AIU_AIFIFO_STATUS 0x204 ++#define AIU_AIFIFO_GBIT 0x208 ++#define AIU_AIFIFO_CLB 0x20C ++#define AIU_MEM_AIFIFO_START_PTR 0x210 ++#define AIU_MEM_AIFIFO_CURR_PTR 0x214 ++#define AIU_MEM_AIFIFO_END_PTR 0x218 ++#define AIU_MEM_AIFIFO_BYTES_AVAIL 0x21C ++#define AIU_MEM_AIFIFO_CONTROL 0x220 ++#define AIU_MEM_AIFIFO_MAN_WP 0x224 ++#define AIU_MEM_AIFIFO_MAN_RP 0x228 ++#define AIU_MEM_AIFIFO_LEVEL 0x22C ++#define AIU_MEM_AIFIFO_BUF_CNTL 0x230 ++#define AIU_MEM_AIFIFO_BUF_WRAP_COUNT 0x234 ++#define AIU_MEM_AIFIFO2_BUF_WRAP_COUNT 0x238 ++#define AIU_MEM_AIFIFO_MEM_CTL 0x23C ++#define AIFIFO_TIME_STAMP_CNTL 0x240 ++#define AIFIFO_TIME_STAMP_SYNC_0 0x244 ++#define AIFIFO_TIME_STAMP_SYNC_1 0x248 ++#define AIFIFO_TIME_STAMP_0 0x24C ++#define AIFIFO_TIME_STAMP_1 0x250 ++#define AIFIFO_TIME_STAMP_2 0x254 ++#define AIFIFO_TIME_STAMP_3 0x258 ++#define AIFIFO_TIME_STAMP_LENGTH 0x25C ++#define AIFIFO2_TIME_STAMP_CNTL 0x260 ++#define AIFIFO2_TIME_STAMP_SYNC_0 0x264 ++#define AIFIFO2_TIME_STAMP_SYNC_1 0x268 ++#define AIFIFO2_TIME_STAMP_0 0x26C ++#define AIFIFO2_TIME_STAMP_1 0x270 ++#define AIFIFO2_TIME_STAMP_2 0x274 ++#define AIFIFO2_TIME_STAMP_3 0x278 ++#define AIFIFO2_TIME_STAMP_LENGTH 0x27C ++#define IEC958_TIME_STAMP_CNTL 0x280 ++#define IEC958_TIME_STAMP_SYNC_0 0x284 ++#define IEC958_TIME_STAMP_SYNC_1 0x288 ++#define IEC958_TIME_STAMP_0 0x28C ++#define IEC958_TIME_STAMP_1 0x290 ++#define IEC958_TIME_STAMP_2 0x294 ++#define IEC958_TIME_STAMP_3 0x298 ++#define IEC958_TIME_STAMP_LENGTH 0x29C ++#define AIU_MEM_AIFIFO2_MEM_CTL 0x2A0 ++#define AIU_I2S_CBUS_DDR_CNTL 0x2A4 ++#define AIU_I2S_CBUS_DDR_WDATA 0x2A8 ++#define AIU_I2S_CBUS_DDR_ADDR 0x2AC ++ ++#endif /* _AIU_REGS_H_ */ +diff --git a/sound/soc/meson-gx/audin-regs.h b/sound/soc/meson-gx/audin-regs.h +new file mode 100644 +index 0000000000000..f224610e80e73 +--- /dev/null ++++ b/sound/soc/meson-gx/audin-regs.h +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#ifndef _AUDIN_REGS_H_ ++#define _AUDIN_REGS_H_ ++ ++/* ++ * Note : ++ * Datasheet issue page 196 ++ * AUDIN_MUTE_VAL 0x35 => impossible: Already assigned to AUDIN_FIFO1_PTR ++ * AUDIN_FIFO1_PTR is more likely to be correct here since surrounding registers ++ * also deal with AUDIN_FIFO1 ++ * ++ * Clarification needed from Amlogic ++ */ ++ ++#define AUDIN_SPDIF_MODE 0x000 ++#define AUDIN_SPDIF_FS_CLK_RLTN 0x004 ++#define AUDIN_SPDIF_CHNL_STS_A 0x008 ++#define AUDIN_SPDIF_CHNL_STS_B 0x00C ++#define AUDIN_SPDIF_MISC 0x010 ++#define AUDIN_SPDIF_NPCM_PCPD 0x014 ++#define AUDIN_SPDIF_END 0x03C /* Unknown */ ++#define AUDIN_I2SIN_CTRL 0x040 ++#define AUDIN_SOURCE_SEL 0x044 ++#define AUDIN_DECODE_FORMAT 0x048 ++#define AUDIN_DECODE_CONTROL_STATUS 0x04C ++#define AUDIN_DECODE_CHANNEL_STATUS_A_0 0x050 ++#define AUDIN_DECODE_CHANNEL_STATUS_A_1 0x054 ++#define AUDIN_DECODE_CHANNEL_STATUS_A_2 0x058 ++#define AUDIN_DECODE_CHANNEL_STATUS_A_3 0x05C ++#define AUDIN_DECODE_CHANNEL_STATUS_A_4 0x060 ++#define AUDIN_DECODE_CHANNEL_STATUS_A_5 0x064 ++#define AUDIN_FIFO0_START 0x080 ++#define AUDIN_FIFO0_END 0x084 ++#define AUDIN_FIFO0_PTR 0x088 ++#define AUDIN_FIFO0_INTR 0x08C ++#define AUDIN_FIFO0_RDPTR 0x090 ++#define AUDIN_FIFO0_CTRL 0x094 ++#define AUDIN_FIFO0_CTRL1 0x098 ++#define AUDIN_FIFO0_LVL0 0x09C ++#define AUDIN_FIFO0_LVL1 0x0A0 ++#define AUDIN_FIFO0_LVL2 0x0A4 ++#define AUDIN_FIFO0_REQID 0x0C0 ++#define AUDIN_FIFO0_WRAP 0x0C4 ++#define AUDIN_FIFO1_START 0x0CC ++#define AUDIN_FIFO1_END 0x0D0 ++#define AUDIN_FIFO1_PTR 0x0D4 ++#define AUDIN_FIFO1_INTR 0x0D8 ++#define AUDIN_FIFO1_RDPTR 0x0DC ++#define AUDIN_FIFO1_CTRL 0x0E0 ++#define AUDIN_FIFO1_CTRL1 0x0E4 ++#define AUDIN_FIFO1_LVL0 0x100 ++#define AUDIN_FIFO1_LVL1 0x104 ++#define AUDIN_FIFO1_LVL2 0x108 ++#define AUDIN_FIFO1_REQID 0x10C ++#define AUDIN_FIFO1_WRAP 0x110 ++#define AUDIN_FIFO2_START 0x114 ++#define AUDIN_FIFO2_END 0x118 ++#define AUDIN_FIFO2_PTR 0x11C ++#define AUDIN_FIFO2_INTR 0x120 ++#define AUDIN_FIFO2_RDPTR 0x124 ++#define AUDIN_FIFO2_CTRL 0x128 ++#define AUDIN_FIFO2_CTRL1 0x12C ++#define AUDIN_FIFO2_LVL0 0x130 ++#define AUDIN_FIFO2_LVL1 0x134 ++#define AUDIN_FIFO2_LVL2 0x138 ++#define AUDIN_FIFO2_REQID 0x13C ++#define AUDIN_FIFO2_WRAP 0x140 ++#define AUDIN_INT_CTRL 0x144 ++#define AUDIN_FIFO_INT 0x148 ++#define PCMIN_CTRL0 0x180 ++#define PCMIN_CTRL1 0x184 ++#define PCMIN1_CTRL0 0x188 ++#define PCMIN1_CTRL1 0x18C ++#define PCMOUT_CTRL0 0x1C0 ++#define PCMOUT_CTRL1 0x1C4 ++#define PCMOUT_CTRL2 0x1C8 ++#define PCMOUT_CTRL3 0x1CC ++#define PCMOUT1_CTRL0 0x1D0 ++#define PCMOUT1_CTRL1 0x1D4 ++#define PCMOUT1_CTRL2 0x1D8 ++#define PCMOUT1_CTRL3 0x1DC ++#define AUDOUT_CTRL 0x200 ++#define AUDOUT_CTRL1 0x204 ++#define AUDOUT_BUF0_STA 0x208 ++#define AUDOUT_BUF0_EDA 0x20C ++#define AUDOUT_BUF0_WPTR 0x210 ++#define AUDOUT_BUF1_STA 0x214 ++#define AUDOUT_BUF1_EDA 0x218 ++#define AUDOUT_BUF1_WPTR 0x21C ++#define AUDOUT_FIFO_RPTR 0x220 ++#define AUDOUT_INTR_PTR 0x224 ++#define AUDOUT_FIFO_STS 0x228 ++#define AUDOUT1_CTRL 0x240 ++#define AUDOUT1_CTRL1 0x244 ++#define AUDOUT1_BUF0_STA 0x248 ++#define AUDOUT1_BUF0_EDA 0x24C ++#define AUDOUT1_BUF0_WPTR 0x250 ++#define AUDOUT1_BUF1_STA 0x254 ++#define AUDOUT1_BUF1_EDA 0x258 ++#define AUDOUT1_BUF1_WPTR 0x25C ++#define AUDOUT1_FIFO_RPTR 0x260 ++#define AUDOUT1_INTR_PTR 0x264 ++#define AUDOUT1_FIFO_STS 0x268 ++#define AUDIN_HDMI_MEAS_CTRL 0x280 ++#define AUDIN_HDMI_MEAS_CYCLES_M1 0x284 ++#define AUDIN_HDMI_MEAS_INTR_MASKN 0x288 ++#define AUDIN_HDMI_MEAS_INTR_STAT 0x28C ++#define AUDIN_HDMI_REF_CYCLES_STAT_0 0x290 ++#define AUDIN_HDMI_REF_CYCLES_STAT_1 0x294 ++#define AUDIN_HDMIRX_AFIFO_STAT 0x298 ++#define AUDIN_FIFO0_PIO_STS 0x2C0 ++#define AUDIN_FIFO0_PIO_RDL 0x2C4 ++#define AUDIN_FIFO0_PIO_RDH 0x2C8 ++#define AUDIN_FIFO1_PIO_STS 0x2CC ++#define AUDIN_FIFO1_PIO_RDL 0x2D0 ++#define AUDIN_FIFO1_PIO_RDH 0x2D4 ++#define AUDIN_FIFO2_PIO_STS 0x2D8 ++#define AUDIN_FIFO2_PIO_RDL 0x2DC ++#define AUDIN_FIFO2_PIO_RDH 0x2E0 ++#define AUDOUT_FIFO_PIO_STS 0x2E4 ++#define AUDOUT_FIFO_PIO_WRL 0x2E8 ++#define AUDOUT_FIFO_PIO_WRH 0x2EC ++#define AUDOUT1_FIFO_PIO_STS 0x2F0 /* Unknown */ ++#define AUDOUT1_FIFO_PIO_WRL 0x2F4 /* Unknown */ ++#define AUDOUT1_FIFO_PIO_WRH 0x2F8 /* Unknown */ ++#define AUD_RESAMPLE_CTRL0 0x2FC ++#define AUD_RESAMPLE_CTRL1 0x300 ++#define AUD_RESAMPLE_STATUS 0x304 ++ ++#endif /* _AUDIN_REGS_H_ */ + +From 55cee0743a8e0257f1afde8b79734fdaeea1b81a Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 12:17:27 +0200 +Subject: [PATCH 230/249] ASoC: meson: add initial aiu i2s support + +Add support for the aiu i2s found on Amlogic Meson SoC family. +With this initial implementation, only playback is supported. +Capture will be part of furture work. + +Signed-off-by: Jerome Brunet +--- + sound/soc/meson-gx/Kconfig | 8 + + sound/soc/meson-gx/Makefile | 3 + + sound/soc/meson-gx/aiu-i2s.c | 749 +++++++++++++++++++++++++++++++++++ + 3 files changed, 760 insertions(+) + create mode 100644 sound/soc/meson-gx/aiu-i2s.c + +diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig +index 280e49e7c16fe..8ec683cdf3276 100644 +--- a/sound/soc/meson-gx/Kconfig ++++ b/sound/soc/meson-gx/Kconfig +@@ -9,3 +9,11 @@ menuconfig SND_SOC_MESON_GX + select the audio interfaces to support below. This WIP drivers + are kept separated from the actual upstream amlogic ASoC driver + to minimize conflicts until support is submitted and merged ++ ++config SND_SOC_MESON_GX_I2S ++ tristate "Meson i2s interface" ++ depends on SND_SOC_MESON_GX ++ help ++ Say Y or M if you want to add support for i2s driver for Amlogic ++ Meson SoCs. ++ +diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile +index 6f124c31a85cc..02f9c4df6348d 100644 +--- a/sound/soc/meson-gx/Makefile ++++ b/sound/soc/meson-gx/Makefile +@@ -1,3 +1,6 @@ + snd-soc-meson-audio-core-objs := audio-core.o ++snd-soc-meson-aiu-i2s-objs := aiu-i2s.o + + obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o ++obj-$(CONFIG_SND_SOC_MESON_GX_I2S) += snd-soc-meson-aiu-i2s.o ++ +diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c +new file mode 100644 +index 0000000000000..63d7821c2c72d +--- /dev/null ++++ b/sound/soc/meson-gx/aiu-i2s.c +@@ -0,0 +1,749 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "aiu-regs.h" ++#include "audio-core.h" ++ ++#define DRV_NAME "meson-aiu-i2s" ++ ++struct meson_aiu_i2s { ++ struct meson_audio_core_data *core; ++ struct clk *mclk; ++ struct clk *bclks; ++ struct clk *iface; ++ struct clk *fast; ++ bool bclks_idle; ++ int irq; ++}; ++ ++#define AIU_MEM_I2S_BUF_CNTL_INIT BIT(0) ++#define AIU_MEM_I2S_CONTROL_INIT BIT(0) ++#define AIU_MEM_I2S_CONTROL_FILL_EN BIT(1) ++#define AIU_MEM_I2S_CONTROL_EMPTY_EN BIT(2) ++#define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6) ++#define AIU_MEM_I2S_CONTROL_BUSY BIT(7) ++#define AIU_MEM_I2S_CONTROL_DATA_READY BIT(8) ++#define AIU_MEM_I2S_CONTROL_LEVEL_CNTL BIT(9) ++#define AIU_MEM_I2S_MASKS_IRQ_BLOCK_MASK GENMASK(31, 16) ++#define AIU_MEM_I2S_MASKS_IRQ_BLOCK(n) ((n) << 16) ++#define AIU_MEM_I2S_MASKS_CH_MEM_MASK GENMASK(15, 8) ++#define AIU_MEM_I2S_MASKS_CH_MEM(ch) ((ch) << 8) ++#define AIU_MEM_I2S_MASKS_CH_RD_MASK GENMASK(7, 0) ++#define AIU_MEM_I2S_MASKS_CH_RD(ch) ((ch) << 0) ++#define AIU_RST_SOFT_I2S_FAST_DOMAIN BIT(0) ++#define AIU_RST_SOFT_I2S_SLOW_DOMAIN BIT(1) ++ ++/* ++ * The DMA works by i2s "blocks" (or DMA burst). The burst size and the memory ++ * layout expected depends on the mode of operation. ++ * ++ * - Normal mode: The channels are expected to be packed in 32 bytes groups ++ * interleaved the buffer. AIU_MEM_I2S_MASKS_CH_MEM is a bitfield representing ++ * the channels present in memory. AIU_MEM_I2S_MASKS_CH_MEM represents the ++ * channels read by the DMA. This is very flexible but the unsual memory layout ++ * makes it less easy to deal with. The burst size is 32 bytes times the number ++ * of channels read. ++ * ++ * - Split mode: ++ * Classical channel interleaved frame organisation. In this mode, ++ * AIU_MEM_I2S_MASKS_CH_MEM and AIU_MEM_I2S_MASKS_CH_MEM must be set to 0xff and ++ * the burst size is fixed to 256 bytes. The input can be either 2 or 8 ++ * channels. ++ * ++ * The following driver implements the split mode. ++ */ ++ ++#define AIU_I2S_DMA_BURST 256 ++ ++static struct snd_pcm_hardware meson_aiu_i2s_dma_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_PAUSE), ++ ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE), ++ ++ /* ++ * TODO: The DMA can change the endianness, the msb position ++ * and deal with unsigned - support this later on ++ */ ++ ++ .rate_min = 8000, ++ .rate_max = 192000, ++ .channels_min = 2, ++ .channels_max = 8, ++ .period_bytes_min = AIU_I2S_DMA_BURST, ++ .period_bytes_max = AIU_I2S_DMA_BURST * 65535, ++ .periods_min = 2, ++ .periods_max = UINT_MAX, ++ .buffer_bytes_max = 1 * 1024 * 1024, ++ .fifo_size = 0, ++}; ++ ++static struct meson_aiu_i2s *meson_aiu_i2s_dma_priv(struct snd_pcm_substream *s) ++{ ++ struct snd_soc_pcm_runtime *rtd = s->private_data; ++ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); ++ ++ return snd_soc_component_get_drvdata(component); ++} ++ ++static snd_pcm_uframes_t ++meson_aiu_i2s_dma_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ unsigned int addr; ++ int ret; ++ ++ ret = regmap_read(priv->core->aiu, AIU_MEM_I2S_RD_PTR, ++ &addr); ++ if (ret) ++ return 0; ++ ++ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); ++} ++ ++static void __dma_enable(struct meson_aiu_i2s *priv, bool enable) ++{ ++ unsigned int en_mask = (AIU_MEM_I2S_CONTROL_FILL_EN | ++ AIU_MEM_I2S_CONTROL_EMPTY_EN); ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, en_mask, ++ enable ? en_mask : 0); ++ ++} ++ ++static int meson_aiu_i2s_dma_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ __dma_enable(priv, true); ++ break; ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ case SNDRV_PCM_TRIGGER_STOP: ++ __dma_enable(priv, false); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void __dma_init_mem(struct meson_aiu_i2s *priv) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, ++ AIU_MEM_I2S_CONTROL_INIT, ++ AIU_MEM_I2S_CONTROL_INIT); ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL, ++ AIU_MEM_I2S_BUF_CNTL_INIT, ++ AIU_MEM_I2S_BUF_CNTL_INIT); ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, ++ AIU_MEM_I2S_CONTROL_INIT, ++ 0); ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_BUF_CNTL, ++ AIU_MEM_I2S_BUF_CNTL_INIT, ++ 0); ++} ++ ++static int meson_aiu_i2s_dma_prepare(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ ++ __dma_init_mem(priv); ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dma_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ int ret; ++ u32 burst_num, mem_ctl; ++ dma_addr_t end_ptr; ++ ++ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); ++ if (ret < 0) ++ return ret; ++ ++ /* Setup memory layout */ ++ if (params_physical_width(params) == 16) ++ mem_ctl = AIU_MEM_I2S_CONTROL_MODE_16BIT; ++ else ++ mem_ctl = 0; ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_I2S_CONTROL, ++ AIU_MEM_I2S_CONTROL_MODE_16BIT, ++ mem_ctl); ++ ++ /* Initialize memory pointers */ ++ regmap_write(priv->core->aiu, AIU_MEM_I2S_START_PTR, runtime->dma_addr); ++ regmap_write(priv->core->aiu, AIU_MEM_I2S_RD_PTR, runtime->dma_addr); ++ ++ /* The end pointer is the address of the last valid block */ ++ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_I2S_DMA_BURST; ++ regmap_write(priv->core->aiu, AIU_MEM_I2S_END_PTR, end_ptr); ++ ++ /* Memory masks */ ++ burst_num = params_period_bytes(params) / AIU_I2S_DMA_BURST; ++ regmap_write(priv->core->aiu, AIU_MEM_I2S_MASKS, ++ AIU_MEM_I2S_MASKS_CH_RD(0xff) | ++ AIU_MEM_I2S_MASKS_CH_MEM(0xff) | ++ AIU_MEM_I2S_MASKS_IRQ_BLOCK(burst_num)); ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dma_hw_free(struct snd_pcm_substream *substream) ++{ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++ ++static irqreturn_t meson_aiu_i2s_dma_irq_block(int irq, void *dev_id) ++{ ++ struct snd_pcm_substream *playback = dev_id; ++ ++ snd_pcm_period_elapsed(playback); ++ ++ return IRQ_HANDLED; ++} ++ ++static int meson_aiu_i2s_dma_open(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ int ret; ++ ++ snd_soc_set_runtime_hwparams(substream, &meson_aiu_i2s_dma_hw); ++ ++ /* ++ * Make sure the buffer and period size are multiple of the DMA burst ++ * size ++ */ ++ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, ++ AIU_I2S_DMA_BURST); ++ if (ret) ++ return ret; ++ ++ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ AIU_I2S_DMA_BURST); ++ if (ret) ++ return ret; ++ ++ /* Request the I2S DDR irq */ ++ ret = request_irq(priv->irq, meson_aiu_i2s_dma_irq_block, 0, ++ DRV_NAME, substream); ++ if (ret) ++ return ret; ++ ++ /* Power up the i2s fast domain - can't write the registers w/o it */ ++ ret = clk_prepare_enable(priv->fast); ++ if (ret) ++ return ret; ++ ++ /* Make sure the dma is initially disabled */ ++ __dma_enable(priv, false); ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dma_close(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_i2s *priv = meson_aiu_i2s_dma_priv(substream); ++ ++ clk_disable_unprepare(priv->fast); ++ free_irq(priv->irq, substream); ++ ++ return 0; ++} ++ ++static const struct snd_pcm_ops meson_aiu_i2s_dma_ops = { ++ .open = meson_aiu_i2s_dma_open, ++ .close = meson_aiu_i2s_dma_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = meson_aiu_i2s_dma_hw_params, ++ .hw_free = meson_aiu_i2s_dma_hw_free, ++ .prepare = meson_aiu_i2s_dma_prepare, ++ .pointer = meson_aiu_i2s_dma_pointer, ++ .trigger = meson_aiu_i2s_dma_trigger, ++}; ++ ++static int meson_aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_card *card = rtd->card->snd_card; ++ size_t size = meson_aiu_i2s_dma_hw.buffer_bytes_max; ++ ++ snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, ++ SNDRV_DMA_TYPE_DEV, ++ card->dev, size, size); ++ ++ return 0; ++} ++ ++#define AIU_CLK_CTRL_I2S_DIV_EN BIT(0) ++#define AIU_CLK_CTRL_I2S_DIV_MASK GENMASK(3, 2) ++#define AIU_CLK_CTRL_AOCLK_POLARITY_MASK BIT(6) ++#define AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL (0 << 6) ++#define AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED (1 << 6) ++#define AIU_CLK_CTRL_ALRCLK_POLARITY_MASK BIT(7) ++#define AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL (0 << 7) ++#define AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED (1 << 7) ++#define AIU_CLK_CTRL_ALRCLK_SKEW_MASK GENMASK(9, 8) ++#define AIU_CLK_CTRL_ALRCLK_LEFT_J (0 << 8) ++#define AIU_CLK_CTRL_ALRCLK_I2S (1 << 8) ++#define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8) ++#define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0) ++#define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0) ++#define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0) ++#define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0) ++#define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0) ++#define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0) ++#define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0) ++#define AIU_I2S_DAC_CFG_AOCLK_64 (3 << 0) ++#define AIU_I2S_MISC_HOLD_EN BIT(2) ++#define AIU_I2S_SOURCE_DESC_MODE_8CH BIT(0) ++#define AIU_I2S_SOURCE_DESC_MODE_24BIT BIT(5) ++#define AIU_I2S_SOURCE_DESC_MODE_32BIT BIT(9) ++#define AIU_I2S_SOURCE_DESC_MODE_SPLIT BIT(11) ++ ++static void __hold(struct meson_aiu_i2s *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_I2S_MISC, ++ AIU_I2S_MISC_HOLD_EN, ++ enable ? AIU_I2S_MISC_HOLD_EN : 0); ++} ++ ++static void __divider_enable(struct meson_aiu_i2s *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_I2S_DIV_EN, ++ enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0); ++} ++ ++static void __playback_start(struct meson_aiu_i2s *priv) ++{ ++ __divider_enable(priv, true); ++ __hold(priv, false); ++} ++ ++static void __playback_stop(struct meson_aiu_i2s *priv, bool clk_force) ++{ ++ __hold(priv, true); ++ /* Disable the bit clks if necessary */ ++ if (clk_force || !priv->bclks_idle) ++ __divider_enable(priv, false); ++} ++ ++static int meson_aiu_i2s_dai_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ bool clk_force_stop = false; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ __playback_start(priv); ++ return 0; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ clk_force_stop = true; ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ __playback_stop(priv, clk_force_stop); ++ return 0; ++ ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int __bclks_set_rate(struct meson_aiu_i2s *priv, unsigned int srate, ++ unsigned int width) ++{ ++ unsigned int fs; ++ ++ /* Get the oversampling factor */ ++ fs = DIV_ROUND_CLOSEST(clk_get_rate(priv->mclk), srate); ++ ++ /* ++ * This DAI is usually connected to the dw-hdmi which does not support ++ * bclk being 32 * lrclk or 48 * lrclk ++ * Restrict to blck = 64 * lrclk ++ */ ++ if (fs % 64) ++ return -EINVAL; ++ ++ /* Set the divider between lrclk and bclk */ ++ regmap_update_bits(priv->core->aiu, AIU_I2S_DAC_CFG, ++ AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK, ++ AIU_I2S_DAC_CFG_AOCLK_64); ++ ++ regmap_update_bits(priv->core->aiu, AIU_CODEC_DAC_LRCLK_CTRL, ++ AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK, ++ AIU_CODEC_DAC_LRCLK_CTRL_DIV(64)); ++ ++ /* Use CLK_MORE for the i2s divider */ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_I2S_DIV_MASK, ++ 0); ++ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE, ++ AIU_CLK_CTRL_MORE_I2S_DIV_MASK, ++ AIU_CLK_CTRL_MORE_I2S_DIV(fs / 64)); ++ ++ return 0; ++} ++ ++static int __setup_desc(struct meson_aiu_i2s *priv, unsigned int width, ++ unsigned int channels) ++{ ++ u32 desc = 0; ++ ++ switch (width) { ++ case 24: ++ /* ++ * For some reason, 24 bits wide audio don't play well ++ * if the 32 bits mode is not set ++ */ ++ desc |= (AIU_I2S_SOURCE_DESC_MODE_24BIT | ++ AIU_I2S_SOURCE_DESC_MODE_32BIT); ++ break; ++ case 16: ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ switch (channels) { ++ case 2: /* Nothing to do */ ++ break; ++ case 8: ++ /* TODO: Still requires testing ... */ ++ desc |= AIU_I2S_SOURCE_DESC_MODE_8CH; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC, ++ AIU_I2S_SOURCE_DESC_MODE_8CH | ++ AIU_I2S_SOURCE_DESC_MODE_24BIT | ++ AIU_I2S_SOURCE_DESC_MODE_32BIT, ++ desc); ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dai_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ unsigned int width = params_width(params); ++ unsigned int channels = params_channels(params); ++ unsigned int rate = params_rate(params); ++ int ret; ++ ++ ret = __setup_desc(priv, width, channels); ++ if (ret) { ++ dev_err(dai->dev, "Unable set to set i2s description\n"); ++ return ret; ++ } ++ ++ ret = __bclks_set_rate(priv, rate, width); ++ if (ret) { ++ dev_err(dai->dev, "Unable set to the i2s clock rates\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ u32 val; ++ ++ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) ++ return -EINVAL; ++ ++ /* DAI output mode */ ++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ val = AIU_CLK_CTRL_ALRCLK_I2S; ++ break; ++ case SND_SOC_DAIFMT_LEFT_J: ++ val = AIU_CLK_CTRL_ALRCLK_LEFT_J; ++ break; ++ case SND_SOC_DAIFMT_RIGHT_J: ++ val = AIU_CLK_CTRL_ALRCLK_RIGHT_J; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_ALRCLK_SKEW_MASK, ++ val); ++ ++ /* DAI clock polarity */ ++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_IB_IF: ++ /* Invert both clocks */ ++ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED | ++ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ /* Invert bit clock */ ++ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL | ++ AIU_CLK_CTRL_AOCLK_POLARITY_INVERTED; ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ /* Invert frame clock */ ++ val = AIU_CLK_CTRL_ALRCLK_POLARITY_INVERTED | ++ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL; ++ break; ++ case SND_SOC_DAIFMT_NB_NF: ++ /* Normal clocks */ ++ val = AIU_CLK_CTRL_ALRCLK_POLARITY_NORMAL | ++ AIU_CLK_CTRL_AOCLK_POLARITY_NORMAL; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_ALRCLK_POLARITY_MASK | ++ AIU_CLK_CTRL_AOCLK_POLARITY_MASK, ++ val); ++ ++ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { ++ case SND_SOC_DAIFMT_CONT: ++ priv->bclks_idle = true; ++ break; ++ case SND_SOC_DAIFMT_GATED: ++ priv->bclks_idle = false; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, ++ unsigned int freq, int dir) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ int ret; ++ ++ if (WARN_ON(clk_id != 0)) ++ return -EINVAL; ++ ++ if (dir == SND_SOC_CLOCK_IN) ++ return 0; ++ ++ ret = clk_set_rate(priv->mclk, freq); ++ if (ret) { ++ dev_err(dai->dev, "Failed to set sysclk to %uHz", freq); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int meson_aiu_i2s_dai_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ int ret; ++ ++ /* Power up the i2s fast domain - can't write the registers w/o it */ ++ ret = clk_prepare_enable(priv->fast); ++ if (ret) ++ goto out_clk_fast; ++ ++ /* Make sure nothing gets out of the DAI yet */ ++ __hold(priv, true); ++ ++ /* I2S encoder needs the mixer interface gate */ ++ ret = clk_prepare_enable(priv->iface); ++ if (ret) ++ goto out_clk_iface; ++ ++ /* Enable the i2s master clock */ ++ ret = clk_prepare_enable(priv->mclk); ++ if (ret) ++ goto out_mclk; ++ ++ /* Enable the bit clock gate */ ++ ret = clk_prepare_enable(priv->bclks); ++ if (ret) ++ goto out_bclks; ++ ++ /* Make sure the interface expect a memory layout we can work with */ ++ regmap_update_bits(priv->core->aiu, AIU_I2S_SOURCE_DESC, ++ AIU_I2S_SOURCE_DESC_MODE_SPLIT, ++ AIU_I2S_SOURCE_DESC_MODE_SPLIT); ++ ++ return 0; ++ ++out_bclks: ++ clk_disable_unprepare(priv->mclk); ++out_mclk: ++ clk_disable_unprepare(priv->iface); ++out_clk_iface: ++ clk_disable_unprepare(priv->fast); ++out_clk_fast: ++ return ret; ++} ++ ++static void meson_aiu_i2s_dai_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_i2s *priv = snd_soc_dai_get_drvdata(dai); ++ ++ clk_disable_unprepare(priv->bclks); ++ clk_disable_unprepare(priv->mclk); ++ clk_disable_unprepare(priv->iface); ++ clk_disable_unprepare(priv->fast); ++} ++ ++static const struct snd_soc_dai_ops meson_aiu_i2s_dai_ops = { ++ .startup = meson_aiu_i2s_dai_startup, ++ .shutdown = meson_aiu_i2s_dai_shutdown, ++ .trigger = meson_aiu_i2s_dai_trigger, ++ .hw_params = meson_aiu_i2s_dai_hw_params, ++ .set_fmt = meson_aiu_i2s_dai_set_fmt, ++ .set_sysclk = meson_aiu_i2s_dai_set_sysclk, ++}; ++ ++static struct snd_soc_dai_driver meson_aiu_i2s_dai = { ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 8, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE) ++ }, ++ .ops = &meson_aiu_i2s_dai_ops, ++}; ++ ++static const struct snd_soc_component_driver meson_aiu_i2s_component = { ++ .ops = &meson_aiu_i2s_dma_ops, ++ .pcm_new = meson_aiu_i2s_dma_new, ++ .name = DRV_NAME, ++}; ++ ++static int meson_aiu_i2s_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct meson_aiu_i2s *priv; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, priv); ++ priv->core = dev_get_drvdata(dev->parent); ++ ++ priv->fast = devm_clk_get(dev, "fast"); ++ if (IS_ERR(priv->fast)) { ++ if (PTR_ERR(priv->fast) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get the i2s fast domain clock\n"); ++ return PTR_ERR(priv->fast); ++ } ++ ++ priv->iface = devm_clk_get(dev, "iface"); ++ if (IS_ERR(priv->iface)) { ++ if (PTR_ERR(priv->iface) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get i2s dai clock gate\n"); ++ return PTR_ERR(priv->iface); ++ } ++ ++ priv->bclks = devm_clk_get(dev, "bclks"); ++ if (IS_ERR(priv->bclks)) { ++ if (PTR_ERR(priv->bclks) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get bit clocks gate\n"); ++ return PTR_ERR(priv->bclks); ++ } ++ ++ priv->mclk = devm_clk_get(dev, "mclk"); ++ if (IS_ERR(priv->mclk)) { ++ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER) ++ dev_err(dev, "failed to get the i2s master clock\n"); ++ return PTR_ERR(priv->mclk); ++ } ++ ++ priv->irq = platform_get_irq(pdev, 0); ++ if (priv->irq <= 0) { ++ dev_err(dev, "Can't get i2s ddr irq\n"); ++ return priv->irq; ++ } ++ ++ return devm_snd_soc_register_component(dev, &meson_aiu_i2s_component, ++ &meson_aiu_i2s_dai, 1); ++} ++ ++static const struct of_device_id meson_aiu_i2s_of_match[] = { ++ { .compatible = "amlogic,meson-aiu-i2s", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, meson_aiu_i2s_of_match); ++ ++static struct platform_driver meson_aiu_i2s_pdrv = { ++ .probe = meson_aiu_i2s_probe, ++ .driver = { ++ .name = DRV_NAME, ++ .of_match_table = meson_aiu_i2s_of_match, ++ }, ++}; ++module_platform_driver(meson_aiu_i2s_pdrv); ++ ++MODULE_DESCRIPTION("Meson AIU i2s ASoC Driver"); ++MODULE_AUTHOR("Jerome Brunet "); ++MODULE_LICENSE("GPL v2"); + +From aea5536958e43c3908dbf31ddad800a8e03aaa37 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 13:46:03 +0200 +Subject: [PATCH 231/249] ASoC: meson: add initial spdif support + +Add support for the spdif found on Amlogic Meson SoC family. +With this initial implementation, only uncompressed pcm playback +from the spdif dma is supported. Future work will add compressed +support, pcm playback from i2s dma and capture. + +Signed-off-by: Jerome Brunet +--- + sound/soc/meson-gx/Kconfig | 7 + + sound/soc/meson-gx/Makefile | 3 +- + sound/soc/meson-gx/aiu-spdif.c | 671 +++++++++++++++++++++++++++++++++ + 3 files changed, 680 insertions(+), 1 deletion(-) + create mode 100644 sound/soc/meson-gx/aiu-spdif.c + +diff --git a/sound/soc/meson-gx/Kconfig b/sound/soc/meson-gx/Kconfig +index 8ec683cdf3276..141afabfaceaa 100644 +--- a/sound/soc/meson-gx/Kconfig ++++ b/sound/soc/meson-gx/Kconfig +@@ -17,3 +17,10 @@ config SND_SOC_MESON_GX_I2S + Say Y or M if you want to add support for i2s driver for Amlogic + Meson SoCs. + ++config SND_SOC_MESON_GX_SPDIF ++ tristate "Meson spdif interface" ++ depends on SND_SOC_MESON_GX ++ select SND_PCM_IEC958 ++ help ++ Say Y or M if you want to add support for spdif driver for Amlogic ++ Meson SoCs. +diff --git a/sound/soc/meson-gx/Makefile b/sound/soc/meson-gx/Makefile +index 02f9c4df6348d..d37672ebe57bf 100644 +--- a/sound/soc/meson-gx/Makefile ++++ b/sound/soc/meson-gx/Makefile +@@ -1,6 +1,7 @@ + snd-soc-meson-audio-core-objs := audio-core.o + snd-soc-meson-aiu-i2s-objs := aiu-i2s.o ++snd-soc-meson-aiu-spdif-objs := aiu-spdif.o + + obj-$(CONFIG_SND_SOC_MESON_GX) += snd-soc-meson-audio-core.o + obj-$(CONFIG_SND_SOC_MESON_GX_I2S) += snd-soc-meson-aiu-i2s.o +- ++obj-$(CONFIG_SND_SOC_MESON_GX_SPDIF) += snd-soc-meson-aiu-spdif.o +diff --git a/sound/soc/meson-gx/aiu-spdif.c b/sound/soc/meson-gx/aiu-spdif.c +new file mode 100644 +index 0000000000000..748a9b1d680c0 +--- /dev/null ++++ b/sound/soc/meson-gx/aiu-spdif.c +@@ -0,0 +1,671 @@ ++/* ++ * Copyright (C) 2017 BayLibre, SAS ++ * Author: Jerome Brunet ++ * 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. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "aiu-regs.h" ++#include "audio-core.h" ++ ++#define DRV_NAME "meson-aiu-spdif" ++ ++struct meson_aiu_spdif { ++ struct meson_audio_core_data *core; ++ struct clk *iface; ++ struct clk *fast; ++ struct clk *mclk_i958; ++ struct clk *mclk; ++ int irq; ++}; ++ ++ ++#define AIU_958_DCU_FF_CTRL_EN BIT(0) ++#define AIU_958_DCU_FF_CTRL_AUTO_DISABLE BIT(1) ++#define AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK GENMASK(3, 2) ++#define AIU_958_DCU_FF_CTRL_IRQ_OUT_THD BIT(2) ++#define AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ BIT(3) ++#define AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN BIT(4) ++#define AIU_958_DCU_FF_CTRL_BYTE_SEEK BIT(5) ++#define AIU_958_DCU_FF_CTRL_CONTINUE BIT(6) ++#define AIU_MEM_IEC958_BUF_CNTL_INIT BIT(0) ++#define AIU_MEM_IEC958_CONTROL_INIT BIT(0) ++#define AIU_MEM_IEC958_CONTROL_FILL_EN BIT(1) ++#define AIU_MEM_IEC958_CONTROL_EMPTY_EN BIT(2) ++#define AIU_MEM_IEC958_CONTROL_ENDIAN_MASK GENMASK(5, 3) ++#define AIU_MEM_IEC958_CONTROL_RD_DDR BIT(6) ++#define AIU_MEM_IEC958_CONTROL_MODE_16BIT BIT(7) ++#define AIU_MEM_IEC958_MASKS_CH_MEM_MASK GENMASK(15, 8) ++#define AIU_MEM_IEC958_MASKS_CH_MEM(ch) ((ch) << 8) ++#define AIU_MEM_IEC958_MASKS_CH_RD_MASK GENMASK(7, 0) ++#define AIU_MEM_IEC958_MASKS_CH_RD(ch) ((ch) << 0) ++ ++#define AIU_SPDIF_DMA_BURST 8 ++#define AIU_SPDIF_BPF_MAX USHRT_MAX ++ ++static struct snd_pcm_hardware meson_aiu_spdif_dma_hw = { ++ .info = (SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_PAUSE), ++ ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE | ++ SNDRV_PCM_FMTBIT_S32_LE), ++ ++ .rates = (SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_96000 | ++ SNDRV_PCM_RATE_192000), ++ /* ++ * TODO: The DMA can change the endianness, the msb position ++ * and deal with unsigned - support this later on ++ */ ++ ++ .channels_min = 2, ++ .channels_max = 2, ++ .period_bytes_min = AIU_SPDIF_DMA_BURST, ++ .period_bytes_max = AIU_SPDIF_BPF_MAX, ++ .periods_min = 2, ++ .periods_max = UINT_MAX, ++ .buffer_bytes_max = 1 * 1024 * 1024, ++ .fifo_size = 0, ++}; ++ ++static struct meson_aiu_spdif *meson_aiu_spdif_dma_priv(struct snd_pcm_substream *s) ++{ ++ struct snd_soc_pcm_runtime *rtd = s->private_data; ++ struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); ++ ++ return snd_soc_component_get_drvdata(component); ++} ++ ++static snd_pcm_uframes_t ++meson_aiu_spdif_dma_pointer(struct snd_pcm_substream *substream) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ unsigned int addr; ++ int ret; ++ ++ ret = regmap_read(priv->core->aiu, AIU_MEM_IEC958_RD_PTR, ++ &addr); ++ if (ret) ++ return 0; ++ ++ return bytes_to_frames(runtime, addr - (unsigned int)runtime->dma_addr); ++} ++ ++static void __dma_enable(struct meson_aiu_spdif *priv, bool enable) ++{ ++ unsigned int en_mask = (AIU_MEM_IEC958_CONTROL_FILL_EN | ++ AIU_MEM_IEC958_CONTROL_EMPTY_EN); ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, en_mask, ++ enable ? en_mask : 0); ++} ++ ++static void __dcu_fifo_enable(struct meson_aiu_spdif *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL, ++ AIU_958_DCU_FF_CTRL_EN, ++ enable ? AIU_958_DCU_FF_CTRL_EN : 0); ++} ++ ++static int meson_aiu_spdif_dma_trigger(struct snd_pcm_substream *substream, int cmd) ++{ ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ __dcu_fifo_enable(priv, true); ++ __dma_enable(priv, true); ++ break; ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ case SNDRV_PCM_TRIGGER_STOP: ++ __dma_enable(priv, false); ++ __dcu_fifo_enable(priv, false); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static void __dma_init_mem(struct meson_aiu_spdif *priv) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, ++ AIU_MEM_IEC958_CONTROL_INIT, ++ AIU_MEM_IEC958_CONTROL_INIT); ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL, ++ AIU_MEM_IEC958_BUF_CNTL_INIT, ++ AIU_MEM_IEC958_BUF_CNTL_INIT); ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, ++ AIU_MEM_IEC958_CONTROL_INIT, ++ 0); ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_BUF_CNTL, ++ AIU_MEM_IEC958_BUF_CNTL_INIT, ++ 0); ++} ++ ++static int meson_aiu_spdif_dma_prepare(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ ++ __dma_init_mem(priv); ++ ++ return 0; ++} ++ ++static int __setup_memory_layout(struct meson_aiu_spdif *priv, ++ unsigned int width) ++{ ++ u32 mem_ctl = AIU_MEM_IEC958_CONTROL_RD_DDR; ++ ++ if (width == 16) ++ mem_ctl |= AIU_MEM_IEC958_CONTROL_MODE_16BIT; ++ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, ++ AIU_MEM_IEC958_CONTROL_ENDIAN_MASK | ++ AIU_MEM_IEC958_CONTROL_MODE_16BIT | ++ AIU_MEM_IEC958_CONTROL_RD_DDR, ++ mem_ctl); ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dma_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_pcm_runtime *runtime = substream->runtime; ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ int ret; ++ dma_addr_t end_ptr; ++ ++ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); ++ if (ret < 0) ++ return ret; ++ ++ ret = __setup_memory_layout(priv, params_physical_width(params)); ++ if (ret) ++ return ret; ++ ++ /* Initialize memory pointers */ ++ regmap_write(priv->core->aiu, ++ AIU_MEM_IEC958_START_PTR, runtime->dma_addr); ++ regmap_write(priv->core->aiu, ++ AIU_MEM_IEC958_RD_PTR, runtime->dma_addr); ++ ++ /* The end pointer is the address of the last valid block */ ++ end_ptr = runtime->dma_addr + runtime->dma_bytes - AIU_SPDIF_DMA_BURST; ++ regmap_write(priv->core->aiu, AIU_MEM_IEC958_END_PTR, end_ptr); ++ ++ /* Memory masks */ ++ regmap_write(priv->core->aiu, AIU_MEM_IEC958_MASKS, ++ AIU_MEM_IEC958_MASKS_CH_RD(0xff) | ++ AIU_MEM_IEC958_MASKS_CH_MEM(0xff)); ++ ++ /* Setup the number bytes read by the FIFO between each IRQ */ ++ regmap_write(priv->core->aiu, AIU_958_BPF, params_period_bytes(params)); ++ ++ /* ++ * AUTO_DISABLE and SYNC_HEAD are enabled by default but ++ * this should be disabled in PCM (uncompressed) mode ++ */ ++ regmap_update_bits(priv->core->aiu, AIU_958_DCU_FF_CTRL, ++ AIU_958_DCU_FF_CTRL_AUTO_DISABLE | ++ AIU_958_DCU_FF_CTRL_IRQ_MODE_MASK | ++ AIU_958_DCU_FF_CTRL_SYNC_HEAD_EN, ++ AIU_958_DCU_FF_CTRL_IRQ_FRAME_READ); ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dma_hw_free(struct snd_pcm_substream *substream) ++{ ++ return snd_pcm_lib_free_pages(substream); ++} ++ ++static irqreturn_t meson_aiu_spdif_dma_irq(int irq, void *dev_id) ++{ ++ struct snd_pcm_substream *playback = dev_id; ++ ++ snd_pcm_period_elapsed(playback); ++ ++ return IRQ_HANDLED; ++} ++ ++static int meson_aiu_spdif_dma_open(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ int ret; ++ ++ snd_soc_set_runtime_hwparams(substream, &meson_aiu_spdif_dma_hw); ++ ++ /* ++ * Make sure the buffer and period size are multiple of the DMA burst ++ * size ++ */ ++ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_BUFFER_BYTES, ++ AIU_SPDIF_DMA_BURST); ++ if (ret) ++ return ret; ++ ++ ret = snd_pcm_hw_constraint_step(substream->runtime, 0, ++ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, ++ AIU_SPDIF_DMA_BURST); ++ if (ret) ++ return ret; ++ ++ /* Request the SPDIF DDR irq */ ++ ret = request_irq(priv->irq, meson_aiu_spdif_dma_irq, 0, ++ DRV_NAME, substream); ++ if (ret) ++ return ret; ++ ++ /* Power up the spdif fast domain - can't write the register w/o it */ ++ ret = clk_prepare_enable(priv->fast); ++ if (ret) ++ return ret; ++ ++ /* Make sure the dma is initially halted */ ++ __dma_enable(priv, false); ++ __dcu_fifo_enable(priv, false); ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dma_close(struct snd_pcm_substream *substream) ++{ ++ struct meson_aiu_spdif *priv = meson_aiu_spdif_dma_priv(substream); ++ ++ clk_disable_unprepare(priv->fast); ++ free_irq(priv->irq, substream); ++ ++ return 0; ++} ++ ++static const struct snd_pcm_ops meson_aiu_spdif_dma_ops = { ++ .open = meson_aiu_spdif_dma_open, ++ .close = meson_aiu_spdif_dma_close, ++ .ioctl = snd_pcm_lib_ioctl, ++ .hw_params = meson_aiu_spdif_dma_hw_params, ++ .hw_free = meson_aiu_spdif_dma_hw_free, ++ .prepare = meson_aiu_spdif_dma_prepare, ++ .pointer = meson_aiu_spdif_dma_pointer, ++ .trigger = meson_aiu_spdif_dma_trigger, ++}; ++ ++static int meson_aiu_spdif_dma_new(struct snd_soc_pcm_runtime *rtd) ++{ ++ struct snd_card *card = rtd->card->snd_card; ++ size_t size = meson_aiu_spdif_dma_hw.buffer_bytes_max; ++ ++ snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, ++ SNDRV_DMA_TYPE_DEV, ++ card->dev, size, size); ++ ++ return 0; ++} ++ ++#define AIU_CLK_CTRL_958_DIV_EN BIT(1) ++#define AIU_CLK_CTRL_958_DIV_MASK GENMASK(5, 4) ++#define AIU_CLK_CTRL_958_DIV_MORE BIT(12) ++#define AIU_MEM_IEC958_CONTROL_MODE_LINEAR BIT(8) ++#define AIU_958_CTRL_HOLD_EN BIT(0) ++#define AIU_958_MISC_NON_PCM BIT(0) ++#define AIU_958_MISC_MODE_16BITS BIT(1) ++#define AIU_958_MISC_16BITS_ALIGN_MASK GENMASK(6, 5) ++#define AIU_958_MISC_16BITS_ALIGN(val) ((val) << 5) ++#define AIU_958_MISC_MODE_32BITS BIT(7) ++#define AIU_958_MISC_32BITS_SHIFT_MASK GENMASK(10, 8) ++#define AIU_958_MISC_32BITS_SHIFT(val) ((val) << 8) ++#define AIU_958_MISC_U_FROM_STREAM BIT(12) ++#define AIU_958_MISC_FORCE_LR BIT(13) ++ ++#define AIU_CS_WORD_LEN 4 ++ ++static void __hold(struct meson_aiu_spdif *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_958_CTRL, ++ AIU_958_CTRL_HOLD_EN, ++ enable ? AIU_958_CTRL_HOLD_EN : 0); ++} ++ ++static void __divider_enable(struct meson_aiu_spdif *priv, bool enable) ++{ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_958_DIV_EN, ++ enable ? AIU_CLK_CTRL_958_DIV_EN : 0); ++} ++ ++static void __playback_start(struct meson_aiu_spdif *priv) ++{ ++ __divider_enable(priv, true); ++ __hold(priv, false); ++} ++ ++static void __playback_stop(struct meson_aiu_spdif *priv) ++{ ++ __hold(priv, true); ++ __divider_enable(priv, false); ++} ++ ++static int meson_aiu_spdif_dai_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ __playback_start(priv); ++ return 0; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ __playback_stop(priv); ++ return 0; ++ ++ default: ++ return -EINVAL; ++ } ++} ++ ++static int __setup_spdif_clk(struct meson_aiu_spdif *priv, unsigned int rate) ++{ ++ unsigned int mrate; ++ ++ /* Leave the internal divisor alone */ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL, ++ AIU_CLK_CTRL_958_DIV_MASK | ++ AIU_CLK_CTRL_958_DIV_MORE, ++ 0); ++ ++ /* 2 * 32bits per subframe * 2 channels = 128 */ ++ mrate = rate * 128; ++ return clk_set_rate(priv->mclk, mrate); ++} ++ ++static int __setup_cs_word(struct meson_aiu_spdif *priv, ++ struct snd_pcm_hw_params *params) ++{ ++ u8 cs[AIU_CS_WORD_LEN]; ++ u32 val; ++ int ret; ++ ++ ret = snd_pcm_create_iec958_consumer_hw_params(params, cs, ++ AIU_CS_WORD_LEN); ++ if (ret < 0) ++ return -EINVAL; ++ ++ /* Write the 1st half word */ ++ val = cs[1] | cs[0] << 8; ++ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L0, val); ++ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R0, val); ++ ++ /* Write the 2nd half word */ ++ val = cs[3] | cs[2] << 8; ++ regmap_write(priv->core->aiu, AIU_958_CHSTAT_L1, val); ++ regmap_write(priv->core->aiu, AIU_958_CHSTAT_R1, val); ++ ++ return 0; ++} ++ ++static int __setup_pcm_fmt(struct meson_aiu_spdif *priv, ++ unsigned int width) ++{ ++ u32 val = 0; ++ ++ switch (width) { ++ case 16: ++ val |= AIU_958_MISC_MODE_16BITS; ++ val |= AIU_958_MISC_16BITS_ALIGN(2); ++ break; ++ case 32: ++ case 24: ++ /* ++ * Looks like this should only be set for 32bits mode, but the ++ * vendor kernel sets it like this for 24bits as well, let's ++ * try and see ++ */ ++ val |= AIU_958_MISC_MODE_32BITS; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* No idea what this actually does, copying the vendor kernel for now */ ++ val |= AIU_958_MISC_FORCE_LR; ++ val |= AIU_958_MISC_U_FROM_STREAM; ++ ++ regmap_update_bits(priv->core->aiu, AIU_958_MISC, ++ AIU_958_MISC_NON_PCM | ++ AIU_958_MISC_MODE_16BITS | ++ AIU_958_MISC_16BITS_ALIGN_MASK | ++ AIU_958_MISC_MODE_32BITS | ++ AIU_958_MISC_FORCE_LR, ++ val); ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dai_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); ++ int ret; ++ ++ ret = __setup_spdif_clk(priv, params_rate(params)); ++ if (ret) { ++ dev_err(dai->dev, "Unable to set the spdif clock\n"); ++ return ret; ++ } ++ ++ ret = __setup_cs_word(priv, params); ++ if (ret) { ++ dev_err(dai->dev, "Unable to set the channel status word\n"); ++ return ret; ++ } ++ ++ ret = __setup_pcm_fmt(priv, params_width(params)); ++ if (ret) { ++ dev_err(dai->dev, "Unable to set the pcm format\n"); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int meson_aiu_spdif_dai_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); ++ int ret; ++ ++ /* Power up the spdif fast domain - can't write the registers w/o it */ ++ ret = clk_prepare_enable(priv->fast); ++ if (ret) ++ goto out_clk_fast; ++ ++ /* Make sure nothing gets out of the DAI yet*/ ++ __hold(priv, true); ++ ++ ret = clk_set_parent(priv->mclk, priv->mclk_i958); ++ if (ret) ++ return ret; ++ ++ /* Enable the clock gate */ ++ ret = clk_prepare_enable(priv->iface); ++ if (ret) ++ goto out_clk_iface; ++ ++ /* Enable the spdif clock */ ++ ret = clk_prepare_enable(priv->mclk); ++ if (ret) ++ goto out_mclk; ++ ++ /* ++ * Make sure the interface expect a memory layout we can work with ++ * MEM prefixed register usually belong to the DMA, but when the spdif ++ * DAI takes data from the i2s buffer, we need to make sure it works in ++ * split mode and not the "normal mode" (channel samples packed in ++ * 32 bytes groups) ++ */ ++ regmap_update_bits(priv->core->aiu, AIU_MEM_IEC958_CONTROL, ++ AIU_MEM_IEC958_CONTROL_MODE_LINEAR, ++ AIU_MEM_IEC958_CONTROL_MODE_LINEAR); ++ ++ return 0; ++ ++out_mclk: ++ clk_disable_unprepare(priv->iface); ++out_clk_iface: ++ clk_disable_unprepare(priv->fast); ++out_clk_fast: ++ return ret; ++} ++ ++static void meson_aiu_spdif_dai_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct meson_aiu_spdif *priv = snd_soc_dai_get_drvdata(dai); ++ ++ clk_disable_unprepare(priv->iface); ++ clk_disable_unprepare(priv->mclk); ++ clk_disable_unprepare(priv->fast); ++} ++ ++static const struct snd_soc_dai_ops meson_aiu_spdif_dai_ops = { ++ .startup = meson_aiu_spdif_dai_startup, ++ .shutdown = meson_aiu_spdif_dai_shutdown, ++ .trigger = meson_aiu_spdif_dai_trigger, ++ .hw_params = meson_aiu_spdif_dai_hw_params, ++}; ++ ++static struct snd_soc_dai_driver meson_aiu_spdif_dai = { ++ .playback = { ++ .stream_name = "Playback", ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = (SNDRV_PCM_RATE_32000 | ++ SNDRV_PCM_RATE_44100 | ++ SNDRV_PCM_RATE_48000 | ++ SNDRV_PCM_RATE_96000 | ++ SNDRV_PCM_RATE_192000), ++ .formats = (SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S24_LE) ++ }, ++ .ops = &meson_aiu_spdif_dai_ops, ++}; ++ ++static const struct snd_soc_component_driver meson_aiu_spdif_component = { ++ .ops = &meson_aiu_spdif_dma_ops, ++ .pcm_new = meson_aiu_spdif_dma_new, ++ .name = DRV_NAME, ++}; ++ ++static int meson_aiu_spdif_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct meson_aiu_spdif *priv; ++ ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ platform_set_drvdata(pdev, priv); ++ priv->core = dev_get_drvdata(dev->parent); ++ ++ priv->fast = devm_clk_get(dev, "fast"); ++ if (IS_ERR(priv->fast)) { ++ if (PTR_ERR(priv->fast) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get spdif fast domain clockt\n"); ++ return PTR_ERR(priv->fast); ++ } ++ ++ priv->iface = devm_clk_get(dev, "iface"); ++ if (IS_ERR(priv->iface)) { ++ if (PTR_ERR(priv->iface) != -EPROBE_DEFER) ++ dev_err(dev, ++ "Can't get the dai clock gate\n"); ++ return PTR_ERR(priv->iface); ++ } ++ ++ priv->mclk_i958 = devm_clk_get(dev, "mclk_i958"); ++ if (IS_ERR(priv->mclk_i958)) { ++ if (PTR_ERR(priv->mclk_i958) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get the spdif master clock\n"); ++ return PTR_ERR(priv->mclk_i958); ++ } ++ ++ /* ++ * TODO: the spdif dai can also get its data from the i2s fifo. ++ * For this use-case, the DAI driver will need to get the i2s master ++ * clock in order to reparent the spdif clock from cts_mclk_i958 to ++ * cts_amclk ++ */ ++ ++ priv->mclk = devm_clk_get(dev, "mclk"); ++ if (IS_ERR(priv->mclk)) { ++ if (PTR_ERR(priv->mclk) != -EPROBE_DEFER) ++ dev_err(dev, "Can't get the spdif input mux clock\n"); ++ return PTR_ERR(priv->mclk); ++ } ++ ++ return devm_snd_soc_register_component(dev, &meson_aiu_spdif_component, ++ &meson_aiu_spdif_dai, 1); ++} ++ ++static const struct of_device_id meson_aiu_spdif_of_match[] = { ++ { .compatible = "amlogic,meson-aiu-spdif", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, meson_aiu_spdif_of_match); ++ ++static struct platform_driver meson_aiu_spdif_pdrv = { ++ .probe = meson_aiu_spdif_probe, ++ .driver = { ++ .name = DRV_NAME, ++ .of_match_table = meson_aiu_spdif_of_match, ++ }, ++}; ++module_platform_driver(meson_aiu_spdif_pdrv); ++ ++MODULE_DESCRIPTION("Meson AIU spdif ASoC Driver"); ++MODULE_AUTHOR("Jerome Brunet "); ++MODULE_LICENSE("GPL v2"); + +From 819f125da865f76477bd982abbafcf7e274e83fc Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 31 Mar 2017 15:55:03 +0200 +Subject: [PATCH 232/249] ARM64: defconfig: enable audio support for meson SoCs + as module + +Add audio support for meson SoCs. This includes the audio core +driver and the i2s and spdif output interfaces + +Signed-off-by: Jerome Brunet +--- + arch/arm64/configs/defconfig | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig +index 552868cb15ae5..ad87d5dbf09e6 100644 +--- a/arch/arm64/configs/defconfig ++++ b/arch/arm64/configs/defconfig +@@ -528,6 +528,9 @@ CONFIG_SOUND=y + CONFIG_SND=y + CONFIG_SND_SOC=y + CONFIG_SND_BCM2835_SOC_I2S=m ++CONFIG_SND_SOC_MESON_GX=m ++CONFIG_SND_SOC_MESON_GX_I2S=m ++CONFIG_SND_SOC_MESON_GX_SPDIF=m + CONFIG_SND_SOC_ROCKCHIP=m + CONFIG_SND_SOC_ROCKCHIP_SPDIF=m + CONFIG_SND_SOC_ROCKCHIP_RT5645=m + +From 463caeec5faa1fc46f8a07d970a1b8f97f9e549e Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Thu, 30 Mar 2017 15:19:04 +0200 +Subject: [PATCH 233/249] ARM64: dts: meson-gx: add audio controller nodes + +Add audio controller nodes for Amlogic meson gxbb and gxl. +This includes the audio-core node, the i2s and spdif DAIs + +Audio on this SoC family is still a work in progress. More nodes are likely +to be added later on (pcm DAIs, input DMAs, etc ...) + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 23 ++++++++++++++++++ + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 27 +++++++++++++++++++++ + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 27 +++++++++++++++++++++ + 3 files changed, 77 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index be7096869b2e7..5984f75be4169 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -225,6 +225,29 @@ + #reset-cells = <1>; + }; + ++ audio: audio@5400 { ++ compatible = "amlogic,meson-gx-audio-core"; ++ reg = <0x0 0x5400 0x0 0x2ac>, ++ <0x0 0xa000 0x0 0x304>; ++ reg-names = "aiu", "audin"; ++ status = "disabled"; ++ ++ aiu_i2s: audio-controller-0 { ++ #sound-dai-cells = <0>; ++ compatible = "amlogic,meson-aiu-i2s"; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ aiu_spdif: audio-controller-1 { ++ #sound-dai-cells = <0>; ++ compatible = "amlogic,meson-aiu-spdif"; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ }; ++ + uart_A: serial@84c0 { + compatible = "amlogic,meson-gx-uart"; + reg = <0x0 0x84c0 0x0 0x18>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index e900a93960fb6..277beb6e4f0b2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -709,6 +709,24 @@ + }; + }; + ++&audio { ++ clocks = <&clkc CLKID_AIU>, ++ <&clkc CLKID_AIU_GLUE>, ++ <&clkc CLKID_I2S_SPDIF>; ++ clock-names = "aiu_top", "aiu_glue", "audin"; ++ resets = <&reset RESET_AIU>, ++ <&reset RESET_AUDIN>; ++ reset-names = "aiu", "audin"; ++}; ++ ++&aiu_i2s { ++ clocks = <&clkc CLKID_I2S_OUT>, ++ <&clkc CLKID_MIXER_IFACE>, ++ <&clkc CLKID_AOCLK_GATE>, ++ <&clkc CLKID_CTS_AMCLK>; ++ clock-names = "fast", "iface", "bclks", "mclk"; ++}; ++ + &pwrc_vpu { + resets = <&reset RESET_VIU>, + <&reset RESET_VENC>, +@@ -797,6 +815,15 @@ + num-cs = <1>; + }; + ++&aiu_spdif { ++ clocks = <&clkc CLKID_IEC958>, ++ <&clkc CLKID_IEC958_GATE>, ++ <&clkc CLKID_CTS_MCLK_I958>, ++ <&clkc CLKID_CTS_AMCLK>, ++ <&clkc CLKID_CTS_I958>; ++ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk"; ++}; ++ + &spifc { + clocks = <&clkc CLKID_SPI>; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index 1d105047661ed..e30633e7824bc 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -712,6 +712,24 @@ + }; + }; + ++&audio { ++ clocks = <&clkc CLKID_AIU>, ++ <&clkc CLKID_AIU_GLUE>, ++ <&clkc CLKID_I2S_SPDIF>; ++ clock-names = "aiu_top", "aiu_glue", "audin"; ++ resets = <&reset RESET_AIU>, ++ <&reset RESET_AUDIN>; ++ reset-names = "aiu", "audin"; ++}; ++ ++&aiu_i2s { ++ clocks = <&clkc CLKID_I2S_OUT>, ++ <&clkc CLKID_MIXER_IFACE>, ++ <&clkc CLKID_AOCLK_GATE>, ++ <&clkc CLKID_CTS_AMCLK>; ++ clock-names = "fast", "iface", "bclks", "mclk"; ++}; ++ + &pwrc_vpu { + resets = <&reset RESET_VIU>, + <&reset RESET_VENC>, +@@ -800,6 +818,15 @@ + num-cs = <1>; + }; + ++&aiu_spdif { ++ clocks = <&clkc CLKID_IEC958>, ++ <&clkc CLKID_IEC958_GATE>, ++ <&clkc CLKID_CTS_MCLK_I958>, ++ <&clkc CLKID_CTS_AMCLK>, ++ <&clkc CLKID_CTS_I958>; ++ clock-names = "fast", "iface", "mclk_i958", "mclk_i2s", "mclk"; ++}; ++ + &spifc { + clocks = <&clkc CLKID_SPI>; + }; + +From 671225a756b59a2f8840744ba0ac876e8894daed Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Fri, 7 Jul 2017 17:39:21 +0200 +Subject: [PATCH 234/249] snd: meson: activate HDMI audio path + +Signed-off-by: Jerome Brunet +--- + sound/soc/meson-gx/aiu-i2s.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c +index 63d7821c2c72d..c6bfd5d8c8081 100644 +--- a/sound/soc/meson-gx/aiu-i2s.c ++++ b/sound/soc/meson-gx/aiu-i2s.c +@@ -334,8 +334,19 @@ static int meson_aiu_i2s_dma_new(struct snd_soc_pcm_runtime *rtd) + #define AIU_CLK_CTRL_ALRCLK_RIGHT_J (2 << 8) + #define AIU_CLK_CTRL_MORE_I2S_DIV_MASK GENMASK(5, 0) + #define AIU_CLK_CTRL_MORE_I2S_DIV(div) (((div) - 1) << 0) ++#define AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK BIT(6) ++#define AIU_CLK_CTRL_MORE_HDMI_TX_I958_CLK (0 << 6) ++#define AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK (1 << 6) + #define AIU_CODEC_DAC_LRCLK_CTRL_DIV_MASK GENMASK(11, 0) + #define AIU_CODEC_DAC_LRCLK_CTRL_DIV(div) (((div) - 1) << 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK GENMASK(1, 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_DISABLE (0 << 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_PCM (1 << 0) ++#define AIU_HDMI_CLK_DATA_CTRL_CLK_I2S (2 << 0) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK GENMASK(5, 4) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_MUTE (0 << 4) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_PCM (1 << 4) ++#define AIU_HDMI_CLK_DATA_CTRL_DATA_I2S (2 << 4) + #define AIU_I2S_DAC_CFG_PAYLOAD_SIZE_MASK GENMASK(1, 0) + #define AIU_I2S_DAC_CFG_AOCLK_32 (0 << 0) + #define AIU_I2S_DAC_CFG_AOCLK_48 (2 << 0) +@@ -499,6 +510,17 @@ static int meson_aiu_i2s_dai_hw_params(struct snd_pcm_substream *substream, + return ret; + } + ++ /* Quick and dirty hack for HDMI */ ++ regmap_update_bits(priv->core->aiu, AIU_HDMI_CLK_DATA_CTRL, ++ AIU_HDMI_CLK_DATA_CTRL_CLK_SEL_MASK | ++ AIU_HDMI_CLK_DATA_CTRL_DATA_SEL_MASK, ++ AIU_HDMI_CLK_DATA_CTRL_CLK_I2S | ++ AIU_HDMI_CLK_DATA_CTRL_DATA_I2S); ++ ++ regmap_update_bits(priv->core->aiu, AIU_CLK_CTRL_MORE, ++ AIU_CLK_CTRL_MORE_HDMI_TX_SEL_MASK, ++ AIU_CLK_CTRL_MORE_HDMI_TX_INT_CLK); ++ + return 0; + } + + +From 2dadbc74cbfd814b3fb2c4ae5b189ba816975724 Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Wed, 20 Sep 2017 18:01:26 +0200 +Subject: [PATCH 235/249] ARM64: dts: meson-gx: add sound-dai-cells to HDMI + node + +Signed-off-by: Jerome Brunet +--- + arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 1 + + arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +index 277beb6e4f0b2..586f1a934b1a4 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi +@@ -330,6 +330,7 @@ + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; ++ #sound-dai-cells = <0>; + }; + + &sysctrl { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +index e30633e7824bc..54fd6af965eed 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi +@@ -280,6 +280,7 @@ + <&clkc CLKID_CLK81>, + <&clkc CLKID_GCLK_VENCI_INT0>; + clock-names = "isfr", "iahb", "venci"; ++ #sound-dai-cells = <0>; + }; + + &sysctrl { + +From d16b7150d1e7f6018ee4779d2caced3effc1163f Mon Sep 17 00:00:00 2001 +From: Jerome Brunet +Date: Wed, 20 Sep 2017 18:10:08 +0200 +Subject: [PATCH 236/249] ARM64: dts: meson: activate hdmi audio HDMI enabled + boards + +This patch activate audio over HDMI on selected boards + +Please note that this audio support is based on WIP changes +This should be considered as preview and it does not reflect +the audio I expect to see merged + +Signed-off-by: Jerome Brunet +Signed-off-by: Neil Armstrong +--- + .../boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxbb-nanopi-k2.dts | 37 +++++++++++++++++++ + .../dts/amlogic/meson-gxbb-nexbox-a95x.dts | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxbb-odroidc2.dts | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxbb-p20x.dtsi | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxbb-wetek.dtsi | 37 +++++++++++++++++++ + .../amlogic/meson-gxl-s905x-khadas-vim.dts | 37 +++++++++++++++++++ + .../amlogic/meson-gxl-s905x-libretech-cc.dts | 37 +++++++++++++++++++ + .../amlogic/meson-gxl-s905x-nexbox-a95x.dts | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxl-s905x-p212.dts | 37 +++++++++++++++++++ + .../dts/amlogic/meson-gxm-khadas-vim2.dts | 37 +++++++++++++++++++ + .../boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 37 +++++++++++++++++++ + 12 files changed, 444 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +index 016641a41694a..398830b839bf1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi +@@ -102,6 +102,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -111,6 +140,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts +index ade2ee09ae962..d67ff037a25cf 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nanopi-k2.dts +@@ -88,6 +88,35 @@ + clock-names = "ext_clock"; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + vcc1v8: regulator-vcc1v8 { + compatible = "regulator-fixed"; + regulator-name = "VCC1.8V"; +@@ -131,6 +160,14 @@ + }; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cec_AO { + status = "okay"; + pinctrl-0 = <&ao_cec_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts +index 25105ac96d559..6b01f7bb02c7e 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts +@@ -119,6 +119,35 @@ + clock-names = "ext_clock"; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + cvbs-connector { + compatible = "composite-video-connector"; + +@@ -154,6 +183,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + ðmac { + status = "okay"; + pinctrl-0 = <ð_rmii_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +index 1cc9dc68ef00b..c3740edafdac4 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +@@ -110,6 +110,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -119,6 +148,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + ðmac { + status = "okay"; + pinctrl-0 = <ð_rgmii_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi +index 0be0f2a5d2fe9..4a5db4380fe21 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi +@@ -113,6 +113,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -122,6 +151,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +index 2d2db783c44c1..60ab0336d4cd7 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +@@ -105,6 +105,43 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++}; ++ ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; + }; + + &cec_AO { +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +index 5499e8de5c74c..bf3453f549dc1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +@@ -65,6 +65,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -74,6 +103,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &hdmi_tx { + status = "okay"; + pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +index 255cede7b4476..79b09f637ccfb 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-libretech-cc.dts +@@ -84,6 +84,35 @@ + regulator-always-on; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + vcc_3v3: regulator-vcc_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC_3V3"; +@@ -130,6 +159,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts +index 9cbdb85fb5917..7a5abee9e9096 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts +@@ -102,6 +102,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -111,6 +140,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts +index 2602940c2077b..78c3060c5d567 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-p212.dts +@@ -32,6 +32,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -41,6 +70,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +index 3f086ed7de055..df101709d90c9 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +@@ -85,6 +85,35 @@ + }; + }; + ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + pwmleds { + compatible = "pwm-leds"; + +@@ -201,6 +230,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cpu0 { + #cooling-cells = <2>; + }; +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +index 8acfd40090d2e..93a968fa5a0d3 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +@@ -75,6 +75,35 @@ + }; + }; + }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "meson-gx-audio"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <256>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; + }; + + &cec_AO { +@@ -84,6 +113,14 @@ + hdmi-phandle = <&hdmi_tx>; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ + &cvbs_vdac_port { + cvbs_vdac_out: endpoint { + remote-endpoint = <&cvbs_connector_in>; + +From 7c9306b6ccfbc218bf2d9ac076cf7e06f351cf98 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 2 Jul 2018 12:21:55 +0200 +Subject: [PATCH 237/249] drm: bridge: dw-hdmi: Use AUTO CTS setup mode when + non-AHB audio + +Signed-off-by: Neil Armstrong +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 41 ++++++++++++++--------- + 1 file changed, 26 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index c68b6ed1bb35e..e4948dbcaa841 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -437,8 +437,12 @@ static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts, + /* nshift factor = 0 */ + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); + +- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | +- HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); ++ /* Use Auto CTS mode with CTS is unknown */ ++ if (cts) ++ hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | ++ HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); ++ else ++ hdmi_writeb(hdmi, 0, HDMI_AUD_CTS3); + hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); + hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); + +@@ -508,24 +512,31 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi, + { + unsigned long ftdms = pixel_clk; + unsigned int n, cts; ++ u8 config3; + u64 tmp; + + n = hdmi_compute_n(sample_rate, pixel_clk); + +- /* +- * Compute the CTS value from the N value. Note that CTS and N +- * can be up to 20 bits in total, so we need 64-bit math. Also +- * note that our TDMS clock is not fully accurate; it is accurate +- * to kHz. This can introduce an unnecessary remainder in the +- * calculation below, so we don't try to warn about that. +- */ +- tmp = (u64)ftdms * n; +- do_div(tmp, 128 * sample_rate); +- cts = tmp; ++ config3 = hdmi_readb(hdmi, HDMI_CONFIG3_ID); + +- dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", +- __func__, sample_rate, ftdms / 1000000, (ftdms / 1000) % 1000, +- n, cts); ++ if (config3 & HDMI_CONFIG3_AHBAUDDMA) { ++ /* ++ * Compute the CTS value from the N value. Note that CTS and N ++ * can be up to 20 bits in total, so we need 64-bit math. Also ++ * note that our TDMS clock is not fully accurate; it is ++ * accurate to kHz. This can introduce an unnecessary remainder ++ * in the calculation below, so we don't try to warn about that. ++ */ ++ tmp = (u64)ftdms * n; ++ do_div(tmp, 128 * sample_rate); ++ cts = tmp; ++ ++ dev_dbg(hdmi->dev, "%s: fs=%uHz ftdms=%lu.%03luMHz N=%d cts=%d\n", ++ __func__, sample_rate, ++ ftdms / 1000000, (ftdms / 1000) % 1000, ++ n, cts); ++ } else ++ cts = 0; + + spin_lock_irq(&hdmi->audio_lock); + hdmi->audio_n = n; + +From 7fe6319492989af793de178ecb44718186e232b7 Mon Sep 17 00:00:00 2001 +From: Qiang Yu +Date: Mon, 25 Feb 2019 22:07:16 +0800 +Subject: [PATCH 238/249] drm: export drm_timeout_abs_to_jiffies + +For other driver like lima usage. + +Cc: Rob Herring +Signed-off-by: Qiang Yu +Signed-off-by: Rob Herring +Link: https://patchwork.freedesktop.org/patch/msgid/20190225140717.20586-2-yuq825@gmail.com +(cherry picked from commit 877b372996bfd4f195d363d22de89571c9faab38) +--- + drivers/gpu/drm/drm_syncobj.c | 3 ++- + include/drm/drm_utils.h | 4 ++++ + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c +index e19525af0ccee..5329e66598c63 100644 +--- a/drivers/gpu/drm/drm_syncobj.c ++++ b/drivers/gpu/drm/drm_syncobj.c +@@ -731,7 +731,7 @@ static signed long drm_syncobj_array_wait_timeout(struct drm_syncobj **syncobjs, + * + * Calculate the timeout in jiffies from an absolute time in sec/nsec. + */ +-static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec) ++signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec) + { + ktime_t abs_timeout, now; + u64 timeout_ns, timeout_jiffies64; +@@ -755,6 +755,7 @@ static signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec) + + return timeout_jiffies64 + 1; + } ++EXPORT_SYMBOL(drm_timeout_abs_to_jiffies); + + static int drm_syncobj_array_wait(struct drm_device *dev, + struct drm_file *file_private, +diff --git a/include/drm/drm_utils.h b/include/drm/drm_utils.h +index a803988d85792..70775748d243b 100644 +--- a/include/drm/drm_utils.h ++++ b/include/drm/drm_utils.h +@@ -10,6 +10,10 @@ + #ifndef __DRM_UTILS_H__ + #define __DRM_UTILS_H__ + ++#include ++ + int drm_get_panel_orientation_quirk(int width, int height); + ++signed long drm_timeout_abs_to_jiffies(int64_t timeout_nsec); ++ + #endif + +From d95904cfc1605336b6454acab8df4e932bdfc3df Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= +Date: Tue, 27 Nov 2018 12:38:20 -0800 +Subject: [PATCH 239/249] drm: Add library for shmem backed GEM objects +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This adds a library for shmem backed GEM objects. + +v8: +- export drm_gem_shmem_create_with_handle +- call mapping_set_gfp_mask to set default zone to GFP_HIGHUSER +- Add helper drm_gem_shmem_get_pages_sgt() + +v7: +- Use write-combine for mmap instead. This is the more common + case. (robher) + +v6: +- Fix uninitialized variable issue in an error path (anholt). +- Add a drm_gem_shmem_vm_open() to the fops to get proper refcounting + of the pages (anholt). + +v5: +- Drop drm_gem_shmem_prime_mmap() (Daniel Vetter) +- drm_gem_shmem_mmap(): Subtract drm_vma_node_start() to get the real + vma->vm_pgoff +- drm_gem_shmem_fault(): Use vmf->pgoff now that vma->vm_pgoff is correct + +v4: +- Drop cache modes (Thomas Hellstrom) +- Add a GEM attached vtable + +v3: +- Grammar (Sam Ravnborg) +- s/drm_gem_shmem_put_pages_unlocked/drm_gem_shmem_put_pages_locked/ + (Sam Ravnborg) +- Add debug output in error path (Sam Ravnborg) + +Signed-off-by: Noralf Trønnes +Signed-off-by: Eric Anholt +Signed-off-by: Rob Herring + +shmem: set mapping zone + +Signed-off-by: Rob Herring + +shmem fixes + +(cherry picked from commit 403e85012e9ee0a2a113bec757f545df193cfb7a) +--- + Documentation/gpu/drm-kms-helpers.rst | 12 + + drivers/gpu/drm/Kconfig | 6 + + drivers/gpu/drm/Makefile | 1 + + drivers/gpu/drm/drm_gem_shmem_helper.c | 625 +++++++++++++++++++++++++ + include/drm/drm_gem_shmem_helper.h | 159 +++++++ + 5 files changed, 803 insertions(+) + create mode 100644 drivers/gpu/drm/drm_gem_shmem_helper.c + create mode 100644 include/drm/drm_gem_shmem_helper.h + +diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst +index 17ca7f8bf3d3c..58b375e47615b 100644 +--- a/Documentation/gpu/drm-kms-helpers.rst ++++ b/Documentation/gpu/drm-kms-helpers.rst +@@ -369,3 +369,15 @@ Legacy CRTC/Modeset Helper Functions Reference + + .. kernel-doc:: drivers/gpu/drm/drm_crtc_helper.c + :export: ++ ++SHMEM GEM Helper Reference ++========================== ++ ++.. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c ++ :doc: overview ++ ++.. kernel-doc:: include/drm/drm_gem_shmem_helper.h ++ :internal: ++ ++.. kernel-doc:: drivers/gpu/drm/drm_gem_shmem_helper.c ++ :export: +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index bd943a71756ca..febdc102b75c2 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -173,6 +173,12 @@ config DRM_KMS_CMA_HELPER + help + Choose this if you need the KMS CMA helper functions + ++config DRM_GEM_SHMEM_HELPER ++ bool ++ depends on DRM ++ help ++ Choose this if you need the GEM shmem helper functions ++ + config DRM_VM + bool + depends on DRM && MMU +diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile +index 1ac55c65eac0d..7476ed945e303 100644 +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -25,6 +25,7 @@ drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o + drm-$(CONFIG_DRM_VM) += drm_vm.o + drm-$(CONFIG_COMPAT) += drm_ioc32.o + drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o ++drm-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_gem_shmem_helper.o + drm-$(CONFIG_PCI) += ati_pcigart.o + drm-$(CONFIG_DRM_PANEL) += drm_panel.o + drm-$(CONFIG_OF) += drm_of.o +diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c +new file mode 100644 +index 0000000000000..3750a982aaf6b +--- /dev/null ++++ b/drivers/gpu/drm/drm_gem_shmem_helper.c +@@ -0,0 +1,625 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright 2018 Noralf Trønnes ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * DOC: overview ++ * ++ * This library provides helpers for GEM objects backed by shmem buffers ++ * allocated using anonymous pageable memory. ++ */ ++ ++static const struct drm_gem_object_funcs drm_gem_shmem_funcs = { ++ .free = drm_gem_shmem_free_object, ++ .print_info = drm_gem_shmem_print_info, ++ .pin = drm_gem_shmem_pin, ++ .unpin = drm_gem_shmem_unpin, ++ .get_sg_table = drm_gem_shmem_get_sg_table, ++ .vmap = drm_gem_shmem_vmap, ++ .vunmap = drm_gem_shmem_vunmap, ++ .vm_ops = &drm_gem_shmem_vm_ops, ++}; ++ ++/** ++ * drm_gem_shmem_create - Allocate an object with the given size ++ * @dev: DRM device ++ * @size: Size of the object to allocate ++ * ++ * This function creates a shmem GEM object. ++ * ++ * Returns: ++ * A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative ++ * error code on failure. ++ */ ++struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size) ++{ ++ struct drm_gem_shmem_object *shmem; ++ struct drm_gem_object *obj; ++ int ret; ++ ++ size = PAGE_ALIGN(size); ++ ++ if (dev->driver->gem_create_object) ++ obj = dev->driver->gem_create_object(dev, size); ++ else ++ obj = kzalloc(sizeof(*shmem), GFP_KERNEL); ++ if (!obj) ++ return ERR_PTR(-ENOMEM); ++ ++ if (!obj->funcs) ++ obj->funcs = &drm_gem_shmem_funcs; ++ ++ ret = drm_gem_object_init(dev, obj, size); ++ if (ret) ++ goto err_free; ++ ++ ret = drm_gem_create_mmap_offset(obj); ++ if (ret) ++ goto err_release; ++ ++ shmem = to_drm_gem_shmem_obj(obj); ++ mutex_init(&shmem->pages_lock); ++ mutex_init(&shmem->vmap_lock); ++ ++ /* ++ * Our buffers are kept pinned, so allocating them ++ * from the MOVABLE zone is a really bad idea, and ++ * conflicts with CMA. See comments above new_inode() ++ * why this is required _and_ expected if you're ++ * going to pin these pages. ++ */ ++ mapping_set_gfp_mask(obj->filp->f_mapping, GFP_HIGHUSER | ++ __GFP_RETRY_MAYFAIL | __GFP_NOWARN); ++ ++ return shmem; ++ ++err_release: ++ drm_gem_object_release(obj); ++err_free: ++ kfree(obj); ++ ++ return ERR_PTR(ret); ++} ++EXPORT_SYMBOL_GPL(drm_gem_shmem_create); ++ ++/** ++ * drm_gem_shmem_free_object - Free resources associated with a shmem GEM object ++ * @obj: GEM object to free ++ * ++ * This function cleans up the GEM object state and frees the memory used to ++ * store the object itself. ++ */ ++void drm_gem_shmem_free_object(struct drm_gem_object *obj) ++{ ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ ++ WARN_ON(shmem->vmap_use_count); ++ ++ if (obj->import_attach) { ++ shmem->pages_use_count--; ++ drm_prime_gem_destroy(obj, shmem->sgt); ++ kvfree(shmem->pages); ++ } else { ++ if (shmem->sgt) { ++ dma_unmap_sg(obj->dev->dev, shmem->sgt->sgl, ++ shmem->sgt->nents, DMA_BIDIRECTIONAL); ++ ++ drm_gem_shmem_put_pages(shmem); ++ sg_free_table(shmem->sgt); ++ kfree(shmem->sgt); ++ } ++ } ++ ++ WARN_ON(shmem->pages_use_count); ++ ++ drm_gem_object_release(obj); ++ mutex_destroy(&shmem->pages_lock); ++ mutex_destroy(&shmem->vmap_lock); ++ kfree(shmem); ++} ++EXPORT_SYMBOL_GPL(drm_gem_shmem_free_object); ++ ++static int drm_gem_shmem_get_pages_locked(struct drm_gem_shmem_object *shmem) ++{ ++ struct drm_gem_object *obj = &shmem->base; ++ struct page **pages; ++ ++ if (shmem->pages_use_count++ > 0) ++ return 0; ++ ++ pages = drm_gem_get_pages(obj); ++ if (IS_ERR(pages)) { ++ DRM_DEBUG_KMS("Failed to get pages (%ld)\n", PTR_ERR(pages)); ++ shmem->pages_use_count = 0; ++ return PTR_ERR(pages); ++ } ++ ++ shmem->pages = pages; ++ ++ return 0; ++} ++ ++/* ++ * drm_gem_shmem_get_pages - Allocate backing pages for a shmem GEM object ++ * @shmem: shmem GEM object ++ * ++ * This function makes sure that backing pages exists for the shmem GEM object ++ * and increases the use count. ++ * ++ * Returns: ++ * 0 on success or a negative error code on failure. ++ */ ++int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem) ++{ ++ int ret; ++ ++ ret = mutex_lock_interruptible(&shmem->pages_lock); ++ if (ret) ++ return ret; ++ ret = drm_gem_shmem_get_pages_locked(shmem); ++ mutex_unlock(&shmem->pages_lock); ++ ++ return ret; ++} ++EXPORT_SYMBOL(drm_gem_shmem_get_pages); ++ ++static void drm_gem_shmem_put_pages_locked(struct drm_gem_shmem_object *shmem) ++{ ++ struct drm_gem_object *obj = &shmem->base; ++ ++ if (WARN_ON_ONCE(!shmem->pages_use_count)) ++ return; ++ ++ if (--shmem->pages_use_count > 0) ++ return; ++ ++ drm_gem_put_pages(obj, shmem->pages, ++ shmem->pages_mark_dirty_on_put, ++ shmem->pages_mark_accessed_on_put); ++ shmem->pages = NULL; ++} ++ ++/* ++ * drm_gem_shmem_put_pages - Decrease use count on the backing pages for a shmem GEM object ++ * @shmem: shmem GEM object ++ * ++ * This function decreases the use count and puts the backing pages when use drops to zero. ++ */ ++void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem) ++{ ++ mutex_lock(&shmem->pages_lock); ++ drm_gem_shmem_put_pages_locked(shmem); ++ mutex_unlock(&shmem->pages_lock); ++} ++EXPORT_SYMBOL(drm_gem_shmem_put_pages); ++ ++/** ++ * drm_gem_shmem_pin - Pin backing pages for a shmem GEM object ++ * @obj: GEM object ++ * ++ * This function makes sure the backing pages are pinned in memory while the ++ * buffer is exported. ++ * ++ * Returns: ++ * 0 on success or a negative error code on failure. ++ */ ++int drm_gem_shmem_pin(struct drm_gem_object *obj) ++{ ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ ++ return drm_gem_shmem_get_pages(shmem); ++} ++EXPORT_SYMBOL(drm_gem_shmem_pin); ++ ++/** ++ * drm_gem_shmem_unpin - Unpin backing pages for a shmem GEM object ++ * @obj: GEM object ++ * ++ * This function removes the requirement that the backing pages are pinned in ++ * memory. ++ */ ++void drm_gem_shmem_unpin(struct drm_gem_object *obj) ++{ ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ ++ drm_gem_shmem_put_pages(shmem); ++} ++EXPORT_SYMBOL(drm_gem_shmem_unpin); ++ ++static void *drm_gem_shmem_vmap_locked(struct drm_gem_shmem_object *shmem) ++{ ++ struct drm_gem_object *obj = &shmem->base; ++ int ret; ++ ++ if (shmem->vmap_use_count++ > 0) ++ return shmem->vaddr; ++ ++ ret = drm_gem_shmem_get_pages(shmem); ++ if (ret) ++ goto err_zero_use; ++ ++ if (obj->import_attach) ++ shmem->vaddr = dma_buf_vmap(obj->import_attach->dmabuf); ++ else ++ shmem->vaddr = vmap(shmem->pages, obj->size >> PAGE_SHIFT, VM_MAP, PAGE_KERNEL); ++ ++ if (!shmem->vaddr) { ++ DRM_DEBUG_KMS("Failed to vmap pages\n"); ++ ret = -ENOMEM; ++ goto err_put_pages; ++ } ++ ++ return shmem->vaddr; ++ ++err_put_pages: ++ drm_gem_shmem_put_pages(shmem); ++err_zero_use: ++ shmem->vmap_use_count = 0; ++ ++ return ERR_PTR(ret); ++} ++ ++/* ++ * drm_gem_shmem_vmap - Create a virtual mapping for a shmem GEM object ++ * @shmem: shmem GEM object ++ * ++ * This function makes sure that a virtual address exists for the buffer backing ++ * the shmem GEM object. ++ * ++ * Returns: ++ * 0 on success or a negative error code on failure. ++ */ ++void *drm_gem_shmem_vmap(struct drm_gem_object *obj) ++{ ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ void *vaddr; ++ int ret; ++ ++ ret = mutex_lock_interruptible(&shmem->vmap_lock); ++ if (ret) ++ return ERR_PTR(ret); ++ vaddr = drm_gem_shmem_vmap_locked(shmem); ++ mutex_unlock(&shmem->vmap_lock); ++ ++ return vaddr; ++} ++EXPORT_SYMBOL(drm_gem_shmem_vmap); ++ ++static void drm_gem_shmem_vunmap_locked(struct drm_gem_shmem_object *shmem) ++{ ++ struct drm_gem_object *obj = &shmem->base; ++ ++ if (WARN_ON_ONCE(!shmem->vmap_use_count)) ++ return; ++ ++ if (--shmem->vmap_use_count > 0) ++ return; ++ ++ if (obj->import_attach) ++ dma_buf_vunmap(obj->import_attach->dmabuf, shmem->vaddr); ++ else ++ vunmap(shmem->vaddr); ++ ++ shmem->vaddr = NULL; ++ drm_gem_shmem_put_pages(shmem); ++} ++ ++/* ++ * drm_gem_shmem_vunmap - Unmap a virtual mapping fo a shmem GEM object ++ * @shmem: shmem GEM object ++ * ++ * This function removes the virtual address when use count drops to zero. ++ */ ++void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr) ++{ ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ ++ mutex_lock(&shmem->vmap_lock); ++ drm_gem_shmem_vunmap_locked(shmem); ++ mutex_unlock(&shmem->vmap_lock); ++} ++EXPORT_SYMBOL(drm_gem_shmem_vunmap); ++ ++struct drm_gem_shmem_object * ++drm_gem_shmem_create_with_handle(struct drm_file *file_priv, ++ struct drm_device *dev, size_t size, ++ uint32_t *handle) ++{ ++ struct drm_gem_shmem_object *shmem; ++ int ret; ++ ++ shmem = drm_gem_shmem_create(dev, size); ++ if (IS_ERR(shmem)) ++ return shmem; ++ ++ /* ++ * Allocate an id of idr table where the obj is registered ++ * and handle has the id what user can see. ++ */ ++ ret = drm_gem_handle_create(file_priv, &shmem->base, handle); ++ /* drop reference from allocate - handle holds it now. */ ++ drm_gem_object_put_unlocked(&shmem->base); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ return shmem; ++} ++EXPORT_SYMBOL(drm_gem_shmem_create_with_handle); ++ ++/** ++ * drm_gem_shmem_dumb_create - Create a dumb shmem buffer object ++ * @file: DRM file structure to create the dumb buffer for ++ * @dev: DRM device ++ * @args: IOCTL data ++ * ++ * This function computes the pitch of the dumb buffer and rounds it up to an ++ * integer number of bytes per pixel. Drivers for hardware that doesn't have ++ * any additional restrictions on the pitch can directly use this function as ++ * their &drm_driver.dumb_create callback. ++ * ++ * For hardware with additional restrictions, drivers can adjust the fields ++ * set up by userspace before calling into this function. ++ * ++ * Returns: ++ * 0 on success or a negative error code on failure. ++ */ ++int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, ++ struct drm_mode_create_dumb *args) ++{ ++ u32 min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); ++ struct drm_gem_shmem_object *shmem; ++ ++ if (!args->pitch || !args->size) { ++ args->pitch = min_pitch; ++ args->size = args->pitch * args->height; ++ } else { ++ /* ensure sane minimum values */ ++ if (args->pitch < min_pitch) ++ args->pitch = min_pitch; ++ if (args->size < args->pitch * args->height) ++ args->size = args->pitch * args->height; ++ } ++ ++ shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, &args->handle); ++ ++ return PTR_ERR_OR_ZERO(shmem); ++} ++EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); ++ ++static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) ++{ ++ struct vm_area_struct *vma = vmf->vma; ++ struct drm_gem_object *obj = vma->vm_private_data; ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ loff_t num_pages = obj->size >> PAGE_SHIFT; ++ struct page *page; ++ ++ if (vmf->pgoff > num_pages || WARN_ON_ONCE(!shmem->pages)) ++ return VM_FAULT_SIGBUS; ++ ++ page = shmem->pages[vmf->pgoff]; ++ ++ return vmf_insert_page(vma, vmf->address, page); ++} ++ ++static void drm_gem_shmem_vm_open(struct vm_area_struct *vma) ++{ ++ struct drm_gem_object *obj = vma->vm_private_data; ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ int ret; ++ ++ ret = drm_gem_shmem_get_pages(shmem); ++ WARN_ON_ONCE(ret != 0); ++ ++ drm_gem_vm_open(vma); ++} ++ ++static void drm_gem_shmem_vm_close(struct vm_area_struct *vma) ++{ ++ struct drm_gem_object *obj = vma->vm_private_data; ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ ++ drm_gem_shmem_put_pages(shmem); ++ drm_gem_vm_close(vma); ++} ++ ++const struct vm_operations_struct drm_gem_shmem_vm_ops = { ++ .fault = drm_gem_shmem_fault, ++ .open = drm_gem_shmem_vm_open, ++ .close = drm_gem_shmem_vm_close, ++}; ++EXPORT_SYMBOL_GPL(drm_gem_shmem_vm_ops); ++ ++/** ++ * drm_gem_shmem_mmap - Memory-map a shmem GEM object ++ * @filp: File object ++ * @vma: VMA for the area to be mapped ++ * ++ * This function implements an augmented version of the GEM DRM file mmap ++ * operation for shmem objects. Drivers which employ the shmem helpers should ++ * use this function as their &file_operations.mmap handler in the DRM device file's ++ * file_operations structure. ++ * ++ * Instead of directly referencing this function, drivers should use the ++ * DEFINE_DRM_GEM_SHMEM_FOPS() macro. ++ * ++ * Returns: ++ * 0 on success or a negative error code on failure. ++ */ ++int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ struct drm_gem_shmem_object *shmem; ++ int ret; ++ ++ ret = drm_gem_mmap(filp, vma); ++ if (ret) ++ return ret; ++ ++ shmem = to_drm_gem_shmem_obj(vma->vm_private_data); ++ ++ ret = drm_gem_shmem_get_pages(shmem); ++ if (ret) { ++ drm_gem_vm_close(vma); ++ return ret; ++ } ++ ++ /* VM_PFNMAP was set by drm_gem_mmap() */ ++ vma->vm_flags &= ~VM_PFNMAP; ++ vma->vm_flags |= VM_MIXEDMAP; ++ ++ /* Remove the fake offset */ ++ vma->vm_pgoff -= drm_vma_node_start(&shmem->base.vma_node); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(drm_gem_shmem_mmap); ++ ++/** ++ * drm_gem_shmem_print_info() - Print &drm_gem_shmem_object info for debugfs ++ * @p: DRM printer ++ * @indent: Tab indentation level ++ * @obj: GEM object ++ */ ++void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent, ++ const struct drm_gem_object *obj) ++{ ++ const struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ ++ drm_printf_indent(p, indent, "pages_use_count=%u\n", shmem->pages_use_count); ++ drm_printf_indent(p, indent, "vmap_use_count=%u\n", shmem->vmap_use_count); ++ drm_printf_indent(p, indent, "vaddr=%p\n", shmem->vaddr); ++} ++EXPORT_SYMBOL(drm_gem_shmem_print_info); ++ ++/** ++ * drm_gem_shmem_get_sg_table - Provide a scatter/gather table of pinned ++ * pages for a shmem GEM object ++ * @obj: GEM object ++ * ++ * This function exports a scatter/gather table suitable for PRIME usage by ++ * calling the standard DMA mapping API. ++ * ++ * Returns: ++ * A pointer to the scatter/gather table of pinned pages or NULL on failure. ++ */ ++struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj) ++{ ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ ++ return drm_prime_pages_to_sg(shmem->pages, obj->size >> PAGE_SHIFT); ++} ++EXPORT_SYMBOL_GPL(drm_gem_shmem_get_sg_table); ++ ++/** ++ * drm_gem_shmem_get_pages_sgt - Pin pages, dma map them, and return a ++ * scatter/gather table for a shmem GEM object. ++ * @obj: GEM object ++ * ++ * This function returns a scatter/gather table suitable for driver usage. If ++ * the sg table doesn't exist, the pages are pinned, dma-mapped, and a sg ++ * table created. ++ * ++ * Returns: ++ * A pointer to the scatter/gather table of pinned pages or errno on failure. ++ */ ++struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_object *obj) ++{ ++ int ret; ++ struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj); ++ struct sg_table *sgt; ++ ++ if (shmem->sgt) ++ return shmem->sgt; ++ ++ WARN_ON(obj->import_attach); ++ ++ ret = drm_gem_shmem_get_pages(shmem); ++ if (ret) ++ return ERR_PTR(ret); ++ ++ sgt = drm_gem_shmem_get_sg_table(&shmem->base); ++ if (IS_ERR(sgt)) { ++ ret = PTR_ERR(sgt); ++ goto err_put_pages; ++ } ++ /* Map the pages for use by the h/w. */ ++ dma_map_sg(obj->dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL); ++ ++ shmem->sgt = sgt; ++ ++ return sgt; ++ ++err_put_pages: ++ drm_gem_shmem_put_pages(shmem); ++ return ERR_PTR(ret); ++} ++EXPORT_SYMBOL_GPL(drm_gem_shmem_get_pages_sgt); ++ ++/** ++ * drm_gem_shmem_prime_import_sg_table - Produce a shmem GEM object from ++ * another driver's scatter/gather table of pinned pages ++ * @dev: Device to import into ++ * @attach: DMA-BUF attachment ++ * @sgt: Scatter/gather table of pinned pages ++ * ++ * This function imports a scatter/gather table exported via DMA-BUF by ++ * another driver. Drivers that use the shmem helpers should set this as their ++ * &drm_driver.gem_prime_import_sg_table callback. ++ * ++ * Returns: ++ * A pointer to a newly created GEM object or an ERR_PTR-encoded negative ++ * error code on failure. ++ */ ++struct drm_gem_object * ++drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, ++ struct dma_buf_attachment *attach, ++ struct sg_table *sgt) ++{ ++ size_t size = PAGE_ALIGN(attach->dmabuf->size); ++ size_t npages = size >> PAGE_SHIFT; ++ struct drm_gem_shmem_object *shmem; ++ int ret; ++ ++ shmem = drm_gem_shmem_create(dev, size); ++ if (IS_ERR(shmem)) ++ return ERR_CAST(shmem); ++ ++ shmem->pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); ++ if (!shmem->pages) { ++ ret = -ENOMEM; ++ goto err_free_gem; ++ } ++ ++ ret = drm_prime_sg_to_page_addr_arrays(sgt, shmem->pages, NULL, npages); ++ if (ret < 0) ++ goto err_free_array; ++ ++ shmem->sgt = sgt; ++ shmem->pages_use_count = 1; /* Permanently pinned from our point of view */ ++ ++ DRM_DEBUG_PRIME("size = %zu\n", size); ++ ++ return &shmem->base; ++ ++err_free_array: ++ kvfree(shmem->pages); ++err_free_gem: ++ drm_gem_object_put_unlocked(&shmem->base); ++ ++ return ERR_PTR(ret); ++} ++EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_sg_table); +diff --git a/include/drm/drm_gem_shmem_helper.h b/include/drm/drm_gem_shmem_helper.h +new file mode 100644 +index 0000000000000..038b6d3134471 +--- /dev/null ++++ b/include/drm/drm_gem_shmem_helper.h +@@ -0,0 +1,159 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef __DRM_GEM_SHMEM_HELPER_H__ ++#define __DRM_GEM_SHMEM_HELPER_H__ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++struct dma_buf_attachment; ++struct drm_mode_create_dumb; ++struct drm_printer; ++struct sg_table; ++ ++/** ++ * struct drm_gem_shmem_object - GEM object backed by shmem ++ */ ++struct drm_gem_shmem_object { ++ /** ++ * @base: Base GEM object ++ */ ++ struct drm_gem_object base; ++ ++ /** ++ * @pages_lock: Protects the page table and use count ++ */ ++ struct mutex pages_lock; ++ ++ /** ++ * @pages: Page table ++ */ ++ struct page **pages; ++ ++ /** ++ * @pages_use_count: ++ * ++ * Reference count on the pages table. ++ * The pages are put when the count reaches zero. ++ */ ++ unsigned int pages_use_count; ++ ++ /** ++ * @pages_mark_dirty_on_put: ++ * ++ * Mark pages as dirty when they are put. ++ */ ++ unsigned int pages_mark_dirty_on_put : 1; ++ ++ /** ++ * @pages_mark_accessed_on_put: ++ * ++ * Mark pages as accessed when they are put. ++ */ ++ unsigned int pages_mark_accessed_on_put : 1; ++ ++ /** ++ * @sgt: Scatter/gather table for imported PRIME buffers ++ */ ++ struct sg_table *sgt; ++ ++ /** ++ * @vmap_lock: Protects the vmap address and use count ++ */ ++ struct mutex vmap_lock; ++ ++ /** ++ * @vaddr: Kernel virtual address of the backing memory ++ */ ++ void *vaddr; ++ ++ /** ++ * @vmap_use_count: ++ * ++ * Reference count on the virtual address. ++ * The address are un-mapped when the count reaches zero. ++ */ ++ unsigned int vmap_use_count; ++}; ++ ++#define to_drm_gem_shmem_obj(obj) \ ++ container_of(obj, struct drm_gem_shmem_object, base) ++ ++/** ++ * DEFINE_DRM_GEM_SHMEM_FOPS() - Macro to generate file operations for shmem drivers ++ * @name: name for the generated structure ++ * ++ * This macro autogenerates a suitable &struct file_operations for shmem based ++ * drivers, which can be assigned to &drm_driver.fops. Note that this structure ++ * cannot be shared between drivers, because it contains a reference to the ++ * current module using THIS_MODULE. ++ * ++ * Note that the declaration is already marked as static - if you need a ++ * non-static version of this you're probably doing it wrong and will break the ++ * THIS_MODULE reference by accident. ++ */ ++#define DEFINE_DRM_GEM_SHMEM_FOPS(name) \ ++ static const struct file_operations name = {\ ++ .owner = THIS_MODULE,\ ++ .open = drm_open,\ ++ .release = drm_release,\ ++ .unlocked_ioctl = drm_ioctl,\ ++ .compat_ioctl = drm_compat_ioctl,\ ++ .poll = drm_poll,\ ++ .read = drm_read,\ ++ .llseek = noop_llseek,\ ++ .mmap = drm_gem_shmem_mmap, \ ++ } ++ ++struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size); ++void drm_gem_shmem_free_object(struct drm_gem_object *obj); ++ ++int drm_gem_shmem_get_pages(struct drm_gem_shmem_object *shmem); ++void drm_gem_shmem_put_pages(struct drm_gem_shmem_object *shmem); ++int drm_gem_shmem_pin(struct drm_gem_object *obj); ++void drm_gem_shmem_unpin(struct drm_gem_object *obj); ++void *drm_gem_shmem_vmap(struct drm_gem_object *obj); ++void drm_gem_shmem_vunmap(struct drm_gem_object *obj, void *vaddr); ++ ++struct drm_gem_shmem_object * ++drm_gem_shmem_create_with_handle(struct drm_file *file_priv, ++ struct drm_device *dev, size_t size, ++ uint32_t *handle); ++int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, ++ struct drm_mode_create_dumb *args); ++ ++int drm_gem_shmem_mmap(struct file *filp, struct vm_area_struct *vma); ++ ++extern const struct vm_operations_struct drm_gem_shmem_vm_ops; ++ ++void drm_gem_shmem_print_info(struct drm_printer *p, unsigned int indent, ++ const struct drm_gem_object *obj); ++ ++struct sg_table *drm_gem_shmem_get_sg_table(struct drm_gem_object *obj); ++struct drm_gem_object * ++drm_gem_shmem_prime_import_sg_table(struct drm_device *dev, ++ struct dma_buf_attachment *attach, ++ struct sg_table *sgt); ++ ++struct sg_table *drm_gem_shmem_get_pages_sgt(struct drm_gem_object *obj); ++ ++/** ++ * DRM_GEM_SHMEM_DRIVER_OPS - Default shmem GEM operations ++ * ++ * This macro provides a shortcut for setting the shmem GEM operations in ++ * the &drm_driver structure. ++ */ ++#define DRM_GEM_SHMEM_DRIVER_OPS \ ++ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, \ ++ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, \ ++ .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, \ ++ .gem_prime_mmap = drm_gem_prime_mmap, \ ++ .dumb_create = drm_gem_shmem_dumb_create ++ ++#endif /* __DRM_GEM_SHMEM_HELPER_H__ */ + +From de612cb421aeed0335762c01e2c344ee6323504b Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Sat, 2 Feb 2019 09:41:54 -0600 +Subject: [PATCH 240/249] drm: Add reservation_object to drm_gem_object + +Many users of drm_gem_object embed a struct reservation_object into +their subclassed struct, so let's add one to struct drm_gem_object. +This will allow removing the reservation object from the subclasses +and removing the ->gem_prime_res_obj callback. + +With the addition, add a drm_gem_reservation_object_wait() helper +function for drivers to use in wait ioctls. + +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Sean Paul +Cc: David Airlie +Cc: Daniel Vetter +Signed-off-by: Rob Herring +Acked-by: Daniel Vetter +Reviewed-by: Eric Anholt +Reviewed-by: Christian Gmeiner +Link: https://patchwork.freedesktop.org/patch/msgid/20190202154158.10443-2-robh@kernel.org +Signed-off-by: Maxime Ripard +(cherry picked from commit 1ba627148ef5d9dee879585687c4b0ee644f7ab5) +--- + Documentation/gpu/todo.rst | 8 +++---- + drivers/gpu/drm/drm_gem.c | 43 +++++++++++++++++++++++++++++++++++++ + drivers/gpu/drm/drm_prime.c | 1 + + include/drm/drm_gem.h | 21 ++++++++++++++++++ + 4 files changed, 69 insertions(+), 4 deletions(-) + +diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst +index 159a4aba49e6e..4afbc186f119c 100644 +--- a/Documentation/gpu/todo.rst ++++ b/Documentation/gpu/todo.rst +@@ -215,12 +215,12 @@ Might be good to also have some igt testcases for this. + + Contact: Daniel Vetter, Noralf Tronnes + +-Put a reservation_object into drm_gem_object ++Remove the ->gem_prime_res_obj callback + -------------------------------------------- + +-This would remove the need for the ->gem_prime_res_obj callback. It would also +-allow us to implement generic helpers for waiting for a bo, allowing for quite a +-bit of refactoring in the various wait ioctl implementations. ++The ->gem_prime_res_obj callback can be removed from drivers by using the ++reservation_object in the drm_gem_object. It may also be possible to use the ++generic drm_gem_reservation_object_wait helper for waiting for a bo. + + Contact: Daniel Vetter + +diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c +index d0b9f6a9953f3..ad124f5a6f4da 100644 +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -171,6 +171,10 @@ void drm_gem_private_object_init(struct drm_device *dev, + kref_init(&obj->refcount); + obj->handle_count = 0; + obj->size = size; ++ reservation_object_init(&obj->_resv); ++ if (!obj->resv) ++ obj->resv = &obj->_resv; ++ + drm_vma_node_reset(&obj->vma_node); + } + EXPORT_SYMBOL(drm_gem_private_object_init); +@@ -687,6 +691,44 @@ drm_gem_object_lookup(struct drm_file *filp, u32 handle) + } + EXPORT_SYMBOL(drm_gem_object_lookup); + ++/** ++ * drm_gem_reservation_object_wait - Wait on GEM object's reservation's objects ++ * shared and/or exclusive fences. ++ * @filep: DRM file private date ++ * @handle: userspace handle ++ * @wait_all: if true, wait on all fences, else wait on just exclusive fence ++ * @timeout: timeout value in jiffies or zero to return immediately ++ * ++ * Returns: ++ * ++ * Returns -ERESTARTSYS if interrupted, 0 if the wait timed out, or ++ * greater than 0 on success. ++ */ ++long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, ++ bool wait_all, unsigned long timeout) ++{ ++ long ret; ++ struct drm_gem_object *obj; ++ ++ obj = drm_gem_object_lookup(filep, handle); ++ if (!obj) { ++ DRM_DEBUG("Failed to look up GEM BO %d\n", handle); ++ return -EINVAL; ++ } ++ ++ ret = reservation_object_wait_timeout_rcu(obj->resv, wait_all, ++ true, timeout); ++ if (ret == 0) ++ ret = -ETIME; ++ else if (ret > 0) ++ ret = 0; ++ ++ drm_gem_object_put_unlocked(obj); ++ ++ return ret; ++} ++EXPORT_SYMBOL(drm_gem_reservation_object_wait); ++ + /** + * drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl + * @dev: drm_device +@@ -851,6 +893,7 @@ drm_gem_object_release(struct drm_gem_object *obj) + if (obj->filp) + fput(obj->filp); + ++ reservation_object_fini(&obj->_resv); + drm_gem_free_mmap_offset(obj); + } + EXPORT_SYMBOL(drm_gem_object_release); +diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c +index 231e3f6d5f416..dc079efb3b0fc 100644 +--- a/drivers/gpu/drm/drm_prime.c ++++ b/drivers/gpu/drm/drm_prime.c +@@ -504,6 +504,7 @@ struct dma_buf *drm_gem_prime_export(struct drm_device *dev, + .size = obj->size, + .flags = flags, + .priv = obj, ++ .resv = obj->resv, + }; + + if (dev->driver->gem_prime_res_obj) +diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h +index c957274252844..25f1ff2df464a 100644 +--- a/include/drm/drm_gem.h ++++ b/include/drm/drm_gem.h +@@ -35,6 +35,7 @@ + */ + + #include ++#include + + #include + +@@ -262,6 +263,24 @@ struct drm_gem_object { + */ + struct dma_buf_attachment *import_attach; + ++ /** ++ * @resv: ++ * ++ * Pointer to reservation object associated with the this GEM object. ++ * ++ * Normally (@resv == &@_resv) except for imported GEM objects. ++ */ ++ struct reservation_object *resv; ++ ++ /** ++ * @_resv: ++ * ++ * A reservation object for this GEM object. ++ * ++ * This is unused for imported GEM objects. ++ */ ++ struct reservation_object _resv; ++ + /** + * @funcs: + * +@@ -363,6 +382,8 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, + bool dirty, bool accessed); + + struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); ++long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, ++ bool wait_all, unsigned long timeout); + int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + u32 handle, u64 *offset); + int drm_gem_dumb_destroy(struct drm_file *file, + +From bfd2175626cc4c247ad1a146a5c98674aaddf56c Mon Sep 17 00:00:00 2001 +From: Eric Anholt +Date: Fri, 8 Mar 2019 08:17:13 -0800 +Subject: [PATCH 241/249] drm: Add helpers for locking an array of BO + reservations. + +Now that we have the reservation object in the GEM object, it's easy +to provide a helper for this common case. Noticed while reviewing +panfrost and lima drivers. This particular version came out of v3d, +which in turn was a copy from vc4. + +v2: Fix kerneldoc warnings. + +Signed-off-by: Eric Anholt +Link: https://patchwork.freedesktop.org/patch/msgid/20190308161716.2466-2-eric@anholt.net +Acked-by: Rob Herring (v1) +(cherry picked from commit 7edc3e3b975b5b3b1de313f43670738acbcc8e1d) +--- + drivers/gpu/drm/drm_gem.c | 78 +++++++++++++++++++++++++++++++++++++++ + include/drm/drm_gem.h | 4 ++ + 2 files changed, 82 insertions(+) + +diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c +index ad124f5a6f4da..388b3742e562a 100644 +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -1233,3 +1233,81 @@ void drm_gem_vunmap(struct drm_gem_object *obj, void *vaddr) + obj->dev->driver->gem_prime_vunmap(obj, vaddr); + } + EXPORT_SYMBOL(drm_gem_vunmap); ++ ++/** ++ * drm_gem_lock_reservations - Sets up the ww context and acquires ++ * the lock on an array of GEM objects. ++ * ++ * Once you've locked your reservations, you'll want to set up space ++ * for your shared fences (if applicable), submit your job, then ++ * drm_gem_unlock_reservations(). ++ * ++ * @objs: drm_gem_objects to lock ++ * @count: Number of objects in @objs ++ * @acquire_ctx: struct ww_acquire_ctx that will be initialized as ++ * part of tracking this set of locked reservations. ++ */ ++int ++drm_gem_lock_reservations(struct drm_gem_object **objs, int count, ++ struct ww_acquire_ctx *acquire_ctx) ++{ ++ int contended = -1; ++ int i, ret; ++ ++ ww_acquire_init(acquire_ctx, &reservation_ww_class); ++ ++retry: ++ if (contended != -1) { ++ struct drm_gem_object *obj = objs[contended]; ++ ++ ret = ww_mutex_lock_slow_interruptible(&obj->resv->lock, ++ acquire_ctx); ++ if (ret) { ++ ww_acquire_done(acquire_ctx); ++ return ret; ++ } ++ } ++ ++ for (i = 0; i < count; i++) { ++ if (i == contended) ++ continue; ++ ++ ret = ww_mutex_lock_interruptible(&objs[i]->resv->lock, ++ acquire_ctx); ++ if (ret) { ++ int j; ++ ++ for (j = 0; j < i; j++) ++ ww_mutex_unlock(&objs[j]->resv->lock); ++ ++ if (contended != -1 && contended >= i) ++ ww_mutex_unlock(&objs[contended]->resv->lock); ++ ++ if (ret == -EDEADLK) { ++ contended = i; ++ goto retry; ++ } ++ ++ ww_acquire_done(acquire_ctx); ++ return ret; ++ } ++ } ++ ++ ww_acquire_done(acquire_ctx); ++ ++ return 0; ++} ++EXPORT_SYMBOL(drm_gem_lock_reservations); ++ ++void ++drm_gem_unlock_reservations(struct drm_gem_object **objs, int count, ++ struct ww_acquire_ctx *acquire_ctx) ++{ ++ int i; ++ ++ for (i = 0; i < count; i++) ++ ww_mutex_unlock(&objs[i]->resv->lock); ++ ++ ww_acquire_fini(acquire_ctx); ++} ++EXPORT_SYMBOL(drm_gem_unlock_reservations); +diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h +index 25f1ff2df464a..2955aaab3dca0 100644 +--- a/include/drm/drm_gem.h ++++ b/include/drm/drm_gem.h +@@ -384,6 +384,10 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, + struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); + long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, + bool wait_all, unsigned long timeout); ++int drm_gem_lock_reservations(struct drm_gem_object **objs, int count, ++ struct ww_acquire_ctx *acquire_ctx); ++void drm_gem_unlock_reservations(struct drm_gem_object **objs, int count, ++ struct ww_acquire_ctx *acquire_ctx); + int drm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev, + u32 handle, u64 *offset); + int drm_gem_dumb_destroy(struct drm_file *file, + +From 2400863a56ce5ad8ca29c3296e9ca46f9337013a Mon Sep 17 00:00:00 2001 +From: Qiang Yu +Date: Sat, 9 Mar 2019 20:20:12 +0800 +Subject: [PATCH 242/249] BACKPORT: drm/lima: driver for ARM Mali4xx GPUs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +- Mali 4xx GPUs have two kinds of processors GP and PP. GP is for + OpenGL vertex shader processing and PP is for fragment shader + processing. Each processor has its own MMU so prcessors work in + virtual address space. +- There's only one GP but multiple PP (max 4 for mali 400 and 8 + for mali 450) in the same mali 4xx GPU. All PPs are grouped + togather to handle a single fragment shader task divided by + FB output tiled pixels. Mali 400 user space driver is + responsible for assign target tiled pixels to each PP, but mali + 450 has a HW module called DLBU to dynamically balance each + PP's load. +- User space driver allocate buffer object and map into GPU + virtual address space, upload command stream and draw data with + CPU mmap of the buffer object, then submit task to GP/PP with + a register frame indicating where is the command stream and misc + settings. +- There's no command stream validation/relocation due to each user + process has its own GPU virtual address space. GP/PP's MMU switch + virtual address space before running two tasks from different + user process. Error or evil user space code just get MMU fault + or GP/PP error IRQ, then the HW/SW will be recovered. +- Use GEM+shmem for MM. Currently just alloc and pin memory when + gem object creation. GPU vm map of the buffer is also done in + the alloc stage in kernel space. We may delay the memory + allocation and real GPU vm map to command submission stage in the + furture as improvement. +- Use drm_sched for GPU task schedule. Each OpenGL context should + have a lima context object in the kernel to distinguish tasks + from different user. drm_sched gets task from each lima context + in a fair way. + +mesa driver can be found here before upstreamed: +https://gitlab.freedesktop.org/lima/mesa + +v8: +- add comments for in_sync +- fix ctx free miss mutex unlock + +v7: +- remove lima_fence_ops with default value +- move fence slab create to device probe +- check pad ioctl args to be zero +- add comments for user/kernel interface + +v6: +- fix comments by checkpatch.pl + +v5: +- export gp/pp version to userspace +- rebase on drm-misc-next + +v4: +- use get param interface to get info +- separate context create/free ioctl +- remove unused max sched task param +- update copyright time +- use xarray instead of idr +- stop using drmP.h + +v3: +- fix comments from kbuild robot +- restrict supported arch to tested ones + +v2: +- fix syscall argument check +- fix job finish fence leak since kernel 5.0 +- use drm syncobj to replace native fence +- move buffer object GPU va map into kernel +- reserve syscall argument space for future info +- remove kernel gem modifier +- switch TTM back to GEM+shmem MM +- use time based io poll +- use whole register name +- adopt gem reservation obj integration +- use drm_timeout_abs_to_jiffies + +Cc: Eric Anholt +Cc: Rob Herring +Cc: Christian König +Cc: Daniel Vetter +Cc: Alex Deucher +Cc: Sam Ravnborg +Cc: Rob Clark +Cc: Dave Airlie +Signed-off-by: Andreas Baierl +Signed-off-by: Erico Nunes +Signed-off-by: Heiko Stuebner +Signed-off-by: Marek Vasut +Signed-off-by: Neil Armstrong +Signed-off-by: Simon Shields +Signed-off-by: Vasily Khoruzhick +Signed-off-by: Qiang Yu +Reviewed-by: Eric Anholt +Reviewed-by: Rob Herring +Signed-off-by: Eric Anholt +Link: https://patchwork.freedesktop.org/patch/291200/ +(cherry picked from commit a1d2a6339961efc078208dc3b2f006e9e9a8e119) + +Conflicts: + drivers/gpu/drm/Kconfig + drivers/gpu/drm/Makefile +--- + drivers/gpu/drm/Kconfig | 2 + + drivers/gpu/drm/Makefile | 1 + + drivers/gpu/drm/lima/Kconfig | 10 + + drivers/gpu/drm/lima/Makefile | 21 ++ + drivers/gpu/drm/lima/lima_bcast.c | 47 +++ + drivers/gpu/drm/lima/lima_bcast.h | 14 + + drivers/gpu/drm/lima/lima_ctx.c | 98 ++++++ + drivers/gpu/drm/lima/lima_ctx.h | 30 ++ + drivers/gpu/drm/lima/lima_device.c | 385 +++++++++++++++++++++++ + drivers/gpu/drm/lima/lima_device.h | 131 ++++++++ + drivers/gpu/drm/lima/lima_dlbu.c | 58 ++++ + drivers/gpu/drm/lima/lima_dlbu.h | 18 ++ + drivers/gpu/drm/lima/lima_drv.c | 376 +++++++++++++++++++++++ + drivers/gpu/drm/lima/lima_drv.h | 45 +++ + drivers/gpu/drm/lima/lima_gem.c | 381 +++++++++++++++++++++++ + drivers/gpu/drm/lima/lima_gem.h | 25 ++ + drivers/gpu/drm/lima/lima_gem_prime.c | 47 +++ + drivers/gpu/drm/lima/lima_gem_prime.h | 13 + + drivers/gpu/drm/lima/lima_gp.c | 283 +++++++++++++++++ + drivers/gpu/drm/lima/lima_gp.h | 16 + + drivers/gpu/drm/lima/lima_l2_cache.c | 80 +++++ + drivers/gpu/drm/lima/lima_l2_cache.h | 14 + + drivers/gpu/drm/lima/lima_mmu.c | 142 +++++++++ + drivers/gpu/drm/lima/lima_mmu.h | 16 + + drivers/gpu/drm/lima/lima_object.c | 122 ++++++++ + drivers/gpu/drm/lima/lima_object.h | 36 +++ + drivers/gpu/drm/lima/lima_pmu.c | 60 ++++ + drivers/gpu/drm/lima/lima_pmu.h | 12 + + drivers/gpu/drm/lima/lima_pp.c | 427 ++++++++++++++++++++++++++ + drivers/gpu/drm/lima/lima_pp.h | 19 ++ + drivers/gpu/drm/lima/lima_regs.h | 298 ++++++++++++++++++ + drivers/gpu/drm/lima/lima_sched.c | 404 ++++++++++++++++++++++++ + drivers/gpu/drm/lima/lima_sched.h | 104 +++++++ + drivers/gpu/drm/lima/lima_vm.c | 282 +++++++++++++++++ + drivers/gpu/drm/lima/lima_vm.h | 62 ++++ + include/uapi/drm/lima_drm.h | 169 ++++++++++ + 36 files changed, 4248 insertions(+) + create mode 100644 drivers/gpu/drm/lima/Kconfig + create mode 100644 drivers/gpu/drm/lima/Makefile + create mode 100644 drivers/gpu/drm/lima/lima_bcast.c + create mode 100644 drivers/gpu/drm/lima/lima_bcast.h + create mode 100644 drivers/gpu/drm/lima/lima_ctx.c + create mode 100644 drivers/gpu/drm/lima/lima_ctx.h + create mode 100644 drivers/gpu/drm/lima/lima_device.c + create mode 100644 drivers/gpu/drm/lima/lima_device.h + create mode 100644 drivers/gpu/drm/lima/lima_dlbu.c + create mode 100644 drivers/gpu/drm/lima/lima_dlbu.h + create mode 100644 drivers/gpu/drm/lima/lima_drv.c + create mode 100644 drivers/gpu/drm/lima/lima_drv.h + create mode 100644 drivers/gpu/drm/lima/lima_gem.c + create mode 100644 drivers/gpu/drm/lima/lima_gem.h + create mode 100644 drivers/gpu/drm/lima/lima_gem_prime.c + create mode 100644 drivers/gpu/drm/lima/lima_gem_prime.h + create mode 100644 drivers/gpu/drm/lima/lima_gp.c + create mode 100644 drivers/gpu/drm/lima/lima_gp.h + create mode 100644 drivers/gpu/drm/lima/lima_l2_cache.c + create mode 100644 drivers/gpu/drm/lima/lima_l2_cache.h + create mode 100644 drivers/gpu/drm/lima/lima_mmu.c + create mode 100644 drivers/gpu/drm/lima/lima_mmu.h + create mode 100644 drivers/gpu/drm/lima/lima_object.c + create mode 100644 drivers/gpu/drm/lima/lima_object.h + create mode 100644 drivers/gpu/drm/lima/lima_pmu.c + create mode 100644 drivers/gpu/drm/lima/lima_pmu.h + create mode 100644 drivers/gpu/drm/lima/lima_pp.c + create mode 100644 drivers/gpu/drm/lima/lima_pp.h + create mode 100644 drivers/gpu/drm/lima/lima_regs.h + create mode 100644 drivers/gpu/drm/lima/lima_sched.c + create mode 100644 drivers/gpu/drm/lima/lima_sched.h + create mode 100644 drivers/gpu/drm/lima/lima_vm.c + create mode 100644 drivers/gpu/drm/lima/lima_vm.h + create mode 100644 include/uapi/drm/lima_drm.h + +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index febdc102b75c2..433250cf2beb1 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -335,6 +335,8 @@ source "drivers/gpu/drm/tve200/Kconfig" + + source "drivers/gpu/drm/xen/Kconfig" + ++source "drivers/gpu/drm/lima/Kconfig" ++ + # Keep legacy drivers last + + menuconfig DRM_LEGACY +diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile +index 7476ed945e303..00e0dcc9a2ef5 100644 +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -110,3 +110,4 @@ obj-$(CONFIG_DRM_TINYDRM) += tinydrm/ + obj-$(CONFIG_DRM_PL111) += pl111/ + obj-$(CONFIG_DRM_TVE200) += tve200/ + obj-$(CONFIG_DRM_XEN) += xen/ ++obj-$(CONFIG_DRM_LIMA) += lima/ +diff --git a/drivers/gpu/drm/lima/Kconfig b/drivers/gpu/drm/lima/Kconfig +new file mode 100644 +index 0000000000000..f113144480939 +--- /dev/null ++++ b/drivers/gpu/drm/lima/Kconfig +@@ -0,0 +1,10 @@ ++# SPDX-License-Identifier: GPL-2.0 OR MIT ++# Copyright 2017-2019 Qiang Yu ++ ++config DRM_LIMA ++ tristate "LIMA (DRM support for ARM Mali 400/450 GPU)" ++ depends on DRM ++ depends on ARM || ARM64 || COMPILE_TEST ++ select DRM_SCHED ++ help ++ DRM driver for ARM Mali 400/450 GPUs. +diff --git a/drivers/gpu/drm/lima/Makefile b/drivers/gpu/drm/lima/Makefile +new file mode 100644 +index 0000000000000..38cc70281ba5b +--- /dev/null ++++ b/drivers/gpu/drm/lima/Makefile +@@ -0,0 +1,21 @@ ++# SPDX-License-Identifier: GPL-2.0 OR MIT ++# Copyright 2017-2019 Qiang Yu ++ ++lima-y := \ ++ lima_drv.o \ ++ lima_device.o \ ++ lima_pmu.o \ ++ lima_l2_cache.o \ ++ lima_mmu.o \ ++ lima_gp.o \ ++ lima_pp.o \ ++ lima_gem.o \ ++ lima_vm.o \ ++ lima_sched.o \ ++ lima_ctx.o \ ++ lima_gem_prime.o \ ++ lima_dlbu.o \ ++ lima_bcast.o \ ++ lima_object.o ++ ++obj-$(CONFIG_DRM_LIMA) += lima.o +diff --git a/drivers/gpu/drm/lima/lima_bcast.c b/drivers/gpu/drm/lima/lima_bcast.c +new file mode 100644 +index 0000000000000..288398027bfa8 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_bcast.c +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#include ++#include ++ ++#include "lima_device.h" ++#include "lima_bcast.h" ++#include "lima_regs.h" ++ ++#define bcast_write(reg, data) writel(data, ip->iomem + reg) ++#define bcast_read(reg) readl(ip->iomem + reg) ++ ++void lima_bcast_enable(struct lima_device *dev, int num_pp) ++{ ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ struct lima_ip *ip = dev->ip + lima_ip_bcast; ++ int i, mask = bcast_read(LIMA_BCAST_BROADCAST_MASK) & 0xffff0000; ++ ++ for (i = 0; i < num_pp; i++) { ++ struct lima_ip *pp = pipe->processor[i]; ++ ++ mask |= 1 << (pp->id - lima_ip_pp0); ++ } ++ ++ bcast_write(LIMA_BCAST_BROADCAST_MASK, mask); ++} ++ ++int lima_bcast_init(struct lima_ip *ip) ++{ ++ int i, mask = 0; ++ ++ for (i = lima_ip_pp0; i <= lima_ip_pp7; i++) { ++ if (ip->dev->ip[i].present) ++ mask |= 1 << (i - lima_ip_pp0); ++ } ++ ++ bcast_write(LIMA_BCAST_BROADCAST_MASK, mask << 16); ++ bcast_write(LIMA_BCAST_INTERRUPT_MASK, mask); ++ return 0; ++} ++ ++void lima_bcast_fini(struct lima_ip *ip) ++{ ++ ++} ++ +diff --git a/drivers/gpu/drm/lima/lima_bcast.h b/drivers/gpu/drm/lima/lima_bcast.h +new file mode 100644 +index 0000000000000..c47e58563d0a2 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_bcast.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#ifndef __LIMA_BCAST_H__ ++#define __LIMA_BCAST_H__ ++ ++struct lima_ip; ++ ++int lima_bcast_init(struct lima_ip *ip); ++void lima_bcast_fini(struct lima_ip *ip); ++ ++void lima_bcast_enable(struct lima_device *dev, int num_pp); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_ctx.c b/drivers/gpu/drm/lima/lima_ctx.c +new file mode 100644 +index 0000000000000..22fff6caa961b +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_ctx.c +@@ -0,0 +1,98 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#include ++ ++#include "lima_device.h" ++#include "lima_ctx.h" ++ ++int lima_ctx_create(struct lima_device *dev, struct lima_ctx_mgr *mgr, u32 *id) ++{ ++ struct lima_ctx *ctx; ++ int i, err; ++ ++ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ++ if (!ctx) ++ return -ENOMEM; ++ ctx->dev = dev; ++ kref_init(&ctx->refcnt); ++ ++ for (i = 0; i < lima_pipe_num; i++) { ++ err = lima_sched_context_init(dev->pipe + i, ctx->context + i, &ctx->guilty); ++ if (err) ++ goto err_out0; ++ } ++ ++ err = xa_alloc(&mgr->handles, id, ctx, xa_limit_32b, GFP_KERNEL); ++ if (err < 0) ++ goto err_out0; ++ ++ return 0; ++ ++err_out0: ++ for (i--; i >= 0; i--) ++ lima_sched_context_fini(dev->pipe + i, ctx->context + i); ++ kfree(ctx); ++ return err; ++} ++ ++static void lima_ctx_do_release(struct kref *ref) ++{ ++ struct lima_ctx *ctx = container_of(ref, struct lima_ctx, refcnt); ++ int i; ++ ++ for (i = 0; i < lima_pipe_num; i++) ++ lima_sched_context_fini(ctx->dev->pipe + i, ctx->context + i); ++ kfree(ctx); ++} ++ ++int lima_ctx_free(struct lima_ctx_mgr *mgr, u32 id) ++{ ++ struct lima_ctx *ctx; ++ int ret = 0; ++ ++ mutex_lock(&mgr->lock); ++ ctx = xa_erase(&mgr->handles, id); ++ if (ctx) ++ kref_put(&ctx->refcnt, lima_ctx_do_release); ++ else ++ ret = -EINVAL; ++ mutex_unlock(&mgr->lock); ++ return ret; ++} ++ ++struct lima_ctx *lima_ctx_get(struct lima_ctx_mgr *mgr, u32 id) ++{ ++ struct lima_ctx *ctx; ++ ++ mutex_lock(&mgr->lock); ++ ctx = xa_load(&mgr->handles, id); ++ if (ctx) ++ kref_get(&ctx->refcnt); ++ mutex_unlock(&mgr->lock); ++ return ctx; ++} ++ ++void lima_ctx_put(struct lima_ctx *ctx) ++{ ++ kref_put(&ctx->refcnt, lima_ctx_do_release); ++} ++ ++void lima_ctx_mgr_init(struct lima_ctx_mgr *mgr) ++{ ++ mutex_init(&mgr->lock); ++ xa_init_flags(&mgr->handles, XA_FLAGS_ALLOC); ++} ++ ++void lima_ctx_mgr_fini(struct lima_ctx_mgr *mgr) ++{ ++ struct lima_ctx *ctx; ++ unsigned long id; ++ ++ xa_for_each(&mgr->handles, id, ctx) { ++ kref_put(&ctx->refcnt, lima_ctx_do_release); ++ } ++ ++ xa_destroy(&mgr->handles); ++ mutex_destroy(&mgr->lock); ++} +diff --git a/drivers/gpu/drm/lima/lima_ctx.h b/drivers/gpu/drm/lima/lima_ctx.h +new file mode 100644 +index 0000000000000..6154e5c9bfe49 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_ctx.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#ifndef __LIMA_CTX_H__ ++#define __LIMA_CTX_H__ ++ ++#include ++ ++#include "lima_device.h" ++ ++struct lima_ctx { ++ struct kref refcnt; ++ struct lima_device *dev; ++ struct lima_sched_context context[lima_pipe_num]; ++ atomic_t guilty; ++}; ++ ++struct lima_ctx_mgr { ++ struct mutex lock; ++ struct xarray handles; ++}; ++ ++int lima_ctx_create(struct lima_device *dev, struct lima_ctx_mgr *mgr, u32 *id); ++int lima_ctx_free(struct lima_ctx_mgr *mgr, u32 id); ++struct lima_ctx *lima_ctx_get(struct lima_ctx_mgr *mgr, u32 id); ++void lima_ctx_put(struct lima_ctx *ctx); ++void lima_ctx_mgr_init(struct lima_ctx_mgr *mgr); ++void lima_ctx_mgr_fini(struct lima_ctx_mgr *mgr); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_device.c b/drivers/gpu/drm/lima/lima_device.c +new file mode 100644 +index 0000000000000..570d0e93f9a99 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_device.c +@@ -0,0 +1,385 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "lima_device.h" ++#include "lima_gp.h" ++#include "lima_pp.h" ++#include "lima_mmu.h" ++#include "lima_pmu.h" ++#include "lima_l2_cache.h" ++#include "lima_dlbu.h" ++#include "lima_bcast.h" ++#include "lima_vm.h" ++ ++struct lima_ip_desc { ++ char *name; ++ char *irq_name; ++ bool must_have[lima_gpu_num]; ++ int offset[lima_gpu_num]; ++ ++ int (*init)(struct lima_ip *ip); ++ void (*fini)(struct lima_ip *ip); ++}; ++ ++#define LIMA_IP_DESC(ipname, mst0, mst1, off0, off1, func, irq) \ ++ [lima_ip_##ipname] = { \ ++ .name = #ipname, \ ++ .irq_name = irq, \ ++ .must_have = { \ ++ [lima_gpu_mali400] = mst0, \ ++ [lima_gpu_mali450] = mst1, \ ++ }, \ ++ .offset = { \ ++ [lima_gpu_mali400] = off0, \ ++ [lima_gpu_mali450] = off1, \ ++ }, \ ++ .init = lima_##func##_init, \ ++ .fini = lima_##func##_fini, \ ++ } ++ ++static struct lima_ip_desc lima_ip_desc[lima_ip_num] = { ++ LIMA_IP_DESC(pmu, false, false, 0x02000, 0x02000, pmu, "pmu"), ++ LIMA_IP_DESC(l2_cache0, true, true, 0x01000, 0x10000, l2_cache, NULL), ++ LIMA_IP_DESC(l2_cache1, false, true, -1, 0x01000, l2_cache, NULL), ++ LIMA_IP_DESC(l2_cache2, false, false, -1, 0x11000, l2_cache, NULL), ++ LIMA_IP_DESC(gp, true, true, 0x00000, 0x00000, gp, "gp"), ++ LIMA_IP_DESC(pp0, true, true, 0x08000, 0x08000, pp, "pp0"), ++ LIMA_IP_DESC(pp1, false, false, 0x0A000, 0x0A000, pp, "pp1"), ++ LIMA_IP_DESC(pp2, false, false, 0x0C000, 0x0C000, pp, "pp2"), ++ LIMA_IP_DESC(pp3, false, false, 0x0E000, 0x0E000, pp, "pp3"), ++ LIMA_IP_DESC(pp4, false, false, -1, 0x28000, pp, "pp4"), ++ LIMA_IP_DESC(pp5, false, false, -1, 0x2A000, pp, "pp5"), ++ LIMA_IP_DESC(pp6, false, false, -1, 0x2C000, pp, "pp6"), ++ LIMA_IP_DESC(pp7, false, false, -1, 0x2E000, pp, "pp7"), ++ LIMA_IP_DESC(gpmmu, true, true, 0x03000, 0x03000, mmu, "gpmmu"), ++ LIMA_IP_DESC(ppmmu0, true, true, 0x04000, 0x04000, mmu, "ppmmu0"), ++ LIMA_IP_DESC(ppmmu1, false, false, 0x05000, 0x05000, mmu, "ppmmu1"), ++ LIMA_IP_DESC(ppmmu2, false, false, 0x06000, 0x06000, mmu, "ppmmu2"), ++ LIMA_IP_DESC(ppmmu3, false, false, 0x07000, 0x07000, mmu, "ppmmu3"), ++ LIMA_IP_DESC(ppmmu4, false, false, -1, 0x1C000, mmu, "ppmmu4"), ++ LIMA_IP_DESC(ppmmu5, false, false, -1, 0x1D000, mmu, "ppmmu5"), ++ LIMA_IP_DESC(ppmmu6, false, false, -1, 0x1E000, mmu, "ppmmu6"), ++ LIMA_IP_DESC(ppmmu7, false, false, -1, 0x1F000, mmu, "ppmmu7"), ++ LIMA_IP_DESC(dlbu, false, true, -1, 0x14000, dlbu, NULL), ++ LIMA_IP_DESC(bcast, false, true, -1, 0x13000, bcast, NULL), ++ LIMA_IP_DESC(pp_bcast, false, true, -1, 0x16000, pp_bcast, "pp"), ++ LIMA_IP_DESC(ppmmu_bcast, false, true, -1, 0x15000, mmu, NULL), ++}; ++ ++const char *lima_ip_name(struct lima_ip *ip) ++{ ++ return lima_ip_desc[ip->id].name; ++} ++ ++static int lima_clk_init(struct lima_device *dev) ++{ ++ int err; ++ unsigned long bus_rate, gpu_rate; ++ ++ dev->clk_bus = devm_clk_get(dev->dev, "bus"); ++ if (IS_ERR(dev->clk_bus)) { ++ dev_err(dev->dev, "get bus clk failed %ld\n", PTR_ERR(dev->clk_bus)); ++ return PTR_ERR(dev->clk_bus); ++ } ++ ++ dev->clk_gpu = devm_clk_get(dev->dev, "core"); ++ if (IS_ERR(dev->clk_gpu)) { ++ dev_err(dev->dev, "get core clk failed %ld\n", PTR_ERR(dev->clk_gpu)); ++ return PTR_ERR(dev->clk_gpu); ++ } ++ ++ bus_rate = clk_get_rate(dev->clk_bus); ++ dev_info(dev->dev, "bus rate = %lu\n", bus_rate); ++ ++ gpu_rate = clk_get_rate(dev->clk_gpu); ++ dev_info(dev->dev, "mod rate = %lu", gpu_rate); ++ ++ err = clk_prepare_enable(dev->clk_bus); ++ if (err) ++ return err; ++ ++ err = clk_prepare_enable(dev->clk_gpu); ++ if (err) ++ goto error_out0; ++ ++ dev->reset = devm_reset_control_get_optional(dev->dev, NULL); ++ if (IS_ERR(dev->reset)) { ++ err = PTR_ERR(dev->reset); ++ goto error_out1; ++ } else if (dev->reset != NULL) { ++ err = reset_control_deassert(dev->reset); ++ if (err) ++ goto error_out1; ++ } ++ ++ return 0; ++ ++error_out1: ++ clk_disable_unprepare(dev->clk_gpu); ++error_out0: ++ clk_disable_unprepare(dev->clk_bus); ++ return err; ++} ++ ++static void lima_clk_fini(struct lima_device *dev) ++{ ++ if (dev->reset != NULL) ++ reset_control_assert(dev->reset); ++ clk_disable_unprepare(dev->clk_gpu); ++ clk_disable_unprepare(dev->clk_bus); ++} ++ ++static int lima_regulator_init(struct lima_device *dev) ++{ ++ int ret; ++ ++ dev->regulator = devm_regulator_get_optional(dev->dev, "mali"); ++ if (IS_ERR(dev->regulator)) { ++ ret = PTR_ERR(dev->regulator); ++ dev->regulator = NULL; ++ if (ret == -ENODEV) ++ return 0; ++ dev_err(dev->dev, "failed to get regulator: %d\n", ret); ++ return ret; ++ } ++ ++ ret = regulator_enable(dev->regulator); ++ if (ret < 0) { ++ dev_err(dev->dev, "failed to enable regulator: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void lima_regulator_fini(struct lima_device *dev) ++{ ++ if (dev->regulator) ++ regulator_disable(dev->regulator); ++} ++ ++static int lima_init_ip(struct lima_device *dev, int index) ++{ ++ struct lima_ip_desc *desc = lima_ip_desc + index; ++ struct lima_ip *ip = dev->ip + index; ++ int offset = desc->offset[dev->id]; ++ bool must = desc->must_have[dev->id]; ++ int err; ++ ++ if (offset < 0) ++ return 0; ++ ++ ip->dev = dev; ++ ip->id = index; ++ ip->iomem = dev->iomem + offset; ++ if (desc->irq_name) { ++ err = platform_get_irq_byname(dev->pdev, desc->irq_name); ++ if (err < 0) ++ goto out; ++ ip->irq = err; ++ } ++ ++ err = desc->init(ip); ++ if (!err) { ++ ip->present = true; ++ return 0; ++ } ++ ++out: ++ return must ? err : 0; ++} ++ ++static void lima_fini_ip(struct lima_device *ldev, int index) ++{ ++ struct lima_ip_desc *desc = lima_ip_desc + index; ++ struct lima_ip *ip = ldev->ip + index; ++ ++ if (ip->present) ++ desc->fini(ip); ++} ++ ++static int lima_init_gp_pipe(struct lima_device *dev) ++{ ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; ++ int err; ++ ++ err = lima_sched_pipe_init(pipe, "gp"); ++ if (err) ++ return err; ++ ++ pipe->l2_cache[pipe->num_l2_cache++] = dev->ip + lima_ip_l2_cache0; ++ pipe->mmu[pipe->num_mmu++] = dev->ip + lima_ip_gpmmu; ++ pipe->processor[pipe->num_processor++] = dev->ip + lima_ip_gp; ++ ++ err = lima_gp_pipe_init(dev); ++ if (err) { ++ lima_sched_pipe_fini(pipe); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void lima_fini_gp_pipe(struct lima_device *dev) ++{ ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; ++ ++ lima_gp_pipe_fini(dev); ++ lima_sched_pipe_fini(pipe); ++} ++ ++static int lima_init_pp_pipe(struct lima_device *dev) ++{ ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ int err, i; ++ ++ err = lima_sched_pipe_init(pipe, "pp"); ++ if (err) ++ return err; ++ ++ for (i = 0; i < LIMA_SCHED_PIPE_MAX_PROCESSOR; i++) { ++ struct lima_ip *pp = dev->ip + lima_ip_pp0 + i; ++ struct lima_ip *ppmmu = dev->ip + lima_ip_ppmmu0 + i; ++ struct lima_ip *l2_cache; ++ ++ if (dev->id == lima_gpu_mali400) ++ l2_cache = dev->ip + lima_ip_l2_cache0; ++ else ++ l2_cache = dev->ip + lima_ip_l2_cache1 + (i >> 2); ++ ++ if (pp->present && ppmmu->present && l2_cache->present) { ++ pipe->mmu[pipe->num_mmu++] = ppmmu; ++ pipe->processor[pipe->num_processor++] = pp; ++ if (!pipe->l2_cache[i >> 2]) ++ pipe->l2_cache[pipe->num_l2_cache++] = l2_cache; ++ } ++ } ++ ++ if (dev->ip[lima_ip_bcast].present) { ++ pipe->bcast_processor = dev->ip + lima_ip_pp_bcast; ++ pipe->bcast_mmu = dev->ip + lima_ip_ppmmu_bcast; ++ } ++ ++ err = lima_pp_pipe_init(dev); ++ if (err) { ++ lima_sched_pipe_fini(pipe); ++ return err; ++ } ++ ++ return 0; ++} ++ ++static void lima_fini_pp_pipe(struct lima_device *dev) ++{ ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ ++ lima_pp_pipe_fini(dev); ++ lima_sched_pipe_fini(pipe); ++} ++ ++int lima_device_init(struct lima_device *ldev) ++{ ++ int err, i; ++ struct resource *res; ++ ++ dma_set_coherent_mask(ldev->dev, DMA_BIT_MASK(32)); ++ ++ err = lima_clk_init(ldev); ++ if (err) { ++ dev_err(ldev->dev, "clk init fail %d\n", err); ++ return err; ++ } ++ ++ err = lima_regulator_init(ldev); ++ if (err) { ++ dev_err(ldev->dev, "regulator init fail %d\n", err); ++ goto err_out0; ++ } ++ ++ ldev->empty_vm = lima_vm_create(ldev); ++ if (!ldev->empty_vm) { ++ err = -ENOMEM; ++ goto err_out1; ++ } ++ ++ ldev->va_start = 0; ++ if (ldev->id == lima_gpu_mali450) { ++ ldev->va_end = LIMA_VA_RESERVE_START; ++ ldev->dlbu_cpu = dma_alloc_wc( ++ ldev->dev, LIMA_PAGE_SIZE, ++ &ldev->dlbu_dma, GFP_KERNEL); ++ if (!ldev->dlbu_cpu) { ++ err = -ENOMEM; ++ goto err_out2; ++ } ++ } else ++ ldev->va_end = LIMA_VA_RESERVE_END; ++ ++ res = platform_get_resource(ldev->pdev, IORESOURCE_MEM, 0); ++ ldev->iomem = devm_ioremap_resource(ldev->dev, res); ++ if (IS_ERR(ldev->iomem)) { ++ dev_err(ldev->dev, "fail to ioremap iomem\n"); ++ err = PTR_ERR(ldev->iomem); ++ goto err_out3; ++ } ++ ++ for (i = 0; i < lima_ip_num; i++) { ++ err = lima_init_ip(ldev, i); ++ if (err) ++ goto err_out4; ++ } ++ ++ err = lima_init_gp_pipe(ldev); ++ if (err) ++ goto err_out4; ++ ++ err = lima_init_pp_pipe(ldev); ++ if (err) ++ goto err_out5; ++ ++ return 0; ++ ++err_out5: ++ lima_fini_gp_pipe(ldev); ++err_out4: ++ while (--i >= 0) ++ lima_fini_ip(ldev, i); ++err_out3: ++ if (ldev->dlbu_cpu) ++ dma_free_wc(ldev->dev, LIMA_PAGE_SIZE, ++ ldev->dlbu_cpu, ldev->dlbu_dma); ++err_out2: ++ lima_vm_put(ldev->empty_vm); ++err_out1: ++ lima_regulator_fini(ldev); ++err_out0: ++ lima_clk_fini(ldev); ++ return err; ++} ++ ++void lima_device_fini(struct lima_device *ldev) ++{ ++ int i; ++ ++ lima_fini_pp_pipe(ldev); ++ lima_fini_gp_pipe(ldev); ++ ++ for (i = lima_ip_num - 1; i >= 0; i--) ++ lima_fini_ip(ldev, i); ++ ++ if (ldev->dlbu_cpu) ++ dma_free_wc(ldev->dev, LIMA_PAGE_SIZE, ++ ldev->dlbu_cpu, ldev->dlbu_dma); ++ ++ lima_vm_put(ldev->empty_vm); ++ ++ lima_regulator_fini(ldev); ++ ++ lima_clk_fini(ldev); ++} +diff --git a/drivers/gpu/drm/lima/lima_device.h b/drivers/gpu/drm/lima/lima_device.h +new file mode 100644 +index 0000000000000..31158d86271c2 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_device.h +@@ -0,0 +1,131 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#ifndef __LIMA_DEVICE_H__ ++#define __LIMA_DEVICE_H__ ++ ++#include ++#include ++ ++#include "lima_sched.h" ++ ++enum lima_gpu_id { ++ lima_gpu_mali400 = 0, ++ lima_gpu_mali450, ++ lima_gpu_num, ++}; ++ ++enum lima_ip_id { ++ lima_ip_pmu, ++ lima_ip_gpmmu, ++ lima_ip_ppmmu0, ++ lima_ip_ppmmu1, ++ lima_ip_ppmmu2, ++ lima_ip_ppmmu3, ++ lima_ip_ppmmu4, ++ lima_ip_ppmmu5, ++ lima_ip_ppmmu6, ++ lima_ip_ppmmu7, ++ lima_ip_gp, ++ lima_ip_pp0, ++ lima_ip_pp1, ++ lima_ip_pp2, ++ lima_ip_pp3, ++ lima_ip_pp4, ++ lima_ip_pp5, ++ lima_ip_pp6, ++ lima_ip_pp7, ++ lima_ip_l2_cache0, ++ lima_ip_l2_cache1, ++ lima_ip_l2_cache2, ++ lima_ip_dlbu, ++ lima_ip_bcast, ++ lima_ip_pp_bcast, ++ lima_ip_ppmmu_bcast, ++ lima_ip_num, ++}; ++ ++struct lima_device; ++ ++struct lima_ip { ++ struct lima_device *dev; ++ enum lima_ip_id id; ++ bool present; ++ ++ void __iomem *iomem; ++ int irq; ++ ++ union { ++ /* gp/pp */ ++ bool async_reset; ++ /* l2 cache */ ++ spinlock_t lock; ++ } data; ++}; ++ ++enum lima_pipe_id { ++ lima_pipe_gp, ++ lima_pipe_pp, ++ lima_pipe_num, ++}; ++ ++struct lima_device { ++ struct device *dev; ++ struct drm_device *ddev; ++ struct platform_device *pdev; ++ ++ enum lima_gpu_id id; ++ u32 gp_version; ++ u32 pp_version; ++ int num_pp; ++ ++ void __iomem *iomem; ++ struct clk *clk_bus; ++ struct clk *clk_gpu; ++ struct reset_control *reset; ++ struct regulator *regulator; ++ ++ struct lima_ip ip[lima_ip_num]; ++ struct lima_sched_pipe pipe[lima_pipe_num]; ++ ++ struct lima_vm *empty_vm; ++ uint64_t va_start; ++ uint64_t va_end; ++ ++ u32 *dlbu_cpu; ++ dma_addr_t dlbu_dma; ++}; ++ ++static inline struct lima_device * ++to_lima_dev(struct drm_device *dev) ++{ ++ return dev->dev_private; ++} ++ ++int lima_device_init(struct lima_device *ldev); ++void lima_device_fini(struct lima_device *ldev); ++ ++const char *lima_ip_name(struct lima_ip *ip); ++ ++typedef int (*lima_poll_func_t)(struct lima_ip *); ++ ++static inline int lima_poll_timeout(struct lima_ip *ip, lima_poll_func_t func, ++ int sleep_us, int timeout_us) ++{ ++ ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); ++ ++ might_sleep_if(sleep_us); ++ while (1) { ++ if (func(ip)) ++ return 0; ++ ++ if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) ++ return -ETIMEDOUT; ++ ++ if (sleep_us) ++ usleep_range((sleep_us >> 2) + 1, sleep_us); ++ } ++ return 0; ++} ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_dlbu.c b/drivers/gpu/drm/lima/lima_dlbu.c +new file mode 100644 +index 0000000000000..8399ceffb94bb +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_dlbu.c +@@ -0,0 +1,58 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#include ++#include ++ ++#include "lima_device.h" ++#include "lima_dlbu.h" ++#include "lima_vm.h" ++#include "lima_regs.h" ++ ++#define dlbu_write(reg, data) writel(data, ip->iomem + reg) ++#define dlbu_read(reg) readl(ip->iomem + reg) ++ ++void lima_dlbu_enable(struct lima_device *dev, int num_pp) ++{ ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ struct lima_ip *ip = dev->ip + lima_ip_dlbu; ++ int i, mask = 0; ++ ++ for (i = 0; i < num_pp; i++) { ++ struct lima_ip *pp = pipe->processor[i]; ++ ++ mask |= 1 << (pp->id - lima_ip_pp0); ++ } ++ ++ dlbu_write(LIMA_DLBU_PP_ENABLE_MASK, mask); ++} ++ ++void lima_dlbu_disable(struct lima_device *dev) ++{ ++ struct lima_ip *ip = dev->ip + lima_ip_dlbu; ++ ++ dlbu_write(LIMA_DLBU_PP_ENABLE_MASK, 0); ++} ++ ++void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg) ++{ ++ dlbu_write(LIMA_DLBU_TLLIST_VBASEADDR, reg[0]); ++ dlbu_write(LIMA_DLBU_FB_DIM, reg[1]); ++ dlbu_write(LIMA_DLBU_TLLIST_CONF, reg[2]); ++ dlbu_write(LIMA_DLBU_START_TILE_POS, reg[3]); ++} ++ ++int lima_dlbu_init(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ ++ dlbu_write(LIMA_DLBU_MASTER_TLLIST_PHYS_ADDR, dev->dlbu_dma | 1); ++ dlbu_write(LIMA_DLBU_MASTER_TLLIST_VADDR, LIMA_VA_RESERVE_DLBU); ++ ++ return 0; ++} ++ ++void lima_dlbu_fini(struct lima_ip *ip) ++{ ++ ++} +diff --git a/drivers/gpu/drm/lima/lima_dlbu.h b/drivers/gpu/drm/lima/lima_dlbu.h +new file mode 100644 +index 0000000000000..16f877984466d +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_dlbu.h +@@ -0,0 +1,18 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#ifndef __LIMA_DLBU_H__ ++#define __LIMA_DLBU_H__ ++ ++struct lima_ip; ++struct lima_device; ++ ++void lima_dlbu_enable(struct lima_device *dev, int num_pp); ++void lima_dlbu_disable(struct lima_device *dev); ++ ++void lima_dlbu_set_reg(struct lima_ip *ip, u32 *reg); ++ ++int lima_dlbu_init(struct lima_ip *ip); ++void lima_dlbu_fini(struct lima_ip *ip); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_drv.c b/drivers/gpu/drm/lima/lima_drv.c +new file mode 100644 +index 0000000000000..f9a281a620831 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_drv.c +@@ -0,0 +1,376 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lima_drv.h" ++#include "lima_gem.h" ++#include "lima_gem_prime.h" ++#include "lima_vm.h" ++ ++int lima_sched_timeout_ms; ++ ++MODULE_PARM_DESC(sched_timeout_ms, "task run timeout in ms (0 = no timeout (default))"); ++module_param_named(sched_timeout_ms, lima_sched_timeout_ms, int, 0444); ++ ++static int lima_ioctl_get_param(struct drm_device *dev, void *data, struct drm_file *file) ++{ ++ struct drm_lima_get_param *args = data; ++ struct lima_device *ldev = to_lima_dev(dev); ++ ++ if (args->pad) ++ return -EINVAL; ++ ++ switch (args->param) { ++ case DRM_LIMA_PARAM_GPU_ID: ++ switch (ldev->id) { ++ case lima_gpu_mali400: ++ args->value = DRM_LIMA_PARAM_GPU_ID_MALI400; ++ break; ++ case lima_gpu_mali450: ++ args->value = DRM_LIMA_PARAM_GPU_ID_MALI450; ++ break; ++ default: ++ args->value = DRM_LIMA_PARAM_GPU_ID_UNKNOWN; ++ break; ++ } ++ break; ++ ++ case DRM_LIMA_PARAM_NUM_PP: ++ args->value = ldev->pipe[lima_pipe_pp].num_processor; ++ break; ++ ++ case DRM_LIMA_PARAM_GP_VERSION: ++ args->value = ldev->gp_version; ++ break; ++ ++ case DRM_LIMA_PARAM_PP_VERSION: ++ args->value = ldev->pp_version; ++ break; ++ ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int lima_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_file *file) ++{ ++ struct drm_lima_gem_create *args = data; ++ ++ if (args->pad) ++ return -EINVAL; ++ ++ if (args->flags) ++ return -EINVAL; ++ ++ if (args->size == 0) ++ return -EINVAL; ++ ++ return lima_gem_create_handle(dev, file, args->size, args->flags, &args->handle); ++} ++ ++static int lima_ioctl_gem_info(struct drm_device *dev, void *data, struct drm_file *file) ++{ ++ struct drm_lima_gem_info *args = data; ++ ++ return lima_gem_get_info(file, args->handle, &args->va, &args->offset); ++} ++ ++static int lima_ioctl_gem_submit(struct drm_device *dev, void *data, struct drm_file *file) ++{ ++ struct drm_lima_gem_submit *args = data; ++ struct lima_device *ldev = to_lima_dev(dev); ++ struct lima_drm_priv *priv = file->driver_priv; ++ struct drm_lima_gem_submit_bo *bos; ++ struct lima_sched_pipe *pipe; ++ struct lima_sched_task *task; ++ struct lima_ctx *ctx; ++ struct lima_submit submit = {0}; ++ size_t size; ++ int err = 0; ++ ++ if (args->pipe >= lima_pipe_num || args->nr_bos == 0) ++ return -EINVAL; ++ ++ if (args->flags & ~(LIMA_SUBMIT_FLAG_EXPLICIT_FENCE)) ++ return -EINVAL; ++ ++ pipe = ldev->pipe + args->pipe; ++ if (args->frame_size != pipe->frame_size) ++ return -EINVAL; ++ ++ bos = kvcalloc(args->nr_bos, sizeof(*submit.bos) + sizeof(*submit.lbos), GFP_KERNEL); ++ if (!bos) ++ return -ENOMEM; ++ ++ size = args->nr_bos * sizeof(*submit.bos); ++ if (copy_from_user(bos, u64_to_user_ptr(args->bos), size)) { ++ err = -EFAULT; ++ goto out0; ++ } ++ ++ task = kmem_cache_zalloc(pipe->task_slab, GFP_KERNEL); ++ if (!task) { ++ err = -ENOMEM; ++ goto out0; ++ } ++ ++ task->frame = task + 1; ++ if (copy_from_user(task->frame, u64_to_user_ptr(args->frame), args->frame_size)) { ++ err = -EFAULT; ++ goto out1; ++ } ++ ++ err = pipe->task_validate(pipe, task); ++ if (err) ++ goto out1; ++ ++ ctx = lima_ctx_get(&priv->ctx_mgr, args->ctx); ++ if (!ctx) { ++ err = -ENOENT; ++ goto out1; ++ } ++ ++ submit.pipe = args->pipe; ++ submit.bos = bos; ++ submit.lbos = (void *)bos + size; ++ submit.nr_bos = args->nr_bos; ++ submit.task = task; ++ submit.ctx = ctx; ++ submit.flags = args->flags; ++ submit.in_sync[0] = args->in_sync[0]; ++ submit.in_sync[1] = args->in_sync[1]; ++ submit.out_sync = args->out_sync; ++ ++ err = lima_gem_submit(file, &submit); ++ ++ lima_ctx_put(ctx); ++out1: ++ if (err) ++ kmem_cache_free(pipe->task_slab, task); ++out0: ++ kvfree(bos); ++ return err; ++} ++ ++static int lima_ioctl_gem_wait(struct drm_device *dev, void *data, struct drm_file *file) ++{ ++ struct drm_lima_gem_wait *args = data; ++ ++ if (args->op & ~(LIMA_GEM_WAIT_READ|LIMA_GEM_WAIT_WRITE)) ++ return -EINVAL; ++ ++ return lima_gem_wait(file, args->handle, args->op, args->timeout_ns); ++} ++ ++static int lima_ioctl_ctx_create(struct drm_device *dev, void *data, struct drm_file *file) ++{ ++ struct drm_lima_ctx_create *args = data; ++ struct lima_drm_priv *priv = file->driver_priv; ++ struct lima_device *ldev = to_lima_dev(dev); ++ ++ if (args->_pad) ++ return -EINVAL; ++ ++ return lima_ctx_create(ldev, &priv->ctx_mgr, &args->id); ++} ++ ++static int lima_ioctl_ctx_free(struct drm_device *dev, void *data, struct drm_file *file) ++{ ++ struct drm_lima_ctx_create *args = data; ++ struct lima_drm_priv *priv = file->driver_priv; ++ ++ if (args->_pad) ++ return -EINVAL; ++ ++ return lima_ctx_free(&priv->ctx_mgr, args->id); ++} ++ ++static int lima_drm_driver_open(struct drm_device *dev, struct drm_file *file) ++{ ++ int err; ++ struct lima_drm_priv *priv; ++ struct lima_device *ldev = to_lima_dev(dev); ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->vm = lima_vm_create(ldev); ++ if (!priv->vm) { ++ err = -ENOMEM; ++ goto err_out0; ++ } ++ ++ lima_ctx_mgr_init(&priv->ctx_mgr); ++ ++ file->driver_priv = priv; ++ return 0; ++ ++err_out0: ++ kfree(priv); ++ return err; ++} ++ ++static void lima_drm_driver_postclose(struct drm_device *dev, struct drm_file *file) ++{ ++ struct lima_drm_priv *priv = file->driver_priv; ++ ++ lima_ctx_mgr_fini(&priv->ctx_mgr); ++ lima_vm_put(priv->vm); ++ kfree(priv); ++} ++ ++static const struct drm_ioctl_desc lima_drm_driver_ioctls[] = { ++ DRM_IOCTL_DEF_DRV(LIMA_GET_PARAM, lima_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(LIMA_GEM_CREATE, lima_ioctl_gem_create, DRM_AUTH|DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(LIMA_GEM_INFO, lima_ioctl_gem_info, DRM_AUTH|DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(LIMA_GEM_SUBMIT, lima_ioctl_gem_submit, DRM_AUTH|DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(LIMA_GEM_WAIT, lima_ioctl_gem_wait, DRM_AUTH|DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(LIMA_CTX_CREATE, lima_ioctl_ctx_create, DRM_AUTH|DRM_RENDER_ALLOW), ++ DRM_IOCTL_DEF_DRV(LIMA_CTX_FREE, lima_ioctl_ctx_free, DRM_AUTH|DRM_RENDER_ALLOW), ++}; ++ ++static const struct file_operations lima_drm_driver_fops = { ++ .owner = THIS_MODULE, ++ .open = drm_open, ++ .release = drm_release, ++ .unlocked_ioctl = drm_ioctl, ++#ifdef CONFIG_COMPAT ++ .compat_ioctl = drm_compat_ioctl, ++#endif ++ .mmap = lima_gem_mmap, ++}; ++ ++static struct drm_driver lima_drm_driver = { ++ .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_PRIME | DRIVER_SYNCOBJ, ++ .open = lima_drm_driver_open, ++ .postclose = lima_drm_driver_postclose, ++ .ioctls = lima_drm_driver_ioctls, ++ .num_ioctls = ARRAY_SIZE(lima_drm_driver_ioctls), ++ .fops = &lima_drm_driver_fops, ++ .gem_free_object_unlocked = lima_gem_free_object, ++ .gem_open_object = lima_gem_object_open, ++ .gem_close_object = lima_gem_object_close, ++ .gem_vm_ops = &lima_gem_vm_ops, ++ .name = "lima", ++ .desc = "lima DRM", ++ .date = "20190217", ++ .major = 1, ++ .minor = 0, ++ .patchlevel = 0, ++ ++ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, ++ .gem_prime_import_sg_table = lima_gem_prime_import_sg_table, ++ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, ++ .gem_prime_get_sg_table = lima_gem_prime_get_sg_table, ++ .gem_prime_mmap = lima_gem_prime_mmap, ++}; ++ ++static int lima_pdev_probe(struct platform_device *pdev) ++{ ++ struct lima_device *ldev; ++ struct drm_device *ddev; ++ int err; ++ ++ err = lima_sched_slab_init(); ++ if (err) ++ return err; ++ ++ ldev = devm_kzalloc(&pdev->dev, sizeof(*ldev), GFP_KERNEL); ++ if (!ldev) { ++ err = -ENOMEM; ++ goto err_out0; ++ } ++ ++ ldev->pdev = pdev; ++ ldev->dev = &pdev->dev; ++ ldev->id = (enum lima_gpu_id)of_device_get_match_data(&pdev->dev); ++ ++ platform_set_drvdata(pdev, ldev); ++ ++ /* Allocate and initialize the DRM device. */ ++ ddev = drm_dev_alloc(&lima_drm_driver, &pdev->dev); ++ if (IS_ERR(ddev)) ++ return PTR_ERR(ddev); ++ ++ ddev->dev_private = ldev; ++ ldev->ddev = ddev; ++ ++ err = lima_device_init(ldev); ++ if (err) { ++ dev_err(&pdev->dev, "Fatal error during GPU init\n"); ++ goto err_out1; ++ } ++ ++ /* ++ * Register the DRM device with the core and the connectors with ++ * sysfs. ++ */ ++ err = drm_dev_register(ddev, 0); ++ if (err < 0) ++ goto err_out2; ++ ++ return 0; ++ ++err_out2: ++ lima_device_fini(ldev); ++err_out1: ++ drm_dev_put(ddev); ++err_out0: ++ lima_sched_slab_fini(); ++ return err; ++} ++ ++static int lima_pdev_remove(struct platform_device *pdev) ++{ ++ struct lima_device *ldev = platform_get_drvdata(pdev); ++ struct drm_device *ddev = ldev->ddev; ++ ++ drm_dev_unregister(ddev); ++ lima_device_fini(ldev); ++ drm_dev_put(ddev); ++ lima_sched_slab_fini(); ++ return 0; ++} ++ ++static const struct of_device_id dt_match[] = { ++ { .compatible = "arm,mali-400", .data = (void *)lima_gpu_mali400 }, ++ { .compatible = "arm,mali-450", .data = (void *)lima_gpu_mali450 }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, dt_match); ++ ++static struct platform_driver lima_platform_driver = { ++ .probe = lima_pdev_probe, ++ .remove = lima_pdev_remove, ++ .driver = { ++ .name = "lima", ++ .of_match_table = dt_match, ++ }, ++}; ++ ++static int __init lima_init(void) ++{ ++ return platform_driver_register(&lima_platform_driver); ++} ++module_init(lima_init); ++ ++static void __exit lima_exit(void) ++{ ++ platform_driver_unregister(&lima_platform_driver); ++} ++module_exit(lima_exit); ++ ++MODULE_AUTHOR("Lima Project Developers"); ++MODULE_DESCRIPTION("Lima DRM Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/gpu/drm/lima/lima_drv.h b/drivers/gpu/drm/lima/lima_drv.h +new file mode 100644 +index 0000000000000..69c7344715c9b +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_drv.h +@@ -0,0 +1,45 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_DRV_H__ ++#define __LIMA_DRV_H__ ++ ++#include ++ ++#include "lima_ctx.h" ++ ++extern int lima_sched_timeout_ms; ++ ++struct lima_vm; ++struct lima_bo; ++struct lima_sched_task; ++ ++struct drm_lima_gem_submit_bo; ++ ++struct lima_drm_priv { ++ struct lima_vm *vm; ++ struct lima_ctx_mgr ctx_mgr; ++}; ++ ++struct lima_submit { ++ struct lima_ctx *ctx; ++ int pipe; ++ u32 flags; ++ ++ struct drm_lima_gem_submit_bo *bos; ++ struct lima_bo **lbos; ++ u32 nr_bos; ++ ++ u32 in_sync[2]; ++ u32 out_sync; ++ ++ struct lima_sched_task *task; ++}; ++ ++static inline struct lima_drm_priv * ++to_lima_drm_priv(struct drm_file *file) ++{ ++ return file->driver_priv; ++} ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_gem.c b/drivers/gpu/drm/lima/lima_gem.c +new file mode 100644 +index 0000000000000..2d3cf96f6c58d +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_gem.c +@@ -0,0 +1,381 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "lima_drv.h" ++#include "lima_gem.h" ++#include "lima_gem_prime.h" ++#include "lima_vm.h" ++#include "lima_object.h" ++ ++int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, ++ u32 size, u32 flags, u32 *handle) ++{ ++ int err; ++ struct lima_bo *bo; ++ struct lima_device *ldev = to_lima_dev(dev); ++ ++ bo = lima_bo_create(ldev, size, flags, NULL, NULL); ++ if (IS_ERR(bo)) ++ return PTR_ERR(bo); ++ ++ err = drm_gem_handle_create(file, &bo->gem, handle); ++ ++ /* drop reference from allocate - handle holds it now */ ++ drm_gem_object_put_unlocked(&bo->gem); ++ ++ return err; ++} ++ ++void lima_gem_free_object(struct drm_gem_object *obj) ++{ ++ struct lima_bo *bo = to_lima_bo(obj); ++ ++ if (!list_empty(&bo->va)) ++ dev_err(obj->dev->dev, "lima gem free bo still has va\n"); ++ ++ lima_bo_destroy(bo); ++} ++ ++int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file) ++{ ++ struct lima_bo *bo = to_lima_bo(obj); ++ struct lima_drm_priv *priv = to_lima_drm_priv(file); ++ struct lima_vm *vm = priv->vm; ++ ++ return lima_vm_bo_add(vm, bo, true); ++} ++ ++void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file) ++{ ++ struct lima_bo *bo = to_lima_bo(obj); ++ struct lima_drm_priv *priv = to_lima_drm_priv(file); ++ struct lima_vm *vm = priv->vm; ++ ++ lima_vm_bo_del(vm, bo); ++} ++ ++int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset) ++{ ++ struct drm_gem_object *obj; ++ struct lima_bo *bo; ++ struct lima_drm_priv *priv = to_lima_drm_priv(file); ++ struct lima_vm *vm = priv->vm; ++ int err; ++ ++ obj = drm_gem_object_lookup(file, handle); ++ if (!obj) ++ return -ENOENT; ++ ++ bo = to_lima_bo(obj); ++ ++ *va = lima_vm_get_va(vm, bo); ++ ++ err = drm_gem_create_mmap_offset(obj); ++ if (!err) ++ *offset = drm_vma_node_offset_addr(&obj->vma_node); ++ ++ drm_gem_object_put_unlocked(obj); ++ return err; ++} ++ ++static vm_fault_t lima_gem_fault(struct vm_fault *vmf) ++{ ++ struct vm_area_struct *vma = vmf->vma; ++ struct drm_gem_object *obj = vma->vm_private_data; ++ struct lima_bo *bo = to_lima_bo(obj); ++ pfn_t pfn; ++ pgoff_t pgoff; ++ ++ /* We don't use vmf->pgoff since that has the fake offset: */ ++ pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; ++ pfn = __pfn_to_pfn_t(page_to_pfn(bo->pages[pgoff]), PFN_DEV); ++ ++ return vmf_insert_mixed(vma, vmf->address, pfn); ++} ++ ++const struct vm_operations_struct lima_gem_vm_ops = { ++ .fault = lima_gem_fault, ++ .open = drm_gem_vm_open, ++ .close = drm_gem_vm_close, ++}; ++ ++void lima_set_vma_flags(struct vm_area_struct *vma) ++{ ++ pgprot_t prot = vm_get_page_prot(vma->vm_flags); ++ ++ vma->vm_flags |= VM_MIXEDMAP; ++ vma->vm_flags &= ~VM_PFNMAP; ++ vma->vm_page_prot = pgprot_writecombine(prot); ++} ++ ++int lima_gem_mmap(struct file *filp, struct vm_area_struct *vma) ++{ ++ int ret; ++ ++ ret = drm_gem_mmap(filp, vma); ++ if (ret) ++ return ret; ++ ++ lima_set_vma_flags(vma); ++ return 0; ++} ++ ++static int lima_gem_sync_bo(struct lima_sched_task *task, struct lima_bo *bo, ++ bool write, bool explicit) ++{ ++ int err = 0; ++ ++ if (!write) { ++ err = reservation_object_reserve_shared(bo->gem.resv, 1); ++ if (err) ++ return err; ++ } ++ ++ /* explicit sync use user passed dep fence */ ++ if (explicit) ++ return 0; ++ ++ /* implicit sync use bo fence in resv obj */ ++ if (write) { ++ unsigned nr_fences; ++ struct dma_fence **fences; ++ int i; ++ ++ err = reservation_object_get_fences_rcu( ++ bo->gem.resv, NULL, &nr_fences, &fences); ++ if (err || !nr_fences) ++ return err; ++ ++ for (i = 0; i < nr_fences; i++) { ++ err = lima_sched_task_add_dep(task, fences[i]); ++ if (err) ++ break; ++ } ++ ++ /* for error case free remaining fences */ ++ for ( ; i < nr_fences; i++) ++ dma_fence_put(fences[i]); ++ ++ kfree(fences); ++ } else { ++ struct dma_fence *fence; ++ ++ fence = reservation_object_get_excl_rcu(bo->gem.resv); ++ if (fence) { ++ err = lima_sched_task_add_dep(task, fence); ++ if (err) ++ dma_fence_put(fence); ++ } ++ } ++ ++ return err; ++} ++ ++static int lima_gem_lock_bos(struct lima_bo **bos, u32 nr_bos, ++ struct ww_acquire_ctx *ctx) ++{ ++ int i, ret = 0, contended, slow_locked = -1; ++ ++ ww_acquire_init(ctx, &reservation_ww_class); ++ ++retry: ++ for (i = 0; i < nr_bos; i++) { ++ if (i == slow_locked) { ++ slow_locked = -1; ++ continue; ++ } ++ ++ ret = ww_mutex_lock_interruptible(&bos[i]->gem.resv->lock, ctx); ++ if (ret < 0) { ++ contended = i; ++ goto err; ++ } ++ } ++ ++ ww_acquire_done(ctx); ++ return 0; ++ ++err: ++ for (i--; i >= 0; i--) ++ ww_mutex_unlock(&bos[i]->gem.resv->lock); ++ ++ if (slow_locked >= 0) ++ ww_mutex_unlock(&bos[slow_locked]->gem.resv->lock); ++ ++ if (ret == -EDEADLK) { ++ /* we lost out in a seqno race, lock and retry.. */ ++ ret = ww_mutex_lock_slow_interruptible( ++ &bos[contended]->gem.resv->lock, ctx); ++ if (!ret) { ++ slow_locked = contended; ++ goto retry; ++ } ++ } ++ ww_acquire_fini(ctx); ++ ++ return ret; ++} ++ ++static void lima_gem_unlock_bos(struct lima_bo **bos, u32 nr_bos, ++ struct ww_acquire_ctx *ctx) ++{ ++ int i; ++ ++ for (i = 0; i < nr_bos; i++) ++ ww_mutex_unlock(&bos[i]->gem.resv->lock); ++ ww_acquire_fini(ctx); ++} ++ ++static int lima_gem_add_deps(struct drm_file *file, struct lima_submit *submit) ++{ ++ int i, err; ++ ++ for (i = 0; i < ARRAY_SIZE(submit->in_sync); i++) { ++ struct dma_fence *fence = NULL; ++ ++ if (!submit->in_sync[i]) ++ continue; ++ ++ err = drm_syncobj_find_fence(file, submit->in_sync[i], ++ 0, 0, &fence); ++ if (err) ++ return err; ++ ++ err = lima_sched_task_add_dep(submit->task, fence); ++ if (err) { ++ dma_fence_put(fence); ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ ++int lima_gem_submit(struct drm_file *file, struct lima_submit *submit) ++{ ++ int i, err = 0; ++ struct ww_acquire_ctx ctx; ++ struct lima_drm_priv *priv = to_lima_drm_priv(file); ++ struct lima_vm *vm = priv->vm; ++ struct drm_syncobj *out_sync = NULL; ++ struct dma_fence *fence; ++ struct lima_bo **bos = submit->lbos; ++ ++ if (submit->out_sync) { ++ out_sync = drm_syncobj_find(file, submit->out_sync); ++ if (!out_sync) ++ return -ENOENT; ++ } ++ ++ for (i = 0; i < submit->nr_bos; i++) { ++ struct drm_gem_object *obj; ++ struct lima_bo *bo; ++ ++ obj = drm_gem_object_lookup(file, submit->bos[i].handle); ++ if (!obj) { ++ err = -ENOENT; ++ goto err_out0; ++ } ++ ++ bo = to_lima_bo(obj); ++ ++ /* increase refcnt of gpu va map to prevent unmapped when executing, ++ * will be decreased when task done ++ */ ++ err = lima_vm_bo_add(vm, bo, false); ++ if (err) { ++ drm_gem_object_put_unlocked(obj); ++ goto err_out0; ++ } ++ ++ bos[i] = bo; ++ } ++ ++ err = lima_gem_lock_bos(bos, submit->nr_bos, &ctx); ++ if (err) ++ goto err_out0; ++ ++ err = lima_sched_task_init( ++ submit->task, submit->ctx->context + submit->pipe, ++ bos, submit->nr_bos, vm); ++ if (err) ++ goto err_out1; ++ ++ err = lima_gem_add_deps(file, submit); ++ if (err) ++ goto err_out2; ++ ++ for (i = 0; i < submit->nr_bos; i++) { ++ err = lima_gem_sync_bo( ++ submit->task, bos[i], ++ submit->bos[i].flags & LIMA_SUBMIT_BO_WRITE, ++ submit->flags & LIMA_SUBMIT_FLAG_EXPLICIT_FENCE); ++ if (err) ++ goto err_out2; ++ } ++ ++ fence = lima_sched_context_queue_task( ++ submit->ctx->context + submit->pipe, submit->task); ++ ++ for (i = 0; i < submit->nr_bos; i++) { ++ if (submit->bos[i].flags & LIMA_SUBMIT_BO_WRITE) ++ reservation_object_add_excl_fence(bos[i]->gem.resv, fence); ++ else ++ reservation_object_add_shared_fence(bos[i]->gem.resv, fence); ++ } ++ ++ lima_gem_unlock_bos(bos, submit->nr_bos, &ctx); ++ ++ for (i = 0; i < submit->nr_bos; i++) ++ drm_gem_object_put_unlocked(&bos[i]->gem); ++ ++ if (out_sync) { ++ drm_syncobj_replace_fence(out_sync, fence); ++ drm_syncobj_put(out_sync); ++ } ++ ++ dma_fence_put(fence); ++ ++ return 0; ++ ++err_out2: ++ lima_sched_task_fini(submit->task); ++err_out1: ++ lima_gem_unlock_bos(bos, submit->nr_bos, &ctx); ++err_out0: ++ for (i = 0; i < submit->nr_bos; i++) { ++ if (!bos[i]) ++ break; ++ lima_vm_bo_del(vm, bos[i]); ++ drm_gem_object_put_unlocked(&bos[i]->gem); ++ } ++ if (out_sync) ++ drm_syncobj_put(out_sync); ++ return err; ++} ++ ++int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns) ++{ ++ bool write = op & LIMA_GEM_WAIT_WRITE; ++ long ret, timeout; ++ ++ if (!op) ++ return 0; ++ ++ timeout = drm_timeout_abs_to_jiffies(timeout_ns); ++ ++ ret = drm_gem_reservation_object_wait(file, handle, write, timeout); ++ if (ret == 0) ++ ret = timeout ? -ETIMEDOUT : -EBUSY; ++ ++ return ret; ++} +diff --git a/drivers/gpu/drm/lima/lima_gem.h b/drivers/gpu/drm/lima/lima_gem.h +new file mode 100644 +index 0000000000000..556111a01135d +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_gem.h +@@ -0,0 +1,25 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_GEM_H__ ++#define __LIMA_GEM_H__ ++ ++struct lima_bo; ++struct lima_submit; ++ ++extern const struct vm_operations_struct lima_gem_vm_ops; ++ ++struct lima_bo *lima_gem_create_bo(struct drm_device *dev, u32 size, u32 flags); ++int lima_gem_create_handle(struct drm_device *dev, struct drm_file *file, ++ u32 size, u32 flags, u32 *handle); ++void lima_gem_free_object(struct drm_gem_object *obj); ++int lima_gem_object_open(struct drm_gem_object *obj, struct drm_file *file); ++void lima_gem_object_close(struct drm_gem_object *obj, struct drm_file *file); ++int lima_gem_get_info(struct drm_file *file, u32 handle, u32 *va, u64 *offset); ++int lima_gem_mmap(struct file *filp, struct vm_area_struct *vma); ++int lima_gem_submit(struct drm_file *file, struct lima_submit *submit); ++int lima_gem_wait(struct drm_file *file, u32 handle, u32 op, s64 timeout_ns); ++ ++void lima_set_vma_flags(struct vm_area_struct *vma); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_gem_prime.c b/drivers/gpu/drm/lima/lima_gem_prime.c +new file mode 100644 +index 0000000000000..9c6d9f1dba557 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_gem_prime.c +@@ -0,0 +1,47 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#include ++#include ++#include ++#include ++ ++#include "lima_device.h" ++#include "lima_object.h" ++#include "lima_gem.h" ++#include "lima_gem_prime.h" ++ ++struct drm_gem_object *lima_gem_prime_import_sg_table( ++ struct drm_device *dev, struct dma_buf_attachment *attach, ++ struct sg_table *sgt) ++{ ++ struct lima_device *ldev = to_lima_dev(dev); ++ struct lima_bo *bo; ++ ++ bo = lima_bo_create(ldev, attach->dmabuf->size, 0, sgt, ++ attach->dmabuf->resv); ++ if (IS_ERR(bo)) ++ return ERR_CAST(bo); ++ ++ return &bo->gem; ++} ++ ++struct sg_table *lima_gem_prime_get_sg_table(struct drm_gem_object *obj) ++{ ++ struct lima_bo *bo = to_lima_bo(obj); ++ int npages = obj->size >> PAGE_SHIFT; ++ ++ return drm_prime_pages_to_sg(bo->pages, npages); ++} ++ ++int lima_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) ++{ ++ int ret; ++ ++ ret = drm_gem_mmap_obj(obj, obj->size, vma); ++ if (ret) ++ return ret; ++ ++ lima_set_vma_flags(vma); ++ return 0; ++} +diff --git a/drivers/gpu/drm/lima/lima_gem_prime.h b/drivers/gpu/drm/lima/lima_gem_prime.h +new file mode 100644 +index 0000000000000..34b4d35c21e3e +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_gem_prime.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#ifndef __LIMA_GEM_PRIME_H__ ++#define __LIMA_GEM_PRIME_H__ ++ ++struct drm_gem_object *lima_gem_prime_import_sg_table( ++ struct drm_device *dev, struct dma_buf_attachment *attach, ++ struct sg_table *sgt); ++struct sg_table *lima_gem_prime_get_sg_table(struct drm_gem_object *obj); ++int lima_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_gp.c b/drivers/gpu/drm/lima/lima_gp.c +new file mode 100644 +index 0000000000000..ccf49faedebf8 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_gp.c +@@ -0,0 +1,283 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "lima_device.h" ++#include "lima_gp.h" ++#include "lima_regs.h" ++ ++#define gp_write(reg, data) writel(data, ip->iomem + reg) ++#define gp_read(reg) readl(ip->iomem + reg) ++ ++static irqreturn_t lima_gp_irq_handler(int irq, void *data) ++{ ++ struct lima_ip *ip = data; ++ struct lima_device *dev = ip->dev; ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; ++ u32 state = gp_read(LIMA_GP_INT_STAT); ++ u32 status = gp_read(LIMA_GP_STATUS); ++ bool done = false; ++ ++ /* for shared irq case */ ++ if (!state) ++ return IRQ_NONE; ++ ++ if (state & LIMA_GP_IRQ_MASK_ERROR) { ++ dev_err(dev->dev, "gp error irq state=%x status=%x\n", ++ state, status); ++ ++ /* mask all interrupts before hard reset */ ++ gp_write(LIMA_GP_INT_MASK, 0); ++ ++ pipe->error = true; ++ done = true; ++ } else { ++ bool valid = state & (LIMA_GP_IRQ_VS_END_CMD_LST | ++ LIMA_GP_IRQ_PLBU_END_CMD_LST); ++ bool active = status & (LIMA_GP_STATUS_VS_ACTIVE | ++ LIMA_GP_STATUS_PLBU_ACTIVE); ++ done = valid && !active; ++ } ++ ++ gp_write(LIMA_GP_INT_CLEAR, state); ++ ++ if (done) ++ lima_sched_pipe_task_done(pipe); ++ ++ return IRQ_HANDLED; ++} ++ ++static void lima_gp_soft_reset_async(struct lima_ip *ip) ++{ ++ if (ip->data.async_reset) ++ return; ++ ++ gp_write(LIMA_GP_INT_MASK, 0); ++ gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_RESET_COMPLETED); ++ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_SOFT_RESET); ++ ip->data.async_reset = true; ++} ++ ++static int lima_gp_soft_reset_async_wait(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int err; ++ u32 v; ++ ++ if (!ip->data.async_reset) ++ return 0; ++ ++ err = readl_poll_timeout(ip->iomem + LIMA_GP_INT_RAWSTAT, v, ++ v & LIMA_GP_IRQ_RESET_COMPLETED, ++ 0, 100); ++ if (err) { ++ dev_err(dev->dev, "gp soft reset time out\n"); ++ return err; ++ } ++ ++ gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL); ++ gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); ++ ++ ip->data.async_reset = false; ++ return 0; ++} ++ ++static int lima_gp_task_validate(struct lima_sched_pipe *pipe, ++ struct lima_sched_task *task) ++{ ++ struct drm_lima_gp_frame *frame = task->frame; ++ u32 *f = frame->frame; ++ (void)pipe; ++ ++ if (f[LIMA_GP_VSCL_START_ADDR >> 2] > ++ f[LIMA_GP_VSCL_END_ADDR >> 2] || ++ f[LIMA_GP_PLBUCL_START_ADDR >> 2] > ++ f[LIMA_GP_PLBUCL_END_ADDR >> 2] || ++ f[LIMA_GP_PLBU_ALLOC_START_ADDR >> 2] > ++ f[LIMA_GP_PLBU_ALLOC_END_ADDR >> 2]) ++ return -EINVAL; ++ ++ if (f[LIMA_GP_VSCL_START_ADDR >> 2] == ++ f[LIMA_GP_VSCL_END_ADDR >> 2] && ++ f[LIMA_GP_PLBUCL_START_ADDR >> 2] == ++ f[LIMA_GP_PLBUCL_END_ADDR >> 2]) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void lima_gp_task_run(struct lima_sched_pipe *pipe, ++ struct lima_sched_task *task) ++{ ++ struct lima_ip *ip = pipe->processor[0]; ++ struct drm_lima_gp_frame *frame = task->frame; ++ u32 *f = frame->frame; ++ u32 cmd = 0; ++ int i; ++ ++ if (f[LIMA_GP_VSCL_START_ADDR >> 2] != ++ f[LIMA_GP_VSCL_END_ADDR >> 2]) ++ cmd |= LIMA_GP_CMD_START_VS; ++ if (f[LIMA_GP_PLBUCL_START_ADDR >> 2] != ++ f[LIMA_GP_PLBUCL_END_ADDR >> 2]) ++ cmd |= LIMA_GP_CMD_START_PLBU; ++ ++ /* before any hw ops, wait last success task async soft reset */ ++ lima_gp_soft_reset_async_wait(ip); ++ ++ for (i = 0; i < LIMA_GP_FRAME_REG_NUM; i++) ++ writel(f[i], ip->iomem + LIMA_GP_VSCL_START_ADDR + i * 4); ++ ++ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_UPDATE_PLBU_ALLOC); ++ gp_write(LIMA_GP_CMD, cmd); ++} ++ ++static int lima_gp_hard_reset_poll(struct lima_ip *ip) ++{ ++ gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC01A0000); ++ return gp_read(LIMA_GP_PERF_CNT_0_LIMIT) == 0xC01A0000; ++} ++ ++static int lima_gp_hard_reset(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int ret; ++ ++ gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0xC0FFE000); ++ gp_write(LIMA_GP_INT_MASK, 0); ++ gp_write(LIMA_GP_CMD, LIMA_GP_CMD_RESET); ++ ret = lima_poll_timeout(ip, lima_gp_hard_reset_poll, 10, 100); ++ if (ret) { ++ dev_err(dev->dev, "gp hard reset timeout\n"); ++ return ret; ++ } ++ ++ gp_write(LIMA_GP_PERF_CNT_0_LIMIT, 0); ++ gp_write(LIMA_GP_INT_CLEAR, LIMA_GP_IRQ_MASK_ALL); ++ gp_write(LIMA_GP_INT_MASK, LIMA_GP_IRQ_MASK_USED); ++ return 0; ++} ++ ++static void lima_gp_task_fini(struct lima_sched_pipe *pipe) ++{ ++ lima_gp_soft_reset_async(pipe->processor[0]); ++} ++ ++static void lima_gp_task_error(struct lima_sched_pipe *pipe) ++{ ++ struct lima_ip *ip = pipe->processor[0]; ++ ++ dev_err(ip->dev->dev, "gp task error int_state=%x status=%x\n", ++ gp_read(LIMA_GP_INT_STAT), gp_read(LIMA_GP_STATUS)); ++ ++ lima_gp_hard_reset(ip); ++} ++ ++static void lima_gp_task_mmu_error(struct lima_sched_pipe *pipe) ++{ ++ lima_sched_pipe_task_done(pipe); ++} ++ ++static void lima_gp_print_version(struct lima_ip *ip) ++{ ++ u32 version, major, minor; ++ char *name; ++ ++ version = gp_read(LIMA_GP_VERSION); ++ major = (version >> 8) & 0xFF; ++ minor = version & 0xFF; ++ switch (version >> 16) { ++ case 0xA07: ++ name = "mali200"; ++ break; ++ case 0xC07: ++ name = "mali300"; ++ break; ++ case 0xB07: ++ name = "mali400"; ++ break; ++ case 0xD07: ++ name = "mali450"; ++ break; ++ default: ++ name = "unknown"; ++ break; ++ } ++ dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n", ++ lima_ip_name(ip), name, major, minor); ++} ++ ++static struct kmem_cache *lima_gp_task_slab; ++static int lima_gp_task_slab_refcnt; ++ ++int lima_gp_init(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int err; ++ ++ lima_gp_print_version(ip); ++ ++ ip->data.async_reset = false; ++ lima_gp_soft_reset_async(ip); ++ err = lima_gp_soft_reset_async_wait(ip); ++ if (err) ++ return err; ++ ++ err = devm_request_irq(dev->dev, ip->irq, lima_gp_irq_handler, ++ IRQF_SHARED, lima_ip_name(ip), ip); ++ if (err) { ++ dev_err(dev->dev, "gp %s fail to request irq\n", ++ lima_ip_name(ip)); ++ return err; ++ } ++ ++ dev->gp_version = gp_read(LIMA_GP_VERSION); ++ ++ return 0; ++} ++ ++void lima_gp_fini(struct lima_ip *ip) ++{ ++ ++} ++ ++int lima_gp_pipe_init(struct lima_device *dev) ++{ ++ int frame_size = sizeof(struct drm_lima_gp_frame); ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_gp; ++ ++ if (!lima_gp_task_slab) { ++ lima_gp_task_slab = kmem_cache_create_usercopy( ++ "lima_gp_task", sizeof(struct lima_sched_task) + frame_size, ++ 0, SLAB_HWCACHE_ALIGN, sizeof(struct lima_sched_task), ++ frame_size, NULL); ++ if (!lima_gp_task_slab) ++ return -ENOMEM; ++ } ++ lima_gp_task_slab_refcnt++; ++ ++ pipe->frame_size = frame_size; ++ pipe->task_slab = lima_gp_task_slab; ++ ++ pipe->task_validate = lima_gp_task_validate; ++ pipe->task_run = lima_gp_task_run; ++ pipe->task_fini = lima_gp_task_fini; ++ pipe->task_error = lima_gp_task_error; ++ pipe->task_mmu_error = lima_gp_task_mmu_error; ++ ++ return 0; ++} ++ ++void lima_gp_pipe_fini(struct lima_device *dev) ++{ ++ if (!--lima_gp_task_slab_refcnt) { ++ kmem_cache_destroy(lima_gp_task_slab); ++ lima_gp_task_slab = NULL; ++ } ++} +diff --git a/drivers/gpu/drm/lima/lima_gp.h b/drivers/gpu/drm/lima/lima_gp.h +new file mode 100644 +index 0000000000000..516e5c1babbb4 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_gp.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_GP_H__ ++#define __LIMA_GP_H__ ++ ++struct lima_ip; ++struct lima_device; ++ ++int lima_gp_init(struct lima_ip *ip); ++void lima_gp_fini(struct lima_ip *ip); ++ ++int lima_gp_pipe_init(struct lima_device *dev); ++void lima_gp_pipe_fini(struct lima_device *dev); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_l2_cache.c b/drivers/gpu/drm/lima/lima_l2_cache.c +new file mode 100644 +index 0000000000000..6873a7af5a5ce +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_l2_cache.c +@@ -0,0 +1,80 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++ ++#include "lima_device.h" ++#include "lima_l2_cache.h" ++#include "lima_regs.h" ++ ++#define l2_cache_write(reg, data) writel(data, ip->iomem + reg) ++#define l2_cache_read(reg) readl(ip->iomem + reg) ++ ++static int lima_l2_cache_wait_idle(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int err; ++ u32 v; ++ ++ err = readl_poll_timeout(ip->iomem + LIMA_L2_CACHE_STATUS, v, ++ !(v & LIMA_L2_CACHE_STATUS_COMMAND_BUSY), ++ 0, 1000); ++ if (err) { ++ dev_err(dev->dev, "l2 cache wait command timeout\n"); ++ return err; ++ } ++ return 0; ++} ++ ++int lima_l2_cache_flush(struct lima_ip *ip) ++{ ++ int ret; ++ ++ spin_lock(&ip->data.lock); ++ l2_cache_write(LIMA_L2_CACHE_COMMAND, LIMA_L2_CACHE_COMMAND_CLEAR_ALL); ++ ret = lima_l2_cache_wait_idle(ip); ++ spin_unlock(&ip->data.lock); ++ return ret; ++} ++ ++int lima_l2_cache_init(struct lima_ip *ip) ++{ ++ int i, err; ++ u32 size; ++ struct lima_device *dev = ip->dev; ++ ++ /* l2_cache2 only exists when one of PP4-7 present */ ++ if (ip->id == lima_ip_l2_cache2) { ++ for (i = lima_ip_pp4; i <= lima_ip_pp7; i++) { ++ if (dev->ip[i].present) ++ break; ++ } ++ if (i > lima_ip_pp7) ++ return -ENODEV; ++ } ++ ++ spin_lock_init(&ip->data.lock); ++ ++ size = l2_cache_read(LIMA_L2_CACHE_SIZE); ++ dev_info(dev->dev, "l2 cache %uK, %u-way, %ubyte cache line, %ubit external bus\n", ++ 1 << (((size >> 16) & 0xff) - 10), ++ 1 << ((size >> 8) & 0xff), ++ 1 << (size & 0xff), ++ 1 << ((size >> 24) & 0xff)); ++ ++ err = lima_l2_cache_flush(ip); ++ if (err) ++ return err; ++ ++ l2_cache_write(LIMA_L2_CACHE_ENABLE, ++ LIMA_L2_CACHE_ENABLE_ACCESS|LIMA_L2_CACHE_ENABLE_READ_ALLOCATE); ++ l2_cache_write(LIMA_L2_CACHE_MAX_READS, 0x1c); ++ ++ return 0; ++} ++ ++void lima_l2_cache_fini(struct lima_ip *ip) ++{ ++ ++} +diff --git a/drivers/gpu/drm/lima/lima_l2_cache.h b/drivers/gpu/drm/lima/lima_l2_cache.h +new file mode 100644 +index 0000000000000..c63fb676ff141 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_l2_cache.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_L2_CACHE_H__ ++#define __LIMA_L2_CACHE_H__ ++ ++struct lima_ip; ++ ++int lima_l2_cache_init(struct lima_ip *ip); ++void lima_l2_cache_fini(struct lima_ip *ip); ++ ++int lima_l2_cache_flush(struct lima_ip *ip); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_mmu.c b/drivers/gpu/drm/lima/lima_mmu.c +new file mode 100644 +index 0000000000000..8e1651d6a61fa +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_mmu.c +@@ -0,0 +1,142 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++#include ++ ++#include "lima_device.h" ++#include "lima_mmu.h" ++#include "lima_vm.h" ++#include "lima_object.h" ++#include "lima_regs.h" ++ ++#define mmu_write(reg, data) writel(data, ip->iomem + reg) ++#define mmu_read(reg) readl(ip->iomem + reg) ++ ++#define lima_mmu_send_command(cmd, addr, val, cond) \ ++({ \ ++ int __ret; \ ++ \ ++ mmu_write(LIMA_MMU_COMMAND, cmd); \ ++ __ret = readl_poll_timeout(ip->iomem + (addr), val, \ ++ cond, 0, 100); \ ++ if (__ret) \ ++ dev_err(dev->dev, \ ++ "mmu command %x timeout\n", cmd); \ ++ __ret; \ ++}) ++ ++static irqreturn_t lima_mmu_irq_handler(int irq, void *data) ++{ ++ struct lima_ip *ip = data; ++ struct lima_device *dev = ip->dev; ++ u32 status = mmu_read(LIMA_MMU_INT_STATUS); ++ struct lima_sched_pipe *pipe; ++ ++ /* for shared irq case */ ++ if (!status) ++ return IRQ_NONE; ++ ++ if (status & LIMA_MMU_INT_PAGE_FAULT) { ++ u32 fault = mmu_read(LIMA_MMU_PAGE_FAULT_ADDR); ++ ++ dev_err(dev->dev, "mmu page fault at 0x%x from bus id %d of type %s on %s\n", ++ fault, LIMA_MMU_STATUS_BUS_ID(status), ++ status & LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE ? "write" : "read", ++ lima_ip_name(ip)); ++ } ++ ++ if (status & LIMA_MMU_INT_READ_BUS_ERROR) ++ dev_err(dev->dev, "mmu %s irq bus error\n", lima_ip_name(ip)); ++ ++ /* mask all interrupts before resume */ ++ mmu_write(LIMA_MMU_INT_MASK, 0); ++ mmu_write(LIMA_MMU_INT_CLEAR, status); ++ ++ pipe = dev->pipe + (ip->id == lima_ip_gpmmu ? lima_pipe_gp : lima_pipe_pp); ++ lima_sched_pipe_mmu_error(pipe); ++ ++ return IRQ_HANDLED; ++} ++ ++int lima_mmu_init(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int err; ++ u32 v; ++ ++ if (ip->id == lima_ip_ppmmu_bcast) ++ return 0; ++ ++ mmu_write(LIMA_MMU_DTE_ADDR, 0xCAFEBABE); ++ if (mmu_read(LIMA_MMU_DTE_ADDR) != 0xCAFEB000) { ++ dev_err(dev->dev, "mmu %s dte write test fail\n", lima_ip_name(ip)); ++ return -EIO; ++ } ++ ++ mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_HARD_RESET); ++ err = lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET, ++ LIMA_MMU_DTE_ADDR, v, v == 0); ++ if (err) ++ return err; ++ ++ err = devm_request_irq(dev->dev, ip->irq, lima_mmu_irq_handler, ++ IRQF_SHARED, lima_ip_name(ip), ip); ++ if (err) { ++ dev_err(dev->dev, "mmu %s fail to request irq\n", lima_ip_name(ip)); ++ return err; ++ } ++ ++ mmu_write(LIMA_MMU_INT_MASK, LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR); ++ mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma); ++ return lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING, ++ LIMA_MMU_STATUS, v, ++ v & LIMA_MMU_STATUS_PAGING_ENABLED); ++} ++ ++void lima_mmu_fini(struct lima_ip *ip) ++{ ++ ++} ++ ++void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm) ++{ ++ struct lima_device *dev = ip->dev; ++ u32 v; ++ ++ lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_STALL, ++ LIMA_MMU_STATUS, v, ++ v & LIMA_MMU_STATUS_STALL_ACTIVE); ++ ++ if (vm) ++ mmu_write(LIMA_MMU_DTE_ADDR, vm->pd.dma); ++ ++ /* flush the TLB */ ++ mmu_write(LIMA_MMU_COMMAND, LIMA_MMU_COMMAND_ZAP_CACHE); ++ ++ lima_mmu_send_command(LIMA_MMU_COMMAND_DISABLE_STALL, ++ LIMA_MMU_STATUS, v, ++ !(v & LIMA_MMU_STATUS_STALL_ACTIVE)); ++} ++ ++void lima_mmu_page_fault_resume(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ u32 status = mmu_read(LIMA_MMU_STATUS); ++ u32 v; ++ ++ if (status & LIMA_MMU_STATUS_PAGE_FAULT_ACTIVE) { ++ dev_info(dev->dev, "mmu resume\n"); ++ ++ mmu_write(LIMA_MMU_INT_MASK, 0); ++ mmu_write(LIMA_MMU_DTE_ADDR, 0xCAFEBABE); ++ lima_mmu_send_command(LIMA_MMU_COMMAND_HARD_RESET, ++ LIMA_MMU_DTE_ADDR, v, v == 0); ++ mmu_write(LIMA_MMU_INT_MASK, LIMA_MMU_INT_PAGE_FAULT | LIMA_MMU_INT_READ_BUS_ERROR); ++ mmu_write(LIMA_MMU_DTE_ADDR, dev->empty_vm->pd.dma); ++ lima_mmu_send_command(LIMA_MMU_COMMAND_ENABLE_PAGING, ++ LIMA_MMU_STATUS, v, ++ v & LIMA_MMU_STATUS_PAGING_ENABLED); ++ } ++} +diff --git a/drivers/gpu/drm/lima/lima_mmu.h b/drivers/gpu/drm/lima/lima_mmu.h +new file mode 100644 +index 0000000000000..8c78319bcc8e2 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_mmu.h +@@ -0,0 +1,16 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_MMU_H__ ++#define __LIMA_MMU_H__ ++ ++struct lima_ip; ++struct lima_vm; ++ ++int lima_mmu_init(struct lima_ip *ip); ++void lima_mmu_fini(struct lima_ip *ip); ++ ++void lima_mmu_switch_vm(struct lima_ip *ip, struct lima_vm *vm); ++void lima_mmu_page_fault_resume(struct lima_ip *ip); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_object.c b/drivers/gpu/drm/lima/lima_object.c +new file mode 100644 +index 0000000000000..5c41f859a72fa +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_object.c +@@ -0,0 +1,122 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#include ++#include ++#include ++ ++#include "lima_object.h" ++ ++void lima_bo_destroy(struct lima_bo *bo) ++{ ++ if (bo->sgt) { ++ kfree(bo->pages); ++ drm_prime_gem_destroy(&bo->gem, bo->sgt); ++ } else { ++ if (bo->pages_dma_addr) { ++ int i, npages = bo->gem.size >> PAGE_SHIFT; ++ ++ for (i = 0; i < npages; i++) { ++ if (bo->pages_dma_addr[i]) ++ dma_unmap_page(bo->gem.dev->dev, ++ bo->pages_dma_addr[i], ++ PAGE_SIZE, DMA_BIDIRECTIONAL); ++ } ++ } ++ ++ if (bo->pages) ++ drm_gem_put_pages(&bo->gem, bo->pages, true, true); ++ } ++ ++ kfree(bo->pages_dma_addr); ++ drm_gem_object_release(&bo->gem); ++ kfree(bo); ++} ++ ++static struct lima_bo *lima_bo_create_struct(struct lima_device *dev, u32 size, u32 flags, ++ struct reservation_object *resv) ++{ ++ struct lima_bo *bo; ++ int err; ++ ++ size = PAGE_ALIGN(size); ++ ++ bo = kzalloc(sizeof(*bo), GFP_KERNEL); ++ if (!bo) ++ return ERR_PTR(-ENOMEM); ++ ++ mutex_init(&bo->lock); ++ INIT_LIST_HEAD(&bo->va); ++ bo->gem.resv = resv; ++ ++ err = drm_gem_object_init(dev->ddev, &bo->gem, size); ++ if (err) { ++ kfree(bo); ++ return ERR_PTR(err); ++ } ++ ++ return bo; ++} ++ ++struct lima_bo *lima_bo_create(struct lima_device *dev, u32 size, ++ u32 flags, struct sg_table *sgt, ++ struct reservation_object *resv) ++{ ++ int i, err; ++ size_t npages; ++ struct lima_bo *bo, *ret; ++ ++ bo = lima_bo_create_struct(dev, size, flags, resv); ++ if (IS_ERR(bo)) ++ return bo; ++ ++ npages = bo->gem.size >> PAGE_SHIFT; ++ ++ bo->pages_dma_addr = kcalloc(npages, sizeof(dma_addr_t), GFP_KERNEL); ++ if (!bo->pages_dma_addr) { ++ ret = ERR_PTR(-ENOMEM); ++ goto err_out; ++ } ++ ++ if (sgt) { ++ bo->sgt = sgt; ++ ++ bo->pages = kcalloc(npages, sizeof(*bo->pages), GFP_KERNEL); ++ if (!bo->pages) { ++ ret = ERR_PTR(-ENOMEM); ++ goto err_out; ++ } ++ ++ err = drm_prime_sg_to_page_addr_arrays( ++ sgt, bo->pages, bo->pages_dma_addr, npages); ++ if (err) { ++ ret = ERR_PTR(err); ++ goto err_out; ++ } ++ } else { ++ mapping_set_gfp_mask(bo->gem.filp->f_mapping, GFP_DMA32); ++ bo->pages = drm_gem_get_pages(&bo->gem); ++ if (IS_ERR(bo->pages)) { ++ ret = ERR_CAST(bo->pages); ++ bo->pages = NULL; ++ goto err_out; ++ } ++ ++ for (i = 0; i < npages; i++) { ++ dma_addr_t addr = dma_map_page(dev->dev, bo->pages[i], 0, ++ PAGE_SIZE, DMA_BIDIRECTIONAL); ++ if (dma_mapping_error(dev->dev, addr)) { ++ ret = ERR_PTR(-EFAULT); ++ goto err_out; ++ } ++ bo->pages_dma_addr[i] = addr; ++ } ++ ++ } ++ ++ return bo; ++ ++err_out: ++ lima_bo_destroy(bo); ++ return ret; ++} +diff --git a/drivers/gpu/drm/lima/lima_object.h b/drivers/gpu/drm/lima/lima_object.h +new file mode 100644 +index 0000000000000..6738724afb7b0 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_object.h +@@ -0,0 +1,36 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2018-2019 Qiang Yu */ ++ ++#ifndef __LIMA_OBJECT_H__ ++#define __LIMA_OBJECT_H__ ++ ++#include ++ ++#include "lima_device.h" ++ ++struct lima_bo { ++ struct drm_gem_object gem; ++ ++ struct page **pages; ++ dma_addr_t *pages_dma_addr; ++ struct sg_table *sgt; ++ void *vaddr; ++ ++ struct mutex lock; ++ struct list_head va; ++}; ++ ++static inline struct lima_bo * ++to_lima_bo(struct drm_gem_object *obj) ++{ ++ return container_of(obj, struct lima_bo, gem); ++} ++ ++struct lima_bo *lima_bo_create(struct lima_device *dev, u32 size, ++ u32 flags, struct sg_table *sgt, ++ struct reservation_object *resv); ++void lima_bo_destroy(struct lima_bo *bo); ++void *lima_bo_vmap(struct lima_bo *bo); ++void lima_bo_vunmap(struct lima_bo *bo); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_pmu.c b/drivers/gpu/drm/lima/lima_pmu.c +new file mode 100644 +index 0000000000000..571f6d6615818 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_pmu.c +@@ -0,0 +1,60 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++ ++#include "lima_device.h" ++#include "lima_pmu.h" ++#include "lima_regs.h" ++ ++#define pmu_write(reg, data) writel(data, ip->iomem + reg) ++#define pmu_read(reg) readl(ip->iomem + reg) ++ ++static int lima_pmu_wait_cmd(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int err; ++ u32 v; ++ ++ err = readl_poll_timeout(ip->iomem + LIMA_PMU_INT_RAWSTAT, ++ v, v & LIMA_PMU_INT_CMD_MASK, ++ 100, 100000); ++ if (err) { ++ dev_err(dev->dev, "timeout wait pmd cmd\n"); ++ return err; ++ } ++ ++ pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK); ++ return 0; ++} ++ ++int lima_pmu_init(struct lima_ip *ip) ++{ ++ int err; ++ u32 stat; ++ ++ pmu_write(LIMA_PMU_INT_MASK, 0); ++ ++ /* If this value is too low, when in high GPU clk freq, ++ * GPU will be in unstable state. ++ */ ++ pmu_write(LIMA_PMU_SW_DELAY, 0xffff); ++ ++ /* status reg 1=off 0=on */ ++ stat = pmu_read(LIMA_PMU_STATUS); ++ ++ /* power up all ip */ ++ if (stat) { ++ pmu_write(LIMA_PMU_POWER_UP, stat); ++ err = lima_pmu_wait_cmd(ip); ++ if (err) ++ return err; ++ } ++ return 0; ++} ++ ++void lima_pmu_fini(struct lima_ip *ip) ++{ ++ ++} +diff --git a/drivers/gpu/drm/lima/lima_pmu.h b/drivers/gpu/drm/lima/lima_pmu.h +new file mode 100644 +index 0000000000000..a2a18775eb07d +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_pmu.h +@@ -0,0 +1,12 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_PMU_H__ ++#define __LIMA_PMU_H__ ++ ++struct lima_ip; ++ ++int lima_pmu_init(struct lima_ip *ip); ++void lima_pmu_fini(struct lima_ip *ip); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_pp.c b/drivers/gpu/drm/lima/lima_pp.c +new file mode 100644 +index 0000000000000..d29721e177bf9 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_pp.c +@@ -0,0 +1,427 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "lima_device.h" ++#include "lima_pp.h" ++#include "lima_dlbu.h" ++#include "lima_bcast.h" ++#include "lima_vm.h" ++#include "lima_regs.h" ++ ++#define pp_write(reg, data) writel(data, ip->iomem + reg) ++#define pp_read(reg) readl(ip->iomem + reg) ++ ++static void lima_pp_handle_irq(struct lima_ip *ip, u32 state) ++{ ++ struct lima_device *dev = ip->dev; ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ ++ if (state & LIMA_PP_IRQ_MASK_ERROR) { ++ u32 status = pp_read(LIMA_PP_STATUS); ++ ++ dev_err(dev->dev, "pp error irq state=%x status=%x\n", ++ state, status); ++ ++ pipe->error = true; ++ ++ /* mask all interrupts before hard reset */ ++ pp_write(LIMA_PP_INT_MASK, 0); ++ } ++ ++ pp_write(LIMA_PP_INT_CLEAR, state); ++} ++ ++static irqreturn_t lima_pp_irq_handler(int irq, void *data) ++{ ++ struct lima_ip *ip = data; ++ struct lima_device *dev = ip->dev; ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ u32 state = pp_read(LIMA_PP_INT_STATUS); ++ ++ /* for shared irq case */ ++ if (!state) ++ return IRQ_NONE; ++ ++ lima_pp_handle_irq(ip, state); ++ ++ if (atomic_dec_and_test(&pipe->task)) ++ lima_sched_pipe_task_done(pipe); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t lima_pp_bcast_irq_handler(int irq, void *data) ++{ ++ int i; ++ irqreturn_t ret = IRQ_NONE; ++ struct lima_ip *pp_bcast = data; ++ struct lima_device *dev = pp_bcast->dev; ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ struct drm_lima_m450_pp_frame *frame = pipe->current_task->frame; ++ ++ for (i = 0; i < frame->num_pp; i++) { ++ struct lima_ip *ip = pipe->processor[i]; ++ u32 status, state; ++ ++ if (pipe->done & (1 << i)) ++ continue; ++ ++ /* status read first in case int state change in the middle ++ * which may miss the interrupt handling ++ */ ++ status = pp_read(LIMA_PP_STATUS); ++ state = pp_read(LIMA_PP_INT_STATUS); ++ ++ if (state) { ++ lima_pp_handle_irq(ip, state); ++ ret = IRQ_HANDLED; ++ } else { ++ if (status & LIMA_PP_STATUS_RENDERING_ACTIVE) ++ continue; ++ } ++ ++ pipe->done |= (1 << i); ++ if (atomic_dec_and_test(&pipe->task)) ++ lima_sched_pipe_task_done(pipe); ++ } ++ ++ return ret; ++} ++ ++static void lima_pp_soft_reset_async(struct lima_ip *ip) ++{ ++ if (ip->data.async_reset) ++ return; ++ ++ pp_write(LIMA_PP_INT_MASK, 0); ++ pp_write(LIMA_PP_INT_RAWSTAT, LIMA_PP_IRQ_MASK_ALL); ++ pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_SOFT_RESET); ++ ip->data.async_reset = true; ++} ++ ++static int lima_pp_soft_reset_poll(struct lima_ip *ip) ++{ ++ return !(pp_read(LIMA_PP_STATUS) & LIMA_PP_STATUS_RENDERING_ACTIVE) && ++ pp_read(LIMA_PP_INT_RAWSTAT) == LIMA_PP_IRQ_RESET_COMPLETED; ++} ++ ++static int lima_pp_soft_reset_async_wait_one(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int ret; ++ ++ ret = lima_poll_timeout(ip, lima_pp_soft_reset_poll, 0, 100); ++ if (ret) { ++ dev_err(dev->dev, "pp %s reset time out\n", lima_ip_name(ip)); ++ return ret; ++ } ++ ++ pp_write(LIMA_PP_INT_CLEAR, LIMA_PP_IRQ_MASK_ALL); ++ pp_write(LIMA_PP_INT_MASK, LIMA_PP_IRQ_MASK_USED); ++ return 0; ++} ++ ++static int lima_pp_soft_reset_async_wait(struct lima_ip *ip) ++{ ++ int i, err = 0; ++ ++ if (!ip->data.async_reset) ++ return 0; ++ ++ if (ip->id == lima_ip_pp_bcast) { ++ struct lima_device *dev = ip->dev; ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ struct drm_lima_m450_pp_frame *frame = pipe->current_task->frame; ++ ++ for (i = 0; i < frame->num_pp; i++) ++ err |= lima_pp_soft_reset_async_wait_one(pipe->processor[i]); ++ } else ++ err = lima_pp_soft_reset_async_wait_one(ip); ++ ++ ip->data.async_reset = false; ++ return err; ++} ++ ++static void lima_pp_write_frame(struct lima_ip *ip, u32 *frame, u32 *wb) ++{ ++ int i, j, n = 0; ++ ++ for (i = 0; i < LIMA_PP_FRAME_REG_NUM; i++) ++ writel(frame[i], ip->iomem + LIMA_PP_FRAME + i * 4); ++ ++ for (i = 0; i < 3; i++) { ++ for (j = 0; j < LIMA_PP_WB_REG_NUM; j++) ++ writel(wb[n++], ip->iomem + LIMA_PP_WB(i) + j * 4); ++ } ++} ++ ++static int lima_pp_hard_reset_poll(struct lima_ip *ip) ++{ ++ pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0xC01A0000); ++ return pp_read(LIMA_PP_PERF_CNT_0_LIMIT) == 0xC01A0000; ++} ++ ++static int lima_pp_hard_reset(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int ret; ++ ++ pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0xC0FFE000); ++ pp_write(LIMA_PP_INT_MASK, 0); ++ pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_FORCE_RESET); ++ ret = lima_poll_timeout(ip, lima_pp_hard_reset_poll, 10, 100); ++ if (ret) { ++ dev_err(dev->dev, "pp hard reset timeout\n"); ++ return ret; ++ } ++ ++ pp_write(LIMA_PP_PERF_CNT_0_LIMIT, 0); ++ pp_write(LIMA_PP_INT_CLEAR, LIMA_PP_IRQ_MASK_ALL); ++ pp_write(LIMA_PP_INT_MASK, LIMA_PP_IRQ_MASK_USED); ++ return 0; ++} ++ ++static void lima_pp_print_version(struct lima_ip *ip) ++{ ++ u32 version, major, minor; ++ char *name; ++ ++ version = pp_read(LIMA_PP_VERSION); ++ major = (version >> 8) & 0xFF; ++ minor = version & 0xFF; ++ switch (version >> 16) { ++ case 0xC807: ++ name = "mali200"; ++ break; ++ case 0xCE07: ++ name = "mali300"; ++ break; ++ case 0xCD07: ++ name = "mali400"; ++ break; ++ case 0xCF07: ++ name = "mali450"; ++ break; ++ default: ++ name = "unknown"; ++ break; ++ } ++ dev_info(ip->dev->dev, "%s - %s version major %d minor %d\n", ++ lima_ip_name(ip), name, major, minor); ++} ++ ++int lima_pp_init(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int err; ++ ++ lima_pp_print_version(ip); ++ ++ ip->data.async_reset = false; ++ lima_pp_soft_reset_async(ip); ++ err = lima_pp_soft_reset_async_wait(ip); ++ if (err) ++ return err; ++ ++ err = devm_request_irq(dev->dev, ip->irq, lima_pp_irq_handler, ++ IRQF_SHARED, lima_ip_name(ip), ip); ++ if (err) { ++ dev_err(dev->dev, "pp %s fail to request irq\n", ++ lima_ip_name(ip)); ++ return err; ++ } ++ ++ dev->pp_version = pp_read(LIMA_PP_VERSION); ++ ++ return 0; ++} ++ ++void lima_pp_fini(struct lima_ip *ip) ++{ ++ ++} ++ ++int lima_pp_bcast_init(struct lima_ip *ip) ++{ ++ struct lima_device *dev = ip->dev; ++ int err; ++ ++ err = devm_request_irq(dev->dev, ip->irq, lima_pp_bcast_irq_handler, ++ IRQF_SHARED, lima_ip_name(ip), ip); ++ if (err) { ++ dev_err(dev->dev, "pp %s fail to request irq\n", ++ lima_ip_name(ip)); ++ return err; ++ } ++ ++ return 0; ++} ++ ++void lima_pp_bcast_fini(struct lima_ip *ip) ++{ ++ ++} ++ ++static int lima_pp_task_validate(struct lima_sched_pipe *pipe, ++ struct lima_sched_task *task) ++{ ++ u32 num_pp; ++ ++ if (pipe->bcast_processor) { ++ struct drm_lima_m450_pp_frame *f = task->frame; ++ ++ num_pp = f->num_pp; ++ ++ if (f->_pad) ++ return -EINVAL; ++ } else { ++ struct drm_lima_m400_pp_frame *f = task->frame; ++ ++ num_pp = f->num_pp; ++ } ++ ++ if (num_pp == 0 || num_pp > pipe->num_processor) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static void lima_pp_task_run(struct lima_sched_pipe *pipe, ++ struct lima_sched_task *task) ++{ ++ if (pipe->bcast_processor) { ++ struct drm_lima_m450_pp_frame *frame = task->frame; ++ struct lima_device *dev = pipe->bcast_processor->dev; ++ struct lima_ip *ip = pipe->bcast_processor; ++ int i; ++ ++ pipe->done = 0; ++ atomic_set(&pipe->task, frame->num_pp); ++ ++ if (frame->use_dlbu) { ++ lima_dlbu_enable(dev, frame->num_pp); ++ ++ frame->frame[LIMA_PP_FRAME >> 2] = LIMA_VA_RESERVE_DLBU; ++ lima_dlbu_set_reg(dev->ip + lima_ip_dlbu, frame->dlbu_regs); ++ } else ++ lima_dlbu_disable(dev); ++ ++ lima_bcast_enable(dev, frame->num_pp); ++ ++ lima_pp_soft_reset_async_wait(ip); ++ ++ lima_pp_write_frame(ip, frame->frame, frame->wb); ++ ++ for (i = 0; i < frame->num_pp; i++) { ++ struct lima_ip *ip = pipe->processor[i]; ++ ++ pp_write(LIMA_PP_STACK, frame->fragment_stack_address[i]); ++ if (!frame->use_dlbu) ++ pp_write(LIMA_PP_FRAME, frame->plbu_array_address[i]); ++ } ++ ++ pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_START_RENDERING); ++ } else { ++ struct drm_lima_m400_pp_frame *frame = task->frame; ++ int i; ++ ++ atomic_set(&pipe->task, frame->num_pp); ++ ++ for (i = 0; i < frame->num_pp; i++) { ++ struct lima_ip *ip = pipe->processor[i]; ++ ++ frame->frame[LIMA_PP_FRAME >> 2] = ++ frame->plbu_array_address[i]; ++ frame->frame[LIMA_PP_STACK >> 2] = ++ frame->fragment_stack_address[i]; ++ ++ lima_pp_soft_reset_async_wait(ip); ++ ++ lima_pp_write_frame(ip, frame->frame, frame->wb); ++ ++ pp_write(LIMA_PP_CTRL, LIMA_PP_CTRL_START_RENDERING); ++ } ++ } ++} ++ ++static void lima_pp_task_fini(struct lima_sched_pipe *pipe) ++{ ++ if (pipe->bcast_processor) ++ lima_pp_soft_reset_async(pipe->bcast_processor); ++ else { ++ int i; ++ ++ for (i = 0; i < pipe->num_processor; i++) ++ lima_pp_soft_reset_async(pipe->processor[i]); ++ } ++} ++ ++static void lima_pp_task_error(struct lima_sched_pipe *pipe) ++{ ++ int i; ++ ++ for (i = 0; i < pipe->num_processor; i++) { ++ struct lima_ip *ip = pipe->processor[i]; ++ ++ dev_err(ip->dev->dev, "pp task error %d int_state=%x status=%x\n", ++ i, pp_read(LIMA_PP_INT_STATUS), pp_read(LIMA_PP_STATUS)); ++ ++ lima_pp_hard_reset(ip); ++ } ++} ++ ++static void lima_pp_task_mmu_error(struct lima_sched_pipe *pipe) ++{ ++ if (atomic_dec_and_test(&pipe->task)) ++ lima_sched_pipe_task_done(pipe); ++} ++ ++static struct kmem_cache *lima_pp_task_slab; ++static int lima_pp_task_slab_refcnt; ++ ++int lima_pp_pipe_init(struct lima_device *dev) ++{ ++ int frame_size; ++ struct lima_sched_pipe *pipe = dev->pipe + lima_pipe_pp; ++ ++ if (dev->id == lima_gpu_mali400) ++ frame_size = sizeof(struct drm_lima_m400_pp_frame); ++ else ++ frame_size = sizeof(struct drm_lima_m450_pp_frame); ++ ++ if (!lima_pp_task_slab) { ++ lima_pp_task_slab = kmem_cache_create_usercopy( ++ "lima_pp_task", sizeof(struct lima_sched_task) + frame_size, ++ 0, SLAB_HWCACHE_ALIGN, sizeof(struct lima_sched_task), ++ frame_size, NULL); ++ if (!lima_pp_task_slab) ++ return -ENOMEM; ++ } ++ lima_pp_task_slab_refcnt++; ++ ++ pipe->frame_size = frame_size; ++ pipe->task_slab = lima_pp_task_slab; ++ ++ pipe->task_validate = lima_pp_task_validate; ++ pipe->task_run = lima_pp_task_run; ++ pipe->task_fini = lima_pp_task_fini; ++ pipe->task_error = lima_pp_task_error; ++ pipe->task_mmu_error = lima_pp_task_mmu_error; ++ ++ return 0; ++} ++ ++void lima_pp_pipe_fini(struct lima_device *dev) ++{ ++ if (!--lima_pp_task_slab_refcnt) { ++ kmem_cache_destroy(lima_pp_task_slab); ++ lima_pp_task_slab = NULL; ++ } ++} +diff --git a/drivers/gpu/drm/lima/lima_pp.h b/drivers/gpu/drm/lima/lima_pp.h +new file mode 100644 +index 0000000000000..bf60c77b26338 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_pp.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_PP_H__ ++#define __LIMA_PP_H__ ++ ++struct lima_ip; ++struct lima_device; ++ ++int lima_pp_init(struct lima_ip *ip); ++void lima_pp_fini(struct lima_ip *ip); ++ ++int lima_pp_bcast_init(struct lima_ip *ip); ++void lima_pp_bcast_fini(struct lima_ip *ip); ++ ++int lima_pp_pipe_init(struct lima_device *dev); ++void lima_pp_pipe_fini(struct lima_device *dev); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_regs.h b/drivers/gpu/drm/lima/lima_regs.h +new file mode 100644 +index 0000000000000..ace8ecefbe906 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_regs.h +@@ -0,0 +1,298 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright 2010-2017 ARM Limited. All rights reserved. ++ * Copyright 2017-2019 Qiang Yu ++ */ ++ ++#ifndef __LIMA_REGS_H__ ++#define __LIMA_REGS_H__ ++ ++/* This file's register definition is collected from the ++ * official ARM Mali Utgard GPU kernel driver source code ++ */ ++ ++/* PMU regs */ ++#define LIMA_PMU_POWER_UP 0x00 ++#define LIMA_PMU_POWER_DOWN 0x04 ++#define LIMA_PMU_POWER_GP0_MASK BIT(0) ++#define LIMA_PMU_POWER_L2_MASK BIT(1) ++#define LIMA_PMU_POWER_PP_MASK(i) BIT(2 + i) ++ ++/* ++ * On Mali450 each block automatically starts up its corresponding L2 ++ * and the PPs are not fully independent controllable. ++ * Instead PP0, PP1-3 and PP4-7 can be turned on or off. ++ */ ++#define LIMA450_PMU_POWER_PP0_MASK BIT(1) ++#define LIMA450_PMU_POWER_PP13_MASK BIT(2) ++#define LIMA450_PMU_POWER_PP47_MASK BIT(3) ++ ++#define LIMA_PMU_STATUS 0x08 ++#define LIMA_PMU_INT_MASK 0x0C ++#define LIMA_PMU_INT_RAWSTAT 0x10 ++#define LIMA_PMU_INT_CLEAR 0x18 ++#define LIMA_PMU_INT_CMD_MASK BIT(0) ++#define LIMA_PMU_SW_DELAY 0x1C ++ ++/* L2 cache regs */ ++#define LIMA_L2_CACHE_SIZE 0x0004 ++#define LIMA_L2_CACHE_STATUS 0x0008 ++#define LIMA_L2_CACHE_STATUS_COMMAND_BUSY BIT(0) ++#define LIMA_L2_CACHE_STATUS_DATA_BUSY BIT(1) ++#define LIMA_L2_CACHE_COMMAND 0x0010 ++#define LIMA_L2_CACHE_COMMAND_CLEAR_ALL BIT(0) ++#define LIMA_L2_CACHE_CLEAR_PAGE 0x0014 ++#define LIMA_L2_CACHE_MAX_READS 0x0018 ++#define LIMA_L2_CACHE_ENABLE 0x001C ++#define LIMA_L2_CACHE_ENABLE_ACCESS BIT(0) ++#define LIMA_L2_CACHE_ENABLE_READ_ALLOCATE BIT(1) ++#define LIMA_L2_CACHE_PERFCNT_SRC0 0x0020 ++#define LIMA_L2_CACHE_PERFCNT_VAL0 0x0024 ++#define LIMA_L2_CACHE_PERFCNT_SRC1 0x0028 ++#define LIMA_L2_CACHE_ERFCNT_VAL1 0x002C ++ ++/* GP regs */ ++#define LIMA_GP_VSCL_START_ADDR 0x00 ++#define LIMA_GP_VSCL_END_ADDR 0x04 ++#define LIMA_GP_PLBUCL_START_ADDR 0x08 ++#define LIMA_GP_PLBUCL_END_ADDR 0x0c ++#define LIMA_GP_PLBU_ALLOC_START_ADDR 0x10 ++#define LIMA_GP_PLBU_ALLOC_END_ADDR 0x14 ++#define LIMA_GP_CMD 0x20 ++#define LIMA_GP_CMD_START_VS BIT(0) ++#define LIMA_GP_CMD_START_PLBU BIT(1) ++#define LIMA_GP_CMD_UPDATE_PLBU_ALLOC BIT(4) ++#define LIMA_GP_CMD_RESET BIT(5) ++#define LIMA_GP_CMD_FORCE_HANG BIT(6) ++#define LIMA_GP_CMD_STOP_BUS BIT(9) ++#define LIMA_GP_CMD_SOFT_RESET BIT(10) ++#define LIMA_GP_INT_RAWSTAT 0x24 ++#define LIMA_GP_INT_CLEAR 0x28 ++#define LIMA_GP_INT_MASK 0x2C ++#define LIMA_GP_INT_STAT 0x30 ++#define LIMA_GP_IRQ_VS_END_CMD_LST BIT(0) ++#define LIMA_GP_IRQ_PLBU_END_CMD_LST BIT(1) ++#define LIMA_GP_IRQ_PLBU_OUT_OF_MEM BIT(2) ++#define LIMA_GP_IRQ_VS_SEM_IRQ BIT(3) ++#define LIMA_GP_IRQ_PLBU_SEM_IRQ BIT(4) ++#define LIMA_GP_IRQ_HANG BIT(5) ++#define LIMA_GP_IRQ_FORCE_HANG BIT(6) ++#define LIMA_GP_IRQ_PERF_CNT_0_LIMIT BIT(7) ++#define LIMA_GP_IRQ_PERF_CNT_1_LIMIT BIT(8) ++#define LIMA_GP_IRQ_WRITE_BOUND_ERR BIT(9) ++#define LIMA_GP_IRQ_SYNC_ERROR BIT(10) ++#define LIMA_GP_IRQ_AXI_BUS_ERROR BIT(11) ++#define LIMA_GP_IRQ_AXI_BUS_STOPPED BIT(12) ++#define LIMA_GP_IRQ_VS_INVALID_CMD BIT(13) ++#define LIMA_GP_IRQ_PLB_INVALID_CMD BIT(14) ++#define LIMA_GP_IRQ_RESET_COMPLETED BIT(19) ++#define LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW BIT(20) ++#define LIMA_GP_IRQ_SEMAPHORE_OVERFLOW BIT(21) ++#define LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS BIT(22) ++#define LIMA_GP_WRITE_BOUND_LOW 0x34 ++#define LIMA_GP_PERF_CNT_0_ENABLE 0x3C ++#define LIMA_GP_PERF_CNT_1_ENABLE 0x40 ++#define LIMA_GP_PERF_CNT_0_SRC 0x44 ++#define LIMA_GP_PERF_CNT_1_SRC 0x48 ++#define LIMA_GP_PERF_CNT_0_VALUE 0x4C ++#define LIMA_GP_PERF_CNT_1_VALUE 0x50 ++#define LIMA_GP_PERF_CNT_0_LIMIT 0x54 ++#define LIMA_GP_STATUS 0x68 ++#define LIMA_GP_STATUS_VS_ACTIVE BIT(1) ++#define LIMA_GP_STATUS_BUS_STOPPED BIT(2) ++#define LIMA_GP_STATUS_PLBU_ACTIVE BIT(3) ++#define LIMA_GP_STATUS_BUS_ERROR BIT(6) ++#define LIMA_GP_STATUS_WRITE_BOUND_ERR BIT(8) ++#define LIMA_GP_VERSION 0x6C ++#define LIMA_GP_VSCL_START_ADDR_READ 0x80 ++#define LIMA_GP_PLBCL_START_ADDR_READ 0x84 ++#define LIMA_GP_CONTR_AXI_BUS_ERROR_STAT 0x94 ++ ++#define LIMA_GP_IRQ_MASK_ALL \ ++ ( \ ++ LIMA_GP_IRQ_VS_END_CMD_LST | \ ++ LIMA_GP_IRQ_PLBU_END_CMD_LST | \ ++ LIMA_GP_IRQ_PLBU_OUT_OF_MEM | \ ++ LIMA_GP_IRQ_VS_SEM_IRQ | \ ++ LIMA_GP_IRQ_PLBU_SEM_IRQ | \ ++ LIMA_GP_IRQ_HANG | \ ++ LIMA_GP_IRQ_FORCE_HANG | \ ++ LIMA_GP_IRQ_PERF_CNT_0_LIMIT | \ ++ LIMA_GP_IRQ_PERF_CNT_1_LIMIT | \ ++ LIMA_GP_IRQ_WRITE_BOUND_ERR | \ ++ LIMA_GP_IRQ_SYNC_ERROR | \ ++ LIMA_GP_IRQ_AXI_BUS_ERROR | \ ++ LIMA_GP_IRQ_AXI_BUS_STOPPED | \ ++ LIMA_GP_IRQ_VS_INVALID_CMD | \ ++ LIMA_GP_IRQ_PLB_INVALID_CMD | \ ++ LIMA_GP_IRQ_RESET_COMPLETED | \ ++ LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW | \ ++ LIMA_GP_IRQ_SEMAPHORE_OVERFLOW | \ ++ LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS) ++ ++#define LIMA_GP_IRQ_MASK_ERROR \ ++ ( \ ++ LIMA_GP_IRQ_PLBU_OUT_OF_MEM | \ ++ LIMA_GP_IRQ_FORCE_HANG | \ ++ LIMA_GP_IRQ_WRITE_BOUND_ERR | \ ++ LIMA_GP_IRQ_SYNC_ERROR | \ ++ LIMA_GP_IRQ_AXI_BUS_ERROR | \ ++ LIMA_GP_IRQ_VS_INVALID_CMD | \ ++ LIMA_GP_IRQ_PLB_INVALID_CMD | \ ++ LIMA_GP_IRQ_SEMAPHORE_UNDERFLOW | \ ++ LIMA_GP_IRQ_SEMAPHORE_OVERFLOW | \ ++ LIMA_GP_IRQ_PTR_ARRAY_OUT_OF_BOUNDS) ++ ++#define LIMA_GP_IRQ_MASK_USED \ ++ ( \ ++ LIMA_GP_IRQ_VS_END_CMD_LST | \ ++ LIMA_GP_IRQ_PLBU_END_CMD_LST | \ ++ LIMA_GP_IRQ_MASK_ERROR) ++ ++/* PP regs */ ++#define LIMA_PP_FRAME 0x0000 ++#define LIMA_PP_RSW 0x0004 ++#define LIMA_PP_STACK 0x0030 ++#define LIMA_PP_STACK_SIZE 0x0034 ++#define LIMA_PP_ORIGIN_OFFSET_X 0x0040 ++#define LIMA_PP_WB(i) (0x0100 * (i + 1)) ++#define LIMA_PP_WB_SOURCE_SELECT 0x0000 ++#define LIMA_PP_WB_SOURCE_ADDR 0x0004 ++ ++#define LIMA_PP_VERSION 0x1000 ++#define LIMA_PP_CURRENT_REND_LIST_ADDR 0x1004 ++#define LIMA_PP_STATUS 0x1008 ++#define LIMA_PP_STATUS_RENDERING_ACTIVE BIT(0) ++#define LIMA_PP_STATUS_BUS_STOPPED BIT(4) ++#define LIMA_PP_CTRL 0x100c ++#define LIMA_PP_CTRL_STOP_BUS BIT(0) ++#define LIMA_PP_CTRL_FLUSH_CACHES BIT(3) ++#define LIMA_PP_CTRL_FORCE_RESET BIT(5) ++#define LIMA_PP_CTRL_START_RENDERING BIT(6) ++#define LIMA_PP_CTRL_SOFT_RESET BIT(7) ++#define LIMA_PP_INT_RAWSTAT 0x1020 ++#define LIMA_PP_INT_CLEAR 0x1024 ++#define LIMA_PP_INT_MASK 0x1028 ++#define LIMA_PP_INT_STATUS 0x102c ++#define LIMA_PP_IRQ_END_OF_FRAME BIT(0) ++#define LIMA_PP_IRQ_END_OF_TILE BIT(1) ++#define LIMA_PP_IRQ_HANG BIT(2) ++#define LIMA_PP_IRQ_FORCE_HANG BIT(3) ++#define LIMA_PP_IRQ_BUS_ERROR BIT(4) ++#define LIMA_PP_IRQ_BUS_STOP BIT(5) ++#define LIMA_PP_IRQ_CNT_0_LIMIT BIT(6) ++#define LIMA_PP_IRQ_CNT_1_LIMIT BIT(7) ++#define LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR BIT(8) ++#define LIMA_PP_IRQ_INVALID_PLIST_COMMAND BIT(9) ++#define LIMA_PP_IRQ_CALL_STACK_UNDERFLOW BIT(10) ++#define LIMA_PP_IRQ_CALL_STACK_OVERFLOW BIT(11) ++#define LIMA_PP_IRQ_RESET_COMPLETED BIT(12) ++#define LIMA_PP_WRITE_BOUNDARY_LOW 0x1044 ++#define LIMA_PP_BUS_ERROR_STATUS 0x1050 ++#define LIMA_PP_PERF_CNT_0_ENABLE 0x1080 ++#define LIMA_PP_PERF_CNT_0_SRC 0x1084 ++#define LIMA_PP_PERF_CNT_0_LIMIT 0x1088 ++#define LIMA_PP_PERF_CNT_0_VALUE 0x108c ++#define LIMA_PP_PERF_CNT_1_ENABLE 0x10a0 ++#define LIMA_PP_PERF_CNT_1_SRC 0x10a4 ++#define LIMA_PP_PERF_CNT_1_LIMIT 0x10a8 ++#define LIMA_PP_PERF_CNT_1_VALUE 0x10ac ++#define LIMA_PP_PERFMON_CONTR 0x10b0 ++#define LIMA_PP_PERFMON_BASE 0x10b4 ++ ++#define LIMA_PP_IRQ_MASK_ALL \ ++ ( \ ++ LIMA_PP_IRQ_END_OF_FRAME | \ ++ LIMA_PP_IRQ_END_OF_TILE | \ ++ LIMA_PP_IRQ_HANG | \ ++ LIMA_PP_IRQ_FORCE_HANG | \ ++ LIMA_PP_IRQ_BUS_ERROR | \ ++ LIMA_PP_IRQ_BUS_STOP | \ ++ LIMA_PP_IRQ_CNT_0_LIMIT | \ ++ LIMA_PP_IRQ_CNT_1_LIMIT | \ ++ LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR | \ ++ LIMA_PP_IRQ_INVALID_PLIST_COMMAND | \ ++ LIMA_PP_IRQ_CALL_STACK_UNDERFLOW | \ ++ LIMA_PP_IRQ_CALL_STACK_OVERFLOW | \ ++ LIMA_PP_IRQ_RESET_COMPLETED) ++ ++#define LIMA_PP_IRQ_MASK_ERROR \ ++ ( \ ++ LIMA_PP_IRQ_FORCE_HANG | \ ++ LIMA_PP_IRQ_BUS_ERROR | \ ++ LIMA_PP_IRQ_WRITE_BOUNDARY_ERROR | \ ++ LIMA_PP_IRQ_INVALID_PLIST_COMMAND | \ ++ LIMA_PP_IRQ_CALL_STACK_UNDERFLOW | \ ++ LIMA_PP_IRQ_CALL_STACK_OVERFLOW) ++ ++#define LIMA_PP_IRQ_MASK_USED \ ++ ( \ ++ LIMA_PP_IRQ_END_OF_FRAME | \ ++ LIMA_PP_IRQ_MASK_ERROR) ++ ++/* MMU regs */ ++#define LIMA_MMU_DTE_ADDR 0x0000 ++#define LIMA_MMU_STATUS 0x0004 ++#define LIMA_MMU_STATUS_PAGING_ENABLED BIT(0) ++#define LIMA_MMU_STATUS_PAGE_FAULT_ACTIVE BIT(1) ++#define LIMA_MMU_STATUS_STALL_ACTIVE BIT(2) ++#define LIMA_MMU_STATUS_IDLE BIT(3) ++#define LIMA_MMU_STATUS_REPLAY_BUFFER_EMPTY BIT(4) ++#define LIMA_MMU_STATUS_PAGE_FAULT_IS_WRITE BIT(5) ++#define LIMA_MMU_STATUS_BUS_ID(x) ((x >> 6) & 0x1F) ++#define LIMA_MMU_COMMAND 0x0008 ++#define LIMA_MMU_COMMAND_ENABLE_PAGING 0x00 ++#define LIMA_MMU_COMMAND_DISABLE_PAGING 0x01 ++#define LIMA_MMU_COMMAND_ENABLE_STALL 0x02 ++#define LIMA_MMU_COMMAND_DISABLE_STALL 0x03 ++#define LIMA_MMU_COMMAND_ZAP_CACHE 0x04 ++#define LIMA_MMU_COMMAND_PAGE_FAULT_DONE 0x05 ++#define LIMA_MMU_COMMAND_HARD_RESET 0x06 ++#define LIMA_MMU_PAGE_FAULT_ADDR 0x000C ++#define LIMA_MMU_ZAP_ONE_LINE 0x0010 ++#define LIMA_MMU_INT_RAWSTAT 0x0014 ++#define LIMA_MMU_INT_CLEAR 0x0018 ++#define LIMA_MMU_INT_MASK 0x001C ++#define LIMA_MMU_INT_PAGE_FAULT BIT(0) ++#define LIMA_MMU_INT_READ_BUS_ERROR BIT(1) ++#define LIMA_MMU_INT_STATUS 0x0020 ++ ++#define LIMA_VM_FLAG_PRESENT BIT(0) ++#define LIMA_VM_FLAG_READ_PERMISSION BIT(1) ++#define LIMA_VM_FLAG_WRITE_PERMISSION BIT(2) ++#define LIMA_VM_FLAG_OVERRIDE_CACHE BIT(3) ++#define LIMA_VM_FLAG_WRITE_CACHEABLE BIT(4) ++#define LIMA_VM_FLAG_WRITE_ALLOCATE BIT(5) ++#define LIMA_VM_FLAG_WRITE_BUFFERABLE BIT(6) ++#define LIMA_VM_FLAG_READ_CACHEABLE BIT(7) ++#define LIMA_VM_FLAG_READ_ALLOCATE BIT(8) ++#define LIMA_VM_FLAG_MASK 0x1FF ++ ++#define LIMA_VM_FLAGS_CACHE ( \ ++ LIMA_VM_FLAG_PRESENT | \ ++ LIMA_VM_FLAG_READ_PERMISSION | \ ++ LIMA_VM_FLAG_WRITE_PERMISSION | \ ++ LIMA_VM_FLAG_OVERRIDE_CACHE | \ ++ LIMA_VM_FLAG_WRITE_CACHEABLE | \ ++ LIMA_VM_FLAG_WRITE_BUFFERABLE | \ ++ LIMA_VM_FLAG_READ_CACHEABLE | \ ++ LIMA_VM_FLAG_READ_ALLOCATE) ++ ++#define LIMA_VM_FLAGS_UNCACHE ( \ ++ LIMA_VM_FLAG_PRESENT | \ ++ LIMA_VM_FLAG_READ_PERMISSION | \ ++ LIMA_VM_FLAG_WRITE_PERMISSION) ++ ++/* DLBU regs */ ++#define LIMA_DLBU_MASTER_TLLIST_PHYS_ADDR 0x0000 ++#define LIMA_DLBU_MASTER_TLLIST_VADDR 0x0004 ++#define LIMA_DLBU_TLLIST_VBASEADDR 0x0008 ++#define LIMA_DLBU_FB_DIM 0x000C ++#define LIMA_DLBU_TLLIST_CONF 0x0010 ++#define LIMA_DLBU_START_TILE_POS 0x0014 ++#define LIMA_DLBU_PP_ENABLE_MASK 0x0018 ++ ++/* BCAST regs */ ++#define LIMA_BCAST_BROADCAST_MASK 0x0 ++#define LIMA_BCAST_INTERRUPT_MASK 0x4 ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_sched.c b/drivers/gpu/drm/lima/lima_sched.c +new file mode 100644 +index 0000000000000..97bd9c1deb871 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_sched.c +@@ -0,0 +1,404 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++ ++#include "lima_drv.h" ++#include "lima_sched.h" ++#include "lima_vm.h" ++#include "lima_mmu.h" ++#include "lima_l2_cache.h" ++#include "lima_object.h" ++ ++struct lima_fence { ++ struct dma_fence base; ++ struct lima_sched_pipe *pipe; ++}; ++ ++static struct kmem_cache *lima_fence_slab; ++static int lima_fence_slab_refcnt; ++ ++int lima_sched_slab_init(void) ++{ ++ if (!lima_fence_slab) { ++ lima_fence_slab = kmem_cache_create( ++ "lima_fence", sizeof(struct lima_fence), 0, ++ SLAB_HWCACHE_ALIGN, NULL); ++ if (!lima_fence_slab) ++ return -ENOMEM; ++ } ++ ++ lima_fence_slab_refcnt++; ++ return 0; ++} ++ ++void lima_sched_slab_fini(void) ++{ ++ if (!--lima_fence_slab_refcnt) { ++ kmem_cache_destroy(lima_fence_slab); ++ lima_fence_slab = NULL; ++ } ++} ++ ++static inline struct lima_fence *to_lima_fence(struct dma_fence *fence) ++{ ++ return container_of(fence, struct lima_fence, base); ++} ++ ++static const char *lima_fence_get_driver_name(struct dma_fence *fence) ++{ ++ return "lima"; ++} ++ ++static const char *lima_fence_get_timeline_name(struct dma_fence *fence) ++{ ++ struct lima_fence *f = to_lima_fence(fence); ++ ++ return f->pipe->base.name; ++} ++ ++static void lima_fence_release_rcu(struct rcu_head *rcu) ++{ ++ struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); ++ struct lima_fence *fence = to_lima_fence(f); ++ ++ kmem_cache_free(lima_fence_slab, fence); ++} ++ ++static void lima_fence_release(struct dma_fence *fence) ++{ ++ struct lima_fence *f = to_lima_fence(fence); ++ ++ call_rcu(&f->base.rcu, lima_fence_release_rcu); ++} ++ ++static const struct dma_fence_ops lima_fence_ops = { ++ .get_driver_name = lima_fence_get_driver_name, ++ .get_timeline_name = lima_fence_get_timeline_name, ++ .release = lima_fence_release, ++}; ++ ++static struct lima_fence *lima_fence_create(struct lima_sched_pipe *pipe) ++{ ++ struct lima_fence *fence; ++ ++ fence = kmem_cache_zalloc(lima_fence_slab, GFP_KERNEL); ++ if (!fence) ++ return NULL; ++ ++ fence->pipe = pipe; ++ dma_fence_init(&fence->base, &lima_fence_ops, &pipe->fence_lock, ++ pipe->fence_context, ++pipe->fence_seqno); ++ ++ return fence; ++} ++ ++static inline struct lima_sched_task *to_lima_task(struct drm_sched_job *job) ++{ ++ return container_of(job, struct lima_sched_task, base); ++} ++ ++static inline struct lima_sched_pipe *to_lima_pipe(struct drm_gpu_scheduler *sched) ++{ ++ return container_of(sched, struct lima_sched_pipe, base); ++} ++ ++int lima_sched_task_init(struct lima_sched_task *task, ++ struct lima_sched_context *context, ++ struct lima_bo **bos, int num_bos, ++ struct lima_vm *vm) ++{ ++ int err, i; ++ ++ task->bos = kmemdup(bos, sizeof(*bos) * num_bos, GFP_KERNEL); ++ if (!task->bos) ++ return -ENOMEM; ++ ++ for (i = 0; i < num_bos; i++) ++ drm_gem_object_get(&bos[i]->gem); ++ ++ err = drm_sched_job_init(&task->base, &context->base, vm); ++ if (err) { ++ kfree(task->bos); ++ return err; ++ } ++ ++ task->num_bos = num_bos; ++ task->vm = lima_vm_get(vm); ++ return 0; ++} ++ ++void lima_sched_task_fini(struct lima_sched_task *task) ++{ ++ int i; ++ ++ drm_sched_job_cleanup(&task->base); ++ ++ for (i = 0; i < task->num_dep; i++) ++ dma_fence_put(task->dep[i]); ++ ++ kfree(task->dep); ++ ++ if (task->bos) { ++ for (i = 0; i < task->num_bos; i++) ++ drm_gem_object_put_unlocked(&task->bos[i]->gem); ++ kfree(task->bos); ++ } ++ ++ lima_vm_put(task->vm); ++} ++ ++int lima_sched_task_add_dep(struct lima_sched_task *task, struct dma_fence *fence) ++{ ++ int i, new_dep = 4; ++ ++ /* same context's fence is definitly earlier then this task */ ++ if (fence->context == task->base.s_fence->finished.context) { ++ dma_fence_put(fence); ++ return 0; ++ } ++ ++ if (task->dep && task->num_dep == task->max_dep) ++ new_dep = task->max_dep * 2; ++ ++ if (task->max_dep < new_dep) { ++ void *dep = krealloc(task->dep, sizeof(*task->dep) * new_dep, GFP_KERNEL); ++ ++ if (!dep) ++ return -ENOMEM; ++ ++ task->max_dep = new_dep; ++ task->dep = dep; ++ } ++ ++ for (i = 0; i < task->num_dep; i++) { ++ if (task->dep[i]->context == fence->context && ++ dma_fence_is_later(fence, task->dep[i])) { ++ dma_fence_put(task->dep[i]); ++ task->dep[i] = fence; ++ return 0; ++ } ++ } ++ ++ task->dep[task->num_dep++] = fence; ++ return 0; ++} ++ ++int lima_sched_context_init(struct lima_sched_pipe *pipe, ++ struct lima_sched_context *context, ++ atomic_t *guilty) ++{ ++ struct drm_sched_rq *rq = pipe->base.sched_rq + DRM_SCHED_PRIORITY_NORMAL; ++ ++ return drm_sched_entity_init(&context->base, &rq, 1, guilty); ++} ++ ++void lima_sched_context_fini(struct lima_sched_pipe *pipe, ++ struct lima_sched_context *context) ++{ ++ drm_sched_entity_fini(&context->base); ++} ++ ++struct dma_fence *lima_sched_context_queue_task(struct lima_sched_context *context, ++ struct lima_sched_task *task) ++{ ++ struct dma_fence *fence = dma_fence_get(&task->base.s_fence->finished); ++ ++ drm_sched_entity_push_job(&task->base, &context->base); ++ return fence; ++} ++ ++static struct dma_fence *lima_sched_dependency(struct drm_sched_job *job, ++ struct drm_sched_entity *entity) ++{ ++ struct lima_sched_task *task = to_lima_task(job); ++ int i; ++ ++ for (i = 0; i < task->num_dep; i++) { ++ struct dma_fence *fence = task->dep[i]; ++ ++ if (!task->dep[i]) ++ continue; ++ ++ task->dep[i] = NULL; ++ ++ if (!dma_fence_is_signaled(fence)) ++ return fence; ++ ++ dma_fence_put(fence); ++ } ++ ++ return NULL; ++} ++ ++static struct dma_fence *lima_sched_run_job(struct drm_sched_job *job) ++{ ++ struct lima_sched_task *task = to_lima_task(job); ++ struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); ++ struct lima_fence *fence; ++ struct dma_fence *ret; ++ struct lima_vm *vm = NULL, *last_vm = NULL; ++ int i; ++ ++ /* after GPU reset */ ++ if (job->s_fence->finished.error < 0) ++ return NULL; ++ ++ fence = lima_fence_create(pipe); ++ if (!fence) ++ return NULL; ++ task->fence = &fence->base; ++ ++ /* for caller usage of the fence, otherwise irq handler ++ * may consume the fence before caller use it ++ */ ++ ret = dma_fence_get(task->fence); ++ ++ pipe->current_task = task; ++ ++ /* this is needed for MMU to work correctly, otherwise GP/PP ++ * will hang or page fault for unknown reason after running for ++ * a while. ++ * ++ * Need to investigate: ++ * 1. is it related to TLB ++ * 2. how much performance will be affected by L2 cache flush ++ * 3. can we reduce the calling of this function because all ++ * GP/PP use the same L2 cache on mali400 ++ * ++ * TODO: ++ * 1. move this to task fini to save some wait time? ++ * 2. when GP/PP use different l2 cache, need PP wait GP l2 ++ * cache flush? ++ */ ++ for (i = 0; i < pipe->num_l2_cache; i++) ++ lima_l2_cache_flush(pipe->l2_cache[i]); ++ ++ if (task->vm != pipe->current_vm) { ++ vm = lima_vm_get(task->vm); ++ last_vm = pipe->current_vm; ++ pipe->current_vm = task->vm; ++ } ++ ++ if (pipe->bcast_mmu) ++ lima_mmu_switch_vm(pipe->bcast_mmu, vm); ++ else { ++ for (i = 0; i < pipe->num_mmu; i++) ++ lima_mmu_switch_vm(pipe->mmu[i], vm); ++ } ++ ++ if (last_vm) ++ lima_vm_put(last_vm); ++ ++ pipe->error = false; ++ pipe->task_run(pipe, task); ++ ++ return task->fence; ++} ++ ++static void lima_sched_handle_error_task(struct lima_sched_pipe *pipe, ++ struct lima_sched_task *task) ++{ ++ drm_sched_stop(&pipe->base); ++ ++ if (task) ++ drm_sched_increase_karma(&task->base); ++ ++ pipe->task_error(pipe); ++ ++ if (pipe->bcast_mmu) ++ lima_mmu_page_fault_resume(pipe->bcast_mmu); ++ else { ++ int i; ++ ++ for (i = 0; i < pipe->num_mmu; i++) ++ lima_mmu_page_fault_resume(pipe->mmu[i]); ++ } ++ ++ if (pipe->current_vm) ++ lima_vm_put(pipe->current_vm); ++ ++ pipe->current_vm = NULL; ++ pipe->current_task = NULL; ++ ++ drm_sched_resubmit_jobs(&pipe->base); ++ drm_sched_start(&pipe->base, true); ++} ++ ++static void lima_sched_timedout_job(struct drm_sched_job *job) ++{ ++ struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); ++ struct lima_sched_task *task = to_lima_task(job); ++ ++ DRM_ERROR("lima job timeout\n"); ++ ++ lima_sched_handle_error_task(pipe, task); ++} ++ ++static void lima_sched_free_job(struct drm_sched_job *job) ++{ ++ struct lima_sched_task *task = to_lima_task(job); ++ struct lima_sched_pipe *pipe = to_lima_pipe(job->sched); ++ struct lima_vm *vm = task->vm; ++ struct lima_bo **bos = task->bos; ++ int i; ++ ++ dma_fence_put(task->fence); ++ ++ for (i = 0; i < task->num_bos; i++) ++ lima_vm_bo_del(vm, bos[i]); ++ ++ lima_sched_task_fini(task); ++ kmem_cache_free(pipe->task_slab, task); ++} ++ ++const struct drm_sched_backend_ops lima_sched_ops = { ++ .dependency = lima_sched_dependency, ++ .run_job = lima_sched_run_job, ++ .timedout_job = lima_sched_timedout_job, ++ .free_job = lima_sched_free_job, ++}; ++ ++static void lima_sched_error_work(struct work_struct *work) ++{ ++ struct lima_sched_pipe *pipe = ++ container_of(work, struct lima_sched_pipe, error_work); ++ struct lima_sched_task *task = pipe->current_task; ++ ++ lima_sched_handle_error_task(pipe, task); ++} ++ ++int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name) ++{ ++ long timeout; ++ ++ if (lima_sched_timeout_ms <= 0) ++ timeout = MAX_SCHEDULE_TIMEOUT; ++ else ++ timeout = msecs_to_jiffies(lima_sched_timeout_ms); ++ ++ pipe->fence_context = dma_fence_context_alloc(1); ++ spin_lock_init(&pipe->fence_lock); ++ ++ INIT_WORK(&pipe->error_work, lima_sched_error_work); ++ ++ return drm_sched_init(&pipe->base, &lima_sched_ops, 1, 0, timeout, name); ++} ++ ++void lima_sched_pipe_fini(struct lima_sched_pipe *pipe) ++{ ++ drm_sched_fini(&pipe->base); ++} ++ ++void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe) ++{ ++ if (pipe->error) ++ schedule_work(&pipe->error_work); ++ else { ++ struct lima_sched_task *task = pipe->current_task; ++ ++ pipe->task_fini(pipe); ++ dma_fence_signal(task->fence); ++ } ++} +diff --git a/drivers/gpu/drm/lima/lima_sched.h b/drivers/gpu/drm/lima/lima_sched.h +new file mode 100644 +index 0000000000000..b017cfa7e3276 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_sched.h +@@ -0,0 +1,104 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_SCHED_H__ ++#define __LIMA_SCHED_H__ ++ ++#include ++ ++struct lima_vm; ++ ++struct lima_sched_task { ++ struct drm_sched_job base; ++ ++ struct lima_vm *vm; ++ void *frame; ++ ++ struct dma_fence **dep; ++ int num_dep; ++ int max_dep; ++ ++ struct lima_bo **bos; ++ int num_bos; ++ ++ /* pipe fence */ ++ struct dma_fence *fence; ++}; ++ ++struct lima_sched_context { ++ struct drm_sched_entity base; ++}; ++ ++#define LIMA_SCHED_PIPE_MAX_MMU 8 ++#define LIMA_SCHED_PIPE_MAX_L2_CACHE 2 ++#define LIMA_SCHED_PIPE_MAX_PROCESSOR 8 ++ ++struct lima_ip; ++ ++struct lima_sched_pipe { ++ struct drm_gpu_scheduler base; ++ ++ u64 fence_context; ++ u32 fence_seqno; ++ spinlock_t fence_lock; ++ ++ struct lima_sched_task *current_task; ++ struct lima_vm *current_vm; ++ ++ struct lima_ip *mmu[LIMA_SCHED_PIPE_MAX_MMU]; ++ int num_mmu; ++ ++ struct lima_ip *l2_cache[LIMA_SCHED_PIPE_MAX_L2_CACHE]; ++ int num_l2_cache; ++ ++ struct lima_ip *processor[LIMA_SCHED_PIPE_MAX_PROCESSOR]; ++ int num_processor; ++ ++ struct lima_ip *bcast_processor; ++ struct lima_ip *bcast_mmu; ++ ++ u32 done; ++ bool error; ++ atomic_t task; ++ ++ int frame_size; ++ struct kmem_cache *task_slab; ++ ++ int (*task_validate)(struct lima_sched_pipe *pipe, struct lima_sched_task *task); ++ void (*task_run)(struct lima_sched_pipe *pipe, struct lima_sched_task *task); ++ void (*task_fini)(struct lima_sched_pipe *pipe); ++ void (*task_error)(struct lima_sched_pipe *pipe); ++ void (*task_mmu_error)(struct lima_sched_pipe *pipe); ++ ++ struct work_struct error_work; ++}; ++ ++int lima_sched_task_init(struct lima_sched_task *task, ++ struct lima_sched_context *context, ++ struct lima_bo **bos, int num_bos, ++ struct lima_vm *vm); ++void lima_sched_task_fini(struct lima_sched_task *task); ++int lima_sched_task_add_dep(struct lima_sched_task *task, struct dma_fence *fence); ++ ++int lima_sched_context_init(struct lima_sched_pipe *pipe, ++ struct lima_sched_context *context, ++ atomic_t *guilty); ++void lima_sched_context_fini(struct lima_sched_pipe *pipe, ++ struct lima_sched_context *context); ++struct dma_fence *lima_sched_context_queue_task(struct lima_sched_context *context, ++ struct lima_sched_task *task); ++ ++int lima_sched_pipe_init(struct lima_sched_pipe *pipe, const char *name); ++void lima_sched_pipe_fini(struct lima_sched_pipe *pipe); ++void lima_sched_pipe_task_done(struct lima_sched_pipe *pipe); ++ ++static inline void lima_sched_pipe_mmu_error(struct lima_sched_pipe *pipe) ++{ ++ pipe->error = true; ++ pipe->task_mmu_error(pipe); ++} ++ ++int lima_sched_slab_init(void); ++void lima_sched_slab_fini(void); ++ ++#endif +diff --git a/drivers/gpu/drm/lima/lima_vm.c b/drivers/gpu/drm/lima/lima_vm.c +new file mode 100644 +index 0000000000000..19e88ca165270 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_vm.c +@@ -0,0 +1,282 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#include ++#include ++ ++#include "lima_device.h" ++#include "lima_vm.h" ++#include "lima_object.h" ++#include "lima_regs.h" ++ ++struct lima_bo_va { ++ struct list_head list; ++ unsigned int ref_count; ++ ++ struct drm_mm_node node; ++ ++ struct lima_vm *vm; ++}; ++ ++#define LIMA_VM_PD_SHIFT 22 ++#define LIMA_VM_PT_SHIFT 12 ++#define LIMA_VM_PB_SHIFT (LIMA_VM_PD_SHIFT + LIMA_VM_NUM_PT_PER_BT_SHIFT) ++#define LIMA_VM_BT_SHIFT LIMA_VM_PT_SHIFT ++ ++#define LIMA_VM_PT_MASK ((1 << LIMA_VM_PD_SHIFT) - 1) ++#define LIMA_VM_BT_MASK ((1 << LIMA_VM_PB_SHIFT) - 1) ++ ++#define LIMA_PDE(va) (va >> LIMA_VM_PD_SHIFT) ++#define LIMA_PTE(va) ((va & LIMA_VM_PT_MASK) >> LIMA_VM_PT_SHIFT) ++#define LIMA_PBE(va) (va >> LIMA_VM_PB_SHIFT) ++#define LIMA_BTE(va) ((va & LIMA_VM_BT_MASK) >> LIMA_VM_BT_SHIFT) ++ ++ ++static void lima_vm_unmap_page_table(struct lima_vm *vm, u32 start, u32 end) ++{ ++ u32 addr; ++ ++ for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) { ++ u32 pbe = LIMA_PBE(addr); ++ u32 bte = LIMA_BTE(addr); ++ ++ vm->bts[pbe].cpu[bte] = 0; ++ } ++} ++ ++static int lima_vm_map_page_table(struct lima_vm *vm, dma_addr_t *dma, ++ u32 start, u32 end) ++{ ++ u64 addr; ++ int i = 0; ++ ++ for (addr = start; addr <= end; addr += LIMA_PAGE_SIZE) { ++ u32 pbe = LIMA_PBE(addr); ++ u32 bte = LIMA_BTE(addr); ++ ++ if (!vm->bts[pbe].cpu) { ++ dma_addr_t pts; ++ u32 *pd; ++ int j; ++ ++ vm->bts[pbe].cpu = dma_alloc_wc( ++ vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT, ++ &vm->bts[pbe].dma, GFP_KERNEL | __GFP_ZERO); ++ if (!vm->bts[pbe].cpu) { ++ if (addr != start) ++ lima_vm_unmap_page_table(vm, start, addr - 1); ++ return -ENOMEM; ++ } ++ ++ pts = vm->bts[pbe].dma; ++ pd = vm->pd.cpu + (pbe << LIMA_VM_NUM_PT_PER_BT_SHIFT); ++ for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) { ++ pd[j] = pts | LIMA_VM_FLAG_PRESENT; ++ pts += LIMA_PAGE_SIZE; ++ } ++ } ++ ++ vm->bts[pbe].cpu[bte] = dma[i++] | LIMA_VM_FLAGS_CACHE; ++ } ++ ++ return 0; ++} ++ ++static struct lima_bo_va * ++lima_vm_bo_find(struct lima_vm *vm, struct lima_bo *bo) ++{ ++ struct lima_bo_va *bo_va, *ret = NULL; ++ ++ list_for_each_entry(bo_va, &bo->va, list) { ++ if (bo_va->vm == vm) { ++ ret = bo_va; ++ break; ++ } ++ } ++ ++ return ret; ++} ++ ++int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create) ++{ ++ struct lima_bo_va *bo_va; ++ int err; ++ ++ mutex_lock(&bo->lock); ++ ++ bo_va = lima_vm_bo_find(vm, bo); ++ if (bo_va) { ++ bo_va->ref_count++; ++ mutex_unlock(&bo->lock); ++ return 0; ++ } ++ ++ /* should not create new bo_va if not asked by caller */ ++ if (!create) { ++ mutex_unlock(&bo->lock); ++ return -ENOENT; ++ } ++ ++ bo_va = kzalloc(sizeof(*bo_va), GFP_KERNEL); ++ if (!bo_va) { ++ err = -ENOMEM; ++ goto err_out0; ++ } ++ ++ bo_va->vm = vm; ++ bo_va->ref_count = 1; ++ ++ mutex_lock(&vm->lock); ++ ++ err = drm_mm_insert_node(&vm->mm, &bo_va->node, bo->gem.size); ++ if (err) ++ goto err_out1; ++ ++ err = lima_vm_map_page_table(vm, bo->pages_dma_addr, bo_va->node.start, ++ bo_va->node.start + bo_va->node.size - 1); ++ if (err) ++ goto err_out2; ++ ++ mutex_unlock(&vm->lock); ++ ++ list_add_tail(&bo_va->list, &bo->va); ++ ++ mutex_unlock(&bo->lock); ++ return 0; ++ ++err_out2: ++ drm_mm_remove_node(&bo_va->node); ++err_out1: ++ mutex_unlock(&vm->lock); ++ kfree(bo_va); ++err_out0: ++ mutex_unlock(&bo->lock); ++ return err; ++} ++ ++void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo) ++{ ++ struct lima_bo_va *bo_va; ++ ++ mutex_lock(&bo->lock); ++ ++ bo_va = lima_vm_bo_find(vm, bo); ++ if (--bo_va->ref_count > 0) { ++ mutex_unlock(&bo->lock); ++ return; ++ } ++ ++ mutex_lock(&vm->lock); ++ ++ lima_vm_unmap_page_table(vm, bo_va->node.start, ++ bo_va->node.start + bo_va->node.size - 1); ++ ++ drm_mm_remove_node(&bo_va->node); ++ ++ mutex_unlock(&vm->lock); ++ ++ list_del(&bo_va->list); ++ ++ mutex_unlock(&bo->lock); ++ ++ kfree(bo_va); ++} ++ ++u32 lima_vm_get_va(struct lima_vm *vm, struct lima_bo *bo) ++{ ++ struct lima_bo_va *bo_va; ++ u32 ret; ++ ++ mutex_lock(&bo->lock); ++ ++ bo_va = lima_vm_bo_find(vm, bo); ++ ret = bo_va->node.start; ++ ++ mutex_unlock(&bo->lock); ++ ++ return ret; ++} ++ ++struct lima_vm *lima_vm_create(struct lima_device *dev) ++{ ++ struct lima_vm *vm; ++ ++ vm = kzalloc(sizeof(*vm), GFP_KERNEL); ++ if (!vm) ++ return NULL; ++ ++ vm->dev = dev; ++ mutex_init(&vm->lock); ++ kref_init(&vm->refcount); ++ ++ vm->pd.cpu = dma_alloc_wc(dev->dev, LIMA_PAGE_SIZE, &vm->pd.dma, ++ GFP_KERNEL | __GFP_ZERO); ++ if (!vm->pd.cpu) ++ goto err_out0; ++ ++ if (dev->dlbu_cpu) { ++ int err = lima_vm_map_page_table( ++ vm, &dev->dlbu_dma, LIMA_VA_RESERVE_DLBU, ++ LIMA_VA_RESERVE_DLBU + LIMA_PAGE_SIZE - 1); ++ if (err) ++ goto err_out1; ++ } ++ ++ drm_mm_init(&vm->mm, dev->va_start, dev->va_end - dev->va_start); ++ ++ return vm; ++ ++err_out1: ++ dma_free_wc(dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma); ++err_out0: ++ kfree(vm); ++ return NULL; ++} ++ ++void lima_vm_release(struct kref *kref) ++{ ++ struct lima_vm *vm = container_of(kref, struct lima_vm, refcount); ++ int i; ++ ++ drm_mm_takedown(&vm->mm); ++ ++ for (i = 0; i < LIMA_VM_NUM_BT; i++) { ++ if (vm->bts[i].cpu) ++ dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE << LIMA_VM_NUM_PT_PER_BT_SHIFT, ++ vm->bts[i].cpu, vm->bts[i].dma); ++ } ++ ++ if (vm->pd.cpu) ++ dma_free_wc(vm->dev->dev, LIMA_PAGE_SIZE, vm->pd.cpu, vm->pd.dma); ++ ++ kfree(vm); ++} ++ ++void lima_vm_print(struct lima_vm *vm) ++{ ++ int i, j, k; ++ u32 *pd, *pt; ++ ++ if (!vm->pd.cpu) ++ return; ++ ++ pd = vm->pd.cpu; ++ for (i = 0; i < LIMA_VM_NUM_BT; i++) { ++ if (!vm->bts[i].cpu) ++ continue; ++ ++ pt = vm->bts[i].cpu; ++ for (j = 0; j < LIMA_VM_NUM_PT_PER_BT; j++) { ++ int idx = (i << LIMA_VM_NUM_PT_PER_BT_SHIFT) + j; ++ ++ printk(KERN_INFO "lima vm pd %03x:%08x\n", idx, pd[idx]); ++ ++ for (k = 0; k < LIMA_PAGE_ENT_NUM; k++) { ++ u32 pte = *pt++; ++ ++ if (pte) ++ printk(KERN_INFO " pt %03x:%08x\n", k, pte); ++ } ++ } ++ } ++} +diff --git a/drivers/gpu/drm/lima/lima_vm.h b/drivers/gpu/drm/lima/lima_vm.h +new file mode 100644 +index 0000000000000..caee2f8a29b40 +--- /dev/null ++++ b/drivers/gpu/drm/lima/lima_vm.h +@@ -0,0 +1,62 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* Copyright 2017-2019 Qiang Yu */ ++ ++#ifndef __LIMA_VM_H__ ++#define __LIMA_VM_H__ ++ ++#include ++#include ++ ++#define LIMA_PAGE_SIZE 4096 ++#define LIMA_PAGE_MASK (LIMA_PAGE_SIZE - 1) ++#define LIMA_PAGE_ENT_NUM (LIMA_PAGE_SIZE / sizeof(u32)) ++ ++#define LIMA_VM_NUM_PT_PER_BT_SHIFT 3 ++#define LIMA_VM_NUM_PT_PER_BT (1 << LIMA_VM_NUM_PT_PER_BT_SHIFT) ++#define LIMA_VM_NUM_BT (LIMA_PAGE_ENT_NUM >> LIMA_VM_NUM_PT_PER_BT_SHIFT) ++ ++#define LIMA_VA_RESERVE_START 0xFFF00000 ++#define LIMA_VA_RESERVE_DLBU LIMA_VA_RESERVE_START ++#define LIMA_VA_RESERVE_END 0x100000000 ++ ++struct lima_device; ++ ++struct lima_vm_page { ++ u32 *cpu; ++ dma_addr_t dma; ++}; ++ ++struct lima_vm { ++ struct mutex lock; ++ struct kref refcount; ++ ++ struct drm_mm mm; ++ ++ struct lima_device *dev; ++ ++ struct lima_vm_page pd; ++ struct lima_vm_page bts[LIMA_VM_NUM_BT]; ++}; ++ ++int lima_vm_bo_add(struct lima_vm *vm, struct lima_bo *bo, bool create); ++void lima_vm_bo_del(struct lima_vm *vm, struct lima_bo *bo); ++ ++u32 lima_vm_get_va(struct lima_vm *vm, struct lima_bo *bo); ++ ++struct lima_vm *lima_vm_create(struct lima_device *dev); ++void lima_vm_release(struct kref *kref); ++ ++static inline struct lima_vm *lima_vm_get(struct lima_vm *vm) ++{ ++ kref_get(&vm->refcount); ++ return vm; ++} ++ ++static inline void lima_vm_put(struct lima_vm *vm) ++{ ++ kref_put(&vm->refcount, lima_vm_release); ++} ++ ++void lima_vm_print(struct lima_vm *vm); ++ ++#endif +diff --git a/include/uapi/drm/lima_drm.h b/include/uapi/drm/lima_drm.h +new file mode 100644 +index 0000000000000..95a00fb867e62 +--- /dev/null ++++ b/include/uapi/drm/lima_drm.h +@@ -0,0 +1,169 @@ ++/* SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT */ ++/* Copyright 2017-2018 Qiang Yu */ ++ ++#ifndef __LIMA_DRM_H__ ++#define __LIMA_DRM_H__ ++ ++#include "drm.h" ++ ++#if defined(__cplusplus) ++extern "C" { ++#endif ++ ++enum drm_lima_param_gpu_id { ++ DRM_LIMA_PARAM_GPU_ID_UNKNOWN, ++ DRM_LIMA_PARAM_GPU_ID_MALI400, ++ DRM_LIMA_PARAM_GPU_ID_MALI450, ++}; ++ ++enum drm_lima_param { ++ DRM_LIMA_PARAM_GPU_ID, ++ DRM_LIMA_PARAM_NUM_PP, ++ DRM_LIMA_PARAM_GP_VERSION, ++ DRM_LIMA_PARAM_PP_VERSION, ++}; ++ ++/** ++ * get various information of the GPU ++ */ ++struct drm_lima_get_param { ++ __u32 param; /* in, value in enum drm_lima_param */ ++ __u32 pad; /* pad, must be zero */ ++ __u64 value; /* out, parameter value */ ++}; ++ ++/** ++ * create a buffer for used by GPU ++ */ ++struct drm_lima_gem_create { ++ __u32 size; /* in, buffer size */ ++ __u32 flags; /* in, currently no flags, must be zero */ ++ __u32 handle; /* out, GEM buffer handle */ ++ __u32 pad; /* pad, must be zero */ ++}; ++ ++/** ++ * get information of a buffer ++ */ ++struct drm_lima_gem_info { ++ __u32 handle; /* in, GEM buffer handle */ ++ __u32 va; /* out, virtual address mapped into GPU MMU */ ++ __u64 offset; /* out, used to mmap this buffer to CPU */ ++}; ++ ++#define LIMA_SUBMIT_BO_READ 0x01 ++#define LIMA_SUBMIT_BO_WRITE 0x02 ++ ++/* buffer information used by one task */ ++struct drm_lima_gem_submit_bo { ++ __u32 handle; /* in, GEM buffer handle */ ++ __u32 flags; /* in, buffer read/write by GPU */ ++}; ++ ++#define LIMA_GP_FRAME_REG_NUM 6 ++ ++/* frame used to setup GP for each task */ ++struct drm_lima_gp_frame { ++ __u32 frame[LIMA_GP_FRAME_REG_NUM]; ++}; ++ ++#define LIMA_PP_FRAME_REG_NUM 23 ++#define LIMA_PP_WB_REG_NUM 12 ++ ++/* frame used to setup mali400 GPU PP for each task */ ++struct drm_lima_m400_pp_frame { ++ __u32 frame[LIMA_PP_FRAME_REG_NUM]; ++ __u32 num_pp; ++ __u32 wb[3 * LIMA_PP_WB_REG_NUM]; ++ __u32 plbu_array_address[4]; ++ __u32 fragment_stack_address[4]; ++}; ++ ++/* frame used to setup mali450 GPU PP for each task */ ++struct drm_lima_m450_pp_frame { ++ __u32 frame[LIMA_PP_FRAME_REG_NUM]; ++ __u32 num_pp; ++ __u32 wb[3 * LIMA_PP_WB_REG_NUM]; ++ __u32 use_dlbu; ++ __u32 _pad; ++ union { ++ __u32 plbu_array_address[8]; ++ __u32 dlbu_regs[4]; ++ }; ++ __u32 fragment_stack_address[8]; ++}; ++ ++#define LIMA_PIPE_GP 0x00 ++#define LIMA_PIPE_PP 0x01 ++ ++#define LIMA_SUBMIT_FLAG_EXPLICIT_FENCE (1 << 0) ++ ++/** ++ * submit a task to GPU ++ * ++ * User can always merge multi sync_file and drm_syncobj ++ * into one drm_syncobj as in_sync[0], but we reserve ++ * in_sync[1] for another task's out_sync to avoid the ++ * export/import/merge pass when explicit sync. ++ */ ++struct drm_lima_gem_submit { ++ __u32 ctx; /* in, context handle task is submitted to */ ++ __u32 pipe; /* in, which pipe to use, GP/PP */ ++ __u32 nr_bos; /* in, array length of bos field */ ++ __u32 frame_size; /* in, size of frame field */ ++ __u64 bos; /* in, array of drm_lima_gem_submit_bo */ ++ __u64 frame; /* in, GP/PP frame */ ++ __u32 flags; /* in, submit flags */ ++ __u32 out_sync; /* in, drm_syncobj handle used to wait task finish after submission */ ++ __u32 in_sync[2]; /* in, drm_syncobj handle used to wait before start this task */ ++}; ++ ++#define LIMA_GEM_WAIT_READ 0x01 ++#define LIMA_GEM_WAIT_WRITE 0x02 ++ ++/** ++ * wait pending GPU task finish of a buffer ++ */ ++struct drm_lima_gem_wait { ++ __u32 handle; /* in, GEM buffer handle */ ++ __u32 op; /* in, CPU want to read/write this buffer */ ++ __s64 timeout_ns; /* in, wait timeout in absulute time */ ++}; ++ ++/** ++ * create a context ++ */ ++struct drm_lima_ctx_create { ++ __u32 id; /* out, context handle */ ++ __u32 _pad; /* pad, must be zero */ ++}; ++ ++/** ++ * free a context ++ */ ++struct drm_lima_ctx_free { ++ __u32 id; /* in, context handle */ ++ __u32 _pad; /* pad, must be zero */ ++}; ++ ++#define DRM_LIMA_GET_PARAM 0x00 ++#define DRM_LIMA_GEM_CREATE 0x01 ++#define DRM_LIMA_GEM_INFO 0x02 ++#define DRM_LIMA_GEM_SUBMIT 0x03 ++#define DRM_LIMA_GEM_WAIT 0x04 ++#define DRM_LIMA_CTX_CREATE 0x05 ++#define DRM_LIMA_CTX_FREE 0x06 ++ ++#define DRM_IOCTL_LIMA_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GET_PARAM, struct drm_lima_get_param) ++#define DRM_IOCTL_LIMA_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GEM_CREATE, struct drm_lima_gem_create) ++#define DRM_IOCTL_LIMA_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_LIMA_GEM_INFO, struct drm_lima_gem_info) ++#define DRM_IOCTL_LIMA_GEM_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_GEM_SUBMIT, struct drm_lima_gem_submit) ++#define DRM_IOCTL_LIMA_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_GEM_WAIT, struct drm_lima_gem_wait) ++#define DRM_IOCTL_LIMA_CTX_CREATE DRM_IOR(DRM_COMMAND_BASE + DRM_LIMA_CTX_CREATE, struct drm_lima_ctx_create) ++#define DRM_IOCTL_LIMA_CTX_FREE DRM_IOW(DRM_COMMAND_BASE + DRM_LIMA_CTX_FREE, struct drm_lima_ctx_free) ++ ++#if defined(__cplusplus) ++} ++#endif ++ ++#endif /* __LIMA_DRM_H__ */ + +From aee623b0324304230a81980cea78cc5d029502f9 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Tue, 9 Apr 2019 15:54:25 -0500 +Subject: [PATCH 243/249] iommu: io-pgtable: Add ARM Mali midgard MMU page + table format + +ARM Mali midgard GPU is similar to standard 64-bit stage 1 page tables, but +have a few differences. Add a new format type to represent the format. The +input address size is 48-bits and the output address size is 40-bits (and +possibly less?). Note that the later bifrost GPUs follow the standard +64-bit stage 1 format. + +The differences in the format compared to 64-bit stage 1 format are: + +The 3rd level page entry bits are 0x1 instead of 0x3 for page entries. + +The access flags are not read-only and unprivileged, but read and write. +This is similar to stage 2 entries, but the memory attributes field matches +stage 1 being an index. + +The nG bit is not set by the vendor driver. This one didn't seem to matter, +but we'll keep it aligned to the vendor driver. + +Cc: Will Deacon +Acked-by: Robin Murphy +Cc: Joerg Roedel +Cc: linux-arm-kernel@lists.infradead.org +Cc: iommu@lists.linux-foundation.org +Acked-by: Alyssa Rosenzweig +Signed-off-by: Rob Herring +--- + drivers/iommu/io-pgtable-arm.c | 91 ++++++++++++++++++++++++++-------- + drivers/iommu/io-pgtable.c | 1 + + include/linux/io-pgtable.h | 7 +++ + 3 files changed, 77 insertions(+), 22 deletions(-) + +diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c +index d3700ec15cbde..4e21efbc44595 100644 +--- a/drivers/iommu/io-pgtable-arm.c ++++ b/drivers/iommu/io-pgtable-arm.c +@@ -172,6 +172,10 @@ + #define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1 + #define ARM_LPAE_MAIR_ATTR_IDX_DEV 2 + ++#define ARM_MALI_LPAE_TTBR_ADRMODE_TABLE (3u << 0) ++#define ARM_MALI_LPAE_TTBR_READ_INNER BIT(2) ++#define ARM_MALI_LPAE_TTBR_SHARE_OUTER BIT(4) ++ + /* IOPTE accessors */ + #define iopte_deref(pte,d) __va(iopte_to_paddr(pte, d)) + +@@ -180,11 +184,6 @@ + + #define iopte_prot(pte) ((pte) & ARM_LPAE_PTE_ATTR_MASK) + +-#define iopte_leaf(pte,l) \ +- (l == (ARM_LPAE_MAX_LEVELS - 1) ? \ +- (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_PAGE) : \ +- (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_BLOCK)) +- + struct arm_lpae_io_pgtable { + struct io_pgtable iop; + +@@ -198,6 +197,15 @@ struct arm_lpae_io_pgtable { + + typedef u64 arm_lpae_iopte; + ++static inline bool iopte_leaf(arm_lpae_iopte pte, int lvl, ++ enum io_pgtable_fmt fmt) ++{ ++ if (lvl == (ARM_LPAE_MAX_LEVELS - 1) && fmt != ARM_MALI_LPAE) ++ return iopte_type(pte, lvl) == ARM_LPAE_PTE_TYPE_PAGE; ++ ++ return iopte_type(pte, lvl) == ARM_LPAE_PTE_TYPE_BLOCK; ++} ++ + static arm_lpae_iopte paddr_to_iopte(phys_addr_t paddr, + struct arm_lpae_io_pgtable *data) + { +@@ -303,12 +311,14 @@ static void __arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, + if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS) + pte |= ARM_LPAE_PTE_NS; + +- if (lvl == ARM_LPAE_MAX_LEVELS - 1) ++ if (data->iop.fmt != ARM_MALI_LPAE && lvl == ARM_LPAE_MAX_LEVELS - 1) + pte |= ARM_LPAE_PTE_TYPE_PAGE; + else + pte |= ARM_LPAE_PTE_TYPE_BLOCK; + +- pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS; ++ if (data->iop.fmt != ARM_MALI_LPAE) ++ pte |= ARM_LPAE_PTE_AF; ++ pte |= ARM_LPAE_PTE_SH_IS; + pte |= paddr_to_iopte(paddr, data); + + __arm_lpae_set_pte(ptep, pte, &data->iop.cfg); +@@ -321,7 +331,7 @@ static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data, + { + arm_lpae_iopte pte = *ptep; + +- if (iopte_leaf(pte, lvl)) { ++ if (iopte_leaf(pte, lvl, data->iop.fmt)) { + /* We require an unmap first */ + WARN_ON(!selftest_running); + return -EEXIST; +@@ -409,7 +419,7 @@ static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova, + __arm_lpae_sync_pte(ptep, cfg); + } + +- if (pte && !iopte_leaf(pte, lvl)) { ++ if (pte && !iopte_leaf(pte, lvl, data->iop.fmt)) { + cptep = iopte_deref(pte, data); + } else if (pte) { + /* We require an unmap first */ +@@ -429,31 +439,37 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, + if (data->iop.fmt == ARM_64_LPAE_S1 || + data->iop.fmt == ARM_32_LPAE_S1) { + pte = ARM_LPAE_PTE_nG; +- + if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) + pte |= ARM_LPAE_PTE_AP_RDONLY; +- + if (!(prot & IOMMU_PRIV)) + pte |= ARM_LPAE_PTE_AP_UNPRIV; +- +- if (prot & IOMMU_MMIO) +- pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV +- << ARM_LPAE_PTE_ATTRINDX_SHIFT); +- else if (prot & IOMMU_CACHE) +- pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE +- << ARM_LPAE_PTE_ATTRINDX_SHIFT); + } else { + pte = ARM_LPAE_PTE_HAP_FAULT; + if (prot & IOMMU_READ) + pte |= ARM_LPAE_PTE_HAP_READ; + if (prot & IOMMU_WRITE) + pte |= ARM_LPAE_PTE_HAP_WRITE; ++ } ++ ++ /* ++ * Note that this logic is structured to accommodate Mali LPAE ++ * having stage-1-like attributes but stage-2-like permissions. ++ */ ++ if (data->iop.fmt == ARM_64_LPAE_S2 || ++ data->iop.fmt == ARM_32_LPAE_S2) { + if (prot & IOMMU_MMIO) + pte |= ARM_LPAE_PTE_MEMATTR_DEV; + else if (prot & IOMMU_CACHE) + pte |= ARM_LPAE_PTE_MEMATTR_OIWB; + else + pte |= ARM_LPAE_PTE_MEMATTR_NC; ++ } else { ++ if (prot & IOMMU_MMIO) ++ pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV ++ << ARM_LPAE_PTE_ATTRINDX_SHIFT); ++ else if (prot & IOMMU_CACHE) ++ pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE ++ << ARM_LPAE_PTE_ATTRINDX_SHIFT); + } + + if (prot & IOMMU_NOEXEC) +@@ -511,7 +527,7 @@ static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl, + while (ptep != end) { + arm_lpae_iopte pte = *ptep++; + +- if (!pte || iopte_leaf(pte, lvl)) ++ if (!pte || iopte_leaf(pte, lvl, data->iop.fmt)) + continue; + + __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data)); +@@ -602,7 +618,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, + if (size == ARM_LPAE_BLOCK_SIZE(lvl, data)) { + __arm_lpae_set_pte(ptep, 0, &iop->cfg); + +- if (!iopte_leaf(pte, lvl)) { ++ if (!iopte_leaf(pte, lvl, iop->fmt)) { + /* Also flush any partial walks */ + io_pgtable_tlb_add_flush(iop, iova, size, + ARM_LPAE_GRANULE(data), false); +@@ -621,7 +637,7 @@ static size_t __arm_lpae_unmap(struct arm_lpae_io_pgtable *data, + } + + return size; +- } else if (iopte_leaf(pte, lvl)) { ++ } else if (iopte_leaf(pte, lvl, iop->fmt)) { + /* + * Insert a table at the next level to map the old region, + * minus the part we want to unmap +@@ -669,7 +685,7 @@ static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops, + return 0; + + /* Leaf entry? */ +- if (iopte_leaf(pte,lvl)) ++ if (iopte_leaf(pte, lvl, data->iop.fmt)) + goto found_translation; + + /* Take it to the next level */ +@@ -995,6 +1011,32 @@ arm_32_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie) + return iop; + } + ++static struct io_pgtable * ++arm_mali_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie) ++{ ++ struct io_pgtable *iop; ++ ++ if (cfg->ias != 48 || cfg->oas > 40) ++ return NULL; ++ ++ cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G); ++ iop = arm_64_lpae_alloc_pgtable_s1(cfg, cookie); ++ if (iop) { ++ u64 mair, ttbr; ++ ++ /* Copy values as union fields overlap */ ++ mair = cfg->arm_lpae_s1_cfg.mair[0]; ++ ttbr = cfg->arm_lpae_s1_cfg.ttbr[0]; ++ ++ cfg->arm_mali_lpae_cfg.memattr = mair; ++ cfg->arm_mali_lpae_cfg.transtab = ttbr | ++ ARM_MALI_LPAE_TTBR_READ_INNER | ++ ARM_MALI_LPAE_TTBR_ADRMODE_TABLE; ++ } ++ ++ return iop; ++} ++ + struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = { + .alloc = arm_64_lpae_alloc_pgtable_s1, + .free = arm_lpae_free_pgtable, +@@ -1015,6 +1057,11 @@ struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns = { + .free = arm_lpae_free_pgtable, + }; + ++struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns = { ++ .alloc = arm_mali_lpae_alloc_pgtable, ++ .free = arm_lpae_free_pgtable, ++}; ++ + #ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST + + static struct io_pgtable_cfg *cfg_cookie; +diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c +index 93f2880be6c67..5227cfdbb65b5 100644 +--- a/drivers/iommu/io-pgtable.c ++++ b/drivers/iommu/io-pgtable.c +@@ -30,6 +30,7 @@ io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] = { + [ARM_32_LPAE_S2] = &io_pgtable_arm_32_lpae_s2_init_fns, + [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns, + [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns, ++ [ARM_MALI_LPAE] = &io_pgtable_arm_mali_lpae_init_fns, + #endif + #ifdef CONFIG_IOMMU_IO_PGTABLE_ARMV7S + [ARM_V7S] = &io_pgtable_arm_v7s_init_fns, +diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h +index 47d5ae5593297..76969a5648314 100644 +--- a/include/linux/io-pgtable.h ++++ b/include/linux/io-pgtable.h +@@ -12,6 +12,7 @@ enum io_pgtable_fmt { + ARM_64_LPAE_S1, + ARM_64_LPAE_S2, + ARM_V7S, ++ ARM_MALI_LPAE, + IO_PGTABLE_NUM_FMTS, + }; + +@@ -108,6 +109,11 @@ struct io_pgtable_cfg { + u32 nmrr; + u32 prrr; + } arm_v7s_cfg; ++ ++ struct { ++ u64 transtab; ++ u64 memattr; ++ } arm_mali_lpae_cfg; + }; + }; + +@@ -209,5 +215,6 @@ extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns; + extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns; + extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns; + extern struct io_pgtable_init_fns io_pgtable_arm_v7s_init_fns; ++extern struct io_pgtable_init_fns io_pgtable_arm_mali_lpae_init_fns; + + #endif /* __IO_PGTABLE_H */ + +From c137ed8338c4206619299008ced60f1ba39976fb Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Tue, 9 Apr 2019 15:54:26 -0500 +Subject: [PATCH 244/249] drm: Add a drm_gem_objects_lookup helper + +Similar to the single handle drm_gem_object_lookup(), +drm_gem_objects_lookup() takes an array of handles and returns an array +of GEM objects. + +v2: +- Take the userspace pointer directly and allocate the array. +- Expand the function documentation. + +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Sean Paul +Cc: David Airlie +Cc: Daniel Vetter +Acked-by: Alyssa Rosenzweig +Signed-off-by: Rob Herring +Acked-by: Tomeu Vizoso +--- + drivers/gpu/drm/drm_gem.c | 93 ++++++++++++++++++++++++++++++++++----- + include/drm/drm_gem.h | 2 + + 2 files changed, 85 insertions(+), 10 deletions(-) + +diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c +index 388b3742e562a..faa2718e85e8b 100644 +--- a/drivers/gpu/drm/drm_gem.c ++++ b/drivers/gpu/drm/drm_gem.c +@@ -663,6 +663,85 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, + } + EXPORT_SYMBOL(drm_gem_put_pages); + ++static int objects_lookup(struct drm_file *filp, u32 *handle, int count, ++ struct drm_gem_object **objs) ++{ ++ int i, ret = 0; ++ struct drm_gem_object *obj; ++ ++ spin_lock(&filp->table_lock); ++ ++ for (i = 0; i < count; i++) { ++ /* Check if we currently have a reference on the object */ ++ obj = idr_find(&filp->object_idr, handle[i]); ++ if (!obj) { ++ ret = -ENOENT; ++ break; ++ } ++ drm_gem_object_get(obj); ++ objs[i] = obj; ++ } ++ spin_unlock(&filp->table_lock); ++ ++ return ret; ++} ++ ++/** ++ * drm_gem_objects_lookup - look up GEM objects from an array of handles ++ * @filp: DRM file private date ++ * @bo_handles: user pointer to array of userspace handle ++ * @count: size of handle array ++ * @objs_out: returned pointer to array of drm_gem_object pointers ++ * ++ * Takes an array of userspace handles and returns a newly allocated array of ++ * GEM objects. ++ * ++ * For a single handle lookup, use drm_gem_object_lookup(). ++ * ++ * Returns: ++ * ++ * @objs filled in with GEM object pointers. Returned GEM objects need to be ++ * released with drm_gem_object_put(). -ENOENT is returned on a lookup ++ * failure. 0 is returned on success. ++ * ++ */ ++int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, ++ int count, struct drm_gem_object ***objs_out) ++{ ++ int ret; ++ u32 *handles; ++ struct drm_gem_object **objs; ++ ++ if (!count) ++ return 0; ++ ++ objs = kvmalloc_array(count, sizeof(struct drm_gem_object *), ++ GFP_KERNEL | __GFP_ZERO); ++ if (!objs) ++ return -ENOMEM; ++ ++ handles = kvmalloc_array(count, sizeof(u32), GFP_KERNEL); ++ if (!handles) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ if (copy_from_user(handles, bo_handles, count * sizeof(u32))) { ++ ret = -EFAULT; ++ DRM_DEBUG("Failed to copy in GEM handles\n"); ++ goto out; ++ } ++ ++ ret = objects_lookup(filp, handles, count, objs); ++ *objs_out = objs; ++ ++out: ++ kvfree(handles); ++ return ret; ++ ++} ++EXPORT_SYMBOL(drm_gem_objects_lookup); ++ + /** + * drm_gem_object_lookup - look up a GEM object from its handle + * @filp: DRM file private date +@@ -672,21 +751,15 @@ EXPORT_SYMBOL(drm_gem_put_pages); + * + * A reference to the object named by the handle if such exists on @filp, NULL + * otherwise. ++ * ++ * If looking up an array of handles, use drm_gem_objects_lookup(). + */ + struct drm_gem_object * + drm_gem_object_lookup(struct drm_file *filp, u32 handle) + { +- struct drm_gem_object *obj; +- +- spin_lock(&filp->table_lock); +- +- /* Check if we currently have a reference on the object */ +- obj = idr_find(&filp->object_idr, handle); +- if (obj) +- drm_gem_object_get(obj); +- +- spin_unlock(&filp->table_lock); ++ struct drm_gem_object *obj = NULL; + ++ objects_lookup(filp, &handle, 1, &obj); + return obj; + } + EXPORT_SYMBOL(drm_gem_object_lookup); +diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h +index 2955aaab3dca0..5ee85c9eaa9db 100644 +--- a/include/drm/drm_gem.h ++++ b/include/drm/drm_gem.h +@@ -381,6 +381,8 @@ struct page **drm_gem_get_pages(struct drm_gem_object *obj); + void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, + bool dirty, bool accessed); + ++int drm_gem_objects_lookup(struct drm_file *filp, void __user *bo_handles, ++ int count, struct drm_gem_object ***objs_out); + struct drm_gem_object *drm_gem_object_lookup(struct drm_file *filp, u32 handle); + long drm_gem_reservation_object_wait(struct drm_file *filep, u32 handle, + bool wait_all, unsigned long timeout); + +From cbe2b4a4c7c5a9997aa78c19554be368c7d6ff49 Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Tue, 9 Apr 2019 15:54:27 -0500 +Subject: [PATCH 245/249] FROMLIST: drm/panfrost: Add initial panfrost driver + +This adds the initial driver for panfrost which supports Arm Mali +Midgard and Bifrost family of GPUs. Currently, only the T860 and +T760 Midgard GPUs have been tested. + +v2: +- Add GPU reset on job hangs (Tomeu) +- Add RuntimePM and devfreq support (Tomeu) +- Fix T760 support (Tomeu) +- Add a TODO file (Rob, Tomeu) +- Support multiple in fences (Tomeu) +- Drop support for shared fences (Tomeu) +- Fill in MMU de-init (Rob) +- Move register definitions back to single header (Rob) +- Clean-up hardcoded job submit todos (Rob) +- Implement feature setup based on features/issues (Rob) +- Add remaining Midgard DT compatible strings (Rob) + +v3: +- Add support for reset lines (Neil) +- Add a MAINTAINERS entry (Rob) +- Call dma_set_mask_and_coherent (Rob) +- Do MMU invalidate on map and unmap. Restructure to do a single + operation per map/unmap call. (Rob) +- Add a missing explicit padding to struct drm_panfrost_create_bo (Rob) +- Fix 0-day error: "panfrost_devfreq.c:151:9-16: ERROR: PTR_ERR applied after initialization to constant on line 150" +- Drop HW_FEATURE_AARCH64_MMU conditional (Rob) +- s/DRM_PANFROST_PARAM_GPU_ID/DRM_PANFROST_PARAM_GPU_PROD_ID/ (Rob) +- Check drm_gem_shmem_prime_import_sg_table() error code (Rob) +- Re-order power on sequence (Rob) +- Move panfrost_acquire_object_fences() before scheduling job (Rob) +- Add NULL checks on array pointers in job clean-up (Rob) +- Rework devfreq (Tomeu) +- Fix devfreq init with no regulator (Rob) +- Various WS and comments clean-up (Rob) + +Cc: Maarten Lankhorst +Cc: Maxime Ripard +Cc: Sean Paul +Cc: David Airlie +Cc: Daniel Vetter +Cc: Lyude Paul +Reviewed-by: Alyssa Rosenzweig +Reviewed-by: Eric Anholt +Signed-off-by: Marty E. Plummer +Signed-off-by: Tomeu Vizoso +Signed-off-by: Neil Armstrong +Signed-off-by: Rob Herring +Reviewed-by: Steven Price +--- + MAINTAINERS | 9 + + drivers/gpu/drm/Kconfig | 2 + + drivers/gpu/drm/Makefile | 1 + + drivers/gpu/drm/panfrost/Kconfig | 14 + + drivers/gpu/drm/panfrost/Makefile | 12 + + drivers/gpu/drm/panfrost/TODO | 27 + + drivers/gpu/drm/panfrost/panfrost_devfreq.c | 218 ++++++++ + drivers/gpu/drm/panfrost/panfrost_devfreq.h | 14 + + drivers/gpu/drm/panfrost/panfrost_device.c | 252 +++++++++ + drivers/gpu/drm/panfrost/panfrost_device.h | 124 ++++ + drivers/gpu/drm/panfrost/panfrost_drv.c | 460 +++++++++++++++ + drivers/gpu/drm/panfrost/panfrost_features.h | 309 ++++++++++ + drivers/gpu/drm/panfrost/panfrost_gem.c | 95 ++++ + drivers/gpu/drm/panfrost/panfrost_gem.h | 29 + + drivers/gpu/drm/panfrost/panfrost_gpu.c | 362 ++++++++++++ + drivers/gpu/drm/panfrost/panfrost_gpu.h | 19 + + drivers/gpu/drm/panfrost/panfrost_issues.h | 176 ++++++ + drivers/gpu/drm/panfrost/panfrost_job.c | 560 +++++++++++++++++++ + drivers/gpu/drm/panfrost/panfrost_job.h | 51 ++ + drivers/gpu/drm/panfrost/panfrost_mmu.c | 369 ++++++++++++ + drivers/gpu/drm/panfrost/panfrost_mmu.h | 17 + + drivers/gpu/drm/panfrost/panfrost_regs.h | 298 ++++++++++ + include/uapi/drm/panfrost_drm.h | 142 +++++ + 23 files changed, 3560 insertions(+) + create mode 100644 drivers/gpu/drm/panfrost/Kconfig + create mode 100644 drivers/gpu/drm/panfrost/Makefile + create mode 100644 drivers/gpu/drm/panfrost/TODO + create mode 100644 drivers/gpu/drm/panfrost/panfrost_devfreq.c + create mode 100644 drivers/gpu/drm/panfrost/panfrost_devfreq.h + create mode 100644 drivers/gpu/drm/panfrost/panfrost_device.c + create mode 100644 drivers/gpu/drm/panfrost/panfrost_device.h + create mode 100644 drivers/gpu/drm/panfrost/panfrost_drv.c + create mode 100644 drivers/gpu/drm/panfrost/panfrost_features.h + create mode 100644 drivers/gpu/drm/panfrost/panfrost_gem.c + create mode 100644 drivers/gpu/drm/panfrost/panfrost_gem.h + create mode 100644 drivers/gpu/drm/panfrost/panfrost_gpu.c + create mode 100644 drivers/gpu/drm/panfrost/panfrost_gpu.h + create mode 100644 drivers/gpu/drm/panfrost/panfrost_issues.h + create mode 100644 drivers/gpu/drm/panfrost/panfrost_job.c + create mode 100644 drivers/gpu/drm/panfrost/panfrost_job.h + create mode 100644 drivers/gpu/drm/panfrost/panfrost_mmu.c + create mode 100644 drivers/gpu/drm/panfrost/panfrost_mmu.h + create mode 100644 drivers/gpu/drm/panfrost/panfrost_regs.h + create mode 100644 include/uapi/drm/panfrost_drm.h + +diff --git a/MAINTAINERS b/MAINTAINERS +index f620e30ba67cb..d5f4434338ae8 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -1180,6 +1180,15 @@ F: drivers/gpu/drm/arm/ + F: Documentation/devicetree/bindings/display/arm,malidp.txt + F: Documentation/gpu/afbc.rst + ++ARM MALI PANFROST DRM DRIVER ++M: Rob Herring ++M: Tomeu Vizoso ++L: dri-devel@lists.freedesktop.org ++S: Supported ++T: git git://anongit.freedesktop.org/drm/drm-misc ++F: drivers/gpu/drm/panfrost/ ++F: include/uapi/drm/panfrost_drm.h ++ + ARM MFM AND FLOPPY DRIVERS + M: Ian Molton + S: Maintained +diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig +index 433250cf2beb1..cfddf1f240714 100644 +--- a/drivers/gpu/drm/Kconfig ++++ b/drivers/gpu/drm/Kconfig +@@ -337,6 +337,8 @@ source "drivers/gpu/drm/xen/Kconfig" + + source "drivers/gpu/drm/lima/Kconfig" + ++source "drivers/gpu/drm/panfrost/Kconfig" ++ + # Keep legacy drivers last + + menuconfig DRM_LEGACY +diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile +index 00e0dcc9a2ef5..29a6835db74fe 100644 +--- a/drivers/gpu/drm/Makefile ++++ b/drivers/gpu/drm/Makefile +@@ -111,3 +111,4 @@ obj-$(CONFIG_DRM_PL111) += pl111/ + obj-$(CONFIG_DRM_TVE200) += tve200/ + obj-$(CONFIG_DRM_XEN) += xen/ + obj-$(CONFIG_DRM_LIMA) += lima/ ++obj-$(CONFIG_DRM_PANFROST) += panfrost/ +diff --git a/drivers/gpu/drm/panfrost/Kconfig b/drivers/gpu/drm/panfrost/Kconfig +new file mode 100644 +index 0000000000000..7f5e572daa2dd +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/Kconfig +@@ -0,0 +1,14 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++config DRM_PANFROST ++ tristate "Panfrost (DRM support for ARM Mali Midgard/Bifrost GPUs)" ++ depends on DRM ++ depends on ARM || ARM64 || COMPILE_TEST ++ depends on MMU ++ select DRM_SCHED ++ select IOMMU_SUPPORT ++ select IOMMU_IO_PGTABLE_LPAE ++ select DRM_GEM_SHMEM_HELPER ++ help ++ DRM driver for ARM Mali Midgard (T6xx, T7xx, T8xx) and ++ Bifrost (G3x, G5x, G7x) GPUs. +diff --git a/drivers/gpu/drm/panfrost/Makefile b/drivers/gpu/drm/panfrost/Makefile +new file mode 100644 +index 0000000000000..6de72d13c58f8 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/Makefile +@@ -0,0 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0 ++ ++panfrost-y := \ ++ panfrost_drv.o \ ++ panfrost_device.o \ ++ panfrost_devfreq.o \ ++ panfrost_gem.o \ ++ panfrost_gpu.o \ ++ panfrost_job.o \ ++ panfrost_mmu.o ++ ++obj-$(CONFIG_DRM_PANFROST) += panfrost.o +diff --git a/drivers/gpu/drm/panfrost/TODO b/drivers/gpu/drm/panfrost/TODO +new file mode 100644 +index 0000000000000..c2e44add37d89 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/TODO +@@ -0,0 +1,27 @@ ++- Thermal support. ++ ++- Bifrost support: ++ - DT bindings (Neil, WIP) ++ - MMU page table format and address space setup ++ - Bifrost specific feature and issue handling ++ - Coherent DMA support ++ ++- Support for 2MB pages. The io-pgtable code already supports this. Finishing ++ support involves either copying or adapting the iommu API to handle passing ++ aligned addresses and sizes to the io-pgtable code. ++ ++- Per FD address space support. The h/w supports multiple addresses spaces. ++ The hard part is handling when more address spaces are needed than what ++ the h/w provides. ++ ++- Support pinning pages on demand (GPU page faults). ++ ++- Support userspace controlled GPU virtual addresses. Needed for Vulkan. (Tomeu) ++ ++- Support for madvise and a shrinker. ++ ++- Compute job support. So called 'compute only' jobs need to be plumbed up to ++ userspace. ++ ++- Performance counter support. (Boris) ++ +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +new file mode 100644 +index 0000000000000..a8121ae67ee33 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c +@@ -0,0 +1,218 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright 2019 Collabora ltd. */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "panfrost_device.h" ++#include "panfrost_features.h" ++#include "panfrost_issues.h" ++#include "panfrost_gpu.h" ++#include "panfrost_regs.h" ++ ++static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev, int slot); ++ ++static int panfrost_devfreq_target(struct device *dev, unsigned long *freq, ++ u32 flags) ++{ ++ struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev)); ++ struct dev_pm_opp *opp; ++ unsigned long old_clk_rate = pfdev->devfreq.cur_freq; ++ unsigned long target_volt, target_rate; ++ int err; ++ ++ opp = devfreq_recommended_opp(dev, freq, flags); ++ if (IS_ERR(opp)) ++ return PTR_ERR(opp); ++ ++ target_rate = dev_pm_opp_get_freq(opp); ++ target_volt = dev_pm_opp_get_voltage(opp); ++ dev_pm_opp_put(opp); ++ ++ if (old_clk_rate == target_rate) ++ return 0; ++ ++ /* ++ * If frequency scaling from low to high, adjust voltage first. ++ * If frequency scaling from high to low, adjust frequency first. ++ */ ++ if (old_clk_rate < target_rate) { ++ err = regulator_set_voltage(pfdev->regulator, target_volt, ++ target_volt); ++ if (err) { ++ dev_err(dev, "Cannot set voltage %lu uV\n", ++ target_volt); ++ return err; ++ } ++ } ++ ++ err = clk_set_rate(pfdev->clock, target_rate); ++ if (err) { ++ dev_err(dev, "Cannot set frequency %lu (%d)\n", target_rate, ++ err); ++ regulator_set_voltage(pfdev->regulator, pfdev->devfreq.cur_volt, ++ pfdev->devfreq.cur_volt); ++ return err; ++ } ++ ++ if (old_clk_rate > target_rate) { ++ err = regulator_set_voltage(pfdev->regulator, target_volt, ++ target_volt); ++ if (err) ++ dev_err(dev, "Cannot set voltage %lu uV\n", target_volt); ++ } ++ ++ pfdev->devfreq.cur_freq = target_rate; ++ pfdev->devfreq.cur_volt = target_volt; ++ ++ return 0; ++} ++ ++static void panfrost_devfreq_reset(struct panfrost_device *pfdev) ++{ ++ ktime_t now = ktime_get(); ++ int i; ++ ++ for (i = 0; i < NUM_JOB_SLOTS; i++) { ++ pfdev->devfreq.slot[i].busy_time = 0; ++ pfdev->devfreq.slot[i].idle_time = 0; ++ pfdev->devfreq.slot[i].time_last_update = now; ++ } ++} ++ ++static int panfrost_devfreq_get_dev_status(struct device *dev, ++ struct devfreq_dev_status *status) ++{ ++ struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev)); ++ int i; ++ ++ for (i = 0; i < NUM_JOB_SLOTS; i++) { ++ panfrost_devfreq_update_utilization(pfdev, i); ++ } ++ ++ status->current_frequency = clk_get_rate(pfdev->clock); ++ status->total_time = ktime_to_ns(ktime_add(pfdev->devfreq.slot[0].busy_time, ++ pfdev->devfreq.slot[0].idle_time)); ++ ++ status->busy_time = 0; ++ for (i = 0; i < NUM_JOB_SLOTS; i++) { ++ status->busy_time += ktime_to_ns(pfdev->devfreq.slot[i].busy_time); ++ } ++ ++ /* We're scheduling only to one core atm, so don't divide for now */ ++ /* status->busy_time /= NUM_JOB_SLOTS; */ ++ ++ panfrost_devfreq_reset(pfdev); ++ ++ dev_dbg(pfdev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n", status->busy_time, ++ status->total_time, ++ status->busy_time / (status->total_time / 100), ++ status->current_frequency / 1000 / 1000); ++ ++ return 0; ++} ++ ++static int panfrost_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) ++{ ++ struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev)); ++ ++ *freq = pfdev->devfreq.cur_freq; ++ ++ return 0; ++} ++ ++static struct devfreq_dev_profile panfrost_devfreq_profile = { ++ .polling_ms = 50, /* ~3 frames */ ++ .target = panfrost_devfreq_target, ++ .get_dev_status = panfrost_devfreq_get_dev_status, ++ .get_cur_freq = panfrost_devfreq_get_cur_freq, ++}; ++ ++int panfrost_devfreq_init(struct panfrost_device *pfdev) ++{ ++ int ret; ++ struct dev_pm_opp *opp; ++ ++ if (!pfdev->regulator) ++ return 0; ++ ++ ret = dev_pm_opp_of_add_table(&pfdev->pdev->dev); ++ if (ret == -ENODEV) /* Optional, continue without devfreq */ ++ return 0; ++ ++ panfrost_devfreq_reset(pfdev); ++ ++ pfdev->devfreq.cur_freq = clk_get_rate(pfdev->clock); ++ ++ opp = devfreq_recommended_opp(&pfdev->pdev->dev, &pfdev->devfreq.cur_freq, 0); ++ if (IS_ERR(opp)) ++ return PTR_ERR(opp); ++ ++ panfrost_devfreq_profile.initial_freq = pfdev->devfreq.cur_freq; ++ dev_pm_opp_put(opp); ++ ++ pfdev->devfreq.devfreq = devm_devfreq_add_device(&pfdev->pdev->dev, ++ &panfrost_devfreq_profile, "simple_ondemand", NULL); ++ if (IS_ERR(pfdev->devfreq.devfreq)) { ++ DRM_DEV_ERROR(&pfdev->pdev->dev, "Couldn't initialize GPU devfreq\n"); ++ ret = PTR_ERR(pfdev->devfreq.devfreq); ++ pfdev->devfreq.devfreq = NULL; ++ return ret; ++ } ++ ++ return 0; ++} ++ ++void panfrost_devfreq_resume(struct panfrost_device *pfdev) ++{ ++ int i; ++ ++ if (!pfdev->devfreq.devfreq) ++ return; ++ ++ panfrost_devfreq_reset(pfdev); ++ for (i = 0; i < NUM_JOB_SLOTS; i++) ++ pfdev->devfreq.slot[i].busy = false; ++ ++ devfreq_resume_device(pfdev->devfreq.devfreq); ++} ++ ++void panfrost_devfreq_suspend(struct panfrost_device *pfdev) ++{ ++ if (!pfdev->devfreq.devfreq) ++ return; ++ ++ devfreq_suspend_device(pfdev->devfreq.devfreq); ++} ++ ++static void panfrost_devfreq_update_utilization(struct panfrost_device *pfdev, int slot) ++{ ++ struct panfrost_devfreq_slot *devfreq_slot = &pfdev->devfreq.slot[slot]; ++ ktime_t now; ++ ktime_t last; ++ ++ if (!pfdev->devfreq.devfreq) ++ return; ++ ++ now = ktime_get(); ++ last = pfdev->devfreq.slot[slot].time_last_update; ++ ++ /* If we last recorded a transition to busy, we have been idle since */ ++ if (devfreq_slot->busy) ++ pfdev->devfreq.slot[slot].busy_time += ktime_sub(now, last); ++ else ++ pfdev->devfreq.slot[slot].idle_time += ktime_sub(now, last); ++ ++ pfdev->devfreq.slot[slot].time_last_update = now; ++} ++ ++/* The job scheduler is expected to call this at every transition busy <-> idle */ ++void panfrost_devfreq_record_transition(struct panfrost_device *pfdev, int slot) ++{ ++ struct panfrost_devfreq_slot *devfreq_slot = &pfdev->devfreq.slot[slot]; ++ ++ panfrost_devfreq_update_utilization(pfdev, slot); ++ devfreq_slot->busy = !devfreq_slot->busy; ++} +diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +new file mode 100644 +index 0000000000000..eb999531ed900 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h +@@ -0,0 +1,14 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright 2019 Collabora ltd. */ ++ ++#ifndef __PANFROST_DEVFREQ_H__ ++#define __PANFROST_DEVFREQ_H__ ++ ++int panfrost_devfreq_init(struct panfrost_device *pfdev); ++ ++void panfrost_devfreq_resume(struct panfrost_device *pfdev); ++void panfrost_devfreq_suspend(struct panfrost_device *pfdev); ++ ++void panfrost_devfreq_record_transition(struct panfrost_device *pfdev, int slot); ++ ++#endif /* __PANFROST_DEVFREQ_H__ */ +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c +new file mode 100644 +index 0000000000000..91e8fb0f2b25b +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_device.c +@@ -0,0 +1,252 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright 2018 Marty E. Plummer */ ++/* Copyright 2019 Linaro, Ltd, Rob Herring */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "panfrost_device.h" ++#include "panfrost_devfreq.h" ++#include "panfrost_features.h" ++#include "panfrost_gpu.h" ++#include "panfrost_job.h" ++#include "panfrost_mmu.h" ++ ++static int panfrost_reset_init(struct panfrost_device *pfdev) ++{ ++ int err; ++ ++ pfdev->rstc = devm_reset_control_array_get(pfdev->dev, false, true); ++ if (IS_ERR(pfdev->rstc)) { ++ dev_err(pfdev->dev, "get reset failed %ld\n", PTR_ERR(pfdev->rstc)); ++ return PTR_ERR(pfdev->rstc); ++ } ++ ++ err = reset_control_deassert(pfdev->rstc); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static void panfrost_reset_fini(struct panfrost_device *pfdev) ++{ ++ reset_control_assert(pfdev->rstc); ++} ++ ++static int panfrost_clk_init(struct panfrost_device *pfdev) ++{ ++ int err; ++ unsigned long rate; ++ ++ pfdev->clock = devm_clk_get(pfdev->dev, NULL); ++ if (IS_ERR(pfdev->clock)) { ++ dev_err(pfdev->dev, "get clock failed %ld\n", PTR_ERR(pfdev->clock)); ++ return PTR_ERR(pfdev->clock); ++ } ++ ++ rate = clk_get_rate(pfdev->clock); ++ dev_info(pfdev->dev, "clock rate = %lu\n", rate); ++ ++ err = clk_prepare_enable(pfdev->clock); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static void panfrost_clk_fini(struct panfrost_device *pfdev) ++{ ++ clk_disable_unprepare(pfdev->clock); ++} ++ ++static int panfrost_regulator_init(struct panfrost_device *pfdev) ++{ ++ int ret; ++ ++ pfdev->regulator = devm_regulator_get_optional(pfdev->dev, "mali"); ++ if (IS_ERR(pfdev->regulator)) { ++ ret = PTR_ERR(pfdev->regulator); ++ pfdev->regulator = NULL; ++ if (ret == -ENODEV) ++ return 0; ++ dev_err(pfdev->dev, "failed to get regulator: %d\n", ret); ++ return ret; ++ } ++ ++ ret = regulator_enable(pfdev->regulator); ++ if (ret < 0) { ++ dev_err(pfdev->dev, "failed to enable regulator: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void panfrost_regulator_fini(struct panfrost_device *pfdev) ++{ ++ if (pfdev->regulator) ++ regulator_disable(pfdev->regulator); ++} ++ ++int panfrost_device_init(struct panfrost_device *pfdev) ++{ ++ int err; ++ struct resource *res; ++ ++ mutex_init(&pfdev->sched_lock); ++ INIT_LIST_HEAD(&pfdev->scheduled_jobs); ++ ++ spin_lock_init(&pfdev->hwaccess_lock); ++ ++ err = panfrost_clk_init(pfdev); ++ if (err) { ++ dev_err(pfdev->dev, "clk init failed %d\n", err); ++ return err; ++ } ++ ++ err = panfrost_regulator_init(pfdev); ++ if (err) { ++ dev_err(pfdev->dev, "regulator init failed %d\n", err); ++ goto err_out0; ++ } ++ ++ err = panfrost_reset_init(pfdev); ++ if (err) { ++ dev_err(pfdev->dev, "reset init failed %d\n", err); ++ goto err_out1; ++ } ++ ++ res = platform_get_resource(pfdev->pdev, IORESOURCE_MEM, 0); ++ pfdev->iomem = devm_ioremap_resource(pfdev->dev, res); ++ if (IS_ERR(pfdev->iomem)) { ++ dev_err(pfdev->dev, "failed to ioremap iomem\n"); ++ err = PTR_ERR(pfdev->iomem); ++ goto err_out2; ++ } ++ ++ err = panfrost_gpu_init(pfdev); ++ if (err) ++ goto err_out2; ++ ++ err = panfrost_mmu_init(pfdev); ++ if (err) ++ goto err_out3; ++ ++ err = panfrost_job_init(pfdev); ++ if (err) ++ goto err_out4; ++ ++ /* runtime PM will wake us up later */ ++ panfrost_gpu_power_off(pfdev); ++ ++ pm_runtime_set_active(pfdev->dev); ++ pm_runtime_get_sync(pfdev->dev); ++ pm_runtime_mark_last_busy(pfdev->dev); ++ pm_runtime_put_autosuspend(pfdev->dev); ++ ++ return 0; ++err_out4: ++ panfrost_mmu_fini(pfdev); ++err_out3: ++ panfrost_gpu_fini(pfdev); ++err_out2: ++ panfrost_reset_fini(pfdev); ++err_out1: ++ panfrost_regulator_fini(pfdev); ++err_out0: ++ panfrost_clk_fini(pfdev); ++ return err; ++} ++ ++void panfrost_device_fini(struct panfrost_device *pfdev) ++{ ++ panfrost_regulator_fini(pfdev); ++ panfrost_clk_fini(pfdev); ++} ++ ++const char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception_code) ++{ ++ switch (exception_code) { ++ /* Non-Fault Status code */ ++ case 0x00: return "NOT_STARTED/IDLE/OK"; ++ case 0x01: return "DONE"; ++ case 0x02: return "INTERRUPTED"; ++ case 0x03: return "STOPPED"; ++ case 0x04: return "TERMINATED"; ++ case 0x08: return "ACTIVE"; ++ /* Job exceptions */ ++ case 0x40: return "JOB_CONFIG_FAULT"; ++ case 0x41: return "JOB_POWER_FAULT"; ++ case 0x42: return "JOB_READ_FAULT"; ++ case 0x43: return "JOB_WRITE_FAULT"; ++ case 0x44: return "JOB_AFFINITY_FAULT"; ++ case 0x48: return "JOB_BUS_FAULT"; ++ case 0x50: return "INSTR_INVALID_PC"; ++ case 0x51: return "INSTR_INVALID_ENC"; ++ case 0x52: return "INSTR_TYPE_MISMATCH"; ++ case 0x53: return "INSTR_OPERAND_FAULT"; ++ case 0x54: return "INSTR_TLS_FAULT"; ++ case 0x55: return "INSTR_BARRIER_FAULT"; ++ case 0x56: return "INSTR_ALIGN_FAULT"; ++ case 0x58: return "DATA_INVALID_FAULT"; ++ case 0x59: return "TILE_RANGE_FAULT"; ++ case 0x5A: return "ADDR_RANGE_FAULT"; ++ case 0x60: return "OUT_OF_MEMORY"; ++ /* GPU exceptions */ ++ case 0x80: return "DELAYED_BUS_FAULT"; ++ case 0x88: return "SHAREABILITY_FAULT"; ++ /* MMU exceptions */ ++ case 0xC1: return "TRANSLATION_FAULT_LEVEL1"; ++ case 0xC2: return "TRANSLATION_FAULT_LEVEL2"; ++ case 0xC3: return "TRANSLATION_FAULT_LEVEL3"; ++ case 0xC4: return "TRANSLATION_FAULT_LEVEL4"; ++ case 0xC8: return "PERMISSION_FAULT"; ++ case 0xC9 ... 0xCF: return "PERMISSION_FAULT"; ++ case 0xD1: return "TRANSTAB_BUS_FAULT_LEVEL1"; ++ case 0xD2: return "TRANSTAB_BUS_FAULT_LEVEL2"; ++ case 0xD3: return "TRANSTAB_BUS_FAULT_LEVEL3"; ++ case 0xD4: return "TRANSTAB_BUS_FAULT_LEVEL4"; ++ case 0xD8: return "ACCESS_FLAG"; ++ case 0xD9 ... 0xDF: return "ACCESS_FLAG"; ++ case 0xE0 ... 0xE7: return "ADDRESS_SIZE_FAULT"; ++ case 0xE8 ... 0xEF: return "MEMORY_ATTRIBUTES_FAULT"; ++ } ++ ++ return "UNKNOWN"; ++} ++ ++#ifdef CONFIG_PM ++int panfrost_device_resume(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct panfrost_device *pfdev = platform_get_drvdata(pdev); ++ ++ panfrost_gpu_soft_reset(pfdev); ++ ++ /* TODO: Re-enable all other address spaces */ ++ panfrost_gpu_power_on(pfdev); ++ panfrost_mmu_enable(pfdev, 0); ++ panfrost_job_enable_interrupts(pfdev); ++ panfrost_devfreq_resume(pfdev); ++ ++ return 0; ++} ++ ++int panfrost_device_suspend(struct device *dev) ++{ ++ struct platform_device *pdev = to_platform_device(dev); ++ struct panfrost_device *pfdev = platform_get_drvdata(pdev); ++ ++ if (!panfrost_job_is_idle(pfdev)) ++ return -EBUSY; ++ ++ panfrost_devfreq_suspend(pfdev); ++ panfrost_gpu_power_off(pfdev); ++ ++ return 0; ++} ++#endif +diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h +new file mode 100644 +index 0000000000000..1ba48d105763d +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_device.h +@@ -0,0 +1,124 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright 2018 Marty E. Plummer */ ++/* Copyright 2019 Linaro, Ltd, Rob Herring */ ++ ++#ifndef __PANFROST_DEVICE_H__ ++#define __PANFROST_DEVICE_H__ ++ ++#include ++#include ++#include ++#include ++ ++struct panfrost_device; ++struct panfrost_mmu; ++struct panfrost_job_slot; ++struct panfrost_job; ++ ++#define NUM_JOB_SLOTS 3 ++ ++struct panfrost_features { ++ u16 id; ++ u16 revision; ++ ++ u64 shader_present; ++ u64 tiler_present; ++ u64 l2_present; ++ u64 stack_present; ++ u32 as_present; ++ u32 js_present; ++ ++ u32 l2_features; ++ u32 core_features; ++ u32 tiler_features; ++ u32 mem_features; ++ u32 mmu_features; ++ u32 thread_features; ++ u32 max_threads; ++ u32 thread_max_workgroup_sz; ++ u32 thread_max_barrier_sz; ++ u32 coherency_features; ++ u32 texture_features[4]; ++ u32 js_features[16]; ++ ++ u32 nr_core_groups; ++ ++ unsigned long hw_features[64 / BITS_PER_LONG]; ++ unsigned long hw_issues[64 / BITS_PER_LONG]; ++}; ++ ++struct panfrost_devfreq_slot { ++ ktime_t busy_time; ++ ktime_t idle_time; ++ ktime_t time_last_update; ++ bool busy; ++}; ++ ++struct panfrost_device { ++ struct device *dev; ++ struct drm_device *ddev; ++ struct platform_device *pdev; ++ ++ spinlock_t hwaccess_lock; ++ ++ struct drm_mm mm; ++ spinlock_t mm_lock; ++ ++ void __iomem *iomem; ++ struct clk *clock; ++ struct regulator *regulator; ++ struct reset_control *rstc; ++ ++ struct panfrost_features features; ++ ++ struct panfrost_mmu *mmu; ++ struct panfrost_job_slot *js; ++ ++ struct panfrost_job *jobs[NUM_JOB_SLOTS]; ++ struct list_head scheduled_jobs; ++ ++ struct mutex sched_lock; ++ ++ struct { ++ struct devfreq *devfreq; ++ struct thermal_cooling_device *cooling; ++ unsigned long cur_freq; ++ unsigned long cur_volt; ++ struct panfrost_devfreq_slot slot[NUM_JOB_SLOTS]; ++ } devfreq; ++}; ++ ++struct panfrost_file_priv { ++ struct panfrost_device *pfdev; ++ ++ struct drm_sched_entity sched_entity[NUM_JOB_SLOTS]; ++}; ++ ++static inline struct panfrost_device *to_panfrost_device(struct drm_device *ddev) ++{ ++ return ddev->dev_private; ++} ++ ++static inline int panfrost_model_cmp(struct panfrost_device *pfdev, s32 id) ++{ ++ s32 match_id = pfdev->features.id; ++ ++ if (match_id & 0xf000) ++ match_id &= 0xf00f; ++ return match_id - id; ++} ++ ++static inline bool panfrost_model_eq(struct panfrost_device *pfdev, s32 id) ++{ ++ return !panfrost_model_cmp(pfdev, id); ++} ++ ++int panfrost_device_init(struct panfrost_device *pfdev); ++void panfrost_device_fini(struct panfrost_device *pfdev); ++ ++int panfrost_device_resume(struct device *dev); ++int panfrost_device_suspend(struct device *dev); ++ ++const char *panfrost_exception_name(struct panfrost_device *pfdev, u32 exception_code); ++ ++#endif +diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c +new file mode 100644 +index 0000000000000..46da249edf32d +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_drv.c +@@ -0,0 +1,460 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright 2018 Marty E. Plummer */ ++/* Copyright 2019 Linaro, Ltd., Rob Herring */ ++/* Copyright 2019 Collabora ltd. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "panfrost_device.h" ++#include "panfrost_devfreq.h" ++#include "panfrost_gem.h" ++#include "panfrost_mmu.h" ++#include "panfrost_job.h" ++#include "panfrost_gpu.h" ++ ++static int panfrost_ioctl_get_param(struct drm_device *ddev, void *data, struct drm_file *file) ++{ ++ struct drm_panfrost_get_param *param = data; ++ struct panfrost_device *pfdev = ddev->dev_private; ++ ++ if (param->pad != 0) ++ return -EINVAL; ++ ++ switch (param->param) { ++ case DRM_PANFROST_PARAM_GPU_PROD_ID: ++ param->value = pfdev->features.id; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int panfrost_ioctl_create_bo(struct drm_device *dev, void *data, ++ struct drm_file *file) ++{ ++ int ret; ++ struct drm_gem_shmem_object *shmem; ++ struct drm_panfrost_create_bo *args = data; ++ ++ if (!args->size || args->flags) ++ return -EINVAL; ++ ++ shmem = drm_gem_shmem_create_with_handle(file, dev, args->size, ++ &args->handle); ++ if (IS_ERR(shmem)) ++ return PTR_ERR(shmem); ++ ++ ret = panfrost_mmu_map(to_panfrost_bo(&shmem->base)); ++ if (ret) ++ goto err_free; ++ ++ args->offset = to_panfrost_bo(&shmem->base)->node.start << PAGE_SHIFT; ++ ++ return 0; ++ ++err_free: ++ drm_gem_object_put_unlocked(&shmem->base); ++ return ret; ++} ++ ++/** ++ * panfrost_lookup_bos() - Sets up job->bo[] with the GEM objects ++ * referenced by the job. ++ * @dev: DRM device ++ * @file_priv: DRM file for this fd ++ * @args: IOCTL args ++ * @job: job being set up ++ * ++ * Resolve handles from userspace to BOs and attach them to job. ++ * ++ * Note that this function doesn't need to unreference the BOs on ++ * failure, because that will happen at panfrost_job_cleanup() time. ++ */ ++static int ++panfrost_lookup_bos(struct drm_device *dev, ++ struct drm_file *file_priv, ++ struct drm_panfrost_submit *args, ++ struct panfrost_job *job) ++{ ++ job->bo_count = args->bo_handle_count; ++ ++ if (!job->bo_count) ++ return 0; ++ ++ job->implicit_fences = kvmalloc_array(job->bo_count, ++ sizeof(struct dma_fence *), ++ GFP_KERNEL | __GFP_ZERO); ++ if (!job->implicit_fences) ++ return -ENOMEM; ++ ++ return drm_gem_objects_lookup(file_priv, ++ (void __user *)(uintptr_t)args->bo_handles, ++ job->bo_count, &job->bos); ++} ++ ++/** ++ * panfrost_copy_in_sync() - Sets up job->in_fences[] with the sync objects ++ * referenced by the job. ++ * @dev: DRM device ++ * @file_priv: DRM file for this fd ++ * @args: IOCTL args ++ * @job: job being set up ++ * ++ * Resolve syncobjs from userspace to fences and attach them to job. ++ * ++ * Note that this function doesn't need to unreference the fences on ++ * failure, because that will happen at panfrost_job_cleanup() time. ++ */ ++static int ++panfrost_copy_in_sync(struct drm_device *dev, ++ struct drm_file *file_priv, ++ struct drm_panfrost_submit *args, ++ struct panfrost_job *job) ++{ ++ u32 *handles; ++ int ret = 0; ++ int i; ++ ++ job->in_fence_count = args->in_sync_count; ++ ++ if (!job->in_fence_count) ++ return 0; ++ ++ job->in_fences = kvmalloc_array(job->in_fence_count, ++ sizeof(struct dma_fence *), ++ GFP_KERNEL | __GFP_ZERO); ++ if (!job->in_fences) { ++ DRM_DEBUG("Failed to allocate job in fences\n"); ++ return -ENOMEM; ++ } ++ ++ handles = kvmalloc_array(job->in_fence_count, sizeof(u32), GFP_KERNEL); ++ if (!handles) { ++ ret = -ENOMEM; ++ DRM_DEBUG("Failed to allocate incoming syncobj handles\n"); ++ goto fail; ++ } ++ ++ if (copy_from_user(handles, ++ (void __user *)(uintptr_t)args->in_syncs, ++ job->in_fence_count * sizeof(u32))) { ++ ret = -EFAULT; ++ DRM_DEBUG("Failed to copy in syncobj handles\n"); ++ goto fail; ++ } ++ ++ for (i = 0; i < job->in_fence_count; i++) { ++ ret = drm_syncobj_find_fence(file_priv, handles[i], 0, 0, ++ &job->in_fences[i]); ++ if (ret == -EINVAL) ++ goto fail; ++ } ++ ++fail: ++ kvfree(handles); ++ return ret; ++} ++ ++static int panfrost_ioctl_submit(struct drm_device *dev, void *data, ++ struct drm_file *file) ++{ ++ struct panfrost_device *pfdev = dev->dev_private; ++ struct drm_panfrost_submit *args = data; ++ struct drm_syncobj *sync_out; ++ struct panfrost_job *job; ++ int ret = 0; ++ ++ job = kcalloc(1, sizeof(*job), GFP_KERNEL); ++ if (!job) ++ return -ENOMEM; ++ ++ kref_init(&job->refcount); ++ ++ job->pfdev = pfdev; ++ job->jc = args->jc; ++ job->requirements = args->requirements; ++ job->flush_id = panfrost_gpu_get_latest_flush_id(pfdev); ++ job->file_priv = file->driver_priv; ++ ++ ret = panfrost_copy_in_sync(dev, file, args, job); ++ if (ret) ++ goto fail; ++ ++ ret = panfrost_lookup_bos(dev, file, args, job); ++ if (ret) ++ goto fail; ++ ++ ret = panfrost_job_push(job); ++ if (ret) ++ goto fail; ++ ++ /* Update the return sync object for the job */ ++ sync_out = drm_syncobj_find(file, args->out_sync); ++ if (sync_out) { ++ drm_syncobj_replace_fence(sync_out, job->render_done_fence); ++ drm_syncobj_put(sync_out); ++ } ++ ++fail: ++ panfrost_job_put(job); ++ ++ return ret; ++} ++ ++static int ++panfrost_ioctl_wait_bo(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ long ret; ++ struct drm_panfrost_wait_bo *args = data; ++ struct drm_gem_object *gem_obj; ++ unsigned long timeout = drm_timeout_abs_to_jiffies(args->timeout_ns); ++ ++ if (args->pad) ++ return -EINVAL; ++ ++ gem_obj = drm_gem_object_lookup(file_priv, args->handle); ++ if (!gem_obj) ++ return -ENOENT; ++ ++ ret = reservation_object_wait_timeout_rcu(gem_obj->resv, true, ++ true, timeout); ++ if (!ret) ++ ret = timeout ? -ETIMEDOUT : -EBUSY; ++ ++ drm_gem_object_put_unlocked(gem_obj); ++ ++ return ret; ++} ++ ++static int panfrost_ioctl_mmap_bo(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_panfrost_mmap_bo *args = data; ++ struct drm_gem_object *gem_obj; ++ int ret; ++ ++ if (args->flags != 0) { ++ DRM_INFO("unknown mmap_bo flags: %d\n", args->flags); ++ return -EINVAL; ++ } ++ ++ gem_obj = drm_gem_object_lookup(file_priv, args->handle); ++ if (!gem_obj) { ++ DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); ++ return -ENOENT; ++ } ++ ++ ret = drm_gem_create_mmap_offset(gem_obj); ++ if (ret == 0) ++ args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); ++ drm_gem_object_put_unlocked(gem_obj); ++ ++ return ret; ++} ++ ++static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data, ++ struct drm_file *file_priv) ++{ ++ struct drm_panfrost_get_bo_offset *args = data; ++ struct drm_gem_object *gem_obj; ++ struct panfrost_gem_object *bo; ++ ++ gem_obj = drm_gem_object_lookup(file_priv, args->handle); ++ if (!gem_obj) { ++ DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle); ++ return -ENOENT; ++ } ++ bo = to_panfrost_bo(gem_obj); ++ ++ args->offset = bo->node.start << PAGE_SHIFT; ++ ++ drm_gem_object_put_unlocked(gem_obj); ++ return 0; ++} ++ ++static int ++panfrost_open(struct drm_device *dev, struct drm_file *file) ++{ ++ struct panfrost_device *pfdev = dev->dev_private; ++ struct panfrost_file_priv *panfrost_priv; ++ ++ panfrost_priv = kzalloc(sizeof(*panfrost_priv), GFP_KERNEL); ++ if (!panfrost_priv) ++ return -ENOMEM; ++ ++ panfrost_priv->pfdev = pfdev; ++ file->driver_priv = panfrost_priv; ++ ++ return panfrost_job_open(panfrost_priv); ++} ++ ++static void ++panfrost_postclose(struct drm_device *dev, struct drm_file *file) ++{ ++ struct panfrost_file_priv *panfrost_priv = file->driver_priv; ++ ++ panfrost_job_close(panfrost_priv); ++ ++ kfree(panfrost_priv); ++} ++ ++/* DRM_AUTH is required on SUBMIT for now, while all clients share a single ++ * address space. Note that render nodes would be able to submit jobs that ++ * could access BOs from clients authenticated with the master node. ++ */ ++static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { ++#define PANFROST_IOCTL(n, func, flags) \ ++ DRM_IOCTL_DEF_DRV(PANFROST_##n, panfrost_ioctl_##func, flags) ++ ++ PANFROST_IOCTL(SUBMIT, submit, DRM_RENDER_ALLOW | DRM_AUTH), ++ PANFROST_IOCTL(WAIT_BO, wait_bo, DRM_RENDER_ALLOW), ++ PANFROST_IOCTL(CREATE_BO, create_bo, DRM_RENDER_ALLOW), ++ PANFROST_IOCTL(MMAP_BO, mmap_bo, DRM_RENDER_ALLOW), ++ PANFROST_IOCTL(GET_PARAM, get_param, DRM_RENDER_ALLOW), ++ PANFROST_IOCTL(GET_BO_OFFSET, get_bo_offset, DRM_RENDER_ALLOW), ++}; ++ ++DEFINE_DRM_GEM_SHMEM_FOPS(panfrost_drm_driver_fops); ++ ++static struct drm_driver panfrost_drm_driver = { ++ .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_PRIME | ++ DRIVER_SYNCOBJ, ++ .open = panfrost_open, ++ .postclose = panfrost_postclose, ++ .ioctls = panfrost_drm_driver_ioctls, ++ .num_ioctls = ARRAY_SIZE(panfrost_drm_driver_ioctls), ++ .fops = &panfrost_drm_driver_fops, ++ .name = "panfrost", ++ .desc = "panfrost DRM", ++ .date = "20180908", ++ .major = 1, ++ .minor = 0, ++ ++ .gem_create_object = panfrost_gem_create_object, ++ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, ++ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, ++ .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, ++ .gem_prime_mmap = drm_gem_prime_mmap, ++}; ++ ++static int panfrost_probe(struct platform_device *pdev) ++{ ++ struct panfrost_device *pfdev; ++ struct drm_device *ddev; ++ int err; ++ ++ pfdev = devm_kzalloc(&pdev->dev, sizeof(*pfdev), GFP_KERNEL); ++ if (!pfdev) ++ return -ENOMEM; ++ ++ pfdev->pdev = pdev; ++ pfdev->dev = &pdev->dev; ++ ++ platform_set_drvdata(pdev, pfdev); ++ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40)); ++ ++ /* Allocate and initialze the DRM device. */ ++ ddev = drm_dev_alloc(&panfrost_drm_driver, &pdev->dev); ++ if (IS_ERR(ddev)) ++ return PTR_ERR(ddev); ++ ++ ddev->dev_private = pfdev; ++ pfdev->ddev = ddev; ++ ++ spin_lock_init(&pfdev->mm_lock); ++ ++ /* 4G enough for now. can be 48-bit */ ++ drm_mm_init(&pfdev->mm, SZ_32M >> PAGE_SHIFT, SZ_4G); ++ ++ pm_runtime_use_autosuspend(pfdev->dev); ++ pm_runtime_set_autosuspend_delay(pfdev->dev, 50); /* ~3 frames */ ++ pm_runtime_enable(pfdev->dev); ++ ++ err = panfrost_device_init(pfdev); ++ if (err) { ++ dev_err(&pdev->dev, "Fatal error during GPU init\n"); ++ goto err_out0; ++ } ++ ++ err = panfrost_devfreq_init(pfdev); ++ if (err) { ++ dev_err(&pdev->dev, "Fatal error during devfreq init\n"); ++ goto err_out1; ++ } ++ ++ /* ++ * Register the DRM device with the core and the connectors with ++ * sysfs ++ */ ++ err = drm_dev_register(ddev, 0); ++ if (err < 0) ++ goto err_out1; ++ ++ return 0; ++ ++err_out1: ++ panfrost_device_fini(pfdev); ++err_out0: ++ drm_dev_put(ddev); ++ return err; ++} ++ ++static int panfrost_remove(struct platform_device *pdev) ++{ ++ struct panfrost_device *pfdev = platform_get_drvdata(pdev); ++ struct drm_device *ddev = pfdev->ddev; ++ ++ drm_dev_unregister(ddev); ++ pm_runtime_get_sync(pfdev->dev); ++ pm_runtime_put_sync_autosuspend(pfdev->dev); ++ pm_runtime_disable(pfdev->dev); ++ panfrost_device_fini(pfdev); ++ drm_dev_put(ddev); ++ return 0; ++} ++ ++static const struct of_device_id dt_match[] = { ++ { .compatible = "arm,mali-t604" }, ++ { .compatible = "arm,mali-t624" }, ++ { .compatible = "arm,mali-t628" }, ++ { .compatible = "arm,mali-t720" }, ++ { .compatible = "arm,mali-t760" }, ++ { .compatible = "arm,mali-t820" }, ++ { .compatible = "arm,mali-t830" }, ++ { .compatible = "arm,mali-t860" }, ++ { .compatible = "arm,mali-t880" }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, dt_match); ++ ++static const struct dev_pm_ops panfrost_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) ++ SET_RUNTIME_PM_OPS(panfrost_device_suspend, panfrost_device_resume, NULL) ++}; ++ ++static struct platform_driver panfrost_driver = { ++ .probe = panfrost_probe, ++ .remove = panfrost_remove, ++ .driver = { ++ .name = "panfrost", ++ .pm = &panfrost_pm_ops, ++ .of_match_table = dt_match, ++ }, ++}; ++module_platform_driver(panfrost_driver); ++ ++MODULE_AUTHOR("Panfrost Project Developers"); ++MODULE_DESCRIPTION("Panfrost DRM Driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/gpu/drm/panfrost/panfrost_features.h b/drivers/gpu/drm/panfrost/panfrost_features.h +new file mode 100644 +index 0000000000000..5056777c77449 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_features.h +@@ -0,0 +1,309 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* (C) COPYRIGHT 2014-2018 ARM Limited. All rights reserved. */ ++/* Copyright 2019 Linaro, Ltd., Rob Herring */ ++#ifndef __PANFROST_FEATURES_H__ ++#define __PANFROST_FEATURES_H__ ++ ++#include ++ ++#include "panfrost_device.h" ++ ++enum panfrost_hw_feature { ++ HW_FEATURE_JOBCHAIN_DISAMBIGUATION, ++ HW_FEATURE_PWRON_DURING_PWROFF_TRANS, ++ HW_FEATURE_XAFFINITY, ++ HW_FEATURE_OUT_OF_ORDER_EXEC, ++ HW_FEATURE_MRT, ++ HW_FEATURE_BRNDOUT_CC, ++ HW_FEATURE_INTERPIPE_REG_ALIASING, ++ HW_FEATURE_LD_ST_TILEBUFFER, ++ HW_FEATURE_MSAA_16X, ++ HW_FEATURE_32_BIT_UNIFORM_ADDRESS, ++ HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, ++ HW_FEATURE_OPTIMIZED_COVERAGE_MASK, ++ HW_FEATURE_T7XX_PAIRING_RULES, ++ HW_FEATURE_LD_ST_LEA_TEX, ++ HW_FEATURE_LINEAR_FILTER_FLOAT, ++ HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4, ++ HW_FEATURE_IMAGES_IN_FRAGMENT_SHADERS, ++ HW_FEATURE_TEST4_DATUM_MODE, ++ HW_FEATURE_NEXT_INSTRUCTION_TYPE, ++ HW_FEATURE_BRNDOUT_KILL, ++ HW_FEATURE_WARPING, ++ HW_FEATURE_V4, ++ HW_FEATURE_FLUSH_REDUCTION, ++ HW_FEATURE_PROTECTED_MODE, ++ HW_FEATURE_COHERENCY_REG, ++ HW_FEATURE_PROTECTED_DEBUG_MODE, ++ HW_FEATURE_AARCH64_MMU, ++ HW_FEATURE_TLS_HASHING, ++ HW_FEATURE_THREAD_GROUP_SPLIT, ++ HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG, ++}; ++ ++#define hw_features_t600 (\ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_V4)) ++ ++#define hw_features_t620 (\ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_V4)) ++ ++#define hw_features_t720 (\ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_OPTIMIZED_COVERAGE_MASK) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_V4)) ++ ++ ++#define hw_features_t760 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_MSAA_16X) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) ++ ++// T860 ++#define hw_features_t860 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_MSAA_16X) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) ++ ++#define hw_features_t880 hw_features_t860 ++ ++#define hw_features_t830 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) ++ ++#define hw_features_t820 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) ++ ++#define hw_features_g71 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_MSAA_16X) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ ++ BIT_ULL(HW_FEATURE_COHERENCY_REG)) ++ ++#define hw_features_g72 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_MSAA_16X) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ ++ BIT_ULL(HW_FEATURE_COHERENCY_REG)) ++ ++#define hw_features_g51 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_MSAA_16X) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ ++ BIT_ULL(HW_FEATURE_COHERENCY_REG)) ++ ++#define hw_features_g52 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_MSAA_16X) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ ++ BIT_ULL(HW_FEATURE_COHERENCY_REG)) ++ ++#define hw_features_g76 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_MSAA_16X) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ ++ BIT_ULL(HW_FEATURE_COHERENCY_REG) | \ ++ BIT_ULL(HW_FEATURE_AARCH64_MMU) | \ ++ BIT_ULL(HW_FEATURE_TLS_HASHING) | \ ++ BIT_ULL(HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) ++ ++#define hw_features_g31 (\ ++ BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ ++ BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ ++ BIT_ULL(HW_FEATURE_XAFFINITY) | \ ++ BIT_ULL(HW_FEATURE_WARPING) | \ ++ BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ ++ BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ ++ BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ ++ BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ ++ BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ ++ BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ ++ BIT_ULL(HW_FEATURE_MRT) | \ ++ BIT_ULL(HW_FEATURE_MSAA_16X) | \ ++ BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ ++ BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ ++ BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ ++ BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ ++ BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ ++ BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ ++ BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ ++ BIT_ULL(HW_FEATURE_COHERENCY_REG) | \ ++ BIT_ULL(HW_FEATURE_AARCH64_MMU) | \ ++ BIT_ULL(HW_FEATURE_TLS_HASHING) | \ ++ BIT_ULL(HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) ++ ++static inline bool panfrost_has_hw_feature(struct panfrost_device *pfdev, ++ enum panfrost_hw_feature feat) ++{ ++ return test_bit(feat, pfdev->features.hw_features); ++} ++ ++#endif +diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c +new file mode 100644 +index 0000000000000..8a0376283a215 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_gem.c +@@ -0,0 +1,95 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright 2019 Linaro, Ltd, Rob Herring */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include "panfrost_device.h" ++#include "panfrost_gem.h" ++#include "panfrost_mmu.h" ++ ++/* Called DRM core on the last userspace/kernel unreference of the ++ * BO. ++ */ ++void panfrost_gem_free_object(struct drm_gem_object *obj) ++{ ++ struct panfrost_gem_object *bo = to_panfrost_bo(obj); ++ struct panfrost_device *pfdev = obj->dev->dev_private; ++ ++ panfrost_mmu_unmap(bo); ++ ++ spin_lock(&pfdev->mm_lock); ++ drm_mm_remove_node(&bo->node); ++ spin_unlock(&pfdev->mm_lock); ++ ++ drm_gem_shmem_free_object(obj); ++} ++ ++static const struct drm_gem_object_funcs panfrost_gem_funcs = { ++ .free = panfrost_gem_free_object, ++ .print_info = drm_gem_shmem_print_info, ++ .pin = drm_gem_shmem_pin, ++ .unpin = drm_gem_shmem_unpin, ++ .get_sg_table = drm_gem_shmem_get_sg_table, ++ .vmap = drm_gem_shmem_vmap, ++ .vunmap = drm_gem_shmem_vunmap, ++ .vm_ops = &drm_gem_shmem_vm_ops, ++}; ++ ++/** ++ * panfrost_gem_create_object - Implementation of driver->gem_create_object. ++ * @dev: DRM device ++ * @size: Size in bytes of the memory the object will reference ++ * ++ * This lets the GEM helpers allocate object structs for us, and keep ++ * our BO stats correct. ++ */ ++struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size) ++{ ++ int ret; ++ struct panfrost_device *pfdev = dev->dev_private; ++ struct panfrost_gem_object *obj; ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) ++ return NULL; ++ ++ obj->base.base.funcs = &panfrost_gem_funcs; ++ ++ spin_lock(&pfdev->mm_lock); ++ ret = drm_mm_insert_node(&pfdev->mm, &obj->node, ++ roundup(size, PAGE_SIZE) >> PAGE_SHIFT); ++ spin_unlock(&pfdev->mm_lock); ++ if (ret) ++ goto free_obj; ++ ++ return &obj->base.base; ++ ++free_obj: ++ kfree(obj); ++ return ERR_PTR(ret); ++} ++ ++struct drm_gem_object * ++panfrost_gem_prime_import_sg_table(struct drm_device *dev, ++ struct dma_buf_attachment *attach, ++ struct sg_table *sgt) ++{ ++ struct drm_gem_object *obj; ++ struct panfrost_gem_object *pobj; ++ ++ obj = drm_gem_shmem_prime_import_sg_table(dev, attach, sgt); ++ if (IS_ERR(obj)) ++ return ERR_CAST(obj); ++ ++ pobj = to_panfrost_bo(obj); ++ ++ obj->resv = attach->dmabuf->resv; ++ ++ panfrost_mmu_map(pobj); ++ ++ return obj; ++} +diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h +new file mode 100644 +index 0000000000000..045000eb5fcfd +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_gem.h +@@ -0,0 +1,29 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright 2019 Linaro, Ltd, Rob Herring */ ++ ++#ifndef __PANFROST_GEM_H__ ++#define __PANFROST_GEM_H__ ++ ++#include ++#include ++ ++struct panfrost_gem_object { ++ struct drm_gem_shmem_object base; ++ ++ struct drm_mm_node node; ++}; ++ ++static inline ++struct panfrost_gem_object *to_panfrost_bo(struct drm_gem_object *obj) ++{ ++ return container_of(to_drm_gem_shmem_obj(obj), struct panfrost_gem_object, base); ++} ++ ++struct drm_gem_object *panfrost_gem_create_object(struct drm_device *dev, size_t size); ++ ++struct drm_gem_object * ++panfrost_gem_prime_import_sg_table(struct drm_device *dev, ++ struct dma_buf_attachment *attach, ++ struct sg_table *sgt); ++ ++#endif /* __PANFROST_GEM_H__ */ +diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c +new file mode 100644 +index 0000000000000..aceaf6e44a099 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c +@@ -0,0 +1,362 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright 2018 Marty E. Plummer */ ++/* Copyright 2019 Linaro, Ltd., Rob Herring */ ++/* Copyright 2019 Collabora ltd. */ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "panfrost_device.h" ++#include "panfrost_features.h" ++#include "panfrost_issues.h" ++#include "panfrost_gpu.h" ++#include "panfrost_regs.h" ++ ++#define gpu_write(dev, reg, data) writel(data, dev->iomem + reg) ++#define gpu_read(dev, reg) readl(dev->iomem + reg) ++ ++static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data) ++{ ++ struct panfrost_device *pfdev = data; ++ u32 state = gpu_read(pfdev, GPU_INT_STAT); ++ u32 fault_status = gpu_read(pfdev, GPU_FAULT_STATUS); ++ ++ if (!state) ++ return IRQ_NONE; ++ ++ if (state & GPU_IRQ_MASK_ERROR) { ++ u64 address = (u64) gpu_read(pfdev, GPU_FAULT_ADDRESS_HI) << 32; ++ address |= gpu_read(pfdev, GPU_FAULT_ADDRESS_LO); ++ ++ dev_warn(pfdev->dev, "GPU Fault 0x%08x (%s) at 0x%016llx\n", ++ fault_status & 0xFF, panfrost_exception_name(pfdev, fault_status), ++ address); ++ ++ if (state & GPU_IRQ_MULTIPLE_FAULT) ++ dev_warn(pfdev->dev, "There were multiple GPU faults - some have not been reported\n"); ++ ++ gpu_write(pfdev, GPU_INT_MASK, 0); ++ } ++ ++ gpu_write(pfdev, GPU_INT_CLEAR, state); ++ ++ return IRQ_HANDLED; ++} ++ ++int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) ++{ ++ int ret; ++ u32 val; ++ ++ gpu_write(pfdev, GPU_INT_MASK, 0); ++ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); ++ gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); ++ ++ ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, ++ val, val & GPU_IRQ_RESET_COMPLETED, 100, 10000); ++ ++ if (ret) { ++ dev_err(pfdev->dev, "gpu soft reset timed out\n"); ++ return ret; ++ } ++ ++ gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL); ++ gpu_write(pfdev, GPU_INT_MASK, GPU_IRQ_MASK_ALL); ++ ++ return 0; ++} ++ ++static void panfrost_gpu_init_quirks(struct panfrost_device *pfdev) ++{ ++ u32 quirks = 0; ++ ++ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_8443) || ++ panfrost_has_hw_issue(pfdev, HW_ISSUE_11035)) ++ quirks |= SC_LS_PAUSEBUFFER_DISABLE; ++ ++ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_10327)) ++ quirks |= SC_SDC_DISABLE_OQ_DISCARD; ++ ++ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_10797)) ++ quirks |= SC_ENABLE_TEXGRD_FLAGS; ++ ++ if (!panfrost_has_hw_issue(pfdev, GPUCORE_1619)) { ++ if (panfrost_model_cmp(pfdev, 0x750) < 0) /* T60x, T62x, T72x */ ++ quirks |= SC_LS_ATTR_CHECK_DISABLE; ++ else if (panfrost_model_cmp(pfdev, 0x880) <= 0) /* T76x, T8xx */ ++ quirks |= SC_LS_ALLOW_ATTR_TYPES; ++ } ++ ++ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_TLS_HASHING)) ++ quirks |= SC_TLS_HASH_ENABLE; ++ ++ if (quirks) ++ gpu_write(pfdev, GPU_SHADER_CONFIG, quirks); ++ ++ ++ quirks = gpu_read(pfdev, GPU_TILER_CONFIG); ++ ++ /* Set tiler clock gate override if required */ ++ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_T76X_3953)) ++ quirks |= TC_CLOCK_GATE_OVERRIDE; ++ ++ gpu_write(pfdev, GPU_TILER_CONFIG, quirks); ++ ++ ++ quirks = gpu_read(pfdev, GPU_L2_MMU_CONFIG); ++ ++ /* Limit read & write ID width for AXI */ ++ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_3BIT_EXT_RW_L2_MMU_CONFIG)) ++ quirks &= ~(L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS | ++ L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES); ++ else ++ quirks &= ~(L2_MMU_CONFIG_LIMIT_EXTERNAL_READS | ++ L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES); ++ ++ gpu_write(pfdev, GPU_L2_MMU_CONFIG, quirks); ++ ++ quirks = 0; ++ if ((panfrost_model_eq(pfdev, 0x860) || panfrost_model_eq(pfdev, 0x880)) && ++ pfdev->features.revision >= 0x2000) ++ quirks |= JM_MAX_JOB_THROTTLE_LIMIT << JM_JOB_THROTTLE_LIMIT_SHIFT; ++ else if (panfrost_model_eq(pfdev, 0x6000) && ++ pfdev->features.coherency_features == COHERENCY_ACE) ++ quirks |= (COHERENCY_ACE_LITE | COHERENCY_ACE) << ++ JM_FORCE_COHERENCY_FEATURES_SHIFT; ++ ++ if (quirks) ++ gpu_write(pfdev, GPU_JM_CONFIG, quirks); ++} ++ ++#define MAX_HW_REVS 6 ++ ++struct panfrost_model { ++ const char *name; ++ u32 id; ++ u32 id_mask; ++ u64 features; ++ u64 issues; ++ struct { ++ u32 revision; ++ u64 issues; ++ } revs[MAX_HW_REVS]; ++}; ++ ++#define GPU_MODEL(_name, _id, ...) \ ++{\ ++ .name = __stringify(_name), \ ++ .id = _id, \ ++ .features = hw_features_##_name, \ ++ .issues = hw_issues_##_name, \ ++ .revs = { __VA_ARGS__ }, \ ++} ++ ++#define GPU_REV_EXT(name, _rev, _p, _s, stat) \ ++{\ ++ .revision = (_rev) << 12 | (_p) << 4 | (_s), \ ++ .issues = hw_issues_##name##_r##_rev##p##_p##stat, \ ++} ++#define GPU_REV(name, r, p) GPU_REV_EXT(name, r, p, 0, ) ++ ++static const struct panfrost_model gpu_models[] = { ++ /* T60x has an oddball version */ ++ GPU_MODEL(t600, 0x600, ++ GPU_REV_EXT(t600, 0, 0, 1, _15dev0)), ++ GPU_MODEL(t620, 0x620, ++ GPU_REV(t620, 0, 1), GPU_REV(t620, 1, 0)), ++ GPU_MODEL(t720, 0x720), ++ GPU_MODEL(t760, 0x750, ++ GPU_REV(t760, 0, 0), GPU_REV(t760, 0, 1), ++ GPU_REV_EXT(t760, 0, 1, 0, _50rel0), ++ GPU_REV(t760, 0, 2), GPU_REV(t760, 0, 3)), ++ GPU_MODEL(t820, 0x820), ++ GPU_MODEL(t830, 0x830), ++ GPU_MODEL(t860, 0x860), ++ GPU_MODEL(t880, 0x880), ++ ++ GPU_MODEL(g71, 0x6000, ++ GPU_REV_EXT(g71, 0, 0, 1, _05dev0)), ++ GPU_MODEL(g72, 0x6001), ++ GPU_MODEL(g51, 0x7000), ++ GPU_MODEL(g76, 0x7001), ++ GPU_MODEL(g52, 0x7002), ++ GPU_MODEL(g31, 0x7003, ++ GPU_REV(g31, 1, 0)), ++}; ++ ++static void panfrost_gpu_init_features(struct panfrost_device *pfdev) ++{ ++ u32 gpu_id, num_js, major, minor, status, rev; ++ const char *name = "unknown"; ++ u64 hw_feat = 0; ++ u64 hw_issues = hw_issues_all; ++ const struct panfrost_model *model; ++ int i; ++ ++ pfdev->features.l2_features = gpu_read(pfdev, GPU_L2_FEATURES); ++ pfdev->features.core_features = gpu_read(pfdev, GPU_CORE_FEATURES); ++ pfdev->features.tiler_features = gpu_read(pfdev, GPU_TILER_FEATURES); ++ pfdev->features.mem_features = gpu_read(pfdev, GPU_MEM_FEATURES); ++ pfdev->features.mmu_features = gpu_read(pfdev, GPU_MMU_FEATURES); ++ pfdev->features.thread_features = gpu_read(pfdev, GPU_THREAD_FEATURES); ++ pfdev->features.coherency_features = gpu_read(pfdev, GPU_COHERENCY_FEATURES); ++ for (i = 0; i < 4; i++) ++ pfdev->features.texture_features[i] = gpu_read(pfdev, GPU_TEXTURE_FEATURES(i)); ++ ++ pfdev->features.as_present = gpu_read(pfdev, GPU_AS_PRESENT); ++ ++ pfdev->features.js_present = gpu_read(pfdev, GPU_JS_PRESENT); ++ num_js = hweight32(pfdev->features.js_present); ++ for (i = 0; i < num_js; i++) ++ pfdev->features.js_features[i] = gpu_read(pfdev, GPU_JS_FEATURES(i)); ++ ++ pfdev->features.shader_present = gpu_read(pfdev, GPU_SHADER_PRESENT_LO); ++ pfdev->features.shader_present |= (u64)gpu_read(pfdev, GPU_SHADER_PRESENT_HI) << 32; ++ ++ pfdev->features.tiler_present = gpu_read(pfdev, GPU_TILER_PRESENT_LO); ++ pfdev->features.tiler_present |= (u64)gpu_read(pfdev, GPU_TILER_PRESENT_HI) << 32; ++ ++ pfdev->features.l2_present = gpu_read(pfdev, GPU_L2_PRESENT_LO); ++ pfdev->features.l2_present |= (u64)gpu_read(pfdev, GPU_L2_PRESENT_HI) << 32; ++ pfdev->features.nr_core_groups = hweight64(pfdev->features.l2_present); ++ ++ pfdev->features.stack_present = gpu_read(pfdev, GPU_STACK_PRESENT_LO); ++ pfdev->features.stack_present |= (u64)gpu_read(pfdev, GPU_STACK_PRESENT_HI) << 32; ++ ++ gpu_id = gpu_read(pfdev, GPU_ID); ++ pfdev->features.revision = gpu_id & 0xffff; ++ pfdev->features.id = gpu_id >> 16; ++ ++ /* The T60x has an oddball ID value. Fix it up to the standard Midgard ++ * format so we (and userspace) don't have to special case it. ++ */ ++ if (pfdev->features.id == 0x6956) ++ pfdev->features.id = 0x0600; ++ ++ major = (pfdev->features.revision >> 12) & 0xf; ++ minor = (pfdev->features.revision >> 4) & 0xff; ++ status = pfdev->features.revision & 0xf; ++ rev = pfdev->features.revision; ++ ++ gpu_id = pfdev->features.id; ++ ++ for (model = gpu_models; model->name; model++) { ++ int best = -1; ++ ++ if (!panfrost_model_eq(pfdev, model->id)) ++ continue; ++ ++ name = model->name; ++ hw_feat = model->features; ++ hw_issues |= model->issues; ++ for (i = 0; i < MAX_HW_REVS; i++) { ++ if (model->revs[i].revision == rev) { ++ best = i; ++ break; ++ } else if (model->revs[i].revision == (rev & ~0xf)) ++ best = i; ++ } ++ ++ if (best >= 0) ++ hw_issues |= model->revs[best].issues; ++ ++ break; ++ } ++ ++ bitmap_from_u64(pfdev->features.hw_features, hw_feat); ++ bitmap_from_u64(pfdev->features.hw_issues, hw_issues); ++ ++ dev_info(pfdev->dev, "mali-%s id 0x%x major 0x%x minor 0x%x status 0x%x", ++ name, gpu_id, major, minor, status); ++ dev_info(pfdev->dev, "features: %64pb, issues: %64pb", ++ pfdev->features.hw_features, ++ pfdev->features.hw_issues); ++ ++ dev_info(pfdev->dev, "Features: L2:0x%08x Shader:0x%08x Tiler:0x%08x Mem:0x%0x MMU:0x%08x AS:0x%x JS:0x%x", ++ gpu_read(pfdev, GPU_L2_FEATURES), ++ gpu_read(pfdev, GPU_CORE_FEATURES), ++ gpu_read(pfdev, GPU_TILER_FEATURES), ++ gpu_read(pfdev, GPU_MEM_FEATURES), ++ gpu_read(pfdev, GPU_MMU_FEATURES), ++ gpu_read(pfdev, GPU_AS_PRESENT), ++ gpu_read(pfdev, GPU_JS_PRESENT)); ++ ++ dev_info(pfdev->dev, "shader_present=0x%0llx l2_present=0x%0llx", ++ pfdev->features.shader_present, pfdev->features.l2_present); ++} ++ ++void panfrost_gpu_power_on(struct panfrost_device *pfdev) ++{ ++ int ret; ++ u32 val; ++ ++ /* Just turn on everything for now */ ++ gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present); ++ ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, ++ val, val == pfdev->features.l2_present, 100, 1000); ++ ++ gpu_write(pfdev, STACK_PWRON_LO, pfdev->features.stack_present); ++ ret |= readl_relaxed_poll_timeout(pfdev->iomem + STACK_READY_LO, ++ val, val == pfdev->features.stack_present, 100, 1000); ++ ++ gpu_write(pfdev, SHADER_PWRON_LO, pfdev->features.shader_present); ++ ret |= readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, ++ val, val == pfdev->features.shader_present, 100, 1000); ++ ++ gpu_write(pfdev, TILER_PWRON_LO, pfdev->features.tiler_present); ++ ret |= readl_relaxed_poll_timeout(pfdev->iomem + TILER_READY_LO, ++ val, val == pfdev->features.tiler_present, 100, 1000); ++ ++ if (ret) ++ dev_err(pfdev->dev, "error powering up gpu"); ++} ++ ++void panfrost_gpu_power_off(struct panfrost_device *pfdev) ++{ ++ gpu_write(pfdev, TILER_PWROFF_LO, 0); ++ gpu_write(pfdev, SHADER_PWROFF_LO, 0); ++ gpu_write(pfdev, STACK_PWROFF_LO, 0); ++ gpu_write(pfdev, L2_PWROFF_LO, 0); ++} ++ ++int panfrost_gpu_init(struct panfrost_device *pfdev) ++{ ++ int err, irq; ++ ++ err = panfrost_gpu_soft_reset(pfdev); ++ if (err) ++ return err; ++ ++ panfrost_gpu_init_features(pfdev); ++ ++ irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); ++ if (irq <= 0) ++ return -ENODEV; ++ ++ err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler, ++ IRQF_SHARED, "gpu", pfdev); ++ if (err) { ++ dev_err(pfdev->dev, "failed to request gpu irq"); ++ return err; ++ } ++ ++ panfrost_gpu_init_quirks(pfdev); ++ panfrost_gpu_power_on(pfdev); ++ ++ return 0; ++} ++ ++void panfrost_gpu_fini(struct panfrost_device *pfdev) ++{ ++ panfrost_gpu_power_off(pfdev); ++} ++ ++u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev) ++{ ++ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) ++ return gpu_read(pfdev, GPU_LATEST_FLUSH_ID); ++ return 0; ++} +diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h +new file mode 100644 +index 0000000000000..4112412087b27 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright 2018 Marty E. Plummer */ ++/* Copyright 2019 Collabora ltd. */ ++ ++#ifndef __PANFROST_GPU_H__ ++#define __PANFROST_GPU_H__ ++ ++struct panfrost_device; ++ ++int panfrost_gpu_init(struct panfrost_device *pfdev); ++void panfrost_gpu_fini(struct panfrost_device *pfdev); ++ ++u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev); ++ ++int panfrost_gpu_soft_reset(struct panfrost_device *pfdev); ++void panfrost_gpu_power_on(struct panfrost_device *pfdev); ++void panfrost_gpu_power_off(struct panfrost_device *pfdev); ++ ++#endif +diff --git a/drivers/gpu/drm/panfrost/panfrost_issues.h b/drivers/gpu/drm/panfrost/panfrost_issues.h +new file mode 100644 +index 0000000000000..cec6dcdadb5c3 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_issues.h +@@ -0,0 +1,176 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* (C) COPYRIGHT 2014-2018 ARM Limited. All rights reserved. */ ++/* Copyright 2019 Linaro, Ltd., Rob Herring */ ++#ifndef __PANFROST_ISSUES_H__ ++#define __PANFROST_ISSUES_H__ ++ ++#include ++ ++#include "panfrost_device.h" ++ ++/* ++ * This is not a complete list of issues, but only the ones the driver needs ++ * to care about. ++ */ ++enum panfrost_hw_issue { ++ HW_ISSUE_6367, ++ HW_ISSUE_6787, ++ HW_ISSUE_8186, ++ HW_ISSUE_8245, ++ HW_ISSUE_8316, ++ HW_ISSUE_8394, ++ HW_ISSUE_8401, ++ HW_ISSUE_8408, ++ HW_ISSUE_8443, ++ HW_ISSUE_8987, ++ HW_ISSUE_9435, ++ HW_ISSUE_9510, ++ HW_ISSUE_9630, ++ HW_ISSUE_10327, ++ HW_ISSUE_10649, ++ HW_ISSUE_10676, ++ HW_ISSUE_10797, ++ HW_ISSUE_10817, ++ HW_ISSUE_10883, ++ HW_ISSUE_10959, ++ HW_ISSUE_10969, ++ HW_ISSUE_11020, ++ HW_ISSUE_11024, ++ HW_ISSUE_11035, ++ HW_ISSUE_11056, ++ HW_ISSUE_T76X_3542, ++ HW_ISSUE_T76X_3953, ++ HW_ISSUE_TMIX_8463, ++ GPUCORE_1619, ++ HW_ISSUE_TMIX_8438, ++ HW_ISSUE_TGOX_R1_1234, ++ HW_ISSUE_END ++}; ++ ++#define hw_issues_all (\ ++ BIT_ULL(HW_ISSUE_9435)) ++ ++#define hw_issues_t600 (\ ++ BIT_ULL(HW_ISSUE_6367) | \ ++ BIT_ULL(HW_ISSUE_6787) | \ ++ BIT_ULL(HW_ISSUE_8408) | \ ++ BIT_ULL(HW_ISSUE_9510) | \ ++ BIT_ULL(HW_ISSUE_10649) | \ ++ BIT_ULL(HW_ISSUE_10676) | \ ++ BIT_ULL(HW_ISSUE_10883) | \ ++ BIT_ULL(HW_ISSUE_11020) | \ ++ BIT_ULL(HW_ISSUE_11035) | \ ++ BIT_ULL(HW_ISSUE_11056) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_t600_r0p0_15dev0 (\ ++ BIT_ULL(HW_ISSUE_8186) | \ ++ BIT_ULL(HW_ISSUE_8245) | \ ++ BIT_ULL(HW_ISSUE_8316) | \ ++ BIT_ULL(HW_ISSUE_8394) | \ ++ BIT_ULL(HW_ISSUE_8401) | \ ++ BIT_ULL(HW_ISSUE_8443) | \ ++ BIT_ULL(HW_ISSUE_8987) | \ ++ BIT_ULL(HW_ISSUE_9630) | \ ++ BIT_ULL(HW_ISSUE_10969) | \ ++ BIT_ULL(GPUCORE_1619)) ++ ++#define hw_issues_t620 (\ ++ BIT_ULL(HW_ISSUE_10649) | \ ++ BIT_ULL(HW_ISSUE_10883) | \ ++ BIT_ULL(HW_ISSUE_10959) | \ ++ BIT_ULL(HW_ISSUE_11056) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_t620_r0p1 (\ ++ BIT_ULL(HW_ISSUE_10327) | \ ++ BIT_ULL(HW_ISSUE_10676) | \ ++ BIT_ULL(HW_ISSUE_10817) | \ ++ BIT_ULL(HW_ISSUE_11020) | \ ++ BIT_ULL(HW_ISSUE_11024) | \ ++ BIT_ULL(HW_ISSUE_11035)) ++ ++#define hw_issues_t620_r1p0 (\ ++ BIT_ULL(HW_ISSUE_11020) | \ ++ BIT_ULL(HW_ISSUE_11024)) ++ ++#define hw_issues_t720 (\ ++ BIT_ULL(HW_ISSUE_10649) | \ ++ BIT_ULL(HW_ISSUE_10797) | \ ++ BIT_ULL(HW_ISSUE_10883) | \ ++ BIT_ULL(HW_ISSUE_11056) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_t760 (\ ++ BIT_ULL(HW_ISSUE_10883) | \ ++ BIT_ULL(HW_ISSUE_T76X_3953) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_t760_r0p0 (\ ++ BIT_ULL(HW_ISSUE_11020) | \ ++ BIT_ULL(HW_ISSUE_11024) | \ ++ BIT_ULL(HW_ISSUE_T76X_3542)) ++ ++#define hw_issues_t760_r0p1 (\ ++ BIT_ULL(HW_ISSUE_11020) | \ ++ BIT_ULL(HW_ISSUE_11024) | \ ++ BIT_ULL(HW_ISSUE_T76X_3542)) ++ ++#define hw_issues_t760_r0p1_50rel0 (\ ++ BIT_ULL(HW_ISSUE_T76X_3542)) ++ ++#define hw_issues_t760_r0p2 (\ ++ BIT_ULL(HW_ISSUE_11020) | \ ++ BIT_ULL(HW_ISSUE_11024) | \ ++ BIT_ULL(HW_ISSUE_T76X_3542)) ++ ++#define hw_issues_t760_r0p3 (\ ++ BIT_ULL(HW_ISSUE_T76X_3542)) ++ ++#define hw_issues_t820 (\ ++ BIT_ULL(HW_ISSUE_10883) | \ ++ BIT_ULL(HW_ISSUE_T76X_3953) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_t830 (\ ++ BIT_ULL(HW_ISSUE_10883) | \ ++ BIT_ULL(HW_ISSUE_T76X_3953) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_t860 (\ ++ BIT_ULL(HW_ISSUE_10883) | \ ++ BIT_ULL(HW_ISSUE_T76X_3953) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_t880 (\ ++ BIT_ULL(HW_ISSUE_10883) | \ ++ BIT_ULL(HW_ISSUE_T76X_3953) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_g31 0 ++ ++#define hw_issues_g31_r1p0 (\ ++ BIT_ULL(HW_ISSUE_TGOX_R1_1234)) ++ ++#define hw_issues_g51 0 ++ ++#define hw_issues_g52 0 ++ ++#define hw_issues_g71 (\ ++ BIT_ULL(HW_ISSUE_TMIX_8463) | \ ++ BIT_ULL(HW_ISSUE_TMIX_8438)) ++ ++#define hw_issues_g71_r0p0_05dev0 (\ ++ BIT_ULL(HW_ISSUE_T76X_3953)) ++ ++#define hw_issues_g72 0 ++ ++#define hw_issues_g76 0 ++ ++static inline bool panfrost_has_hw_issue(struct panfrost_device *pfdev, ++ enum panfrost_hw_issue issue) ++{ ++ return test_bit(issue, pfdev->features.hw_issues); ++} ++ ++#endif /* __PANFROST_ISSUES_H__ */ +diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c +new file mode 100644 +index 0000000000000..0a7ed04f7d52b +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_job.c +@@ -0,0 +1,560 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright 2019 Linaro, Ltd, Rob Herring */ ++/* Copyright 2019 Collabora ltd. */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "panfrost_device.h" ++#include "panfrost_devfreq.h" ++#include "panfrost_job.h" ++#include "panfrost_features.h" ++#include "panfrost_issues.h" ++#include "panfrost_gem.h" ++#include "panfrost_regs.h" ++#include "panfrost_gpu.h" ++#include "panfrost_mmu.h" ++ ++#define job_write(dev, reg, data) writel(data, dev->iomem + (reg)) ++#define job_read(dev, reg) readl(dev->iomem + (reg)) ++ ++struct panfrost_queue_state { ++ struct drm_gpu_scheduler sched; ++ ++ u64 fence_context; ++ u64 emit_seqno; ++}; ++ ++struct panfrost_job_slot { ++ struct panfrost_queue_state queue[NUM_JOB_SLOTS]; ++ spinlock_t job_lock; ++}; ++ ++static struct panfrost_job * ++to_panfrost_job(struct drm_sched_job *sched_job) ++{ ++ return container_of(sched_job, struct panfrost_job, base); ++} ++ ++struct panfrost_fence { ++ struct dma_fence base; ++ struct drm_device *dev; ++ /* panfrost seqno for signaled() test */ ++ u64 seqno; ++ int queue; ++}; ++ ++static inline struct panfrost_fence * ++to_panfrost_fence(struct dma_fence *fence) ++{ ++ return (struct panfrost_fence *)fence; ++} ++ ++static const char *panfrost_fence_get_driver_name(struct dma_fence *fence) ++{ ++ return "panfrost"; ++} ++ ++static const char *panfrost_fence_get_timeline_name(struct dma_fence *fence) ++{ ++ struct panfrost_fence *f = to_panfrost_fence(fence); ++ ++ switch (f->queue) { ++ case 0: ++ return "panfrost-js-0"; ++ case 1: ++ return "panfrost-js-1"; ++ case 2: ++ return "panfrost-js-2"; ++ default: ++ return NULL; ++ } ++} ++ ++static const struct dma_fence_ops panfrost_fence_ops = { ++ .get_driver_name = panfrost_fence_get_driver_name, ++ .get_timeline_name = panfrost_fence_get_timeline_name, ++}; ++ ++static struct dma_fence *panfrost_fence_create(struct panfrost_device *pfdev, int js_num) ++{ ++ struct panfrost_fence *fence; ++ struct panfrost_job_slot *js = pfdev->js; ++ ++ fence = kzalloc(sizeof(*fence), GFP_KERNEL); ++ if (!fence) ++ return ERR_PTR(-ENOMEM); ++ ++ fence->dev = pfdev->ddev; ++ fence->queue = js_num; ++ fence->seqno = ++js->queue[js_num].emit_seqno; ++ dma_fence_init(&fence->base, &panfrost_fence_ops, &js->job_lock, ++ js->queue[js_num].fence_context, fence->seqno); ++ ++ return &fence->base; ++} ++ ++static int panfrost_job_get_slot(struct panfrost_job *job) ++{ ++ /* JS0: fragment jobs. ++ * JS1: vertex/tiler jobs ++ * JS2: compute jobs ++ */ ++ if (job->requirements & PANFROST_JD_REQ_FS) ++ return 0; ++ ++/* Not exposed to userspace yet */ ++#if 0 ++ if (job->requirements & PANFROST_JD_REQ_ONLY_COMPUTE) { ++ if ((job->requirements & PANFROST_JD_REQ_CORE_GRP_MASK) && ++ (job->pfdev->features.nr_core_groups == 2)) ++ return 2; ++ if (panfrost_has_hw_issue(job->pfdev, HW_ISSUE_8987)) ++ return 2; ++ } ++#endif ++ return 1; ++} ++ ++static void panfrost_job_write_affinity(struct panfrost_device *pfdev, ++ u32 requirements, ++ int js) ++{ ++ u64 affinity; ++ ++ /* ++ * Use all cores for now. ++ * Eventually we may need to support tiler only jobs and h/w with ++ * multiple (2) coherent core groups ++ */ ++ affinity = pfdev->features.shader_present; ++ ++ job_write(pfdev, JS_AFFINITY_NEXT_LO(js), affinity & 0xFFFFFFFF); ++ job_write(pfdev, JS_AFFINITY_NEXT_HI(js), affinity >> 32); ++} ++ ++static void panfrost_job_hw_submit(struct panfrost_job *job, int js) ++{ ++ struct panfrost_device *pfdev = job->pfdev; ++ unsigned long flags; ++ u32 cfg; ++ u64 jc_head = job->jc; ++ int ret; ++ ++ ret = pm_runtime_get_sync(pfdev->dev); ++ if (ret < 0) ++ return; ++ ++ if (WARN_ON(job_read(pfdev, JS_COMMAND_NEXT(js)))) ++ goto end; ++ ++ panfrost_devfreq_record_transition(pfdev, js); ++ spin_lock_irqsave(&pfdev->hwaccess_lock, flags); ++ ++ job_write(pfdev, JS_HEAD_NEXT_LO(js), jc_head & 0xFFFFFFFF); ++ job_write(pfdev, JS_HEAD_NEXT_HI(js), jc_head >> 32); ++ ++ panfrost_job_write_affinity(pfdev, job->requirements, js); ++ ++ /* start MMU, medium priority, cache clean/flush on end, clean/flush on ++ * start */ ++ /* TODO: different address spaces */ ++ cfg = JS_CONFIG_THREAD_PRI(8) | ++ JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE | ++ JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE; ++ ++ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) ++ cfg |= JS_CONFIG_ENABLE_FLUSH_REDUCTION; ++ ++ if (panfrost_has_hw_issue(pfdev, HW_ISSUE_10649)) ++ cfg |= JS_CONFIG_START_MMU; ++ ++ job_write(pfdev, JS_CONFIG_NEXT(js), cfg); ++ ++ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_FLUSH_REDUCTION)) ++ job_write(pfdev, JS_FLUSH_ID_NEXT(js), job->flush_id); ++ ++ /* GO ! */ ++ dev_dbg(pfdev->dev, "JS: Submitting atom %p to js[%d] with head=0x%llx", ++ job, js, jc_head); ++ ++ job_write(pfdev, JS_COMMAND_NEXT(js), JS_COMMAND_START); ++ ++ spin_unlock_irqrestore(&pfdev->hwaccess_lock, flags); ++ ++end: ++ pm_runtime_mark_last_busy(pfdev->dev); ++ pm_runtime_put_autosuspend(pfdev->dev); ++} ++ ++static void panfrost_acquire_object_fences(struct drm_gem_object **bos, ++ int bo_count, ++ struct dma_fence **implicit_fences) ++{ ++ int i; ++ ++ for (i = 0; i < bo_count; i++) ++ implicit_fences[i] = reservation_object_get_excl_rcu(bos[i]->resv); ++} ++ ++static void panfrost_attach_object_fences(struct drm_gem_object **bos, ++ int bo_count, ++ struct dma_fence *fence) ++{ ++ int i; ++ ++ for (i = 0; i < bo_count; i++) ++ reservation_object_add_excl_fence(bos[i]->resv, fence); ++} ++ ++int panfrost_job_push(struct panfrost_job *job) ++{ ++ struct panfrost_device *pfdev = job->pfdev; ++ int slot = panfrost_job_get_slot(job); ++ struct drm_sched_entity *entity = &job->file_priv->sched_entity[slot]; ++ struct ww_acquire_ctx acquire_ctx; ++ int ret = 0; ++ ++ mutex_lock(&pfdev->sched_lock); ++ ++ ret = drm_gem_lock_reservations(job->bos, job->bo_count, ++ &acquire_ctx); ++ if (ret) { ++ mutex_unlock(&pfdev->sched_lock); ++ return ret; ++ } ++ ++ ret = drm_sched_job_init(&job->base, entity, NULL); ++ if (ret) { ++ mutex_unlock(&pfdev->sched_lock); ++ goto unlock; ++ } ++ ++ job->render_done_fence = dma_fence_get(&job->base.s_fence->finished); ++ ++ kref_get(&job->refcount); /* put by scheduler job completion */ ++ ++ panfrost_acquire_object_fences(job->bos, job->bo_count, ++ job->implicit_fences); ++ ++ drm_sched_entity_push_job(&job->base, entity); ++ ++ mutex_unlock(&pfdev->sched_lock); ++ ++ panfrost_attach_object_fences(job->bos, job->bo_count, ++ job->render_done_fence); ++ ++unlock: ++ drm_gem_unlock_reservations(job->bos, job->bo_count, &acquire_ctx); ++ ++ return ret; ++} ++ ++static void panfrost_job_cleanup(struct kref *ref) ++{ ++ struct panfrost_job *job = container_of(ref, struct panfrost_job, ++ refcount); ++ unsigned int i; ++ ++ if (job->in_fences) { ++ for (i = 0; i < job->in_fence_count; i++) ++ dma_fence_put(job->in_fences[i]); ++ kvfree(job->in_fences); ++ } ++ if (job->implicit_fences) { ++ for (i = 0; i < job->bo_count; i++) ++ dma_fence_put(job->implicit_fences[i]); ++ kvfree(job->implicit_fences); ++ } ++ dma_fence_put(job->done_fence); ++ dma_fence_put(job->render_done_fence); ++ ++ if (job->bos) { ++ for (i = 0; i < job->bo_count; i++) ++ drm_gem_object_put_unlocked(job->bos[i]); ++ kvfree(job->bos); ++ } ++ ++ kfree(job); ++} ++ ++void panfrost_job_put(struct panfrost_job *job) ++{ ++ kref_put(&job->refcount, panfrost_job_cleanup); ++} ++ ++static void panfrost_job_free(struct drm_sched_job *sched_job) ++{ ++ struct panfrost_job *job = to_panfrost_job(sched_job); ++ ++ drm_sched_job_cleanup(sched_job); ++ ++ panfrost_job_put(job); ++} ++ ++static struct dma_fence *panfrost_job_dependency(struct drm_sched_job *sched_job, ++ struct drm_sched_entity *s_entity) ++{ ++ struct panfrost_job *job = to_panfrost_job(sched_job); ++ struct dma_fence *fence; ++ unsigned int i; ++ ++ /* Explicit fences */ ++ for (i = 0; i < job->in_fence_count; i++) { ++ if (job->in_fences[i]) { ++ fence = job->in_fences[i]; ++ job->in_fences[i] = NULL; ++ return fence; ++ } ++ } ++ ++ /* Implicit fences, max. one per BO */ ++ for (i = 0; i < job->bo_count; i++) { ++ if (job->implicit_fences[i]) { ++ fence = job->implicit_fences[i]; ++ job->implicit_fences[i] = NULL; ++ return fence; ++ } ++ } ++ ++ return NULL; ++} ++ ++static struct dma_fence *panfrost_job_run(struct drm_sched_job *sched_job) ++{ ++ struct panfrost_job *job = to_panfrost_job(sched_job); ++ struct panfrost_device *pfdev = job->pfdev; ++ int slot = panfrost_job_get_slot(job); ++ struct dma_fence *fence = NULL; ++ ++ if (unlikely(job->base.s_fence->finished.error)) ++ return NULL; ++ ++ pfdev->jobs[slot] = job; ++ ++ fence = panfrost_fence_create(pfdev, slot); ++ if (IS_ERR(fence)) ++ return NULL; ++ ++ if (job->done_fence) ++ dma_fence_put(job->done_fence); ++ job->done_fence = dma_fence_get(fence); ++ ++ panfrost_job_hw_submit(job, slot); ++ ++ return fence; ++} ++ ++void panfrost_job_enable_interrupts(struct panfrost_device *pfdev) ++{ ++ int j; ++ u32 irq_mask = 0; ++ ++ for (j = 0; j < NUM_JOB_SLOTS; j++) { ++ irq_mask |= MK_JS_MASK(j); ++ } ++ ++ job_write(pfdev, JOB_INT_CLEAR, irq_mask); ++ job_write(pfdev, JOB_INT_MASK, irq_mask); ++} ++ ++static void panfrost_job_timedout(struct drm_sched_job *sched_job) ++{ ++ struct panfrost_job *job = to_panfrost_job(sched_job); ++ struct panfrost_device *pfdev = job->pfdev; ++ int js = panfrost_job_get_slot(job); ++ int i; ++ ++ /* ++ * If the GPU managed to complete this jobs fence, the timeout is ++ * spurious. Bail out. ++ */ ++ if (dma_fence_is_signaled(job->done_fence)) ++ return; ++ ++ dev_err(pfdev->dev, "gpu sched timeout, js=%d, status=0x%x, head=0x%x, tail=0x%x, sched_job=%p", ++ js, ++ job_read(pfdev, JS_STATUS(js)), ++ job_read(pfdev, JS_HEAD_LO(js)), ++ job_read(pfdev, JS_TAIL_LO(js)), ++ sched_job); ++ ++ for (i = 0; i < NUM_JOB_SLOTS; i++) ++ drm_sched_stop(&pfdev->js->queue[i].sched); ++ ++ if (sched_job) ++ drm_sched_increase_karma(sched_job); ++ ++ /* panfrost_core_dump(pfdev); */ ++ ++ panfrost_devfreq_record_transition(pfdev, js); ++ panfrost_gpu_soft_reset(pfdev); ++ ++ /* TODO: Re-enable all other address spaces */ ++ panfrost_mmu_enable(pfdev, 0); ++ panfrost_gpu_power_on(pfdev); ++ panfrost_job_enable_interrupts(pfdev); ++ ++ for (i = 0; i < NUM_JOB_SLOTS; i++) ++ drm_sched_resubmit_jobs(&pfdev->js->queue[i].sched); ++ ++ /* restart scheduler after GPU is usable again */ ++ for (i = 0; i < NUM_JOB_SLOTS; i++) ++ drm_sched_start(&pfdev->js->queue[i].sched, true); ++} ++ ++static const struct drm_sched_backend_ops panfrost_sched_ops = { ++ .dependency = panfrost_job_dependency, ++ .run_job = panfrost_job_run, ++ .timedout_job = panfrost_job_timedout, ++ .free_job = panfrost_job_free ++}; ++ ++static irqreturn_t panfrost_job_irq_handler(int irq, void *data) ++{ ++ struct panfrost_device *pfdev = data; ++ u32 status = job_read(pfdev, JOB_INT_STAT); ++ int j; ++ ++ dev_dbg(pfdev->dev, "jobslot irq status=%x\n", status); ++ ++ if (!status) ++ return IRQ_NONE; ++ ++ pm_runtime_mark_last_busy(pfdev->dev); ++ ++ for (j = 0; status; j++) { ++ u32 mask = MK_JS_MASK(j); ++ ++ if (!(status & mask)) ++ continue; ++ ++ job_write(pfdev, JOB_INT_CLEAR, mask); ++ ++ if (status & JOB_INT_MASK_ERR(j)) { ++ job_write(pfdev, JS_COMMAND_NEXT(j), JS_COMMAND_NOP); ++ ++ dev_err(pfdev->dev, "js fault, js=%d, status=%s, head=0x%x, tail=0x%x", ++ j, ++ panfrost_exception_name(pfdev, job_read(pfdev, JS_STATUS(j))), ++ job_read(pfdev, JS_HEAD_LO(j)), ++ job_read(pfdev, JS_TAIL_LO(j))); ++ ++ drm_sched_fault(&pfdev->js->queue[j].sched); ++ } ++ ++ if (status & JOB_INT_MASK_DONE(j)) { ++ panfrost_devfreq_record_transition(pfdev, j); ++ dma_fence_signal(pfdev->jobs[j]->done_fence); ++ } ++ ++ status &= ~mask; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++int panfrost_job_init(struct panfrost_device *pfdev) ++{ ++ struct panfrost_job_slot *js; ++ int ret, j, irq; ++ ++ pfdev->js = js = devm_kzalloc(pfdev->dev, sizeof(*js), GFP_KERNEL); ++ if (!js) ++ return -ENOMEM; ++ ++ spin_lock_init(&js->job_lock); ++ ++ irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "job"); ++ if (irq <= 0) ++ return -ENODEV; ++ ++ ret = devm_request_irq(pfdev->dev, irq, panfrost_job_irq_handler, ++ IRQF_SHARED, "job", pfdev); ++ if (ret) { ++ dev_err(pfdev->dev, "failed to request job irq"); ++ return ret; ++ } ++ ++ for (j = 0; j < NUM_JOB_SLOTS; j++) { ++ js->queue[j].fence_context = dma_fence_context_alloc(1); ++ ++ ret = drm_sched_init(&js->queue[j].sched, ++ &panfrost_sched_ops, ++ 1, 0, msecs_to_jiffies(500), ++ "pan_js"); ++ if (ret) { ++ dev_err(pfdev->dev, "Failed to create scheduler: %d.", ret); ++ goto err_sched; ++ } ++ } ++ ++ panfrost_job_enable_interrupts(pfdev); ++ ++ return 0; ++ ++err_sched: ++ for (j--; j >= 0; j--) ++ drm_sched_fini(&js->queue[j].sched); ++ ++ return ret; ++} ++ ++void panfrost_job_fini(struct panfrost_device *pfdev) ++{ ++ struct panfrost_job_slot *js = pfdev->js; ++ int j; ++ ++ job_write(pfdev, JOB_INT_MASK, 0); ++ ++ for (j = 0; j < NUM_JOB_SLOTS; j++) ++ drm_sched_fini(&js->queue[j].sched); ++ ++} ++ ++int panfrost_job_open(struct panfrost_file_priv *panfrost_priv) ++{ ++ struct panfrost_device *pfdev = panfrost_priv->pfdev; ++ struct panfrost_job_slot *js = pfdev->js; ++ struct drm_sched_rq *rq; ++ int ret, i; ++ ++ for (i = 0; i < NUM_JOB_SLOTS; i++) { ++ rq = &js->queue[i].sched.sched_rq[DRM_SCHED_PRIORITY_NORMAL]; ++ ret = drm_sched_entity_init(&panfrost_priv->sched_entity[i], &rq, 1, NULL); ++ if (WARN_ON(ret)) ++ return ret; ++ } ++ return 0; ++} ++ ++void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_JOB_SLOTS; i++) ++ drm_sched_entity_destroy(&panfrost_priv->sched_entity[i]); ++} ++ ++int panfrost_job_is_idle(struct panfrost_device *pfdev) ++{ ++ struct panfrost_job_slot *js = pfdev->js; ++ int i; ++ ++ for (i = 0; i < NUM_JOB_SLOTS; i++) { ++ /* If there are any jobs in the HW queue, we're not idle */ ++ if (atomic_read(&js->queue[i].sched.hw_rq_count)) ++ return false; ++ ++ /* Check whether the hardware is idle */ ++ if (pfdev->devfreq.slot[i].busy) ++ return false; ++ } ++ ++ return true; ++} +diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h +new file mode 100644 +index 0000000000000..62454128a792e +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_job.h +@@ -0,0 +1,51 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright 2019 Collabora ltd. */ ++ ++#ifndef __PANFROST_JOB_H__ ++#define __PANFROST_JOB_H__ ++ ++#include ++#include ++ ++struct panfrost_device; ++struct panfrost_gem_object; ++struct panfrost_file_priv; ++ ++struct panfrost_job { ++ struct drm_sched_job base; ++ ++ struct kref refcount; ++ ++ struct panfrost_device *pfdev; ++ struct panfrost_file_priv *file_priv; ++ ++ /* Optional fences userspace can pass in for the job to depend on. */ ++ struct dma_fence **in_fences; ++ u32 in_fence_count; ++ ++ /* Fence to be signaled by IRQ handler when the job is complete. */ ++ struct dma_fence *done_fence; ++ ++ __u64 jc; ++ __u32 requirements; ++ __u32 flush_id; ++ ++ /* Exclusive fences we have taken from the BOs to wait for */ ++ struct dma_fence **implicit_fences; ++ struct drm_gem_object **bos; ++ u32 bo_count; ++ ++ /* Fence to be signaled by drm-sched once its done with the job */ ++ struct dma_fence *render_done_fence; ++}; ++ ++int panfrost_job_init(struct panfrost_device *pfdev); ++void panfrost_job_fini(struct panfrost_device *pfdev); ++int panfrost_job_open(struct panfrost_file_priv *panfrost_priv); ++void panfrost_job_close(struct panfrost_file_priv *panfrost_priv); ++int panfrost_job_push(struct panfrost_job *job); ++void panfrost_job_put(struct panfrost_job *job); ++void panfrost_job_enable_interrupts(struct panfrost_device *pfdev); ++int panfrost_job_is_idle(struct panfrost_device *pfdev); ++ ++#endif +diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c +new file mode 100644 +index 0000000000000..9692c18df785e +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c +@@ -0,0 +1,369 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* Copyright 2019 Linaro, Ltd, Rob Herring */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "panfrost_device.h" ++#include "panfrost_mmu.h" ++#include "panfrost_gem.h" ++#include "panfrost_features.h" ++#include "panfrost_regs.h" ++ ++#define mmu_write(dev, reg, data) writel(data, dev->iomem + reg) ++#define mmu_read(dev, reg) readl(dev->iomem + reg) ++ ++struct panfrost_mmu { ++ struct io_pgtable_cfg pgtbl_cfg; ++ struct io_pgtable_ops *pgtbl_ops; ++ struct mutex lock; ++}; ++ ++static int wait_ready(struct panfrost_device *pfdev, u32 as_nr) ++{ ++ int ret; ++ u32 val; ++ ++ /* Wait for the MMU status to indicate there is no active command, in ++ * case one is pending. */ ++ ret = readl_relaxed_poll_timeout_atomic(pfdev->iomem + AS_STATUS(as_nr), ++ val, !(val & AS_STATUS_AS_ACTIVE), 10, 1000); ++ ++ if (ret) ++ dev_err(pfdev->dev, "AS_ACTIVE bit stuck\n"); ++ ++ return ret; ++} ++ ++static int write_cmd(struct panfrost_device *pfdev, u32 as_nr, u32 cmd) ++{ ++ int status; ++ ++ /* write AS_COMMAND when MMU is ready to accept another command */ ++ status = wait_ready(pfdev, as_nr); ++ if (!status) ++ mmu_write(pfdev, AS_COMMAND(as_nr), cmd); ++ ++ return status; ++} ++ ++static void lock_region(struct panfrost_device *pfdev, u32 as_nr, ++ u64 iova, size_t size) ++{ ++ u8 region_width; ++ u64 region = iova & PAGE_MASK; ++ /* ++ * fls returns: ++ * 1 .. 32 ++ * ++ * 10 + fls(num_pages) ++ * results in the range (11 .. 42) ++ */ ++ ++ size = round_up(size, PAGE_SIZE); ++ ++ region_width = 10 + fls(size >> PAGE_SHIFT); ++ if ((size >> PAGE_SHIFT) != (1ul << (region_width - 11))) { ++ /* not pow2, so must go up to the next pow2 */ ++ region_width += 1; ++ } ++ region |= region_width; ++ ++ /* Lock the region that needs to be updated */ ++ mmu_write(pfdev, AS_LOCKADDR_LO(as_nr), region & 0xFFFFFFFFUL); ++ mmu_write(pfdev, AS_LOCKADDR_HI(as_nr), (region >> 32) & 0xFFFFFFFFUL); ++ write_cmd(pfdev, as_nr, AS_COMMAND_LOCK); ++} ++ ++ ++static int mmu_hw_do_operation(struct panfrost_device *pfdev, u32 as_nr, ++ u64 iova, size_t size, u32 op) ++{ ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&pfdev->hwaccess_lock, flags); ++ ++ if (op != AS_COMMAND_UNLOCK) ++ lock_region(pfdev, as_nr, iova, size); ++ ++ /* Run the MMU operation */ ++ write_cmd(pfdev, as_nr, op); ++ ++ /* Wait for the flush to complete */ ++ ret = wait_ready(pfdev, as_nr); ++ ++ spin_unlock_irqrestore(&pfdev->hwaccess_lock, flags); ++ ++ return ret; ++} ++ ++void panfrost_mmu_enable(struct panfrost_device *pfdev, u32 as_nr) ++{ ++ struct io_pgtable_cfg *cfg = &pfdev->mmu->pgtbl_cfg; ++ u64 transtab = cfg->arm_mali_lpae_cfg.transtab; ++ u64 memattr = cfg->arm_mali_lpae_cfg.memattr; ++ ++ mmu_write(pfdev, MMU_INT_CLEAR, ~0); ++ mmu_write(pfdev, MMU_INT_MASK, ~0); ++ ++ mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), transtab & 0xffffffffUL); ++ mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), transtab >> 32); ++ ++ /* Need to revisit mem attrs. ++ * NC is the default, Mali driver is inner WT. ++ */ ++ mmu_write(pfdev, AS_MEMATTR_LO(as_nr), memattr & 0xffffffffUL); ++ mmu_write(pfdev, AS_MEMATTR_HI(as_nr), memattr >> 32); ++ ++ write_cmd(pfdev, as_nr, AS_COMMAND_UPDATE); ++} ++ ++static void mmu_disable(struct panfrost_device *pfdev, u32 as_nr) ++{ ++ mmu_write(pfdev, AS_TRANSTAB_LO(as_nr), 0); ++ mmu_write(pfdev, AS_TRANSTAB_HI(as_nr), 0); ++ ++ mmu_write(pfdev, AS_MEMATTR_LO(as_nr), 0); ++ mmu_write(pfdev, AS_MEMATTR_HI(as_nr), 0); ++ ++ write_cmd(pfdev, as_nr, AS_COMMAND_UPDATE); ++} ++ ++int panfrost_mmu_map(struct panfrost_gem_object *bo) ++{ ++ struct drm_gem_object *obj = &bo->base.base; ++ struct panfrost_device *pfdev = to_panfrost_device(obj->dev); ++ struct io_pgtable_ops *ops = pfdev->mmu->pgtbl_ops; ++ u64 iova = bo->node.start << PAGE_SHIFT; ++ unsigned int count; ++ struct scatterlist *sgl; ++ struct sg_table *sgt; ++ int ret; ++ ++ sgt = drm_gem_shmem_get_pages_sgt(obj); ++ if (WARN_ON(IS_ERR(sgt))) ++ return PTR_ERR(sgt); ++ ++ ret = pm_runtime_get_sync(pfdev->dev); ++ if (ret < 0) ++ return ret; ++ ++ mutex_lock(&pfdev->mmu->lock); ++ ++ for_each_sg(sgt->sgl, sgl, sgt->nents, count) { ++ unsigned long paddr = sg_dma_address(sgl); ++ size_t len = sg_dma_len(sgl); ++ ++ dev_dbg(pfdev->dev, "map: iova=%llx, paddr=%lx, len=%zx", iova, paddr, len); ++ ++ while (len) { ++ ops->map(ops, iova, paddr, SZ_4K, IOMMU_WRITE | IOMMU_READ); ++ iova += SZ_4K; ++ paddr += SZ_4K; ++ len -= SZ_4K; ++ } ++ } ++ ++ mmu_hw_do_operation(pfdev, 0, bo->node.start << PAGE_SHIFT, ++ bo->node.size << PAGE_SHIFT, AS_COMMAND_FLUSH_PT); ++ ++ mutex_unlock(&pfdev->mmu->lock); ++ ++ pm_runtime_mark_last_busy(pfdev->dev); ++ pm_runtime_put_autosuspend(pfdev->dev); ++ ++ return 0; ++} ++ ++void panfrost_mmu_unmap(struct panfrost_gem_object *bo) ++{ ++ struct drm_gem_object *obj = &bo->base.base; ++ struct panfrost_device *pfdev = to_panfrost_device(obj->dev); ++ struct io_pgtable_ops *ops = pfdev->mmu->pgtbl_ops; ++ u64 iova = bo->node.start << PAGE_SHIFT; ++ size_t len = bo->node.size << PAGE_SHIFT; ++ size_t unmapped_len = 0; ++ int ret; ++ ++ dev_dbg(pfdev->dev, "unmap: iova=%llx, len=%zx", iova, len); ++ ++ ret = pm_runtime_get_sync(pfdev->dev); ++ if (ret < 0) ++ return; ++ ++ mutex_lock(&pfdev->mmu->lock); ++ ++ while (unmapped_len < len) { ++ ops->unmap(ops, iova, SZ_4K); ++ iova += SZ_4K; ++ unmapped_len += SZ_4K; ++ } ++ ++ mmu_hw_do_operation(pfdev, 0, bo->node.start << PAGE_SHIFT, ++ bo->node.size << PAGE_SHIFT, AS_COMMAND_FLUSH_PT); ++ ++ mutex_unlock(&pfdev->mmu->lock); ++ ++ pm_runtime_mark_last_busy(pfdev->dev); ++ pm_runtime_put_autosuspend(pfdev->dev); ++} ++ ++static void mmu_tlb_inv_context_s1(void *cookie) ++{ ++ struct panfrost_device *pfdev = cookie; ++ ++ mmu_hw_do_operation(pfdev, 0, 0, ~0UL, AS_COMMAND_FLUSH_MEM); ++} ++ ++static void mmu_tlb_inv_range_nosync(unsigned long iova, size_t size, ++ size_t granule, bool leaf, void *cookie) ++{} ++ ++static void mmu_tlb_sync_context(void *cookie) ++{ ++ //struct panfrost_device *pfdev = cookie; ++ // TODO: Wait 1000 GPU cycles for HW_ISSUE_6367/T60X ++} ++ ++static const struct iommu_gather_ops mmu_tlb_ops = { ++ .tlb_flush_all = mmu_tlb_inv_context_s1, ++ .tlb_add_flush = mmu_tlb_inv_range_nosync, ++ .tlb_sync = mmu_tlb_sync_context, ++}; ++ ++static const char *access_type_name(struct panfrost_device *pfdev, ++ u32 fault_status) ++{ ++ switch (fault_status & AS_FAULTSTATUS_ACCESS_TYPE_MASK) { ++ case AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC: ++ if (panfrost_has_hw_feature(pfdev, HW_FEATURE_AARCH64_MMU)) ++ return "ATOMIC"; ++ else ++ return "UNKNOWN"; ++ case AS_FAULTSTATUS_ACCESS_TYPE_READ: ++ return "READ"; ++ case AS_FAULTSTATUS_ACCESS_TYPE_WRITE: ++ return "WRITE"; ++ case AS_FAULTSTATUS_ACCESS_TYPE_EX: ++ return "EXECUTE"; ++ default: ++ WARN_ON(1); ++ return NULL; ++ } ++} ++ ++static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data) ++{ ++ struct panfrost_device *pfdev = data; ++ u32 status = mmu_read(pfdev, MMU_INT_STAT); ++ int i; ++ ++ if (!status) ++ return IRQ_NONE; ++ ++ dev_err(pfdev->dev, "mmu irq status=%x\n", status); ++ ++ for (i = 0; status; i++) { ++ u32 mask = BIT(i) | BIT(i + 16); ++ u64 addr; ++ u32 fault_status; ++ u32 exception_type; ++ u32 access_type; ++ u32 source_id; ++ ++ if (!(status & mask)) ++ continue; ++ ++ fault_status = mmu_read(pfdev, AS_FAULTSTATUS(i)); ++ addr = mmu_read(pfdev, AS_FAULTADDRESS_LO(i)); ++ addr |= (u64)mmu_read(pfdev, AS_FAULTADDRESS_HI(i)) << 32; ++ ++ /* decode the fault status */ ++ exception_type = fault_status & 0xFF; ++ access_type = (fault_status >> 8) & 0x3; ++ source_id = (fault_status >> 16); ++ ++ /* terminal fault, print info about the fault */ ++ dev_err(pfdev->dev, ++ "Unhandled Page fault in AS%d at VA 0x%016llX\n" ++ "Reason: %s\n" ++ "raw fault status: 0x%X\n" ++ "decoded fault status: %s\n" ++ "exception type 0x%X: %s\n" ++ "access type 0x%X: %s\n" ++ "source id 0x%X\n", ++ i, addr, ++ "TODO", ++ fault_status, ++ (fault_status & (1 << 10) ? "DECODER FAULT" : "SLAVE FAULT"), ++ exception_type, panfrost_exception_name(pfdev, exception_type), ++ access_type, access_type_name(pfdev, fault_status), ++ source_id); ++ ++ mmu_write(pfdev, MMU_INT_CLEAR, mask); ++ ++ status &= ~mask; ++ } ++ ++ return IRQ_HANDLED; ++}; ++ ++int panfrost_mmu_init(struct panfrost_device *pfdev) ++{ ++ struct io_pgtable_ops *pgtbl_ops; ++ int err, irq; ++ ++ pfdev->mmu = devm_kzalloc(pfdev->dev, sizeof(*pfdev->mmu), GFP_KERNEL); ++ if (!pfdev->mmu) ++ return -ENOMEM; ++ ++ mutex_init(&pfdev->mmu->lock); ++ ++ irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu"); ++ if (irq <= 0) ++ return -ENODEV; ++ ++ err = devm_request_irq(pfdev->dev, irq, panfrost_mmu_irq_handler, ++ IRQF_SHARED, "mmu", pfdev); ++ ++ if (err) { ++ dev_err(pfdev->dev, "failed to request mmu irq"); ++ return err; ++ } ++ mmu_write(pfdev, MMU_INT_CLEAR, ~0); ++ mmu_write(pfdev, MMU_INT_MASK, ~0); ++ ++ pfdev->mmu->pgtbl_cfg = (struct io_pgtable_cfg) { ++ .pgsize_bitmap = SZ_4K, // | SZ_2M | SZ_1G), ++ .ias = 48, ++ .oas = 40, ++ .tlb = &mmu_tlb_ops, ++ .iommu_dev = pfdev->dev, ++ }; ++ ++ pgtbl_ops = alloc_io_pgtable_ops(ARM_MALI_LPAE, &pfdev->mmu->pgtbl_cfg, ++ pfdev); ++ if (!pgtbl_ops) ++ return -ENOMEM; ++ ++ pfdev->mmu->pgtbl_ops = pgtbl_ops; ++ ++ panfrost_mmu_enable(pfdev, 0); ++ ++ return 0; ++} ++ ++void panfrost_mmu_fini(struct panfrost_device *pfdev) ++{ ++ mmu_write(pfdev, MMU_INT_MASK, 0); ++ mmu_disable(pfdev, 0); ++ ++ free_io_pgtable_ops(pfdev->mmu->pgtbl_ops); ++} +diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.h b/drivers/gpu/drm/panfrost/panfrost_mmu.h +new file mode 100644 +index 0000000000000..f5878d86a5cea +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_mmu.h +@@ -0,0 +1,17 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright 2019 Linaro, Ltd, Rob Herring */ ++ ++#ifndef __PANFROST_MMU_H__ ++#define __PANFROST_MMU_H__ ++ ++struct panfrost_gem_object; ++ ++int panfrost_mmu_map(struct panfrost_gem_object *bo); ++void panfrost_mmu_unmap(struct panfrost_gem_object *bo); ++ ++int panfrost_mmu_init(struct panfrost_device *pfdev); ++void panfrost_mmu_fini(struct panfrost_device *pfdev); ++ ++void panfrost_mmu_enable(struct panfrost_device *pfdev, u32 as_nr); ++ ++#endif +diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h +new file mode 100644 +index 0000000000000..578c5fc2188b6 +--- /dev/null ++++ b/drivers/gpu/drm/panfrost/panfrost_regs.h +@@ -0,0 +1,298 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* Copyright 2018 Marty E. Plummer */ ++/* Copyright 2019 Linaro, Ltd, Rob Herring */ ++/* ++ * Register definitions based on mali_midg_regmap.h ++ * (C) COPYRIGHT 2010-2018 ARM Limited. All rights reserved. ++ */ ++#ifndef __PANFROST_REGS_H__ ++#define __PANFROST_REGS_H__ ++ ++#define GPU_ID 0x00 ++#define GPU_L2_FEATURES 0x004 /* (RO) Level 2 cache features */ ++#define GPU_CORE_FEATURES 0x008 /* (RO) Shader Core Features */ ++#define GPU_TILER_FEATURES 0x00C /* (RO) Tiler Features */ ++#define GPU_MEM_FEATURES 0x010 /* (RO) Memory system features */ ++#define GROUPS_L2_COHERENT BIT(0) /* Cores groups are l2 coherent */ ++ ++#define GPU_MMU_FEATURES 0x014 /* (RO) MMU features */ ++#define GPU_AS_PRESENT 0x018 /* (RO) Address space slots present */ ++#define GPU_JS_PRESENT 0x01C /* (RO) Job slots present */ ++ ++#define GPU_INT_RAWSTAT 0x20 ++#define GPU_INT_CLEAR 0x24 ++#define GPU_INT_MASK 0x28 ++#define GPU_INT_STAT 0x2c ++#define GPU_IRQ_FAULT BIT(0) ++#define GPU_IRQ_MULTIPLE_FAULT BIT(7) ++#define GPU_IRQ_RESET_COMPLETED BIT(8) ++#define GPU_IRQ_POWER_CHANGED BIT(9) ++#define GPU_IRQ_POWER_CHANGED_ALL BIT(10) ++#define GPU_IRQ_PERFCNT_SAMPLE_COMPLETED BIT(16) ++#define GPU_IRQ_CLEAN_CACHES_COMPLETED BIT(17) ++#define GPU_IRQ_MASK_ALL \ ++ (GPU_IRQ_FAULT |\ ++ GPU_IRQ_MULTIPLE_FAULT |\ ++ GPU_IRQ_RESET_COMPLETED |\ ++ GPU_IRQ_POWER_CHANGED |\ ++ GPU_IRQ_POWER_CHANGED_ALL |\ ++ GPU_IRQ_PERFCNT_SAMPLE_COMPLETED |\ ++ GPU_IRQ_CLEAN_CACHES_COMPLETED) ++#define GPU_IRQ_MASK_ERROR \ ++ ( \ ++ GPU_IRQ_FAULT |\ ++ GPU_IRQ_MULTIPLE_FAULT) ++#define GPU_CMD 0x30 ++#define GPU_CMD_SOFT_RESET 0x01 ++#define GPU_STATUS 0x34 ++#define GPU_LATEST_FLUSH_ID 0x38 ++#define GPU_FAULT_STATUS 0x3C ++#define GPU_FAULT_ADDRESS_LO 0x40 ++#define GPU_FAULT_ADDRESS_HI 0x44 ++ ++#define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */ ++#define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */ ++#define GPU_THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */ ++#define GPU_THREAD_FEATURES 0x0AC /* (RO) Thread features */ ++#define GPU_THREAD_TLS_ALLOC 0x310 /* (RO) Number of threads per core that ++ * TLS must be allocated for */ ++ ++#define GPU_TEXTURE_FEATURES(n) (0x0B0 + ((n) * 4)) ++#define GPU_JS_FEATURES(n) (0x0C0 + ((n) * 4)) ++ ++#define GPU_SHADER_PRESENT_LO 0x100 /* (RO) Shader core present bitmap, low word */ ++#define GPU_SHADER_PRESENT_HI 0x104 /* (RO) Shader core present bitmap, high word */ ++#define GPU_TILER_PRESENT_LO 0x110 /* (RO) Tiler core present bitmap, low word */ ++#define GPU_TILER_PRESENT_HI 0x114 /* (RO) Tiler core present bitmap, high word */ ++ ++#define GPU_L2_PRESENT_LO 0x120 /* (RO) Level 2 cache present bitmap, low word */ ++#define GPU_L2_PRESENT_HI 0x124 /* (RO) Level 2 cache present bitmap, high word */ ++ ++#define GPU_COHERENCY_FEATURES 0x300 /* (RO) Coherency features present */ ++#define COHERENCY_ACE_LITE BIT(0) ++#define COHERENCY_ACE BIT(1) ++ ++#define GPU_STACK_PRESENT_LO 0xE00 /* (RO) Core stack present bitmap, low word */ ++#define GPU_STACK_PRESENT_HI 0xE04 /* (RO) Core stack present bitmap, high word */ ++ ++#define SHADER_READY_LO 0x140 /* (RO) Shader core ready bitmap, low word */ ++#define SHADER_READY_HI 0x144 /* (RO) Shader core ready bitmap, high word */ ++ ++#define TILER_READY_LO 0x150 /* (RO) Tiler core ready bitmap, low word */ ++#define TILER_READY_HI 0x154 /* (RO) Tiler core ready bitmap, high word */ ++ ++#define L2_READY_LO 0x160 /* (RO) Level 2 cache ready bitmap, low word */ ++#define L2_READY_HI 0x164 /* (RO) Level 2 cache ready bitmap, high word */ ++ ++#define STACK_READY_LO 0xE10 /* (RO) Core stack ready bitmap, low word */ ++#define STACK_READY_HI 0xE14 /* (RO) Core stack ready bitmap, high word */ ++ ++ ++#define SHADER_PWRON_LO 0x180 /* (WO) Shader core power on bitmap, low word */ ++#define SHADER_PWRON_HI 0x184 /* (WO) Shader core power on bitmap, high word */ ++ ++#define TILER_PWRON_LO 0x190 /* (WO) Tiler core power on bitmap, low word */ ++#define TILER_PWRON_HI 0x194 /* (WO) Tiler core power on bitmap, high word */ ++ ++#define L2_PWRON_LO 0x1A0 /* (WO) Level 2 cache power on bitmap, low word */ ++#define L2_PWRON_HI 0x1A4 /* (WO) Level 2 cache power on bitmap, high word */ ++ ++#define STACK_PWRON_LO 0xE20 /* (RO) Core stack power on bitmap, low word */ ++#define STACK_PWRON_HI 0xE24 /* (RO) Core stack power on bitmap, high word */ ++ ++ ++#define SHADER_PWROFF_LO 0x1C0 /* (WO) Shader core power off bitmap, low word */ ++#define SHADER_PWROFF_HI 0x1C4 /* (WO) Shader core power off bitmap, high word */ ++ ++#define TILER_PWROFF_LO 0x1D0 /* (WO) Tiler core power off bitmap, low word */ ++#define TILER_PWROFF_HI 0x1D4 /* (WO) Tiler core power off bitmap, high word */ ++ ++#define L2_PWROFF_LO 0x1E0 /* (WO) Level 2 cache power off bitmap, low word */ ++#define L2_PWROFF_HI 0x1E4 /* (WO) Level 2 cache power off bitmap, high word */ ++ ++#define STACK_PWROFF_LO 0xE30 /* (RO) Core stack power off bitmap, low word */ ++#define STACK_PWROFF_HI 0xE34 /* (RO) Core stack power off bitmap, high word */ ++ ++ ++#define SHADER_PWRTRANS_LO 0x200 /* (RO) Shader core power transition bitmap, low word */ ++#define SHADER_PWRTRANS_HI 0x204 /* (RO) Shader core power transition bitmap, high word */ ++ ++#define TILER_PWRTRANS_LO 0x210 /* (RO) Tiler core power transition bitmap, low word */ ++#define TILER_PWRTRANS_HI 0x214 /* (RO) Tiler core power transition bitmap, high word */ ++ ++#define L2_PWRTRANS_LO 0x220 /* (RO) Level 2 cache power transition bitmap, low word */ ++#define L2_PWRTRANS_HI 0x224 /* (RO) Level 2 cache power transition bitmap, high word */ ++ ++#define STACK_PWRTRANS_LO 0xE40 /* (RO) Core stack power transition bitmap, low word */ ++#define STACK_PWRTRANS_HI 0xE44 /* (RO) Core stack power transition bitmap, high word */ ++ ++ ++#define SHADER_PWRACTIVE_LO 0x240 /* (RO) Shader core active bitmap, low word */ ++#define SHADER_PWRACTIVE_HI 0x244 /* (RO) Shader core active bitmap, high word */ ++ ++#define TILER_PWRACTIVE_LO 0x250 /* (RO) Tiler core active bitmap, low word */ ++#define TILER_PWRACTIVE_HI 0x254 /* (RO) Tiler core active bitmap, high word */ ++ ++#define L2_PWRACTIVE_LO 0x260 /* (RO) Level 2 cache active bitmap, low word */ ++#define L2_PWRACTIVE_HI 0x264 /* (RO) Level 2 cache active bitmap, high word */ ++ ++#define GPU_JM_CONFIG 0xF00 /* (RW) Job Manager configuration register (Implementation specific register) */ ++#define GPU_SHADER_CONFIG 0xF04 /* (RW) Shader core configuration settings (Implementation specific register) */ ++#define GPU_TILER_CONFIG 0xF08 /* (RW) Tiler core configuration settings (Implementation specific register) */ ++#define GPU_L2_MMU_CONFIG 0xF0C /* (RW) Configuration of the L2 cache and MMU (Implementation specific register) */ ++ ++/* L2_MMU_CONFIG register */ ++#define L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY_SHIFT 23 ++#define L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY (0x1 << L2_MMU_CONFIG_ALLOW_SNOOP_DISPARITY_SHIFT) ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT 24 ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_OCTANT (0x1 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_QUARTER (0x2 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_HALF (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) ++ ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT 26 ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_OCTANT (0x1 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_QUARTER (0x2 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) ++#define L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_HALF (0x3 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) ++ ++#define L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS_SHIFT 12 ++#define L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_READS (0x7 << L2_MMU_CONFIG_LIMIT_EXTERNAL_READS_SHIFT) ++ ++#define L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES_SHIFT 15 ++#define L2_MMU_CONFIG_3BIT_LIMIT_EXTERNAL_WRITES (0x7 << L2_MMU_CONFIG_LIMIT_EXTERNAL_WRITES_SHIFT) ++ ++/* SHADER_CONFIG register */ ++#define SC_ALT_COUNTERS BIT(3) ++#define SC_OVERRIDE_FWD_PIXEL_KILL BIT(4) ++#define SC_SDC_DISABLE_OQ_DISCARD BIT(6) ++#define SC_LS_ALLOW_ATTR_TYPES BIT(16) ++#define SC_LS_PAUSEBUFFER_DISABLE BIT(16) ++#define SC_TLS_HASH_ENABLE BIT(17) ++#define SC_LS_ATTR_CHECK_DISABLE BIT(18) ++#define SC_ENABLE_TEXGRD_FLAGS BIT(25) ++/* End SHADER_CONFIG register */ ++ ++/* TILER_CONFIG register */ ++#define TC_CLOCK_GATE_OVERRIDE BIT(0) ++ ++/* JM_CONFIG register */ ++#define JM_TIMESTAMP_OVERRIDE BIT(0) ++#define JM_CLOCK_GATE_OVERRIDE BIT(1) ++#define JM_JOB_THROTTLE_ENABLE BIT(2) ++#define JM_JOB_THROTTLE_LIMIT_SHIFT 3 ++#define JM_MAX_JOB_THROTTLE_LIMIT 0x3F ++#define JM_FORCE_COHERENCY_FEATURES_SHIFT 2 ++#define JM_IDVS_GROUP_SIZE_SHIFT 16 ++#define JM_MAX_IDVS_GROUP_SIZE 0x3F ++ ++ ++/* Job Control regs */ ++#define JOB_INT_RAWSTAT 0x1000 ++#define JOB_INT_CLEAR 0x1004 ++#define JOB_INT_MASK 0x1008 ++#define JOB_INT_STAT 0x100c ++#define JOB_INT_JS_STATE 0x1010 ++#define JOB_INT_THROTTLE 0x1014 ++ ++#define MK_JS_MASK(j) (0x10001 << (j)) ++#define JOB_INT_MASK_ERR(j) BIT((j) + 16) ++#define JOB_INT_MASK_DONE(j) BIT(j) ++ ++#define JS_BASE 0x1800 ++#define JS_HEAD_LO(n) (JS_BASE + ((n) * 0x80) + 0x00) ++#define JS_HEAD_HI(n) (JS_BASE + ((n) * 0x80) + 0x04) ++#define JS_TAIL_LO(n) (JS_BASE + ((n) * 0x80) + 0x08) ++#define JS_TAIL_HI(n) (JS_BASE + ((n) * 0x80) + 0x0c) ++#define JS_AFFINITY_LO(n) (JS_BASE + ((n) * 0x80) + 0x10) ++#define JS_AFFINITY_HI(n) (JS_BASE + ((n) * 0x80) + 0x14) ++#define JS_CONFIG(n) (JS_BASE + ((n) * 0x80) + 0x18) ++#define JS_XAFFINITY(n) (JS_BASE + ((n) * 0x80) + 0x1c) ++#define JS_COMMAND(n) (JS_BASE + ((n) * 0x80) + 0x20) ++#define JS_STATUS(n) (JS_BASE + ((n) * 0x80) + 0x24) ++#define JS_HEAD_NEXT_LO(n) (JS_BASE + ((n) * 0x80) + 0x40) ++#define JS_HEAD_NEXT_HI(n) (JS_BASE + ((n) * 0x80) + 0x44) ++#define JS_AFFINITY_NEXT_LO(n) (JS_BASE + ((n) * 0x80) + 0x50) ++#define JS_AFFINITY_NEXT_HI(n) (JS_BASE + ((n) * 0x80) + 0x54) ++#define JS_CONFIG_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x58) ++#define JS_COMMAND_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x60) ++#define JS_FLUSH_ID_NEXT(n) (JS_BASE + ((n) * 0x80) + 0x70) ++ ++/* Possible values of JS_CONFIG and JS_CONFIG_NEXT registers */ ++#define JS_CONFIG_START_FLUSH_CLEAN BIT(8) ++#define JS_CONFIG_START_FLUSH_CLEAN_INVALIDATE (3u << 8) ++#define JS_CONFIG_START_MMU BIT(10) ++#define JS_CONFIG_JOB_CHAIN_FLAG BIT(11) ++#define JS_CONFIG_END_FLUSH_CLEAN BIT(12) ++#define JS_CONFIG_END_FLUSH_CLEAN_INVALIDATE (3u << 12) ++#define JS_CONFIG_ENABLE_FLUSH_REDUCTION BIT(14) ++#define JS_CONFIG_DISABLE_DESCRIPTOR_WR_BK BIT(15) ++#define JS_CONFIG_THREAD_PRI(n) ((n) << 16) ++ ++#define JS_COMMAND_NOP 0x00 ++#define JS_COMMAND_START 0x01 ++#define JS_COMMAND_SOFT_STOP 0x02 /* Gently stop processing a job chain */ ++#define JS_COMMAND_HARD_STOP 0x03 /* Rudely stop processing a job chain */ ++#define JS_COMMAND_SOFT_STOP_0 0x04 /* Execute SOFT_STOP if JOB_CHAIN_FLAG is 0 */ ++#define JS_COMMAND_HARD_STOP_0 0x05 /* Execute HARD_STOP if JOB_CHAIN_FLAG is 0 */ ++#define JS_COMMAND_SOFT_STOP_1 0x06 /* Execute SOFT_STOP if JOB_CHAIN_FLAG is 1 */ ++#define JS_COMMAND_HARD_STOP_1 0x07 /* Execute HARD_STOP if JOB_CHAIN_FLAG is 1 */ ++ ++#define JS_STATUS_EVENT_ACTIVE 0x08 ++ ++ ++/* MMU regs */ ++#define MMU_INT_RAWSTAT 0x2000 ++#define MMU_INT_CLEAR 0x2004 ++#define MMU_INT_MASK 0x2008 ++#define MMU_INT_STAT 0x200c ++ ++/* AS_COMMAND register commands */ ++#define AS_COMMAND_NOP 0x00 /* NOP Operation */ ++#define AS_COMMAND_UPDATE 0x01 /* Broadcasts the values in AS_TRANSTAB and ASn_MEMATTR to all MMUs */ ++#define AS_COMMAND_LOCK 0x02 /* Issue a lock region command to all MMUs */ ++#define AS_COMMAND_UNLOCK 0x03 /* Issue a flush region command to all MMUs */ ++#define AS_COMMAND_FLUSH 0x04 /* Flush all L2 caches then issue a flush region command to all MMUs ++ (deprecated - only for use with T60x) */ ++#define AS_COMMAND_FLUSH_PT 0x04 /* Flush all L2 caches then issue a flush region command to all MMUs */ ++#define AS_COMMAND_FLUSH_MEM 0x05 /* Wait for memory accesses to complete, flush all the L1s cache then ++ flush all L2 caches then issue a flush region command to all MMUs */ ++ ++#define MMU_AS(as) (0x2400 + ((as) << 6)) ++ ++#define AS_TRANSTAB_LO(as) (MMU_AS(as) + 0x00) /* (RW) Translation Table Base Address for address space n, low word */ ++#define AS_TRANSTAB_HI(as) (MMU_AS(as) + 0x04) /* (RW) Translation Table Base Address for address space n, high word */ ++#define AS_MEMATTR_LO(as) (MMU_AS(as) + 0x08) /* (RW) Memory attributes for address space n, low word. */ ++#define AS_MEMATTR_HI(as) (MMU_AS(as) + 0x0C) /* (RW) Memory attributes for address space n, high word. */ ++#define AS_LOCKADDR_LO(as) (MMU_AS(as) + 0x10) /* (RW) Lock region address for address space n, low word */ ++#define AS_LOCKADDR_HI(as) (MMU_AS(as) + 0x14) /* (RW) Lock region address for address space n, high word */ ++#define AS_COMMAND(as) (MMU_AS(as) + 0x18) /* (WO) MMU command register for address space n */ ++#define AS_FAULTSTATUS(as) (MMU_AS(as) + 0x1C) /* (RO) MMU fault status register for address space n */ ++#define AS_FAULTADDRESS_LO(as) (MMU_AS(as) + 0x20) /* (RO) Fault Address for address space n, low word */ ++#define AS_FAULTADDRESS_HI(as) (MMU_AS(as) + 0x24) /* (RO) Fault Address for address space n, high word */ ++#define AS_STATUS(as) (MMU_AS(as) + 0x28) /* (RO) Status flags for address space n */ ++/* Additional Bifrost AS regsiters */ ++#define AS_TRANSCFG_LO(as) (MMU_AS(as) + 0x30) /* (RW) Translation table configuration for address space n, low word */ ++#define AS_TRANSCFG_HI(as) (MMU_AS(as) + 0x34) /* (RW) Translation table configuration for address space n, high word */ ++#define AS_FAULTEXTRA_LO(as) (MMU_AS(as) + 0x38) /* (RO) Secondary fault address for address space n, low word */ ++#define AS_FAULTEXTRA_HI(as) (MMU_AS(as) + 0x3C) /* (RO) Secondary fault address for address space n, high word */ ++ ++/* ++ * Begin LPAE MMU TRANSTAB register values ++ */ ++#define AS_TRANSTAB_LPAE_ADDR_SPACE_MASK 0xfffffffffffff000 ++#define AS_TRANSTAB_LPAE_ADRMODE_IDENTITY 0x2 ++#define AS_TRANSTAB_LPAE_ADRMODE_TABLE 0x3 ++#define AS_TRANSTAB_LPAE_ADRMODE_MASK 0x3 ++#define AS_TRANSTAB_LPAE_READ_INNER BIT(2) ++#define AS_TRANSTAB_LPAE_SHARE_OUTER BIT(4) ++ ++#define AS_STATUS_AS_ACTIVE 0x01 ++ ++#define AS_FAULTSTATUS_ACCESS_TYPE_MASK (0x3 << 8) ++#define AS_FAULTSTATUS_ACCESS_TYPE_ATOMIC (0x0 << 8) ++#define AS_FAULTSTATUS_ACCESS_TYPE_EX (0x1 << 8) ++#define AS_FAULTSTATUS_ACCESS_TYPE_READ (0x2 << 8) ++#define AS_FAULTSTATUS_ACCESS_TYPE_WRITE (0x3 << 8) ++ ++#endif +diff --git a/include/uapi/drm/panfrost_drm.h b/include/uapi/drm/panfrost_drm.h +new file mode 100644 +index 0000000000000..a52e0283b90d5 +--- /dev/null ++++ b/include/uapi/drm/panfrost_drm.h +@@ -0,0 +1,142 @@ ++/* SPDX-License-Identifier: MIT */ ++/* ++ * Copyright © 2014-2018 Broadcom ++ * Copyright © 2019 Collabora ltd. ++ */ ++#ifndef _PANFROST_DRM_H_ ++#define _PANFROST_DRM_H_ ++ ++#include "drm.h" ++ ++#if defined(__cplusplus) ++extern "C" { ++#endif ++ ++#define DRM_PANFROST_SUBMIT 0x00 ++#define DRM_PANFROST_WAIT_BO 0x01 ++#define DRM_PANFROST_CREATE_BO 0x02 ++#define DRM_PANFROST_MMAP_BO 0x03 ++#define DRM_PANFROST_GET_PARAM 0x04 ++#define DRM_PANFROST_GET_BO_OFFSET 0x05 ++ ++#define DRM_IOCTL_PANFROST_SUBMIT DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_SUBMIT, struct drm_panfrost_submit) ++#define DRM_IOCTL_PANFROST_WAIT_BO DRM_IOW(DRM_COMMAND_BASE + DRM_PANFROST_WAIT_BO, struct drm_panfrost_wait_bo) ++#define DRM_IOCTL_PANFROST_CREATE_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_CREATE_BO, struct drm_panfrost_create_bo) ++#define DRM_IOCTL_PANFROST_MMAP_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_MMAP_BO, struct drm_panfrost_mmap_bo) ++#define DRM_IOCTL_PANFROST_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_PARAM, struct drm_panfrost_get_param) ++#define DRM_IOCTL_PANFROST_GET_BO_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_PANFROST_GET_BO_OFFSET, struct drm_panfrost_get_bo_offset) ++ ++#define PANFROST_JD_REQ_FS (1 << 0) ++/** ++ * struct drm_panfrost_submit - ioctl argument for submitting commands to the 3D ++ * engine. ++ * ++ * This asks the kernel to have the GPU execute a render command list. ++ */ ++struct drm_panfrost_submit { ++ ++ /** Address to GPU mapping of job descriptor */ ++ __u64 jc; ++ ++ /** An optional array of sync objects to wait on before starting this job. */ ++ __u64 in_syncs; ++ ++ /** Number of sync objects to wait on before starting this job. */ ++ __u32 in_sync_count; ++ ++ /** An optional sync object to place the completion fence in. */ ++ __u32 out_sync; ++ ++ /** Pointer to a u32 array of the BOs that are referenced by the job. */ ++ __u64 bo_handles; ++ ++ /** Number of BO handles passed in (size is that times 4). */ ++ __u32 bo_handle_count; ++ ++ /** A combination of PANFROST_JD_REQ_* */ ++ __u32 requirements; ++}; ++ ++/** ++ * struct drm_panfrost_wait_bo - ioctl argument for waiting for ++ * completion of the last DRM_PANFROST_SUBMIT on a BO. ++ * ++ * This is useful for cases where multiple processes might be ++ * rendering to a BO and you want to wait for all rendering to be ++ * completed. ++ */ ++struct drm_panfrost_wait_bo { ++ __u32 handle; ++ __u32 pad; ++ __s64 timeout_ns; /* absolute */ ++}; ++ ++/** ++ * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. ++ * ++ * There are currently no values for the flags argument, but it may be ++ * used in a future extension. ++ */ ++struct drm_panfrost_create_bo { ++ __u32 size; ++ __u32 flags; ++ /** Returned GEM handle for the BO. */ ++ __u32 handle; ++ /* Pad, must be zero-filled. */ ++ __u32 pad; ++ /** ++ * Returned offset for the BO in the GPU address space. This offset ++ * is private to the DRM fd and is valid for the lifetime of the GEM ++ * handle. ++ * ++ * This offset value will always be nonzero, since various HW ++ * units treat 0 specially. ++ */ ++ __u64 offset; ++}; ++ ++/** ++ * struct drm_panfrost_mmap_bo - ioctl argument for mapping Panfrost BOs. ++ * ++ * This doesn't actually perform an mmap. Instead, it returns the ++ * offset you need to use in an mmap on the DRM device node. This ++ * means that tools like valgrind end up knowing about the mapped ++ * memory. ++ * ++ * There are currently no values for the flags argument, but it may be ++ * used in a future extension. ++ */ ++struct drm_panfrost_mmap_bo { ++ /** Handle for the object being mapped. */ ++ __u32 handle; ++ __u32 flags; ++ /** offset into the drm node to use for subsequent mmap call. */ ++ __u64 offset; ++}; ++ ++enum drm_panfrost_param { ++ DRM_PANFROST_PARAM_GPU_PROD_ID, ++}; ++ ++struct drm_panfrost_get_param { ++ __u32 param; ++ __u32 pad; ++ __u64 value; ++}; ++ ++/** ++ * Returns the offset for the BO in the GPU address space for this DRM fd. ++ * This is the same value returned by drm_panfrost_create_bo, if that was called ++ * from this DRM fd. ++ */ ++struct drm_panfrost_get_bo_offset { ++ __u32 handle; ++ __u32 pad; ++ __u64 offset; ++}; ++ ++#if defined(__cplusplus) ++} ++#endif ++ ++#endif /* _PANFROST_DRM_H_ */ + +From d6082cb08bbb55d68dfe56584a5779caa8e0878a Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Thu, 6 Dec 2018 14:26:00 +0100 +Subject: [PATCH 246/249] arm64: dts: meson-gxm: Add Mali-T820 node + +The Amlogic Meson GXM SoC embeds an ARM Mali T820 GPU. + +This patch adds the node with all the needed properties to power +on the GPU. + +This has been tested with the work-in-progress PanFrost project +aiming support for ARM Mali Midgard and later GPUs. + +Signed-off-by: Christian Hewitt +Signed-off-by: Neil Armstrong +(cherry picked from commit a21b179e7eba2ab96ecd66ddc782f3c5ecd21cfb) +--- + arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 27 ++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi +index d74cb4993bae2..13e76d4136c05 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi +@@ -91,6 +91,33 @@ + reset-names = "phy"; + status = "okay"; + }; ++ ++ mali: gpu@c0000 { ++ compatible = "amlogic,meson-gxm-mali", "arm,mali-t820"; ++ reg = <0x0 0xc0000 0x0 0x40000>; ++ interrupt-parent = <&gic>; ++ interrupts = , ++ , ++ ; ++ interrupt-names = "gpu", "mmu", "job"; ++ clocks = <&clkc CLKID_MALI>; ++ resets = <&reset RESET_MALI_CAPB3>, <&reset RESET_MALI>; ++ ++ /* ++ * Mali clocking is provided by two identical clock paths ++ * MALI_0 and MALI_1 muxed to a single clock by a glitch ++ * free mux to safely change frequency while running. ++ */ ++ assigned-clocks = <&clkc CLKID_MALI_0_SEL>, ++ <&clkc CLKID_MALI_0>, ++ <&clkc CLKID_MALI>; /* Glitch free mux */ ++ assigned-clock-parents = <&clkc CLKID_FCLK_DIV3>, ++ <0>, /* Do Nothing */ ++ <&clkc CLKID_MALI_0>; ++ assigned-clock-rates = <0>, /* Do Nothing */ ++ <666666666>, ++ <0>; /* Do Nothing */ ++ }; + }; + + &clkc_AO { + +From 5a848cbeaeb7cbbe4d93ec64b0ddf6783973ba1f Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Mon, 10 Dec 2018 14:00:23 +0100 +Subject: [PATCH 247/249] arm64: dts: meson-gxm-nexbox-a1: Enable USB + +(cherry picked from commit d8b1846fbdec9b43b2655e01fcd58086538da2d0) +--- + arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +index 93a968fa5a0d3..b8eb7f7c3dff6 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +@@ -215,3 +215,7 @@ + pinctrl-0 = <&uart_ao_a_pins>; + pinctrl-names = "default"; + }; ++ ++&usb0 { ++ status = "okay"; ++}; + +From aedb35fe0a4ab763d69f50174317734b388bc125 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Wed, 13 Mar 2019 17:34:09 +0100 +Subject: [PATCH 248/249] arm64: dts: meson-gxm-nexbox-a1: disable cvbs + +(cherry picked from commit 43a438462f00880abaa6ac5241f78644d2b4da07) +--- + arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +index b8eb7f7c3dff6..fe6d84319e948 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts +@@ -57,6 +57,7 @@ + + cvbs-connector { + compatible = "composite-video-connector"; ++ status = "disabled"; + + port { + cvbs_connector_in: endpoint { + +From df28223b151155ab0edd8419b0347a7135443fd3 Mon Sep 17 00:00:00 2001 +From: Neil Armstrong +Date: Thu, 14 Mar 2019 09:37:38 +0100 +Subject: [PATCH 249/249] [WiP] drm/panfrost: add support for custom soft-reset + on Amlogic GXM + +(cherry picked from commit 2e5230c1bf9cf01f035da72291cc460cb3b37096) +--- + drivers/gpu/drm/panfrost/panfrost_gpu.c | 13 ++++++++++++- + drivers/gpu/drm/panfrost/panfrost_regs.h | 4 ++++ + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c +index aceaf6e44a099..9cd02cba54206 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c ++++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c +@@ -5,7 +5,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include + +@@ -53,7 +55,16 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) + + gpu_write(pfdev, GPU_INT_MASK, 0); + gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED); +- gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); ++ ++ if (of_device_is_compatible(pfdev->dev->of_node, "amlogic,meson-gxm-mali")) { ++ reset_control_assert(pfdev->rstc); ++ udelay(10); ++ reset_control_deassert(pfdev->rstc); ++ ++ gpu_write(pfdev, GPU_PWR_KEY, 0x2968A819); ++ gpu_write(pfdev, GPU_PWR_OVERRIDE1, 0xfff | (0x20 << 16)); ++ } else ++ gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET); + + ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT, + val, val & GPU_IRQ_RESET_COMPLETED, 100, 10000); +diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h +index 578c5fc2188b6..d61b2cd0a99b6 100644 +--- a/drivers/gpu/drm/panfrost/panfrost_regs.h ++++ b/drivers/gpu/drm/panfrost/panfrost_regs.h +@@ -50,6 +50,10 @@ + #define GPU_FAULT_ADDRESS_LO 0x40 + #define GPU_FAULT_ADDRESS_HI 0x44 + ++#define GPU_PWR_KEY 0x050 /* (WO) Power manager key register */ ++#define GPU_PWR_OVERRIDE0 0x054 /* (RW) Power manager override settings */ ++#define GPU_PWR_OVERRIDE1 0x058 /* (RW) Power manager override settings */ ++ + #define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */ + #define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */ + #define GPU_THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */ diff --git a/projects/Amlogic/patches/linux/c-hdmi-audio-and-cec.patch b/projects/Amlogic/patches/linux/c-hdmi-audio-and-cec.patch new file mode 100644 index 0000000000..507ff9b4d3 --- /dev/null +++ b/projects/Amlogic/patches/linux/c-hdmi-audio-and-cec.patch @@ -0,0 +1,1150 @@ +From 995ea27fe624bf8a3e7522bf8121a7443c73ef84 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 16 Dec 2018 10:22:09 +0100 +Subject: [PATCH 01/15] drm: dw-hdmi: extract dw_hdmi_connector_update_edid() + +Extract code that updates EDID into a dw_hdmi_connector_update_edid() helper, +it will be called from dw_hdmi_connector_detect(). + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index e4948db..daa4351 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2084,7 +2084,8 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) + return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); + } + +-static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ++static int dw_hdmi_connector_update_edid(struct drm_connector *connector, ++ bool add_modes) + { + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, + connector); +@@ -2103,7 +2104,8 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) + hdmi->sink_has_audio = drm_detect_monitor_audio(edid); + drm_connector_update_edid_property(connector, edid); + cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); +- ret = drm_add_edid_modes(connector, edid); ++ if (add_modes) ++ ret = drm_add_edid_modes(connector, edid); + kfree(edid); + } else { + dev_dbg(hdmi->dev, "failed to get edid\n"); +@@ -2112,6 +2114,11 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) + return ret; + } + ++static int dw_hdmi_connector_get_modes(struct drm_connector *connector) ++{ ++ return dw_hdmi_connector_update_edid(connector, true); ++} ++ + static void dw_hdmi_connector_force(struct drm_connector *connector) + { + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, +-- +2.7.4 + + +From ccf5389b259e8b30ce30ccfcbf573004dfd6a888 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 16 Dec 2018 11:38:43 +0100 +Subject: [PATCH 02/15] drm: dw-hdmi: move dw_hdmi_connector_detect() + +Move dw_hdmi_connector_detect() it will call dw_hdmi_connector_update_edid(). + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 30 +++++++++++++++--------------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index daa4351..6e20041 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2069,21 +2069,6 @@ static void dw_hdmi_update_phy_mask(struct dw_hdmi *hdmi) + hdmi->rxsense); + } + +-static enum drm_connector_status +-dw_hdmi_connector_detect(struct drm_connector *connector, bool force) +-{ +- struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, +- connector); +- +- mutex_lock(&hdmi->mutex); +- hdmi->force = DRM_FORCE_UNSPECIFIED; +- dw_hdmi_update_power(hdmi); +- dw_hdmi_update_phy_mask(hdmi); +- mutex_unlock(&hdmi->mutex); +- +- return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); +-} +- + static int dw_hdmi_connector_update_edid(struct drm_connector *connector, + bool add_modes) + { +@@ -2114,6 +2099,21 @@ static int dw_hdmi_connector_update_edid(struct drm_connector *connector, + return ret; + } + ++static enum drm_connector_status ++dw_hdmi_connector_detect(struct drm_connector *connector, bool force) ++{ ++ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, ++ connector); ++ ++ mutex_lock(&hdmi->mutex); ++ hdmi->force = DRM_FORCE_UNSPECIFIED; ++ dw_hdmi_update_power(hdmi); ++ dw_hdmi_update_phy_mask(hdmi); ++ mutex_unlock(&hdmi->mutex); ++ ++ return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); ++} ++ + static int dw_hdmi_connector_get_modes(struct drm_connector *connector) + { + return dw_hdmi_connector_update_edid(connector, true); +-- +2.7.4 + + +From b589578b0dd467100be6165258ce8a34fd1d7ca2 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 16 Dec 2018 10:22:09 +0100 +Subject: [PATCH 03/15] drm: dw-hdmi: update CEC phys addr and EDID on HPD + event + +Update CEC phys addr and EDID on HPD event, fixes lost CEC phys addr and +stale EDID when HDMI cable is unplugged/replugged or AVR is powered on/off. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 6e20041..c438142 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2102,6 +2102,7 @@ static int dw_hdmi_connector_update_edid(struct drm_connector *connector, + static enum drm_connector_status + dw_hdmi_connector_detect(struct drm_connector *connector, bool force) + { ++ enum drm_connector_status status; + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, + connector); + +@@ -2111,7 +2112,14 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) + dw_hdmi_update_phy_mask(hdmi); + mutex_unlock(&hdmi->mutex); + +- return hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); ++ status = hdmi->phy.ops->read_hpd(hdmi, hdmi->phy.data); ++ ++ if (status == connector_status_connected) ++ dw_hdmi_connector_update_edid(connector, false); ++ else ++ cec_notifier_set_phys_addr(hdmi->cec_notifier, CEC_PHYS_ADDR_INVALID); ++ ++ return status; + } + + static int dw_hdmi_connector_get_modes(struct drm_connector *connector) +@@ -2326,10 +2334,6 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) + dw_hdmi_setup_rx_sense(hdmi, + phy_stat & HDMI_PHY_HPD, + phy_stat & HDMI_PHY_RX_SENSE); +- +- if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0) +- cec_notifier_set_phys_addr(hdmi->cec_notifier, +- CEC_PHYS_ADDR_INVALID); + } + + if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { +-- +2.7.4 + + +From c168ef33a8f989a7a05879ae1f79c30e5d54dc1e Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 16 Dec 2018 10:22:09 +0100 +Subject: [PATCH 04/15] Revert "drm/edid: make drm_edid_to_eld() static" + +drm_edid_to_eld() is needed to update stale connector ELD on HPD event. + +This reverts part of commit 79436a1c9bccf5e38cb6ea26e4e4b9283baf2e20. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/drm_edid.c | 5 +++-- + include/drm/drm_edid.h | 1 + + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c +index 990b190..288534e 100644 +--- a/drivers/gpu/drm/drm_edid.c ++++ b/drivers/gpu/drm/drm_edid.c +@@ -3906,7 +3906,7 @@ static void clear_eld(struct drm_connector *connector) + connector->audio_latency[1] = 0; + } + +-/* ++/** + * drm_edid_to_eld - build ELD from EDID + * @connector: connector corresponding to the HDMI/DP sink + * @edid: EDID to parse +@@ -3914,7 +3914,7 @@ static void clear_eld(struct drm_connector *connector) + * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The + * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. + */ +-static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) ++void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) + { + uint8_t *eld = connector->eld; + u8 *cea; +@@ -3999,6 +3999,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) + DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", + drm_eld_size(eld), total_sad_count); + } ++EXPORT_SYMBOL(drm_edid_to_eld); + + /** + * drm_edid_to_sad - extracts SADs from EDID +diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h +index 8dc1a08..4784784 100644 +--- a/include/drm/drm_edid.h ++++ b/include/drm/drm_edid.h +@@ -333,6 +333,7 @@ struct drm_encoder; + struct drm_connector; + struct drm_display_mode; + ++void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid); + int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads); + int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb); + int drm_av_sync_delay(struct drm_connector *connector, +-- +2.7.4 + + +From a632d4ce08386c9929fa0f81eecccab200dc1577 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 16 Dec 2018 10:22:09 +0100 +Subject: [PATCH 05/15] drm: dw-hdmi: update ELD on HPD event + +Update connector ELD on HPD event, fixes stale ELD when +HDMI cable is unplugged/replugged or AVR is powered on/off. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index c438142..efd4399 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2091,6 +2091,8 @@ static int dw_hdmi_connector_update_edid(struct drm_connector *connector, + cec_notifier_set_phys_addr_from_edid(hdmi->cec_notifier, edid); + if (add_modes) + ret = drm_add_edid_modes(connector, edid); ++ else ++ drm_edid_to_eld(connector, edid); + kfree(edid); + } else { + dev_dbg(hdmi->dev, "failed to get edid\n"); +-- +2.7.4 + + +From 99ee583dce02d6f2432390f2af4c6c3ecb2c81a8 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 16 Dec 2018 10:22:09 +0100 +Subject: [PATCH 06/15] ASoC: hdmi-codec: add hdmi_codec_eld_notify() + +Add helper that will notify userspace when ELD control has changed. + +Signed-off-by: Jonas Karlman +--- + include/sound/hdmi-codec.h | 2 ++ + sound/soc/codecs/hdmi-codec.c | 26 ++++++++++++++++++++++---- + 2 files changed, 24 insertions(+), 4 deletions(-) + +diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h +index 9483c55..7cf66a4 100644 +--- a/include/sound/hdmi-codec.h ++++ b/include/sound/hdmi-codec.h +@@ -107,6 +107,8 @@ struct hdmi_codec_pdata { + void *data; + }; + ++void hdmi_codec_eld_notify(struct device *dev); ++ + #define HDMI_CODEC_DRV_NAME "hdmi-audio-codec" + + #endif /* __HDMI_CODEC_H__ */ +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 6a0cc8d..367e663 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -282,6 +282,8 @@ struct hdmi_codec_priv { + struct snd_pcm_chmap *chmap_info; + unsigned int chmap_idx; + struct mutex lock; ++ struct snd_card *snd_card; ++ struct snd_kcontrol *kctl; + }; + + static const struct snd_soc_dapm_widget hdmi_widgets[] = { +@@ -614,7 +616,6 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, + { + struct snd_soc_dai_driver *drv = dai->driver; + struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); +- struct snd_kcontrol *kctl; + struct snd_kcontrol_new hdmi_eld_ctl = { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, +@@ -641,12 +642,29 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + + /* add ELD ctl with the device number corresponding to the PCM stream */ +- kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); +- if (!kctl) ++ hcp->kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); ++ if (!hcp->kctl) + return -ENOMEM; + +- return snd_ctl_add(rtd->card->snd_card, kctl); ++ hcp->snd_card = rtd->card->snd_card; ++ ++ return snd_ctl_add(hcp->snd_card, hcp->kctl); ++} ++ ++void hdmi_codec_eld_notify(struct device *dev) ++{ ++ struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); ++ struct snd_ctl_elem_id id; ++ ++ if (!hcp || ++ !hcp->snd_card || ++ !hcp->kctl) ++ return; ++ ++ id = hcp->kctl->id; ++ snd_ctl_notify(hcp->snd_card, SNDRV_CTL_EVENT_MASK_VALUE, &id); + } ++EXPORT_SYMBOL_GPL(hdmi_codec_eld_notify); + + static int hdmi_dai_probe(struct snd_soc_dai *dai) + { +-- +2.7.4 + + +From 93719d8e794d72ac21c2a433360b4cf9813fbd04 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 16 Dec 2018 12:56:33 +0100 +Subject: [PATCH 07/15] drm: dw-hdmi: add dw_hdmi_update_eld() callback + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 15 +++++++++++++++ + include/drm/bridge/dw_hdmi.h | 2 ++ + 2 files changed, 17 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index efd4399..3a031d1 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -188,6 +188,7 @@ struct dw_hdmi { + struct regmap *regm; + void (*enable_audio)(struct dw_hdmi *hdmi); + void (*disable_audio)(struct dw_hdmi *hdmi); ++ void (*update_eld)(struct device *dev, u8 *eld); + + struct cec_notifier *cec_notifier; + }; +@@ -624,6 +625,19 @@ void dw_hdmi_audio_disable(struct dw_hdmi *hdmi) + } + EXPORT_SYMBOL_GPL(dw_hdmi_audio_disable); + ++static void dw_hdmi_update_eld(struct dw_hdmi *hdmi, u8 *eld) ++{ ++ if (hdmi->audio && hdmi->update_eld) ++ hdmi->update_eld(&hdmi->audio->dev, eld); ++} ++ ++void dw_hdmi_set_update_eld(struct dw_hdmi *hdmi, ++ void (*update_eld)(struct device *dev, u8 *eld)) ++{ ++ hdmi->update_eld = update_eld; ++} ++EXPORT_SYMBOL_GPL(dw_hdmi_set_update_eld); ++ + static bool hdmi_bus_fmt_is_rgb(unsigned int bus_format) + { + switch (bus_format) { +@@ -2093,6 +2107,7 @@ static int dw_hdmi_connector_update_edid(struct drm_connector *connector, + ret = drm_add_edid_modes(connector, edid); + else + drm_edid_to_eld(connector, edid); ++ dw_hdmi_update_eld(hdmi, connector->eld); + kfree(edid); + } else { + dev_dbg(hdmi->dev, "failed to get edid\n"); +diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h +index ede8bff..57e2d18 100644 +--- a/include/drm/bridge/dw_hdmi.h ++++ b/include/drm/bridge/dw_hdmi.h +@@ -165,6 +165,8 @@ void dw_hdmi_setup_rx_sense(struct dw_hdmi *hdmi, bool hpd, bool rx_sense); + void dw_hdmi_set_sample_rate(struct dw_hdmi *hdmi, unsigned int rate); + void dw_hdmi_audio_enable(struct dw_hdmi *hdmi); + void dw_hdmi_audio_disable(struct dw_hdmi *hdmi); ++void dw_hdmi_set_update_eld(struct dw_hdmi *hdmi, ++ void (*update_eld)(struct device *dev, u8 *eld)); + void dw_hdmi_set_high_tmds_clock_ratio(struct dw_hdmi *hdmi); + + /* PHY configuration */ +-- +2.7.4 + + +From ae1a9144f7dce398403f8cb6f0539fc0a387d53a Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 16 Dec 2018 10:22:09 +0100 +Subject: [PATCH 08/15] drm: dw-hdmi-i2s: add .get_eld callback for ALSA SoC + +Add get_eld() callback and call hdmi_codec_eld_notify() when ELD has changed. + +Signed-off-by: Jonas Karlman +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h | 1 + + .../gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 36 +++++++++++++++++++++- + 2 files changed, 36 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +index 63b5756..69b8a97 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +@@ -14,6 +14,7 @@ struct dw_hdmi_audio_data { + + struct dw_hdmi_i2s_audio_data { + struct dw_hdmi *hdmi; ++ u8 eld[128]; + + void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); + u8 (*read)(struct dw_hdmi *hdmi, int offset); +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index cdb1480..2eab862 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -104,6 +104,32 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) + hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); + } + ++static void dw_hdmi_i2s_update_eld(struct device *dev, u8 *eld) ++{ ++ struct dw_hdmi_i2s_audio_data *audio = dev_get_platdata(dev); ++ struct platform_device *hcpdev = dev_get_drvdata(dev); ++ ++ if (!audio || !hcpdev) ++ return; ++ ++ if (!memcmp(audio->eld, eld, sizeof(audio->eld))) ++ return; ++ ++ memcpy(audio->eld, eld, sizeof(audio->eld)); ++ ++ hdmi_codec_eld_notify(&hcpdev->dev); ++} ++ ++static int dw_hdmi_i2s_get_eld(struct device *dev, void *data, ++ u8 *buf, size_t len) ++{ ++ struct dw_hdmi_i2s_audio_data *audio = data; ++ ++ memcpy(buf, audio->eld, min(sizeof(audio->eld), len)); ++ ++ return 0; ++} ++ + static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, + struct device_node *endpoint) + { +@@ -127,16 +153,19 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, + static struct hdmi_codec_ops dw_hdmi_i2s_ops = { + .hw_params = dw_hdmi_i2s_hw_params, + .audio_shutdown = dw_hdmi_i2s_audio_shutdown, ++ .get_eld = dw_hdmi_i2s_get_eld, + .get_dai_id = dw_hdmi_i2s_get_dai_id, + }; + + static int snd_dw_hdmi_probe(struct platform_device *pdev) + { +- struct dw_hdmi_i2s_audio_data *audio = pdev->dev.platform_data; ++ struct dw_hdmi_i2s_audio_data *audio = dev_get_platdata(&pdev->dev); + struct platform_device_info pdevinfo; + struct hdmi_codec_pdata pdata; + struct platform_device *platform; + ++ memset(audio->eld, 0, sizeof(audio->eld)); ++ + pdata.ops = &dw_hdmi_i2s_ops; + pdata.i2s = 1; + pdata.max_i2s_channels = 8; +@@ -156,13 +185,18 @@ static int snd_dw_hdmi_probe(struct platform_device *pdev) + + dev_set_drvdata(&pdev->dev, platform); + ++ dw_hdmi_set_update_eld(audio->hdmi, dw_hdmi_i2s_update_eld); ++ + return 0; + } + + static int snd_dw_hdmi_remove(struct platform_device *pdev) + { ++ struct dw_hdmi_i2s_audio_data *audio = dev_get_platdata(&pdev->dev); + struct platform_device *platform = dev_get_drvdata(&pdev->dev); + ++ dw_hdmi_set_update_eld(audio->hdmi, NULL); ++ + platform_device_unregister(platform); + + return 0; +-- +2.7.4 + + +From 743a2323412554e399fcb833c1554b5e9deefc37 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 25 Mar 2018 22:17:06 +0200 +Subject: [PATCH 09/15] ASoC: hdmi-codec: reorder channel allocation list + +Wrong channel allocation is selected by hdmi_codec_get_ch_alloc_table_idx(). + +E.g when ELD reports FL|FR|LFE|FC|RL|RR or FL|FR|LFE|FC|RL|RR|RC|RLC|RRC + +ca_id 0x01 with speaker mask FL|FR|LFE gets selected instead of +ca_id 0x03 with speaker mask FL|FR|LFE|FC for 4 channels + +and + +ca_id 0x04 with speaker mask FL|FR|RC gets selected instead of +ca_id 0x0b with speaker mask FL|FR|LFE|FC|RL|RR for 6 channels + +Fix this by reorder the channel allocation list with +most specific speaker mask at the top. + +Signed-off-by: Jonas Karlman +--- + sound/soc/codecs/hdmi-codec.c | 115 +++++++++++++++++++----------------------- + 1 file changed, 53 insertions(+), 62 deletions(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 367e663..4cacade 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -196,84 +196,75 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { + /* + * hdmi_codec_channel_alloc: speaker configuration available for CEA + * +- * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct ++ * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps + * The preceding ones have better chances to be selected by + * hdmi_codec_get_ch_alloc_table_idx(). + */ + static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { + { .ca_id = 0x00, .n_ch = 2, +- .mask = FL | FR}, +- /* 2.1 */ +- { .ca_id = 0x01, .n_ch = 4, +- .mask = FL | FR | LFE}, +- /* Dolby Surround */ ++ .mask = FL | FR }, ++ { .ca_id = 0x03, .n_ch = 4, ++ .mask = FL | FR | LFE | FC }, + { .ca_id = 0x02, .n_ch = 4, + .mask = FL | FR | FC }, +- /* surround51 */ ++ { .ca_id = 0x01, .n_ch = 4, ++ .mask = FL | FR | LFE }, + { .ca_id = 0x0b, .n_ch = 6, +- .mask = FL | FR | LFE | FC | RL | RR}, +- /* surround40 */ +- { .ca_id = 0x08, .n_ch = 6, +- .mask = FL | FR | RL | RR }, +- /* surround41 */ +- { .ca_id = 0x09, .n_ch = 6, +- .mask = FL | FR | LFE | RL | RR }, +- /* surround50 */ ++ .mask = FL | FR | LFE | FC | RL | RR }, + { .ca_id = 0x0a, .n_ch = 6, + .mask = FL | FR | FC | RL | RR }, +- /* 6.1 */ +- { .ca_id = 0x0f, .n_ch = 8, +- .mask = FL | FR | LFE | FC | RL | RR | RC }, +- /* surround71 */ ++ { .ca_id = 0x09, .n_ch = 6, ++ .mask = FL | FR | LFE | RL | RR }, ++ { .ca_id = 0x08, .n_ch = 6, ++ .mask = FL | FR | RL | RR }, ++ { .ca_id = 0x07, .n_ch = 6, ++ .mask = FL | FR | LFE | FC | RC }, ++ { .ca_id = 0x06, .n_ch = 6, ++ .mask = FL | FR | FC | RC }, ++ { .ca_id = 0x05, .n_ch = 6, ++ .mask = FL | FR | LFE | RC }, ++ { .ca_id = 0x04, .n_ch = 6, ++ .mask = FL | FR | RC }, + { .ca_id = 0x13, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, +- /* others */ +- { .ca_id = 0x03, .n_ch = 8, +- .mask = FL | FR | LFE | FC }, +- { .ca_id = 0x04, .n_ch = 8, +- .mask = FL | FR | RC}, +- { .ca_id = 0x05, .n_ch = 8, +- .mask = FL | FR | LFE | RC }, +- { .ca_id = 0x06, .n_ch = 8, +- .mask = FL | FR | FC | RC }, +- { .ca_id = 0x07, .n_ch = 8, +- .mask = FL | FR | LFE | FC | RC }, +- { .ca_id = 0x0c, .n_ch = 8, +- .mask = FL | FR | RC | RL | RR }, +- { .ca_id = 0x0d, .n_ch = 8, +- .mask = FL | FR | LFE | RL | RR | RC }, +- { .ca_id = 0x0e, .n_ch = 8, +- .mask = FL | FR | FC | RL | RR | RC }, +- { .ca_id = 0x10, .n_ch = 8, +- .mask = FL | FR | RL | RR | RLC | RRC }, +- { .ca_id = 0x11, .n_ch = 8, +- .mask = FL | FR | LFE | RL | RR | RLC | RRC }, ++ { .ca_id = 0x1f, .n_ch = 8, ++ .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, + { .ca_id = 0x12, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RLC | RRC }, +- { .ca_id = 0x14, .n_ch = 8, +- .mask = FL | FR | FLC | FRC }, +- { .ca_id = 0x15, .n_ch = 8, +- .mask = FL | FR | LFE | FLC | FRC }, +- { .ca_id = 0x16, .n_ch = 8, +- .mask = FL | FR | FC | FLC | FRC }, +- { .ca_id = 0x17, .n_ch = 8, +- .mask = FL | FR | LFE | FC | FLC | FRC }, +- { .ca_id = 0x18, .n_ch = 8, +- .mask = FL | FR | RC | FLC | FRC }, +- { .ca_id = 0x19, .n_ch = 8, +- .mask = FL | FR | LFE | RC | FLC | FRC }, +- { .ca_id = 0x1a, .n_ch = 8, +- .mask = FL | FR | RC | FC | FLC | FRC }, +- { .ca_id = 0x1b, .n_ch = 8, +- .mask = FL | FR | LFE | RC | FC | FLC | FRC }, +- { .ca_id = 0x1c, .n_ch = 8, +- .mask = FL | FR | RL | RR | FLC | FRC }, +- { .ca_id = 0x1d, .n_ch = 8, +- .mask = FL | FR | LFE | RL | RR | FLC | FRC }, + { .ca_id = 0x1e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | FLC | FRC }, +- { .ca_id = 0x1f, .n_ch = 8, +- .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, ++ { .ca_id = 0x11, .n_ch = 8, ++ .mask = FL | FR | LFE | RL | RR | RLC | RRC }, ++ { .ca_id = 0x1d, .n_ch = 8, ++ .mask = FL | FR | LFE | RL | RR | FLC | FRC }, ++ { .ca_id = 0x10, .n_ch = 8, ++ .mask = FL | FR | RL | RR | RLC | RRC }, ++ { .ca_id = 0x1c, .n_ch = 8, ++ .mask = FL | FR | RL | RR | FLC | FRC }, ++ { .ca_id = 0x0f, .n_ch = 8, ++ .mask = FL | FR | LFE | FC | RL | RR | RC }, ++ { .ca_id = 0x1b, .n_ch = 8, ++ .mask = FL | FR | LFE | RC | FC | FLC | FRC }, ++ { .ca_id = 0x0e, .n_ch = 8, ++ .mask = FL | FR | FC | RL | RR | RC }, ++ { .ca_id = 0x1a, .n_ch = 8, ++ .mask = FL | FR | RC | FC | FLC | FRC }, ++ { .ca_id = 0x0d, .n_ch = 8, ++ .mask = FL | FR | LFE | RL | RR | RC }, ++ { .ca_id = 0x19, .n_ch = 8, ++ .mask = FL | FR | LFE | RC | FLC | FRC }, ++ { .ca_id = 0x0c, .n_ch = 8, ++ .mask = FL | FR | RC | RL | RR }, ++ { .ca_id = 0x18, .n_ch = 8, ++ .mask = FL | FR | RC | FLC | FRC }, ++ { .ca_id = 0x17, .n_ch = 8, ++ .mask = FL | FR | LFE | FC | FLC | FRC }, ++ { .ca_id = 0x16, .n_ch = 8, ++ .mask = FL | FR | FC | FLC | FRC }, ++ { .ca_id = 0x15, .n_ch = 8, ++ .mask = FL | FR | LFE | FLC | FRC }, ++ { .ca_id = 0x14, .n_ch = 8, ++ .mask = FL | FR | FLC | FRC }, + }; + + struct hdmi_codec_priv { +-- +2.7.4 + + +From 16b832719367b751845159338b64dd0f31d00fd2 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 10 Jul 2018 20:54:33 +0200 +Subject: [PATCH 10/15] drm: dw-hdmi-i2s: add multi-channel lpcm support + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h | 1 + + .../gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 73 +++++++++++++++++++++- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 1 + + drivers/gpu/drm/bridge/synopsys/dw-hdmi.h | 24 +++++++ + 4 files changed, 97 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +index 69b8a97..9e9cbf9 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-audio.h +@@ -18,6 +18,7 @@ struct dw_hdmi_i2s_audio_data { + + void (*write)(struct dw_hdmi *hdmi, u8 val, int offset); + u8 (*read)(struct dw_hdmi *hdmi, int offset); ++ void (*mod)(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg); + }; + + #endif +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 2eab862..4bc97ab 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -33,6 +33,14 @@ static inline u8 hdmi_read(struct dw_hdmi_i2s_audio_data *audio, int offset) + return audio->read(hdmi, offset); + } + ++static inline void hdmi_update_bits(struct dw_hdmi_i2s_audio_data *audio, ++ u8 data, u8 mask, unsigned int reg) ++{ ++ struct dw_hdmi *hdmi = audio->hdmi; ++ ++ audio->mod(hdmi, data, mask, reg); ++} ++ + static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *fmt, + struct hdmi_codec_params *hparms) +@@ -42,6 +50,7 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + u8 conf0 = 0; + u8 conf1 = 0; + u8 inputclkfs = 0; ++ u8 val; + + /* it cares I2S only */ + if (fmt->bit_clk_master | fmt->frame_clk_master) { +@@ -49,8 +58,23 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + return -EINVAL; + } + +- inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; +- conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; ++ inputclkfs = HDMI_AUD_INPUTCLKFS_64FS; ++ ++ switch (hparms->channels) { ++ case 2: ++ conf0 = HDMI_AUD_CONF0_I2S_2CHANNEL_ENABLE; ++ break; ++ case 4: ++ conf0 = HDMI_AUD_CONF0_I2S_4CHANNEL_ENABLE; ++ break; ++ case 6: ++ conf0 = HDMI_AUD_CONF0_I2S_6CHANNEL_ENABLE; ++ break; ++ case 8: ++ default: ++ conf0 = HDMI_AUD_CONF0_I2S_ALL_ENABLE; ++ break; ++ } + + switch (hparms->sample_width) { + case 16: +@@ -83,12 +107,56 @@ static int dw_hdmi_i2s_hw_params(struct device *dev, void *data, + return -EINVAL; + } + ++ hdmi_update_bits(audio, HDMI_AUD_CONF0_SW_RESET, ++ HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); ++ hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); ++ + dw_hdmi_set_sample_rate(hdmi, hparms->sample_rate); + + hdmi_write(audio, inputclkfs, HDMI_AUD_INPUTCLKFS); + hdmi_write(audio, conf0, HDMI_AUD_CONF0); + hdmi_write(audio, conf1, HDMI_AUD_CONF1); + ++ val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0; ++ if (hparms->channels > 2) ++ val = HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1; ++ hdmi_update_bits(audio, val, HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK, ++ HDMI_FC_AUDSCONF); ++ ++ switch (hparms->sample_rate) { ++ case 32000: ++ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_32K; ++ break; ++ case 44100: ++ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_441K; ++ break; ++ case 48000: ++ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_48K; ++ break; ++ case 88200: ++ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_882K; ++ break; ++ case 96000: ++ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_96K; ++ break; ++ case 176400: ++ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_1764K; ++ break; ++ case 192000: ++ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_192K; ++ break; ++ default: ++ val = HDMI_FC_AUDSCHNLS_SAMPFREQ_441K; ++ break; ++ } ++ ++ hdmi_update_bits(audio, val, HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK, ++ HDMI_FC_AUDSCHNLS7); ++ hdmi_update_bits(audio, ++ (hparms->channels - 1) << HDMI_FC_AUDICONF0_CC_OFFSET, ++ HDMI_FC_AUDICONF0_CC_MASK, HDMI_FC_AUDICONF0); ++ hdmi_write(audio, hparms->cea.channel_allocation, HDMI_FC_AUDICONF2); ++ + dw_hdmi_audio_enable(hdmi); + + return 0; +@@ -102,6 +170,7 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) + dw_hdmi_audio_disable(hdmi); + + hdmi_write(audio, HDMI_AUD_CONF0_SW_RESET, HDMI_AUD_CONF0); ++ hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); + } + + static void dw_hdmi_i2s_update_eld(struct device *dev, u8 *eld) +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 3a031d1..69ad730 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -2717,6 +2717,7 @@ __dw_hdmi_probe(struct platform_device *pdev, + audio.hdmi = hdmi; + audio.write = hdmi_writeb; + audio.read = hdmi_readb; ++ audio.mod = hdmi_modb; + hdmi->enable_audio = dw_hdmi_i2s_audio_enable; + hdmi->disable_audio = dw_hdmi_i2s_audio_disable; + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +index 6ff14dc..5c4cbd5 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.h +@@ -162,6 +162,15 @@ + #define HDMI_FC_SPDDEVICEINF 0x1062 + #define HDMI_FC_AUDSCONF 0x1063 + #define HDMI_FC_AUDSSTAT 0x1064 ++#define HDMI_FC_AUDSCHNLS0 0x1067 ++#define HDMI_FC_AUDSCHNLS1 0x1068 ++#define HDMI_FC_AUDSCHNLS2 0x1069 ++#define HDMI_FC_AUDSCHNLS3 0x106a ++#define HDMI_FC_AUDSCHNLS4 0x106b ++#define HDMI_FC_AUDSCHNLS5 0x106c ++#define HDMI_FC_AUDSCHNLS6 0x106d ++#define HDMI_FC_AUDSCHNLS7 0x106e ++#define HDMI_FC_AUDSCHNLS8 0x106f + #define HDMI_FC_DATACH0FILL 0x1070 + #define HDMI_FC_DATACH1FILL 0x1071 + #define HDMI_FC_DATACH2FILL 0x1072 +@@ -710,6 +719,8 @@ enum { + /* HDMI_FC_AUDSCHNLS7 field values */ + HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4, + HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30, ++ HDMI_FC_AUDSCHNLS7_SAMPFREQ_OFFSET = 0, ++ HDMI_FC_AUDSCHNLS7_SAMPFREQ_MASK = 0x0f, + + /* HDMI_FC_AUDSCHNLS8 field values */ + HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0, +@@ -717,6 +728,15 @@ enum { + HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f, + HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0, + ++/* HDMI_FC_AUDSCHNLS sampling frequency */ ++ HDMI_FC_AUDSCHNLS_SAMPFREQ_32K = 0x3, ++ HDMI_FC_AUDSCHNLS_SAMPFREQ_441K = 0x0, ++ HDMI_FC_AUDSCHNLS_SAMPFREQ_48K = 0x2, ++ HDMI_FC_AUDSCHNLS_SAMPFREQ_882K = 0x8, ++ HDMI_FC_AUDSCHNLS_SAMPFREQ_96K = 0xa, ++ HDMI_FC_AUDSCHNLS_SAMPFREQ_1764K = 0xc, ++ HDMI_FC_AUDSCHNLS_SAMPFREQ_192K = 0xe, ++ + /* FC_AUDSCONF field values */ + HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0, + HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4, +@@ -869,6 +889,9 @@ enum { + + /* AUD_CONF0 field values */ + HDMI_AUD_CONF0_SW_RESET = 0x80, ++ HDMI_AUD_CONF0_I2S_2CHANNEL_ENABLE = 0x21, ++ HDMI_AUD_CONF0_I2S_4CHANNEL_ENABLE = 0x23, ++ HDMI_AUD_CONF0_I2S_6CHANNEL_ENABLE = 0x27, + HDMI_AUD_CONF0_I2S_ALL_ENABLE = 0x2F, + + /* AUD_CONF1 field values */ +@@ -944,6 +967,7 @@ enum { + HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1, + + /* MC_SWRSTZ field values */ ++ HDMI_MC_SWRSTZ_I2SSWRST_REQ = 0x08, + HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02, + + /* MC_FLOWCTRL field values */ +-- +2.7.4 + + +From 0e4dfdd42b6b9c2efe9adc199177336bdf1593c7 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Mon, 9 Jul 2018 21:25:15 +0200 +Subject: [PATCH 11/15] drm: dw-hdmi: call hdmi_set_cts_n after clock is + enabled + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +index 69ad730..844fd4b 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +@@ -578,6 +578,11 @@ static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi, bool enable) + 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 void dw_hdmi_ahb_audio_enable(struct dw_hdmi *hdmi) +-- +2.7.4 + + +From 8b260e3406c683012df816bfd59766b1f365b804 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Sun, 23 Dec 2018 02:24:38 +0100 +Subject: [PATCH 12/15] fix chmap_idx + +--- + sound/soc/codecs/hdmi-codec.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c +index 4cacade..3b04f84 100644 +--- a/sound/soc/codecs/hdmi-codec.c ++++ b/sound/soc/codecs/hdmi-codec.c +@@ -370,7 +370,8 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = info->private_data; + +- map = info->chmap[hcp->chmap_idx].map; ++ if (hcp->chmap_idx != HDMI_CODEC_CHMAP_IDX_UNKNOWN) ++ map = info->chmap[hcp->chmap_idx].map; + + for (i = 0; i < info->max_channels; i++) { + if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN) +-- +2.7.4 + + +From 7039ea0f6f9fffbfe942903df3cb5bfa70ced5ed Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Wed, 2 Jan 2019 23:08:59 +0100 +Subject: [PATCH 13/15] media: cec-notifier: debounce callback setting invalid + phys addr + +--- + drivers/media/cec/cec-notifier.c | 19 ++++++++++++++++++- + 1 file changed, 18 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c +index 9598c77..1b665a9 100644 +--- a/drivers/media/cec/cec-notifier.c ++++ b/drivers/media/cec/cec-notifier.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -27,11 +28,23 @@ struct cec_notifier { + void (*callback)(struct cec_adapter *adap, u16 pa); + + u16 phys_addr; ++ struct delayed_work work; + }; + + static LIST_HEAD(cec_notifiers); + static DEFINE_MUTEX(cec_notifiers_lock); + ++static void cec_notifier_delayed_work(struct work_struct *work) ++{ ++ struct cec_notifier *n = ++ container_of(to_delayed_work(work), struct cec_notifier, work); ++ ++ mutex_lock(&n->lock); ++ if (n->callback) ++ n->callback(n->cec_adap, n->phys_addr); ++ mutex_unlock(&n->lock); ++} ++ + struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) + { + struct cec_notifier *n; +@@ -52,6 +65,7 @@ struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) + if (conn) + n->conn = kstrdup(conn, GFP_KERNEL); + n->phys_addr = CEC_PHYS_ADDR_INVALID; ++ INIT_DELAYED_WORK(&n->work, cec_notifier_delayed_work); + mutex_init(&n->lock); + kref_init(&n->kref); + list_add_tail(&n->head, &cec_notifiers); +@@ -84,9 +98,12 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) + if (n == NULL) + return; + ++ cancel_delayed_work_sync(&n->work); + mutex_lock(&n->lock); + n->phys_addr = pa; +- if (n->callback) ++ if (pa == CEC_PHYS_ADDR_INVALID) ++ schedule_delayed_work(&n->work, msecs_to_jiffies(5000)); ++ else if (n->callback) + n->callback(n->cec_adap, n->phys_addr); + mutex_unlock(&n->lock); + } +-- +2.7.4 + + +From e9001fa0bf51038a9cbdf69cca5453cdb09b1aa4 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Tue, 26 Feb 2019 20:45:14 +0000 +Subject: [PATCH 14/15] WIP: dw-hdmi-cec: sleep 100ms on error + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 18 ++++++++++++++++-- + 1 file changed, 16 insertions(+), 2 deletions(-) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +index 6c32351..b5a1a85 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c +@@ -7,6 +7,7 @@ + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ ++#include + #include + #include + #include +@@ -132,8 +133,15 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + + dw_hdmi_write(cec, stat, HDMI_IH_CEC_STAT0); + +- if (stat & CEC_STAT_ERROR_INIT) { +- cec->tx_status = CEC_TX_STATUS_ERROR; ++ /* Status with both done and error_initiator bits have been seen ++ * on Rockchip RK3328 devices, transmit attempt seems to have failed ++ * when this happens, report as low drive and block cec-framework ++ * 100ms before core retransmits the failed message, this seems to ++ * mitigate the issue with failed transmit attempts. ++ */ ++ if ((stat & (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) == (CEC_STAT_DONE|CEC_STAT_ERROR_INIT)) { ++ pr_info("dw_hdmi_cec_hardirq: stat=%02x LOW_DRIVE\n", stat); ++ cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; + } else if (stat & CEC_STAT_DONE) { +@@ -144,6 +152,10 @@ static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data) + cec->tx_status = CEC_TX_STATUS_NACK; + cec->tx_done = true; + ret = IRQ_WAKE_THREAD; ++ } else if (stat & CEC_STAT_ERROR_INIT) { ++ cec->tx_status = CEC_TX_STATUS_ERROR; ++ cec->tx_done = true; ++ ret = IRQ_WAKE_THREAD; + } + + if (stat & CEC_STAT_EOM) { +@@ -176,6 +188,8 @@ static irqreturn_t dw_hdmi_cec_thread(int irq, void *data) + + if (cec->tx_done) { + cec->tx_done = false; ++ if (cec->tx_status == CEC_TX_STATUS_LOW_DRIVE) ++ msleep(100); + cec_transmit_attempt_done(adap, cec->tx_status); + } + if (cec->rx_done) { +-- +2.7.4 + + +From 3f12c4a5852b51439fcea2bb6f0d4e2ae5e7f863 Mon Sep 17 00:00:00 2001 +From: Jonas Karlman +Date: Fri, 3 May 2019 01:34:16 +0000 +Subject: [PATCH 15/15] drm: dw-hdmi-i2s: add .digital_mute callback for ALSA + SoC + +--- + drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +index 4bc97ab..c526860 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c +@@ -173,6 +173,17 @@ static void dw_hdmi_i2s_audio_shutdown(struct device *dev, void *data) + hdmi_write(audio, (u8)~HDMI_MC_SWRSTZ_I2SSWRST_REQ, HDMI_MC_SWRSTZ); + } + ++static int dw_hdmi_i2s_digital_mute(struct device *dev, void *data, bool enable) ++{ ++ struct dw_hdmi_i2s_audio_data *audio = data; ++ ++ hdmi_update_bits(audio, enable ? 0 : 0xf, ++ HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK, ++ HDMI_FC_AUDSCONF); ++ ++ return 0; ++} ++ + static void dw_hdmi_i2s_update_eld(struct device *dev, u8 *eld) + { + struct dw_hdmi_i2s_audio_data *audio = dev_get_platdata(dev); +@@ -222,6 +233,7 @@ static int dw_hdmi_i2s_get_dai_id(struct snd_soc_component *component, + static struct hdmi_codec_ops dw_hdmi_i2s_ops = { + .hw_params = dw_hdmi_i2s_hw_params, + .audio_shutdown = dw_hdmi_i2s_audio_shutdown, ++ .digital_mute = dw_hdmi_i2s_digital_mute, + .get_eld = dw_hdmi_i2s_get_eld, + .get_dai_id = dw_hdmi_i2s_get_dai_id, + }; +-- +2.7.4 + diff --git a/projects/Amlogic/patches/linux/e-0001-HACK-set-cma-pool-to-896MB.patch b/projects/Amlogic/patches/linux/e-0001-HACK-set-cma-pool-to-896MB.patch new file mode 100644 index 0000000000..dd67db81fb --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0001-HACK-set-cma-pool-to-896MB.patch @@ -0,0 +1,28 @@ +From 78a5fa8623ffbc3a4f661d42aaea172c7d80cc9d Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 05:41:51 +0000 +Subject: [PATCH 01/37] HACK: set cma pool to 896MB + +This change sets the CMA pool to a larger 896MB! value for (WIP) vdec use + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index 8238f55666e7..46cb715de241 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -44,7 +44,7 @@ + linux,cma { + compatible = "shared-dma-pool"; + reusable; +- size = <0x0 0x10000000>; ++ size = <0x0 0x38000000>; + alignment = <0x0 0x400000>; + linux,cma-default; + }; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0002-HACK-fix-Kodi-sysinfo-CPU-information.patch b/projects/Amlogic/patches/linux/e-0002-HACK-fix-Kodi-sysinfo-CPU-information.patch new file mode 100644 index 0000000000..e8d0ecf237 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0002-HACK-fix-Kodi-sysinfo-CPU-information.patch @@ -0,0 +1,31 @@ +From 42a2fa4e82892cb9089b6870f41dc84c595f8df4 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 05:45:18 +0000 +Subject: [PATCH 02/37] HACK: fix Kodi sysinfo CPU information + +This allows the CPU information to show in the Kodi sysinfo screen, e.g. + +"ARMv8 Processor rev 4 (v81)" on S905* devices + +Signed-off-by: Christian Hewitt +--- + arch/arm64/kernel/cpuinfo.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c +index ca0685f33900..e1a26a315733 100644 +--- a/arch/arm64/kernel/cpuinfo.c ++++ b/arch/arm64/kernel/cpuinfo.c +@@ -140,8 +140,7 @@ static int c_show(struct seq_file *m, void *v) + * "processor". Give glibc what it expects. + */ + seq_printf(m, "processor\t: %d\n", i); +- if (compat) +- seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", ++ seq_printf(m, "model name\t: ARMv8 Processor rev %d (%s)\n", + MIDR_REVISION(midr), COMPAT_ELF_PLATFORM); + + seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0004-HACK-silence-meson-ir-warn-once-log-spam.patch b/projects/Amlogic/patches/linux/e-0004-HACK-silence-meson-ir-warn-once-log-spam.patch new file mode 100644 index 0000000000..fc21061876 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0004-HACK-silence-meson-ir-warn-once-log-spam.patch @@ -0,0 +1,29 @@ +From 2585e9b6e91d529c2ac27133f1219761726a643c Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 06:27:33 +0000 +Subject: [PATCH 04/37] HACK: silence meson-ir warn once log spam + +This silences another warning message that spams the system log. + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/meson-ir.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c +index 9914c83fecb9..ba2f3fb92889 100644 +--- a/drivers/media/rc/meson-ir.c ++++ b/drivers/media/rc/meson-ir.c +@@ -97,7 +97,8 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id) + status = readl_relaxed(ir->reg + IR_DEC_STATUS); + rawir.pulse = !!(status & STATUS_IR_DEC_IN); + +- ir_raw_event_store_with_timeout(ir->rc, &rawir); ++ if (ir_raw_event_store_with_filter(ir->rc, &rawir)) ++ ir_raw_event_handle(ir->rc); + + spin_unlock(&ir->lock); + +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0005-HACK-silence-hrtimer-log-spam.patch b/projects/Amlogic/patches/linux/e-0005-HACK-silence-hrtimer-log-spam.patch new file mode 100644 index 0000000000..60c01a3fa1 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0005-HACK-silence-hrtimer-log-spam.patch @@ -0,0 +1,28 @@ +From 48b392bb606eb916a0a2fc0a3d318c4bde92bd2b Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 06:35:17 +0000 +Subject: [PATCH 05/37] HACK: silence hrtimer log spam + +This silences another annoying system log message + +Signed-off-by: Christian Hewitt +--- + kernel/time/hrtimer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c +index 41dfff23c1f9..bb6d137388ca 100644 +--- a/kernel/time/hrtimer.c ++++ b/kernel/time/hrtimer.c +@@ -905,7 +905,7 @@ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) + if (delta < 0) + return 0; + +- if (WARN_ON(timer->state & HRTIMER_STATE_ENQUEUED)) ++ if (timer->state & HRTIMER_STATE_ENQUEUED) + return 0; + + if (interval < hrtimer_resolution) +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0006-HACK-Bluetooth-Fix-spurious-error-message.patch b/projects/Amlogic/patches/linux/e-0006-HACK-Bluetooth-Fix-spurious-error-message.patch new file mode 100644 index 0000000000..e7dd9cd3fe --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0006-HACK-Bluetooth-Fix-spurious-error-message.patch @@ -0,0 +1,37 @@ +From e0f59e98b6603924e5b44a276a6939b7893c86e1 Mon Sep 17 00:00:00 2001 +From: Szymon Janc +Date: Thu, 29 Mar 2018 11:41:17 +0200 +Subject: [PATCH 06/37] HACK: Bluetooth: Fix spurious error message + +This message was debug message before 2064ee332e4c1b7495cf68b. Looks +like it was changed by accident in that patch. This is causing some +error messages when doing BR/EDR discovery since Inquiry Command +generates Command Status event, not Command Complete. + +I'm sending this as RFC for now since while things seem to work fine +despite this condition (and it was like that for quite some time) it +feels like this is indeed case that should be handled by HCI request +code. + +Signed-off-by: Szymon Janc +--- + net/bluetooth/hci_event.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index 609fd6871c5a..3cac7023aa95 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -5718,8 +5718,7 @@ static bool hci_get_cmd_complete(struct hci_dev *hdev, u16 opcode, + return false; + + if (hdr->evt != HCI_EV_CMD_COMPLETE) { +- bt_dev_err(hdev, "last event is not cmd complete (0x%2.2x)", +- hdr->evt); ++ BT_DBG("last event is not cmd complete (0x%2.2x)", hdr->evt); + return false; + } + +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0011-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-many-.patch b/projects/Amlogic/patches/linux/e-0011-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-many-.patch new file mode 100644 index 0000000000..0897ef34d9 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0011-arm64-dts-meson-gxbb-vega-s95-update-dtsi-with-many-.patch @@ -0,0 +1,255 @@ +From d724c862a105e5921abf71275d1e250bb4331a3d Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 06:18:39 +0000 +Subject: [PATCH 11/37] arm64: dts: meson-gxbb-vega-s95: update dtsi with many + changes + +Signed-off-by: Christian Hewitt +--- + .../boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 133 ++++++++++++++++-- + 1 file changed, 119 insertions(+), 14 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +index d8c262b9be01..58aaa196d576 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +@@ -4,12 +4,15 @@ + */ + + #include "meson-gxbb.dtsi" ++#include ++#include + + / { + compatible = "tronsmart,vega-s95", "amlogic,meson-gxbb"; + + aliases { + serial0 = &uart_AO; ++ serial1 = &uart_A; + ethernet0 = ðmac; + }; + +@@ -28,10 +31,10 @@ + }; + }; + +- usb_vbus: regulator-usb0-vbus { ++ usb_pwr: regulator-usb-pwrs { + compatible = "regulator-fixed"; + +- regulator-name = "USB0_VBUS"; ++ regulator-name = "USB_PWR"; + + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; +@@ -40,20 +43,34 @@ + enable-active-high; + }; + +- vcc_3v3: regulator-vcc_3v3 { ++ vddio_boot: regulator-vddio_boot { + compatible = "regulator-fixed"; +- regulator-name = "VCC_3V3"; ++ regulator-name = "VDDIO_BOOT"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ ++ vddao_3v3: regulator-vddao_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDAO_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + +- vcc_1v8: regulator-vcc_1v8 { ++ vddio_ao18: regulator-vddio_ao18 { + compatible = "regulator-fixed"; +- regulator-name = "VCC_1V8"; ++ regulator-name = "VDDIO_AO18"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ }; ++ + emmc_pwrseq: emmc-pwrseq { + compatible = "mmc-pwrseq-emmc"; + reset-gpios = <&gpio BOOT_9 GPIO_ACTIVE_LOW>; +@@ -66,15 +83,69 @@ + pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ + }; + ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ ++ sound { ++ compatible = "simple-audio-card"; ++ simple-audio-card,name = "HDMI"; ++ ++ assigned-clocks = <&clkc CLKID_MPLL2>, ++ <&clkc CLKID_MPLL0>, ++ <&clkc CLKID_MPLL1>; ++ assigned-clock-parents = <0>, <0>, <0>; ++ assigned-clock-rates = <294912000>, ++ <270950400>, ++ <393216000>; ++ ++ simple-audio-card,dai-link@0 { ++ /* HDMI Output */ ++ format = "i2s"; ++ mclk-fs = <128>; ++ bitclock-master = <&aiu_i2s>; ++ frame-master = <&aiu_i2s>; ++ ++ cpu { ++ sound-dai = <&aiu_i2s>; ++ }; ++ ++ codec { ++ sound-dai = <&hdmi_tx>; ++ }; ++ }; ++ }; ++ + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; +- reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>, +- <&gpio GPIOX_20 GPIO_ACTIVE_LOW>; ++ reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>; + clocks = <&wifi32k>; + clock-names = "ext_clock"; + }; + }; + ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ ++&cec_AO { ++ status = "okay"; ++ pinctrl-0 = <&ao_cec_pins>; ++ pinctrl-names = "default"; ++ hdmi-phandle = <&hdmi_tx>; ++}; ++ + ðmac { + status = "okay"; + pinctrl-0 = <ð_rgmii_pins>; +@@ -97,10 +168,25 @@ + eth_phy0: ethernet-phy@0 { + /* Realtek RTL8211F (0x001cc916) */ + reg = <0>; ++ interrupt-parent = <&gpio_intc>; ++ /* MAC_INTR on GPIOZ_15 */ ++ interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + }; + }; + }; + ++&hdmi_tx { ++ status = "okay"; ++ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&hdmi_tx_tmds_port { ++ hdmi_tx_tmds_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++}; ++ + &ir { + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; +@@ -115,10 +201,15 @@ + clock-names = "clkin0"; + }; + ++&saradc { ++ status = "okay"; ++ vref-supply = <&vddio_ao18>; ++}; ++ + /* Wireless SDIO Module */ + &sd_emmc_a { + status = "okay"; +- pinctrl-0 = <&sdio_pins &sdio_irq_pins>; ++ pinctrl-0 = <&sdio_pins>; + pinctrl-1 = <&sdio_clk_gate_pins>; + pinctrl-names = "default", "clk-gate"; + #address-cells = <1>; +@@ -133,8 +224,8 @@ + + mmc-pwrseq = <&sdio_pwrseq>; + +- vmmc-supply = <&vcc_3v3>; +- vqmmc-supply = <&vcc_1v8>; ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddio_boot>; + + brcmf: wifi@1 { + reg = <1>; +@@ -156,7 +247,8 @@ + + cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>; + +- vmmc-supply = <&vcc_3v3>; ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vcc_3v3>; + }; + + /* eMMC */ +@@ -176,9 +268,22 @@ + + mmc-pwrseq = <&emmc_pwrseq>; + vmmc-supply = <&vcc_3v3>; +- vmmcq-sumpply = <&vcc_1v8>; ++ vqmmc-supply = <&vddio_boot>; ++}; ++ ++/* This is connected to the Bluetooth module: */ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_20 GPIO_ACTIVE_HIGH>; ++ }; + }; + ++/* This UART is brought out to the DB9 connector */ + &uart_AO { + status = "okay"; + pinctrl-0 = <&uart_ao_a_pins>; +@@ -187,7 +292,7 @@ + + &usb0_phy { + status = "okay"; +- phy-supply = <&usb_vbus>; ++ phy-supply = <&usb_pwr>; + }; + + &usb1_phy { +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0012-arm64-dts-meson-gxbb-wetek.dtsi-enable-bluetooth.patch b/projects/Amlogic/patches/linux/e-0012-arm64-dts-meson-gxbb-wetek.dtsi-enable-bluetooth.patch new file mode 100644 index 0000000000..2e947837f3 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0012-arm64-dts-meson-gxbb-wetek.dtsi-enable-bluetooth.patch @@ -0,0 +1,50 @@ +From ecffab2a2ca4471b37d984bda5c356ed811c46c1 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 06:50:48 +0000 +Subject: [PATCH 12/37] arm64: dts: meson-gxbb-wetek.dtsi: enable bluetooth + +This enables Bluetooth support for the following models: + +AP6335 in the WeTek Hub rev1 - BCM4335C0.hcd +AP6255 in the WeTek Hub rev2 - BCM4345C0.hcd +AP6330 in the WeTek Play 2 - BCM4330B1.hcd (TBC) + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +index ff9b182afac7..5cdca2eed7d9 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +@@ -10,6 +10,7 @@ + / { + aliases { + serial0 = &uart_AO; ++ serial1 = &uart_A; + ethernet0 = ðmac; + }; + +@@ -274,6 +275,18 @@ + vqmmc-supply = <&vddio_boot>; + }; + ++/* This is connected to the Bluetooth module: */ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_20 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ + /* This UART is brought out to the DB9 connector */ + &uart_AO { + status = "okay"; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0013-arm64-dts-meson-gxbb-wetek.dtsi-enable-saradc-node.patch b/projects/Amlogic/patches/linux/e-0013-arm64-dts-meson-gxbb-wetek.dtsi-enable-saradc-node.patch new file mode 100644 index 0000000000..736dfb27d8 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0013-arm64-dts-meson-gxbb-wetek.dtsi-enable-saradc-node.patch @@ -0,0 +1,43 @@ +From 17bb4637c8f9a78cab585b9f0d55960784fb90ed Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 06:58:59 +0000 +Subject: [PATCH 13/37] arm64: dts: meson-gxbb-wetek.dtsi: enable saradc node + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +index 5cdca2eed7d9..e7d27daa1357 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek.dtsi +@@ -60,6 +60,13 @@ + regulator-max-microvolt = <3300000>; + }; + ++ vddio_ao18: regulator-vddio_ao18 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VDDIO_AO18"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ + vcc_3v3: regulator-vcc_3v3 { + compatible = "regulator-fixed"; + regulator-name = "VCC_3V3"; +@@ -210,6 +217,11 @@ + clock-names = "clkin0"; + }; + ++&saradc { ++ status = "okay"; ++ vref-supply = <&vddio_ao18>; ++}; ++ + /* Wireless SDIO Module */ + &sd_emmc_a { + status = "okay"; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0015-arm64-dts-meson-gxbb-odroid-set-blue-led-to-on.patch b/projects/Amlogic/patches/linux/e-0015-arm64-dts-meson-gxbb-odroid-set-blue-led-to-on.patch new file mode 100644 index 0000000000..1dac753e78 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0015-arm64-dts-meson-gxbb-odroid-set-blue-led-to-on.patch @@ -0,0 +1,30 @@ +From eff5b2f4af16279259e7dbb2b61b915f5dc1f519 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Wed, 24 Apr 2019 03:40:16 +0000 +Subject: [PATCH 15/37] arm64: dts: meson-gxbb-odroid: set blue led to on + +The constantly flashing blue LED heartbeat is annoying for an HTPC device +so remove the heartbeat and simply default to on. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +index 80a7d47160e9..88816c20800f 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +@@ -45,8 +45,7 @@ + blue { + label = "c2:blue:alive"; + gpios = <&gpio_ao GPIOAO_13 GPIO_ACTIVE_LOW>; +- linux,default-trigger = "heartbeat"; +- default-state = "off"; ++ default-state = "on"; + }; + }; + +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0016-arm64-dts-meson-gxbb-odroid-set-rc-odroid-ir-keymap.patch b/projects/Amlogic/patches/linux/e-0016-arm64-dts-meson-gxbb-odroid-set-rc-odroid-ir-keymap.patch new file mode 100644 index 0000000000..3822b4b823 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0016-arm64-dts-meson-gxbb-odroid-set-rc-odroid-ir-keymap.patch @@ -0,0 +1,25 @@ +From dd2f7889db3a060d67849344d33ed0693fdd3aef Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Wed, 24 Apr 2019 03:26:16 +0000 +Subject: [PATCH 16/37] arm64: dts: meson-gxbb-odroid: set rc-odroid ir keymap + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +index 88816c20800f..723cd5a114aa 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-odroidc2.dts +@@ -220,6 +220,7 @@ + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; ++ linux,rc-map-name = "rc-odroid"; + }; + + &gpio_ao { +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0017-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir-key.patch b/projects/Amlogic/patches/linux/e-0017-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir-key.patch new file mode 100644 index 0000000000..8428bac6a8 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0017-arm64-dts-meson-gxbb-vega-s95-set-rc-vega-s95-ir-key.patch @@ -0,0 +1,26 @@ +From 761f9019c724644a2b41f7860182429f96eecdae Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 26 Apr 2019 08:43:58 +0000 +Subject: [PATCH 17/37] arm64: dts: meson-gxbb-vega-s95: set rc-vega-s95 ir + keymap + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +index 58aaa196d576..795a1e78873d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-vega-s95.dtsi +@@ -191,6 +191,7 @@ + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; ++ linux,rc-map-name = "rc-vega-s95"; + }; + + &pwm_ef { +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0018-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-hub-ir-k.patch b/projects/Amlogic/patches/linux/e-0018-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-hub-ir-k.patch new file mode 100644 index 0000000000..af81dc26ff --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0018-arm64-dts-meson-gxbb-wetek-hub-set-rc-wetek-hub-ir-k.patch @@ -0,0 +1,26 @@ +From 7d2742b632882567076501490110d92d7fad8d4e Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 15 Apr 2019 04:40:25 +0000 +Subject: [PATCH 18/37] arm64: dts: meson-gxbb-wetek-hub: set rc-wetek-hub ir + keymap + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts +index 2bfe69902552..83b985bb015e 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-hub.dts +@@ -12,3 +12,7 @@ + compatible = "wetek,hub", "amlogic,meson-gxbb"; + model = "WeTek Hub"; + }; ++ ++&ir { ++ linux,rc-map-name = "rc-wetek-hub"; ++}; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0019-arm64-dts-meson-gxbb-wetek-play2-set-rc-wetek-play2-.patch b/projects/Amlogic/patches/linux/e-0019-arm64-dts-meson-gxbb-wetek-play2-set-rc-wetek-play2-.patch new file mode 100644 index 0000000000..7d41422151 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0019-arm64-dts-meson-gxbb-wetek-play2-set-rc-wetek-play2-.patch @@ -0,0 +1,26 @@ +From 7b15154d606081d14c64d84b61840d695fbba75c Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 21 Apr 2019 02:27:40 +0000 +Subject: [PATCH 19/37] arm64: dts: meson-gxbb-wetek-play2: set rc-wetek-play2 + ir keymap + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts +index 0038522315de..1d32d1f6d032 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-wetek-play2.dts +@@ -54,3 +54,7 @@ + &usb1 { + status = "okay"; + }; ++ ++&ir { ++ linux,rc-map-name = "rc-wetek-play2"; ++}; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0020-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-khadas-r.patch b/projects/Amlogic/patches/linux/e-0020-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-khadas-r.patch new file mode 100644 index 0000000000..2dfaf202e6 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0020-arm64-dts-meson-gxl-s905x-khadas-vim-use-rc-khadas-r.patch @@ -0,0 +1,34 @@ +From 133ba868862509bcd50dfd2ebaf942552e0399b1 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 29 Apr 2019 03:37:28 +0000 +Subject: [PATCH 20/37] arm64: dts: meson-gxl-s905x-khadas-vim: use rc-khadas + remote not rc-geekbox + +Khadas shipped the first batch of VIM devices with the 'geekbox' remote from +another of their brands. All further shipments have used a 'khadas' branded +remote that provides an Android mouse function instead of KEY_SCREEN. As the +IR keycode for the geekbox screen button is different to the khadas mouse +button KEY_SCREEN doesn't work on the Khadas remote, so swap to the rc-khadas +keymap to gain an extra button mapped to KEY_MUTE. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +index b2493e9dfd08..5d87649aedf1 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +@@ -147,7 +147,7 @@ + }; + + &ir { +- linux,rc-map-name = "rc-geekbox"; ++ linux,rc-map-name = "rc-khadas"; + }; + + &gpio_ao { +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0021-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address-siz.patch b/projects/Amlogic/patches/linux/e-0021-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address-siz.patch new file mode 100644 index 0000000000..53c1365d34 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0021-arm64-dts-meson-gxl-s905x-khadas-vim-fix-address-siz.patch @@ -0,0 +1,33 @@ +From 9f1e034f25ee294bee0a636f0b0ecd571fc40d17 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Tue, 16 Apr 2019 13:06:08 +0000 +Subject: [PATCH 21/37] arm64: dts: meson-gxl-s905x-khadas-vim: fix + address/size cells dtc warnings + +Fix DTC warnings: + +arch/arm/dts/meson-gxl-s905x-khadas-vim.dtb: Warning (avoid_unnecessary_addr_size): + /gpio-keys-polled: unnecessary #address-cells/#size-cells + without "ranges" or child "reg" property + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +index 5d87649aedf1..fccea95297e2 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-khadas-vim.dts +@@ -33,8 +33,6 @@ + + gpio-keys-polled { + compatible = "gpio-keys-polled"; +- #address-cells = <1>; +- #size-cells = <0>; + poll-interval = <100>; + + button@0 { +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0022-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx3mini-ir.patch b/projects/Amlogic/patches/linux/e-0022-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx3mini-ir.patch new file mode 100644 index 0000000000..d07df00904 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0022-arm64-dts-meson-gxl-s905w-tx3-mini-set-rc-tx3mini-ir.patch @@ -0,0 +1,26 @@ +From 58677981f9e080fb42f329273e94a7e0c5d2b09b Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 15 Apr 2019 02:58:24 +0000 +Subject: [PATCH 22/37] arm64: dts: meson-gxl-s905w-tx3-mini: set rc-tx3mini ir + keymap + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts +index 789c819c99c4..dd729ac2300d 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905w-tx3-mini.dts +@@ -20,3 +20,7 @@ + reg = <0x0 0x0 0x0 0x40000000>; /* 1 GiB or 2 GiB */ + }; + }; ++ ++&ir { ++ linux,rc-map-name = "rc-tanix-tx3mini"; ++}; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0023-arm64-dts-meson-gxm-khadas-vim2-set-eee-broken-1000t.patch b/projects/Amlogic/patches/linux/e-0023-arm64-dts-meson-gxm-khadas-vim2-set-eee-broken-1000t.patch new file mode 100644 index 0000000000..bcb2dc5526 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0023-arm64-dts-meson-gxm-khadas-vim2-set-eee-broken-1000t.patch @@ -0,0 +1,25 @@ +From 05a9bf407fae671f1994d2a4504c23093b769f9f Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 13 Apr 2019 08:27:53 +0000 +Subject: [PATCH 23/37] arm64: dts: meson-gxm-khadas-vim2: set eee-broken-1000t + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +index b2dad05b89fe..dc6e33636082 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +@@ -297,6 +297,7 @@ + interrupt-parent = <&gpio_intc>; + /* MAC_INTR on GPIOZ_15 */ + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; ++ eee-broken-1000t; + }; + }; + +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0024-arm64-dts-meson-gxm-khadas-vim2-fix-address-size-cel.patch b/projects/Amlogic/patches/linux/e-0024-arm64-dts-meson-gxm-khadas-vim2-fix-address-size-cel.patch new file mode 100644 index 0000000000..80c60e170c --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0024-arm64-dts-meson-gxm-khadas-vim2-fix-address-size-cel.patch @@ -0,0 +1,33 @@ +From 688f83acbd11367a6ced2894329c462ee5a9caa6 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Tue, 16 Apr 2019 13:15:32 +0000 +Subject: [PATCH 24/37] arm64: dts: meson-gxm-khadas-vim2: fix address/size + cells dtc warnings + +Fix DTC warnings: + +arch/arm/dts/meson-gxm-khadas-vim2.dtb: Warning (avoid_unnecessary_addr_size): + /gpio-keys-polled: unnecessary #address-cells/#size-cells + without "ranges" or child "reg" property + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +index dc6e33636082..79981bf85678 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +@@ -63,8 +63,6 @@ + + gpio-keys-polled { + compatible = "gpio-keys-polled"; +- #address-cells = <1>; +- #size-cells = <0>; + poll-interval = <100>; + + button@0 { +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0025-arm64-dts-meson-gxm-khadas-vim2-set-bt-compatible.patch b/projects/Amlogic/patches/linux/e-0025-arm64-dts-meson-gxm-khadas-vim2-set-bt-compatible.patch new file mode 100644 index 0000000000..40e6ee43da --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0025-arm64-dts-meson-gxm-khadas-vim2-set-bt-compatible.patch @@ -0,0 +1,33 @@ +From 10508df1fa03e4a4f3e46d3b3d3dcc2d29e15281 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Wed, 24 Apr 2019 13:58:32 +0000 +Subject: [PATCH 25/37] arm64: dts: meson-gxm-khadas-vim2: set bt compatible + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +index 79981bf85678..a4ab5615a603 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-khadas-vim2.dts +@@ -440,8 +440,14 @@ + /* This one is connected to the Bluetooth module */ + &uart_A { + status = "okay"; +- pinctrl-0 = <&uart_a_pins>; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; + pinctrl-names = "default"; ++ uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ }; + }; + + /* This is brought out on the Linux_RX (18) and Linux_TX (19) pins: */ +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0026-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-keym.patch b/projects/Amlogic/patches/linux/e-0026-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-keym.patch new file mode 100644 index 0000000000..f1928f56ca --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0026-arm64-dts-meson-gxm-vega-s96-set-rc-vega-s95-ir-keym.patch @@ -0,0 +1,31 @@ +From ee8c2d72348e6e882775bafb7e1e2a6c6bcdd0ad Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 26 Apr 2019 08:47:22 +0000 +Subject: [PATCH 26/37] arm64: dts: meson-gxm-vega-s96: set rc-vega-s95 ir + keymap + +S96 uses the same remote as the S95 series devices. + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-gxm-vega-s96.dts | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-vega-s96.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-vega-s96.dts +index e2ea6753263b..c25fd80b14bf 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gxm-vega-s96.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-gxm-vega-s96.dts +@@ -35,3 +35,10 @@ + reg = <0>; + }; + }; ++ ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++ linux,rc-map-name = "rc-vega-s95"; ++}; +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0027-media-rc-add-keymap-for-HardKernel-ODROID-remote.patch b/projects/Amlogic/patches/linux/e-0027-media-rc-add-keymap-for-HardKernel-ODROID-remote.patch new file mode 100644 index 0000000000..ea18c5367b --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0027-media-rc-add-keymap-for-HardKernel-ODROID-remote.patch @@ -0,0 +1,100 @@ +From 529ed7f6209726674fa4a17de1ce30e958bc720d Mon Sep 17 00:00:00 2001 +From: Christian Hewitt +Date: Mon, 1 Apr 2019 04:22:30 +0400 +Subject: [PATCH 27/37] media: rc: add keymap for HardKernel ODROID remote + +This is a simple NEC remote controll device shipped with the HardKernel +ODROID range of ARM Single Board Computer (SBC) devices. + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-odroid.c | 51 ++++++++++++++++++++++++++++ + include/media/rc-map.h | 1 + + 3 files changed, 53 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-odroid.c + +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index 5b1399af6b3a..03fbac32befb 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -75,6 +75,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-nec-terratec-cinergy-xs.o \ + rc-norwood.o \ + rc-npgtech.o \ ++ rc-odroid.o \ + rc-pctv-sedna.o \ + rc-pinnacle-color.o \ + rc-pinnacle-grey.o \ +diff --git a/drivers/media/rc/keymaps/rc-odroid.c b/drivers/media/rc/keymaps/rc-odroid.c +new file mode 100644 +index 000000000000..e95aab608c5a +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-odroid.c +@@ -0,0 +1,51 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// ++// Copyright (C) 2019 Christian Hewitt ++ ++#include ++#include ++ ++// ++// Keytable for the HardKernel ODROID remote controller ++// ++ ++static struct rc_map_table odroid[] = { ++ ++ { 0xb2dc, KEY_POWER }, ++ { 0xb288, KEY_MUTE }, ++ { 0xb282, KEY_HOME }, ++ { 0xb2ca, KEY_UP }, ++ { 0xb299, KEY_LEFT }, ++ { 0xb2ce, KEY_OK }, ++ { 0xb2c1, KEY_RIGHT }, ++ { 0xb2d2, KEY_DOWN }, ++ { 0xb2c5, KEY_MENU }, ++ { 0xb29a, KEY_BACK }, ++ { 0xb281, KEY_VOLUMEDOWN }, ++ { 0xb280, KEY_VOLUMEUP }, ++}; ++ ++static struct rc_map_list odroid_map = { ++ .map = { ++ .scan = odroid, ++ .size = ARRAY_SIZE(odroid), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_ODROID, ++ } ++}; ++ ++static int __init init_rc_map_odroid(void) ++{ ++ return rc_map_register(&odroid_map); ++} ++ ++static void __exit exit_rc_map_odroid(void) ++{ ++ rc_map_unregister(&odroid_map); ++} ++ ++module_init(init_rc_map_odroid) ++module_exit(exit_rc_map_odroid) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt +Date: Mon, 29 Apr 2019 03:23:38 +0000 +Subject: [PATCH 28/37] media: rc: add keymap for Khadas VIM/EDGE remote + +This is a simple NEC remote control device shipped with the Khadas VIM +and EDGE range of ARM Single Board Computer (SBC) devices. It includes +a mouse button for Android use which is mapped to KEY_MUTE. This is the +sole difference from the Khadas 'geekbox' remote which shipped with an +earlier generation of Shenzen Wesion (Khadas) devices under the GeekBox +brand. + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/Makefile | 2 + + drivers/media/rc/keymaps/rc-khadas.c | 56 ++++++++++++++++++++++++++++ + include/media/rc-map.h | 2 + + 3 files changed, 60 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-khadas.c + +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index 03fbac32befb..7cd930b43e9b 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -58,6 +58,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-it913x-v1.o \ + rc-it913x-v2.o \ + rc-kaiomy.o \ ++ rc-khadas.o \ ++ rc-khamsin.o \ + rc-kworld-315u.o \ + rc-kworld-pc150u.o \ + rc-kworld-plus-tv-analog.o \ +diff --git a/drivers/media/rc/keymaps/rc-khadas.c b/drivers/media/rc/keymaps/rc-khadas.c +new file mode 100644 +index 000000000000..bb183ed90d69 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-khadas.c +@@ -0,0 +1,56 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// ++// Copyright (C) 2019 Christian Hewitt ++ ++/* ++ * Keytable for the Khadas (VIM/EDGE) remote controller ++ */ ++ ++#include ++#include ++ ++static struct rc_map_table khadas[] = { ++ ++ { 0x14, KEY_POWER }, ++ ++ { 0x03, KEY_UP }, ++ { 0x02, KEY_DOWN }, ++ { 0x0e, KEY_LEFT }, ++ { 0x1a, KEY_RIGHT }, ++ { 0x07, KEY_OK }, ++ ++ { 0x01, KEY_BACK }, ++ { 0x5b, KEY_MUTE }, // mouse ++ { 0x13, KEY_MENU }, ++ ++ { 0x58, KEY_VOLUMEDOWN }, ++ { 0x0b, KEY_VOLUMEUP }, ++ ++ { 0x48, KEY_HOME }, ++ ++}; ++ ++static struct rc_map_list khadas_map = { ++ .map = { ++ .scan = khadas, ++ .size = ARRAY_SIZE(khadas), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_KHADAS, ++ } ++}; ++ ++static int __init init_rc_map_khadas(void) ++{ ++ return rc_map_register(&khadas_map); ++} ++ ++static void __exit exit_rc_map_khadas(void) ++{ ++ rc_map_unregister(&khadas_map); ++} ++ ++module_init(init_rc_map_khadas) ++module_exit(exit_rc_map_khadas) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt "); +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index 771e9e2cca50..2e4b83be000c 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -226,6 +226,8 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_IT913X_V1 "rc-it913x-v1" + #define RC_MAP_IT913X_V2 "rc-it913x-v2" + #define RC_MAP_KAIOMY "rc-kaiomy" ++#define RC_MAP_KHADAS "rc-khadas" ++#define RC_MAP_KHAMSIN "rc-khamsin" + #define RC_MAP_KWORLD_315U "rc-kworld-315u" + #define RC_MAP_KWORLD_PC150U "rc-kworld-pc150u" + #define RC_MAP_KWORLD_PLUS_TV_ANALOG "rc-kworld-plus-tv-analog" +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0029-media-rc-add-keymap-for-KHAMSIN-remote.patch b/projects/Amlogic/patches/linux/e-0029-media-rc-add-keymap-for-KHAMSIN-remote.patch new file mode 100644 index 0000000000..602f14cb0d --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0029-media-rc-add-keymap-for-KHAMSIN-remote.patch @@ -0,0 +1,100 @@ +From 63247dd85895163effd5cffeab10a9e080aa38d6 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 12 Apr 2019 12:26:30 +0000 +Subject: [PATCH 29/37] media: rc: add keymap for KHAMSIN remote + +Add an IR keymap for the KHAMSIN IR/BT remote supplied with the SmartLabs +SML-5442TW set-top box. The IR keymap allows basic GUI navigation to pair +the more functional BT mode of the remote. + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/rc-khamsin.c | 76 +++++++++++++++++++++++++++ + 1 file changed, 76 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-khamsin.c + +diff --git a/drivers/media/rc/keymaps/rc-khamsin.c b/drivers/media/rc/keymaps/rc-khamsin.c +new file mode 100644 +index 000000000000..c5c031f54414 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-khamsin.c +@@ -0,0 +1,76 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2019 Christian Hewitt ++ ++#include ++#include ++ ++/* ++ * KHAMSIN is an IR/Bluetooth RCU supplied with the SmartLabs ++ * SML-5442TW DVB-S/VOD box. The RCU has separate IR (TV) and ++ * BT (STB) modes. This keymap adds IR controls so that users ++ * can navigate and initiate BT pairing. ++ */ ++ ++static struct rc_map_table khamsin[] = { ++ { 0x70702, KEY_POWER}, ++ ++ { 0x70701, KEY_VIDEO}, // source ++ ++ { 0x7076c, KEY_RED}, ++ { 0x70714, KEY_GREEN}, ++ { 0x70715, KEY_YELLOW}, ++ { 0x70716, KEY_BLUE}, ++ ++ { 0x7071a, KEY_MENU}, ++ { 0x7074f, KEY_EPG}, ++ ++ { 0x70760, KEY_UP }, ++ { 0x70761, KEY_DOWN }, ++ { 0x70765, KEY_LEFT }, ++ { 0x70762, KEY_RIGHT }, ++ { 0x70768, KEY_ENTER }, ++ ++ { 0x7072d, KEY_ESC }, // back ++ ++ { 0x70707, KEY_VOLUMEUP }, ++ { 0x7070b, KEY_VOLUMEDOWN }, ++ { 0x7070f, KEY_MUTE }, ++ { 0x70712, KEY_CHANNELUP }, ++ { 0x70710, KEY_CHANNELDOWN }, ++ ++ { 0x70704, KEY_1 }, ++ { 0x70705, KEY_2 }, ++ { 0x70706, KEY_3 }, ++ { 0x70708, KEY_4 }, ++ { 0x70709, KEY_5 }, ++ { 0x7070a, KEY_6 }, ++ { 0x7070c, KEY_7 }, ++ { 0x7070d, KEY_8 }, ++ { 0x7070e, KEY_9 }, ++ { 0x70711, KEY_0 }, ++}; ++ ++static struct rc_map_list khamsin_map = { ++ .map = { ++ .scan = khamsin, ++ .size = ARRAY_SIZE(khamsin), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_KHAMSIN, ++ } ++}; ++ ++static int __init init_rc_map_khamsin(void) ++{ ++ return rc_map_register(&khamsin_map); ++} ++ ++static void __exit exit_rc_map_khamsin(void) ++{ ++ rc_map_unregister(&khamsin_map); ++} ++ ++module_init(init_rc_map_khamsin) ++module_exit(exit_rc_map_khamsin) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt "); +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0030-media-rc-add-keymap-for-Philips-RC242-remote.patch b/projects/Amlogic/patches/linux/e-0030-media-rc-add-keymap-for-Philips-RC242-remote.patch new file mode 100644 index 0000000000..d58653960c --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0030-media-rc-add-keymap-for-Philips-RC242-remote.patch @@ -0,0 +1,141 @@ +From 252bc63a831762e232d708d32207e866ec8a2193 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Fri, 12 Apr 2019 12:32:11 +0000 +Subject: [PATCH 30/37] media: rc: add keymap for Philips RC242 remote + +Add an IR keymap for the Philips RC242 remote used with some IPTV/VOD STB's. + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-philips-rc242.c | 93 +++++++++++++++++++++ + include/media/rc-map.h | 1 + + 3 files changed, 95 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-philips-rc242.c + +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index 7cd930b43e9b..b29353476d0d 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -79,6 +79,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-npgtech.o \ + rc-odroid.o \ + rc-pctv-sedna.o \ ++ rc-philips-rc242.o \ + rc-pinnacle-color.o \ + rc-pinnacle-grey.o \ + rc-pinnacle-pctv-hd.o \ +diff --git a/drivers/media/rc/keymaps/rc-philips-rc242.c b/drivers/media/rc/keymaps/rc-philips-rc242.c +new file mode 100644 +index 000000000000..7821eb122419 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-philips-rc242.c +@@ -0,0 +1,93 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2019 Christian Hewitt ++ ++#include ++#include ++ ++/* ++ * The Philips RC242 remote ships is used with the IPTV/VOD STB ++ * from O2 Czech Republic. ++ */ ++ ++static struct rc_map_table philips_rc242[] = { ++ ++ { 0x40c, KEY_POWER }, ++ { 0x44a, KEY_INFO }, ++ { 0x461, KEY_FAVORITES }, ++ ++ { 0x401, KEY_1 }, ++ { 0x402, KEY_2 }, ++ { 0x403, KEY_3 }, ++ ++ { 0x404, KEY_4 }, ++ { 0x405, KEY_5 }, ++ { 0x406, KEY_6 }, ++ ++ { 0x407, KEY_7 }, ++ { 0x408, KEY_8 }, ++ { 0x409, KEY_9 }, ++ ++ { 0x448, KEY_ZOOM }, ++ { 0x400, KEY_0 }, ++ { 0x441, KEY_EPG }, ++ ++ { 0x412, KEY_CONTEXT_MENU }, ++ { 0x437, KEY_RECORD }, ++ { 0x430, KEY_PAUSE }, ++ { 0x41d, KEY_ZOOM }, ++ ++ { 0x410, KEY_UP }, ++ { 0x411, KEY_DOWN }, ++ { 0x415, KEY_LEFT }, ++ { 0x416, KEY_RIGHT }, ++ { 0x424, KEY_OK }, ++ ++ { 0x414, KEY_VOLUMEUP }, ++ { 0x41f, KEY_BACK }, ++ { 0x40e, KEY_CHANNELUP }, ++ ++ { 0x417, KEY_VOLUMEDOWN }, ++ { 0x40d, KEY_MUTE }, ++ { 0x40a, KEY_CHANNELDOWN }, ++ ++ { 0x432, KEY_REWIND }, ++ { 0x435, KEY_PLAYPAUSE }, ++ { 0x436, KEY_STOP }, ++ { 0x434, KEY_FORWARD }, ++ ++ { 0x451, KEY_PREVIOUSSONG }, ++ { 0x43c, KEY_SUBTITLE }, ++ { 0x40f, KEY_LANGUAGE }, ++ { 0x450, KEY_NEXTSONG }, ++ ++ { 0x46b, KEY_RED }, ++ { 0x46c, KEY_GREEN }, ++ { 0x46d, KEY_YELLOW }, ++ { 0x46e, KEY_BLUE }, ++ ++}; ++ ++static struct rc_map_list philips_rc242_map = { ++ .map = { ++ .scan = philips_rc242, ++ .size = ARRAY_SIZE(philips_rc242), ++ .rc_proto = RC_PROTO_RC5, ++ .name = RC_MAP_PHILIPS_RC242, ++ } ++}; ++ ++static int __init init_rc_map_philips_rc242(void) ++{ ++ return rc_map_register(&philips_rc242_map); ++} ++ ++static void __exit exit_rc_map_philips_rc242(void) ++{ ++ rc_map_unregister(&philips_rc242_map); ++} ++ ++module_init(init_rc_map_philips_rc242) ++module_exit(exit_rc_map_philips_rc242) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt "); +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index 2e4b83be000c..bd7738bf197f 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -247,6 +247,7 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_NPGTECH "rc-npgtech" + #define RC_MAP_ODROID "rc-odroid" + #define RC_MAP_PCTV_SEDNA "rc-pctv-sedna" ++#define RC_MAP_PHILIPS_RC242 "rc-philips-rc242" + #define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color" + #define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey" + #define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd" +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0031-media-rc-add-keymap-for-Tanix-TX3-mini-remote.patch b/projects/Amlogic/patches/linux/e-0031-media-rc-add-keymap-for-Tanix-TX3-mini-remote.patch new file mode 100644 index 0000000000..a1dc9026b0 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0031-media-rc-add-keymap-for-Tanix-TX3-mini-remote.patch @@ -0,0 +1,128 @@ +From 68be11762925f08a53f2e0ea4064550540d3d7e6 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 15 Apr 2019 02:44:48 +0000 +Subject: [PATCH 31/37] media: rc: add keymap for Tanix TX3 mini remote + +This is a simple NEC remote control device shipped with the Tanix TX3 +Android STB device. + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-tanix-tx3mini.c | 79 +++++++++++++++++++++ + include/media/rc-map.h | 1 + + 3 files changed, 81 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-tanix-tx3mini.c + +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index b29353476d0d..23382bbfb3da 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -98,6 +98,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-snapstream-firefly.o \ + rc-streamzap.o \ + rc-tango.o \ ++ rc-tanix-tx3mini.o \ + rc-tbs-nec.o \ + rc-technisat-ts35.o \ + rc-technisat-usb2.o \ +diff --git a/drivers/media/rc/keymaps/rc-tanix-tx3mini.c b/drivers/media/rc/keymaps/rc-tanix-tx3mini.c +new file mode 100644 +index 000000000000..e5013981fdc4 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-tanix-tx3mini.c +@@ -0,0 +1,79 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2018 Christian Hewitt ++ ++#include ++#include ++ ++/* ++ * This keymap is used with the Oranth Tanix TX3 mini ++ * and other Android STB devices. ++ */ ++ ++static struct rc_map_table tanix_tx3mini[] = { ++ ++ { 0x8051, KEY_POWER }, ++ { 0x804d, KEY_MUTE }, ++ ++ { 0x8009, KEY_RED }, ++ { 0x8011, KEY_GREEN }, ++ { 0x8054, KEY_YELLOW }, ++ { 0x804f, KEY_BLUE }, ++ ++ { 0x8056, KEY_VOLUMEDOWN }, ++ { 0x80bd, KEY_PREVIOUS }, ++ { 0x80bb, KEY_NEXT }, ++ { 0x804e, KEY_VOLUMEUP }, ++ ++ { 0x8053, KEY_HOME }, ++ { 0x801b, KEY_BACK }, ++ ++ { 0x8026, KEY_UP }, ++ { 0x8028, KEY_DOWN }, ++ { 0x8025, KEY_LEFT }, ++ { 0x8027, KEY_RIGHT }, ++ { 0x800d, KEY_OK }, ++ ++ { 0x8049, KEY_MENU }, ++ { 0x8052, KEY_EPG }, // mouse ++ ++ { 0x8031, KEY_1 }, ++ { 0x8032, KEY_2 }, ++ { 0x8033, KEY_3 }, ++ ++ { 0x8034, KEY_4 }, ++ { 0x8035, KEY_5 }, ++ { 0x8036, KEY_6 }, ++ ++ { 0x8037, KEY_7 }, ++ { 0x8038, KEY_8 }, ++ { 0x8039, KEY_9 }, ++ ++ { 0x8058, KEY_SUBTITLE }, // 1/a ++ { 0x8030, KEY_0 }, ++ { 0x8044, KEY_DELETE }, ++}; ++ ++static struct rc_map_list tanix_tx3mini_map = { ++ .map = { ++ .scan = tanix_tx3mini, ++ .size = ARRAY_SIZE(tanix_tx3mini), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_TANIX_TX3MINI, ++ } ++}; ++ ++static int __init init_rc_map_tanix_tx3mini(void) ++{ ++ return rc_map_register(&tanix_tx3mini_map); ++} ++ ++static void __exit exit_rc_map_tanix_tx3mini(void) ++{ ++ rc_map_unregister(&tanix_tx3mini_map); ++} ++ ++module_init(init_rc_map_tanix_tx3mini) ++module_exit(exit_rc_map_tanix_tx3mini) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt "); +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index bd7738bf197f..30513f5d764a 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -267,6 +267,7 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" + #define RC_MAP_STREAMZAP "rc-streamzap" + #define RC_MAP_TANGO "rc-tango" ++#define RC_MAP_TANIX_TX3MINI "rc-tanix-tx3mini" + #define RC_MAP_TBS_NEC "rc-tbs-nec" + #define RC_MAP_TECHNISAT_TS35 "rc-technisat-ts35" + #define RC_MAP_TECHNISAT_USB2 "rc-technisat-usb2" +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0032-media-rc-add-keymap-for-WeTek-Hub-remote.patch b/projects/Amlogic/patches/linux/e-0032-media-rc-add-keymap-for-WeTek-Hub-remote.patch new file mode 100644 index 0000000000..758d8065f7 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0032-media-rc-add-keymap-for-WeTek-Hub-remote.patch @@ -0,0 +1,104 @@ +From cb88289d080823bb33f162d05304724190b88763 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 15 Apr 2019 04:37:44 +0000 +Subject: [PATCH 32/37] media: rc: add keymap for WeTek Hub remote + +This is a simple RC5 remote control device shipped with the WeTek Hub +Android STB device. + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-wetek-hub.c | 55 +++++++++++++++++++++++++ + include/media/rc-map.h | 1 + + 3 files changed, 57 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-wetek-hub.c + +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index 23382bbfb3da..32f93942c3b2 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -118,6 +118,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-videomate-m1f.o \ + rc-videomate-s350.o \ + rc-videomate-tv-pvr.o \ ++ rc-wetek-hub.o \ + rc-winfast.o \ + rc-winfast-usbii-deluxe.o \ + rc-su3000.o \ +diff --git a/drivers/media/rc/keymaps/rc-wetek-hub.c b/drivers/media/rc/keymaps/rc-wetek-hub.c +new file mode 100644 +index 000000000000..8d114ae59669 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-wetek-hub.c +@@ -0,0 +1,55 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// Copyright (c) 2018 Christian Hewitt ++ ++#include ++#include ++ ++/* ++ * This keymap is used with the WeTek Hub STB. ++ */ ++ ++static struct rc_map_table wetek_hub[] = { ++ ++ { 0x77f1, KEY_POWER }, ++ ++ { 0x77f2, KEY_HOME }, ++ { 0x77f3, KEY_MUTE }, // mouse ++ ++ { 0x77f4, KEY_UP }, ++ { 0x77f5, KEY_DOWN }, ++ { 0x77f6, KEY_LEFT }, ++ { 0x77f7, KEY_RIGHT }, ++ { 0x77f8, KEY_OK }, ++ ++ { 0x77f9, KEY_BACK }, ++ { 0x77fa, KEY_MENU }, ++ ++ { 0x77fb, KEY_VOLUMEUP }, ++ { 0x77fc, KEY_VOLUMEDOWN }, ++ ++}; ++ ++static struct rc_map_list wetek_hub_map = { ++ .map = { ++ .scan = wetek_hub, ++ .size = ARRAY_SIZE(wetek_hub), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_WETEK_HUB, ++ } ++}; ++ ++static int __init init_rc_map_wetek_hub(void) ++{ ++ return rc_map_register(&wetek_hub_map); ++} ++ ++static void __exit exit_rc_map_wetek_hub(void) ++{ ++ rc_map_unregister(&wetek_hub_map); ++} ++ ++module_init(init_rc_map_wetek_hub) ++module_exit(exit_rc_map_wetek_hub) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt "); +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index 30513f5d764a..034bd38dffe7 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -287,6 +287,7 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_VIDEOMATE_K100 "rc-videomate-k100" + #define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350" + #define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr" ++#define RC_MAP_WETEK_HUB "rc-wetek-hub" + #define RC_MAP_WINFAST "rc-winfast" + #define RC_MAP_WINFAST_USBII_DELUXE "rc-winfast-usbii-deluxe" + #define RC_MAP_SU3000 "rc-su3000" +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0033-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch b/projects/Amlogic/patches/linux/e-0033-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch new file mode 100644 index 0000000000..4e0ca8db95 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0033-media-rc-add-keymap-for-WeTeK-Play-2-remote.patch @@ -0,0 +1,141 @@ +From 316e5b987b9e72138eb2270d5f3c41118b61152b Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 21 Apr 2019 02:24:07 +0000 +Subject: [PATCH 33/37] media: rc: add keymap for WeTeK Play 2 remote + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-wetek-play2.c | 95 +++++++++++++++++++++++ + include/media/rc-map.h | 1 + + 3 files changed, 97 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-wetek-play2.c + +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index 32f93942c3b2..b2c13dac1755 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -119,6 +119,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-videomate-s350.o \ + rc-videomate-tv-pvr.o \ + rc-wetek-hub.o \ ++ rc-wetek-play2.o \ + rc-winfast.o \ + rc-winfast-usbii-deluxe.o \ + rc-su3000.o \ +diff --git a/drivers/media/rc/keymaps/rc-wetek-play2.c b/drivers/media/rc/keymaps/rc-wetek-play2.c +new file mode 100644 +index 000000000000..77504f207578 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-wetek-play2.c +@@ -0,0 +1,95 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// ++// Copyright (C) 2019 Christian Hewitt ++ ++#include ++#include ++ ++// ++// Keytable for the WeTek Play 2 remote controller ++// ++ ++static struct rc_map_table wetek_play2[] = { ++ ++ { 0x5e5f02, KEY_POWER }, ++ { 0x5e5f46, KEY_SLEEP }, // tv ++ { 0x5e5f10, KEY_MUTE }, ++ ++ { 0x5e5f22, KEY_1 }, ++ { 0x5e5f23, KEY_2 }, ++ { 0x5e5f24, KEY_3 }, ++ ++ { 0x5e5f25, KEY_4 }, ++ { 0x5e5f26, KEY_5 }, ++ { 0x5e5f27, KEY_6 }, ++ ++ { 0x5e5f28, KEY_7 }, ++ { 0x5e5f29, KEY_8 }, ++ { 0x5e5f30, KEY_9 }, ++ ++ { 0x5e5f71, KEY_BACK }, ++ { 0x5e5f21, KEY_0 }, ++ { 0x5e5f72, KEY_CAPSLOCK }, ++ ++ // outer ring clockwide from top ++ { 0x5e5f03, KEY_HOME }, ++ { 0x5e5f61, KEY_BACK }, ++ { 0x5e5f77, KEY_CONFIG }, // mouse ++ { 0x5e5f83, KEY_EPG }, ++ { 0x5e5f84, KEY_SCREEN }, // square ++ { 0x5e5f48, KEY_MENU }, ++ ++ // inner ring ++ { 0x5e5f50, KEY_UP }, ++ { 0x5e5f4b, KEY_DOWN }, ++ { 0x5e5f4c, KEY_LEFT }, ++ { 0x5e5f4d, KEY_RIGHT }, ++ { 0x5e5f47, KEY_OK }, ++ ++ { 0x5e5f44, KEY_VOLUMEUP }, ++ { 0x5e5f43, KEY_VOLUMEDOWN }, ++ { 0x5e5f4f, KEY_FAVORITES }, ++ { 0x5e5f82, KEY_SUBTITLE }, // txt ++ { 0x5e5f41, KEY_PAGEUP }, ++ { 0x5e5f42, KEY_PAGEDOWN }, ++ ++ { 0x5e5f73, KEY_RED }, ++ { 0x5e5f74, KEY_GREEN }, ++ { 0x5e5f75, KEY_YELLOW }, ++ { 0x5e5f76, KEY_BLUE }, ++ ++ { 0x5e5f67, KEY_PREVIOUSSONG }, ++ { 0x5e5f79, KEY_REWIND }, ++ { 0x5e5f80, KEY_FASTFORWARD }, ++ { 0x5e5f81, KEY_NEXTSONG }, ++ ++ { 0x5e5f04, KEY_RECORD }, ++ { 0x5e5f2c, KEY_PLAYPAUSE }, ++ { 0x5e5f2b, KEY_STOP }, ++ ++}; ++ ++static struct rc_map_list wetek_play2_map = { ++ .map = { ++ .scan = wetek_play2, ++ .size = ARRAY_SIZE(wetek_play2), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_WETEK_PLAY2, ++ } ++}; ++ ++static int __init init_rc_map_wetek_play2(void) ++{ ++ return rc_map_register(&wetek_play2_map); ++} ++ ++static void __exit exit_rc_map_wetek_play2(void) ++{ ++ rc_map_unregister(&wetek_play2_map); ++} ++ ++module_init(init_rc_map_wetek_play2) ++module_exit(exit_rc_map_wetek_play2) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt +Date: Sun, 14 Apr 2019 03:25:54 +0000 +Subject: [PATCH 34/37] ASoC: meson: correct i2s error messages + +Reorder words so they read correctly. + +Signed-off-by: Christian Hewitt +--- + sound/soc/meson-gx/aiu-i2s.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/meson-gx/aiu-i2s.c b/sound/soc/meson-gx/aiu-i2s.c +index c6bfd5d8c808..3d1937946db0 100644 +--- a/sound/soc/meson-gx/aiu-i2s.c ++++ b/sound/soc/meson-gx/aiu-i2s.c +@@ -500,13 +500,13 @@ static int meson_aiu_i2s_dai_hw_params(struct snd_pcm_substream *substream, + + ret = __setup_desc(priv, width, channels); + if (ret) { +- dev_err(dai->dev, "Unable set to set i2s description\n"); ++ dev_err(dai->dev, "Unable to set i2s description\n"); + return ret; + } + + ret = __bclks_set_rate(priv, rate, width); + if (ret) { +- dev_err(dai->dev, "Unable set to the i2s clock rates\n"); ++ dev_err(dai->dev, "Unable to set i2s clock rates\n"); + return ret; + } + +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0035-dt-bindings-Add-vendor-prefix-for-SmartLabs-LLC.patch b/projects/Amlogic/patches/linux/e-0035-dt-bindings-Add-vendor-prefix-for-SmartLabs-LLC.patch new file mode 100644 index 0000000000..cc41eabf75 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0035-dt-bindings-Add-vendor-prefix-for-SmartLabs-LLC.patch @@ -0,0 +1,28 @@ +From 301268ffe271846dbd8aad357ac1cc727d5d2259 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Wed, 24 Apr 2019 10:49:48 +0000 +Subject: [PATCH 35/37] dt-bindings: Add vendor prefix for SmartLabs LLC. + +SmartLabs LLC. are an integrator of Interactive TV solutions and IPTV/STB +devices (https://www.smartlabs.tv/en/about/) for Telco/ISP customers. + +Signed-off-by: Christian Hewitt +--- + Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt +index 8162b0eb4b50..1de094caec5c 100644 +--- a/Documentation/devicetree/bindings/vendor-prefixes.txt ++++ b/Documentation/devicetree/bindings/vendor-prefixes.txt +@@ -374,6 +374,7 @@ sirf SiRF Technology, Inc. + sis Silicon Integrated Systems Corp. + sitronix Sitronix Technology Corporation + skyworks Skyworks Solutions, Inc. ++smartlabs SmartLabs LLC. + smsc Standard Microsystems Corporation + snps Synopsys, Inc. + socionext Socionext Inc. +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0036-dt-bindings-arm-amlogic-Add-support-for-the-SmartLab.patch b/projects/Amlogic/patches/linux/e-0036-dt-bindings-arm-amlogic-Add-support-for-the-SmartLab.patch new file mode 100644 index 0000000000..e8bfef73b0 --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0036-dt-bindings-arm-amlogic-Add-support-for-the-SmartLab.patch @@ -0,0 +1,44 @@ +From 30ae92c1678dcab79407fd2a03635d11141e666c Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Wed, 24 Apr 2019 10:52:06 +0000 +Subject: [PATCH 36/37] dt-bindings: arm: amlogic: Add support for the + SmartLabs SML-5442TW + +The SmartLabs SML-5442TW is the next-gen/4K IPTV/DVB-S STB for O2 Czech based +on the Amlogic P231 reference design using the S905D chipset with widevine L1 +license. Hardware specification: + +- 2GB DDR3 RAM +- 8GB eMMC storage +- 10/100 Base-T Ethernet +- 802.11 a/b/g/n/ac + BT 4.1 HS sdio wireless module (QCA9377) +- 2x single colour and 1x dual colour LEDs on the front panel +- 1x reset button on the front panel +- HDMI 2.0 (4k@60p) video +- Composite video + 2-channel audio output on 3.5mm jack +- S/PDIF audio output +- Single DVB-S tuner (AVL6762/MxL608) +- 2x USB 2.0 ports +- 1x micro SD card slot +- UART pins (internal) + +Signed-off-by: Christian Hewitt +--- + Documentation/devicetree/bindings/arm/amlogic.txt | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt +index 7f40cb5f490b..2e706c6dd175 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.txt ++++ b/Documentation/devicetree/bindings/arm/amlogic.txt +@@ -92,6 +92,7 @@ Board compatible values (alphabetically, grouped by SoC): + - "amlogic,p230" (Meson gxl s905d) + - "amlogic,p231" (Meson gxl s905d) + - "phicomm,n1" (Meson gxl s905d) ++ - "smartlabs,sml5442tw" (Meson gxl s905d) + + - "amlogic,p241" (Meson gxl s805x) + - "libretech,aml-s805x-ac" (Meson gxl s805x) +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/e-0037-ARM64-dts-meson-gxl-Add-support-for-the-SmartLabs-SM.patch b/projects/Amlogic/patches/linux/e-0037-ARM64-dts-meson-gxl-Add-support-for-the-SmartLabs-SM.patch new file mode 100644 index 0000000000..8d07a51acd --- /dev/null +++ b/projects/Amlogic/patches/linux/e-0037-ARM64-dts-meson-gxl-Add-support-for-the-SmartLabs-SM.patch @@ -0,0 +1,334 @@ +From eec12dffbedb498597b8eb3b7f6fad76cd24d0d7 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Wed, 24 Apr 2019 10:56:33 +0000 +Subject: [PATCH 37/37] ARM64: dts: meson-gxl: Add support for the SmartLabs + SML-5442TW + +The SmartLabs SML-5442TW is broadly similar to the P231 reference design +but with the following differences: + +- Yellow and Blue front-panel LEDs are available but disabled +- Red/Green LED is used to signal off/on status +- GPIOX_17 is set high to enable the QCA9377 wireless module +- uart_AO can be accessed after opening the case; soldered pins exist + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/Makefile | 1 + + .../meson-gxl-s905d-smartlabs-sml5442tw.dts | 202 ++++++++++++++++++ + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-vega-s95.c | 56 +++++ + include/media/rc-map.h | 1 + + 5 files changed, 261 insertions(+) + create mode 100644 arch/arm64/boot/dts/amlogic/meson-gxl-s905d-smartlabs-sml5442tw.dts + create mode 100644 drivers/media/rc/keymaps/rc-vega-s95.c + +diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile +index 0821fed4c074..8a948b6b4f5d 100644 +--- a/arch/arm64/boot/dts/amlogic/Makefile ++++ b/arch/arm64/boot/dts/amlogic/Makefile +@@ -21,6 +21,7 @@ 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-smartlabs-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 +diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-smartlabs-sml5442tw.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-smartlabs-sml5442tw.dts +new file mode 100644 +index 000000000000..a574fdc17dd3 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905d-smartlabs-sml5442tw.dts +@@ -0,0 +1,202 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) Christian Hewitt ++ */ ++ ++/dts-v1/; ++ ++#include "meson-gxl-s905d-p231.dts" ++ ++/ { ++ compatible = "smartlabs,sml5442tw", "amlogic,s905d", "amlogic,meson-gxl"; ++ model = "SmartLabs SML-5442TW for O2.cz"; ++ ++ aliases { ++ serial1 = &uart_A; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ ++ yellow { ++ label = "sml5442tw:yellow"; ++ gpios = <&gpio_ao GPIOAO_6 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ ++ blue { ++ label = "sml5442tw:blue"; ++ gpios = <&gpio GPIODV_28 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ ++ green { ++ label = "sml5442tw:green"; ++ gpios = <&gpio_ao GPIOAO_9 GPIO_ACTIVE_HIGH>; ++ default-state = "on"; ++ }; ++ ++ red { ++ label = "sml5442tw:red"; ++ gpios = <&gpio GPIODV_27 GPIO_ACTIVE_HIGH>; ++ default-state = "off"; ++ }; ++ }; ++}; ++ ++&cec_AO { ++ status = "okay"; ++ pinctrl-0 = <&ao_cec_pins>; ++ pinctrl-names = "default"; ++ hdmi-phandle = <&hdmi_tx>; ++}; ++ ++&audio { ++ status = "okay"; ++}; ++ ++&aiu_i2s { ++ status = "okay"; ++}; ++ ++&cvbs_vdac_port { ++ cvbs_vdac_out: endpoint { ++ remote-endpoint = <&cvbs_connector_in>; ++ }; ++}; ++ ++ðmac { ++ status = "okay"; ++ phy-mode = "rmii"; ++ phy-handle = <&internal_phy>; ++}; ++ ++/* This will enable the bluetooth module */ ++&gpio { ++ bt-en { ++ gpio-hog; ++ gpios = ; ++ output-high; ++ line-name = "bt-en"; ++ }; ++}; ++ ++&hdmi_tx { ++ status = "okay"; ++ pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&hdmi_tx_tmds_port { ++ hdmi_tx_tmds_out: endpoint { ++ remote-endpoint = <&hdmi_connector_in>; ++ }; ++}; ++ ++&i2c_A { ++ status = "okay"; ++ pinctrl-0 = <&i2c_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&internal_phy { ++ pinctrl-0 = <ð_link_led_pins>, <ð_act_led_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++ linux,rc-map-name = "rc-khamsin"; ++}; ++ ++&pwm_ef { ++ status = "okay"; ++ pinctrl-0 = <&pwm_e_pins>; ++ pinctrl-names = "default"; ++ clocks = <&clkc CLKID_FCLK_DIV4>; ++ clock-names = "clkin0"; ++}; ++ ++&saradc { ++ status = "okay"; ++ vref-supply = <&vddio_ao18>; ++}; ++ ++/* Wireless SDIO Module */ ++&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; ++ max-frequency = <100000000>; ++ ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&sdio_pwrseq>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddio_boot>; ++}; ++ ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ pinctrl-0 = <&sdcard_pins>; ++ pinctrl-1 = <&sdcard_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <4>; ++ cap-sd-highspeed; ++ max-frequency = <100000000>; ++ disable-wp; ++ ++ cd-gpios = <&gpio CARD_6 GPIO_ACTIVE_LOW>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddio_boot>; ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; ++ pinctrl-1 = <&emmc_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ max-frequency = <200000000>; ++ non-removable; ++ disable-wp; ++ mmc-ddr-1_8v; ++ mmc-hs200-1_8v; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vcc_3v3>; ++ vqmmc-supply = <&vddio_boot>; ++}; ++ ++/* This is connected to the Bluetooth module: */ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&uart_AO { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&usb0 { ++ status = "okay"; ++}; +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index b2c13dac1755..ce4dff101355 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -118,6 +118,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-videomate-m1f.o \ + rc-videomate-s350.o \ + rc-videomate-tv-pvr.o \ ++ rc-vega-s95.o \ + rc-wetek-hub.o \ + rc-wetek-play2.o \ + rc-winfast.o \ +diff --git a/drivers/media/rc/keymaps/rc-vega-s95.c b/drivers/media/rc/keymaps/rc-vega-s95.c +new file mode 100644 +index 000000000000..533464ecf932 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-vega-s95.c +@@ -0,0 +1,56 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// ++// Copyright (c) 2018 Christian Hewitt ++ ++#include ++#include ++ ++/* ++ * This keymap is used with the Tronsmart Vega S95 Android STB ++ */ ++ ++static struct rc_map_table vega_s95[] = { ++ ++ { 0x18, KEY_POWER }, ++ { 0x17, KEY_INFO }, // mouse ++ ++ { 0x46, KEY_UP }, ++ { 0x16, KEY_DOWN }, ++ { 0x47, KEY_LEFT }, ++ { 0x15, KEY_RIGHT }, ++ { 0x55, KEY_OK }, ++ ++ { 0x06, KEY_HOME }, ++ { 0x42, KEY_PLAYPAUSE}, ++ { 0x40, KEY_BACK }, ++ ++ { 0x14, KEY_VOLUMEDOWN }, ++ { 0x04, KEY_MENU }, ++ { 0x10, KEY_VOLUMEUP }, ++ ++}; ++ ++static struct rc_map_list vega_s95_map = { ++ .map = { ++ .scan = vega_s95, ++ .size = ARRAY_SIZE(vega_s95), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_VEGA_S95, ++ } ++}; ++ ++static int __init init_rc_map_vega_s95(void) ++{ ++ return rc_map_register(&vega_s95_map); ++} ++ ++static void __exit exit_rc_map_vega_s95(void) ++{ ++ rc_map_unregister(&vega_s95_map); ++} ++ ++module_init(init_rc_map_vega_s95) ++module_exit(exit_rc_map_vega_s95) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt "); +diff --git a/include/media/rc-map.h b/include/media/rc-map.h +index 49fe4e73b28b..491ef0382575 100644 +--- a/include/media/rc-map.h ++++ b/include/media/rc-map.h +@@ -284,6 +284,7 @@ struct rc_map *rc_map_get(const char *name); + #define RC_MAP_TT_1500 "rc-tt-1500" + #define RC_MAP_TWINHAN_DTV_CAB_CI "rc-twinhan-dtv-cab-ci" + #define RC_MAP_TWINHAN_VP1027_DVBS "rc-twinhan1027" ++#define RC_MAP_VEGA_S95 "rc-vega-s95" + #define RC_MAP_VIDEOMATE_K100 "rc-videomate-k100" + #define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350" + #define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr" +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/f-0001-ARM64-dts-meson-gx-add-ATF-BL32-reserved-memory-regi.patch b/projects/Amlogic/patches/linux/f-0001-ARM64-dts-meson-gx-add-ATF-BL32-reserved-memory-regi.patch new file mode 100644 index 0000000000..aa00a276e6 --- /dev/null +++ b/projects/Amlogic/patches/linux/f-0001-ARM64-dts-meson-gx-add-ATF-BL32-reserved-memory-regi.patch @@ -0,0 +1,36 @@ +From 20f45db7f0cbe5523f0b6618d533f9e40cb6d051 Mon Sep 17 00:00:00 2001 +From: kszaq +Date: Mon, 29 Apr 2019 22:42:13 +0200 +Subject: [PATCH] ARM64: dts: meson-gx: add ATF BL32 reserved memory region + +Vendor firmware/uboot has an additional reserved region +for BL32 trusted firmware. If a board uses BL32 firmware, +booting kernel without knowledge of this region would cause +an immediate kernel panic on SError Interrupt. + +TODO: This should be enabled only for boards actually requiring it. + +--- + arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +index 8238f55..17e8d37 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi ++++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi +@@ -41,6 +41,12 @@ + no-map; + }; + ++ /* 32 MiB reserved for ARM Trusted Firmware (BL32) */ ++ secmon_reserved_bl32: secmon@5300000 { ++ reg = <0x0 0x05300000 0x0 0x2000000>; ++ no-map; ++ }; ++ + linux,cma { + compatible = "shared-dma-pool"; + reusable; +-- +2.7.4 + diff --git a/projects/Amlogic/patches/linux/f-0002-media-rc-add-keymap-for-Amediatech-X96-MAX-remote.patch b/projects/Amlogic/patches/linux/f-0002-media-rc-add-keymap-for-Amediatech-X96-MAX-remote.patch new file mode 100644 index 0000000000..7c27880743 --- /dev/null +++ b/projects/Amlogic/patches/linux/f-0002-media-rc-add-keymap-for-Amediatech-X96-MAX-remote.patch @@ -0,0 +1,134 @@ +From 87585a9b61475fb44bdba734124ce6071191b201 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sun, 7 Apr 2019 04:20:56 +0000 +Subject: [PATCH 2/6] media: rc: add keymap for Amediatech X96-MAX remote + +This is a simple NEC remote control device shipped with the Amediatech +X96 MAX Android 'TV Box' device. The remote contains a programmable TV +controls section with buttons that are not mappable, but are indicated +in the keymap for reference. + +Signed-off-by: Christian Hewitt +--- + drivers/media/rc/keymaps/Makefile | 1 + + drivers/media/rc/keymaps/rc-x96max.c | 85 ++++++++++++++++++++++++++++ + include/media/rc-map.h | 1 + + 3 files changed, 87 insertions(+) + create mode 100644 drivers/media/rc/keymaps/rc-x96max.c + +diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile +index 03fbac32befb..f757305eacb2 100644 +--- a/drivers/media/rc/keymaps/Makefile ++++ b/drivers/media/rc/keymaps/Makefile +@@ -118,4 +118,5 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ + rc-winfast-usbii-deluxe.o \ + rc-su3000.o \ + rc-xbox-dvd.o \ ++ rc-x96max.o \ + rc-zx-irdec.o +diff --git a/drivers/media/rc/keymaps/rc-x96max.c b/drivers/media/rc/keymaps/rc-x96max.c +new file mode 100644 +index 000000000000..cea5c1c7bf36 +--- /dev/null ++++ b/drivers/media/rc/keymaps/rc-x96max.c +@@ -0,0 +1,85 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++// ++// Copyright (C) 2019 Christian Hewitt ++ ++#include ++#include ++ ++// ++// Keytable for the Amediatecch X96-max remote control ++// ++ ++static struct rc_map_table x96max[] = { ++ ++ { 0x140, KEY_POWER }, ++ ++ // ** TV CONTROLS ** ++ // SET ++ // AV/TV ++ // POWER ++ // VOLUME UP ++ // VOLUME DOWN ++ ++ { 0x118, KEY_VOLUMEUP }, ++ { 0x110, KEY_VOLUMEDOWN }, ++ ++ { 0x143, KEY_CONFIG }, ++ ++ { 0x100, KEY_INFO }, // MOUSE ++ { 0x119, KEY_BACK }, ++ ++ { 0x116, KEY_UP }, ++ { 0x151, KEY_LEFT }, ++ { 0x150, KEY_RIGHT }, ++ { 0x11a, KEY_DOWN }, ++ { 0x113, KEY_OK }, ++ ++ { 0x111, KEY_HOME }, ++ { 0x14c, KEY_CONTEXT_MENU }, ++ ++ { 0x159, KEY_PREVIOUS }, ++ { 0x15a, KEY_PLAYPAUSE }, ++ { 0x158, KEY_NEXT }, ++ ++ { 0x147, KEY_MENU }, // @ KEY ++ { 0x101, KEY_NUMERIC_0 }, ++ { 0x142, KEY_BACKSPACE }, ++ ++ { 0x14e, KEY_NUMERIC_1 }, ++ { 0x10d, KEY_NUMERIC_2 }, ++ { 0x10c, KEY_NUMERIC_3 }, ++ ++ { 0x14a, KEY_NUMERIC_4 }, ++ { 0x109, KEY_NUMERIC_5 }, ++ { 0x108, KEY_NUMERIC_6 }, ++ ++ { 0x146, KEY_NUMERIC_7 }, ++ { 0x105, KEY_NUMERIC_8 }, ++ { 0x104, KEY_NUMERIC_9 }, ++ ++}; ++ ++static struct rc_map_list x96max_map = { ++ .map = { ++ .scan = x96max, ++ .size = ARRAY_SIZE(x96max), ++ .rc_proto = RC_PROTO_NEC, ++ .name = RC_MAP_X96MAX, ++ } ++}; ++ ++static int __init init_rc_map_x96max(void) ++{ ++ return rc_map_register(&x96max_map); ++} ++ ++static void __exit exit_rc_map_x96max(void) ++{ ++ rc_map_unregister(&x96max_map); ++} ++ ++module_init(init_rc_map_x96max) ++module_exit(exit_rc_map_x96max) ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Christian Hewitt +Date: Sat, 20 Apr 2019 23:51:04 +0000 +Subject: [PATCH 3/6] arm64: dts: meson-g12b-odroid-n2: add rc-odroid ir keymap + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +index 380b5cebb21d..9ab68ff0cca3 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12b-odroid-n2.dts +@@ -228,6 +228,7 @@ + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; ++ linux,rc-map-name = "rc-odroid"; + }; + + /* SD card */ +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/f-0004-arm64-dts-meson-g12a-x96-max-add-rc-x96max-ir-keymap.patch b/projects/Amlogic/patches/linux/f-0004-arm64-dts-meson-g12a-x96-max-add-rc-x96max-ir-keymap.patch new file mode 100644 index 0000000000..818762ab94 --- /dev/null +++ b/projects/Amlogic/patches/linux/f-0004-arm64-dts-meson-g12a-x96-max-add-rc-x96max-ir-keymap.patch @@ -0,0 +1,25 @@ +From 8337a65c09a0252ac8d25e1c5720cafd8c635252 Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Sat, 20 Apr 2019 23:52:15 +0000 +Subject: [PATCH 4/6] arm64: dts: meson-g12a-x96-max: add rc-x96max ir keymap + +Signed-off-by: Christian Hewitt +--- + arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +index 648b7deed22d..3ad4db440fbd 100644 +--- a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max.dts +@@ -168,6 +168,7 @@ + status = "okay"; + pinctrl-0 = <&remote_input_ao_pins>; + pinctrl-names = "default"; ++ linux,rc-map-name = "rc-x96max"; + }; + + &ext_mdio { +-- +2.17.1 + diff --git a/projects/Amlogic/patches/linux/f-0005-arm64-dts-add-meson-g12a-x96-max-rmii-dts.patch b/projects/Amlogic/patches/linux/f-0005-arm64-dts-add-meson-g12a-x96-max-rmii-dts.patch new file mode 100644 index 0000000000..0abdbc8096 --- /dev/null +++ b/projects/Amlogic/patches/linux/f-0005-arm64-dts-add-meson-g12a-x96-max-rmii-dts.patch @@ -0,0 +1,332 @@ +From 3dc28e080cbd6da0d9d908266aff6d14c053dbda Mon Sep 17 00:00:00 2001 +From: chewitt +Date: Mon, 22 Apr 2019 07:17:31 +0000 +Subject: [PATCH 5/6] arm64: dts: add meson-g12a-x96-max-rmii dts + +Some variants of the X96 max use the internal rmii PHY instead of external +rgmii PHY so provide a device-tree for them. + +Signed-off-by: Christian Hewitt +--- + .../devicetree/bindings/arm/amlogic.txt | 3 +- + arch/arm64/boot/dts/amlogic/Makefile | 1 + + .../dts/amlogic/meson-g12a-x96-max-rmii.dts | 281 ++++++++++++++++++ + 3 files changed, 284 insertions(+), 1 deletion(-) + create mode 100644 arch/arm64/boot/dts/amlogic/meson-g12a-x96-max-rmii.dts + +diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt +index eff41128268e..b78220bb3feb 100644 +--- a/Documentation/devicetree/bindings/arm/amlogic.txt ++++ b/Documentation/devicetree/bindings/arm/amlogic.txt +@@ -113,7 +113,8 @@ Board compatible values (alphabetically, grouped by SoC): + - "amlogic,s400" (Meson axg a113d) + + - "amlogic,u200" (Meson g12a s905d2) +- - "amediatech,x96-max" (Meson g12a s905x2) ++ - "amediatech,x96-max" (Meson g12a s905x2 using external PHY) ++ - "amediatech,x96-max-rmii" (Meson g12a s905x2 using internal PHY) + - "seirobotics,sei510" (Meson g12a s905x2) + + - "hardkernel,odroid-n2" (Meson g12b s922x) +diff --git a/arch/arm64/boot/dts/amlogic/Makefile b/arch/arm64/boot/dts/amlogic/Makefile +index 07b861fe5fa5..3eeda866ced1 100644 +--- a/arch/arm64/boot/dts/amlogic/Makefile ++++ b/arch/arm64/boot/dts/amlogic/Makefile +@@ -3,6 +3,7 @@ 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-g12a-x96-max-rmii.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-g12b-odroid-n2.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nanopi-k2.dtb + dtb-$(CONFIG_ARCH_MESON) += meson-gxbb-nexbox-a95x.dtb +diff --git a/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max-rmii.dts b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max-rmii.dts +new file mode 100644 +index 000000000000..72751bfe88d3 +--- /dev/null ++++ b/arch/arm64/boot/dts/amlogic/meson-g12a-x96-max-rmii.dts +@@ -0,0 +1,281 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR MIT) ++/* ++ * Copyright (c) 2018 BayLibre SAS. All rights reserved. ++ */ ++ ++/dts-v1/; ++ ++#include "meson-g12a.dtsi" ++#include ++#include ++ ++/ { ++ compatible = "amediatech,x96-max-rmii", "amlogic,u200", "amlogic,g12a"; ++ model = "Shenzhen Amediatech Technology Co., Ltd X96 Max"; ++ ++ aliases { ++ serial0 = &uart_AO; ++ ethernet0 = ðmac; ++ }; ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x40000000>; ++ }; ++ ++ cvbs-connector { ++ compatible = "composite-video-connector"; ++ ++ port { ++ cvbs_connector_in: endpoint { ++ remote-endpoint = <&cvbs_vdac_out>; ++ }; ++ }; ++ }; ++ ++ hdmi-connector { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_connector_in: endpoint { ++ remote-endpoint = <&hdmi_tx_tmds_out>; ++ }; ++ }; ++ }; ++ ++ 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>; ++ clocks = <&wifi32k>; ++ clock-names = "ext_clock"; ++ }; ++ ++ flash_1v8: regulator-flash_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "FLASH_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ dc_in: regulator-dc_in { ++ compatible = "regulator-fixed"; ++ regulator-name = "DC_IN"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ regulator-always-on; ++ }; ++ ++ vcc_1v8: regulator-vcc_1v8 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_1V8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ vin-supply = <&vcc_3v3>; ++ regulator-always-on; ++ }; ++ ++ vcc_3v3: regulator-vcc_3v3 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ vin-supply = <&vddao_3v3>; ++ regulator-always-on; ++ /* FIXME: actually controlled by VDDCPU_B_EN */ ++ }; ++ ++ vcc_5v: regulator-vcc_5v { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC_5V"; ++ regulator-min-microvolt = <5000000>; ++ regulator-max-microvolt = <5000000>; ++ vin-supply = <&dc_in>; ++ ++ gpio = <&gpio GPIOH_8 GPIO_OPEN_DRAIN>; ++ enable-active-low; ++ }; ++ ++ 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; ++ }; ++ ++ 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; ++ }; ++ ++ wifi32k: wifi32k { ++ compatible = "pwm-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <32768>; ++ pwms = <&pwm_ef 0 30518 0>; /* PWM_E at 32.768KHz */ ++ }; ++}; ++ ++&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>; ++}; ++ ++&cvbs_vdac_port { ++ cvbs_vdac_out: endpoint { ++ remote-endpoint = <&cvbs_connector_in>; ++ }; ++}; ++ ++&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>; ++ }; ++}; ++ ++&ir { ++ status = "okay"; ++ pinctrl-0 = <&remote_input_ao_pins>; ++ pinctrl-names = "default"; ++ linux,rc-map-name = "rc-x96max"; ++}; ++ ++&ext_mdio { ++ external_phy: ethernet-phy@0 { ++ compatible = "ethernet-phy-id001c.c916", "ethernet-phy-ieee802.3-c22"; ++ reg = <0>; ++ max-speed = <1000>; ++ eee-broken-1000t; ++ }; ++}; ++ ++ðmac { ++ status = "okay"; ++ pinctrl-0 = <ð_leds_pins>; ++ pinctrl-names = "default"; ++ phy-handle = <&internal_ephy>; ++ phy-mode = "rmii"; ++}; ++ ++&pwm_ef { ++ status = "okay"; ++ pinctrl-0 = <&pwm_e_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&uart_A { ++ status = "okay"; ++ pinctrl-0 = <&uart_a_pins>, <&uart_a_cts_rts_pins>; ++ pinctrl-names = "default"; ++ uart-has-rtscts; ++ ++ bluetooth { ++ compatible = "brcm,bcm43438-bt"; ++ shutdown-gpios = <&gpio GPIOX_17 GPIO_ACTIVE_HIGH>; ++ }; ++}; ++ ++&uart_AO { ++ status = "okay"; ++ pinctrl-0 = <&uart_ao_a_pins>; ++ pinctrl-names = "default"; ++}; ++ ++&usb { ++ status = "okay"; ++ dr_mode = "host"; ++}; ++ ++/* 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-sdr50; ++ max-frequency = <100000000>; ++ ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&sdio_pwrseq>; ++ ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddao_1v8>; ++ ++ brcmf: wifi@1 { ++ reg = <1>; ++ compatible = "brcm,bcm4329-fmac"; ++ }; ++}; ++ ++/* SD card */ ++&sd_emmc_b { ++ status = "okay"; ++ 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 = <100000000>; ++ disable-wp; ++ ++ cd-gpios = <&gpio GPIOC_6 GPIO_ACTIVE_LOW>; ++ vmmc-supply = <&vddao_3v3>; ++ vqmmc-supply = <&vddao_3v3>; ++}; ++ ++/* eMMC */ ++&sd_emmc_c { ++ status = "okay"; ++ pinctrl-0 = <&emmc_pins>, <&emmc_ds_pins>; ++ pinctrl-1 = <&emmc_clk_gate_pins>; ++ pinctrl-names = "default", "clk-gate"; ++ ++ bus-width = <8>; ++ cap-mmc-highspeed; ++ max-frequency = <100000000>; ++ non-removable; ++ disable-wp; ++ ++ mmc-pwrseq = <&emmc_pwrseq>; ++ vmmc-supply = <&vcc_3v3>; ++ vqmmc-supply = <&flash_1v8>; ++}; +-- +2.17.1 + From 301e10e6ac1b1bb01a0f88a8d3fce3653c6f3d4d Mon Sep 17 00:00:00 2001 From: kszaq Date: Sat, 11 May 2019 22:00:43 +0200 Subject: [PATCH 21/21] project: add README.md Borrow it from Rockchip, keep useful commands, remove everything else, TODO: expand. --- projects/Amlogic/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 projects/Amlogic/README.md diff --git a/projects/Amlogic/README.md b/projects/Amlogic/README.md new file mode 100644 index 0000000000..6c4a103bd4 --- /dev/null +++ b/projects/Amlogic/README.md @@ -0,0 +1,16 @@ +# Amlogic + +This project is for Amlogic SoC devices + +## Links + +* http://linux-meson.com + +## Useful debug commands + +* `cat /sys/kernel/debug/cec/cec0/status` +* `cat /sys/kernel/debug/clk/clk_summary` +* `cat /sys/class/drm/card0-HDMI-A-1/status` +* `hexdump -C /sys/class/drm/card0-HDMI-A-1/edid` +* `edid-decode /sys/class/drm/card0-HDMI-A-1/edid` +* `cat /sys/kernel/debug/dma_buf/bufinfo`