diff --git a/.github/workflows/Dockerfile.toolchain b/.github/workflows/Dockerfile.toolchain new file mode 100644 index 00000000000..949bc2bb5c2 --- /dev/null +++ b/.github/workflows/Dockerfile.toolchain @@ -0,0 +1,8 @@ +ARG OWNER_LC +ARG CONTAINER_TAG + +FROM ghcr.io/$OWNER_LC/tools:$CONTAINER_TAG + +ARG TOOLCHAIN_NAME + +ADD $TOOLCHAIN_NAME /external-toolchain/ diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52fba8e1063..78f856962e6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,9 @@ on: secrets: coverity_api_token: inputs: + container_name: + type: string + default: tools target: required: true type: string @@ -47,6 +50,10 @@ on: mbedtls wolfssl openssl + build_external_toolchain: + type: boolean + upload_external_toolchain: + type: boolean permissions: contents: read @@ -59,6 +66,7 @@ jobs: owner_lc: ${{ steps.lower_owner.outputs.owner_lc }} ccache_hash: ${{ steps.ccache_hash.outputs.ccache_hash }} container_tag: ${{ steps.determine_tools_container.outputs.container_tag }} + container_name: ${{ steps.determine_tools_container.outputs.container_name }} steps: - name: Checkout @@ -92,6 +100,7 @@ jobs: - name: Determine tools container tag id: determine_tools_container run: | + CONTAINER_NAME=${{ inputs.container_name }} CONTAINER_TAG=latest if [ -n "${{ github.base_ref }}" ]; then if echo "${{ github.base_ref }}" | grep -q -E '^openwrt-[0-9][0-9]\.[0-9][0-9]$'; then @@ -108,15 +117,29 @@ jobs: CONTAINER_TAG=openwrt-"$(echo ${{ github.ref_name }} | sed 's/^v\([0-9][0-9]\.[0-9][0-9]\)\..\+/\1/')" fi fi - echo "Tools container to use tools:$CONTAINER_TAG" + + if [ "$CONTAINER_NAME" = "toolchain" ]; then + GHCR_TOKEN=$(echo ${{ secrets.GITHUB_TOKEN }} | base64) + GHCR_HEADER="Authorization: Bearer ${GHCR_TOKEN}" + GHCR_MANIFEST_LINK=https://ghcr.io/v2/${{ steps.lower_owner.outputs.owner_lc }}/${{ inputs.container_name }}/manifests/${{ inputs.target }}-${{ inputs.subtarget }}-"$CONTAINER_TAG" + # Check if container exist + if [ $(curl -s -o /dev/null -w "%{http_code}" -H "$GHCR_HEADER" -I "$GHCR_MANIFEST_LINK") = 200 ]; then + CONTAINER_TAG=${{ inputs.target }}-${{ inputs.subtarget }}-"$CONTAINER_TAG" + else + CONTAINER_NAME=tools + fi + fi + + echo "Tools container to use $CONTAINER_NAME:$CONTAINER_TAG" echo "container_tag=$CONTAINER_TAG" >> $GITHUB_OUTPUT + echo "container_name=$CONTAINER_NAME" >> $GITHUB_OUTPUT build: name: Build ${{ inputs.target }}/${{ inputs.subtarget }} needs: setup_build runs-on: ubuntu-latest - container: ghcr.io/${{ needs.setup_build.outputs.owner_lc }}/tools:${{ needs.setup_build.outputs.container_tag }} + container: ghcr.io/${{ needs.setup_build.outputs.owner_lc }}/${{ needs.setup_build.outputs.container_name }}:${{ needs.setup_build.outputs.container_tag }} permissions: contents: read @@ -156,33 +179,16 @@ jobs: repository: openwrt/telephony path: openwrt/feeds/telephony - - name: Fix permission - run: | - chown -R buildbot:buildbot openwrt - - - name: Prepare prebuilt tools - shell: su buildbot -c "sh -e {0}" - working-directory: openwrt - run: | - mkdir -p staging_dir build_dir - ln -s /prebuilt_tools/staging_dir/host staging_dir/host - ln -s /prebuilt_tools/build_dir/host build_dir/host - - ./scripts/ext-tools.sh --refresh - - - name: Update & Install feeds - if: inputs.include_feeds == true - shell: su buildbot -c "sh -e {0}" - working-directory: openwrt - run: | - ./scripts/feeds update -a - ./scripts/feeds install -a - - name: Parse toolchain file if: inputs.build_toolchain == false id: parse-toolchain working-directory: openwrt run: | + if [ -d /external-toolchain/ ]; then + echo "toolchain-type=external_container" >> $GITHUB_OUTPUT + exit 0 + fi + TOOLCHAIN_PATH=snapshots if [ -n "${{ github.base_ref }}" ]; then @@ -227,6 +233,28 @@ jobs: echo "TOOLCHAIN_FILE=$TOOLCHAIN_FILE" >> "$GITHUB_ENV" echo "TOOLCHAIN_PATH=$TOOLCHAIN_PATH" >> "$GITHUB_ENV" + - name: Fix permission + run: | + chown -R buildbot:buildbot openwrt + + - name: Prepare prebuilt tools + shell: su buildbot -c "sh -e {0}" + working-directory: openwrt + run: | + mkdir -p staging_dir build_dir + ln -s /prebuilt_tools/staging_dir/host staging_dir/host + ln -s /prebuilt_tools/build_dir/host build_dir/host + + ./scripts/ext-tools.sh --refresh + + - name: Update & Install feeds + if: inputs.include_feeds == true + shell: su buildbot -c "sh -e {0}" + working-directory: openwrt + run: | + ./scripts/feeds update -a + ./scripts/feeds install -a + - name: Cache ccache uses: actions/cache@v3 with: @@ -236,7 +264,7 @@ jobs: ccache-kernel-${{ inputs.target }}/${{ inputs.subtarget }}- - name: Download external toolchain/sdk - if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type != 'internal' + if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type != 'internal' && steps.parse-toolchain.outputs.toolchain-type != 'external_container' shell: su buildbot -c "sh -e {0}" working-directory: openwrt run: | @@ -273,6 +301,20 @@ jobs: echo CONFIG_TARGET_PER_DEVICE_ROOTFS=y >> .config echo CONFIG_TARGET_ALL_PROFILES=y >> .config + - name: Configure external toolchain in container + if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type == 'external_container' + shell: su buildbot -c "sh -e {0}" + working-directory: openwrt + run: | + echo CONFIG_DEVEL=y >> .config + echo CONFIG_AUTOREMOVE=y >> .config + echo CONFIG_CCACHE=y >> .config + + ./scripts/ext-toolchain.sh \ + --toolchain /external-toolchain/$(ls /external-toolchain/ | grep openwrt-toolchain)/toolchain-* \ + --overwrite-config \ + --config ${{ inputs.target }}/${{ inputs.subtarget }} + - name: Configure external toolchain if: inputs.build_toolchain == false && steps.parse-toolchain.outputs.toolchain-type == 'external_toolchain' shell: su buildbot -c "sh -e {0}" @@ -376,6 +418,12 @@ jobs: working-directory: openwrt run: make -j$(nproc) BUILD_LOG=1 || ret=$? .github/workflows/scripts/show_build_failures.sh + - name: Build external toolchain + if: inputs.build_external_toolchain == true + shell: su buildbot -c "sh -e {0}" + working-directory: openwrt + run: make target/toolchain/compile -j$(nproc) BUILD_LOG=1 || ret=$? .github/workflows/scripts/show_build_failures.sh + - name: Coverity prepare toolchain if: inputs.coverity_check_packages != '' shell: su buildbot -c "sh -e {0}" @@ -433,3 +481,19 @@ jobs: with: name: ${{ inputs.target }}-${{ inputs.subtarget }}-logs path: "openwrt/logs" + + - name: Find external toolchain name + id: get-toolchain-name + if: inputs.upload_external_toolchain == true + working-directory: openwrt + run: | + TOOLCHAIN_NAME=$(ls bin/targets/${{inputs.target }}/${{ inputs.subtarget }} | grep toolchain) + echo "toolchain-name=$TOOLCHAIN_NAME" >> $GITHUB_OUTPUT + + - name: Upload prebuilt toolchain + if: inputs.upload_external_toolchain == true + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.target }}-${{ inputs.subtarget }}-external-toolchain + path: openwrt/bin/targets/${{ inputs.target }}/${{ inputs.subtarget }}/${{ steps.get-toolchain-name.outputs.toolchain-name }} + retention-days: 1 diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index db59ef8ca68..10355456321 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -17,6 +17,7 @@ jobs: packages: read uses: ./.github/workflows/build.yml with: + container_name: toolchain target: x86 subtarget: 64 build_full: true diff --git a/.github/workflows/kernel.yml b/.github/workflows/kernel.yml index 02aee8b27cc..6be7ef28c2f 100644 --- a/.github/workflows/kernel.yml +++ b/.github/workflows/kernel.yml @@ -17,6 +17,8 @@ on: - 'include/kernel*' - 'package/kernel/**' - 'target/linux/**' + branches-ignore: + - master permissions: contents: read @@ -109,6 +111,7 @@ jobs: include: ${{fromJson(needs.determine_targets.outputs.targets_subtargets)}} uses: ./.github/workflows/build.yml with: + container_name: toolchain target: ${{ matrix.target }} subtarget: ${{ matrix.subtarget }} build_kernel: true diff --git a/.github/workflows/label-kernel.yml b/.github/workflows/label-kernel.yml index 1156e0ad985..243d285e289 100644 --- a/.github/workflows/label-kernel.yml +++ b/.github/workflows/label-kernel.yml @@ -13,6 +13,7 @@ jobs: runs-on: ubuntu-latest outputs: target: ${{ steps.set_target.outputs.target }} + subtarget: ${{ steps.set_target.outputs.subtarget }} steps: - name: Set target @@ -20,7 +21,8 @@ jobs: env: CI_EVENT_LABEL_NAME: ${{ github.event.label.name }} run: | - echo "$CI_EVENT_LABEL_NAME" | sed -n 's/.*:\(.*\):\(.*\)$/target="\1\/\2"/p' | tee --append $GITHUB_OUTPUT + echo "$CI_EVENT_LABEL_NAME" | sed -n 's/.*:\(.*\):\(.*\)$/target="\1"/p' | tee --append $GITHUB_OUTPUT + echo "$CI_EVENT_LABEL_NAME" | sed -n 's/.*:\(.*\):\(.*\)$/subtarget="\2"/p' | tee --append $GITHUB_OUTPUT build_kernel: name: Build Kernel with external toolchain @@ -31,6 +33,7 @@ jobs: uses: ./.github/workflows/build.yml with: target: ${{ needs.set_target.outputs.target }} + subtarget: ${{ needs.set_target.outputs.subtarget }} build_kernel: true build_all_kmods: true @@ -43,3 +46,4 @@ jobs: uses: ./.github/workflows/check-kernel-patches.yml with: target: ${{ needs.set_target.outputs.target }} + subtarget: ${{ needs.set_target.outputs.subtarget }} diff --git a/.github/workflows/label-target.yml b/.github/workflows/label-target.yml index e1890240764..3a624598b1e 100644 --- a/.github/workflows/label-target.yml +++ b/.github/workflows/label-target.yml @@ -13,6 +13,7 @@ jobs: runs-on: ubuntu-latest outputs: target: ${{ steps.set_target.outputs.target }} + subtarget: ${{ steps.set_target.outputs.subtarget }} steps: - name: Set target @@ -20,7 +21,8 @@ jobs: env: CI_EVENT_LABEL_NAME: ${{ github.event.label.name }} run: | - echo "$CI_EVENT_LABEL_NAME" | sed -n 's/.*:\(.*\):\(.*\)$/target="\1\/\2"/p' | tee --append $GITHUB_OUTPUT + echo "$CI_EVENT_LABEL_NAME" | sed -n 's/.*:\(.*\):\(.*\)$/target="\1"/p' | tee --append $GITHUB_OUTPUT + echo "$CI_EVENT_LABEL_NAME" | sed -n 's/.*:\(.*\):\(.*\)$/subtarget="\2"/p' | tee --append $GITHUB_OUTPUT build_target: name: Build target @@ -31,6 +33,7 @@ jobs: uses: ./.github/workflows/build.yml with: target: ${{ needs.set_target.outputs.target }} + subtarget: ${{ needs.set_target.outputs.subtarget }} build_full: true build_all_kmods: true build_all_boards: true diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index e2f932b1ba3..d4d3565cd70 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -19,6 +19,8 @@ on: - 'package/**' - 'target/linux/generic/**' - 'toolchain/**' + branches-ignore: + - master permissions: contents: read @@ -43,6 +45,7 @@ jobs: subtarget: 64 uses: ./.github/workflows/build.yml with: + container_name: toolchain target: ${{ matrix.target }} subtarget: ${{ matrix.subtarget }} build_kernel: true diff --git a/.github/workflows/push-containers.yml b/.github/workflows/push-containers.yml index bad39c2fc2c..eb6ffd30c1e 100644 --- a/.github/workflows/push-containers.yml +++ b/.github/workflows/push-containers.yml @@ -3,10 +3,17 @@ name: Build and Push prebuilt tools container on: push: paths: + - 'include/version.mk' - 'tools/**' - '.github/workflows/build-tools.yml' - '.github/workflows/push-containers.yml' - '.github/workflows/Dockerfile.tools' + - 'toolchain/**' + - '.github/workflows/build.yml' + - '.github/workflows/toolchain.yml' + - '.github/workflows/Dockerfile.toolchain' + branches-ignore: + - master permissions: contents: read @@ -16,29 +23,21 @@ concurrency: cancel-in-progress: true jobs: - build-linux-buildbot: - name: Build tools with buildbot container - if: ${{ github.repository_owner == 'openwrt' }} - uses: ./.github/workflows/build-tools.yml - with: - generate_prebuilt_artifacts: true - - push-tools-container: - needs: build-linux-buildbot - name: Push prebuilt tools container + determine-container-info: + name: Determine needed info to push containers if: ${{ github.repository_owner == 'openwrt' }} runs-on: ubuntu-latest - - permissions: - contents: read - packages: write + outputs: + owner-lc: ${{ steps.generate-owner-lc.outputs.owner-lc }} + container-tag: ${{ steps.determine-container-tag.outputs.container-tag }} steps: - name: Set lower case owner name + id: generate-owner-lc env: OWNER: ${{ github.repository_owner }} run: | - echo "OWNER_LC=${OWNER,,}" >> "$GITHUB_ENV" + echo "owner-lc=${OWNER,,}" >> "$GITHUB_OUTPUT" # Per branch tools container tag # By default stick to latest @@ -49,6 +48,7 @@ jobs: # (example branch openwrt-22.03 -> tools:openwrt-22.03) # (example branch openwrt-22.03-test -> tools:openwrt-22.03) - name: Determine tools container tag + id: determine-container-tag run: | CONTAINER_TAG=latest @@ -62,9 +62,27 @@ jobs: fi fi - echo "Tools container to push tools:$CONTAINER_TAG" - echo "CONTAINER_TAG=$CONTAINER_TAG" >> "$GITHUB_ENV" + echo "Container tag to push for tools and toolchain is $CONTAINER_TAG" + echo "container-tag=$CONTAINER_TAG" >> "$GITHUB_OUTPUT" + build-linux-buildbot: + name: Build tools with buildbot container + if: ${{ github.repository_owner == 'openwrt' }} + uses: ./.github/workflows/build-tools.yml + with: + generate_prebuilt_artifacts: true + + push-tools-container: + needs: [ determine-container-info, build-linux-buildbot ] + if: ${{ github.repository_owner == 'openwrt' }} + name: Push prebuilt tools container + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: - name: Checkout uses: actions/checkout@v3 with: @@ -92,5 +110,110 @@ jobs: with: context: openwrt push: true - tags: ghcr.io/${{ env.OWNER_LC }}/tools:${{ env.CONTAINER_TAG }} + tags: ghcr.io/${{ needs.determine-container-info.outputs.owner-lc }}/tools:${{ needs.determine-container-info.outputs.container-tag }} file: openwrt/.github/workflows/Dockerfile.tools + + determine-targets: + name: Set targets + if: ${{ github.repository_owner == 'openwrt' }} + runs-on: ubuntu-latest + outputs: + target: ${{ steps.find_targets.outputs.target }} + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set targets + id: find_targets + run: | + export TARGETS="$(perl ./scripts/dump-target-info.pl targets 2>/dev/null \ + | awk '{ print $1 }')" + + JSON='[' + FIRST=1 + for TARGET in $TARGETS; do + TUPLE='{"target":"'"$(echo $TARGET | cut -d "/" -f 1)"'","subtarget":"'"$(echo $TARGET | cut -d "/" -f 2)"'"}' + [[ $FIRST -ne 1 ]] && JSON="$JSON"',' + JSON="$JSON""$TUPLE" + FIRST=0 + done + JSON="$JSON"']' + + echo -e "\n---- targets ----\n" + echo "$JSON" + echo -e "\n---- targets ----\n" + + echo "target=$JSON" >> $GITHUB_OUTPUT + + build: + name: Build Target Toolchain + if: ${{ github.repository_owner == 'openwrt' }} + needs: [ determine-targets, push-tools-container ] + permissions: + contents: read + packages: read + strategy: + fail-fast: False + matrix: + include: ${{fromJson(needs.determine-targets.outputs.target)}} + uses: ./.github/workflows/build.yml + with: + target: ${{ matrix.target }} + subtarget: ${{ matrix.subtarget }} + build_toolchain: true + build_external_toolchain: true + upload_external_toolchain: true + + push-toolchain-container: + name: Push Target Toolchain container + if: ${{ github.repository_owner == 'openwrt' }} + needs: [ determine-container-info, determine-targets, build ] + runs-on: ubuntu-latest + + strategy: + fail-fast: False + matrix: + include: ${{fromJson(needs.determine-targets.outputs.target)}} + + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: 'openwrt' + + - name: Download external toolchain from build job + uses: actions/download-artifact@v3 + with: + name: ${{ matrix.target }}-${{ matrix.subtarget }}-external-toolchain + path: openwrt + + - name: Find external toolchain name + id: get-toolchain-name + working-directory: openwrt + run: | + TOOLCHAIN_NAME=$(ls | grep toolchain-${{ matrix.target }}-${{ matrix.subtarget }}) + echo "toolchain-name=$TOOLCHAIN_NAME" >> $GITHUB_OUTPUT + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: openwrt + push: true + tags: ghcr.io/${{ needs.determine-container-info.outputs.owner-lc }}/toolchain:${{ matrix.target }}-${{ matrix.subtarget }}-${{ needs.determine-container-info.outputs.container-tag }} + file: openwrt/.github/workflows/Dockerfile.toolchain + build-args: | + OWNER_LC=${{ needs.determine-container-info.outputs.owner-lc }} + CONTAINER_TAG=${{ needs.determine-container-info.outputs.container-tag }} + TOOLCHAIN_NAME=${{ steps.get-toolchain-name.outputs.toolchain-name }} diff --git a/.github/workflows/toolchain.yml b/.github/workflows/toolchain.yml index 5755ca25b9d..54e31069e6f 100644 --- a/.github/workflows/toolchain.yml +++ b/.github/workflows/toolchain.yml @@ -11,6 +11,8 @@ on: - '.github/workflows/build.yml' - '.github/workflows/toolchain.yml' - 'toolchain/**' + branches-ignore: + - master permissions: contents: read diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index b9d712c2a69..83bf5e98f5a 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -3,14 +3,18 @@ name: Build host tools on: pull_request: paths: + - 'include/**' - 'tools/**' - '.github/workflows/build-tools.yml' - '.github/workflows/tools.yml' push: paths: + - 'include/**' - 'tools/**' - '.github/workflows/build-tools.yml' - '.github/workflows/tools.yml' + branches-ignore: + - master permissions: contents: read diff --git a/feeds.conf.default b/feeds.conf.default index 35b4e5f8cad..5a0c00a7006 100644 --- a/feeds.conf.default +++ b/feeds.conf.default @@ -1,4 +1,4 @@ src-git-full packages https://github.com/DifuseHQ/packages.git src-git-full luci https://github.com/DifuseHQ/luci.git src-git-full routing https://github.com/DifuseHQ/routing.git -src-git-full telephony https://github.com/DifuseHQ/telephony.git +src-git-full telephony https://github.com/DifuseHQ/telephony.git \ No newline at end of file diff --git a/include/prereq.mk b/include/prereq.mk index 5646b24efaa..74c3914d060 100644 --- a/include/prereq.mk +++ b/include/prereq.mk @@ -113,7 +113,7 @@ define SetupHostCommand ;; \ esac; \ ln -sf "$$$$$$$$bin" "$(STAGING_DIR_HOST)/bin/$(strip $(1))"; \ - exit 1; \ + exit 0; \ fi; \ fi; \ done; \ diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile index 248b48c3c15..a7472ee7794 100644 --- a/package/kernel/mac80211/Makefile +++ b/package/kernel/mac80211/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mac80211 PKG_VERSION:=6.1.24 -PKG_RELEASE:=3 +PKG_RELEASE:=4 # PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15.58/ PKG_SOURCE_URL:=http://mirror2.openwrt.org/sources/ PKG_HASH:=5d39aca7e34c33cb9b3e366117b2e86841b7bdd37933679d6b1e61be6b150648 diff --git a/package/kernel/mac80211/patches/subsys/315-v6.3-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch b/package/kernel/mac80211/patches/subsys/315-v6.3-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch index 6aec9bc85fc..59b799b6b17 100644 --- a/package/kernel/mac80211/patches/subsys/315-v6.3-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch +++ b/package/kernel/mac80211/patches/subsys/315-v6.3-wifi-mac80211-fix-receiving-A-MSDU-frames-on-mesh-in.patch @@ -1,5 +1,6 @@ +From 986e43b19ae9176093da35e0a844e65c8bf9ede7 Mon Sep 17 00:00:00 2001 From: Felix Fietkau -Date: Tue, 6 Dec 2022 11:15:02 +0100 +Date: Mon, 13 Feb 2023 11:08:54 +0100 Subject: [PATCH] wifi: mac80211: fix receiving A-MSDU frames on mesh interfaces @@ -33,7 +34,15 @@ For locally received packets, the Mesh Control header is stripped away. For forwarded packets, a new 802.11 header gets added. Signed-off-by: Felix Fietkau +Link: https://lore.kernel.org/r/20230213100855.34315-4-nbd@nbd.name +[fix fortify build error] +Signed-off-by: Johannes Berg --- + .../wireless/marvell/mwifiex/11n_rxreorder.c | 2 +- + include/net/cfg80211.h | 27 +- + net/mac80211/rx.c | 350 ++++++++++-------- + net/wireless/util.c | 120 +++--- + 4 files changed, 297 insertions(+), 202 deletions(-) --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -557,7 +566,7 @@ Signed-off-by: Felix Fietkau + memcpy(&payload.eth.h_source, mesh_addr, ETH_ALEN); + break; + case MESH_FLAGS_AE_A5_A6: -+ memcpy(&payload.eth.h_dest, mesh_addr, 2 * ETH_ALEN); ++ memcpy(&payload.eth, mesh_addr, 2 * ETH_ALEN); + break; + default: + break; diff --git a/package/kernel/qca-ssdk/Makefile b/package/kernel/qca-ssdk/Makefile index 62c60fc1bec..92f7b66490b 100644 --- a/package/kernel/qca-ssdk/Makefile +++ b/package/kernel/qca-ssdk/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qca-ssdk -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_URL:=https://git.codelinaro.org/clo/qsdk/oss/lklm/qca-ssdk.git PKG_SOURCE_PROTO:=git @@ -37,6 +37,8 @@ else TOOLCHAIN_BIN_PATH=$(TOOLCHAIN_DIR)/bin endif +LNX_CONFIG_OPTS = LNX_MAKEOPTS='$(KERNEL_MAKEOPTS)' MODULE_TYPE=KSLIB modules + MAKE_FLAGS+= \ TARGET_NAME=$(CONFIG_TARGET_NAME) \ TOOL_PATH=$(TOOLCHAIN_BIN_PATH) \ @@ -47,7 +49,7 @@ MAKE_FLAGS+= \ TARGET_SUFFIX=$(CONFIG_TARGET_SUFFIX) \ GCC_VERSION=$(GCC_VERSION) \ EXTRA_CFLAGS=-fno-stack-protector -I$(STAGING_DIR)/usr/include \ - $(KERNEL_MAKE_FLAGS) + $(LNX_CONFIG_OPTS) ifeq ($(CONFIG_TARGET_BOARD), "ipq807x") MAKE_FLAGS+= CHIP_TYPE=HPPE PTP_FEATURE=disable SWCONFIG_FEATURE=disable diff --git a/package/kernel/qca-ssdk/patches/0012-qca-ssdk-Support-Linux-Style-Makefile-for-SSDK.patch b/package/kernel/qca-ssdk/patches/0012-qca-ssdk-Support-Linux-Style-Makefile-for-SSDK.patch new file mode 100644 index 00000000000..91b7d570d8a --- /dev/null +++ b/package/kernel/qca-ssdk/patches/0012-qca-ssdk-Support-Linux-Style-Makefile-for-SSDK.patch @@ -0,0 +1,286 @@ +From edd3d4347cc73a99c7cf59aceeb1e8ad4d4dd303 Mon Sep 17 00:00:00 2001 +From: crao +Date: Tue, 15 Nov 2022 18:50:01 +0800 +Subject: [PATCH] [qca-ssdk]: Support Linux-Style Makefile for SSDK + +Change-Id: I8c4399433b6422ef6192f70bf08b0d3023cc94b6 +Signed-off-by: crao +--- + Makefile | 15 +++++++++++++ + Makefile.modules | 16 ++++++++++++++ + make/defs.mk | 1 + + make/linux_opt.mk | 54 ++++++++++++++++++++++++++++------------------- + make/target.mk | 12 +++++++++++ + src/api/Makefile | 2 +- + 6 files changed, 77 insertions(+), 23 deletions(-) + mode change 100755 => 100644 Makefile + create mode 100644 Makefile.modules + mode change 100755 => 100644 make/defs.mk + mode change 100755 => 100644 make/linux_opt.mk + mode change 100755 => 100644 make/target.mk + mode change 100755 => 100644 src/api/Makefile + +--- a/Makefile ++++ b/Makefile +@@ -12,6 +12,9 @@ include ./make/$(OS)_opt.mk + SUB_DIR=$(patsubst %/, %, $(dir $(wildcard src/*/Makefile))) + SUB_LIB=$(subst src/, , $(SUB_DIR)) + ++#################################################################### ++# SSDK-Style Makefile ++#################################################################### + all: $(BIN_DIR) kslib + mkdir -p ./temp/;cd ./temp;cp ../build/bin/ssdk_ks_km.a ./;ar -x ssdk_ks_km.a; cp ../ko_Makefile ./Makefile; + make -C $(SYS_PATH) M=$(PRJ_PATH)/temp/ CROSS_COMPILE=$(TOOLPREFIX) modules +@@ -20,6 +23,18 @@ all: $(BIN_DIR) kslib + rm -Rf ./temp/*.o ./temp/*.ko ./temp/*.a + @echo "---Build [SSDK-$(VERSION)] at $(BUILD_DATE) finished." + ++#################################################################### ++# LNX Modules-Style Makefile ++#################################################################### ++modules: $(BIN_DIR) kslib_c ++ cp Makefile.modules ./Makefile; ++ make -C $(SYS_PATH) M=$(PRJ_PATH)/ $(LNX_MAKEOPTS) modules ++ cp *.ko build/bin; ++ @echo "---Build [SSDK-$(VERSION)] at $(BUILD_DATE) finished." ++ ++kslib_c: ++ $(foreach i, $(SUB_LIB), $(MAKE) MODULE_TYPE=KSLIB -C src/$i src_list_loop || exit 1;) ++ + kslib:kslib_o + $(AR) -r $(BIN_DIR)/$(KS_MOD)_$(RUNMODE).a $(wildcard $(BLD_DIR)/KSLIB/*.o) + +--- /dev/null ++++ b/Makefile.modules +@@ -0,0 +1,16 @@ ++#################################################################### ++# Add All Local Flags ++#################################################################### ++ccflags-y += $(LNX_LOCAL_CFLAGS) -Wno-error ++ ++#################################################################### ++# Build Object List ++#################################################################### ++SRC_LIST := $(shell cat $(PRJ_PATH)/src_list.dep) ++OBJ_LIST := $(patsubst %.c,%.o,$(SRC_LIST)) ++ ++#################################################################### ++# Linux Kernel Module ++#################################################################### ++obj-m := qca-ssdk.o ++qca-ssdk-objs := $(OBJ_LIST) +--- a/make/defs.mk ++++ b/make/defs.mk +@@ -7,6 +7,7 @@ ifeq (,$(findstring $(LIB), $(COMPONENTS + endif + + SRC_FILE=$(addprefix $(PRJ_PATH)/$(LOC_DIR)/, $(SRC_LIST)) ++LOC_SRC_FILE=$(addprefix $(LOC_DIR)/, $(SRC_LIST)) + + OBJ_LIST=$(SRC_LIST:.c=.o) + OBJ_FILE=$(addprefix $(DST_DIR)/, $(OBJ_LIST)) +--- a/make/linux_opt.mk ++++ b/make/linux_opt.mk +@@ -295,7 +295,7 @@ ifeq (TRUE, $(DEBUG_ON)) + MODULE_CFLAG += -g + endif + +-MODULE_CFLAG += $(OPT_FLAG) -Wall -DVERSION=\"$(VERSION)\" -DBUILD_DATE=\"$(BUILD_DATE)\" -DOS=\"$(OS)\" -D"KBUILD_STR(s)=\#s" -D"KBUILD_MODNAME=KBUILD_STR(qca-ssdk)" ++MODULE_CFLAG += $(OPT_FLAG) -Wall -DVERSION=\"$(VERSION)\" -DBUILD_DATE=\"$(BUILD_DATE)\" -DOS=\"$(OS)\" -D"KBUILD_STR(s)=\#s" + + MODULE_INC += -I$(PRJ_PATH)/include \ + -I$(PRJ_PATH)/include/common \ +@@ -450,7 +450,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + MODULE_CFLAG += -DKVER34 + MODULE_CFLAG += -DKVER32 + MODULE_CFLAG += -DLNX26_22 +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/$(GCC_VERSION)/include/ \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/source/include \ +@@ -473,7 +473,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + MODULE_CFLAG += -DKVER32 + MODULE_CFLAG += -DLNX26_22 + ifeq ($(ARCH), arm64) +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/$(GCC_VERSION)/include/ \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/source \ +@@ -492,13 +492,13 @@ ifeq (KSLIB, $(MODULE_TYPE)) + -I$(SYS_PATH)/source/include/uapi + + ifneq ($(wildcard $(SYS_PATH)/include/linux/kconfig.h),) +- MODULE_INC += -include $(SYS_PATH)/include/linux/kconfig.h ++ SYS_INC += -include $(SYS_PATH)/include/linux/kconfig.h + else +- MODULE_INC += -include $(KERNEL_SRC)/include/linux/kconfig.h ++ SYS_INC += -include $(KERNEL_SRC)/include/linux/kconfig.h + endif + + else ifeq ($(ARCH), arm) +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/$(GCC_VERSION)/include/ \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/7.5.0/include/ \ + -I$(TOOL_PATH)/../../lib/armv7a-vfp-neon-rdk-linux-gnueabi/gcc/arm-rdk-linux-gnueabi/4.8.4/include/ \ +@@ -522,13 +522,13 @@ ifeq (KSLIB, $(MODULE_TYPE)) + -I$(TOOL_PATH)/../../lib/arm-rdk-linux-gnueabi/gcc/arm-rdk-linux-gnueabi/9.3.0/include/ + + ifneq ($(wildcard $(SYS_PATH)/include/linux/kconfig.h),) +- MODULE_INC += -include $(SYS_PATH)/include/linux/kconfig.h ++ SYS_INC += -include $(SYS_PATH)/include/linux/kconfig.h + else +- MODULE_INC += -include $(KERNEL_SRC)/include/linux/kconfig.h ++ SYS_INC += -include $(KERNEL_SRC)/include/linux/kconfig.h + endif + + else +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/$(GCC_VERSION)/include/ \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/source \ +@@ -564,7 +564,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + MODULE_CFLAG += -DLNX26_22 + ifeq ($(ARCH), arm64) + KCONF_FILE = $(SYS_PATH)/source/include/linux/kconfig.h +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/$(GCC_VERSION)/include/ \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/source/include \ +@@ -581,7 +581,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + -I$(SYS_PATH)/source/arch/arm64/include/asm/mach \ + -include $(KCONF_FILE) + else ifeq ($(ARCH), arm) +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/$(GCC_VERSION)/include/ \ + -I$(TOOL_PATH)/../../lib/armv7a-vfp-neon-rdk-linux-gnueabi/gcc/arm-rdk-linux-gnueabi/4.8.4/include/ \ + -I$(SYS_PATH)/include \ +@@ -604,7 +604,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + MODULE_CFLAG += -DKVER34 + MODULE_CFLAG += -DKVER32 + MODULE_CFLAG += -DLNX26_22 +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(TOOL_PATH)/../lib/gcc/$(TARGET_NAME)/$(GCC_VERSION)/include/ \ + -I$(TOOL_PATH)/../../lib/arm-poky-linux-gnueabi/gcc/arm-poky-linux-gnueabi/5.3.0/include/ \ + -I$(TOOL_PATH)/../../lib/armv7a-vfp-neon-rdk-linux-gnueabi/gcc/arm-rdk-linux-gnueabi/4.8.4/include/ \ +@@ -627,10 +627,10 @@ ifeq (KSLIB, $(MODULE_TYPE)) + -I$(EXT_PATH) \ + -I$(SYS_PATH)/source/arch/arm/include/asm/mach + ifneq ($(wildcard $(SYS_PATH)/include/linux/kconfig.h),) +- MODULE_INC += \ ++ SYS_INC += \ + -include $(SYS_PATH)/include/linux/kconfig.h + else +- MODULE_INC += \ ++ SYS_INC += \ + -include $(SYS_PATH)/source/include/linux/kconfig.h + endif + +@@ -641,7 +641,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + MODULE_CFLAG += -DKVER32 + MODULE_CFLAG += -DLNX26_22 + MODULE_CFLAG += -Werror +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/source/include \ + -I$(SYS_PATH)/source/arch/arm/mach-msm/include \ +@@ -657,7 +657,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + MODULE_CFLAG += -DKVER32 + MODULE_CFLAG += -DLNX26_22 + ifeq (mips, $(CPU)) +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/arch/mips/include \ + -I$(SYS_PATH)/arch/mips/include/asm/mach-ar7240 \ +@@ -678,7 +678,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + -O2 -fno-pic -pipe -mabi=32 -march=mips32r2 -DMODULE -mlong-calls -DEXPORT_SYMTAB + endif + else +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/arch/arm/include \ + -I$(SYS_PATH)/arch/arm/include/asm \ +@@ -695,7 +695,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + MODULE_CFLAG += -DKVER26 + MODULE_CFLAG += -DLNX26_22 + ifeq (mips, $(CPU)) +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/arch/mips/include \ + -I$(SYS_PATH)/arch/mips/include/asm/mach-ar7240 \ +@@ -708,7 +708,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + -O2 -fno-pic -pipe -mabi=32 -march=mips32r2 -DMODULE -mlong-calls -DEXPORT_SYMTAB + endif + else +- MODULE_INC += -I$(SYS_PATH) \ ++ SYS_INC += -I$(SYS_PATH) \ + -I$(SYS_PATH)/include \ + -I$(SYS_PATH)/arch/arm/include \ + -I$(SYS_PATH)/arch/arm/include/asm \ +@@ -721,8 +721,7 @@ ifeq (KSLIB, $(MODULE_TYPE)) + + endif + +- MODULE_CFLAG += -D__KERNEL__ -DKERNEL_MODULE $(CPU_CFLAG) +- ++ MODULE_CFLAG += -D__KERNEL__ -DKERNEL_MODULE + + endif + +@@ -748,4 +747,15 @@ ifneq (TRUE, $(KERNEL_MODE)) + endif + endif + +-LOCAL_CFLAGS += $(MODULE_INC) $(MODULE_CFLAG) $(EXTRA_CFLAGS) ++LOCAL_CFLAGS += $(MODULE_INC) $(SYS_INC) $(MODULE_CFLAG) $(EXTRA_CFLAGS) ++ ++#################################################################### ++# cflags for SSDK-Style Makefile ++#################################################################### ++LOCAL_CFLAGS += $(CPU_CFLAG) -D"KBUILD_MODNAME=KBUILD_STR(qca-ssdk)" ++ ++#################################################################### ++# cflags for LNX Modules-Style Makefile ++#################################################################### ++LNX_LOCAL_CFLAGS += $(MODULE_INC) $(MODULE_CFLAG) ${EXTRA_INC} ++export LNX_LOCAL_CFLAGS +--- a/make/target.mk ++++ b/make/target.mk +@@ -3,6 +3,18 @@ include $(PRJ_PATH)/make/$(OS)_opt.mk + + include $(PRJ_PATH)/make/tools.mk + ++#################################################################### ++# LNX Modules-Style Makefile ++#################################################################### ++src_list_loop: src_list ++ $(foreach i, $(SUB_DIR), $(MAKE) -C $(i) src_list_loop || exit 1;) ++ ++src_list: ++ echo -n "$(LOC_SRC_FILE) " >> $(PRJ_PATH)/src_list.dep ++ ++#################################################################### ++# SSDK-Style Makefile ++#################################################################### + obj: $(OBJ_LIST) + $(OBJ_LOOP) + +--- a/src/api/Makefile ++++ b/src/api/Makefile +@@ -1,4 +1,4 @@ +-LOC_DIR=src/sal ++LOC_DIR=src/api + LIB=API + + include $(PRJ_PATH)/make/config.mk diff --git a/package/kernel/qca-ssdk/patches/0013-qca-ssdk-fix-compilation-issue-in-Linux-Style-Makefi.patch b/package/kernel/qca-ssdk/patches/0013-qca-ssdk-fix-compilation-issue-in-Linux-Style-Makefi.patch new file mode 100644 index 00000000000..792cd9e31b5 --- /dev/null +++ b/package/kernel/qca-ssdk/patches/0013-qca-ssdk-fix-compilation-issue-in-Linux-Style-Makefi.patch @@ -0,0 +1,27 @@ +From 3026f89b06049df01d5fe19c5fccc972637aa344 Mon Sep 17 00:00:00 2001 +From: crao +Date: Tue, 7 Mar 2023 17:15:07 +0800 +Subject: [PATCH] [qca-ssdk]: fix compilation issue in Linux-Style Makefile + +Change-Id: If38251fc0a2bf4abc666d30f4812c0d9507310dc +Signed-off-by: crao +--- + Makefile | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + mode change 100644 => 100755 Makefile + +--- a/Makefile ++++ b/Makefile +@@ -27,9 +27,9 @@ all: $(BIN_DIR) kslib + # LNX Modules-Style Makefile + #################################################################### + modules: $(BIN_DIR) kslib_c +- cp Makefile.modules ./Makefile; +- make -C $(SYS_PATH) M=$(PRJ_PATH)/ $(LNX_MAKEOPTS) modules +- cp *.ko build/bin; ++ mkdir -p ./temp/;cp * ./temp -a;cd ./temp;cp ../Makefile.modules ./Makefile; ++ make -C $(SYS_PATH) M=$(PRJ_PATH)/temp $(LNX_MAKEOPTS) modules ++ cp temp/*.ko build/bin; + @echo "---Build [SSDK-$(VERSION)] at $(BUILD_DATE) finished." + + kslib_c: diff --git a/package/kernel/qca-ssdk/patches/0014-qca-ssdk-fix-compilation-issue-in-Miami-yocto.patch b/package/kernel/qca-ssdk/patches/0014-qca-ssdk-fix-compilation-issue-in-Miami-yocto.patch new file mode 100644 index 00000000000..53c0c341316 --- /dev/null +++ b/package/kernel/qca-ssdk/patches/0014-qca-ssdk-fix-compilation-issue-in-Miami-yocto.patch @@ -0,0 +1,23 @@ +From 6e4efd68e6e560a1994bc273fe6f7a72139f3957 Mon Sep 17 00:00:00 2001 +From: crao +Date: Wed, 15 Mar 2023 11:19:39 +0800 +Subject: [PATCH] [qca-ssdk]: fix compilation issue in Miami yocto + +Change-Id: I8526b9e43667d72ae9afa4ef8a13167088d194ba +Signed-off-by: crao +--- + Makefile | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/Makefile ++++ b/Makefile +@@ -29,7 +29,9 @@ all: $(BIN_DIR) kslib + modules: $(BIN_DIR) kslib_c + mkdir -p ./temp/;cp * ./temp -a;cd ./temp;cp ../Makefile.modules ./Makefile; + make -C $(SYS_PATH) M=$(PRJ_PATH)/temp $(LNX_MAKEOPTS) modules ++ cp $(PRJ_PATH)/temp/Module.symvers $(PRJ_PATH)/Module.symvers; + cp temp/*.ko build/bin; ++ rm -Rf ./temp/*.o ./temp/*.ko ./temp/*.a + @echo "---Build [SSDK-$(VERSION)] at $(BUILD_DATE) finished." + + kslib_c: diff --git a/package/kernel/ubnt-ledbar/Makefile b/package/kernel/ubnt-ledbar/Makefile index 90eccf1c21b..69236ffbb33 100644 --- a/package/kernel/ubnt-ledbar/Makefile +++ b/package/kernel/ubnt-ledbar/Makefile @@ -20,7 +20,7 @@ define KernelPackage/leds-ubnt-ledbar FILES:= \ $(PKG_BUILD_DIR)/leds-ubnt-ledbar.ko AUTOLOAD:=$(call AutoProbe,leds-ubnt-ledbar,1) - DEPENDS:=+kmod-i2c-core + DEPENDS:=@TARGET_mediatek_mt7622||TARGET_ramips_mt7621 +kmod-i2c-core endef define KernelPackage/leds-ubnt-ledbar/description diff --git a/package/kernel/ubnt-ledbar/src/leds-ubnt-ledbar.c b/package/kernel/ubnt-ledbar/src/leds-ubnt-ledbar.c index 555340c5e87..ee9d34601c6 100644 --- a/package/kernel/ubnt-ledbar/src/leds-ubnt-ledbar.c +++ b/package/kernel/ubnt-ledbar/src/leds-ubnt-ledbar.c @@ -9,6 +9,7 @@ #include #include #include +#include /** * Driver for the Ubiquiti RGB LED controller (LEDBAR). @@ -218,13 +219,19 @@ static int ubnt_ledbar_probe(struct i2c_client *client, return ubnt_ledbar_apply_state(ledbar); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) static int ubnt_ledbar_remove(struct i2c_client *client) +#else +static void ubnt_ledbar_remove(struct i2c_client *client) +#endif { struct ubnt_ledbar *ledbar = i2c_get_clientdata(client); mutex_destroy(&ledbar->lock); +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) return 0; +#endif } static const struct i2c_device_id ubnt_ledbar_id[] = { diff --git a/package/libs/libbpf/Makefile b/package/libs/libbpf/Makefile new file mode 100644 index 00000000000..ee7666f734d --- /dev/null +++ b/package/libs/libbpf/Makefile @@ -0,0 +1,75 @@ +# +# Copyright (C) 2020-2023 Tony Ambardar +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=libbpf +PKG_VERSION:=1.2.0 +PKG_RELEASE:=1 + +PKG_SOURCE_URL:=https://github.com/libbpf/libbpf +PKG_SOURCE_PROTO:=git +PKG_SOURCE_VERSION:=fbd60dbff51c870f5e80a17c4f2fd639eb80af90 +PKG_MIRROR_HASH:=80a80dfba71576e017b596fb28068e2a92de629e426f063e4b37314c8d576336 +PKG_ABI_VERSION:=$(firstword $(subst .,$(space),$(PKG_VERSION))) + +PKG_MAINTAINER:=Tony Ambardar + +PKG_BUILD_FLAGS:=no-mips16 +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/nls.mk + +define Package/libbpf + SECTION:=libs + CATEGORY:=Libraries + TITLE:=libbpf - eBPF helper library + LICENSE:=LGPL-2.1 OR BSD-2-Clause + ABI_VERSION:=$(PKG_ABI_VERSION) + URL:=http://www.kernel.org + DEPENDS:=+libelf +endef + +define Package/libbpf/description + libbpf is a library for loading eBPF programs and reading and manipulating eBPF objects from user-space. +endef + +MAKE_VARS = \ + EXTRA_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" + +MAKE_FLAGS += \ + $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \ + LIBSUBDIR=lib + +MAKE_PATH = src + +define Build/InstallDev/libbpf + $(INSTALL_DIR) $(1)/usr/include/bpf + $(CP) $(PKG_INSTALL_DIR)/usr/include/bpf/*.h $(1)/usr/include/bpf/ + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libbpf.{a,so*} \ + $(1)/usr/lib/ + $(INSTALL_DIR) $(1)/usr/lib/pkgconfig + $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libbpf.pc \ + $(1)/usr/lib/pkgconfig/ + $(SED) 's,/usr/include,$$$${prefix}/include,g' \ + $(1)/usr/lib/pkgconfig/libbpf.pc + $(SED) 's,/usr/lib,$$$${exec_prefix}/lib,g' \ + $(1)/usr/lib/pkgconfig/libbpf.pc +endef + +Build/InstallDev=$(Build/InstallDev/libbpf) + +define Package/libbpf/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libbpf.so.* $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,libbpf)) diff --git a/package/libs/libbpf/patches/001-cflags.patch b/package/libs/libbpf/patches/001-cflags.patch new file mode 100644 index 00000000000..d6ffc3f907f --- /dev/null +++ b/package/libs/libbpf/patches/001-cflags.patch @@ -0,0 +1,10 @@ +--- a/src/Makefile ++++ b/src/Makefile +@@ -34,6 +34,7 @@ ALL_CFLAGS := $(INCLUDES) + + SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED + ++CFLAGS = $(EXTRA_CFLAGS) + CFLAGS ?= -g -O2 -Werror -Wall -std=gnu89 + ALL_CFLAGS += $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(EXTRA_CFLAGS) + ALL_LDFLAGS += $(LDFLAGS) $(EXTRA_LDFLAGS) diff --git a/package/network/utils/bpftools/Makefile b/package/network/utils/bpftool/Makefile similarity index 55% rename from package/network/utils/bpftools/Makefile rename to package/network/utils/bpftool/Makefile index 047d2a0967e..cbbba2dba59 100644 --- a/package/network/utils/bpftools/Makefile +++ b/package/network/utils/bpftool/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2020 Tony Ambardar +# Copyright (C) 2020-2023 Tony Ambardar # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -8,14 +8,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=bpftools +PKG_VERSION:=7.2.0 PKG_RELEASE:=1 PKG_SOURCE_URL:=https://github.com/libbpf/bpftool PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=7.1.0 -PKG_SOURCE_VERSION:=b01941c8f7890489f09713348a7d89567538504b -PKG_MIRROR_HASH:=641fb337342e25ae784a3efe72c71d8c88600a326300d8d5834e26be21547015 -PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE)) +PKG_SOURCE_VERSION:=19ff0564980a7429e730f6987a0b0bf418b3c676 +PKG_MIRROR_HASH:=f9b9871f64986dd2e5dab7060bb919398256ba93964da49c62efaf0e6bc9bbc4 PKG_MAINTAINER:=Tony Ambardar @@ -63,27 +62,8 @@ define Package/bpftool-full/description eBPF programs and jited code. endef -define Package/libbpf - SECTION:=libs - CATEGORY:=Libraries - TITLE:=libbpf - eBPF helper library - VARIANT:=lib - LICENSE:=LGPL-2.1 OR BSD-2-Clause - ABI_VERSION:=$(PKG_ABI_VERSION) - URL:=http://www.kernel.org - DEPENDS:=+libelf -endef - -define Package/libbpf/description - libbpf is a library for loading eBPF programs and reading and manipulating eBPF objects from user-space. -endef - - -# LTO not compatible with DSO using PIC -ifneq ($(BUILD_VARIANT),lib) - TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto - TARGET_LDFLAGS += -Wl,--gc-sections -flto -endif +TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto +TARGET_LDFLAGS += -Wl,--gc-sections -flto ifeq ($(BUILD_VARIANT),full) full:=1 @@ -99,7 +79,6 @@ MAKE_FLAGS += \ OUTPUT="$(PKG_BUILD_DIR)/" \ prefix="/usr" \ $(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \ - LIBSUBDIR=lib \ check_feat=0 \ feature-clang-bpf-co-re=0 \ feature-libbfd=$(full) \ @@ -108,30 +87,7 @@ MAKE_FLAGS += \ feature-disassembler-four-args=1 \ feature-disassembler-init-styled=1 -ifeq ($(BUILD_VARIANT),lib) - MAKE_PATH = libbpf/src -else - MAKE_PATH = src -endif - -define Build/InstallDev/libbpf - $(INSTALL_DIR) $(1)/usr/include/bpf - $(CP) $(PKG_INSTALL_DIR)/usr/include/bpf/*.h $(1)/usr/include/bpf/ - $(INSTALL_DIR) $(1)/usr/lib - $(CP) $(PKG_INSTALL_DIR)/usr/lib/libbpf.{a,so*} \ - $(1)/usr/lib/ - $(INSTALL_DIR) $(1)/usr/lib/pkgconfig - $(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libbpf.pc \ - $(1)/usr/lib/pkgconfig/ - $(SED) 's,/usr/include,$$$${prefix}/include,g' \ - $(1)/usr/lib/pkgconfig/libbpf.pc - $(SED) 's,/usr/lib,$$$${exec_prefix}/lib,g' \ - $(1)/usr/lib/pkgconfig/libbpf.pc -endef - -ifeq ($(BUILD_VARIANT),lib) - Build/InstallDev=$(Build/InstallDev/libbpf) -endif +MAKE_PATH = src define Package/bpftool-$(BUILD_VARIANT)/install $(INSTALL_DIR) $(1)/usr/libexec @@ -139,11 +95,5 @@ define Package/bpftool-$(BUILD_VARIANT)/install $(1)/usr/libexec/bpftool-$(BUILD_VARIANT) endef -define Package/libbpf/install - $(INSTALL_DIR) $(1)/usr/lib - $(CP) $(PKG_INSTALL_DIR)/usr/lib/libbpf.so.* $(1)/usr/lib/ -endef - -$(eval $(call BuildPackage,libbpf)) $(eval $(call BuildPackage,bpftool-full)) $(eval $(call BuildPackage,bpftool-minimal)) diff --git a/package/network/utils/bpftools/patches/001-cflags.patch b/package/network/utils/bpftool/patches/001-cflags.patch similarity index 100% rename from package/network/utils/bpftools/patches/001-cflags.patch rename to package/network/utils/bpftool/patches/001-cflags.patch diff --git a/package/network/utils/bpftools/patches/002-includes.patch b/package/network/utils/bpftool/patches/002-includes.patch similarity index 100% rename from package/network/utils/bpftools/patches/002-includes.patch rename to package/network/utils/bpftool/patches/002-includes.patch diff --git a/target/linux/armvirt/64/config-5.15 b/target/linux/armvirt/64/config-5.15 index 19ae3dc0cfa..eb5405eb1ef 100644 --- a/target/linux/armvirt/64/config-5.15 +++ b/target/linux/armvirt/64/config-5.15 @@ -23,7 +23,6 @@ CONFIG_ARM64_ERRATUM_832075=y CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_HW_AFDBM=y CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y -CONFIG_ARM64_MODULE_PLTS=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PAN=y CONFIG_ARM64_PA_BITS=48 diff --git a/target/linux/bcm27xx/bcm2710/config-5.15 b/target/linux/bcm27xx/bcm2710/config-5.15 index 477d70fc66c..193bc7d5ee3 100644 --- a/target/linux/bcm27xx/bcm2710/config-5.15 +++ b/target/linux/bcm27xx/bcm2710/config-5.15 @@ -27,7 +27,6 @@ CONFIG_ARM64_ERRATUM_832075=y CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_HW_AFDBM=y CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y -CONFIG_ARM64_MODULE_PLTS=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PAN=y CONFIG_ARM64_PA_BITS=48 diff --git a/target/linux/bcm27xx/bcm2711/config-5.15 b/target/linux/bcm27xx/bcm2711/config-5.15 index 2f8f9dccb1b..e18728e49d6 100644 --- a/target/linux/bcm27xx/bcm2711/config-5.15 +++ b/target/linux/bcm27xx/bcm2711/config-5.15 @@ -27,7 +27,6 @@ CONFIG_ARM64_ERRATUM_832075=y CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_HW_AFDBM=y CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y -CONFIG_ARM64_MODULE_PLTS=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PAN=y CONFIG_ARM64_PA_BITS=48 diff --git a/target/linux/bcm27xx/patches-5.15/950-0281-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch b/target/linux/bcm27xx/patches-5.15/950-0281-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch index e756fa2fff6..bb0afb1a2a3 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0281-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0281-media-i2c-Add-driver-for-Sony-IMX477-sensor.patch @@ -25,7 +25,7 @@ Signed-off-by: Naushir Patuck --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -17538,6 +17538,14 @@ T: git git://linuxtv.org/media_tree.git +@@ -17541,6 +17541,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml F: drivers/media/i2c/imx412.c diff --git a/target/linux/bcm27xx/patches-5.15/950-0413-Documentation-devicetree-Add-documentation-for-imx37.patch b/target/linux/bcm27xx/patches-5.15/950-0413-Documentation-devicetree-Add-documentation-for-imx37.patch index 27fd0e57938..f9021eea55f 100644 --- a/target/linux/bcm27xx/patches-5.15/950-0413-Documentation-devicetree-Add-documentation-for-imx37.patch +++ b/target/linux/bcm27xx/patches-5.15/950-0413-Documentation-devicetree-Add-documentation-for-imx37.patch @@ -132,7 +132,7 @@ Signed-off-by: David Plowman +... --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -17552,6 +17552,7 @@ M: Raspberry Pi Kernel Maintenance +... --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -17556,6 +17556,14 @@ F: Documentation/devicetree/bindings/med +@@ -17559,6 +17559,14 @@ F: Documentation/devicetree/bindings/med F: Documentation/devicetree/bindings/media/i2c/imx477.yaml F: drivers/media/i2c/imx477.c diff --git a/target/linux/generic/backport-5.15/021-v6.4-mm-Multi-gen-LRU-remove-wait_event_killable.patch b/target/linux/generic/backport-5.15/021-v6.4-mm-Multi-gen-LRU-remove-wait_event_killable.patch new file mode 100644 index 00000000000..e154494a51e --- /dev/null +++ b/target/linux/generic/backport-5.15/021-v6.4-mm-Multi-gen-LRU-remove-wait_event_killable.patch @@ -0,0 +1,266 @@ +From 087ed25eaf5a78a678508e893f80addab9b1c103 Mon Sep 17 00:00:00 2001 +From: Kalesh Singh +Date: Thu, 13 Apr 2023 14:43:26 -0700 +Subject: [PATCH] mm: Multi-gen LRU: remove wait_event_killable() + +Android 14 and later default to MGLRU [1] and field telemetry showed +occasional long tail latency (>100ms) in the reclaim path. + +Tracing revealed priority inversion in the reclaim path. In +try_to_inc_max_seq(), when high priority tasks were blocked on +wait_event_killable(), the preemption of the low priority task to call +wake_up_all() caused those high priority tasks to wait longer than +necessary. In general, this problem is not different from others of its +kind, e.g., one caused by mutex_lock(). However, it is specific to MGLRU +because it introduced the new wait queue lruvec->mm_state.wait. + +The purpose of this new wait queue is to avoid the thundering herd +problem. If many direct reclaimers rush into try_to_inc_max_seq(), only +one can succeed, i.e., the one to wake up the rest, and the rest who +failed might cause premature OOM kills if they do not wait. So far there +is no evidence supporting this scenario, based on how often the wait has +been hit. And this begs the question how useful the wait queue is in +practice. + +Based on Minchan's recommendation, which is in line with his commit +6d4675e60135 ("mm: don't be stuck to rmap lock on reclaim path") and the +rest of the MGLRU code which also uses trylock when possible, remove the +wait queue. + +[1] https://android-review.googlesource.com/q/I7ed7fbfd6ef9ce10053347528125dd98c39e50bf + +Link: https://lkml.kernel.org/r/20230413214326.2147568-1-kaleshsingh@google.com +Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks") +Change-Id: I911f3968fd1adb25171279cc5b6f48ccb7efc8de +Signed-off-by: Kalesh Singh +Suggested-by: Minchan Kim +Reported-by: Wei Wang +Acked-by: Yu Zhao +Cc: Minchan Kim +Cc: Jan Alexander Steffens (heftig) +Cc: Oleksandr Natalenko +Cc: Suleiman Souhlal +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + include/linux/mmzone.h | 8 +-- + mm/vmscan.c | 111 +++++++++++++++-------------------------- + 2 files changed, 42 insertions(+), 77 deletions(-) + +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -452,18 +452,14 @@ enum { + struct lru_gen_mm_state { + /* set to max_seq after each iteration */ + unsigned long seq; +- /* where the current iteration continues (inclusive) */ ++ /* where the current iteration continues after */ + struct list_head *head; +- /* where the last iteration ended (exclusive) */ ++ /* where the last iteration ended before */ + struct list_head *tail; +- /* to wait for the last page table walker to finish */ +- struct wait_queue_head wait; + /* Bloom filters flip after each iteration */ + unsigned long *filters[NR_BLOOM_FILTERS]; + /* the mm stats for debugging */ + unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; +- /* the number of concurrent page table walkers */ +- int nr_walkers; + }; + + struct lru_gen_mm_walk { +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -2999,18 +2999,13 @@ void lru_gen_del_mm(struct mm_struct *mm + if (!lruvec) + continue; + +- /* where the last iteration ended (exclusive) */ ++ /* where the current iteration continues after */ ++ if (lruvec->mm_state.head == &mm->lru_gen.list) ++ lruvec->mm_state.head = lruvec->mm_state.head->prev; ++ ++ /* where the last iteration ended before */ + if (lruvec->mm_state.tail == &mm->lru_gen.list) + lruvec->mm_state.tail = lruvec->mm_state.tail->next; +- +- /* where the current iteration continues (inclusive) */ +- if (lruvec->mm_state.head != &mm->lru_gen.list) +- continue; +- +- lruvec->mm_state.head = lruvec->mm_state.head->next; +- /* the deletion ends the current iteration */ +- if (lruvec->mm_state.head == &mm_list->fifo) +- WRITE_ONCE(lruvec->mm_state.seq, lruvec->mm_state.seq + 1); + } + + list_del_init(&mm->lru_gen.list); +@@ -3194,68 +3189,54 @@ static bool iterate_mm_list(struct lruve + struct mm_struct **iter) + { + bool first = false; +- bool last = true; ++ bool last = false; + struct mm_struct *mm = NULL; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + struct lru_gen_mm_state *mm_state = &lruvec->mm_state; + + /* +- * There are four interesting cases for this page table walker: +- * 1. It tries to start a new iteration of mm_list with a stale max_seq; +- * there is nothing left to do. +- * 2. It's the first of the current generation, and it needs to reset +- * the Bloom filter for the next generation. +- * 3. It reaches the end of mm_list, and it needs to increment +- * mm_state->seq; the iteration is done. +- * 4. It's the last of the current generation, and it needs to reset the +- * mm stats counters for the next generation. ++ * mm_state->seq is incremented after each iteration of mm_list. There ++ * are three interesting cases for this page table walker: ++ * 1. It tries to start a new iteration with a stale max_seq: there is ++ * nothing left to do. ++ * 2. It started the next iteration: it needs to reset the Bloom filter ++ * so that a fresh set of PTE tables can be recorded. ++ * 3. It ended the current iteration: it needs to reset the mm stats ++ * counters and tell its caller to increment max_seq. + */ + spin_lock(&mm_list->lock); + + VM_WARN_ON_ONCE(mm_state->seq + 1 < walk->max_seq); +- VM_WARN_ON_ONCE(*iter && mm_state->seq > walk->max_seq); +- VM_WARN_ON_ONCE(*iter && !mm_state->nr_walkers); + +- if (walk->max_seq <= mm_state->seq) { +- if (!*iter) +- last = false; ++ if (walk->max_seq <= mm_state->seq) + goto done; +- } + +- if (!mm_state->nr_walkers) { +- VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); ++ if (!mm_state->head) ++ mm_state->head = &mm_list->fifo; + +- mm_state->head = mm_list->fifo.next; ++ if (mm_state->head == &mm_list->fifo) + first = true; +- } +- +- while (!mm && mm_state->head != &mm_list->fifo) { +- mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); + ++ do { + mm_state->head = mm_state->head->next; ++ if (mm_state->head == &mm_list->fifo) { ++ WRITE_ONCE(mm_state->seq, mm_state->seq + 1); ++ last = true; ++ break; ++ } + + /* force scan for those added after the last iteration */ +- if (!mm_state->tail || mm_state->tail == &mm->lru_gen.list) { +- mm_state->tail = mm_state->head; ++ if (!mm_state->tail || mm_state->tail == mm_state->head) { ++ mm_state->tail = mm_state->head->next; + walk->force_scan = true; + } + ++ mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); + if (should_skip_mm(mm, walk)) + mm = NULL; +- } +- +- if (mm_state->head == &mm_list->fifo) +- WRITE_ONCE(mm_state->seq, mm_state->seq + 1); ++ } while (!mm); + done: +- if (*iter && !mm) +- mm_state->nr_walkers--; +- if (!*iter && mm) +- mm_state->nr_walkers++; +- +- if (mm_state->nr_walkers) +- last = false; +- + if (*iter || last) + reset_mm_stats(lruvec, walk, last); + +@@ -3283,9 +3264,9 @@ static bool iterate_mm_list_nowalk(struc + + VM_WARN_ON_ONCE(mm_state->seq + 1 < max_seq); + +- if (max_seq > mm_state->seq && !mm_state->nr_walkers) { +- VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); +- ++ if (max_seq > mm_state->seq) { ++ mm_state->head = NULL; ++ mm_state->tail = NULL; + WRITE_ONCE(mm_state->seq, mm_state->seq + 1); + reset_mm_stats(lruvec, NULL, true); + success = true; +@@ -3894,10 +3875,6 @@ restart: + + walk_pmd_range(&val, addr, next, args); + +- /* a racy check to curtail the waiting time */ +- if (wq_has_sleeper(&walk->lruvec->mm_state.wait)) +- return 1; +- + if (need_resched() || walk->batched >= MAX_LRU_BATCH) { + end = (addr | ~PUD_MASK) + 1; + goto done; +@@ -3930,8 +3907,14 @@ static void walk_mm(struct lruvec *lruve + walk->next_addr = FIRST_USER_ADDRESS; + + do { ++ DEFINE_MAX_SEQ(lruvec); ++ + err = -EBUSY; + ++ /* another thread might have called inc_max_seq() */ ++ if (walk->max_seq != max_seq) ++ break; ++ + /* page_update_gen() requires stable page_memcg() */ + if (!mem_cgroup_trylock_pages(memcg)) + break; +@@ -4164,25 +4147,12 @@ static bool try_to_inc_max_seq(struct lr + success = iterate_mm_list(lruvec, walk, &mm); + if (mm) + walk_mm(lruvec, mm, walk); +- +- cond_resched(); + } while (mm); + done: +- if (!success) { +- if (sc->priority <= DEF_PRIORITY - 2) +- wait_event_killable(lruvec->mm_state.wait, +- max_seq < READ_ONCE(lrugen->max_seq)); +- return false; +- } ++ if (success) ++ inc_max_seq(lruvec, can_swap, force_scan); + +- VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); +- +- inc_max_seq(lruvec, can_swap, force_scan); +- /* either this sees any waiters or they will see updated max_seq */ +- if (wq_has_sleeper(&lruvec->mm_state.wait)) +- wake_up_all(&lruvec->mm_state.wait); +- +- return true; ++ return success; + } + + static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) +@@ -5746,7 +5716,6 @@ void lru_gen_init_lruvec(struct lruvec * + INIT_LIST_HEAD(&lrugen->pages[gen][type][zone]); + + lruvec->mm_state.seq = MIN_NR_GENS; +- init_waitqueue_head(&lruvec->mm_state.wait); + } + + #ifdef CONFIG_MEMCG diff --git a/target/linux/generic/backport-5.15/790-v6.4-0001-net-dsa-mt7530-make-some-noise-if-register-read-fail.patch b/target/linux/generic/backport-5.15/790-v6.4-0001-net-dsa-mt7530-make-some-noise-if-register-read-fail.patch new file mode 100644 index 00000000000..ffbdde5a577 --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0001-net-dsa-mt7530-make-some-noise-if-register-read-fail.patch @@ -0,0 +1,32 @@ +From b6f56cddb5f57a0b8da0ce582232a2f1933558c6 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:17:19 +0100 +Subject: [PATCH 04/16] net: dsa: mt7530: make some noise if register read + fails + +Simply returning the negative error value instead of the read value +doesn't seem like a good idea. Return 0 instead and add WARN_ON_ONCE(1) +so this kind of error will not go unnoticed. + +Suggested-by: Andrew Lunn +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -224,9 +224,10 @@ mt7530_mii_read(struct mt7530_priv *priv + /* MT7530 uses 31 as the pseudo port */ + ret = bus->write(bus, 0x1f, 0x1f, page); + if (ret < 0) { ++ WARN_ON_ONCE(1); + dev_err(&bus->dev, + "failed to read mt7530 register\n"); +- return ret; ++ return 0; + } + + lo = bus->read(bus, 0x1f, r); diff --git a/target/linux/generic/backport-5.15/790-v6.4-0002-net-dsa-mt7530-refactor-SGMII-PCS-creation.patch b/target/linux/generic/backport-5.15/790-v6.4-0002-net-dsa-mt7530-refactor-SGMII-PCS-creation.patch new file mode 100644 index 00000000000..8963d93d107 --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0002-net-dsa-mt7530-refactor-SGMII-PCS-creation.patch @@ -0,0 +1,111 @@ +From 9ecc00164dc2300dfcd40afe549a8ee951dfea9f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:17:30 +0100 +Subject: [PATCH 05/16] net: dsa: mt7530: refactor SGMII PCS creation + +Instead of macro templates use a dedidated function and allocated +regmap_config when creating the regmaps for the pcs-mtk-lynxi +instances. +This is in preparation to switching to use unlocked regmap accessors +and have regmap's locking API handle locking for us. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 74 +++++++++++++++++++++++++++------------- + 1 file changed, 50 insertions(+), 24 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2926,26 +2926,56 @@ static const struct regmap_bus mt7531_re + .reg_update_bits = mt7530_regmap_update_bits, + }; + +-#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \ +- { \ +- .name = _name, \ +- .reg_bits = 16, \ +- .val_bits = 32, \ +- .reg_stride = 4, \ +- .reg_base = _reg_base, \ +- .max_register = 0x17c, \ ++static int ++mt7531_create_sgmii(struct mt7530_priv *priv) ++{ ++ struct regmap_config *mt7531_pcs_config[2]; ++ struct phylink_pcs *pcs; ++ struct regmap *regmap; ++ int i, ret = 0; ++ ++ for (i = 0; i < 2; i++) { ++ mt7531_pcs_config[i] = devm_kzalloc(priv->dev, ++ sizeof(struct regmap_config), ++ GFP_KERNEL); ++ if (!mt7531_pcs_config[i]) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ mt7531_pcs_config[i]->name = i ? "port6" : "port5"; ++ mt7531_pcs_config[i]->reg_bits = 16; ++ mt7531_pcs_config[i]->val_bits = 32; ++ mt7531_pcs_config[i]->reg_stride = 4; ++ mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i); ++ mt7531_pcs_config[i]->max_register = 0x17c; ++ ++ regmap = devm_regmap_init(priv->dev, ++ &mt7531_regmap_bus, priv, ++ mt7531_pcs_config[i]); ++ if (IS_ERR(regmap)) { ++ ret = PTR_ERR(regmap); ++ break; ++ } ++ pcs = mtk_pcs_lynxi_create(priv->dev, regmap, ++ MT7531_PHYA_CTRL_SIGNAL3, 0); ++ if (!pcs) { ++ ret = -ENXIO; ++ break; ++ } ++ priv->ports[5 + i].sgmii_pcs = pcs; + } + +-static const struct regmap_config mt7531_pcs_config[] = { +- MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)), +- MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)), +-}; ++ if (ret && i) ++ mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs); ++ ++ return ret; ++} + + static int + mt753x_setup(struct dsa_switch *ds) + { + struct mt7530_priv *priv = ds->priv; +- struct regmap *regmap; + int i, ret; + + /* Initialise the PCS devices */ +@@ -2967,15 +2997,11 @@ mt753x_setup(struct dsa_switch *ds) + if (ret && priv->irq) + mt7530_free_irq_common(priv); + +- if (priv->id == ID_MT7531) +- for (i = 0; i < 2; i++) { +- regmap = devm_regmap_init(ds->dev, +- &mt7531_regmap_bus, priv, +- &mt7531_pcs_config[i]); +- priv->ports[5 + i].sgmii_pcs = +- mtk_pcs_lynxi_create(ds->dev, regmap, +- MT7531_PHYA_CTRL_SIGNAL3, 0); +- } ++ if (priv->id == ID_MT7531) { ++ ret = mt7531_create_sgmii(priv); ++ if (ret && priv->irq) ++ mt7530_free_irq_common(priv); ++ } + + return ret; + } diff --git a/target/linux/generic/backport-5.15/790-v6.4-0003-net-dsa-mt7530-use-unlocked-regmap-accessors.patch b/target/linux/generic/backport-5.15/790-v6.4-0003-net-dsa-mt7530-use-unlocked-regmap-accessors.patch new file mode 100644 index 00000000000..1b4a9561992 --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0003-net-dsa-mt7530-use-unlocked-regmap-accessors.patch @@ -0,0 +1,74 @@ +From 1bd099c49f65ed923b9f19b8c4b3cd1ff0024091 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:17:40 +0100 +Subject: [PATCH 06/16] net: dsa: mt7530: use unlocked regmap accessors + +Instead of wrapping the locked register accessor functions, use the +unlocked variants and add locking wrapper functions to let regmap +handle the locking. + +This is a preparation towards being able to always use regmap to +access switch registers instead of open-coded accessor functions. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2899,7 +2899,7 @@ static int mt7530_regmap_read(void *cont + { + struct mt7530_priv *priv = context; + +- *val = mt7530_read(priv, reg); ++ *val = mt7530_mii_read(priv, reg); + return 0; + }; + +@@ -2907,23 +2907,25 @@ static int mt7530_regmap_write(void *con + { + struct mt7530_priv *priv = context; + +- mt7530_write(priv, reg, val); ++ mt7530_mii_write(priv, reg, val); + return 0; + }; + +-static int mt7530_regmap_update_bits(void *context, unsigned int reg, +- unsigned int mask, unsigned int val) ++static void ++mt7530_mdio_regmap_lock(void *mdio_lock) + { +- struct mt7530_priv *priv = context; ++ mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED); ++} + +- mt7530_rmw(priv, reg, mask, val); +- return 0; +-}; ++static void ++mt7530_mdio_regmap_unlock(void *mdio_lock) ++{ ++ mutex_unlock(mdio_lock); ++} + + static const struct regmap_bus mt7531_regmap_bus = { + .reg_write = mt7530_regmap_write, + .reg_read = mt7530_regmap_read, +- .reg_update_bits = mt7530_regmap_update_bits, + }; + + static int +@@ -2949,6 +2951,9 @@ mt7531_create_sgmii(struct mt7530_priv * + mt7531_pcs_config[i]->reg_stride = 4; + mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i); + mt7531_pcs_config[i]->max_register = 0x17c; ++ mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock; ++ mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock; ++ mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock; + + regmap = devm_regmap_init(priv->dev, + &mt7531_regmap_bus, priv, diff --git a/target/linux/generic/backport-5.15/790-v6.4-0004-net-dsa-mt7530-use-regmap-to-access-switch-register-.patch b/target/linux/generic/backport-5.15/790-v6.4-0004-net-dsa-mt7530-use-regmap-to-access-switch-register-.patch new file mode 100644 index 00000000000..2d8bab9da63 --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0004-net-dsa-mt7530-use-regmap-to-access-switch-register-.patch @@ -0,0 +1,224 @@ +From a08c045580e060a6886bbb656c50ae20b0c780b5 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:17:52 +0100 +Subject: [PATCH 07/16] net: dsa: mt7530: use regmap to access switch register + space + +Use regmap API to access the switch register space. + +Signed-off-by: Daniel Golle +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 99 ++++++++++++++++++++++++---------------- + drivers/net/dsa/mt7530.h | 2 + + 2 files changed, 62 insertions(+), 39 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -183,9 +183,9 @@ core_clear(struct mt7530_priv *priv, u32 + } + + static int +-mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val) ++mt7530_regmap_write(void *context, unsigned int reg, unsigned int val) + { +- struct mii_bus *bus = priv->bus; ++ struct mii_bus *bus = context; + u16 page, r, lo, hi; + int ret; + +@@ -197,24 +197,34 @@ mt7530_mii_write(struct mt7530_priv *pri + /* MT7530 uses 31 as the pseudo port */ + ret = bus->write(bus, 0x1f, 0x1f, page); + if (ret < 0) +- goto err; ++ return ret; + + ret = bus->write(bus, 0x1f, r, lo); + if (ret < 0) +- goto err; ++ return ret; + + ret = bus->write(bus, 0x1f, 0x10, hi); +-err: ++ return ret; ++} ++ ++static int ++mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ int ret; ++ ++ ret = regmap_write(priv->regmap, reg, val); ++ + if (ret < 0) +- dev_err(&bus->dev, ++ dev_err(priv->dev, + "failed to write mt7530 register\n"); ++ + return ret; + } + +-static u32 +-mt7530_mii_read(struct mt7530_priv *priv, u32 reg) ++static int ++mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val) + { +- struct mii_bus *bus = priv->bus; ++ struct mii_bus *bus = context; + u16 page, r, lo, hi; + int ret; + +@@ -223,17 +233,32 @@ mt7530_mii_read(struct mt7530_priv *priv + + /* MT7530 uses 31 as the pseudo port */ + ret = bus->write(bus, 0x1f, 0x1f, page); +- if (ret < 0) { ++ if (ret < 0) ++ return ret; ++ ++ lo = bus->read(bus, 0x1f, r); ++ hi = bus->read(bus, 0x1f, 0x10); ++ ++ *val = (hi << 16) | (lo & 0xffff); ++ ++ return 0; ++} ++ ++static u32 ++mt7530_mii_read(struct mt7530_priv *priv, u32 reg) ++{ ++ int ret; ++ u32 val; ++ ++ ret = regmap_read(priv->regmap, reg, &val); ++ if (ret) { + WARN_ON_ONCE(1); +- dev_err(&bus->dev, ++ dev_err(priv->dev, + "failed to read mt7530 register\n"); + return 0; + } + +- lo = bus->read(bus, 0x1f, r); +- hi = bus->read(bus, 0x1f, 0x10); +- +- return (hi << 16) | (lo & 0xffff); ++ return val; + } + + static void +@@ -283,14 +308,10 @@ mt7530_rmw(struct mt7530_priv *priv, u32 + u32 mask, u32 set) + { + struct mii_bus *bus = priv->bus; +- u32 val; + + mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); + +- val = mt7530_mii_read(priv, reg); +- val &= ~mask; +- val |= set; +- mt7530_mii_write(priv, reg, val); ++ regmap_update_bits(priv->regmap, reg, mask, set); + + mutex_unlock(&bus->mdio_lock); + } +@@ -298,7 +319,7 @@ mt7530_rmw(struct mt7530_priv *priv, u32 + static void + mt7530_set(struct mt7530_priv *priv, u32 reg, u32 val) + { +- mt7530_rmw(priv, reg, 0, val); ++ mt7530_rmw(priv, reg, val, val); + } + + static void +@@ -2895,22 +2916,6 @@ static const struct phylink_pcs_ops mt75 + .pcs_an_restart = mt7530_pcs_an_restart, + }; + +-static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val) +-{ +- struct mt7530_priv *priv = context; +- +- *val = mt7530_mii_read(priv, reg); +- return 0; +-}; +- +-static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val) +-{ +- struct mt7530_priv *priv = context; +- +- mt7530_mii_write(priv, reg, val); +- return 0; +-}; +- + static void + mt7530_mdio_regmap_lock(void *mdio_lock) + { +@@ -2923,7 +2928,7 @@ mt7530_mdio_regmap_unlock(void *mdio_loc + mutex_unlock(mdio_lock); + } + +-static const struct regmap_bus mt7531_regmap_bus = { ++static const struct regmap_bus mt7530_regmap_bus = { + .reg_write = mt7530_regmap_write, + .reg_read = mt7530_regmap_read, + }; +@@ -2956,7 +2961,7 @@ mt7531_create_sgmii(struct mt7530_priv * + mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock; + + regmap = devm_regmap_init(priv->dev, +- &mt7531_regmap_bus, priv, ++ &mt7530_regmap_bus, priv->bus, + mt7531_pcs_config[i]); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); +@@ -3121,6 +3126,7 @@ MODULE_DEVICE_TABLE(of, mt7530_of_match) + static int + mt7530_probe(struct mdio_device *mdiodev) + { ++ static struct regmap_config *regmap_config; + struct mt7530_priv *priv; + struct device_node *dn; + +@@ -3200,6 +3206,21 @@ mt7530_probe(struct mdio_device *mdiodev + mutex_init(&priv->reg_mutex); + dev_set_drvdata(&mdiodev->dev, priv); + ++ regmap_config = devm_kzalloc(&mdiodev->dev, sizeof(*regmap_config), ++ GFP_KERNEL); ++ if (!regmap_config) ++ return -ENOMEM; ++ ++ regmap_config->reg_bits = 16; ++ regmap_config->val_bits = 32; ++ regmap_config->reg_stride = 4; ++ regmap_config->max_register = MT7530_CREV; ++ regmap_config->disable_locking = true; ++ priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, ++ priv->bus, regmap_config); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ + return dsa_register_switch(priv->ds); + } + +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -747,6 +747,7 @@ struct mt753x_info { + * @dev: The device pointer + * @ds: The pointer to the dsa core structure + * @bus: The bus used for the device and built-in PHY ++ * @regmap: The regmap instance representing all switch registers + * @rstc: The pointer to reset control used by MCM + * @core_pwr: The power supplied into the core + * @io_pwr: The power supplied into the I/O +@@ -767,6 +768,7 @@ struct mt7530_priv { + struct device *dev; + struct dsa_switch *ds; + struct mii_bus *bus; ++ struct regmap *regmap; + struct reset_control *rstc; + struct regulator *core_pwr; + struct regulator *io_pwr; diff --git a/target/linux/generic/backport-5.15/790-v6.4-0005-net-dsa-mt7530-move-SGMII-PCS-creation-to-mt7530_pro.patch b/target/linux/generic/backport-5.15/790-v6.4-0005-net-dsa-mt7530-move-SGMII-PCS-creation-to-mt7530_pro.patch new file mode 100644 index 00000000000..0bb64c3c5e9 --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0005-net-dsa-mt7530-move-SGMII-PCS-creation-to-mt7530_pro.patch @@ -0,0 +1,54 @@ +From 6de2852297737171ba96b91e89bf302ca1fda869 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:18:04 +0100 +Subject: [PATCH 08/16] net: dsa: mt7530: move SGMII PCS creation to + mt7530_probe function + +Move creating the SGMII PCS from mt753x_setup() to the more appropriate +mt7530_probe() function. +This is done also in preparation of moving all functions related to +MDIO-connected MT753x switches to a separate module. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -3007,12 +3007,6 @@ mt753x_setup(struct dsa_switch *ds) + if (ret && priv->irq) + mt7530_free_irq_common(priv); + +- if (priv->id == ID_MT7531) { +- ret = mt7531_create_sgmii(priv); +- if (ret && priv->irq) +- mt7530_free_irq_common(priv); +- } +- + return ret; + } + +@@ -3129,6 +3123,7 @@ mt7530_probe(struct mdio_device *mdiodev + static struct regmap_config *regmap_config; + struct mt7530_priv *priv; + struct device_node *dn; ++ int ret; + + dn = mdiodev->dev.of_node; + +@@ -3221,6 +3216,12 @@ mt7530_probe(struct mdio_device *mdiodev + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + ++ if (priv->id == ID_MT7531) { ++ ret = mt7531_create_sgmii(priv); ++ if (ret) ++ return ret; ++ } ++ + return dsa_register_switch(priv->ds); + } + diff --git a/target/linux/generic/backport-5.15/790-v6.4-0006-net-dsa-mt7530-introduce-mutex-helpers.patch b/target/linux/generic/backport-5.15/790-v6.4-0006-net-dsa-mt7530-introduce-mutex-helpers.patch new file mode 100644 index 00000000000..c23f96e7a66 --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0006-net-dsa-mt7530-introduce-mutex-helpers.patch @@ -0,0 +1,273 @@ +From 1557c679f71c82a994eae0baadbaeb62b71e15bf Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:18:16 +0100 +Subject: [PATCH 09/16] net: dsa: mt7530: introduce mutex helpers + +As the MDIO bus lock only needs to be involved if actually operating +on an MDIO-connected switch we will need to skip locking for built-in +switches which are accessed via MMIO. +Create helper functions which simplify that upcoming change. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 73 ++++++++++++++++++++-------------------- + 1 file changed, 36 insertions(+), 37 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -143,31 +143,40 @@ err: + } + + static void +-core_write(struct mt7530_priv *priv, u32 reg, u32 val) ++mt7530_mutex_lock(struct mt7530_priv *priv) + { +- struct mii_bus *bus = priv->bus; ++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); ++} + +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++static void ++mt7530_mutex_unlock(struct mt7530_priv *priv) ++{ ++ mutex_unlock(&priv->bus->mdio_lock); ++} ++ ++static void ++core_write(struct mt7530_priv *priv, u32 reg, u32 val) ++{ ++ mt7530_mutex_lock(priv); + + core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); + +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + } + + static void + core_rmw(struct mt7530_priv *priv, u32 reg, u32 mask, u32 set) + { +- struct mii_bus *bus = priv->bus; + u32 val; + +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + + val = core_read_mmd_indirect(priv, reg, MDIO_MMD_VEND2); + val &= ~mask; + val |= set; + core_write_mmd_indirect(priv, reg, MDIO_MMD_VEND2, val); + +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + } + + static void +@@ -264,13 +273,11 @@ mt7530_mii_read(struct mt7530_priv *priv + static void + mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val) + { +- struct mii_bus *bus = priv->bus; +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + + mt7530_mii_write(priv, reg, val); + +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + } + + static u32 +@@ -282,14 +289,13 @@ _mt7530_unlocked_read(struct mt7530_dumm + static u32 + _mt7530_read(struct mt7530_dummy_poll *p) + { +- struct mii_bus *bus = p->priv->bus; + u32 val; + +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(p->priv); + + val = mt7530_mii_read(p->priv, p->reg); + +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(p->priv); + + return val; + } +@@ -307,13 +313,11 @@ static void + mt7530_rmw(struct mt7530_priv *priv, u32 reg, + u32 mask, u32 set) + { +- struct mii_bus *bus = priv->bus; +- +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + + regmap_update_bits(priv->regmap, reg, mask, set); + +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + } + + static void +@@ -645,14 +649,13 @@ static int + mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad, + int regnum) + { +- struct mii_bus *bus = priv->bus; + struct mt7530_dummy_poll p; + u32 reg, val; + int ret; + + INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); + +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, + !(val & MT7531_PHY_ACS_ST), 20, 100000); +@@ -685,7 +688,7 @@ mt7531_ind_c45_phy_read(struct mt7530_pr + + ret = val & MT7531_MDIO_RW_DATA_MASK; + out: +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + + return ret; + } +@@ -694,14 +697,13 @@ static int + mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad, + int regnum, u32 data) + { +- struct mii_bus *bus = priv->bus; + struct mt7530_dummy_poll p; + u32 val, reg; + int ret; + + INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); + +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, + !(val & MT7531_PHY_ACS_ST), 20, 100000); +@@ -733,7 +735,7 @@ mt7531_ind_c45_phy_write(struct mt7530_p + } + + out: +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + + return ret; + } +@@ -741,14 +743,13 @@ out: + static int + mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum) + { +- struct mii_bus *bus = priv->bus; + struct mt7530_dummy_poll p; + int ret; + u32 val; + + INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); + +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val, + !(val & MT7531_PHY_ACS_ST), 20, 100000); +@@ -771,7 +772,7 @@ mt7531_ind_c22_phy_read(struct mt7530_pr + + ret = val & MT7531_MDIO_RW_DATA_MASK; + out: +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + + return ret; + } +@@ -780,14 +781,13 @@ static int + mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum, + u16 data) + { +- struct mii_bus *bus = priv->bus; + struct mt7530_dummy_poll p; + int ret; + u32 reg; + + INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC); + +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + + ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg, + !(reg & MT7531_PHY_ACS_ST), 20, 100000); +@@ -809,7 +809,7 @@ mt7531_ind_c22_phy_write(struct mt7530_p + } + + out: +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + + return ret; + } +@@ -1109,7 +1109,6 @@ static int + mt7530_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu) + { + struct mt7530_priv *priv = ds->priv; +- struct mii_bus *bus = priv->bus; + int length; + u32 val; + +@@ -1120,7 +1119,7 @@ mt7530_port_change_mtu(struct dsa_switch + if (!dsa_is_cpu_port(ds, port)) + return 0; + +- mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + + val = mt7530_mii_read(priv, MT7530_GMACCR); + val &= ~MAX_RX_PKT_LEN_MASK; +@@ -1141,7 +1140,7 @@ mt7530_port_change_mtu(struct dsa_switch + + mt7530_mii_write(priv, MT7530_GMACCR, val); + +- mutex_unlock(&bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + + return 0; + } +@@ -1937,10 +1936,10 @@ mt7530_irq_thread_fn(int irq, void *dev_ + u32 val; + int p; + +- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + val = mt7530_mii_read(priv, MT7530_SYS_INT_STS); + mt7530_mii_write(priv, MT7530_SYS_INT_STS, val); +- mutex_unlock(&priv->bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + + for (p = 0; p < MT7530_NUM_PHYS; p++) { + if (BIT(p) & val) { +@@ -1976,7 +1975,7 @@ mt7530_irq_bus_lock(struct irq_data *d) + { + struct mt7530_priv *priv = irq_data_get_irq_chip_data(d); + +- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); ++ mt7530_mutex_lock(priv); + } + + static void +@@ -1985,7 +1984,7 @@ mt7530_irq_bus_sync_unlock(struct irq_da + struct mt7530_priv *priv = irq_data_get_irq_chip_data(d); + + mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable); +- mutex_unlock(&priv->bus->mdio_lock); ++ mt7530_mutex_unlock(priv); + } + + static struct irq_chip mt7530_irq_chip = { diff --git a/target/linux/generic/backport-5.15/790-v6.4-0007-net-dsa-mt7530-move-p5_intf_modes-function-to-mt7530.patch b/target/linux/generic/backport-5.15/790-v6.4-0007-net-dsa-mt7530-move-p5_intf_modes-function-to-mt7530.patch new file mode 100644 index 00000000000..bd7ca33f6ed --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0007-net-dsa-mt7530-move-p5_intf_modes-function-to-mt7530.patch @@ -0,0 +1,75 @@ +From 25d15dee34a1a40d5fd71636a205e3211f09fd1d Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:18:28 +0100 +Subject: [PATCH 10/16] net: dsa: mt7530: move p5_intf_modes() function to + mt7530.c + +In preparation of splitting mt7530.c into a driver for MDIO-connected +as well as MDIO-accessed built-in switches on one hand and MMIO-accessed +built-in switches move the p5_inft_modes() function from mt7530.h to +mt7530.c. The function is only needed there and will trigger a compiler +warning about a defined but unused function otherwise when including +mt7530.h in the to-be-introduced bus-specific drivers. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 18 ++++++++++++++++++ + drivers/net/dsa/mt7530.h | 18 ------------------ + 2 files changed, 18 insertions(+), 18 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -950,6 +950,24 @@ mt7530_set_ageing_time(struct dsa_switch + return 0; + } + ++static const char *p5_intf_modes(unsigned int p5_interface) ++{ ++ switch (p5_interface) { ++ case P5_DISABLED: ++ return "DISABLED"; ++ case P5_INTF_SEL_PHY_P0: ++ return "PHY P0"; ++ case P5_INTF_SEL_PHY_P4: ++ return "PHY P4"; ++ case P5_INTF_SEL_GMAC5: ++ return "GMAC5"; ++ case P5_INTF_SEL_GMAC5_SGMII: ++ return "GMAC5_SGMII"; ++ default: ++ return "unknown"; ++ } ++} ++ + static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface) + { + struct mt7530_priv *priv = ds->priv; +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -682,24 +682,6 @@ enum p5_interface_select { + P5_INTF_SEL_GMAC5_SGMII, + }; + +-static const char *p5_intf_modes(unsigned int p5_interface) +-{ +- switch (p5_interface) { +- case P5_DISABLED: +- return "DISABLED"; +- case P5_INTF_SEL_PHY_P0: +- return "PHY P0"; +- case P5_INTF_SEL_PHY_P4: +- return "PHY P4"; +- case P5_INTF_SEL_GMAC5: +- return "GMAC5"; +- case P5_INTF_SEL_GMAC5_SGMII: +- return "GMAC5_SGMII"; +- default: +- return "unknown"; +- } +-} +- + struct mt7530_priv; + + struct mt753x_pcs { diff --git a/target/linux/generic/backport-5.15/790-v6.4-0008-net-dsa-mt7530-introduce-mt7530_probe_common-helper-.patch b/target/linux/generic/backport-5.15/790-v6.4-0008-net-dsa-mt7530-introduce-mt7530_probe_common-helper-.patch new file mode 100644 index 00000000000..34a1bd7372d --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0008-net-dsa-mt7530-introduce-mt7530_probe_common-helper-.patch @@ -0,0 +1,155 @@ +From 37c9c0d8d0b2e24f8c9af72ecd4edd31537284d3 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:18:39 +0100 +Subject: [PATCH 11/16] net: dsa: mt7530: introduce mt7530_probe_common helper + function + +Move commonly used parts from mt7530_probe into new mt7530_probe_common +helper function which will be used by both, mt7530_probe and the +to-be-introduced mt7988_probe. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 98 ++++++++++++++++++++++------------------ + 1 file changed, 54 insertions(+), 44 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -3135,44 +3135,21 @@ static const struct of_device_id mt7530_ + MODULE_DEVICE_TABLE(of, mt7530_of_match); + + static int +-mt7530_probe(struct mdio_device *mdiodev) ++mt7530_probe_common(struct mt7530_priv *priv) + { +- static struct regmap_config *regmap_config; +- struct mt7530_priv *priv; +- struct device_node *dn; +- int ret; ++ struct device *dev = priv->dev; + +- dn = mdiodev->dev.of_node; +- +- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); ++ priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); + if (!priv->ds) + return -ENOMEM; + +- priv->ds->dev = &mdiodev->dev; ++ priv->ds->dev = dev; + priv->ds->num_ports = MT7530_NUM_PORTS; + +- /* Use medatek,mcm property to distinguish hardware type that would +- * casues a little bit differences on power-on sequence. +- */ +- priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); +- if (priv->mcm) { +- dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); +- +- priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); +- if (IS_ERR(priv->rstc)) { +- dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); +- return PTR_ERR(priv->rstc); +- } +- } +- + /* Get the hardware identifier from the devicetree node. + * We will need it for some of the clock and regulator setup. + */ +- priv->info = of_device_get_match_data(&mdiodev->dev); ++ priv->info = of_device_get_match_data(dev); + if (!priv->info) + return -EINVAL; + +@@ -3186,23 +3163,53 @@ mt7530_probe(struct mdio_device *mdiodev + return -EINVAL; + + priv->id = priv->info->id; ++ priv->dev = dev; ++ priv->ds->priv = priv; ++ priv->ds->ops = &mt7530_switch_ops; ++ mutex_init(&priv->reg_mutex); ++ dev_set_drvdata(dev, priv); + +- if (priv->id == ID_MT7530) { +- priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); +- if (IS_ERR(priv->core_pwr)) +- return PTR_ERR(priv->core_pwr); ++ return 0; ++} + +- priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); +- if (IS_ERR(priv->io_pwr)) +- return PTR_ERR(priv->io_pwr); +- } ++static int ++mt7530_probe(struct mdio_device *mdiodev) ++{ ++ static struct regmap_config *regmap_config; ++ struct mt7530_priv *priv; ++ struct device_node *dn; ++ int ret; ++ ++ dn = mdiodev->dev.of_node; ++ ++ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; + +- /* Not MCM that indicates switch works as the remote standalone ++ priv->bus = mdiodev->bus; ++ priv->dev = &mdiodev->dev; ++ ++ ret = mt7530_probe_common(priv); ++ if (ret) ++ return ret; ++ ++ /* Use medatek,mcm property to distinguish hardware type that would ++ * cause a little bit differences on power-on sequence. ++ * Not MCM that indicates switch works as the remote standalone + * integrated circuit so the GPIO pin would be used to complete + * the reset, otherwise memory-mapped register accessing used + * through syscon provides in the case of MCM. + */ +- if (!priv->mcm) { ++ priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); ++ if (priv->mcm) { ++ dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); ++ ++ priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); ++ if (IS_ERR(priv->rstc)) { ++ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(priv->rstc); ++ } ++ } else { + priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(priv->reset)) { +@@ -3211,12 +3218,15 @@ mt7530_probe(struct mdio_device *mdiodev + } + } + +- priv->bus = mdiodev->bus; +- priv->dev = &mdiodev->dev; +- priv->ds->priv = priv; +- priv->ds->ops = &mt7530_switch_ops; +- mutex_init(&priv->reg_mutex); +- dev_set_drvdata(&mdiodev->dev, priv); ++ if (priv->id == ID_MT7530) { ++ priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); ++ if (IS_ERR(priv->core_pwr)) ++ return PTR_ERR(priv->core_pwr); ++ ++ priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); ++ if (IS_ERR(priv->io_pwr)) ++ return PTR_ERR(priv->io_pwr); ++ } + + regmap_config = devm_kzalloc(&mdiodev->dev, sizeof(*regmap_config), + GFP_KERNEL); diff --git a/target/linux/generic/backport-5.15/790-v6.4-0009-net-dsa-mt7530-introduce-mt7530_remove_common-helper.patch b/target/linux/generic/backport-5.15/790-v6.4-0009-net-dsa-mt7530-introduce-mt7530_remove_common-helper.patch new file mode 100644 index 00000000000..2881365ec77 --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0009-net-dsa-mt7530-introduce-mt7530_remove_common-helper.patch @@ -0,0 +1,55 @@ +From 720d736351761574af02ed093658ab60de60576c Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:18:50 +0100 +Subject: [PATCH 12/16] net: dsa: mt7530: introduce mt7530_remove_common helper + function + +Move commonly used parts from mt7530_remove into new +mt7530_remove_common helper function which will be used by both, +mt7530_remove and the to-be-introduced mt7988_remove. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -3253,6 +3253,17 @@ mt7530_probe(struct mdio_device *mdiodev + } + + static void ++mt7530_remove_common(struct mt7530_priv *priv) ++{ ++ if (priv->irq) ++ mt7530_free_irq(priv); ++ ++ dsa_unregister_switch(priv->ds); ++ ++ mutex_destroy(&priv->reg_mutex); ++} ++ ++static void + mt7530_remove(struct mdio_device *mdiodev) + { + struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); +@@ -3271,16 +3282,11 @@ mt7530_remove(struct mdio_device *mdiode + dev_err(priv->dev, "Failed to disable io pwr: %d\n", + ret); + +- if (priv->irq) +- mt7530_free_irq(priv); +- +- dsa_unregister_switch(priv->ds); ++ mt7530_remove_common(priv); + + for (i = 0; i < 2; ++i) + mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs); + +- mutex_destroy(&priv->reg_mutex); +- + dev_set_drvdata(&mdiodev->dev, NULL); + } + diff --git a/target/linux/generic/backport-5.15/790-v6.4-0010-net-dsa-mt7530-split-off-common-parts-from-mt7531_se.patch b/target/linux/generic/backport-5.15/790-v6.4-0010-net-dsa-mt7530-split-off-common-parts-from-mt7531_se.patch new file mode 100644 index 00000000000..c8e7d93026d --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0010-net-dsa-mt7530-split-off-common-parts-from-mt7531_se.patch @@ -0,0 +1,143 @@ +From 7f54cc9772ced2d76ac11832f0ada43798443ac9 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:19:02 +0100 +Subject: [PATCH 13/16] net: dsa: mt7530: split-off common parts from + mt7531_setup + +MT7988 shares a significant part of the setup function with MT7531. +Split-off those parts into a shared function which is going to be used +also by mt7988_setup. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 99 ++++++++++++++++++++++------------------ + 1 file changed, 55 insertions(+), 44 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -2348,11 +2348,64 @@ mt7530_setup(struct dsa_switch *ds) + } + + static int ++mt7531_setup_common(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ struct dsa_port *cpu_dp; ++ int ret, i; ++ ++ /* BPDU to CPU port */ ++ dsa_switch_for_each_cpu_port(cpu_dp, ds) { ++ mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, ++ BIT(cpu_dp->index)); ++ break; ++ } ++ mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, ++ MT753X_BPDU_CPU_ONLY); ++ ++ /* Enable and reset MIB counters */ ++ mt7530_mib_reset(ds); ++ ++ for (i = 0; i < MT7530_NUM_PORTS; i++) { ++ /* Disable forwarding by default on all ports */ ++ mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, ++ PCR_MATRIX_CLR); ++ ++ /* Disable learning by default on all ports */ ++ mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); ++ ++ mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR); ++ ++ if (dsa_is_cpu_port(ds, i)) { ++ ret = mt753x_cpu_port_enable(ds, i); ++ if (ret) ++ return ret; ++ } else { ++ mt7530_port_disable(ds, i); ++ ++ /* Set default PVID to 0 on all user ports */ ++ mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK, ++ G0_PORT_VID_DEF); ++ } ++ ++ /* Enable consistent egress tag */ ++ mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK, ++ PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); ++ } ++ ++ /* Flush the FDB table */ ++ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); ++ if (ret < 0) ++ return ret; ++ ++ return 0; ++} ++ ++static int + mt7531_setup(struct dsa_switch *ds) + { + struct mt7530_priv *priv = ds->priv; + struct mt7530_dummy_poll p; +- struct dsa_port *cpu_dp; + u32 val, id; + int ret, i; + +@@ -2426,44 +2479,7 @@ mt7531_setup(struct dsa_switch *ds) + mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2, + CORE_PLL_GROUP4, val); + +- /* BPDU to CPU port */ +- dsa_switch_for_each_cpu_port(cpu_dp, ds) { +- mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK, +- BIT(cpu_dp->index)); +- break; +- } +- mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK, +- MT753X_BPDU_CPU_ONLY); +- +- /* Enable and reset MIB counters */ +- mt7530_mib_reset(ds); +- +- for (i = 0; i < MT7530_NUM_PORTS; i++) { +- /* Disable forwarding by default on all ports */ +- mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK, +- PCR_MATRIX_CLR); +- +- /* Disable learning by default on all ports */ +- mt7530_set(priv, MT7530_PSC_P(i), SA_DIS); +- +- mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR); +- +- if (dsa_is_cpu_port(ds, i)) { +- ret = mt753x_cpu_port_enable(ds, i); +- if (ret) +- return ret; +- } else { +- mt7530_port_disable(ds, i); +- +- /* Set default PVID to 0 on all user ports */ +- mt7530_rmw(priv, MT7530_PPBV1_P(i), G0_PORT_VID_MASK, +- G0_PORT_VID_DEF); +- } +- +- /* Enable consistent egress tag */ +- mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK, +- PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT)); +- } ++ mt7531_setup_common(ds); + + /* Setup VLAN ID 0 for VLAN-unaware bridges */ + ret = mt7530_setup_vlan0(priv); +@@ -2473,11 +2489,6 @@ mt7531_setup(struct dsa_switch *ds) + ds->assisted_learning_on_cpu_port = true; + ds->mtu_enforcement_ingress = true; + +- /* Flush the FDB table */ +- ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); +- if (ret < 0) +- return ret; +- + return 0; + } + diff --git a/target/linux/generic/backport-5.15/790-v6.4-0011-net-dsa-mt7530-introduce-separate-MDIO-driver.patch b/target/linux/generic/backport-5.15/790-v6.4-0011-net-dsa-mt7530-introduce-separate-MDIO-driver.patch new file mode 100644 index 00000000000..96afa041aad --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0011-net-dsa-mt7530-introduce-separate-MDIO-driver.patch @@ -0,0 +1,692 @@ +From cb675afcddbbeb2bfa6596e3bc236bc026cd425f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:19:13 +0100 +Subject: [PATCH 14/16] net: dsa: mt7530: introduce separate MDIO driver + +Split MT7530 switch driver into a common part and a part specific +for MDIO connected switches and multi-chip modules. +Move MDIO-specific functions to newly introduced mt7530-mdio.c while +keeping the common parts in mt7530.c. +Introduce new Kconfig symbol CONFIG_NET_DSA_MT7530_MDIO which is +implied by CONFIG_NET_DSA_MT7530. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + MAINTAINERS | 1 + + drivers/net/dsa/Kconfig | 15 +- + drivers/net/dsa/Makefile | 1 + + drivers/net/dsa/mt7530-mdio.c | 271 ++++++++++++++++++++++++++++++++++ + drivers/net/dsa/mt7530.c | 264 +-------------------------------- + drivers/net/dsa/mt7530.h | 6 + + 6 files changed, 300 insertions(+), 258 deletions(-) + create mode 100644 drivers/net/dsa/mt7530-mdio.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -11901,6 +11901,7 @@ M: Landen Chao + L: netdev@vger.kernel.org + S: Maintained ++F: drivers/net/dsa/mt7530-mdio.c + F: drivers/net/dsa/mt7530.* + F: net/dsa/tag_mtk.c + +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -37,10 +37,22 @@ config NET_DSA_MT7530 + tristate "MediaTek MT753x and MT7621 Ethernet switch support" + select NET_DSA_TAG_MTK + select MEDIATEK_GE_PHY ++ imply NET_DSA_MT7530_MDIO ++ help ++ This enables support for the MediaTek MT7530 and MT7531 Ethernet ++ switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT, ++ MT7621ST and MT7623AI SoCs, and built-in switch in MT7988 SoC are ++ supported as well. ++ ++config NET_DSA_MT7530_MDIO ++ tristate "MediaTek MT7530 MDIO interface driver" ++ depends on NET_DSA_MT7530 + select PCS_MTK_LYNXI + help +- This enables support for the MediaTek MT7530, MT7531, and MT7621 +- Ethernet switch chips. ++ This enables support for the MediaTek MT7530 and MT7531 switch ++ chips which are connected via MDIO, as well as multi-chip ++ module MT7530 which can be found in the MT7621AT, MT7621DAT, ++ MT7621ST and MT7623AI SoCs. + + config NET_DSA_MV88E6060 + tristate "Marvell 88E6060 ethernet switch chip support" +--- a/drivers/net/dsa/Makefile ++++ b/drivers/net/dsa/Makefile +@@ -7,6 +7,7 @@ obj-$(CONFIG_FIXED_PHY) += dsa_loop_bdi + endif + obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o + obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o ++obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o + obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o + obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o + realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o +--- /dev/null ++++ b/drivers/net/dsa/mt7530-mdio.c +@@ -0,0 +1,271 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mt7530.h" ++ ++static int ++mt7530_regmap_write(void *context, unsigned int reg, unsigned int val) ++{ ++ struct mii_bus *bus = context; ++ u16 page, r, lo, hi; ++ int ret; ++ ++ page = (reg >> 6) & 0x3ff; ++ r = (reg >> 2) & 0xf; ++ lo = val & 0xffff; ++ hi = val >> 16; ++ ++ /* MT7530 uses 31 as the pseudo port */ ++ ret = bus->write(bus, 0x1f, 0x1f, page); ++ if (ret < 0) ++ return ret; ++ ++ ret = bus->write(bus, 0x1f, r, lo); ++ if (ret < 0) ++ return ret; ++ ++ ret = bus->write(bus, 0x1f, 0x10, hi); ++ return ret; ++} ++ ++static int ++mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val) ++{ ++ struct mii_bus *bus = context; ++ u16 page, r, lo, hi; ++ int ret; ++ ++ page = (reg >> 6) & 0x3ff; ++ r = (reg >> 2) & 0xf; ++ ++ /* MT7530 uses 31 as the pseudo port */ ++ ret = bus->write(bus, 0x1f, 0x1f, page); ++ if (ret < 0) ++ return ret; ++ ++ lo = bus->read(bus, 0x1f, r); ++ hi = bus->read(bus, 0x1f, 0x10); ++ ++ *val = (hi << 16) | (lo & 0xffff); ++ ++ return 0; ++} ++ ++static void ++mt7530_mdio_regmap_lock(void *mdio_lock) ++{ ++ mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED); ++} ++ ++static void ++mt7530_mdio_regmap_unlock(void *mdio_lock) ++{ ++ mutex_unlock(mdio_lock); ++} ++ ++static const struct regmap_bus mt7530_regmap_bus = { ++ .reg_write = mt7530_regmap_write, ++ .reg_read = mt7530_regmap_read, ++}; ++ ++static int ++mt7531_create_sgmii(struct mt7530_priv *priv) ++{ ++ struct regmap_config *mt7531_pcs_config[2]; ++ struct phylink_pcs *pcs; ++ struct regmap *regmap; ++ int i, ret = 0; ++ ++ for (i = 0; i < 2; i++) { ++ mt7531_pcs_config[i] = devm_kzalloc(priv->dev, ++ sizeof(struct regmap_config), ++ GFP_KERNEL); ++ if (!mt7531_pcs_config[i]) { ++ ret = -ENOMEM; ++ break; ++ } ++ ++ mt7531_pcs_config[i]->name = i ? "port6" : "port5"; ++ mt7531_pcs_config[i]->reg_bits = 16; ++ mt7531_pcs_config[i]->val_bits = 32; ++ mt7531_pcs_config[i]->reg_stride = 4; ++ mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i); ++ mt7531_pcs_config[i]->max_register = 0x17c; ++ mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock; ++ mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock; ++ mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock; ++ ++ regmap = devm_regmap_init(priv->dev, ++ &mt7530_regmap_bus, priv->bus, ++ mt7531_pcs_config[i]); ++ if (IS_ERR(regmap)) { ++ ret = PTR_ERR(regmap); ++ break; ++ } ++ pcs = mtk_pcs_lynxi_create(priv->dev, regmap, ++ MT7531_PHYA_CTRL_SIGNAL3, 0); ++ if (!pcs) { ++ ret = -ENXIO; ++ break; ++ } ++ priv->ports[5 + i].sgmii_pcs = pcs; ++ } ++ ++ if (ret && i) ++ mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs); ++ ++ return ret; ++} ++ ++static const struct of_device_id mt7530_of_match[] = { ++ { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], }, ++ { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], }, ++ { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, mt7530_of_match); ++ ++static int ++mt7530_probe(struct mdio_device *mdiodev) ++{ ++ static struct regmap_config *regmap_config; ++ struct mt7530_priv *priv; ++ struct device_node *dn; ++ int ret; ++ ++ dn = mdiodev->dev.of_node; ++ ++ priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->bus = mdiodev->bus; ++ priv->dev = &mdiodev->dev; ++ ++ ret = mt7530_probe_common(priv); ++ if (ret) ++ return ret; ++ ++ /* Use medatek,mcm property to distinguish hardware type that would ++ * cause a little bit differences on power-on sequence. ++ * Not MCM that indicates switch works as the remote standalone ++ * integrated circuit so the GPIO pin would be used to complete ++ * the reset, otherwise memory-mapped register accessing used ++ * through syscon provides in the case of MCM. ++ */ ++ priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); ++ if (priv->mcm) { ++ dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); ++ ++ priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); ++ if (IS_ERR(priv->rstc)) { ++ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(priv->rstc); ++ } ++ } else { ++ priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset", ++ GPIOD_OUT_LOW); ++ if (IS_ERR(priv->reset)) { ++ dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(priv->reset); ++ } ++ } ++ ++ if (priv->id == ID_MT7530) { ++ priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); ++ if (IS_ERR(priv->core_pwr)) ++ return PTR_ERR(priv->core_pwr); ++ ++ priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); ++ if (IS_ERR(priv->io_pwr)) ++ return PTR_ERR(priv->io_pwr); ++ } ++ ++ regmap_config = devm_kzalloc(&mdiodev->dev, sizeof(*regmap_config), ++ GFP_KERNEL); ++ if (!regmap_config) ++ return -ENOMEM; ++ ++ regmap_config->reg_bits = 16; ++ regmap_config->val_bits = 32; ++ regmap_config->reg_stride = 4; ++ regmap_config->max_register = MT7530_CREV; ++ regmap_config->disable_locking = true; ++ priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, ++ priv->bus, regmap_config); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ if (priv->id == ID_MT7531) { ++ ret = mt7531_create_sgmii(priv); ++ if (ret) ++ return ret; ++ } ++ ++ return dsa_register_switch(priv->ds); ++} ++ ++static void ++mt7530_remove(struct mdio_device *mdiodev) ++{ ++ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ int ret = 0, i; ++ ++ if (!priv) ++ return; ++ ++ ret = regulator_disable(priv->core_pwr); ++ if (ret < 0) ++ dev_err(priv->dev, ++ "Failed to disable core power: %d\n", ret); ++ ++ ret = regulator_disable(priv->io_pwr); ++ if (ret < 0) ++ dev_err(priv->dev, "Failed to disable io pwr: %d\n", ++ ret); ++ ++ mt7530_remove_common(priv); ++ ++ for (i = 0; i < 2; ++i) ++ mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs); ++} ++ ++static void mt7530_shutdown(struct mdio_device *mdiodev) ++{ ++ struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); ++ ++ if (!priv) ++ return; ++ ++ dsa_switch_shutdown(priv->ds); ++ ++ dev_set_drvdata(&mdiodev->dev, NULL); ++} ++ ++static struct mdio_driver mt7530_mdio_driver = { ++ .probe = mt7530_probe, ++ .remove = mt7530_remove, ++ .shutdown = mt7530_shutdown, ++ .mdiodrv.driver = { ++ .name = "mt7530-mdio", ++ .of_match_table = mt7530_of_match, ++ }, ++}; ++ ++mdio_module_driver(mt7530_mdio_driver); ++ ++MODULE_AUTHOR("Sean Wang "); ++MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MDIO)"); ++MODULE_LICENSE("GPL"); +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -14,7 +14,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -192,31 +191,6 @@ core_clear(struct mt7530_priv *priv, u32 + } + + static int +-mt7530_regmap_write(void *context, unsigned int reg, unsigned int val) +-{ +- struct mii_bus *bus = context; +- u16 page, r, lo, hi; +- int ret; +- +- page = (reg >> 6) & 0x3ff; +- r = (reg >> 2) & 0xf; +- lo = val & 0xffff; +- hi = val >> 16; +- +- /* MT7530 uses 31 as the pseudo port */ +- ret = bus->write(bus, 0x1f, 0x1f, page); +- if (ret < 0) +- return ret; +- +- ret = bus->write(bus, 0x1f, r, lo); +- if (ret < 0) +- return ret; +- +- ret = bus->write(bus, 0x1f, 0x10, hi); +- return ret; +-} +- +-static int + mt7530_mii_write(struct mt7530_priv *priv, u32 reg, u32 val) + { + int ret; +@@ -230,29 +204,6 @@ mt7530_mii_write(struct mt7530_priv *pri + return ret; + } + +-static int +-mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val) +-{ +- struct mii_bus *bus = context; +- u16 page, r, lo, hi; +- int ret; +- +- page = (reg >> 6) & 0x3ff; +- r = (reg >> 2) & 0xf; +- +- /* MT7530 uses 31 as the pseudo port */ +- ret = bus->write(bus, 0x1f, 0x1f, page); +- if (ret < 0) +- return ret; +- +- lo = bus->read(bus, 0x1f, r); +- hi = bus->read(bus, 0x1f, 0x10); +- +- *val = (hi << 16) | (lo & 0xffff); +- +- return 0; +-} +- + static u32 + mt7530_mii_read(struct mt7530_priv *priv, u32 reg) + { +@@ -2944,72 +2895,6 @@ static const struct phylink_pcs_ops mt75 + .pcs_an_restart = mt7530_pcs_an_restart, + }; + +-static void +-mt7530_mdio_regmap_lock(void *mdio_lock) +-{ +- mutex_lock_nested(mdio_lock, MDIO_MUTEX_NESTED); +-} +- +-static void +-mt7530_mdio_regmap_unlock(void *mdio_lock) +-{ +- mutex_unlock(mdio_lock); +-} +- +-static const struct regmap_bus mt7530_regmap_bus = { +- .reg_write = mt7530_regmap_write, +- .reg_read = mt7530_regmap_read, +-}; +- +-static int +-mt7531_create_sgmii(struct mt7530_priv *priv) +-{ +- struct regmap_config *mt7531_pcs_config[2]; +- struct phylink_pcs *pcs; +- struct regmap *regmap; +- int i, ret = 0; +- +- for (i = 0; i < 2; i++) { +- mt7531_pcs_config[i] = devm_kzalloc(priv->dev, +- sizeof(struct regmap_config), +- GFP_KERNEL); +- if (!mt7531_pcs_config[i]) { +- ret = -ENOMEM; +- break; +- } +- +- mt7531_pcs_config[i]->name = i ? "port6" : "port5"; +- mt7531_pcs_config[i]->reg_bits = 16; +- mt7531_pcs_config[i]->val_bits = 32; +- mt7531_pcs_config[i]->reg_stride = 4; +- mt7531_pcs_config[i]->reg_base = MT7531_SGMII_REG_BASE(5 + i); +- mt7531_pcs_config[i]->max_register = 0x17c; +- mt7531_pcs_config[i]->lock = mt7530_mdio_regmap_lock; +- mt7531_pcs_config[i]->unlock = mt7530_mdio_regmap_unlock; +- mt7531_pcs_config[i]->lock_arg = &priv->bus->mdio_lock; +- +- regmap = devm_regmap_init(priv->dev, +- &mt7530_regmap_bus, priv->bus, +- mt7531_pcs_config[i]); +- if (IS_ERR(regmap)) { +- ret = PTR_ERR(regmap); +- break; +- } +- pcs = mtk_pcs_lynxi_create(priv->dev, regmap, +- MT7531_PHYA_CTRL_SIGNAL3, 0); +- if (!pcs) { +- ret = -ENXIO; +- break; +- } +- priv->ports[5 + i].sgmii_pcs = pcs; +- } +- +- if (ret && i) +- mtk_pcs_lynxi_destroy(priv->ports[5].sgmii_pcs); +- +- return ret; +-} +- + static int + mt753x_setup(struct dsa_switch *ds) + { +@@ -3068,7 +2953,7 @@ static int mt753x_set_mac_eee(struct dsa + return 0; + } + +-static const struct dsa_switch_ops mt7530_switch_ops = { ++const struct dsa_switch_ops mt7530_switch_ops = { + .get_tag_protocol = mtk_get_tag_protocol, + .setup = mt753x_setup, + .get_strings = mt7530_get_strings, +@@ -3102,8 +2987,9 @@ static const struct dsa_switch_ops mt753 + .get_mac_eee = mt753x_get_mac_eee, + .set_mac_eee = mt753x_set_mac_eee, + }; ++EXPORT_SYMBOL_GPL(mt7530_switch_ops); + +-static const struct mt753x_info mt753x_table[] = { ++const struct mt753x_info mt753x_table[] = { + [ID_MT7621] = { + .id = ID_MT7621, + .pcs_ops = &mt7530_pcs_ops, +@@ -3136,16 +3022,9 @@ static const struct mt753x_info mt753x_t + .mac_port_config = mt7531_mac_config, + }, + }; ++EXPORT_SYMBOL_GPL(mt753x_table); + +-static const struct of_device_id mt7530_of_match[] = { +- { .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], }, +- { .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], }, +- { .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], }, +- { /* sentinel */ }, +-}; +-MODULE_DEVICE_TABLE(of, mt7530_of_match); +- +-static int ++int + mt7530_probe_common(struct mt7530_priv *priv) + { + struct device *dev = priv->dev; +@@ -3182,88 +3061,9 @@ mt7530_probe_common(struct mt7530_priv * + + return 0; + } ++EXPORT_SYMBOL_GPL(mt7530_probe_common); + +-static int +-mt7530_probe(struct mdio_device *mdiodev) +-{ +- static struct regmap_config *regmap_config; +- struct mt7530_priv *priv; +- struct device_node *dn; +- int ret; +- +- dn = mdiodev->dev.of_node; +- +- priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); +- if (!priv) +- return -ENOMEM; +- +- priv->bus = mdiodev->bus; +- priv->dev = &mdiodev->dev; +- +- ret = mt7530_probe_common(priv); +- if (ret) +- return ret; +- +- /* Use medatek,mcm property to distinguish hardware type that would +- * cause a little bit differences on power-on sequence. +- * Not MCM that indicates switch works as the remote standalone +- * integrated circuit so the GPIO pin would be used to complete +- * the reset, otherwise memory-mapped register accessing used +- * through syscon provides in the case of MCM. +- */ +- priv->mcm = of_property_read_bool(dn, "mediatek,mcm"); +- if (priv->mcm) { +- dev_info(&mdiodev->dev, "MT7530 adapts as multi-chip module\n"); +- +- priv->rstc = devm_reset_control_get(&mdiodev->dev, "mcm"); +- if (IS_ERR(priv->rstc)) { +- dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); +- return PTR_ERR(priv->rstc); +- } +- } else { +- priv->reset = devm_gpiod_get_optional(&mdiodev->dev, "reset", +- GPIOD_OUT_LOW); +- if (IS_ERR(priv->reset)) { +- dev_err(&mdiodev->dev, "Couldn't get our reset line\n"); +- return PTR_ERR(priv->reset); +- } +- } +- +- if (priv->id == ID_MT7530) { +- priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core"); +- if (IS_ERR(priv->core_pwr)) +- return PTR_ERR(priv->core_pwr); +- +- priv->io_pwr = devm_regulator_get(&mdiodev->dev, "io"); +- if (IS_ERR(priv->io_pwr)) +- return PTR_ERR(priv->io_pwr); +- } +- +- regmap_config = devm_kzalloc(&mdiodev->dev, sizeof(*regmap_config), +- GFP_KERNEL); +- if (!regmap_config) +- return -ENOMEM; +- +- regmap_config->reg_bits = 16; +- regmap_config->val_bits = 32; +- regmap_config->reg_stride = 4; +- regmap_config->max_register = MT7530_CREV; +- regmap_config->disable_locking = true; +- priv->regmap = devm_regmap_init(priv->dev, &mt7530_regmap_bus, +- priv->bus, regmap_config); +- if (IS_ERR(priv->regmap)) +- return PTR_ERR(priv->regmap); +- +- if (priv->id == ID_MT7531) { +- ret = mt7531_create_sgmii(priv); +- if (ret) +- return ret; +- } +- +- return dsa_register_switch(priv->ds); +-} +- +-static void ++void + mt7530_remove_common(struct mt7530_priv *priv) + { + if (priv->irq) +@@ -3274,57 +3074,6 @@ mt7530_remove_common(struct mt7530_priv + mutex_destroy(&priv->reg_mutex); + } + +-static void +-mt7530_remove(struct mdio_device *mdiodev) +-{ +- struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); +- int ret = 0, i; +- +- if (!priv) +- return; +- +- ret = regulator_disable(priv->core_pwr); +- if (ret < 0) +- dev_err(priv->dev, +- "Failed to disable core power: %d\n", ret); +- +- ret = regulator_disable(priv->io_pwr); +- if (ret < 0) +- dev_err(priv->dev, "Failed to disable io pwr: %d\n", +- ret); +- +- mt7530_remove_common(priv); +- +- for (i = 0; i < 2; ++i) +- mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs); +- +- dev_set_drvdata(&mdiodev->dev, NULL); +-} +- +-static void mt7530_shutdown(struct mdio_device *mdiodev) +-{ +- struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev); +- +- if (!priv) +- return; +- +- dsa_switch_shutdown(priv->ds); +- +- dev_set_drvdata(&mdiodev->dev, NULL); +-} +- +-static struct mdio_driver mt7530_mdio_driver = { +- .probe = mt7530_probe, +- .remove = mt7530_remove, +- .shutdown = mt7530_shutdown, +- .mdiodrv.driver = { +- .name = "mt7530", +- .of_match_table = mt7530_of_match, +- }, +-}; +- +-mdio_module_driver(mt7530_mdio_driver); +- + MODULE_AUTHOR("Sean Wang "); + MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch"); + MODULE_LICENSE("GPL"); +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -807,4 +807,10 @@ static inline void INIT_MT7530_DUMMY_POL + p->reg = reg; + } + ++int mt7530_probe_common(struct mt7530_priv *priv); ++void mt7530_remove_common(struct mt7530_priv *priv); ++ ++extern const struct dsa_switch_ops mt7530_switch_ops; ++extern const struct mt753x_info mt753x_table[]; ++ + #endif /* __MT7530_H */ diff --git a/target/linux/generic/backport-5.15/790-v6.4-0012-net-dsa-mt7530-skip-locking-if-MDIO-bus-isn-t-presen.patch b/target/linux/generic/backport-5.15/790-v6.4-0012-net-dsa-mt7530-skip-locking-if-MDIO-bus-isn-t-presen.patch new file mode 100644 index 00000000000..95b7cc6afe5 --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0012-net-dsa-mt7530-skip-locking-if-MDIO-bus-isn-t-presen.patch @@ -0,0 +1,47 @@ +From 54d4147a121cec5004a673a58572da346e4458f8 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:19:28 +0100 +Subject: [PATCH 15/16] net: dsa: mt7530: skip locking if MDIO bus isn't + present + +As MT7530 and MT7531 internally use 32-bit wide registers, each access +to any register of the switch requires several operations on the MDIO +bus. Hence if there is congruent access, e.g. due to PCS or PHY +polling, this can mess up and interfere with another ongoing register +access sequence. + +However, the MDIO bus mutex is only relevant for MDIO-connected +switches. Prepare switches which have there registers directly mapped +into the SoCs register space via MMIO which do not require such +locking. There we can simply use regmap's default locking mechanism. + +Hence guard mutex operations to only be performed in case of MDIO +connected switches. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + drivers/net/dsa/mt7530.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -144,13 +144,15 @@ err: + static void + mt7530_mutex_lock(struct mt7530_priv *priv) + { +- mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); ++ if (priv->bus) ++ mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED); + } + + static void + mt7530_mutex_unlock(struct mt7530_priv *priv) + { +- mutex_unlock(&priv->bus->mdio_lock); ++ if (priv->bus) ++ mutex_unlock(&priv->bus->mdio_lock); + } + + static void diff --git a/target/linux/generic/backport-5.15/790-v6.4-0013-net-dsa-mt7530-introduce-driver-for-MT7988-built-in-.patch b/target/linux/generic/backport-5.15/790-v6.4-0013-net-dsa-mt7530-introduce-driver-for-MT7988-built-in-.patch new file mode 100644 index 00000000000..8210aae27ce --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0013-net-dsa-mt7530-introduce-driver-for-MT7988-built-in-.patch @@ -0,0 +1,421 @@ +From 110c18bfed41421edd677935dd33be5e6507ba92 Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 3 Apr 2023 02:19:40 +0100 +Subject: [PATCH 16/16] net: dsa: mt7530: introduce driver for MT7988 built-in + switch + +Add driver for the built-in Gigabit Ethernet switch which can be found +in the MediaTek MT7988 SoC. + +The switch shares most of its design with MT7530 and MT7531, but has +it's registers mapped into the SoCs register space rather than being +connected externally or internally via MDIO. + +Introduce a new platform driver to support that. + +Signed-off-by: Daniel Golle +Reviewed-by: Andrew Lunn +Signed-off-by: David S. Miller +--- + MAINTAINERS | 2 + + drivers/net/dsa/Kconfig | 12 +++ + drivers/net/dsa/Makefile | 1 + + drivers/net/dsa/mt7530-mmio.c | 101 +++++++++++++++++++++++++ + drivers/net/dsa/mt7530.c | 137 +++++++++++++++++++++++++++++++++- + drivers/net/dsa/mt7530.h | 12 +-- + 6 files changed, 255 insertions(+), 10 deletions(-) + create mode 100644 drivers/net/dsa/mt7530-mmio.c + +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -11899,9 +11899,11 @@ MEDIATEK SWITCH DRIVER + M: Sean Wang + M: Landen Chao + M: DENG Qingfang ++M: Daniel Golle + L: netdev@vger.kernel.org + S: Maintained + F: drivers/net/dsa/mt7530-mdio.c ++F: drivers/net/dsa/mt7530-mmio.c + F: drivers/net/dsa/mt7530.* + F: net/dsa/tag_mtk.c + +--- a/drivers/net/dsa/Kconfig ++++ b/drivers/net/dsa/Kconfig +@@ -38,6 +38,7 @@ config NET_DSA_MT7530 + select NET_DSA_TAG_MTK + select MEDIATEK_GE_PHY + imply NET_DSA_MT7530_MDIO ++ imply NET_DSA_MT7530_MMIO + help + This enables support for the MediaTek MT7530 and MT7531 Ethernet + switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT, +@@ -54,6 +55,17 @@ config NET_DSA_MT7530_MDIO + module MT7530 which can be found in the MT7621AT, MT7621DAT, + MT7621ST and MT7623AI SoCs. + ++config NET_DSA_MT7530_MMIO ++ tristate "MediaTek MT7530 MMIO interface driver" ++ depends on NET_DSA_MT7530 ++ depends on HAS_IOMEM ++ help ++ This enables support for the built-in Ethernet switch found ++ in the MediaTek MT7988 SoC. ++ The switch is a similar design as MT7531, but the switch registers ++ are directly mapped into the SoCs register space rather than being ++ accessible via MDIO. ++ + config NET_DSA_MV88E6060 + tristate "Marvell 88E6060 ethernet switch chip support" + select NET_DSA_TAG_TRAILER +--- a/drivers/net/dsa/Makefile ++++ b/drivers/net/dsa/Makefile +@@ -8,6 +8,7 @@ endif + obj-$(CONFIG_NET_DSA_LANTIQ_GSWIP) += lantiq_gswip.o + obj-$(CONFIG_NET_DSA_MT7530) += mt7530.o + obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o ++obj-$(CONFIG_NET_DSA_MT7530_MMIO) += mt7530-mmio.o + obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o + obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o + realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o +--- /dev/null ++++ b/drivers/net/dsa/mt7530-mmio.c +@@ -0,0 +1,101 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "mt7530.h" ++ ++static const struct of_device_id mt7988_of_match[] = { ++ { .compatible = "mediatek,mt7988-switch", .data = &mt753x_table[ID_MT7988], }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, mt7988_of_match); ++ ++static int ++mt7988_probe(struct platform_device *pdev) ++{ ++ static struct regmap_config *sw_regmap_config; ++ struct mt7530_priv *priv; ++ void __iomem *base_addr; ++ int ret; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->bus = NULL; ++ priv->dev = &pdev->dev; ++ ++ ret = mt7530_probe_common(priv); ++ if (ret) ++ return ret; ++ ++ priv->rstc = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->rstc)) { ++ dev_err(&pdev->dev, "Couldn't get our reset line\n"); ++ return PTR_ERR(priv->rstc); ++ } ++ ++ base_addr = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(base_addr)) { ++ dev_err(&pdev->dev, "cannot request I/O memory space\n"); ++ return -ENXIO; ++ } ++ ++ sw_regmap_config = devm_kzalloc(&pdev->dev, sizeof(*sw_regmap_config), GFP_KERNEL); ++ if (!sw_regmap_config) ++ return -ENOMEM; ++ ++ sw_regmap_config->name = "switch"; ++ sw_regmap_config->reg_bits = 16; ++ sw_regmap_config->val_bits = 32; ++ sw_regmap_config->reg_stride = 4; ++ sw_regmap_config->max_register = MT7530_CREV; ++ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base_addr, sw_regmap_config); ++ if (IS_ERR(priv->regmap)) ++ return PTR_ERR(priv->regmap); ++ ++ return dsa_register_switch(priv->ds); ++} ++ ++static int ++mt7988_remove(struct platform_device *pdev) ++{ ++ struct mt7530_priv *priv = platform_get_drvdata(pdev); ++ ++ if (priv) ++ mt7530_remove_common(priv); ++ ++ return 0; ++} ++ ++static void mt7988_shutdown(struct platform_device *pdev) ++{ ++ struct mt7530_priv *priv = platform_get_drvdata(pdev); ++ ++ if (!priv) ++ return; ++ ++ dsa_switch_shutdown(priv->ds); ++ ++ dev_set_drvdata(&pdev->dev, NULL); ++} ++ ++static struct platform_driver mt7988_platform_driver = { ++ .probe = mt7988_probe, ++ .remove = mt7988_remove, ++ .shutdown = mt7988_shutdown, ++ .driver = { ++ .name = "mt7530-mmio", ++ .of_match_table = mt7988_of_match, ++ }, ++}; ++module_platform_driver(mt7988_platform_driver); ++ ++MODULE_AUTHOR("Daniel Golle "); ++MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MMIO)"); ++MODULE_LICENSE("GPL"); +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -1984,6 +1984,47 @@ static const struct irq_domain_ops mt753 + }; + + static void ++mt7988_irq_mask(struct irq_data *d) ++{ ++ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ priv->irq_enable &= ~BIT(d->hwirq); ++ mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable); ++} ++ ++static void ++mt7988_irq_unmask(struct irq_data *d) ++{ ++ struct mt7530_priv *priv = irq_data_get_irq_chip_data(d); ++ ++ priv->irq_enable |= BIT(d->hwirq); ++ mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable); ++} ++ ++static struct irq_chip mt7988_irq_chip = { ++ .name = KBUILD_MODNAME, ++ .irq_mask = mt7988_irq_mask, ++ .irq_unmask = mt7988_irq_unmask, ++}; ++ ++static int ++mt7988_irq_map(struct irq_domain *domain, unsigned int irq, ++ irq_hw_number_t hwirq) ++{ ++ irq_set_chip_data(irq, domain->host_data); ++ irq_set_chip_and_handler(irq, &mt7988_irq_chip, handle_simple_irq); ++ irq_set_nested_thread(irq, true); ++ irq_set_noprobe(irq); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops mt7988_irq_domain_ops = { ++ .map = mt7988_irq_map, ++ .xlate = irq_domain_xlate_onecell, ++}; ++ ++static void + mt7530_setup_mdio_irq(struct mt7530_priv *priv) + { + struct dsa_switch *ds = priv->ds; +@@ -2017,8 +2058,15 @@ mt7530_setup_irq(struct mt7530_priv *pri + return priv->irq ? : -EINVAL; + } + +- priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS, +- &mt7530_irq_domain_ops, priv); ++ if (priv->id == ID_MT7988) ++ priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS, ++ &mt7988_irq_domain_ops, ++ priv); ++ else ++ priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS, ++ &mt7530_irq_domain_ops, ++ priv); ++ + if (!priv->irq_domain) { + dev_err(dev, "failed to create IRQ domain\n"); + return -ENOMEM; +@@ -2507,6 +2555,25 @@ static void mt7531_mac_port_get_caps(str + } + } + ++static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, ++ struct phylink_config *config) ++{ ++ phy_interface_zero(config->supported_interfaces); ++ ++ switch (port) { ++ case 0 ... 4: /* Internal phy */ ++ __set_bit(PHY_INTERFACE_MODE_INTERNAL, ++ config->supported_interfaces); ++ break; ++ ++ case 6: ++ __set_bit(PHY_INTERFACE_MODE_INTERNAL, ++ config->supported_interfaces); ++ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | ++ MAC_10000FD; ++ } ++} ++ + static int + mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state) + { +@@ -2583,6 +2650,17 @@ static bool mt753x_is_mac_port(u32 port) + } + + static int ++mt7988_mac_config(struct dsa_switch *ds, int port, unsigned int mode, ++ phy_interface_t interface) ++{ ++ if (dsa_is_cpu_port(ds, port) && ++ interface == PHY_INTERFACE_MODE_INTERNAL) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int + mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode, + phy_interface_t interface) + { +@@ -2652,7 +2730,8 @@ mt753x_phylink_mac_config(struct dsa_swi + + switch (port) { + case 0 ... 4: /* Internal phy */ +- if (state->interface != PHY_INTERFACE_MODE_GMII) ++ if (state->interface != PHY_INTERFACE_MODE_GMII && ++ state->interface != PHY_INTERFACE_MODE_INTERNAL) + goto unsupported; + break; + case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ +@@ -2730,7 +2809,8 @@ static void mt753x_phylink_mac_link_up(s + /* MT753x MAC works in 1G full duplex mode for all up-clocked + * variants. + */ +- if (interface == PHY_INTERFACE_MODE_TRGMII || ++ if (interface == PHY_INTERFACE_MODE_INTERNAL || ++ interface == PHY_INTERFACE_MODE_TRGMII || + (phy_interface_mode_is_8023z(interface))) { + speed = SPEED_1000; + duplex = DUPLEX_FULL; +@@ -2810,6 +2890,21 @@ mt7531_cpu_port_config(struct dsa_switch + return 0; + } + ++static int ++mt7988_cpu_port_config(struct dsa_switch *ds, int port) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ mt7530_write(priv, MT7530_PMCR_P(port), ++ PMCR_CPU_PORT_SETTING(priv->id)); ++ ++ mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, ++ PHY_INTERFACE_MODE_INTERNAL, NULL, ++ SPEED_10000, DUPLEX_FULL, true, true); ++ ++ return 0; ++} ++ + static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port, + struct phylink_config *config) + { +@@ -2955,6 +3050,27 @@ static int mt753x_set_mac_eee(struct dsa + return 0; + } + ++static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface) ++{ ++ return 0; ++} ++ ++static int mt7988_setup(struct dsa_switch *ds) ++{ ++ struct mt7530_priv *priv = ds->priv; ++ ++ /* Reset the switch */ ++ reset_control_assert(priv->rstc); ++ usleep_range(20, 50); ++ reset_control_deassert(priv->rstc); ++ usleep_range(20, 50); ++ ++ /* Reset the switch PHYs */ ++ mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST); ++ ++ return mt7531_setup_common(ds); ++} ++ + const struct dsa_switch_ops mt7530_switch_ops = { + .get_tag_protocol = mtk_get_tag_protocol, + .setup = mt753x_setup, +@@ -3023,6 +3139,17 @@ const struct mt753x_info mt753x_table[] + .mac_port_get_caps = mt7531_mac_port_get_caps, + .mac_port_config = mt7531_mac_config, + }, ++ [ID_MT7988] = { ++ .id = ID_MT7988, ++ .pcs_ops = &mt7530_pcs_ops, ++ .sw_setup = mt7988_setup, ++ .phy_read = mt7531_ind_phy_read, ++ .phy_write = mt7531_ind_phy_write, ++ .pad_setup = mt7988_pad_setup, ++ .cpu_port_config = mt7988_cpu_port_config, ++ .mac_port_get_caps = mt7988_mac_port_get_caps, ++ .mac_port_config = mt7988_mac_config, ++ }, + }; + EXPORT_SYMBOL_GPL(mt753x_table); + +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -18,6 +18,7 @@ enum mt753x_id { + ID_MT7530 = 0, + ID_MT7621 = 1, + ID_MT7531 = 2, ++ ID_MT7988 = 3, + }; + + #define NUM_TRGMII_CTRL 5 +@@ -54,11 +55,11 @@ enum mt753x_id { + #define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16) + #define MT7531_CPU_PMAP_MASK GENMASK(7, 0) + +-#define MT753X_MIRROR_REG(id) (((id) == ID_MT7531) ? \ ++#define MT753X_MIRROR_REG(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ + MT7531_CFC : MT7530_MFC) +-#define MT753X_MIRROR_EN(id) (((id) == ID_MT7531) ? \ ++#define MT753X_MIRROR_EN(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ + MT7531_MIRROR_EN : MIRROR_EN) +-#define MT753X_MIRROR_MASK(id) (((id) == ID_MT7531) ? \ ++#define MT753X_MIRROR_MASK(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ + MT7531_MIRROR_MASK : MIRROR_MASK) + + /* Registers for BPDU and PAE frame control*/ +@@ -295,9 +296,8 @@ enum mt7530_vlan_port_acc_frm { + MT7531_FORCE_DPX | \ + MT7531_FORCE_RX_FC | \ + MT7531_FORCE_TX_FC) +-#define PMCR_FORCE_MODE_ID(id) (((id) == ID_MT7531) ? \ +- MT7531_FORCE_MODE : \ +- PMCR_FORCE_MODE) ++#define PMCR_FORCE_MODE_ID(id) ((((id) == ID_MT7531) || ((id) == ID_MT7988)) ? \ ++ MT7531_FORCE_MODE : PMCR_FORCE_MODE) + #define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \ + PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \ + PMCR_TX_FC_EN | PMCR_RX_FC_EN | \ diff --git a/target/linux/generic/backport-5.15/790-v6.4-0014-net-dsa-mt7530-fix-support-for-MT7531BE.patch b/target/linux/generic/backport-5.15/790-v6.4-0014-net-dsa-mt7530-fix-support-for-MT7531BE.patch new file mode 100644 index 00000000000..5259730996d --- /dev/null +++ b/target/linux/generic/backport-5.15/790-v6.4-0014-net-dsa-mt7530-fix-support-for-MT7531BE.patch @@ -0,0 +1,118 @@ +From 91daa4f62ce878b6e1ac5908aceb83550332447f Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Sun, 16 Apr 2023 13:08:14 +0100 +Subject: [PATCH] net: dsa: mt7530: fix support for MT7531BE +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There are two variants of the MT7531 switch IC which got different +features (and pins) regarding port 5: + * MT7531AE: SGMII/1000Base-X/2500Base-X SerDes PCS + * MT7531BE: RGMII + +Moving the creation of the SerDes PCS from mt753x_setup to mt7530_probe +with commit 6de285229773 ("net: dsa: mt7530: move SGMII PCS creation +to mt7530_probe function") works fine for MT7531AE which got two +instances of mtk-pcs-lynxi, however, MT7531BE requires mt7531_pll_setup +to setup clocks before the single PCS on port 6 (usually used as CPU +port) starts to work and hence the PCS creation failed on MT7531BE. + +Fix this by introducing a pointer to mt7531_create_sgmii function in +struct mt7530_priv and call it again at the end of mt753x_setup like it +was before commit 6de285229773 ("net: dsa: mt7530: move SGMII PCS +creation to mt7530_probe function"). + +Fixes: 6de285229773 ("net: dsa: mt7530: move SGMII PCS creation to mt7530_probe function") +Signed-off-by: Daniel Golle +Acked-by: Arınç ĂœNAL +Link: https://lore.kernel.org/r/ZDvlLhhqheobUvOK@makrotopia.org +Signed-off-by: Jakub Kicinski +--- + drivers/net/dsa/mt7530-mdio.c | 16 ++++++++-------- + drivers/net/dsa/mt7530.c | 6 ++++++ + drivers/net/dsa/mt7530.h | 4 ++-- + 3 files changed, 16 insertions(+), 10 deletions(-) + +--- a/drivers/net/dsa/mt7530-mdio.c ++++ b/drivers/net/dsa/mt7530-mdio.c +@@ -81,14 +81,17 @@ static const struct regmap_bus mt7530_re + }; + + static int +-mt7531_create_sgmii(struct mt7530_priv *priv) ++mt7531_create_sgmii(struct mt7530_priv *priv, bool dual_sgmii) + { +- struct regmap_config *mt7531_pcs_config[2]; ++ struct regmap_config *mt7531_pcs_config[2] = {}; + struct phylink_pcs *pcs; + struct regmap *regmap; + int i, ret = 0; + +- for (i = 0; i < 2; i++) { ++ /* MT7531AE has two SGMII units for port 5 and port 6 ++ * MT7531BE has only one SGMII unit for port 6 ++ */ ++ for (i = dual_sgmii ? 0 : 1; i < 2; i++) { + mt7531_pcs_config[i] = devm_kzalloc(priv->dev, + sizeof(struct regmap_config), + GFP_KERNEL); +@@ -208,11 +211,8 @@ mt7530_probe(struct mdio_device *mdiodev + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + +- if (priv->id == ID_MT7531) { +- ret = mt7531_create_sgmii(priv); +- if (ret) +- return ret; +- } ++ if (priv->id == ID_MT7531) ++ priv->create_sgmii = mt7531_create_sgmii; + + return dsa_register_switch(priv->ds); + } +--- a/drivers/net/dsa/mt7530.c ++++ b/drivers/net/dsa/mt7530.c +@@ -3017,6 +3017,12 @@ mt753x_setup(struct dsa_switch *ds) + if (ret && priv->irq) + mt7530_free_irq_common(priv); + ++ if (priv->create_sgmii) { ++ ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv)); ++ if (ret && priv->irq) ++ mt7530_free_irq(priv); ++ } ++ + return ret; + } + +--- a/drivers/net/dsa/mt7530.h ++++ b/drivers/net/dsa/mt7530.h +@@ -741,10 +741,10 @@ struct mt753x_info { + * registers + * @p6_interface Holding the current port 6 interface + * @p5_intf_sel: Holding the current port 5 interface select +- * + * @irq: IRQ number of the switch + * @irq_domain: IRQ domain of the switch irq_chip + * @irq_enable: IRQ enable bits, synced to SYS_INT_EN ++ * @create_sgmii: Pointer to function creating SGMII PCS instance(s) + */ + struct mt7530_priv { + struct device *dev; +@@ -763,7 +763,6 @@ struct mt7530_priv { + unsigned int p5_intf_sel; + u8 mirror_rx; + u8 mirror_tx; +- + struct mt7530_port ports[MT7530_NUM_PORTS]; + struct mt753x_pcs pcs[MT7530_NUM_PORTS]; + /* protect among processes for registers access*/ +@@ -771,6 +770,7 @@ struct mt7530_priv { + int irq; + struct irq_domain *irq_domain; + u32 irq_enable; ++ int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii); + }; + + struct mt7530_hw_vlan_entry { diff --git a/target/linux/generic/backport-5.15/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch b/target/linux/generic/backport-5.15/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch index 57137c34fc6..e2a0e25a794 100644 --- a/target/linux/generic/backport-5.15/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch +++ b/target/linux/generic/backport-5.15/791-v6.2-01-net-phy-Add-driver-for-Motorcomm-yt8521-gigabit-ethernet.patch @@ -21,7 +21,7 @@ Signed-off-by: David S. Miller --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -12697,6 +12697,7 @@ F: include/uapi/linux/meye.h +@@ -12700,6 +12700,7 @@ F: include/uapi/linux/meye.h MOTORCOMM PHY DRIVER M: Peter Geis diff --git a/target/linux/generic/backport-5.15/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch b/target/linux/generic/backport-5.15/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch index 2a9dc749478..ae177e0cb03 100644 --- a/target/linux/generic/backport-5.15/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch +++ b/target/linux/generic/backport-5.15/804-v5.18-0009-nvmem-Add-driver-for-OCOTP-in-Sunplus-SP7021.patch @@ -19,7 +19,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -17962,6 +17962,11 @@ L: netdev@vger.kernel.org +@@ -17965,6 +17965,11 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/dlink/sundance.c diff --git a/target/linux/generic/backport-5.15/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch b/target/linux/generic/backport-5.15/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch index b1855d1f2f2..ad0460d4f36 100644 --- a/target/linux/generic/backport-5.15/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch +++ b/target/linux/generic/backport-5.15/806-v6.0-0001-nvmem-microchip-otpc-add-support.patch @@ -57,7 +57,7 @@ Signed-off-by: Greg Kroah-Hartman --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -12361,6 +12361,14 @@ S: Supported +@@ -12364,6 +12364,14 @@ S: Supported F: Documentation/devicetree/bindings/mtd/atmel-nand.txt F: drivers/mtd/nand/raw/atmel/* diff --git a/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch b/target/linux/generic/backport-6.1/020-v6.3-01-UPSTREAM-mm-multi-gen-LRU-rename-lru_gen_struct-to-l.patch similarity index 81% rename from target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch rename to target/linux/generic/backport-6.1/020-v6.3-01-UPSTREAM-mm-multi-gen-LRU-rename-lru_gen_struct-to-l.patch index 881ef4e528f..d63b03e6e87 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-21-mm-multi-gen-LRU-rename-lru_gen_struct-to-lru_gen_pa.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-01-UPSTREAM-mm-multi-gen-LRU-rename-lru_gen_struct-to-l.patch @@ -1,7 +1,7 @@ -From 348fdbada9fb3f0bf1a53651be46319105af187f Mon Sep 17 00:00:00 2001 +From 8c20e2eb5f2a0175b774134685e4d7bd93e85ff8 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:18:59 -0700 -Subject: [PATCH 21/29] mm: multi-gen LRU: rename lru_gen_struct to +Subject: [PATCH 01/19] UPSTREAM: mm: multi-gen LRU: rename lru_gen_struct to lru_gen_folio Patch series "mm: multi-gen LRU: memcg LRU", v3. @@ -115,6 +115,10 @@ Cc: Mike Rapoport Cc: Roman Gushchin Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit 391655fe08d1f942359a11148aa9aaf3f99d6d6f) +Change-Id: I7df67e0e2435ba28f10eaa57d28d98b61a9210a6 +Signed-off-by: T.J. Mercier --- include/linux/mm_inline.h | 4 ++-- include/linux/mmzone.h | 6 +++--- @@ -122,9 +126,11 @@ Signed-off-by: Andrew Morton mm/workingset.c | 4 ++-- 4 files changed, 24 insertions(+), 24 deletions(-) +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index e8ed225d8f7ca..f63968bd7de59 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -178,7 +178,7 @@ static inline void lru_gen_update_size(s +@@ -178,7 +178,7 @@ static inline void lru_gen_update_size(struct lruvec *lruvec, struct folio *foli int zone = folio_zonenum(folio); int delta = folio_nr_pages(folio); enum lru_list lru = type * LRU_INACTIVE_FILE; @@ -133,7 +139,7 @@ Signed-off-by: Andrew Morton VM_WARN_ON_ONCE(old_gen != -1 && old_gen >= MAX_NR_GENS); VM_WARN_ON_ONCE(new_gen != -1 && new_gen >= MAX_NR_GENS); -@@ -224,7 +224,7 @@ static inline bool lru_gen_add_folio(str +@@ -224,7 +224,7 @@ static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio, int gen = folio_lru_gen(folio); int type = folio_is_file_lru(folio); int zone = folio_zonenum(folio); @@ -142,6 +148,8 @@ Signed-off-by: Andrew Morton VM_WARN_ON_ONCE_FOLIO(gen != -1, folio); +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 5f74891556f33..bd3e4689f72dc 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -404,7 +404,7 @@ enum { @@ -171,9 +179,11 @@ Signed-off-by: Andrew Morton /* to concurrently iterate lru_gen_mm_list */ struct lru_gen_mm_state mm_state; #endif +diff --git a/mm/vmscan.c b/mm/vmscan.c +index d18296109aa7e..27142caf284c1 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3190,7 +3190,7 @@ static int get_nr_gens(struct lruvec *lr +@@ -3190,7 +3190,7 @@ static int get_nr_gens(struct lruvec *lruvec, int type) static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) { @@ -191,7 +201,7 @@ Signed-off-by: Andrew Morton int hist = lru_hist_from_seq(lrugen->min_seq[type]); pos->refaulted = lrugen->avg_refaulted[type][tier] + -@@ -3611,7 +3611,7 @@ static void read_ctrl_pos(struct lruvec +@@ -3611,7 +3611,7 @@ static void read_ctrl_pos(struct lruvec *lruvec, int type, int tier, int gain, static void reset_ctrl_pos(struct lruvec *lruvec, int type, bool carryover) { int hist, tier; @@ -200,7 +210,7 @@ Signed-off-by: Andrew Morton bool clear = carryover ? NR_HIST_GENS == 1 : NR_HIST_GENS > 1; unsigned long seq = carryover ? lrugen->min_seq[type] : lrugen->max_seq + 1; -@@ -3688,7 +3688,7 @@ static int folio_update_gen(struct folio +@@ -3688,7 +3688,7 @@ static int folio_update_gen(struct folio *folio, int gen) static int folio_inc_gen(struct lruvec *lruvec, struct folio *folio, bool reclaiming) { int type = folio_is_file_lru(folio); @@ -209,7 +219,7 @@ Signed-off-by: Andrew Morton int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); unsigned long new_flags, old_flags = READ_ONCE(folio->flags); -@@ -3733,7 +3733,7 @@ static void update_batch_size(struct lru +@@ -3733,7 +3733,7 @@ static void update_batch_size(struct lru_gen_mm_walk *walk, struct folio *folio, static void reset_batch_size(struct lruvec *lruvec, struct lru_gen_mm_walk *walk) { int gen, type, zone; @@ -218,7 +228,7 @@ Signed-off-by: Andrew Morton walk->batched = 0; -@@ -4253,7 +4253,7 @@ static bool inc_min_seq(struct lruvec *l +@@ -4250,7 +4250,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) { int zone; int remaining = MAX_LRU_BATCH; @@ -227,7 +237,7 @@ Signed-off-by: Andrew Morton int new_gen, old_gen = lru_gen_from_seq(lrugen->min_seq[type]); if (type == LRU_GEN_ANON && !can_swap) -@@ -4289,7 +4289,7 @@ static bool try_to_inc_min_seq(struct lr +@@ -4286,7 +4286,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) { int gen, type, zone; bool success = false; @@ -236,7 +246,7 @@ Signed-off-by: Andrew Morton DEFINE_MIN_SEQ(lruvec); VM_WARN_ON_ONCE(!seq_is_valid(lruvec)); -@@ -4310,7 +4310,7 @@ next: +@@ -4307,7 +4307,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) ; } @@ -245,7 +255,7 @@ Signed-off-by: Andrew Morton if (can_swap) { min_seq[LRU_GEN_ANON] = min(min_seq[LRU_GEN_ANON], min_seq[LRU_GEN_FILE]); min_seq[LRU_GEN_FILE] = max(min_seq[LRU_GEN_ANON], lrugen->min_seq[LRU_GEN_FILE]); -@@ -4332,7 +4332,7 @@ static void inc_max_seq(struct lruvec *l +@@ -4329,7 +4329,7 @@ static void inc_max_seq(struct lruvec *lruvec, bool can_swap, bool force_scan) { int prev, next; int type, zone; @@ -254,7 +264,7 @@ Signed-off-by: Andrew Morton spin_lock_irq(&lruvec->lru_lock); -@@ -4390,7 +4390,7 @@ static bool try_to_inc_max_seq(struct lr +@@ -4387,7 +4387,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, bool success; struct lru_gen_mm_walk *walk; struct mm_struct *mm = NULL; @@ -263,7 +273,7 @@ Signed-off-by: Andrew Morton VM_WARN_ON_ONCE(max_seq > READ_ONCE(lrugen->max_seq)); -@@ -4455,7 +4455,7 @@ static bool should_run_aging(struct lruv +@@ -4452,7 +4452,7 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig unsigned long old = 0; unsigned long young = 0; unsigned long total = 0; @@ -272,7 +282,7 @@ Signed-off-by: Andrew Morton struct mem_cgroup *memcg = lruvec_memcg(lruvec); for (type = !can_swap; type < ANON_AND_FILE; type++) { -@@ -4740,7 +4740,7 @@ static bool sort_folio(struct lruvec *lr +@@ -4737,7 +4737,7 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, int tier_idx) int delta = folio_nr_pages(folio); int refs = folio_lru_refs(folio); int tier = lru_tier_from_refs(refs); @@ -281,7 +291,7 @@ Signed-off-by: Andrew Morton VM_WARN_ON_ONCE_FOLIO(gen >= MAX_NR_GENS, folio); -@@ -4840,7 +4840,7 @@ static int scan_folios(struct lruvec *lr +@@ -4837,7 +4837,7 @@ static int scan_folios(struct lruvec *lruvec, struct scan_control *sc, int scanned = 0; int isolated = 0; int remaining = MAX_LRU_BATCH; @@ -290,7 +300,7 @@ Signed-off-by: Andrew Morton struct mem_cgroup *memcg = lruvec_memcg(lruvec); VM_WARN_ON_ONCE(!list_empty(list)); -@@ -5240,7 +5240,7 @@ done: +@@ -5237,7 +5237,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc static bool __maybe_unused state_is_valid(struct lruvec *lruvec) { @@ -299,7 +309,7 @@ Signed-off-by: Andrew Morton if (lrugen->enabled) { enum lru_list lru; -@@ -5522,7 +5522,7 @@ static void lru_gen_seq_show_full(struct +@@ -5519,7 +5519,7 @@ static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec, int i; int type, tier; int hist = lru_hist_from_seq(seq); @@ -308,7 +318,7 @@ Signed-off-by: Andrew Morton for (tier = 0; tier < MAX_NR_TIERS; tier++) { seq_printf(m, " %10d", tier); -@@ -5572,7 +5572,7 @@ static int lru_gen_seq_show(struct seq_f +@@ -5569,7 +5569,7 @@ static int lru_gen_seq_show(struct seq_file *m, void *v) unsigned long seq; bool full = !debugfs_real_fops(m->file)->write; struct lruvec *lruvec = v; @@ -317,7 +327,7 @@ Signed-off-by: Andrew Morton int nid = lruvec_pgdat(lruvec)->node_id; struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); -@@ -5826,7 +5826,7 @@ void lru_gen_init_lruvec(struct lruvec * +@@ -5823,7 +5823,7 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) { int i; int gen, type, zone; @@ -326,9 +336,11 @@ Signed-off-by: Andrew Morton lrugen->max_seq = MIN_NR_GENS + 1; lrugen->enabled = lru_gen_enabled(); +diff --git a/mm/workingset.c b/mm/workingset.c +index ae7e984b23c6b..688aaa73f64e8 100644 --- a/mm/workingset.c +++ b/mm/workingset.c -@@ -223,7 +223,7 @@ static void *lru_gen_eviction(struct fol +@@ -223,7 +223,7 @@ static void *lru_gen_eviction(struct folio *folio) unsigned long token; unsigned long min_seq; struct lruvec *lruvec; @@ -337,7 +349,7 @@ Signed-off-by: Andrew Morton int type = folio_is_file_lru(folio); int delta = folio_nr_pages(folio); int refs = folio_lru_refs(folio); -@@ -252,7 +252,7 @@ static void lru_gen_refault(struct folio +@@ -252,7 +252,7 @@ static void lru_gen_refault(struct folio *folio, void *shadow) unsigned long token; unsigned long min_seq; struct lruvec *lruvec; @@ -346,3 +358,6 @@ Signed-off-by: Andrew Morton struct mem_cgroup *memcg; struct pglist_data *pgdat; int type = folio_is_file_lru(folio); +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch b/target/linux/generic/backport-6.1/020-v6.3-02-UPSTREAM-mm-multi-gen-LRU-rename-lrugen-lists-to-lru.patch similarity index 60% rename from target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch rename to target/linux/generic/backport-6.1/020-v6.3-02-UPSTREAM-mm-multi-gen-LRU-rename-lrugen-lists-to-lru.patch index 7940380c5ce..65fb0144b1e 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-22-mm-multi-gen-LRU-rename-lrugen-lists-to-lrugen-pages.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-02-UPSTREAM-mm-multi-gen-LRU-rename-lrugen-lists-to-lru.patch @@ -1,7 +1,7 @@ -From afd37e73db04c7e6b47411120ac5f6a7eca51fec Mon Sep 17 00:00:00 2001 +From 656287d55d9cfc72a4bcd4d9bd098570f12ce409 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:00 -0700 -Subject: [PATCH 22/29] mm: multi-gen LRU: rename lrugen->lists[] to +Subject: [PATCH 02/19] UPSTREAM: mm: multi-gen LRU: rename lrugen->lists[] to lrugen->folios[] lru_gen_folio will be chained into per-node lists by the coming @@ -17,15 +17,54 @@ Cc: Mike Rapoport Cc: Roman Gushchin Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit 6df1b2212950aae2b2188c6645ea18e2a9e3fdd5) +Change-Id: I09f53e0fb2cd6b8b3adbb8a80b15dc5efbeae857 +Signed-off-by: T.J. Mercier --- - include/linux/mm_inline.h | 4 ++-- - include/linux/mmzone.h | 8 ++++---- - mm/vmscan.c | 20 ++++++++++---------- - 3 files changed, 16 insertions(+), 16 deletions(-) + Documentation/mm/multigen_lru.rst | 8 ++++---- + include/linux/mm_inline.h | 4 ++-- + include/linux/mmzone.h | 8 ++++---- + mm/vmscan.c | 20 ++++++++++---------- + 4 files changed, 20 insertions(+), 20 deletions(-) +diff --git a/Documentation/mm/multigen_lru.rst b/Documentation/mm/multigen_lru.rst +index d7062c6a89464..d8f721f98868a 100644 +--- a/Documentation/mm/multigen_lru.rst ++++ b/Documentation/mm/multigen_lru.rst +@@ -89,15 +89,15 @@ variables are monotonically increasing. + + Generation numbers are truncated into ``order_base_2(MAX_NR_GENS+1)`` + bits in order to fit into the gen counter in ``folio->flags``. Each +-truncated generation number is an index to ``lrugen->lists[]``. The ++truncated generation number is an index to ``lrugen->folios[]``. The + sliding window technique is used to track at least ``MIN_NR_GENS`` and + at most ``MAX_NR_GENS`` generations. The gen counter stores a value + within ``[1, MAX_NR_GENS]`` while a page is on one of +-``lrugen->lists[]``; otherwise it stores zero. ++``lrugen->folios[]``; otherwise it stores zero. + + Each generation is divided into multiple tiers. A page accessed ``N`` + times through file descriptors is in tier ``order_base_2(N)``. Unlike +-generations, tiers do not have dedicated ``lrugen->lists[]``. In ++generations, tiers do not have dedicated ``lrugen->folios[]``. In + contrast to moving across generations, which requires the LRU lock, + moving across tiers only involves atomic operations on + ``folio->flags`` and therefore has a negligible cost. A feedback loop +@@ -127,7 +127,7 @@ page mapped by this PTE to ``(max_seq%MAX_NR_GENS)+1``. + Eviction + -------- + The eviction consumes old generations. Given an ``lruvec``, it +-increments ``min_seq`` when ``lrugen->lists[]`` indexed by ++increments ``min_seq`` when ``lrugen->folios[]`` indexed by + ``min_seq%MAX_NR_GENS`` becomes empty. To select a type and a tier to + evict from, it first compares ``min_seq[]`` to select the older type. + If both types are equally old, it selects the one whose first tier has +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index f63968bd7de59..da38e3d962e2f 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -256,9 +256,9 @@ static inline bool lru_gen_add_folio(str +@@ -256,9 +256,9 @@ static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio, lru_gen_update_size(lruvec, folio, -1, gen); /* for folio_rotate_reclaimable() */ if (reclaiming) @@ -37,6 +76,8 @@ Signed-off-by: Andrew Morton return true; } +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index bd3e4689f72dc..02e4323744715 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -312,7 +312,7 @@ enum lruvec_flags { @@ -68,9 +109,11 @@ Signed-off-by: Andrew Morton /* the multi-gen LRU sizes, eventually consistent */ long nr_pages[MAX_NR_GENS][ANON_AND_FILE][MAX_NR_ZONES]; /* the exponential moving average of refaulted */ +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 27142caf284c1..b02fed912f742 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4261,7 +4261,7 @@ static bool inc_min_seq(struct lruvec *l +@@ -4258,7 +4258,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) /* prevent cold/hot inversion if force_scan is true */ for (zone = 0; zone < MAX_NR_ZONES; zone++) { @@ -79,7 +122,7 @@ Signed-off-by: Andrew Morton while (!list_empty(head)) { struct folio *folio = lru_to_folio(head); -@@ -4272,7 +4272,7 @@ static bool inc_min_seq(struct lruvec *l +@@ -4269,7 +4269,7 @@ static bool inc_min_seq(struct lruvec *lruvec, int type, bool can_swap) VM_WARN_ON_ONCE_FOLIO(folio_zonenum(folio) != zone, folio); new_gen = folio_inc_gen(lruvec, folio, false); @@ -88,7 +131,7 @@ Signed-off-by: Andrew Morton if (!--remaining) return false; -@@ -4300,7 +4300,7 @@ static bool try_to_inc_min_seq(struct lr +@@ -4297,7 +4297,7 @@ static bool try_to_inc_min_seq(struct lruvec *lruvec, bool can_swap) gen = lru_gen_from_seq(min_seq[type]); for (zone = 0; zone < MAX_NR_ZONES; zone++) { @@ -97,7 +140,7 @@ Signed-off-by: Andrew Morton goto next; } -@@ -4765,7 +4765,7 @@ static bool sort_folio(struct lruvec *lr +@@ -4762,7 +4762,7 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, int tier_idx) /* promoted */ if (gen != lru_gen_from_seq(lrugen->min_seq[type])) { @@ -106,7 +149,7 @@ Signed-off-by: Andrew Morton return true; } -@@ -4774,7 +4774,7 @@ static bool sort_folio(struct lruvec *lr +@@ -4771,7 +4771,7 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, int tier_idx) int hist = lru_hist_from_seq(lrugen->min_seq[type]); gen = folio_inc_gen(lruvec, folio, false); @@ -115,7 +158,7 @@ Signed-off-by: Andrew Morton WRITE_ONCE(lrugen->protected[hist][type][tier - 1], lrugen->protected[hist][type][tier - 1] + delta); -@@ -4786,7 +4786,7 @@ static bool sort_folio(struct lruvec *lr +@@ -4783,7 +4783,7 @@ static bool sort_folio(struct lruvec *lruvec, struct folio *folio, int tier_idx) if (folio_test_locked(folio) || folio_test_writeback(folio) || (type == LRU_GEN_FILE && folio_test_dirty(folio))) { gen = folio_inc_gen(lruvec, folio, true); @@ -124,7 +167,7 @@ Signed-off-by: Andrew Morton return true; } -@@ -4853,7 +4853,7 @@ static int scan_folios(struct lruvec *lr +@@ -4850,7 +4850,7 @@ static int scan_folios(struct lruvec *lruvec, struct scan_control *sc, for (zone = sc->reclaim_idx; zone >= 0; zone--) { LIST_HEAD(moved); int skipped = 0; @@ -133,7 +176,7 @@ Signed-off-by: Andrew Morton while (!list_empty(head)) { struct folio *folio = lru_to_folio(head); -@@ -5253,7 +5253,7 @@ static bool __maybe_unused state_is_vali +@@ -5250,7 +5250,7 @@ static bool __maybe_unused state_is_valid(struct lruvec *lruvec) int gen, type, zone; for_each_gen_type_zone(gen, type, zone) { @@ -142,7 +185,7 @@ Signed-off-by: Andrew Morton return false; } } -@@ -5298,7 +5298,7 @@ static bool drain_evictable(struct lruve +@@ -5295,7 +5295,7 @@ static bool drain_evictable(struct lruvec *lruvec) int remaining = MAX_LRU_BATCH; for_each_gen_type_zone(gen, type, zone) { @@ -151,7 +194,7 @@ Signed-off-by: Andrew Morton while (!list_empty(head)) { bool success; -@@ -5835,7 +5835,7 @@ void lru_gen_init_lruvec(struct lruvec * +@@ -5832,7 +5832,7 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) lrugen->timestamps[i] = jiffies; for_each_gen_type_zone(gen, type, zone) @@ -160,3 +203,6 @@ Signed-off-by: Andrew Morton lruvec->mm_state.seq = MIN_NR_GENS; init_waitqueue_head(&lruvec->mm_state.wait); +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch b/target/linux/generic/backport-6.1/020-v6.3-03-UPSTREAM-mm-multi-gen-LRU-remove-eviction-fairness-s.patch similarity index 79% rename from target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch rename to target/linux/generic/backport-6.1/020-v6.3-03-UPSTREAM-mm-multi-gen-LRU-remove-eviction-fairness-s.patch index d214898a6d0..6d764bb2b44 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-23-mm-multi-gen-LRU-remove-eviction-fairness-safeguard.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-03-UPSTREAM-mm-multi-gen-LRU-remove-eviction-fairness-s.patch @@ -1,7 +1,8 @@ -From ce45f1c4b32cf69b166f56ef5bc6c761e06ed4e5 Mon Sep 17 00:00:00 2001 +From 14f9a7a15f3d1af351f30e0438fd747b7ac253b0 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:01 -0700 -Subject: [PATCH 23/29] mm: multi-gen LRU: remove eviction fairness safeguard +Subject: [PATCH 03/19] UPSTREAM: mm: multi-gen LRU: remove eviction fairness + safeguard Recall that the eviction consumes the oldest generation: first it bucket-sorts folios whose gen counters were updated by the aging and @@ -31,13 +32,19 @@ Cc: Mike Rapoport Cc: Roman Gushchin Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit a579086c99ed70cc4bfc104348dbe3dd8f2787e6) +Change-Id: I08ac1b3c90e29cafd0566785aaa4bcdb5db7d22c +Signed-off-by: T.J. Mercier --- - mm/vmscan.c | 82 +++++++++++++++-------------------------------------- - 1 file changed, 23 insertions(+), 59 deletions(-) + mm/vmscan.c | 81 +++++++++++++++-------------------------------------- + 1 file changed, 23 insertions(+), 58 deletions(-) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index b02fed912f742..991961180b320 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -448,6 +448,11 @@ static bool cgroup_reclaim(struct scan_c +@@ -448,6 +448,11 @@ static bool cgroup_reclaim(struct scan_control *sc) return sc->target_mem_cgroup; } @@ -49,7 +56,7 @@ Signed-off-by: Andrew Morton /** * writeback_throttling_sane - is the usual dirty throttling mechanism available? * @sc: scan_control in question -@@ -498,6 +503,11 @@ static bool cgroup_reclaim(struct scan_c +@@ -498,6 +503,11 @@ static bool cgroup_reclaim(struct scan_control *sc) return false; } @@ -61,7 +68,7 @@ Signed-off-by: Andrew Morton static bool writeback_throttling_sane(struct scan_control *sc) { return true; -@@ -4996,8 +5006,7 @@ static int isolate_folios(struct lruvec +@@ -4993,8 +5003,7 @@ static int isolate_folios(struct lruvec *lruvec, struct scan_control *sc, int sw return scanned; } @@ -71,7 +78,7 @@ Signed-off-by: Andrew Morton { int type; int scanned; -@@ -5086,9 +5095,6 @@ retry: +@@ -5083,9 +5092,6 @@ static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swap goto retry; } @@ -81,7 +88,7 @@ Signed-off-by: Andrew Morton return scanned; } -@@ -5127,67 +5133,26 @@ done: +@@ -5124,67 +5130,26 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * return min_seq[!can_swap] + MIN_NR_GENS <= max_seq ? nr_to_scan : 0; } @@ -158,7 +165,7 @@ Signed-off-by: Andrew Morton lru_add_drain(); -@@ -5211,7 +5176,7 @@ static void lru_gen_shrink_lruvec(struct +@@ -5208,7 +5173,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc if (!nr_to_scan) goto done; @@ -167,7 +174,7 @@ Signed-off-by: Andrew Morton if (!delta) goto done; -@@ -5219,7 +5184,7 @@ static void lru_gen_shrink_lruvec(struct +@@ -5216,7 +5181,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc if (scanned >= nr_to_scan) break; @@ -176,7 +183,7 @@ Signed-off-by: Andrew Morton break; cond_resched(); -@@ -5669,7 +5634,7 @@ static int run_eviction(struct lruvec *l +@@ -5666,7 +5631,7 @@ static int run_eviction(struct lruvec *lruvec, unsigned long seq, struct scan_co if (sc->nr_reclaimed >= nr_to_reclaim) return 0; @@ -185,3 +192,6 @@ Signed-off-by: Andrew Morton return 0; cond_resched(); +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch b/target/linux/generic/backport-6.1/020-v6.3-04-BACKPORT-mm-multi-gen-LRU-remove-aging-fairness-safe.patch similarity index 85% rename from target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch rename to target/linux/generic/backport-6.1/020-v6.3-04-BACKPORT-mm-multi-gen-LRU-remove-aging-fairness-safe.patch index 7cbabd34e4f..c3f534a9e0c 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-24-mm-multi-gen-LRU-remove-aging-fairness-safeguard.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-04-BACKPORT-mm-multi-gen-LRU-remove-aging-fairness-safe.patch @@ -1,7 +1,8 @@ -From e20b7386fccc18c791796eb1dc1a91eee3ccf801 Mon Sep 17 00:00:00 2001 +From f3c93d2e37a3c56593d7ccf4f4bcf1b58426fdd8 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:02 -0700 -Subject: [PATCH 24/29] mm: multi-gen LRU: remove aging fairness safeguard +Subject: [PATCH 04/19] BACKPORT: mm: multi-gen LRU: remove aging fairness + safeguard Recall that the aging produces the youngest generation: first it scans for accessed folios and updates their gen counters; then it increments @@ -31,10 +32,18 @@ Cc: Mike Rapoport Cc: Roman Gushchin Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit 7348cc91821b0cb24dfb00e578047f68299a50ab) +[TJ: Resolved conflicts with older function signatures for +min_cgroup_below_min / min_cgroup_below_low] +Change-Id: I6e36ecfbaaefbc0a56d9a9d5d7cbe404ed7f57a5 +Signed-off-by: T.J. Mercier --- mm/vmscan.c | 126 ++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 67 deletions(-) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 991961180b320..5a2e83e673232 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -136,7 +136,6 @@ struct scan_control { @@ -45,7 +54,7 @@ Signed-off-by: Andrew Morton unsigned long last_reclaimed; #endif -@@ -4458,7 +4457,7 @@ done: +@@ -4455,7 +4454,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, return true; } @@ -54,7 +63,7 @@ Signed-off-by: Andrew Morton struct scan_control *sc, bool can_swap, unsigned long *nr_to_scan) { int gen, type, zone; -@@ -4467,6 +4466,13 @@ static bool should_run_aging(struct lruv +@@ -4464,6 +4463,13 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig unsigned long total = 0; struct lru_gen_folio *lrugen = &lruvec->lrugen; struct mem_cgroup *memcg = lruvec_memcg(lruvec); @@ -68,7 +77,7 @@ Signed-off-by: Andrew Morton for (type = !can_swap; type < ANON_AND_FILE; type++) { unsigned long seq; -@@ -4495,8 +4501,6 @@ static bool should_run_aging(struct lruv +@@ -4492,8 +4498,6 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig * stalls when the number of generations reaches MIN_NR_GENS. Hence, the * ideal number of generations is MIN_NR_GENS+1. */ @@ -77,7 +86,7 @@ Signed-off-by: Andrew Morton if (min_seq[!can_swap] + MIN_NR_GENS < max_seq) return false; -@@ -4515,40 +4519,54 @@ static bool should_run_aging(struct lruv +@@ -4512,40 +4516,54 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, unsig return false; } @@ -153,7 +162,7 @@ Signed-off-by: Andrew Morton } /* to protect the working set of the last N jiffies */ -@@ -4557,46 +4575,32 @@ static unsigned long lru_gen_min_ttl __r +@@ -4554,46 +4572,32 @@ static unsigned long lru_gen_min_ttl __read_mostly; static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) { struct mem_cgroup *memcg; @@ -207,7 +216,7 @@ Signed-off-by: Andrew Morton */ if (mutex_trylock(&oom_lock)) { struct oom_control oc = { -@@ -5104,33 +5108,27 @@ retry: +@@ -5101,33 +5105,27 @@ static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swap * reclaim. */ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, @@ -247,7 +256,7 @@ Signed-off-by: Andrew Morton } static unsigned long get_nr_to_reclaim(struct scan_control *sc) -@@ -5149,9 +5147,7 @@ static unsigned long get_nr_to_reclaim(s +@@ -5146,9 +5144,7 @@ static unsigned long get_nr_to_reclaim(struct scan_control *sc) static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) { struct blk_plug plug; @@ -257,7 +266,7 @@ Signed-off-by: Andrew Morton unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); lru_add_drain(); -@@ -5172,13 +5168,13 @@ static void lru_gen_shrink_lruvec(struct +@@ -5169,13 +5165,13 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc else swappiness = 0; @@ -274,7 +283,7 @@ Signed-off-by: Andrew Morton scanned += delta; if (scanned >= nr_to_scan) -@@ -5190,10 +5186,6 @@ static void lru_gen_shrink_lruvec(struct +@@ -5187,10 +5183,6 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc cond_resched(); } @@ -285,3 +294,6 @@ Signed-off-by: Andrew Morton clear_mm_walk(); blk_finish_plug(&plug); +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch b/target/linux/generic/backport-6.1/020-v6.3-05-UPSTREAM-mm-multi-gen-LRU-shuffle-should_run_aging.patch similarity index 87% rename from target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch rename to target/linux/generic/backport-6.1/020-v6.3-05-UPSTREAM-mm-multi-gen-LRU-shuffle-should_run_aging.patch index bedbbd3e1b6..d6bfe2a91c2 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-25-mm-multi-gen-LRU-shuffle-should_run_aging.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-05-UPSTREAM-mm-multi-gen-LRU-shuffle-should_run_aging.patch @@ -1,12 +1,11 @@ -From 107d54931df3c28d81648122e219bf0034ef4e99 Mon Sep 17 00:00:00 2001 +From eca3858631e0cbad2ca6e40f788892749428e4cb Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:03 -0700 -Subject: [PATCH 25/29] mm: multi-gen LRU: shuffle should_run_aging() +Subject: [PATCH 05/19] UPSTREAM: mm: multi-gen LRU: shuffle should_run_aging() Move should_run_aging() next to its only caller left. Link: https://lkml.kernel.org/r/20221222041905.2431096-6-yuzhao@google.com -Signed-off-by: Yu Zhao Cc: Johannes Weiner Cc: Jonathan Corbet Cc: Michael Larabel @@ -15,13 +14,21 @@ Cc: Mike Rapoport Cc: Roman Gushchin Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit 77d4459a4a1a472b7309e475f962dda87d950abd) +Signed-off-by: T.J. Mercier +Change-Id: I3b0383fe16b93a783b4d8c0b3a0b325160392576 +Signed-off-by: Yu Zhao +Signed-off-by: T.J. Mercier --- mm/vmscan.c | 124 ++++++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 62 deletions(-) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 5a2e83e673232..0c47952714b26 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4457,68 +4457,6 @@ done: +@@ -4454,68 +4454,6 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, return true; } @@ -90,7 +97,7 @@ Signed-off-by: Andrew Morton static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) { int gen, type, zone; -@@ -5102,6 +5040,68 @@ retry: +@@ -5099,6 +5037,68 @@ static int evict_folios(struct lruvec *lruvec, struct scan_control *sc, int swap return scanned; } @@ -159,3 +166,6 @@ Signed-off-by: Andrew Morton /* * For future optimizations: * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch b/target/linux/generic/backport-6.1/020-v6.3-06-BACKPORT-mm-multi-gen-LRU-per-node-lru_gen_folio-lis.patch similarity index 85% rename from target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch rename to target/linux/generic/backport-6.1/020-v6.3-06-BACKPORT-mm-multi-gen-LRU-per-node-lru_gen_folio-lis.patch index 45789ff2094..14f28820ec0 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-26-mm-multi-gen-LRU-per-node-lru_gen_page-lists.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-06-BACKPORT-mm-multi-gen-LRU-per-node-lru_gen_folio-lis.patch @@ -1,7 +1,8 @@ -From fa6363828d314e837c5f79e97ea5e8c0d2f7f062 Mon Sep 17 00:00:00 2001 +From 8ee8571e47aa75221e5fbd4c9c7802fc4244c346 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:04 -0700 -Subject: [PATCH 26/29] mm: multi-gen LRU: per-node lru_gen_folio lists +Subject: [PATCH 06/19] BACKPORT: mm: multi-gen LRU: per-node lru_gen_folio + lists For each node, memcgs are divided into two generations: the old and the young. For each generation, memcgs are randomly sharded into @@ -58,18 +59,26 @@ Cc: Mike Rapoport Cc: Roman Gushchin Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit e4dde56cd208674ce899b47589f263499e5b8cdc) +[TJ: Resolved conflicts with older function signatures for +min_cgroup_below_min / min_cgroup_below_low and includes] +Change-Id: Idc8a0f635e035d72dd911f807d1224cb47cbd655 +Signed-off-by: T.J. Mercier --- include/linux/memcontrol.h | 10 + include/linux/mm_inline.h | 17 ++ include/linux/mmzone.h | 117 +++++++++++- mm/memcontrol.c | 16 ++ - mm/folio_alloc.c | 1 + - mm/vmscan.c | 373 +++++++++++++++++++++++++++++++++---- - 6 files changed, 499 insertions(+), 35 deletions(-) + mm/page_alloc.c | 1 + + mm/vmscan.c | 374 +++++++++++++++++++++++++++++++++---- + 6 files changed, 500 insertions(+), 35 deletions(-) +diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h +index e039763029563..82d28b052a9e5 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h -@@ -790,6 +790,11 @@ static inline void obj_cgroup_put(struct +@@ -790,6 +790,11 @@ static inline void obj_cgroup_put(struct obj_cgroup *objcg) percpu_ref_put(&objcg->refcnt); } @@ -81,7 +90,7 @@ Signed-off-by: Andrew Morton static inline void mem_cgroup_put(struct mem_cgroup *memcg) { if (memcg) -@@ -1290,6 +1295,11 @@ static inline void obj_cgroup_put(struct +@@ -1290,6 +1295,11 @@ static inline void obj_cgroup_put(struct obj_cgroup *objcg) { } @@ -93,9 +102,11 @@ Signed-off-by: Andrew Morton static inline void mem_cgroup_put(struct mem_cgroup *memcg) { } +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index da38e3d962e2f..c1fd3922dc5dd 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -122,6 +122,18 @@ static inline bool lru_gen_in_fault(void +@@ -122,6 +122,18 @@ static inline bool lru_gen_in_fault(void) return current->in_lru_fault; } @@ -114,7 +125,7 @@ Signed-off-by: Andrew Morton static inline int lru_gen_from_seq(unsigned long seq) { return seq % MAX_NR_GENS; -@@ -297,6 +309,11 @@ static inline bool lru_gen_in_fault(void +@@ -297,6 +309,11 @@ static inline bool lru_gen_in_fault(void) return false; } @@ -126,6 +137,8 @@ Signed-off-by: Andrew Morton static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio, bool reclaiming) { return false; +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 02e4323744715..66e067a635682 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -7,6 +7,7 @@ @@ -167,7 +180,7 @@ Signed-off-by: Andrew Morton }; enum { -@@ -479,12 +497,87 @@ void lru_gen_init_lruvec(struct lruvec * +@@ -479,12 +497,87 @@ void lru_gen_init_lruvec(struct lruvec *lruvec); void lru_gen_look_around(struct page_vma_mapped_walk *pvmw); #ifdef CONFIG_MEMCG @@ -256,7 +269,7 @@ Signed-off-by: Andrew Morton static inline void lru_gen_init_lruvec(struct lruvec *lruvec) { } -@@ -494,6 +587,7 @@ static inline void lru_gen_look_around(s +@@ -494,6 +587,7 @@ static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) } #ifdef CONFIG_MEMCG @@ -264,7 +277,7 @@ Signed-off-by: Andrew Morton static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) { } -@@ -501,7 +595,24 @@ static inline void lru_gen_init_memcg(st +@@ -501,7 +595,24 @@ static inline void lru_gen_init_memcg(struct mem_cgroup *memcg) static inline void lru_gen_exit_memcg(struct mem_cgroup *memcg) { } @@ -299,9 +312,11 @@ Signed-off-by: Andrew Morton #endif CACHELINE_PADDING(_pad2_); +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index 3e8f1ad0fe9db..7815d556e38cc 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c -@@ -477,6 +477,16 @@ static void mem_cgroup_update_tree(struc +@@ -477,6 +477,16 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, int nid) struct mem_cgroup_per_node *mz; struct mem_cgroup_tree_per_node *mctz; @@ -318,7 +333,7 @@ Signed-off-by: Andrew Morton mctz = soft_limit_tree.rb_tree_per_node[nid]; if (!mctz) return; -@@ -3522,6 +3532,9 @@ unsigned long mem_cgroup_soft_limit_recl +@@ -3522,6 +3532,9 @@ unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order, struct mem_cgroup_tree_per_node *mctz; unsigned long excess; @@ -328,7 +343,7 @@ Signed-off-by: Andrew Morton if (order > 0) return 0; -@@ -5382,6 +5395,7 @@ static int mem_cgroup_css_online(struct +@@ -5382,6 +5395,7 @@ static int mem_cgroup_css_online(struct cgroup_subsys_state *css) if (unlikely(mem_cgroup_is_root(memcg))) queue_delayed_work(system_unbound_wq, &stats_flush_dwork, 2UL*HZ); @@ -336,7 +351,7 @@ Signed-off-by: Andrew Morton return 0; offline_kmem: memcg_offline_kmem(memcg); -@@ -5413,6 +5427,7 @@ static void mem_cgroup_css_offline(struc +@@ -5413,6 +5427,7 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) memcg_offline_kmem(memcg); reparent_shrinker_deferred(memcg); wb_memcg_offline(memcg); @@ -344,7 +359,7 @@ Signed-off-by: Andrew Morton drain_all_stock(memcg); -@@ -5424,6 +5439,7 @@ static void mem_cgroup_css_released(stru +@@ -5424,6 +5439,7 @@ static void mem_cgroup_css_released(struct cgroup_subsys_state *css) struct mem_cgroup *memcg = mem_cgroup_from_css(css); invalidate_reclaim_iterators(memcg); @@ -352,9 +367,11 @@ Signed-off-by: Andrew Morton } static void mem_cgroup_css_free(struct cgroup_subsys_state *css) +diff --git a/mm/page_alloc.c b/mm/page_alloc.c +index 69668817fed37..473057b81a9df 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c -@@ -7957,6 +7957,7 @@ static void __init free_area_init_node(i +@@ -7957,6 +7957,7 @@ static void __init free_area_init_node(int nid) pgdat_set_deferred_range(pgdat); free_area_init_core(pgdat); @@ -362,6 +379,8 @@ Signed-off-by: Andrew Morton } static void __init free_area_init_memoryless_node(int nid) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 0c47952714b26..65eb28448f216 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -54,6 +54,8 @@ @@ -385,7 +404,7 @@ Signed-off-by: Andrew Morton /* Allocation order */ s8 order; -@@ -3160,6 +3157,9 @@ DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_ca +@@ -3160,6 +3157,9 @@ DEFINE_STATIC_KEY_ARRAY_FALSE(lru_gen_caps, NR_LRU_GEN_CAPS); for ((type) = 0; (type) < ANON_AND_FILE; (type)++) \ for ((zone) = 0; (zone) < MAX_NR_ZONES; (zone)++) @@ -395,7 +414,7 @@ Signed-off-by: Andrew Morton static struct lruvec *get_lruvec(struct mem_cgroup *memcg, int nid) { struct pglist_data *pgdat = NODE_DATA(nid); -@@ -4443,8 +4443,7 @@ done: +@@ -4440,8 +4440,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, if (sc->priority <= DEF_PRIORITY - 2) wait_event_killable(lruvec->mm_state.wait, max_seq < READ_ONCE(lrugen->max_seq)); @@ -405,7 +424,7 @@ Signed-off-by: Andrew Morton } VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); -@@ -4517,8 +4516,6 @@ static void lru_gen_age_node(struct pgli +@@ -4514,8 +4513,6 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) VM_WARN_ON_ONCE(!current_is_kswapd()); @@ -414,7 +433,7 @@ Signed-off-by: Andrew Morton /* check the order to exclude compaction-induced reclaim */ if (!min_ttl || sc->order || sc->priority == DEF_PRIORITY) return; -@@ -5107,8 +5104,7 @@ static bool should_run_aging(struct lruv +@@ -5104,8 +5101,7 @@ static bool should_run_aging(struct lruvec *lruvec, unsigned long max_seq, * 1. Defer try_to_inc_max_seq() to workqueues to reduce latency for memcg * reclaim. */ @@ -424,7 +443,7 @@ Signed-off-by: Andrew Morton { unsigned long nr_to_scan; struct mem_cgroup *memcg = lruvec_memcg(lruvec); -@@ -5125,10 +5121,8 @@ static unsigned long get_nr_to_scan(stru +@@ -5122,10 +5118,8 @@ static unsigned long get_nr_to_scan(struct lruvec *lruvec, struct scan_control * if (sc->priority == DEF_PRIORITY) return nr_to_scan; @@ -436,7 +455,7 @@ Signed-off-by: Andrew Morton } static unsigned long get_nr_to_reclaim(struct scan_control *sc) -@@ -5137,29 +5131,18 @@ static unsigned long get_nr_to_reclaim(s +@@ -5134,29 +5128,18 @@ static unsigned long get_nr_to_reclaim(struct scan_control *sc) if (!global_reclaim(sc)) return -1; @@ -468,7 +487,7 @@ Signed-off-by: Andrew Morton if (sc->may_swap) swappiness = get_swappiness(lruvec, sc); -@@ -5169,7 +5152,7 @@ static void lru_gen_shrink_lruvec(struct +@@ -5166,7 +5149,7 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc swappiness = 0; nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); @@ -477,7 +496,7 @@ Signed-off-by: Andrew Morton break; delta = evict_folios(lruvec, sc, swappiness); -@@ -5186,10 +5169,250 @@ static void lru_gen_shrink_lruvec(struct +@@ -5183,11 +5166,252 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc cond_resched(); } @@ -515,8 +534,9 @@ Signed-off-by: Andrew Morton + + shrink_slab(sc->gfp_mask, pgdat->node_id, memcg, sc->priority); + -+ vmpressure(sc->gfp_mask, memcg, false, sc->nr_scanned - scanned, -+ sc->nr_reclaimed - reclaimed); ++ if (!sc->proactive) ++ vmpressure(sc->gfp_mask, memcg, false, sc->nr_scanned - scanned, ++ sc->nr_reclaimed - reclaimed); + + sc->nr_reclaimed += current->reclaim_state->reclaimed_slab; + current->reclaim_state->reclaimed_slab = 0; @@ -538,7 +558,7 @@ Signed-off-by: Andrew Morton + struct mem_cgroup *memcg = NULL; + unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); + -+ bin = first_bin = prandom_u32_max(MEMCG_NR_BINS); ++ bin = first_bin = get_random_u32_below(MEMCG_NR_BINS); +restart: + gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq)); + @@ -601,11 +621,11 @@ Signed-off-by: Andrew Morton + if (try_to_shrink_lruvec(lruvec, sc)) + lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); + -+ clear_mm_walk(); -+ -+ blk_finish_plug(&plug); -+} -+ + clear_mm_walk(); + + blk_finish_plug(&plug); + } + +#else /* !CONFIG_MEMCG */ + +static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) @@ -671,9 +691,9 @@ Signed-off-by: Andrew Morton + if (current_is_kswapd()) + sc->nr_reclaimed += reclaimed; + - clear_mm_walk(); - - blk_finish_plug(&plug); ++ clear_mm_walk(); ++ ++ blk_finish_plug(&plug); + + /* kswapd should never fail */ + pgdat->kswapd_failures = 0; @@ -684,7 +704,7 @@ Signed-off-by: Andrew Morton +{ + int seg; + int old, new; -+ int bin = prandom_u32_max(MEMCG_NR_BINS); ++ int bin = get_random_u32_below(MEMCG_NR_BINS); + struct pglist_data *pgdat = lruvec_pgdat(lruvec); + + spin_lock(&pgdat->memcg_lru.lock); @@ -723,12 +743,13 @@ Signed-off-by: Andrew Morton + WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); + + spin_unlock(&pgdat->memcg_lru.lock); - } ++} +#endif - ++ /****************************************************************************** * state change -@@ -5647,11 +5870,11 @@ static int run_cmd(char cmd, int memcg_i + ******************************************************************************/ +@@ -5644,11 +5868,11 @@ static int run_cmd(char cmd, int memcg_id, int nid, unsigned long seq, if (!mem_cgroup_disabled()) { rcu_read_lock(); @@ -743,7 +764,7 @@ Signed-off-by: Andrew Morton rcu_read_unlock(); if (!memcg) -@@ -5799,6 +6022,19 @@ void lru_gen_init_lruvec(struct lruvec * +@@ -5796,6 +6020,19 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) } #ifdef CONFIG_MEMCG @@ -763,7 +784,7 @@ Signed-off-by: Andrew Morton void lru_gen_init_memcg(struct mem_cgroup *memcg) { INIT_LIST_HEAD(&memcg->mm_list.fifo); -@@ -5822,7 +6058,69 @@ void lru_gen_exit_memcg(struct mem_cgrou +@@ -5819,7 +6056,69 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) } } } @@ -773,7 +794,7 @@ Signed-off-by: Andrew Morton +{ + int gen; + int nid; -+ int bin = prandom_u32_max(MEMCG_NR_BINS); ++ int bin = get_random_u32_below(MEMCG_NR_BINS); + + for_each_node(nid) { + struct pglist_data *pgdat = NODE_DATA(nid); @@ -834,7 +855,7 @@ Signed-off-by: Andrew Morton static int __init init_lru_gen(void) { -@@ -5849,6 +6147,10 @@ static void lru_gen_shrink_lruvec(struct +@@ -5846,6 +6145,10 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc { } @@ -845,7 +866,7 @@ Signed-off-by: Andrew Morton #endif /* CONFIG_LRU_GEN */ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) -@@ -5862,7 +6164,7 @@ static void shrink_lruvec(struct lruvec +@@ -5859,7 +6162,7 @@ static void shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) bool proportional_reclaim; struct blk_plug plug; @@ -854,7 +875,7 @@ Signed-off-by: Andrew Morton lru_gen_shrink_lruvec(lruvec, sc); return; } -@@ -6105,6 +6407,11 @@ static void shrink_node(pg_data_t *pgdat +@@ -6102,6 +6405,11 @@ static void shrink_node(pg_data_t *pgdat, struct scan_control *sc) struct lruvec *target_lruvec; bool reclaimable = false; @@ -866,3 +887,6 @@ Signed-off-by: Andrew Morton target_lruvec = mem_cgroup_lruvec(sc->target_mem_cgroup, pgdat); again: +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch b/target/linux/generic/backport-6.1/020-v6.3-07-BACKPORT-mm-multi-gen-LRU-clarify-scan_control-flags.patch similarity index 71% rename from target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch rename to target/linux/generic/backport-6.1/020-v6.3-07-BACKPORT-mm-multi-gen-LRU-clarify-scan_control-flags.patch index 89f7ed30afa..9aaf247a098 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-27-mm-multi-gen-LRU-clarify-scan_control-flags.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-07-BACKPORT-mm-multi-gen-LRU-clarify-scan_control-flags.patch @@ -1,7 +1,7 @@ -From 93147736b5b3a21bea24313bfc7a696829932009 Mon Sep 17 00:00:00 2001 +From 11b14ee8cbbbebd8204609076a9327a1171cd253 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:05 -0700 -Subject: [PATCH 27/29] mm: multi-gen LRU: clarify scan_control flags +Subject: [PATCH 07/19] BACKPORT: mm: multi-gen LRU: clarify scan_control flags Among the flags in scan_control: 1. sc->may_swap, which indicates swap constraint due to memsw.max, is @@ -12,7 +12,7 @@ Among the flags in scan_control: 3. !(sc->gfp_mask & __GFP_IO), which indicates IO constraint, lowers swappiness to prioritize file LRU, since clean file folios are more likely to exist. -4. sc->may_writefolio and sc->may_unmap, which indicates opportunistic +4. sc->may_writepage and sc->may_unmap, which indicates opportunistic reclaim, are rejected, since unmapped clean folios are already prioritized. Scanning for more of them is likely futile and can cause high reclaim latency when there is a large number of memcgs. @@ -29,13 +29,21 @@ Cc: Mike Rapoport Cc: Roman Gushchin Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit e9d4e1ee788097484606c32122f146d802a9c5fb) +[TJ: Resolved conflict with older function signature for min_cgroup_below_min, and over +cdded861182142ac4488a4d64c571107aeb77f53 ("ANDROID: MGLRU: Don't skip anon reclaim if swap low")] +Change-Id: Ic2e779eaf4e91a3921831b4e2fa10c740dc59d50 +Signed-off-by: T.J. Mercier --- mm/vmscan.c | 55 +++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 65eb28448f216..0a0e1250ffc87 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3185,6 +3185,9 @@ static int get_swappiness(struct lruvec +@@ -3185,6 +3185,9 @@ static int get_swappiness(struct lruvec *lruvec, struct scan_control *sc) struct mem_cgroup *memcg = lruvec_memcg(lruvec); struct pglist_data *pgdat = lruvec_pgdat(lruvec); @@ -45,7 +53,7 @@ Signed-off-by: Andrew Morton if (!can_demote(pgdat->node_id, sc) && mem_cgroup_get_nr_swap_pages(memcg) < MIN_LRU_BATCH) return 0; -@@ -4226,7 +4229,7 @@ static void walk_mm(struct lruvec *lruve +@@ -4223,7 +4226,7 @@ static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_ } while (err == -EAGAIN); } @@ -54,7 +62,7 @@ Signed-off-by: Andrew Morton { struct lru_gen_mm_walk *walk = current->reclaim_state->mm_walk; -@@ -4234,7 +4237,7 @@ static struct lru_gen_mm_walk *set_mm_wa +@@ -4231,7 +4234,7 @@ static struct lru_gen_mm_walk *set_mm_walk(struct pglist_data *pgdat) VM_WARN_ON_ONCE(walk); walk = &pgdat->mm_walk; @@ -63,7 +71,7 @@ Signed-off-by: Andrew Morton VM_WARN_ON_ONCE(current_is_kswapd()); walk = kzalloc(sizeof(*walk), __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); -@@ -4420,7 +4423,7 @@ static bool try_to_inc_max_seq(struct lr +@@ -4417,7 +4420,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, goto done; } @@ -72,7 +80,7 @@ Signed-off-by: Andrew Morton if (!walk) { success = iterate_mm_list_nowalk(lruvec, max_seq); goto done; -@@ -4489,8 +4492,6 @@ static bool lruvec_is_reclaimable(struct +@@ -4486,8 +4489,6 @@ static bool lruvec_is_reclaimable(struct lruvec *lruvec, struct scan_control *sc struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MIN_SEQ(lruvec); @@ -81,7 +89,7 @@ Signed-off-by: Andrew Morton /* see the comment on lru_gen_folio */ gen = lru_gen_from_seq(min_seq[LRU_GEN_FILE]); birth = READ_ONCE(lruvec->lrugen.timestamps[gen]); -@@ -4746,12 +4747,8 @@ static bool isolate_folio(struct lruvec +@@ -4743,12 +4744,8 @@ static bool isolate_folio(struct lruvec *lruvec, struct folio *folio, struct sca { bool success; @@ -95,19 +103,19 @@ Signed-off-by: Andrew Morton (folio_test_dirty(folio) || (folio_test_anon(folio) && !folio_test_swapcache(folio)))) return false; -@@ -4848,9 +4845,8 @@ static int scan_folios(struct lruvec *lr +@@ -4845,9 +4842,8 @@ static int scan_folios(struct lruvec *lruvec, struct scan_control *sc, __count_vm_events(PGSCAN_ANON + type, isolated); /* - * There might not be eligible pages due to reclaim_idx, may_unmap and - * may_writepage. Check the remaining to prevent livelock if it's not - * making progress. -+ * There might not be eligible pages due to reclaim_idx. Check the ++ * There might not be eligible folios due to reclaim_idx. Check the + * remaining to prevent livelock if it's not making progress. */ return isolated || !remaining ? scanned : 0; } -@@ -5110,8 +5106,7 @@ static long get_nr_to_scan(struct lruvec +@@ -5107,8 +5103,7 @@ static long get_nr_to_scan(struct lruvec *lruvec, struct scan_control *sc, bool struct mem_cgroup *memcg = lruvec_memcg(lruvec); DEFINE_MAX_SEQ(lruvec); @@ -117,7 +125,7 @@ Signed-off-by: Andrew Morton return 0; if (!should_run_aging(lruvec, max_seq, sc, can_swap, &nr_to_scan)) -@@ -5139,17 +5134,14 @@ static bool try_to_shrink_lruvec(struct +@@ -5136,17 +5131,14 @@ static bool try_to_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) long nr_to_scan; unsigned long scanned = 0; unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); @@ -140,7 +148,7 @@ Signed-off-by: Andrew Morton nr_to_scan = get_nr_to_scan(lruvec, sc, swappiness); if (nr_to_scan <= 0) -@@ -5279,12 +5271,13 @@ static void lru_gen_shrink_lruvec(struct +@@ -5277,12 +5269,13 @@ static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc struct blk_plug plug; VM_WARN_ON_ONCE(global_reclaim(sc)); @@ -155,7 +163,7 @@ Signed-off-by: Andrew Morton if (try_to_shrink_lruvec(lruvec, sc)) lru_gen_rotate_memcg(lruvec, MEMCG_LRU_YOUNG); -@@ -5340,11 +5333,19 @@ static void lru_gen_shrink_node(struct p +@@ -5338,11 +5331,19 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control * VM_WARN_ON_ONCE(!global_reclaim(sc)); @@ -172,11 +180,11 @@ Signed-off-by: Andrew Morton blk_start_plug(&plug); - set_mm_walk(pgdat); -+ set_mm_walk(NULL, sc->proactive); ++ set_mm_walk(pgdat, sc->proactive); set_initial_priority(pgdat, sc); -@@ -5362,7 +5363,7 @@ static void lru_gen_shrink_node(struct p +@@ -5360,7 +5361,7 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control * clear_mm_walk(); blk_finish_plug(&plug); @@ -185,7 +193,7 @@ Signed-off-by: Andrew Morton /* kswapd should never fail */ pgdat->kswapd_failures = 0; } -@@ -5934,7 +5935,7 @@ static ssize_t lru_gen_seq_write(struct +@@ -5932,7 +5933,7 @@ static ssize_t lru_gen_seq_write(struct file *file, const char __user *src, set_task_reclaim_state(current, &sc.reclaim_state); flags = memalloc_noreclaim_save(); blk_start_plug(&plug); @@ -194,3 +202,6 @@ Signed-off-by: Andrew Morton err = -ENOMEM; goto done; } +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch b/target/linux/generic/backport-6.1/020-v6.3-08-UPSTREAM-mm-multi-gen-LRU-simplify-arch_has_hw_pte_y.patch similarity index 67% rename from target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch rename to target/linux/generic/backport-6.1/020-v6.3-08-UPSTREAM-mm-multi-gen-LRU-simplify-arch_has_hw_pte_y.patch index 367f93363bb..adf85b616f4 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-28-mm-multi-gen-LRU-simplify-arch_has_hw_pte_young-chec.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-08-UPSTREAM-mm-multi-gen-LRU-simplify-arch_has_hw_pte_y.patch @@ -1,8 +1,8 @@ -From cf3297e4c7a928da8b2b2f0baff2f9c69ea57952 Mon Sep 17 00:00:00 2001 +From 25887d48dff860751a06caa4188bfaf6bfb6e4b2 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Wed, 21 Dec 2022 21:19:06 -0700 -Subject: [PATCH 28/29] mm: multi-gen LRU: simplify arch_has_hw_pte_young() - check +Subject: [PATCH 08/19] UPSTREAM: mm: multi-gen LRU: simplify + arch_has_hw_pte_young() check Scanning page tables when hardware does not set the accessed bit has no real use cases. @@ -17,13 +17,19 @@ Cc: Mike Rapoport Cc: Roman Gushchin Cc: Suren Baghdasaryan Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit f386e9314025ea99dae639ed2032560a92081430) +Change-Id: I84d97ab665b4e3bb862a9bc7d72f50dea7191a6b +Signed-off-by: T.J. Mercier --- mm/vmscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 0a0e1250ffc87..aa9746f2bc80b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -4418,7 +4418,7 @@ static bool try_to_inc_max_seq(struct lr +@@ -4415,7 +4415,7 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, * handful of PTEs. Spreading the work out over a period of time usually * is less efficient, but it avoids bursty page faults. */ @@ -32,3 +38,6 @@ Signed-off-by: Andrew Morton success = iterate_mm_list_nowalk(lruvec, max_seq); goto done; } +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch b/target/linux/generic/backport-6.1/020-v6.3-09-UPSTREAM-mm-multi-gen-LRU-avoid-futile-retries.patch similarity index 74% rename from target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch rename to target/linux/generic/backport-6.1/020-v6.3-09-UPSTREAM-mm-multi-gen-LRU-avoid-futile-retries.patch index b9eb5f694e7..2cf14d78166 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-29-mm-multi-gen-LRU-avoid-futile-retries.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-09-UPSTREAM-mm-multi-gen-LRU-avoid-futile-retries.patch @@ -1,7 +1,7 @@ -From cc67f962cc53f6e1dfa92eb85b7b26fe83a3c66f Mon Sep 17 00:00:00 2001 +From 620b0ee94455e48d124414cd06d8a53f69fb6453 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Mon, 13 Feb 2023 00:53:22 -0700 -Subject: [PATCH 29/29] mm: multi-gen LRU: avoid futile retries +Subject: [PATCH 09/19] UPSTREAM: mm: multi-gen LRU: avoid futile retries Recall that the per-node memcg LRU has two generations and they alternate when the last memcg (of a given node) is moved from one to the other. @@ -19,13 +19,19 @@ Fixes: e4dde56cd208 ("mm: multi-gen LRU: per-node lru_gen_folio lists") Signed-off-by: Yu Zhao Reported-by: T.J. Mercier Signed-off-by: Andrew Morton +Bug: 274865848 +(cherry picked from commit 9f550d78b40da21b4da515db4c37d8d7b12aa1a6) +Change-Id: Ie92535676b005ec9e7987632b742fdde8d54436f +Signed-off-by: T.J. Mercier --- mm/vmscan.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) +diff --git a/mm/vmscan.c b/mm/vmscan.c +index aa9746f2bc80b..49da02f841c81 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -5208,18 +5208,20 @@ static int shrink_one(struct lruvec *lru +@@ -5206,18 +5206,20 @@ static int shrink_one(struct lruvec *lruvec, struct scan_control *sc) static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) { @@ -41,14 +47,14 @@ Signed-off-by: Andrew Morton - struct mem_cgroup *memcg = NULL; unsigned long nr_to_reclaim = get_nr_to_reclaim(sc); - bin = first_bin = prandom_u32_max(MEMCG_NR_BINS); + bin = first_bin = get_random_u32_below(MEMCG_NR_BINS); restart: + op = 0; + memcg = NULL; gen = get_memcg_gen(READ_ONCE(pgdat->memcg_lru.seq)); rcu_read_lock(); -@@ -5243,14 +5245,22 @@ restart: +@@ -5241,14 +5243,22 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) op = shrink_one(lruvec, sc); @@ -74,7 +80,7 @@ Signed-off-by: Andrew Morton /* restart if raced with lru_gen_rotate_memcg() */ if (gen != get_nulls_value(pos)) goto restart; -@@ -5259,11 +5269,6 @@ restart: +@@ -5257,11 +5267,6 @@ static void shrink_many(struct pglist_data *pgdat, struct scan_control *sc) bin = get_memcg_bin(bin + 1); if (bin != first_bin) goto restart; @@ -86,3 +92,6 @@ Signed-off-by: Andrew Morton } static void lru_gen_shrink_lruvec(struct lruvec *lruvec, struct scan_control *sc) +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch b/target/linux/generic/backport-6.1/020-v6.3-10-UPSTREAM-mm-add-vma_has_recency.patch similarity index 75% rename from target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch rename to target/linux/generic/backport-6.1/020-v6.3-10-UPSTREAM-mm-add-vma_has_recency.patch index 5335b804880..0a0b439e25f 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-19-mm-add-vma_has_recency.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-10-UPSTREAM-mm-add-vma_has_recency.patch @@ -1,7 +1,7 @@ -From 6c7f552a48b49a8612786a28a2239fbc24fac289 Mon Sep 17 00:00:00 2001 +From 70d216c71ff5c5b17dd1da6294f97b91fb6aba7a Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Fri, 30 Dec 2022 14:52:51 -0700 -Subject: [PATCH 19/29] mm: add vma_has_recency() +Subject: [PATCH 10/19] UPSTREAM: mm: add vma_has_recency() Add vma_has_recency() to indicate whether a VMA may exhibit temporal locality that the LRU algorithm relies on. @@ -43,22 +43,28 @@ results are available in that thread. [1] https://lore.kernel.org/r/Y31s%2FK8T85jh05wH@google.com/ Link: https://lkml.kernel.org/r/20221230215252.2628425-1-yuzhao@google.com +Change-Id: I291dcb795197659e40e46539cd32b857677c34ad Signed-off-by: Yu Zhao Cc: Alexander Viro Cc: Andrea Righi Cc: Johannes Weiner Cc: Michael Larabel Signed-off-by: Andrew Morton +(cherry picked from commit 8788f6781486769d9598dcaedc3fe0eb12fc3e59) +Bug: 274865848 +Signed-off-by: T.J. Mercier --- - include/linux/mm_inline.h | 9 +++++++++ - mm/memory.c | 8 ++++---- + include/linux/mm_inline.h | 8 ++++++++ + mm/memory.c | 7 +++---- mm/rmap.c | 42 +++++++++++++++++---------------------- mm/vmscan.c | 5 ++++- - 4 files changed, 35 insertions(+), 29 deletions(-) + 4 files changed, 33 insertions(+), 29 deletions(-) +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index c1fd3922dc5dd..7bb2e5f94734c 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -578,4 +578,12 @@ pte_install_uffd_wp_if_needed(struct vm_ +@@ -595,4 +595,12 @@ pte_install_uffd_wp_if_needed(struct vm_area_struct *vma, unsigned long addr, #endif } @@ -71,9 +77,11 @@ Signed-off-by: Andrew Morton +} + #endif +diff --git a/mm/memory.c b/mm/memory.c +index 747b7ea30f890..c2f48f8003c2e 100644 --- a/mm/memory.c +++ b/mm/memory.c -@@ -1435,8 +1435,7 @@ again: +@@ -1435,8 +1435,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb, force_flush = 1; set_page_dirty(page); } @@ -83,7 +91,7 @@ Signed-off-by: Andrew Morton mark_page_accessed(page); } rss[mm_counter(page)]--; -@@ -5170,8 +5169,8 @@ static inline void mm_account_fault(stru +@@ -5170,8 +5169,8 @@ static inline void mm_account_fault(struct pt_regs *regs, #ifdef CONFIG_LRU_GEN static void lru_gen_enter_fault(struct vm_area_struct *vma) { @@ -94,9 +102,11 @@ Signed-off-by: Andrew Morton } static void lru_gen_exit_fault(void) +diff --git a/mm/rmap.c b/mm/rmap.c +index 7da2d8d097d9b..825dac3caa1e5 100644 --- a/mm/rmap.c +++ b/mm/rmap.c -@@ -823,25 +823,14 @@ static bool folio_referenced_one(struct +@@ -823,25 +823,14 @@ static bool folio_referenced_one(struct folio *folio, } if (pvmw.pte) { @@ -125,16 +135,16 @@ Signed-off-by: Andrew Morton } else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) { if (pmdp_clear_flush_young_notify(vma, address, pvmw.pmd)) -@@ -875,7 +864,20 @@ static bool invalid_folio_referenced_vma +@@ -875,7 +864,20 @@ static bool invalid_folio_referenced_vma(struct vm_area_struct *vma, void *arg) struct folio_referenced_arg *pra = arg; struct mem_cgroup *memcg = pra->memcg; - if (!mm_match_cgroup(vma->vm_mm, memcg)) + /* + * Ignore references from this mapping if it has no recency. If the -+ * page has been used in another mapping, we will catch it; if this ++ * folio has been used in another mapping, we will catch it; if this + * other mapping is already gone, the unmap path will have set the -+ * referenced flag or activated the page in zap_pte_range(). ++ * referenced flag or activated the folio in zap_pte_range(). + */ + if (!vma_has_recency(vma)) + return true; @@ -147,7 +157,7 @@ Signed-off-by: Andrew Morton return true; return false; -@@ -906,6 +908,7 @@ int folio_referenced(struct folio *folio +@@ -906,6 +908,7 @@ int folio_referenced(struct folio *folio, int is_locked, .arg = (void *)&pra, .anon_lock = folio_lock_anon_vma_read, .try_lock = true, @@ -155,7 +165,7 @@ Signed-off-by: Andrew Morton }; *vm_flags = 0; -@@ -921,15 +924,6 @@ int folio_referenced(struct folio *folio +@@ -921,15 +924,6 @@ int folio_referenced(struct folio *folio, int is_locked, return 1; } @@ -171,9 +181,11 @@ Signed-off-by: Andrew Morton rmap_walk(folio, &rwc); *vm_flags = pra.vm_flags; +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 49da02f841c81..596fed6ae0439 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c -@@ -3766,7 +3766,10 @@ static int should_skip_vma(unsigned long +@@ -3778,7 +3778,10 @@ static int should_skip_vma(unsigned long start, unsigned long end, struct mm_wal if (is_vm_hugetlb_page(vma)) return true; @@ -185,3 +197,6 @@ Signed-off-by: Andrew Morton return true; if (vma == get_gate_vma(vma->vm_mm)) +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch b/target/linux/generic/backport-6.1/020-v6.3-11-UPSTREAM-mm-support-POSIX_FADV_NOREUSE.patch similarity index 78% rename from target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch rename to target/linux/generic/backport-6.1/020-v6.3-11-UPSTREAM-mm-support-POSIX_FADV_NOREUSE.patch index b2b7c605ca5..4c6fcecdac1 100644 --- a/target/linux/generic/backport-6.1/020-v6.3-20-mm-support-POSIX_FADV_NOREUSE.patch +++ b/target/linux/generic/backport-6.1/020-v6.3-11-UPSTREAM-mm-support-POSIX_FADV_NOREUSE.patch @@ -1,7 +1,7 @@ -From 686c3d4f71de9e0e7a27f03a5617a712385f90cd Mon Sep 17 00:00:00 2001 +From 9ca4e437a24dfc4ec6c362f319eb9850b9eca497 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Fri, 30 Dec 2022 14:52:52 -0700 -Subject: [PATCH 20/29] mm: support POSIX_FADV_NOREUSE +Subject: [PATCH 11/19] UPSTREAM: mm: support POSIX_FADV_NOREUSE This patch adds POSIX_FADV_NOREUSE to vma_has_recency() so that the LRU algorithm can ignore access to mapped files marked by this flag. @@ -22,7 +22,7 @@ Its limitations are: by two users and one of them having set POSIX_FADV_NOREUSE on the file, this page will be activated upon the second user accessing it. This corner case can be covered by checking POSIX_FADV_NOREUSE - before calling mark_page_accessed() on the read path. But it is + before calling folio_mark_accessed() on the read path. But it is considered not worth the effort. There have been a few attempts to support POSIX_FADV_NOREUSE, e.g., [1]. @@ -67,32 +67,40 @@ which makes it on par with the active/inactive LRU. [2] https://openbenchmarking.org/result/2209259-PTS-MGLRU8GB57 Link: https://lkml.kernel.org/r/20221230215252.2628425-2-yuzhao@google.com +Change-Id: I0b7f5f971d78014ea1ba44cee6a8ec902a4330d0 Signed-off-by: Yu Zhao Cc: Alexander Viro Cc: Andrea Righi Cc: Johannes Weiner Cc: Michael Larabel Signed-off-by: Andrew Morton +(cherry picked from commit 17e810229cb3068b692fa078bd9b3a6527e0866a) +Bug: 274865848 +Signed-off-by: T.J. Mercier --- include/linux/fs.h | 2 ++ include/linux/mm_inline.h | 3 +++ mm/fadvise.c | 5 ++++- 3 files changed, 9 insertions(+), 1 deletion(-) +diff --git a/include/linux/fs.h b/include/linux/fs.h +index f14ecbeab2a9d..97f9c41c1a43a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h -@@ -166,6 +166,8 @@ typedef int (dio_iodone_t)(struct kiocb +@@ -166,6 +166,8 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, /* File supports DIRECT IO */ #define FMODE_CAN_ODIRECT ((__force fmode_t)0x400000) -+#define FMODE_NOREUSE ((__force fmode_t)0x400000) ++#define FMODE_NOREUSE ((__force fmode_t)0x800000) + /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index 7bb2e5f94734c..9a8e2049333c0 100644 --- a/include/linux/mm_inline.h +++ b/include/linux/mm_inline.h -@@ -583,6 +583,9 @@ static inline bool vma_has_recency(struc +@@ -600,6 +600,9 @@ static inline bool vma_has_recency(struct vm_area_struct *vma) if (vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ)) return false; @@ -102,9 +110,11 @@ Signed-off-by: Andrew Morton return true; } +diff --git a/mm/fadvise.c b/mm/fadvise.c +index c76ee665355a4..2ba24d865bf5f 100644 --- a/mm/fadvise.c +++ b/mm/fadvise.c -@@ -80,7 +80,7 @@ int generic_fadvise(struct file *file, l +@@ -80,7 +80,7 @@ int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice) case POSIX_FADV_NORMAL: file->f_ra.ra_pages = bdi->ra_pages; spin_lock(&file->f_lock); @@ -113,7 +123,7 @@ Signed-off-by: Andrew Morton spin_unlock(&file->f_lock); break; case POSIX_FADV_RANDOM: -@@ -107,6 +107,9 @@ int generic_fadvise(struct file *file, l +@@ -107,6 +107,9 @@ int generic_fadvise(struct file *file, loff_t offset, loff_t len, int advice) force_page_cache_readahead(mapping, file, start_index, nrpages); break; case POSIX_FADV_NOREUSE: @@ -123,3 +133,6 @@ Signed-off-by: Andrew Morton break; case POSIX_FADV_DONTNEED: __filemap_fdatawrite_range(mapping, offset, endbyte, +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-12-UPSTREAM-mm-multi-gen-LRU-section-for-working-set-pr.patch b/target/linux/generic/backport-6.1/020-v6.3-12-UPSTREAM-mm-multi-gen-LRU-section-for-working-set-pr.patch new file mode 100644 index 00000000000..08804e00235 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-12-UPSTREAM-mm-multi-gen-LRU-section-for-working-set-pr.patch @@ -0,0 +1,74 @@ +From 1b5e4c317d80f4826eceb3781702d18d06b14394 Mon Sep 17 00:00:00 2001 +From: "T.J. Alumbaugh" +Date: Wed, 18 Jan 2023 00:18:21 +0000 +Subject: [PATCH 12/19] UPSTREAM: mm: multi-gen LRU: section for working set + protection + +Patch series "mm: multi-gen LRU: improve". + +This patch series improves a few MGLRU functions, collects related +functions, and adds additional documentation. + +This patch (of 7): + +Add a section for working set protection in the code and the design doc. +The admin doc already contains its usage. + +Link: https://lkml.kernel.org/r/20230118001827.1040870-1-talumbau@google.com +Link: https://lkml.kernel.org/r/20230118001827.1040870-2-talumbau@google.com +Change-Id: I65599075fd42951db7739a2ab7cee78516e157b3 +Signed-off-by: T.J. Alumbaugh +Cc: Yu Zhao +Signed-off-by: Andrew Morton +(cherry picked from commit 7b8144e63d84716f16a1b929e0c7e03ae5c4d5c1) +Bug: 274865848 +Signed-off-by: T.J. Mercier +--- + Documentation/mm/multigen_lru.rst | 15 +++++++++++++++ + mm/vmscan.c | 4 ++++ + 2 files changed, 19 insertions(+) + +diff --git a/Documentation/mm/multigen_lru.rst b/Documentation/mm/multigen_lru.rst +index d8f721f98868a..6e1483e70fdca 100644 +--- a/Documentation/mm/multigen_lru.rst ++++ b/Documentation/mm/multigen_lru.rst +@@ -141,6 +141,21 @@ loop has detected outlying refaults from the tier this page is in. To + this end, the feedback loop uses the first tier as the baseline, for + the reason stated earlier. + ++Working set protection ++---------------------- ++Each generation is timestamped at birth. If ``lru_gen_min_ttl`` is ++set, an ``lruvec`` is protected from the eviction when its oldest ++generation was born within ``lru_gen_min_ttl`` milliseconds. In other ++words, it prevents the working set of ``lru_gen_min_ttl`` milliseconds ++from getting evicted. The OOM killer is triggered if this working set ++cannot be kept in memory. ++ ++This time-based approach has the following advantages: ++ ++1. It is easier to configure because it is agnostic to applications ++ and memory sizes. ++2. It is more reliable because it is directly wired to the OOM killer. ++ + Summary + ------- + The multi-gen LRU can be disassembled into the following parts: +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 596fed6ae0439..ab0b8d3b9d88f 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4459,6 +4459,10 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + return true; + } + ++/****************************************************************************** ++ * working set protection ++ ******************************************************************************/ ++ + static bool lruvec_is_sizable(struct lruvec *lruvec, struct scan_control *sc) + { + int gen, type, zone; +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-13-UPSTREAM-mm-multi-gen-LRU-section-for-rmap-PT-walk-f.patch b/target/linux/generic/backport-6.1/020-v6.3-13-UPSTREAM-mm-multi-gen-LRU-section-for-rmap-PT-walk-f.patch new file mode 100644 index 00000000000..f80dedb4057 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-13-UPSTREAM-mm-multi-gen-LRU-section-for-rmap-PT-walk-f.patch @@ -0,0 +1,64 @@ +From 5ddf9d53d375e42af49b744bd7c2f8247c6bce15 Mon Sep 17 00:00:00 2001 +From: "T.J. Alumbaugh" +Date: Wed, 18 Jan 2023 00:18:22 +0000 +Subject: [PATCH 13/19] UPSTREAM: mm: multi-gen LRU: section for rmap/PT walk + feedback + +Add a section for lru_gen_look_around() in the code and the design doc. + +Link: https://lkml.kernel.org/r/20230118001827.1040870-3-talumbau@google.com +Change-Id: I5097af63f61b3b69ec2abee6cdbdc33c296df213 +Signed-off-by: T.J. Alumbaugh +Cc: Yu Zhao +Signed-off-by: Andrew Morton +(cherry picked from commit db19a43d9b3a8876552f00f656008206ef9a5efa) +Bug: 274865848 +Signed-off-by: T.J. Mercier +--- + Documentation/mm/multigen_lru.rst | 14 ++++++++++++++ + mm/vmscan.c | 4 ++++ + 2 files changed, 18 insertions(+) + +diff --git a/Documentation/mm/multigen_lru.rst b/Documentation/mm/multigen_lru.rst +index 6e1483e70fdca..bd988a142bc2f 100644 +--- a/Documentation/mm/multigen_lru.rst ++++ b/Documentation/mm/multigen_lru.rst +@@ -156,6 +156,20 @@ This time-based approach has the following advantages: + and memory sizes. + 2. It is more reliable because it is directly wired to the OOM killer. + ++Rmap/PT walk feedback ++--------------------- ++Searching the rmap for PTEs mapping each page on an LRU list (to test ++and clear the accessed bit) can be expensive because pages from ++different VMAs (PA space) are not cache friendly to the rmap (VA ++space). For workloads mostly using mapped pages, searching the rmap ++can incur the highest CPU cost in the reclaim path. ++ ++``lru_gen_look_around()`` exploits spatial locality to reduce the ++trips into the rmap. It scans the adjacent PTEs of a young PTE and ++promotes hot pages. If the scan was done cacheline efficiently, it ++adds the PMD entry pointing to the PTE table to the Bloom filter. This ++forms a feedback loop between the eviction and the aging. ++ + Summary + ------- + The multi-gen LRU can be disassembled into the following parts: +diff --git a/mm/vmscan.c b/mm/vmscan.c +index ab0b8d3b9d88f..8fa82630240d6 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4553,6 +4553,10 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + } + } + ++/****************************************************************************** ++ * rmap/PT walk feedback ++ ******************************************************************************/ ++ + /* + * This function exploits spatial locality when shrink_folio_list() walks the + * rmap. It scans the adjacent PTEs of a young PTE and promotes hot pages. If +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-14-UPSTREAM-mm-multi-gen-LRU-section-for-Bloom-filters.patch b/target/linux/generic/backport-6.1/020-v6.3-14-UPSTREAM-mm-multi-gen-LRU-section-for-Bloom-filters.patch new file mode 100644 index 00000000000..f98588c4d89 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-14-UPSTREAM-mm-multi-gen-LRU-section-for-Bloom-filters.patch @@ -0,0 +1,250 @@ +From 397624e12244ec038f51cb1f178ccb7a2ec562e5 Mon Sep 17 00:00:00 2001 +From: "T.J. Alumbaugh" +Date: Wed, 18 Jan 2023 00:18:23 +0000 +Subject: [PATCH 14/19] UPSTREAM: mm: multi-gen LRU: section for Bloom filters + +Move Bloom filters code into a dedicated section. Improve the design doc +to explain Bloom filter usage and connection between aging and eviction in +their use. + +Link: https://lkml.kernel.org/r/20230118001827.1040870-4-talumbau@google.com +Change-Id: I73e866f687c1ed9f5c8538086aa39408b79897db +Signed-off-by: T.J. Alumbaugh +Cc: Yu Zhao +Signed-off-by: Andrew Morton +(cherry picked from commit ccbbbb85945d8f0255aa9dbc1b617017e2294f2c) +Bug: 274865848 +Signed-off-by: T.J. Mercier +--- + Documentation/mm/multigen_lru.rst | 16 +++ + mm/vmscan.c | 180 +++++++++++++++--------------- + 2 files changed, 108 insertions(+), 88 deletions(-) + +diff --git a/Documentation/mm/multigen_lru.rst b/Documentation/mm/multigen_lru.rst +index bd988a142bc2f..770b5d539856c 100644 +--- a/Documentation/mm/multigen_lru.rst ++++ b/Documentation/mm/multigen_lru.rst +@@ -170,6 +170,22 @@ promotes hot pages. If the scan was done cacheline efficiently, it + adds the PMD entry pointing to the PTE table to the Bloom filter. This + forms a feedback loop between the eviction and the aging. + ++Bloom Filters ++------------- ++Bloom filters are a space and memory efficient data structure for set ++membership test, i.e., test if an element is not in the set or may be ++in the set. ++ ++In the eviction path, specifically, in ``lru_gen_look_around()``, if a ++PMD has a sufficient number of hot pages, its address is placed in the ++filter. In the aging path, set membership means that the PTE range ++will be scanned for young pages. ++ ++Note that Bloom filters are probabilistic on set membership. If a test ++is false positive, the cost is an additional scan of a range of PTEs, ++which may yield hot pages anyway. Parameters of the filter itself can ++control the false positive rate in the limit. ++ + Summary + ------- + The multi-gen LRU can be disassembled into the following parts: +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 8fa82630240d6..74b4f9d660b56 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3208,6 +3208,98 @@ static bool __maybe_unused seq_is_valid(struct lruvec *lruvec) + get_nr_gens(lruvec, LRU_GEN_ANON) <= MAX_NR_GENS; + } + ++/****************************************************************************** ++ * Bloom filters ++ ******************************************************************************/ ++ ++/* ++ * Bloom filters with m=1<<15, k=2 and the false positive rates of ~1/5 when ++ * n=10,000 and ~1/2 when n=20,000, where, conventionally, m is the number of ++ * bits in a bitmap, k is the number of hash functions and n is the number of ++ * inserted items. ++ * ++ * Page table walkers use one of the two filters to reduce their search space. ++ * To get rid of non-leaf entries that no longer have enough leaf entries, the ++ * aging uses the double-buffering technique to flip to the other filter each ++ * time it produces a new generation. For non-leaf entries that have enough ++ * leaf entries, the aging carries them over to the next generation in ++ * walk_pmd_range(); the eviction also report them when walking the rmap ++ * in lru_gen_look_around(). ++ * ++ * For future optimizations: ++ * 1. It's not necessary to keep both filters all the time. The spare one can be ++ * freed after the RCU grace period and reallocated if needed again. ++ * 2. And when reallocating, it's worth scaling its size according to the number ++ * of inserted entries in the other filter, to reduce the memory overhead on ++ * small systems and false positives on large systems. ++ * 3. Jenkins' hash function is an alternative to Knuth's. ++ */ ++#define BLOOM_FILTER_SHIFT 15 ++ ++static inline int filter_gen_from_seq(unsigned long seq) ++{ ++ return seq % NR_BLOOM_FILTERS; ++} ++ ++static void get_item_key(void *item, int *key) ++{ ++ u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); ++ ++ BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); ++ ++ key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); ++ key[1] = hash >> BLOOM_FILTER_SHIFT; ++} ++ ++static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) ++{ ++ int key[2]; ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = READ_ONCE(lruvec->mm_state.filters[gen]); ++ if (!filter) ++ return true; ++ ++ get_item_key(item, key); ++ ++ return test_bit(key[0], filter) && test_bit(key[1], filter); ++} ++ ++static void update_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) ++{ ++ int key[2]; ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = READ_ONCE(lruvec->mm_state.filters[gen]); ++ if (!filter) ++ return; ++ ++ get_item_key(item, key); ++ ++ if (!test_bit(key[0], filter)) ++ set_bit(key[0], filter); ++ if (!test_bit(key[1], filter)) ++ set_bit(key[1], filter); ++} ++ ++static void reset_bloom_filter(struct lruvec *lruvec, unsigned long seq) ++{ ++ unsigned long *filter; ++ int gen = filter_gen_from_seq(seq); ++ ++ filter = lruvec->mm_state.filters[gen]; ++ if (filter) { ++ bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); ++ return; ++ } ++ ++ filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), ++ __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); ++ WRITE_ONCE(lruvec->mm_state.filters[gen], filter); ++} ++ + /****************************************************************************** + * mm_struct list + ******************************************************************************/ +@@ -3333,94 +3425,6 @@ void lru_gen_migrate_mm(struct mm_struct *mm) + } + #endif + +-/* +- * Bloom filters with m=1<<15, k=2 and the false positive rates of ~1/5 when +- * n=10,000 and ~1/2 when n=20,000, where, conventionally, m is the number of +- * bits in a bitmap, k is the number of hash functions and n is the number of +- * inserted items. +- * +- * Page table walkers use one of the two filters to reduce their search space. +- * To get rid of non-leaf entries that no longer have enough leaf entries, the +- * aging uses the double-buffering technique to flip to the other filter each +- * time it produces a new generation. For non-leaf entries that have enough +- * leaf entries, the aging carries them over to the next generation in +- * walk_pmd_range(); the eviction also report them when walking the rmap +- * in lru_gen_look_around(). +- * +- * For future optimizations: +- * 1. It's not necessary to keep both filters all the time. The spare one can be +- * freed after the RCU grace period and reallocated if needed again. +- * 2. And when reallocating, it's worth scaling its size according to the number +- * of inserted entries in the other filter, to reduce the memory overhead on +- * small systems and false positives on large systems. +- * 3. Jenkins' hash function is an alternative to Knuth's. +- */ +-#define BLOOM_FILTER_SHIFT 15 +- +-static inline int filter_gen_from_seq(unsigned long seq) +-{ +- return seq % NR_BLOOM_FILTERS; +-} +- +-static void get_item_key(void *item, int *key) +-{ +- u32 hash = hash_ptr(item, BLOOM_FILTER_SHIFT * 2); +- +- BUILD_BUG_ON(BLOOM_FILTER_SHIFT * 2 > BITS_PER_TYPE(u32)); +- +- key[0] = hash & (BIT(BLOOM_FILTER_SHIFT) - 1); +- key[1] = hash >> BLOOM_FILTER_SHIFT; +-} +- +-static void reset_bloom_filter(struct lruvec *lruvec, unsigned long seq) +-{ +- unsigned long *filter; +- int gen = filter_gen_from_seq(seq); +- +- filter = lruvec->mm_state.filters[gen]; +- if (filter) { +- bitmap_clear(filter, 0, BIT(BLOOM_FILTER_SHIFT)); +- return; +- } +- +- filter = bitmap_zalloc(BIT(BLOOM_FILTER_SHIFT), +- __GFP_HIGH | __GFP_NOMEMALLOC | __GFP_NOWARN); +- WRITE_ONCE(lruvec->mm_state.filters[gen], filter); +-} +- +-static void update_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) +-{ +- int key[2]; +- unsigned long *filter; +- int gen = filter_gen_from_seq(seq); +- +- filter = READ_ONCE(lruvec->mm_state.filters[gen]); +- if (!filter) +- return; +- +- get_item_key(item, key); +- +- if (!test_bit(key[0], filter)) +- set_bit(key[0], filter); +- if (!test_bit(key[1], filter)) +- set_bit(key[1], filter); +-} +- +-static bool test_bloom_filter(struct lruvec *lruvec, unsigned long seq, void *item) +-{ +- int key[2]; +- unsigned long *filter; +- int gen = filter_gen_from_seq(seq); +- +- filter = READ_ONCE(lruvec->mm_state.filters[gen]); +- if (!filter) +- return true; +- +- get_item_key(item, key); +- +- return test_bit(key[0], filter) && test_bit(key[1], filter); +-} +- + static void reset_mm_stats(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, bool last) + { + int i; +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-15-UPSTREAM-mm-multi-gen-LRU-section-for-memcg-LRU.patch b/target/linux/generic/backport-6.1/020-v6.3-15-UPSTREAM-mm-multi-gen-LRU-section-for-memcg-LRU.patch new file mode 100644 index 00000000000..c26e28c3cad --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-15-UPSTREAM-mm-multi-gen-LRU-section-for-memcg-LRU.patch @@ -0,0 +1,440 @@ +From 48c916b812652f9453be5bd45a703728926d41ca Mon Sep 17 00:00:00 2001 +From: "T.J. Alumbaugh" +Date: Wed, 18 Jan 2023 00:18:24 +0000 +Subject: [PATCH 15/19] UPSTREAM: mm: multi-gen LRU: section for memcg LRU + +Move memcg LRU code into a dedicated section. Improve the design doc to +outline its architecture. + +Link: https://lkml.kernel.org/r/20230118001827.1040870-5-talumbau@google.com +Change-Id: Id252e420cff7a858acb098cf2b3642da5c40f602 +Signed-off-by: T.J. Alumbaugh +Cc: Yu Zhao +Signed-off-by: Andrew Morton +(cherry picked from commit 36c7b4db7c942ae9e1b111f0c6b468c8b2e33842) +Bug: 274865848 +Signed-off-by: T.J. Mercier +--- + Documentation/mm/multigen_lru.rst | 33 +++- + include/linux/mm_inline.h | 17 -- + include/linux/mmzone.h | 13 +- + mm/memcontrol.c | 8 +- + mm/vmscan.c | 250 +++++++++++++++++------------- + 5 files changed, 178 insertions(+), 143 deletions(-) + +diff --git a/Documentation/mm/multigen_lru.rst b/Documentation/mm/multigen_lru.rst +index 770b5d539856c..5f1f6ecbb79b9 100644 +--- a/Documentation/mm/multigen_lru.rst ++++ b/Documentation/mm/multigen_lru.rst +@@ -186,9 +186,40 @@ is false positive, the cost is an additional scan of a range of PTEs, + which may yield hot pages anyway. Parameters of the filter itself can + control the false positive rate in the limit. + ++Memcg LRU ++--------- ++An memcg LRU is a per-node LRU of memcgs. It is also an LRU of LRUs, ++since each node and memcg combination has an LRU of folios (see ++``mem_cgroup_lruvec()``). Its goal is to improve the scalability of ++global reclaim, which is critical to system-wide memory overcommit in ++data centers. Note that memcg LRU only applies to global reclaim. ++ ++The basic structure of an memcg LRU can be understood by an analogy to ++the active/inactive LRU (of folios): ++ ++1. It has the young and the old (generations), i.e., the counterparts ++ to the active and the inactive; ++2. The increment of ``max_seq`` triggers promotion, i.e., the ++ counterpart to activation; ++3. Other events trigger similar operations, e.g., offlining an memcg ++ triggers demotion, i.e., the counterpart to deactivation. ++ ++In terms of global reclaim, it has two distinct features: ++ ++1. Sharding, which allows each thread to start at a random memcg (in ++ the old generation) and improves parallelism; ++2. Eventual fairness, which allows direct reclaim to bail out at will ++ and reduces latency without affecting fairness over some time. ++ ++In terms of traversing memcgs during global reclaim, it improves the ++best-case complexity from O(n) to O(1) and does not affect the ++worst-case complexity O(n). Therefore, on average, it has a sublinear ++complexity. ++ + Summary + ------- +-The multi-gen LRU can be disassembled into the following parts: ++The multi-gen LRU (of folios) can be disassembled into the following ++parts: + + * Generations + * Rmap walks +diff --git a/include/linux/mm_inline.h b/include/linux/mm_inline.h +index 9a8e2049333c0..5567f4850243b 100644 +--- a/include/linux/mm_inline.h ++++ b/include/linux/mm_inline.h +@@ -122,18 +122,6 @@ static inline bool lru_gen_in_fault(void) + return current->in_lru_fault; + } + +-#ifdef CONFIG_MEMCG +-static inline int lru_gen_memcg_seg(struct lruvec *lruvec) +-{ +- return READ_ONCE(lruvec->lrugen.seg); +-} +-#else +-static inline int lru_gen_memcg_seg(struct lruvec *lruvec) +-{ +- return 0; +-} +-#endif +- + static inline int lru_gen_from_seq(unsigned long seq) + { + return seq % MAX_NR_GENS; +@@ -309,11 +297,6 @@ static inline bool lru_gen_in_fault(void) + return false; + } + +-static inline int lru_gen_memcg_seg(struct lruvec *lruvec) +-{ +- return 0; +-} +- + static inline bool lru_gen_add_folio(struct lruvec *lruvec, struct folio *folio, bool reclaiming) + { + return false; +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 66e067a635682..403c7461e7a70 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -368,15 +368,6 @@ struct page_vma_mapped_walk; + #define LRU_GEN_MASK ((BIT(LRU_GEN_WIDTH) - 1) << LRU_GEN_PGOFF) + #define LRU_REFS_MASK ((BIT(LRU_REFS_WIDTH) - 1) << LRU_REFS_PGOFF) + +-/* see the comment on MEMCG_NR_GENS */ +-enum { +- MEMCG_LRU_NOP, +- MEMCG_LRU_HEAD, +- MEMCG_LRU_TAIL, +- MEMCG_LRU_OLD, +- MEMCG_LRU_YOUNG, +-}; +- + #ifdef CONFIG_LRU_GEN + + enum { +@@ -557,7 +548,7 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg); + void lru_gen_online_memcg(struct mem_cgroup *memcg); + void lru_gen_offline_memcg(struct mem_cgroup *memcg); + void lru_gen_release_memcg(struct mem_cgroup *memcg); +-void lru_gen_rotate_memcg(struct lruvec *lruvec, int op); ++void lru_gen_soft_reclaim(struct lruvec *lruvec); + + #else /* !CONFIG_MEMCG */ + +@@ -608,7 +599,7 @@ static inline void lru_gen_release_memcg(struct mem_cgroup *memcg) + { + } + +-static inline void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) ++static inline void lru_gen_soft_reclaim(struct lruvec *lruvec) + { + } + +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index 7815d556e38cc..5397aeb43986d 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -478,12 +478,8 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, int nid) + struct mem_cgroup_tree_per_node *mctz; + + if (lru_gen_enabled()) { +- struct lruvec *lruvec = &memcg->nodeinfo[nid]->lruvec; +- +- /* see the comment on MEMCG_NR_GENS */ +- if (soft_limit_excess(memcg) && lru_gen_memcg_seg(lruvec) != MEMCG_LRU_HEAD) +- lru_gen_rotate_memcg(lruvec, MEMCG_LRU_HEAD); +- ++ if (soft_limit_excess(memcg)) ++ lru_gen_soft_reclaim(&memcg->nodeinfo[nid]->lruvec); + return; + } + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 74b4f9d660b56..ccde215c084ca 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4689,6 +4689,148 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + mem_cgroup_unlock_pages(); + } + ++/****************************************************************************** ++ * memcg LRU ++ ******************************************************************************/ ++ ++/* see the comment on MEMCG_NR_GENS */ ++enum { ++ MEMCG_LRU_NOP, ++ MEMCG_LRU_HEAD, ++ MEMCG_LRU_TAIL, ++ MEMCG_LRU_OLD, ++ MEMCG_LRU_YOUNG, ++}; ++ ++#ifdef CONFIG_MEMCG ++ ++static int lru_gen_memcg_seg(struct lruvec *lruvec) ++{ ++ return READ_ONCE(lruvec->lrugen.seg); ++} ++ ++static void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) ++{ ++ int seg; ++ int old, new; ++ int bin = get_random_u32_below(MEMCG_NR_BINS); ++ struct pglist_data *pgdat = lruvec_pgdat(lruvec); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ seg = 0; ++ new = old = lruvec->lrugen.gen; ++ ++ /* see the comment on MEMCG_NR_GENS */ ++ if (op == MEMCG_LRU_HEAD) ++ seg = MEMCG_LRU_HEAD; ++ else if (op == MEMCG_LRU_TAIL) ++ seg = MEMCG_LRU_TAIL; ++ else if (op == MEMCG_LRU_OLD) ++ new = get_memcg_gen(pgdat->memcg_lru.seq); ++ else if (op == MEMCG_LRU_YOUNG) ++ new = get_memcg_gen(pgdat->memcg_lru.seq + 1); ++ else ++ VM_WARN_ON_ONCE(true); ++ ++ hlist_nulls_del_rcu(&lruvec->lrugen.list); ++ ++ if (op == MEMCG_LRU_HEAD || op == MEMCG_LRU_OLD) ++ hlist_nulls_add_head_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]); ++ else ++ hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]); ++ ++ pgdat->memcg_lru.nr_memcgs[old]--; ++ pgdat->memcg_lru.nr_memcgs[new]++; ++ ++ lruvec->lrugen.gen = new; ++ WRITE_ONCE(lruvec->lrugen.seg, seg); ++ ++ if (!pgdat->memcg_lru.nr_memcgs[old] && old == get_memcg_gen(pgdat->memcg_lru.seq)) ++ WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); ++ ++ spin_unlock(&pgdat->memcg_lru.lock); ++} ++ ++void lru_gen_online_memcg(struct mem_cgroup *memcg) ++{ ++ int gen; ++ int nid; ++ int bin = get_random_u32_below(MEMCG_NR_BINS); ++ ++ for_each_node(nid) { ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(!hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ gen = get_memcg_gen(pgdat->memcg_lru.seq); ++ ++ hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[gen][bin]); ++ pgdat->memcg_lru.nr_memcgs[gen]++; ++ ++ lruvec->lrugen.gen = gen; ++ ++ spin_unlock(&pgdat->memcg_lru.lock); ++ } ++} ++ ++void lru_gen_offline_memcg(struct mem_cgroup *memcg) ++{ ++ int nid; ++ ++ for_each_node(nid) { ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ lru_gen_rotate_memcg(lruvec, MEMCG_LRU_OLD); ++ } ++} ++ ++void lru_gen_release_memcg(struct mem_cgroup *memcg) ++{ ++ int gen; ++ int nid; ++ ++ for_each_node(nid) { ++ struct pglist_data *pgdat = NODE_DATA(nid); ++ struct lruvec *lruvec = get_lruvec(memcg, nid); ++ ++ spin_lock(&pgdat->memcg_lru.lock); ++ ++ VM_WARN_ON_ONCE(hlist_nulls_unhashed(&lruvec->lrugen.list)); ++ ++ gen = lruvec->lrugen.gen; ++ ++ hlist_nulls_del_rcu(&lruvec->lrugen.list); ++ pgdat->memcg_lru.nr_memcgs[gen]--; ++ ++ if (!pgdat->memcg_lru.nr_memcgs[gen] && gen == get_memcg_gen(pgdat->memcg_lru.seq)) ++ WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); ++ ++ spin_unlock(&pgdat->memcg_lru.lock); ++ } ++} ++ ++void lru_gen_soft_reclaim(struct lruvec *lruvec) ++{ ++ /* see the comment on MEMCG_NR_GENS */ ++ if (lru_gen_memcg_seg(lruvec) != MEMCG_LRU_HEAD) ++ lru_gen_rotate_memcg(lruvec, MEMCG_LRU_HEAD); ++} ++ ++#else /* !CONFIG_MEMCG */ ++ ++static int lru_gen_memcg_seg(struct lruvec *lruvec) ++{ ++ return 0; ++} ++ ++#endif ++ + /****************************************************************************** + * the eviction + ******************************************************************************/ +@@ -5386,53 +5528,6 @@ static void lru_gen_shrink_node(struct pglist_data *pgdat, struct scan_control * + pgdat->kswapd_failures = 0; + } + +-#ifdef CONFIG_MEMCG +-void lru_gen_rotate_memcg(struct lruvec *lruvec, int op) +-{ +- int seg; +- int old, new; +- int bin = get_random_u32_below(MEMCG_NR_BINS); +- struct pglist_data *pgdat = lruvec_pgdat(lruvec); +- +- spin_lock(&pgdat->memcg_lru.lock); +- +- VM_WARN_ON_ONCE(hlist_nulls_unhashed(&lruvec->lrugen.list)); +- +- seg = 0; +- new = old = lruvec->lrugen.gen; +- +- /* see the comment on MEMCG_NR_GENS */ +- if (op == MEMCG_LRU_HEAD) +- seg = MEMCG_LRU_HEAD; +- else if (op == MEMCG_LRU_TAIL) +- seg = MEMCG_LRU_TAIL; +- else if (op == MEMCG_LRU_OLD) +- new = get_memcg_gen(pgdat->memcg_lru.seq); +- else if (op == MEMCG_LRU_YOUNG) +- new = get_memcg_gen(pgdat->memcg_lru.seq + 1); +- else +- VM_WARN_ON_ONCE(true); +- +- hlist_nulls_del_rcu(&lruvec->lrugen.list); +- +- if (op == MEMCG_LRU_HEAD || op == MEMCG_LRU_OLD) +- hlist_nulls_add_head_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]); +- else +- hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[new][bin]); +- +- pgdat->memcg_lru.nr_memcgs[old]--; +- pgdat->memcg_lru.nr_memcgs[new]++; +- +- lruvec->lrugen.gen = new; +- WRITE_ONCE(lruvec->lrugen.seg, seg); +- +- if (!pgdat->memcg_lru.nr_memcgs[old] && old == get_memcg_gen(pgdat->memcg_lru.seq)) +- WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); +- +- spin_unlock(&pgdat->memcg_lru.lock); +-} +-#endif +- + /****************************************************************************** + * state change + ******************************************************************************/ +@@ -6078,67 +6173,6 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) + } + } + +-void lru_gen_online_memcg(struct mem_cgroup *memcg) +-{ +- int gen; +- int nid; +- int bin = get_random_u32_below(MEMCG_NR_BINS); +- +- for_each_node(nid) { +- struct pglist_data *pgdat = NODE_DATA(nid); +- struct lruvec *lruvec = get_lruvec(memcg, nid); +- +- spin_lock(&pgdat->memcg_lru.lock); +- +- VM_WARN_ON_ONCE(!hlist_nulls_unhashed(&lruvec->lrugen.list)); +- +- gen = get_memcg_gen(pgdat->memcg_lru.seq); +- +- hlist_nulls_add_tail_rcu(&lruvec->lrugen.list, &pgdat->memcg_lru.fifo[gen][bin]); +- pgdat->memcg_lru.nr_memcgs[gen]++; +- +- lruvec->lrugen.gen = gen; +- +- spin_unlock(&pgdat->memcg_lru.lock); +- } +-} +- +-void lru_gen_offline_memcg(struct mem_cgroup *memcg) +-{ +- int nid; +- +- for_each_node(nid) { +- struct lruvec *lruvec = get_lruvec(memcg, nid); +- +- lru_gen_rotate_memcg(lruvec, MEMCG_LRU_OLD); +- } +-} +- +-void lru_gen_release_memcg(struct mem_cgroup *memcg) +-{ +- int gen; +- int nid; +- +- for_each_node(nid) { +- struct pglist_data *pgdat = NODE_DATA(nid); +- struct lruvec *lruvec = get_lruvec(memcg, nid); +- +- spin_lock(&pgdat->memcg_lru.lock); +- +- VM_WARN_ON_ONCE(hlist_nulls_unhashed(&lruvec->lrugen.list)); +- +- gen = lruvec->lrugen.gen; +- +- hlist_nulls_del_rcu(&lruvec->lrugen.list); +- pgdat->memcg_lru.nr_memcgs[gen]--; +- +- if (!pgdat->memcg_lru.nr_memcgs[gen] && gen == get_memcg_gen(pgdat->memcg_lru.seq)) +- WRITE_ONCE(pgdat->memcg_lru.seq, pgdat->memcg_lru.seq + 1); +- +- spin_unlock(&pgdat->memcg_lru.lock); +- } +-} +- + #endif /* CONFIG_MEMCG */ + + static int __init init_lru_gen(void) +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-16-UPSTREAM-mm-multi-gen-LRU-improve-lru_gen_exit_memcg.patch b/target/linux/generic/backport-6.1/020-v6.3-16-UPSTREAM-mm-multi-gen-LRU-improve-lru_gen_exit_memcg.patch new file mode 100644 index 00000000000..1f3f8ffe6da --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-16-UPSTREAM-mm-multi-gen-LRU-improve-lru_gen_exit_memcg.patch @@ -0,0 +1,45 @@ +From bec433f29537652ed054148edfd7e2183ddcf7c3 Mon Sep 17 00:00:00 2001 +From: "T.J. Alumbaugh" +Date: Wed, 18 Jan 2023 00:18:25 +0000 +Subject: [PATCH 16/19] UPSTREAM: mm: multi-gen LRU: improve + lru_gen_exit_memcg() + +Add warnings and poison ->next. + +Link: https://lkml.kernel.org/r/20230118001827.1040870-6-talumbau@google.com +Change-Id: I53de9e04c1ae941e122b33cd45d2bbb5f34aae0c +Signed-off-by: T.J. Alumbaugh +Cc: Yu Zhao +Signed-off-by: Andrew Morton +(cherry picked from commit 37cc99979d04cca677c0ad5c0acd1149ec165d1b) +Bug: 274865848 +Signed-off-by: T.J. Mercier +--- + mm/vmscan.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index ccde215c084ca..d5d6f8d94f58a 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -6160,12 +6160,17 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) + int i; + int nid; + ++ VM_WARN_ON_ONCE(!list_empty(&memcg->mm_list.fifo)); ++ + for_each_node(nid) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + ++ VM_WARN_ON_ONCE(lruvec->mm_state.nr_walkers); + VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, + sizeof(lruvec->lrugen.nr_pages))); + ++ lruvec->lrugen.list.next = LIST_POISON1; ++ + for (i = 0; i < NR_BLOOM_FILTERS; i++) { + bitmap_free(lruvec->mm_state.filters[i]); + lruvec->mm_state.filters[i] = NULL; +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-17-UPSTREAM-mm-multi-gen-LRU-improve-walk_pmd_range.patch b/target/linux/generic/backport-6.1/020-v6.3-17-UPSTREAM-mm-multi-gen-LRU-improve-walk_pmd_range.patch new file mode 100644 index 00000000000..02dd920e54c --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-17-UPSTREAM-mm-multi-gen-LRU-improve-walk_pmd_range.patch @@ -0,0 +1,140 @@ +From fc0e3b06e0f19917b7ecad7967a72f61d4743644 Mon Sep 17 00:00:00 2001 +From: "T.J. Alumbaugh" +Date: Wed, 18 Jan 2023 00:18:26 +0000 +Subject: [PATCH 17/19] UPSTREAM: mm: multi-gen LRU: improve walk_pmd_range() + +Improve readability of walk_pmd_range() and walk_pmd_range_locked(). + +Link: https://lkml.kernel.org/r/20230118001827.1040870-7-talumbau@google.com +Change-Id: Ia084fbf53fe989673b7804ca8ca520af12d7d52a +Signed-off-by: T.J. Alumbaugh +Cc: Yu Zhao +Signed-off-by: Andrew Morton +(cherry picked from commit b5ff4133617d0eced35b685da0bd0929dd9fabb7) +Bug: 274865848 +Signed-off-by: T.J. Mercier +--- + mm/vmscan.c | 40 ++++++++++++++++++++-------------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index d5d6f8d94f58a..8f496c2e670a9 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3980,8 +3980,8 @@ static bool walk_pte_range(pmd_t *pmd, unsigned long start, unsigned long end, + } + + #if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) +-static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, +- struct mm_walk *args, unsigned long *bitmap, unsigned long *start) ++static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area_struct *vma, ++ struct mm_walk *args, unsigned long *bitmap, unsigned long *first) + { + int i; + pmd_t *pmd; +@@ -3994,18 +3994,19 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area + VM_WARN_ON_ONCE(pud_leaf(*pud)); + + /* try to batch at most 1+MIN_LRU_BATCH+1 entries */ +- if (*start == -1) { +- *start = next; ++ if (*first == -1) { ++ *first = addr; ++ bitmap_zero(bitmap, MIN_LRU_BATCH); + return; + } + +- i = next == -1 ? 0 : pmd_index(next) - pmd_index(*start); ++ i = addr == -1 ? 0 : pmd_index(addr) - pmd_index(*first); + if (i && i <= MIN_LRU_BATCH) { + __set_bit(i - 1, bitmap); + return; + } + +- pmd = pmd_offset(pud, *start); ++ pmd = pmd_offset(pud, *first); + + ptl = pmd_lockptr(args->mm, pmd); + if (!spin_trylock(ptl)) +@@ -4016,15 +4017,16 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area + do { + unsigned long pfn; + struct folio *folio; +- unsigned long addr = i ? (*start & PMD_MASK) + i * PMD_SIZE : *start; ++ ++ /* don't round down the first address */ ++ addr = i ? (*first & PMD_MASK) + i * PMD_SIZE : *first; + + pfn = get_pmd_pfn(pmd[i], vma, addr); + if (pfn == -1) + goto next; + + if (!pmd_trans_huge(pmd[i])) { +- if (arch_has_hw_nonleaf_pmd_young() && +- get_cap(LRU_GEN_NONLEAF_YOUNG)) ++ if (arch_has_hw_nonleaf_pmd_young() && get_cap(LRU_GEN_NONLEAF_YOUNG)) + pmdp_test_and_clear_young(vma, addr, pmd + i); + goto next; + } +@@ -4053,12 +4055,11 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area + arch_leave_lazy_mmu_mode(); + spin_unlock(ptl); + done: +- *start = -1; +- bitmap_zero(bitmap, MIN_LRU_BATCH); ++ *first = -1; + } + #else +-static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area_struct *vma, +- struct mm_walk *args, unsigned long *bitmap, unsigned long *start) ++static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area_struct *vma, ++ struct mm_walk *args, unsigned long *bitmap, unsigned long *first) + { + } + #endif +@@ -4071,9 +4072,9 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, + unsigned long next; + unsigned long addr; + struct vm_area_struct *vma; +- unsigned long pos = -1; ++ unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)]; ++ unsigned long first = -1; + struct lru_gen_mm_walk *walk = args->private; +- unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; + + VM_WARN_ON_ONCE(pud_leaf(*pud)); + +@@ -4115,18 +4116,17 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, + if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat)) + continue; + +- walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &first); + continue; + } + #endif + walk->mm_stats[MM_NONLEAF_TOTAL]++; + +- if (arch_has_hw_nonleaf_pmd_young() && +- get_cap(LRU_GEN_NONLEAF_YOUNG)) { ++ if (arch_has_hw_nonleaf_pmd_young() && get_cap(LRU_GEN_NONLEAF_YOUNG)) { + if (!pmd_young(val)) + continue; + +- walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos); ++ walk_pmd_range_locked(pud, addr, vma, args, bitmap, &first); + } + + if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i)) +@@ -4143,7 +4143,7 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end, + update_bloom_filter(walk->lruvec, walk->max_seq + 1, pmd + i); + } + +- walk_pmd_range_locked(pud, -1, vma, args, bitmap, &pos); ++ walk_pmd_range_locked(pud, -1, vma, args, bitmap, &first); + + if (i < PTRS_PER_PMD && get_next_vma(PUD_MASK, PMD_SIZE, args, &start, &end)) + goto restart; +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.3-18-UPSTREAM-mm-multi-gen-LRU-simplify-lru_gen_look_arou.patch b/target/linux/generic/backport-6.1/020-v6.3-18-UPSTREAM-mm-multi-gen-LRU-simplify-lru_gen_look_arou.patch new file mode 100644 index 00000000000..caee6b096f1 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.3-18-UPSTREAM-mm-multi-gen-LRU-simplify-lru_gen_look_arou.patch @@ -0,0 +1,153 @@ +From e604c3ccb4dfbdde2467fccef9bb36170a392695 Mon Sep 17 00:00:00 2001 +From: "T.J. Alumbaugh" +Date: Wed, 18 Jan 2023 00:18:27 +0000 +Subject: [PATCH 18/19] UPSTREAM: mm: multi-gen LRU: simplify + lru_gen_look_around() + +Update the folio generation in place with or without +current->reclaim_state->mm_walk. The LRU lock is held for longer, if +mm_walk is NULL and the number of folios to update is more than +PAGEVEC_SIZE. + +This causes a measurable regression from the LRU lock contention during a +microbencmark. But a tiny regression is not worth the complexity. + +Link: https://lkml.kernel.org/r/20230118001827.1040870-8-talumbau@google.com +Change-Id: I9ce18b4f4062e6c1c13c98ece9422478eb8e1846 +Signed-off-by: T.J. Alumbaugh +Cc: Yu Zhao +Signed-off-by: Andrew Morton +(cherry picked from commit abf086721a2f1e6897c57796f7268df1b194c750) +Bug: 274865848 +Signed-off-by: T.J. Mercier +--- + mm/vmscan.c | 73 +++++++++++++++++------------------------------------ + 1 file changed, 23 insertions(+), 50 deletions(-) + +diff --git a/mm/vmscan.c b/mm/vmscan.c +index 8f496c2e670a9..f6ce7a1fd78a3 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -4571,13 +4571,12 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc) + void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + { + int i; +- pte_t *pte; + unsigned long start; + unsigned long end; +- unsigned long addr; + struct lru_gen_mm_walk *walk; + int young = 0; +- unsigned long bitmap[BITS_TO_LONGS(MIN_LRU_BATCH)] = {}; ++ pte_t *pte = pvmw->pte; ++ unsigned long addr = pvmw->address; + struct folio *folio = pfn_folio(pvmw->pfn); + struct mem_cgroup *memcg = folio_memcg(folio); + struct pglist_data *pgdat = folio_pgdat(folio); +@@ -4594,25 +4593,28 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + /* avoid taking the LRU lock under the PTL when possible */ + walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL; + +- start = max(pvmw->address & PMD_MASK, pvmw->vma->vm_start); +- end = min(pvmw->address | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; ++ start = max(addr & PMD_MASK, pvmw->vma->vm_start); ++ end = min(addr | ~PMD_MASK, pvmw->vma->vm_end - 1) + 1; + + if (end - start > MIN_LRU_BATCH * PAGE_SIZE) { +- if (pvmw->address - start < MIN_LRU_BATCH * PAGE_SIZE / 2) ++ if (addr - start < MIN_LRU_BATCH * PAGE_SIZE / 2) + end = start + MIN_LRU_BATCH * PAGE_SIZE; +- else if (end - pvmw->address < MIN_LRU_BATCH * PAGE_SIZE / 2) ++ else if (end - addr < MIN_LRU_BATCH * PAGE_SIZE / 2) + start = end - MIN_LRU_BATCH * PAGE_SIZE; + else { +- start = pvmw->address - MIN_LRU_BATCH * PAGE_SIZE / 2; +- end = pvmw->address + MIN_LRU_BATCH * PAGE_SIZE / 2; ++ start = addr - MIN_LRU_BATCH * PAGE_SIZE / 2; ++ end = addr + MIN_LRU_BATCH * PAGE_SIZE / 2; + } + } + +- pte = pvmw->pte - (pvmw->address - start) / PAGE_SIZE; ++ /* folio_update_gen() requires stable folio_memcg() */ ++ if (!mem_cgroup_trylock_pages(memcg)) ++ return; + +- rcu_read_lock(); + arch_enter_lazy_mmu_mode(); + ++ pte -= (addr - start) / PAGE_SIZE; ++ + for (i = 0, addr = start; addr != end; i++, addr += PAGE_SIZE) { + unsigned long pfn; + +@@ -4637,56 +4639,27 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw) + !folio_test_swapcache(folio))) + folio_mark_dirty(folio); + ++ if (walk) { ++ old_gen = folio_update_gen(folio, new_gen); ++ if (old_gen >= 0 && old_gen != new_gen) ++ update_batch_size(walk, folio, old_gen, new_gen); ++ ++ continue; ++ } ++ + old_gen = folio_lru_gen(folio); + if (old_gen < 0) + folio_set_referenced(folio); + else if (old_gen != new_gen) +- __set_bit(i, bitmap); ++ folio_activate(folio); + } + + arch_leave_lazy_mmu_mode(); +- rcu_read_unlock(); ++ mem_cgroup_unlock_pages(); + + /* feedback from rmap walkers to page table walkers */ + if (suitable_to_scan(i, young)) + update_bloom_filter(lruvec, max_seq, pvmw->pmd); +- +- if (!walk && bitmap_weight(bitmap, MIN_LRU_BATCH) < PAGEVEC_SIZE) { +- for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { +- folio = pfn_folio(pte_pfn(pte[i])); +- folio_activate(folio); +- } +- return; +- } +- +- /* folio_update_gen() requires stable folio_memcg() */ +- if (!mem_cgroup_trylock_pages(memcg)) +- return; +- +- if (!walk) { +- spin_lock_irq(&lruvec->lru_lock); +- new_gen = lru_gen_from_seq(lruvec->lrugen.max_seq); +- } +- +- for_each_set_bit(i, bitmap, MIN_LRU_BATCH) { +- folio = pfn_folio(pte_pfn(pte[i])); +- if (folio_memcg_rcu(folio) != memcg) +- continue; +- +- old_gen = folio_update_gen(folio, new_gen); +- if (old_gen < 0 || old_gen == new_gen) +- continue; +- +- if (walk) +- update_batch_size(walk, folio, old_gen, new_gen); +- else +- lru_gen_update_size(lruvec, folio, old_gen, new_gen); +- } +- +- if (!walk) +- spin_unlock_irq(&lruvec->lru_lock); +- +- mem_cgroup_unlock_pages(); + } + + /****************************************************************************** +-- +2.40.1 + diff --git a/target/linux/generic/backport-6.1/020-v6.4-19-mm-Multi-gen-LRU-remove-wait_event_killable.patch b/target/linux/generic/backport-6.1/020-v6.4-19-mm-Multi-gen-LRU-remove-wait_event_killable.patch new file mode 100644 index 00000000000..4bf796c93d2 --- /dev/null +++ b/target/linux/generic/backport-6.1/020-v6.4-19-mm-Multi-gen-LRU-remove-wait_event_killable.patch @@ -0,0 +1,280 @@ +From 418038c22452df38cde519cc8c662bb15139764a Mon Sep 17 00:00:00 2001 +From: Kalesh Singh +Date: Thu, 13 Apr 2023 14:43:26 -0700 +Subject: [PATCH 19/19] mm: Multi-gen LRU: remove wait_event_killable() + +Android 14 and later default to MGLRU [1] and field telemetry showed +occasional long tail latency (>100ms) in the reclaim path. + +Tracing revealed priority inversion in the reclaim path. In +try_to_inc_max_seq(), when high priority tasks were blocked on +wait_event_killable(), the preemption of the low priority task to call +wake_up_all() caused those high priority tasks to wait longer than +necessary. In general, this problem is not different from others of its +kind, e.g., one caused by mutex_lock(). However, it is specific to MGLRU +because it introduced the new wait queue lruvec->mm_state.wait. + +The purpose of this new wait queue is to avoid the thundering herd +problem. If many direct reclaimers rush into try_to_inc_max_seq(), only +one can succeed, i.e., the one to wake up the rest, and the rest who +failed might cause premature OOM kills if they do not wait. So far there +is no evidence supporting this scenario, based on how often the wait has +been hit. And this begs the question how useful the wait queue is in +practice. + +Based on Minchan's recommendation, which is in line with his commit +6d4675e60135 ("mm: don't be stuck to rmap lock on reclaim path") and the +rest of the MGLRU code which also uses trylock when possible, remove the +wait queue. + +[1] https://android-review.googlesource.com/q/I7ed7fbfd6ef9ce10053347528125dd98c39e50bf + +Link: https://lkml.kernel.org/r/20230413214326.2147568-1-kaleshsingh@google.com +Fixes: bd74fdaea146 ("mm: multi-gen LRU: support page table walks") +Signed-off-by: Kalesh Singh +Suggested-by: Minchan Kim +Reported-by: Wei Wang +Acked-by: Yu Zhao +Cc: Minchan Kim +Cc: Jan Alexander Steffens (heftig) +Cc: Oleksandr Natalenko +Cc: Suleiman Souhlal +Cc: Suren Baghdasaryan +Signed-off-by: Andrew Morton +--- + include/linux/mmzone.h | 8 +-- + mm/vmscan.c | 112 +++++++++++++++-------------------------- + 2 files changed, 42 insertions(+), 78 deletions(-) + +diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h +index 403c7461e7a70..d62a5accf1be4 100644 +--- a/include/linux/mmzone.h ++++ b/include/linux/mmzone.h +@@ -453,18 +453,14 @@ enum { + struct lru_gen_mm_state { + /* set to max_seq after each iteration */ + unsigned long seq; +- /* where the current iteration continues (inclusive) */ ++ /* where the current iteration continues after */ + struct list_head *head; +- /* where the last iteration ended (exclusive) */ ++ /* where the last iteration ended before */ + struct list_head *tail; +- /* to wait for the last page table walker to finish */ +- struct wait_queue_head wait; + /* Bloom filters flip after each iteration */ + unsigned long *filters[NR_BLOOM_FILTERS]; + /* the mm stats for debugging */ + unsigned long stats[NR_HIST_GENS][NR_MM_STATS]; +- /* the number of concurrent page table walkers */ +- int nr_walkers; + }; + + struct lru_gen_mm_walk { +diff --git a/mm/vmscan.c b/mm/vmscan.c +index f6ce7a1fd78a3..851758303dbf4 100644 +--- a/mm/vmscan.c ++++ b/mm/vmscan.c +@@ -3371,18 +3371,13 @@ void lru_gen_del_mm(struct mm_struct *mm) + if (!lruvec) + continue; + +- /* where the last iteration ended (exclusive) */ ++ /* where the current iteration continues after */ ++ if (lruvec->mm_state.head == &mm->lru_gen.list) ++ lruvec->mm_state.head = lruvec->mm_state.head->prev; ++ ++ /* where the last iteration ended before */ + if (lruvec->mm_state.tail == &mm->lru_gen.list) + lruvec->mm_state.tail = lruvec->mm_state.tail->next; +- +- /* where the current iteration continues (inclusive) */ +- if (lruvec->mm_state.head != &mm->lru_gen.list) +- continue; +- +- lruvec->mm_state.head = lruvec->mm_state.head->next; +- /* the deletion ends the current iteration */ +- if (lruvec->mm_state.head == &mm_list->fifo) +- WRITE_ONCE(lruvec->mm_state.seq, lruvec->mm_state.seq + 1); + } + + list_del_init(&mm->lru_gen.list); +@@ -3478,68 +3473,54 @@ static bool iterate_mm_list(struct lruvec *lruvec, struct lru_gen_mm_walk *walk, + struct mm_struct **iter) + { + bool first = false; +- bool last = true; ++ bool last = false; + struct mm_struct *mm = NULL; + struct mem_cgroup *memcg = lruvec_memcg(lruvec); + struct lru_gen_mm_list *mm_list = get_mm_list(memcg); + struct lru_gen_mm_state *mm_state = &lruvec->mm_state; + + /* +- * There are four interesting cases for this page table walker: +- * 1. It tries to start a new iteration of mm_list with a stale max_seq; +- * there is nothing left to do. +- * 2. It's the first of the current generation, and it needs to reset +- * the Bloom filter for the next generation. +- * 3. It reaches the end of mm_list, and it needs to increment +- * mm_state->seq; the iteration is done. +- * 4. It's the last of the current generation, and it needs to reset the +- * mm stats counters for the next generation. ++ * mm_state->seq is incremented after each iteration of mm_list. There ++ * are three interesting cases for this page table walker: ++ * 1. It tries to start a new iteration with a stale max_seq: there is ++ * nothing left to do. ++ * 2. It started the next iteration: it needs to reset the Bloom filter ++ * so that a fresh set of PTE tables can be recorded. ++ * 3. It ended the current iteration: it needs to reset the mm stats ++ * counters and tell its caller to increment max_seq. + */ + spin_lock(&mm_list->lock); + + VM_WARN_ON_ONCE(mm_state->seq + 1 < walk->max_seq); +- VM_WARN_ON_ONCE(*iter && mm_state->seq > walk->max_seq); +- VM_WARN_ON_ONCE(*iter && !mm_state->nr_walkers); + +- if (walk->max_seq <= mm_state->seq) { +- if (!*iter) +- last = false; ++ if (walk->max_seq <= mm_state->seq) + goto done; +- } + +- if (!mm_state->nr_walkers) { +- VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); ++ if (!mm_state->head) ++ mm_state->head = &mm_list->fifo; + +- mm_state->head = mm_list->fifo.next; ++ if (mm_state->head == &mm_list->fifo) + first = true; +- } +- +- while (!mm && mm_state->head != &mm_list->fifo) { +- mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); + ++ do { + mm_state->head = mm_state->head->next; ++ if (mm_state->head == &mm_list->fifo) { ++ WRITE_ONCE(mm_state->seq, mm_state->seq + 1); ++ last = true; ++ break; ++ } + + /* force scan for those added after the last iteration */ +- if (!mm_state->tail || mm_state->tail == &mm->lru_gen.list) { +- mm_state->tail = mm_state->head; ++ if (!mm_state->tail || mm_state->tail == mm_state->head) { ++ mm_state->tail = mm_state->head->next; + walk->force_scan = true; + } + ++ mm = list_entry(mm_state->head, struct mm_struct, lru_gen.list); + if (should_skip_mm(mm, walk)) + mm = NULL; +- } +- +- if (mm_state->head == &mm_list->fifo) +- WRITE_ONCE(mm_state->seq, mm_state->seq + 1); ++ } while (!mm); + done: +- if (*iter && !mm) +- mm_state->nr_walkers--; +- if (!*iter && mm) +- mm_state->nr_walkers++; +- +- if (mm_state->nr_walkers) +- last = false; +- + if (*iter || last) + reset_mm_stats(lruvec, walk, last); + +@@ -3567,9 +3548,9 @@ static bool iterate_mm_list_nowalk(struct lruvec *lruvec, unsigned long max_seq) + + VM_WARN_ON_ONCE(mm_state->seq + 1 < max_seq); + +- if (max_seq > mm_state->seq && !mm_state->nr_walkers) { +- VM_WARN_ON_ONCE(mm_state->head && mm_state->head != &mm_list->fifo); +- ++ if (max_seq > mm_state->seq) { ++ mm_state->head = NULL; ++ mm_state->tail = NULL; + WRITE_ONCE(mm_state->seq, mm_state->seq + 1); + reset_mm_stats(lruvec, NULL, true); + success = true; +@@ -4172,10 +4153,6 @@ static int walk_pud_range(p4d_t *p4d, unsigned long start, unsigned long end, + + walk_pmd_range(&val, addr, next, args); + +- /* a racy check to curtail the waiting time */ +- if (wq_has_sleeper(&walk->lruvec->mm_state.wait)) +- return 1; +- + if (need_resched() || walk->batched >= MAX_LRU_BATCH) { + end = (addr | ~PUD_MASK) + 1; + goto done; +@@ -4208,8 +4185,14 @@ static void walk_mm(struct lruvec *lruvec, struct mm_struct *mm, struct lru_gen_ + walk->next_addr = FIRST_USER_ADDRESS; + + do { ++ DEFINE_MAX_SEQ(lruvec); ++ + err = -EBUSY; + ++ /* another thread might have called inc_max_seq() */ ++ if (walk->max_seq != max_seq) ++ break; ++ + /* folio_update_gen() requires stable folio_memcg() */ + if (!mem_cgroup_trylock_pages(memcg)) + break; +@@ -4442,25 +4425,12 @@ static bool try_to_inc_max_seq(struct lruvec *lruvec, unsigned long max_seq, + success = iterate_mm_list(lruvec, walk, &mm); + if (mm) + walk_mm(lruvec, mm, walk); +- +- cond_resched(); + } while (mm); + done: +- if (!success) { +- if (sc->priority <= DEF_PRIORITY - 2) +- wait_event_killable(lruvec->mm_state.wait, +- max_seq < READ_ONCE(lrugen->max_seq)); +- return false; +- } ++ if (success) ++ inc_max_seq(lruvec, can_swap, force_scan); + +- VM_WARN_ON_ONCE(max_seq != READ_ONCE(lrugen->max_seq)); +- +- inc_max_seq(lruvec, can_swap, force_scan); +- /* either this sees any waiters or they will see updated max_seq */ +- if (wq_has_sleeper(&lruvec->mm_state.wait)) +- wake_up_all(&lruvec->mm_state.wait); +- +- return true; ++ return success; + } + + /****************************************************************************** +@@ -6105,7 +6075,6 @@ void lru_gen_init_lruvec(struct lruvec *lruvec) + INIT_LIST_HEAD(&lrugen->folios[gen][type][zone]); + + lruvec->mm_state.seq = MIN_NR_GENS; +- init_waitqueue_head(&lruvec->mm_state.wait); + } + + #ifdef CONFIG_MEMCG +@@ -6138,7 +6107,6 @@ void lru_gen_exit_memcg(struct mem_cgroup *memcg) + for_each_node(nid) { + struct lruvec *lruvec = get_lruvec(memcg, nid); + +- VM_WARN_ON_ONCE(lruvec->mm_state.nr_walkers); + VM_WARN_ON_ONCE(memchr_inv(lruvec->lrugen.nr_pages, 0, + sizeof(lruvec->lrugen.nr_pages))); + +-- +2.40.1 + diff --git a/target/linux/generic/config-5.15 b/target/linux/generic/config-5.15 index f13af8ba268..934af3a7681 100644 --- a/target/linux/generic/config-5.15 +++ b/target/linux/generic/config-5.15 @@ -343,7 +343,7 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARM64_ERRATUM_858921 is not set # CONFIG_ARM64_HW_AFDBM is not set # CONFIG_ARM64_LSE_ATOMICS is not set -# CONFIG_ARM64_MODULE_PLTS is not set +CONFIG_ARM64_MODULE_PLTS=y # CONFIG_ARM64_MTE is not set # CONFIG_ARM64_PAN is not set # CONFIG_ARM64_PMEM is not set @@ -408,7 +408,7 @@ CONFIG_ARM_GIC_MAX_NR=1 # CONFIG_ARM_LPAE is not set # CONFIG_ARM_MEDIATEK_CPUFREQ_HW is not set # CONFIG_ARM_MHU is not set -# CONFIG_ARM_MODULE_PLTS is not set +CONFIG_ARM_MODULE_PLTS=y # CONFIG_ARM_PATCH_PHYS_VIRT is not set # CONFIG_ARM_PSCI is not set # CONFIG_ARM_PSCI_CHECKER is not set @@ -7262,7 +7262,6 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_HEXIUM_ORION is not set # CONFIG_VIDEO_HI556 is not set # CONFIG_VIDEO_I2C is not set -# CONFIG_VIDEO_IMX_PXP is not set # CONFIG_VIDEO_IMX208 is not set # CONFIG_VIDEO_IMX214 is not set # CONFIG_VIDEO_IMX219 is not set @@ -7276,6 +7275,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_IMX412 is not set # CONFIG_VIDEO_IMX477 is not set # CONFIG_VIDEO_IMX8_JPEG is not set +# CONFIG_VIDEO_IMX_PXP is not set # CONFIG_VIDEO_IRS1125 is not set # CONFIG_VIDEO_IR_I2C is not set # CONFIG_VIDEO_IVTV is not set diff --git a/target/linux/generic/config-6.1 b/target/linux/generic/config-6.1 index 48485051cb9..6a4913535d7 100644 --- a/target/linux/generic/config-6.1 +++ b/target/linux/generic/config-6.1 @@ -277,6 +277,7 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARCH_NOMADIK is not set # CONFIG_ARCH_NPCM is not set # CONFIG_ARCH_NSPIRE is not set +# CONFIG_ARCH_NXP is not set # CONFIG_ARCH_OMAP is not set # CONFIG_ARCH_OMAP1 is not set # CONFIG_ARCH_OMAP2 is not set @@ -367,7 +368,7 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8 # CONFIG_ARM64_ERRATUM_858921 is not set # CONFIG_ARM64_HW_AFDBM is not set # CONFIG_ARM64_LSE_ATOMICS is not set -# CONFIG_ARM64_MODULE_PLTS is not set +CONFIG_ARM64_MODULE_PLTS=y # CONFIG_ARM64_MTE is not set # CONFIG_ARM64_PAN is not set # CONFIG_ARM64_PMEM is not set @@ -433,7 +434,7 @@ CONFIG_ARM_GIC_MAX_NR=1 # CONFIG_ARM_LPAE is not set # CONFIG_ARM_MEDIATEK_CPUFREQ_HW is not set # CONFIG_ARM_MHU is not set -# CONFIG_ARM_MODULE_PLTS is not set +CONFIG_ARM_MODULE_PLTS=y # CONFIG_ARM_PATCH_PHYS_VIRT is not set # CONFIG_ARM_PSCI is not set # CONFIG_ARM_PSCI_CHECKER is not set @@ -912,8 +913,8 @@ CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y # CONFIG_CEPH_FS is not set # CONFIG_CEPH_LIB is not set # CONFIG_CFG80211 is not set -CONFIG_CFG80211_HEADERS=y # CONFIG_CFG80211_CERTIFICATION_ONUS is not set +CONFIG_CFG80211_HEADERS=y # CONFIG_CGROUPS is not set # CONFIG_CGROUP_FAVOR_DYNMODS is not set # CONFIG_CGROUP_MISC is not set @@ -1070,6 +1071,7 @@ CONFIG_CONSTRUCTORS=y # CONFIG_CPU_IDLE_GOV_TEO is not set # CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set # CONFIG_CPU_ISOLATION is not set +# CONFIG_CPU_LITTLE_ENDIAN is not set # CONFIG_CPU_NO_EFFICIENT_FFS is not set CONFIG_CPU_SW_DOMAIN_PAN=y # CONFIG_CPU_THERMAL is not set @@ -2479,6 +2481,7 @@ CONFIG_HIGH_RES_TIMERS=y CONFIG_HPET_MMAP_DEFAULT=y # CONFIG_HPFS_FS is not set # CONFIG_HP_ILO is not set +# CONFIG_HP_WATCHDOG is not set # CONFIG_HP_WIRELESS is not set # CONFIG_HSA_AMD is not set # CONFIG_HSI is not set @@ -4560,6 +4563,7 @@ CONFIG_NMI_LOG_BUF_SHIFT=13 # CONFIG_OCFS2_FS is not set # CONFIG_OCTEONTX2_AF is not set # CONFIG_OCTEONTX2_PF is not set +# CONFIG_OCTEON_EP is not set # CONFIG_OF_OVERLAY is not set CONFIG_OF_RESERVED_MEM=y # CONFIG_OF_UNITTEST is not set @@ -6535,6 +6539,7 @@ CONFIG_SUNRPC_DISABLE_INSECURE_ENCTYPES=y # CONFIG_SUNXI_SRAM is not set # CONFIG_SUN_PARTITION is not set # CONFIG_SURFACE_3_BUTTON is not set +# CONFIG_SURFACE_PLATFORMS is not set # CONFIG_SUSPEND is not set # CONFIG_SUSPEND_SKIP_SYNC is not set CONFIG_SWAP=y @@ -7450,7 +7455,6 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_HI846 is not set # CONFIG_VIDEO_HI847 is not set # CONFIG_VIDEO_I2C is not set -# CONFIG_VIDEO_IMX_PXP is not set # CONFIG_VIDEO_IMX208 is not set # CONFIG_VIDEO_IMX214 is not set # CONFIG_VIDEO_IMX219 is not set @@ -7464,6 +7468,7 @@ CONFIG_VHOST_MENU=y # CONFIG_VIDEO_IMX412 is not set # CONFIG_VIDEO_IMX477 is not set # CONFIG_VIDEO_IMX8_JPEG is not set +# CONFIG_VIDEO_IMX_PXP is not set # CONFIG_VIDEO_IRS1125 is not set # CONFIG_VIDEO_IR_I2C is not set # CONFIG_VIDEO_ISL7998X is not set @@ -7605,6 +7610,7 @@ CONFIG_VLAN_8021Q=y CONFIG_VMSPLIT_3G=y # CONFIG_VMSPLIT_3G_OPT is not set # CONFIG_VMWARE_PVSCSI is not set +# CONFIG_VMWARE_VMCI is not set # CONFIG_VMXNET3 is not set # CONFIG_VM_EVENT_COUNTERS is not set # CONFIG_VOP_BUS is not set diff --git a/target/linux/generic/config-filter b/target/linux/generic/config-filter index 201b68dddf2..e7aa90f8b54 100644 --- a/target/linux/generic/config-filter +++ b/target/linux/generic/config-filter @@ -10,6 +10,7 @@ CONFIG_CLANG_VERSION=.* # CONFIG_LD_.* is not set CONFIG_LLD_VERSION=.* CONFIG_PAHOLE_VERSION=.* +CONFIG_PAHOLE_HAS_SPLIT_BTF=.* CONFIG_PLUGIN_HOSTCC=".*" # CONFIG_SET_FS is not set # CONFIG_TASKS_.* is not set diff --git a/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch b/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch index d93ee0685b2..bd806a7a6df 100644 --- a/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch +++ b/target/linux/generic/pending-5.15/723-net-mt7531-ensure-all-MACs-are-powered-down-before-r.patch @@ -15,7 +15,7 @@ Signed-off-by: Alexander Couzens --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2347,6 +2347,10 @@ mt7531_setup(struct dsa_switch *ds) +@@ -2440,6 +2440,10 @@ mt7531_setup(struct dsa_switch *ds) return -ENODEV; } diff --git a/target/linux/generic/pending-5.15/737-01-net-ethernet-mtk_eth_soc-add-MTK_NETSYS_V1-capabilit.patch b/target/linux/generic/pending-5.15/737-01-net-ethernet-mtk_eth_soc-add-MTK_NETSYS_V1-capabilit.patch new file mode 100644 index 00000000000..621a7b0fcf0 --- /dev/null +++ b/target/linux/generic/pending-5.15/737-01-net-ethernet-mtk_eth_soc-add-MTK_NETSYS_V1-capabilit.patch @@ -0,0 +1,223 @@ +From 663fa1b7e0cb2c929008482014a70c6625caad75 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 7 Mar 2023 15:55:13 +0000 +Subject: [PATCH 1/7] net: ethernet: mtk_eth_soc: add MTK_NETSYS_V1 capability + bit + +Introduce MTK_NETSYS_V1 bit in the device capabilities for +MT7621/MT7622/MT7623/MT7628/MT7629 SoCs. +Use !MTK_NETSYS_V1 instead of MTK_NETSYS_V2 in the driver codebase. +This is a preliminary patch to introduce support for MT7988 SoC. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 30 +++++++------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 45 ++++++++++++--------- + 2 files changed, 41 insertions(+), 34 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -597,7 +597,7 @@ static void mtk_set_queue_speed(struct m + FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) | + FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) | + MTK_QTX_SCH_LEAKY_BUCKET_SIZE; +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) + val |= MTK_QTX_SCH_LEAKY_BUCKET_EN; + + if (IS_ENABLED(CONFIG_SOC_MT7621)) { +@@ -974,7 +974,7 @@ static bool mtk_rx_get_desc(struct mtk_e + rxd->rxd1 = READ_ONCE(dma_rxd->rxd1); + rxd->rxd3 = READ_ONCE(dma_rxd->rxd3); + rxd->rxd4 = READ_ONCE(dma_rxd->rxd4); +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) { + rxd->rxd5 = READ_ONCE(dma_rxd->rxd5); + rxd->rxd6 = READ_ONCE(dma_rxd->rxd6); + } +@@ -1032,7 +1032,7 @@ static int mtk_init_fq_dma(struct mtk_et + + txd->txd3 = TX_DMA_PLEN0(MTK_QDMA_PAGE_SIZE); + txd->txd4 = 0; +- if (MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V2)) { ++ if (!MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V1)) { + txd->txd5 = 0; + txd->txd6 = 0; + txd->txd7 = 0; +@@ -1221,7 +1221,7 @@ static void mtk_tx_set_dma_desc(struct n + struct mtk_mac *mac = netdev_priv(dev); + struct mtk_eth *eth = mac->hw; + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) + mtk_tx_set_dma_desc_v2(dev, txd, info); + else + mtk_tx_set_dma_desc_v1(dev, txd, info); +@@ -1902,7 +1902,7 @@ static int mtk_poll_rx(struct napi_struc + break; + + /* find out which mac the packet come from. values start at 1 */ +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) + mac = RX_DMA_GET_SPORT_V2(trxd.rxd5) - 1; + else if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && + !(trxd.rxd4 & RX_DMA_SPECIAL_TAG)) +@@ -1998,7 +1998,7 @@ static int mtk_poll_rx(struct napi_struc + skb->dev = netdev; + bytes += skb->len; + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) { + reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON, trxd.rxd5); + hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY; + if (hash != MTK_RXD5_FOE_ENTRY) +@@ -2023,7 +2023,7 @@ static int mtk_poll_rx(struct napi_struc + /* When using VLAN untagging in combination with DSA, the + * hardware treats the MTK special tag as a VLAN and untags it. + */ +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) && ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1) && + (trxd.rxd2 & RX_DMA_VTAG) && netdev_uses_dsa(netdev)) { + unsigned int port = RX_DMA_VPID(trxd.rxd3) & GENMASK(2, 0); + +@@ -2328,7 +2328,7 @@ static int mtk_tx_alloc(struct mtk_eth * + txd->txd2 = next_ptr; + txd->txd3 = TX_DMA_LS0 | TX_DMA_OWNER_CPU; + txd->txd4 = 0; +- if (MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V2)) { ++ if (!MTK_HAS_CAPS(soc->caps, MTK_NETSYS_V1)) { + txd->txd5 = 0; + txd->txd6 = 0; + txd->txd7 = 0; +@@ -2381,7 +2381,7 @@ static int mtk_tx_alloc(struct mtk_eth * + FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) | + FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) | + MTK_QTX_SCH_LEAKY_BUCKET_SIZE; +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) + val |= MTK_QTX_SCH_LEAKY_BUCKET_EN; + mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs); + ofs += MTK_QTX_OFFSET; +@@ -2515,7 +2515,7 @@ static int mtk_rx_alloc(struct mtk_eth * + + rxd->rxd3 = 0; + rxd->rxd4 = 0; +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) { + rxd->rxd5 = 0; + rxd->rxd6 = 0; + rxd->rxd7 = 0; +@@ -3063,7 +3063,7 @@ static int mtk_start_dma(struct mtk_eth + MTK_TX_BT_32DWORDS | MTK_NDP_CO_PRO | + MTK_RX_2B_OFFSET | MTK_TX_WB_DDONE; + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) + val |= MTK_MUTLI_CNT | MTK_RESV_BUF | + MTK_WCOMP_EN | MTK_DMAD_WR_WDONE | + MTK_CHK_DDONE_EN | MTK_LEAKY_BUCKET_EN; +@@ -3475,7 +3475,7 @@ static void mtk_hw_reset(struct mtk_eth + { + u32 val; + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) { + regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, 0); + val = RSTCTRL_PPE0_V2; + } else { +@@ -3487,7 +3487,7 @@ static void mtk_hw_reset(struct mtk_eth + + ethsys_reset(eth, RSTCTRL_ETH | RSTCTRL_FE | val); + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) + regmap_write(eth->ethsys, ETHSYS_FE_RST_CHK_IDLE_EN, + 0x3ffffff); + } +@@ -3683,7 +3683,7 @@ static int mtk_hw_init(struct mtk_eth *e + else + mtk_hw_reset(eth); + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) { + /* Set FE to PDMAv2 if necessary */ + val = mtk_r32(eth, MTK_FE_GLO_MISC); + mtk_w32(eth, val | BIT(4), MTK_FE_GLO_MISC); +@@ -3720,7 +3720,7 @@ static int mtk_hw_init(struct mtk_eth *e + */ + val = mtk_r32(eth, MTK_CDMQ_IG_CTRL); + mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL); +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) { + val = mtk_r32(eth, MTK_CDMP_IG_CTRL); + mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL); + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -816,6 +816,7 @@ enum mkt_eth_capabilities { + MTK_SHARED_INT_BIT, + MTK_TRGMII_MT7621_CLK_BIT, + MTK_QDMA_BIT, ++ MTK_NETSYS_V1_BIT, + MTK_NETSYS_V2_BIT, + MTK_SOC_MT7628_BIT, + MTK_RSTCTRL_PPE1_BIT, +@@ -851,6 +852,7 @@ enum mkt_eth_capabilities { + #define MTK_SHARED_INT BIT(MTK_SHARED_INT_BIT) + #define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT) + #define MTK_QDMA BIT(MTK_QDMA_BIT) ++#define MTK_NETSYS_V1 BIT(MTK_NETSYS_V1_BIT) + #define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) + #define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) + #define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) +@@ -913,25 +915,30 @@ enum mkt_eth_capabilities { + + #define MTK_HAS_CAPS(caps, _x) (((caps) & (_x) & ~(MTK_CAP_MASK)) == (_x)) + +-#define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \ +- MTK_GMAC2_RGMII | MTK_SHARED_INT | \ +- MTK_TRGMII_MT7621_CLK | MTK_QDMA) +- +-#define MT7622_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | MTK_GMAC2_RGMII | \ +- MTK_GMAC2_SGMII | MTK_GDM1_ESW | \ +- MTK_MUX_GDM1_TO_GMAC1_ESW | \ +- MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_QDMA) +- +-#define MT7623_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | MTK_GMAC2_RGMII | \ +- MTK_QDMA) +- +-#define MT7628_CAPS (MTK_SHARED_INT | MTK_SOC_MT7628) +- +-#define MT7629_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ +- MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW | \ +- MTK_MUX_GMAC2_GMAC0_TO_GEPHY | \ +- MTK_MUX_U3_GMAC2_TO_QPHY | \ +- MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA) ++#define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \ ++ MTK_GMAC2_RGMII | MTK_SHARED_INT | \ ++ MTK_TRGMII_MT7621_CLK | MTK_QDMA | \ ++ MTK_NETSYS_V1) ++ ++#define MT7622_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_SGMII | \ ++ MTK_GMAC2_RGMII | MTK_GMAC2_SGMII | \ ++ MTK_GDM1_ESW | MTK_MUX_GDM1_TO_GMAC1_ESW |\ ++ MTK_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | \ ++ MTK_QDMA | MTK_NETSYS_V1) ++ ++#define MT7623_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \ ++ MTK_GMAC2_RGMII | MTK_QDMA | \ ++ MTK_NETSYS_V1) ++ ++#define MT7628_CAPS (MTK_SHARED_INT | MTK_SOC_MT7628 | \ ++ MTK_NETSYS_V1) ++ ++#define MT7629_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ ++ MTK_GMAC2_GEPHY | MTK_GDM1_ESW | \ ++ MTK_MUX_GMAC2_GMAC0_TO_GEPHY | MTK_QDMA | \ ++ MTK_MUX_U3_GMAC2_TO_QPHY | MTK_NETSYS_V1 |\ ++ MTK_MUX_GDM1_TO_GMAC1_ESW | \ ++ MTK_MUX_GMAC12_TO_GEPHY_SGMII) + + #define MT7981_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | MTK_GMAC2_GEPHY | \ + MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ diff --git a/target/linux/generic/pending-5.15/737-02-net-ethernet-mtk_eth_soc-move-MAX_DEVS-in-mtk_soc_da.patch b/target/linux/generic/pending-5.15/737-02-net-ethernet-mtk_eth_soc-move-MAX_DEVS-in-mtk_soc_da.patch new file mode 100644 index 00000000000..a8debc41bfb --- /dev/null +++ b/target/linux/generic/pending-5.15/737-02-net-ethernet-mtk_eth_soc-move-MAX_DEVS-in-mtk_soc_da.patch @@ -0,0 +1,181 @@ +From 5af2b2dc4d6ba0ff7696e79f18e5b2bf862194eb Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 7 Mar 2023 15:55:24 +0000 +Subject: [PATCH 2/7] net: ethernet: mtk_eth_soc: move MAX_DEVS in mtk_soc_data + +This is a preliminary patch to add MT7988 SoC support since it runs 3 +macs instead of 2. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 34 +++++++++++++++++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 11 +++---- + 2 files changed, 36 insertions(+), 9 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -3989,7 +3989,10 @@ static void mtk_sgmii_destroy(struct mtk + { + int i; + +- for (i = 0; i < MTK_MAX_DEVS; i++) ++ if (!eth->sgmii_pcs) ++ return; ++ ++ for (i = 0; i < eth->soc->num_devs; i++) + mtk_pcs_lynxi_destroy(eth->sgmii_pcs[i]); + } + +@@ -4432,7 +4435,12 @@ static int mtk_sgmii_init(struct mtk_eth + u32 flags; + int i; + +- for (i = 0; i < MTK_MAX_DEVS; i++) { ++ eth->sgmii_pcs = devm_kzalloc(eth->dev, ++ sizeof(*eth->sgmii_pcs) * ++ eth->soc->num_devs, ++ GFP_KERNEL); ++ ++ for (i = 0; i < eth->soc->num_devs; i++) { + np = of_parse_phandle(eth->dev->of_node, "mediatek,sgmiisys", i); + if (!np) + break; +@@ -4477,6 +4485,18 @@ static int mtk_probe(struct platform_dev + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + eth->ip_align = NET_IP_ALIGN; + ++ eth->netdev = devm_kzalloc(eth->dev, ++ sizeof(*eth->netdev) * eth->soc->num_devs, ++ GFP_KERNEL); ++ if (!eth->netdev) ++ return -ENOMEM; ++ ++ eth->mac = devm_kzalloc(eth->dev, ++ sizeof(*eth->mac) * eth->soc->num_devs, ++ GFP_KERNEL); ++ if (!eth->mac) ++ return -ENOMEM; ++ + spin_lock_init(ð->page_lock); + spin_lock_init(ð->tx_irq_lock); + spin_lock_init(ð->rx_irq_lock); +@@ -4662,7 +4682,7 @@ static int mtk_probe(struct platform_dev + goto err_free_dev; + } + +- for (i = 0; i < MTK_MAX_DEVS; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + if (!eth->netdev[i]) + continue; + +@@ -4739,6 +4759,7 @@ static const struct mtk_soc_data mt2701_ + .hw_features = MTK_HW_FEATURES, + .required_clks = MT7623_CLKS_BITMAP, + .required_pctl = true, ++ .num_devs = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4757,6 +4778,7 @@ static const struct mtk_soc_data mt7621_ + .required_pctl = false, + .offload_version = 1, + .hash_offset = 2, ++ .num_devs = 2, + .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), +@@ -4778,6 +4800,7 @@ static const struct mtk_soc_data mt7622_ + .offload_version = 2, + .hash_offset = 2, + .has_accounting = true, ++ .num_devs = 2, + .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), +@@ -4797,6 +4820,7 @@ static const struct mtk_soc_data mt7623_ + .required_pctl = true, + .offload_version = 1, + .hash_offset = 2, ++ .num_devs = 2, + .foe_entry_size = sizeof(struct mtk_foe_entry) - 16, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), +@@ -4816,6 +4840,7 @@ static const struct mtk_soc_data mt7629_ + .required_clks = MT7629_CLKS_BITMAP, + .required_pctl = false, + .has_accounting = true, ++ .num_devs = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +@@ -4837,6 +4862,7 @@ static const struct mtk_soc_data mt7981_ + .hash_offset = 4, + .foe_entry_size = sizeof(struct mtk_foe_entry), + .has_accounting = true, ++ .num_devs = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma_v2), + .rxd_size = sizeof(struct mtk_rx_dma_v2), +@@ -4856,6 +4882,7 @@ static const struct mtk_soc_data mt7986_ + .required_pctl = false, + .offload_version = 2, + .hash_offset = 4, ++ .num_devs = 2, + .foe_entry_size = sizeof(struct mtk_foe_entry), + .has_accounting = true, + .txrx = { +@@ -4874,6 +4901,7 @@ static const struct mtk_soc_data rt5350_ + .hw_features = MTK_HW_FEATURES_MT7628, + .required_clks = MT7628_CLKS_BITMAP, + .required_pctl = false, ++ .num_devs = 2, + .txrx = { + .txd_size = sizeof(struct mtk_tx_dma), + .rxd_size = sizeof(struct mtk_rx_dma), +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1018,6 +1018,7 @@ struct mtk_reg_map { + * @required_pctl A bool value to show whether the SoC requires + * the extra setup for those pins used by GMAC. + * @hash_offset Flow table hash offset. ++ * @num_devs SoC number of macs. + * @foe_entry_size Foe table entry size. + * @has_accounting Bool indicating support for accounting of + * offloaded flows. +@@ -1036,6 +1037,7 @@ struct mtk_soc_data { + bool required_pctl; + u8 offload_version; + u8 hash_offset; ++ u8 num_devs; + u16 foe_entry_size; + netdev_features_t hw_features; + bool has_accounting; +@@ -1051,9 +1053,6 @@ struct mtk_soc_data { + + #define MTK_DMA_MONITOR_TIMEOUT msecs_to_jiffies(1000) + +-/* currently no SoC has more than 2 macs */ +-#define MTK_MAX_DEVS 2 +- + /* struct mtk_eth - This is the main datasructure for holding the state + * of the driver + * @dev: The device pointer +@@ -1108,14 +1107,14 @@ struct mtk_eth { + spinlock_t tx_irq_lock; + spinlock_t rx_irq_lock; + struct net_device dummy_dev; +- struct net_device *netdev[MTK_MAX_DEVS]; +- struct mtk_mac *mac[MTK_MAX_DEVS]; ++ struct net_device **netdev; ++ struct mtk_mac **mac; + int irq[3]; + u32 msg_enable; + unsigned long sysclk; + struct regmap *ethsys; + struct regmap *infra; +- struct phylink_pcs *sgmii_pcs[MTK_MAX_DEVS]; ++ struct phylink_pcs **sgmii_pcs; + struct regmap *pctl; + bool hwlro; + refcount_t dma_refcnt; diff --git a/target/linux/generic/pending-5.15/737-03-net-ethernet-mtk_eth_soc-rely-on-num_devs-and-remove.patch b/target/linux/generic/pending-5.15/737-03-net-ethernet-mtk_eth_soc-rely-on-num_devs-and-remove.patch new file mode 100644 index 00000000000..d6b36bf6368 --- /dev/null +++ b/target/linux/generic/pending-5.15/737-03-net-ethernet-mtk_eth_soc-rely-on-num_devs-and-remove.patch @@ -0,0 +1,153 @@ +From 4e35e80750b33727e606be9e7ce447bde2e0deb7 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 7 Mar 2023 15:55:35 +0000 +Subject: [PATCH 3/7] net: ethernet: mtk_eth_soc: rely on num_devs and remove + MTK_MAC_COUNT + +Get rid of MTK_MAC_COUNT since it is a duplicated of eth->soc->num_devs. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 30 ++++++++++----------- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 - + 2 files changed, 15 insertions(+), 16 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -900,7 +900,7 @@ static void mtk_stats_update(struct mtk_ + { + int i; + +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + if (!eth->mac[i] || !eth->mac[i]->hw_stats) + continue; + if (spin_trylock(ð->mac[i]->hw_stats->stats_lock)) { +@@ -1403,7 +1403,7 @@ static int mtk_queue_stopped(struct mtk_ + { + int i; + +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + if (!eth->netdev[i]) + continue; + if (netif_queue_stopped(eth->netdev[i])) +@@ -1417,7 +1417,7 @@ static void mtk_wake_queue(struct mtk_et + { + int i; + +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + if (!eth->netdev[i]) + continue; + netif_tx_wake_all_queues(eth->netdev[i]); +@@ -1908,7 +1908,7 @@ static int mtk_poll_rx(struct napi_struc + !(trxd.rxd4 & RX_DMA_SPECIAL_TAG)) + mac = RX_DMA_GET_SPORT(trxd.rxd4) - 1; + +- if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT || ++ if (unlikely(mac < 0 || mac >= eth->soc->num_devs || + !eth->netdev[mac])) + goto release_desc; + +@@ -2937,7 +2937,7 @@ static void mtk_dma_free(struct mtk_eth + const struct mtk_soc_data *soc = eth->soc; + int i; + +- for (i = 0; i < MTK_MAC_COUNT; i++) ++ for (i = 0; i < soc->num_devs; i++) + if (eth->netdev[i]) + netdev_reset_queue(eth->netdev[i]); + if (eth->scratch_ring) { +@@ -3091,7 +3091,7 @@ static void mtk_gdm_config(struct mtk_et + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) + return; + +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + u32 val = mtk_r32(eth, MTK_GDMA_FWD_CFG(i)); + + /* default setup the forward port to send frame to PDMA */ +@@ -3704,7 +3704,7 @@ static int mtk_hw_init(struct mtk_eth *e + * up with the more appropriate value when mtk_mac_config call is being + * invoked. + */ +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + struct net_device *dev = eth->netdev[i]; + + mtk_w32(eth, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(i)); +@@ -3909,7 +3909,7 @@ static void mtk_pending_work(struct work + mtk_prepare_for_reset(eth); + + /* stop all devices to make sure that dma is properly shut down */ +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + if (!eth->netdev[i] || !netif_running(eth->netdev[i])) + continue; + +@@ -3925,7 +3925,7 @@ static void mtk_pending_work(struct work + mtk_hw_init(eth, true); + + /* restart DMA and enable IRQs */ +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + if (!test_bit(i, &restart)) + continue; + +@@ -3953,7 +3953,7 @@ static int mtk_free_dev(struct mtk_eth * + { + int i; + +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + if (!eth->netdev[i]) + continue; + free_netdev(eth->netdev[i]); +@@ -3972,7 +3972,7 @@ static int mtk_unreg_dev(struct mtk_eth + { + int i; + +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + struct mtk_mac *mac; + if (!eth->netdev[i]) + continue; +@@ -4277,7 +4277,7 @@ static int mtk_add_mac(struct mtk_eth *e + } + + id = be32_to_cpup(_id); +- if (id >= MTK_MAC_COUNT) { ++ if (id >= eth->soc->num_devs) { + dev_err(eth->dev, "%d is not a valid mac id\n", id); + return -EINVAL; + } +@@ -4407,7 +4407,7 @@ void mtk_eth_set_dma_device(struct mtk_e + + rtnl_lock(); + +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + dev = eth->netdev[i]; + + if (!dev || !(dev->flags & IFF_UP)) +@@ -4734,7 +4734,7 @@ static int mtk_remove(struct platform_de + int i; + + /* stop all devices to make sure that dma is properly shut down */ +- for (i = 0; i < MTK_MAC_COUNT; i++) { ++ for (i = 0; i < eth->soc->num_devs; i++) { + if (!eth->netdev[i]) + continue; + mtk_stop(eth->netdev[i]); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -33,7 +33,6 @@ + #define MTK_TX_DMA_BUF_LEN_V2 0xffff + #define MTK_QDMA_RING_SIZE 2048 + #define MTK_DMA_SIZE 512 +-#define MTK_MAC_COUNT 2 + #define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + ETH_FCS_LEN) + #define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN) + #define MTK_DMA_DUMMY_DESC 0xffffffff diff --git a/target/linux/generic/pending-5.15/737-04-net-ethernet-mtk_eth_soc-add-MTK_NETSYS_V3-capabilit.patch b/target/linux/generic/pending-5.15/737-04-net-ethernet-mtk_eth_soc-add-MTK_NETSYS_V3-capabilit.patch new file mode 100644 index 00000000000..80d729db17f --- /dev/null +++ b/target/linux/generic/pending-5.15/737-04-net-ethernet-mtk_eth_soc-add-MTK_NETSYS_V3-capabilit.patch @@ -0,0 +1,292 @@ +From ab817f559d505329d8a413c7d29250f6d87d77a0 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 7 Mar 2023 15:55:47 +0000 +Subject: [PATCH 4/7] net: ethernet: mtk_eth_soc: add MTK_NETSYS_V3 capability + bit + +Introduce MTK_NETSYS_V3 bit in the device capabilities. +This is a preliminary patch to introduce support for MT7988 SoC. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 115 ++++++++++++++++---- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 44 +++++++- + 2 files changed, 134 insertions(+), 25 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -880,17 +880,32 @@ void mtk_stats_update_mac(struct mtk_mac + mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x20 + offs); + hw_stats->rx_flow_control_packets += + mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x24 + offs); +- hw_stats->tx_skip += +- mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x28 + offs); +- hw_stats->tx_collisions += +- mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x2c + offs); +- hw_stats->tx_bytes += +- mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x30 + offs); +- stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x34 + offs); +- if (stats) +- hw_stats->tx_bytes += (stats << 32); +- hw_stats->tx_packets += +- mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x38 + offs); ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) { ++ hw_stats->tx_skip += ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x50 + offs); ++ hw_stats->tx_collisions += ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x54 + offs); ++ hw_stats->tx_bytes += ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x40 + offs); ++ stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x44 + offs); ++ if (stats) ++ hw_stats->tx_bytes += (stats << 32); ++ hw_stats->tx_packets += ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x48 + offs); ++ } else { ++ hw_stats->tx_skip += ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x28 + offs); ++ hw_stats->tx_collisions += ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x2c + offs); ++ hw_stats->tx_bytes += ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x30 + offs); ++ stats = mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x34 + offs); ++ if (stats) ++ hw_stats->tx_bytes += (stats << 32); ++ hw_stats->tx_packets += ++ mtk_r32(mac->hw, reg_map->gdm1_cnt + 0x38 + offs); ++ } + } + + u64_stats_update_end(&hw_stats->syncp); +@@ -1192,7 +1207,10 @@ static void mtk_tx_set_dma_desc_v2(struc + data |= TX_DMA_LS0; + WRITE_ONCE(desc->txd3, data); + +- data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */ ++ if (mac->id == MTK_GMAC3_ID) ++ data = PSE_GDM3_PORT; ++ else ++ data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */ + data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid); + WRITE_ONCE(desc->txd4, data); + +@@ -1203,6 +1221,9 @@ static void mtk_tx_set_dma_desc_v2(struc + /* tx checksum offload */ + if (info->csum) + data |= TX_DMA_CHKSUM_V2; ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) && ++ netdev_uses_dsa(dev)) ++ data |= TX_DMA_SPTAG_V3; + } + WRITE_ONCE(desc->txd5, data); + +@@ -1268,8 +1289,13 @@ static int mtk_tx_map(struct sk_buff *sk + mtk_tx_set_dma_desc(dev, itxd, &txd_info); + + itx_buf->flags |= MTK_TX_FLAGS_SINGLE0; +- itx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : +- MTK_TX_FLAGS_FPORT1; ++ if (mac->id == MTK_GMAC1_ID) ++ itx_buf->flags |= MTK_TX_FLAGS_FPORT0; ++ else if (mac->id == MTK_GMAC2_ID) ++ itx_buf->flags |= MTK_TX_FLAGS_FPORT1; ++ else ++ itx_buf->flags |= MTK_TX_FLAGS_FPORT2; ++ + setup_tx_buf(eth, itx_buf, itxd_pdma, txd_info.addr, txd_info.size, + k++); + +@@ -1317,8 +1343,13 @@ static int mtk_tx_map(struct sk_buff *sk + memset(tx_buf, 0, sizeof(*tx_buf)); + tx_buf->data = (void *)MTK_DMA_DUMMY_DESC; + tx_buf->flags |= MTK_TX_FLAGS_PAGE0; +- tx_buf->flags |= (!mac->id) ? MTK_TX_FLAGS_FPORT0 : +- MTK_TX_FLAGS_FPORT1; ++ ++ if (mac->id == MTK_GMAC1_ID) ++ tx_buf->flags |= MTK_TX_FLAGS_FPORT0; ++ else if (mac->id == MTK_GMAC2_ID) ++ tx_buf->flags |= MTK_TX_FLAGS_FPORT1; ++ else ++ tx_buf->flags |= MTK_TX_FLAGS_FPORT2; + + setup_tx_buf(eth, tx_buf, txd_pdma, txd_info.addr, + txd_info.size, k++); +@@ -1902,11 +1933,24 @@ static int mtk_poll_rx(struct napi_struc + break; + + /* find out which mac the packet come from. values start at 1 */ +- if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) +- mac = RX_DMA_GET_SPORT_V2(trxd.rxd5) - 1; +- else if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && +- !(trxd.rxd4 & RX_DMA_SPECIAL_TAG)) ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V1)) { ++ u32 val = RX_DMA_GET_SPORT_V2(trxd.rxd5); ++ ++ switch (val) { ++ case PSE_GDM1_PORT: ++ case PSE_GDM2_PORT: ++ mac = val - 1; ++ break; ++ case PSE_GDM3_PORT: ++ mac = MTK_GMAC3_ID; ++ break; ++ default: ++ break; ++ } ++ } else if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628) && ++ !(trxd.rxd4 & RX_DMA_SPECIAL_TAG)) { + mac = RX_DMA_GET_SPORT(trxd.rxd4) - 1; ++ } + + if (unlikely(mac < 0 || mac >= eth->soc->num_devs || + !eth->netdev[mac])) +@@ -2135,7 +2179,9 @@ static int mtk_poll_tx_qdma(struct mtk_e + tx_buf = mtk_desc_to_tx_buf(ring, desc, + eth->soc->txrx.txd_size); + if (tx_buf->flags & MTK_TX_FLAGS_FPORT1) +- mac = 1; ++ mac = MTK_GMAC2_ID; ++ else if (tx_buf->flags & MTK_TX_FLAGS_FPORT2) ++ mac = MTK_GMAC3_ID; + + if (!tx_buf->data) + break; +@@ -3742,7 +3788,26 @@ static int mtk_hw_init(struct mtk_eth *e + mtk_w32(eth, eth->soc->txrx.rx_irq_done_mask, reg_map->qdma.int_grp + 4); + mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP); + +- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) { ++ /* PSE should not drop port1, port8 and port9 packets */ ++ mtk_w32(eth, 0x00000302, PSE_DROP_CFG); ++ ++ /* GDM and CDM Threshold */ ++ mtk_w32(eth, 0x00000707, MTK_CDMW0_THRES); ++ mtk_w32(eth, 0x00000077, MTK_CDMW1_THRES); ++ ++ /* Disable GDM1 RX CRC stripping */ ++ val = mtk_r32(eth, MTK_GDMA_FWD_CFG(0)); ++ val &= ~MTK_GDMA_STRP_CRC; ++ mtk_w32(eth, val, MTK_GDMA_FWD_CFG(0)); ++ ++ /* PSE GDM3 MIB counter has incorrect hw default values, ++ * so the driver ought to read clear the values beforehand ++ * in case ethtool retrieve wrong mib values. ++ */ ++ for (i = 0; i < 0x80; i += 0x4) ++ mtk_r32(eth, reg_map->gdm1_cnt + 0x100 + i); ++ } else if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) { + /* PSE should not drop port8 and port9 packets from WDMA Tx */ + mtk_w32(eth, 0x00000300, PSE_DROP_CFG); + +@@ -4314,7 +4379,11 @@ static int mtk_add_mac(struct mtk_eth *e + } + spin_lock_init(&mac->hw_stats->stats_lock); + u64_stats_init(&mac->hw_stats->syncp); +- mac->hw_stats->reg_offset = id * MTK_STAT_OFFSET; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) ++ mac->hw_stats->reg_offset = id * 0x80; ++ else ++ mac->hw_stats->reg_offset = id * 0x40; + + /* phylink create */ + err = of_get_phy_mode(np, &phy_mode); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -121,6 +121,7 @@ + #define MTK_GDMA_ICS_EN BIT(22) + #define MTK_GDMA_TCS_EN BIT(21) + #define MTK_GDMA_UCS_EN BIT(20) ++#define MTK_GDMA_STRP_CRC BIT(16) + #define MTK_GDMA_TO_PDMA 0x0 + #define MTK_GDMA_DROP_ALL 0x7777 + +@@ -286,8 +287,6 @@ + /* QDMA Interrupt grouping registers */ + #define MTK_RLS_DONE_INT BIT(0) + +-#define MTK_STAT_OFFSET 0x40 +- + /* QDMA TX NUM */ + #define QID_BITS_V2(x) (((x) & 0x3f) << 16) + #define MTK_QDMA_GMAC2_QID 8 +@@ -300,6 +299,8 @@ + #define TX_DMA_CHKSUM_V2 (0x7 << 28) + #define TX_DMA_TSO_V2 BIT(31) + ++#define TX_DMA_SPTAG_V3 BIT(27) ++ + /* QDMA V2 descriptor txd4 */ + #define TX_DMA_FPORT_SHIFT_V2 8 + #define TX_DMA_FPORT_MASK_V2 0xf +@@ -636,6 +637,7 @@ enum mtk_tx_flags { + */ + MTK_TX_FLAGS_FPORT0 = 0x04, + MTK_TX_FLAGS_FPORT1 = 0x08, ++ MTK_TX_FLAGS_FPORT2 = 0x10, + }; + + /* This enum allows us to identify how the clock is defined on the array of the +@@ -721,6 +723,42 @@ enum mtk_dev_state { + MTK_RESETTING + }; + ++/* PSE Port Definition */ ++enum mtk_pse_port { ++ PSE_ADMA_PORT = 0, ++ PSE_GDM1_PORT, ++ PSE_GDM2_PORT, ++ PSE_PPE0_PORT, ++ PSE_PPE1_PORT, ++ PSE_QDMA_TX_PORT, ++ PSE_QDMA_RX_PORT, ++ PSE_DROP_PORT, ++ PSE_WDMA0_PORT, ++ PSE_WDMA1_PORT, ++ PSE_TDMA_PORT, ++ PSE_NONE_PORT, ++ PSE_PPE2_PORT, ++ PSE_WDMA2_PORT, ++ PSE_EIP197_PORT, ++ PSE_GDM3_PORT, ++ PSE_PORT_MAX ++}; ++ ++/* GMAC Identifier */ ++enum mtk_gmac_id { ++ MTK_GMAC1_ID = 0, ++ MTK_GMAC2_ID, ++ MTK_GMAC3_ID, ++ MTK_GMAC_ID_MAX ++}; ++ ++/* GDM Type */ ++enum mtk_gdm_type { ++ MTK_GDM_TYPE = 0, ++ MTK_XGDM_TYPE, ++ MTK_GDM_TYPE_MAX ++}; ++ + enum mtk_tx_buf_type { + MTK_TYPE_SKB, + MTK_TYPE_XDP_TX, +@@ -817,6 +855,7 @@ enum mkt_eth_capabilities { + MTK_QDMA_BIT, + MTK_NETSYS_V1_BIT, + MTK_NETSYS_V2_BIT, ++ MTK_NETSYS_V3_BIT, + MTK_SOC_MT7628_BIT, + MTK_RSTCTRL_PPE1_BIT, + MTK_U3_COPHY_V2_BIT, +@@ -853,6 +892,7 @@ enum mkt_eth_capabilities { + #define MTK_QDMA BIT(MTK_QDMA_BIT) + #define MTK_NETSYS_V1 BIT(MTK_NETSYS_V1_BIT) + #define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) ++#define MTK_NETSYS_V3 BIT(MTK_NETSYS_V3_BIT) + #define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) + #define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) + #define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT) diff --git a/target/linux/generic/pending-5.15/737-05-net-ethernet-mtk_eth_soc-convert-caps-in-mtk_soc_dat.patch b/target/linux/generic/pending-5.15/737-05-net-ethernet-mtk_eth_soc-convert-caps-in-mtk_soc_dat.patch new file mode 100644 index 00000000000..bd26cca305d --- /dev/null +++ b/target/linux/generic/pending-5.15/737-05-net-ethernet-mtk_eth_soc-convert-caps-in-mtk_soc_dat.patch @@ -0,0 +1,197 @@ +From 45b575fd9e6a455090820248bf1b98b1f2c7b6c8 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Tue, 7 Mar 2023 15:56:00 +0000 +Subject: [PATCH 5/7] net: ethernet: mtk_eth_soc: convert caps in mtk_soc_data + struct to u64 + +This is a preliminary patch to introduce support for MT7988 SoC. + +Signed-off-by: Lorenzo Bianconi +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/mtk_eth_path.c | 22 +++---- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 62 ++++++++++---------- + 2 files changed, 42 insertions(+), 42 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c +@@ -15,10 +15,10 @@ + struct mtk_eth_muxc { + const char *name; + int cap_bit; +- int (*set_path)(struct mtk_eth *eth, int path); ++ int (*set_path)(struct mtk_eth *eth, u64 path); + }; + +-static const char *mtk_eth_path_name(int path) ++static const char *mtk_eth_path_name(u64 path) + { + switch (path) { + case MTK_ETH_PATH_GMAC1_RGMII: +@@ -40,7 +40,7 @@ static const char *mtk_eth_path_name(int + } + } + +-static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, int path) ++static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path) + { + bool updated = true; + u32 val, mask, set; +@@ -71,7 +71,7 @@ static int set_mux_gdm1_to_gmac1_esw(str + return 0; + } + +-static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, int path) ++static int set_mux_gmac2_gmac0_to_gephy(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0; + bool updated = true; +@@ -94,7 +94,7 @@ static int set_mux_gmac2_gmac0_to_gephy( + return 0; + } + +-static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, int path) ++static int set_mux_u3_gmac2_to_qphy(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0, mask = 0, reg = 0; + bool updated = true; +@@ -125,7 +125,7 @@ static int set_mux_u3_gmac2_to_qphy(stru + return 0; + } + +-static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, int path) ++static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0; + bool updated = true; +@@ -163,7 +163,7 @@ static int set_mux_gmac1_gmac2_to_sgmii_ + return 0; + } + +-static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, int path) ++static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0; + bool updated = true; +@@ -218,7 +218,7 @@ static const struct mtk_eth_muxc mtk_eth + }, + }; + +-static int mtk_eth_mux_setup(struct mtk_eth *eth, int path) ++static int mtk_eth_mux_setup(struct mtk_eth *eth, u64 path) + { + int i, err = 0; + +@@ -249,7 +249,7 @@ out: + + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) + { +- int path; ++ u64 path; + + path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : + MTK_ETH_PATH_GMAC2_SGMII; +@@ -260,7 +260,7 @@ int mtk_gmac_sgmii_path_setup(struct mtk + + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id) + { +- int path = 0; ++ u64 path = 0; + + if (mac_id == 1) + path = MTK_ETH_PATH_GMAC2_GEPHY; +@@ -274,7 +274,7 @@ int mtk_gmac_gephy_path_setup(struct mtk + + int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id) + { +- int path; ++ u64 path; + + path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_RGMII : + MTK_ETH_PATH_GMAC2_RGMII; +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -878,44 +878,44 @@ enum mkt_eth_capabilities { + }; + + /* Supported hardware group on SoCs */ +-#define MTK_RGMII BIT(MTK_RGMII_BIT) +-#define MTK_TRGMII BIT(MTK_TRGMII_BIT) +-#define MTK_SGMII BIT(MTK_SGMII_BIT) +-#define MTK_ESW BIT(MTK_ESW_BIT) +-#define MTK_GEPHY BIT(MTK_GEPHY_BIT) +-#define MTK_MUX BIT(MTK_MUX_BIT) +-#define MTK_INFRA BIT(MTK_INFRA_BIT) +-#define MTK_SHARED_SGMII BIT(MTK_SHARED_SGMII_BIT) +-#define MTK_HWLRO BIT(MTK_HWLRO_BIT) +-#define MTK_SHARED_INT BIT(MTK_SHARED_INT_BIT) +-#define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT) +-#define MTK_QDMA BIT(MTK_QDMA_BIT) +-#define MTK_NETSYS_V1 BIT(MTK_NETSYS_V1_BIT) +-#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT) +-#define MTK_NETSYS_V3 BIT(MTK_NETSYS_V3_BIT) +-#define MTK_SOC_MT7628 BIT(MTK_SOC_MT7628_BIT) +-#define MTK_RSTCTRL_PPE1 BIT(MTK_RSTCTRL_PPE1_BIT) +-#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT) ++#define MTK_RGMII BIT_ULL(MTK_RGMII_BIT) ++#define MTK_TRGMII BIT_ULL(MTK_TRGMII_BIT) ++#define MTK_SGMII BIT_ULL(MTK_SGMII_BIT) ++#define MTK_ESW BIT_ULL(MTK_ESW_BIT) ++#define MTK_GEPHY BIT_ULL(MTK_GEPHY_BIT) ++#define MTK_MUX BIT_ULL(MTK_MUX_BIT) ++#define MTK_INFRA BIT_ULL(MTK_INFRA_BIT) ++#define MTK_SHARED_SGMII BIT_ULL(MTK_SHARED_SGMII_BIT) ++#define MTK_HWLRO BIT_ULL(MTK_HWLRO_BIT) ++#define MTK_SHARED_INT BIT_ULL(MTK_SHARED_INT_BIT) ++#define MTK_TRGMII_MT7621_CLK BIT_ULL(MTK_TRGMII_MT7621_CLK_BIT) ++#define MTK_QDMA BIT_ULL(MTK_QDMA_BIT) ++#define MTK_NETSYS_V1 BIT_ULL(MTK_NETSYS_V1_BIT) ++#define MTK_NETSYS_V2 BIT_ULL(MTK_NETSYS_V2_BIT) ++#define MTK_NETSYS_V3 BIT_ULL(MTK_NETSYS_V3_BIT) ++#define MTK_SOC_MT7628 BIT_ULL(MTK_SOC_MT7628_BIT) ++#define MTK_RSTCTRL_PPE1 BIT_ULL(MTK_RSTCTRL_PPE1_BIT) ++#define MTK_U3_COPHY_V2 BIT_ULL(MTK_U3_COPHY_V2_BIT) + + #define MTK_ETH_MUX_GDM1_TO_GMAC1_ESW \ +- BIT(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) ++ BIT_ULL(MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT) + #define MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY \ +- BIT(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT) ++ BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT) + #define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \ +- BIT(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT) ++ BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT) + #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ +- BIT(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT) ++ BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT) + #define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \ +- BIT(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT) ++ BIT_ULL(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT) + + /* Supported path present on SoCs */ +-#define MTK_ETH_PATH_GMAC1_RGMII BIT(MTK_ETH_PATH_GMAC1_RGMII_BIT) +-#define MTK_ETH_PATH_GMAC1_TRGMII BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT) +-#define MTK_ETH_PATH_GMAC1_SGMII BIT(MTK_ETH_PATH_GMAC1_SGMII_BIT) +-#define MTK_ETH_PATH_GMAC2_RGMII BIT(MTK_ETH_PATH_GMAC2_RGMII_BIT) +-#define MTK_ETH_PATH_GMAC2_SGMII BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT) +-#define MTK_ETH_PATH_GMAC2_GEPHY BIT(MTK_ETH_PATH_GMAC2_GEPHY_BIT) +-#define MTK_ETH_PATH_GDM1_ESW BIT(MTK_ETH_PATH_GDM1_ESW_BIT) ++#define MTK_ETH_PATH_GMAC1_RGMII BIT_ULL(MTK_ETH_PATH_GMAC1_RGMII_BIT) ++#define MTK_ETH_PATH_GMAC1_TRGMII BIT_ULL(MTK_ETH_PATH_GMAC1_TRGMII_BIT) ++#define MTK_ETH_PATH_GMAC1_SGMII BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_RGMII BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_SGMII BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_GEPHY BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT) ++#define MTK_ETH_PATH_GDM1_ESW BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT) + + #define MTK_GMAC1_RGMII (MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII) + #define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII) +@@ -1071,7 +1071,7 @@ struct mtk_reg_map { + struct mtk_soc_data { + const struct mtk_reg_map *reg_map; + u32 ana_rgc3; +- u32 caps; ++ u64 caps; + u32 required_clks; + bool required_pctl; + u8 offload_version; diff --git a/target/linux/generic/pending-5.15/737-06-net-ethernet-mtk_eth_soc-add-support-for-MT7988-SoC.patch b/target/linux/generic/pending-5.15/737-06-net-ethernet-mtk_eth_soc-add-support-for-MT7988-SoC.patch new file mode 100644 index 00000000000..504d2ea2266 --- /dev/null +++ b/target/linux/generic/pending-5.15/737-06-net-ethernet-mtk_eth_soc-add-support-for-MT7988-SoC.patch @@ -0,0 +1,495 @@ +From 661bacf4363ca68939c15e20056b5f72fbd034e7 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Sat, 25 Feb 2023 00:08:24 +0100 +Subject: [PATCH 6/7] net: ethernet: mtk_eth_soc: add support for MT7988 SoC + +Introduce support for ethernet chip available in MT7988 SoC to +mtk_eth_soc driver. +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 153 ++++++++++++++-- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 193 ++++++++++++++------ + 2 files changed, 279 insertions(+), 67 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -152,6 +152,54 @@ static const struct mtk_reg_map mt7986_r + .pse_oq_sta = 0x01a0, + }; + ++static const struct mtk_reg_map mt7988_reg_map = { ++ .tx_irq_mask = 0x461c, ++ .tx_irq_status = 0x4618, ++ .pdma = { ++ .rx_ptr = 0x6900, ++ .rx_cnt_cfg = 0x6904, ++ .pcrx_ptr = 0x6908, ++ .glo_cfg = 0x6a04, ++ .rst_idx = 0x6a08, ++ .delay_irq = 0x6a0c, ++ .irq_status = 0x6a20, ++ .irq_mask = 0x6a28, ++ .adma_rx_dbg0 = 0x6a38, ++ .int_grp = 0x6a50, ++ }, ++ .qdma = { ++ .qtx_cfg = 0x4400, ++ .qtx_sch = 0x4404, ++ .rx_ptr = 0x4500, ++ .rx_cnt_cfg = 0x4504, ++ .qcrx_ptr = 0x4508, ++ .glo_cfg = 0x4604, ++ .rst_idx = 0x4608, ++ .delay_irq = 0x460c, ++ .fc_th = 0x4610, ++ .int_grp = 0x4620, ++ .hred = 0x4644, ++ .ctx_ptr = 0x4700, ++ .dtx_ptr = 0x4704, ++ .crx_ptr = 0x4710, ++ .drx_ptr = 0x4714, ++ .fq_head = 0x4720, ++ .fq_tail = 0x4724, ++ .fq_count = 0x4728, ++ .fq_blen = 0x472c, ++ .tx_sch_rate = 0x4798, ++ }, ++ .gdm1_cnt = 0x1c00, ++ .gdma_to_ppe0 = 0x3333, ++ .ppe_base = 0x2200, ++ .wdma_base = { ++ [0] = 0x4800, ++ [1] = 0x4c00, ++ }, ++ .pse_iq_sta = 0x0180, ++ .pse_oq_sta = 0x01a0, ++}; ++ + /* strings used by ethtool */ + static const struct mtk_ethtool_stats { + char str[ETH_GSTRING_LEN]; +@@ -179,10 +227,54 @@ static const struct mtk_ethtool_stats { + }; + + static const char * const mtk_clks_source_name[] = { +- "ethif", "sgmiitop", "esw", "gp0", "gp1", "gp2", "fe", "trgpll", +- "sgmii_tx250m", "sgmii_rx250m", "sgmii_cdr_ref", "sgmii_cdr_fb", +- "sgmii2_tx250m", "sgmii2_rx250m", "sgmii2_cdr_ref", "sgmii2_cdr_fb", +- "sgmii_ck", "eth2pll", "wocpu0", "wocpu1", "netsys0", "netsys1" ++ "ethif", ++ "sgmiitop", ++ "esw", ++ "gp0", ++ "gp1", ++ "gp2", ++ "gp3", ++ "xgp1", ++ "xgp2", ++ "xgp3", ++ "crypto", ++ "fe", ++ "trgpll", ++ "sgmii_tx250m", ++ "sgmii_rx250m", ++ "sgmii_cdr_ref", ++ "sgmii_cdr_fb", ++ "sgmii2_tx250m", ++ "sgmii2_rx250m", ++ "sgmii2_cdr_ref", ++ "sgmii2_cdr_fb", ++ "sgmii_ck", ++ "eth2pll", ++ "wocpu0", ++ "wocpu1", ++ "netsys0", ++ "netsys1", ++ "ethwarp_wocpu2", ++ "ethwarp_wocpu1", ++ "ethwarp_wocpu0", ++ "top_usxgmii0_sel", ++ "top_usxgmii1_sel", ++ "top_sgm0_sel", ++ "top_sgm1_sel", ++ "top_xfi_phy0_xtal_sel", ++ "top_xfi_phy1_xtal_sel", ++ "top_eth_gmii_sel", ++ "top_eth_refck_50m_sel", ++ "top_eth_sys_200m_sel", ++ "top_eth_sys_sel", ++ "top_eth_xgmii_sel", ++ "top_eth_mii_sel", ++ "top_netsys_sel", ++ "top_netsys_500m_sel", ++ "top_netsys_pao_2x_sel", ++ "top_netsys_sync_250m_sel", ++ "top_netsys_ppefb_250m_sel", ++ "top_netsys_warp_sel", + }; + + void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg) +@@ -1207,10 +1299,19 @@ static void mtk_tx_set_dma_desc_v2(struc + data |= TX_DMA_LS0; + WRITE_ONCE(desc->txd3, data); + +- if (mac->id == MTK_GMAC3_ID) +- data = PSE_GDM3_PORT; +- else +- data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */ ++ /* set forward port */ ++ switch (mac->id) { ++ case MTK_GMAC1_ID: ++ data = PSE_GDM1_PORT << TX_DMA_FPORT_SHIFT_V2; ++ break; ++ case MTK_GMAC2_ID: ++ data = PSE_GDM2_PORT << TX_DMA_FPORT_SHIFT_V2; ++ break; ++ case MTK_GMAC3_ID: ++ data = PSE_GDM3_PORT << TX_DMA_FPORT_SHIFT_V2; ++ break; ++ } ++ + data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid); + WRITE_ONCE(desc->txd4, data); + +@@ -4964,6 +5065,25 @@ static const struct mtk_soc_data mt7986_ + }, + }; + ++static const struct mtk_soc_data mt7988_data = { ++ .reg_map = &mt7988_reg_map, ++ .ana_rgc3 = 0x128, ++ .caps = MT7988_CAPS, ++ .hw_features = MTK_HW_FEATURES, ++ .required_clks = MT7988_CLKS_BITMAP, ++ .required_pctl = false, ++ .num_devs = 3, ++ .txrx = { ++ .txd_size = sizeof(struct mtk_tx_dma_v2), ++ .rxd_size = sizeof(struct mtk_rx_dma_v2), ++ .rx_irq_done_mask = MTK_RX_DONE_INT_V2, ++ .rx_dma_l4_valid = RX_DMA_L4_VALID_V2, ++ .dma_max_len = MTK_TX_DMA_BUF_LEN_V2, ++ .dma_len_offset = 8, ++ }, ++}; ++ ++ + static const struct mtk_soc_data rt5350_data = { + .reg_map = &mt7628_reg_map, + .caps = MT7628_CAPS, +@@ -4982,14 +5102,15 @@ static const struct mtk_soc_data rt5350_ + }; + + const struct of_device_id of_mtk_match[] = { +- { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data}, +- { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data}, +- { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data}, +- { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data}, +- { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data}, +- { .compatible = "mediatek,mt7981-eth", .data = &mt7981_data}, +- { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data}, +- { .compatible = "ralink,rt5350-eth", .data = &rt5350_data}, ++ { .compatible = "mediatek,mt2701-eth", .data = &mt2701_data }, ++ { .compatible = "mediatek,mt7621-eth", .data = &mt7621_data }, ++ { .compatible = "mediatek,mt7622-eth", .data = &mt7622_data }, ++ { .compatible = "mediatek,mt7623-eth", .data = &mt7623_data }, ++ { .compatible = "mediatek,mt7629-eth", .data = &mt7629_data }, ++ { .compatible = "mediatek,mt7981-eth", .data = &mt7981_data }, ++ { .compatible = "mediatek,mt7986-eth", .data = &mt7986_data }, ++ { .compatible = "mediatek,mt7988-eth", .data = &mt7988_data }, ++ { .compatible = "ralink,rt5350-eth", .data = &rt5350_data }, + {}, + }; + MODULE_DEVICE_TABLE(of, of_mtk_match); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -116,7 +116,8 @@ + #define MTK_CDMP_EG_CTRL 0x404 + + /* GDM Exgress Control Register */ +-#define MTK_GDMA_FWD_CFG(x) (0x500 + (x * 0x1000)) ++#define MTK_GDMA_FWD_CFG(x) ((x == MTK_GMAC3_ID) ? \ ++ 0x540 : 0x500 + (x * 0x1000)) + #define MTK_GDMA_SPECIAL_TAG BIT(24) + #define MTK_GDMA_ICS_EN BIT(22) + #define MTK_GDMA_TCS_EN BIT(21) +@@ -650,6 +651,11 @@ enum mtk_clks_map { + MTK_CLK_GP0, + MTK_CLK_GP1, + MTK_CLK_GP2, ++ MTK_CLK_GP3, ++ MTK_CLK_XGP1, ++ MTK_CLK_XGP2, ++ MTK_CLK_XGP3, ++ MTK_CLK_CRYPTO, + MTK_CLK_FE, + MTK_CLK_TRGPLL, + MTK_CLK_SGMII_TX_250M, +@@ -666,57 +672,108 @@ enum mtk_clks_map { + MTK_CLK_WOCPU1, + MTK_CLK_NETSYS0, + MTK_CLK_NETSYS1, ++ MTK_CLK_ETHWARP_WOCPU2, ++ MTK_CLK_ETHWARP_WOCPU1, ++ MTK_CLK_ETHWARP_WOCPU0, ++ MTK_CLK_TOP_USXGMII_SBUS_0_SEL, ++ MTK_CLK_TOP_USXGMII_SBUS_1_SEL, ++ MTK_CLK_TOP_SGM_0_SEL, ++ MTK_CLK_TOP_SGM_1_SEL, ++ MTK_CLK_TOP_XFI_PHY_0_XTAL_SEL, ++ MTK_CLK_TOP_XFI_PHY_1_XTAL_SEL, ++ MTK_CLK_TOP_ETH_GMII_SEL, ++ MTK_CLK_TOP_ETH_REFCK_50M_SEL, ++ MTK_CLK_TOP_ETH_SYS_200M_SEL, ++ MTK_CLK_TOP_ETH_SYS_SEL, ++ MTK_CLK_TOP_ETH_XGMII_SEL, ++ MTK_CLK_TOP_ETH_MII_SEL, ++ MTK_CLK_TOP_NETSYS_SEL, ++ MTK_CLK_TOP_NETSYS_500M_SEL, ++ MTK_CLK_TOP_NETSYS_PAO_2X_SEL, ++ MTK_CLK_TOP_NETSYS_SYNC_250M_SEL, ++ MTK_CLK_TOP_NETSYS_PPEFB_250M_SEL, ++ MTK_CLK_TOP_NETSYS_WARP_SEL, + MTK_CLK_MAX + }; + +-#define MT7623_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \ +- BIT(MTK_CLK_GP1) | BIT(MTK_CLK_GP2) | \ +- BIT(MTK_CLK_TRGPLL)) +-#define MT7622_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \ +- BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \ +- BIT(MTK_CLK_GP2) | \ +- BIT(MTK_CLK_SGMII_TX_250M) | \ +- BIT(MTK_CLK_SGMII_RX_250M) | \ +- BIT(MTK_CLK_SGMII_CDR_REF) | \ +- BIT(MTK_CLK_SGMII_CDR_FB) | \ +- BIT(MTK_CLK_SGMII_CK) | \ +- BIT(MTK_CLK_ETH2PLL)) ++#define MT7623_CLKS_BITMAP (BIT_ULL(MTK_CLK_ETHIF) | BIT_ULL(MTK_CLK_ESW) | \ ++ BIT_ULL(MTK_CLK_GP1) | BIT_ULL(MTK_CLK_GP2) | \ ++ BIT_ULL(MTK_CLK_TRGPLL)) ++#define MT7622_CLKS_BITMAP (BIT_ULL(MTK_CLK_ETHIF) | BIT_ULL(MTK_CLK_ESW) | \ ++ BIT_ULL(MTK_CLK_GP0) | BIT_ULL(MTK_CLK_GP1) | \ ++ BIT_ULL(MTK_CLK_GP2) | \ ++ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_CDR_REF) | \ ++ BIT_ULL(MTK_CLK_SGMII_CDR_FB) | \ ++ BIT_ULL(MTK_CLK_SGMII_CK) | \ ++ BIT_ULL(MTK_CLK_ETH2PLL)) + #define MT7621_CLKS_BITMAP (0) + #define MT7628_CLKS_BITMAP (0) +-#define MT7629_CLKS_BITMAP (BIT(MTK_CLK_ETHIF) | BIT(MTK_CLK_ESW) | \ +- BIT(MTK_CLK_GP0) | BIT(MTK_CLK_GP1) | \ +- BIT(MTK_CLK_GP2) | BIT(MTK_CLK_FE) | \ +- BIT(MTK_CLK_SGMII_TX_250M) | \ +- BIT(MTK_CLK_SGMII_RX_250M) | \ +- BIT(MTK_CLK_SGMII_CDR_REF) | \ +- BIT(MTK_CLK_SGMII_CDR_FB) | \ +- BIT(MTK_CLK_SGMII2_TX_250M) | \ +- BIT(MTK_CLK_SGMII2_RX_250M) | \ +- BIT(MTK_CLK_SGMII2_CDR_REF) | \ +- BIT(MTK_CLK_SGMII2_CDR_FB) | \ +- BIT(MTK_CLK_SGMII_CK) | \ +- BIT(MTK_CLK_ETH2PLL) | BIT(MTK_CLK_SGMIITOP)) +-#define MT7981_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ +- BIT(MTK_CLK_WOCPU0) | \ +- BIT(MTK_CLK_SGMII_TX_250M) | \ +- BIT(MTK_CLK_SGMII_RX_250M) | \ +- BIT(MTK_CLK_SGMII_CDR_REF) | \ +- BIT(MTK_CLK_SGMII_CDR_FB) | \ +- BIT(MTK_CLK_SGMII2_TX_250M) | \ +- BIT(MTK_CLK_SGMII2_RX_250M) | \ +- BIT(MTK_CLK_SGMII2_CDR_REF) | \ +- BIT(MTK_CLK_SGMII2_CDR_FB) | \ +- BIT(MTK_CLK_SGMII_CK)) +-#define MT7986_CLKS_BITMAP (BIT(MTK_CLK_FE) | BIT(MTK_CLK_GP2) | BIT(MTK_CLK_GP1) | \ +- BIT(MTK_CLK_WOCPU1) | BIT(MTK_CLK_WOCPU0) | \ +- BIT(MTK_CLK_SGMII_TX_250M) | \ +- BIT(MTK_CLK_SGMII_RX_250M) | \ +- BIT(MTK_CLK_SGMII_CDR_REF) | \ +- BIT(MTK_CLK_SGMII_CDR_FB) | \ +- BIT(MTK_CLK_SGMII2_TX_250M) | \ +- BIT(MTK_CLK_SGMII2_RX_250M) | \ +- BIT(MTK_CLK_SGMII2_CDR_REF) | \ +- BIT(MTK_CLK_SGMII2_CDR_FB)) ++#define MT7629_CLKS_BITMAP (BIT_ULL(MTK_CLK_ETHIF) | BIT_ULL(MTK_CLK_ESW) | \ ++ BIT_ULL(MTK_CLK_GP0) | BIT_ULL(MTK_CLK_GP1) | \ ++ BIT_ULL(MTK_CLK_GP2) | BIT_ULL(MTK_CLK_FE) | \ ++ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_CDR_REF) | \ ++ BIT_ULL(MTK_CLK_SGMII_CDR_FB) | \ ++ BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII2_CDR_REF) | \ ++ BIT_ULL(MTK_CLK_SGMII2_CDR_FB) | \ ++ BIT_ULL(MTK_CLK_SGMII_CK) | \ ++ BIT_ULL(MTK_CLK_ETH2PLL) | BIT_ULL(MTK_CLK_SGMIITOP)) ++#define MT7981_CLKS_BITMAP (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_GP2) | BIT_ULL(MTK_CLK_GP1) | \ ++ BIT_ULL(MTK_CLK_WOCPU0) | \ ++ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_CDR_REF) | \ ++ BIT_ULL(MTK_CLK_SGMII_CDR_FB) | \ ++ BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII2_CDR_REF) | \ ++ BIT_ULL(MTK_CLK_SGMII2_CDR_FB) | \ ++ BIT_ULL(MTK_CLK_SGMII_CK)) ++#define MT7986_CLKS_BITMAP (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_GP2) | BIT_ULL(MTK_CLK_GP1) | \ ++ BIT_ULL(MTK_CLK_WOCPU1) | BIT_ULL(MTK_CLK_WOCPU0) | \ ++ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_CDR_REF) | \ ++ BIT_ULL(MTK_CLK_SGMII_CDR_FB) | \ ++ BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII2_CDR_REF) | \ ++ BIT_ULL(MTK_CLK_SGMII2_CDR_FB)) ++#define MT7988_CLKS_BITMAP (BIT_ULL(MTK_CLK_FE) | BIT_ULL(MTK_CLK_ESW) | \ ++ BIT_ULL(MTK_CLK_GP1) | BIT_ULL(MTK_CLK_GP2) | \ ++ BIT_ULL(MTK_CLK_GP3) | BIT_ULL(MTK_CLK_XGP1) | \ ++ BIT_ULL(MTK_CLK_XGP2) | BIT_ULL(MTK_CLK_XGP3) | \ ++ BIT_ULL(MTK_CLK_CRYPTO) | \ ++ BIT_ULL(MTK_CLK_SGMII_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII_RX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII2_TX_250M) | \ ++ BIT_ULL(MTK_CLK_SGMII2_RX_250M) | \ ++ BIT_ULL(MTK_CLK_ETHWARP_WOCPU2) | \ ++ BIT_ULL(MTK_CLK_ETHWARP_WOCPU1) | \ ++ BIT_ULL(MTK_CLK_ETHWARP_WOCPU0) | \ ++ BIT_ULL(MTK_CLK_TOP_USXGMII_SBUS_0_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_USXGMII_SBUS_1_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_SGM_0_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_SGM_1_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_XFI_PHY_0_XTAL_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_XFI_PHY_1_XTAL_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_GMII_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_REFCK_50M_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_SYS_200M_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_SYS_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_XGMII_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_ETH_MII_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_500M_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_PAO_2X_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_SYNC_250M_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_PPEFB_250M_SEL) | \ ++ BIT_ULL(MTK_CLK_TOP_NETSYS_WARP_SEL)) + + enum mtk_dev_state { + MTK_HW_INIT, +@@ -844,6 +901,7 @@ enum mkt_eth_capabilities { + MTK_RGMII_BIT = 0, + MTK_TRGMII_BIT, + MTK_SGMII_BIT, ++ MTK_USXGMII_BIT, + MTK_ESW_BIT, + MTK_GEPHY_BIT, + MTK_MUX_BIT, +@@ -866,6 +924,8 @@ enum mkt_eth_capabilities { + MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT, + MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT, + MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT, ++ MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT, ++ MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT, + + /* PATH BITS */ + MTK_ETH_PATH_GMAC1_RGMII_BIT, +@@ -874,13 +934,18 @@ enum mkt_eth_capabilities { + MTK_ETH_PATH_GMAC2_RGMII_BIT, + MTK_ETH_PATH_GMAC2_SGMII_BIT, + MTK_ETH_PATH_GMAC2_GEPHY_BIT, ++ MTK_ETH_PATH_GMAC3_SGMII_BIT, + MTK_ETH_PATH_GDM1_ESW_BIT, ++ MTK_ETH_PATH_GMAC1_USXGMII_BIT, ++ MTK_ETH_PATH_GMAC2_USXGMII_BIT, ++ MTK_ETH_PATH_GMAC3_USXGMII_BIT, + }; + + /* Supported hardware group on SoCs */ + #define MTK_RGMII BIT_ULL(MTK_RGMII_BIT) + #define MTK_TRGMII BIT_ULL(MTK_TRGMII_BIT) + #define MTK_SGMII BIT_ULL(MTK_SGMII_BIT) ++#define MTK_USXGMII BIT_ULL(MTK_USXGMII_BIT) + #define MTK_ESW BIT_ULL(MTK_ESW_BIT) + #define MTK_GEPHY BIT_ULL(MTK_GEPHY_BIT) + #define MTK_MUX BIT_ULL(MTK_MUX_BIT) +@@ -907,6 +972,10 @@ enum mkt_eth_capabilities { + BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT) + #define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \ + BIT_ULL(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT) ++#define MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII \ ++ BIT_ULL(MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT) ++#define MTK_ETH_MUX_GMAC123_TO_USXGMII \ ++ BIT_ULL(MTK_ETH_MUX_GMAC123_TO_USXGMII_BIT) + + /* Supported path present on SoCs */ + #define MTK_ETH_PATH_GMAC1_RGMII BIT_ULL(MTK_ETH_PATH_GMAC1_RGMII_BIT) +@@ -915,7 +984,11 @@ enum mkt_eth_capabilities { + #define MTK_ETH_PATH_GMAC2_RGMII BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT) + #define MTK_ETH_PATH_GMAC2_SGMII BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT) + #define MTK_ETH_PATH_GMAC2_GEPHY BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT) ++#define MTK_ETH_PATH_GMAC3_SGMII BIT_ULL(MTK_ETH_PATH_GMAC3_SGMII_BIT) + #define MTK_ETH_PATH_GDM1_ESW BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT) ++#define MTK_ETH_PATH_GMAC1_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC1_USXGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC2_USXGMII_BIT) ++#define MTK_ETH_PATH_GMAC3_USXGMII BIT_ULL(MTK_ETH_PATH_GMAC3_USXGMII_BIT) + + #define MTK_GMAC1_RGMII (MTK_ETH_PATH_GMAC1_RGMII | MTK_RGMII) + #define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII) +@@ -923,7 +996,11 @@ enum mkt_eth_capabilities { + #define MTK_GMAC2_RGMII (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII) + #define MTK_GMAC2_SGMII (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII) + #define MTK_GMAC2_GEPHY (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY) ++#define MTK_GMAC3_SGMII (MTK_ETH_PATH_GMAC3_SGMII | MTK_SGMII) + #define MTK_GDM1_ESW (MTK_ETH_PATH_GDM1_ESW | MTK_ESW) ++#define MTK_GMAC1_USXGMII (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII) ++#define MTK_GMAC2_USXGMII (MTK_ETH_PATH_GMAC2_USXGMII | MTK_USXGMII) ++#define MTK_GMAC3_USXGMII (MTK_ETH_PATH_GMAC3_USXGMII | MTK_USXGMII) + + /* MUXes present on SoCs */ + /* 0: GDM1 -> GMAC1, 1: GDM1 -> ESW */ +@@ -946,6 +1023,12 @@ enum mkt_eth_capabilities { + #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ + (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) + ++#define MTK_MUX_GMAC123_TO_GEPHY_SGMII \ ++ (MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII | MTK_MUX) ++ ++#define MTK_MUX_GMAC123_TO_USXGMII \ ++ (MTK_ETH_MUX_GMAC123_TO_USXGMII | MTK_MUX | MTK_INFRA) ++ + #ifdef CONFIG_SOC_MT7621 + #define MTK_CAP_MASK MTK_NETSYS_V2 + #else +@@ -984,9 +1067,17 @@ enum mkt_eth_capabilities { + MTK_MUX_U3_GMAC2_TO_QPHY | MTK_U3_COPHY_V2 | \ + MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) + +-#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ +- MTK_MUX_GMAC12_TO_GEPHY_SGMII | MTK_QDMA | \ +- MTK_NETSYS_V2 | MTK_RSTCTRL_PPE1) ++#define MT7986_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ ++ MTK_MUX_GMAC12_TO_GEPHY_SGMII | \ ++ MTK_QDMA | MTK_NETSYS_V2 | \ ++ MTK_RSTCTRL_PPE1) ++ ++#define MT7988_CAPS (MTK_GMAC1_SGMII | MTK_GMAC2_SGMII | \ ++ MTK_GMAC3_SGMII | MTK_QDMA | \ ++ MTK_MUX_GMAC123_TO_GEPHY_SGMII | \ ++ MTK_NETSYS_V3 | MTK_RSTCTRL_PPE1 | \ ++ MTK_GMAC1_USXGMII | MTK_GMAC2_USXGMII | \ ++ MTK_GMAC3_USXGMII | MTK_MUX_GMAC123_TO_USXGMII) + + struct mtk_tx_dma_desc_info { + dma_addr_t addr; +@@ -1072,7 +1163,7 @@ struct mtk_soc_data { + const struct mtk_reg_map *reg_map; + u32 ana_rgc3; + u64 caps; +- u32 required_clks; ++ u64 required_clks; + bool required_pctl; + u8 offload_version; + u8 hash_offset; diff --git a/target/linux/generic/pending-5.15/737-07-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch b/target/linux/generic/pending-5.15/737-07-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch new file mode 100644 index 00000000000..68170b6614b --- /dev/null +++ b/target/linux/generic/pending-5.15/737-07-net-ethernet-mtk_eth_soc-add-paths-and-SerDes-modes-.patch @@ -0,0 +1,1671 @@ +From 20ac14fedba025b6b336a821ea60660afe2d46cd Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Wed, 1 Mar 2023 11:56:04 +0000 +Subject: [PATCH 7/7] net: ethernet: mtk_eth_soc: add paths and SerDes modes + for MT7988 + +MT7988 comes with a built-in 2.5G PHY as well as USXGMII or 10Base-KR +compatible SerDes lanes for external PHYs. +Add support for configuring the MAC and SerDes parts for the new paths. + +Signed-off-by: Daniel Golle +--- + drivers/net/ethernet/mediatek/Makefile | 2 +- + drivers/net/ethernet/mediatek/mtk_eth_path.c | 154 ++++- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 291 +++++++- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 162 ++++- + drivers/net/ethernet/mediatek/mtk_usxgmii.c | 659 +++++++++++++++++++ + 5 files changed, 1236 insertions(+), 32 deletions(-) + create mode 100644 drivers/net/ethernet/mediatek/mtk_usxgmii.c + +--- a/drivers/net/ethernet/mediatek/Makefile ++++ b/drivers/net/ethernet/mediatek/Makefile +@@ -5,6 +5,7 @@ + + obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o + mtk_eth-y := mtk_eth_soc.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o ++mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_USXGMII) += mtk_usxgmii.o + mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o + ifdef CONFIG_DEBUG_FS + mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o +--- a/drivers/net/ethernet/mediatek/mtk_eth_path.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_path.c +@@ -31,10 +31,20 @@ static const char *mtk_eth_path_name(u64 + return "gmac2_rgmii"; + case MTK_ETH_PATH_GMAC2_SGMII: + return "gmac2_sgmii"; ++ case MTK_ETH_PATH_GMAC2_2P5GPHY: ++ return "gmac2_2p5gphy"; + case MTK_ETH_PATH_GMAC2_GEPHY: + return "gmac2_gephy"; ++ case MTK_ETH_PATH_GMAC3_SGMII: ++ return "gmac3_sgmii"; + case MTK_ETH_PATH_GDM1_ESW: + return "gdm1_esw"; ++ case MTK_ETH_PATH_GMAC1_USXGMII: ++ return "gmac1_usxgmii"; ++ case MTK_ETH_PATH_GMAC2_USXGMII: ++ return "gmac2_usxgmii"; ++ case MTK_ETH_PATH_GMAC3_USXGMII: ++ return "gmac3_usxgmii"; + default: + return "unknown path"; + } +@@ -42,8 +52,8 @@ static const char *mtk_eth_path_name(u64 + + static int set_mux_gdm1_to_gmac1_esw(struct mtk_eth *eth, u64 path) + { ++ u32 val, mask, set, reg; + bool updated = true; +- u32 val, mask, set; + + switch (path) { + case MTK_ETH_PATH_GMAC1_SGMII: +@@ -59,10 +69,15 @@ static int set_mux_gdm1_to_gmac1_esw(str + break; + } + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) ++ reg = MTK_MAC_MISC_V3; ++ else ++ reg = MTK_MAC_MISC; ++ + if (updated) { +- val = mtk_r32(eth, MTK_MAC_MISC); ++ val = mtk_r32(eth, reg); + val = (val & mask) | set; +- mtk_w32(eth, val, MTK_MAC_MISC); ++ mtk_w32(eth, val, reg); + } + + dev_dbg(eth->dev, "path %s in %s updated = %d\n", +@@ -125,6 +140,31 @@ static int set_mux_u3_gmac2_to_qphy(stru + return 0; + } + ++static int set_mux_gmac2_to_2p5gphy(struct mtk_eth *eth, u64 path) ++{ ++ unsigned int val = 0; ++ bool updated = true; ++ int mac_id = 0; ++ ++ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC2_2P5GPHY: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; ++ mac_id = MTK_GMAC2_ID; ++ break; ++ default: ++ updated = false; ++ break; ++ }; ++ ++ if (updated) ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, val); ++ ++ return 0; ++} ++ + static int set_mux_gmac1_gmac2_to_sgmii_rgmii(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0; +@@ -163,7 +203,61 @@ static int set_mux_gmac1_gmac2_to_sgmii_ + return 0; + } + +-static int set_mux_gmac12_to_gephy_sgmii(struct mtk_eth *eth, u64 path) ++static int set_mux_gmac123_to_usxgmii(struct mtk_eth *eth, u64 path) ++{ ++ unsigned int val = 0; ++ bool updated = true; ++ int mac_id = 0; ++ ++ dev_dbg(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name(path), __func__, updated); ++ ++ /* Disable SYSCFG1 SGMII */ ++ regmap_read(eth->ethsys, ETHSYS_SYSCFG0, &val); ++ ++ switch (path) { ++ case MTK_ETH_PATH_GMAC1_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC1_V2; ++ mac_id = MTK_GMAC1_ID; ++ break; ++ case MTK_ETH_PATH_GMAC2_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC2_V2; ++ mac_id = MTK_GMAC2_ID; ++ break; ++ case MTK_ETH_PATH_GMAC3_USXGMII: ++ val &= ~(u32)SYSCFG0_SGMII_GMAC3_V2; ++ mac_id = MTK_GMAC3_ID; ++ break; ++ default: ++ updated = false; ++ }; ++ ++ if (updated) { ++ regmap_update_bits(eth->ethsys, ETHSYS_SYSCFG0, ++ SYSCFG0_SGMII_MASK, val); ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) && ++ mac_id == MTK_GMAC2_ID) { ++ regmap_update_bits(eth->infra, ++ TOP_MISC_NETSYS_PCS_MUX, ++ NETSYS_PCS_MUX_MASK, ++ MUX_G2_USXGMII_SEL); ++ } ++ } ++ ++ /* Enable XGDM Path */ ++ val = mtk_r32(eth, MTK_GDMA_EG_CTRL(mac_id)); ++ val |= MTK_GDMA_XGDM_SEL; ++ mtk_w32(eth, val, MTK_GDMA_EG_CTRL(mac_id)); ++ ++ dev_dbg(eth->dev, "path %s in %s updated = %d\n", ++ mtk_eth_path_name(path), __func__, updated); ++ ++ ++ return 0; ++} ++ ++static int set_mux_gmac123_to_gephy_sgmii(struct mtk_eth *eth, u64 path) + { + unsigned int val = 0; + bool updated = true; +@@ -180,6 +274,9 @@ static int set_mux_gmac12_to_gephy_sgmii + case MTK_ETH_PATH_GMAC2_SGMII: + val |= SYSCFG0_SGMII_GMAC2_V2; + break; ++ case MTK_ETH_PATH_GMAC3_SGMII: ++ val |= SYSCFG0_SGMII_GMAC3_V2; ++ break; + default: + updated = false; + } +@@ -208,13 +305,25 @@ static const struct mtk_eth_muxc mtk_eth + .cap_bit = MTK_ETH_MUX_U3_GMAC2_TO_QPHY, + .set_path = set_mux_u3_gmac2_to_qphy, + }, { ++ .name = "mux_gmac2_to_2p5gphy", ++ .cap_bit = MTK_ETH_MUX_GMAC2_TO_2P5GPHY, ++ .set_path = set_mux_gmac2_to_2p5gphy, ++ }, { + .name = "mux_gmac1_gmac2_to_sgmii_rgmii", + .cap_bit = MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII, + .set_path = set_mux_gmac1_gmac2_to_sgmii_rgmii, + }, { + .name = "mux_gmac12_to_gephy_sgmii", + .cap_bit = MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII, +- .set_path = set_mux_gmac12_to_gephy_sgmii, ++ .set_path = set_mux_gmac123_to_gephy_sgmii, ++ }, { ++ .name = "mux_gmac123_to_gephy_sgmii", ++ .cap_bit = MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII, ++ .set_path = set_mux_gmac123_to_gephy_sgmii, ++ }, { ++ .name = "mux_gmac123_to_usxgmii", ++ .cap_bit = MTK_ETH_MUX_GMAC123_TO_USXGMII, ++ .set_path = set_mux_gmac123_to_usxgmii, + }, + }; + +@@ -243,16 +352,46 @@ static int mtk_eth_mux_setup(struct mtk_ + } + } + ++ dev_dbg(eth->dev, "leaving mux_setup %s\n", ++ mtk_eth_path_name(path)); ++ + out: + return err; + } + ++int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id) ++{ ++ u64 path; ++ ++ path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_USXGMII : ++ (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_USXGMII : ++ MTK_ETH_PATH_GMAC3_USXGMII; ++ ++ /* Setup proper MUXes along the path */ ++ return mtk_eth_mux_setup(eth, path); ++} ++ + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id) + { + u64 path; + +- path = (mac_id == 0) ? MTK_ETH_PATH_GMAC1_SGMII : +- MTK_ETH_PATH_GMAC2_SGMII; ++ path = (mac_id == MTK_GMAC1_ID) ? MTK_ETH_PATH_GMAC1_SGMII : ++ (mac_id == MTK_GMAC2_ID) ? MTK_ETH_PATH_GMAC2_SGMII : ++ MTK_ETH_PATH_GMAC3_SGMII; ++ ++ /* Setup proper MUXes along the path */ ++ return mtk_eth_mux_setup(eth, path); ++} ++ ++int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id) ++{ ++ u64 path = 0; ++ ++ if (mac_id == MTK_GMAC2_ID) ++ path = MTK_ETH_PATH_GMAC2_2P5GPHY; ++ ++ if (!path) ++ return -EINVAL; + + /* Setup proper MUXes along the path */ + return mtk_eth_mux_setup(eth, path); +@@ -282,4 +421,3 @@ int mtk_gmac_rgmii_path_setup(struct mtk + /* Setup proper MUXes along the path */ + return mtk_eth_mux_setup(eth, path); + } +- +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -437,6 +437,23 @@ static void mtk_gmac0_rgmii_adjust(struc + mtk_w32(eth, val, TRGMII_TCK_CTRL); + } + ++static void mtk_setup_bridge_switch(struct mtk_eth *eth) ++{ ++ int val; ++ ++ /* Force Port1 XGMAC Link Up */ ++ val = mtk_r32(eth, MTK_XGMAC_STS(MTK_GMAC1_ID)); ++ mtk_w32(eth, val | MTK_XGMAC_FORCE_LINK(MTK_GMAC1_ID), ++ MTK_XGMAC_STS(MTK_GMAC1_ID)); ++ ++ /* Adjust GSW bridge IPG to 11*/ ++ val = mtk_r32(eth, MTK_GSW_CFG); ++ val &= ~(GSWTX_IPG_MASK | GSWRX_IPG_MASK); ++ val |= (GSW_IPG_11 << GSWTX_IPG_SHIFT) | ++ (GSW_IPG_11 << GSWRX_IPG_SHIFT); ++ mtk_w32(eth, val, MTK_GSW_CFG); ++} ++ + static struct phylink_pcs *mtk_mac_select_pcs(struct phylink_config *config, + phy_interface_t interface) + { +@@ -462,7 +479,7 @@ static void mtk_mac_config(struct phylin + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); + struct mtk_eth *eth = mac->hw; +- int val, ge_mode, err = 0; ++ int val, ge_mode, force_link, err = 0; + u32 i; + + /* MT76x8 has no hardware settings between for the MAC */ +@@ -506,6 +523,23 @@ static void mtk_mac_config(struct phylin + goto init_err; + } + break; ++ case PHY_INTERFACE_MODE_USXGMII: ++ case PHY_INTERFACE_MODE_10GKR: ++ case PHY_INTERFACE_MODE_5GBASER: ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) { ++ err = mtk_gmac_usxgmii_path_setup(eth, mac->id); ++ if (err) ++ goto init_err; ++ } ++ break; ++ case PHY_INTERFACE_MODE_INTERNAL: ++ if (mac->id == MTK_GMAC2_ID && ++ MTK_HAS_CAPS(eth->soc->caps, MTK_2P5GPHY)) { ++ err = mtk_gmac_2p5gphy_path_setup(eth, mac->id); ++ if (err) ++ goto init_err; ++ } ++ break; + default: + goto err_phy; + } +@@ -584,14 +618,92 @@ static void mtk_mac_config(struct phylin + SYSCFG0_SGMII_MASK, + ~(u32)SYSCFG0_SGMII_MASK); + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) { ++ mtk_xfi_pll_enable(eth); ++ mtk_sgmii_reset(eth, mac->id); ++ if (phylink_autoneg_inband(mode)) ++ mtk_sgmii_setup_phya_gen1(eth, mac->id); ++ else ++ mtk_sgmii_setup_phya_gen2(eth, mac->id); ++ } + /* Save the syscfg0 value for mac_finish */ + mac->syscfg0 = val; ++ } else if (state->interface == PHY_INTERFACE_MODE_USXGMII || ++ state->interface == PHY_INTERFACE_MODE_10GKR || ++ state->interface == PHY_INTERFACE_MODE_5GBASER) { ++ ++ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) { ++ err = -EINVAL; ++ goto init_err; ++ } ++ if (phylink_autoneg_inband(mode)) ++ err = mtk_usxgmii_setup_mode_force(eth, mac->id, ++ state); ++ else ++ err = mtk_usxgmii_setup_mode_an(eth, mac->id, ++ SPEED_10000); ++ ++ if (err) ++ goto init_err; + } else if (phylink_autoneg_inband(mode)) { + dev_err(eth->dev, + "In-band mode not supported in non SGMII mode!\n"); + return; + } + ++ /* Setup gmac */ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3) && ++ (mtk_interface_mode_is_xgmii(state->interface) || ++ mac->interface == PHY_INTERFACE_MODE_INTERNAL)) { ++ mtk_w32(mac->hw, MTK_GDMA_XGDM_SEL, MTK_GDMA_EG_CTRL(mac->id)); ++ mtk_w32(mac->hw, MAC_MCR_FORCE_LINK_DOWN, MTK_MAC_MCR(mac->id)); ++ ++ switch (mac->id) { ++ case MTK_GMAC1_ID: ++ mtk_setup_bridge_switch(eth); ++ break; ++ case MTK_GMAC2_ID: ++ force_link = (mac->interface == ++ PHY_INTERFACE_MODE_INTERNAL) ? ++ MTK_XGMAC_FORCE_LINK(mac->id) : 0; ++ val = mtk_r32(eth, MTK_XGMAC_STS(mac->id)); ++ mtk_w32(eth, val | force_link, ++ MTK_XGMAC_STS(mac->id)); ++ break; ++ case MTK_GMAC3_ID: ++ val = mtk_r32(eth, MTK_XGMAC_STS(mac->id)); ++ mtk_w32(eth, val | MTK_XGMAC_FORCE_LINK(mac->id), ++ MTK_XGMAC_STS(mac->id)); ++ break; ++ } ++ } else { ++ val = mtk_r32(eth, MTK_GDMA_EG_CTRL(mac->id)); ++ mtk_w32(eth, val & ~MTK_GDMA_XGDM_SEL, ++ MTK_GDMA_EG_CTRL(mac->id)); ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) { ++ switch (mac->id) { ++ case MTK_GMAC2_ID: ++ case MTK_GMAC3_ID: ++ val = mtk_r32(eth, MTK_XGMAC_STS(mac->id)); ++ mtk_w32(eth, ++ val & ~MTK_XGMAC_FORCE_LINK(mac->id), ++ MTK_XGMAC_STS(mac->id)); ++ break; ++ } ++ } ++ ++/* ++ if (mac->type != mac_type) { ++ if (atomic_read(&reset_pending) == 0) { ++ atomic_inc(&force); ++ schedule_work(ð->pending_work); ++ atomic_inc(&reset_pending); ++ } else ++ atomic_dec(&reset_pending); ++ } ++*/ ++ } + return; + + err_phy: +@@ -632,11 +744,37 @@ static int mtk_mac_finish(struct phylink + return 0; + } + +-static void mtk_mac_pcs_get_state(struct phylink_config *config, ++static void mtk_xgdm_pcs_get_state(struct mtk_mac *mac, ++ struct phylink_link_state *state) ++{ ++ u32 sts = mtk_r32(mac->hw, MTK_XGMAC_STS(mac->id)); ++ ++ if (mac->id == MTK_GMAC2_ID) ++ sts = sts >> 16; ++ ++ state->duplex = 1; ++ ++ switch (FIELD_GET(MTK_USXGMII_PCS_MODE, sts)) { ++ case 0: ++ state->speed = SPEED_10000; ++ break; ++ case 1: ++ state->speed = SPEED_5000; ++ break; ++ case 2: ++ state->speed = SPEED_2500; ++ break; ++ case 3: ++ state->speed = SPEED_1000; ++ break; ++ } ++ ++ state->link = FIELD_GET(MTK_USXGMII_PCS_LINK, sts); ++} ++ ++static void mtk_gdm_pcs_get_state(struct mtk_mac *mac, + struct phylink_link_state *state) + { +- struct mtk_mac *mac = container_of(config, struct mtk_mac, +- phylink_config); + u32 pmsr = mtk_r32(mac->hw, MTK_MAC_MSR(mac->id)); + + state->link = (pmsr & MAC_MSR_LINK); +@@ -664,15 +802,35 @@ static void mtk_mac_pcs_get_state(struct + state->pause |= MLO_PAUSE_TX; + } + ++static void mtk_mac_pcs_get_state(struct phylink_config *config, ++ struct phylink_link_state *state) ++{ ++ struct mtk_mac *mac = container_of(config, struct mtk_mac, ++ phylink_config); ++ ++ if (mtk_interface_mode_is_xgmii(state->interface)) ++ mtk_xgdm_pcs_get_state(mac, state); ++ else ++ mtk_gdm_pcs_get_state(mac, state); ++} ++ + static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) + { + struct mtk_mac *mac = container_of(config, struct mtk_mac, + phylink_config); +- u32 mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); ++ u32 mcr; + +- mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN); +- mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); ++ if (!mtk_interface_mode_is_xgmii(interface)) { ++ mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); ++ mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN); ++ mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); ++ } else if (mac->id != MTK_GMAC1_ID) { ++ mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id)); ++ mcr &= 0xfffffff0; ++ mcr |= XMAC_MCR_TRX_DISABLE; ++ mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id)); ++ } + } + + static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx, +@@ -744,13 +902,11 @@ static void mtk_set_queue_speed(struct m + mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs); + } + +-static void mtk_mac_link_up(struct phylink_config *config, +- struct phy_device *phy, +- unsigned int mode, phy_interface_t interface, +- int speed, int duplex, bool tx_pause, bool rx_pause) ++static void mtk_gdm_mac_link_up(struct mtk_mac *mac, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) + { +- struct mtk_mac *mac = container_of(config, struct mtk_mac, +- phylink_config); + u32 mcr; + + mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); +@@ -784,6 +940,47 @@ static void mtk_mac_link_up(struct phyli + mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id)); + } + ++static void mtk_xgdm_mac_link_up(struct mtk_mac *mac, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++ u32 mcr; ++ ++ if (mac->id == MTK_GMAC1_ID) ++ return; ++ ++ mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id)); ++ ++ mcr &= ~(XMAC_MCR_FORCE_TX_FC | XMAC_MCR_FORCE_RX_FC); ++ /* Configure pause modes - ++ * phylink will avoid these for half duplex ++ */ ++ if (tx_pause) ++ mcr |= XMAC_MCR_FORCE_TX_FC; ++ if (rx_pause) ++ mcr |= XMAC_MCR_FORCE_RX_FC; ++ ++ mcr &= ~(XMAC_MCR_TRX_DISABLE); ++ mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id)); ++} ++ ++static void mtk_mac_link_up(struct phylink_config *config, ++ struct phy_device *phy, ++ unsigned int mode, phy_interface_t interface, ++ int speed, int duplex, bool tx_pause, bool rx_pause) ++{ ++ struct mtk_mac *mac = container_of(config, struct mtk_mac, ++ phylink_config); ++ ++ if (mtk_interface_mode_is_xgmii(interface)) ++ mtk_xgdm_mac_link_up(mac, phy, mode, interface, speed, duplex, ++ tx_pause, rx_pause); ++ else ++ mtk_gdm_mac_link_up(mac, phy, mode, interface, speed, duplex, ++ tx_pause, rx_pause); ++} ++ + static const struct phylink_mac_ops mtk_phylink_ops = { + .validate = phylink_generic_validate, + .mac_select_pcs = mtk_mac_select_pcs, +@@ -836,10 +1033,21 @@ static int mtk_mdio_init(struct mtk_eth + } + divider = min_t(unsigned int, DIV_ROUND_UP(MDC_MAX_FREQ, max_clk), 63); + ++ /* Configure MDC Turbo Mode */ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) { ++ val = mtk_r32(eth, MTK_MAC_MISC_V3); ++ val |= MISC_MDC_TURBO; ++ mtk_w32(eth, val, MTK_MAC_MISC_V3); ++ } else { ++ val = mtk_r32(eth, MTK_PPSC); ++ val |= PPSC_MDC_TURBO; ++ mtk_w32(eth, val, MTK_PPSC); ++ } ++ + /* Configure MDC Divider */ + val = mtk_r32(eth, MTK_PPSC); + val &= ~PPSC_MDC_CFG; +- val |= FIELD_PREP(PPSC_MDC_CFG, divider) | PPSC_MDC_TURBO; ++ val |= FIELD_PREP(PPSC_MDC_CFG, divider); + mtk_w32(eth, val, MTK_PPSC); + + dev_dbg(eth->dev, "MDC is running on %d Hz\n", MDC_MAX_FREQ / divider); +@@ -4433,8 +4641,8 @@ static int mtk_add_mac(struct mtk_eth *e + const __be32 *_id = of_get_property(np, "reg", NULL); + phy_interface_t phy_mode; + struct phylink *phylink; +- struct mtk_mac *mac; + int id, err; ++ struct mtk_mac *mac; + int txqs = 1; + + if (!_id) { +@@ -4525,6 +4733,32 @@ static int mtk_add_mac(struct mtk_eth *e + mac->phylink_config.supported_interfaces); + } + ++ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_USXGMII)) { ++ if (id == MTK_GMAC1_ID) { ++ mac->phylink_config.mac_capabilities = MAC_ASYM_PAUSE | ++ MAC_SYM_PAUSE | ++ MAC_10000FD; ++ phy_interface_zero( ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_INTERNAL, ++ mac->phylink_config.supported_interfaces); ++ } else { ++ mac->phylink_config.mac_capabilities |= MAC_5000FD | MAC_10000FD; ++ __set_bit(PHY_INTERFACE_MODE_5GBASER, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_10GKR, ++ mac->phylink_config.supported_interfaces); ++ __set_bit(PHY_INTERFACE_MODE_USXGMII, ++ mac->phylink_config.supported_interfaces); ++ } ++ } ++ ++ if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY)) { ++ if (id == MTK_GMAC2_ID) ++ __set_bit(PHY_INTERFACE_MODE_INTERNAL, ++ mac->phylink_config.supported_interfaces); ++ } ++ + phylink = phylink_create(&mac->phylink_config, + of_fwnode_handle(mac->of_node), + phy_mode, &mtk_phylink_ops); +@@ -4714,6 +4948,33 @@ static int mtk_probe(struct platform_dev + return err; + } + ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_USXGMII)) { ++ eth->xgmii = devm_kzalloc(eth->dev, sizeof(*eth->xgmii), GFP_KERNEL); ++ err = mtk_usxgmii_init(eth); ++ if (err) { ++ dev_err(&pdev->dev, "usxgmii init failed\n"); ++ return err; ++ } ++ ++ err = mtk_xfi_pextp_init(eth); ++ if (err) { ++ dev_err(&pdev->dev, "pextp init failed\n"); ++ return err; ++ } ++ ++ err = mtk_xfi_pll_init(eth); ++ if (err) { ++ dev_err(&pdev->dev, "xfi pll init failed\n"); ++ return err; ++ } ++ ++ err = mtk_toprgu_init(eth); ++ if (err) { ++ dev_err(&pdev->dev, "toprgu init failed\n"); ++ return err; ++ } ++ } ++ + if (eth->soc->required_pctl) { + eth->pctl = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "mediatek,pctl"); +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -126,6 +126,11 @@ + #define MTK_GDMA_TO_PDMA 0x0 + #define MTK_GDMA_DROP_ALL 0x7777 + ++/* GDM Egress Control Register */ ++#define MTK_GDMA_EG_CTRL(x) ((x == MTK_GMAC3_ID) ? \ ++ 0x544 : 0x504 + (x * 0x1000)) ++#define MTK_GDMA_XGDM_SEL BIT(31) ++ + /* Unicast Filter MAC Address Register - Low */ + #define MTK_GDMA_MAC_ADRL(x) (0x508 + (x * 0x1000)) + +@@ -386,7 +391,26 @@ + #define PHY_IAC_TIMEOUT HZ + + #define MTK_MAC_MISC 0x1000c ++#define MTK_MAC_MISC_V3 0x10010 + #define MTK_MUX_TO_ESW BIT(0) ++#define MISC_MDC_TURBO BIT(4) ++ ++/* XMAC status registers */ ++#define MTK_XGMAC_STS(x) ((x == MTK_GMAC3_ID) ? 0x1001C : 0x1000C) ++#define MTK_XGMAC_FORCE_LINK(x) ((x == MTK_GMAC2_ID) ? BIT(31) : BIT(15)) ++#define MTK_USXGMII_PCS_LINK BIT(8) ++#define MTK_XGMAC_RX_FC BIT(5) ++#define MTK_XGMAC_TX_FC BIT(4) ++#define MTK_USXGMII_PCS_MODE GENMASK(3, 1) ++#define MTK_XGMAC_LINK_STS BIT(0) ++ ++/* GSW bridge registers */ ++#define MTK_GSW_CFG (0x10080) ++#define GSWTX_IPG_MASK GENMASK(19, 16) ++#define GSWTX_IPG_SHIFT 16 ++#define GSWRX_IPG_MASK GENMASK(3, 0) ++#define GSWRX_IPG_SHIFT 0 ++#define GSW_IPG_11 11 + + /* Mac control registers */ + #define MTK_MAC_MCR(x) (0x10100 + (x * 0x100)) +@@ -411,6 +435,17 @@ + #define MAC_MCR_FORCE_LINK BIT(0) + #define MAC_MCR_FORCE_LINK_DOWN (MAC_MCR_FORCE_MODE) + ++/* Mac EEE control registers */ ++#define MTK_MAC_EEE(x) (0x10104 + (x * 0x100)) ++#define MAC_EEE_WAKEUP_TIME_1000 GENMASK(31, 24) ++#define MAC_EEE_WAKEUP_TIME_100 GENMASK(23, 16) ++#define MAC_EEE_LPI_TXIDLE_THD GENMASK(15, 8) ++#define MAC_EEE_RESV0 GENMASK(7, 4) ++#define MAC_EEE_CKG_TXILDE BIT(3) ++#define MAC_EEE_CKG_RXLPI BIT(2) ++#define MAC_EEE_TX_DOWN_REQ BIT(1) ++#define MAC_EEE_LPI_MODE BIT(0) ++ + /* Mac status registers */ + #define MTK_MAC_MSR(x) (0x10108 + (x * 0x100)) + #define MAC_MSR_EEE1G BIT(7) +@@ -455,6 +490,12 @@ + #define INTF_MODE_RGMII_1000 (TRGMII_MODE | TRGMII_CENTRAL_ALIGNED) + #define INTF_MODE_RGMII_10_100 0 + ++/* XFI Mac control registers */ ++#define MTK_XMAC_MCR(x) (0x12000 + ((x - 1) * 0x1000)) ++#define XMAC_MCR_TRX_DISABLE 0xf ++#define XMAC_MCR_FORCE_TX_FC BIT(5) ++#define XMAC_MCR_FORCE_RX_FC BIT(4) ++ + /* GPIO port control registers for GMAC 2*/ + #define GPIO_OD33_CTRL8 0x4c0 + #define GPIO_BIAS_CTRL 0xed0 +@@ -480,6 +521,7 @@ + #define SYSCFG0_SGMII_GMAC2 ((3 << 8) & SYSCFG0_SGMII_MASK) + #define SYSCFG0_SGMII_GMAC1_V2 BIT(9) + #define SYSCFG0_SGMII_GMAC2_V2 BIT(8) ++#define SYSCFG0_SGMII_GMAC3_V2 BIT(7) + + + /* ethernet subsystem clock register */ +@@ -506,16 +548,69 @@ + #define ETHSYS_DMA_AG_MAP_QDMA BIT(1) + #define ETHSYS_DMA_AG_MAP_PPE BIT(2) + ++/* USXGMII subsystem config registers */ ++/* Register to control speed */ ++#define RG_PHY_TOP_SPEED_CTRL1 0x80C ++#define RG_USXGMII_RATE_UPDATE_MODE BIT(31) ++#define RG_MAC_CK_GATED BIT(29) ++#define RG_IF_FORCE_EN BIT(28) ++#define RG_RATE_ADAPT_MODE GENMASK(10, 8) ++#define RG_RATE_ADAPT_MODE_X1 0 ++#define RG_RATE_ADAPT_MODE_X2 1 ++#define RG_RATE_ADAPT_MODE_X4 2 ++#define RG_RATE_ADAPT_MODE_X10 3 ++#define RG_RATE_ADAPT_MODE_X100 4 ++#define RG_RATE_ADAPT_MODE_X5 5 ++#define RG_RATE_ADAPT_MODE_X50 6 ++#define RG_XFI_RX_MODE GENMASK(6, 4) ++#define RG_XFI_RX_MODE_10G 0 ++#define RG_XFI_RX_MODE_5G 1 ++#define RG_XFI_TX_MODE GENMASK(2, 0) ++#define RG_XFI_TX_MODE_10G 0 ++#define RG_XFI_TX_MODE_5G 1 ++ ++/* Register to control PCS AN */ ++#define RG_PCS_AN_CTRL0 0x810 ++#define RG_AN_ENABLE BIT(0) ++ ++/* Register to control USXGMII XFI PLL digital */ ++#define XFI_PLL_DIG_GLB8 0x08 ++#define RG_XFI_PLL_EN BIT(31) ++ ++/* Register to control USXGMII XFI PLL analog */ ++#define XFI_PLL_ANA_GLB8 0x108 ++#define RG_XFI_PLL_ANA_SWWA 0x02283248 ++ + /* Infrasys subsystem config registers */ + #define INFRA_MISC2 0x70c + #define CO_QPHY_SEL BIT(0) + #define GEPHY_MAC_SEL BIT(1) + ++/* Toprgu subsystem config registers */ ++#define TOPRGU_SWSYSRST 0x18 ++#define SWSYSRST_UNLOCK_KEY GENMASK(31, 24) ++#define SWSYSRST_XFI_PLL_GRST BIT(16) ++#define SWSYSRST_XFI_PEXPT1_GRST BIT(15) ++#define SWSYSRST_XFI_PEXPT0_GRST BIT(14) ++#define SWSYSRST_SGMII1_GRST BIT(2) ++#define SWSYSRST_SGMII0_GRST BIT(1) ++#define TOPRGU_SWSYSRST_EN 0xFC ++ + /* Top misc registers */ ++#define TOP_MISC_NETSYS_PCS_MUX 0x84 ++#define NETSYS_PCS_MUX_MASK GENMASK(1, 0) ++#define MUX_G2_USXGMII_SEL BIT(1) ++#define MUX_HSGMII1_G1_SEL BIT(0) ++ + #define USB_PHY_SWITCH_REG 0x218 + #define QPHY_SEL_MASK GENMASK(1, 0) + #define SGMII_QPHY_SEL 0x2 + ++/* MDIO control */ ++#define MII_MMD_ACC_CTL_REG 0x0d ++#define MII_MMD_ADDR_DATA_REG 0x0e ++#define MMD_OP_MODE_DATA BIT(14) ++ + /* MT7628/88 specific stuff */ + #define MT7628_PDMA_OFFSET 0x0800 + #define MT7628_SDM_OFFSET 0x0c00 +@@ -809,13 +904,6 @@ enum mtk_gmac_id { + MTK_GMAC_ID_MAX + }; + +-/* GDM Type */ +-enum mtk_gdm_type { +- MTK_GDM_TYPE = 0, +- MTK_XGDM_TYPE, +- MTK_GDM_TYPE_MAX +-}; +- + enum mtk_tx_buf_type { + MTK_TYPE_SKB, + MTK_TYPE_XDP_TX, +@@ -902,6 +990,7 @@ enum mkt_eth_capabilities { + MTK_TRGMII_BIT, + MTK_SGMII_BIT, + MTK_USXGMII_BIT, ++ MTK_2P5GPHY_BIT, + MTK_ESW_BIT, + MTK_GEPHY_BIT, + MTK_MUX_BIT, +@@ -922,6 +1011,7 @@ enum mkt_eth_capabilities { + MTK_ETH_MUX_GDM1_TO_GMAC1_ESW_BIT, + MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT, + MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT, ++ MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT, + MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT, + MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII_BIT, + MTK_ETH_MUX_GMAC123_TO_GEPHY_SGMII_BIT, +@@ -933,6 +1023,7 @@ enum mkt_eth_capabilities { + MTK_ETH_PATH_GMAC1_SGMII_BIT, + MTK_ETH_PATH_GMAC2_RGMII_BIT, + MTK_ETH_PATH_GMAC2_SGMII_BIT, ++ MTK_ETH_PATH_GMAC2_2P5GPHY_BIT, + MTK_ETH_PATH_GMAC2_GEPHY_BIT, + MTK_ETH_PATH_GMAC3_SGMII_BIT, + MTK_ETH_PATH_GDM1_ESW_BIT, +@@ -946,6 +1037,7 @@ enum mkt_eth_capabilities { + #define MTK_TRGMII BIT_ULL(MTK_TRGMII_BIT) + #define MTK_SGMII BIT_ULL(MTK_SGMII_BIT) + #define MTK_USXGMII BIT_ULL(MTK_USXGMII_BIT) ++#define MTK_2P5GPHY BIT_ULL(MTK_2P5GPHY_BIT) + #define MTK_ESW BIT_ULL(MTK_ESW_BIT) + #define MTK_GEPHY BIT_ULL(MTK_GEPHY_BIT) + #define MTK_MUX BIT_ULL(MTK_MUX_BIT) +@@ -968,6 +1060,8 @@ enum mkt_eth_capabilities { + BIT_ULL(MTK_ETH_MUX_GMAC2_GMAC0_TO_GEPHY_BIT) + #define MTK_ETH_MUX_U3_GMAC2_TO_QPHY \ + BIT_ULL(MTK_ETH_MUX_U3_GMAC2_TO_QPHY_BIT) ++#define MTK_ETH_MUX_GMAC2_TO_2P5GPHY \ ++ BIT_ULL(MTK_ETH_MUX_GMAC2_TO_2P5GPHY_BIT) + #define MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII \ + BIT_ULL(MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII_BIT) + #define MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII \ +@@ -983,6 +1077,7 @@ enum mkt_eth_capabilities { + #define MTK_ETH_PATH_GMAC1_SGMII BIT_ULL(MTK_ETH_PATH_GMAC1_SGMII_BIT) + #define MTK_ETH_PATH_GMAC2_RGMII BIT_ULL(MTK_ETH_PATH_GMAC2_RGMII_BIT) + #define MTK_ETH_PATH_GMAC2_SGMII BIT_ULL(MTK_ETH_PATH_GMAC2_SGMII_BIT) ++#define MTK_ETH_PATH_GMAC2_2P5GPHY BIT_ULL(MTK_ETH_PATH_GMAC2_2P5GPHY_BIT) + #define MTK_ETH_PATH_GMAC2_GEPHY BIT_ULL(MTK_ETH_PATH_GMAC2_GEPHY_BIT) + #define MTK_ETH_PATH_GMAC3_SGMII BIT_ULL(MTK_ETH_PATH_GMAC3_SGMII_BIT) + #define MTK_ETH_PATH_GDM1_ESW BIT_ULL(MTK_ETH_PATH_GDM1_ESW_BIT) +@@ -996,6 +1091,7 @@ enum mkt_eth_capabilities { + #define MTK_GMAC2_RGMII (MTK_ETH_PATH_GMAC2_RGMII | MTK_RGMII) + #define MTK_GMAC2_SGMII (MTK_ETH_PATH_GMAC2_SGMII | MTK_SGMII) + #define MTK_GMAC2_GEPHY (MTK_ETH_PATH_GMAC2_GEPHY | MTK_GEPHY) ++#define MTK_GMAC2_2P5GPHY (MTK_ETH_PATH_GMAC2_2P5GPHY | MTK_2P5GPHY) + #define MTK_GMAC3_SGMII (MTK_ETH_PATH_GMAC3_SGMII | MTK_SGMII) + #define MTK_GDM1_ESW (MTK_ETH_PATH_GDM1_ESW | MTK_ESW) + #define MTK_GMAC1_USXGMII (MTK_ETH_PATH_GMAC1_USXGMII | MTK_USXGMII) +@@ -1019,6 +1115,10 @@ enum mkt_eth_capabilities { + (MTK_ETH_MUX_GMAC1_GMAC2_TO_SGMII_RGMII | MTK_MUX | \ + MTK_SHARED_SGMII) + ++/* 2: GMAC2 -> XGMII */ ++#define MTK_MUX_GMAC2_TO_2P5GPHY \ ++ (MTK_ETH_MUX_GMAC2_TO_2P5GPHY | MTK_MUX | MTK_INFRA) ++ + /* 0: GMACx -> GEPHY, 1: GMACx -> SGMII where x is 1 or 2 */ + #define MTK_MUX_GMAC12_TO_GEPHY_SGMII \ + (MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX) +@@ -1077,7 +1177,8 @@ enum mkt_eth_capabilities { + MTK_MUX_GMAC123_TO_GEPHY_SGMII | \ + MTK_NETSYS_V3 | MTK_RSTCTRL_PPE1 | \ + MTK_GMAC1_USXGMII | MTK_GMAC2_USXGMII | \ +- MTK_GMAC3_USXGMII | MTK_MUX_GMAC123_TO_USXGMII) ++ MTK_GMAC3_USXGMII | MTK_MUX_GMAC123_TO_USXGMII | \ ++ MTK_GMAC2_2P5GPHY | MTK_MUX_GMAC2_TO_2P5GPHY) + + struct mtk_tx_dma_desc_info { + dma_addr_t addr; +@@ -1183,6 +1284,19 @@ struct mtk_soc_data { + + #define MTK_DMA_MONITOR_TIMEOUT msecs_to_jiffies(1000) + ++/* struct mtk_xgmii - This is the structure holding sgmii/usxgmii regmap and ++ * its characteristics ++ * @regmap: The register map pointing at the range used to setup ++ * SGMII/USXGMII modes ++ * @flags: The enum refers to which mode the sgmii wants to run on ++ * @ana_rgc3: The offset refers to register ANA_RGC3 related to regmap ++ */ ++struct mtk_xgmii { ++ struct regmap **regmap_usxgmii; ++ struct regmap **regmap_pextp; ++ struct regmap *regmap_pll; ++}; ++ + /* struct mtk_eth - This is the main datasructure for holding the state + * of the driver + * @dev: The device pointer +@@ -1244,7 +1358,9 @@ struct mtk_eth { + unsigned long sysclk; + struct regmap *ethsys; + struct regmap *infra; ++ struct regmap *toprgu; + struct phylink_pcs **sgmii_pcs; ++ struct mtk_xgmii *xgmii; + struct regmap *pctl; + bool hwlro; + refcount_t dma_refcnt; +@@ -1400,6 +1516,19 @@ static inline u32 mtk_get_ib2_multicast_ + return MTK_FOE_IB2_MULTICAST; + } + ++static inline bool mtk_interface_mode_is_xgmii(phy_interface_t interface) ++{ ++ switch (interface) { ++ case PHY_INTERFACE_MODE_USXGMII: ++ case PHY_INTERFACE_MODE_10GKR: ++ case PHY_INTERFACE_MODE_5GBASER: ++ return true; ++ break; ++ default: ++ return false; ++ } ++} ++ + /* read the hardware status register */ + void mtk_stats_update_mac(struct mtk_mac *mac); + +@@ -1407,8 +1536,10 @@ void mtk_w32(struct mtk_eth *eth, u32 va + u32 mtk_r32(struct mtk_eth *eth, unsigned reg); + + int mtk_gmac_sgmii_path_setup(struct mtk_eth *eth, int mac_id); ++int mtk_gmac_2p5gphy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_gephy_path_setup(struct mtk_eth *eth, int mac_id); + int mtk_gmac_rgmii_path_setup(struct mtk_eth *eth, int mac_id); ++int mtk_gmac_usxgmii_path_setup(struct mtk_eth *eth, int mac_id); + + int mtk_eth_offload_init(struct mtk_eth *eth); + int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type, +@@ -1418,5 +1549,36 @@ int mtk_flow_offload_cmd(struct mtk_eth + void mtk_flow_offload_cleanup(struct mtk_eth *eth, struct list_head *list); + void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev); + ++#ifdef CONFIG_NET_MEDIATEK_SOC_USXGMII ++int mtk_usxgmii_init(struct mtk_eth *eth); ++int mtk_xfi_pextp_init(struct mtk_eth *eth); ++int mtk_xfi_pll_init(struct mtk_eth *eth); ++int mtk_toprgu_init(struct mtk_eth *eth); ++int mtk_xfi_pll_enable(struct mtk_eth *eth); ++int mtk_usxgmii_setup_mode_an(struct mtk_eth *eth, int mac_id, ++ int max_speed); ++int mtk_usxgmii_setup_mode_force(struct mtk_eth *eth, int mac_id, ++ const struct phylink_link_state *state); ++void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth *eth, int mac_id); ++void mtk_usxgmii_reset(struct mtk_eth *eth, int mac_id); ++void mtk_sgmii_setup_phya_gen1(struct mtk_eth *eth, int mac_id); ++void mtk_sgmii_setup_phya_gen2(struct mtk_eth *eth, int mac_id); ++void mtk_sgmii_reset(struct mtk_eth *eth, int mac_id); ++#else ++static inline int mtk_usxgmii_init(struct mtk_eth *eth) { return 0; }; ++static inline int mtk_xfi_pextp_init(struct mtk_eth *eth) { return 0; }; ++static inline int mtk_xfi_pll_init(struct mtk_eth *eth) { return 0; }; ++static inline int mtk_toprgu_init(struct mtk_eth *eth) { return 0; }; ++static inline int mtk_xfi_pll_enable(struct mtk_eth *eth) { return 0; }; ++static inline int mtk_usxgmii_setup_mode_an(struct mtk_eth *eth, int mac_id, ++ int max_speed) { return 0; }; ++static inline int mtk_usxgmii_setup_mode_force(struct mtk_eth *eth, int mac_id, ++ const struct phylink_link_state *state) { return 0; }; ++static inline void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth *eth, int mac_id) { }; ++static inline void mtk_usxgmii_reset(struct mtk_eth *eth, int mac_id) { }; ++static inline void mtk_sgmii_setup_phya_gen1(struct mtk_eth *eth, int mac_id) { }; ++static inline void mtk_sgmii_setup_phya_gen2(struct mtk_eth *eth, int mac_id) { }; ++static inline void mtk_sgmii_reset(struct mtk_eth *eth, int mac_id) { }; ++#endif + + #endif /* MTK_ETH_H */ +--- /dev/null ++++ b/drivers/net/ethernet/mediatek/mtk_usxgmii.c +@@ -0,0 +1,646 @@ ++/* SPDX-License-Identifier: GPL-2.0 ++ * ++ * Copyright (c) 2022 MediaTek Inc. ++ * Author: Henry Yen ++ */ ++ ++#include ++#include ++#include ++#include "mtk_eth_soc.h" ++ ++int mtk_usxgmii_init(struct mtk_eth *eth) ++{ ++ struct device_node *r = eth->dev->of_node; ++ struct mtk_xgmii *xs = eth->xgmii; ++ struct device *dev = eth->dev; ++ struct device_node *np; ++ int i; ++ ++ xs->regmap_usxgmii = devm_kzalloc(dev, sizeof(*xs->regmap_usxgmii) * ++ eth->soc->num_devs, GFP_KERNEL); ++ if (!xs->regmap_usxgmii) ++ return -ENOMEM; ++ ++ for (i = 0; i < eth->soc->num_devs; i++) { ++ np = of_parse_phandle(r, "mediatek,usxgmiisys", i); ++ if (!np) ++ break; ++ ++ xs->regmap_usxgmii[i] = syscon_node_to_regmap(np); ++ if (IS_ERR(xs->regmap_usxgmii[i])) ++ return PTR_ERR(xs->regmap_usxgmii[i]); ++ } ++ ++ return 0; ++} ++ ++int mtk_xfi_pextp_init(struct mtk_eth *eth) ++{ ++ struct device *dev = eth->dev; ++ struct device_node *r = dev->of_node; ++ struct mtk_xgmii *xs = eth->xgmii; ++ struct device_node *np; ++ int i; ++ ++ xs->regmap_pextp = devm_kzalloc(dev, sizeof(*xs->regmap_pextp) * ++ eth->soc->num_devs, GFP_KERNEL); ++ if (!xs->regmap_pextp) ++ return -ENOMEM; ++ ++ for (i = 0; i < eth->soc->num_devs; i++) { ++ np = of_parse_phandle(r, "mediatek,xfi_pextp", i); ++ if (!np) ++ break; ++ ++ xs->regmap_pextp[i] = syscon_node_to_regmap(np); ++ if (IS_ERR(xs->regmap_pextp[i])) ++ return PTR_ERR(xs->regmap_pextp[i]); ++ } ++ ++ return 0; ++} ++ ++int mtk_xfi_pll_init(struct mtk_eth *eth) ++{ ++ struct device_node *r = eth->dev->of_node; ++ struct mtk_xgmii *xs = eth->xgmii; ++ struct device_node *np; ++ ++ np = of_parse_phandle(r, "mediatek,xfi_pll", 0); ++ if (!np) ++ return -1; ++ ++ xs->regmap_pll = syscon_node_to_regmap(np); ++ if (IS_ERR(xs->regmap_pll)) ++ return PTR_ERR(xs->regmap_pll); ++ ++ return 0; ++} ++ ++int mtk_toprgu_init(struct mtk_eth *eth) ++{ ++ struct device_node *r = eth->dev->of_node; ++ struct device_node *np; ++ ++ np = of_parse_phandle(r, "mediatek,toprgu", 0); ++ if (!np) ++ return -1; ++ ++ eth->toprgu = syscon_node_to_regmap(np); ++ if (IS_ERR(eth->toprgu)) ++ return PTR_ERR(eth->toprgu); ++ ++ return 0; ++} ++ ++int mtk_xfi_pll_enable(struct mtk_eth *eth) ++{ ++ struct mtk_xgmii *xs = eth->xgmii; ++ u32 val = 0; ++ ++ if (!xs->regmap_pll) ++ return -EINVAL; ++ ++ /* Add software workaround for USXGMII PLL TCL issue */ ++ regmap_write(xs->regmap_pll, XFI_PLL_ANA_GLB8, RG_XFI_PLL_ANA_SWWA); ++ ++ regmap_read(xs->regmap_pll, XFI_PLL_DIG_GLB8, &val); ++ val |= RG_XFI_PLL_EN; ++ regmap_write(xs->regmap_pll, XFI_PLL_DIG_GLB8, val); ++ ++ return 0; ++} ++ ++static int mtk_mac2xgmii_id(struct mtk_eth *eth, int mac_id) ++{ ++ int xgmii_id = mac_id; ++ ++ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V3)) { ++ switch (mac_id) { ++ case MTK_GMAC1_ID: ++ case MTK_GMAC2_ID: ++ xgmii_id = 1; ++ break; ++ case MTK_GMAC3_ID: ++ xgmii_id = 0; ++ break; ++ default: ++ xgmii_id = -1; ++ } ++ } ++ ++ return xgmii_id; ++} ++ ++void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth *eth, int mac_id) ++{ ++ struct mtk_xgmii *xs = eth->xgmii; ++ u32 id = mtk_mac2xgmii_id(eth, mac_id); ++ ++ if (id >= eth->soc->num_devs || ++ !xs->regmap_usxgmii[id] || !xs->regmap_pextp[id]) ++ return; ++ ++ regmap_write(xs->regmap_usxgmii[id], RG_PCS_AN_CTRL0, 0x000FFE6D); ++ regmap_write(xs->regmap_usxgmii[id], 0x818, 0x07B1EC7B); ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, 0x30000000); ++ ndelay(1020); ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, 0x10000000); ++ ndelay(1020); ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, 0x00000000); ++ ++ regmap_write(xs->regmap_pextp[id], 0x9024, 0x00C9071C); ++ regmap_write(xs->regmap_pextp[id], 0x2020, 0xAA8585AA); ++ regmap_write(xs->regmap_pextp[id], 0x2030, 0x0C020707); ++ regmap_write(xs->regmap_pextp[id], 0x2034, 0x0E050F0F); ++ regmap_write(xs->regmap_pextp[id], 0x2040, 0x00140032); ++ regmap_write(xs->regmap_pextp[id], 0x50F0, 0x00C014AA); ++ regmap_write(xs->regmap_pextp[id], 0x50E0, 0x3777C12B); ++ regmap_write(xs->regmap_pextp[id], 0x506C, 0x005F9CFF); ++ regmap_write(xs->regmap_pextp[id], 0x5070, 0x9D9DFAFA); ++ regmap_write(xs->regmap_pextp[id], 0x5074, 0x27273F3F); ++ regmap_write(xs->regmap_pextp[id], 0x5078, 0xA7883C68); ++ regmap_write(xs->regmap_pextp[id], 0x507C, 0x11661166); ++ regmap_write(xs->regmap_pextp[id], 0x5080, 0x0E000AAF); ++ regmap_write(xs->regmap_pextp[id], 0x5084, 0x08080D0D); ++ regmap_write(xs->regmap_pextp[id], 0x5088, 0x02030909); ++ regmap_write(xs->regmap_pextp[id], 0x50E4, 0x0C0C0000); ++ regmap_write(xs->regmap_pextp[id], 0x50E8, 0x04040000); ++ regmap_write(xs->regmap_pextp[id], 0x50EC, 0x0F0F0C06); ++ regmap_write(xs->regmap_pextp[id], 0x50A8, 0x506E8C8C); ++ regmap_write(xs->regmap_pextp[id], 0x6004, 0x18190000); ++ regmap_write(xs->regmap_pextp[id], 0x00F8, 0x01423342); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F20); ++ regmap_write(xs->regmap_pextp[id], 0x0030, 0x00050C00); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x02002800); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000020); ++ regmap_write(xs->regmap_pextp[id], 0x3028, 0x00008A01); ++ regmap_write(xs->regmap_pextp[id], 0x302C, 0x0000A884); ++ regmap_write(xs->regmap_pextp[id], 0x3024, 0x00083002); ++ regmap_write(xs->regmap_pextp[id], 0x3010, 0x00022220); ++ regmap_write(xs->regmap_pextp[id], 0x5064, 0x0F020A01); ++ regmap_write(xs->regmap_pextp[id], 0x50B4, 0x06100600); ++ regmap_write(xs->regmap_pextp[id], 0x3048, 0x40704000); ++ regmap_write(xs->regmap_pextp[id], 0x3050, 0xA8000000); ++ regmap_write(xs->regmap_pextp[id], 0x3054, 0x000000AA); ++ regmap_write(xs->regmap_pextp[id], 0x306C, 0x00000F00); ++ regmap_write(xs->regmap_pextp[id], 0xA060, 0x00040000); ++ regmap_write(xs->regmap_pextp[id], 0x90D0, 0x00000001); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200E800); ++ udelay(150); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C101); ++ udelay(15); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0202C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0202C101); ++ udelay(100); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000030); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F00); ++ regmap_write(xs->regmap_pextp[id], 0x3040, 0x30000000); ++ udelay(400); ++} ++ ++void mtk_usxgmii_setup_phya_force_5000(struct mtk_eth *eth, int mac_id) ++{ ++ unsigned int val; ++ struct mtk_xgmii *xs = eth->xgmii; ++ u32 id = mtk_mac2xgmii_id(eth, mac_id); ++ ++ if (id >= eth->soc->num_devs || ++ !xs->regmap_usxgmii[id] || !xs->regmap_pextp[id]) ++ return; ++ ++ /* Setup USXGMII speed */ ++ val = FIELD_PREP(RG_XFI_RX_MODE, RG_XFI_RX_MODE_5G) | ++ FIELD_PREP(RG_XFI_TX_MODE, RG_XFI_TX_MODE_5G); ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val); ++ ++ /* Disable USXGMII AN mode */ ++ regmap_read(xs->regmap_usxgmii[id], RG_PCS_AN_CTRL0, &val); ++ val &= ~RG_AN_ENABLE; ++ regmap_write(xs->regmap_usxgmii[id], RG_PCS_AN_CTRL0, val); ++ ++ /* Gated USXGMII */ ++ regmap_read(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val); ++ val |= RG_MAC_CK_GATED; ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val); ++ ++ ndelay(1020); ++ ++ /* USXGMII force mode setting */ ++ regmap_read(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val); ++ val |= RG_USXGMII_RATE_UPDATE_MODE; ++ val |= RG_IF_FORCE_EN; ++ val |= FIELD_PREP(RG_RATE_ADAPT_MODE, RG_RATE_ADAPT_MODE_X1); ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val); ++ ++ /* Un-gated USXGMII */ ++ regmap_read(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val); ++ val &= ~RG_MAC_CK_GATED; ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val); ++ ++ ndelay(1020); ++ ++ regmap_write(xs->regmap_pextp[id], 0x9024, 0x00D9071C); ++ regmap_write(xs->regmap_pextp[id], 0x2020, 0xAAA5A5AA); ++ regmap_write(xs->regmap_pextp[id], 0x2030, 0x0C020707); ++ regmap_write(xs->regmap_pextp[id], 0x2034, 0x0E050F0F); ++ regmap_write(xs->regmap_pextp[id], 0x2040, 0x00140032); ++ regmap_write(xs->regmap_pextp[id], 0x50F0, 0x00C018AA); ++ regmap_write(xs->regmap_pextp[id], 0x50E0, 0x3777812B); ++ regmap_write(xs->regmap_pextp[id], 0x506C, 0x005C9CFF); ++ regmap_write(xs->regmap_pextp[id], 0x5070, 0x9DFAFAFA); ++ regmap_write(xs->regmap_pextp[id], 0x5074, 0x273F3F3F); ++ regmap_write(xs->regmap_pextp[id], 0x5078, 0xA8883868); ++ regmap_write(xs->regmap_pextp[id], 0x507C, 0x14661466); ++ regmap_write(xs->regmap_pextp[id], 0x5080, 0x0E001ABF); ++ regmap_write(xs->regmap_pextp[id], 0x5084, 0x080B0D0D); ++ regmap_write(xs->regmap_pextp[id], 0x5088, 0x02050909); ++ regmap_write(xs->regmap_pextp[id], 0x50E4, 0x0C000000); ++ regmap_write(xs->regmap_pextp[id], 0x50E8, 0x04000000); ++ regmap_write(xs->regmap_pextp[id], 0x50EC, 0x0F0F0C06); ++ regmap_write(xs->regmap_pextp[id], 0x50A8, 0x50808C8C); ++ regmap_write(xs->regmap_pextp[id], 0x6004, 0x18000000); ++ regmap_write(xs->regmap_pextp[id], 0x00F8, 0x00A132A1); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F20); ++ regmap_write(xs->regmap_pextp[id], 0x0030, 0x00050C00); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x02002800); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000020); ++ regmap_write(xs->regmap_pextp[id], 0x3028, 0x00008A01); ++ regmap_write(xs->regmap_pextp[id], 0x302C, 0x0000A884); ++ regmap_write(xs->regmap_pextp[id], 0x3024, 0x00083002); ++ regmap_write(xs->regmap_pextp[id], 0x3010, 0x00022220); ++ regmap_write(xs->regmap_pextp[id], 0x5064, 0x0F020A01); ++ regmap_write(xs->regmap_pextp[id], 0x50B4, 0x06100600); ++ regmap_write(xs->regmap_pextp[id], 0x3048, 0x40704000); ++ regmap_write(xs->regmap_pextp[id], 0x3050, 0xA8000000); ++ regmap_write(xs->regmap_pextp[id], 0x3054, 0x000000AA); ++ regmap_write(xs->regmap_pextp[id], 0x306C, 0x00000F00); ++ regmap_write(xs->regmap_pextp[id], 0xA060, 0x00040000); ++ regmap_write(xs->regmap_pextp[id], 0x90D0, 0x00000003); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200E800); ++ udelay(150); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C101); ++ udelay(15); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0202C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0202C101); ++ udelay(100); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000030); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F00); ++ regmap_write(xs->regmap_pextp[id], 0x3040, 0x30000000); ++ udelay(400); ++} ++ ++void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth *eth, int mac_id) ++{ ++ struct mtk_xgmii *xs = eth->xgmii; ++ unsigned int val; ++ u32 id = mtk_mac2xgmii_id(eth, mac_id); ++ ++ if (id >= eth->soc->num_devs || ++ !xs->regmap_usxgmii[id] || !xs->regmap_pextp[id]) ++ return; ++ ++ /* Setup USXGMII speed */ ++ val = FIELD_PREP(RG_XFI_RX_MODE, RG_XFI_RX_MODE_10G) | ++ FIELD_PREP(RG_XFI_TX_MODE, RG_XFI_TX_MODE_10G); ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val); ++ ++ /* Disable USXGMII AN mode */ ++ regmap_read(xs->regmap_usxgmii[id], RG_PCS_AN_CTRL0, &val); ++ val &= ~RG_AN_ENABLE; ++ regmap_write(xs->regmap_usxgmii[id], RG_PCS_AN_CTRL0, val); ++ ++ /* Gated USXGMII */ ++ regmap_read(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val); ++ val |= RG_MAC_CK_GATED; ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val); ++ ++ ndelay(1020); ++ ++ /* USXGMII force mode setting */ ++ regmap_read(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val); ++ val |= RG_USXGMII_RATE_UPDATE_MODE; ++ val |= RG_IF_FORCE_EN; ++ val |= FIELD_PREP(RG_RATE_ADAPT_MODE, RG_RATE_ADAPT_MODE_X1); ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val); ++ ++ /* Un-gated USXGMII */ ++ regmap_read(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, &val); ++ val &= ~RG_MAC_CK_GATED; ++ regmap_write(xs->regmap_usxgmii[id], RG_PHY_TOP_SPEED_CTRL1, val); ++ ++ ndelay(1020); ++ ++ regmap_write(xs->regmap_pextp[id], 0x9024, 0x00C9071C); ++ regmap_write(xs->regmap_pextp[id], 0x2020, 0xAA8585AA); ++ regmap_write(xs->regmap_pextp[id], 0x2030, 0x0C020707); ++ regmap_write(xs->regmap_pextp[id], 0x2034, 0x0E050F0F); ++ regmap_write(xs->regmap_pextp[id], 0x2040, 0x00140032); ++ regmap_write(xs->regmap_pextp[id], 0x50F0, 0x00C014AA); ++ regmap_write(xs->regmap_pextp[id], 0x50E0, 0x3777C12B); ++ regmap_write(xs->regmap_pextp[id], 0x506C, 0x005F9CFF); ++ regmap_write(xs->regmap_pextp[id], 0x5070, 0x9D9DFAFA); ++ regmap_write(xs->regmap_pextp[id], 0x5074, 0x27273F3F); ++ regmap_write(xs->regmap_pextp[id], 0x5078, 0xA7883C68); ++ regmap_write(xs->regmap_pextp[id], 0x507C, 0x11661166); ++ regmap_write(xs->regmap_pextp[id], 0x5080, 0x0E000AAF); ++ regmap_write(xs->regmap_pextp[id], 0x5084, 0x08080D0D); ++ regmap_write(xs->regmap_pextp[id], 0x5088, 0x02030909); ++ regmap_write(xs->regmap_pextp[id], 0x50E4, 0x0C0C0000); ++ regmap_write(xs->regmap_pextp[id], 0x50E8, 0x04040000); ++ regmap_write(xs->regmap_pextp[id], 0x50EC, 0x0F0F0C06); ++ regmap_write(xs->regmap_pextp[id], 0x50A8, 0x506E8C8C); ++ regmap_write(xs->regmap_pextp[id], 0x6004, 0x18190000); ++ regmap_write(xs->regmap_pextp[id], 0x00F8, 0x01423342); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F20); ++ regmap_write(xs->regmap_pextp[id], 0x0030, 0x00050C00); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x02002800); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000020); ++ regmap_write(xs->regmap_pextp[id], 0x3028, 0x00008A01); ++ regmap_write(xs->regmap_pextp[id], 0x302C, 0x0000A884); ++ regmap_write(xs->regmap_pextp[id], 0x3024, 0x00083002); ++ regmap_write(xs->regmap_pextp[id], 0x3010, 0x00022220); ++ regmap_write(xs->regmap_pextp[id], 0x5064, 0x0F020A01); ++ regmap_write(xs->regmap_pextp[id], 0x50B4, 0x06100600); ++ regmap_write(xs->regmap_pextp[id], 0x3048, 0x49664100); ++ regmap_write(xs->regmap_pextp[id], 0x3050, 0x00000000); ++ regmap_write(xs->regmap_pextp[id], 0x3054, 0x00000000); ++ regmap_write(xs->regmap_pextp[id], 0x306C, 0x00000F00); ++ regmap_write(xs->regmap_pextp[id], 0xA060, 0x00040000); ++ regmap_write(xs->regmap_pextp[id], 0x90D0, 0x00000001); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200E800); ++ udelay(150); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C101); ++ udelay(15); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0202C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0202C101); ++ udelay(100); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000030); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F00); ++ regmap_write(xs->regmap_pextp[id], 0x3040, 0x30000000); ++ udelay(400); ++} ++ ++void mtk_usxgmii_reset(struct mtk_eth *eth, int mac_id) ++{ ++ u32 id = mtk_mac2xgmii_id(eth, mac_id); ++ ++ if (id >= eth->soc->num_devs || !eth->toprgu) ++ return; ++ ++ switch (mac_id) { ++ case MTK_GMAC2_ID: ++ regmap_write(eth->toprgu, 0xFC, 0x0000A004); ++ regmap_write(eth->toprgu, 0x18, 0x88F0A004); ++ regmap_write(eth->toprgu, 0xFC, 0x00000000); ++ regmap_write(eth->toprgu, 0x18, 0x88F00000); ++ regmap_write(eth->toprgu, 0x18, 0x00F00000); ++ break; ++ case MTK_GMAC3_ID: ++ regmap_write(eth->toprgu, 0xFC, 0x00005002); ++ regmap_write(eth->toprgu, 0x18, 0x88F05002); ++ regmap_write(eth->toprgu, 0xFC, 0x00000000); ++ regmap_write(eth->toprgu, 0x18, 0x88F00000); ++ regmap_write(eth->toprgu, 0x18, 0x00F00000); ++ break; ++ } ++ ++ mdelay(10); ++} ++ ++int mtk_usxgmii_setup_mode_an(struct mtk_eth *eth, int mac_id, int max_speed) ++{ ++ if (mac_id < 0 || mac_id >= eth->soc->num_devs) ++ return -EINVAL; ++ ++ if ((max_speed != SPEED_10000) && (max_speed != SPEED_5000)) ++ return -EINVAL; ++ ++ mtk_xfi_pll_enable(eth); ++ mtk_usxgmii_reset(eth, mac_id); ++ mtk_usxgmii_setup_phya_an_10000(eth, mac_id); ++ ++ return 0; ++} ++ ++int mtk_usxgmii_setup_mode_force(struct mtk_eth *eth, int mac_id, ++ const struct phylink_link_state *state) ++{ ++ if (mac_id < 0 || mac_id >= eth->soc->num_devs) ++ return -EINVAL; ++ ++ mtk_xfi_pll_enable(eth); ++ mtk_usxgmii_reset(eth, mac_id); ++ if (state->interface == PHY_INTERFACE_MODE_5GBASER) ++ mtk_usxgmii_setup_phya_force_5000(eth, mac_id); ++ else ++ mtk_usxgmii_setup_phya_force_10000(eth, mac_id); ++ ++ return 0; ++} ++ ++void mtk_sgmii_setup_phya_gen1(struct mtk_eth *eth, int mac_id) ++{ ++ u32 id = mtk_mac2xgmii_id(eth, mac_id); ++ struct mtk_xgmii *xs = eth->xgmii; ++ ++ if (id >= eth->soc->num_devs || !xs->regmap_pextp[id]) ++ return; ++ ++ regmap_write(xs->regmap_pextp[id], 0x9024, 0x00D9071C); ++ regmap_write(xs->regmap_pextp[id], 0x2020, 0xAA8585AA); ++ regmap_write(xs->regmap_pextp[id], 0x2030, 0x0C020207); ++ regmap_write(xs->regmap_pextp[id], 0x2034, 0x0E05050F); ++ regmap_write(xs->regmap_pextp[id], 0x2040, 0x00200032); ++ regmap_write(xs->regmap_pextp[id], 0x50F0, 0x00C014BA); ++ regmap_write(xs->regmap_pextp[id], 0x50E0, 0x3777C12B); ++ regmap_write(xs->regmap_pextp[id], 0x506C, 0x005F9CFF); ++ regmap_write(xs->regmap_pextp[id], 0x5070, 0x9D9DFAFA); ++ regmap_write(xs->regmap_pextp[id], 0x5074, 0x27273F3F); ++ regmap_write(xs->regmap_pextp[id], 0x5078, 0xA7883C68); ++ regmap_write(xs->regmap_pextp[id], 0x507C, 0x11661166); ++ regmap_write(xs->regmap_pextp[id], 0x5080, 0x0E000EAF); ++ regmap_write(xs->regmap_pextp[id], 0x5084, 0x08080E0D); ++ regmap_write(xs->regmap_pextp[id], 0x5088, 0x02030B09); ++ regmap_write(xs->regmap_pextp[id], 0x50E4, 0x0C0C0000); ++ regmap_write(xs->regmap_pextp[id], 0x50E8, 0x04040000); ++ regmap_write(xs->regmap_pextp[id], 0x50EC, 0x0F0F0606); ++ regmap_write(xs->regmap_pextp[id], 0x50A8, 0x506E8C8C); ++ regmap_write(xs->regmap_pextp[id], 0x6004, 0x18190000); ++ regmap_write(xs->regmap_pextp[id], 0x00F8, 0x00FA32FA); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F21); ++ regmap_write(xs->regmap_pextp[id], 0x0030, 0x00050C00); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x02002800); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000020); ++ regmap_write(xs->regmap_pextp[id], 0x3028, 0x00008A01); ++ regmap_write(xs->regmap_pextp[id], 0x302C, 0x0000A884); ++ regmap_write(xs->regmap_pextp[id], 0x3024, 0x00083002); ++ regmap_write(xs->regmap_pextp[id], 0x3010, 0x00011110); ++ regmap_write(xs->regmap_pextp[id], 0x3048, 0x40704000); ++ regmap_write(xs->regmap_pextp[id], 0x3064, 0x0000C000); ++ regmap_write(xs->regmap_pextp[id], 0x3050, 0xA8000000); ++ regmap_write(xs->regmap_pextp[id], 0x3054, 0x000000AA); ++ regmap_write(xs->regmap_pextp[id], 0x306C, 0x20200F00); ++ regmap_write(xs->regmap_pextp[id], 0xA060, 0x00050000); ++ regmap_write(xs->regmap_pextp[id], 0x90D0, 0x00000007); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200E800); ++ udelay(150); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C101); ++ udelay(15); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0201C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0201C101); ++ udelay(100); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000030); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F01); ++ regmap_write(xs->regmap_pextp[id], 0x3040, 0x30000000); ++ udelay(400); ++} ++ ++void mtk_sgmii_setup_phya_gen2(struct mtk_eth *eth, int mac_id) ++{ ++ struct mtk_xgmii *xs = eth->xgmii; ++ u32 id = mtk_mac2xgmii_id(eth, mac_id); ++ ++ if (id >= eth->soc->num_devs || !xs->regmap_pextp[id]) ++ return; ++ ++ regmap_write(xs->regmap_pextp[id], 0x9024, 0x00D9071C); ++ regmap_write(xs->regmap_pextp[id], 0x2020, 0xAA8585AA); ++ regmap_write(xs->regmap_pextp[id], 0x2030, 0x0C020707); ++ regmap_write(xs->regmap_pextp[id], 0x2034, 0x0E050F0F); ++ regmap_write(xs->regmap_pextp[id], 0x2040, 0x00140032); ++ regmap_write(xs->regmap_pextp[id], 0x50F0, 0x00C014AA); ++ regmap_write(xs->regmap_pextp[id], 0x50E0, 0x3777C12B); ++ regmap_write(xs->regmap_pextp[id], 0x506C, 0x005F9CFF); ++ regmap_write(xs->regmap_pextp[id], 0x5070, 0x9D9DFAFA); ++ regmap_write(xs->regmap_pextp[id], 0x5074, 0x27273F3F); ++ regmap_write(xs->regmap_pextp[id], 0x5078, 0xA7883C68); ++ regmap_write(xs->regmap_pextp[id], 0x507C, 0x11661166); ++ regmap_write(xs->regmap_pextp[id], 0x5080, 0x0E000AAF); ++ regmap_write(xs->regmap_pextp[id], 0x5084, 0x08080D0D); ++ regmap_write(xs->regmap_pextp[id], 0x5088, 0x02030909); ++ regmap_write(xs->regmap_pextp[id], 0x50E4, 0x0C0C0000); ++ regmap_write(xs->regmap_pextp[id], 0x50E8, 0x04040000); ++ regmap_write(xs->regmap_pextp[id], 0x50EC, 0x0F0F0C06); ++ regmap_write(xs->regmap_pextp[id], 0x50A8, 0x506E8C8C); ++ regmap_write(xs->regmap_pextp[id], 0x6004, 0x18190000); ++ regmap_write(xs->regmap_pextp[id], 0x00F8, 0x009C329C); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F21); ++ regmap_write(xs->regmap_pextp[id], 0x0030, 0x00050C00); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x02002800); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000020); ++ regmap_write(xs->regmap_pextp[id], 0x3028, 0x00008A01); ++ regmap_write(xs->regmap_pextp[id], 0x302C, 0x0000A884); ++ regmap_write(xs->regmap_pextp[id], 0x3024, 0x00083002); ++ regmap_write(xs->regmap_pextp[id], 0x3010, 0x00011110); ++ regmap_write(xs->regmap_pextp[id], 0x3048, 0x40704000); ++ regmap_write(xs->regmap_pextp[id], 0x3050, 0xA8000000); ++ regmap_write(xs->regmap_pextp[id], 0x3054, 0x000000AA); ++ regmap_write(xs->regmap_pextp[id], 0x306C, 0x22000F00); ++ regmap_write(xs->regmap_pextp[id], 0xA060, 0x00050000); ++ regmap_write(xs->regmap_pextp[id], 0x90D0, 0x00000005); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200E800); ++ udelay(150); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0200C101); ++ udelay(15); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0201C111); ++ ndelay(1020); ++ regmap_write(xs->regmap_pextp[id], 0x0070, 0x0201C101); ++ udelay(100); ++ regmap_write(xs->regmap_pextp[id], 0x30B0, 0x00000030); ++ regmap_write(xs->regmap_pextp[id], 0x00F4, 0x80201F01); ++ regmap_write(xs->regmap_pextp[id], 0x3040, 0x30000000); ++ udelay(400); ++} ++ ++void mtk_sgmii_reset(struct mtk_eth *eth, int mac_id) ++{ ++ u32 id = mtk_mac2xgmii_id(eth, mac_id); ++ u32 val = 0; ++ ++ if (id >= eth->soc->num_devs || !eth->toprgu) ++ return; ++ ++ switch (mac_id) { ++ case MTK_GMAC2_ID: ++ /* Enable software reset */ ++ regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val); ++ val |= SWSYSRST_XFI_PEXPT1_GRST | ++ SWSYSRST_SGMII1_GRST; ++ regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val); ++ ++ /* Assert SGMII reset */ ++ regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val); ++ val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) | ++ SWSYSRST_XFI_PEXPT1_GRST | ++ SWSYSRST_SGMII1_GRST; ++ regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val); ++ ++ udelay(100); ++ ++ /* De-assert SGMII reset */ ++ regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val); ++ val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88); ++ val &= ~(SWSYSRST_XFI_PEXPT1_GRST | ++ SWSYSRST_SGMII1_GRST); ++ regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val); ++ ++ /* Disable software reset */ ++ regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val); ++ val &= ~(SWSYSRST_XFI_PEXPT1_GRST | ++ SWSYSRST_SGMII1_GRST); ++ regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val); ++ break; ++ case MTK_GMAC3_ID: ++ /* Enable Software reset */ ++ regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val); ++ val |= SWSYSRST_XFI_PEXPT0_GRST | ++ SWSYSRST_SGMII0_GRST; ++ regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val); ++ ++ /* Assert SGMII reset */ ++ regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val); ++ val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88) | ++ SWSYSRST_XFI_PEXPT0_GRST | ++ SWSYSRST_SGMII0_GRST; ++ regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val); ++ ++ udelay(100); ++ ++ /* De-assert SGMII reset */ ++ regmap_read(eth->toprgu, TOPRGU_SWSYSRST, &val); ++ val |= FIELD_PREP(SWSYSRST_UNLOCK_KEY, 0x88); ++ val &= ~(SWSYSRST_XFI_PEXPT0_GRST | ++ SWSYSRST_SGMII0_GRST); ++ regmap_write(eth->toprgu, TOPRGU_SWSYSRST, val); ++ ++ /* Disable software reset */ ++ regmap_read(eth->toprgu, TOPRGU_SWSYSRST_EN, &val); ++ val &= ~(SWSYSRST_XFI_PEXPT0_GRST | ++ SWSYSRST_SGMII0_GRST); ++ regmap_write(eth->toprgu, TOPRGU_SWSYSRST_EN, val); ++ break; ++ } ++ ++ mdelay(1); ++} +--- a/drivers/net/ethernet/mediatek/Kconfig ++++ b/drivers/net/ethernet/mediatek/Kconfig +@@ -11,6 +11,14 @@ config NET_MEDIATEK_SOC_WED + depends on ARCH_MEDIATEK || COMPILE_TEST + def_bool NET_MEDIATEK_SOC != n + ++config NET_MEDIATEK_SOC_USXGMII ++ bool "Support USXGMII SerDes on MT7988" ++ depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST ++ def_bool NET_MEDIATEK_SOC != n ++ help ++ Include support for 10G USXGMII SerDes unit which can ++ be found on MT7988. ++ + config NET_MEDIATEK_SOC + tristate "MediaTek SoC Gigabit Ethernet support" + depends on NET_DSA || !NET_DSA diff --git a/target/linux/generic/pending-5.15/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch b/target/linux/generic/pending-5.15/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch index f9b88db9955..8a64a2a985e 100644 --- a/target/linux/generic/pending-5.15/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch +++ b/target/linux/generic/pending-5.15/795-mt7530-register-OF-node-for-internal-MDIO-bus.patch @@ -16,7 +16,7 @@ Signed-off-by: David Bauer --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c -@@ -2081,10 +2081,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr +@@ -2121,10 +2121,13 @@ mt7530_setup_mdio(struct mt7530_priv *pr { struct dsa_switch *ds = priv->ds; struct device *dev = priv->dev; @@ -30,7 +30,7 @@ Signed-off-by: David Bauer bus = devm_mdiobus_alloc(dev); if (!bus) return -ENOMEM; -@@ -2101,7 +2104,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr +@@ -2141,7 +2144,9 @@ mt7530_setup_mdio(struct mt7530_priv *pr if (priv->irq) mt7530_setup_mdio_irq(priv); diff --git a/target/linux/ipq806x/base-files/etc/board.d/01_leds b/target/linux/ipq806x/base-files/etc/board.d/01_leds index 82ca270dd6b..d4d40bd6463 100644 --- a/target/linux/ipq806x/base-files/etc/board.d/01_leds +++ b/target/linux/ipq806x/base-files/etc/board.d/01_leds @@ -37,6 +37,7 @@ netgear,d7800 |\ netgear,r7500 |\ netgear,r7500v2 |\ netgear,r7800 |\ +netgear,xr450 |\ netgear,xr500) ucidef_set_led_usbport "usb1" "USB 1" "white:usb1" "usb1-port1" "usb2-port1" ucidef_set_led_usbport "usb2" "USB 2" "white:usb2" "usb3-port1" "usb4-port1" diff --git a/target/linux/ipq806x/base-files/etc/board.d/02_network b/target/linux/ipq806x/base-files/etc/board.d/02_network index 8dd52452b17..70812a1013c 100644 --- a/target/linux/ipq806x/base-files/etc/board.d/02_network +++ b/target/linux/ipq806x/base-files/etc/board.d/02_network @@ -59,6 +59,7 @@ nec,wg2600hp3) "2:lan" "3:lan" "4:lan" "5:lan" "0@eth1" "1:wan" "6@eth0" ;; netgear,r7800 |\ +netgear,xr450 |\ netgear,xr500 |\ tplink,c2600 |\ tplink,vr2600v) diff --git a/target/linux/ipq806x/base-files/lib/upgrade/platform.sh b/target/linux/ipq806x/base-files/lib/upgrade/platform.sh index 5ec4f513bd3..108b0b76307 100644 --- a/target/linux/ipq806x/base-files/lib/upgrade/platform.sh +++ b/target/linux/ipq806x/base-files/lib/upgrade/platform.sh @@ -17,6 +17,7 @@ platform_do_upgrade() { netgear,r7500 |\ netgear,r7500v2 |\ netgear,r7800 |\ + netgear,xr450 |\ netgear,xr500 |\ nokia,ac400i |\ qcom,ipq8064-ap148 |\ diff --git a/target/linux/ipq806x/config-5.15 b/target/linux/ipq806x/config-5.15 index 69e17cfa504..286f327e39d 100644 --- a/target/linux/ipq806x/config-5.15 +++ b/target/linux/ipq806x/config-5.15 @@ -39,7 +39,6 @@ CONFIG_ARM_HAS_SG_CHAIN=y # CONFIG_ARM_KRAIT_CACHE_DEVFREQ is not set CONFIG_ARM_L1_CACHE_SHIFT=6 CONFIG_ARM_L1_CACHE_SHIFT_6=y -CONFIG_ARM_MODULE_PLTS=y CONFIG_ARM_PATCH_IDIV=y CONFIG_ARM_PATCH_PHYS_VIRT=y # CONFIG_ARM_QCOM_CPUFREQ_HW is not set diff --git a/target/linux/ipq806x/config-6.1 b/target/linux/ipq806x/config-6.1 index aae2f8a0b0f..4f8c3c88dfc 100644 --- a/target/linux/ipq806x/config-6.1 +++ b/target/linux/ipq806x/config-6.1 @@ -43,7 +43,6 @@ CONFIG_ARM_HAS_SG_CHAIN=y # CONFIG_ARM_KRAIT_CACHE_DEVFREQ is not set CONFIG_ARM_L1_CACHE_SHIFT=6 CONFIG_ARM_L1_CACHE_SHIFT_6=y -CONFIG_ARM_MODULE_PLTS=y CONFIG_ARM_PATCH_IDIV=y CONFIG_ARM_PATCH_PHYS_VIRT=y # CONFIG_ARM_QCOM_CPUFREQ_HW is not set diff --git a/target/linux/ipq806x/files-5.15/arch/arm/boot/dts/qcom-ipq8065-xr450.dts b/target/linux/ipq806x/files-5.15/arch/arm/boot/dts/qcom-ipq8065-xr450.dts new file mode 100644 index 00000000000..4353aec7ac0 --- /dev/null +++ b/target/linux/ipq806x/files-5.15/arch/arm/boot/dts/qcom-ipq8065-xr450.dts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR MIT + +#include "qcom-ipq8065-nighthawk.dtsi" + +/ { + model = "Netgear Nighthawk XR450"; + compatible = "netgear,xr450", "qcom,ipq8065", "qcom,ipq8064"; + +}; + +&leds { + usb1 { + label = "white:usb1"; + gpios = <&qcom_pinmux 8 GPIO_ACTIVE_HIGH>; + }; + + usb2 { + label = "white:usb2"; + gpios = <&qcom_pinmux 26 GPIO_ACTIVE_HIGH>; + }; +}; + +&partitions { + partition@1880000 { + label = "ubi"; + reg = <0x1880000 0xce00000>; + }; + + partition@e680000 { + label = "reserve"; + reg = <0xe680000 0x0780000>; + read-only; + }; +}; + +&wifi0 { + nvmem-cells = <&macaddr_art_c>, <&precal_art_1000>; + nvmem-cell-names = "mac-address", "pre-calibration"; +}; + +&wifi1 { + nvmem-cells = <&macaddr_art_0>, <&precal_art_5000>; + nvmem-cell-names = "mac-address", "pre-calibration"; +}; + +&art { + macaddr_art_c: macaddr@c { + reg = <0xc 0x6>; + }; +}; diff --git a/target/linux/ipq806x/image/generic.mk b/target/linux/ipq806x/image/generic.mk index b83999dd00e..7ed2b808473 100644 --- a/target/linux/ipq806x/image/generic.mk +++ b/target/linux/ipq806x/image/generic.mk @@ -320,6 +320,20 @@ define Device/netgear_r7800 endef TARGET_DEVICES += netgear_r7800 +define Device/netgear_xr450 + $(call Device/DniImage) + DEVICE_VENDOR := NETGEAR + DEVICE_MODEL := Nighthawk XR450 + SOC := qcom-ipq8065 + KERNEL_SIZE := 4096k + NETGEAR_BOARD_ID := XR450 + NETGEAR_HW_ID := 29764958+0+256+512+4x4+4x4+cascade + BLOCKSIZE := 128k + PAGESIZE := 2048 + DEVICE_PACKAGES := ath10k-firmware-qca9984-ct kmod-ramoops +endef +TARGET_DEVICES += netgear_xr450 + define Device/netgear_xr500 $(call Device/DniImage) DEVICE_VENDOR := NETGEAR diff --git a/target/linux/layerscape/armv8_64b/config-5.15 b/target/linux/layerscape/armv8_64b/config-5.15 index 3fe55e61188..df0a3fd849c 100644 --- a/target/linux/layerscape/armv8_64b/config-5.15 +++ b/target/linux/layerscape/armv8_64b/config-5.15 @@ -30,7 +30,6 @@ CONFIG_ARM64_ERRATUM_832075=y CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_HW_AFDBM=y CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y -CONFIG_ARM64_MODULE_PLTS=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PAN=y CONFIG_ARM64_PA_BITS=48 diff --git a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi index 279bce14e86..95b548143b4 100644 --- a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi +++ b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7981.dtsi @@ -555,14 +555,15 @@ "mediatek,mt7981-mmc"; reg = <0 0x11230000 0 0x1000>, <0 0x11c20000 0 0x1000>; interrupts = ; - clocks = <&topckgen CLK_TOP_EMMC_208M>, - <&topckgen CLK_TOP_EMMC_400M>, - <&infracfg CLK_INFRA_MSDC_CK>; + clocks = <&infracfg CLK_INFRA_MSDC_CK>, + <&infracfg CLK_INFRA_MSDC_HCK_CK>, + <&infracfg CLK_INFRA_MSDC_66M_CK>, + <&infracfg CLK_INFRA_MSDC_133M_CK>; assigned-clocks = <&topckgen CLK_TOP_EMMC_208M_SEL>, <&topckgen CLK_TOP_EMMC_400M_SEL>; assigned-clock-parents = <&topckgen CLK_TOP_CB_M_D2>, <&topckgen CLK_TOP_CB_NET2_D2>; - clock-names = "source", "hclk", "source_cg"; + clock-names = "source", "hclk", "axi_cg", "ahb_cg"; status = "disabled"; }; @@ -640,7 +641,6 @@ phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>; vusb33-supply = <®_3p3v>; - mediatek,u3p-dis-msk = <0x01>; status = "disabled"; }; diff --git a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts new file mode 100644 index 00000000000..98dbf8d6913 --- /dev/null +++ b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-dsa-10g-spim-nand.dts @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +#include "mt7988a-rfb-spim-nand.dtsi" +#include + +/ { + model = "MediaTek MT7988A DSA 10G SPIM-NAND RFB"; + compatible = "mediatek,mt7988a-dsa-10g-spim-snand", + "mediatek,mt7988a-rfb-snand", + "mediatek,mt7988"; + + chosen { + bootargs = "console=ttyS0,115200n1 loglevel=8 \ + earlycon=uart8250,mmio32,0x11000000 \ + pci=pcie_bus_perf"; + }; + + memory { + reg = <0 0x40000000 0 0x40000000>; + }; +}; + +ð { + pinctrl-0 = <&mdio0_pins>; + pinctrl-names = "default"; + status = "okay"; + + gmac0: mac@0 { + compatible = "mediatek,eth-mac"; + reg = <0>; + phy-mode = "internal"; + + fixed-link { + speed = <10000>; + full-duplex; + pause; + }; + }; + + gmac1: mac@1 { + compatible = "mediatek,eth-mac"; + reg = <1>; + phy-mode = "internal"; + phy-connection-type = "internal"; + phy = <&phy15>; + }; + + gmac2: mac@2 { + compatible = "mediatek,eth-mac"; + reg = <2>; + phy-mode = "10gbase-kr"; + phy-connection-type = "10gbase-kr"; + phy = <&phy8>; + }; + + mdio0: mdio-bus { + #address-cells = <1>; + #size-cells = <0>; + + /* external Aquantia AQR113C */ + phy0: ethernet-phy@0 { + reg = <0>; + compatible = "ethernet-phy-ieee802.3-c45"; + reset-gpios = <&pio 72 1>; + reset-assert-us = <100000>; + reset-deassert-us = <221000>; + }; + + /* external Aquantia AQR113C */ + phy8: ethernet-phy@8 { + reg = <8>; + compatible = "ethernet-phy-ieee802.3-c45"; + reset-gpios = <&pio 71 1>; + reset-assert-us = <100000>; + reset-deassert-us = <221000>; + }; + + /* external Maxlinear GPY211C */ + phy5: ethernet-phy@5 { + reg = <5>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "2500base-x"; + }; + + /* external Maxlinear GPY211C */ + phy13: ethernet-phy@13 { + reg = <13>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "2500base-x"; + }; + + /* internal 2.5G PHY */ + phy15: ethernet-phy@15 { + reg = <15>; + pinctrl-names = "i2p5gbe-led"; + pinctrl-0 = <&i2p5gbe_led0_pins>; + compatible = "ethernet-phy-ieee802.3-c45"; + phy-mode = "internal"; + }; + }; +}; + +&switch { + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + label = "lan0"; + phy-mode = "internal"; + phy-handle = <&gsw_phy0>; + }; + + port@1 { + reg = <1>; + label = "lan1"; + phy-mode = "internal"; + phy-handle = <&gsw_phy1>; + }; + + port@2 { + reg = <2>; + label = "lan2"; + phy-mode = "internal"; + phy-handle = <&gsw_phy2>; + }; + + port@3 { + reg = <3>; + label = "lan3"; + phy-mode = "internal"; + phy-handle = <&gsw_phy3>; + }; + + port@6 { + reg = <6>; + ethernet = <&gmac0>; + phy-mode = "internal"; + + fixed-link { + speed = <10000>; + full-duplex; + pause; + }; + }; + }; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + gsw_phy0: ethernet-phy@0 { + compatible = "ethernet-phy-id03a2.9481"; + reg = <0>; + phy-mode = "internal"; + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe0_led0_pins>; + nvmem-cells = <&phy_calibration_p0>; + nvmem-cell-names = "phy-cal-data"; + }; + + gsw_phy1: ethernet-phy@1 { + compatible = "ethernet-phy-id03a2.9481"; + reg = <1>; + phy-mode = "internal"; + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe1_led0_pins>; + nvmem-cells = <&phy_calibration_p1>; + nvmem-cell-names = "phy-cal-data"; + }; + + gsw_phy2: ethernet-phy@2 { + compatible = "ethernet-phy-id03a2.9481"; + reg = <2>; + phy-mode = "internal"; + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe2_led0_pins>; + nvmem-cells = <&phy_calibration_p2>; + nvmem-cell-names = "phy-cal-data"; + }; + + gsw_phy3: ethernet-phy@3 { + compatible = "ethernet-phy-id03a2.9481"; + reg = <3>; + phy-mode = "internal"; + pinctrl-names = "gbe-led"; + pinctrl-0 = <&gbe3_led0_pins>; + nvmem-cells = <&phy_calibration_p3>; + nvmem-cell-names = "phy-cal-data"; + }; + }; +}; diff --git a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtsi b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtsi new file mode 100644 index 00000000000..e4c05712509 --- /dev/null +++ b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand.dtsi @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +#include "mt7988a-rfb.dtsi" + +&pio { + spi0_flash_pins: spi0-pins { + mux { + function = "spi"; + groups = "spi0", "spi0_wp_hold"; + }; + }; +}; + +&spi0 { + pinctrl-names = "default"; + pinctrl-0 = <&spi0_flash_pins>; + status = "okay"; + + spi_nand: spi_nand@0 { + compatible = "spi-nand"; + reg = <0>; + spi-max-frequency = <52000000>; + spi-tx-buswidth = <4>; + spi-rx-buswidth = <4>; + }; + +}; + +&spi_nand { + mediatek,nmbm; + mediatek,bmt-max-ratio = <1>; + mediatek,bmt-max-reserved-blocks = <64>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + partition@0 { + label = "BL2"; + reg = <0x00000 0x0100000>; + read-only; + }; + + partition@100000 { + label = "u-boot-env"; + reg = <0x0100000 0x0080000>; + }; + + factory: partition@180000 { + label = "Factory"; + reg = <0x180000 0x0400000>; + }; + + partition@580000 { + label = "FIP"; + reg = <0x580000 0x0200000>; + }; + + partition@780000 { + label = "ubi"; + reg = <0x780000 0x7080000>; + }; + }; +}; diff --git a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dtsi b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dtsi new file mode 100644 index 00000000000..423b3860c6c --- /dev/null +++ b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dtsi @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2022 MediaTek Inc. + * Author: Sam.Shih + */ + +/dts-v1/; +#include "mt7988a.dtsi" +#include + +&cpu0 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu1 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu2 { + proc-supply = <&rt5190_buck3>; +}; + +&cpu3 { + proc-supply = <&rt5190_buck3>; +}; + +&cci { + proc-supply = <&rt5190_buck3>; +}; + +ð { + status = "okay"; +}; + +&i2c0 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins>; + status = "okay"; + + rt5190a_64: rt5190a@64 { + compatible = "richtek,rt5190a"; + reg = <0x64>; + /*interrupts-extended = <&gpio26 0 IRQ_TYPE_LEVEL_LOW>;*/ + vin2-supply = <&rt5190_buck1>; + vin3-supply = <&rt5190_buck1>; + vin4-supply = <&rt5190_buck1>; + + regulators { + rt5190_buck1: buck1 { + regulator-name = "rt5190a-buck1"; + regulator-min-microvolt = <5090000>; + regulator-max-microvolt = <5090000>; + regulator-allowed-modes = + ; + regulator-boot-on; + regulator-always-on; + }; + buck2 { + regulator-name = "vcore"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + regulator-always-on; + }; + rt5190_buck3: buck3 { + regulator-name = "vproc"; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <1400000>; + regulator-boot-on; + }; + buck4 { + regulator-name = "rt5190a-buck4"; + regulator-min-microvolt = <850000>; + regulator-max-microvolt = <850000>; + regulator-allowed-modes = + ; + regulator-boot-on; + regulator-always-on; + }; + ldo { + regulator-name = "rt5190a-ldo"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-boot-on; + regulator-always-on; + }; + }; + }; +}; + +&pcie0 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_pins>; + status = "okay"; +}; + +&pcie1 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_pins>; + status = "okay"; +}; + +&pcie2 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie2_pins>; + status = "disabled"; +}; + +&pcie3 { + pinctrl-names = "default"; + pinctrl-0 = <&pcie3_pins>; + status = "okay"; +}; + +&ssusb0 { + status = "okay"; +}; + +&ssusb1 { + status = "okay"; +}; + +&tphy { + status = "okay"; +}; + +&pio { + pcie0_pins: pcie0-pins { + mux { + function = "pcie"; + groups = "pcie_2l_0_pereset", "pcie_clk_req_n0_0", + "pcie_wake_n0_0"; + }; + }; + + pcie1_pins: pcie1-pins { + mux { + function = "pcie"; + groups = "pcie_2l_1_pereset", "pcie_clk_req_n1", + "pcie_wake_n1_0"; + }; + }; + + pcie2_pins: pcie2-pins { + mux { + function = "pcie"; + groups = "pcie_1l_0_pereset", "pcie_clk_req_n2_0", + "pcie_wake_n2_0"; + }; + }; + + pcie3_pins: pcie3-pins { + mux { + function = "pcie"; + groups = "pcie_1l_1_pereset", "pcie_clk_req_n3", + "pcie_wake_n3_0"; + }; + }; +}; + +&spi0 { + status = "disabled"; +}; + +&uart0 { + status = "okay"; +}; + +&watchdog { + status = "okay"; +}; + +&xphy { + status = "okay"; +}; diff --git a/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a.dtsi b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a.dtsi new file mode 100644 index 00000000000..13ad39500d1 --- /dev/null +++ b/target/linux/mediatek/files-5.15/arch/arm64/boot/dts/mediatek/mt7988a.dtsi @@ -0,0 +1,853 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright (C) 2023 MediaTek Inc. + * Author: Sam.Shih + */ + +#include +#include +#include +#include +#include +#include +#include + +/ { + compatible = "mediatek,mt7988"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + clk40m: oscillator@0 { + compatible = "fixed-clock"; + clock-frequency = <40000000>; + #clock-cells = <0>; + clock-output-names = "clkxtal"; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a73"; + enable-method = "psci"; + reg = <0x0>; + clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; + mediatek,cci = <&cci>; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a73"; + enable-method = "psci"; + reg = <0x1>; + clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; + mediatek,cci = <&cci>; + }; + + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a73"; + enable-method = "psci"; + reg = <0x2>; + clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; + mediatek,cci = <&cci>; + }; + + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a73"; + enable-method = "psci"; + reg = <0x3>; + clocks = <&mcusys CLK_MCU_ARM_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cpu", "intermediate"; + operating-points-v2 = <&cluster0_opp>; + mediatek,cci = <&cci>; + }; + + cluster0_opp: opp_table0 { + compatible = "operating-points-v2"; + opp-shared; + opp00 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <850000>; + }; + opp01 { + opp-hz = /bits/ 64 <1100000000>; + opp-microvolt = <850000>; + }; + opp02 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <850000>; + }; + opp03 { + opp-hz = /bits/ 64 <1800000000>; + opp-microvolt = <900000>; + }; + }; + }; + + cci: cci { + compatible = "mediatek,mt7988-cci", + "mediatek,mt8183-cci"; + clocks = <&mcusys CLK_MCU_BUS_DIV_SEL>, + <&topckgen CLK_TOP_XTAL>; + clock-names = "cci", "intermediate"; + operating-points-v2 = <&cci_opp>; + }; + + cci_opp: opp_table_cci { + compatible = "operating-points-v2"; + opp-shared; + opp00 { + opp-hz = /bits/ 64 <480000000>; + opp-microvolt = <850000>; + }; + opp01 { + opp-hz = /bits/ 64 <660000000>; + opp-microvolt = <850000>; + }; + opp02 { + opp-hz = /bits/ 64 <900000000>; + opp-microvolt = <850000>; + }; + opp03 { + opp-hz = /bits/ 64 <1080000000>; + opp-microvolt = <900000>; + }; + }; + + pmu { + compatible = "arm,cortex-a73-pmu"; + interrupt-parent = <&gic>; + interrupt = ; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + /* 192 KiB reserved for ARM Trusted Firmware (BL31) */ + secmon_reserved: secmon@43000000 { + reg = <0 0x43000000 0 0x30000>; + no-map; + }; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupt-parent = <&gic>; + interrupts = , + , + , + ; + }; + + soc { + #address-cells = <2>; + #size-cells = <2>; + compatible = "simple-bus"; + ranges; + + gic: interrupt-controller@c000000 { + compatible = "arm,gic-v3"; + #interrupt-cells = <3>; + interrupt-parent = <&gic>; + interrupt-controller; + reg = <0 0x0c000000 0 0x40000>, /* GICD */ + <0 0x0c080000 0 0x200000>, /* GICR */ + <0 0x0c400000 0 0x2000>, /* GICC */ + <0 0x0c410000 0 0x1000>, /* GICH */ + <0 0x0c420000 0 0x2000>; /* GICV */ + + interrupts = ; + }; + + phyfw: phy-firmware@f000000 { + compatible = "mediatek,2p5gphy-fw"; + reg = <0 0x0f000000 0 0x8000>, + <0 0x0f100000 0 0x20000>, + <0 0x0f0f0000 0 0x200>; + }; + + infracfg: infracfg@10001000 { + compatible = "mediatek,mt7988-infracfg", "syscon"; + reg = <0 0x10001000 0 0x1000>; + #clock-cells = <1>; + }; + + topckgen: topckgen@1001b000 { + compatible = "mediatek,mt7988-topckgen", "syscon"; + reg = <0 0x1001b000 0 0x1000>; + #clock-cells = <1>; + }; + + watchdog: watchdog@1001c000 { + compatible = "mediatek,mt7988-wdt", + "mediatek,mt6589-wdt", + "syscon"; + reg = <0 0x1001c000 0 0x1000>; + interrupts = ; + #reset-cells = <1>; + }; + + apmixedsys: apmixedsys@1001e000 { + compatible = "mediatek,mt7988-apmixedsys"; + reg = <0 0x1001e000 0 0x1000>; + #clock-cells = <1>; + }; + + pio: pinctrl@1001f000 { + compatible = "mediatek,mt7988-pinctrl"; + reg = <0 0x1001f000 0 0x1000>, + <0 0x11c10000 0 0x1000>, + <0 0x11d00000 0 0x1000>, + <0 0x11d20000 0 0x1000>, + <0 0x11e00000 0 0x1000>, + <0 0x11f00000 0 0x1000>, + <0 0x1000b000 0 0x1000>; + reg-names = "gpio_base", "iocfg_tr_base", + "iocfg_br_base", "iocfg_rb_base", + "iocfg_lb_base", "iocfg_tl_base", "eint"; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = <&pio 0 0 83>; + interrupt-controller; + interrupts = ; + interrupt-parent = <&gic>; + #interrupt-cells = <2>; + + mdio0_pins: mdio0-pins { + mux { + function = "eth"; + groups = "mdc_mdio0"; + }; + + conf { + groups = "mdc_mdio0"; + drive-strength = ; + }; + }; + + i2c0_pins: i2c0-pins-g0 { + mux { + function = "i2c"; + groups = "i2c0_1"; + }; + }; + + i2c1_pins: i2c1-pins-g0 { + mux { + function = "i2c"; + groups = "i2c1_0"; + }; + }; + + i2c2_pins: i2c2-pins-g0 { + mux { + function = "i2c"; + groups = "i2c2_1"; + }; + }; + + gbe0_led0_pins: gbe0-pins { + mux { + function = "led"; + groups = "gbe0_led0"; + }; + }; + + gbe1_led0_pins: gbe1-pins { + mux { + function = "led"; + groups = "gbe1_led0"; + }; + }; + + gbe2_led0_pins: gbe2-pins { + mux { + function = "led"; + groups = "gbe2_led0"; + }; + }; + + gbe3_led0_pins: gbe3-pins { + mux { + function = "led"; + groups = "gbe3_led0"; + }; + }; + + i2p5gbe_led0_pins: 2p5gbe-pins { + mux { + function = "led"; + groups = "2p5gbe_led0"; + }; + }; + }; + + boottrap: boottrap@1001f6f0 { + compatible = "mediatek,boottrap"; + reg = <0 0x1001f6f0 0 0x4>; + }; + + sgmiisys0: syscon@10060000 { + compatible = "mediatek,mt7988-sgmiisys", + "mediatek,mt7988-sgmiisys_0", + "syscon"; + reg = <0 0x10060000 0 0x1000>; + #clock-cells = <1>; + }; + + sgmiisys1: syscon@10070000 { + compatible = "mediatek,mt7988-sgmiisys", + "mediatek,mt7988-sgmiisys_1", + "syscon"; + reg = <0 0x10070000 0 0x1000>; + #clock-cells = <1>; + }; + + usxgmiisys0: usxgmiisys@10080000 { + compatible = "mediatek,mt7988-usxgmiisys", + "mediatek,mt7988-usxgmiisys_0", + "syscon"; + reg = <0 0x10080000 0 0x1000>; + #clock-cells = <1>; + }; + + usxgmiisys1: usxgmiisys@10081000 { + compatible = "mediatek,mt7988-usxgmiisys", + "mediatek,mt7988-usxgmiisys_1", + "syscon"; + reg = <0 0x10081000 0 0x1000>; + #clock-cells = <1>; + }; + + xfi_pextp0: xfi_pextp@11f20000 { + compatible = "mediatek,mt7988-xfi_pextp", + "mediatek,mt7988-xfi_pextp_0", + "syscon"; + reg = <0 0x11f20000 0 0x10000>; + #clock-cells = <1>; + }; + + xfi_pextp1: xfi_pextp@11f30000 { + compatible = "mediatek,mt7988-xfi_pextp", + "mediatek,mt7988-xfi_pextp_1", + "syscon"; + reg = <0 0x11f30000 0 0x10000>; + #clock-cells = <1>; + }; + + xfi_pll: xfi_pll@11f40000 { + compatible = "mediatek,mt7988-xfi_pll", "syscon"; + reg = <0 0x11f40000 0 0x1000>; + #clock-cells = <1>; + }; + + mcusys: mcusys@100e0000 { + compatible = "mediatek,mt7988-mcusys", "syscon"; + reg = <0 0x100e0000 0 0x1000>; + #clock-cells = <1>; + }; + + uart0: serial@11000000 { + compatible = "mediatek,mt7986-uart", + "mediatek,mt6577-uart"; + reg = <0 0x11000000 0 0x100>; + interrupts = ; + /* + * 8250-mtk driver don't control "baud" clock since commit + * e32a83c70cf9 (kernel v5.7), but both "baud" and "bus" clocks + * still need to be passed to the driver to prevent probe fail + */ + clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_52M_UART0_CK>; + clock-names = "baud", "bus"; + assigned-clocks = <&topckgen CLK_TOP_UART_SEL>, + <&infracfg CLK_INFRA_MUX_UART0_SEL>; + assigned-clock-parents = <&topckgen CLK_TOP_XTAL>, + <&topckgen CLK_TOP_UART_SEL>; + status = "disabled"; + }; + + i2c0: i2c@11003000 { + compatible = "mediatek,mt7988-i2c", + "mediatek,mt7981-i2c"; + reg = <0 0x11003000 0 0x1000>, + <0 0x10217080 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&infracfg CLK_INFRA_I2C_BCK>, + <&infracfg CLK_INFRA_66M_AP_DMA_BCK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c1: i2c@11004000 { + compatible = "mediatek,mt7988-i2c", + "mediatek,mt7981-i2c"; + reg = <0 0x11004000 0 0x1000>, + <0 0x10217100 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&infracfg CLK_INFRA_I2C_BCK>, + <&infracfg CLK_INFRA_66M_AP_DMA_BCK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + i2c2: i2c@11005000 { + compatible = "mediatek,mt7988-i2c", + "mediatek,mt7981-i2c"; + reg = <0 0x11005000 0 0x1000>, + <0 0x10217180 0 0x80>; + interrupts = ; + clock-div = <1>; + clocks = <&infracfg CLK_INFRA_I2C_BCK>, + <&infracfg CLK_INFRA_66M_AP_DMA_BCK>; + clock-names = "main", "dma"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi0: spi@11007000 { + compatible = "mediatek,ipm-spi-quad", "mediatek,spi-ipm"; + reg = <0 0x11007000 0 0x100>; + interrupts = ; + clocks = <&topckgen CLK_TOP_MPLL_D2>, + <&topckgen CLK_TOP_SPI_SEL>, + <&infracfg CLK_INFRA_104M_SPI0>, + <&infracfg CLK_INFRA_66M_SPI0_HCK>; + clock-names = "parent-clk", "sel-clk", "spi-clk", + "spi-hclk"; + + #address-cells = <1>; + #size-cells = <0>; + + status = "disabled"; + }; + + pcie2: pcie@11280000 { + compatible = "mediatek,mt7988-pcie", + "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0 0x11280000 0 0x2000>; + reg-names = "pcie-mac"; + linux,pci-domain = <3>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0x00 0x20000000 0x00 + 0x20000000 0x00 0x00200000>, + <0x82000000 0x00 0x20200000 0x00 + 0x20200000 0x00 0x07e00000>; + clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P2>, + <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P2>, + <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P2>, + <&infracfg CLK_INFRA_133M_PCIE_CK_P2>; + clock-names = "pl_250m", "tl_26m", "peri_26m", + "top_133m"; + status = "disabled"; + + phys = <&xphyu3port0 PHY_TYPE_PCIE>; + phy-names = "pcie-phy"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc2 0>, + <0 0 0 2 &pcie_intc2 1>, + <0 0 0 3 &pcie_intc2 2>, + <0 0 0 4 &pcie_intc2 3>; + pcie_intc2: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + pcie3: pcie@11290000 { + compatible = "mediatek,mt7988-pcie", + "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0 0x11290000 0 0x2000>; + reg-names = "pcie-mac"; + linux,pci-domain = <2>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0x00 0x28000000 0x00 + 0x28000000 0x00 0x00200000>, + <0x82000000 0x00 0x28200000 0x00 + 0x28200000 0x00 0x07e00000>; + clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P3>, + <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P3>, + <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P3>, + <&infracfg CLK_INFRA_133M_PCIE_CK_P3>; + clock-names = "pl_250m", "tl_26m", "peri_26m", + "top_133m"; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc3 0>, + <0 0 0 2 &pcie_intc3 1>, + <0 0 0 3 &pcie_intc3 2>, + <0 0 0 4 &pcie_intc3 3>; + pcie_intc3: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + pcie0: pcie@11300000 { + compatible = "mediatek,mt7988-pcie", + "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0 0x11300000 0 0x2000>; + reg-names = "pcie-mac"; + linux,pci-domain = <0>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0x00 0x30000000 0x00 + 0x30000000 0x00 0x00200000>, + <0x82000000 0x00 0x30200000 0x00 + 0x30200000 0x00 0x07e00000>; + clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P0>, + <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P0>, + <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P0>, + <&infracfg CLK_INFRA_133M_PCIE_CK_P0>; + clock-names = "pl_250m", "tl_26m", "peri_26m", + "top_133m"; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc0 0>, + <0 0 0 2 &pcie_intc0 1>, + <0 0 0 3 &pcie_intc0 2>, + <0 0 0 4 &pcie_intc0 3>; + pcie_intc0: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + pcie1: pcie@11310000 { + compatible = "mediatek,mt7988-pcie", + "mediatek,mt7986-pcie", + "mediatek,mt8192-pcie"; + device_type = "pci"; + #address-cells = <3>; + #size-cells = <2>; + reg = <0 0x11310000 0 0x2000>; + reg-names = "pcie-mac"; + linux,pci-domain = <1>; + interrupts = ; + bus-range = <0x00 0xff>; + ranges = <0x81000000 0x00 0x38000000 0x00 + 0x38000000 0x00 0x00200000>, + <0x82000000 0x00 0x38200000 0x00 + 0x38200000 0x00 0x07e00000>; + clocks = <&infracfg CLK_INFRA_PCIE_PIPE_P1>, + <&infracfg CLK_INFRA_PCIE_GFMUX_TL_P1>, + <&infracfg CLK_INFRA_PCIE_PERI_26M_CK_P1>, + <&infracfg CLK_INFRA_133M_PCIE_CK_P1>; + clock-names = "pl_250m", "tl_26m", "peri_26m", + "top_133m"; + status = "disabled"; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0x7>; + interrupt-map = <0 0 0 1 &pcie_intc1 0>, + <0 0 0 2 &pcie_intc1 1>, + <0 0 0 3 &pcie_intc1 2>, + <0 0 0 4 &pcie_intc1 3>; + pcie_intc1: interrupt-controller { + #address-cells = <0>; + #interrupt-cells = <1>; + interrupt-controller; + }; + }; + + ssusb0: usb@11190000 { + compatible = "mediatek,mt7988-xhci", + "mediatek,mtk-xhci"; + reg = <0 0x11190000 0 0x2e00>, + <0 0x11193e00 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + phys = <&xphyu2port0 PHY_TYPE_USB2>, + <&xphyu3port0 PHY_TYPE_USB3>; + clocks = <&infracfg CLK_INFRA_USB_SYS>, + <&infracfg CLK_INFRA_USB_XHCI>, + <&infracfg CLK_INFRA_USB_REF>, + <&infracfg CLK_INFRA_66M_USB_HCK>, + <&infracfg CLK_INFRA_133M_USB_HCK>; + clock-names = "sys_ck", + "xhci_ck", + "ref_ck", + "mcu_ck", + "dma_ck"; + #address-cells = <2>; + #size-cells = <2>; + mediatek,p0_speed_fixup; + status = "disabled"; + }; + + ssusb1: usb@11200000 { + compatible = "mediatek,mt7988-xhci", + "mediatek,mtk-xhci"; + reg = <0 0x11200000 0 0x2e00>, + <0 0x11203e00 0 0x0100>; + reg-names = "mac", "ippc"; + interrupts = ; + phys = <&tphyu2port0 PHY_TYPE_USB2>, + <&tphyu3port0 PHY_TYPE_USB3>; + clocks = <&infracfg CLK_INFRA_USB_SYS_CK_P1>, + <&infracfg CLK_INFRA_USB_XHCI_CK_P1>, + <&infracfg CLK_INFRA_USB_CK_P1>, + <&infracfg CLK_INFRA_66M_USB_HCK_CK_P1>, + <&infracfg CLK_INFRA_133M_USB_HCK_CK_P1>; + clock-names = "sys_ck", + "xhci_ck", + "ref_ck", + "mcu_ck", + "dma_ck"; + #address-cells = <2>; + #size-cells = <2>; + status = "disabled"; + }; + + tphy: tphy@11c50000 { + compatible = "mediatek,mt7988", + "mediatek,generic-tphy-v2"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + tphyu2port0: usb-phy@11c50000 { + reg = <0 0x11c50000 0 0x700>; + clocks = <&infracfg CLK_INFRA_USB_UTMI_CK_P1>; + clock-names = "ref"; + #phy-cells = <1>; + }; + tphyu3port0: usb-phy@11c50700 { + reg = <0 0x11c50700 0 0x900>; + clocks = <&infracfg CLK_INFRA_USB_PIPE_CK_P1>; + clock-names = "ref"; + #phy-cells = <1>; + mediatek,usb3-pll-ssc-delta; + mediatek,usb3-pll-ssc-delta1; + }; + }; + + topmisc: topmisc@11d10000 { + compatible = "mediatek,mt7988-topmisc", "syscon", + "mediatek,mt7988-power-controller"; + reg = <0 0x11d10000 0 0x10000>; + #clock-cells = <1>; + #power-domain-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + + xphy: xphy@11e10000 { + compatible = "mediatek,mt7988", + "mediatek,xsphy"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + xphyu2port0: usb-phy@11e10000 { + reg = <0 0x11e10000 0 0x400>; + clocks = <&infracfg CLK_INFRA_USB_UTMI>; + clock-names = "ref"; + #phy-cells = <1>; + }; + + xphyu3port0: usb-phy@11e13000 { + reg = <0 0x11e13400 0 0x500>; + clocks = <&infracfg CLK_INFRA_USB_PIPE>; + clock-names = "ref"; + #phy-cells = <1>; + mediatek,syscon-type = <&topmisc 0x218 0>; + }; + }; + + efuse: efuse@11f50000 { + compatible = "mediatek,efuse"; + reg = <0 0x11f50000 0 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + lvts_calibration: calib@918 { + reg = <0x918 0x28>; + }; + phy_calibration_p0: calib@940 { + reg = <0x940 0x10>; + }; + phy_calibration_p1: calib@954 { + reg = <0x954 0x10>; + }; + phy_calibration_p2: calib@968 { + reg = <0x968 0x10>; + }; + phy_calibration_p3: calib@97c { + reg = <0x97c 0x10>; + }; + cpufreq_calibration: calib@278 { + reg = <0x278 0x1>; + }; + }; + + ethsys: syscon@15000000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mediatek,mt7988-ethsys", "syscon"; + reg = <0 0x15000000 0 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + switch: switch@15020000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "mediatek,mt7988-switch"; + reg = <0 0x15020000 0 0x8000>; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&gic>; + interrupts = ; + resets = <ðrst 0>; + }; + + ethwarp: syscon@15031000 { + compatible = "mediatek,mt7988-ethwarp", "syscon", "simple-mfd"; + reg = <0 0x15031000 0 0x1000>; + #clock-cells = <1>; + + ethrst: reset-controller { + compatible = "ti,syscon-reset"; + #reset-cells = <1>; + ti,reset-bits = < + 0x8 9 0x8 9 0 0 (ASSERT_SET | DEASSERT_CLEAR | STATUS_NONE) + >; + }; + }; + + eth: ethernet@15100000 { + compatible = "mediatek,mt7988-eth"; + reg = <0 0x15100000 0 0x80000>, + <0 0x15400000 0 0x380000>; + interrupts = , + , + , + ; + clocks = <ðsys CLK_ETHDMA_XGP1_EN>, + <ðsys CLK_ETHDMA_XGP2_EN>, + <ðsys CLK_ETHDMA_XGP3_EN>, + <ðsys CLK_ETHDMA_FE_EN>, + <ðsys CLK_ETHDMA_GP2_EN>, + <ðsys CLK_ETHDMA_GP1_EN>, + <ðsys CLK_ETHDMA_GP3_EN>, + <ðsys CLK_ETHDMA_ESW_EN>, + <ðsys CLK_ETHDMA_CRYPT0_EN>, + <&sgmiisys0 CLK_SGM0_TX_EN>, + <&sgmiisys0 CLK_SGM0_RX_EN>, + <&sgmiisys1 CLK_SGM1_TX_EN>, + <&sgmiisys1 CLK_SGM1_RX_EN>, + <ðwarp CLK_ETHWARP_WOCPU2_EN>, + <ðwarp CLK_ETHWARP_WOCPU1_EN>, + <ðwarp CLK_ETHWARP_WOCPU0_EN>, + <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>, + <&topckgen CLK_TOP_USXGMII_SBUS_1_SEL>, + <&topckgen CLK_TOP_SGM_0_SEL>, + <&topckgen CLK_TOP_SGM_1_SEL>, + <&topckgen CLK_TOP_XFI_PHY_0_XTAL_SEL>, + <&topckgen CLK_TOP_XFI_PHY_1_XTAL_SEL>, + <&topckgen CLK_TOP_ETH_GMII_SEL>, + <&topckgen CLK_TOP_ETH_REFCK_50M_SEL>, + <&topckgen CLK_TOP_ETH_SYS_200M_SEL>, + <&topckgen CLK_TOP_ETH_SYS_SEL>, + <&topckgen CLK_TOP_ETH_XGMII_SEL>, + <&topckgen CLK_TOP_ETH_MII_SEL>, + <&topckgen CLK_TOP_NETSYS_SEL>, + <&topckgen CLK_TOP_NETSYS_500M_SEL>, + <&topckgen CLK_TOP_NETSYS_PAO_2X_SEL>, + <&topckgen CLK_TOP_NETSYS_SYNC_250M_SEL>, + <&topckgen CLK_TOP_NETSYS_PPEFB_250M_SEL>, + <&topckgen CLK_TOP_NETSYS_WARP_SEL>; + clock-names = "xgp1", "xgp2", "xgp3", "fe", "gp2", "gp1", + "gp3", "esw", "crypto", "sgmii_tx250m", + "sgmii_rx250m", "sgmii2_tx250m", "sgmii2_rx250m", + "ethwarp_wocpu2", "ethwarp_wocpu1", + "ethwarp_wocpu0", "top_usxgmii0_sel", + "top_usxgmii1_sel", "top_sgm0_sel", + "top_sgm1_sel", "top_xfi_phy0_xtal_sel", + "top_xfi_phy1_xtal_sel", "top_eth_gmii_sel", + "top_eth_refck_50m_sel", "top_eth_sys_200m_sel", + "top_eth_sys_sel", "top_eth_xgmii_sel", + "top_eth_mii_sel", "top_netsys_sel", + "top_netsys_500m_sel", "top_netsys_pao_2x_sel", + "top_netsys_sync_250m_sel", + "top_netsys_ppefb_250m_sel", + "top_netsys_warp_sel"; + assigned-clocks = <&topckgen CLK_TOP_NETSYS_2X_SEL>, + <&topckgen CLK_TOP_NETSYS_GSW_SEL>, + <&topckgen CLK_TOP_USXGMII_SBUS_0_SEL>, + <&topckgen CLK_TOP_USXGMII_SBUS_1_SEL>, + <&topckgen CLK_TOP_SGM_0_SEL>, + <&topckgen CLK_TOP_SGM_1_SEL>; + assigned-clock-parents = <&apmixedsys CLK_APMIXED_NET2PLL>, + <&topckgen CLK_TOP_NET1PLL_D4>, + <&topckgen CLK_TOP_NET1PLL_D8_D4>, + <&topckgen CLK_TOP_NET1PLL_D8_D4>, + <&apmixedsys CLK_APMIXED_SGMPLL>, + <&apmixedsys CLK_APMIXED_SGMPLL>; + mediatek,ethsys = <ðsys>; + mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>; + mediatek,usxgmiisys = <&usxgmiisys0>, <&usxgmiisys1>; + mediatek,xfi_pextp = <&xfi_pextp0>, <&xfi_pextp1>; + mediatek,xfi_pll = <&xfi_pll>; + mediatek,infracfg = <&topmisc>; + mediatek,toprgu = <&watchdog>; + #reset-cells = <1>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + }; +}; diff --git a/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-apmixed.c b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-apmixed.c new file mode 100644 index 00000000000..587b70767eb --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-apmixed.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" +#include + +#define MT7988_PLL_FMAX (2500UL * MHZ) +#define MT7988_PCW_CHG_SHIFT 2 + +#define PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, \ + _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, \ + _div_table) \ + { \ + .id = _id, .name = _name, .reg = _reg, .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, .flags = _flags, \ + .rst_bar_mask = BIT(_rst_bar_mask), .fmax = MT7988_PLL_FMAX, \ + .pcwbits = _pcwbits, .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, .pcw_shift = _pcw_shift, \ + .pcw_chg_reg = _pcw_chg_reg, \ + .pcw_chg_shift = MT7988_PCW_CHG_SHIFT, \ + .div_table = _div_table, .parent_name = "clkxtal", \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, \ + _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg) \ + PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _rst_bar_mask, \ + _pcwbits, _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, _pcw_chg_reg, NULL) + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_NETSYSPLL, "netsyspll", 0x0104, 0x0110, 0x00000001, 0, + 0, 32, 0x0104, 4, 0, 0, 0, 0x0108, 0, 0x0104), + PLL(CLK_APMIXED_MPLL, "mpll", 0x0114, 0x0120, 0xff000001, HAVE_RST_BAR, + 23, 32, 0x0114, 4, 0, 0, 0, 0x0118, 0, 0x0114), + PLL(CLK_APMIXED_MMPLL, "mmpll", 0x0124, 0x0130, 0xff000001, + HAVE_RST_BAR, 23, 32, 0x0124, 4, 0, 0, 0, 0x0128, 0, 0x0124), + PLL(CLK_APMIXED_APLL2, "apll2", 0x0134, 0x0140, 0x00000001, 0, 0, 32, + 0x0134, 4, 0x0704, 0x0700, 1, 0x0138, 0, 0x0134), + PLL(CLK_APMIXED_NET1PLL, "net1pll", 0x0144, 0x0150, 0xff000001, + HAVE_RST_BAR, 23, 32, 0x0144, 4, 0, 0, 0, 0x0148, 0, 0x0144), + PLL(CLK_APMIXED_NET2PLL, "net2pll", 0x0154, 0x0160, 0xff000001, + (HAVE_RST_BAR | PLL_AO), 23, 32, 0x0154, 4, 0, 0, 0, 0x0158, 0, + 0x0154), + PLL(CLK_APMIXED_WEDMCUPLL, "wedmcupll", 0x0164, 0x0170, 0x00000001, 0, + 0, 32, 0x0164, 4, 0, 0, 0, 0x0168, 0, 0x0164), + PLL(CLK_APMIXED_SGMPLL, "sgmpll", 0x0174, 0x0180, 0x00000001, 0, 0, 32, + 0x0174, 4, 0, 0, 0, 0x0178, 0, 0x0174), + PLL(CLK_APMIXED_ARM_B, "arm_b", 0x0204, 0x0210, 0xff000001, + (HAVE_RST_BAR | PLL_AO), 23, 32, 0x0204, 4, 0, 0, 0, 0x0208, 0, + 0x0204), + PLL(CLK_APMIXED_CCIPLL2_B, "ccipll2_b", 0x0214, 0x0220, 0xff000001, + HAVE_RST_BAR, 23, 32, 0x0214, 4, 0, 0, 0, 0x0218, 0, 0x0214), + PLL(CLK_APMIXED_USXGMIIPLL, "usxgmiipll", 0x0304, 0x0310, 0xff000001, + HAVE_RST_BAR, 23, 32, 0x0304, 4, 0, 0, 0, 0x0308, 0, 0x0304), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0314, 0x0320, 0x00000001, 0, 0, + 32, 0x0314, 4, 0, 0, 0, 0x0318, 0, 0x0314), +}; + +static const struct of_device_id of_match_clk_mt7988_apmixed[] = { + { + .compatible = "mediatek,mt7988-apmixedsys", + }, + {} +}; + +static int clk_mt7988_apmixed_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(plls)); + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_apmixed_data; + } + return r; + +free_apmixed_data: + mtk_free_clk_data(clk_data); + return r; +} + +static struct platform_driver clk_mt7988_apmixed_drv = { + .probe = clk_mt7988_apmixed_probe, + .driver = { + .name = "clk-mt7988-apmixed", + .of_match_table = of_match_clk_mt7988_apmixed, + }, +}; +builtin_platform_driver(clk_mt7988_apmixed_drv); diff --git a/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-eth.c b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-eth.c new file mode 100644 index 00000000000..341d0f73fd3 --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-eth.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include + +static const struct mtk_gate_regs ethdma_cg_regs = { + .set_ofs = 0x30, + .clr_ofs = 0x30, + .sta_ofs = 0x30, +}; + +#define GATE_ETHDMA(_id, _name, _parent, _shift) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = ðdma_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate ethdma_clks[] = { + GATE_ETHDMA(CLK_ETHDMA_XGP1_EN, "ethdma_xgp1_en", "top_xtal", 0), + GATE_ETHDMA(CLK_ETHDMA_XGP2_EN, "ethdma_xgp2_en", "top_xtal", 1), + GATE_ETHDMA(CLK_ETHDMA_XGP3_EN, "ethdma_xgp3_en", "top_xtal", 2), + GATE_ETHDMA(CLK_ETHDMA_FE_EN, "ethdma_fe_en", "netsys_2x_sel", 6), + GATE_ETHDMA(CLK_ETHDMA_GP2_EN, "ethdma_gp2_en", "top_xtal", 7), + GATE_ETHDMA(CLK_ETHDMA_GP1_EN, "ethdma_gp1_en", "top_xtal", 8), + GATE_ETHDMA(CLK_ETHDMA_GP3_EN, "ethdma_gp3_en", "top_xtal", 10), + GATE_ETHDMA(CLK_ETHDMA_ESW_EN, "ethdma_esw_en", "netsys_gsw_sel", 16), + GATE_ETHDMA(CLK_ETHDMA_CRYPT0_EN, "ethdma_crypt0_en", "eip197_sel", + 29), +}; + +static int clk_mt7988_ethsys_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(ethdma_clks)); + + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_gates(node, ethdma_clks, ARRAY_SIZE(ethdma_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_data; + } + return r; + +free_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const struct mtk_gate_regs sgmii0_cg_regs = { + .set_ofs = 0xe4, + .clr_ofs = 0xe4, + .sta_ofs = 0xe4, +}; + +#define GATE_SGMII0(_id, _name, _parent, _shift) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &sgmii0_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate sgmii0_clks[] = { + GATE_SGMII0(CLK_SGM0_TX_EN, "sgm0_tx_en", "top_xtal", 2), + GATE_SGMII0(CLK_SGM0_RX_EN, "sgm0_rx_en", "top_xtal", 3), +}; + +static int clk_mt7988_sgmii0_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii0_clks)); + + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_gates(node, sgmii0_clks, ARRAY_SIZE(sgmii0_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_data; + } + return r; + +free_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const struct mtk_gate_regs sgmii1_cg_regs = { + .set_ofs = 0xe4, + .clr_ofs = 0xe4, + .sta_ofs = 0xe4, +}; + +#define GATE_SGMII1(_id, _name, _parent, _shift) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &sgmii1_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate sgmii1_clks[] = { + GATE_SGMII1(CLK_SGM1_TX_EN, "sgm1_tx_en", "top_xtal", 2), + GATE_SGMII1(CLK_SGM1_RX_EN, "sgm1_rx_en", "top_xtal", 3), +}; + +static int clk_mt7988_sgmii1_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(sgmii1_clks)); + + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_gates(node, sgmii1_clks, ARRAY_SIZE(sgmii1_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_data; + } + return r; + +free_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const struct mtk_gate_regs ethwarp_cg_regs = { + .set_ofs = 0x14, + .clr_ofs = 0x14, + .sta_ofs = 0x14, +}; + +#define GATE_ETHWARP(_id, _name, _parent, _shift) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = ðwarp_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate ethwarp_clks[] = { + GATE_ETHWARP(CLK_ETHWARP_WOCPU2_EN, "ethwarp_wocpu2_en", + "netsys_mcu_sel", 13), + GATE_ETHWARP(CLK_ETHWARP_WOCPU1_EN, "ethwarp_wocpu1_en", + "netsys_mcu_sel", 14), + GATE_ETHWARP(CLK_ETHWARP_WOCPU0_EN, "ethwarp_wocpu0_en", + "netsys_mcu_sel", 15), +}; + +static int clk_mt7988_ethwarp_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(ARRAY_SIZE(ethwarp_clks)); + + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_gates(node, ethwarp_clks, ARRAY_SIZE(ethwarp_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_data; + } + return r; + +free_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const struct of_device_id of_match_clk_mt7988_ethsys[] = { + { + .compatible = "mediatek,mt7988-ethsys", + }, + {} +}; + +static struct platform_driver clk_mt7988_ethsys_drv = { + .probe = clk_mt7988_ethsys_probe, + .driver = { + .name = "clk-mt7988-ethsys", + .of_match_table = of_match_clk_mt7988_ethsys, + }, +}; +builtin_platform_driver(clk_mt7988_ethsys_drv); + +static const struct of_device_id of_match_clk_mt7988_sgmii0[] = { + { + .compatible = "mediatek,mt7988-sgmiisys_0", + }, + {} +}; + +static struct platform_driver clk_mt7988_sgmii0_drv = { + .probe = clk_mt7988_sgmii0_probe, + .driver = { + .name = "clk-mt7988-sgmiisys_0", + .of_match_table = of_match_clk_mt7988_sgmii0, + }, +}; +builtin_platform_driver(clk_mt7988_sgmii0_drv); + +static const struct of_device_id of_match_clk_mt7988_sgmii1[] = { + { + .compatible = "mediatek,mt7988-sgmiisys_1", + }, + {} +}; + +static struct platform_driver clk_mt7988_sgmii1_drv = { + .probe = clk_mt7988_sgmii1_probe, + .driver = { + .name = "clk-mt7988-sgmiisys_1", + .of_match_table = of_match_clk_mt7988_sgmii1, + }, +}; +builtin_platform_driver(clk_mt7988_sgmii1_drv); + +static const struct of_device_id of_match_clk_mt7988_ethwarp[] = { + { + .compatible = "mediatek,mt7988-ethwarp", + }, + {} +}; + +static struct platform_driver clk_mt7988_ethwarp_drv = { + .probe = clk_mt7988_ethwarp_probe, + .driver = { + .name = "clk-mt7988-ethwarp", + .of_match_table = of_match_clk_mt7988_ethwarp, + }, +}; +builtin_platform_driver(clk_mt7988_ethwarp_drv); \ No newline at end of file diff --git a/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-infracfg.c b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-infracfg.c new file mode 100644 index 00000000000..77e25383b6e --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-infracfg.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" +#include + +static DEFINE_SPINLOCK(mt7988_clk_lock); + +static const char *const infra_mux_uart0_parents[] __initconst = { + "csw_infra_f26m_sel", "uart_sel" +}; + +static const char *const infra_mux_uart1_parents[] __initconst = { + "csw_infra_f26m_sel", "uart_sel" +}; + +static const char *const infra_mux_uart2_parents[] __initconst = { + "csw_infra_f26m_sel", "uart_sel" +}; + +static const char *const infra_mux_spi0_parents[] __initconst = { "i2c_sel", + "spi_sel" }; + +static const char *const infra_mux_spi1_parents[] __initconst = { + "i2c_sel", "spim_mst_sel" +}; + +static const char *const infra_pwm_bck_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "sysaxi_sel", "pwm_sel" +}; + +static const char *const infra_pcie_gfmux_tl_ck_o_p0_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", + "pextp_tl_sel" +}; + +static const char *const infra_pcie_gfmux_tl_ck_o_p1_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", + "pextp_tl_p1_sel" +}; + +static const char *const infra_pcie_gfmux_tl_ck_o_p2_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", + "pextp_tl_p2_sel" +}; + +static const char *const infra_pcie_gfmux_tl_ck_o_p3_parents[] __initconst = { + "top_rtc_32p7k", "csw_infra_f26m_sel", "csw_infra_f26m_sel", + "pextp_tl_p3_sel" +}; + +static const struct mtk_mux infra_muxes[] = { + /* MODULE_CLK_SEL_0 */ + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel", + infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, + 0, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel", + infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, + 1, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel", + infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, + 2, 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel", + infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 4, + 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel", + infra_mux_spi1_parents, 0x0018, 0x0010, 0x0014, 5, + 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel", + infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 6, + 1, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_SEL, "infra_pwm_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 14, + 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 16, + 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 18, + 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 20, + 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 22, + 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 24, + 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 26, + 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 28, + 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel", + infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 30, + 2, -1, -1, -1), + /* MODULE_CLK_SEL_1 */ + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL, + "infra_pcie_gfmux_tl_o_p0_sel", + infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028, + 0x0020, 0x0024, 0, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL, + "infra_pcie_gfmux_tl_o_p1_sel", + infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028, + 0x0020, 0x0024, 2, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL, + "infra_pcie_gfmux_tl_o_p2_sel", + infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028, + 0x0020, 0x0024, 4, 2, -1, -1, -1), + MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL, + "infra_pcie_gfmux_tl_o_p3_sel", + infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028, + 0x0020, 0x0024, 6, 2, -1, -1, -1), +}; + +static const struct mtk_gate_regs infra0_cg_regs = { + .set_ofs = 0x10, + .clr_ofs = 0x14, + .sta_ofs = 0x18, +}; + +static const struct mtk_gate_regs infra1_cg_regs = { + .set_ofs = 0x40, + .clr_ofs = 0x44, + .sta_ofs = 0x48, +}; + +static const struct mtk_gate_regs infra2_cg_regs = { + .set_ofs = 0x50, + .clr_ofs = 0x54, + .sta_ofs = 0x58, +}; + +static const struct mtk_gate_regs infra3_cg_regs = { + .set_ofs = 0x60, + .clr_ofs = 0x64, + .sta_ofs = 0x68, +}; + +#define GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, _flags) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &infra0_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, .flags = _flags, \ + } + +#define GATE_INFRA1_FLAGS(_id, _name, _parent, _shift, _flags) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &infra1_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, .flags = _flags, \ + } + +#define GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, _flags) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &infra2_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, .flags = _flags, \ + } + +#define GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, _flags) \ + { \ + .id = _id, .name = _name, .parent_name = _parent, \ + .regs = &infra3_cg_regs, .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, .flags = _flags, \ + } + +#define GATE_INFRA0(_id, _name, _parent, _shift) \ + GATE_INFRA0_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA1(_id, _name, _parent, _shift) \ + GATE_INFRA1_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA2(_id, _name, _parent, _shift) \ + GATE_INFRA2_FLAGS(_id, _name, _parent, _shift, 0) + +#define GATE_INFRA3(_id, _name, _parent, _shift) \ + GATE_INFRA3_FLAGS(_id, _name, _parent, _shift, 0) + +static const struct mtk_gate infra_clks[] = { + /* INFRA0 */ + GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P0, + "infra_pcie_peri_ck_26m_ck_p0", "csw_infra_f26m_sel", 7), + GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P1, + "infra_pcie_peri_ck_26m_ck_p1", "csw_infra_f26m_sel", 8), + GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P2, + "infra_pcie_peri_ck_26m_ck_p2", "csw_infra_f26m_sel", 9), + GATE_INFRA0(CLK_INFRA_PCIE_PERI_26M_CK_P3, + "infra_pcie_peri_ck_26m_ck_p3", "csw_infra_f26m_sel", 10), + /* INFRA1 */ + GATE_INFRA1(CLK_INFRA_66M_GPT_BCK, "infra_hf_66m_gpt_bck", + "sysaxi_sel", 0), + GATE_INFRA1(CLK_INFRA_66M_PWM_HCK, "infra_hf_66m_pwm_hck", + "sysaxi_sel", 1), + GATE_INFRA1(CLK_INFRA_66M_PWM_BCK, "infra_hf_66m_pwm_bck", + "infra_pwm_sel", 2), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK1, "infra_hf_66m_pwm_ck1", + "infra_pwm_ck1_sel", 3), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK2, "infra_hf_66m_pwm_ck2", + "infra_pwm_ck2_sel", 4), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK3, "infra_hf_66m_pwm_ck3", + "infra_pwm_ck3_sel", 5), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK4, "infra_hf_66m_pwm_ck4", + "infra_pwm_ck4_sel", 6), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK5, "infra_hf_66m_pwm_ck5", + "infra_pwm_ck5_sel", 7), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK6, "infra_hf_66m_pwm_ck6", + "infra_pwm_ck6_sel", 8), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK7, "infra_hf_66m_pwm_ck7", + "infra_pwm_ck7_sel", 9), + GATE_INFRA1(CLK_INFRA_66M_PWM_CK8, "infra_hf_66m_pwm_ck8", + "infra_pwm_ck8_sel", 10), + GATE_INFRA1(CLK_INFRA_133M_CQDMA_BCK, "infra_hf_133m_cqdma_bck", + "sysaxi_sel", 12), + GATE_INFRA1(CLK_INFRA_66M_AUD_SLV_BCK, "infra_66m_aud_slv_bck", + "sysaxi_sel", 13), + GATE_INFRA1(CLK_INFRA_AUD_26M, "infra_f_faud_26m", + "csw_infra_f26m_sel", 14), + GATE_INFRA1(CLK_INFRA_AUD_L, "infra_f_faud_l", "aud_l_sel", 15), + GATE_INFRA1(CLK_INFRA_AUD_AUD, "infra_f_aud_aud", "a1sys_sel", 16), + GATE_INFRA1(CLK_INFRA_AUD_EG2, "infra_f_faud_eg2", "a_tuner_sel", 18), + GATE_INFRA1_FLAGS(CLK_INFRA_DRAMC_F26M, "infra_dramc_f26m", + "csw_infra_f26m_sel", 19, CLK_IS_CRITICAL), + // JTAG + GATE_INFRA1_FLAGS(CLK_INFRA_133M_DBG_ACKM, "infra_hf_133m_dbg_ackm", + "sysaxi_sel", 20, CLK_IS_CRITICAL), + GATE_INFRA1(CLK_INFRA_66M_AP_DMA_BCK, "infra_66m_ap_dma_bck", + "sysaxi_sel", 21), + GATE_INFRA1(CLK_INFRA_66M_SEJ_BCK, "infra_hf_66m_sej_bck", + "sysaxi_sel", 29), + GATE_INFRA1(CLK_INFRA_PRE_CK_SEJ_F13M, "infra_pre_ck_sej_f13m", + "csw_infra_f26m_sel", 30), + /* INFRA2 */ + GATE_INFRA2(CLK_INFRA_26M_THERM_SYSTEM, "infra_hf_26m_therm_system", + "csw_infra_f26m_sel", 0), + GATE_INFRA2(CLK_INFRA_I2C_BCK, "infra_i2c_bck", "i2c_sel", 1), + GATE_INFRA2(CLK_INFRA_52M_UART0_CK, "infra_f_52m_uart0", + "infra_mux_uart0_sel", 3), + GATE_INFRA2(CLK_INFRA_52M_UART1_CK, "infra_f_52m_uart1", + "infra_mux_uart1_sel", 4), + GATE_INFRA2(CLK_INFRA_52M_UART2_CK, "infra_f_52m_uart2", + "infra_mux_uart2_sel", 5), + GATE_INFRA2(CLK_INFRA_NFI, "infra_f_fnfi", "nfi1x_sel", 9), + GATE_INFRA2(CLK_INFRA_SPINFI, "infra_f_fspinfi", "spinfi_sel", 10), + GATE_INFRA2_FLAGS(CLK_INFRA_66M_NFI_HCK, "infra_hf_66m_nfi_hck", + "sysaxi_sel", 11, CLK_IS_CRITICAL), + GATE_INFRA2_FLAGS(CLK_INFRA_104M_SPI0, "infra_hf_104m_spi0", + "infra_mux_spi0_sel", 12, CLK_IS_CRITICAL), + GATE_INFRA2(CLK_INFRA_104M_SPI1, "infra_hf_104m_spi1", + "infra_mux_spi1_sel", 13), + GATE_INFRA2(CLK_INFRA_104M_SPI2_BCK, "infra_hf_104m_spi2_bck", + "infra_mux_spi2_sel", 14), + GATE_INFRA2_FLAGS(CLK_INFRA_66M_SPI0_HCK, "infra_hf_66m_spi0_hck", + "sysaxi_sel", 15, CLK_IS_CRITICAL), + GATE_INFRA2(CLK_INFRA_66M_SPI1_HCK, "infra_hf_66m_spi1_hck", + "sysaxi_sel", 16), + GATE_INFRA2(CLK_INFRA_66M_SPI2_HCK, "infra_hf_66m_spi2_hck", + "sysaxi_sel", 17), + GATE_INFRA2(CLK_INFRA_66M_FLASHIF_AXI, "infra_hf_66m_flashif_axi", + "sysaxi_sel", 18), + GATE_INFRA2(CLK_INFRA_RTC, "infra_f_frtc", "top_rtc_32k", 19), + GATE_INFRA2(CLK_INFRA_26M_ADC_BCK, "infra_f_26m_adc_bck", + "csw_infra_f26m_sel", 20), + GATE_INFRA2(CLK_INFRA_RC_ADC, "infra_f_frc_adc", "infra_f_26m_adc_bck", + 21), + GATE_INFRA2(CLK_INFRA_MSDC400, "infra_f_fmsdc400", "emmc_400m_sel", + 22), + GATE_INFRA2(CLK_INFRA_MSDC2_HCK, "infra_f_fmsdc2_hck", "emmc_250m_sel", + 23), + GATE_INFRA2(CLK_INFRA_133M_MSDC_0_HCK, "infra_hf_133m_msdc_0_hck", + "sysaxi_sel", 24), + GATE_INFRA2(CLK_INFRA_66M_MSDC_0_HCK, "infra_66m_msdc_0_hck", + "sysaxi_sel", 25), + GATE_INFRA2(CLK_INFRA_133M_CPUM_BCK, "infra_hf_133m_cpum_bck", + "sysaxi_sel", 26), + GATE_INFRA2(CLK_INFRA_BIST2FPC, "infra_hf_fbist2fpc", "nfi1x_sel", 27), + GATE_INFRA2(CLK_INFRA_I2C_X16W_MCK_CK_P1, + "infra_hf_i2c_x16w_mck_ck_p1", "sysaxi_sel", 29), + GATE_INFRA2(CLK_INFRA_I2C_X16W_PCK_CK_P1, + "infra_hf_i2c_x16w_pck_ck_p1", "sysaxi_sel", 31), + /* INFRA3 */ + GATE_INFRA3(CLK_INFRA_133M_USB_HCK, "infra_133m_usb_hck", "sysaxi_sel", + 0), + GATE_INFRA3(CLK_INFRA_133M_USB_HCK_CK_P1, "infra_133m_usb_hck_ck_p1", + "sysaxi_sel", 1), + GATE_INFRA3(CLK_INFRA_66M_USB_HCK, "infra_66m_usb_hck", "sysaxi_sel", + 2), + GATE_INFRA3(CLK_INFRA_66M_USB_HCK_CK_P1, "infra_66m_usb_hck_ck_p1", + "sysaxi_sel", 3), + GATE_INFRA3(CLK_INFRA_USB_SYS, "infra_usb_sys", "usb_sys_sel", 4), + GATE_INFRA3(CLK_INFRA_USB_SYS_CK_P1, "infra_usb_sys_ck_p1", + "usb_sys_p1_sel", 5), + GATE_INFRA3(CLK_INFRA_USB_REF, "infra_usb_ref", "top_xtal", 6), + GATE_INFRA3(CLK_INFRA_USB_CK_P1, "infra_usb_ck_p1", "top_xtal", 7), + GATE_INFRA3_FLAGS(CLK_INFRA_USB_FRMCNT, "infra_usb_frmcnt", + "usb_frmcnt_sel", 8, CLK_IS_CRITICAL), + GATE_INFRA3_FLAGS(CLK_INFRA_USB_FRMCNT_CK_P1, "infra_usb_frmcnt_ck_p1", + "usb_frmcnt_p1_sel", 9, CLK_IS_CRITICAL), + GATE_INFRA3(CLK_INFRA_USB_PIPE, "infra_usb_pipe", "sspxtp_sel", 10), + GATE_INFRA3(CLK_INFRA_USB_PIPE_CK_P1, "infra_usb_pipe_ck_p1", + "usb_phy_sel", 11), + GATE_INFRA3(CLK_INFRA_USB_UTMI, "infra_usb_utmi", "top_xtal", 12), + GATE_INFRA3(CLK_INFRA_USB_UTMI_CK_P1, "infra_usb_utmi_ck_p1", + "top_xtal", 13), + GATE_INFRA3(CLK_INFRA_USB_XHCI, "infra_usb_xhci", "usb_xhci_sel", 14), + GATE_INFRA3(CLK_INFRA_USB_XHCI_CK_P1, "infra_usb_xhci_ck_p1", + "usb_xhci_p1_sel", 15), + GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P0, "infra_pcie_gfmux_tl_ck_p0", + "infra_pcie_gfmux_tl_o_p0_sel", 20), + GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P1, "infra_pcie_gfmux_tl_ck_p1", + "infra_pcie_gfmux_tl_o_p1_sel", 21), + GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P2, "infra_pcie_gfmux_tl_ck_p2", + "infra_pcie_gfmux_tl_o_p2_sel", 22), + GATE_INFRA3(CLK_INFRA_PCIE_GFMUX_TL_P3, "infra_pcie_gfmux_tl_ck_p3", + "infra_pcie_gfmux_tl_o_p3_sel", 23), + GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P0, "infra_pcie_pipe_ck_p0", + "top_xtal", 24), + GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P1, "infra_pcie_pipe_ck_p1", + "top_xtal", 25), + GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P2, "infra_pcie_pipe_ck_p2", + "top_xtal", 26), + GATE_INFRA3(CLK_INFRA_PCIE_PIPE_P3, "infra_pcie_pipe_ck_p3", + "top_xtal", 27), + GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P0, "infra_133m_pcie_ck_p0", + "sysaxi_sel", 28), + GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P1, "infra_133m_pcie_ck_p1", + "sysaxi_sel", 29), + GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P2, "infra_133m_pcie_ck_p2", + "sysaxi_sel", 30), + GATE_INFRA3(CLK_INFRA_133M_PCIE_CK_P3, "infra_133m_pcie_ck_p3", + "sysaxi_sel", 31), +}; + +static int clk_mt7988_infracfg_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + int nr = ARRAY_SIZE(infra_muxes) + ARRAY_SIZE(infra_clks); + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(nr); + + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_muxes(infra_muxes, ARRAY_SIZE(infra_muxes), node, + &mt7988_clk_lock, clk_data); + + mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_infracfg_data; + } + return r; + +free_infracfg_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const struct of_device_id of_match_clk_mt7988_infracfg[] = { + { + .compatible = "mediatek,mt7988-infracfg", + }, + {} +}; + +static struct platform_driver clk_mt7988_infracfg_drv = { + .probe = clk_mt7988_infracfg_probe, + .driver = { + .name = "clk-mt7988-infracfg", + .of_match_table = of_match_clk_mt7988_infracfg, + }, +}; +builtin_platform_driver(clk_mt7988_infracfg_drv); diff --git a/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-topckgen.c b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-topckgen.c new file mode 100644 index 00000000000..917302b6df6 --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/clk/mediatek/clk-mt7988-topckgen.c @@ -0,0 +1,522 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#include +#include +#include +#include +#include +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-mux.h" +#include + +static DEFINE_SPINLOCK(mt7988_clk_lock); + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_XTAL, "top_xtal", "clkxtal", 40000000), +}; + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_XTAL_D2, "top_xtal_d2", "top_xtal", 1, 2), + FACTOR(CLK_TOP_RTC_32K, "top_rtc_32k", "top_xtal", 1, 1250), + FACTOR(CLK_TOP_RTC_32P7K, "top_rtc_32p7k", "top_xtal", 1, 1220), + FACTOR(CLK_TOP_MPLL_D2, "mpll_d2", "mpll", 1, 2), + FACTOR(CLK_TOP_MPLL_D3_D2, "mpll_d3_d2", "mpll", 1, 2), + FACTOR(CLK_TOP_MPLL_D4, "mpll_d4", "mpll", 1, 4), + FACTOR(CLK_TOP_MPLL_D8, "mpll_d8", "mpll", 1, 8), + FACTOR(CLK_TOP_MPLL_D8_D2, "mpll_d8_d2", "mpll", 1, 16), + FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2), + FACTOR(CLK_TOP_MMPLL_D3_D5, "mmpll_d3_d5", "mmpll", 1, 15), + FACTOR(CLK_TOP_MMPLL_D4, "mmpll_d4", "mmpll", 1, 4), + FACTOR(CLK_TOP_MMPLL_D6_D2, "mmpll_d6_d2", "mmpll", 1, 12), + FACTOR(CLK_TOP_MMPLL_D8, "mmpll_d8", "mmpll", 1, 8), + FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2", 1, 4), + FACTOR(CLK_TOP_NET1PLL_D4, "net1pll_d4", "net1pll", 1, 4), + FACTOR(CLK_TOP_NET1PLL_D5, "net1pll_d5", "net1pll", 1, 5), + FACTOR(CLK_TOP_NET1PLL_D5_D2, "net1pll_d5_d2", "net1pll", 1, 10), + FACTOR(CLK_TOP_NET1PLL_D5_D4, "net1pll_d5_d4", "net1pll", 1, 20), + FACTOR(CLK_TOP_NET1PLL_D8, "net1pll_d8", "net1pll", 1, 8), + FACTOR(CLK_TOP_NET1PLL_D8_D2, "net1pll_d8_d2", "net1pll", 1, 16), + FACTOR(CLK_TOP_NET1PLL_D8_D4, "net1pll_d8_d4", "net1pll", 1, 32), + FACTOR(CLK_TOP_NET1PLL_D8_D8, "net1pll_d8_d8", "net1pll", 1, 64), + FACTOR(CLK_TOP_NET1PLL_D8_D16, "net1pll_d8_d16", "net1pll", 1, 128), + FACTOR(CLK_TOP_NET2PLL_D2, "net2pll_d2", "net2pll", 1, 2), + FACTOR(CLK_TOP_NET2PLL_D4, "net2pll_d4", "net2pll", 1, 4), + FACTOR(CLK_TOP_NET2PLL_D4_D4, "net2pll_d4_d4", "net2pll", 1, 16), + FACTOR(CLK_TOP_NET2PLL_D4_D8, "net2pll_d4_d8", "net2pll", 1, 32), + FACTOR(CLK_TOP_NET2PLL_D6, "net2pll_d6", "net2pll", 1, 6), + FACTOR(CLK_TOP_NET2PLL_D8, "net2pll_d8", "net2pll", 1, 8), +}; + +static const char *const netsys_parents[] = { "top_xtal", "net2pll_d2", + "mmpll_d2" }; + +static const char *const netsys_500m_parents[] = { "top_xtal", "net1pll_d5", + "net1pll_d5_d2" }; + +static const char *const netsys_2x_parents[] = { "top_xtal", "net2pll", + "mmpll" }; + +static const char *const netsys_gsw_parents[] = { "top_xtal", "net1pll_d4", + "net1pll_d5" }; + +static const char *const eth_gmii_parents[] = { "top_xtal", "net1pll_d5_d4" }; + +static const char *const netsys_mcu_parents[] = { "top_xtal", "net2pll", + "mmpll", "net1pll_d4", + "net1pll_d5", "mpll" }; + +static const char *const eip197_parents[] = { "top_xtal", "netsyspll", + "net2pll", "mmpll", + "net1pll_d4", "net1pll_d5" }; + +static const char *const axi_infra_parents[] = { "top_xtal", "net1pll_d8_d2" }; + +static const char *const uart_parents[] = { "top_xtal", "mpll_d8", + "mpll_d8_d2" }; + +static const char *const emmc_250m_parents[] = { "top_xtal", "net1pll_d5_d2", + "mmpll_d4" }; + +static const char *const emmc_400m_parents[] = { "top_xtal", "msdcpll", + "mmpll_d2", "mpll_d2", + "mmpll_d4", "net1pll_d8_d2" }; + +static const char *const spi_parents[] = { "top_xtal", "mpll_d2", + "mmpll_d4", "net1pll_d8_d2", + "net2pll_d6", "net1pll_d5_d4", + "mpll_d4", "net1pll_d8_d4" }; + +static const char *const nfi1x_parents[] = { "top_xtal", "mmpll_d4", + "net1pll_d8_d2", "net2pll_d6", + "mpll_d4", "mmpll_d8", + "net1pll_d8_d4", "mpll_d8" }; + +static const char *const spinfi_parents[] = { "top_xtal_d2", "top_xtal", + "net1pll_d5_d4", "mpll_d4", + "mmpll_d8", "net1pll_d8_d4", + "mmpll_d6_d2", "mpll_d8" }; + +static const char *const pwm_parents[] = { "top_xtal", "net1pll_d8_d2", + "net1pll_d5_d4", "mpll_d4", + "mpll_d8_d2", "top_rtc_32k" }; + +static const char *const i2c_parents[] = { "top_xtal", "net1pll_d5_d4", + "mpll_d4", "net1pll_d8_d4" }; + +static const char *const pcie_mbist_250m_parents[] = { "top_xtal", + "net1pll_d5_d2" }; + +static const char *const pextp_tl_ck_parents[] = { "top_xtal", "net2pll_d6", + "mmpll_d8", "mpll_d8_d2", + "top_rtc_32k" }; + +static const char *const usb_frmcnt_parents[] = { "top_xtal", "mmpll_d3_d5" }; + +static const char *const aud_parents[] = { "top_xtal", "apll2" }; + +static const char *const a1sys_parents[] = { "top_xtal", "apll2_d4" }; + +static const char *const aud_l_parents[] = { "top_xtal", "apll2", + "mpll_d8_d2" }; + +static const char *const sspxtp_parents[] = { "top_xtal_d2", "mpll_d8_d2" }; + +static const char *const usxgmii_sbus_0_parents[] = { "top_xtal", + "net1pll_d8_d4" }; + +static const char *const sgm_0_parents[] = { "top_xtal", "sgmpll" }; + +static const char *const sysapb_parents[] = { "top_xtal", "mpll_d3_d2" }; + +static const char *const eth_refck_50m_parents[] = { "top_xtal", + "net2pll_d4_d4" }; + +static const char *const eth_sys_200m_parents[] = { "top_xtal", "net2pll_d4" }; + +static const char *const eth_xgmii_parents[] = { "top_xtal_d2", + "net1pll_d8_d8", + "net1pll_d8_d16" }; + +static const char *const bus_tops_parents[] = { "top_xtal", "net1pll_d5", + "net2pll_d2" }; + +static const char *const npu_tops_parents[] = { "top_xtal", "net2pll" }; + +static const char *const dramc_md32_parents[] = { "top_xtal", "mpll_d2", + "wedmcupll" }; + +static const char *const da_xtp_glb_p0_parents[] = { "top_xtal", + "net2pll_d8" }; + +static const char *const mcusys_backup_625m_parents[] = { "top_xtal", + "net1pll_d4" }; + +static const char *const macsec_parents[] = { "top_xtal", "sgmpll", + "net1pll_d8" }; + +static const char *const netsys_tops_400m_parents[] = { "top_xtal", + "net2pll_d2" }; + +static const char *const eth_mii_parents[] = { "top_xtal_d2", + "net2pll_d4_d8" }; + +static const struct mtk_mux top_muxes[] = { + /* CLK_CFG_0 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SEL, "netsys_sel", netsys_parents, + 0x000, 0x004, 0x008, 0, 2, 7, 0x1c0, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_500M_SEL, "netsys_500m_sel", + netsys_500m_parents, 0x000, 0x004, 0x008, 8, 2, + 15, 0x1C0, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_2X_SEL, "netsys_2x_sel", + netsys_2x_parents, 0x000, 0x004, 0x008, 16, 2, 23, + 0x1C0, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_GSW_SEL, "netsys_gsw_sel", + netsys_gsw_parents, 0x000, 0x004, 0x008, 24, 2, + 31, 0x1C0, 3), + /* CLK_CFG_1 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_GMII_SEL, "eth_gmii_sel", + eth_gmii_parents, 0x010, 0x014, 0x018, 0, 1, 7, + 0x1C0, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_MCU_SEL, "netsys_mcu_sel", + netsys_mcu_parents, 0x010, 0x014, 0x018, 8, 3, 15, + 0x1C0, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_PAO_2X_SEL, "netsys_pao_2x_sel", + netsys_mcu_parents, 0x010, 0x014, 0x018, 16, 3, + 23, 0x1C0, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EIP197_SEL, "eip197_sel", eip197_parents, + 0x010, 0x014, 0x018, 24, 3, 31, 0x1c0, 7), + /* CLK_CFG_2 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_AXI_INFRA_SEL, "axi_infra_sel", + axi_infra_parents, 0x020, 0x024, 0x028, 0, + 1, 7, 0x1C0, 8, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_parents, 0x020, + 0x024, 0x028, 8, 2, 15, 0x1c0, 9), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_250M_SEL, "emmc_250m_sel", + emmc_250m_parents, 0x020, 0x024, 0x028, 16, 2, 23, + 0x1C0, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_EMMC_400M_SEL, "emmc_400m_sel", + emmc_400m_parents, 0x020, 0x024, 0x028, 24, 3, 31, + 0x1C0, 11), + /* CLK_CFG_3 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_parents, 0x030, + 0x034, 0x038, 0, 3, 7, 0x1c0, 12), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPIM_MST_SEL, "spim_mst_sel", spi_parents, + 0x030, 0x034, 0x038, 8, 3, 15, 0x1c0, 13), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NFI1X_SEL, "nfi1x_sel", nfi1x_parents, + 0x030, 0x034, 0x038, 16, 3, 23, 0x1c0, 14), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SPINFI_SEL, "spinfi_sel", spinfi_parents, + 0x030, 0x034, 0x038, 24, 3, 31, 0x1c0, 15), + /* CLK_CFG_4 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, 0x040, + 0x044, 0x048, 0, 3, 7, 0x1c0, 16), + MUX_GATE_CLR_SET_UPD(CLK_TOP_I2C_SEL, "i2c_sel", i2c_parents, 0x040, + 0x044, 0x048, 8, 2, 15, 0x1c0, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PCIE_MBIST_250M_SEL, + "pcie_mbist_250m_sel", pcie_mbist_250m_parents, + 0x040, 0x044, 0x048, 16, 1, 23, 0x1C0, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_SEL, "pextp_tl_sel", + pextp_tl_ck_parents, 0x040, 0x044, 0x048, 24, 3, + 31, 0x1C0, 19), + /* CLK_CFG_5 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P1_SEL, "pextp_tl_p1_sel", + pextp_tl_ck_parents, 0x050, 0x054, 0x058, 0, 3, 7, + 0x1C0, 20), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P2_SEL, "pextp_tl_p2_sel", + pextp_tl_ck_parents, 0x050, 0x054, 0x058, 8, 3, + 15, 0x1C0, 21), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_TL_P3_SEL, "pextp_tl_p3_sel", + pextp_tl_ck_parents, 0x050, 0x054, 0x058, 16, 3, + 23, 0x1C0, 22), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_SYS_SEL, "usb_sys_sel", + eth_gmii_parents, 0x050, 0x054, 0x058, 24, 1, 31, + 0x1C0, 23), + /* CLK_CFG_6 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_SYS_P1_SEL, "usb_sys_p1_sel", + eth_gmii_parents, 0x060, 0x064, 0x068, 0, 1, 7, + 0x1C0, 24), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_SEL, "usb_xhci_sel", + eth_gmii_parents, 0x060, 0x064, 0x068, 8, 1, 15, + 0x1C0, 25), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_XHCI_P1_SEL, "usb_xhci_p1_sel", + eth_gmii_parents, 0x060, 0x064, 0x068, 16, 1, 23, + 0x1C0, 26), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_SEL, "usb_frmcnt_sel", + usb_frmcnt_parents, 0x060, 0x064, 0x068, 24, 1, + 31, 0x1C0, 27), + /* CLK_CFG_7 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_FRMCNT_P1_SEL, "usb_frmcnt_p1_sel", + usb_frmcnt_parents, 0x070, 0x074, 0x078, 0, 1, 7, + 0x1C0, 28), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_SEL, "aud_sel", aud_parents, 0x070, + 0x074, 0x078, 8, 1, 15, 0x1c0, 29), + MUX_GATE_CLR_SET_UPD(CLK_TOP_A1SYS_SEL, "a1sys_sel", a1sys_parents, + 0x070, 0x074, 0x078, 16, 1, 23, 0x1c0, 30), + MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD_L_SEL, "aud_l_sel", aud_l_parents, + 0x070, 0x074, 0x078, 24, 2, 31, 0x1c4, 0), + /* CLK_CFG_8 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_A_TUNER_SEL, "a_tuner_sel", a1sys_parents, + 0x080, 0x084, 0x088, 0, 1, 7, 0x1c4, 1), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SSPXTP_SEL, "sspxtp_sel", sspxtp_parents, + 0x080, 0x084, 0x088, 8, 1, 15, 0x1c4, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USB_PHY_SEL, "usb_phy_sel", + sspxtp_parents, 0x080, 0x084, 0x088, 16, 1, 23, + 0x1c4, 3), + MUX_GATE_CLR_SET_UPD(CLK_TOP_USXGMII_SBUS_0_SEL, "usxgmii_sbus_0_sel", + usxgmii_sbus_0_parents, 0x080, 0x084, 0x088, 24, + 1, 31, 0x1C4, 4), + /* CLK_CFG_9 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_USXGMII_SBUS_1_SEL, "usxgmii_sbus_1_sel", + usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, 0, 1, + 7, 0x1C4, 5), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_0_SEL, "sgm_0_sel", sgm_0_parents, + 0x090, 0x094, 0x098, 8, 1, 15, 0x1c4, 6), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_SBUS_0_SEL, "sgm_sbus_0_sel", + usxgmii_sbus_0_parents, 0x090, 0x094, 0x098, + 16, 1, 23, 0x1C4, 7, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_SGM_1_SEL, "sgm_1_sel", sgm_0_parents, + 0x090, 0x094, 0x098, 24, 1, 31, 0x1c4, 8), + /* CLK_CFG_10 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SGM_SBUS_1_SEL, "sgm_sbus_1_sel", + usxgmii_sbus_0_parents, 0x0a0, 0x0a4, 0x0a8, + 0, 1, 7, 0x1C4, 9, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_XFI_PHY_0_XTAL_SEL, "xfi_phy_0_xtal_sel", + sspxtp_parents, 0x0a0, 0x0a4, 0x0a8, 8, 1, 15, + 0x1C4, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_XFI_PHY_1_XTAL_SEL, "xfi_phy_1_xtal_sel", + sspxtp_parents, 0x0a0, 0x0a4, 0x0a8, 16, 1, 23, + 0x1C4, 11), + /* CLK_CFG_11 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAXI_SEL, "sysaxi_sel", + axi_infra_parents, 0x0a0, 0x0a4, 0x0a8, 24, + 1, 31, 0x1C4, 12, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_SYSAPB_SEL, "sysapb_sel", + sysapb_parents, 0x0b0, 0x0b4, 0x0b8, 0, 1, + 7, 0x1c4, 13, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_REFCK_50M_SEL, "eth_refck_50m_sel", + eth_refck_50m_parents, 0x0b0, 0x0b4, 0x0b8, 8, 1, + 15, 0x1C4, 14), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_SYS_200M_SEL, "eth_sys_200m_sel", + eth_sys_200m_parents, 0x0b0, 0x0b4, 0x0b8, 16, 1, + 23, 0x1C4, 15), + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_SYS_SEL, "eth_sys_sel", + pcie_mbist_250m_parents, 0x0b0, 0x0b4, 0x0b8, 24, + 1, 31, 0x1C4, 16), + /* CLK_CFG_12 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_XGMII_SEL, "eth_xgmii_sel", + eth_xgmii_parents, 0x0c0, 0x0c4, 0x0c8, 0, 2, 7, + 0x1C4, 17), + MUX_GATE_CLR_SET_UPD(CLK_TOP_BUS_TOPS_SEL, "bus_tops_sel", + bus_tops_parents, 0x0c0, 0x0c4, 0x0c8, 8, 2, 15, + 0x1C4, 18), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NPU_TOPS_SEL, "npu_tops_sel", + npu_tops_parents, 0x0c0, 0x0c4, 0x0c8, 16, 1, 23, + 0x1C4, 19), + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_SEL, "dramc_sel", + sspxtp_parents, 0x0c0, 0x0c4, 0x0c8, 24, 1, + 31, 0x1C4, 20, CLK_IS_CRITICAL), + /* CLK_CFG_13 */ + MUX_GATE_CLR_SET_UPD_FLAGS(CLK_TOP_DRAMC_MD32_SEL, "dramc_md32_sel", + dramc_md32_parents, 0x0d0, 0x0d4, 0x0d8, 0, + 2, 7, 0x1C4, 21, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD_FLAGS( + CLK_TOP_INFRA_F26M_SEL, "csw_infra_f26m_sel", sspxtp_parents, + 0x0d0, 0x0d4, 0x0d8, 8, 1, 15, 0x1C4, 22, CLK_IS_CRITICAL), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P0_SEL, "pextp_p0_sel", + sspxtp_parents, 0x0d0, 0x0d4, 0x0d8, 16, 1, 23, + 0x1C4, 23), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P1_SEL, "pextp_p1_sel", + sspxtp_parents, 0x0d0, 0x0d4, 0x0d8, 24, 1, 31, + 0x1C4, 24), + /* CLK_CFG_14 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P2_SEL, "pextp_p2_sel", + sspxtp_parents, 0x0e0, 0x0e4, 0x0e8, 0, 1, 7, + 0x1C4, 25), + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_P3_SEL, "pextp_p3_sel", + sspxtp_parents, 0x0e0, 0x0e4, 0x0e8, 8, 1, 15, + 0x1C4, 26), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P0_SEL, "da_xtp_glb_p0_sel", + da_xtp_glb_p0_parents, 0x0e0, 0x0e4, 0x0e8, 16, 1, + 23, 0x1C4, 27), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P1_SEL, "da_xtp_glb_p1_sel", + da_xtp_glb_p0_parents, 0x0e0, 0x0e4, 0x0e8, 24, 1, + 31, 0x1C4, 28), + /* CLK_CFG_15 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P2_SEL, "da_xtp_glb_p2_sel", + da_xtp_glb_p0_parents, 0x0f0, 0x0f4, 0x0f8, 0, 1, + 7, 0x1C4, 29), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_XTP_GLB_P3_SEL, "da_xtp_glb_p3_sel", + da_xtp_glb_p0_parents, 0x0f0, 0x0f4, 0x0f8, 8, 1, + 15, 0x1C4, 30), + MUX_GATE_CLR_SET_UPD(CLK_TOP_CKM_SEL, "ckm_sel", sspxtp_parents, 0x0F0, + 0x0f4, 0x0f8, 16, 1, 23, 0x1c8, 0), + MUX_GATE_CLR_SET_UPD(CLK_TOP_DA_SEL, "da_sel", sspxtp_parents, 0x0f0, + 0x0f4, 0x0f8, 24, 1, 31, 0x1C8, 1), + /* CLK_CFG_16 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_PEXTP_SEL, "pextp_sel", sspxtp_parents, + 0x0100, 0x104, 0x108, 0, 1, 7, 0x1c8, 2), + MUX_GATE_CLR_SET_UPD(CLK_TOP_TOPS_P2_26M_SEL, "tops_p2_26m_sel", + sspxtp_parents, 0x0100, 0x104, 0x108, 8, 1, 15, + 0x1C8, 3), + MUX_GATE_CLR_SET_UPD(CLK_TOP_MCUSYS_BACKUP_625M_SEL, + "mcusys_backup_625m_sel", + mcusys_backup_625m_parents, 0x0100, 0x104, 0x108, + 16, 1, 23, 0x1C8, 4), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_SYNC_250M_SEL, + "netsys_sync_250m_sel", pcie_mbist_250m_parents, + 0x0100, 0x104, 0x108, 24, 1, 31, 0x1c8, 5), + /* CLK_CFG_17 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_MACSEC_SEL, "macsec_sel", macsec_parents, + 0x0110, 0x114, 0x118, 0, 2, 7, 0x1c8, 6), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_TOPS_400M_SEL, + "netsys_tops_400m_sel", netsys_tops_400m_parents, + 0x0110, 0x114, 0x118, 8, 1, 15, 0x1c8, 7), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_PPEFB_250M_SEL, + "netsys_ppefb_250m_sel", pcie_mbist_250m_parents, + 0x0110, 0x114, 0x118, 16, 1, 23, 0x1c8, 8), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NETSYS_WARP_SEL, "netsys_warp_sel", + netsys_parents, 0x0110, 0x114, 0x118, 24, 2, 31, + 0x1C8, 9), + /* CLK_CFG_18 */ + MUX_GATE_CLR_SET_UPD(CLK_TOP_ETH_MII_SEL, "eth_mii_sel", + eth_mii_parents, 0x0120, 0x124, 0x128, 0, 1, 7, + 0x1c8, 10), + MUX_GATE_CLR_SET_UPD(CLK_TOP_NPU_SEL, "ck_npu_sel", netsys_2x_parents, + 0x0120, 0x124, 0x128, 8, 2, 15, 0x1c8, 11), +}; + +static const struct mtk_composite top_aud_divs[] = { + DIV_GATE(CLK_TOP_AUD_I2S_M, "aud_i2s_m", "aud_sel", 0x0420, 0, 0x0420, + 8, 8), +}; + +static int clk_mt7988_topckgen_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + int nr = ARRAY_SIZE(top_fixed_clks) + ARRAY_SIZE(top_divs) + + ARRAY_SIZE(top_muxes) + ARRAY_SIZE(top_aud_divs); + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(nr); + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + clk_data); + + mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), clk_data); + + mtk_clk_register_muxes(top_muxes, ARRAY_SIZE(top_muxes), node, + &mt7988_clk_lock, clk_data); + + mtk_clk_register_composites(top_aud_divs, ARRAY_SIZE(top_aud_divs), + base, &mt7988_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_topckgen_data; + } + return r; + +free_topckgen_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const char *const mcu_bus_div_parents[] = { "top_xtal", "ccipll2_b", + "net1pll_d4" }; + +static const char *const mcu_arm_div_parents[] = { "top_xtal", "arm_b", + "net1pll_d4" }; + +static struct mtk_composite mcu_muxes[] = { + /* bus_pll_divider_cfg */ + MUX_GATE_FLAGS(CLK_MCU_BUS_DIV_SEL, "mcu_bus_div_sel", + mcu_bus_div_parents, 0x7C0, 9, 2, -1, CLK_IS_CRITICAL), + /* mp2_pll_divider_cfg */ + MUX_GATE_FLAGS(CLK_MCU_ARM_DIV_SEL, "mcu_arm_div_sel", + mcu_arm_div_parents, 0x7A8, 9, 2, -1, CLK_IS_CRITICAL), +}; + +static int clk_mt7988_mcusys_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + void __iomem *base; + int nr = ARRAY_SIZE(mcu_muxes); + + base = of_iomap(node, 0); + if (!base) { + pr_err("%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + clk_data = mtk_alloc_clk_data(nr); + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base, + &mt7988_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r) { + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + goto free_mcusys_data; + } + return r; + +free_mcusys_data: + mtk_free_clk_data(clk_data); + return r; +} + +static const struct of_device_id of_match_clk_mt7988_topckgen[] = { + { + .compatible = "mediatek,mt7988-topckgen", + }, + {} +}; + +static struct platform_driver clk_mt7988_topckgen_drv = { + .probe = clk_mt7988_topckgen_probe, + .driver = { + .name = "clk-mt7988-topckgen", + .of_match_table = of_match_clk_mt7988_topckgen, + }, +}; +builtin_platform_driver(clk_mt7988_topckgen_drv); + +static const struct of_device_id of_match_clk_mt7988_mcusys[] = { + { + .compatible = "mediatek,mt7988-mcusys", + }, + {} +}; + +static struct platform_driver clk_mt7988_mcusys_drv = { + .probe = clk_mt7988_mcusys_probe, + .driver = { + .name = "clk-mt7988-mcusys", + .of_match_table = of_match_clk_mt7988_mcusys, + }, +}; +builtin_platform_driver(clk_mt7988_mcusys_drv); \ No newline at end of file diff --git a/target/linux/mediatek/files-5.15/drivers/net/phy/mediatek-2p5ge.c b/target/linux/mediatek/files-5.15/drivers/net/phy/mediatek-2p5ge.c new file mode 100644 index 00000000000..c12e6b8eb6f --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/net/phy/mediatek-2p5ge.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MEDAITEK_2P5GE_PHY_DMB_FW "mediatek/mediatek-2p5ge-phy-dmb.bin" +#define MEDIATEK_2P5GE_PHY_PMB_FW "mediatek/mediatek-2p5ge-phy-pmb.bin" + +#define MD32_EN_CFG 0x18 +#define MD32_EN BIT(0) + +#define BASE100T_STATUS_EXTEND 0x10 +#define BASE1000T_STATUS_EXTEND 0x11 +#define EXTEND_CTRL_AND_STATUS 0x16 + +#define PHY_AUX_CTRL_STATUS 0x1d +#define PHY_AUX_DPX_MASK GENMASK(5, 5) +#define PHY_AUX_SPEED_MASK GENMASK(4, 2) + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_LINK_STATUS_MISC 0xa2 +#define MTK_PHY_FDX_ENABLE BIT(5) + +/* Registers on MDIO_MMD_VEND2 */ +#define MTK_PHY_LED0_ON_CTRL 0x24 +#define MTK_PHY_LED0_ON_LINK1000 BIT(0) +#define MTK_PHY_LED0_ON_LINK100 BIT(1) +#define MTK_PHY_LED0_ON_LINK10 BIT(2) +#define MTK_PHY_LED0_ON_LINK2500 BIT(7) +#define MTK_PHY_LED0_POLARITY BIT(14) + +#define MTK_PHY_LED1_ON_CTRL 0x26 +#define MTK_PHY_LED1_ON_FDX BIT(4) +#define MTK_PHY_LED1_ON_HDX BIT(5) +#define MTK_PHY_LED1_POLARITY BIT(14) + +enum { + PHY_AUX_SPD_10 = 0, + PHY_AUX_SPD_100, + PHY_AUX_SPD_1000, + PHY_AUX_SPD_2500, +}; + +static int mt798x_2p5ge_phy_config_init(struct phy_device *phydev) +{ + int ret; + int i; + const struct firmware *fw; + struct device *dev = &phydev->mdio.dev; + struct device_node *np; + void __iomem *dmb_addr; + void __iomem *pmb_addr; + void __iomem *mcucsr_base; + u16 reg; + struct pinctrl *pinctrl; + + np = of_find_compatible_node(NULL, NULL, "mediatek,2p5gphy-fw"); + if (!np) + return -ENOENT; + + dmb_addr = of_iomap(np, 0); + if (!dmb_addr) + return -ENOMEM; + pmb_addr = of_iomap(np, 1); + if (!pmb_addr) + return -ENOMEM; + mcucsr_base = of_iomap(np, 2); + if (!mcucsr_base) + return -ENOMEM; + + ret = request_firmware(&fw, MEDAITEK_2P5GE_PHY_DMB_FW, dev); + if (ret) { + dev_err(dev, "failed to load firmware: %s, ret: %d\n", + MEDAITEK_2P5GE_PHY_DMB_FW, ret); + return ret; + } + for (i = 0; i < fw->size - 1; i += 4) + writel(*((uint32_t *)(fw->data + i)), dmb_addr + i); + release_firmware(fw); + + ret = request_firmware(&fw, MEDIATEK_2P5GE_PHY_PMB_FW, dev); + if (ret) { + dev_err(dev, "failed to load firmware: %s, ret: %d\n", + MEDIATEK_2P5GE_PHY_PMB_FW, ret); + return ret; + } + for (i = 0; i < fw->size - 1; i += 4) + writel(*((uint32_t *)(fw->data + i)), pmb_addr + i); + release_firmware(fw); + + reg = readw(mcucsr_base + MD32_EN_CFG); + writew(reg | MD32_EN, mcucsr_base + MD32_EN_CFG); + dev_dbg(dev, "Firmware loading/trigger ok.\n"); + + /* Setup LED */ + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED0_POLARITY); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED0_ON_LINK10 | + MTK_PHY_LED0_ON_LINK100 | + MTK_PHY_LED0_ON_LINK1000 | + MTK_PHY_LED0_ON_LINK2500); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL, + MTK_PHY_LED1_ON_FDX | MTK_PHY_LED1_ON_HDX); + + pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "i2p5gbe-led"); + if (IS_ERR(pinctrl)) { + dev_err(&phydev->mdio.dev, "Fail to set LED pins!\n"); + return PTR_ERR(pinctrl); + } + + return 0; +} + +static int mt798x_2p5ge_phy_config_aneg(struct phy_device *phydev) +{ + bool changed = false; + u32 adv; + int ret; + + if (phydev->autoneg == AUTONEG_DISABLE) { + /* Configure half duplex with genphy_setup_forced, + * because genphy_c45_pma_setup_forced does not support. + */ + return phydev->duplex != DUPLEX_FULL + ? genphy_setup_forced(phydev) + : genphy_c45_pma_setup_forced(phydev); + } + + ret = genphy_c45_an_config_aneg(phydev); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising); + ret = phy_modify_changed(phydev, MII_CTRL1000, + ADVERTISE_1000FULL | ADVERTISE_1000HALF, + adv); + if (ret < 0) + return ret; + if (ret > 0) + changed = true; + + return genphy_c45_check_and_restart_aneg(phydev, changed); +} + +static int mt798x_2p5ge_phy_get_features(struct phy_device *phydev) +{ + int ret; + + ret = genphy_read_abilities(phydev); + if (ret) + return ret; + + /* We don't support HDX at MAC layer on mt798x. + * So mask phy's HDX capabilities, too. + */ + linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + phydev->supported); + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + + return 0; +} + +static int mt798x_2p5ge_phy_read_status(struct phy_device *phydev) +{ + int ret; + + ret = genphy_update_link(phydev); + if (ret) + return ret; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + if (!phydev->link) + return 0; + + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) { + ret = genphy_c45_read_lpa(phydev); + if (ret < 0) + return ret; + + /* Read the link partner's 1G advertisement */ + ret = phy_read(phydev, MII_STAT1000); + if (ret < 0) + return ret; + mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret); + } else if (phydev->autoneg == AUTONEG_DISABLE) { + linkmode_zero(phydev->lp_advertising); + } + + ret = phy_read(phydev, PHY_AUX_CTRL_STATUS); + if (ret < 0) + return ret; + + switch (FIELD_GET(PHY_AUX_SPEED_MASK, ret)) { + case PHY_AUX_SPD_10: + phydev->speed = SPEED_10; + break; + case PHY_AUX_SPD_100: + phydev->speed = SPEED_100; + break; + case PHY_AUX_SPD_1000: + phydev->speed = SPEED_1000; + break; + case PHY_AUX_SPD_2500: + phydev->speed = SPEED_2500; + phydev->duplex = DUPLEX_FULL; /* 2.5G must be FDX */ + break; + } + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_MISC); + if (ret < 0) + return ret; + + phydev->duplex = (ret & MTK_PHY_FDX_ENABLE) ? DUPLEX_FULL : DUPLEX_HALF; + + return 0; +} + +static struct phy_driver mtk_gephy_driver[] = { + { + PHY_ID_MATCH_EXACT(0x00339c11), + .name = "MediaTek MT798x 2.5GbE PHY", + .config_init = mt798x_2p5ge_phy_config_init, + .config_aneg = mt798x_2p5ge_phy_config_aneg, + .get_features = mt798x_2p5ge_phy_get_features, + .read_status = mt798x_2p5ge_phy_read_status, + }, +}; + +module_phy_driver(mtk_gephy_driver); + +static struct mdio_device_id __maybe_unused mtk_2p5ge_phy_tbl[] = { + { PHY_ID_MATCH_VENDOR(0x00339c00) }, + { } +}; + +MODULE_DESCRIPTION("MediaTek 2.5Gb Ethernet PHY driver"); +MODULE_AUTHOR("SkyLake Huang "); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(mdio, mtk_2p5ge_phy_tbl); +MODULE_FIRMWARE(MEDAITEK_2P5GE_PHY_DMB_FW); +MODULE_FIRMWARE(MEDIATEK_2P5GE_PHY_PMB_FW); diff --git a/target/linux/mediatek/files-5.15/drivers/net/phy/mediatek-ge-soc.c b/target/linux/mediatek/files-5.15/drivers/net/phy/mediatek-ge-soc.c new file mode 100644 index 00000000000..e48502ac3fd --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/net/phy/mediatek-ge-soc.c @@ -0,0 +1,1263 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include +#include +#include +#include +#include +#include +#include + +#define MTK_GPHY_ID_MT7981 0x03a29461 +#define MTK_GPHY_ID_MT7988 0x03a29481 + +#define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_STANDARD 0x0000 +#define MTK_PHY_PAGE_EXTENDED_3 0x0003 + +#define MTK_PHY_LPI_REG_14 0x14 +#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0) + +#define MTK_PHY_LPI_REG_1c 0x1c +#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8) + +#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 +#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + +#define ANALOG_INTERNAL_OPERATION_MAX_US 20 +#define TXRESERVE_MIN 0 +#define TXRESERVE_MAX 7 + +#define MTK_PHY_ANARG_RG 0x10 +#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8) + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_TXVLD_DA_RG 0x12 +#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10) +#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16 +#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10) +#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17 +#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18 +#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19 +#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20 +#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21 +#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0) + +#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22 +#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8) +#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0) + +#define MTK_PHY_RXADC_CTRL_RG7 0xc6 +#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) + +#define MTK_PHY_RXADC_CTRL_RG9 0xc8 +#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12) +#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8) +#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4) +#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0) + +#define MTK_PHY_LDO_OUTPUT_V 0xd7 + +#define MTK_PHY_RG_ANA_CAL_RG0 0xdb +#define MTK_PHY_RG_CAL_CKINV BIT(12) +#define MTK_PHY_RG_ANA_CALEN BIT(8) +#define MTK_PHY_RG_ZCALEN_A BIT(0) + +#define MTK_PHY_RG_ANA_CAL_RG1 0xdc +#define MTK_PHY_RG_ZCALEN_B BIT(12) +#define MTK_PHY_RG_ZCALEN_C BIT(8) +#define MTK_PHY_RG_ZCALEN_D BIT(4) +#define MTK_PHY_RG_TXVOS_CALEN BIT(0) + +#define MTK_PHY_RG_ANA_CAL_RG5 0xe0 +#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8) + +#define MTK_PHY_RG_TX_FILTER 0xfe + +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120 +#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8) +#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0) + +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122 +#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0) + +#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144 +#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5) + +#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172 +#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8) +#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0) + +#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173 +#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8) +#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) + +#define MTK_PHY_RG_AD_CAL_COMP 0x17a +#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) + +#define MTK_PHY_RG_AD_CAL_CLK 0x17b +#define MTK_PHY_DA_CAL_CLK BIT(0) + +#define MTK_PHY_RG_AD_CALIN 0x17c +#define MTK_PHY_DA_CALIN_FLAG BIT(0) + +#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d +#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e +#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f +#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180 +#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181 +#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182 +#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183 +#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184 +#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0) + +#define MTK_PHY_RG_DEV1E_REG19b 0x19b +#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8) + +#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a +#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b +#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c +#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d +#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e +#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f +#define MTK_PHY_RG_LP_IIR2_K4_L 0x230 +#define MTK_PHY_RG_LP_IIR2_K4_U 0x231 +#define MTK_PHY_RG_LP_IIR2_K5_L 0x232 +#define MTK_PHY_RG_LP_IIR2_K5_U 0x233 + +#define MTK_PHY_RG_DEV1E_REG234 0x234 +#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0) +#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4) +#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12) + +#define MTK_PHY_RG_LPF_CNT_VAL 0x235 + +#define MTK_PHY_RG_DEV1E_REG238 0x238 +#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0) +#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12) + +#define MTK_PHY_RG_DEV1E_REG239 0x239 +#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0) +#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12) + +#define MTK_PHY_RG_DEV1E_REG27C 0x27c +#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8) +#define MTK_PHY_RG_DEV1E_REG27D 0x27d +#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0) + +#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7 +#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0) +#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8) + +#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1 +#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0) +#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8) +#define MTK_PHY_LPI_TR_READY BIT(9) +#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10) + +#define MTK_PHY_RG_DEV1E_REG323 0x323 +#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0) +#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4) + +#define MTK_PHY_RG_DEV1E_REG324 0x324 +#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0) +#define MTK_PHY_SMI_DET_MAX_EN BIT(8) + +#define MTK_PHY_RG_DEV1E_REG326 0x326 +#define MTK_PHY_LPI_MODE_SD_ON BIT(0) +#define MTK_PHY_RESET_RANDUPD_CNT BIT(1) +#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2) +#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4) +#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5) + +#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502 +#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503 + +#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d +#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e +#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f +#define MTK_PHY_DA_TX_R50_PAIR_D 0x540 + +/* Registers on MDIO_MMD_VEND2 */ +#define MTK_PHY_LED0_ON_CTRL 0x24 +#define MTK_PHY_LED0_ON_MASK GENMASK(6, 0) +#define MTK_PHY_LED0_ON_LINK1000 BIT(0) +#define MTK_PHY_LED0_ON_LINK100 BIT(1) +#define MTK_PHY_LED0_ON_LINK10 BIT(2) +#define MTK_PHY_LED0_ON_LINKDOWN BIT(3) +#define MTK_PHY_LED0_ON_FDX BIT(4) /* Full duplex */ +#define MTK_PHY_LED0_ON_HDX BIT(5) /* Half duplex */ +#define MTK_PHY_LED0_FORCE_ON BIT(6) +#define MTK_PHY_LED0_POLARITY BIT(14) +#define MTK_PHY_LED0_ENABLE BIT(15) + +#define MTK_PHY_LED0_BLINK_CTRL 0x25 +#define MTK_PHY_LED0_1000TX BIT(0) +#define MTK_PHY_LED0_1000RX BIT(1) +#define MTK_PHY_LED0_100TX BIT(2) +#define MTK_PHY_LED0_100RX BIT(3) +#define MTK_PHY_LED0_10TX BIT(4) +#define MTK_PHY_LED0_10RX BIT(5) +#define MTK_PHY_LED0_COLLISION BIT(6) +#define MTK_PHY_LED0_RX_CRC_ERR BIT(7) +#define MTK_PHY_LED0_RX_IDLE_ERR BIT(8) +#define MTK_PHY_LED0_FORCE_BLINK BIT(9) + +#define MTK_PHY_LED1_ON_CTRL 0x26 +#define MTK_PHY_LED1_ON_MASK GENMASK(6, 0) +#define MTK_PHY_LED1_ON_LINK1000 BIT(0) +#define MTK_PHY_LED1_ON_LINK100 BIT(1) +#define MTK_PHY_LED1_ON_LINK10 BIT(2) +#define MTK_PHY_LED1_ON_LINKDOWN BIT(3) +#define MTK_PHY_LED1_ON_FDX BIT(4) /* Full duplex */ +#define MTK_PHY_LED1_ON_HDX BIT(5) /* Half duplex */ +#define MTK_PHY_LED1_FORCE_ON BIT(6) +#define MTK_PHY_LED1_POLARITY BIT(14) +#define MTK_PHY_LED1_ENABLE BIT(15) + +#define MTK_PHY_LED1_BLINK_CTRL 0x27 +#define MTK_PHY_LED1_1000TX BIT(0) +#define MTK_PHY_LED1_1000RX BIT(1) +#define MTK_PHY_LED1_100TX BIT(2) +#define MTK_PHY_LED1_100RX BIT(3) +#define MTK_PHY_LED1_10TX BIT(4) +#define MTK_PHY_LED1_10RX BIT(5) +#define MTK_PHY_LED1_COLLISION BIT(6) +#define MTK_PHY_LED1_RX_CRC_ERR BIT(7) +#define MTK_PHY_LED1_RX_IDLE_ERR BIT(8) +#define MTK_PHY_LED1_FORCE_BLINK BIT(9) + +#define MTK_PHY_RG_BG_RASEL 0x115 +#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0) + +/* These macro privides efuse parsing for internal phy. */ +#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0)) + +#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0)) + +#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0)) + +#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0)) +#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0)) + +enum { + NO_PAIR, + PAIR_A, + PAIR_B, + PAIR_C, + PAIR_D, +}; + +enum { + GPHY_PORT0, + GPHY_PORT1, + GPHY_PORT2, + GPHY_PORT3, +}; + +enum calibration_mode { + EFUSE_K, + SW_K +}; + +enum CAL_ITEM { + REXT, + TX_OFFSET, + TX_AMP, + TX_R50, + TX_VCM +}; + +enum CAL_MODE { + EFUSE_M, + SW_M +}; + +struct mtk_socphy_shared_priv { + u32 boottrap; +}; + +static int mtk_socphy_read_page(struct phy_device *phydev) +{ + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +} + +static int mtk_socphy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); +} + +/* One calibration cycle consists of: + * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high + * until AD_CAL_COMP is ready to output calibration result. + * 2.Wait until DA_CAL_CLK is available. + * 3.Fetch AD_CAL_COMP_OUT. + */ +static int cal_cycle(struct phy_device *phydev, int devad, + u32 regnum, u16 mask, u16 cal_val) +{ + int reg_val; + int ret; + + phy_modify_mmd(phydev, devad, regnum, + mask, cal_val); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); + + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_AD_CAL_CLK, reg_val, + reg_val & MTK_PHY_DA_CAL_CLK, 500, + ANALOG_INTERNAL_OPERATION_MAX_US, false); + if (ret) { + phydev_err(phydev, "Calibration cycle timeout\n"); + return ret; + } + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >> + MTK_PHY_AD_CAL_COMP_OUT_SHIFT; + phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); + + return ret; +} + +static int rext_fill_result(struct phy_device *phydev, u16 *buf) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, + MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL, + MTK_PHY_RG_BG_RASEL_MASK, buf[1]); + + return 0; +} + +static int rext_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 rext_cal_val[2]; + + rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]); + rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]); + rext_fill_result(phydev, rext_cal_val); + + return 0; +} + +static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, + MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, + MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, + MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, + MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]); + + return 0; +} + +static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 tx_offset_cal_val[4]; + + tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]); + tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]); + tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]); + tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]); + + tx_offset_fill_result(phydev, tx_offset_cal_val); + + return 0; +} + +static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) +{ + int i; + int bias[16] = {}; + const int vals_9461[16] = { 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7 }; + const int vals_9481[16] = { 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10 }; + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + /* We add some calibration to efuse values + * due to board level influence. + * GBE: +7, TBT: +1, HBT: +4, TST: +7 + */ + memcpy(bias, (const void *)vals_9461, sizeof(bias)); + break; + case MTK_GPHY_ID_MT7988: + memcpy(bias, (const void *)vals_9481, sizeof(bias)); + break; + } + + /* Prevent overflow */ + for (i = 0; i < 12; i++) { + if (buf[i >> 2] + bias[i] > 63) { + buf[i >> 2] = 63; + bias[i] = 0; + } + } + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, + MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, + MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, + MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, + MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, + MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, + MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, + MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, + MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, + MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, + MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, + MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, + MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, + MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, + MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, + MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, + MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]); + + return 0; +} + +static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf) +{ + u16 tx_amp_cal_val[4]; + + tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]); + tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]); + tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]); + tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]); + tx_amp_fill_result(phydev, tx_amp_cal_val); + + return 0; +} + +static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val, + u8 txg_calen_x) +{ + int bias = 0; + u16 reg, val; + + if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988) + bias = -2; + + val = clamp_val(bias + tx_r50_cal_val, 0, 63); + + switch (txg_calen_x) { + case PAIR_A: + reg = MTK_PHY_DA_TX_R50_PAIR_A; + break; + case PAIR_B: + reg = MTK_PHY_DA_TX_R50_PAIR_B; + break; + case PAIR_C: + reg = MTK_PHY_DA_TX_R50_PAIR_C; + break; + case PAIR_D: + reg = MTK_PHY_DA_TX_R50_PAIR_D; + break; + default: + return -EINVAL; + } + + phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8); + + return 0; +} + +static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf, + u8 txg_calen_x) +{ + u16 tx_r50_cal_val; + + switch (txg_calen_x) { + case PAIR_A: + tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]); + break; + case PAIR_B: + tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]); + break; + case PAIR_C: + tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]); + break; + case PAIR_D: + tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]); + break; + default: + return -EINVAL; + } + tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); + + return 0; +} + +static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) +{ + u8 lower_idx, upper_idx, txreserve_val; + u8 lower_ret, upper_ret; + int ret; + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ANA_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_CAL_CKINV); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_TXVOS_CALEN); + + switch (rg_txreserve_x) { + case PAIR_A: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_A, + MTK_PHY_DASN_DAC_IN0_A_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_A, + MTK_PHY_DASN_DAC_IN1_A_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ZCALEN_A); + break; + case PAIR_B: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_B, + MTK_PHY_DASN_DAC_IN0_B_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_B, + MTK_PHY_DASN_DAC_IN1_B_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_B); + break; + case PAIR_C: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_C, + MTK_PHY_DASN_DAC_IN0_C_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_C, + MTK_PHY_DASN_DAC_IN1_C_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_C); + break; + case PAIR_D: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_D, + MTK_PHY_DASN_DAC_IN0_D_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_D, + MTK_PHY_DASN_DAC_IN1_D_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_D); + break; + default: + ret = -EINVAL; + goto restore; + } + + lower_idx = TXRESERVE_MIN; + upper_idx = TXRESERVE_MAX; + + phydev_dbg(phydev, "Start TX-VCM SW cal.\n"); + while ((upper_idx - lower_idx) > 1) { + txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2); + ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + txreserve_val << 12 | txreserve_val << 8 | + txreserve_val << 4 | txreserve_val); + if (ret == 1) { + upper_idx = txreserve_val; + upper_ret = ret; + } else if (ret == 0) { + lower_idx = txreserve_val; + lower_ret = ret; + } else { + goto restore; + } + } + + if (lower_idx == TXRESERVE_MIN) { + lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, + MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + lower_idx << 12 | lower_idx << 8 | + lower_idx << 4 | lower_idx); + ret = lower_ret; + } else if (upper_idx == TXRESERVE_MAX) { + upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, + MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + upper_idx << 12 | upper_idx << 8 | + upper_idx << 4 | upper_idx); + ret = upper_ret; + } + if (ret < 0) + goto restore; + + /* We calibrate TX-VCM in different logic. Check upper index and then + * lower index. If this calibration is valid, apply lower index's result. + */ + ret = upper_ret - lower_ret; + if (ret == 1) { + ret = 0; + /* Make sure we use upper_idx in our calibration system */ + cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + upper_idx << 12 | upper_idx << 8 | + upper_idx << 4 | upper_idx); + phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx); + } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && + lower_ret == 1) { + ret = 0; + cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + lower_idx << 12 | lower_idx << 8 | + lower_idx << 4 | lower_idx); + phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n", + lower_idx); + } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && + lower_ret == 0) { + ret = 0; + phydev_warn(phydev, "TX-VCM SW cal result at high margin 0x%x\n", + upper_idx); + } else { + ret = -EINVAL; + } + +restore: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ANA_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_TXVOS_CALEN); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ZCALEN_A); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | + MTK_PHY_RG_ZCALEN_D); + + return ret; +} + +static void mt798x_phy_common_finetune(struct phy_device *phydev) +{ + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* EnabRandUpdTrig = 1 */ + __phy_write(phydev, 0x11, 0x2f00); + __phy_write(phydev, 0x12, 0xe); + __phy_write(phydev, 0x10, 0x8fb0); + + /* NormMseLoThresh = 85 */ + __phy_write(phydev, 0x11, 0x55a0); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x83aa); + + /* TrFreeze = 0 */ + __phy_write(phydev, 0x11, 0x0); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9686); + + /* SSTrKp1000Slv = 5 */ + __phy_write(phydev, 0x11, 0xbaef); + __phy_write(phydev, 0x12, 0x2e); + __phy_write(phydev, 0x10, 0x968c); + + /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, + * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 + */ + __phy_write(phydev, 0x11, 0xd10a); + __phy_write(phydev, 0x12, 0x34); + __phy_write(phydev, 0x10, 0x8f82); + + /* VcoSlicerThreshBitsHigh */ + __phy_write(phydev, 0x11, 0x5555); + __phy_write(phydev, 0x12, 0x55); + __phy_write(phydev, 0x10, 0x8ec0); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, + MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, + BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); + + /* rg_tr_lpf_cnt_val = 512 */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); + + /* IIR2 related */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); + + /* FFE peaking */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, + MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, + MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); + + /* Disable LDO pump */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0); + /* Adjust LDO output voltage */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222); +} + +static void mt7981_phy_finetune(struct phy_device *phydev) +{ + u16 val[8] = { 0x01ce, 0x01c1, + 0x020f, 0x0202, + 0x03d0, 0x03c0, + 0x0013, 0x0005 }; + int i, k; + + /* 100M eye finetune: + * Keep middle level of TX MLT3 shapper as default. + * Only change TX MLT3 overshoot level here. + */ + for (k = 0, i = 1; i < 12; i++) { + if (i % 3 == 0) + continue; + phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]); + } + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* SlvDSPreadyTime = 24, MasDSPreadyTime = 24 */ + __phy_write(phydev, 0x11, 0xc71); + __phy_write(phydev, 0x12, 0xc); + __phy_write(phydev, 0x10, 0x8fae); + + /* ResetSyncOffset = 6 */ + __phy_write(phydev, 0x11, 0x600); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8fc0); + + /* VgaDecRate = 1 */ + __phy_write(phydev, 0x11, 0x4c2a); + __phy_write(phydev, 0x12, 0x3e); + __phy_write(phydev, 0x10, 0x8fa4); + + /* FfeUpdGainForce = 4 */ + __phy_write(phydev, 0x11, 0x240); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9680); + + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); +} + +static void mt7988_phy_finetune(struct phy_device *phydev) +{ + u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182, + 0x020d, 0x0206, 0x0384, 0x03d0, + 0x03c6, 0x030a, 0x0011, 0x0005 }; + int i; + + /* Set default MLT3 shaper first */ + for (i = 0; i < 12; i++) + phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]); + + /* TCT finetune */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); + + /* Disable TX power saving */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, + MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + + /* SlvDSPreadyTime = 24, MasDSPreadyTime = 12 */ + __phy_write(phydev, 0x11, 0x671); + __phy_write(phydev, 0x12, 0xc); + __phy_write(phydev, 0x10, 0x8fae); + + /* ResetSyncOffset = 5 */ + __phy_write(phydev, 0x11, 0x500); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8fc0); + + /* VgaDecRate is 1 at default on mt7988 */ + + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30); + /* TxClkOffset = 2 */ + __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK, + FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); +} + +static void mt798x_phy_eee(struct phy_device *phydev) +{ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120, + MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK | + MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK, 0x0) | + FIELD_PREP(MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK, 0x14)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, + MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + 0xff)); + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_TESTMUX_ADC_CTRL, + MTK_PHY_RG_TXEN_DIG_MASK); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DEV1E_REG19b, MTK_PHY_BYPASS_DSP_LPI_READY); + + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DEV1E_REG234, MTK_PHY_TR_LP_IIR_EEE_EN); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG238, + MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK | + MTK_PHY_LPI_SLV_SEND_TX_EN, + FIELD_PREP(MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK, 0x120)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG239, + MTK_PHY_LPI_SEND_LOC_TIMER_MASK | + MTK_PHY_LPI_TXPCS_LOC_RCV, + FIELD_PREP(MTK_PHY_LPI_SEND_LOC_TIMER_MASK, 0x117)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7, + MTK_PHY_MAX_GAIN_MASK | MTK_PHY_MIN_GAIN_MASK, + FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) | + FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13)); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2D1, + MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK, + FIELD_PREP(MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK, + 0x33) | + MTK_PHY_LPI_SKIP_SD_SLV_TR | MTK_PHY_LPI_TR_READY | + MTK_PHY_LPI_VCO_EEE_STG0_EN); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG323, + MTK_PHY_EEE_WAKE_MAS_INT_DC | + MTK_PHY_EEE_WAKE_SLV_INT_DC); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG324, + MTK_PHY_SMI_DETCNT_MAX_MASK, + FIELD_PREP(MTK_PHY_SMI_DETCNT_MAX_MASK, 0x3f) | + MTK_PHY_SMI_DET_MAX_EN); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG326, + MTK_PHY_LPI_MODE_SD_ON | MTK_PHY_RESET_RANDUPD_CNT | + MTK_PHY_TREC_UPDATE_ENAB_CLR | + MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF | + MTK_PHY_TR_READY_SKIP_AFE_WAKEUP); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + /* Regsigdet_sel_1000 = 0 */ + __phy_write(phydev, 0x11, 0xb); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x9690); + + /* REG_EEE_st2TrKf1000 = 3 */ + __phy_write(phydev, 0x11, 0x114f); + __phy_write(phydev, 0x12, 0x2); + __phy_write(phydev, 0x10, 0x969a); + + /* RegEEE_slv_wake_tr_timer_tar = 6, RegEEE_slv_remtx_timer_tar = 20 */ + __phy_write(phydev, 0x11, 0x3028); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x969e); + + /* RegEEE_slv_wake_int_timer_tar = 8 */ + __phy_write(phydev, 0x11, 0x5010); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96a0); + + /* RegEEE_trfreeze_timer2 = 586 */ + __phy_write(phydev, 0x11, 0x24a); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96a8); + + /* RegEEE100Stg1_tar = 16 */ + __phy_write(phydev, 0x11, 0x3210); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96b8); + + /* REGEEE_wake_slv_tr_wait_dfesigdet_en = 1 */ + __phy_write(phydev, 0x11, 0x1463); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x96ca); + + /* DfeTailEnableVgaThresh1000 = 27 */ + __phy_write(phydev, 0x11, 0x36); + __phy_write(phydev, 0x12, 0x0); + __phy_write(phydev, 0x10, 0x8f80); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_3); + __phy_modify(phydev, MTK_PHY_LPI_REG_14, MTK_PHY_LPI_WAKE_TIMER_1000_MASK, + FIELD_PREP(MTK_PHY_LPI_WAKE_TIMER_1000_MASK, 0x19c)); + + __phy_modify(phydev, MTK_PHY_LPI_REG_1c, MTK_PHY_SMI_DET_ON_THRESH_MASK, + FIELD_PREP(MTK_PHY_SMI_DET_ON_THRESH_MASK, 0xc)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + phy_modify_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122, + MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, + FIELD_PREP(MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK, 0xff)); +} + +static int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item, + u8 start_pair, u8 end_pair) +{ + u8 pair_n; + int ret; + + for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { + /* TX_OFFSET & TX_AMP have no SW calibration. */ + switch (cal_item) { + case TX_VCM: + ret = tx_vcm_cal_sw(phydev, pair_n); + break; + default: + return -EINVAL; + } + if (ret) + return ret; + } + return 0; +} + +static int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item, + u8 start_pair, u8 end_pair, u32 *buf) +{ + u8 pair_n; + int ret; + + for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { + /* TX_VCM has no efuse calibration. */ + switch (cal_item) { + case REXT: + ret = rext_cal_efuse(phydev, buf); + break; + case TX_OFFSET: + ret = tx_offset_cal_efuse(phydev, buf); + break; + case TX_AMP: + ret = tx_amp_cal_efuse(phydev, buf); + break; + case TX_R50: + ret = tx_r50_cal_efuse(phydev, buf, pair_n); + break; + default: + return -EINVAL; + } + if (ret) + return ret; + } + + return 0; +} + +static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item, + enum CAL_MODE cal_mode, u8 start_pair, + u8 end_pair, u32 *buf) +{ + int ret; + + switch (cal_mode) { + case EFUSE_M: + ret = cal_efuse(phydev, cal_item, start_pair, + end_pair, buf); + break; + case SW_M: + ret = cal_sw(phydev, cal_item, start_pair, end_pair); + break; + default: + return -EINVAL; + } + + if (ret) { + phydev_err(phydev, "cal %d failed\n", cal_item); + return -EIO; + } + + return 0; +} + +static int mt798x_phy_calibration(struct phy_device *phydev) +{ + int ret = 0; + u32 *buf; + size_t len; + struct nvmem_cell *cell; + + cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); + if (IS_ERR(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) + return PTR_ERR(cell); + return 0; + } + + buf = (u32 *)nvmem_cell_read(cell, &len); + if (IS_ERR(buf)) + return PTR_ERR(buf); + nvmem_cell_put(cell); + + if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) { + phydev_err(phydev, "invalid efuse data\n"); + ret = -EINVAL; + goto out; + } + + ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf); + if (ret) + goto out; + +out: + kfree(buf); + return ret; +} + +static int mt798x_phy_config_init(struct phy_device *phydev) +{ + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + mt7981_phy_finetune(phydev); + break; + case MTK_GPHY_ID_MT7988: + mt7988_phy_finetune(phydev); + break; + } + + mt798x_phy_common_finetune(phydev); + mt798x_phy_eee(phydev); + + return mt798x_phy_calibration(phydev); +} + +static int mt7988_phy_setup_led(struct phy_device *phydev) +{ + struct mtk_socphy_shared_priv *priv = phydev->shared->priv; + int port = phydev->mdio.addr; + u32 reg = priv->boottrap; + struct pinctrl *pinctrl; + + phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED0_ENABLE | MTK_PHY_LED0_POLARITY | + MTK_PHY_LED0_ON_LINK10 | + MTK_PHY_LED0_ON_LINK100 | + MTK_PHY_LED0_ON_LINK1000); + phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL, + MTK_PHY_LED1_ENABLE | MTK_PHY_LED1_POLARITY | + MTK_PHY_LED1_ON_LINK10 | + MTK_PHY_LED1_ON_LINK100 | + MTK_PHY_LED1_ON_LINK1000); + + if ((port == GPHY_PORT0 && reg & BIT(8)) || + (port == GPHY_PORT1 && reg & BIT(9)) || + (port == GPHY_PORT2 && reg & BIT(10)) || + (port == GPHY_PORT3 && reg & BIT(11))) { + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED0_POLARITY); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL, + MTK_PHY_LED1_POLARITY); + } + + phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_BLINK_CTRL, + MTK_PHY_LED0_1000TX | MTK_PHY_LED0_1000RX | + MTK_PHY_LED0_100TX | MTK_PHY_LED0_100RX | + MTK_PHY_LED0_10TX | MTK_PHY_LED0_10RX); + phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_BLINK_CTRL, + MTK_PHY_LED1_1000TX | MTK_PHY_LED1_1000RX | + MTK_PHY_LED1_100TX | MTK_PHY_LED1_100RX | + MTK_PHY_LED1_10TX | MTK_PHY_LED1_10RX); + + pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led"); + if (IS_ERR(pinctrl)) { + dev_err(&phydev->mdio.bus->dev, "Failed to setup LED pins\n"); + return PTR_ERR(pinctrl); + } + + return 0; +} + +static int mt7988_phy_probe_shared(struct phy_device *phydev) +{ + struct mtk_socphy_shared_priv *priv = phydev->shared->priv; + void __iomem *boottrap; + struct device_node *np; + u32 reg; + + np = of_find_compatible_node(NULL, NULL, "mediatek,boottrap"); + if (!np) + return -ENOENT; + + boottrap = of_iomap(np, 0); + if (!boottrap) + return -ENOMEM; + + reg = readl(boottrap); + iounmap(boottrap); + + priv->boottrap = reg; + + return 0; +} + +static int mt7981_phy_probe(struct phy_device *phydev) +{ + return mt798x_phy_calibration(phydev); +} + +static int mt7988_phy_probe(struct phy_device *phydev) +{ + int err; + + err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0, + sizeof(struct mtk_socphy_shared_priv)); + if (err) + return err; + + if (phy_package_probe_once(phydev)) { + err = mt7988_phy_probe_shared(phydev); + if (err) + return err; + } + + mt7988_phy_setup_led(phydev); + + return mt798x_phy_calibration(phydev); +} + +static struct phy_driver mtk_socphy_driver[] = { + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981), + .name = "MediaTek MT7981 PHY", + .config_init = mt798x_phy_config_init, + .config_intr = genphy_no_config_intr, + .handle_interrupt = genphy_handle_interrupt_no_ack, + .probe = mt7981_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_socphy_read_page, + .write_page = mtk_socphy_write_page, + }, + { + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988), + .name = "MediaTek MT7988 PHY", + .config_init = mt798x_phy_config_init, + .config_intr = genphy_no_config_intr, + .handle_interrupt = genphy_handle_interrupt_no_ack, + .probe = mt7988_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_socphy_read_page, + .write_page = mtk_socphy_write_page, + }, +}; + +module_phy_driver(mtk_socphy_driver); + +static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, + { } +}; + +MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver"); +MODULE_AUTHOR("Daniel Golle "); +MODULE_AUTHOR("SkyLake Huang "); +MODULE_LICENSE("GPL"); + +MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl); diff --git a/target/linux/mediatek/files-5.15/drivers/pinctrl/mediatek/pinctrl-mt7988.c b/target/linux/mediatek/files-5.15/drivers/pinctrl/mediatek/pinctrl-mt7988.c new file mode 100644 index 00000000000..80a7e19f7a2 --- /dev/null +++ b/target/linux/mediatek/files-5.15/drivers/pinctrl/mediatek/pinctrl-mt7988.c @@ -0,0 +1,1281 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * The MT7988 driver based on Linux generic pinctrl binding. + * + * Copyright (C) 2020 MediaTek Inc. + * Author: Sam Shih + */ + +#include "pinctrl-moore.h" + +enum MT7988_PINCTRL_REG_PAGE { + GPIO_BASE, + IOCFG_TR_BASE, + IOCFG_BR_BASE, + IOCFG_RB_BASE, + IOCFG_LB_BASE, + IOCFG_TL_BASE, +}; + +#define MT7988_PIN(_number, _name) MTK_PIN(_number, _name, 0, _number, DRV_GRP4) + +#define PIN_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 0) + +#define PINS_FIELD_BASE(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits) \ + PIN_FIELD_CALC(_s_pin, _e_pin, _i_base, _s_addr, _x_addrs, _s_bit, \ + _x_bits, 32, 1) + +static const struct mtk_pin_field_calc mt7988_pin_mode_range[] = { + PIN_FIELD(0, 83, 0x300, 0x10, 0, 4), +}; + +static const struct mtk_pin_field_calc mt7988_pin_dir_range[] = { + PIN_FIELD(0, 83, 0x0, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_di_range[] = { + PIN_FIELD(0, 83, 0x200, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_do_range[] = { + PIN_FIELD(0, 83, 0x100, 0x10, 0, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_ies_range[] = { + PIN_FIELD_BASE(0, 1, 5, 0x30, 0x10, 13, 1), + PIN_FIELD_BASE(2, 3, 5, 0x30, 0x10, 11, 1), + PIN_FIELD_BASE(4, 4, 5, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(5, 6, 5, 0x30, 0x10, 9, 1), + PIN_FIELD_BASE(7, 7, 4, 0x30, 0x10, 8, 1), + PIN_FIELD_BASE(8, 8, 4, 0x30, 0x10, 6, 1), + PIN_FIELD_BASE(9, 9, 4, 0x30, 0x10, 5, 1), + PIN_FIELD_BASE(10, 10, 4, 0x30, 0x10, 3, 1), + PIN_FIELD_BASE(11, 11, 1, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0x40, 0x10, 21, 1), + PIN_FIELD_BASE(13, 14, 1, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(15, 16, 5, 0x30, 0x10, 7, 1), + PIN_FIELD_BASE(17, 18, 5, 0x30, 0x10, 3, 1), + PIN_FIELD_BASE(19, 19, 4, 0x30, 0x10, 7, 1), + PIN_FIELD_BASE(20, 20, 4, 0x30, 0x10, 4, 1), + PIN_FIELD_BASE(21, 21, 3, 0x50, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0x50, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0x50, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0x50, 0x10, 19, 1), + PIN_FIELD_BASE(25, 26, 3, 0x50, 0x10, 21, 1), + PIN_FIELD_BASE(27, 27, 3, 0x50, 0x10, 18, 1), + PIN_FIELD_BASE(28, 30, 3, 0x50, 0x10, 25, 1), + PIN_FIELD_BASE(31, 31, 3, 0x50, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0x50, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0x50, 0x10, 31, 1), + PIN_FIELD_BASE(35, 36, 3, 0x50, 0x10, 29, 1), + PIN_FIELD_BASE(37, 37, 3, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0x50, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0x50, 0x10, 10, 1), + PIN_FIELD_BASE(40, 41, 3, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 3, 0x50, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0x50, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0x50, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0x50, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0x50, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0x50, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0x50, 0x10, 15, 1), + PIN_FIELD_BASE(51, 53, 3, 0x50, 0x10, 12, 1), + PIN_FIELD_BASE(54, 54, 3, 0x50, 0x10, 16, 1), + PIN_FIELD_BASE(55, 56, 1, 0x40, 0x10, 14, 1), + PIN_FIELD_BASE(57, 57, 1, 0x40, 0x10, 13, 1), + PIN_FIELD_BASE(58, 60, 1, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(61, 61, 1, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(62, 62, 1, 0x40, 0x10, 7, 1), + PIN_FIELD_BASE(63, 63, 1, 0x40, 0x10, 20, 1), + PIN_FIELD_BASE(64, 68, 1, 0x40, 0x10, 8, 1), + PIN_FIELD_BASE(69, 70, 5, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(71, 72, 5, 0x30, 0x10, 5, 1), + PIN_FIELD_BASE(73, 73, 4, 0x30, 0x10, 10, 1), + PIN_FIELD_BASE(74, 74, 4, 0x30, 0x10, 1, 1), + PIN_FIELD_BASE(75, 75, 4, 0x30, 0x10, 11, 1), + PIN_FIELD_BASE(76, 76, 4, 0x30, 0x10, 9, 1), + PIN_FIELD_BASE(77, 77, 4, 0x30, 0x10, 2, 1), + PIN_FIELD_BASE(78, 78, 4, 0x30, 0x10, 0, 1), + PIN_FIELD_BASE(79, 79, 4, 0x30, 0x10, 12, 1), + PIN_FIELD_BASE(80, 81, 1, 0x40, 0x10, 18, 1), + PIN_FIELD_BASE(82, 83, 1, 0x40, 0x10, 16, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_smt_range[] = { + PIN_FIELD_BASE(0, 1, 5, 0xc0, 0x10, 13, 1), + PIN_FIELD_BASE(2, 3, 5, 0xc0, 0x10, 11, 1), + PIN_FIELD_BASE(4, 4, 5, 0xc0, 0x10, 0, 1), + PIN_FIELD_BASE(5, 6, 5, 0xc0, 0x10, 9, 1), + PIN_FIELD_BASE(7, 7, 4, 0xb0, 0x10, 8, 1), + PIN_FIELD_BASE(8, 8, 4, 0xb0, 0x10, 6, 1), + PIN_FIELD_BASE(9, 9, 4, 0xb0, 0x10, 5, 1), + PIN_FIELD_BASE(10, 10, 4, 0xb0, 0x10, 3, 1), + PIN_FIELD_BASE(11, 11, 1, 0xe0, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0xe0, 0x10, 21, 1), + PIN_FIELD_BASE(13, 14, 1, 0xe0, 0x10, 1, 1), + PIN_FIELD_BASE(15, 16, 5, 0xc0, 0x10, 7, 1), + PIN_FIELD_BASE(17, 18, 5, 0xc0, 0x10, 3, 1), + PIN_FIELD_BASE(19, 19, 4, 0xb0, 0x10, 7, 1), + PIN_FIELD_BASE(20, 20, 4, 0xb0, 0x10, 4, 1), + PIN_FIELD_BASE(21, 21, 3, 0x140, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0x140, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0x140, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0x140, 0x10, 19, 1), + PIN_FIELD_BASE(25, 26, 3, 0x140, 0x10, 21, 1), + PIN_FIELD_BASE(27, 27, 3, 0x140, 0x10, 18, 1), + PIN_FIELD_BASE(28, 30, 3, 0x140, 0x10, 25, 1), + PIN_FIELD_BASE(31, 31, 3, 0x140, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0x140, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0x150, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0x140, 0x10, 31, 1), + PIN_FIELD_BASE(35, 36, 3, 0x140, 0x10, 29, 1), + PIN_FIELD_BASE(37, 37, 3, 0x150, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0x140, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0x140, 0x10, 10, 1), + PIN_FIELD_BASE(40, 41, 3, 0x140, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 3, 0x140, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0x140, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0x140, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0x140, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0x140, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0x140, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0x140, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0x140, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0x140, 0x10, 15, 1), + PIN_FIELD_BASE(51, 53, 3, 0x140, 0x10, 12, 1), + PIN_FIELD_BASE(54, 54, 3, 0x140, 0x10, 16, 1), + PIN_FIELD_BASE(55, 56, 1, 0xe0, 0x10, 14, 1), + PIN_FIELD_BASE(57, 57, 1, 0xe0, 0x10, 13, 1), + PIN_FIELD_BASE(58, 60, 1, 0xe0, 0x10, 4, 1), + PIN_FIELD_BASE(61, 61, 1, 0xe0, 0x10, 3, 1), + PIN_FIELD_BASE(62, 62, 1, 0xe0, 0x10, 7, 1), + PIN_FIELD_BASE(63, 63, 1, 0xe0, 0x10, 20, 1), + PIN_FIELD_BASE(64, 68, 1, 0xe0, 0x10, 8, 1), + PIN_FIELD_BASE(69, 70, 5, 0xc0, 0x10, 1, 1), + PIN_FIELD_BASE(71, 72, 5, 0xc0, 0x10, 5, 1), + PIN_FIELD_BASE(73, 73, 4, 0xb0, 0x10, 10, 1), + PIN_FIELD_BASE(74, 74, 4, 0xb0, 0x10, 1, 1), + PIN_FIELD_BASE(75, 75, 4, 0xb0, 0x10, 11, 1), + PIN_FIELD_BASE(76, 76, 4, 0xb0, 0x10, 9, 1), + PIN_FIELD_BASE(77, 77, 4, 0xb0, 0x10, 2, 1), + PIN_FIELD_BASE(78, 78, 4, 0xb0, 0x10, 0, 1), + PIN_FIELD_BASE(79, 79, 4, 0xb0, 0x10, 12, 1), + PIN_FIELD_BASE(80, 81, 1, 0xe0, 0x10, 18, 1), + PIN_FIELD_BASE(82, 83, 1, 0xe0, 0x10, 16, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_pu_range[] = { + PIN_FIELD_BASE(7, 7, 4, 0x60, 0x10, 5, 1), + PIN_FIELD_BASE(8, 8, 4, 0x60, 0x10, 4, 1), + PIN_FIELD_BASE(9, 9, 4, 0x60, 0x10, 3, 1), + PIN_FIELD_BASE(10, 10, 4, 0x60, 0x10, 2, 1), + PIN_FIELD_BASE(13, 14, 1, 0x70, 0x10, 0, 1), + PIN_FIELD_BASE(63, 63, 1, 0x70, 0x10, 2, 1), + PIN_FIELD_BASE(75, 75, 4, 0x60, 0x10, 7, 1), + PIN_FIELD_BASE(76, 76, 4, 0x60, 0x10, 6, 1), + PIN_FIELD_BASE(77, 77, 4, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(78, 78, 4, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(79, 79, 4, 0x60, 0x10, 8, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_pd_range[] = { + PIN_FIELD_BASE(7, 7, 4, 0x40, 0x10, 5, 1), + PIN_FIELD_BASE(8, 8, 4, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(9, 9, 4, 0x40, 0x10, 3, 1), + PIN_FIELD_BASE(10, 10, 4, 0x40, 0x10, 2, 1), + PIN_FIELD_BASE(13, 14, 1, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(15, 16, 5, 0x40, 0x10, 4, 1), + PIN_FIELD_BASE(17, 18, 5, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(63, 63, 1, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(71, 72, 5, 0x40, 0x10, 2, 1), + PIN_FIELD_BASE(75, 75, 4, 0x40, 0x10, 7, 1), + PIN_FIELD_BASE(76, 76, 4, 0x40, 0x10, 6, 1), + PIN_FIELD_BASE(77, 77, 4, 0x40, 0x10, 1, 1), + PIN_FIELD_BASE(78, 78, 4, 0x40, 0x10, 0, 1), + PIN_FIELD_BASE(79, 79, 4, 0x40, 0x10, 8, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_drv_range[] = { + PIN_FIELD_BASE(0, 1, 5, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(2, 3, 5, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(4, 4, 5, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(5, 6, 5, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(8, 8, 4, 0x00, 0x10, 28, 3), + PIN_FIELD_BASE(9, 9, 4, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(10, 10, 4, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(11, 11, 1, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(12, 12, 1, 0x20, 0x10, 3, 3), + PIN_FIELD_BASE(13, 14, 1, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(19, 19, 4, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(20, 20, 4, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(21, 21, 3, 0x10, 0x10, 21, 3), + PIN_FIELD_BASE(22, 22, 3, 0x20, 0x10, 9, 3), + PIN_FIELD_BASE(23, 23, 3, 0x20, 0x10, 0, 3), + PIN_FIELD_BASE(24, 24, 3, 0x10, 0x10, 27, 3), + PIN_FIELD_BASE(25, 26, 3, 0x20, 0x10, 3, 3), + PIN_FIELD_BASE(27, 27, 3, 0x10, 0x10, 24, 3), + PIN_FIELD_BASE(28, 30, 3, 0x20, 0x10, 15, 3), + PIN_FIELD_BASE(31, 31, 3, 0x20, 0x10, 12, 3), + PIN_FIELD_BASE(32, 32, 3, 0x20, 0x10, 24, 3), + PIN_FIELD_BASE(33, 33, 3, 0x30, 0x10, 6, 3), + PIN_FIELD_BASE(34, 34, 3, 0x30, 0x10, 3, 3), + PIN_FIELD_BASE(35, 35, 3, 0x20, 0x10, 27, 3), + PIN_FIELD_BASE(36, 36, 3, 0x30, 0x10, 0, 3), + PIN_FIELD_BASE(37, 37, 3, 0x30, 0x10, 9, 3), + PIN_FIELD_BASE(38, 38, 3, 0x10, 0x10, 3, 3), + PIN_FIELD_BASE(39, 39, 3, 0x10, 0x10, 0, 3), + PIN_FIELD_BASE(40, 41, 3, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(42, 42, 3, 0x00, 0x10, 27, 3), + PIN_FIELD_BASE(43, 43, 3, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(44, 44, 3, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(45, 45, 3, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(46, 46, 3, 0x00, 0x10, 15, 3), + PIN_FIELD_BASE(47, 47, 3, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(48, 48, 3, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(49, 49, 3, 0x00, 0x10, 6, 3), + PIN_FIELD_BASE(50, 50, 3, 0x10, 0x10, 15, 3), + PIN_FIELD_BASE(51, 53, 3, 0x10, 0x10, 6, 3), + PIN_FIELD_BASE(54, 54, 3, 0x10, 0x10, 18, 3), + PIN_FIELD_BASE(55, 56, 1, 0x10, 0x10, 12, 3), + PIN_FIELD_BASE(57, 57, 1, 0x10, 0x10, 9, 3), + PIN_FIELD_BASE(58, 60, 1, 0x00, 0x10, 12, 3), + PIN_FIELD_BASE(61, 61, 1, 0x00, 0x10, 9, 3), + PIN_FIELD_BASE(62, 62, 1, 0x00, 0x10, 21, 3), + PIN_FIELD_BASE(63, 63, 1, 0x20, 0x10, 0, 3), + PIN_FIELD_BASE(64, 65, 1, 0x00, 0x10, 24, 3), + PIN_FIELD_BASE(66, 68, 1, 0x10, 0x10, 0, 3), + PIN_FIELD_BASE(69, 70, 5, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(73, 73, 4, 0x10, 0x10, 0, 3), + PIN_FIELD_BASE(74, 74, 4, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(75, 75, 4, 0x10, 0x10, 3, 3), + PIN_FIELD_BASE(76, 76, 4, 0x00, 0x10, 27, 3), + PIN_FIELD_BASE(77, 77, 4, 0x00, 0x10, 6, 3), + PIN_FIELD_BASE(78, 78, 4, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(79, 79, 4, 0x10, 0x10, 6, 3), + PIN_FIELD_BASE(80, 81, 1, 0x10, 0x10, 24, 3), + PIN_FIELD_BASE(82, 83, 1, 0x10, 0x10, 18, 3), +}; + +static const struct mtk_pin_field_calc mt7988_pin_pupd_range[] = { + PIN_FIELD_BASE(0, 1, 5, 0x50, 0x10, 7, 1), + PIN_FIELD_BASE(2, 3, 5, 0x50, 0x10, 5, 1), + PIN_FIELD_BASE(4, 4, 5, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(5, 6, 5, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(11, 11, 1, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0x60, 0x10, 18, 1), + PIN_FIELD_BASE(19, 19, 4, 0x50, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 4, 0x50, 0x10, 1, 1), + PIN_FIELD_BASE(21, 21, 3, 0x70, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0x70, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0x70, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0x70, 0x10, 19, 1), + PIN_FIELD_BASE(25, 26, 3, 0x70, 0x10, 21, 1), + PIN_FIELD_BASE(27, 27, 3, 0x70, 0x10, 18, 1), + PIN_FIELD_BASE(28, 30, 3, 0x70, 0x10, 25, 1), + PIN_FIELD_BASE(31, 31, 3, 0x70, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0x70, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0x80, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0x70, 0x10, 31, 1), + PIN_FIELD_BASE(35, 36, 3, 0x70, 0x10, 29, 1), + PIN_FIELD_BASE(37, 37, 3, 0x80, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0x70, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0x70, 0x10, 10, 1), + PIN_FIELD_BASE(40, 41, 3, 0x70, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 3, 0x70, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0x70, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0x70, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0x70, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0x70, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0x70, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0x70, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0x70, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0x70, 0x10, 15, 1), + PIN_FIELD_BASE(51, 53, 3, 0x70, 0x10, 12, 1), + PIN_FIELD_BASE(54, 54, 3, 0x70, 0x10, 16, 1), + PIN_FIELD_BASE(55, 56, 1, 0x60, 0x10, 12, 1), + PIN_FIELD_BASE(57, 57, 1, 0x60, 0x10, 11, 1), + PIN_FIELD_BASE(58, 60, 1, 0x60, 0x10, 2, 1), + PIN_FIELD_BASE(61, 61, 1, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(62, 62, 1, 0x60, 0x10, 5, 1), + PIN_FIELD_BASE(64, 68, 1, 0x60, 0x10, 6, 1), + PIN_FIELD_BASE(69, 70, 5, 0x50, 0x10, 1, 1), + PIN_FIELD_BASE(73, 73, 4, 0x50, 0x10, 3, 1), + PIN_FIELD_BASE(74, 74, 4, 0x50, 0x10, 0, 1), + PIN_FIELD_BASE(80, 81, 1, 0x60, 0x10, 16, 1), + PIN_FIELD_BASE(82, 83, 1, 0x60, 0x10, 14, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_r0_range[] = { + PIN_FIELD_BASE(0, 1, 5, 0x60, 0x10, 7, 1), + PIN_FIELD_BASE(2, 3, 5, 0x60, 0x10, 5, 1), + PIN_FIELD_BASE(4, 4, 5, 0x60, 0x10, 0, 1), + PIN_FIELD_BASE(5, 6, 5, 0x60, 0x10, 3, 1), + PIN_FIELD_BASE(11, 11, 1, 0x80, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0x80, 0x10, 18, 1), + PIN_FIELD_BASE(19, 19, 4, 0x70, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 4, 0x70, 0x10, 1, 1), + PIN_FIELD_BASE(21, 21, 3, 0x90, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0x90, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0x90, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0x90, 0x10, 19, 1), + PIN_FIELD_BASE(25, 26, 3, 0x90, 0x10, 21, 1), + PIN_FIELD_BASE(27, 27, 3, 0x90, 0x10, 18, 1), + PIN_FIELD_BASE(28, 30, 3, 0x90, 0x10, 25, 1), + PIN_FIELD_BASE(31, 31, 3, 0x90, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0x90, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0xa0, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0x90, 0x10, 31, 1), + PIN_FIELD_BASE(35, 36, 3, 0x90, 0x10, 29, 1), + PIN_FIELD_BASE(37, 37, 3, 0xa0, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0x90, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0x90, 0x10, 10, 1), + PIN_FIELD_BASE(40, 41, 3, 0x90, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 3, 0x90, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0x90, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0x90, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0x90, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0x90, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0x90, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0x90, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0x90, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0x90, 0x10, 15, 1), + PIN_FIELD_BASE(51, 53, 3, 0x90, 0x10, 12, 1), + PIN_FIELD_BASE(54, 54, 3, 0x90, 0x10, 16, 1), + PIN_FIELD_BASE(55, 56, 1, 0x80, 0x10, 12, 1), + PIN_FIELD_BASE(57, 57, 1, 0x80, 0x10, 11, 1), + PIN_FIELD_BASE(58, 60, 1, 0x80, 0x10, 2, 1), + PIN_FIELD_BASE(61, 61, 1, 0x80, 0x10, 1, 1), + PIN_FIELD_BASE(62, 62, 1, 0x80, 0x10, 5, 1), + PIN_FIELD_BASE(64, 68, 1, 0x80, 0x10, 6, 1), + PIN_FIELD_BASE(69, 70, 5, 0x60, 0x10, 1, 1), + PIN_FIELD_BASE(73, 73, 4, 0x70, 0x10, 3, 1), + PIN_FIELD_BASE(74, 74, 4, 0x70, 0x10, 0, 1), + PIN_FIELD_BASE(80, 81, 1, 0x80, 0x10, 16, 1), + PIN_FIELD_BASE(82, 83, 1, 0x80, 0x10, 14, 1), +}; + +static const struct mtk_pin_field_calc mt7988_pin_r1_range[] = { + PIN_FIELD_BASE(0, 1, 5, 0x70, 0x10, 7, 1), + PIN_FIELD_BASE(2, 3, 5, 0x70, 0x10, 5, 1), + PIN_FIELD_BASE(4, 4, 5, 0x70, 0x10, 0, 1), + PIN_FIELD_BASE(5, 6, 5, 0x70, 0x10, 3, 1), + PIN_FIELD_BASE(11, 11, 1, 0x90, 0x10, 0, 1), + PIN_FIELD_BASE(12, 12, 1, 0x90, 0x10, 18, 1), + PIN_FIELD_BASE(19, 19, 4, 0x80, 0x10, 2, 1), + PIN_FIELD_BASE(20, 20, 4, 0x80, 0x10, 1, 1), + PIN_FIELD_BASE(21, 21, 3, 0xb0, 0x10, 17, 1), + PIN_FIELD_BASE(22, 22, 3, 0xb0, 0x10, 23, 1), + PIN_FIELD_BASE(23, 23, 3, 0xb0, 0x10, 20, 1), + PIN_FIELD_BASE(24, 24, 3, 0xb0, 0x10, 19, 1), + PIN_FIELD_BASE(25, 26, 3, 0xb0, 0x10, 21, 1), + PIN_FIELD_BASE(27, 27, 3, 0xb0, 0x10, 18, 1), + PIN_FIELD_BASE(28, 30, 3, 0xb0, 0x10, 25, 1), + PIN_FIELD_BASE(31, 31, 3, 0xb0, 0x10, 24, 1), + PIN_FIELD_BASE(32, 32, 3, 0xb0, 0x10, 28, 1), + PIN_FIELD_BASE(33, 33, 3, 0xc0, 0x10, 0, 1), + PIN_FIELD_BASE(34, 34, 3, 0xb0, 0x10, 31, 1), + PIN_FIELD_BASE(35, 36, 3, 0xb0, 0x10, 29, 1), + PIN_FIELD_BASE(37, 37, 3, 0xc0, 0x10, 1, 1), + PIN_FIELD_BASE(38, 38, 3, 0xb0, 0x10, 11, 1), + PIN_FIELD_BASE(39, 39, 3, 0xb0, 0x10, 10, 1), + PIN_FIELD_BASE(40, 41, 3, 0xb0, 0x10, 0, 1), + PIN_FIELD_BASE(42, 42, 3, 0xb0, 0x10, 9, 1), + PIN_FIELD_BASE(43, 43, 3, 0xb0, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 3, 0xb0, 0x10, 7, 1), + PIN_FIELD_BASE(45, 45, 3, 0xb0, 0x10, 6, 1), + PIN_FIELD_BASE(46, 46, 3, 0xb0, 0x10, 5, 1), + PIN_FIELD_BASE(47, 47, 3, 0xb0, 0x10, 4, 1), + PIN_FIELD_BASE(48, 48, 3, 0xb0, 0x10, 3, 1), + PIN_FIELD_BASE(49, 49, 3, 0xb0, 0x10, 2, 1), + PIN_FIELD_BASE(50, 50, 3, 0xb0, 0x10, 15, 1), + PIN_FIELD_BASE(51, 53, 3, 0xb0, 0x10, 12, 1), + PIN_FIELD_BASE(54, 54, 3, 0xb0, 0x10, 16, 1), + PIN_FIELD_BASE(55, 56, 1, 0x90, 0x10, 12, 1), + PIN_FIELD_BASE(57, 57, 1, 0x90, 0x10, 11, 1), + PIN_FIELD_BASE(58, 60, 1, 0x90, 0x10, 2, 1), + PIN_FIELD_BASE(61, 61, 1, 0x90, 0x10, 1, 1), + PIN_FIELD_BASE(62, 62, 1, 0x90, 0x10, 5, 1), + PIN_FIELD_BASE(64, 68, 1, 0x90, 0x10, 6, 1), + PIN_FIELD_BASE(69, 70, 5, 0x70, 0x10, 1, 1), + PIN_FIELD_BASE(73, 73, 4, 0x80, 0x10, 3, 1), + PIN_FIELD_BASE(74, 74, 4, 0x80, 0x10, 0, 1), + PIN_FIELD_BASE(80, 81, 1, 0x90, 0x10, 16, 1), + PIN_FIELD_BASE(82, 83, 1, 0x90, 0x10, 14, 1), +}; + +static const struct mtk_pin_reg_calc mt7988_reg_cals[] = { + [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt7988_pin_mode_range), + [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt7988_pin_dir_range), + [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt7988_pin_di_range), + [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt7988_pin_do_range), + [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt7988_pin_smt_range), + [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt7988_pin_ies_range), + [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt7988_pin_pu_range), + [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt7988_pin_pd_range), + [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt7988_pin_drv_range), + [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt7988_pin_pupd_range), + [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt7988_pin_r0_range), + [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt7988_pin_r1_range), +}; + +static const struct mtk_pin_desc mt7988_pins[] = { + MT7988_PIN(0, "UART2_RXD"), + MT7988_PIN(1, "UART2_TXD"), + MT7988_PIN(2, "UART2_CTS"), + MT7988_PIN(3, "UART2_RTS"), + MT7988_PIN(4, "GPIO_A"), + MT7988_PIN(5, "SMI_0_MDC"), + MT7988_PIN(6, "SMI_0_MDIO"), + MT7988_PIN(7, "PCIE30_2L_0_WAKE_N"), + MT7988_PIN(8, "PCIE30_2L_0_CLKREQ_N"), + MT7988_PIN(9, "PCIE30_1L_1_WAKE_N"), + MT7988_PIN(10, "PCIE30_1L_1_CLKREQ_N"), + MT7988_PIN(11, "GPIO_P"), + MT7988_PIN(12, "WATCHDOG"), + MT7988_PIN(13, "GPIO_RESET"), + MT7988_PIN(14, "GPIO_WPS"), + MT7988_PIN(15, "PMIC_I2C_SCL"), + MT7988_PIN(16, "PMIC_I2C_SDA"), + MT7988_PIN(17, "I2C_1_SCL"), + MT7988_PIN(18, "I2C_1_SDA"), + MT7988_PIN(19, "PCIE30_2L_0_PRESET_N"), + MT7988_PIN(20, "PCIE30_1L_1_PRESET_N"), + MT7988_PIN(21, "PWMD1"), + MT7988_PIN(22, "SPI0_WP"), + MT7988_PIN(23, "SPI0_HOLD"), + MT7988_PIN(24, "SPI0_CSB"), + MT7988_PIN(25, "SPI0_MISO"), + MT7988_PIN(26, "SPI0_MOSI"), + MT7988_PIN(27, "SPI0_CLK"), + MT7988_PIN(28, "SPI1_CSB"), + MT7988_PIN(29, "SPI1_MISO"), + MT7988_PIN(30, "SPI1_MOSI"), + MT7988_PIN(31, "SPI1_CLK"), + MT7988_PIN(32, "SPI2_CLK"), + MT7988_PIN(33, "SPI2_MOSI"), + MT7988_PIN(34, "SPI2_MISO"), + MT7988_PIN(35, "SPI2_CSB"), + MT7988_PIN(36, "SPI2_HOLD"), + MT7988_PIN(37, "SPI2_WP"), + MT7988_PIN(38, "EMMC_RSTB"), + MT7988_PIN(39, "EMMC_DSL"), + MT7988_PIN(40, "EMMC_CK"), + MT7988_PIN(41, "EMMC_CMD"), + MT7988_PIN(42, "EMMC_DATA_7"), + MT7988_PIN(43, "EMMC_DATA_6"), + MT7988_PIN(44, "EMMC_DATA_5"), + MT7988_PIN(45, "EMMC_DATA_4"), + MT7988_PIN(46, "EMMC_DATA_3"), + MT7988_PIN(47, "EMMC_DATA_2"), + MT7988_PIN(48, "EMMC_DATA_1"), + MT7988_PIN(49, "EMMC_DATA_0"), + MT7988_PIN(50, "PCM_FS_I2S_LRCK"), + MT7988_PIN(51, "PCM_CLK_I2S_BCLK"), + MT7988_PIN(52, "PCM_DRX_I2S_DIN"), + MT7988_PIN(53, "PCM_DTX_I2S_DOUT"), + MT7988_PIN(54, "PCM_MCK_I2S_MCLK"), + MT7988_PIN(55, "UART0_RXD"), + MT7988_PIN(56, "UART0_TXD"), + MT7988_PIN(57, "PWMD0"), + MT7988_PIN(58, "JTAG_JTDI"), + MT7988_PIN(59, "JTAG_JTDO"), + MT7988_PIN(60, "JTAG_JTMS"), + MT7988_PIN(61, "JTAG_JTCLK"), + MT7988_PIN(62, "JTAG_JTRST_N"), + MT7988_PIN(63, "USB_DRV_VBUS_P1"), + MT7988_PIN(64, "LED_A"), + MT7988_PIN(65, "LED_B"), + MT7988_PIN(66, "LED_C"), + MT7988_PIN(67, "LED_D"), + MT7988_PIN(68, "LED_E"), + MT7988_PIN(69, "GPIO_B"), + MT7988_PIN(70, "GPIO_C"), + MT7988_PIN(71, "I2C_2_SCL"), + MT7988_PIN(72, "I2C_2_SDA"), + MT7988_PIN(73, "PCIE30_2L_1_PRESET_N"), + MT7988_PIN(74, "PCIE30_1L_0_PRESET_N"), + MT7988_PIN(75, "PCIE30_2L_1_WAKE_N"), + MT7988_PIN(76, "PCIE30_2L_1_CLKREQ_N"), + MT7988_PIN(77, "PCIE30_1L_0_WAKE_N"), + MT7988_PIN(78, "PCIE30_1L_0_CLKREQ_N"), + MT7988_PIN(79, "USB_DRV_VBUS_P0"), + MT7988_PIN(80, "UART1_RXD"), + MT7988_PIN(81, "UART1_TXD"), + MT7988_PIN(82, "UART1_CTS"), + MT7988_PIN(83, "UART1_RTS"), +}; + +/* jtag */ +static int mt7988_tops_jtag0_0_pins[] = { 0, 1, 2, 3, 4 }; +static int mt7988_tops_jtag0_0_funcs[] = { 2, 2, 2, 2, 2 }; + +static int mt7988_wo0_jtag_pins[] = { 50, 51, 52, 53, 54 }; +static int mt7988_wo0_jtag_funcs[] = { 3, 3, 3, 3, 3 }; + +static int mt7988_wo1_jtag_pins[] = { 50, 51, 52, 53, 54 }; +static int mt7988_wo1_jtag_funcs[] = { 4, 4, 4, 4, 4 }; + +static int mt7988_wo2_jtag_pins[] = { 50, 51, 52, 53, 54 }; +static int mt7988_wo2_jtag_funcs[] = { 5, 5, 5, 5, 5 }; + +static int mt7988_jtag_pins[] = { 58, 59, 60, 61, 62 }; +static int mt7988_jtag_funcs[] = { 1, 1, 1, 1, 1 }; + +static int mt7988_tops_jtag0_1_pins[] = { 58, 59, 60, 61, 62 }; +static int mt7988_tops_jtag0_1_funcs[] = { 4, 4, 4, 4, 4 }; + +/* int_usxgmii */ +static int mt7988_int_usxgmii_pins[] = { 2, 3 }; +static int mt7988_int_usxgmii_funcs[] = { 3, 3 }; + +/* pwm */ +static int mt7988_pwm0_pins[] = { 57 }; +static int mt7988_pwm0_funcs[] = { 1 }; + +static int mt7988_pwm1_pins[] = { 21 }; +static int mt7988_pwm1_funcs[] = { 1 }; + +static int mt7988_pwm2_pins[] = { 80 }; +static int mt7988_pwm2_funcs[] = { 2 }; + +static int mt7988_pwm3_pins[] = { 81 }; +static int mt7988_pwm3_funcs[] = { 2 }; + +static int mt7988_pwm4_pins[] = { 82 }; +static int mt7988_pwm4_funcs[] = { 2 }; + +static int mt7988_pwm5_pins[] = { 83 }; +static int mt7988_pwm5_funcs[] = { 2 }; + +static int mt7988_pwm6_pins[] = { 69 }; +static int mt7988_pwm6_funcs[] = { 3 }; + +static int mt7988_pwm7_pins[] = { 70 }; +static int mt7988_pwm7_funcs[] = { 3 }; + +/* dfd */ +static int mt7988_dfd_pins[] = { 0, 1, 2, 3, 4 }; +static int mt7988_dfd_funcs[] = { 4, 4, 4, 4, 4 }; + +/* i2c */ +static int mt7988_xfi_phy0_i2c0_pins[] = { 0, 1 }; +static int mt7988_xfi_phy0_i2c0_funcs[] = { 5, 5 }; + +static int mt7988_xfi_phy1_i2c0_pins[] = { 0, 1 }; +static int mt7988_xfi_phy1_i2c0_funcs[] = { 6, 6 }; + +static int mt7988_xfi_phy_pll_i2c0_pins[] = { 3, 4 }; +static int mt7988_xfi_phy_pll_i2c0_funcs[] = { 5, 5 }; + +static int mt7988_xfi_phy_pll_i2c1_pins[] = { 3, 4 }; +static int mt7988_xfi_phy_pll_i2c1_funcs[] = { 6, 6 }; + +static int mt7988_i2c0_0_pins[] = { 5, 6 }; +static int mt7988_i2c0_0_funcs[] = { 2, 2 }; + +static int mt7988_i2c1_sfp_pins[] = { 5, 6 }; +static int mt7988_i2c1_sfp_funcs[] = { 4, 4 }; + +static int mt7988_xfi_pextp_phy0_i2c_pins[] = { 5, 6 }; +static int mt7988_xfi_pextp_phy0_i2c_funcs[] = { 5, 5 }; + +static int mt7988_xfi_pextp_phy1_i2c_pins[] = { 5, 6 }; +static int mt7988_xfi_pextp_phy1_i2c_funcs[] = { 6, 6 }; + +static int mt7988_i2c0_1_pins[] = { 15, 16 }; +static int mt7988_i2c0_1_funcs[] = { 1, 1 }; + +static int mt7988_u30_phy_i2c0_pins[] = { 15, 16 }; +static int mt7988_u30_phy_i2c0_funcs[] = { 2, 2 }; + +static int mt7988_u32_phy_i2c0_pins[] = { 15, 16 }; +static int mt7988_u32_phy_i2c0_funcs[] = { 3, 3 }; + +static int mt7988_xfi_phy0_i2c1_pins[] = { 15, 16 }; +static int mt7988_xfi_phy0_i2c1_funcs[] = { 5, 5 }; + +static int mt7988_xfi_phy1_i2c1_pins[] = { 15, 16 }; +static int mt7988_xfi_phy1_i2c1_funcs[] = { 6, 6 }; + +static int mt7988_xfi_phy_pll_i2c2_pins[] = { 15, 16 }; +static int mt7988_xfi_phy_pll_i2c2_funcs[] = { 7, 7 }; + +static int mt7988_i2c1_0_pins[] = { 17, 18 }; +static int mt7988_i2c1_0_funcs[] = { 1, 1 }; + +static int mt7988_u30_phy_i2c1_pins[] = { 17, 18 }; +static int mt7988_u30_phy_i2c1_funcs[] = { 2, 2 }; + +static int mt7988_u32_phy_i2c1_pins[] = { 17, 18 }; +static int mt7988_u32_phy_i2c1_funcs[] = { 3, 3 }; + +static int mt7988_xfi_phy_pll_i2c3_pins[] = { 17, 18 }; +static int mt7988_xfi_phy_pll_i2c3_funcs[] = { 4, 4 }; + +static int mt7988_sgmii0_i2c_pins[] = { 17, 18 }; +static int mt7988_sgmii0_i2c_funcs[] = { 5, 5 }; + +static int mt7988_sgmii1_i2c_pins[] = { 17, 18 }; +static int mt7988_sgmii1_i2c_funcs[] = { 6, 6 }; + +static int mt7988_i2c1_2_pins[] = { 69, 70 }; +static int mt7988_i2c1_2_funcs[] = { 2, 2 }; + +static int mt7988_i2c2_0_pins[] = { 69, 70 }; +static int mt7988_i2c2_0_funcs[] = { 4, 4 }; + +static int mt7988_i2c2_1_pins[] = { 71, 72 }; +static int mt7988_i2c2_1_funcs[] = { 1, 1 }; + +/* eth */ +static int mt7988_mdc_mdio0_pins[] = { 5, 6 }; +static int mt7988_mdc_mdio0_funcs[] = { 1, 1 }; + +static int mt7988_2p5g_ext_mdio_pins[] = { 28, 29 }; +static int mt7988_2p5g_ext_mdio_funcs[] = { 6, 6 }; + +static int mt7988_gbe_ext_mdio_pins[] = { 30, 31 }; +static int mt7988_gbe_ext_mdio_funcs[] = { 6, 6 }; + +static int mt7988_mdc_mdio1_pins[] = { 69, 70 }; +static int mt7988_mdc_mdio1_funcs[] = { 1, 1 }; + +/* pcie */ +static int mt7988_pcie_wake_n0_0_pins[] = { 7 }; +static int mt7988_pcie_wake_n0_0_funcs[] = { 1 }; + +static int mt7988_pcie_clk_req_n0_0_pins[] = { 8 }; +static int mt7988_pcie_clk_req_n0_0_funcs[] = { 1 }; + +static int mt7988_pcie_wake_n3_0_pins[] = { 9 }; +static int mt7988_pcie_wake_n3_0_funcs[] = { 1 }; + +static int mt7988_pcie_clk_req_n3_pins[] = { 10 }; +static int mt7988_pcie_clk_req_n3_funcs[] = { 1 }; + +static int mt7988_pcie_clk_req_n0_1_pins[] = { 10 }; +static int mt7988_pcie_clk_req_n0_1_funcs[] = { 2 }; + +static int mt7988_pcie_p0_phy_i2c_pins[] = { 7, 8 }; +static int mt7988_pcie_p0_phy_i2c_funcs[] = { 3, 3 }; + +static int mt7988_pcie_p1_phy_i2c_pins[] = { 7, 8 }; +static int mt7988_pcie_p1_phy_i2c_funcs[] = { 4, 4 }; + +static int mt7988_pcie_p3_phy_i2c_pins[] = { 9, 10 }; +static int mt7988_pcie_p3_phy_i2c_funcs[] = { 4, 4 }; + +static int mt7988_pcie_p2_phy_i2c_pins[] = { 7, 8 }; +static int mt7988_pcie_p2_phy_i2c_funcs[] = { 5, 5 }; + +static int mt7988_ckm_phy_i2c_pins[] = { 9, 10 }; +static int mt7988_ckm_phy_i2c_funcs[] = { 5, 5 }; + +static int mt7988_pcie_wake_n0_1_pins[] = { 13 }; +static int mt7988_pcie_wake_n0_1_funcs[] = { 2 }; + +static int mt7988_pcie_wake_n3_1_pins[] = { 14 }; +static int mt7988_pcie_wake_n3_1_funcs[] = { 2 }; + +static int mt7988_pcie_2l_0_pereset_pins[] = { 19 }; +static int mt7988_pcie_2l_0_pereset_funcs[] = { 1 }; + +static int mt7988_pcie_1l_1_pereset_pins[] = { 20 }; +static int mt7988_pcie_1l_1_pereset_funcs[] = { 1 }; + +static int mt7988_pcie_clk_req_n2_1_pins[] = { 63 }; +static int mt7988_pcie_clk_req_n2_1_funcs[] = { 2 }; + +static int mt7988_pcie_2l_1_pereset_pins[] = { 73 }; +static int mt7988_pcie_2l_1_pereset_funcs[] = { 1 }; + +static int mt7988_pcie_1l_0_pereset_pins[] = { 74 }; +static int mt7988_pcie_1l_0_pereset_funcs[] = { 1 }; + +static int mt7988_pcie_wake_n1_0_pins[] = { 75 }; +static int mt7988_pcie_wake_n1_0_funcs[] = { 1 }; + +static int mt7988_pcie_clk_req_n1_pins[] = { 76 }; +static int mt7988_pcie_clk_req_n1_funcs[] = { 1 }; + +static int mt7988_pcie_wake_n2_0_pins[] = { 77 }; +static int mt7988_pcie_wake_n2_0_funcs[] = { 1 }; + +static int mt7988_pcie_clk_req_n2_0_pins[] = { 78 }; +static int mt7988_pcie_clk_req_n2_0_funcs[] = { 1 }; + +static int mt7988_pcie_wake_n2_1_pins[] = { 79 }; +static int mt7988_pcie_wake_n2_1_funcs[] = { 2 }; + +/* pmic */ +static int mt7988_pmic_pins[] = { 11 }; +static int mt7988_pmic_funcs[] = { 1 }; + +/* watchdog */ +static int mt7988_watchdog_pins[] = { 12 }; +static int mt7988_watchdog_funcs[] = { 1 }; + +/* spi */ +static int mt7988_spi0_wp_hold_pins[] = { 22, 23 }; +static int mt7988_spi0_wp_hold_funcs[] = { 1, 1 }; + +static int mt7988_spi0_pins[] = { 24, 25, 26, 27 }; +static int mt7988_spi0_funcs[] = { 1, 1, 1, 1 }; + +static int mt7988_spi1_pins[] = { 28, 29, 30, 31 }; +static int mt7988_spi1_funcs[] = { 1, 1, 1, 1 }; + +static int mt7988_spi2_pins[] = { 32, 33, 34, 35 }; +static int mt7988_spi2_funcs[] = { 1, 1, 1, 1 }; + +static int mt7988_spi2_wp_hold_pins[] = { 36, 37 }; +static int mt7988_spi2_wp_hold_funcs[] = { 1, 1 }; + +/* flash */ +static int mt7988_snfi_pins[] = { 22, 23, 24, 25, 26, 27 }; +static int mt7988_snfi_funcs[] = { 2, 2, 2, 2, 2, 2 }; + +static int mt7988_emmc_45_pins[] = { + 21, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37 +}; +static int mt7988_emmc_45_funcs[] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; + +static int mt7988_sdcard_pins[] = { 32, 33, 34, 35, 36, 37 }; +static int mt7988_sdcard_funcs[] = { 5, 5, 5, 5, 5, 5 }; + +static int mt7988_emmc_51_pins[] = { 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49 }; +static int mt7988_emmc_51_funcs[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + +/* uart */ +static int mt7988_uart2_pins[] = { 0, 1, 2, 3 }; +static int mt7988_uart2_funcs[] = { 1, 1, 1, 1 }; + +static int mt7988_tops_uart0_0_pins[] = { 22, 23 }; +static int mt7988_tops_uart0_0_funcs[] = { 3, 3 }; + +static int mt7988_uart2_0_pins[] = { 28, 29, 30, 31 }; +static int mt7988_uart2_0_funcs[] = { 2, 2, 2, 2 }; + +static int mt7988_uart1_0_pins[] = { 32, 33, 34, 35 }; +static int mt7988_uart1_0_funcs[] = { 2, 2, 2, 2 }; + +static int mt7988_uart2_1_pins[] = { 32, 33, 34, 35 }; +static int mt7988_uart2_1_funcs[] = { 3, 3, 3, 3 }; + +static int mt7988_net_wo0_uart_txd_0_pins[] = { 28 }; +static int mt7988_net_wo0_uart_txd_0_funcs[] = { 3 }; + +static int mt7988_net_wo1_uart_txd_0_pins[] = { 29 }; +static int mt7988_net_wo1_uart_txd_0_funcs[] = { 3 }; + +static int mt7988_net_wo2_uart_txd_0_pins[] = { 30 }; +static int mt7988_net_wo2_uart_txd_0_funcs[] = { 3 }; + +static int mt7988_tops_uart1_0_pins[] = { 28, 29 }; +static int mt7988_tops_uart1_0_funcs[] = { 4, 4 }; + +static int mt7988_tops_uart0_1_pins[] = { 30, 31 }; +static int mt7988_tops_uart0_1_funcs[] = { 4, 4 }; + +static int mt7988_tops_uart1_1_pins[] = { 36, 37 }; +static int mt7988_tops_uart1_1_funcs[] = { 3, 3 }; + +static int mt7988_uart0_pins[] = { 55, 56 }; +static int mt7988_uart0_funcs[] = { 1, 1 }; + +static int mt7988_tops_uart0_2_pins[] = { 55, 56 }; +static int mt7988_tops_uart0_2_funcs[] = { 2, 2 }; + +static int mt7988_uart2_2_pins[] = { 50, 51, 52, 53 }; +static int mt7988_uart2_2_funcs[] = { 2, 2, 2, 2 }; + +static int mt7988_uart1_1_pins[] = { 58, 59, 60, 61 }; +static int mt7988_uart1_1_funcs[] = { 2, 2, 2, 2 }; + +static int mt7988_uart2_3_pins[] = { 58, 59, 60, 61 }; +static int mt7988_uart2_3_funcs[] = { 3, 3, 3, 3 }; + +static int mt7988_uart1_2_pins[] = { 80, 81, 82, 83 }; +static int mt7988_uart1_2_funcs[] = { 1, 1, 1, 1 }; + +static int mt7988_tops_uart1_2_pins[] = { 80, 81 }; +static int mt7988_tops_uart1_2_funcs[] = { + 4, + 4, +}; + +static int mt7988_net_wo0_uart_txd_1_pins[] = { 80 }; +static int mt7988_net_wo0_uart_txd_1_funcs[] = { 3 }; + +static int mt7988_net_wo1_uart_txd_1_pins[] = { 81 }; +static int mt7988_net_wo1_uart_txd_1_funcs[] = { 3 }; + +static int mt7988_net_wo2_uart_txd_1_pins[] = { 82 }; +static int mt7988_net_wo2_uart_txd_1_funcs[] = { 3 }; + +/* udi */ +static int mt7988_udi_pins[] = { 32, 33, 34, 35, 36 }; +static int mt7988_udi_funcs[] = { 4, 4, 4, 4, 4 }; + +/* i2s */ +static int mt7988_i2s_pins[] = { 50, 51, 52, 53, 54 }; +static int mt7988_i2s_funcs[] = { 1, 1, 1, 1, 1 }; + +/* pcm */ +static int mt7988_pcm_pins[] = { 50, 51, 52, 53 }; +static int mt7988_pcm_funcs[] = { 1, 1, 1, 1 }; + +/* led */ +static int mt7988_gbe0_led1_pins[] = { 58 }; +static int mt7988_gbe0_led1_funcs[] = { 6 }; +static int mt7988_gbe1_led1_pins[] = { 59 }; +static int mt7988_gbe1_led1_funcs[] = { 6 }; +static int mt7988_gbe2_led1_pins[] = { 60 }; +static int mt7988_gbe2_led1_funcs[] = { 6 }; +static int mt7988_gbe3_led1_pins[] = { 61 }; +static int mt7988_gbe3_led1_funcs[] = { 6 }; + +static int mt7988_2p5gbe_led1_pins[] = { 62 }; +static int mt7988_2p5gbe_led1_funcs[] = { 6 }; + +static int mt7988_gbe0_led0_pins[] = { 64 }; +static int mt7988_gbe0_led0_funcs[] = { 1 }; +static int mt7988_gbe1_led0_pins[] = { 65 }; +static int mt7988_gbe1_led0_funcs[] = { 1 }; +static int mt7988_gbe2_led0_pins[] = { 66 }; +static int mt7988_gbe2_led0_funcs[] = { 1 }; +static int mt7988_gbe3_led0_pins[] = { 67 }; +static int mt7988_gbe3_led0_funcs[] = { 1 }; + +static int mt7988_2p5gbe_led0_pins[] = { 68 }; +static int mt7988_2p5gbe_led0_funcs[] = { 1 }; + +/* usb */ +static int mt7988_drv_vbus_p1_pins[] = { 63 }; +static int mt7988_drv_vbus_p1_funcs[] = { 1 }; + +static int mt7988_drv_vbus_pins[] = { 79 }; +static int mt7988_drv_vbus_funcs[] = { 1 }; + +static const struct group_desc mt7988_groups[] = { + /* @GPIO(0,1,2,3): uart2 */ + PINCTRL_PIN_GROUP("uart2", mt7988_uart2), + /* @GPIO(0,1,2,3,4): tops_jtag0_0 */ + PINCTRL_PIN_GROUP("tops_jtag0_0", mt7988_tops_jtag0_0), + /* @GPIO(2,3): int_usxgmii */ + PINCTRL_PIN_GROUP("int_usxgmii", mt7988_int_usxgmii), + /* @GPIO(0,1,2,3,4): dfd */ + PINCTRL_PIN_GROUP("dfd", mt7988_dfd), + /* @GPIO(0,1): xfi_phy0_i2c0 */ + PINCTRL_PIN_GROUP("xfi_phy0_i2c0", mt7988_xfi_phy0_i2c0), + /* @GPIO(0,1): xfi_phy1_i2c0 */ + PINCTRL_PIN_GROUP("xfi_phy1_i2c0", mt7988_xfi_phy1_i2c0), + /* @GPIO(3,4): xfi_phy_pll_i2c0 */ + PINCTRL_PIN_GROUP("xfi_phy_pll_i2c0", mt7988_xfi_phy_pll_i2c0), + /* @GPIO(3,4): xfi_phy_pll_i2c1 */ + PINCTRL_PIN_GROUP("xfi_phy_pll_i2c1", mt7988_xfi_phy_pll_i2c1), + /* @GPIO(5,6) i2c0_0 */ + PINCTRL_PIN_GROUP("i2c0_0", mt7988_i2c0_0), + /* @GPIO(5,6) i2c1_sfp */ + PINCTRL_PIN_GROUP("i2c1_sfp", mt7988_i2c1_sfp), + /* @GPIO(5,6) xfi_pextp_phy0_i2c */ + PINCTRL_PIN_GROUP("xfi_pextp_phy0_i2c", mt7988_xfi_pextp_phy0_i2c), + /* @GPIO(5,6) xfi_pextp_phy1_i2c */ + PINCTRL_PIN_GROUP("xfi_pextp_phy1_i2c", mt7988_xfi_pextp_phy1_i2c), + /* @GPIO(5,6) mdc_mdio0 */ + PINCTRL_PIN_GROUP("mdc_mdio0", mt7988_mdc_mdio0), + /* @GPIO(7): pcie_wake_n0_0 */ + PINCTRL_PIN_GROUP("pcie_wake_n0_0", mt7988_pcie_wake_n0_0), + /* @GPIO(8): pcie_clk_req_n0_0 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n0_0", mt7988_pcie_clk_req_n0_0), + /* @GPIO(9): pcie_wake_n3_0 */ + PINCTRL_PIN_GROUP("pcie_wake_n3_0", mt7988_pcie_wake_n3_0), + /* @GPIO(10): pcie_clk_req_n3 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n3", mt7988_pcie_clk_req_n3), + /* @GPIO(10): pcie_clk_req_n0_1 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n0_1", mt7988_pcie_clk_req_n0_1), + /* @GPIO(7,8) pcie_p0_phy_i2c */ + PINCTRL_PIN_GROUP("pcie_p0_phy_i2c", mt7988_pcie_p0_phy_i2c), + /* @GPIO(7,8) pcie_p1_phy_i2c */ + PINCTRL_PIN_GROUP("pcie_p1_phy_i2c", mt7988_pcie_p1_phy_i2c), + /* @GPIO(7,8) pcie_p2_phy_i2c */ + PINCTRL_PIN_GROUP("pcie_p2_phy_i2c", mt7988_pcie_p2_phy_i2c), + /* @GPIO(9,10) pcie_p3_phy_i2c */ + PINCTRL_PIN_GROUP("pcie_p3_phy_i2c", mt7988_pcie_p3_phy_i2c), + /* @GPIO(9,10) ckm_phy_i2c */ + PINCTRL_PIN_GROUP("ckm_phy_i2c", mt7988_ckm_phy_i2c), + /* @GPIO(11): pmic */ + PINCTRL_PIN_GROUP("pcie_pmic", mt7988_pmic), + /* @GPIO(12): watchdog */ + PINCTRL_PIN_GROUP("watchdog", mt7988_watchdog), + /* @GPIO(13): pcie_wake_n0_1 */ + PINCTRL_PIN_GROUP("pcie_wake_n0_1", mt7988_pcie_wake_n0_1), + /* @GPIO(14): pcie_wake_n3_1 */ + PINCTRL_PIN_GROUP("pcie_wake_n3_1", mt7988_pcie_wake_n3_1), + /* @GPIO(15,16) i2c0_1 */ + PINCTRL_PIN_GROUP("i2c0_1", mt7988_i2c0_1), + /* @GPIO(15,16) u30_phy_i2c0 */ + PINCTRL_PIN_GROUP("u30_phy_i2c0", mt7988_u30_phy_i2c0), + /* @GPIO(15,16) u32_phy_i2c0 */ + PINCTRL_PIN_GROUP("u32_phy_i2c0", mt7988_u32_phy_i2c0), + /* @GPIO(15,16) xfi_phy0_i2c1 */ + PINCTRL_PIN_GROUP("xfi_phy0_i2c1", mt7988_xfi_phy0_i2c1), + /* @GPIO(15,16) xfi_phy1_i2c1 */ + PINCTRL_PIN_GROUP("xfi_phy1_i2c1", mt7988_xfi_phy1_i2c1), + /* @GPIO(15,16) xfi_phy_pll_i2c2 */ + PINCTRL_PIN_GROUP("xfi_phy_pll_i2c2", mt7988_xfi_phy_pll_i2c2), + /* @GPIO(17,18) i2c1_0 */ + PINCTRL_PIN_GROUP("i2c1_0", mt7988_i2c1_0), + /* @GPIO(17,18) u30_phy_i2c1 */ + PINCTRL_PIN_GROUP("u30_phy_i2c1", mt7988_u30_phy_i2c1), + /* @GPIO(17,18) u32_phy_i2c1 */ + PINCTRL_PIN_GROUP("u32_phy_i2c1", mt7988_u32_phy_i2c1), + /* @GPIO(17,18) xfi_phy_pll_i2c3 */ + PINCTRL_PIN_GROUP("xfi_phy_pll_i2c3", mt7988_xfi_phy_pll_i2c3), + /* @GPIO(17,18) sgmii0_i2c */ + PINCTRL_PIN_GROUP("sgmii0_i2c", mt7988_sgmii0_i2c), + /* @GPIO(17,18) sgmii1_i2c */ + PINCTRL_PIN_GROUP("sgmii1_i2c", mt7988_sgmii1_i2c), + /* @GPIO(19): pcie_2l_0_pereset */ + PINCTRL_PIN_GROUP("pcie_2l_0_pereset", mt7988_pcie_2l_0_pereset), + /* @GPIO(20): pcie_1l_1_pereset */ + PINCTRL_PIN_GROUP("pcie_1l_1_pereset", mt7988_pcie_1l_1_pereset), + /* @GPIO(21): pwm1 */ + PINCTRL_PIN_GROUP("pwm1", mt7988_pwm1), + /* @GPIO(22,23) spi0_wp_hold */ + PINCTRL_PIN_GROUP("spi0_wp_hold", mt7988_spi0_wp_hold), + /* @GPIO(24,25,26,27) spi0 */ + PINCTRL_PIN_GROUP("spi0", mt7988_spi0), + /* @GPIO(28,29,30,31) spi1 */ + PINCTRL_PIN_GROUP("spi1", mt7988_spi1), + /* @GPIO(32,33,34,35) spi2 */ + PINCTRL_PIN_GROUP("spi2", mt7988_spi2), + /* @GPIO(36,37) spi2_wp_hold */ + PINCTRL_PIN_GROUP("spi2_wp_hold", mt7988_spi2_wp_hold), + /* @GPIO(22,23,24,25,26,27) snfi */ + PINCTRL_PIN_GROUP("snfi", mt7988_snfi), + /* @GPIO(22,23) tops_uart0_0 */ + PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart0_0), + /* @GPIO(28,29,30,31) uart2_0 */ + PINCTRL_PIN_GROUP("uart2_0", mt7988_uart2_0), + /* @GPIO(32,33,34,35) uart1_0 */ + PINCTRL_PIN_GROUP("uart1_0", mt7988_uart1_0), + /* @GPIO(32,33,34,35) uart2_1 */ + PINCTRL_PIN_GROUP("uart2_1", mt7988_uart2_1), + /* @GPIO(28) net_wo0_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0), + /* @GPIO(29) net_wo1_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0), + /* @GPIO(30) net_wo2_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0), + /* @GPIO(28,29) tops_uart1_0 */ + PINCTRL_PIN_GROUP("tops_uart0_0", mt7988_tops_uart1_0), + /* @GPIO(30,31) tops_uart0_1 */ + PINCTRL_PIN_GROUP("tops_uart0_1", mt7988_tops_uart0_1), + /* @GPIO(36,37) tops_uart1_1 */ + PINCTRL_PIN_GROUP("tops_uart1_1", mt7988_tops_uart1_1), + /* @GPIO(32,33,34,35,36) udi */ + PINCTRL_PIN_GROUP("udi", mt7988_udi), + /* @GPIO(21,28,29,30,31,32,33,34,35,36,37) emmc_45 */ + PINCTRL_PIN_GROUP("emmc_45", mt7988_emmc_45), + /* @GPIO(32,33,34,35,36,37) sdcard */ + PINCTRL_PIN_GROUP("sdcard", mt7988_sdcard), + /* @GPIO(38,39,40,41,42,43,44,45,46,47,48,49) emmc_51 */ + PINCTRL_PIN_GROUP("emmc_51", mt7988_emmc_51), + /* @GPIO(28,29) 2p5g_ext_mdio */ + PINCTRL_PIN_GROUP("2p5g_ext_mdio", mt7988_2p5g_ext_mdio), + /* @GPIO(30,31) gbe_ext_mdio */ + PINCTRL_PIN_GROUP("gbe_ext_mdio", mt7988_gbe_ext_mdio), + /* @GPIO(50,51,52,53,54) i2s */ + PINCTRL_PIN_GROUP("i2s", mt7988_i2s), + /* @GPIO(50,51,52,53) pcm */ + PINCTRL_PIN_GROUP("pcm", mt7988_pcm), + /* @GPIO(55,56) uart0 */ + PINCTRL_PIN_GROUP("uart0", mt7988_uart0), + /* @GPIO(55,56) tops_uart0_2 */ + PINCTRL_PIN_GROUP("tops_uart0_2", mt7988_tops_uart0_2), + /* @GPIO(50,51,52,53) uart2_2 */ + PINCTRL_PIN_GROUP("uart2_2", mt7988_uart2_2), + /* @GPIO(50,51,52,53,54) wo0_jtag */ + PINCTRL_PIN_GROUP("wo0_jtag", mt7988_wo0_jtag), + /* @GPIO(50,51,52,53,54) wo1-wo1_jtag */ + PINCTRL_PIN_GROUP("wo1_jtag", mt7988_wo1_jtag), + /* @GPIO(50,51,52,53,54) wo2_jtag */ + PINCTRL_PIN_GROUP("wo2_jtag", mt7988_wo2_jtag), + /* @GPIO(57) pwm0 */ + PINCTRL_PIN_GROUP("pwm0", mt7988_pwm0), + /* @GPIO(58,59,60,61,62) jtag */ + PINCTRL_PIN_GROUP("jtag", mt7988_jtag), + /* @GPIO(58,59,60,61,62) tops_jtag0_1 */ + PINCTRL_PIN_GROUP("tops_jtag0_1", mt7988_tops_jtag0_1), + /* @GPIO(58,59,60,61) uart2_3 */ + PINCTRL_PIN_GROUP("uart2_3", mt7988_uart2_3), + /* @GPIO(58,59,60,61) uart1_1 */ + PINCTRL_PIN_GROUP("uart1_1", mt7988_uart1_1), + /* @GPIO(58,59,60,61) gbe_led1 */ + PINCTRL_PIN_GROUP("gbe0_led1", mt7988_gbe0_led1), + PINCTRL_PIN_GROUP("gbe1_led1", mt7988_gbe1_led1), + PINCTRL_PIN_GROUP("gbe2_led1", mt7988_gbe2_led1), + PINCTRL_PIN_GROUP("gbe3_led1", mt7988_gbe3_led1), + /* @GPIO(62) 2p5gbe_led1 */ + PINCTRL_PIN_GROUP("2p5gbe_led1", mt7988_2p5gbe_led1), + /* @GPIO(64,65,66,67) gbe_led0 */ + PINCTRL_PIN_GROUP("gbe0_led0", mt7988_gbe0_led0), + PINCTRL_PIN_GROUP("gbe1_led0", mt7988_gbe1_led0), + PINCTRL_PIN_GROUP("gbe2_led0", mt7988_gbe2_led0), + PINCTRL_PIN_GROUP("gbe3_led0", mt7988_gbe3_led0), + /* @GPIO(68) 2p5gbe_led0 */ + PINCTRL_PIN_GROUP("2p5gbe_led0", mt7988_2p5gbe_led0), + /* @GPIO(63) drv_vbus_p1 */ + PINCTRL_PIN_GROUP("drv_vbus_p1", mt7988_drv_vbus_p1), + /* @GPIO(63) pcie_clk_req_n2_1 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n2_1", mt7988_pcie_clk_req_n2_1), + /* @GPIO(69, 70) mdc_mdio1 */ + PINCTRL_PIN_GROUP("mdc_mdio1", mt7988_mdc_mdio1), + /* @GPIO(69, 70) i2c1_2 */ + PINCTRL_PIN_GROUP("i2c1_2", mt7988_i2c1_2), + /* @GPIO(69) pwm6 */ + PINCTRL_PIN_GROUP("pwm6", mt7988_pwm6), + /* @GPIO(70) pwm7 */ + PINCTRL_PIN_GROUP("pwm7", mt7988_pwm7), + /* @GPIO(69,70) i2c2_0 */ + PINCTRL_PIN_GROUP("i2c2_0", mt7988_i2c2_0), + /* @GPIO(71,72) i2c2_1 */ + PINCTRL_PIN_GROUP("i2c2_1", mt7988_i2c2_1), + /* @GPIO(73) pcie_2l_1_pereset */ + PINCTRL_PIN_GROUP("pcie_2l_1_pereset", mt7988_pcie_2l_1_pereset), + /* @GPIO(74) pcie_1l_0_pereset */ + PINCTRL_PIN_GROUP("pcie_1l_0_pereset", mt7988_pcie_1l_0_pereset), + /* @GPIO(75) pcie_wake_n1_0 */ + PINCTRL_PIN_GROUP("pcie_wake_n1_0", mt7988_pcie_wake_n1_0), + /* @GPIO(76) pcie_clk_req_n1 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n1", mt7988_pcie_clk_req_n1), + /* @GPIO(77) pcie_wake_n2_0 */ + PINCTRL_PIN_GROUP("pcie_wake_n2_0", mt7988_pcie_wake_n2_0), + /* @GPIO(78) pcie_clk_req_n2_0 */ + PINCTRL_PIN_GROUP("pcie_clk_req_n2_0", mt7988_pcie_clk_req_n2_0), + /* @GPIO(79) drv_vbus */ + PINCTRL_PIN_GROUP("drv_vbus", mt7988_drv_vbus), + /* @GPIO(79) pcie_wake_n2_1 */ + PINCTRL_PIN_GROUP("pcie_wake_n2_1", mt7988_pcie_wake_n2_1), + /* @GPIO(80,81,82,83) uart1_2 */ + PINCTRL_PIN_GROUP("uart1_2", mt7988_uart1_2), + /* @GPIO(80) pwm2 */ + PINCTRL_PIN_GROUP("pwm2", mt7988_pwm2), + /* @GPIO(81) pwm3 */ + PINCTRL_PIN_GROUP("pwm3", mt7988_pwm3), + /* @GPIO(82) pwm4 */ + PINCTRL_PIN_GROUP("pwm4", mt7988_pwm4), + /* @GPIO(83) pwm5 */ + PINCTRL_PIN_GROUP("pwm5", mt7988_pwm5), + /* @GPIO(80) net_wo0_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_0", mt7988_net_wo0_uart_txd_0), + /* @GPIO(81) net_wo1_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo1_uart_txd_0", mt7988_net_wo1_uart_txd_0), + /* @GPIO(82) net_wo2_uart_txd_0 */ + PINCTRL_PIN_GROUP("net_wo2_uart_txd_0", mt7988_net_wo2_uart_txd_0), + /* @GPIO(80,81) tops_uart1_2 */ + PINCTRL_PIN_GROUP("tops_uart1_2", mt7988_tops_uart1_2), + /* @GPIO(80) net_wo0_uart_txd_1 */ + PINCTRL_PIN_GROUP("net_wo0_uart_txd_1", mt7988_net_wo0_uart_txd_1), + /* @GPIO(81) net_wo1_uart_txd_1 */ + PINCTRL_PIN_GROUP("net_wo1_uart_txd_1", mt7988_net_wo1_uart_txd_1), + /* @GPIO(82) net_wo2_uart_txd_1 */ + PINCTRL_PIN_GROUP("net_wo2_uart_txd_1", mt7988_net_wo2_uart_txd_1), +}; + +/* Joint those groups owning the same capability in user point of view which + * allows that people tend to use through the device tree. + */ +static const char *mt7988_jtag_groups[] = { + "tops_jtag0_0", "wo0_jtag", "wo1_jtag", + "wo2_jtag", "jtag", "tops_jtag0_1", +}; +static const char *mt7988_int_usxgmii_groups[] = { + "int_usxgmii", +}; +static const char *mt7988_pwm_groups[] = { + "pwm0", "pwm1", "pwm2", "pwm3", "pwm4", "pwm5", "pwm6", "pwm7" +}; +static const char *mt7988_dfd_groups[] = { + "dfd", +}; +static const char *mt7988_i2c_groups[] = { + "xfi_phy0_i2c0", + "xfi_phy1_i2c0", + "xfi_phy_pll_i2c0", + "xfi_phy_pll_i2c1", + "i2c0_0", + "i2c1_sfp", + "xfi_pextp_phy0_i2c", + "xfi_pextp_phy1_i2c", + "i2c0_1", + "u30_phy_i2c0", + "u32_phy_i2c0", + "xfi_phy0_i2c1", + "xfi_phy1_i2c1", + "xfi_phy_pll_i2c2", + "i2c1_0", + "u30_phy_i2c1", + "u32_phy_i2c1", + "xfi_phy_pll_i2c3", + "sgmii0_i2c", + "sgmii1_i2c", + "i2c1_2", + "i2c2_0", + "i2c2_1", +}; +static const char *mt7988_ethernet_groups[] = { + "mdc_mdio0", + "2p5g_ext_mdio", + "gbe_ext_mdio", + "mdc_mdio1", +}; +static const char *mt7988_pcie_groups[] = { + "pcie_wake_n0_0", "pcie_clk_req_n0_0", "pcie_wake_n3_0", + "pcie_clk_req_n3", "pcie_p0_phy_i2c", "pcie_p1_phy_i2c", + "pcie_p3_phy_i2c", "pcie_p2_phy_i2c", "ckm_phy_i2c", + "pcie_wake_n0_1", "pcie_wake_n3_1", "pcie_2l_0_pereset", + "pcie_1l_1_pereset", "pcie_clk_req_n2_1", "pcie_2l_1_pereset", + "pcie_1l_0_pereset", "pcie_wake_n1_0", "pcie_clk_req_n1", + "pcie_wake_n2_0", "pcie_clk_req_n2_0", "pcie_wake_n2_1", + "pcie_clk_req_n0_1" +}; +static const char *mt7988_pmic_groups[] = { + "pmic", +}; +static const char *mt7988_wdt_groups[] = { + "watchdog", +}; +static const char *mt7988_spi_groups[] = { + "spi0", "spi0_wp_hold", "spi1", "spi2", "spi2_wp_hold", +}; +static const char *mt7988_flash_groups[] = { "emmc_45", "sdcard", "snfi", + "emmc_51" }; +static const char *mt7988_uart_groups[] = { + "uart2", + "tops_uart0_0", + "uart2_0", + "uart1_0", + "uart2_1", + "net_wo0_uart_txd_0", + "net_wo1_uart_txd_0", + "net_wo2_uart_txd_0", + "tops_uart1_0", + "ops_uart0_1", + "ops_uart1_1", + "uart0", + "tops_uart0_2", + "uart1_1", + "uart2_3", + "uart1_2", + "tops_uart1_2", + "net_wo0_uart_txd_1", + "net_wo1_uart_txd_1", + "net_wo2_uart_txd_1", +}; +static const char *mt7988_udi_groups[] = { + "udi", +}; +static const char *mt7988_audio_groups[] = { + "i2s", "pcm", +}; +static const char *mt7988_led_groups[] = { + "gbe0_led1", "gbe1_led1", "gbe2_led1", "gbe3_led1", "2p5gbe_led1", + "gbe0_led0", "gbe1_led0", "gbe2_led0", "gbe3_led0", "2p5gbe_led0", + "wf5g_led0", "wf5g_led1", +}; +static const char *mt7988_usb_groups[] = { + "drv_vbus", + "drv_vbus_p1", +}; + +static const struct function_desc mt7988_functions[] = { + { "audio", mt7988_audio_groups, ARRAY_SIZE(mt7988_audio_groups) }, + { "jtag", mt7988_jtag_groups, ARRAY_SIZE(mt7988_jtag_groups) }, + { "int_usxgmii", mt7988_int_usxgmii_groups, + ARRAY_SIZE(mt7988_int_usxgmii_groups) }, + { "pwm", mt7988_pwm_groups, ARRAY_SIZE(mt7988_pwm_groups) }, + { "dfd", mt7988_dfd_groups, ARRAY_SIZE(mt7988_dfd_groups) }, + { "i2c", mt7988_i2c_groups, ARRAY_SIZE(mt7988_i2c_groups) }, + { "eth", mt7988_ethernet_groups, ARRAY_SIZE(mt7988_ethernet_groups) }, + { "pcie", mt7988_pcie_groups, ARRAY_SIZE(mt7988_pcie_groups) }, + { "pmic", mt7988_pmic_groups, ARRAY_SIZE(mt7988_pmic_groups) }, + { "watchdog", mt7988_wdt_groups, ARRAY_SIZE(mt7988_wdt_groups) }, + { "spi", mt7988_spi_groups, ARRAY_SIZE(mt7988_spi_groups) }, + { "flash", mt7988_flash_groups, ARRAY_SIZE(mt7988_flash_groups) }, + { "uart", mt7988_uart_groups, ARRAY_SIZE(mt7988_uart_groups) }, + { "udi", mt7988_udi_groups, ARRAY_SIZE(mt7988_udi_groups) }, + { "usb", mt7988_usb_groups, ARRAY_SIZE(mt7988_usb_groups) }, + { "led", mt7988_led_groups, ARRAY_SIZE(mt7988_led_groups) }, +}; + +static const struct mtk_eint_hw mt7988_eint_hw = { + .port_mask = 7, + .ports = 7, + .ap_num = ARRAY_SIZE(mt7988_pins), + .db_cnt = 16, +}; + +static const char *mt7988_pinctrl_register_base_names[] = { + "gpio_base", "iocfg_tr_base", "iocfg_br_base", + "iocfg_rb_base", "iocfg_lb_base", "iocfg_tl_base", +}; + +static struct mtk_pin_soc mt7988_data = { + .reg_cal = mt7988_reg_cals, + .pins = mt7988_pins, + .npins = ARRAY_SIZE(mt7988_pins), + .grps = mt7988_groups, + .ngrps = ARRAY_SIZE(mt7988_groups), + .funcs = mt7988_functions, + .nfuncs = ARRAY_SIZE(mt7988_functions), + .eint_hw = &mt7988_eint_hw, + .gpio_m = 0, + .ies_present = false, + .base_names = mt7988_pinctrl_register_base_names, + .nbase_names = ARRAY_SIZE(mt7988_pinctrl_register_base_names), + .bias_disable_set = mtk_pinconf_bias_disable_set, + .bias_disable_get = mtk_pinconf_bias_disable_get, + .bias_set = mtk_pinconf_bias_set, + .bias_get = mtk_pinconf_bias_get, + .drive_set = mtk_pinconf_drive_set_rev1, + .drive_get = mtk_pinconf_drive_get_rev1, + .adv_pull_get = mtk_pinconf_adv_pull_get, + .adv_pull_set = mtk_pinconf_adv_pull_set, +}; + +static const struct of_device_id mt7988_pinctrl_of_match[] = { + { + .compatible = "mediatek,mt7988-pinctrl", + }, + {} +}; + +static int mt7988_pinctrl_probe(struct platform_device *pdev) +{ + return mtk_moore_pinctrl_probe(pdev, &mt7988_data); +} + +static struct platform_driver mt7988_pinctrl_driver = { + .driver = { + .name = "mt7988-pinctrl", + .of_match_table = mt7988_pinctrl_of_match, + }, + .probe = mt7988_pinctrl_probe, +}; + +static int __init mt7988_pinctrl_init(void) +{ + return platform_driver_register(&mt7988_pinctrl_driver); +} +arch_initcall(mt7988_pinctrl_init); diff --git a/target/linux/mediatek/files-5.15/include/dt-bindings/clock/mediatek,mt7988-clk.h b/target/linux/mediatek/files-5.15/include/dt-bindings/clock/mediatek,mt7988-clk.h new file mode 100644 index 00000000000..77cfea4a8ea --- /dev/null +++ b/target/linux/mediatek/files-5.15/include/dt-bindings/clock/mediatek,mt7988-clk.h @@ -0,0 +1,276 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Sam Shih + * Author: Xiufeng Li + */ + +#ifndef _DT_BINDINGS_CLK_MT7988_H +#define _DT_BINDINGS_CLK_MT7988_H + +/* APMIXEDSYS */ + +#define CLK_APMIXED_NETSYSPLL 0 +#define CLK_APMIXED_MPLL 1 +#define CLK_APMIXED_MMPLL 2 +#define CLK_APMIXED_APLL2 3 +#define CLK_APMIXED_NET1PLL 4 +#define CLK_APMIXED_NET2PLL 5 +#define CLK_APMIXED_WEDMCUPLL 6 +#define CLK_APMIXED_SGMPLL 7 +#define CLK_APMIXED_ARM_B 8 +#define CLK_APMIXED_CCIPLL2_B 9 +#define CLK_APMIXED_USXGMIIPLL 10 +#define CLK_APMIXED_MSDCPLL 11 + +/* TOPCKGEN */ + +#define CLK_TOP_XTAL 0 +#define CLK_TOP_XTAL_D2 1 +#define CLK_TOP_RTC_32K 2 +#define CLK_TOP_RTC_32P7K 3 +#define CLK_TOP_MPLL_D2 4 +#define CLK_TOP_MPLL_D3_D2 5 +#define CLK_TOP_MPLL_D4 6 +#define CLK_TOP_MPLL_D8 7 +#define CLK_TOP_MPLL_D8_D2 8 +#define CLK_TOP_MMPLL_D2 9 +#define CLK_TOP_MMPLL_D3_D5 10 +#define CLK_TOP_MMPLL_D4 11 +#define CLK_TOP_MMPLL_D6_D2 12 +#define CLK_TOP_MMPLL_D8 13 +#define CLK_TOP_APLL2_D4 14 +#define CLK_TOP_NET1PLL_D4 15 +#define CLK_TOP_NET1PLL_D5 16 +#define CLK_TOP_NET1PLL_D5_D2 17 +#define CLK_TOP_NET1PLL_D5_D4 18 +#define CLK_TOP_NET1PLL_D8 19 +#define CLK_TOP_NET1PLL_D8_D2 20 +#define CLK_TOP_NET1PLL_D8_D4 21 +#define CLK_TOP_NET1PLL_D8_D8 22 +#define CLK_TOP_NET1PLL_D8_D16 23 +#define CLK_TOP_NET2PLL_D2 24 +#define CLK_TOP_NET2PLL_D4 25 +#define CLK_TOP_NET2PLL_D4_D4 26 +#define CLK_TOP_NET2PLL_D4_D8 27 +#define CLK_TOP_NET2PLL_D6 28 +#define CLK_TOP_NET2PLL_D8 29 +#define CLK_TOP_NETSYS_SEL 30 +#define CLK_TOP_NETSYS_500M_SEL 31 +#define CLK_TOP_NETSYS_2X_SEL 32 +#define CLK_TOP_NETSYS_GSW_SEL 33 +#define CLK_TOP_ETH_GMII_SEL 34 +#define CLK_TOP_NETSYS_MCU_SEL 35 +#define CLK_TOP_NETSYS_PAO_2X_SEL 36 +#define CLK_TOP_EIP197_SEL 37 +#define CLK_TOP_AXI_INFRA_SEL 38 +#define CLK_TOP_UART_SEL 39 +#define CLK_TOP_EMMC_250M_SEL 40 +#define CLK_TOP_EMMC_400M_SEL 41 +#define CLK_TOP_SPI_SEL 42 +#define CLK_TOP_SPIM_MST_SEL 43 +#define CLK_TOP_NFI1X_SEL 44 +#define CLK_TOP_SPINFI_SEL 45 +#define CLK_TOP_PWM_SEL 46 +#define CLK_TOP_I2C_SEL 47 +#define CLK_TOP_PCIE_MBIST_250M_SEL 48 +#define CLK_TOP_PEXTP_TL_SEL 49 +#define CLK_TOP_PEXTP_TL_P1_SEL 50 +#define CLK_TOP_PEXTP_TL_P2_SEL 51 +#define CLK_TOP_PEXTP_TL_P3_SEL 52 +#define CLK_TOP_USB_SYS_SEL 53 +#define CLK_TOP_USB_SYS_P1_SEL 54 +#define CLK_TOP_USB_XHCI_SEL 55 +#define CLK_TOP_USB_XHCI_P1_SEL 56 +#define CLK_TOP_USB_FRMCNT_SEL 57 +#define CLK_TOP_USB_FRMCNT_P1_SEL 58 +#define CLK_TOP_AUD_SEL 59 +#define CLK_TOP_A1SYS_SEL 60 +#define CLK_TOP_AUD_L_SEL 61 +#define CLK_TOP_A_TUNER_SEL 62 +#define CLK_TOP_SSPXTP_SEL 63 +#define CLK_TOP_USB_PHY_SEL 64 +#define CLK_TOP_USXGMII_SBUS_0_SEL 65 +#define CLK_TOP_USXGMII_SBUS_1_SEL 66 +#define CLK_TOP_SGM_0_SEL 67 +#define CLK_TOP_SGM_SBUS_0_SEL 68 +#define CLK_TOP_SGM_1_SEL 69 +#define CLK_TOP_SGM_SBUS_1_SEL 70 +#define CLK_TOP_XFI_PHY_0_XTAL_SEL 71 +#define CLK_TOP_XFI_PHY_1_XTAL_SEL 72 +#define CLK_TOP_SYSAXI_SEL 73 +#define CLK_TOP_SYSAPB_SEL 74 +#define CLK_TOP_ETH_REFCK_50M_SEL 75 +#define CLK_TOP_ETH_SYS_200M_SEL 76 +#define CLK_TOP_ETH_SYS_SEL 77 +#define CLK_TOP_ETH_XGMII_SEL 78 +#define CLK_TOP_BUS_TOPS_SEL 79 +#define CLK_TOP_NPU_TOPS_SEL 80 +#define CLK_TOP_DRAMC_SEL 81 +#define CLK_TOP_DRAMC_MD32_SEL 82 +#define CLK_TOP_INFRA_F26M_SEL 83 +#define CLK_TOP_PEXTP_P0_SEL 84 +#define CLK_TOP_PEXTP_P1_SEL 85 +#define CLK_TOP_PEXTP_P2_SEL 86 +#define CLK_TOP_PEXTP_P3_SEL 87 +#define CLK_TOP_DA_XTP_GLB_P0_SEL 88 +#define CLK_TOP_DA_XTP_GLB_P1_SEL 89 +#define CLK_TOP_DA_XTP_GLB_P2_SEL 90 +#define CLK_TOP_DA_XTP_GLB_P3_SEL 91 +#define CLK_TOP_CKM_SEL 92 +#define CLK_TOP_DA_SEL 93 +#define CLK_TOP_PEXTP_SEL 94 +#define CLK_TOP_TOPS_P2_26M_SEL 95 +#define CLK_TOP_MCUSYS_BACKUP_625M_SEL 96 +#define CLK_TOP_NETSYS_SYNC_250M_SEL 97 +#define CLK_TOP_MACSEC_SEL 98 +#define CLK_TOP_NETSYS_TOPS_400M_SEL 99 +#define CLK_TOP_NETSYS_PPEFB_250M_SEL 100 +#define CLK_TOP_NETSYS_WARP_SEL 101 +#define CLK_TOP_ETH_MII_SEL 102 +#define CLK_TOP_NPU_SEL 103 +#define CLK_TOP_AUD_I2S_M 104 + +/* MCUSYS */ + +#define CLK_MCU_BUS_DIV_SEL 0 +#define CLK_MCU_ARM_DIV_SEL 1 + +/* INFRACFG_AO */ + +#define CLK_INFRA_MUX_UART0_SEL 0 +#define CLK_INFRA_MUX_UART1_SEL 1 +#define CLK_INFRA_MUX_UART2_SEL 2 +#define CLK_INFRA_MUX_SPI0_SEL 3 +#define CLK_INFRA_MUX_SPI1_SEL 4 +#define CLK_INFRA_MUX_SPI2_SEL 5 +#define CLK_INFRA_PWM_SEL 6 +#define CLK_INFRA_PWM_CK1_SEL 7 +#define CLK_INFRA_PWM_CK2_SEL 8 +#define CLK_INFRA_PWM_CK3_SEL 9 +#define CLK_INFRA_PWM_CK4_SEL 10 +#define CLK_INFRA_PWM_CK5_SEL 11 +#define CLK_INFRA_PWM_CK6_SEL 12 +#define CLK_INFRA_PWM_CK7_SEL 13 +#define CLK_INFRA_PWM_CK8_SEL 14 +#define CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL 15 +#define CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL 16 +#define CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL 17 +#define CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL 18 + +/* INFRACFG */ + +#define CLK_INFRA_PCIE_PERI_26M_CK_P0 19 +#define CLK_INFRA_PCIE_PERI_26M_CK_P1 20 +#define CLK_INFRA_PCIE_PERI_26M_CK_P2 21 +#define CLK_INFRA_PCIE_PERI_26M_CK_P3 22 +#define CLK_INFRA_66M_GPT_BCK 23 +#define CLK_INFRA_66M_PWM_HCK 24 +#define CLK_INFRA_66M_PWM_BCK 25 +#define CLK_INFRA_66M_PWM_CK1 26 +#define CLK_INFRA_66M_PWM_CK2 27 +#define CLK_INFRA_66M_PWM_CK3 28 +#define CLK_INFRA_66M_PWM_CK4 29 +#define CLK_INFRA_66M_PWM_CK5 30 +#define CLK_INFRA_66M_PWM_CK6 31 +#define CLK_INFRA_66M_PWM_CK7 32 +#define CLK_INFRA_66M_PWM_CK8 33 +#define CLK_INFRA_133M_CQDMA_BCK 34 +#define CLK_INFRA_66M_AUD_SLV_BCK 35 +#define CLK_INFRA_AUD_26M 36 +#define CLK_INFRA_AUD_L 37 +#define CLK_INFRA_AUD_AUD 38 +#define CLK_INFRA_AUD_EG2 39 +#define CLK_INFRA_DRAMC_F26M 40 +#define CLK_INFRA_133M_DBG_ACKM 41 +#define CLK_INFRA_66M_AP_DMA_BCK 42 +#define CLK_INFRA_66M_SEJ_BCK 43 +#define CLK_INFRA_PRE_CK_SEJ_F13M 44 +#define CLK_INFRA_26M_THERM_SYSTEM 45 +#define CLK_INFRA_I2C_BCK 46 +#define CLK_INFRA_52M_UART0_CK 47 +#define CLK_INFRA_52M_UART1_CK 48 +#define CLK_INFRA_52M_UART2_CK 49 +#define CLK_INFRA_NFI 50 +#define CLK_INFRA_SPINFI 51 +#define CLK_INFRA_66M_NFI_HCK 52 +#define CLK_INFRA_104M_SPI0 53 +#define CLK_INFRA_104M_SPI1 54 +#define CLK_INFRA_104M_SPI2_BCK 55 +#define CLK_INFRA_66M_SPI0_HCK 56 +#define CLK_INFRA_66M_SPI1_HCK 57 +#define CLK_INFRA_66M_SPI2_HCK 58 +#define CLK_INFRA_66M_FLASHIF_AXI 59 +#define CLK_INFRA_RTC 60 +#define CLK_INFRA_26M_ADC_BCK 61 +#define CLK_INFRA_RC_ADC 62 +#define CLK_INFRA_MSDC400 63 +#define CLK_INFRA_MSDC2_HCK 64 +#define CLK_INFRA_133M_MSDC_0_HCK 65 +#define CLK_INFRA_66M_MSDC_0_HCK 66 +#define CLK_INFRA_133M_CPUM_BCK 67 +#define CLK_INFRA_BIST2FPC 68 +#define CLK_INFRA_I2C_X16W_MCK_CK_P1 69 +#define CLK_INFRA_I2C_X16W_PCK_CK_P1 70 +#define CLK_INFRA_133M_USB_HCK 71 +#define CLK_INFRA_133M_USB_HCK_CK_P1 72 +#define CLK_INFRA_66M_USB_HCK 73 +#define CLK_INFRA_66M_USB_HCK_CK_P1 74 +#define CLK_INFRA_USB_SYS 75 +#define CLK_INFRA_USB_SYS_CK_P1 76 +#define CLK_INFRA_USB_REF 77 +#define CLK_INFRA_USB_CK_P1 78 +#define CLK_INFRA_USB_FRMCNT 79 +#define CLK_INFRA_USB_FRMCNT_CK_P1 80 +#define CLK_INFRA_USB_PIPE 81 +#define CLK_INFRA_USB_PIPE_CK_P1 82 +#define CLK_INFRA_USB_UTMI 83 +#define CLK_INFRA_USB_UTMI_CK_P1 84 +#define CLK_INFRA_USB_XHCI 85 +#define CLK_INFRA_USB_XHCI_CK_P1 86 +#define CLK_INFRA_PCIE_GFMUX_TL_P0 87 +#define CLK_INFRA_PCIE_GFMUX_TL_P1 88 +#define CLK_INFRA_PCIE_GFMUX_TL_P2 89 +#define CLK_INFRA_PCIE_GFMUX_TL_P3 90 +#define CLK_INFRA_PCIE_PIPE_P0 91 +#define CLK_INFRA_PCIE_PIPE_P1 92 +#define CLK_INFRA_PCIE_PIPE_P2 93 +#define CLK_INFRA_PCIE_PIPE_P3 94 +#define CLK_INFRA_133M_PCIE_CK_P0 95 +#define CLK_INFRA_133M_PCIE_CK_P1 96 +#define CLK_INFRA_133M_PCIE_CK_P2 97 +#define CLK_INFRA_133M_PCIE_CK_P3 98 + +/* ETHDMA */ + +#define CLK_ETHDMA_XGP1_EN 0 +#define CLK_ETHDMA_XGP2_EN 1 +#define CLK_ETHDMA_XGP3_EN 2 +#define CLK_ETHDMA_FE_EN 3 +#define CLK_ETHDMA_GP2_EN 4 +#define CLK_ETHDMA_GP1_EN 5 +#define CLK_ETHDMA_GP3_EN 6 +#define CLK_ETHDMA_ESW_EN 7 +#define CLK_ETHDMA_CRYPT0_EN 8 +#define CLK_ETHDMA_NR_CLK 9 + +/* SGMIISYS_0 */ + +#define CLK_SGM0_TX_EN 0 +#define CLK_SGM0_RX_EN 1 +#define CLK_SGMII0_NR_CLK 2 + +/* SGMIISYS_1 */ + +#define CLK_SGM1_TX_EN 0 +#define CLK_SGM1_RX_EN 1 +#define CLK_SGMII1_NR_CLK 2 + +/* ETHWARP */ + +#define CLK_ETHWARP_WOCPU2_EN 0 +#define CLK_ETHWARP_WOCPU1_EN 1 +#define CLK_ETHWARP_WOCPU0_EN 2 +#define CLK_ETHWARP_NR_CLK 3 + +#endif /* _DT_BINDINGS_CLK_MT7988_H */ diff --git a/target/linux/mediatek/filogic/base-files/etc/board.d/02_network b/target/linux/mediatek/filogic/base-files/etc/board.d/02_network index 63f898a9cd2..2fca00921b8 100644 --- a/target/linux/mediatek/filogic/base-files/etc/board.d/02_network +++ b/target/linux/mediatek/filogic/base-files/etc/board.d/02_network @@ -26,6 +26,9 @@ mediatek_setup_interfaces() mediatek,mt7986b-rfb) ucidef_set_interfaces_lan_wan "lan0 lan1 lan2 lan3" eth1 ;; + mediatek,mt7988a-dsa-10g-spim-snand) + ucidef_set_interfaces_lan_wan "lan0 lan1 lan2 lan3" "eth1 eth2" + ;; tplink,tl-xdr4288|\ tplink,tl-xdr6088) ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4 lan5" eth1 diff --git a/target/linux/mediatek/filogic/config-5.15 b/target/linux/mediatek/filogic/config-5.15 index 96ff95be13d..4cae8c50ac7 100644 --- a/target/linux/mediatek/filogic/config-5.15 +++ b/target/linux/mediatek/filogic/config-5.15 @@ -16,11 +16,9 @@ CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_ARCH_WANTS_NO_INSTR=y CONFIG_ARM64=y CONFIG_ARM64_4K_PAGES=y -# CONFIG_ARM64_CNP is not set CONFIG_ARM64_CRYPTO=y CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y -CONFIG_ARM64_MODULE_PLTS=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PA_BITS=48 CONFIG_ARM64_PA_BITS_48=y @@ -61,6 +59,7 @@ CONFIG_COMMON_CLK_MT7981=y CONFIG_COMMON_CLK_MT7981_ETHSYS=y CONFIG_COMMON_CLK_MT7986=y CONFIG_COMMON_CLK_MT7986_ETHSYS=y +CONFIG_COMMON_CLK_MT7988=y # CONFIG_COMMON_CLK_MT8173 is not set # CONFIG_COMMON_CLK_MT8183 is not set # CONFIG_COMMON_CLK_MT8516 is not set @@ -204,8 +203,9 @@ CONFIG_MAXLINEAR_GPHY=y CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVRES=y +CONFIG_MEDIATEK_2P5G_PHY=y CONFIG_MEDIATEK_GE_PHY=y -CONFIG_MEDIATEK_GE_PHY_SOC=y +CONFIG_MEDIATEK_GE_SOC_PHY=y CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEMFD_CREATE=y CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7 @@ -250,9 +250,12 @@ CONFIG_NEED_SG_DMA_LENGTH=y CONFIG_NET_DEVLINK=y CONFIG_NET_DSA=y CONFIG_NET_DSA_MT7530=y +CONFIG_NET_DSA_MT7530_MDIO=y +CONFIG_NET_DSA_MT7530_MMIO=y CONFIG_NET_DSA_TAG_MTK=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NET_MEDIATEK_SOC=y +CONFIG_NET_MEDIATEK_SOC_USXGMII=y CONFIG_NET_MEDIATEK_SOC_WED=y CONFIG_NET_SELFTESTS=y CONFIG_NET_SWITCHDEV=y @@ -311,6 +314,7 @@ CONFIG_PINCTRL=y # CONFIG_PINCTRL_MT7622 is not set CONFIG_PINCTRL_MT7981=y CONFIG_PINCTRL_MT7986=y +CONFIG_PINCTRL_MT7988=y # CONFIG_PINCTRL_MT8173 is not set # CONFIG_PINCTRL_MT8183 is not set CONFIG_PINCTRL_MT8516=y @@ -349,11 +353,14 @@ CONFIG_REED_SOLOMON=y CONFIG_REED_SOLOMON_DEC8=y CONFIG_REED_SOLOMON_ENC8=y CONFIG_REGMAP=y +CONFIG_REGMAP_I2C=y CONFIG_REGMAP_MMIO=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_MT6380=y +CONFIG_REGULATOR_RT5190A=y CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_TI_SYSCON=y CONFIG_RFS_ACCEL=y CONFIG_RODATA_FULL_DEFAULT_ENABLED=y CONFIG_RPS=y diff --git a/target/linux/mediatek/image/filogic.mk b/target/linux/mediatek/image/filogic.mk index 92d1dcfad24..72adb490666 100644 --- a/target/linux/mediatek/image/filogic.mk +++ b/target/linux/mediatek/image/filogic.mk @@ -206,6 +206,24 @@ define Device/mediatek_mt7986b-rfb endef TARGET_DEVICES += mediatek_mt7986b-rfb +define Device/mediatek_mt7988a-rfb-nand + DEVICE_VENDOR := MediaTek + DEVICE_MODEL := MT7988a nand rfb + DEVICE_DTS := mt7988a-dsa-10g-spim-nand + DEVICE_DTS_DIR := $(DTS_DIR)/ + KERNEL_LOADADDR := 0x48000000 + SUPPORTED_DEVICES := mediatek,mt7988a-rfb + UBINIZE_OPTS := -E 5 + BLOCKSIZE := 128k + PAGESIZE := 2048 + IMAGE_SIZE := 65536k + KERNEL_IN_UBI := 1 + IMAGES += factory.bin + IMAGE/factory.bin := append-ubi | check-size $$$$(IMAGE_SIZE) + IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata +endef +TARGET_DEVICES += mediatek_mt7988a-rfb-nand + define Device/tplink_tl-xdr-common DEVICE_VENDOR := TP-Link DEVICE_DTS_DIR := ../dts diff --git a/target/linux/mediatek/image/mt7623.mk b/target/linux/mediatek/image/mt7623.mk index 26befc1c1e5..1645ecd5450 100644 --- a/target/linux/mediatek/image/mt7623.mk +++ b/target/linux/mediatek/image/mt7623.mk @@ -104,8 +104,12 @@ define Device/bananapi_bpi-r2 pad-to 2k | append-preloader $$(UBOOT_TARGET) |\ pad-to $$(UBOOT_OFFSET) | append-bootloader $$(UBOOT_TARGET) |\ pad-to 4092k | mt7623-mbr emmc |\ + $(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),\ pad-to 4M | append-image-stage initramfs-recovery.itb |\ + ) \ + $(if $(CONFIG_TARGET_ROOTFS_SQUASHFS),\ pad-to 48M | append-image squashfs-sysupgrade.itb |\ + ) \ gzip ARTIFACTS := u-boot.bin preloader.bin sdcard.img.gz SUPPORTED_DEVICES := bananapi,bpi-r2 @@ -135,8 +139,12 @@ define Device/unielec_u7623-02 # but OpenWrt expects 'SDMM' magic for sysupgrade. ARTIFACT/emmc.img.gz := mt7623-mbr sdmmc |\ pad-to $$(UBOOT_OFFSET) | append-bootloader $$(UBOOT_TARGET) |\ + $(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),\ pad-to 4M | append-image-stage initramfs-recovery.itb |\ + ) \ + $(if $(CONFIG_TARGET_ROOTFS_SQUASHFS),\ pad-to 48M | append-image squashfs-sysupgrade.itb |\ + ) \ gzip | append-metadata ARTIFACT/scatter.txt := scatterfile emmc.img.gz ARTIFACTS := u-boot.bin scatter.txt emmc.img.gz diff --git a/target/linux/mediatek/mt7622/config-5.15 b/target/linux/mediatek/mt7622/config-5.15 index 1ce6d852ba1..30a5ff948fa 100644 --- a/target/linux/mediatek/mt7622/config-5.15 +++ b/target/linux/mediatek/mt7622/config-5.15 @@ -22,7 +22,6 @@ CONFIG_ARM64_CRYPTO=y CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_ERRATUM_845719=y CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y -CONFIG_ARM64_MODULE_PLTS=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PA_BITS=48 CONFIG_ARM64_PA_BITS_48=y @@ -72,6 +71,7 @@ CONFIG_COMMON_CLK_MT7622_ETHSYS=y CONFIG_COMMON_CLK_MT7622_HIFSYS=y # CONFIG_COMMON_CLK_MT7981 is not set # CONFIG_COMMON_CLK_MT7986 is not set +# CONFIG_COMMON_CLK_MT7988 is not set # CONFIG_COMMON_CLK_MT8173 is not set # CONFIG_COMMON_CLK_MT8183 is not set # CONFIG_COMMON_CLK_MT8183_AUDIOSYS is not set @@ -225,8 +225,9 @@ CONFIG_MAGIC_SYSRQ=y CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y CONFIG_MDIO_DEVRES=y +# CONFIG_MEDIATEK_2P5G_PHY is not set CONFIG_MEDIATEK_GE_PHY=y -# CONFIG_MEDIATEK_GE_PHY_SOC is not set +# CONFIG_MEDIATEK_GE_SOC_PHY is not set CONFIG_MEDIATEK_WATCHDOG=y CONFIG_MEMFD_CREATE=y CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7 @@ -272,9 +273,12 @@ CONFIG_NEED_SG_DMA_LENGTH=y CONFIG_NET_DEVLINK=y CONFIG_NET_DSA=y CONFIG_NET_DSA_MT7530=y +CONFIG_NET_DSA_MT7530_MDIO=y +# CONFIG_NET_DSA_MT7530_MMIO is not set CONFIG_NET_DSA_TAG_MTK=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NET_MEDIATEK_SOC=y +# CONFIG_NET_MEDIATEK_SOC_USXGMII is not set CONFIG_NET_MEDIATEK_SOC_WED=y CONFIG_NET_SELFTESTS=y CONFIG_NET_SWITCHDEV=y @@ -330,6 +334,7 @@ CONFIG_PINCTRL=y CONFIG_PINCTRL_MT7622=y # CONFIG_PINCTRL_MT7981 is not set # CONFIG_PINCTRL_MT7986 is not set +# CONFIG_PINCTRL_MT7988 is not set # CONFIG_PINCTRL_MT8173 is not set # CONFIG_PINCTRL_MT8183 is not set CONFIG_PINCTRL_MT8516=y @@ -372,6 +377,7 @@ CONFIG_REGMAP_MMIO=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_MT6380=y +# CONFIG_REGULATOR_RT5190A is not set CONFIG_RESET_CONTROLLER=y CONFIG_RFS_ACCEL=y CONFIG_RODATA_FULL_DEFAULT_ENABLED=y diff --git a/target/linux/mediatek/mt7623/config-5.15 b/target/linux/mediatek/mt7623/config-5.15 index fb9588ee4f7..039a904f197 100644 --- a/target/linux/mediatek/mt7623/config-5.15 +++ b/target/linux/mediatek/mt7623/config-5.15 @@ -71,6 +71,7 @@ CONFIG_COMMON_CLK_MT2701_VDECSYS=y # CONFIG_COMMON_CLK_MT7629 is not set # CONFIG_COMMON_CLK_MT7981 is not set # CONFIG_COMMON_CLK_MT7986 is not set +# CONFIG_COMMON_CLK_MT7988 is not set # CONFIG_COMMON_CLK_MT8135 is not set # CONFIG_COMMON_CLK_MT8173 is not set CONFIG_COMMON_CLK_MT8516=y @@ -371,6 +372,8 @@ CONFIG_NEON=y CONFIG_NET_DEVLINK=y CONFIG_NET_DSA=y CONFIG_NET_DSA_MT7530=y +CONFIG_NET_DSA_MT7530_MDIO=y +# CONFIG_NET_DSA_MT7530_MMIO is not set CONFIG_NET_DSA_TAG_MTK=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NET_MEDIATEK_SOC=y @@ -469,6 +472,7 @@ CONFIG_REGULATOR_MT6323=y # CONFIG_REGULATOR_MT6358 is not set # CONFIG_REGULATOR_MT6380 is not set # CONFIG_REGULATOR_MT6397 is not set +# CONFIG_REGULATOR_RT5190A is not set # CONFIG_REGULATOR_QCOM_LABIBB is not set # CONFIG_REGULATOR_QCOM_SPMI is not set # CONFIG_REGULATOR_QCOM_USB_VBUS is not set diff --git a/target/linux/mediatek/mt7629/config-5.15 b/target/linux/mediatek/mt7629/config-5.15 index 709be00c744..08089dde2a3 100644 --- a/target/linux/mediatek/mt7629/config-5.15 +++ b/target/linux/mediatek/mt7629/config-5.15 @@ -53,6 +53,7 @@ CONFIG_COMMON_CLK_MT7629_ETHSYS=y CONFIG_COMMON_CLK_MT7629_HIFSYS=y # CONFIG_COMMON_CLK_MT7981 is not set # CONFIG_COMMON_CLK_MT7986 is not set +# CONFIG_COMMON_CLK_MT7988 is not set # CONFIG_COMMON_CLK_MT8135 is not set # CONFIG_COMMON_CLK_MT8173 is not set CONFIG_COMMON_CLK_MT8516=y @@ -196,6 +197,8 @@ CONFIG_NETFILTER=y CONFIG_NET_DEVLINK=y CONFIG_NET_DSA=y CONFIG_NET_DSA_MT7530=y +CONFIG_NET_DSA_MT7530_MDIO=y +# CONFIG_NET_DSA_MT7530_MMIO is not set CONFIG_NET_DSA_TAG_MTK=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NET_MEDIATEK_SOC=y diff --git a/target/linux/mediatek/patches-5.15/240-pinctrl-mediatek-add-support-for-MT7988-SoC.patch b/target/linux/mediatek/patches-5.15/240-pinctrl-mediatek-add-support-for-MT7988-SoC.patch new file mode 100644 index 00000000000..cbee45bc1f8 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/240-pinctrl-mediatek-add-support-for-MT7988-SoC.patch @@ -0,0 +1,26 @@ +--- a/drivers/pinctrl/mediatek/Kconfig ++++ b/drivers/pinctrl/mediatek/Kconfig +@@ -134,6 +134,13 @@ config PINCTRL_MT7986 + default ARM64 && ARCH_MEDIATEK + select PINCTRL_MTK_MOORE + ++config PINCTRL_MT7988 ++ bool "Mediatek MT7988 pin control" ++ depends on OF ++ depends on ARM64 || COMPILE_TEST ++ default ARCH_MEDIATEK ++ select PINCTRL_MTK_MOORE ++ + config PINCTRL_MT8167 + bool "Mediatek MT8167 pin control" + depends on OF +--- a/drivers/pinctrl/mediatek/Makefile ++++ b/drivers/pinctrl/mediatek/Makefile +@@ -19,6 +19,7 @@ obj-$(CONFIG_PINCTRL_MT7623) += pinctrl- + obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o + obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7981.o + obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o ++obj-$(CONFIG_PINCTRL_MT7988) += pinctrl-mt7988.o + obj-$(CONFIG_PINCTRL_MT8167) += pinctrl-mt8167.o + obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o + obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o diff --git a/target/linux/mediatek/patches-5.15/241-clk-mediatek-Add-pcw-chg-shift-control.patch b/target/linux/mediatek/patches-5.15/241-clk-mediatek-Add-pcw-chg-shift-control.patch new file mode 100644 index 00000000000..23a5b7c911a --- /dev/null +++ b/target/linux/mediatek/patches-5.15/241-clk-mediatek-Add-pcw-chg-shift-control.patch @@ -0,0 +1,24 @@ +--- a/drivers/clk/mediatek/clk-mtk.h ++++ b/drivers/clk/mediatek/clk-mtk.h +@@ -233,6 +233,7 @@ struct mtk_pll_data { + u32 pcw_reg; + int pcw_shift; + u32 pcw_chg_reg; ++ int pcw_chg_shift; + const struct mtk_pll_div_table *div_table; + const char *parent_name; + u32 en_reg; +--- a/drivers/clk/mediatek/clk-pll.c ++++ b/drivers/clk/mediatek/clk-pll.c +@@ -137,7 +137,10 @@ static void mtk_pll_set_rate_regs(struct + pll->data->pcw_shift); + val |= pcw << pll->data->pcw_shift; + writel(val, pll->pcw_addr); +- chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK; ++ if (pll->data->pcw_chg_shift) ++ chg = readl(pll->pcw_chg_addr) | BIT(pll->data->pcw_chg_shift); ++ else ++ chg = readl(pll->pcw_chg_addr) | PCW_CHG_MASK; + writel(chg, pll->pcw_chg_addr); + if (pll->tuner_addr) + writel(val + 1, pll->tuner_addr); diff --git a/target/linux/mediatek/patches-5.15/242-clk-mediatek-add-mt7988-clock-support.patch b/target/linux/mediatek/patches-5.15/242-clk-mediatek-add-mt7988-clock-support.patch new file mode 100644 index 00000000000..bf9146352a6 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/242-clk-mediatek-add-mt7988-clock-support.patch @@ -0,0 +1,31 @@ +--- a/drivers/clk/mediatek/Kconfig ++++ b/drivers/clk/mediatek/Kconfig +@@ -378,6 +378,15 @@ config COMMON_CLK_MT7986_ETHSYS + This driver add support for clocks for Ethernet and SGMII + required on MediaTek MT7986 SoC. + ++config COMMON_CLK_MT7988 ++ bool "Clock driver for MediaTek MT7988" ++ depends on ARCH_MEDIATEK || COMPILE_TEST ++ select COMMON_CLK_MEDIATEK ++ default ARCH_MEDIATEK ++ help ++ This driver supports MediaTek MT7988 basic clocks and clocks ++ required for various periperals found on MediaTek. ++ + config COMMON_CLK_MT8135 + bool "Clock driver for MediaTek MT8135" + depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST +--- a/drivers/clk/mediatek/Makefile ++++ b/drivers/clk/mediatek/Makefile +@@ -54,6 +54,10 @@ obj-$(CONFIG_COMMON_CLK_MT7986) += clk-m + obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-topckgen.o + obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986-infracfg.o + obj-$(CONFIG_COMMON_CLK_MT7986_ETHSYS) += clk-mt7986-eth.o ++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-apmixed.o ++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-topckgen.o ++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-infracfg.o ++obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988-eth.o + obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o + obj-$(CONFIG_COMMON_CLK_MT8167) += clk-mt8167.o + obj-$(CONFIG_COMMON_CLK_MT8167_AUDSYS) += clk-mt8167-aud.o diff --git a/target/linux/mediatek/patches-5.15/350-01-cpufreq-mediatek-Cleanup-variables-and-error-handlin.patch b/target/linux/mediatek/patches-5.15/350-01-cpufreq-mediatek-Cleanup-variables-and-error-handlin.patch new file mode 100644 index 00000000000..8fad64a5702 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-01-cpufreq-mediatek-Cleanup-variables-and-error-handlin.patch @@ -0,0 +1,166 @@ +From 7a768326fdba542144833b9198a6d0edab52fad2 Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Fri, 8 Apr 2022 12:58:56 +0800 +Subject: [PATCH 01/21] cpufreq: mediatek: Cleanup variables and error handling + in mtk_cpu_dvfs_info_init() + +- Remove several unnecessary varaibles in mtk_cpu_dvfs_info_init(). +- Unify error message format and use dev_err_probe() if possible. + +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 89 ++++++++++++------------------ + 1 file changed, 34 insertions(+), 55 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -302,96 +302,75 @@ static int mtk_cpufreq_set_target(struct + static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) + { + struct device *cpu_dev; +- struct regulator *proc_reg = ERR_PTR(-ENODEV); +- struct regulator *sram_reg = ERR_PTR(-ENODEV); +- struct clk *cpu_clk = ERR_PTR(-ENODEV); +- struct clk *inter_clk = ERR_PTR(-ENODEV); + struct dev_pm_opp *opp; + unsigned long rate; + int ret; + + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { +- pr_err("failed to get cpu%d device\n", cpu); ++ dev_err(cpu_dev, "failed to get cpu%d device\n", cpu); + return -ENODEV; + } ++ info->cpu_dev = cpu_dev; + +- cpu_clk = clk_get(cpu_dev, "cpu"); +- if (IS_ERR(cpu_clk)) { +- if (PTR_ERR(cpu_clk) == -EPROBE_DEFER) +- pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu); +- else +- pr_err("failed to get cpu clk for cpu%d\n", cpu); +- +- ret = PTR_ERR(cpu_clk); +- return ret; +- } +- +- inter_clk = clk_get(cpu_dev, "intermediate"); +- if (IS_ERR(inter_clk)) { +- if (PTR_ERR(inter_clk) == -EPROBE_DEFER) +- pr_warn("intermediate clk for cpu%d not ready, retry.\n", +- cpu); +- else +- pr_err("failed to get intermediate clk for cpu%d\n", +- cpu); ++ info->cpu_clk = clk_get(cpu_dev, "cpu"); ++ if (IS_ERR(info->cpu_clk)) { ++ ret = PTR_ERR(info->cpu_clk); ++ return dev_err_probe(cpu_dev, ret, ++ "cpu%d: failed to get cpu clk\n", cpu); ++ } + +- ret = PTR_ERR(inter_clk); ++ info->inter_clk = clk_get(cpu_dev, "intermediate"); ++ if (IS_ERR(info->inter_clk)) { ++ ret = PTR_ERR(info->inter_clk); ++ dev_err_probe(cpu_dev, ret, ++ "cpu%d: failed to get intermediate clk\n", cpu); + goto out_free_resources; + } + +- proc_reg = regulator_get_optional(cpu_dev, "proc"); +- if (IS_ERR(proc_reg)) { +- if (PTR_ERR(proc_reg) == -EPROBE_DEFER) +- pr_warn("proc regulator for cpu%d not ready, retry.\n", +- cpu); +- else +- pr_err("failed to get proc regulator for cpu%d\n", +- cpu); +- +- ret = PTR_ERR(proc_reg); ++ info->proc_reg = regulator_get_optional(cpu_dev, "proc"); ++ if (IS_ERR(info->proc_reg)) { ++ ret = PTR_ERR(info->proc_reg); ++ dev_err_probe(cpu_dev, ret, ++ "cpu%d: failed to get proc regulator\n", cpu); + goto out_free_resources; + } + + /* Both presence and absence of sram regulator are valid cases. */ +- sram_reg = regulator_get_exclusive(cpu_dev, "sram"); ++ info->sram_reg = regulator_get_exclusive(cpu_dev, "sram"); ++ if (IS_ERR(info->sram_reg)) ++ info->sram_reg = NULL; + + /* Get OPP-sharing information from "operating-points-v2" bindings */ + ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, &info->cpus); + if (ret) { +- pr_err("failed to get OPP-sharing information for cpu%d\n", +- cpu); ++ dev_err(cpu_dev, ++ "cpu%d: failed to get OPP-sharing information\n", cpu); + goto out_free_resources; + } + + ret = dev_pm_opp_of_cpumask_add_table(&info->cpus); + if (ret) { +- pr_warn("no OPP table for cpu%d\n", cpu); ++ dev_warn(cpu_dev, "cpu%d: no OPP table\n", cpu); + goto out_free_resources; + } + + /* Search a safe voltage for intermediate frequency. */ +- rate = clk_get_rate(inter_clk); ++ rate = clk_get_rate(info->inter_clk); + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); + if (IS_ERR(opp)) { +- pr_err("failed to get intermediate opp for cpu%d\n", cpu); ++ dev_err(cpu_dev, "cpu%d: failed to get intermediate opp\n", cpu); + ret = PTR_ERR(opp); + goto out_free_opp_table; + } + info->intermediate_voltage = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); + +- info->cpu_dev = cpu_dev; +- info->proc_reg = proc_reg; +- info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg; +- info->cpu_clk = cpu_clk; +- info->inter_clk = inter_clk; +- + /* + * If SRAM regulator is present, software "voltage tracking" is needed + * for this CPU power domain. + */ +- info->need_voltage_tracking = !IS_ERR(sram_reg); ++ info->need_voltage_tracking = (info->sram_reg != NULL); + + return 0; + +@@ -399,14 +378,14 @@ out_free_opp_table: + dev_pm_opp_of_cpumask_remove_table(&info->cpus); + + out_free_resources: +- if (!IS_ERR(proc_reg)) +- regulator_put(proc_reg); +- if (!IS_ERR(sram_reg)) +- regulator_put(sram_reg); +- if (!IS_ERR(cpu_clk)) +- clk_put(cpu_clk); +- if (!IS_ERR(inter_clk)) +- clk_put(inter_clk); ++ if (!IS_ERR(info->proc_reg)) ++ regulator_put(info->proc_reg); ++ if (!IS_ERR(info->sram_reg)) ++ regulator_put(info->sram_reg); ++ if (!IS_ERR(info->cpu_clk)) ++ clk_put(info->cpu_clk); ++ if (!IS_ERR(info->inter_clk)) ++ clk_put(info->inter_clk); + + return ret; + } diff --git a/target/linux/mediatek/patches-5.15/350-02-cpufreq-mediatek-Remove-unused-headers.patch b/target/linux/mediatek/patches-5.15/350-02-cpufreq-mediatek-Remove-unused-headers.patch new file mode 100644 index 00000000000..eebeeb09028 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-02-cpufreq-mediatek-Remove-unused-headers.patch @@ -0,0 +1,25 @@ +From 756104b856d4bc3121420af3ced342f5fc2b2123 Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Fri, 8 Apr 2022 12:58:57 +0800 +Subject: [PATCH 02/21] cpufreq: mediatek: Remove unused headers + +Remove unused headers. + +Signed-off-by: Jia-Wei Chang +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -13,8 +13,6 @@ + #include + #include + #include +-#include +-#include + + #define MIN_VOLT_SHIFT (100000) + #define MAX_VOLT_SHIFT (200000) diff --git a/target/linux/mediatek/patches-5.15/350-03-cpufreq-mediatek-Enable-clocks-and-regulators.patch b/target/linux/mediatek/patches-5.15/350-03-cpufreq-mediatek-Enable-clocks-and-regulators.patch new file mode 100644 index 00000000000..c97d5fc3d91 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-03-cpufreq-mediatek-Enable-clocks-and-regulators.patch @@ -0,0 +1,117 @@ +From 342d5545e9f40496db9ae0d31c2427dd5f369a43 Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Fri, 8 Apr 2022 12:58:58 +0800 +Subject: [PATCH 03/21] cpufreq: mediatek: Enable clocks and regulators + +We need to enable regulators so that the max and min requested values will +be recorded. +The intermediate clock is not always enabled by CCF in different projects, +so we should enable it in the cpufreq driver. + +Signed-off-by: Andrew-sh.Cheng +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 50 +++++++++++++++++++++++++++--- + 1 file changed, 45 insertions(+), 5 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -334,10 +334,23 @@ static int mtk_cpu_dvfs_info_init(struct + goto out_free_resources; + } + ++ ret = regulator_enable(info->proc_reg); ++ if (ret) { ++ dev_warn(cpu_dev, "cpu%d: failed to enable vproc\n", cpu); ++ goto out_free_resources; ++ } ++ + /* Both presence and absence of sram regulator are valid cases. */ + info->sram_reg = regulator_get_exclusive(cpu_dev, "sram"); + if (IS_ERR(info->sram_reg)) + info->sram_reg = NULL; ++ else { ++ ret = regulator_enable(info->sram_reg); ++ if (ret) { ++ dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu); ++ goto out_free_resources; ++ } ++ } + + /* Get OPP-sharing information from "operating-points-v2" bindings */ + ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, &info->cpus); +@@ -353,13 +366,21 @@ static int mtk_cpu_dvfs_info_init(struct + goto out_free_resources; + } + ++ ret = clk_prepare_enable(info->cpu_clk); ++ if (ret) ++ goto out_free_opp_table; ++ ++ ret = clk_prepare_enable(info->inter_clk); ++ if (ret) ++ goto out_disable_mux_clock; ++ + /* Search a safe voltage for intermediate frequency. */ + rate = clk_get_rate(info->inter_clk); + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); + if (IS_ERR(opp)) { + dev_err(cpu_dev, "cpu%d: failed to get intermediate opp\n", cpu); + ret = PTR_ERR(opp); +- goto out_free_opp_table; ++ goto out_disable_inter_clock; + } + info->intermediate_voltage = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); +@@ -372,10 +393,21 @@ static int mtk_cpu_dvfs_info_init(struct + + return 0; + ++out_disable_inter_clock: ++ clk_disable_unprepare(info->inter_clk); ++ ++out_disable_mux_clock: ++ clk_disable_unprepare(info->cpu_clk); ++ + out_free_opp_table: + dev_pm_opp_of_cpumask_remove_table(&info->cpus); + + out_free_resources: ++ if (regulator_is_enabled(info->proc_reg)) ++ regulator_disable(info->proc_reg); ++ if (info->sram_reg && regulator_is_enabled(info->sram_reg)) ++ regulator_disable(info->sram_reg); ++ + if (!IS_ERR(info->proc_reg)) + regulator_put(info->proc_reg); + if (!IS_ERR(info->sram_reg)) +@@ -390,14 +422,22 @@ out_free_resources: + + static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) + { +- if (!IS_ERR(info->proc_reg)) ++ if (!IS_ERR(info->proc_reg)) { ++ regulator_disable(info->proc_reg); + regulator_put(info->proc_reg); +- if (!IS_ERR(info->sram_reg)) ++ } ++ if (!IS_ERR(info->sram_reg)) { ++ regulator_disable(info->sram_reg); + regulator_put(info->sram_reg); +- if (!IS_ERR(info->cpu_clk)) ++ } ++ if (!IS_ERR(info->cpu_clk)) { ++ clk_disable_unprepare(info->cpu_clk); + clk_put(info->cpu_clk); +- if (!IS_ERR(info->inter_clk)) ++ } ++ if (!IS_ERR(info->inter_clk)) { ++ clk_disable_unprepare(info->inter_clk); + clk_put(info->inter_clk); ++ } + + dev_pm_opp_of_cpumask_remove_table(&info->cpus); + } diff --git a/target/linux/mediatek/patches-5.15/350-04-cpufreq-mediatek-Use-device-print-to-show-logs.patch b/target/linux/mediatek/patches-5.15/350-04-cpufreq-mediatek-Use-device-print-to-show-logs.patch new file mode 100644 index 00000000000..18e1da728a8 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-04-cpufreq-mediatek-Use-device-print-to-show-logs.patch @@ -0,0 +1,161 @@ +From a02e2b359141035d2d6999940bc1b9f83ec88587 Mon Sep 17 00:00:00 2001 +From: Rex-BC Chen +Date: Fri, 22 Apr 2022 15:52:27 +0800 +Subject: [PATCH 04/21] cpufreq: mediatek: Use device print to show logs + +- Replace pr_* with dev_* to show logs. +- Remove usage of __func__. + +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 54 ++++++++++++++++-------------- + 1 file changed, 28 insertions(+), 26 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -67,7 +67,8 @@ static int mtk_cpufreq_voltage_tracking( + + old_vproc = regulator_get_voltage(proc_reg); + if (old_vproc < 0) { +- pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc); ++ dev_err(info->cpu_dev, ++ "invalid Vproc value: %d\n", old_vproc); + return old_vproc; + } + /* Vsram should not exceed the maximum allowed voltage of SoC. */ +@@ -83,14 +84,14 @@ static int mtk_cpufreq_voltage_tracking( + do { + old_vsram = regulator_get_voltage(sram_reg); + if (old_vsram < 0) { +- pr_err("%s: invalid Vsram value: %d\n", +- __func__, old_vsram); ++ dev_err(info->cpu_dev, ++ "invalid Vsram value: %d\n", old_vsram); + return old_vsram; + } + old_vproc = regulator_get_voltage(proc_reg); + if (old_vproc < 0) { +- pr_err("%s: invalid Vproc value: %d\n", +- __func__, old_vproc); ++ dev_err(info->cpu_dev, ++ "invalid Vproc value: %d\n", old_vproc); + return old_vproc; + } + +@@ -138,14 +139,14 @@ static int mtk_cpufreq_voltage_tracking( + do { + old_vproc = regulator_get_voltage(proc_reg); + if (old_vproc < 0) { +- pr_err("%s: invalid Vproc value: %d\n", +- __func__, old_vproc); ++ dev_err(info->cpu_dev, ++ "invalid Vproc value: %d\n", old_vproc); + return old_vproc; + } + old_vsram = regulator_get_voltage(sram_reg); + if (old_vsram < 0) { +- pr_err("%s: invalid Vsram value: %d\n", +- __func__, old_vsram); ++ dev_err(info->cpu_dev, ++ "invalid Vsram value: %d\n", old_vsram); + return old_vsram; + } + +@@ -216,7 +217,7 @@ static int mtk_cpufreq_set_target(struct + old_freq_hz = clk_get_rate(cpu_clk); + old_vproc = regulator_get_voltage(info->proc_reg); + if (old_vproc < 0) { +- pr_err("%s: invalid Vproc value: %d\n", __func__, old_vproc); ++ dev_err(cpu_dev, "invalid Vproc value: %d\n", old_vproc); + return old_vproc; + } + +@@ -224,8 +225,8 @@ static int mtk_cpufreq_set_target(struct + + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); + if (IS_ERR(opp)) { +- pr_err("cpu%d: failed to find OPP for %ld\n", +- policy->cpu, freq_hz); ++ dev_err(cpu_dev, "cpu%d: failed to find OPP for %ld\n", ++ policy->cpu, freq_hz); + return PTR_ERR(opp); + } + vproc = dev_pm_opp_get_voltage(opp); +@@ -239,8 +240,8 @@ static int mtk_cpufreq_set_target(struct + if (old_vproc < target_vproc) { + ret = mtk_cpufreq_set_voltage(info, target_vproc); + if (ret) { +- pr_err("cpu%d: failed to scale up voltage!\n", +- policy->cpu); ++ dev_err(cpu_dev, ++ "cpu%d: failed to scale up voltage!\n", policy->cpu); + mtk_cpufreq_set_voltage(info, old_vproc); + return ret; + } +@@ -249,8 +250,8 @@ static int mtk_cpufreq_set_target(struct + /* Reparent the CPU clock to intermediate clock. */ + ret = clk_set_parent(cpu_clk, info->inter_clk); + if (ret) { +- pr_err("cpu%d: failed to re-parent cpu clock!\n", +- policy->cpu); ++ dev_err(cpu_dev, ++ "cpu%d: failed to re-parent cpu clock!\n", policy->cpu); + mtk_cpufreq_set_voltage(info, old_vproc); + WARN_ON(1); + return ret; +@@ -259,8 +260,8 @@ static int mtk_cpufreq_set_target(struct + /* Set the original PLL to target rate. */ + ret = clk_set_rate(armpll, freq_hz); + if (ret) { +- pr_err("cpu%d: failed to scale cpu clock rate!\n", +- policy->cpu); ++ dev_err(cpu_dev, ++ "cpu%d: failed to scale cpu clock rate!\n", policy->cpu); + clk_set_parent(cpu_clk, armpll); + mtk_cpufreq_set_voltage(info, old_vproc); + return ret; +@@ -269,8 +270,8 @@ static int mtk_cpufreq_set_target(struct + /* Set parent of CPU clock back to the original PLL. */ + ret = clk_set_parent(cpu_clk, armpll); + if (ret) { +- pr_err("cpu%d: failed to re-parent cpu clock!\n", +- policy->cpu); ++ dev_err(cpu_dev, ++ "cpu%d: failed to re-parent cpu clock!\n", policy->cpu); + mtk_cpufreq_set_voltage(info, inter_vproc); + WARN_ON(1); + return ret; +@@ -283,8 +284,8 @@ static int mtk_cpufreq_set_target(struct + if (vproc < inter_vproc || vproc < old_vproc) { + ret = mtk_cpufreq_set_voltage(info, vproc); + if (ret) { +- pr_err("cpu%d: failed to scale down voltage!\n", +- policy->cpu); ++ dev_err(cpu_dev, ++ "cpu%d: failed to scale down voltage!\n", policy->cpu); + clk_set_parent(cpu_clk, info->inter_clk); + clk_set_rate(armpll, old_freq_hz); + clk_set_parent(cpu_clk, armpll); +@@ -450,15 +451,16 @@ static int mtk_cpufreq_init(struct cpufr + + info = mtk_cpu_dvfs_info_lookup(policy->cpu); + if (!info) { +- pr_err("dvfs info for cpu%d is not initialized.\n", +- policy->cpu); ++ dev_err(info->cpu_dev, ++ "dvfs info for cpu%d is not initialized.\n", policy->cpu); + return -EINVAL; + } + + ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table); + if (ret) { +- pr_err("failed to init cpufreq table for cpu%d: %d\n", +- policy->cpu, ret); ++ dev_err(info->cpu_dev, ++ "failed to init cpufreq table for cpu%d: %d\n", ++ policy->cpu, ret); + return ret; + } + diff --git a/target/linux/mediatek/patches-5.15/350-05-cpufreq-mediatek-Replace-old_-with-pre_.patch b/target/linux/mediatek/patches-5.15/350-05-cpufreq-mediatek-Replace-old_-with-pre_.patch new file mode 100644 index 00000000000..8506f4e4776 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-05-cpufreq-mediatek-Replace-old_-with-pre_.patch @@ -0,0 +1,201 @@ +From 35832d9f9c5c1da01420d962dc56e7e61d104829 Mon Sep 17 00:00:00 2001 +From: Rex-BC Chen +Date: Fri, 22 Apr 2022 15:52:28 +0800 +Subject: [PATCH 05/21] cpufreq: mediatek: Replace old_* with pre_* + +To make driver more readable, replace old_* with pre_*. + +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 84 +++++++++++++++--------------- + 1 file changed, 42 insertions(+), 42 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -63,18 +63,18 @@ static int mtk_cpufreq_voltage_tracking( + { + struct regulator *proc_reg = info->proc_reg; + struct regulator *sram_reg = info->sram_reg; +- int old_vproc, old_vsram, new_vsram, vsram, vproc, ret; ++ int pre_vproc, pre_vsram, new_vsram, vsram, vproc, ret; + +- old_vproc = regulator_get_voltage(proc_reg); +- if (old_vproc < 0) { ++ pre_vproc = regulator_get_voltage(proc_reg); ++ if (pre_vproc < 0) { + dev_err(info->cpu_dev, +- "invalid Vproc value: %d\n", old_vproc); +- return old_vproc; ++ "invalid Vproc value: %d\n", pre_vproc); ++ return pre_vproc; + } + /* Vsram should not exceed the maximum allowed voltage of SoC. */ + new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT); + +- if (old_vproc < new_vproc) { ++ if (pre_vproc < new_vproc) { + /* + * When scaling up voltages, Vsram and Vproc scale up step + * by step. At each step, set Vsram to (Vproc + 200mV) first, +@@ -82,20 +82,20 @@ static int mtk_cpufreq_voltage_tracking( + * Keep doing it until Vsram and Vproc hit target voltages. + */ + do { +- old_vsram = regulator_get_voltage(sram_reg); +- if (old_vsram < 0) { ++ pre_vsram = regulator_get_voltage(sram_reg); ++ if (pre_vsram < 0) { + dev_err(info->cpu_dev, +- "invalid Vsram value: %d\n", old_vsram); +- return old_vsram; ++ "invalid Vsram value: %d\n", pre_vsram); ++ return pre_vsram; + } +- old_vproc = regulator_get_voltage(proc_reg); +- if (old_vproc < 0) { ++ pre_vproc = regulator_get_voltage(proc_reg); ++ if (pre_vproc < 0) { + dev_err(info->cpu_dev, +- "invalid Vproc value: %d\n", old_vproc); +- return old_vproc; ++ "invalid Vproc value: %d\n", pre_vproc); ++ return pre_vproc; + } + +- vsram = min(new_vsram, old_vproc + MAX_VOLT_SHIFT); ++ vsram = min(new_vsram, pre_vproc + MAX_VOLT_SHIFT); + + if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) { + vsram = MAX_VOLT_LIMIT; +@@ -124,12 +124,12 @@ static int mtk_cpufreq_voltage_tracking( + ret = regulator_set_voltage(proc_reg, vproc, + vproc + VOLT_TOL); + if (ret) { +- regulator_set_voltage(sram_reg, old_vsram, +- old_vsram); ++ regulator_set_voltage(sram_reg, pre_vsram, ++ pre_vsram); + return ret; + } + } while (vproc < new_vproc || vsram < new_vsram); +- } else if (old_vproc > new_vproc) { ++ } else if (pre_vproc > new_vproc) { + /* + * When scaling down voltages, Vsram and Vproc scale down step + * by step. At each step, set Vproc to (Vsram - 200mV) first, +@@ -137,20 +137,20 @@ static int mtk_cpufreq_voltage_tracking( + * Keep doing it until Vsram and Vproc hit target voltages. + */ + do { +- old_vproc = regulator_get_voltage(proc_reg); +- if (old_vproc < 0) { ++ pre_vproc = regulator_get_voltage(proc_reg); ++ if (pre_vproc < 0) { + dev_err(info->cpu_dev, +- "invalid Vproc value: %d\n", old_vproc); +- return old_vproc; ++ "invalid Vproc value: %d\n", pre_vproc); ++ return pre_vproc; + } +- old_vsram = regulator_get_voltage(sram_reg); +- if (old_vsram < 0) { ++ pre_vsram = regulator_get_voltage(sram_reg); ++ if (pre_vsram < 0) { + dev_err(info->cpu_dev, +- "invalid Vsram value: %d\n", old_vsram); +- return old_vsram; ++ "invalid Vsram value: %d\n", pre_vsram); ++ return pre_vsram; + } + +- vproc = max(new_vproc, old_vsram - MAX_VOLT_SHIFT); ++ vproc = max(new_vproc, pre_vsram - MAX_VOLT_SHIFT); + ret = regulator_set_voltage(proc_reg, vproc, + vproc + VOLT_TOL); + if (ret) +@@ -180,8 +180,8 @@ static int mtk_cpufreq_voltage_tracking( + } + + if (ret) { +- regulator_set_voltage(proc_reg, old_vproc, +- old_vproc); ++ regulator_set_voltage(proc_reg, pre_vproc, ++ pre_vproc); + return ret; + } + } while (vproc > new_vproc + VOLT_TOL || +@@ -209,16 +209,16 @@ static int mtk_cpufreq_set_target(struct + struct mtk_cpu_dvfs_info *info = policy->driver_data; + struct device *cpu_dev = info->cpu_dev; + struct dev_pm_opp *opp; +- long freq_hz, old_freq_hz; +- int vproc, old_vproc, inter_vproc, target_vproc, ret; ++ long freq_hz, pre_freq_hz; ++ int vproc, pre_vproc, inter_vproc, target_vproc, ret; + + inter_vproc = info->intermediate_voltage; + +- old_freq_hz = clk_get_rate(cpu_clk); +- old_vproc = regulator_get_voltage(info->proc_reg); +- if (old_vproc < 0) { +- dev_err(cpu_dev, "invalid Vproc value: %d\n", old_vproc); +- return old_vproc; ++ pre_freq_hz = clk_get_rate(cpu_clk); ++ pre_vproc = regulator_get_voltage(info->proc_reg); ++ if (pre_vproc < 0) { ++ dev_err(cpu_dev, "invalid Vproc value: %d\n", pre_vproc); ++ return pre_vproc; + } + + freq_hz = freq_table[index].frequency * 1000; +@@ -237,12 +237,12 @@ static int mtk_cpufreq_set_target(struct + * current voltage, scale up voltage first. + */ + target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc; +- if (old_vproc < target_vproc) { ++ if (pre_vproc < target_vproc) { + ret = mtk_cpufreq_set_voltage(info, target_vproc); + if (ret) { + dev_err(cpu_dev, + "cpu%d: failed to scale up voltage!\n", policy->cpu); +- mtk_cpufreq_set_voltage(info, old_vproc); ++ mtk_cpufreq_set_voltage(info, pre_vproc); + return ret; + } + } +@@ -252,7 +252,7 @@ static int mtk_cpufreq_set_target(struct + if (ret) { + dev_err(cpu_dev, + "cpu%d: failed to re-parent cpu clock!\n", policy->cpu); +- mtk_cpufreq_set_voltage(info, old_vproc); ++ mtk_cpufreq_set_voltage(info, pre_vproc); + WARN_ON(1); + return ret; + } +@@ -263,7 +263,7 @@ static int mtk_cpufreq_set_target(struct + dev_err(cpu_dev, + "cpu%d: failed to scale cpu clock rate!\n", policy->cpu); + clk_set_parent(cpu_clk, armpll); +- mtk_cpufreq_set_voltage(info, old_vproc); ++ mtk_cpufreq_set_voltage(info, pre_vproc); + return ret; + } + +@@ -281,13 +281,13 @@ static int mtk_cpufreq_set_target(struct + * If the new voltage is lower than the intermediate voltage or the + * original voltage, scale down to the new voltage. + */ +- if (vproc < inter_vproc || vproc < old_vproc) { ++ if (vproc < inter_vproc || vproc < pre_vproc) { + ret = mtk_cpufreq_set_voltage(info, vproc); + if (ret) { + dev_err(cpu_dev, + "cpu%d: failed to scale down voltage!\n", policy->cpu); + clk_set_parent(cpu_clk, info->inter_clk); +- clk_set_rate(armpll, old_freq_hz); ++ clk_set_rate(armpll, pre_freq_hz); + clk_set_parent(cpu_clk, armpll); + return ret; + } diff --git a/target/linux/mediatek/patches-5.15/350-06-cpufreq-mediatek-Record-previous-target-vproc-value.patch b/target/linux/mediatek/patches-5.15/350-06-cpufreq-mediatek-Record-previous-target-vproc-value.patch new file mode 100644 index 00000000000..94e6617d267 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-06-cpufreq-mediatek-Record-previous-target-vproc-value.patch @@ -0,0 +1,64 @@ +From 34737eb8d0daa0d4183f10286a2f55d8788066bc Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Fri, 22 Apr 2022 15:52:29 +0800 +Subject: [PATCH 06/21] cpufreq: mediatek: Record previous target vproc value + +We found the buck voltage may not be exactly the same with what we set +because CPU may share the same buck with other module. +Therefore, we need to record the previous desired value instead of reading +it from regulators. + +Signed-off-by: Andrew-sh.Cheng +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -40,6 +40,7 @@ struct mtk_cpu_dvfs_info { + struct list_head list_head; + int intermediate_voltage; + bool need_voltage_tracking; ++ int pre_vproc; + }; + + static struct platform_device *cpufreq_pdev; +@@ -193,11 +194,17 @@ static int mtk_cpufreq_voltage_tracking( + + static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc) + { ++ int ret; ++ + if (info->need_voltage_tracking) +- return mtk_cpufreq_voltage_tracking(info, vproc); ++ ret = mtk_cpufreq_voltage_tracking(info, vproc); + else +- return regulator_set_voltage(info->proc_reg, vproc, +- vproc + VOLT_TOL); ++ ret = regulator_set_voltage(info->proc_reg, vproc, ++ MAX_VOLT_LIMIT); ++ if (!ret) ++ info->pre_vproc = vproc; ++ ++ return ret; + } + + static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, +@@ -215,7 +222,12 @@ static int mtk_cpufreq_set_target(struct + inter_vproc = info->intermediate_voltage; + + pre_freq_hz = clk_get_rate(cpu_clk); +- pre_vproc = regulator_get_voltage(info->proc_reg); ++ ++ if (unlikely(info->pre_vproc <= 0)) ++ pre_vproc = regulator_get_voltage(info->proc_reg); ++ else ++ pre_vproc = info->pre_vproc; ++ + if (pre_vproc < 0) { + dev_err(cpu_dev, "invalid Vproc value: %d\n", pre_vproc); + return pre_vproc; diff --git a/target/linux/mediatek/patches-5.15/350-07-cpufreq-mediatek-Make-sram-regulator-optional.patch b/target/linux/mediatek/patches-5.15/350-07-cpufreq-mediatek-Make-sram-regulator-optional.patch new file mode 100644 index 00000000000..4b74873b158 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-07-cpufreq-mediatek-Make-sram-regulator-optional.patch @@ -0,0 +1,30 @@ +From f6114c2bc563a8050e9dc874ad87e1448865f031 Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Fri, 22 Apr 2022 15:52:33 +0800 +Subject: [PATCH 07/21] cpufreq: mediatek: Make sram regulator optional + +For some MediaTek SoCs, like MT8186, it's possible that the sram regulator +is shared between CPU and CCI. +We hope regulator framework can return error for error handling rather +than a dummy handler from regulator_get api. +Therefore, we choose to use regulator_get_optional. + +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -354,7 +354,7 @@ static int mtk_cpu_dvfs_info_init(struct + } + + /* Both presence and absence of sram regulator are valid cases. */ +- info->sram_reg = regulator_get_exclusive(cpu_dev, "sram"); ++ info->sram_reg = regulator_get_optional(cpu_dev, "sram"); + if (IS_ERR(info->sram_reg)) + info->sram_reg = NULL; + else { diff --git a/target/linux/mediatek/patches-5.15/350-08-cpufreq-mediatek-Fix-NULL-pointer-dereference-in-med.patch b/target/linux/mediatek/patches-5.15/350-08-cpufreq-mediatek-Fix-NULL-pointer-dereference-in-med.patch new file mode 100644 index 00000000000..f2f572a753f --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-08-cpufreq-mediatek-Fix-NULL-pointer-dereference-in-med.patch @@ -0,0 +1,32 @@ +From fa7030d8ad4638acfd9e0fac84a20716d031dc95 Mon Sep 17 00:00:00 2001 +From: Wan Jiabing +Date: Tue, 26 Apr 2022 19:17:14 +0800 +Subject: [PATCH 08/21] cpufreq: mediatek: Fix NULL pointer dereference in + mediatek-cpufreq + +Fix following coccicheck error: +drivers/cpufreq/mediatek-cpufreq.c:464:16-23: ERROR: info is NULL but dereferenced. + +Use pr_err instead of dev_err to avoid dereferring a NULL pointer. + +Fixes: f52b16ba9fe4 ("cpufreq: mediatek: Use device print to show logs") +Signed-off-by: Wan Jiabing +Reviewed-by: Matthias Brugger +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -463,8 +463,8 @@ static int mtk_cpufreq_init(struct cpufr + + info = mtk_cpu_dvfs_info_lookup(policy->cpu); + if (!info) { +- dev_err(info->cpu_dev, +- "dvfs info for cpu%d is not initialized.\n", policy->cpu); ++ pr_err("dvfs info for cpu%d is not initialized.\n", ++ policy->cpu); + return -EINVAL; + } + diff --git a/target/linux/mediatek/patches-5.15/350-09-cpufreq-mediatek-Move-voltage-limits-to-platform-dat.patch b/target/linux/mediatek/patches-5.15/350-09-cpufreq-mediatek-Move-voltage-limits-to-platform-dat.patch new file mode 100644 index 00000000000..23b319648dc --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-09-cpufreq-mediatek-Move-voltage-limits-to-platform-dat.patch @@ -0,0 +1,227 @@ +From be2354b064e6bafbbad599ae2e10569ba4f7d5a6 Mon Sep 17 00:00:00 2001 +From: Rex-BC Chen +Date: Thu, 5 May 2022 19:52:19 +0800 +Subject: [PATCH 09/21] cpufreq: mediatek: Move voltage limits to platform data + +Voltages and shifts are defined as macros originally. +There are different requirements of these values for each MediaTek SoCs. +Therefore, we add the platform data and move these values into it. + +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 84 +++++++++++++++++++++--------- + 1 file changed, 58 insertions(+), 26 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -10,15 +10,21 @@ + #include + #include + #include ++#include + #include + #include + #include + +-#define MIN_VOLT_SHIFT (100000) +-#define MAX_VOLT_SHIFT (200000) +-#define MAX_VOLT_LIMIT (1150000) + #define VOLT_TOL (10000) + ++struct mtk_cpufreq_platform_data { ++ int min_volt_shift; ++ int max_volt_shift; ++ int proc_max_volt; ++ int sram_min_volt; ++ int sram_max_volt; ++}; ++ + /* + * The struct mtk_cpu_dvfs_info holds necessary information for doing CPU DVFS + * on each CPU power/clock domain of Mediatek SoCs. Each CPU cluster in +@@ -41,6 +47,7 @@ struct mtk_cpu_dvfs_info { + int intermediate_voltage; + bool need_voltage_tracking; + int pre_vproc; ++ const struct mtk_cpufreq_platform_data *soc_data; + }; + + static struct platform_device *cpufreq_pdev; +@@ -62,6 +69,7 @@ static struct mtk_cpu_dvfs_info *mtk_cpu + static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, + int new_vproc) + { ++ const struct mtk_cpufreq_platform_data *soc_data = info->soc_data; + struct regulator *proc_reg = info->proc_reg; + struct regulator *sram_reg = info->sram_reg; + int pre_vproc, pre_vsram, new_vsram, vsram, vproc, ret; +@@ -73,7 +81,8 @@ static int mtk_cpufreq_voltage_tracking( + return pre_vproc; + } + /* Vsram should not exceed the maximum allowed voltage of SoC. */ +- new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT); ++ new_vsram = min(new_vproc + soc_data->min_volt_shift, ++ soc_data->sram_max_volt); + + if (pre_vproc < new_vproc) { + /* +@@ -96,10 +105,11 @@ static int mtk_cpufreq_voltage_tracking( + return pre_vproc; + } + +- vsram = min(new_vsram, pre_vproc + MAX_VOLT_SHIFT); ++ vsram = min(new_vsram, ++ pre_vproc + soc_data->min_volt_shift); + +- if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) { +- vsram = MAX_VOLT_LIMIT; ++ if (vsram + VOLT_TOL >= soc_data->sram_max_volt) { ++ vsram = soc_data->sram_max_volt; + + /* + * If the target Vsram hits the maximum voltage, +@@ -117,7 +127,7 @@ static int mtk_cpufreq_voltage_tracking( + ret = regulator_set_voltage(sram_reg, vsram, + vsram + VOLT_TOL); + +- vproc = vsram - MIN_VOLT_SHIFT; ++ vproc = vsram - soc_data->min_volt_shift; + } + if (ret) + return ret; +@@ -151,7 +161,8 @@ static int mtk_cpufreq_voltage_tracking( + return pre_vsram; + } + +- vproc = max(new_vproc, pre_vsram - MAX_VOLT_SHIFT); ++ vproc = max(new_vproc, ++ pre_vsram - soc_data->max_volt_shift); + ret = regulator_set_voltage(proc_reg, vproc, + vproc + VOLT_TOL); + if (ret) +@@ -160,10 +171,11 @@ static int mtk_cpufreq_voltage_tracking( + if (vproc == new_vproc) + vsram = new_vsram; + else +- vsram = max(new_vsram, vproc + MIN_VOLT_SHIFT); ++ vsram = max(new_vsram, ++ vproc + soc_data->min_volt_shift); + +- if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) { +- vsram = MAX_VOLT_LIMIT; ++ if (vsram + VOLT_TOL >= soc_data->sram_max_volt) { ++ vsram = soc_data->sram_max_volt; + + /* + * If the target Vsram hits the maximum voltage, +@@ -194,13 +206,14 @@ static int mtk_cpufreq_voltage_tracking( + + static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc) + { ++ const struct mtk_cpufreq_platform_data *soc_data = info->soc_data; + int ret; + + if (info->need_voltage_tracking) + ret = mtk_cpufreq_voltage_tracking(info, vproc); + else + ret = regulator_set_voltage(info->proc_reg, vproc, +- MAX_VOLT_LIMIT); ++ soc_data->proc_max_volt); + if (!ret) + info->pre_vproc = vproc; + +@@ -509,9 +522,17 @@ static struct cpufreq_driver mtk_cpufreq + + static int mtk_cpufreq_probe(struct platform_device *pdev) + { ++ const struct mtk_cpufreq_platform_data *data; + struct mtk_cpu_dvfs_info *info, *tmp; + int cpu, ret; + ++ data = dev_get_platdata(&pdev->dev); ++ if (!data) { ++ dev_err(&pdev->dev, ++ "failed to get mtk cpufreq platform data\n"); ++ return -ENODEV; ++ } ++ + for_each_possible_cpu(cpu) { + info = mtk_cpu_dvfs_info_lookup(cpu); + if (info) +@@ -523,6 +544,7 @@ static int mtk_cpufreq_probe(struct plat + goto release_dvfs_info_list; + } + ++ info->soc_data = data; + ret = mtk_cpu_dvfs_info_init(info, cpu); + if (ret) { + dev_err(&pdev->dev, +@@ -558,20 +580,27 @@ static struct platform_driver mtk_cpufre + .probe = mtk_cpufreq_probe, + }; + ++static const struct mtk_cpufreq_platform_data mt2701_platform_data = { ++ .min_volt_shift = 100000, ++ .max_volt_shift = 200000, ++ .proc_max_volt = 1150000, ++ .sram_min_volt = 0, ++ .sram_max_volt = 1150000, ++}; ++ + /* List of machines supported by this driver */ + static const struct of_device_id mtk_cpufreq_machines[] __initconst = { +- { .compatible = "mediatek,mt2701", }, +- { .compatible = "mediatek,mt2712", }, +- { .compatible = "mediatek,mt7622", }, +- { .compatible = "mediatek,mt7623", }, +- { .compatible = "mediatek,mt8167", }, +- { .compatible = "mediatek,mt817x", }, +- { .compatible = "mediatek,mt8173", }, +- { .compatible = "mediatek,mt8176", }, +- { .compatible = "mediatek,mt8183", }, +- { .compatible = "mediatek,mt8365", }, +- { .compatible = "mediatek,mt8516", }, +- ++ { .compatible = "mediatek,mt2701", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt2712", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt7622", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt7623", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8167", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8176", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8183", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8365", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8516", .data = &mt2701_platform_data }, + { } + }; + MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines); +@@ -580,6 +609,7 @@ static int __init mtk_cpufreq_driver_ini + { + struct device_node *np; + const struct of_device_id *match; ++ const struct mtk_cpufreq_platform_data *data; + int err; + + np = of_find_node_by_path("/"); +@@ -592,6 +622,7 @@ static int __init mtk_cpufreq_driver_ini + pr_debug("Machine is not compatible with mtk-cpufreq\n"); + return -ENODEV; + } ++ data = match->data; + + err = platform_driver_register(&mtk_cpufreq_platdrv); + if (err) +@@ -603,7 +634,8 @@ static int __init mtk_cpufreq_driver_ini + * and the device registration codes are put here to handle defer + * probing. + */ +- cpufreq_pdev = platform_device_register_simple("mtk-cpufreq", -1, NULL, 0); ++ cpufreq_pdev = platform_device_register_data(NULL, "mtk-cpufreq", -1, ++ data, sizeof(*data)); + if (IS_ERR(cpufreq_pdev)) { + pr_err("failed to register mtk-cpufreq platform device\n"); + platform_driver_unregister(&mtk_cpufreq_platdrv); diff --git a/target/linux/mediatek/patches-5.15/350-10-cpufreq-mediatek-Refine-mtk_cpufreq_voltage_tracking.patch b/target/linux/mediatek/patches-5.15/350-10-cpufreq-mediatek-Refine-mtk_cpufreq_voltage_tracking.patch new file mode 100644 index 00000000000..0ba9471ffa7 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-10-cpufreq-mediatek-Refine-mtk_cpufreq_voltage_tracking.patch @@ -0,0 +1,255 @@ +From 944b041c91f1e1cd762c39c1222f078550149486 Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Thu, 5 May 2022 19:52:20 +0800 +Subject: [PATCH 10/21] cpufreq: mediatek: Refine + mtk_cpufreq_voltage_tracking() + +Because the difference of sram and proc should in a range of min_volt_shift +and max_volt_shift. We need to adjust the sram and proc step by step. + +We replace VOLT_TOL (voltage tolerance) with the platform data and update the +logic to determine the voltage boundary and invoking regulator_set_voltage. + +- Use 'sram_min_volt' and 'sram_max_volt' to determine the voltage boundary + of sram regulator. +- Use (sram_min_volt - min_volt_shift) and 'proc_max_volt' to determine the + voltage boundary of vproc regulator. + +Moreover, to prevent infinite loop when tracking voltage, we calculate the +maximum value for each platform data. +We assume min voltage is 0 and tracking target voltage using +min_volt_shift for each iteration. +The retry_max is 3 times of expeted iteration count. + +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 147 ++++++++++------------------- + 1 file changed, 51 insertions(+), 96 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -15,8 +16,6 @@ + #include + #include + +-#define VOLT_TOL (10000) +- + struct mtk_cpufreq_platform_data { + int min_volt_shift; + int max_volt_shift; +@@ -48,6 +47,7 @@ struct mtk_cpu_dvfs_info { + bool need_voltage_tracking; + int pre_vproc; + const struct mtk_cpufreq_platform_data *soc_data; ++ int vtrack_max; + }; + + static struct platform_device *cpufreq_pdev; +@@ -73,6 +73,7 @@ static int mtk_cpufreq_voltage_tracking( + struct regulator *proc_reg = info->proc_reg; + struct regulator *sram_reg = info->sram_reg; + int pre_vproc, pre_vsram, new_vsram, vsram, vproc, ret; ++ int retry = info->vtrack_max; + + pre_vproc = regulator_get_voltage(proc_reg); + if (pre_vproc < 0) { +@@ -80,91 +81,44 @@ static int mtk_cpufreq_voltage_tracking( + "invalid Vproc value: %d\n", pre_vproc); + return pre_vproc; + } +- /* Vsram should not exceed the maximum allowed voltage of SoC. */ +- new_vsram = min(new_vproc + soc_data->min_volt_shift, +- soc_data->sram_max_volt); +- +- if (pre_vproc < new_vproc) { +- /* +- * When scaling up voltages, Vsram and Vproc scale up step +- * by step. At each step, set Vsram to (Vproc + 200mV) first, +- * then set Vproc to (Vsram - 100mV). +- * Keep doing it until Vsram and Vproc hit target voltages. +- */ +- do { +- pre_vsram = regulator_get_voltage(sram_reg); +- if (pre_vsram < 0) { +- dev_err(info->cpu_dev, +- "invalid Vsram value: %d\n", pre_vsram); +- return pre_vsram; +- } +- pre_vproc = regulator_get_voltage(proc_reg); +- if (pre_vproc < 0) { +- dev_err(info->cpu_dev, +- "invalid Vproc value: %d\n", pre_vproc); +- return pre_vproc; +- } + +- vsram = min(new_vsram, +- pre_vproc + soc_data->min_volt_shift); ++ pre_vsram = regulator_get_voltage(sram_reg); ++ if (pre_vsram < 0) { ++ dev_err(info->cpu_dev, "invalid Vsram value: %d\n", pre_vsram); ++ return pre_vsram; ++ } + +- if (vsram + VOLT_TOL >= soc_data->sram_max_volt) { +- vsram = soc_data->sram_max_volt; ++ new_vsram = clamp(new_vproc + soc_data->min_volt_shift, ++ soc_data->sram_min_volt, soc_data->sram_max_volt); ++ ++ do { ++ if (pre_vproc <= new_vproc) { ++ vsram = clamp(pre_vproc + soc_data->max_volt_shift, ++ soc_data->sram_min_volt, new_vsram); ++ ret = regulator_set_voltage(sram_reg, vsram, ++ soc_data->sram_max_volt); + +- /* +- * If the target Vsram hits the maximum voltage, +- * try to set the exact voltage value first. +- */ +- ret = regulator_set_voltage(sram_reg, vsram, +- vsram); +- if (ret) +- ret = regulator_set_voltage(sram_reg, +- vsram - VOLT_TOL, +- vsram); ++ if (ret) ++ return ret; + ++ if (vsram == soc_data->sram_max_volt || ++ new_vsram == soc_data->sram_min_volt) + vproc = new_vproc; +- } else { +- ret = regulator_set_voltage(sram_reg, vsram, +- vsram + VOLT_TOL); +- ++ else + vproc = vsram - soc_data->min_volt_shift; +- } +- if (ret) +- return ret; + + ret = regulator_set_voltage(proc_reg, vproc, +- vproc + VOLT_TOL); ++ soc_data->proc_max_volt); + if (ret) { + regulator_set_voltage(sram_reg, pre_vsram, +- pre_vsram); ++ soc_data->sram_max_volt); + return ret; + } +- } while (vproc < new_vproc || vsram < new_vsram); +- } else if (pre_vproc > new_vproc) { +- /* +- * When scaling down voltages, Vsram and Vproc scale down step +- * by step. At each step, set Vproc to (Vsram - 200mV) first, +- * then set Vproc to (Vproc + 100mV). +- * Keep doing it until Vsram and Vproc hit target voltages. +- */ +- do { +- pre_vproc = regulator_get_voltage(proc_reg); +- if (pre_vproc < 0) { +- dev_err(info->cpu_dev, +- "invalid Vproc value: %d\n", pre_vproc); +- return pre_vproc; +- } +- pre_vsram = regulator_get_voltage(sram_reg); +- if (pre_vsram < 0) { +- dev_err(info->cpu_dev, +- "invalid Vsram value: %d\n", pre_vsram); +- return pre_vsram; +- } +- ++ } else if (pre_vproc > new_vproc) { + vproc = max(new_vproc, + pre_vsram - soc_data->max_volt_shift); + ret = regulator_set_voltage(proc_reg, vproc, +- vproc + VOLT_TOL); ++ soc_data->proc_max_volt); + if (ret) + return ret; + +@@ -174,32 +128,24 @@ static int mtk_cpufreq_voltage_tracking( + vsram = max(new_vsram, + vproc + soc_data->min_volt_shift); + +- if (vsram + VOLT_TOL >= soc_data->sram_max_volt) { +- vsram = soc_data->sram_max_volt; +- +- /* +- * If the target Vsram hits the maximum voltage, +- * try to set the exact voltage value first. +- */ +- ret = regulator_set_voltage(sram_reg, vsram, +- vsram); +- if (ret) +- ret = regulator_set_voltage(sram_reg, +- vsram - VOLT_TOL, +- vsram); +- } else { +- ret = regulator_set_voltage(sram_reg, vsram, +- vsram + VOLT_TOL); +- } +- ++ ret = regulator_set_voltage(sram_reg, vsram, ++ soc_data->sram_max_volt); + if (ret) { + regulator_set_voltage(proc_reg, pre_vproc, +- pre_vproc); ++ soc_data->proc_max_volt); + return ret; + } +- } while (vproc > new_vproc + VOLT_TOL || +- vsram > new_vsram + VOLT_TOL); +- } ++ } ++ ++ pre_vproc = vproc; ++ pre_vsram = vsram; ++ ++ if (--retry < 0) { ++ dev_err(info->cpu_dev, ++ "over loop count, failed to set voltage\n"); ++ return -EINVAL; ++ } ++ } while (vproc != new_vproc || vsram != new_vsram); + + return 0; + } +@@ -261,8 +207,8 @@ static int mtk_cpufreq_set_target(struct + * If the new voltage or the intermediate voltage is higher than the + * current voltage, scale up voltage first. + */ +- target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc; +- if (pre_vproc < target_vproc) { ++ target_vproc = max(inter_vproc, vproc); ++ if (pre_vproc <= target_vproc) { + ret = mtk_cpufreq_set_voltage(info, target_vproc); + if (ret) { + dev_err(cpu_dev, +@@ -417,6 +363,15 @@ static int mtk_cpu_dvfs_info_init(struct + */ + info->need_voltage_tracking = (info->sram_reg != NULL); + ++ /* ++ * We assume min voltage is 0 and tracking target voltage using ++ * min_volt_shift for each iteration. ++ * The vtrack_max is 3 times of expeted iteration count. ++ */ ++ info->vtrack_max = 3 * DIV_ROUND_UP(max(info->soc_data->sram_max_volt, ++ info->soc_data->proc_max_volt), ++ info->soc_data->min_volt_shift); ++ + return 0; + + out_disable_inter_clock: diff --git a/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch b/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch new file mode 100644 index 00000000000..2cb99b907a6 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-11-cpufreq-mediatek-Add-opp-notification-support.patch @@ -0,0 +1,184 @@ +From 01be227eff7e5fc01f7c8de8f6daddd5fb17ddd1 Mon Sep 17 00:00:00 2001 +From: Rex-BC Chen +Date: Thu, 5 May 2022 19:52:21 +0800 +Subject: [PATCH 11/21] cpufreq: mediatek: Add opp notification support + +From this opp notifier, cpufreq should listen to opp notification and do +proper actions when receiving events of disable and voltage adjustment. + +One of the user for this opp notifier is MediaTek SVS. +The MediaTek Smart Voltage Scaling (SVS) is a hardware which calculates +suitable SVS bank voltages to OPP voltage table. + +Signed-off-by: Andrew-sh.Cheng +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +[ Viresh: Renamed opp_freq as current_freq and moved its initialization ] +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 90 +++++++++++++++++++++++++++--- + 1 file changed, 82 insertions(+), 8 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -46,6 +46,11 @@ struct mtk_cpu_dvfs_info { + int intermediate_voltage; + bool need_voltage_tracking; + int pre_vproc; ++ /* Avoid race condition for regulators between notify and policy */ ++ struct mutex reg_lock; ++ struct notifier_block opp_nb; ++ unsigned int opp_cpu; ++ unsigned long current_freq; + const struct mtk_cpufreq_platform_data *soc_data; + int vtrack_max; + }; +@@ -182,6 +187,8 @@ static int mtk_cpufreq_set_target(struct + + pre_freq_hz = clk_get_rate(cpu_clk); + ++ mutex_lock(&info->reg_lock); ++ + if (unlikely(info->pre_vproc <= 0)) + pre_vproc = regulator_get_voltage(info->proc_reg); + else +@@ -214,7 +221,7 @@ static int mtk_cpufreq_set_target(struct + dev_err(cpu_dev, + "cpu%d: failed to scale up voltage!\n", policy->cpu); + mtk_cpufreq_set_voltage(info, pre_vproc); +- return ret; ++ goto out; + } + } + +@@ -224,8 +231,7 @@ static int mtk_cpufreq_set_target(struct + dev_err(cpu_dev, + "cpu%d: failed to re-parent cpu clock!\n", policy->cpu); + mtk_cpufreq_set_voltage(info, pre_vproc); +- WARN_ON(1); +- return ret; ++ goto out; + } + + /* Set the original PLL to target rate. */ +@@ -235,7 +241,7 @@ static int mtk_cpufreq_set_target(struct + "cpu%d: failed to scale cpu clock rate!\n", policy->cpu); + clk_set_parent(cpu_clk, armpll); + mtk_cpufreq_set_voltage(info, pre_vproc); +- return ret; ++ goto out; + } + + /* Set parent of CPU clock back to the original PLL. */ +@@ -244,8 +250,7 @@ static int mtk_cpufreq_set_target(struct + dev_err(cpu_dev, + "cpu%d: failed to re-parent cpu clock!\n", policy->cpu); + mtk_cpufreq_set_voltage(info, inter_vproc); +- WARN_ON(1); +- return ret; ++ goto out; + } + + /* +@@ -260,15 +265,72 @@ static int mtk_cpufreq_set_target(struct + clk_set_parent(cpu_clk, info->inter_clk); + clk_set_rate(armpll, pre_freq_hz); + clk_set_parent(cpu_clk, armpll); +- return ret; ++ goto out; + } + } + +- return 0; ++ info->current_freq = freq_hz; ++ ++out: ++ mutex_unlock(&info->reg_lock); ++ ++ return ret; + } + + #define DYNAMIC_POWER "dynamic-power-coefficient" + ++static int mtk_cpufreq_opp_notifier(struct notifier_block *nb, ++ unsigned long event, void *data) ++{ ++ struct dev_pm_opp *opp = data; ++ struct dev_pm_opp *new_opp; ++ struct mtk_cpu_dvfs_info *info; ++ unsigned long freq, volt; ++ struct cpufreq_policy *policy; ++ int ret = 0; ++ ++ info = container_of(nb, struct mtk_cpu_dvfs_info, opp_nb); ++ ++ if (event == OPP_EVENT_ADJUST_VOLTAGE) { ++ freq = dev_pm_opp_get_freq(opp); ++ ++ mutex_lock(&info->reg_lock); ++ if (info->current_freq == freq) { ++ volt = dev_pm_opp_get_voltage(opp); ++ ret = mtk_cpufreq_set_voltage(info, volt); ++ if (ret) ++ dev_err(info->cpu_dev, ++ "failed to scale voltage: %d\n", ret); ++ } ++ mutex_unlock(&info->reg_lock); ++ } else if (event == OPP_EVENT_DISABLE) { ++ freq = dev_pm_opp_get_freq(opp); ++ ++ /* case of current opp item is disabled */ ++ if (info->current_freq == freq) { ++ freq = 1; ++ new_opp = dev_pm_opp_find_freq_ceil(info->cpu_dev, ++ &freq); ++ if (IS_ERR(new_opp)) { ++ dev_err(info->cpu_dev, ++ "all opp items are disabled\n"); ++ ret = PTR_ERR(new_opp); ++ return notifier_from_errno(ret); ++ } ++ ++ dev_pm_opp_put(new_opp); ++ policy = cpufreq_cpu_get(info->opp_cpu); ++ if (policy) { ++ cpufreq_driver_target(policy, freq / 1000, ++ CPUFREQ_RELATION_L); ++ cpufreq_cpu_put(policy); ++ } ++ } ++ } ++ ++ return notifier_from_errno(ret); ++} ++ + static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) + { + struct device *cpu_dev; +@@ -357,6 +419,17 @@ static int mtk_cpu_dvfs_info_init(struct + info->intermediate_voltage = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); + ++ mutex_init(&info->reg_lock); ++ info->current_freq = clk_get_rate(info->cpu_clk); ++ ++ info->opp_cpu = cpu; ++ info->opp_nb.notifier_call = mtk_cpufreq_opp_notifier; ++ ret = dev_pm_opp_register_notifier(cpu_dev, &info->opp_nb); ++ if (ret) { ++ dev_err(cpu_dev, "cpu%d: failed to register opp notifier\n", cpu); ++ goto out_disable_inter_clock; ++ } ++ + /* + * If SRAM regulator is present, software "voltage tracking" is needed + * for this CPU power domain. +@@ -421,6 +494,7 @@ static void mtk_cpu_dvfs_info_release(st + } + + dev_pm_opp_of_cpumask_remove_table(&info->cpus); ++ dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb); + } + + static int mtk_cpufreq_init(struct cpufreq_policy *policy) diff --git a/target/linux/mediatek/patches-5.15/350-12-cpufreq-mediatek-Fix-potential-deadlock-problem-in-m.patch b/target/linux/mediatek/patches-5.15/350-12-cpufreq-mediatek-Fix-potential-deadlock-problem-in-m.patch new file mode 100644 index 00000000000..76bd795c004 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-12-cpufreq-mediatek-Fix-potential-deadlock-problem-in-m.patch @@ -0,0 +1,43 @@ +From 6a1bd7cf4ed7a1948f564aaf16d34b7352c0029b Mon Sep 17 00:00:00 2001 +From: Wan Jiabing +Date: Tue, 10 May 2022 17:05:31 +0800 +Subject: [PATCH 12/21] cpufreq: mediatek: Fix potential deadlock problem in + mtk_cpufreq_set_target + +Fix following coccichek error: +./drivers/cpufreq/mediatek-cpufreq.c:199:2-8: preceding lock on line +./drivers/cpufreq/mediatek-cpufreq.c:208:2-8: preceding lock on line + +mutex_lock is acquired but not released before return. +Use 'goto out' to help releasing the mutex_lock. + +Fixes: c210063b40ac ("cpufreq: mediatek: Add opp notification support") +Signed-off-by: Wan Jiabing +Reviewed-by: Rex-BC Chen +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -196,7 +196,8 @@ static int mtk_cpufreq_set_target(struct + + if (pre_vproc < 0) { + dev_err(cpu_dev, "invalid Vproc value: %d\n", pre_vproc); +- return pre_vproc; ++ ret = pre_vproc; ++ goto out; + } + + freq_hz = freq_table[index].frequency * 1000; +@@ -205,7 +206,8 @@ static int mtk_cpufreq_set_target(struct + if (IS_ERR(opp)) { + dev_err(cpu_dev, "cpu%d: failed to find OPP for %ld\n", + policy->cpu, freq_hz); +- return PTR_ERR(opp); ++ ret = PTR_ERR(opp); ++ goto out; + } + vproc = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); diff --git a/target/linux/mediatek/patches-5.15/350-13-cpufreq-mediatek-Link-CCI-device-to-CPU.patch b/target/linux/mediatek/patches-5.15/350-13-cpufreq-mediatek-Link-CCI-device-to-CPU.patch new file mode 100644 index 00000000000..eeaa466c326 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-13-cpufreq-mediatek-Link-CCI-device-to-CPU.patch @@ -0,0 +1,188 @@ +From 15aaf74fb734a3e69b10d00b97b322711b81e222 Mon Sep 17 00:00:00 2001 +From: Rex-BC Chen +Date: Thu, 5 May 2022 19:52:22 +0800 +Subject: [PATCH 13/21] cpufreq: mediatek: Link CCI device to CPU + +In some MediaTek SoCs, like MT8183, CPU and CCI share the same power +supplies. Cpufreq needs to check if CCI devfreq exists and wait until +CCI devfreq ready before scaling frequency. + +Before CCI devfreq is ready, we record the voltage when booting to +kernel and use the max(cpu target voltage, booting voltage) to +prevent cpufreq adjust to the lower voltage which will cause the CCI +crash because of high frequency and low voltage. + +- Add is_ccifreq_ready() to link CCI device to CPI, and CPU will start + DVFS when CCI is ready. +- Add platform data for MT8183. + +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Kevin Hilman +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 82 +++++++++++++++++++++++++++++- + 1 file changed, 81 insertions(+), 1 deletion(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -22,6 +22,7 @@ struct mtk_cpufreq_platform_data { + int proc_max_volt; + int sram_min_volt; + int sram_max_volt; ++ bool ccifreq_supported; + }; + + /* +@@ -38,6 +39,7 @@ struct mtk_cpufreq_platform_data { + struct mtk_cpu_dvfs_info { + struct cpumask cpus; + struct device *cpu_dev; ++ struct device *cci_dev; + struct regulator *proc_reg; + struct regulator *sram_reg; + struct clk *cpu_clk; +@@ -45,6 +47,7 @@ struct mtk_cpu_dvfs_info { + struct list_head list_head; + int intermediate_voltage; + bool need_voltage_tracking; ++ int vproc_on_boot; + int pre_vproc; + /* Avoid race condition for regulators between notify and policy */ + struct mutex reg_lock; +@@ -53,6 +56,7 @@ struct mtk_cpu_dvfs_info { + unsigned long current_freq; + const struct mtk_cpufreq_platform_data *soc_data; + int vtrack_max; ++ bool ccifreq_bound; + }; + + static struct platform_device *cpufreq_pdev; +@@ -171,6 +175,28 @@ static int mtk_cpufreq_set_voltage(struc + return ret; + } + ++static bool is_ccifreq_ready(struct mtk_cpu_dvfs_info *info) ++{ ++ struct device_link *sup_link; ++ ++ if (info->ccifreq_bound) ++ return true; ++ ++ sup_link = device_link_add(info->cpu_dev, info->cci_dev, ++ DL_FLAG_AUTOREMOVE_CONSUMER); ++ if (!sup_link) { ++ dev_err(info->cpu_dev, "cpu%d: sup_link is NULL\n", info->opp_cpu); ++ return false; ++ } ++ ++ if (sup_link->supplier->links.status != DL_DEV_DRIVER_BOUND) ++ return false; ++ ++ info->ccifreq_bound = true; ++ ++ return true; ++} ++ + static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, + unsigned int index) + { +@@ -213,6 +239,14 @@ static int mtk_cpufreq_set_target(struct + dev_pm_opp_put(opp); + + /* ++ * If MediaTek cci is supported but is not ready, we will use the value ++ * of max(target cpu voltage, booting voltage) to prevent high freqeuncy ++ * low voltage crash. ++ */ ++ if (info->soc_data->ccifreq_supported && !is_ccifreq_ready(info)) ++ vproc = max(vproc, info->vproc_on_boot); ++ ++ /* + * If the new voltage or the intermediate voltage is higher than the + * current voltage, scale up voltage first. + */ +@@ -333,6 +367,23 @@ static int mtk_cpufreq_opp_notifier(stru + return notifier_from_errno(ret); + } + ++static struct device *of_get_cci(struct device *cpu_dev) ++{ ++ struct device_node *np; ++ struct platform_device *pdev; ++ ++ np = of_parse_phandle(cpu_dev->of_node, "mediatek,cci", 0); ++ if (IS_ERR_OR_NULL(np)) ++ return NULL; ++ ++ pdev = of_find_device_by_node(np); ++ of_node_put(np); ++ if (IS_ERR_OR_NULL(pdev)) ++ return NULL; ++ ++ return &pdev->dev; ++} ++ + static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) + { + struct device *cpu_dev; +@@ -347,6 +398,16 @@ static int mtk_cpu_dvfs_info_init(struct + } + info->cpu_dev = cpu_dev; + ++ info->ccifreq_bound = false; ++ if (info->soc_data->ccifreq_supported) { ++ info->cci_dev = of_get_cci(info->cpu_dev); ++ if (IS_ERR_OR_NULL(info->cci_dev)) { ++ ret = PTR_ERR(info->cci_dev); ++ dev_err(cpu_dev, "cpu%d: failed to get cci device\n", cpu); ++ return -ENODEV; ++ } ++ } ++ + info->cpu_clk = clk_get(cpu_dev, "cpu"); + if (IS_ERR(info->cpu_clk)) { + ret = PTR_ERR(info->cpu_clk); +@@ -410,6 +471,15 @@ static int mtk_cpu_dvfs_info_init(struct + if (ret) + goto out_disable_mux_clock; + ++ if (info->soc_data->ccifreq_supported) { ++ info->vproc_on_boot = regulator_get_voltage(info->proc_reg); ++ if (info->vproc_on_boot < 0) { ++ dev_err(info->cpu_dev, ++ "invalid Vproc value: %d\n", info->vproc_on_boot); ++ goto out_disable_inter_clock; ++ } ++ } ++ + /* Search a safe voltage for intermediate frequency. */ + rate = clk_get_rate(info->inter_clk); + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); +@@ -617,6 +687,16 @@ static const struct mtk_cpufreq_platform + .proc_max_volt = 1150000, + .sram_min_volt = 0, + .sram_max_volt = 1150000, ++ .ccifreq_supported = false, ++}; ++ ++static const struct mtk_cpufreq_platform_data mt8183_platform_data = { ++ .min_volt_shift = 100000, ++ .max_volt_shift = 200000, ++ .proc_max_volt = 1150000, ++ .sram_min_volt = 0, ++ .sram_max_volt = 1150000, ++ .ccifreq_supported = true, + }; + + /* List of machines supported by this driver */ +@@ -629,7 +709,7 @@ static const struct of_device_id mtk_cpu + { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8176", .data = &mt2701_platform_data }, +- { .compatible = "mediatek,mt8183", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8183", .data = &mt8183_platform_data }, + { .compatible = "mediatek,mt8365", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8516", .data = &mt2701_platform_data }, + { } diff --git a/target/linux/mediatek/patches-5.15/350-14-cpufreq-mediatek-Add-support-for-MT8186.patch b/target/linux/mediatek/patches-5.15/350-14-cpufreq-mediatek-Add-support-for-MT8186.patch new file mode 100644 index 00000000000..31000cfbe05 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-14-cpufreq-mediatek-Add-support-for-MT8186.patch @@ -0,0 +1,42 @@ +From b6be0baa6615afc65c3963adab674e36af1d4d5f Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Thu, 5 May 2022 19:52:23 +0800 +Subject: [PATCH 14/21] cpufreq: mediatek: Add support for MT8186 + +The platform data of MT8186 is different from previous MediaTek SoCs, +so we add a new compatible and platform data for it. + +Signed-off-by: Jia-Wei Chang +Signed-off-by: Rex-BC Chen +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -699,6 +699,15 @@ static const struct mtk_cpufreq_platform + .ccifreq_supported = true, + }; + ++static const struct mtk_cpufreq_platform_data mt8186_platform_data = { ++ .min_volt_shift = 100000, ++ .max_volt_shift = 250000, ++ .proc_max_volt = 1118750, ++ .sram_min_volt = 850000, ++ .sram_max_volt = 1118750, ++ .ccifreq_supported = true, ++}; ++ + /* List of machines supported by this driver */ + static const struct of_device_id mtk_cpufreq_machines[] __initconst = { + { .compatible = "mediatek,mt2701", .data = &mt2701_platform_data }, +@@ -710,6 +719,7 @@ static const struct of_device_id mtk_cpu + { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8176", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8183", .data = &mt8183_platform_data }, ++ { .compatible = "mediatek,mt8186", .data = &mt8186_platform_data }, + { .compatible = "mediatek,mt8365", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8516", .data = &mt2701_platform_data }, + { } diff --git a/target/linux/mediatek/patches-5.15/350-15-cpufreq-mediatek-Handle-sram-regulator-probe-deferra.patch b/target/linux/mediatek/patches-5.15/350-15-cpufreq-mediatek-Handle-sram-regulator-probe-deferra.patch new file mode 100644 index 00000000000..c0137894c93 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-15-cpufreq-mediatek-Handle-sram-regulator-probe-deferra.patch @@ -0,0 +1,35 @@ +From 75d19b24aa3203d6c78e4c431c2cc07157ce12fe Mon Sep 17 00:00:00 2001 +From: AngeloGioacchino Del Regno +Date: Wed, 13 Jul 2022 13:15:36 +0200 +Subject: [PATCH 15/21] cpufreq: mediatek: Handle sram regulator probe deferral + +If the regulator_get_optional() call for the SRAM regulator returns +a probe deferral, we must bail out and retry probing later: failing +to do this will produce unstabilities on platforms requiring the +handling for this regulator. + +Fixes: ffa7bdf7f344 ("cpufreq: mediatek: Make sram regulator optional") +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -439,9 +439,13 @@ static int mtk_cpu_dvfs_info_init(struct + + /* Both presence and absence of sram regulator are valid cases. */ + info->sram_reg = regulator_get_optional(cpu_dev, "sram"); +- if (IS_ERR(info->sram_reg)) ++ if (IS_ERR(info->sram_reg)) { ++ ret = PTR_ERR(info->sram_reg); ++ if (ret == -EPROBE_DEFER) ++ goto out_free_resources; ++ + info->sram_reg = NULL; +- else { ++ } else { + ret = regulator_enable(info->sram_reg); + if (ret) { + dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu); diff --git a/target/linux/mediatek/patches-5.15/350-16-cpufreq-mediatek-fix-error-return-code-in-mtk_cpu_dv.patch b/target/linux/mediatek/patches-5.15/350-16-cpufreq-mediatek-fix-error-return-code-in-mtk_cpu_dv.patch new file mode 100644 index 00000000000..45c4477ff1a --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-16-cpufreq-mediatek-fix-error-return-code-in-mtk_cpu_dv.patch @@ -0,0 +1,29 @@ +From dd1174c21dacacd6c0129c1dabc5decad35c02c2 Mon Sep 17 00:00:00 2001 +From: Yang Yingliang +Date: Tue, 17 May 2022 21:34:50 +0800 +Subject: [PATCH 16/21] cpufreq: mediatek: fix error return code in + mtk_cpu_dvfs_info_init() + +If regulator_get_voltage() fails, it should return the error code in +mtk_cpu_dvfs_info_init(). + +Fixes: 0daa47325bae ("cpufreq: mediatek: Link CCI device to CPU") +Reported-by: Hulk Robot +Signed-off-by: Yang Yingliang +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Rex-BC Chen +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -478,6 +478,7 @@ static int mtk_cpu_dvfs_info_init(struct + if (info->soc_data->ccifreq_supported) { + info->vproc_on_boot = regulator_get_voltage(info->proc_reg); + if (info->vproc_on_boot < 0) { ++ ret = info->vproc_on_boot; + dev_err(info->cpu_dev, + "invalid Vproc value: %d\n", info->vproc_on_boot); + goto out_disable_inter_clock; diff --git a/target/linux/mediatek/patches-5.15/350-17-cpufreq-mediatek-fix-passing-zero-to-PTR_ERR.patch b/target/linux/mediatek/patches-5.15/350-17-cpufreq-mediatek-fix-passing-zero-to-PTR_ERR.patch new file mode 100644 index 00000000000..557d02b822b --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-17-cpufreq-mediatek-fix-passing-zero-to-PTR_ERR.patch @@ -0,0 +1,47 @@ +From 230a74d459244411db91bfd678f17fcf7aedfcd0 Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Fri, 24 Mar 2023 18:11:27 +0800 +Subject: [PATCH 17/21] cpufreq: mediatek: fix passing zero to 'PTR_ERR' + +In order to prevent passing zero to 'PTR_ERR' in +mtk_cpu_dvfs_info_init(), we fix the return value of of_get_cci() using +error pointer by explicitly casting error number. + +Signed-off-by: Jia-Wei Chang +Fixes: 0daa47325bae ("cpufreq: mediatek: Link CCI device to CPU") +Reported-by: Dan Carpenter +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -373,13 +373,13 @@ static struct device *of_get_cci(struct + struct platform_device *pdev; + + np = of_parse_phandle(cpu_dev->of_node, "mediatek,cci", 0); +- if (IS_ERR_OR_NULL(np)) +- return NULL; ++ if (!np) ++ return ERR_PTR(-ENODEV); + + pdev = of_find_device_by_node(np); + of_node_put(np); +- if (IS_ERR_OR_NULL(pdev)) +- return NULL; ++ if (!pdev) ++ return ERR_PTR(-ENODEV); + + return &pdev->dev; + } +@@ -401,7 +401,7 @@ static int mtk_cpu_dvfs_info_init(struct + info->ccifreq_bound = false; + if (info->soc_data->ccifreq_supported) { + info->cci_dev = of_get_cci(info->cpu_dev); +- if (IS_ERR_OR_NULL(info->cci_dev)) { ++ if (IS_ERR(info->cci_dev)) { + ret = PTR_ERR(info->cci_dev); + dev_err(cpu_dev, "cpu%d: failed to get cci device\n", cpu); + return -ENODEV; diff --git a/target/linux/mediatek/patches-5.15/350-18-cpufreq-mediatek-fix-KP-caused-by-handler-usage-afte.patch b/target/linux/mediatek/patches-5.15/350-18-cpufreq-mediatek-fix-KP-caused-by-handler-usage-afte.patch new file mode 100644 index 00000000000..61531d38ad2 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-18-cpufreq-mediatek-fix-KP-caused-by-handler-usage-afte.patch @@ -0,0 +1,149 @@ +From fced531b7c7e18192e7982637c8e8f20c29aad64 Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Fri, 24 Mar 2023 18:11:28 +0800 +Subject: [PATCH 18/21] cpufreq: mediatek: fix KP caused by handler usage after + regulator_put/clk_put + +Any kind of failure in mtk_cpu_dvfs_info_init() will lead to calling +regulator_put() or clk_put() and the KP will occur since the regulator/clk +handlers are used after released in mtk_cpu_dvfs_info_release(). + +To prevent the usage after regulator_put()/clk_put(), the regulator/clk +handlers are addressed in a way of "Free the Last Thing Style". + +Signed-off-by: Jia-Wei Chang +Fixes: 4b9ceb757bbb ("cpufreq: mediatek: Enable clocks and regulators") +Suggested-by: AngeloGioacchino Del Regno +Suggested-by: Dan Carpenter +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 62 +++++++++++++++--------------- + 1 file changed, 30 insertions(+), 32 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -420,7 +420,7 @@ static int mtk_cpu_dvfs_info_init(struct + ret = PTR_ERR(info->inter_clk); + dev_err_probe(cpu_dev, ret, + "cpu%d: failed to get intermediate clk\n", cpu); +- goto out_free_resources; ++ goto out_free_mux_clock; + } + + info->proc_reg = regulator_get_optional(cpu_dev, "proc"); +@@ -428,13 +428,13 @@ static int mtk_cpu_dvfs_info_init(struct + ret = PTR_ERR(info->proc_reg); + dev_err_probe(cpu_dev, ret, + "cpu%d: failed to get proc regulator\n", cpu); +- goto out_free_resources; ++ goto out_free_inter_clock; + } + + ret = regulator_enable(info->proc_reg); + if (ret) { + dev_warn(cpu_dev, "cpu%d: failed to enable vproc\n", cpu); +- goto out_free_resources; ++ goto out_free_proc_reg; + } + + /* Both presence and absence of sram regulator are valid cases. */ +@@ -442,14 +442,14 @@ static int mtk_cpu_dvfs_info_init(struct + if (IS_ERR(info->sram_reg)) { + ret = PTR_ERR(info->sram_reg); + if (ret == -EPROBE_DEFER) +- goto out_free_resources; ++ goto out_disable_proc_reg; + + info->sram_reg = NULL; + } else { + ret = regulator_enable(info->sram_reg); + if (ret) { + dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu); +- goto out_free_resources; ++ goto out_free_sram_reg; + } + } + +@@ -458,13 +458,13 @@ static int mtk_cpu_dvfs_info_init(struct + if (ret) { + dev_err(cpu_dev, + "cpu%d: failed to get OPP-sharing information\n", cpu); +- goto out_free_resources; ++ goto out_disable_sram_reg; + } + + ret = dev_pm_opp_of_cpumask_add_table(&info->cpus); + if (ret) { + dev_warn(cpu_dev, "cpu%d: no OPP table\n", cpu); +- goto out_free_resources; ++ goto out_disable_sram_reg; + } + + ret = clk_prepare_enable(info->cpu_clk); +@@ -533,43 +533,41 @@ out_disable_mux_clock: + out_free_opp_table: + dev_pm_opp_of_cpumask_remove_table(&info->cpus); + +-out_free_resources: +- if (regulator_is_enabled(info->proc_reg)) +- regulator_disable(info->proc_reg); +- if (info->sram_reg && regulator_is_enabled(info->sram_reg)) ++out_disable_sram_reg: ++ if (info->sram_reg) + regulator_disable(info->sram_reg); + +- if (!IS_ERR(info->proc_reg)) +- regulator_put(info->proc_reg); +- if (!IS_ERR(info->sram_reg)) ++out_free_sram_reg: ++ if (info->sram_reg) + regulator_put(info->sram_reg); +- if (!IS_ERR(info->cpu_clk)) +- clk_put(info->cpu_clk); +- if (!IS_ERR(info->inter_clk)) +- clk_put(info->inter_clk); ++ ++out_disable_proc_reg: ++ regulator_disable(info->proc_reg); ++ ++out_free_proc_reg: ++ regulator_put(info->proc_reg); ++ ++out_free_inter_clock: ++ clk_put(info->inter_clk); ++ ++out_free_mux_clock: ++ clk_put(info->cpu_clk); + + return ret; + } + + static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) + { +- if (!IS_ERR(info->proc_reg)) { +- regulator_disable(info->proc_reg); +- regulator_put(info->proc_reg); +- } +- if (!IS_ERR(info->sram_reg)) { ++ regulator_disable(info->proc_reg); ++ regulator_put(info->proc_reg); ++ if (info->sram_reg) { + regulator_disable(info->sram_reg); + regulator_put(info->sram_reg); + } +- if (!IS_ERR(info->cpu_clk)) { +- clk_disable_unprepare(info->cpu_clk); +- clk_put(info->cpu_clk); +- } +- if (!IS_ERR(info->inter_clk)) { +- clk_disable_unprepare(info->inter_clk); +- clk_put(info->inter_clk); +- } +- ++ clk_disable_unprepare(info->cpu_clk); ++ clk_put(info->cpu_clk); ++ clk_disable_unprepare(info->inter_clk); ++ clk_put(info->inter_clk); + dev_pm_opp_of_cpumask_remove_table(&info->cpus); + dev_pm_opp_unregister_notifier(info->cpu_dev, &info->opp_nb); + } diff --git a/target/linux/mediatek/patches-5.15/350-19-cpufreq-mediatek-raise-proc-sram-max-voltage-for-MT8.patch b/target/linux/mediatek/patches-5.15/350-19-cpufreq-mediatek-raise-proc-sram-max-voltage-for-MT8.patch new file mode 100644 index 00000000000..2b7d229f1c5 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-19-cpufreq-mediatek-raise-proc-sram-max-voltage-for-MT8.patch @@ -0,0 +1,55 @@ +From 24bc42a2d44cb821818717a5c607270921ec5d20 Mon Sep 17 00:00:00 2001 +From: Jia-Wei Chang +Date: Fri, 24 Mar 2023 18:11:29 +0800 +Subject: [PATCH 19/21] cpufreq: mediatek: raise proc/sram max voltage for + MT8516 + +Since the upper boundary of proc/sram voltage of MT8516 is 1300 mV, +which is greater than the value of MT2701 1150 mV, we fix it by adding +the corresponding platform data and specify proc/sram_max_volt to +support MT8516. + +Signed-off-by: Jia-Wei Chang +Fixes: ead858bd128d ("cpufreq: mediatek: Move voltage limits to platform data") +Fixes: 6a17b3876bc8 ("cpufreq: mediatek: Refine mtk_cpufreq_voltage_tracking()") +Reported-by: Nick Hainke +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -711,20 +711,29 @@ static const struct mtk_cpufreq_platform + .ccifreq_supported = true, + }; + ++static const struct mtk_cpufreq_platform_data mt8516_platform_data = { ++ .min_volt_shift = 100000, ++ .max_volt_shift = 200000, ++ .proc_max_volt = 1310000, ++ .sram_min_volt = 0, ++ .sram_max_volt = 1310000, ++ .ccifreq_supported = false, ++}; ++ + /* List of machines supported by this driver */ + static const struct of_device_id mtk_cpufreq_machines[] __initconst = { + { .compatible = "mediatek,mt2701", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt2712", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt7622", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt7623", .data = &mt2701_platform_data }, +- { .compatible = "mediatek,mt8167", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8167", .data = &mt8516_platform_data }, + { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8176", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8183", .data = &mt8183_platform_data }, + { .compatible = "mediatek,mt8186", .data = &mt8186_platform_data }, + { .compatible = "mediatek,mt8365", .data = &mt2701_platform_data }, +- { .compatible = "mediatek,mt8516", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt8516", .data = &mt8516_platform_data }, + { } + }; + MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines); diff --git a/target/linux/mediatek/patches-5.15/350-20-cpufreq-mediatek-Raise-proc-and-sram-max-voltage-for.patch b/target/linux/mediatek/patches-5.15/350-20-cpufreq-mediatek-Raise-proc-and-sram-max-voltage-for.patch new file mode 100644 index 00000000000..2de8eb6394c --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-20-cpufreq-mediatek-Raise-proc-and-sram-max-voltage-for.patch @@ -0,0 +1,58 @@ +From fe6ef09358dc0cfead9d383a8676fbe7a40fcef7 Mon Sep 17 00:00:00 2001 +From: AngeloGioacchino Del Regno +Date: Fri, 24 Mar 2023 18:11:30 +0800 +Subject: [PATCH 20/21] cpufreq: mediatek: Raise proc and sram max voltage for + MT7622/7623 + +During the addition of SRAM voltage tracking for CCI scaling, this +driver got some voltage limits set for the vtrack algorithm: these +were moved to platform data first, then enforced in a later commit +6a17b3876bc8 ("cpufreq: mediatek: Refine mtk_cpufreq_voltage_tracking()") +using these as max values for the regulator_set_voltage() calls. + +In this case, the vsram/vproc constraints for MT7622 and MT7623 +were supposed to be the same as MT2701 (and a number of other SoCs), +but that turned out to be a mistake because the aforementioned two +SoCs' maximum voltage for both VPROC and VPROC_SRAM is 1.36V. + +Fix that by adding new platform data for MT7622/7623 declaring the +right {proc,sram}_max_volt parameter. + +Fixes: ead858bd128d ("cpufreq: mediatek: Move voltage limits to platform data") +Fixes: 6a17b3876bc8 ("cpufreq: mediatek: Refine mtk_cpufreq_voltage_tracking()") +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Jia-Wei Chang +Signed-off-by: Viresh Kumar +--- + drivers/cpufreq/mediatek-cpufreq.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -693,6 +693,15 @@ static const struct mtk_cpufreq_platform + .ccifreq_supported = false, + }; + ++static const struct mtk_cpufreq_platform_data mt7622_platform_data = { ++ .min_volt_shift = 100000, ++ .max_volt_shift = 200000, ++ .proc_max_volt = 1360000, ++ .sram_min_volt = 0, ++ .sram_max_volt = 1360000, ++ .ccifreq_supported = false, ++}; ++ + static const struct mtk_cpufreq_platform_data mt8183_platform_data = { + .min_volt_shift = 100000, + .max_volt_shift = 200000, +@@ -724,8 +733,8 @@ static const struct mtk_cpufreq_platform + static const struct of_device_id mtk_cpufreq_machines[] __initconst = { + { .compatible = "mediatek,mt2701", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt2712", .data = &mt2701_platform_data }, +- { .compatible = "mediatek,mt7622", .data = &mt2701_platform_data }, +- { .compatible = "mediatek,mt7623", .data = &mt2701_platform_data }, ++ { .compatible = "mediatek,mt7622", .data = &mt7622_platform_data }, ++ { .compatible = "mediatek,mt7623", .data = &mt7622_platform_data }, + { .compatible = "mediatek,mt8167", .data = &mt8516_platform_data }, + { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data }, diff --git a/target/linux/mediatek/patches-5.15/350-21-cpufreq-mediatek-Add-support-for-MT7988.patch b/target/linux/mediatek/patches-5.15/350-21-cpufreq-mediatek-Add-support-for-MT7988.patch new file mode 100644 index 00000000000..6acd3d607fb --- /dev/null +++ b/target/linux/mediatek/patches-5.15/350-21-cpufreq-mediatek-Add-support-for-MT7988.patch @@ -0,0 +1,41 @@ +From 4983a1517e7ddbc6f53fc07607e4ebeb51412843 Mon Sep 17 00:00:00 2001 +From: Sam Shih +Date: Tue, 28 Feb 2023 19:59:22 +0800 +Subject: [PATCH 21/21] cpufreq: mediatek: Add support for MT7988 + +This add cpufreq support for mediatek MT7988 SoC. + +The platform data of MT7988 is different from previous MediaTek SoCs, +so we add a new compatible and platform data for it. + +Signed-off-by: Sam Shih +--- + drivers/cpufreq/mediatek-cpufreq.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -702,6 +702,15 @@ static const struct mtk_cpufreq_platform + .ccifreq_supported = false, + }; + ++static const struct mtk_cpufreq_platform_data mt7988_platform_data = { ++ .min_volt_shift = 100000, ++ .max_volt_shift = 200000, ++ .proc_max_volt = 900000, ++ .sram_min_volt = 0, ++ .sram_max_volt = 1150000, ++ .ccifreq_supported = true, ++}; ++ + static const struct mtk_cpufreq_platform_data mt8183_platform_data = { + .min_volt_shift = 100000, + .max_volt_shift = 200000, +@@ -735,6 +744,7 @@ static const struct of_device_id mtk_cpu + { .compatible = "mediatek,mt2712", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt7622", .data = &mt7622_platform_data }, + { .compatible = "mediatek,mt7623", .data = &mt7622_platform_data }, ++ { .compatible = "mediatek,mt7988", .data = &mt7988_platform_data }, + { .compatible = "mediatek,mt8167", .data = &mt8516_platform_data }, + { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data }, + { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data }, diff --git a/target/linux/mediatek/patches-5.15/351-cpufreq-mediatek-don-t-request-unsupported-voltage.patch b/target/linux/mediatek/patches-5.15/351-cpufreq-mediatek-don-t-request-unsupported-voltage.patch new file mode 100644 index 00000000000..a7a4bd8ea2b --- /dev/null +++ b/target/linux/mediatek/patches-5.15/351-cpufreq-mediatek-don-t-request-unsupported-voltage.patch @@ -0,0 +1,29 @@ +From 20aad28ba5d62f1618408c264384d0b2ad7417db Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Mon, 22 May 2023 23:25:48 +0100 +Subject: [PATCH] cpufreq: mediatek: don't request unsupported voltage + +PMICs on MT7622 and MT7623 boards only support up to 1350000uV despite +the SoC's processor and SRAM voltage can be up to 1360000uV. As a +work-around specify max. processor and SRAM voltage as 1350000uV to +avoid requesting an unsupported voltage from the regulator. + +Signed-off-by: Daniel Golle +--- + drivers/cpufreq/mediatek-cpufreq.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/cpufreq/mediatek-cpufreq.c ++++ b/drivers/cpufreq/mediatek-cpufreq.c +@@ -696,9 +696,9 @@ static const struct mtk_cpufreq_platform + static const struct mtk_cpufreq_platform_data mt7622_platform_data = { + .min_volt_shift = 100000, + .max_volt_shift = 200000, +- .proc_max_volt = 1360000, ++ .proc_max_volt = 1350000, + .sram_min_volt = 0, +- .sram_max_volt = 1360000, ++ .sram_max_volt = 1350000, + .ccifreq_supported = false, + }; + diff --git a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch index 4187557b781..04ca80c213d 100644 --- a/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch +++ b/target/linux/mediatek/patches-5.15/703-v5.17-net-ethernet-mtk_eth_soc-implement-Clause-45-MDIO-ac.patch @@ -20,7 +20,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -231,13 +231,35 @@ static int _mtk_mdio_write(struct mtk_et +@@ -323,13 +323,35 @@ static int _mtk_mdio_write(struct mtk_et if (ret < 0) return ret; @@ -63,7 +63,7 @@ Signed-off-by: David S. Miller ret = mtk_mdio_busy_wait(eth); if (ret < 0) -@@ -254,12 +276,33 @@ static int _mtk_mdio_read(struct mtk_eth +@@ -346,12 +368,33 @@ static int _mtk_mdio_read(struct mtk_eth if (ret < 0) return ret; @@ -103,7 +103,7 @@ Signed-off-by: David S. Miller ret = mtk_mdio_busy_wait(eth); if (ret < 0) -@@ -729,6 +772,7 @@ static int mtk_mdio_init(struct mtk_eth +@@ -1018,6 +1061,7 @@ static int mtk_mdio_init(struct mtk_eth eth->mii_bus->name = "mdio"; eth->mii_bus->read = mtk_mdio_read; eth->mii_bus->write = mtk_mdio_write; @@ -113,7 +113,7 @@ Signed-off-by: David S. Miller --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h -@@ -376,9 +376,12 @@ +@@ -382,9 +382,12 @@ #define PHY_IAC_ADDR_MASK GENMASK(24, 20) #define PHY_IAC_ADDR(x) FIELD_PREP(PHY_IAC_ADDR_MASK, (x)) #define PHY_IAC_CMD_MASK GENMASK(19, 18) diff --git a/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch b/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch index 4e462881c2a..b8d1a606191 100644 --- a/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch +++ b/target/linux/mediatek/patches-5.15/730-net-phy-add-driver-for-MediaTek-SoC-built-in-GE-PHYs.patch @@ -1,23 +1,27 @@ -From a6f143af419bfc3f52d82e88ac033d9833e720af Mon Sep 17 00:00:00 2001 +From 60ed9eb9605656c19ca402b7bd3f47552e901601 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 13 Feb 2023 02:33:14 +0000 Subject: [PATCH] net: phy: add driver for MediaTek SoC built-in GE PHYs Some of MediaTek's Filogic SoCs come with built-in gigabit Ethernet PHYs which require calibration data from the SoC's efuse. -Add support for these PHYs to the mediatek-ge driver if built for -MediaTek's ARM64 SoCs. +Despite the similar design the driver doesn't share any code with the +existing mediatek-ge.c, so add support for these PHYs by introducing a +new driver for only MediaTek's ARM64 SoCs. Signed-off-by: Daniel Golle --- - MAINTAINERS | 8 + - drivers/net/phy/Kconfig | 12 + - drivers/net/phy/mediatek-ge.c | 1351 +++++++++++++++++++++++++++++++++ - 3 files changed, 1371 insertions(+) + MAINTAINERS | 9 + + drivers/net/phy/Kconfig | 12 + + drivers/net/phy/Makefile | 1 + + drivers/net/phy/mediatek-ge-soc.c | 1263 +++++++++++++++++++++++++++++ + drivers/net/phy/mediatek-ge.c | 3 +- + 5 files changed, 1287 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/phy/mediatek-ge-soc.c --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -11797,6 +11797,14 @@ S: Maintained +@@ -11797,6 +11797,15 @@ S: Maintained F: drivers/net/pcs/pcs-mtk-lynxi.c F: include/linux/pcs/pcs-mtk-lynxi.h @@ -27,6 +31,7 @@ Signed-off-by: Daniel Golle +M: SkyLake Huang +L: netdev@vger.kernel.org +S: Maintained ++F: drivers/net/phy/mediatek-ge-soc.c +F: drivers/net/phy/mediatek-ge.c + MEDIATEK I2C CONTROLLER DRIVER @@ -38,9 +43,9 @@ Signed-off-by: Daniel Golle help Supports the MediaTek Gigabit Ethernet PHYs. -+config MEDIATEK_GE_PHY_SOC -+ bool "MediaTek SoC Ethernet PHYs" -+ depends on (ARM64 && ARCH_MEDIATEK && MEDIATEK_GE_PHY) || COMPILE_TEST ++config MEDIATEK_GE_SOC_PHY ++ tristate "MediaTek SoC Ethernet PHYs" ++ depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST + select NVMEM_MTK_EFUSE + help + Supports MediaTek SoC built-in Gigabit Ethernet PHYs. @@ -53,1391 +58,25 @@ Signed-off-by: Daniel Golle config MICREL_PHY tristate "Micrel PHYs" help +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -81,6 +81,7 @@ obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o + obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o + obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o ++obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o + obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o + obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o + obj-$(CONFIG_MICREL_PHY) += micrel.o --- a/drivers/net/phy/mediatek-ge.c +++ b/drivers/net/phy/mediatek-ge.c -@@ -2,6 +2,9 @@ - #include - #include - #include -+#include -+#include -+#include - #include - - #define MTK_EXT_PAGE_ACCESS 0x1f -@@ -12,6 +15,275 @@ - #define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 - #define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 - -+#define ANALOG_INTERNAL_OPERATION_MAX_US (20) -+#define ZCAL_CTRL_MIN (0) -+#define ZCAL_CTRL_MAX (63) -+#define TXRESERVE_MIN (0) -+#define TXRESERVE_MAX (7) -+ -+#define MTK_PHY_ANARG_RG (0x10) -+#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8) -+ -+/* Registers on MDIO_MMD_VEND1 */ -+enum { -+ MTK_PHY_MIDDLE_LEVEL_SHAPPER_0TO1 = 0, -+ MTK_PHY_1st_OVERSHOOT_LEVEL_0TO1, -+ MTK_PHY_2nd_OVERSHOOT_LEVEL_0TO1, -+ MTK_PHY_MIDDLE_LEVEL_SHAPPER_1TO0, -+ MTK_PHY_1st_OVERSHOOT_LEVEL_1TO0, -+ MTK_PHY_2nd_OVERSHOOT_LEVEL_1TO0, -+ MTK_PHY_MIDDLE_LEVEL_SHAPPER_0TON1, /* N means negative */ -+ MTK_PHY_1st_OVERSHOOT_LEVEL_0TON1, -+ MTK_PHY_2nd_OVERSHOOT_LEVEL_0TON1, -+ MTK_PHY_MIDDLE_LEVEL_SHAPPER_N1TO0, -+ MTK_PHY_1st_OVERSHOOT_LEVEL_N1TO0, -+ MTK_PHY_2nd_OVERSHOOT_LEVEL_N1TO0, -+ MTK_PHY_TX_MLT3_END, -+}; -+ -+#define MTK_PHY_TXVLD_DA_RG (0x12) -+#define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10) -+#define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 (0x16) -+#define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10) -+#define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 (0x17) -+#define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8) -+#define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 (0x18) -+#define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8) -+#define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 (0x19) -+#define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8) -+#define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 (0x20) -+#define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8) -+#define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 (0x21) -+#define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8) -+#define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 (0x22) -+#define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8) -+#define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_TANA_CAL_MODE (0xc1) -+#define MTK_PHY_TANA_CAL_MODE_SHIFT (8) -+ -+#define MTK_PHY_RXADC_CTRL_RG7 (0xc6) -+#define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) -+ -+#define MTK_PHY_RXADC_CTRL_RG9 (0xc8) -+#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12) -+#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8) -+#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4) -+#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0) -+ -+#define MTK_PHY_LDO_OUTPUT_V (0xd7) -+ -+#define MTK_PHY_RG_ANA_CAL_RG0 (0xdb) -+#define MTK_PHY_RG_CAL_CKINV BIT(12) -+#define MTK_PHY_RG_ANA_CALEN BIT(8) -+#define MTK_PHY_RG_REXT_CALEN BIT(4) -+#define MTK_PHY_RG_ZCALEN_A BIT(0) -+ -+#define MTK_PHY_RG_ANA_CAL_RG1 (0xdc) -+#define MTK_PHY_RG_ZCALEN_B BIT(12) -+#define MTK_PHY_RG_ZCALEN_C BIT(8) -+#define MTK_PHY_RG_ZCALEN_D BIT(4) -+#define MTK_PHY_RG_TXVOS_CALEN BIT(0) -+ -+#define MTK_PHY_RG_ANA_CAL_RG2 (0xdd) -+#define MTK_PHY_RG_TXG_CALEN_A BIT(12) -+#define MTK_PHY_RG_TXG_CALEN_B BIT(8) -+#define MTK_PHY_RG_TXG_CALEN_C BIT(4) -+#define MTK_PHY_RG_TXG_CALEN_D BIT(0) -+ -+#define MTK_PHY_RG_ANA_CAL_RG5 (0xe0) -+#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8) -+#define MTK_PHY_RG_ZCAL_CTRL_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_RG_TX_FILTER (0xfe) -+ -+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B (0x172) -+#define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8) -+#define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0) -+ -+#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D (0x173) -+#define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8) -+#define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) -+ -+#define MTK_PHY_RG_AD_CAL_COMP (0x17a) -+#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) -+ -+#define MTK_PHY_RG_AD_CAL_CLK (0x17b) -+#define MTK_PHY_DA_CAL_CLK BIT(0) -+ -+#define MTK_PHY_RG_AD_CALIN (0x17c) -+#define MTK_PHY_DA_CALIN_FLAG BIT(0) -+ -+#define MTK_PHY_RG_DASN_DAC_IN0_A (0x17d) -+#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0) -+ -+#define MTK_PHY_RG_DASN_DAC_IN0_B (0x17e) -+#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0) -+ -+#define MTK_PHY_RG_DASN_DAC_IN0_C (0x17f) -+#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0) -+ -+#define MTK_PHY_RG_DASN_DAC_IN0_D (0x180) -+#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0) -+ -+#define MTK_PHY_RG_DASN_DAC_IN1_A (0x181) -+#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0) -+ -+#define MTK_PHY_RG_DASN_DAC_IN1_B (0x182) -+#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0) -+ -+#define MTK_PHY_RG_DASN_DAC_IN1_C (0x183) -+#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0) -+ -+#define MTK_PHY_RG_DASN_DAC_IN1_D (0x180) -+#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0) -+ -+#define MTK_PHY_RG_LP_IIR2_K1_L (0x22a) -+#define MTK_PHY_RG_LP_IIR2_K1_U (0x22b) -+#define MTK_PHY_RG_LP_IIR2_K2_L (0x22c) -+#define MTK_PHY_RG_LP_IIR2_K2_U (0x22d) -+#define MTK_PHY_RG_LP_IIR2_K3_L (0x22e) -+#define MTK_PHY_RG_LP_IIR2_K3_U (0x22f) -+#define MTK_PHY_RG_LP_IIR2_K4_L (0x230) -+#define MTK_PHY_RG_LP_IIR2_K4_U (0x231) -+#define MTK_PHY_RG_LP_IIR2_K5_L (0x232) -+#define MTK_PHY_RG_LP_IIR2_K5_U (0x233) -+ -+#define MTK_PHY_RG_DEV1E_REG234 (0x234) -+#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0) -+#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4) -+ -+#define MTK_PHY_RG_LPF_CNT_VAL (0x235) -+ -+#define MTK_PHY_RG_DEV1E_REG27C (0x27c) -+#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8) -+#define MTK_PHY_RG_DEV1E_REG27D (0x27d) -+#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0) -+ -+#define MTK_PHY_LDO_PUMP_EN_PAIRAB (0x502) -+#define MTK_PHY_LDO_PUMP_EN_PAIRCD (0x503) -+ -+#define MTK_PHY_DA_TX_R50_PAIR_A (0x53d) -+#define MTK_PHY_DA_TX_R50_PAIR_B (0x53e) -+#define MTK_PHY_DA_TX_R50_PAIR_C (0x53f) -+#define MTK_PHY_DA_TX_R50_PAIR_D (0x540) -+ -+/* Registers on MDIO_MMD_VEND2 */ -+#define MTK_PHY_LED0_ON_CTRL (0x24) -+#define MTK_PHY_LED0_ON_MASK GENMASK(6, 0) -+#define MTK_PHY_LED0_ON_LINK1000 BIT(0) -+#define MTK_PHY_LED0_ON_LINK100 BIT(1) -+#define MTK_PHY_LED0_ON_LINK10 BIT(2) -+#define MTK_PHY_LED0_ON_LINKDOWN BIT(3) -+#define MTK_PHY_LED0_ON_FDX BIT(4) /* Full duplex */ -+#define MTK_PHY_LED0_ON_HDX BIT(5) /* Half duplex */ -+#define MTK_PHY_LED0_FORCE_ON BIT(6) -+#define MTK_PHY_LED0_POLARITY BIT(14) -+#define MTK_PHY_LED0_ENABLE BIT(15) -+ -+#define MTK_PHY_LED0_BLINK_CTRL (0x25) -+#define MTK_PHY_LED0_1000TX BIT(0) -+#define MTK_PHY_LED0_1000RX BIT(1) -+#define MTK_PHY_LED0_100TX BIT(2) -+#define MTK_PHY_LED0_100RX BIT(3) -+#define MTK_PHY_LED0_10TX BIT(4) -+#define MTK_PHY_LED0_10RX BIT(5) -+#define MTK_PHY_LED0_COLLISION BIT(6) -+#define MTK_PHY_LED0_RX_CRC_ERR BIT(7) -+#define MTK_PHY_LED0_RX_IDLE_ERR BIT(8) -+#define MTK_PHY_LED0_FORCE_BLINK BIT(9) -+ -+#define MTK_PHY_ANA_TEST_BUS_CTRL_RG (0x100) -+#define MTK_PHY_ANA_TEST_MODE_MASK GENMASK(15, 8) -+ -+#define MTK_PHY_RG_DASN_TXT_DMY2 (0x110) -+#define MTK_PHY_TST_DMY2_MASK GENMASK(5, 0) -+ -+#define MTK_PHY_RG_BG_RASEL (0x115) -+#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0) -+ -+/* These macro privides efuse parsing for internal phy. */ -+#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0)) -+#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0)) -+#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0)) -+#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0)) -+#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0)) -+ -+#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0)) -+#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0)) -+#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0)) -+#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0)) -+#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0)) -+ -+#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0)) -+#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0)) -+#define EFS_DA_TX_R50_A_10M(x) (((x) >> 12) & GENMASK(5, 0)) -+#define EFS_DA_TX_R50_B_10M(x) (((x) >> 18) & GENMASK(5, 0)) -+ -+#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0)) -+#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0)) -+ -+enum { -+ NO_PAIR, -+ PAIR_A, -+ PAIR_B, -+ PAIR_C, -+ PAIR_D, -+}; -+ -+enum { -+ GPHY_PORT0, -+ GPHY_PORT1, -+ GPHY_PORT2, -+ GPHY_PORT3, -+}; -+ -+enum calibration_mode { -+ EFUSE_K, -+ SW_K -+}; -+ -+enum CAL_ITEM { -+ REXT, -+ TX_OFFSET, -+ TX_AMP, -+ TX_R50, -+ TX_VCM -+}; -+ -+enum CAL_MODE { -+ SW_EFUSE_M, -+ EFUSE_M, -+ SW_M -+}; -+ -+const u8 mt798x_zcal_to_r50[64] = { -+ 7, 8, 9, 9, 10, 10, 11, 11, -+ 12, 13, 13, 14, 14, 15, 16, 16, -+ 17, 18, 18, 19, 20, 21, 21, 22, -+ 23, 24, 24, 25, 26, 27, 28, 29, -+ 30, 31, 32, 33, 34, 35, 36, 37, -+ 38, 40, 41, 42, 43, 45, 46, 48, -+ 49, 51, 52, 54, 55, 57, 59, 61, -+ 62, 63, 63, 63, 63, 63, 63, 63 -+}; -+ -+const char pair[4] = {'A', 'B', 'C', 'D'}; -+ - static int mtk_gephy_read_page(struct phy_device *phydev) - { - return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); -@@ -102,6 +374,1059 @@ static int mt7531_phy_config_init(struct - return 0; - } - -+#ifdef CONFIG_MEDIATEK_GE_PHY_SOC -+/* One calibration cycle consists of: -+ * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high -+ * until AD_CAL_COMP is ready to output calibration result. -+ * 2.Wait until DA_CAL_CLK is available. -+ * 3.Fetch AD_CAL_COMP_OUT. -+ */ -+static int cal_cycle(struct phy_device *phydev, int devad, -+ u32 regnum, u16 mask, u16 cal_val) -+{ -+ unsigned long timeout; -+ int reg_val; -+ int ret; -+ -+ phy_modify_mmd(phydev, devad, regnum, -+ mask, cal_val); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, -+ MTK_PHY_DA_CALIN_FLAG); -+ -+ timeout = jiffies + usecs_to_jiffies(ANALOG_INTERNAL_OPERATION_MAX_US); -+ do { -+ reg_val = phy_read_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_AD_CAL_CLK); -+ } while (time_before(jiffies, timeout) && !(reg_val & BIT(0))); -+ -+ if (!(reg_val & BIT(0))) { -+ dev_err(&phydev->mdio.dev, "Calibration cycle timeout\n"); -+ return -ETIMEDOUT; -+ } -+ -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, -+ MTK_PHY_DA_CALIN_FLAG); -+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >> -+ MTK_PHY_AD_CAL_COMP_OUT_SHIFT; -+ dev_dbg(&phydev->mdio.dev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); -+ -+ return ret; -+} -+ -+static int rext_fill_result(struct phy_device *phydev, u16 *buf) -+{ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL, -+ MTK_PHY_RG_BG_RASEL_MASK, buf[1]); -+ -+ return 0; -+} -+ -+static int rext_cal_efuse(struct phy_device *phydev, u32 *buf) -+{ -+ u16 rext_cal_val[2]; -+ -+ rext_cal_val[0] = EFS_RG_REXT_TRIM(buf[3]); -+ rext_cal_val[1] = EFS_RG_BG_RASEL(buf[3]); -+ rext_fill_result(phydev, rext_cal_val); -+ -+ return 0; -+} -+ -+static int rext_cal_sw(struct phy_device *phydev) -+{ -+ u8 rg_zcal_ctrl_def; -+ u8 zcal_lower, zcal_upper, rg_zcal_ctrl; -+ u8 lower_ret, upper_ret; -+ u16 rext_cal_val[2]; -+ int ret; -+ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, -+ MTK_PHY_ANA_TEST_MODE_MASK, MTK_PHY_TANA_CAL_MODE << 8); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, -+ MTK_PHY_RG_TXVOS_CALEN); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN | -+ MTK_PHY_RG_REXT_CALEN); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DASN_TXT_DMY2, -+ MTK_PHY_TST_DMY2_MASK, 0x1); -+ -+ rg_zcal_ctrl_def = phy_read_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG5) & -+ MTK_PHY_RG_ZCAL_CTRL_MASK; -+ zcal_lower = ZCAL_CTRL_MIN; -+ zcal_upper = ZCAL_CTRL_MAX; -+ -+ dev_dbg(&phydev->mdio.dev, "Start REXT SW cal.\n"); -+ while ((zcal_upper - zcal_lower) > 1) { -+ rg_zcal_ctrl = DIV_ROUND_CLOSEST(zcal_lower + zcal_upper, 2); -+ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl); -+ if (ret == 1) { -+ zcal_upper = rg_zcal_ctrl; -+ upper_ret = ret; -+ } else if (ret == 0) { -+ zcal_lower = rg_zcal_ctrl; -+ lower_ret = ret; -+ } else { -+ goto restore; -+ } -+ } -+ -+ if (zcal_lower == ZCAL_CTRL_MIN) { -+ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_lower); -+ ret = lower_ret; -+ } else if (zcal_upper == ZCAL_CTRL_MAX) { -+ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_upper); -+ ret = upper_ret; -+ } -+ if (ret < 0) -+ goto restore; -+ -+ ret = upper_ret - lower_ret; -+ if (ret == 1) { -+ rext_cal_val[0] = zcal_upper; -+ rext_cal_val[1] = zcal_upper >> 3; -+ rext_fill_result(phydev, rext_cal_val); -+ dev_info(&phydev->mdio.dev, "REXT SW cal result: 0x%x\n", -+ zcal_upper); -+ ret = 0; -+ } else { -+ ret = -EINVAL; -+ } -+ -+restore: -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, -+ MTK_PHY_ANA_TEST_BUS_CTRL_RG, -+ MTK_PHY_ANA_TEST_MODE_MASK); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN | -+ MTK_PHY_RG_REXT_CALEN); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DASN_TXT_DMY2, -+ MTK_PHY_TST_DMY2_MASK); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl_def); -+ -+ return ret; -+} -+ -+static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf) -+{ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, -+ MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, -+ MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, -+ MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, -+ MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]); -+ -+ return 0; -+} -+ -+static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) -+{ -+ u16 tx_offset_cal_val[4]; -+ -+ tx_offset_cal_val[0] = EFS_DA_TX_AMP_OFFSET_A(buf[0]); -+ tx_offset_cal_val[1] = EFS_DA_TX_AMP_OFFSET_B(buf[1]); -+ tx_offset_cal_val[2] = EFS_DA_TX_AMP_OFFSET_C(buf[1]); -+ tx_offset_cal_val[3] = EFS_DA_TX_AMP_OFFSET_D(buf[1]); -+ -+ tx_offset_fill_result(phydev, tx_offset_cal_val); -+ -+ return 0; -+} -+ -+static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) -+{ -+ int i; -+ int bias[16] = {0}; -+ const int vals_9461[16] = { 7, 1, 4, 7, -+ 7, 1, 4, 7, -+ 7, 1, 4, 7, -+ 7, 1, 4, 7 }; -+ const int vals_9481[16] = { 10, 6, 6, 10, -+ 10, 6, 6, 10, -+ 10, 6, 6, 10, -+ 10, 6, 6, 10 }; -+ -+ switch (phydev->drv->phy_id) { -+ case 0x03a29461: -+ /* We add some calibration to efuse values -+ * due to board level influence. -+ * GBE: +7, TBT: +1, HBT: +4, TST: +7 -+ */ -+ memcpy(bias, (const void *)vals_9461, sizeof(bias)); -+ for (i = 0; i <= 12; i += 4) { -+ if (likely(buf[i >> 2] + bias[i] >= 32)) { -+ bias[i] -= 13; -+ } else { -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, -+ 0x5c, 0x7 << i, bias[i] << i); -+ bias[i + 1] += 13; -+ bias[i + 2] += 13; -+ bias[i + 3] += 13; -+ } -+ } -+ break; -+ case 0x03a29481: -+ memcpy(bias, (const void *)vals_9481, sizeof(bias)); -+ break; -+ default: -+ break; -+ } -+ -+ /* Prevent overflow */ -+ for (i = 0; i < 12; i++) { -+ if (buf[i >> 2] + bias[i] > 63) { -+ buf[i >> 2] = 63; -+ bias[i] = 0; -+ } else if (buf[i >> 2] + bias[i] < 0) { -+ /* Bias caused by board design may change in the future. -+ * So check negative cases, too. -+ */ -+ buf[i >> 2] = 0; -+ bias[i] = 0; -+ } -+ } -+ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, -+ MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, -+ MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, -+ MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, -+ MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]); -+ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, -+ MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, -+ MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, -+ MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, -+ MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]); -+ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, -+ MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, -+ MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, -+ MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, -+ MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]); -+ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, -+ MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, -+ MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, -+ MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, -+ MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]); -+ -+ return 0; -+} -+ -+static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf) -+{ -+ u16 tx_amp_cal_val[4]; -+ -+ tx_amp_cal_val[0] = EFS_DA_TX_I2MPB_A(buf[0]); -+ tx_amp_cal_val[1] = EFS_DA_TX_I2MPB_B(buf[0]); -+ tx_amp_cal_val[2] = EFS_DA_TX_I2MPB_C(buf[0]); -+ tx_amp_cal_val[3] = EFS_DA_TX_I2MPB_D(buf[0]); -+ tx_amp_fill_result(phydev, tx_amp_cal_val); -+ -+ return 0; -+} -+ -+static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val, -+ u8 txg_calen_x) -+{ -+ int bias = 0; -+ u16 reg, val; -+ -+ switch (phydev->drv->phy_id) { -+ case 0x03a29481: -+ { -+ bias = -2; -+ break; -+ } -+ /* 0x03a29461 enters default case */ -+ default: -+ break; -+ } -+ -+ val = clamp_val(bias + tx_r50_cal_val, 0, 63); -+ -+ switch (txg_calen_x) { -+ case PAIR_A: -+ reg = MTK_PHY_DA_TX_R50_PAIR_A; -+ break; -+ case PAIR_B: -+ reg = MTK_PHY_DA_TX_R50_PAIR_B; -+ break; -+ case PAIR_C: -+ reg = MTK_PHY_DA_TX_R50_PAIR_C; -+ break; -+ case PAIR_D: -+ reg = MTK_PHY_DA_TX_R50_PAIR_D; -+ break; -+ } -+ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8); -+ -+ return 0; -+} -+ -+static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf, -+ u8 txg_calen_x) -+{ -+ u16 tx_r50_cal_val; -+ -+ switch (txg_calen_x) { -+ case PAIR_A: -+ tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]); -+ break; -+ case PAIR_B: -+ tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]); -+ break; -+ case PAIR_C: -+ tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]); -+ break; -+ case PAIR_D: -+ tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]); -+ break; -+ } -+ tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); -+ -+ return 0; -+} -+ -+static int tx_r50_cal_sw(struct phy_device *phydev, u8 txg_calen_x) -+{ -+ u8 zcal_lower, zcal_upper, rg_zcal_ctrl; -+ u8 lower_ret, upper_ret; -+ u8 rg_zcal_ctrl_def; -+ u16 tx_r50_cal_val; -+ int ret; -+ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, -+ MTK_PHY_ANA_TEST_MODE_MASK, MTK_PHY_TANA_CAL_MODE << 8); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, -+ MTK_PHY_RG_TXVOS_CALEN); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG2, -+ BIT(txg_calen_x * 4)); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DASN_TXT_DMY2, -+ MTK_PHY_TST_DMY2_MASK, 0x1); -+ -+ rg_zcal_ctrl_def = phy_read_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG5) & -+ MTK_PHY_RG_ZCAL_CTRL_MASK; -+ zcal_lower = ZCAL_CTRL_MIN; -+ zcal_upper = ZCAL_CTRL_MAX; -+ -+ dev_dbg(&phydev->mdio.dev, "Start TX-R50 Pair%c SW cal.\n", -+ pair[txg_calen_x]); -+ while ((zcal_upper - zcal_lower) > 1) { -+ rg_zcal_ctrl = DIV_ROUND_CLOSEST(zcal_lower + zcal_upper, 2); -+ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl); -+ if (ret == 1) { -+ zcal_upper = rg_zcal_ctrl; -+ upper_ret = ret; -+ } else if (ret == 0) { -+ zcal_lower = rg_zcal_ctrl; -+ lower_ret = ret; -+ } else { -+ goto restore; -+ } -+ } -+ -+ if (zcal_lower == ZCAL_CTRL_MIN) { -+ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_lower); -+ ret = lower_ret; -+ } else if (zcal_upper == ZCAL_CTRL_MAX) { -+ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_upper); -+ ret = upper_ret; -+ } -+ if (ret < 0) -+ goto restore; -+ -+ ret = upper_ret - lower_ret; -+ if (ret == 1) { -+ tx_r50_cal_val = mt798x_zcal_to_r50[zcal_upper]; -+ tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); -+ dev_info(&phydev->mdio.dev, -+ "TX-R50 Pair%c SW cal result: 0x%x\n", -+ pair[txg_calen_x], zcal_lower); -+ ret = 0; -+ } else { -+ ret = -EINVAL; -+ } -+ -+restore: -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, -+ MTK_PHY_ANA_TEST_MODE_MASK); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG2, -+ BIT(txg_calen_x * 4)); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DASN_TXT_DMY2, -+ MTK_PHY_TST_DMY2_MASK); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, -+ MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl_def); -+ -+ return ret; -+} -+ -+static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) -+{ -+ u8 lower_idx, upper_idx, txreserve_val; -+ u8 lower_ret, upper_ret; -+ int ret; -+ -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_ANA_CALEN); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_CAL_CKINV); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, -+ MTK_PHY_RG_TXVOS_CALEN); -+ -+ switch (rg_txreserve_x) { -+ case PAIR_A: -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_DASN_DAC_IN0_A, -+ MTK_PHY_DASN_DAC_IN0_A_MASK); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_DASN_DAC_IN1_A, -+ MTK_PHY_DASN_DAC_IN1_A_MASK); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_ZCALEN_A); -+ break; -+ case PAIR_B: -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_DASN_DAC_IN0_B, -+ MTK_PHY_DASN_DAC_IN0_B_MASK); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_DASN_DAC_IN1_B, -+ MTK_PHY_DASN_DAC_IN1_B_MASK); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG1, -+ MTK_PHY_RG_ZCALEN_B); -+ break; -+ case PAIR_C: -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_DASN_DAC_IN0_C, -+ MTK_PHY_DASN_DAC_IN0_C_MASK); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_DASN_DAC_IN1_C, -+ MTK_PHY_DASN_DAC_IN1_C_MASK); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG1, -+ MTK_PHY_RG_ZCALEN_C); -+ break; -+ case PAIR_D: -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_DASN_DAC_IN0_D, -+ MTK_PHY_DASN_DAC_IN0_D_MASK); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_DASN_DAC_IN1_D, -+ MTK_PHY_DASN_DAC_IN1_D_MASK); -+ phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RG_ANA_CAL_RG1, -+ MTK_PHY_RG_ZCALEN_D); -+ break; -+ default: -+ ret = -EINVAL; -+ goto restore; -+ } -+ -+ lower_idx = TXRESERVE_MIN; -+ upper_idx = TXRESERVE_MAX; -+ -+ dev_dbg(&phydev->mdio.dev, "Start TX-VCM SW cal.\n"); -+ while ((upper_idx - lower_idx) > 1) { -+ txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2); -+ ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, -+ MTK_PHY_DA_RX_PSBN_TBT_MASK | -+ MTK_PHY_DA_RX_PSBN_HBT_MASK | -+ MTK_PHY_DA_RX_PSBN_GBE_MASK | -+ MTK_PHY_DA_RX_PSBN_LP_MASK, -+ txreserve_val << 12 | txreserve_val << 8 | -+ txreserve_val << 4 | txreserve_val); -+ if (ret == 1) { -+ upper_idx = txreserve_val; -+ upper_ret = ret; -+ } else if (ret == 0) { -+ lower_idx = txreserve_val; -+ lower_ret = ret; -+ } else { -+ goto restore; -+ } -+ } -+ -+ if (lower_idx == TXRESERVE_MIN) { -+ lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RXADC_CTRL_RG9, -+ MTK_PHY_DA_RX_PSBN_TBT_MASK | -+ MTK_PHY_DA_RX_PSBN_HBT_MASK | -+ MTK_PHY_DA_RX_PSBN_GBE_MASK | -+ MTK_PHY_DA_RX_PSBN_LP_MASK, -+ lower_idx << 12 | lower_idx << 8 | -+ lower_idx << 4 | lower_idx); -+ ret = lower_ret; -+ } else if (upper_idx == TXRESERVE_MAX) { -+ upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, -+ MTK_PHY_RXADC_CTRL_RG9, -+ MTK_PHY_DA_RX_PSBN_TBT_MASK | -+ MTK_PHY_DA_RX_PSBN_HBT_MASK | -+ MTK_PHY_DA_RX_PSBN_GBE_MASK | -+ MTK_PHY_DA_RX_PSBN_LP_MASK, -+ upper_idx << 12 | upper_idx << 8 | -+ upper_idx << 4 | upper_idx); -+ ret = upper_ret; -+ } -+ if (ret < 0) -+ goto restore; -+ -+ /* We calibrate TX-VCM in different logic. Check upper index and then -+ * lower index. If this calibration is valid, apply lower index's result. -+ */ -+ ret = upper_ret - lower_ret; -+ if (ret == 1) { -+ ret = 0; -+ /* Make sure we use upper_idx in our calibration system */ -+ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, -+ MTK_PHY_DA_RX_PSBN_TBT_MASK | -+ MTK_PHY_DA_RX_PSBN_HBT_MASK | -+ MTK_PHY_DA_RX_PSBN_GBE_MASK | -+ MTK_PHY_DA_RX_PSBN_LP_MASK, -+ upper_idx << 12 | upper_idx << 8 | -+ upper_idx << 4 | upper_idx); -+ dev_info(&phydev->mdio.dev, "TX-VCM SW cal result: 0x%x\n", -+ upper_idx); -+ } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && -+ lower_ret == 1) { -+ ret = 0; -+ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, -+ MTK_PHY_DA_RX_PSBN_TBT_MASK | -+ MTK_PHY_DA_RX_PSBN_HBT_MASK | -+ MTK_PHY_DA_RX_PSBN_GBE_MASK | -+ MTK_PHY_DA_RX_PSBN_LP_MASK, -+ lower_idx << 12 | lower_idx << 8 | -+ lower_idx << 4 | lower_idx); -+ dev_warn(&phydev->mdio.dev, -+ "TX-VCM SW cal result at low margin 0x%x\n", -+ lower_idx); -+ } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && -+ lower_ret == 0) { -+ ret = 0; -+ dev_warn(&phydev->mdio.dev, -+ "TX-VCM SW cal result at high margin 0x%x\n", -+ upper_idx); -+ } else { -+ ret = -EINVAL; -+ } -+ -+restore: -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_ANA_CALEN); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, -+ MTK_PHY_RG_TXVOS_CALEN); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, -+ MTK_PHY_RG_ZCALEN_A); -+ phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, -+ MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | -+ MTK_PHY_RG_ZCALEN_D); -+ -+ return ret; -+} -+ -+static inline void mt7981_phy_finetune(struct phy_device *phydev) -+{ -+ u32 i; -+ -+ /* 100M eye finetune: -+ * Keep middle level of TX MLT3 shapper as default. -+ * Only change TX MLT3 overshoot level here. -+ */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_0TO1, -+ 0x1ce); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_0TO1, -+ 0x1c1); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_1TO0, -+ 0x20f); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_1TO0, -+ 0x202); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_0TON1, -+ 0x3d0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_0TON1, -+ 0x3c0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_N1TO0, -+ 0x13); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_N1TO0, -+ 0x5); -+ -+ /* TX-AMP finetune: -+ * 100M +4, 1000M +6 to default value. -+ * If efuse values aren't valid, TX-AMP uses the below values. -+ */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, 0x9824); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, -+ 0x9026); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, -+ 0x2624); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, -+ 0x2426); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, -+ 0x2624); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, -+ 0x2426); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, -+ 0x2624); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, -+ 0x2426); -+ -+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); -+ /* EnabRandUpdTrig = 1 */ -+ __phy_write(phydev, 0x11, 0x2f00); -+ __phy_write(phydev, 0x12, 0xe); -+ __phy_write(phydev, 0x10, 0x8fb0); -+ -+ /* SlvDSPreadyTime = 0xc */ -+ __phy_write(phydev, 0x11, 0x671); -+ __phy_write(phydev, 0x12, 0xc); -+ __phy_write(phydev, 0x10, 0x8fae); -+ -+ /* NormMseLoThresh = 85 */ -+ __phy_write(phydev, 0x11, 0x55a0); -+ __phy_write(phydev, 0x12, 0x0); -+ __phy_write(phydev, 0x10, 0x83aa); -+ -+ /* InhibitDisableDfeTail1000 = 1 */ -+ __phy_write(phydev, 0x11, 0x2b); -+ __phy_write(phydev, 0x12, 0x0); -+ __phy_write(phydev, 0x10, 0x8f80); -+ -+ /* SSTr related */ -+ __phy_write(phydev, 0x11, 0xbaef); -+ __phy_write(phydev, 0x12, 0x2e); -+ __phy_write(phydev, 0x10, 0x968c); -+ -+ /* VcoSlicerThreshBitsHigh */ -+ __phy_write(phydev, 0x11, 0x5555); -+ __phy_write(phydev, 0x12, 0x55); -+ __phy_write(phydev, 0x10, 0x8ec0); -+ -+ /* ResetSyncOffset = 6 */ -+ __phy_write(phydev, 0x11, 0x600); -+ __phy_write(phydev, 0x12, 0x0); -+ __phy_write(phydev, 0x10, 0x8fc0); -+ -+ /* VgaDecRate = 1 */ -+ __phy_write(phydev, 0x11, 0x4c2a); -+ __phy_write(phydev, 0x12, 0x3e); -+ __phy_write(phydev, 0x10, 0x8fa4); -+ -+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); -+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, -+ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, -+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); -+ -+ /* rg_tr_lpf_cnt_val = 512 */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); -+ -+ /* IIR2 related */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); -+ -+ /* FFE peaking */ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, -+ MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, -+ MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); -+ -+ /* TX shape */ -+ /* 10/100/1000 TX shaper is enabled by default */ -+ for (i = 0x202; i < 0x230; i += 2) { -+ if (i == 0x20c || i == 0x218 || i == 0x224) -+ continue; -+ phy_write_mmd(phydev, MDIO_MMD_VEND2, i, 0x2219); -+ phy_write_mmd(phydev, MDIO_MMD_VEND2, i + 1, 0x23); -+ } -+} -+ -+static inline void mt7988_phy_finetune(struct phy_device *phydev) -+{ -+ u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182, -+ 0x020d, 0x0206, 0x0384, 0x03d0, -+ 0x03c6, 0x030a, 0x0011, 0x0005 }; -+ int i; -+ -+ for (i = 0; i < MTK_PHY_TX_MLT3_END; i++) -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[i]); -+ -+ /* TCT finetune */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_TX_FILTER, 0x5); -+ -+ /* Disable TX power saving */ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, -+ MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); -+ -+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); -+ /* EnabRandUpdTrig = 1 */ -+ __phy_write(phydev, 0x11, 0x2f00); -+ __phy_write(phydev, 0x12, 0xe); -+ __phy_write(phydev, 0x10, 0x8fb0); -+ -+ /* SlvDSPreadyTime = 0xc */ -+ __phy_write(phydev, 0x11, 0x671); -+ __phy_write(phydev, 0x12, 0xc); -+ __phy_write(phydev, 0x10, 0x8fae); -+ -+ /* NormMseLoThresh = 85 */ -+ __phy_write(phydev, 0x11, 0x55a0); -+ __phy_write(phydev, 0x12, 0x0); -+ __phy_write(phydev, 0x10, 0x83aa); -+ -+ /* InhibitDisableDfeTail1000 = 1 */ -+ __phy_write(phydev, 0x11, 0x2b); -+ __phy_write(phydev, 0x12, 0x0); -+ __phy_write(phydev, 0x10, 0x8f80); -+ -+ /* SSTr related */ -+ __phy_write(phydev, 0x11, 0xbaef); -+ __phy_write(phydev, 0x12, 0x2e); -+ __phy_write(phydev, 0x10, 0x968c); -+ -+ /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, -+ * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 -+ */ -+ __phy_write(phydev, 0x11, 0xd10a); -+ __phy_write(phydev, 0x12, 0x34); -+ __phy_write(phydev, 0x10, 0x8f82); -+ -+ /* VcoSlicerThreshBitsHigh */ -+ __phy_write(phydev, 0x11, 0x5555); -+ __phy_write(phydev, 0x12, 0x55); -+ __phy_write(phydev, 0x10, 0x8ec0); -+ -+ /* ResetSyncOffset = 5 */ -+ __phy_write(phydev, 0x11, 0x500); -+ __phy_write(phydev, 0x12, 0x0); -+ __phy_write(phydev, 0x10, 0x8fc0); -+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); -+ -+ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_2A30); -+ /* TxClkOffset = 2 */ -+ __phy_modify(phydev, MTK_PHY_ANARG_RG, MTK_PHY_TCLKOFFSET_MASK, -+ FIELD_PREP(MTK_PHY_TCLKOFFSET_MASK, 0x2)); -+ phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); -+ -+ /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9*/ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, -+ MTK_PHY_TR_OPEN_LOOP_EN_MASK | MTK_PHY_LPF_X_AVERAGE_MASK, -+ BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); -+ -+ /* rg_tr_lpf_cnt_val = 512 */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); -+ -+ /* IIR2 related */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); -+ -+ /* FFE peaking */ -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, -+ MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); -+ phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, -+ MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); -+ -+ /* TX shape */ -+ /* 10/100/1000 TX shaper is enabled by default */ -+ for (i = 0x202; i < 0x230; i += 2) { -+ if (i == 0x20c || i == 0x218 || i == 0x224) -+ continue; -+ phy_write_mmd(phydev, MDIO_MMD_VEND2, i, 0x2219); -+ phy_write_mmd(phydev, MDIO_MMD_VEND2, i + 1, 0x23); -+ } -+ -+ /* Disable LDO pump */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0); -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0); -+ -+ /* Adjust LDO output voltage */ -+ phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222); -+} -+ -+static inline int cal_sw(struct phy_device *phydev, enum CAL_ITEM cal_item, -+ u8 start_pair, u8 end_pair) -+{ -+ u8 pair_n; -+ int ret; -+ -+ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { -+ /* TX_OFFSET & TX_AMP have no SW calibration. */ -+ switch (cal_item) { -+ case REXT: -+ ret = rext_cal_sw(phydev); -+ break; -+ case TX_R50: -+ ret = tx_r50_cal_sw(phydev, pair_n); -+ break; -+ case TX_VCM: -+ ret = tx_vcm_cal_sw(phydev, pair_n); -+ break; -+ default: -+ return -EINVAL; -+ } -+ if (ret) -+ return ret; -+ } -+ return 0; -+} -+ -+static inline int cal_efuse(struct phy_device *phydev, enum CAL_ITEM cal_item, -+ u8 start_pair, u8 end_pair, u32 *buf) -+{ -+ u8 pair_n; -+ int ret; -+ -+ for (pair_n = start_pair; pair_n <= end_pair; pair_n++) { -+ /* TX_VCM has no efuse calibration. */ -+ switch (cal_item) { -+ case REXT: -+ ret = rext_cal_efuse(phydev, buf); -+ break; -+ case TX_OFFSET: -+ ret = tx_offset_cal_efuse(phydev, buf); -+ break; -+ case TX_AMP: -+ ret = tx_amp_cal_efuse(phydev, buf); -+ break; -+ case TX_R50: -+ ret = tx_r50_cal_efuse(phydev, buf, pair_n); -+ break; -+ default: -+ return -EINVAL; -+ } -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int start_cal(struct phy_device *phydev, enum CAL_ITEM cal_item, -+ bool efs_valid, enum CAL_MODE cal_mode, u8 start_pair, -+ u8 end_pair, u32 *buf) -+{ -+ char cal_prop[5][20] = { "mediatek,rext", "mediatek,tx_offset", -+ "mediatek,tx_amp", "mediatek,tx_r50", -+ "mediatek,tx_vcm" }; -+ const char *dts_cal_mode; -+ u8 final_cal_mode = 0; -+ bool is_cal = true; -+ int ret, cal_ret; -+ -+ ret = of_property_read_string(phydev->mdio.dev.of_node, -+ cal_prop[cal_item], &dts_cal_mode); -+ -+ switch (cal_mode) { -+ case SW_EFUSE_M: -+ if ((efs_valid && ret) || -+ (efs_valid && !ret && strcmp("efuse", dts_cal_mode) == 0)) { -+ cal_ret = cal_efuse(phydev, cal_item, start_pair, -+ end_pair, buf); -+ final_cal_mode = EFUSE_K; -+ } else if ((!efs_valid && ret) || -+ (!ret && strcmp("sw", dts_cal_mode) == 0)) { -+ cal_ret = cal_sw(phydev, cal_item, start_pair, end_pair); -+ final_cal_mode = SW_K; -+ } else { -+ is_cal = false; -+ } -+ break; -+ case EFUSE_M: -+ if ((efs_valid && ret) || -+ (efs_valid && !ret && strcmp("efuse", dts_cal_mode) == 0)) { -+ cal_ret = cal_efuse(phydev, cal_item, start_pair, -+ end_pair, buf); -+ final_cal_mode = EFUSE_K; -+ } else { -+ is_cal = false; -+ } -+ break; -+ case SW_M: -+ if (ret || (!ret && strcmp("sw", dts_cal_mode) == 0)) { -+ cal_ret = cal_sw(phydev, cal_item, start_pair, end_pair); -+ final_cal_mode = SW_K; -+ } else { -+ is_cal = false; -+ } -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ if (cal_ret) { -+ dev_err(&phydev->mdio.dev, "[%s]cal failed\n", cal_prop[cal_item]); -+ return -EIO; -+ } -+ -+ if (!is_cal) { -+ dev_dbg(&phydev->mdio.dev, "[%s]K mode: %s(not supported)\n", -+ cal_prop[cal_item], dts_cal_mode); -+ return -EIO; -+ } -+ -+ dev_dbg(&phydev->mdio.dev, "[%s]K mode: %s(dts: %s), efs-valid: %s\n", -+ cal_prop[cal_item], -+ final_cal_mode ? "SW" : "EFUSE", -+ ret ? "not set" : dts_cal_mode, -+ efs_valid ? "yes" : "no"); -+ return 0; -+} -+ -+static int mt798x_phy_calibration(struct phy_device *phydev) -+{ -+ int ret = 0; -+ u32 *buf; -+ bool efs_valid = true; -+ size_t len; -+ struct nvmem_cell *cell; -+ -+ if (phydev->interface != PHY_INTERFACE_MODE_GMII) -+ return -EINVAL; -+ -+ cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); -+ if (IS_ERR(cell)) { -+ if (PTR_ERR(cell) == -EPROBE_DEFER) -+ return PTR_ERR(cell); -+ return 0; -+ } -+ -+ buf = (u32 *)nvmem_cell_read(cell, &len); -+ if (IS_ERR(buf)) -+ return PTR_ERR(buf); -+ nvmem_cell_put(cell); -+ -+ if (!buf[0] || !buf[1] || !buf[2] || !buf[3]) -+ efs_valid = false; -+ -+ if (len < 4 * sizeof(u32)) { -+ dev_err(&phydev->mdio.dev, "invalid calibration data\n"); -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ ret = start_cal(phydev, REXT, efs_valid, SW_EFUSE_M, -+ NO_PAIR, NO_PAIR, buf); -+ if (ret) -+ goto out; -+ ret = start_cal(phydev, TX_OFFSET, efs_valid, EFUSE_M, -+ NO_PAIR, NO_PAIR, buf); -+ if (ret) -+ goto out; -+ ret = start_cal(phydev, TX_AMP, efs_valid, EFUSE_M, -+ NO_PAIR, NO_PAIR, buf); -+ if (ret) -+ goto out; -+ ret = start_cal(phydev, TX_R50, efs_valid, EFUSE_M, -+ PAIR_A, PAIR_D, buf); -+ if (ret) -+ goto out; -+ ret = start_cal(phydev, TX_VCM, efs_valid, SW_M, -+ PAIR_A, PAIR_A, buf); -+ if (ret) -+ goto out; -+ -+out: -+ kfree(buf); -+ return ret; -+} -+ -+static int mt7981_phy_probe(struct phy_device *phydev) -+{ -+ mt7981_phy_finetune(phydev); -+ -+ return mt798x_phy_calibration(phydev); -+} -+ -+static int mt7988_phy_probe(struct phy_device *phydev) -+{ -+ struct device_node *np; -+ void __iomem *boottrap; -+ u32 reg; -+ int port; -+ -+ /* Setup LED polarity according to boottrap's polarity */ -+ np = of_find_compatible_node(NULL, NULL, "mediatek,boottrap"); -+ if (!np) -+ return -ENOENT; -+ boottrap = of_iomap(np, 0); -+ if (!boottrap) -+ return -ENOMEM; -+ reg = readl(boottrap); -+ port = phydev->mdio.addr; -+ if ((port == GPHY_PORT0 && reg & BIT(8)) || -+ (port == GPHY_PORT1 && reg & BIT(9)) || -+ (port == GPHY_PORT2 && reg & BIT(10)) || -+ (port == GPHY_PORT3 && reg & BIT(11))) { -+ phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, -+ MTK_PHY_LED0_ENABLE | MTK_PHY_LED0_ON_LINK10 | -+ MTK_PHY_LED0_ON_LINK100 | -+ MTK_PHY_LED0_ON_LINK1000); -+ } else { -+ phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, -+ MTK_PHY_LED0_ENABLE | MTK_PHY_LED0_POLARITY | -+ MTK_PHY_LED0_ON_LINK10 | -+ MTK_PHY_LED0_ON_LINK100 | -+ MTK_PHY_LED0_ON_LINK1000); -+ } -+ phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_BLINK_CTRL, -+ MTK_PHY_LED0_1000TX | MTK_PHY_LED0_1000RX | -+ MTK_PHY_LED0_100TX | MTK_PHY_LED0_100RX | -+ MTK_PHY_LED0_10TX | MTK_PHY_LED0_10RX); -+ -+ mt7988_phy_finetune(phydev); -+ -+ return mt798x_phy_calibration(phydev); -+} -+#endif -+ - static struct phy_driver mtk_gephy_driver[] = { - { - PHY_ID_MATCH_EXACT(0x03a29412), -@@ -131,6 +1456,30 @@ static struct phy_driver mtk_gephy_drive - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, - }, -+#ifdef CONFIG_MEDIATEK_GE_PHY_SOC -+ { -+ PHY_ID_MATCH_EXACT(0x03a29461), -+ .name = "MediaTek MT7981 PHY", -+ .probe = mt7981_phy_probe, -+ .config_intr = genphy_no_config_intr, -+ .handle_interrupt = genphy_handle_interrupt_no_ack, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ .read_page = mtk_gephy_read_page, -+ .write_page = mtk_gephy_write_page, -+ }, -+ { -+ PHY_ID_MATCH_EXACT(0x03a29481), -+ .name = "MediaTek MT7988 PHY", -+ .probe = mt7988_phy_probe, -+ .config_intr = genphy_no_config_intr, -+ .handle_interrupt = genphy_handle_interrupt_no_ack, -+ .suspend = genphy_suspend, -+ .resume = genphy_resume, -+ .read_page = mtk_gephy_read_page, -+ .write_page = mtk_gephy_write_page, -+ }, -+#endif - }; - +@@ -136,7 +136,8 @@ static struct phy_driver mtk_gephy_drive module_phy_driver(mtk_gephy_driver); -@@ -141,6 +1490,8 @@ static struct mdio_device_id __maybe_unu + + static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { +- { PHY_ID_MATCH_VENDOR(0x03a29400) }, ++ { PHY_ID_MATCH_EXACT(0x03a29441) }, ++ { PHY_ID_MATCH_EXACT(0x03a29412) }, + { } }; - MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver"); -+MODULE_AUTHOR("Daniel Golle "); -+MODULE_AUTHOR("SkyLake Huang "); - MODULE_AUTHOR("DENG, Qingfang "); - MODULE_LICENSE("GPL"); - diff --git a/target/linux/mediatek/patches-5.15/732-net-phy-add-driver-for-MediaTek-2.5G-PHY.patch b/target/linux/mediatek/patches-5.15/732-net-phy-add-driver-for-MediaTek-2.5G-PHY.patch new file mode 100644 index 00000000000..a2a3bab6322 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/732-net-phy-add-driver-for-MediaTek-2.5G-PHY.patch @@ -0,0 +1,39 @@ +From 128dc09b0af36772062142ce9e85b19c84ac789a Mon Sep 17 00:00:00 2001 +From: Daniel Golle +Date: Tue, 28 Feb 2023 17:53:37 +0000 +Subject: [PATCH] net: phy: add driver for MediaTek 2.5G PHY + +Signed-off-by: Daniel Golle +--- + drivers/net/phy/Kconfig | 7 ++ + drivers/net/phy/Makefile | 1 + + drivers/net/phy/mediatek-2p5ge.c | 220 +++++++++++++++++++++++++++++++ + 3 files changed, 226 insertions(+) + create mode 100644 drivers/net/phy/mediatek-2p5ge.c + +--- a/drivers/net/phy/Kconfig ++++ b/drivers/net/phy/Kconfig +@@ -304,6 +304,13 @@ config MEDIATEK_GE_SOC_PHY + present in the SoCs efuse and will dynamically calibrate VCM + (common-mode voltage) during startup. + ++config MEDIATEK_2P5G_PHY ++ tristate "MediaTek 2.5G Ethernet PHY" ++ depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST ++ default NET_MEDIATEK_SOC ++ help ++ Supports the MediaTek 2.5G Ethernet PHY. ++ + config MICREL_PHY + tristate "Micrel PHYs" + help +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -80,6 +80,7 @@ obj-$(CONFIG_MARVELL_10G_PHY) += marvell + obj-$(CONFIG_MARVELL_PHY) += marvell.o + obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o + obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o ++obj-$(CONFIG_MEDIATEK_2P5G_PHY) += mediatek-2p5ge.o + obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o + obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o + obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o diff --git a/target/linux/mediatek/patches-5.15/830-v5.18-regulator-Add-bindings-for-Richtek-RT5190A-PMIC.patch b/target/linux/mediatek/patches-5.15/830-v5.18-regulator-Add-bindings-for-Richtek-RT5190A-PMIC.patch new file mode 100644 index 00000000000..30891d34872 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/830-v5.18-regulator-Add-bindings-for-Richtek-RT5190A-PMIC.patch @@ -0,0 +1,180 @@ +From b77e70f6b8f2cc62fba847f3008a430a09ef275d Mon Sep 17 00:00:00 2001 +From: ChiYuan Huang +Date: Wed, 9 Mar 2022 16:01:42 +0800 +Subject: [PATCH 1/2] regulator: Add bindings for Richtek RT5190A PMIC + +Add bindings for Richtek RT5190A PMIC. + +Signed-off-by: ChiYuan Huang +Reviewed-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/1646812903-32496-2-git-send-email-u0084500@gmail.com +Signed-off-by: Mark Brown +--- + .../regulator/richtek,rt5190a-regulator.yaml | 141 ++++++++++++++++++ + .../regulator/richtek,rt5190a-regulator.h | 15 ++ + 2 files changed, 156 insertions(+) + create mode 100644 Documentation/devicetree/bindings/regulator/richtek,rt5190a-regulator.yaml + create mode 100644 include/dt-bindings/regulator/richtek,rt5190a-regulator.h + +--- /dev/null ++++ b/Documentation/devicetree/bindings/regulator/richtek,rt5190a-regulator.yaml +@@ -0,0 +1,141 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/regulator/richtek,rt5190a-regulator.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Richtek RT5190A PMIC Regulator ++ ++maintainers: ++ - ChiYuan Huang ++ ++description: | ++ The RT5190A integrates 1 channel buck controller, 3 channels high efficiency ++ synchronous buck converters, 1 LDO, I2C control interface and peripherial ++ logical control. ++ ++ It also supports mute AC OFF depop sound and quick setting storage while ++ input power is removed. ++ ++properties: ++ compatible: ++ enum: ++ - richtek,rt5190a ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ vin2-supply: ++ description: phandle to buck2 input voltage. ++ ++ vin3-supply: ++ description: phandle to buck3 input voltage. ++ ++ vin4-supply: ++ description: phandle to buck4 input voltage. ++ ++ vinldo-supply: ++ description: phandle to ldo input voltage ++ ++ richtek,mute-enable: ++ description: | ++ The mute function uses 'mutein', 'muteout', and 'vdet' pins as the control ++ signal. When enabled, The normal behavior is to bypass the 'mutein' signal ++ 'muteout'. But if the power source removal is detected from 'vdet', ++ whatever the 'mutein' signal is, it will pull down the 'muteout' to force ++ speakers mute. this function is commonly used to prevent the speaker pop ++ noise during AC power turned off in the modern TV system design. ++ type: boolean ++ ++ regulators: ++ type: object ++ ++ patternProperties: ++ "^buck[1-4]$|^ldo$": ++ type: object ++ $ref: regulator.yaml# ++ description: | ++ regulator description for buck1 and buck4. ++ ++ properties: ++ regulator-allowed-modes: ++ description: | ++ buck operating mode, only buck1/4 support mode operating. ++ 0: auto mode ++ 1: force pwm mode ++ items: ++ enum: [0, 1] ++ ++ richtek,latchup-enable: ++ type: boolean ++ description: | ++ If specified, undervolt protection mode changes from the default ++ hiccup to latchup. ++ ++ unevaluatedProperties: false ++ ++ additionalProperties: false ++ ++required: ++ - compatible ++ - reg ++ - regulators ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ ++ i2c { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ pmic@64 { ++ compatible = "richtek,rt5190a"; ++ reg = <0x64>; ++ interrupts-extended = <&gpio26 0 IRQ_TYPE_LEVEL_LOW>; ++ vin2-supply = <&rt5190_buck1>; ++ vin3-supply = <&rt5190_buck1>; ++ vin4-supply = <&rt5190_buck1>; ++ ++ regulators { ++ rt5190_buck1: buck1 { ++ regulator-name = "rt5190a-buck1"; ++ regulator-min-microvolt = <5090000>; ++ regulator-max-microvolt = <5090000>; ++ regulator-allowed-modes = ; ++ regulator-boot-on; ++ }; ++ buck2 { ++ regulator-name = "rt5190a-buck2"; ++ regulator-min-microvolt = <600000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ }; ++ buck3 { ++ regulator-name = "rt5190a-buck3"; ++ regulator-min-microvolt = <600000>; ++ regulator-max-microvolt = <1400000>; ++ regulator-boot-on; ++ }; ++ buck4 { ++ regulator-name = "rt5190a-buck4"; ++ regulator-min-microvolt = <850000>; ++ regulator-max-microvolt = <850000>; ++ regulator-allowed-modes = ; ++ regulator-boot-on; ++ }; ++ ldo { ++ regulator-name = "rt5190a-ldo"; ++ regulator-min-microvolt = <1200000>; ++ regulator-max-microvolt = <1200000>; ++ regulator-boot-on; ++ }; ++ }; ++ }; ++ }; +--- /dev/null ++++ b/include/dt-bindings/regulator/richtek,rt5190a-regulator.h +@@ -0,0 +1,15 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++ ++#ifndef __DT_BINDINGS_RICHTEK_RT5190A_REGULATOR_H__ ++#define __DT_BINDINGS_RICHTEK_RT5190A_REGULATOR_H__ ++ ++/* ++ * BUCK/LDO mode constants which may be used in devicetree properties ++ * (eg. regulator-allowed-modes). ++ * See the manufacturer's datasheet for more information on these modes. ++ */ ++ ++#define RT5190A_OPMODE_AUTO 0 ++#define RT5190A_OPMODE_FPWM 1 ++ ++#endif diff --git a/target/linux/mediatek/patches-5.15/831-v5.18-regulator-rt5190a-Add-support-for-Richtek-RT5190A-PM.patch b/target/linux/mediatek/patches-5.15/831-v5.18-regulator-rt5190a-Add-support-for-Richtek-RT5190A-PM.patch new file mode 100644 index 00000000000..0e0f099e505 --- /dev/null +++ b/target/linux/mediatek/patches-5.15/831-v5.18-regulator-rt5190a-Add-support-for-Richtek-RT5190A-PM.patch @@ -0,0 +1,562 @@ +From 760423dfad53877b468490758fe7ea968ded9402 Mon Sep 17 00:00:00 2001 +From: ChiYuan Huang +Date: Wed, 9 Mar 2022 16:01:43 +0800 +Subject: [PATCH 2/2] regulator: rt5190a: Add support for Richtek RT5190A PMIC + +Add support for Richtek RT5190A PMIC. + +Signed-off-by: ChiYuan Huang +Link: https://lore.kernel.org/r/1646812903-32496-3-git-send-email-u0084500@gmail.com +Signed-off-by: Mark Brown +--- + drivers/regulator/Kconfig | 10 + + drivers/regulator/Makefile | 1 + + drivers/regulator/rt5190a-regulator.c | 513 ++++++++++++++++++++++++++ + 3 files changed, 524 insertions(+) + create mode 100644 drivers/regulator/rt5190a-regulator.c + +--- a/drivers/regulator/Kconfig ++++ b/drivers/regulator/Kconfig +@@ -1037,6 +1037,16 @@ config REGULATOR_RT5033 + RT5033 PMIC. The device supports multiple regulators like + current source, LDO and Buck. + ++config REGULATOR_RT5190A ++ tristate "Richtek RT5190A PMIC" ++ depends on I2C ++ select REGMAP_I2C ++ help ++ This adds support for voltage regulator in Richtek RT5190A PMIC. ++ It integratas 1 channel buck controller, 3 channels high efficiency ++ buck converters, 1 LDO, mute AC OFF depop function, with the general ++ I2C control interface. ++ + config REGULATOR_RT6160 + tristate "Richtek RT6160 BuckBoost voltage regulator" + depends on I2C +--- a/drivers/regulator/Makefile ++++ b/drivers/regulator/Makefile +@@ -125,6 +125,7 @@ obj-$(CONFIG_REGULATOR_ROHM) += rohm-reg + obj-$(CONFIG_REGULATOR_RT4801) += rt4801-regulator.o + obj-$(CONFIG_REGULATOR_RT4831) += rt4831-regulator.o + obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o ++obj-$(CONFIG_REGULATOR_RT5190A) += rt5190a-regulator.o + obj-$(CONFIG_REGULATOR_RT6160) += rt6160-regulator.o + obj-$(CONFIG_REGULATOR_RT6245) += rt6245-regulator.o + obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o +--- /dev/null ++++ b/drivers/regulator/rt5190a-regulator.c +@@ -0,0 +1,513 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RT5190A_REG_MANUFACTURE 0x00 ++#define RT5190A_REG_BUCK2VSEL 0x04 ++#define RT5190A_REG_BUCK3VSEL 0x05 ++#define RT5190A_REG_DCDCCNTL 0x06 ++#define RT5190A_REG_ENABLE 0x07 ++#define RT5190A_REG_DISCHARGE 0x09 ++#define RT5190A_REG_PROTMODE 0x0A ++#define RT5190A_REG_MUTECNTL 0x0B ++#define RT5190A_REG_PGSTAT 0x0F ++#define RT5190A_REG_OVINT 0x10 ++#define RT5190A_REG_HOTDIEMASK 0x17 ++ ++#define RT5190A_VSEL_MASK GENMASK(6, 0) ++#define RT5190A_RID_BITMASK(rid) BIT(rid + 1) ++#define RT5190A_BUCK1_DISCHG_MASK GENMASK(1, 0) ++#define RT5190A_BUCK1_DISCHG_ONVAL 0x01 ++#define RT5190A_OVERVOLT_MASK GENMASK(7, 0) ++#define RT5190A_UNDERVOLT_MASK GENMASK(15, 8) ++#define RT5190A_CH234OT_MASK BIT(29) ++#define RT5190A_CHIPOT_MASK BIT(28) ++ ++#define RT5190A_BUCK23_MINUV 600000 ++#define RT5190A_BUCK23_MAXUV 1400000 ++#define RT5190A_BUCK23_STEPUV 10000 ++#define RT5190A_BUCK23_STEPNUM ((1400000 - 600000) / 10000 + 1) ++ ++enum { ++ RT5190A_IDX_BUCK1 = 0, ++ RT5190A_IDX_BUCK2, ++ RT5190A_IDX_BUCK3, ++ RT5190A_IDX_BUCK4, ++ RT5190A_IDX_LDO, ++ RT5190A_MAX_IDX ++}; ++ ++struct rt5190a_priv { ++ struct device *dev; ++ struct regmap *regmap; ++ struct regulator_desc rdesc[RT5190A_MAX_IDX]; ++ struct regulator_dev *rdev[RT5190A_MAX_IDX]; ++}; ++ ++static int rt5190a_get_error_flags(struct regulator_dev *rdev, ++ unsigned int *flags) ++{ ++ struct regmap *regmap = rdev_get_regmap(rdev); ++ int rid = rdev_get_id(rdev); ++ unsigned int pgood_stat; ++ int ret; ++ ++ ret = regmap_read(regmap, RT5190A_REG_PGSTAT, &pgood_stat); ++ if (ret) ++ return ret; ++ ++ if (!(pgood_stat & RT5190A_RID_BITMASK(rid))) ++ *flags = REGULATOR_ERROR_FAIL; ++ else ++ *flags = 0; ++ ++ return 0; ++} ++ ++static int rt5190a_fixed_buck_set_mode(struct regulator_dev *rdev, ++ unsigned int mode) ++{ ++ struct regmap *regmap = rdev_get_regmap(rdev); ++ int rid = rdev_get_id(rdev); ++ unsigned int mask = RT5190A_RID_BITMASK(rid), val; ++ ++ switch (mode) { ++ case REGULATOR_MODE_FAST: ++ val = mask; ++ break; ++ case REGULATOR_MODE_NORMAL: ++ val = 0; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return regmap_update_bits(regmap, RT5190A_REG_DCDCCNTL, mask, val); ++} ++ ++static unsigned int rt5190a_fixed_buck_get_mode(struct regulator_dev *rdev) ++{ ++ struct regmap *regmap = rdev_get_regmap(rdev); ++ int rid = rdev_get_id(rdev); ++ unsigned int val; ++ int ret; ++ ++ ret = regmap_read(regmap, RT5190A_REG_DCDCCNTL, &val); ++ if (ret) { ++ dev_err(&rdev->dev, "Failed to get mode [%d]\n", ret); ++ return ret; ++ } ++ ++ if (val & RT5190A_RID_BITMASK(rid)) ++ return REGULATOR_MODE_FAST; ++ ++ return REGULATOR_MODE_NORMAL; ++} ++ ++static const struct regulator_ops rt5190a_ranged_buck_ops = { ++ .enable = regulator_enable_regmap, ++ .disable = regulator_disable_regmap, ++ .is_enabled = regulator_is_enabled_regmap, ++ .set_voltage_sel = regulator_set_voltage_sel_regmap, ++ .get_voltage_sel = regulator_get_voltage_sel_regmap, ++ .list_voltage = regulator_list_voltage_linear, ++ .set_active_discharge = regulator_set_active_discharge_regmap, ++ .get_error_flags = rt5190a_get_error_flags, ++}; ++ ++static const struct regulator_ops rt5190a_fixed_buck_ops = { ++ .enable = regulator_enable_regmap, ++ .disable = regulator_disable_regmap, ++ .is_enabled = regulator_is_enabled_regmap, ++ .set_active_discharge = regulator_set_active_discharge_regmap, ++ .set_mode = rt5190a_fixed_buck_set_mode, ++ .get_mode = rt5190a_fixed_buck_get_mode, ++ .get_error_flags = rt5190a_get_error_flags, ++}; ++ ++static const struct regulator_ops rt5190a_fixed_ldo_ops = { ++ .enable = regulator_enable_regmap, ++ .disable = regulator_disable_regmap, ++ .is_enabled = regulator_is_enabled_regmap, ++ .set_active_discharge = regulator_set_active_discharge_regmap, ++ .get_error_flags = rt5190a_get_error_flags, ++}; ++ ++static irqreturn_t rt5190a_irq_handler(int irq, void *data) ++{ ++ struct rt5190a_priv *priv = data; ++ __le32 raws; ++ unsigned int events, fields; ++ static const struct { ++ unsigned int bitmask; ++ unsigned int report; ++ } event_tbl[] = { ++ { RT5190A_OVERVOLT_MASK, REGULATOR_ERROR_REGULATION_OUT }, ++ { RT5190A_UNDERVOLT_MASK, REGULATOR_ERROR_UNDER_VOLTAGE } ++ }; ++ int i, j, ret; ++ ++ ret = regmap_raw_read(priv->regmap, RT5190A_REG_OVINT, &raws, ++ sizeof(raws)); ++ if (ret) { ++ dev_err(priv->dev, "Failed to read events\n"); ++ return IRQ_NONE; ++ } ++ ++ events = le32_to_cpu(raws); ++ ++ ret = regmap_raw_write(priv->regmap, RT5190A_REG_OVINT, &raws, ++ sizeof(raws)); ++ if (ret) ++ dev_err(priv->dev, "Failed to write-clear events\n"); ++ ++ /* Handle OV,UV events */ ++ for (i = 0; i < ARRAY_SIZE(event_tbl); i++) { ++ fields = events & event_tbl[i].bitmask; ++ fields >>= ffs(event_tbl[i].bitmask) - 1; ++ ++ for (j = 0; j < RT5190A_MAX_IDX; j++) { ++ if (!(fields & RT5190A_RID_BITMASK(j))) ++ continue; ++ ++ regulator_notifier_call_chain(priv->rdev[j], ++ event_tbl[i].report, ++ NULL); ++ } ++ } ++ ++ /* Handle CH234 OT event */ ++ if (events & RT5190A_CH234OT_MASK) { ++ for (j = RT5190A_IDX_BUCK2; j < RT5190A_IDX_LDO; j++) { ++ regulator_notifier_call_chain(priv->rdev[j], ++ REGULATOR_ERROR_OVER_TEMP, ++ NULL); ++ } ++ } ++ ++ /* Warning if CHIP OT occur */ ++ if (events & RT5190A_CHIPOT_MASK) ++ dev_warn(priv->dev, "CHIP overheat\n"); ++ ++ return IRQ_HANDLED; ++} ++ ++static unsigned int rt5190a_of_map_mode(unsigned int mode) ++{ ++ switch (mode) { ++ case RT5190A_OPMODE_AUTO: ++ return REGULATOR_MODE_NORMAL; ++ case RT5190A_OPMODE_FPWM: ++ return REGULATOR_MODE_FAST; ++ default: ++ return REGULATOR_MODE_INVALID; ++ } ++} ++ ++static int rt5190a_of_parse_cb(struct rt5190a_priv *priv, int rid, ++ struct of_regulator_match *match) ++{ ++ struct regulator_desc *desc = priv->rdesc + rid; ++ struct regulator_init_data *init_data = match->init_data; ++ struct device_node *np = match->of_node; ++ bool latchup_enable; ++ unsigned int mask = RT5190A_RID_BITMASK(rid), val; ++ ++ switch (rid) { ++ case RT5190A_IDX_BUCK1: ++ case RT5190A_IDX_BUCK4: ++ case RT5190A_IDX_LDO: ++ init_data->constraints.apply_uV = 0; ++ ++ if (init_data->constraints.min_uV == ++ init_data->constraints.max_uV) ++ desc->fixed_uV = init_data->constraints.min_uV; ++ else { ++ dev_err(priv->dev, ++ "Variable voltage for fixed regulator\n"); ++ return -EINVAL; ++ } ++ break; ++ default: ++ break; ++ } ++ ++ latchup_enable = of_property_read_bool(np, "richtek,latchup-enable"); ++ ++ /* latchup: 0, default hiccup: 1 */ ++ val = !latchup_enable ? mask : 0; ++ ++ return regmap_update_bits(priv->regmap, RT5190A_REG_PROTMODE, mask, val); ++} ++ ++static void rt5190a_fillin_regulator_desc(struct regulator_desc *desc, int rid) ++{ ++ static const char * const regu_name[] = { "buck1", "buck2", ++ "buck3", "buck4", ++ "ldo" }; ++ static const char * const supply[] = { NULL, "vin2", "vin3", "vin4", ++ "vinldo" }; ++ ++ desc->name = regu_name[rid]; ++ desc->supply_name = supply[rid]; ++ desc->owner = THIS_MODULE; ++ desc->type = REGULATOR_VOLTAGE; ++ desc->id = rid; ++ desc->enable_reg = RT5190A_REG_ENABLE; ++ desc->enable_mask = RT5190A_RID_BITMASK(rid); ++ desc->active_discharge_reg = RT5190A_REG_DISCHARGE; ++ desc->active_discharge_mask = RT5190A_RID_BITMASK(rid); ++ desc->active_discharge_on = RT5190A_RID_BITMASK(rid); ++ ++ switch (rid) { ++ case RT5190A_IDX_BUCK1: ++ desc->active_discharge_mask = RT5190A_BUCK1_DISCHG_MASK; ++ desc->active_discharge_on = RT5190A_BUCK1_DISCHG_ONVAL; ++ desc->n_voltages = 1; ++ desc->ops = &rt5190a_fixed_buck_ops; ++ desc->of_map_mode = rt5190a_of_map_mode; ++ break; ++ case RT5190A_IDX_BUCK2: ++ desc->vsel_reg = RT5190A_REG_BUCK2VSEL; ++ desc->vsel_mask = RT5190A_VSEL_MASK; ++ desc->min_uV = RT5190A_BUCK23_MINUV; ++ desc->uV_step = RT5190A_BUCK23_STEPUV; ++ desc->n_voltages = RT5190A_BUCK23_STEPNUM; ++ desc->ops = &rt5190a_ranged_buck_ops; ++ break; ++ case RT5190A_IDX_BUCK3: ++ desc->vsel_reg = RT5190A_REG_BUCK3VSEL; ++ desc->vsel_mask = RT5190A_VSEL_MASK; ++ desc->min_uV = RT5190A_BUCK23_MINUV; ++ desc->uV_step = RT5190A_BUCK23_STEPUV; ++ desc->n_voltages = RT5190A_BUCK23_STEPNUM; ++ desc->ops = &rt5190a_ranged_buck_ops; ++ break; ++ case RT5190A_IDX_BUCK4: ++ desc->n_voltages = 1; ++ desc->ops = &rt5190a_fixed_buck_ops; ++ desc->of_map_mode = rt5190a_of_map_mode; ++ break; ++ case RT5190A_IDX_LDO: ++ desc->n_voltages = 1; ++ desc->ops = &rt5190a_fixed_ldo_ops; ++ break; ++ } ++} ++ ++static struct of_regulator_match rt5190a_regulator_match[] = { ++ { .name = "buck1", }, ++ { .name = "buck2", }, ++ { .name = "buck3", }, ++ { .name = "buck4", }, ++ { .name = "ldo", } ++}; ++ ++static int rt5190a_parse_regulator_dt_data(struct rt5190a_priv *priv) ++{ ++ struct device_node *regulator_np; ++ struct regulator_desc *reg_desc; ++ struct of_regulator_match *match; ++ int i, ret; ++ ++ for (i = 0; i < RT5190A_MAX_IDX; i++) { ++ reg_desc = priv->rdesc + i; ++ match = rt5190a_regulator_match + i; ++ ++ rt5190a_fillin_regulator_desc(reg_desc, i); ++ ++ match->desc = reg_desc; ++ } ++ ++ regulator_np = of_get_child_by_name(priv->dev->of_node, "regulators"); ++ if (!regulator_np) { ++ dev_err(priv->dev, "Could not find 'regulators' node\n"); ++ return -ENODEV; ++ } ++ ++ ret = of_regulator_match(priv->dev, regulator_np, ++ rt5190a_regulator_match, ++ ARRAY_SIZE(rt5190a_regulator_match)); ++ ++ of_node_put(regulator_np); ++ ++ if (ret < 0) { ++ dev_err(priv->dev, ++ "Error parsing regulator init data: %d\n", ret); ++ return ret; ++ } ++ ++ for (i = 0; i < RT5190A_MAX_IDX; i++) { ++ match = rt5190a_regulator_match + i; ++ ++ ret = rt5190a_of_parse_cb(priv, i, match); ++ if (ret) { ++ dev_err(priv->dev, "Failed in [%d] of_parse_cb\n", i); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct reg_sequence rt5190a_init_patch[] = { ++ { 0x09, 0x3d, }, ++ { 0x0a, 0x3e, }, ++ { 0x0b, 0x01, }, ++ { 0x10, 0xff, }, ++ { 0x11, 0xff, }, ++ { 0x12, 0xff, }, ++ { 0x13, 0xff, }, ++ { 0x14, 0, }, ++ { 0x15, 0, }, ++ { 0x16, 0x3e, }, ++ { 0x17, 0, } ++}; ++ ++static int rt5190a_device_initialize(struct rt5190a_priv *priv) ++{ ++ bool mute_enable; ++ int ret; ++ ++ ret = regmap_register_patch(priv->regmap, rt5190a_init_patch, ++ ARRAY_SIZE(rt5190a_init_patch)); ++ if (ret) { ++ dev_err(priv->dev, "Failed to do register patch\n"); ++ return ret; ++ } ++ ++ mute_enable = device_property_read_bool(priv->dev, ++ "richtek,mute-enable"); ++ ++ if (mute_enable) { ++ ret = regmap_write(priv->regmap, RT5190A_REG_MUTECNTL, 0x00); ++ if (ret) { ++ dev_err(priv->dev, "Failed to enable mute function\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static int rt5190a_device_check(struct rt5190a_priv *priv) ++{ ++ u16 devid; ++ int ret; ++ ++ ret = regmap_raw_read(priv->regmap, RT5190A_REG_MANUFACTURE, &devid, ++ sizeof(devid)); ++ if (ret) ++ return ret; ++ ++ if (devid) { ++ dev_err(priv->dev, "Incorrect device id 0x%04x\n", devid); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static const struct regmap_config rt5190a_regmap_config = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ .max_register = RT5190A_REG_HOTDIEMASK, ++}; ++ ++static int rt5190a_probe(struct i2c_client *i2c) ++{ ++ struct rt5190a_priv *priv; ++ struct regulator_config cfg = {}; ++ int i, ret; ++ ++ priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->dev = &i2c->dev; ++ ++ priv->regmap = devm_regmap_init_i2c(i2c, &rt5190a_regmap_config); ++ if (IS_ERR(priv->regmap)) { ++ dev_err(&i2c->dev, "Failed to allocate regmap\n"); ++ return PTR_ERR(priv->regmap); ++ } ++ ++ ret = rt5190a_device_check(priv); ++ if (ret) { ++ dev_err(&i2c->dev, "Failed to check device %d\n", ret); ++ return ret; ++ } ++ ++ ret = rt5190a_device_initialize(priv); ++ if (ret) { ++ dev_err(&i2c->dev, "Failed to initialize the device\n"); ++ return ret; ++ } ++ ++ ret = rt5190a_parse_regulator_dt_data(priv); ++ if (ret) { ++ dev_err(&i2c->dev, "Failed to parse regulator dt\n"); ++ return ret; ++ } ++ ++ cfg.dev = &i2c->dev; ++ cfg.regmap = priv->regmap; ++ ++ for (i = 0; i < RT5190A_MAX_IDX; i++) { ++ struct regulator_desc *desc = priv->rdesc + i; ++ struct of_regulator_match *match = rt5190a_regulator_match + i; ++ ++ cfg.init_data = match->init_data; ++ cfg.of_node = match->of_node; ++ ++ priv->rdev[i] = devm_regulator_register(&i2c->dev, desc, &cfg); ++ if (IS_ERR(priv->rdev[i])) { ++ dev_err(&i2c->dev, "Failed to register regulator %s\n", ++ desc->name); ++ return PTR_ERR(priv->rdev[i]); ++ } ++ } ++ ++ if (i2c->irq) { ++ ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, ++ rt5190a_irq_handler, ++ IRQF_ONESHOT, ++ dev_name(&i2c->dev), priv); ++ if (ret) { ++ dev_err(&i2c->dev, "Failed to register interrupt\n"); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct of_device_id __maybe_unused rt5190a_device_table[] = { ++ { .compatible = "richtek,rt5190a", }, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, rt5190a_device_table); ++ ++static struct i2c_driver rt5190a_driver = { ++ .driver = { ++ .name = "rt5190a", ++ .of_match_table = rt5190a_device_table, ++ }, ++ .probe_new = rt5190a_probe, ++}; ++module_i2c_driver(rt5190a_driver); ++ ++MODULE_AUTHOR("ChiYuan Huang "); ++MODULE_DESCRIPTION("Richtek RT5190A Regulator Driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/octeontx/config-5.15 b/target/linux/octeontx/config-5.15 index c2ad7e7ab9d..9ca15896432 100644 --- a/target/linux/octeontx/config-5.15 +++ b/target/linux/octeontx/config-5.15 @@ -26,7 +26,6 @@ CONFIG_ARM64_ERRATUM_827319=y CONFIG_ARM64_ERRATUM_843419=y CONFIG_ARM64_HW_AFDBM=y CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y -CONFIG_ARM64_MODULE_PLTS=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PAN=y CONFIG_ARM64_PA_BITS=48 diff --git a/target/linux/ramips/mt7621/config-5.15 b/target/linux/ramips/mt7621/config-5.15 index 1b8a48100df..1b4330c2d16 100644 --- a/target/linux/ramips/mt7621/config-5.15 +++ b/target/linux/ramips/mt7621/config-5.15 @@ -184,6 +184,8 @@ CONFIG_NEED_DMA_MAP_STATE=y CONFIG_NET_DEVLINK=y CONFIG_NET_DSA=y CONFIG_NET_DSA_MT7530=y +CONFIG_NET_DSA_MT7530_MDIO=y +# CONFIG_NET_DSA_MT7530_MMIO is not set CONFIG_NET_DSA_TAG_MTK=y CONFIG_NET_FLOW_LIMIT=y CONFIG_NET_MEDIATEK_SOC=y diff --git a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch index 285e24429a4..a613803ee6d 100644 --- a/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch +++ b/target/linux/ramips/patches-5.15/700-net-ethernet-mediatek-support-net-labels.patch @@ -14,7 +14,7 @@ Signed-off-by: RenĂ© van Dorst --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c -@@ -4261,6 +4261,7 @@ static const struct net_device_ops mtk_n +@@ -4638,6 +4638,7 @@ static const struct net_device_ops mtk_n static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) { @@ -22,7 +22,7 @@ Signed-off-by: RenĂ© van Dorst const __be32 *_id = of_get_property(np, "reg", NULL); phy_interface_t phy_mode; struct phylink *phylink; -@@ -4389,6 +4390,9 @@ static int mtk_add_mac(struct mtk_eth *e +@@ -4796,6 +4797,9 @@ static int mtk_add_mac(struct mtk_eth *e register_netdevice_notifier(&mac->device_notifier); } diff --git a/target/linux/realtek/patches-5.15/008-5.17-watchdog-add-realtek-otto-watchdog-timer.patch b/target/linux/realtek/patches-5.15/008-5.17-watchdog-add-realtek-otto-watchdog-timer.patch index e562dd8396c..17ff729f525 100644 --- a/target/linux/realtek/patches-5.15/008-5.17-watchdog-add-realtek-otto-watchdog-timer.patch +++ b/target/linux/realtek/patches-5.15/008-5.17-watchdog-add-realtek-otto-watchdog-timer.patch @@ -32,7 +32,7 @@ Signed-off-by: Guenter Roeck --- a/MAINTAINERS +++ b/MAINTAINERS -@@ -15899,6 +15899,13 @@ S: Maintained +@@ -15902,6 +15902,13 @@ S: Maintained F: include/sound/rt*.h F: sound/soc/codecs/rt* diff --git a/target/linux/realtek/patches-5.15/700-net-dsa-add-support-for-rtl838x-switch.patch b/target/linux/realtek/patches-5.15/700-net-dsa-add-support-for-rtl838x-switch.patch index 8f400012635..8c6a4c36393 100644 --- a/target/linux/realtek/patches-5.15/700-net-dsa-add-support-for-rtl838x-switch.patch +++ b/target/linux/realtek/patches-5.15/700-net-dsa-add-support-for-rtl838x-switch.patch @@ -22,7 +22,7 @@ Submitted-by: John Crispin --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig -@@ -61,6 +61,8 @@ source "drivers/net/dsa/sja1105/Kconfig" +@@ -85,6 +85,8 @@ source "drivers/net/dsa/sja1105/Kconfig" source "drivers/net/dsa/xrs700x/Kconfig" @@ -33,7 +33,7 @@ Submitted-by: John Crispin select NET_DSA_TAG_RTL4_A --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile -@@ -22,5 +22,6 @@ obj-y += microchip/ +@@ -24,5 +24,6 @@ obj-y += microchip/ obj-y += mv88e6xxx/ obj-y += ocelot/ obj-y += qca/ diff --git a/target/linux/rockchip/armv8/config-5.15 b/target/linux/rockchip/armv8/config-5.15 index 2359fd8729e..0ed009004f1 100644 --- a/target/linux/rockchip/armv8/config-5.15 +++ b/target/linux/rockchip/armv8/config-5.15 @@ -31,7 +31,6 @@ CONFIG_ARM64_ERRATUM_858921=y CONFIG_ARM64_ERRATUM_1742098=y CONFIG_ARM64_HW_AFDBM=y CONFIG_ARM64_LD_HAS_FIX_ERRATUM_843419=y -CONFIG_ARM64_MODULE_PLTS=y CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PAN=y CONFIG_ARM64_PA_BITS=48 diff --git a/tools/meson/Makefile b/tools/meson/Makefile index d53ed897a35..f0810ced96c 100644 --- a/tools/meson/Makefile +++ b/tools/meson/Makefile @@ -1,11 +1,11 @@ include $(TOPDIR)/rules.mk PKG_NAME:=meson -PKG_VERSION:=0.61.5 +PKG_VERSION:=1.1.0 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://github.com/mesonbuild/meson/releases/download/$(PKG_VERSION) -PKG_HASH:=5e9a0d65c1a51936362b9686d1c5e9e184a6fd245d57e7269750ce50c20f5d9a +PKG_HASH:=d9616c44cd6c53689ff8f05fc6958a693f2e17c3472a8daf83cee55dabff829f PKG_MAINTAINER:=Andre Heider PKG_LICENSE:=Apache-2.0 diff --git a/tools/meson/patches/010-wsl2.patch b/tools/meson/patches/010-wsl2.patch deleted file mode 100644 index 4ab799d6992..00000000000 --- a/tools/meson/patches/010-wsl2.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 7d1ef4343ed5b2b7ab51469177a42c32c47f0528 Mon Sep 17 00:00:00 2001 -From: Rosen Penev -Date: Tue, 6 Sep 2022 01:36:17 -0700 -Subject: [PATCH] minstall: handle extra error for selinuxenabled - -Microsoft's WSL2 uses a Plan 9 filesystem, which returns IOError when file is missing. ---- - mesonbuild/minstall.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/mesonbuild/minstall.py -+++ b/mesonbuild/minstall.py -@@ -229,7 +229,7 @@ def restore_selinux_contexts() -> None: - ''' - try: - subprocess.check_call(['selinuxenabled']) -- except (FileNotFoundError, NotADirectoryError, PermissionError, subprocess.CalledProcessError): -+ except (FileNotFoundError, NotADirectoryError, OSError, PermissionError, subprocess.CalledProcessError): - # If we don't have selinux or selinuxenabled returned 1, failure - # is ignored quietly. - return