diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..29a30cc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0-only + +root = true + +[{*.{awk,c,dts,dtsi,dtso,h,mk,s,S},Kconfig,Makefile,Makefile.*}] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = tab +indent_size = 8 + +[*.{json,py,rs}] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 + +# this must be below the general *.py to overwrite it +[tools/{perf,power,rcu,testing/kunit}/**.py,] +indent_style = tab +indent_size = 8 + +[*.yaml] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 diff --git a/.github/workflows/build-drivers-hosted.yaml b/.github/workflows/build-drivers-hosted.yaml new file mode 100644 index 0000000..4d7e880 --- /dev/null +++ b/.github/workflows/build-drivers-hosted.yaml @@ -0,0 +1,19 @@ +name: Build and install camera drivers + +on: + workflow_call: + inputs: + platform: + required: false + type: string + +jobs: + build-drivers: + runs-on: [self-hosted, linux, ARM64, "${{ inputs.platform }}"] + timeout-minutes: 5 + steps: + - uses: actions/checkout@v3 + - name: Build deb package + run: cd ./pkg/ && ./create_deb_pkg.sh + - name: Install deb package and build drivers with DKMS + run: yes Y | sudo dpkg -i *.deb diff --git a/.github/workflows/camera-hotplug-hosted.yaml b/.github/workflows/camera-hotplug-hosted.yaml new file mode 100644 index 0000000..7466fd1 --- /dev/null +++ b/.github/workflows/camera-hotplug-hosted.yaml @@ -0,0 +1,52 @@ +name: Hot plug cameras + +on: + workflow_call: + inputs: + platform: + required: false + type: string + dt-overlay-options: + required: true + type: string + +jobs: + camera-hotplug: + runs-on: [self-hosted, linux, ARM64, "${{ inputs.platform }}"] + timeout-minutes: 3 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Build dtbocfg + run: | + cd ./scripts/common/hotplug/dtbocfg/ + make + ls -l ./dtbocfg.ko + sudo rmmod dtbocfg || true + sudo insmod ./dtbocfg.ko || true + lsmod | grep dtbocfg + - name: Hotplug + run: | + ./scripts/common/hotplug/camera-hotplug.sh ${{ inputs.dt-overlay-options }} + + post-hotplug-checks: + runs-on: [self-hosted, linux, ARM64, "${{ inputs.platform }}"] + needs: camera-hotplug + timeout-minutes: 3 + steps: + - run: | + find /proc/device-tree/ -name "*isx*" || find /proc/device-tree/ -name "*imx*" + find /proc/device-tree/ -name "*max9295*" + find /proc/device-tree/ -name "*max9296*" + find /proc/device-tree/ -name "*fpga*" + ls -l /dev/video* + ls -l /dev/v4l-* + ls -l /dev/media* + ls -l /dev/gmsl/ + for media_device in $(find /dev/ -type c -name "media*"); do + media-ctl -d "${media_device}" -p + done + for video_device in $(find /dev/ -type c -name "video*"); do + v4l2-ctl -d "${video_device}" --all + done diff --git a/.github/workflows/ecu-rqx58g-a.yaml b/.github/workflows/ecu-rqx58g-a.yaml new file mode 100644 index 0000000..b6b55f6 --- /dev/null +++ b/.github/workflows/ecu-rqx58g-a.yaml @@ -0,0 +1,40 @@ +name: ROSCube RQX-58G A C1x8 + +on: + pull_request: + types: [opened, reopened, synchronize] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-drivers: + uses: ./.github/workflows/build-drivers-hosted.yaml + with: + platform: rqx58g-a + + camera-hotplug: + needs: build-drivers + uses: ./.github/workflows/camera-hotplug-hosted.yaml + with: + platform: rqx58g-a + dt-overlay-options: roscube R32.6.1 -8 C1 + + test-8-cameras: + needs: camera-hotplug + strategy: + matrix: + dev-index: [0, 1, 2, 3, 4, 5, 6, 7] + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-a + video-device: /dev/video${{ matrix.dev-index }} + gstreamer-options: 'video/x-raw, width=1920, height=1280, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c1-${{ matrix.dev-index }} + + unload-camera-drivers: + needs: test-8-cameras + uses: ./.github/workflows/unload-drivers-hosted.yaml + with: + platform: rqx58g-a diff --git a/.github/workflows/ecu-rqx58g-b.yaml b/.github/workflows/ecu-rqx58g-b.yaml new file mode 100644 index 0000000..d13ddab --- /dev/null +++ b/.github/workflows/ecu-rqx58g-b.yaml @@ -0,0 +1,40 @@ +name: ROSCube RQX-58G B C2x8 + +on: + pull_request: + types: [opened, reopened, synchronize] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-drivers: + uses: ./.github/workflows/build-drivers-hosted.yaml + with: + platform: rqx58g-b + + camera-hotplug: + needs: build-drivers + uses: ./.github/workflows/camera-hotplug-hosted.yaml + with: + platform: rqx58g-b + dt-overlay-options: roscube R32.6.1 -8 C2 + + test-8-cameras: + needs: camera-hotplug + strategy: + matrix: + dev-index: [0, 1, 2, 3, 4, 5, 6, 7] + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-b + video-device: /dev/video${{ matrix.dev-index }} + gstreamer-options: 'video/x-raw, width=2880, height=1860, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c2-${{ matrix.dev-index }} + + unload-camera-drivers: + needs: test-8-cameras + uses: ./.github/workflows/unload-drivers-hosted.yaml + with: + platform: rqx58g-b diff --git a/.github/workflows/ecu-rqx58g-c.yaml b/.github/workflows/ecu-rqx58g-c.yaml new file mode 100644 index 0000000..7288e29 --- /dev/null +++ b/.github/workflows/ecu-rqx58g-c.yaml @@ -0,0 +1,100 @@ +name: ROSCube RQX-58G C C1x2 C2x2 C1x2 C2x2 + +on: + pull_request: + types: [opened, reopened, synchronize] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-drivers: + uses: ./.github/workflows/build-drivers-hosted.yaml + with: + platform: rqx58g-c + + camera-hotplug: + needs: build-drivers + uses: ./.github/workflows/camera-hotplug-hosted.yaml + with: + platform: rqx58g-c + dt-overlay-options: roscube R32.6.1 -2 C1 -2 C2 -2 C1 -2 C2 + + test-camera-0: + needs: camera-hotplug + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-c + video-device: /dev/gmsl/tier4-isx021-cam1 + gstreamer-options: 'video/x-raw, width=1920, height=1280, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c1-0 + + test-camera-1: + needs: camera-hotplug + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-c + video-device: /dev/gmsl/tier4-isx021-cam2 + gstreamer-options: 'video/x-raw, width=1920, height=1280, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c1-1 + + test-camera-2: + needs: camera-hotplug + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-c + video-device: /dev/gmsl/tier4-imx490-cam3 + gstreamer-options: 'video/x-raw, width=2880, height=1860, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c2-2 + + test-camera-3: + needs: camera-hotplug + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-c + video-device: /dev/gmsl/tier4-imx490-cam4 + gstreamer-options: 'video/x-raw, width=2880, height=1860, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c2-3 + + test-camera-4: + needs: camera-hotplug + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-c + video-device: /dev/gmsl/tier4-isx021-cam5 + gstreamer-options: 'video/x-raw, width=1920, height=1280, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c1-4 + + test-camera-5: + needs: camera-hotplug + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-c + video-device: /dev/gmsl/tier4-isx021-cam6 + gstreamer-options: 'video/x-raw, width=1920, height=1280, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c1-5 + + test-camera-6: + needs: camera-hotplug + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-c + video-device: /dev/gmsl/tier4-imx490-cam7 + gstreamer-options: 'video/x-raw, width=2880, height=1860, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c2-6 + + test-camera-7: + needs: camera-hotplug + uses: ./.github/workflows/test-v4l2-gstreamer-hosted.yaml + with: + platform: rqx58g-c + video-device: /dev/gmsl/tier4-imx490-cam8 + gstreamer-options: 'video/x-raw, width=2880, height=1860, framerate=30/1, format=UYVY' + artifact-name: gstreamer-v4l2-mjpeg-c2-7 + + unload-camera-drivers: + needs: [test-camera-0, test-camera-1, test-camera-2, test-camera-3, test-camera-4, test-camera-5, test-camera-6, test-camera-7] + uses: ./.github/workflows/unload-drivers-hosted.yaml + with: + platform: rqx58g-c diff --git a/.github/workflows/test-make-overlay-dts.yaml b/.github/workflows/test-make-overlay-dts.yaml new file mode 100644 index 0000000..63e2500 --- /dev/null +++ b/.github/workflows/test-make-overlay-dts.yaml @@ -0,0 +1,171 @@ +name: Test camera devicetree overlay generation scripts + +on: + pull_request: + types: [opened, reopened, synchronize] + paths: + - 'tools/dts_generator/make_overlay_dts*.py' + +jobs: + test-make-overlay-dts-roscube: + runs-on: ubuntu-20.04 + timeout-minutes: 3 + strategy: + matrix: + revision: [R32.5.1, R32.5.2, R32.6.1, R35.4.1] + camera-combination: [ + "-8 C1", "-8 C2", + "-6 C1 -2 C2", "-6 C2 -2 C1", "-2 C1 -6 C2", "-2 C2 -6 C1", + "-4 C1 -4 C2", "-4 C2 -4 C1", + "-4 C1 -2 C1 -2 C2", "-4 C1 -2 C2 -2 C1", "-4 C2 -2 C1 -2 C2", "-4 C2 -2 C2 -2 C1", + "-2 C1 -2 C2 -4 C1", "-2 C2 -2 C1 -4 C1", "-2 C1 -2 C2 -4 C2", "-2 C2 -2 C1 -4 C2", + "-2 C1 -2 C2 -2 C1 -2 C2", "-2 C2 -2 C1 -2 C2 -2 C1" + ] + steps: + - uses: actions/checkout@v3 + - name: Install device-tree-compiler + run: command -v dtc || ( sudo apt-get update && sudo apt-get install -y device-tree-compiler ) + - name: Generate devicetree overlay + run: | + ./tools/dts_generator/make_overlay_dts_roscube.py "${{ matrix.revision }}" ${{ matrix.camera-combination }} + ls -l *.dts + - name: Compile the generated devicetree overlay + run: | + dtc -O dtb -@ *.dts -o compiled.dtbo + ls -l *.dtbo + + test-make-overlay-dts-roscube-orin: + runs-on: ubuntu-20.04 + timeout-minutes: 3 + strategy: + matrix: + revision: [R35.1, R35.2.1] + camera-combination: [ + "-8 C1", "-8 C2", + "-6 C1 -2 C2", "-6 C2 -2 C1", "-2 C1 -6 C2", "-2 C2 -6 C1", + "-4 C1 -4 C2", "-4 C2 -4 C1", + "-4 C1 -2 C1 -2 C2", "-4 C1 -2 C2 -2 C1", "-4 C2 -2 C1 -2 C2", "-4 C2 -2 C2 -2 C1", + "-2 C1 -2 C2 -4 C1", "-2 C2 -2 C1 -4 C1", "-2 C1 -2 C2 -4 C2", "-2 C2 -2 C1 -4 C2", + "-2 C1 -2 C2 -2 C1 -2 C2", "-2 C2 -2 C1 -2 C2 -2 C1" + ] + steps: + - uses: actions/checkout@v3 + - name: Install device-tree-compiler + run: command -v dtc || ( sudo apt-get update && sudo apt-get install -y device-tree-compiler ) + - name: Generate devicetree overlay + run: | + ./tools/dts_generator/make_overlay_dts_roscube-orin.py "${{ matrix.revision }}" ${{ matrix.camera-combination }} + ls -l *.dts + - name: Compile the generated devicetree overlay + run: | + dtc -O dtb -@ *.dts -o compiled.dtbo + ls -l *.dtbo + + test-make-overlay-dts-orin-devkit: + runs-on: ubuntu-20.04 + timeout-minutes: 3 + strategy: + matrix: + revision: [R35.1, R35.2.1] + camera-combination: [ + "-8 C1", "-8 C2", + "-6 C1 -2 C2", "-6 C2 -2 C1", "-2 C1 -6 C2", "-2 C2 -6 C1", + "-4 C1 -4 C2", "-4 C2 -4 C1", + "-4 C1 -2 C1 -2 C2", "-4 C1 -2 C2 -2 C1", "-4 C2 -2 C1 -2 C2", "-4 C2 -2 C2 -2 C1", + "-2 C1 -2 C2 -4 C1", "-2 C2 -2 C1 -4 C1", "-2 C1 -2 C2 -4 C2", "-2 C2 -2 C1 -4 C2", + "-2 C1 -2 C2 -2 C1 -2 C2", "-2 C2 -2 C1 -2 C2 -2 C1" + ] + steps: + - uses: actions/checkout@v3 + - name: Install device-tree-compiler + run: command -v dtc || ( sudo apt-get update && sudo apt-get install -y device-tree-compiler ) + - name: Generate devicetree overlay + run: | + ./tools/dts_generator/make_overlay_dts_orin-devkit.py "${{ matrix.revision }}" ${{ matrix.camera-combination }} + ls -l *.dts + - name: Compile the generated devicetree overlay + run: | + dtc -O dtb -@ *.dts -o compiled.dtbo + ls -l *.dtbo + + test-make-overlay-dts-xavier-devkit: + runs-on: ubuntu-20.04 + timeout-minutes: 3 + strategy: + matrix: + revision: [R32.5.1, R32.5.2, R32.6.1, R35.1, R35.2.1, R35.3.1] + camera-combination: [ + "-8 C1", "-8 C2", + "-6 C1 -2 C2", "-6 C2 -2 C1", "-2 C1 -6 C2", "-2 C2 -6 C1", + "-4 C1 -4 C2", "-4 C2 -4 C1", + "-4 C1 -2 C1 -2 C2", "-4 C1 -2 C2 -2 C1", "-4 C2 -2 C1 -2 C2", "-4 C2 -2 C2 -2 C1", + "-2 C1 -2 C2 -4 C1", "-2 C2 -2 C1 -4 C1", "-2 C1 -2 C2 -4 C2", "-2 C2 -2 C1 -4 C2", + "-2 C1 -2 C2 -2 C1 -2 C2", "-2 C2 -2 C1 -2 C2 -2 C1" + ] + steps: + - uses: actions/checkout@v3 + - name: Install device-tree-compiler + run: command -v dtc || ( sudo apt-get update && sudo apt-get install -y device-tree-compiler ) + - name: Generate devicetree overlay + run: | + ./tools/dts_generator/make_overlay_dts_xavier-devkit.py "${{ matrix.revision }}" ${{ matrix.camera-combination }} + ls -l *.dts + - name: Compile the generated devicetree overlay + run: | + dtc -O dtb -@ *.dts -o compiled.dtbo + ls -l *.dtbo + + test-make-overlay-dts-eac-5000: + runs-on: ubuntu-20.04 + timeout-minutes: 3 + strategy: + matrix: + revision: [R35.3.1] + camera-combination: [ + "-8 C1", "-8 C2", + "-6 C1 -2 C2", "-6 C2 -2 C1", "-2 C1 -6 C2", "-2 C2 -6 C1", + "-4 C1 -4 C2", "-4 C2 -4 C1", + "-4 C1 -2 C1 -2 C2", "-4 C1 -2 C2 -2 C1", "-4 C2 -2 C1 -2 C2", "-4 C2 -2 C2 -2 C1", + "-2 C1 -2 C2 -4 C1", "-2 C2 -2 C1 -4 C1", "-2 C1 -2 C2 -4 C2", "-2 C2 -2 C1 -4 C2", + "-2 C1 -2 C2 -2 C1 -2 C2", "-2 C2 -2 C1 -2 C2 -2 C1" + ] + steps: + - uses: actions/checkout@v3 + - name: Install device-tree-compiler + run: command -v dtc || ( sudo apt-get update && sudo apt-get install -y device-tree-compiler ) + - name: Generate devicetree overlay + run: | + ./tools/dts_generator/make_overlay_dts_eac-5000.py "${{ matrix.revision }}" ${{ matrix.camera-combination }} + ls -l *.dts + - name: Compile the generated devicetree overlay + run: | + dtc -O dtb -@ *.dts -o compiled.dtbo + ls -l *.dtbo + + test-make-overlay-dts-anvil: + runs-on: ubuntu-20.04 + timeout-minutes: 3 + strategy: + matrix: + revision: [R35] + camera-combination: [ + "-8 C1", "-8 C2", + "-6 C1 -2 C2", "-6 C2 -2 C1", "-2 C1 -6 C2", "-2 C2 -6 C1", + "-4 C1 -4 C2", "-4 C2 -4 C1", + "-4 C1 -2 C1 -2 C2", "-4 C1 -2 C2 -2 C1", "-4 C2 -2 C1 -2 C2", "-4 C2 -2 C2 -2 C1", + "-2 C1 -2 C2 -4 C1", "-2 C2 -2 C1 -4 C1", "-2 C1 -2 C2 -4 C2", "-2 C2 -2 C1 -4 C2", + "-2 C1 -2 C2 -2 C1 -2 C2", "-2 C2 -2 C1 -2 C2 -2 C1" + ] + steps: + - uses: actions/checkout@v3 + - name: Install device-tree-compiler + run: command -v dtc || ( sudo apt-get update && sudo apt-get install -y device-tree-compiler ) + - name: Generate devicetree overlay + run: | + ./tools/dts_generator/make_overlay_dts_anvil.py "${{ matrix.revision }}" ${{ matrix.camera-combination }} + ls -l *.dts + - name: Compile the generated devicetree overlay + run: | + dtc -O dtb -@ *.dts -o compiled.dtbo + ls -l *.dtbo + diff --git a/.github/workflows/test-v4l2-gstreamer-hosted.yaml b/.github/workflows/test-v4l2-gstreamer-hosted.yaml new file mode 100644 index 0000000..485ebdd --- /dev/null +++ b/.github/workflows/test-v4l2-gstreamer-hosted.yaml @@ -0,0 +1,44 @@ +name: GStreamer V4L2 tests + +on: + workflow_call: + inputs: + platform: + required: false + type: string + video-device: + required: true + type: string + gstreamer-options: + required: true + type: string + artifact-name: + required: false + type: string + +jobs: + check-camera: + runs-on: [self-hosted, linux, ARM64, "${{ inputs.platform }}"] + timeout-minutes: 3 + steps: + - run: | + ls -l ${{ inputs.video-device }} + ls -l /dev/v4l-subdev* + ls -l /dev/media* + v4l2-ctl -d "${{ inputs.video-device }}" --all + + dump-v4l2-stream: + runs-on: [self-hosted, linux, ARM64, "${{ inputs.platform }}"] + needs: check-camera + timeout-minutes: 3 + steps: + - run: | + gst-launch-1.0 -e v4l2src io-mode=0 device=${{ inputs.video-device }} do-timestamp=true num-buffers=60 ! '${{ inputs.gstreamer-options }}' ! nvvidconv ! nvjpegenc ! qtmux ! filesink location=output.mov + ls -l output.mov + test -s output.mov + - name: Upload the captured Motion JPEG video + if: ${{ inputs.artifact-name != '' }} + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.artifact-name }} + path: output.mov diff --git a/.github/workflows/unload-drivers-hosted.yaml b/.github/workflows/unload-drivers-hosted.yaml new file mode 100644 index 0000000..dbba4d5 --- /dev/null +++ b/.github/workflows/unload-drivers-hosted.yaml @@ -0,0 +1,16 @@ +name: Unload camera drivers + +on: + workflow_call: + inputs: + platform: + required: false + type: string + +jobs: + unload-camera-drivers: + runs-on: [self-hosted, linux, ARM64, "${{ inputs.platform }}"] + timeout-minutes: 2 + steps: + - name: Unload camera modules + run: sudo modprobe -r tier4-imx728 diff --git a/.gitignore b/.gitignore index 8442dd3..778cf2f 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,20 @@ modules.order Module.symvers Mkfile.old build + +.tag +.tags + +# deb package +debhelper-build-stamp +.DS_Store +**/*.debhelper +*.deb +*.dsc +*.build +*.buildinfo +*.changes +*.tar.gz +*.log +*.substvars +**/debian/files diff --git a/drivers/README.md b/drivers/README.md deleted file mode 100644 index 608d5f1..0000000 --- a/drivers/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# tier4-camera-gmsl-dkms - -This driver has been developed on ROScube RQX58G/Jetson Orin Devkit, it could not be cross-compiled at this moment. - -## Preparation - -``` sh -sudo apt update -sudo apt install make build-essential debhelper debmake devscripts dkms -``` - -## Build debian-dkms package - -``` sh -dpkg-buildpackage -b -rfakeroot -us -uc -``` - -## Install the debian-dkms package - -``` sh -cd .. -sudo apt update -sudo apt install ./tier4-isx021-gmsl_1.4.1_arm64.deb -``` - -## Confirm the dtbo file exists - -``` -ls /boot/*.dtbo -``` - - -## Combine dtbo file with vanilla dtb - - -``` sh -sudo /opt/nvidia/jetson-io/config-by-hardware.py -n 2="TIERIV ISX021 GMSL2 Camera Device Tree Overlay" -``` - -if you use r32.5.1 BSP, you should use the command below - -``` sh -sudo /opt/nvidia/jetson-io/config-by-hardware.py -n "TIERIV ISX021 GMSL2 Camera Device Tree Overlay" -``` - - -## Confirm custom dtb file has been generated - -``` sh -ls -al /boot/*user-custom.dtb -``` - - -## Then, shutdown the system - -$> sudo shutdown -h now - -## Power on again \ No newline at end of file diff --git a/drivers/create_deb_pkg.sh b/drivers/create_deb_pkg.sh deleted file mode 100755 index 3ca53b2..0000000 --- a/drivers/create_deb_pkg.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -if [ -e ./src/tier4-isx021.bin ] -then - grep -q "TIER4_ISX021_REG_0_ADDR" ./src/tier4-isx021.c - if [ ! $? = 0 ] - then - echo "The register address is not hidden." - echo "exec python ./tool/gen_firmware.py ./src/tier4-isx021.c" - python3 ./tools/gen_firmware.py ./src/tier4-isx021.c - fi - dpkg-buildpackage -b -rfakeroot -us -uc -fi - -#dpkg-buildpackage -b -rfakeroot -us -uc diff --git a/drivers/debian/etc/modprobe.d/tier4-isx021.conf b/drivers/debian/etc/modprobe.d/tier4-isx021.conf deleted file mode 100644 index 5c33b9e..0000000 --- a/drivers/debian/etc/modprobe.d/tier4-isx021.conf +++ /dev/null @@ -1,19 +0,0 @@ -# Configurations: -# "trigger_mode=0" run cameras in master mode. (Default) -# "trigger_mode=1" run cameras in slave(External pulse sync) mode, and valid for ADLINK RQX-58G only. -# -# "enable_auto_exposure=0" disable auto-exposure feature. -# "enable_auto_exposure=1" enable auto-exposure feature. (Default) -# -# "enable_distortion_correction=0" disable distortion correction feature. (Default) -# "enable_distortion_correction=1" enable distortion correction feature. -# - -options tier4_isx021 trigger_mode=0 enable_auto_exposure=1 enable_distortion_correction=1 - -# The following parameter is valid for ADLINK RQX-58G only. -# "generate_fsync=0" External pulse is not automatically genereated by FPGA. (Default) -# "generate_fsync=1" External pulse is automatically genereated by FPGA( not supported yet). -# - -options tier4_fpga generate_fsync=0 diff --git a/drivers/debian/udev b/drivers/debian/udev deleted file mode 100644 index 9854e42..0000000 --- a/drivers/debian/udev +++ /dev/null @@ -1,16 +0,0 @@ -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_imx490 30-002b", SYMLINK+= "gmsl/tier4-imx490-cam1" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_isx021 30-001b", SYMLINK+= "gmsl/tier4-isx021-cam1" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_imx490 30-002c", SYMLINK+= "gmsl/tier4-imx490-cam2" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_isx021 30-001c", SYMLINK+= "gmsl/tier4-isx021-cam2" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_imx490 31-002b", SYMLINK+= "gmsl/tier4-imx490-cam3" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_isx021 31-001b", SYMLINK+= "gmsl/tier4-isx021-cam3" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_imx490 31-002c", SYMLINK+= "gmsl/tier4-imx490-cam4" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_isx021 31-001c", SYMLINK+= "gmsl/tier4-isx021-cam4" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_imx490 32-002b", SYMLINK+= "gmsl/tier4-imx490-cam5" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_isx021 32-001b", SYMLINK+= "gmsl/tier4-isx021-cam5" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_imx490 32-002c", SYMLINK+= "gmsl/tier4-imx490-cam6" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_isx021 32-001c", SYMLINK+= "gmsl/tier4-isx021-cam6" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_imx490 33-002b", SYMLINK+= "gmsl/tier4-imx490-cam7" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_isx021 33-001b", SYMLINK+= "gmsl/tier4-isx021-cam7" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_imx490 33-002c", SYMLINK+= "gmsl/tier4-imx490-cam8" -SUBSYSTEM=="video4linux", ATTR{name}=="vi-output, tier4_isx021 33-001c", SYMLINK+= "gmsl/tier4-isx021-cam8" diff --git a/drivers/src/.clang-format b/drivers/src/.clang-format deleted file mode 100755 index e03f80b..0000000 --- a/drivers/src/.clang-format +++ /dev/null @@ -1,48 +0,0 @@ ---- -BasedOnStyle: Google -AccessModifierOffset: -2 -ConstructorInitializerIndentWidth: 2 -AlignEscapedNewlinesLeft: false -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortIfStatementsOnASingleLine: false -AllowShortLoopsOnASingleLine: false -AllowShortFunctionsOnASingleLine: None -AllowShortLoopsOnASingleLine: false -AlwaysBreakTemplateDeclarations: true -AlwaysBreakBeforeMultilineStrings: false -BreakBeforeBinaryOperators: false -BreakBeforeTernaryOperators: false -BreakConstructorInitializersBeforeComma: true -BinPackParameters: true -ColumnLimit: 120 -ConstructorInitializerAllOnOneLineOrOnePerLine: true -DerivePointerBinding: true -ExperimentalAutoDetectBinPacking: false -IndentCaseLabels: true -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCSpaceBeforeProtocolList: true -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 60 -PenaltyBreakString: 1 -PenaltyBreakFirstLessLess: 1000 -PenaltyExcessCharacter: 1000 -PenaltyReturnTypeOnItsOwnLine: 90 -PointerBindsToType: false -SpacesBeforeTrailingComments: 2 -Cpp11BracedListStyle: false -Standard: Auto -IndentWidth: 2 -TabWidth: 2 -UseTab: Never -BreakBeforeBraces: Allman -IndentFunctionDeclarationAfterType: false -SpacesInParentheses: false -SpacesInAngles: false -SpaceInEmptyParentheses: false -SpacesInCStyleCastParentheses: false -SpaceAfterControlStatementKeyword: true -SpaceBeforeAssignmentOperators: true -ContinuationIndentWidth: 4 -... diff --git a/drivers/src/tier4-fpga.c b/drivers/src/tier4-fpga.c deleted file mode 100644 index 207dd66..0000000 --- a/drivers/src/tier4-fpga.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - * tier4_fpga.c - tier4_fpga driver - * - * Copyright (c) 2022-2023, TIER IV Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -//#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tier4-gmsl-link.h" -#include "tier4-fpga.h" - -//#define DEBUG_INFO - -#define FPGA_ENABLED 0xF0 -#define FPGA_DISABLED 0xFF -#define NO_ERROR 0 - -#define FPGA_REG_VERSION_ADDR 0x1 -#define FPGA_REG_ENABLE_ADDR 0x4 -//#define FPGA_REG_FREQ_BASE_ADDR 0x8 - -#define FREQ_10HZ 10 -#define FREQ_20HZ 20 -#define FREQ_30HZ 30 - -static int fsync_mode; // 0: disabled, 1: enable auto mode, 2: enable manual mode - -module_param(fsync_mode, int, S_IRUGO | S_IWUSR); - - -static int fps_cam1_cam2 = 0xCAFE; -static int fps_cam3_cam4 = 0xCAFE; -static int fps_cam5_cam6 = 0xCAFE; -static int fps_cam7_cam8 = 0xCAFE; - -module_param(fps_cam1_cam2, int, S_IRUGO | S_IWUSR); -module_param(fps_cam3_cam4, int, S_IRUGO | S_IWUSR); -module_param(fps_cam5_cam6, int, S_IRUGO | S_IWUSR); -module_param(fps_cam7_cam8, int, S_IRUGO | S_IWUSR); - - -struct tier4_fpga -{ - struct i2c_client *i2c_client; - struct regmap *regmap; - struct tier4_gmsl_link_ctx g_ctx; - struct mutex lock; - /* FPGA slave address */ - __u32 reg_addr; -// bool generate_fsync; -}; - -//static int generate_fsync; -//module_param(generate_fsync, int, S_IRUGO | S_IWUSR); - -static struct regmap_config tier4_fpga_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .cache_type = REGCACHE_RBTREE, -}; - -/* count channel */ -static __u32 channel_count_fpga; /* should be 1 */ - -#if 1 -static int tier4_fpga_read_reg(struct device *dev, u16 addr, u8 *val) -{ - int err = 0; - u32 reg_val = 0; - struct tier4_fpga *priv = dev_get_drvdata(dev); - - err = regmap_read(priv->regmap, addr, ®_val); - - *val = reg_val & 0xFF; - - return err; -} -#endif - -static int tier4_fpga_write_reg(struct device *dev, u16 addr, u8 val) -{ - struct tier4_fpga *priv = dev_get_drvdata(dev); - int err = 0; - - err = regmap_write(priv->regmap, addr, val); - - if (err) - { - dev_err(dev, "[%s] FPGA I2C write Reg at 0x%04X:[0x%02X] failed.\n", __func__, addr, val); - } -#ifdef DEBUG_INFO - else - { - dev_info(dev, "[%s] FPGA I2C write Reg at 0x%04X:[0x%02X].\n", __func__, addr, val); - } -#endif - - /* delay before next i2c command as required for SERDES link */ - usleep_range(200, 220); -// tier4_fpga_read_reg(dev, addr, &e); -// usleep_range(100, 110); - - return err; -} - -int tier4_fpga_get_fsync_mode(void) -{ - return fsync_mode; // 0: disabled, 1: enable auto mode, 2: enable manual mode -} -EXPORT_SYMBOL(tier4_fpga_get_fsync_mode); - -int tier4_fpga_enable_fsync_mode(struct device *dev) -{ - int err = 0; -// u8 val = 0; - -// err = tier4_fpga_read_reg(dev, FPGA_REG_MODE_ADDR, &val); -// if ((val & 0xFF) == FPGA_MODE_FSYNC) { -// // skip writing the same value to reg in order to save the flash write cycles -// dev_info(dev, "[%s] : Keep FSYNC mode enabled.\n", __func__); -// return err; -// } - - err = tier4_fpga_write_reg(dev, FPGA_REG_MODE_ADDR, FPGA_MODE_FSYNC); - if (err) - { - dev_err(dev, "[%s] Enabling FSYNC mode failed.\n", __func__); - } -#ifdef DEBUG_INFO - else - { - dev_info(dev, "[%s] Enabling FSYNC mode.\n", __func__); - } -#endif - - return err; -} -EXPORT_SYMBOL(tier4_fpga_enable_fsync_mode); - -int tier4_fpga_disable_fsync_mode(struct device *dev) -{ - int err = 0; -// u8 val = 0; - -// err = tier4_fpga_read_reg(dev, FPGA_REG_MODE_ADDR, &val); -// if ((val & 0xFF) == FPGA_MODE_FREE_RUN) { -// // skip writing the same value to reg in order to save the flash write cycles -// dev_info(dev, "[%s] : Keep FSYNC mode disabled.\n", __func__); -// return err; -// } - - err = tier4_fpga_write_reg(dev, FPGA_REG_MODE_ADDR, FPGA_MODE_FREE_RUN); - if (err) - { - dev_err(dev, "[%s] Disabling FSYNC mode failed.\n", __func__); - } -#ifdef DEBUG_INFO - else - { - dev_info(dev, "[%s] Disabling FSYNC mode.\n", __func__); - } -#endif - return err; -} -EXPORT_SYMBOL(tier4_fpga_disable_fsync_mode); - -int tier4_fpga_set_fsync_auto_trigger(struct device *dev) -{ - int err = 0; -// u8 val = 0; - -// err = tier4_fpga_read_reg(dev, FPGA_REG_FSYNC_TRIG_ADDR, &val); -// if ((val & 0xFF) == FPGA_FSYNC_AUTO) { -// // skip writing the same value to reg in order to save the flash write cycles -// dev_info(dev, "[%s] : Keep FSYNC Auto Trigger mode.\n", __func__); -// return err; -// } - - err = tier4_fpga_write_reg(dev, FPGA_REG_FSYNC_TRIG_ADDR, FPGA_FSYNC_AUTO); - if (err) - { - dev_err(dev, "[%s] Enabling FSYNC Auto Trigger mode failed.\n", __func__); - } -#ifdef DEBUG_INFO - else - { - dev_info(dev, "[%s] Enabling FSYNC Auto Trigger mode.\n", __func__); - } -#endif - return err; -} -EXPORT_SYMBOL(tier4_fpga_set_fsync_auto_trigger); - -int tier4_fpga_set_fsync_manual_trigger(struct device *dev) -{ - int err = 0; -// u8 val = 0; - -// err = tier4_fpga_read_reg(dev, FPGA_REG_FSYNC_TRIG_ADDR, &val); -// if ((val & 0xFF) == FPGA_FSYNC_MANUAL) { -// // skip writing the same value to reg in order to save the flash write cycles -// dev_info(dev, "[%s] : Keep FSYNC Auto Trigger mode.\n", __func__); -// return err; -// } - - err = tier4_fpga_write_reg(dev, FPGA_REG_FSYNC_TRIG_ADDR, FPGA_FSYNC_MANUAL); - if (err) - { - dev_err(dev, "[%s] Enabling FSYNC Manual Trigger mode failed.\n", __func__); - } -#ifdef DEBUG_INFO - else - { - dev_info(dev, "[%s] Enabling FSYNC Manual Trigger mode failed.\n", __func__); - } -#endif - - return err; -} -EXPORT_SYMBOL(tier4_fpga_set_fsync_manual_trigger); - -// *************** - -int tier4_fpga_check_access(struct device *dev) -{ - int err = 0; - int i; - u8 dummy8 = 0; - - for (i=0; i < 5 ; i++ ) - { - err = tier4_fpga_read_reg(dev, FPGA_REG_VERSION_ADDR, &dummy8); - if (!err) - { - break; - } - usleep_range(10000,11000); // sleep 10 msec - } - - if (err) - { - dev_err(dev, "[%s] Accessing FPGA failed.\n", __func__); - return err; - } - return NO_ERROR; -} -EXPORT_SYMBOL(tier4_fpga_check_access); - - -static int tier4_fpga_get_fps_camx_camy(struct device *dev, int des_number, int fps, int trigger_mode) -{ - int freq; - char str_fps_camx_camy[15] = "\0"; - -#ifdef DEBUG_INFO - dev_info(dev, "[%s] dns_number=%d trigger_mode=%de.\n", __func__, des_number, trigger_mode); -#endif - - switch (des_number){ - case 0: - strcpy(str_fps_camx_camy,"fps_cam1_cam2"); - break; - case 1: - strcpy(str_fps_camx_camy,"fps_cam3_cam4"); - break; - case 2: - strcpy(str_fps_camx_camy,"fps_cam5_cam6"); - break; - case 3: - strcpy(str_fps_camx_camy,"fps_cam7_cam8"); - break; - default: - strcpy(str_fps_camx_camy,"fps_cam?_cam?"); - break; - } - - if (trigger_mode == 1) - { - if ((fps > 5) && (fps <= 10)) - { - freq = fps; - } - else - { - freq = FREQ_10HZ; - dev_info(dev, "[%s] Invalid %s:%d, Set %s to %d.", __func__, str_fps_camx_camy, fps, str_fps_camx_camy, freq); - - } - } - else if (trigger_mode == 3) - { - if ((fps > 10) && (fps <= 20)) - { - freq = fps; - } - else - { - freq = FREQ_20HZ; - dev_info(dev, "[%s] Invalid %s:%d, Set %s to %d.", __func__, str_fps_camx_camy, fps, str_fps_camx_camy, freq); - } - } - else if (trigger_mode == 5) - { - if ((fps > 20) && (fps <= 30)) - { - freq = fps; - } - else - { - freq = FREQ_30HZ; - dev_info(dev, "[%s] Invalid %s:%d, Set %s to %d.", __func__, str_fps_camx_camy, fps, str_fps_camx_camy, freq); - } - } - -#ifdef DEBUG_INFO - dev_info(dev, "[%s] freq=%d.\n", __func__, freq); -#endif - - return freq; -} - -// -------------------------------------------- - -int tier4_fpga_set_fsync_signal_frequency(struct device *dev, int des_number, int trigger_mode) -{ - int err = 0; - u8 val8, addr8; - int freq = 0; - // u8 read_val = 0; - u8 freq_bitmask = 0x3F; // bit[0:5] - - - switch (des_number){ - case 0: - freq = tier4_fpga_get_fps_camx_camy(dev, des_number, fps_cam1_cam2, trigger_mode); - break; - case 1: - freq = tier4_fpga_get_fps_camx_camy(dev, des_number, fps_cam3_cam4, trigger_mode); - break; - case 2: - freq = tier4_fpga_get_fps_camx_camy(dev, des_number, fps_cam5_cam6, trigger_mode); - break; - case 3: - freq = tier4_fpga_get_fps_camx_camy(dev, des_number, fps_cam7_cam8, trigger_mode); - break; - default: - dev_err(dev, "[%s] Invalid des_number(%d)\n", __func__, des_number); - break; - } - - addr8 = (u8)(FPGA_REG_FREQ_BASE_ADDR + 12 * (des_number)); - val8 = (u8)(freq & freq_bitmask); - -#ifdef DEBUG_INFO - dev_info(dev, "[%s] freq=%d.\n", __func__, freq); -#endif - -// err = tier4_fpga_read_reg(dev, addr8, &read_val); -// if ((read_val & freq_bitmask) == val8) { -// // skip writing the same value to reg in order to save the flash write cycles -// dev_info(dev, "[%s] : Keep the frequency of fsync trigger to %d\n", __func__, val8); -// return err; -// } - - err = tier4_fpga_write_reg(dev, addr8, val8); - - if (err) - { - dev_err(dev, "[%s] Setting the frequency of fsync trigger failed.\n", __func__); - return err; - } - else - { - dev_info(dev, "[%s] Setting the frequency of fsync trigger to %d.\n", __func__, val8); - } - - return NO_ERROR; -} -EXPORT_SYMBOL(tier4_fpga_set_fsync_signal_frequency); - -int tier4_fpga_get_slave_addr(struct device *dev, struct tier4_gmsl_link_ctx *g_ctx) -{ - struct tier4_fpga *priv = dev_get_drvdata(dev); - - if (!g_ctx) - { - dev_err(dev, "[%s] g_ctx is null\n", __func__); - return -1; - } - - g_ctx->sdev_fpga_reg = priv->reg_addr; - - return 0; -} -EXPORT_SYMBOL(tier4_fpga_get_slave_addr); - -const struct of_device_id tier4_fpga_of_match[] = { - { - .compatible = "nvidia,tier4_fpga", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, tier4_fpga_of_match); - -// ----------------------------------------------------- - -static int tier4_fpga_parse_dt(struct tier4_fpga *priv, struct i2c_client *client) -{ - struct device_node *node = client->dev.of_node; - int err = 0; - - if (!node) - return -EINVAL; - - err = of_property_read_u32(node, "reg", &priv->reg_addr); - if (err < 0) - { - dev_err(&client->dev, "[%s] fpga reg not found\n", __func__); - return -EINVAL; - } - - priv->g_ctx.sdev_fpga_reg = priv->reg_addr; - - return NO_ERROR; -} - -// --------------------------------------------------------- - -static int tier4_fpga_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct tier4_fpga *priv; - int err = 0; - int inhibit_fpga_access = 0; - - dev_info(&client->dev, "[%s] probing FPGA\n", __func__); - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - priv->i2c_client = client; - - priv->regmap = devm_regmap_init_i2c(priv->i2c_client, &tier4_fpga_regmap_config); - if (IS_ERR(priv->regmap)) - { - dev_err(&client->dev, "[%s] devm_regmap_init() failed: %ld\n", __func__, PTR_ERR(priv->regmap)); - return -ENODEV; - } - - err = tier4_fpga_parse_dt(priv, client); - - if (err) - { - dev_err(&client->dev, "[%s] Unable to parse fpga dt\n", __func__); - return -EFAULT; - } - - mutex_init(&priv->lock); - - dev_set_drvdata(&client->dev, priv); - - err = tier4_fpga_check_access(&client->dev); - - if (err) - { - inhibit_fpga_access = 1; - } - - // default mode is disabling gnereation of fsync - - err = tier4_fpga_disable_fsync_mode(&client->dev); - - - if (err < 0) - { - dev_err(&client->dev, "[%s] Unable to disable generation of fsync.\n", __func__); - if ( inhibit_fpga_access ) - { - return NO_ERROR; - } - else - { - return -EINVAL; - } - } - - channel_count_fpga++; - - dev_info(&client->dev, "[%s] Probing FPGA succeeded.\n", __func__); - - return err; -} - -static int tier4_fpga_remove(struct i2c_client *client) -{ - struct tier4_fpga *priv; - - if (channel_count_fpga > 0) - channel_count_fpga--; - - if (client != NULL) - { - priv = dev_get_drvdata(&client->dev); - mutex_destroy(&priv->lock); - } - - return 0; -} - -// ---------------------------------------------- - -static const struct i2c_device_id tier4_fpga_id[] = { - { "tier4_fpga", 0 }, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, tier4_fpga_id); - -static struct i2c_driver tier4_fpga_i2c_driver = { - .driver = { - .name = "tier4_fpga", - .owner = THIS_MODULE, - }, - .probe = tier4_fpga_probe, - .remove = tier4_fpga_remove, - .id_table = tier4_fpga_id, -}; - -static int __init tier4_fpga_init(void) -{ - printk("FPGA Driver for Tier4 Cameras.\n"); - - return i2c_add_driver(&tier4_fpga_i2c_driver); -} - -static void __exit tier4_fpga_exit(void) -{ - i2c_del_driver(&tier4_fpga_i2c_driver); -} - -module_init(tier4_fpga_init); -module_exit(tier4_fpga_exit); - -MODULE_DESCRIPTION("FPGA driver tier4_fpga"); -MODULE_AUTHOR("Kohji Iwasaki"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-gw5300.c b/drivers/src/tier4-gw5300.c deleted file mode 100644 index d2357a0..0000000 --- a/drivers/src/tier4-gw5300.c +++ /dev/null @@ -1,964 +0,0 @@ -/* - * tier4_gw5300.c - tier4_gw5300 ISP driver - * - * Copyright (c) 2022-2023, TIER IV Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include -#include -#include - -#include "tier4-gmsl-link.h" -#include "tier4-gw5300.h" - -struct tier4_gw5300 -{ - struct i2c_client *i2c_client; - struct tier4_gmsl_link_ctx g_client; - struct mutex lock; - /* primary ISP properties */ - __u32 def_addr; -}; - -#define MAX_CHANNEL_NUM 8 - -#define NO_ERROR 0 - -/* count channel,the max MAX_CHANNEL_NUM*/ -static __u32 channel_count_gw5300; - -static struct tier4_gw5300 *prim_priv__[MAX_CHANNEL_NUM]; - -static u8 master_30fps[] = { - 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00 - , 0x80, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00 - , 0x00, 0x6A -}; - -static u8 master_10fps[] = { - 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00 - , 0x80, 0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00 - , 0x00, 0x38 -}; - -static u8 slave_10fps[] = { - 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00 - , 0x80, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00 - , 0x00, 0x42 -}; - -static u8 master_20fps[] = { - 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00 - , 0x80, 0x03, 0x00, 0x00, 0x00, 0x5A, 0x00, 0x00 - , 0x00, 0x74 -}; - -static u8 slave_20fps[] = { - 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00 - , 0x80, 0x03, 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00 - , 0x00, 0x79 -}; - -static u8 slave_30fps[] = { - 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00 - , 0x80, 0x03, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00 - , 0x00, 0x6F -}; - -static u8 master_10fps_slow[] = { - 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00 - , 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - , 0x00, 0x17 -}; - -static u8 slave_10fps_slow[] = { - 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, 0x12, 0x00 - , 0x80, 0x03, 0x00, 0x00, 0x00, 0x4B, 0x00, 0x00 - , 0x00, 0x65 -}; - - -/* - * C3 camera mode support - */ -struct mode_command { - u8 *command; - size_t len; - unsigned int delay_ms; -}; - -#define MODE_CMD(cmd, delay) \ - { \ - .command = (cmd), \ - .len = sizeof (cmd), \ - .delay_ms = delay, \ - } - -#define NUM_VA_ARGS(type, ...) (sizeof ((type[]) {__VA_ARGS__}) / sizeof (type)) - -#define MODE_SEQ(h_line_time_ns, ...) \ - { \ - .commands = (struct mode_command[]){ \ - __VA_ARGS__ \ - }, \ - .len = NUM_VA_ARGS(struct mode_command, __VA_ARGS__), \ - .h_line_ns = (h_line_time_ns) \ - } - -struct mode_sequence { - struct mode_command *commands; - size_t len; - u32 h_line_ns; -}; - -/* - * C3 preset modes - */ - -static u8 c3_master_5fps_cmd[] = { - 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, 0x12, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x17 -}; - -/* mode 0 */ -static struct mode_sequence c3_master_5fps_seq = - MODE_SEQ( - 40000, - MODE_CMD(c3_master_5fps_cmd, 0), - ); - -/* mode 4 */ -static u8 c3_master_20fps_cmd[] = { - 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, 0x12, 0x0, 0x80, 0x3, 0x0, 0x0, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x65 -}; -static struct mode_sequence c3_master_20fps_seq = - MODE_SEQ( - 20000, - MODE_CMD(c3_master_20fps_cmd, 0) - ); - -static u8 c3_master_20fps_ebd_cmd[] = { - 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, 0x12, 0x0, 0x80, 0x3, 0x0, 0x0, 0x0, 0x50, 0x0, 0x0, 0x0, 0x6a -}; - -/* mode 10 */ -static struct mode_sequence c3_master_20fps_ebd_seq = - MODE_SEQ( - 20000, - MODE_CMD(c3_master_20fps_ebd_cmd, 0) - ); - -static u8 c3_master_30fps_cmd[] = { - 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, 0x12, 0x0, 0x80, 0x3, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x38 -}; - -/* mode 6 */ -static struct mode_sequence c3_master_30fps_seq = - MODE_SEQ( - 13890, - MODE_CMD(c3_master_30fps_cmd, 0) - ); - -static u8 c3_master_30fps_ebd_cmd[] = { - 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, 0x12, 0x0, 0x80, 0x3, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x42 -}; - -/* mode 12 */ -static struct mode_sequence c3_master_30fps_ebd_seq = - MODE_SEQ( - 13890, - MODE_CMD(c3_master_30fps_ebd_cmd, 0) - ); - - -/* - * C3 derived modes - */ -static u8 c3_regmap_ffff[] = { - 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x25 -}; - -static u8 c3_standby_mode[] = { - 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, 0x4, 0x1b, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0x2, 0x1, 0x45 -}; - -static u8 c3_drive_mode_sel[] = { - 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, 0x40, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x2, 0x1, 0x68 -}; - -static u8 c3_master_sync_mode[] = { - 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, 0x41, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x2, 0x1, 0x6d -}; - -static u8 c3_sensor_streaming[] = { - 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, 0x4, 0x1b, 0x0, 0x0, 0x5c, 0x0, 0x0, 0x0, 0x2, 0x1, 0xa2 -}; - -static u8 c3_master_sync_mode_2[] = { - 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, 0x4, 0x1b, 0x0, 0x0, 0xa3, 0x0, 0x0, 0x0, 0x2, 0x1, 0xe9 -}; - -/* mode 1 */ -static struct mode_sequence c3_slave_5fps_seq = - MODE_SEQ( - 40000, - MODE_CMD(c3_master_5fps_cmd, 5000), - - MODE_CMD(c3_regmap_ffff, 500), - MODE_CMD(c3_standby_mode, 500), - MODE_CMD(c3_drive_mode_sel, 500), - MODE_CMD(c3_master_sync_mode, 500), - MODE_CMD(c3_sensor_streaming, 500), - MODE_CMD(c3_master_sync_mode_2, 500), - ); - -static u8 c3_20_to_10fps_cmd_1[] = { - 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, 0x50, 0x97, 0x0, 0x0, 0xc4, 0x0, 0x0, 0x0, 0x2, 0x1, 0xd2, -}; - -static u8 c3_20_to_10fps_cmd_2[] = { - 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, - 0x0, 0x51, 0x97, 0x0, 0x0, 0x09, 0x0, 0x0, 0x0, 0x2, 0x1, 0x18, -}; - -/* mode 2 */ -static struct mode_sequence c3_master_10fps_seq = - MODE_SEQ( - 20000, - MODE_CMD(c3_master_20fps_cmd, 5000), - - MODE_CMD(c3_20_to_10fps_cmd_1, 2000), - MODE_CMD(c3_20_to_10fps_cmd_2, 500), - ); - -/* mode 3 */ -static struct mode_sequence c3_slave_10fps_seq = - MODE_SEQ( - 20000, - MODE_CMD(c3_master_20fps_cmd, 5000), - - MODE_CMD(c3_20_to_10fps_cmd_1, 2000), - MODE_CMD(c3_20_to_10fps_cmd_2, 500), - - MODE_CMD(c3_regmap_ffff, 500), - MODE_CMD(c3_standby_mode, 500), - MODE_CMD(c3_drive_mode_sel, 500), - MODE_CMD(c3_master_sync_mode, 500), - MODE_CMD(c3_sensor_streaming, 500), - MODE_CMD(c3_master_sync_mode_2, 500), - ); - -/* mode 5 */ -static struct mode_sequence c3_slave_20fps_seq = - MODE_SEQ( - 20000, - MODE_CMD(c3_master_20fps_cmd, 5000), - - MODE_CMD(c3_regmap_ffff, 500), - MODE_CMD(c3_standby_mode, 500), - MODE_CMD(c3_drive_mode_sel, 500), - MODE_CMD(c3_master_sync_mode, 500), - MODE_CMD(c3_sensor_streaming, 500), - MODE_CMD(c3_master_sync_mode_2, 500), - ); - -/* mode 7 */ -static struct mode_sequence c3_slave_30fps_seq = - MODE_SEQ( - 13890, - MODE_CMD(c3_master_30fps_cmd, 5000), - - MODE_CMD(c3_regmap_ffff, 500), - MODE_CMD(c3_standby_mode, 500), - MODE_CMD(c3_drive_mode_sel, 500), - MODE_CMD(c3_master_sync_mode, 500), - MODE_CMD(c3_sensor_streaming, 500), - MODE_CMD(c3_master_sync_mode_2, 500), - ); - -/* mode 8 */ -static struct mode_sequence c3_master_10fps_ebd_seq = - MODE_SEQ( - 20000, - MODE_CMD(c3_master_20fps_ebd_cmd, 5000), - - MODE_CMD(c3_20_to_10fps_cmd_1, 2000), - MODE_CMD(c3_20_to_10fps_cmd_2, 500), - ); - -/* mode 9 */ -static struct mode_sequence c3_slave_10fps_ebd_seq = - MODE_SEQ( - 20000, - MODE_CMD(c3_master_20fps_ebd_cmd, 5000), - - MODE_CMD(c3_20_to_10fps_cmd_1, 2000), - MODE_CMD(c3_20_to_10fps_cmd_2, 500), - - MODE_CMD(c3_regmap_ffff, 500), - MODE_CMD(c3_standby_mode, 500), - MODE_CMD(c3_drive_mode_sel, 500), - MODE_CMD(c3_master_sync_mode, 500), - MODE_CMD(c3_sensor_streaming, 500), - MODE_CMD(c3_master_sync_mode_2, 500), - ); - -/* mode 11 */ -static struct mode_sequence c3_slave_20fps_ebd_seq = - MODE_SEQ( - 20000, - MODE_CMD(c3_master_20fps_ebd_cmd, 5000), - - MODE_CMD(c3_20_to_10fps_cmd_1, 2000), - MODE_CMD(c3_20_to_10fps_cmd_2, 500), - - MODE_CMD(c3_regmap_ffff, 500), - MODE_CMD(c3_standby_mode, 500), - MODE_CMD(c3_drive_mode_sel, 500), - MODE_CMD(c3_master_sync_mode, 500), - MODE_CMD(c3_sensor_streaming, 500), - MODE_CMD(c3_master_sync_mode_2, 500), - ); - -/* mode 13 */ -static struct mode_sequence c3_slave_30fps_ebd_seq = - MODE_SEQ( - 13890, - MODE_CMD(c3_master_30fps_ebd_cmd, 5000), - - MODE_CMD(c3_20_to_10fps_cmd_1, 2000), - MODE_CMD(c3_20_to_10fps_cmd_2, 500), - - MODE_CMD(c3_regmap_ffff, 500), - MODE_CMD(c3_standby_mode, 500), - MODE_CMD(c3_drive_mode_sel, 500), - MODE_CMD(c3_master_sync_mode, 500), - MODE_CMD(c3_sensor_streaming, 500), - MODE_CMD(c3_master_sync_mode_2, 500), - ); - -static struct mode_sequence c3_mode_seqs[GW5300_MODE_MAX]; - - -struct map_ctx -{ - u8 dt; - u16 addr; - u8 val; - u8 st_id; -}; - -#if 0 -static int tier4_gw5300_receive_msg(struct device *dev, u8 *data, int data_size ) -{ - int err = 0; - struct i2c_msg msg; - struct tier4_gw5300 *priv = dev_get_drvdata(dev); - - msg.addr = priv->i2c_client->addr; - msg.flags = I2C_M_RD; // I2C Read - msg.len = data_size; - msg.buf = data; - - err = i2c_transfer(priv->i2c_client->adapter, &msg, 1); - - if (err <= 0 ) { - dev_err(dev, "[%s] : i2c_transer receive message failed : slave addr = 0x%x\n", __func__, msg.addr ); - } - - return err; -} -#endif - -// ------------------------------------------------------------------- - -static int tier4_gw5300_send_and_recv_msg(struct device *dev, u8 *wdata, int wdata_size, u8 *rdata, int rdata_size) -{ - int err = 0; - struct i2c_msg msg[2]; - struct tier4_gw5300 *priv = dev_get_drvdata(dev); - - msg[0].addr = priv->i2c_client->addr; - msg[0].flags = 0; // I2C Write - msg[0].len = wdata_size; - msg[0].buf = wdata; - - msg[1].addr = priv->i2c_client->addr; - msg[1].flags = I2C_M_RD; // I2C Read - msg[1].len = rdata_size; - msg[1].buf = rdata; - - err = i2c_transfer(priv->i2c_client->adapter, msg, 2); - - if (err <= 0) - { - dev_err(dev, "[%s] : i2c_transer send message failed. %d: slave addr = 0x%x\n", __func__, err, msg[0].addr); - } - - return err; // the total number of bytes to have been sent or recived -} - -// ------------------------------------------------------------------- - -static int tier4_gw5300_c3_send_and_recv_msg(struct device *dev, u8 *wdata, int wdata_size, u8 *rdata, int rdata_size) -{ - return tier4_gw5300_send_and_recv_msg(dev, wdata, wdata_size, rdata, rdata_size); -} - -static int tier4_gw5300_mode_seq_send_and_recv_msg(struct device *dev, struct mode_sequence *mode_seq, u8 *rdata, int rdata_size) -{ - int i; - int err = 0; - - for (i = 0; i < mode_seq->len; ++i) { - struct mode_command *cmd = &mode_seq->commands[i]; - - err = tier4_gw5300_send_and_recv_msg(dev, cmd->command, cmd->len, rdata, rdata_size); - msleep(cmd->delay_ms); - if (err < 0) { - dev_err(dev, "%s: Failed to send a command[%d]: %d\n", __func__, i, err); - break; - } - } - - - return err; -} - -// ------------------------------------------------------------------- - -uint8_t calcCheckSum(const uint8_t *data, size_t size){ - uint8_t result = 0; - size_t i =0; - for(i=0; i> 8)&0xFF; - uint8_t b3 = 0; - uint8_t b4 = 0; - - dev_info(dev, "%s: integration time(%u[ns/H line]): max=(%d[us], %d[line]) min=(%d[us], %d[line])\n", - __func__, h_line_ns, max_integration_time, max_line, min_integration_time, min_line); - - cmd_integration_max[max_val_pos] = b1; - cmd_integration_max[max_val_pos+1] = b2; - cmd_integration_max[max_val_pos+2] = b3; - cmd_integration_max[max_val_pos+3] = b4; - cmd_integration_max[sizeof(cmd_integration_max)-1] = calcCheckSum(cmd_integration_max, sizeof(cmd_integration_max)); - - - b1 = min_line &0xFF; - b2 = (min_line >> 8)&0xFF; - - cmd_integration_min[min_val_pos] = b1; - cmd_integration_min[min_val_pos+1] = b2; - - cmd_integration_min[sizeof(cmd_integration_min)-1] = calcCheckSum(cmd_integration_min, sizeof(cmd_integration_min)); - - - msleep(20); - ret += tier4_gw5300_send_and_recv_msg(dev, cmd_integration_max, sizeof(cmd_integration_max), buf, sizeof(buf)); - msleep(20); - ret += tier4_gw5300_send_and_recv_msg(dev, cmd_integration_min, sizeof(cmd_integration_min), buf, sizeof(buf)); - - return ret; - -} - -int tier4_gw5300_c2_set_integration_time_on_aemode(struct device *dev, int trigger_mode, u32 max_integration_time, u32 min_integration_time) -{ - size_t h_line_ns = 12500; - - if (trigger_mode == GW5300_MASTER_MODE_10FPS_SLOW || - trigger_mode == GW5300_SLAVE_MODE_10FPS_SLOW) - h_line_ns = 50000; - - return tier4_gw5300_set_integration_time_on_aemode(dev, h_line_ns, max_integration_time, min_integration_time); -} -EXPORT_SYMBOL(tier4_gw5300_c2_set_integration_time_on_aemode); - - -int tier4_gw5300_c3_set_integration_time_on_aemode(struct device *dev, int trigger_mode, u32 max_integration_time, u32 min_integration_time) -{ - return tier4_gw5300_set_integration_time_on_aemode(dev, c3_mode_seqs[trigger_mode].h_line_ns, - max_integration_time, min_integration_time); -} -EXPORT_SYMBOL(tier4_gw5300_c3_set_integration_time_on_aemode); - -// ------------------------------------------------------------------ - -int tier4_gw5300_set_distortion_correction(struct device *dev, bool val) -{ -int ret = 0; - u8 buf[6]; - u8 cmd_dwp_on[]={0x33, 0x47, 0x06, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x80, 0x04, 0x00, 0x01, 0x52}; - u8 cmd_dwp_off[]={0x33, 0x47, 0x03, 0x00, 0x00, 0x00, 0x45, 0x00, 0x80, 0x42}; - - if(val){ - ret += tier4_gw5300_send_and_recv_msg(dev, cmd_dwp_on, sizeof(cmd_dwp_on), buf, sizeof(buf)); - }else{ - ret += tier4_gw5300_send_and_recv_msg(dev, cmd_dwp_off, sizeof(cmd_dwp_off), buf, sizeof(buf)); - } - return ret; -} -EXPORT_SYMBOL(tier4_gw5300_set_distortion_correction); - -// ------------------------------------------------------------------ - -int tier4_gw5300_c3_set_distortion_correction(struct device *dev, bool val) -{ -int ret = 0; - u8 buf[6]; - u8 cmd_dwp_on[] ={ 0x33, 0x47, 0x6, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x80, 0x04, 0x00, 0x01, 0x52}; - u8 cmd_dwp_off[] ={ 0x33, 0x47, 0x3, 0x00, 0x00, 0x00, 0x45, 0x00, 0x80, 0x042}; - - if(val){ - ret += tier4_gw5300_c3_send_and_recv_msg(dev, cmd_dwp_on, sizeof(cmd_dwp_on), buf, sizeof(buf)); - }else{ - ret += tier4_gw5300_c3_send_and_recv_msg(dev, cmd_dwp_off, sizeof(cmd_dwp_off), buf, sizeof(buf)); - } - return ret; -} -EXPORT_SYMBOL(tier4_gw5300_c3_set_distortion_correction); - -// ------------------------------------------------------------------ - -int tier4_gw5300_c3_set_auto_exposure(struct device *dev, bool val) -{ - int ret = 0; - u8 buf[6]; - u8 cmd_auto_exp_on[] ={ 0x33, 0x47, 0x0C, 0x00, 0x00, 0x00, 0x55, 0x00, 0x80, 0x05, 0x00, 0x07, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x69 }; - u8 cmd_auto_exp_off[] ={ 0x33, 0x47, 0x0C, 0x00, 0x00, 0x00, 0x55, 0x00, 0x80, 0x05, 0x00, 0x07, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x6A }; - - dev_info(dev, "%s: auto exposure is %s\n", __func__, val ? "on" : "off"); - - if (val) { - ret += tier4_gw5300_c3_send_and_recv_msg(dev, cmd_auto_exp_on, sizeof(cmd_auto_exp_on), buf, sizeof(buf)); - } else { - ret += tier4_gw5300_c3_send_and_recv_msg(dev, cmd_auto_exp_off, sizeof(cmd_auto_exp_off), buf, sizeof(buf)); - } - return ret; -} -EXPORT_SYMBOL(tier4_gw5300_c3_set_auto_exposure); - -// ------------------------------------------------------------------ - -int tier4_gw5300_check_device(struct device *dev, u8 *rdata, int rdata_size ) -{ - int err = 0; - struct i2c_msg msg[2]; - struct tier4_gw5300 *priv = dev_get_drvdata(dev); - - msg[0].addr = priv->i2c_client->addr; - msg[0].flags = I2C_M_RD; // I2C Read - msg[0].len = rdata_size; - msg[0].buf = rdata; - - err = i2c_transfer(priv->i2c_client->adapter, msg, 1); - - if (err <= 0) - { - dev_err(dev, "[%s] : i2c_transer send message failed. : slave addr = 0x%x\n", __func__, msg[0].addr); - } - else - { - err = NO_ERROR; - } - - return err; -} -EXPORT_SYMBOL(tier4_gw5300_check_device); - -int tier4_gw5300_prim_slave_addr(struct tier4_gmsl_link_ctx *g_ctx) -{ - if (!g_ctx) - { - dev_err(&prim_priv__[channel_count_gw5300 - 1]->i2c_client->dev, "[%s] : Failed. g_ctx is null\n", __func__); - return -1; - } - - g_ctx->sdev_isp_def = prim_priv__[channel_count_gw5300 - 1]->def_addr; - - return 0; -} -EXPORT_SYMBOL(tier4_gw5300_prim_slave_addr); - -int tier4_gw5300_setup_sensor_mode(struct device *dev, int sensor_mode) -{ - int err = 0; - u8 buf[6]; - - memset(buf, 0x00, 6); - - switch (sensor_mode) - { - case GW5300_MASTER_MODE_10FPS: - err = tier4_gw5300_send_and_recv_msg(dev, master_10fps, sizeof(master_10fps), buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up Master mode 10fps failed. %d message has been sent to gw5300.\n", __func__, - err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up Master mode 10fps failed. %d message has been sent to gw5300.\n", __func__, - err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - - case GW5300_SLAVE_MODE_10FPS: - err = tier4_gw5300_send_and_recv_msg(dev, slave_10fps, sizeof(slave_10fps), buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up Slave mode 10fps failed. %d message has been sent to gw5300.\n", __func__, err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up Slave mode 10fps failed. %d message has been sent to gw5300.\n", __func__, err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - case GW5300_MASTER_MODE_20FPS: - err = tier4_gw5300_send_and_recv_msg(dev, master_20fps, sizeof(master_20fps), buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up Master mode 20fps failed. %d message has been sent to gw5300.\n", __func__, - err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up Master mode 20fps failed. %d message has been sent to gw5300.\n", __func__, - err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - case GW5300_SLAVE_MODE_20FPS: - err = tier4_gw5300_send_and_recv_msg(dev, slave_20fps, sizeof(slave_20fps), buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up Slave mode 20fps failed. %d message has been sent to gw5300.\n", __func__, err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up Slave mode 20fps failed. %d message has been sent to gw5300.\n", __func__, err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - case GW5300_MASTER_MODE_30FPS: - err = tier4_gw5300_send_and_recv_msg(dev, master_30fps, sizeof(master_30fps), buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up Master mode 30fps failed. %d message has been sent to gw5300.\n", __func__, - err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up Master mode 30fps failed. %d message has been sent to gw5300.\n", __func__, - err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - - case GW5300_SLAVE_MODE_30FPS: - err = tier4_gw5300_send_and_recv_msg(dev, slave_30fps, sizeof(slave_30fps), buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up Slave mode 30fps failed. %d message has been sent to gw5300.\n", __func__, err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up Slave mode 30fps failed. %d message has been sent to gw5300.\n", __func__, err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - case GW5300_MASTER_MODE_10FPS_SLOW: - err = tier4_gw5300_send_and_recv_msg(dev, master_10fps_slow, sizeof(master_10fps_slow), buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up Slow clock Master mode 10fps failed. %d message has been sent to gw5300.\n", __func__, - err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up Slow clock Master mode 10fps failed. %d message has been sent to gw5300.\n", __func__, - err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - case GW5300_SLAVE_MODE_10FPS_SLOW: - err = tier4_gw5300_send_and_recv_msg(dev, slave_10fps_slow, sizeof(slave_10fps_slow), buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up Slow clock Slave mode 10fps failed. %d message has been sent to gw5300.\n", __func__, err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up Slow clock Slave mode 10fps failed. %d message has been sent to gw5300.\n", __func__, err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - default: - break; - } - -error: - - return err; -} -EXPORT_SYMBOL(tier4_gw5300_setup_sensor_mode); - -// ----------- for C3 camera ---------- - -int tier4_gw5300_c3_setup_sensor_mode(struct device *dev, int sensor_mode) -{ - int err = 0; - u8 buf[6]; - - memset(buf, 0x00, 6); - - switch (sensor_mode) - { - case GW5300_MASTER_MODE_10FPS: - case GW5300_SLAVE_MODE_10FPS: - case GW5300_MASTER_MODE_20FPS: - case GW5300_SLAVE_MODE_20FPS: - case GW5300_MASTER_MODE_30FPS: - case GW5300_SLAVE_MODE_30FPS: - case GW5300_MASTER_MODE_5FPS: - case GW5300_SLAVE_MODE_5FPS: - case GW5300_MASTER_MODE_10FPS_EBD: - case GW5300_SLAVE_MODE_10FPS_EBD: - case GW5300_MASTER_MODE_20FPS_EBD: - case GW5300_SLAVE_MODE_20FPS_EBD: - case GW5300_MASTER_MODE_30FPS_EBD: - case GW5300_SLAVE_MODE_30FPS_EBD: - err = tier4_gw5300_mode_seq_send_and_recv_msg(dev, &c3_mode_seqs[sensor_mode], buf, sizeof(buf)); - if (err < 0) - { - dev_err(dev, "[%s] : Setting up %s failed. %d message has been sent to gw5300.\n", __func__, - gw5300_mode_name[sensor_mode], err); - goto error; - } - else if (err == 0) - { // it means that 0 message has been sent. - dev_err(dev, "[%s] : Setting up %s failed. %d message has been sent to gw5300.\n", __func__, - gw5300_mode_name[sensor_mode], err); - err = -999; - goto error; - } - else - { - err = 0; - } - break; - default: - break; - } - -error: - - return err; -} -EXPORT_SYMBOL(tier4_gw5300_c3_setup_sensor_mode); - - -static int tier4_gw5300_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct tier4_gw5300 *priv; - int err = 0; - struct device_node *node = client->dev.of_node; - - dev_info(&client->dev, "[%s] : probing GW5300 ISP\n", __func__); - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - priv->i2c_client = client; - - mutex_init(&priv->lock); - - if (of_get_property(node, "is-prim-isp", NULL)) - { - if (prim_priv__[channel_count_gw5300] && channel_count_gw5300 >= MAX_CHANNEL_NUM) - { - dev_err(&client->dev, "[%s] : prim-isp already exists\n", __func__); - return -EEXIST; - } - - err = of_property_read_u32(node, "reg", &priv->def_addr); - if (err < 0) - { - dev_err(&client->dev, "[%s] : reg not found\n", __func__); - return -EINVAL; - } - - prim_priv__[channel_count_gw5300] = priv; - channel_count_gw5300++; - } - - dev_set_drvdata(&client->dev, priv); - - /* dev communication gets validated when GMSL link setup is done */ - dev_info(&client->dev, "[%s] : Probing succeeded\n", __func__); - - return err; -} - -static int tier4_gw5300_remove(struct i2c_client *client) -{ - struct tier4_gw5300 *priv; - - if (channel_count_gw5300 > 0) - channel_count_gw5300--; - - if (client != NULL) - { - priv = dev_get_drvdata(&client->dev); - mutex_destroy(&priv->lock); - } - - return 0; -} - -static const struct i2c_device_id tier4_gw5300_id[] = { - { "tier4_gw5300", 0 }, - {}, -}; - -const struct of_device_id tier4_gw5300_of_match[] = { - { - .compatible = "nvidia,tier4_gw5300", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, tier4_gw5300_of_match); -MODULE_DEVICE_TABLE(i2c, tier4_gw5300_id); - -static struct i2c_driver tier4_gw5300_i2c_driver = { - .driver = { - .name = "tier4_gw5300", - .owner = THIS_MODULE, - }, - .probe = tier4_gw5300_probe, - .remove = tier4_gw5300_remove, - .id_table = tier4_gw5300_id, -}; - -static int __init tier4_gw5300_init(void) -{ - printk(KERN_INFO "ISP Driver for TIERIV Camera.\n"); - - c3_mode_seqs[GW5300_MASTER_MODE_5FPS] = c3_master_5fps_seq; - c3_mode_seqs[GW5300_SLAVE_MODE_5FPS] = c3_slave_5fps_seq; - - c3_mode_seqs[GW5300_MASTER_MODE_10FPS] = c3_master_10fps_seq; - c3_mode_seqs[GW5300_MASTER_MODE_10FPS_EBD] = c3_master_10fps_ebd_seq; - c3_mode_seqs[GW5300_SLAVE_MODE_10FPS] = c3_slave_10fps_seq; - c3_mode_seqs[GW5300_SLAVE_MODE_10FPS_EBD] = c3_slave_10fps_ebd_seq; - - c3_mode_seqs[GW5300_MASTER_MODE_20FPS] = c3_master_20fps_seq; - c3_mode_seqs[GW5300_MASTER_MODE_20FPS_EBD] = c3_master_20fps_ebd_seq; - c3_mode_seqs[GW5300_SLAVE_MODE_20FPS] = c3_slave_20fps_seq; - c3_mode_seqs[GW5300_SLAVE_MODE_20FPS_EBD] = c3_slave_20fps_ebd_seq; - - c3_mode_seqs[GW5300_MASTER_MODE_30FPS] = c3_master_30fps_seq; - c3_mode_seqs[GW5300_MASTER_MODE_30FPS_EBD] = c3_master_30fps_ebd_seq; - c3_mode_seqs[GW5300_SLAVE_MODE_30FPS] = c3_slave_30fps_seq; - c3_mode_seqs[GW5300_SLAVE_MODE_30FPS_EBD] = c3_slave_30fps_ebd_seq; - - return i2c_add_driver(&tier4_gw5300_i2c_driver); -} - -static void __exit tier4_gw5300_exit(void) -{ - i2c_del_driver(&tier4_gw5300_i2c_driver); -} - -module_init(tier4_gw5300_init); -module_exit(tier4_gw5300_exit); - -MODULE_DESCRIPTION("GW5300 ISP driver tier4_gw5300"); -MODULE_AUTHOR("Kohji Iwasaki"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-imx490.c b/drivers/src/tier4-imx490.c deleted file mode 100644 index d3a35eb..0000000 --- a/drivers/src/tier4-imx490.c +++ /dev/null @@ -1,1966 +0,0 @@ -/* - * tier4_imsx490.c - imx490 sensor driver - * - * Copyright (c) 2022-2023, TIER IV Inc. All rights reserved. - * Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tier4-fpga.h" -#include "tier4-gmsl-link.h" -#include "tier4-gw5300.h" -#include "tier4-hw-model.h" -#include "tier4-isx021-extern.h" -#include "tier4-max9295.h" -#include "tier4-max9296.h" - -MODULE_SOFTDEP("pre: tier4_max9296"); -MODULE_SOFTDEP("pre: tier4_max9295"); -MODULE_SOFTDEP("pre: tier4_gw5300"); -MODULE_SOFTDEP("pre: tier4_fpga"); -MODULE_SOFTDEP("pre: tier4_isx021"); - -#define USE_DISTORTION_CORRECTION 1 - -// Register Address - -#define IMX490_DEFAULT_FRAME_LENGTH (2000) - -#define BIT_SHIFT_8 8 -#define BIT_SHIFT_16 16 -#define MASK_1_BIT 0x1 -#define MASK_4_BIT 0xF -#define MASK_8_BIT 0xFF - -#define NO_ERROR 0 -#define NO_C2_CAMERA (-490) - -#define TIME_120_MILISEC 120000 -#define TIME_121_MILISEC 121000 - -#define ISP_PRIM_SLAVE_ADDR 0x6D - -#define TIER4_C2_CAMERA 1 - -#define SENSOR_ID_IMX490 490 - -#define MAX_NUM_CAMERA 8 - -#define FSYNC_FREQ_HZ 10 - -enum -{ - IMX490_MODE_2880x1860_CROP_30FPS, - IMX490_MODE_START_STREAM, - IMX490_MODE_STOP_STREAM, -}; - -static const int tier4_imx490_30fps[] = { - 30, -}; -static const struct camera_common_frmfmt tier4_imx490_frmfmt[] = { - { { 2880, 1860 }, tier4_imx490_30fps, 1, 0, IMX490_MODE_2880x1860_CROP_30FPS }, -}; - -const struct of_device_id tier4_imx490_of_match[] = { - { - .compatible = "nvidia,tier4_imx490", - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, tier4_imx490_of_match); - -// If you add new ioctl VIDIOC_S_EXT_CTRLS function, please add new CID to the following table. -// and define the CID number in nvidia/include/media/tegra-v4l2-camera.h - -static const u32 ctrl_cid_list[] = { - TEGRA_CAMERA_CID_GAIN, TEGRA_CAMERA_CID_EXPOSURE, TEGRA_CAMERA_CID_EXPOSURE_SHORT, - TEGRA_CAMERA_CID_FRAME_RATE, TEGRA_CAMERA_CID_HDR_EN, - // TEGRA_CAMERA_CID_DISTORTION_CORRECTION, -}; - -struct tier4_imx490 -{ - struct i2c_client *i2c_client; - const struct i2c_device_id *id; - struct v4l2_subdev *subdev; - struct device *ser_dev; - struct device *dser_dev; - struct device *isp_dev; - struct tier4_gmsl_link_ctx g_ctx; - u32 frame_length; - struct camera_common_data *s_data; - struct tegracam_device *tc_dev; - int trigger_mode; - bool distortion_correction; - bool last_distortion_correction; - bool auto_exposure; - bool inhibit_fpga_access; - struct device *fpga_dev; -}; - -static const struct regmap_config tier4_sensor_regmap_config = { - .reg_bits = 16, - .val_bits = 8, - .cache_type = REGCACHE_RBTREE, -}; - -struct st_priv -{ - struct i2c_client *p_client; - struct tier4_imx490 *p_priv; - struct tegracam_device *p_tc_dev; - bool isp_ser_shutdown; - bool des_shutdown; - bool running; -}; - -static struct st_priv wst_priv[MAX_NUM_CAMERA]; - -static struct mutex tier4_imx490_lock; - -static int camera_channel_count = 0; - -// --- module parameter --- - -static int trigger_mode; -static int fsync_mfp = 0; -static int enable_distortion_correction = 1; - - -#define IMX490_MIN_EXPOSURE_TIME 11000 // 11 milisecond -#define IMX490_MAX_EXPOSURE_TIME 33000 // 33 milisecond - -static int shutter_time_min = IMX490_MIN_EXPOSURE_TIME; -static int shutter_time_max = IMX490_MAX_EXPOSURE_TIME; - -module_param(trigger_mode, int, 0644); -module_param(shutter_time_min, int, S_IRUGO | S_IWUSR); -module_param(shutter_time_max, int, S_IRUGO | S_IWUSR); - - -module_param(fsync_mfp, int, S_IRUGO | S_IWUSR); -module_param(enable_distortion_correction, int, S_IRUGO | S_IWUSR); - -// ------------------------ -static char upper(char c) -{ - if ('a' <= c && c <= 'z') - { - c = c - ('a' - 'A'); - } - return c; -} - -static void to_upper_string(char *out, const char *in) -{ - int i; - - i = 0; - while (in[i] != '\0') - { - out[i] = upper(in[i]); - i++; - } -} - -static inline int tier4_imx490_read_reg(struct camera_common_data *s_data, u16 addr, u8 *val) -{ - int err = 0; - u32 reg_val = 0; - - err = regmap_read(s_data->regmap, addr, ®_val); - - if (err) - { - dev_err(s_data->dev, "[%s] : I2C read failed, address=0x%x\n", __func__, addr); - } - else - { - *val = reg_val & 0xFF; - } - return err; -} - -static int tier4_imx490_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) -{ - int err = 0; - - err = regmap_write(s_data->regmap, addr, val); - - if (err) - { - dev_err(s_data->dev, "[%s] : I2C write failed at x%x=[0x%x]\n", __func__, addr, val); - } - - return err; -} - -// ------------------------------------------------ - -static int tier4_imx490_set_fsync_trigger_mode(struct tier4_imx490 *priv, int mode) -{ - int err = 0; - struct device *dev = priv->s_data->dev; - int des_num = 0; - - if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || - (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - priv->inhibit_fpga_access = false; - - dev_info(dev, "[%s] : Set fsync trigger mode.\n", __func__); - - err = tier4_fpga_check_access(priv->fpga_dev); - if (err) - { - priv->inhibit_fpga_access = true; - } - - if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_DISABLE) - { - dev_info(dev, "[%s] : Disabling FPGA fsync.\n", __func__); - - err = tier4_fpga_disable_fsync_mode(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Disabling FPGA fsync failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } - else - { - err = tier4_fpga_enable_fsync_mode(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA generate fsync failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - - if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_AUTO) - { - // Auto Trigger Mode - err = tier4_fpga_set_fsync_auto_trigger(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA Fsync Auto Trigger mode failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - des_num = priv->g_ctx.reg_mux; - err = tier4_fpga_set_fsync_signal_frequency(priv->fpga_dev, des_num, priv->trigger_mode); - if (err) - { - dev_err(dev, "[%s] : Setting the frequency of fsync genrated by FPGA failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } - else if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_MANUAL) - { - // Manual Trigger Mode - dev_info(dev, "[%s] : Enabling FPGA Fsync Manual Trigger mode.\n", __func__); - - err = tier4_fpga_set_fsync_manual_trigger(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA Fsync Maunal Trigger mode failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } - } - } - - err = tier4_max9296_setup_gpi(priv->dser_dev, fsync_mfp); - - if (err) - { - dev_err(dev, "[%s] :tier4_max9296_setup_gpi() failed\n", __func__); - return err; - } - - err = tier4_max9295_setup_gpo(priv->ser_dev); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9295_setup_gpo() failed\n", __func__); - return err; - } - - err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, mode); - if (err) - { - dev_err(dev, "[%s] : tier4_gw5300_setup_sensor_mode() failed\n", __func__); - return err; - } - - return err; -} - -static struct mutex serdes_lock__; - -static int tier4_imx490_gmsl_serdes_setup(struct tier4_imx490 *priv) -{ - int err = 0; - int des_err = 0; - struct device *dev; - - if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client) - { - return -EINVAL; - } - - dev = &priv->i2c_client->dev; - - mutex_lock(&serdes_lock__); - - /* For now no separate power on required for serializer device */ - - if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - tier4_max9296_power_on(priv->dser_dev); - } - - /* setup serdes addressing and control pipeline */ - - - err = tier4_max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev); - - if (err) - { - dev_err(dev, "[%s] : GMSL deserializer link config failed\n", __func__); - goto error; - } - - err = tier4_max9295_setup_control(priv->ser_dev); - - /* proceed even if ser setup failed, to setup deser correctly */ - if (err) - { - dev_err(dev, "[%s] : GMSL serializer setup failed\n", __func__); - goto error; - } - - des_err = tier4_max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev); - - if (des_err) - { - dev_err(dev, "[%s] : GMSL deserializer : setup failed\n", __func__); - err = des_err; - } - -error: - mutex_unlock(&serdes_lock__); - return err; -} - -static void tier4_imx490_gmsl_serdes_reset(struct tier4_imx490 *priv) -{ - mutex_lock(&serdes_lock__); - - /* reset serdes addressing and control pipeline */ - tier4_max9295_reset_control(priv->ser_dev); - - tier4_max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev, true); - - if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && - (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - tier4_max9296_power_off(priv->dser_dev); - } - - mutex_unlock(&serdes_lock__); -} - -static int tier4_imx490_power_on(struct camera_common_data *s_data) -{ - int err = 0; - struct camera_common_power_rail *pw = s_data->power; - struct camera_common_pdata *pdata = s_data->pdata; - struct device *dev = s_data->dev; - - if (pdata && pdata->power_on) - { - err = pdata->power_on(pw); - - if (err) - { - dev_err(dev, "[%s] : failed.\n", __func__); - } - else - { - pw->state = SWITCH_ON; - } - return err; - } - - pw->state = SWITCH_ON; - - return err; -} - -static int tier4_imx490_power_off(struct camera_common_data *s_data) -{ - int err = 0; - struct camera_common_power_rail *pw = s_data->power; - struct camera_common_pdata *pdata = s_data->pdata; - struct device *dev = s_data->dev; - - if (pdata && pdata->power_off) - { - err = pdata->power_off(pw); - - if (!err) - { - goto power_off_done; - } - else - { - dev_err(dev, "[%s] : power off failed.\n", __func__); - } - return err; - } - -power_off_done: - pw->state = SWITCH_OFF; - - return err; -} - -static int tier4_imx490_power_get(struct tegracam_device *tc_dev) -{ - struct camera_common_power_rail *pw = tc_dev->s_data->power; - int err = 0; - - pw->state = SWITCH_OFF; - - return err; -} - -static int tier4_imx490_power_put(struct tegracam_device *tc_dev) -{ - if (unlikely(!tc_dev->s_data->power)) - { - return -EFAULT; - } - - return NO_ERROR; -} - -static int tier4_imx490_set_group_hold(struct tegracam_device *tc_dev, bool val) -{ - volatile int err = 0; - - return err; -} - -static int tier4_imx490_set_gain(struct tegracam_device *tc_dev, s64 val) -{ - int err = 0; - - // struct camera_common_data *s_data = tc_dev->s_data; - - // struct device *dev = tc_dev->dev; - - return err; -} - -/* ------------------------------------------------------------------------- */ - -static int tier4_imx490_set_frame_rate(struct tegracam_device *tc_dev, s64 val) -{ - int err = 0; - - struct tier4_imx490 *priv = (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); - // struct device dev = tc_dev->dev; - - /* fixed 30fps */ - priv->frame_length = IMX490_DEFAULT_FRAME_LENGTH; - - return err; -} - -/* ------------------------------------------------------------------------- */ - -static int tier4_imx490_set_auto_exposure(struct tegracam_device *tc_dev) -{ - int err = 0; - //struct tier4_imx490 *priv = (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); - - return err; -} - -/* ------------------------------------------------------------------------- */ - -static int tier4_imx490_set_exposure(struct tegracam_device *tc_dev, s64 val) -{ - int err = 0; - - struct tier4_imx490 *priv = (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); - tier4_gw5300_c2_set_integration_time_on_aemode(priv->isp_dev, priv->trigger_mode, val, val); - - return err; -} -// -------------------------------------------------------------------------------------- -// Enable Distortion Coreection -// -------------------------------------------------------------------------------------- -#if USE_DISTORTION_CORRECTION - -static int tier4_imx490_set_distortion_correction(struct tegracam_device *tc_dev, bool val) -{ - int err = 0; - struct tier4_imx490 *priv = (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); - - if (priv->last_distortion_correction != val) - { - dev_info(&priv->i2c_client->dev, "[%s] : Setting distortion correction mode :%s.\n", __func__,val?"True":"False"); - - err = tier4_gw5300_set_distortion_correction(priv->isp_dev, val); - if (err <= 0) - { - dev_info(&priv->i2c_client->dev, "[%s] : Setting distortion correction mode failed.\n", __func__ ); - } - else - { - err = 0; - priv->last_distortion_correction = val; - } - } - - return err; -} -#endif - -// -------------------------------------------------------------------------------------- -// If you add new ioctl VIDIOC_S_EXT_CTRLS function, -// please add the new memeber and the function at the following table. - -static struct tegracam_ctrl_ops tier4_imx490_ctrl_ops = { - .numctrls = ARRAY_SIZE(ctrl_cid_list), - .ctrl_cid_list = ctrl_cid_list, - .set_gain = tier4_imx490_set_gain, - .set_exposure = tier4_imx490_set_exposure, - .set_exposure_short = tier4_imx490_set_exposure, - .set_frame_rate = tier4_imx490_set_frame_rate, - .set_group_hold = tier4_imx490_set_group_hold, - // .set_distortion_correction = tier4_imx490_set_distortion_correction, -}; - -// -------------------------------------------------------------------------------------- - -static struct camera_common_pdata *tier4_imx490_parse_dt(struct tegracam_device *tc_dev) -{ - struct device *dev = tc_dev->dev; - struct device_node *node = dev->of_node; - struct camera_common_pdata *board_priv_pdata; - const struct of_device_id *match; - int err; - - if (!node) - { - return NULL; - } - - match = of_match_device(tier4_imx490_of_match, dev); - - if (!match) - { - dev_err(dev, "[%s] : Failed to find matching dt id\n", __func__); - return NULL; - } - - board_priv_pdata = devm_kzalloc(dev, sizeof(*board_priv_pdata), GFP_KERNEL); - - err = of_property_read_string(node, "mclk", &board_priv_pdata->mclk_name); - - if (err) - { - dev_err(dev, "[%s] : mclk not in DT\n", __func__); - } - - return board_priv_pdata; -} - -/* tier4_imx490_set_mode() can not be needed. But it remains for compatiblity */ - -static int tier4_imx490_set_mode(struct tegracam_device *tc_dev) -{ - volatile int err = 0; - - return err; -} - -static int tier4_imx490_start_one_streaming(struct tegracam_device *tc_dev) -{ - struct tier4_imx490 *priv = (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); - struct device *dev = tc_dev->dev; - int err; - - /* enable serdes streaming */ - - err = tier4_max9295_setup_streaming(priv->ser_dev); - - if (err) - { - goto exit; - } - - err = tier4_max9296_setup_streaming(priv->dser_dev, dev); - - if (err) - { - dev_err(dev, "[%s] : Setup Streaming failed\n", __func__); - goto exit; - } - - if (priv->auto_exposure == true) - { - err = tier4_imx490_set_auto_exposure(tc_dev); - } - - - if (err) - { - dev_err(dev, "[%s] : Setting Digital Gain to default value failed\n", __func__); - goto exit; - } - - dev_info(dev, "[%s] : trigger_mode = %d\n", __func__, trigger_mode); - - priv->trigger_mode = trigger_mode; - - switch (priv->trigger_mode) - { - - case GW5300_MASTER_MODE_10FPS: - - dev_info(dev, "[%s] : Setting camera sensor to Master mode 10fps\n", __func__); - - err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, GW5300_MASTER_MODE_10FPS); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to Master mode 10fps failed\n", __func__); - return err; - } - - priv->last_distortion_correction = 1; - - break; - - case GW5300_SLAVE_MODE_10FPS: - - dev_info(dev, "[%s] : Setting camera sensor to Slave mode 10fps\n", __func__); - - err = tier4_imx490_set_fsync_trigger_mode(priv, GW5300_SLAVE_MODE_10FPS); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to Slave mode 10fps failed\n", __func__); - goto exit; - } - - priv->last_distortion_correction = 1; - - msleep(20); - - break; - - case GW5300_MASTER_MODE_20FPS: - - dev_info(dev, "[%s] : Setting camera sensor to Master mode 20fps\n", __func__); - - err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, GW5300_MASTER_MODE_20FPS); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to Master mode 20fps failed\n", __func__); - return err; - } - - priv->last_distortion_correction = 1; - - break; - - case GW5300_SLAVE_MODE_20FPS: - - dev_info(dev, "[%s] : Setting camera sensor to Slave mode 20fps\n", __func__); - - err = tier4_imx490_set_fsync_trigger_mode(priv, GW5300_SLAVE_MODE_20FPS); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to Slave mode 20fps failed\n", __func__); - return err; - } - - priv->last_distortion_correction = 1; - - break; - - case GW5300_MASTER_MODE_30FPS: - - dev_info(dev, "[%s] : Setting camera sensor to Master mode 30fps\n", __func__); - - err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, GW5300_MASTER_MODE_30FPS); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to Master mode 30fps failed\n", __func__); - return err; - } - - break; - - case GW5300_SLAVE_MODE_30FPS: - - dev_info(dev, "[%s] : Setting camera sensor to slave mode 30fps\n", __func__); - - err = tier4_imx490_set_fsync_trigger_mode(priv, GW5300_SLAVE_MODE_30FPS); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to Slave mode 30fps failed\n", __func__); - return err; - } - - priv->last_distortion_correction = 1; - - break; - - case GW5300_SLAVE_MODE_10FPS_SLOW: - - err = tier4_imx490_set_fsync_trigger_mode(priv, GW5300_SLAVE_MODE_10FPS_SLOW); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to Slow clock Slave mode 10fps failed\n", __func__); - goto exit; - } - - priv->last_distortion_correction = 1; - - msleep(20); - - break; - - case GW5300_MASTER_MODE_10FPS_SLOW: - - err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, GW5300_MASTER_MODE_10FPS_SLOW); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to Slow clock Master mode 10fps failed\n", __func__); - return err; - } - - priv->last_distortion_correction = 1; - - break; - - default: // case of trigger_mode < 0 - - dev_err(dev, "[%s] : The camera sensor mode(fsync mode) is invalid.\n", __func__); - - return err; - } - - -#if USE_DISTORTION_CORRECTION - - if (priv->last_distortion_correction != enable_distortion_correction ) - { - usleep_range(900000, 910000); - //msleep(900); - } - - if (enable_distortion_correction == 0xCAFE) - { - // if not set kernel param, read device tree param - if (priv->distortion_correction == false) - { - err = tier4_imx490_set_distortion_correction(tc_dev, priv->distortion_correction); - - if (err) - { - dev_err(dev, "[%s] : Disabling Distortion Correction failed\n", __func__); - goto exit; - } - msleep(20); - } - }else{ - err = tier4_imx490_set_distortion_correction(tc_dev, enable_distortion_correction==1); - if (err) - { - dev_err(dev, "[%s] : Setup Distortion Correction failed\n", __func__); - goto exit; - } - msleep(20); - } - -#endif - - err = tier4_max9296_start_streaming(priv->dser_dev, dev); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_start_stream() failed\n", __func__); - return err; - } - - msleep(200); - -//#if 0 - msleep(1000); - tier4_gw5300_c2_set_integration_time_on_aemode(priv->isp_dev, priv->trigger_mode, shutter_time_max, shutter_time_min); -//#endif - - dev_info(dev, "[%s] : Camera has started streaming\n", __func__); - - return NO_ERROR; - -exit: - - dev_err(dev, "[%s] : Camera failed to start streaming.\n", __func__); - - return err; -} - -static bool tier4_imx490_is_camera_connected_to_port(int nport) -{ - if (wst_priv[nport].p_client) - { - return true; - } - return false; -} - -static bool tier4_imx490_check_null_tc_dev_for_port(int nport) -{ - if (wst_priv[nport].p_tc_dev == NULL) - { - return true; - } - return false; -} - -static bool tier4_imx490_is_camera_running_on_port(int nport) -{ - if (wst_priv[nport].running) - { - return true; - } - return false; -} - -static bool tier4_imx490_is_current_port(struct tier4_imx490 *priv, int nport) -{ - if (priv->i2c_client == wst_priv[nport].p_client) - { - return true; - } - return false; -} - -static void tier4_imx490_set_running_flag(int nport, bool flag) -{ - wst_priv[nport].running = flag; -} - -static int tier4_imx490_stop_streaming(struct tegracam_device *tc_dev) -{ - struct device *dev = tc_dev->dev; - struct tier4_imx490 *priv = (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); - int i, err = 0; - - mutex_lock(&tier4_imx490_lock); - - for (i = 0; i < camera_channel_count; i++) - { - if (tier4_imx490_is_camera_connected_to_port(i)) - { - if (tier4_imx490_is_current_port(priv, i) && tier4_imx490_is_camera_running_on_port(i)) - { - /* disable serdes streaming */ - err = tier4_max9296_stop_streaming(priv->dser_dev, dev); - if (err) - { - return err; - } - tier4_imx490_set_running_flag(i, false); - break; - } - } - } - - mutex_unlock(&tier4_imx490_lock); - - return NO_ERROR; -} - -/* *************************************************************************** */ -/* 1. In the case where a camera is connected to GMSL A port on a Des. */ -/* */ -/* a > Check if another camera is connected to GMSL B port */ -/* a-1) Connected: */ -/* b > Check if another camera on GMSL B port is running */ -/* b-1) Running: */ -/* c > Check if the camera on GMSL A port is running */ -/* c-1) Running : */ -/* Do nothing and return */ -/* c-2) Not running : */ -/* Start the camera on GMSL A port. */ -/* b-2) Not Running: */ -/* Start the camera on GMSL B port. */ -/* a-2) Not connected : */ -/* b > Check if the camera on GMSL A port is running */ -/* b-1) Running : */ -/* Do nothing and return */ -/* b-2) Not running : */ -/* Start the camera on GMSL A port. */ -/* */ -/* 2. In the case where a camera is connected to GMSL B port on a Des. */ -/* */ -/* a > Check if the camera on GMSL B port is running */ -/* a-1) Running : */ -/* Do nothing and return */ -/* a-2) Not running : */ -/* Start the camera on GMSL B port. */ -/* *************************************************************************** */ - -static int tier4_imx490_start_streaming(struct tegracam_device *tc_dev) -{ - int i, err = 0; - // struct tier4_imx490 *next_client_priv; - struct tier4_imx490 *priv = (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); - struct device *dev = tc_dev->dev; - - mutex_lock(&tier4_imx490_lock); - - for (i = 0; i < camera_channel_count; i++) - { - if (i & 0x1) - { // if i = 1,3,5,7 ( GMSL B port of a Des ) - - if (tier4_imx490_is_camera_connected_to_port(i)) - { // a camera is connected to GMSL B portL - - if ((tier4_imx490_is_current_port(priv, i) == true) && (tier4_imx490_is_camera_running_on_port(i) == false)) - { - err = tier4_imx490_start_one_streaming(wst_priv[i].p_tc_dev); - - if (err) - { - dev_err(dev, "[%s] : Failed to start one streaming.\n", __func__); - goto error_exit; - } - // wst_priv[i].running = true; - tier4_imx490_set_running_flag(i, true); - break; - } - } - } - else - { // if i = 0,2,4,6 ( GMSL A side port of a Des0,Des1,Des2 or Des3 ) - - if ((tier4_imx490_is_camera_connected_to_port(i) == true) && (tier4_imx490_is_current_port(priv, i) == true)) - { - if (tier4_imx490_is_camera_connected_to_port(i + 1) == false) - { // if another one camera( GMSL B port) is not - // connected to Des. - if (tier4_imx490_is_camera_running_on_port(i) == false) - { // and if the camera is not running. - - err = tier4_imx490_start_one_streaming(wst_priv[i].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Failed to start one streaming for next imx490 client.\n", __func__); - goto error_exit; - } - tier4_imx490_set_running_flag(i, true); - } - break; - } - - // two cameras are connected to one Des. - - if (tier4_imx490_check_null_tc_dev_for_port(i + 1)) - { // check if tc_dev is null - dev_err(dev, "[%s] : wst_priv[%d].p_tc_dev is NULL.\n", __func__, i + 1); - err = -EINVAL; - goto error_exit; - } - - if (tier4_imx490_is_camera_running_on_port(i + 1) == false) - { - err = tier4_imx490_start_one_streaming(wst_priv[i + 1].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Failed to start one streaming for the next imx490 client.\n", __func__); - goto error_exit; - } - tier4_imx490_set_running_flag(i + 1, true); - usleep_range(200000, 220000); - //msleep(200); - mutex_unlock(&tier4_imx490_lock); - tier4_imx490_stop_streaming(wst_priv[i + 1].p_tc_dev); - mutex_lock(&tier4_imx490_lock); - tier4_imx490_set_running_flag(i + 1, false); - } - - if (tier4_imx490_is_camera_running_on_port(i) == false) - { - err = tier4_imx490_start_one_streaming(wst_priv[i].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Failed to start one streaming for current imx490 client.\n", __func__); - goto error_exit; - } - tier4_imx490_set_running_flag(i, true); - } - } - } - } // for loop - - err = NO_ERROR; - -error_exit: - - mutex_unlock(&tier4_imx490_lock); - - // tier4_imx490_sensor_mutex_unlock(); - - return err; -} - -static struct camera_common_sensor_ops tier4_imx490_common_ops = { - .numfrmfmts = ARRAY_SIZE(tier4_imx490_frmfmt), - .frmfmt_table = tier4_imx490_frmfmt, - .power_on = tier4_imx490_power_on, - .power_off = tier4_imx490_power_off, - .write_reg = tier4_imx490_write_reg, - .read_reg = tier4_imx490_read_reg, - .parse_dt = tier4_imx490_parse_dt, - .power_get = tier4_imx490_power_get, - .power_put = tier4_imx490_power_put, - .set_mode = tier4_imx490_set_mode, - .start_streaming = tier4_imx490_start_streaming, - .stop_streaming = tier4_imx490_stop_streaming, -}; - -static int tier4_imx490_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - //struct i2c_client *client = v4l2_get_subdevdata(sd); - - return NO_ERROR; -} - -static const struct v4l2_subdev_internal_ops tier4_imx490_subdev_internal_ops = { - .open = tier4_imx490_open, -}; - -static const char *of_stdout_options; - -static int tier4_imx490_board_setup(struct tier4_imx490 *priv) -{ - struct tegracam_device *tc_dev = priv->tc_dev; - struct device *dev = tc_dev->dev; - struct device_node *node = dev->of_node; - struct device_node *ser_node; - struct i2c_client *ser_i2c = NULL; - struct device_node *dser_node; - struct i2c_client *dser_i2c = NULL; - struct device_node *isp_node; - struct i2c_client *isp_i2c = NULL; - struct device_node *fpga_node = NULL; - struct i2c_client *fpga_i2c = NULL; - struct device_node *gmsl; - struct device_node *root_node; - int value = 0xFFFF; - const char *str_value; - const char *str_value1[2]; - int i; - int err; - const char *str_model; - char upper_str_model[64]; - char *str_err; - char *sub_str_err; - - root_node = of_find_node_opts_by_path("/", &of_stdout_options); - - err = of_property_read_string(root_node, "model", &str_model); - - if (err < 0) - { - dev_err(dev, "[%s] : model not found\n", __func__); - goto error; - } - - memset(upper_str_model, 0, 64); - - to_upper_string(upper_str_model, str_model); - - priv->g_ctx.hardware_model = HW_MODEL_UNKNOWN; - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_XAVIER); - if (str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_XAVIER_DEVKIT; - } - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_XAVIER); - if (str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_XAVIER; - } - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ORIN); - - if (str_err) - { - - sub_str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_ORIN); - - if (sub_str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_ORIN; - } - else - { - priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_ORIN_DEVKIT; - } - } - - - dev_info(dev, "[%s] : model=%s\n", __func__, str_model); - dev_info(dev, "[%s] : hardware_model=%d\n", __func__, priv->g_ctx.hardware_model); - - if (priv->g_ctx.hardware_model == HW_MODEL_UNKNOWN) - { - dev_err(dev, "[%s] : Unknown Hardware Sysytem !\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_isp_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : def-addr not found\n", __func__); - goto error; - } - - if (err < 0) - { - dev_err(dev, "[%s] : reg not found\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "def-addr", &priv->g_ctx.sdev_isp_def); - - if (err < 0) - { - dev_err(dev, "[%s] : def-addr not found\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "reg_mux", &priv->g_ctx.reg_mux); - - if (err < 0) - { - dev_err(dev, "[%s] : reg_mux not found\n", __func__); - goto error; - } - -// err = of_property_read_string(node, "fsync-mode", &str_value); -// -// if (err < 0) -// { -// dev_err(dev, "[%s] : No fsync-mode found\n", __func__); -// goto error; -// } -// -// if (!strcmp(str_value, "true")) -// { -// priv->fsync_mode = true; -// } -// else -// { -// priv->fsync_mode = false; -// } - - err = of_property_read_string(node, "distortion-correction", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No distortion-correction found\n", __func__); - goto error; - } - - if (!strcmp(str_value, "true")) - { - priv->distortion_correction = true; - } - else - { - priv->distortion_correction = false; - } - - err = of_property_read_string(node, "auto-exposure", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : Inavlid Exposure mode.\n", __func__); - goto error; - } - - if (!strcmp(str_value, "true")) - { - priv->auto_exposure = true; - } - else - { - priv->auto_exposure = false; - } - -#if 0 - priv->g_ctx.fpga_generate_fsync = false; - - if (( priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER ) || - ( priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN )) { - - err = of_property_read_string(node, "fpga-generate-fsync", &str_value); - - if ( err < 0) { - if ( err == -EINVAL ) { - dev_info(dev, "[%s] : Parameter of fpga-generate-fsync does not exist.\n", __func__); - } else { - dev_err(dev, "[%s] : Parameter of fpga-generate-fsync is invalid .\n", __func__); - goto error; - } - } else { - if (!strcmp(str_value, "true")) { - priv->g_ctx.fpga_generate_fsync = true; - } - } - } -#endif - - // For Ser node - ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0); - - if (ser_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,gmsl-ser-device"); - goto error; - } - - err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : Serializer reg not found\n", __func__); - goto error; - } - - ser_i2c = of_find_i2c_device_by_node(ser_node); - - of_node_put(ser_node); - - if (ser_i2c == NULL) - { - dev_err(dev, "[%s] : Missing Serializer Dev Handle\n", __func__); - goto error; - } - if (ser_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing serializer driver\n", __func__); - goto error; - } - - priv->ser_dev = &ser_i2c->dev; - - // For ISP node - - isp_node = of_parse_phandle(node, "nvidia,isp-device", 0); - - if (isp_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,isp-device"); - goto error; - } - - err = of_property_read_u32(isp_node, "reg", &priv->g_ctx.sdev_isp_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : ISP reg not found\n", __func__); - goto error; - } - - isp_i2c = of_find_i2c_device_by_node(isp_node); - - of_node_put(isp_node); - - if (isp_i2c == NULL) - { - dev_err(dev, "[%s] : Missing ISP Dev Handle\n", __func__); - goto error; - } - if (isp_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing ISP driver\n", __func__); - goto error; - } - - priv->isp_dev = &isp_i2c->dev; - - err = tier4_gw5300_prim_slave_addr(&priv->g_ctx); - if (err) - { - dev_err(dev, "[%s] : ISP Prim slave address is unavailable, the default address(0x6D) is applied.\n", __func__); - priv->g_ctx.sdev_isp_def = ISP_PRIM_SLAVE_ADDR; - } - - priv->g_ctx.sdev_reg = priv->g_ctx.sdev_isp_reg; - priv->g_ctx.sdev_def = priv->g_ctx.sdev_isp_def; - - // For Dser node - - dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0); - - if (dser_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,gmsl-dser-device"); - goto error; - } - - dser_i2c = of_find_i2c_device_by_node(dser_node); - - of_node_put(dser_node); - - if (dser_i2c == NULL) - { - dev_err(dev, "[%s] : Missing deserializer dev handle\n", __func__); - goto error; - } - - if (dser_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing deserializer driver\n", __func__); - goto error; - } - - priv->dser_dev = &dser_i2c->dev; - - if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || - (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - // for FPGA node - - fpga_node = of_parse_phandle(node, "nvidia,fpga-device", 0); - - if (fpga_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,fpga-device"); - goto error; - } - - err = of_property_read_u32(fpga_node, "reg", &priv->g_ctx.sdev_fpga_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : FPGA reg not found\n", __func__); - goto error; - } - - fpga_i2c = of_find_i2c_device_by_node(fpga_node); - - of_node_put(fpga_node); - - if (fpga_i2c == NULL) - { - dev_err(dev, "[%s] : Missing FPGA Dev Handle\n", __func__); - goto error; - } - if (fpga_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing FPGA driver\n", __func__); - goto error; - } - - priv->fpga_dev = &fpga_i2c->dev; - } - - /* populate g_ctx from DT */ - - gmsl = of_get_child_by_name(node, "gmsl-link"); - - if (gmsl == NULL) - { - dev_err(dev, "[%s] : Missing GMSL-Link device node\n", __func__); - err = -EINVAL; - goto error; - } - - err = of_property_read_string(gmsl, "dst-csi-port", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No dst-csi-port found\n", __func__); - goto error; - } - - priv->g_ctx.dst_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B; - - err = of_property_read_string(gmsl, "src-csi-port", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No src-csi-port found\n", __func__); - goto error; - } - - priv->g_ctx.src_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B; - - err = of_property_read_string(gmsl, "csi-mode", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No csi-mode found\n", __func__); - goto error; - } - - if (!strcmp(str_value, "1x4")) - { - priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE; - } - else if (!strcmp(str_value, "2x4")) - { - priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE; - } - else if (!strcmp(str_value, "4x2")) - { - priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE; - } - else if (!strcmp(str_value, "2x2")) - { - priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE; - } - else - { - dev_err(dev, "[%s] :Invalid csi-mode\n", __func__); - goto error; - } - - err = of_property_read_string(gmsl, "serdes-csi-link", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No serdes-csi-link found\n", __func__); - goto error; - } - - priv->g_ctx.serdes_csi_link = (!strcmp(str_value, "a")) ? GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B; - - err = of_property_read_u32(gmsl, "st-vc", &value); - - if (err < 0) - { - dev_err(dev, "[%s] : No st-vc info\n", __func__); - goto error; - } - - priv->g_ctx.st_vc = value; - - err = of_property_read_u32(gmsl, "vc-id", &value); - - if (err < 0) - { - dev_err(dev, "[%s] : No vc-id info\n", __func__); - goto error; - } - - priv->g_ctx.dst_vc = value; - - err = of_property_read_u32(gmsl, "num-lanes", &value); - - if (err < 0) - { - dev_err(dev, "[%s] : No num-lanes info\n", __func__); - goto error; - } - - priv->g_ctx.num_csi_lanes = value; - - priv->g_ctx.num_streams = of_property_count_strings(gmsl, "streams"); - - if (priv->g_ctx.num_streams <= 0) - { - dev_err(dev, "[%s] : No streams found\n", __func__); - err = -EINVAL; - goto error; - } - - for (i = 0; i < priv->g_ctx.num_streams; i++) - { - of_property_read_string_index(gmsl, "streams", i, &str_value1[i]); - - if (!str_value1[i]) - { - dev_err(dev, "[%s] : Invalid Stream Info\n", __func__); - goto error; - } - - if (!strcmp(str_value1[i], "raw12")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_RAW_12; - } - else if (!strcmp(str_value1[i], "yuv8")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_YUV_8; - } - else if (!strcmp(str_value1[i], "embed")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_EMBED; - } - else if (!strcmp(str_value1[i], "ued-u1")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_UED_U1; - } - else - { - dev_err(dev, "[%s] : Invalid stream data type\n", __func__); - goto error; - } - } - - priv->g_ctx.s_dev = dev; - - return NO_ERROR; - -error: - dev_err(dev, "[%s] : Board Setup failed\n", __func__); - return err; -} - -static int tier4_imx490_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct device *dev = &client->dev; - struct device_node *node = dev->of_node; - struct tegracam_device *tc_dev; - struct tier4_imx490 *priv; - int err = 0; - - dev_info(dev, "[%s] : Probing V4L2 Sensor.\n", __func__); - - if (!IS_ENABLED(CONFIG_OF) || !node) - { - return -EINVAL; - } - - wst_priv[camera_channel_count].p_client = NULL; - wst_priv[camera_channel_count].p_priv = NULL; - wst_priv[camera_channel_count].p_tc_dev = NULL; - - wst_priv[camera_channel_count].isp_ser_shutdown = false; - wst_priv[camera_channel_count].des_shutdown = false; - wst_priv[camera_channel_count].running = false; - - priv = devm_kzalloc(dev, sizeof(struct tier4_imx490), GFP_KERNEL); - - if (!priv) - { - dev_err(dev, "[%s] : Unable to allocate Memory!\n", __func__); - return -ENOMEM; - } - - tc_dev = devm_kzalloc(dev, sizeof(struct tegracam_device), GFP_KERNEL); - - if (!tc_dev) - { - return -ENOMEM; - } - - priv->i2c_client = tc_dev->client = client; - - tc_dev->dev = dev; - - strncpy(tc_dev->name, "imx490", sizeof(tc_dev->name)); - - tc_dev->dev_regmap_config = &tier4_sensor_regmap_config; - tc_dev->sensor_ops = &tier4_imx490_common_ops; - tc_dev->v4l2sd_internal_ops = &tier4_imx490_subdev_internal_ops; - tc_dev->tcctrl_ops = &tier4_imx490_ctrl_ops; - - err = tegracam_device_register(tc_dev); - - if (err) - { - dev_err(dev, "[%s] : Tegra Camera Driver Registration failed\n", __func__); - return err; - } - - priv->tc_dev = tc_dev; - priv->s_data = tc_dev->s_data; - priv->subdev = &tc_dev->s_data->subdev; - - tegracam_set_privdata(tc_dev, (void *)priv); - - priv->g_ctx.sensor_id = SENSOR_ID_IMX490; - - tier4_isx021_sensor_mutex_lock(); - - err = tier4_imx490_board_setup(priv); - - if (err) - { - dev_err(dev, "[%s] : Board Setup failed\n", __func__); - goto err_tegracam_unreg; - } - - /* Pair sensor to serializer dev */ - - err = tier4_max9295_sdev_pair(priv->ser_dev, &priv->g_ctx); - - if (err) - { - dev_err(&client->dev, "[%s] : GMSL Ser Pairing failed\n", __func__); - goto err_tegracam_unreg; - } - /* Register sensor to deserializer dev */ - - err = tier4_max9296_sdev_register(priv->dser_dev, &priv->g_ctx); - - if (err) - { - dev_err(&client->dev, "[%s] : GMSL Deserializer Register failed\n", __func__); - goto err_max9295_unpair; - } - - /* - * gmsl serdes setup - * - * Sensor power on/off should be the right place for serdes - * setup/reset. But the problem is, the total required delay - * in serdes setup/reset exceeds the frame wait timeout, looks to - * be related to multiple channel open and close sequence - * issue (#BUG 200477330). - * Once this bug is fixed, these may be moved to power on/off. - * The delays in serdes is as per guidelines and can't be reduced, - * so it is placed in probe/remove, though for that, deserializer - * would be powered on always post boot, until 1.2v is supplied - * to deserializer from CVB. - */ - - err = tier4_imx490_gmsl_serdes_setup(priv); - - if (err) - { - dev_err(&client->dev, "[%s] : GMSL Serdes setup failed\n", __func__); - goto err_max9296_unreg; - } - - err = tegracam_v4l2subdev_register(tc_dev, true); - - if (err) - { - dev_err(dev, "[%s] : Tegra Camera Subdev Registration failed\n", __func__); - goto err_max9296_unreg; - } - - wst_priv[camera_channel_count].p_client = client; - wst_priv[camera_channel_count].p_priv = priv; - wst_priv[camera_channel_count].p_tc_dev = tc_dev; - - camera_channel_count++; - - tier4_isx021_sensor_mutex_unlock(); - - return NO_ERROR; - -// tier4_isx021_sensor_mutex_unlock(); - -// dev_info(&client->dev, "Detected Tier4 IMX490 sensor\n"); - -err_max9296_unreg: - tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); -err_max9295_unpair: - tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); -err_tegracam_unreg: - tegracam_device_unregister(priv->tc_dev); - - tier4_isx021_sensor_mutex_unlock(); - -// dev_info(dev, "[%s] :camera_channel_count = %d p_client = %p \n", __func__, camera_channel_count, -// wst_priv[camera_channel_count].p_client); - - - return err; - //return NO_ERROR; // err; -} - -static void tier4_imx490_shutdown(struct i2c_client *client); - -static int tier4_imx490_remove(struct i2c_client *client) -{ - struct camera_common_data *s_data = to_camera_common_data(&client->dev); - struct tier4_imx490 *priv = (struct tier4_imx490 *)s_data->priv; - - tier4_imx490_shutdown(client); - - tier4_imx490_gmsl_serdes_reset(priv); - - tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); - tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); - - tegracam_v4l2subdev_unregister(priv->tc_dev); - - tegracam_device_unregister(priv->tc_dev); - - return NO_ERROR; -} - -static struct mutex tier4_imx490_lock; - -static bool tier4_imx490_is_isp_ser_shutdown(int nport) -{ - if (wst_priv[nport].isp_ser_shutdown) - { - return true; - } - return false; -} - -static bool tier4_imx490_is_des_shutdown(int nport) -{ - if (wst_priv[nport].des_shutdown) - { - return true; - } - return false; -} - -static void tier4_imx490_set_isp_ser_shutdown(int nport, bool val) -{ - wst_priv[nport].isp_ser_shutdown = val; -} - -static void tier4_imx490_set_des_shutdown(int nport, bool val) -{ - wst_priv[nport].des_shutdown = val; -} - -static bool tier4_imx490_is_current_i2c_client(struct i2c_client *client, int nport) -{ - if (client == wst_priv[nport].p_client) - { - return true; - } - return false; -} - -// ---------------------------------------------------------------------------- - -static void tier4_imx490_shutdown(struct i2c_client *client) -{ - struct tier4_imx490 *priv = NULL; - int i; - - tier4_isx021_sensor_mutex_lock(); - - mutex_lock(&tier4_imx490_lock); - - if (!client) - { - goto error_exit; - } - - for (i = 0; i < camera_channel_count; i++) - { - if (tier4_imx490_is_current_i2c_client(client, i)) - { - priv = wst_priv[i].p_priv; - - if (i & 0x1) - { // Even port number( GMSL B port on a Des : i = port_number -1 ) - - if (tier4_imx490_is_camera_connected_to_port(i - 1)) - { // if a camera connected to another(GMSL A)port on a Des. - // a camera is connected to each port of the Des. - if (tier4_imx490_is_isp_ser_shutdown(i - 1)) - { // ISP and Ser on another(GMSL A) port have been already shut down ? - - if (tier4_imx490_is_des_shutdown(i - 1) == false) - { // if Des on another(GMSL A)port is not shutdown yet - tier4_imx490_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx490_set_des_shutdown(i, true); // Des will be shut down - } - else - { // if Des on the another port is already shut down. This is Error case. - tier4_imx490_set_isp_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_imx490_set_des_shutdown(i, false); // Des will not be shutdown - } - } - else - { // The camera ISP and Ser on another(GMSL A) port are not shut down yet. - - if (tier4_imx490_is_des_shutdown(i - 1) == false) - { // if Des is not shut down yet. - tier4_imx490_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx490_set_des_shutdown(i, false); // The Des won't be shut down. - } - else - { // Only Des on another port is already shut down. This is Error case. - tier4_imx490_set_isp_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_imx490_set_des_shutdown(i, false); // Des will not be shut down. - } - } // a camera is connected to only (GMSL B) port on Des. - tier4_imx490_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx490_set_des_shutdown(i, true); // The Des won't be shut down. - } - } - else - { // if ( i & 0x1 ) == 0 - - if (tier4_imx490_is_camera_connected_to_port(i + 1)) - { // Another camera is connected to another(GMSL B) port on the Des - - if (tier4_imx490_is_isp_ser_shutdown(i + 1)) - { // if the ISP and Ser on another port are already shut down - - if (tier4_imx490_is_des_shutdown(i + 1) == false) - { // if Des is not shut down yet. - tier4_imx490_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx490_set_des_shutdown(i, false); // The Des will be shut down. - } - else - { // Des is already shut down. This is Error case. - tier4_imx490_set_isp_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_imx490_set_des_shutdown(i, false); // The Des will not be shut down. - } - } - else - { // The ISP and Ser on another(GMSL B) port are not shut down yet. - - if (tier4_imx490_is_des_shutdown(i + 1) == false) - { // if Des on another(GMSL B) port is not shut down yet. - - tier4_imx490_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx490_set_des_shutdown(i, false); // The Des will not be shut down. - } - else - { // Only Des on another(GMSL B) port is already shut down. - // This is Error case. - tier4_imx490_set_isp_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_imx490_set_des_shutdown(i, false); // The Des will not be shut down. - } - } - } - else - { - tier4_imx490_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx490_set_des_shutdown(i, true); // The Des will be shut down. - } - } // if ( i & 0x1 ) - // break; - - if (tier4_imx490_is_isp_ser_shutdown(i)) - { - // Reset camera sensor - tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_IMX490, false); - // S/W Reset max9295 - tier4_max9295_reset_control(priv->ser_dev); - } - - if (tier4_imx490_is_des_shutdown(i)) - { - // S/W Reset max9296 - tier4_max9296_reset_control(priv->dser_dev, &client->dev, true); - } - - if (priv == NULL || i >= camera_channel_count) - { - mutex_unlock(&tier4_imx490_lock); - tier4_isx021_sensor_mutex_unlock(); - return; - } - } - - } // for loop - -error_exit: - - mutex_unlock(&tier4_imx490_lock); - - tier4_isx021_sensor_mutex_unlock(); -} -static const struct i2c_device_id tier4_imx490_id[] = { { "tier4_imx490", 0 }, {} }; - -MODULE_DEVICE_TABLE(i2c, tier4_imx490_id); - -static struct i2c_driver tier4_imx490_i2c_driver = { - .driver = { - .name = "tier4_imx490", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(tier4_imx490_of_match), - }, - .probe = tier4_imx490_probe, - .remove = tier4_imx490_remove, - .shutdown = tier4_imx490_shutdown, - .id_table = tier4_imx490_id, -}; - -static int __init tier4_imx490_init(void) -{ - mutex_init(&serdes_lock__); - mutex_init(&tier4_imx490_lock); - - printk(KERN_INFO "TIERIV Automotive HDR Camera driver.\n"); - - return i2c_add_driver(&tier4_imx490_i2c_driver); -} - -static void __exit tier4_imx490_exit(void) -{ - mutex_destroy(&serdes_lock__); - mutex_destroy(&tier4_imx490_lock); - - i2c_del_driver(&tier4_imx490_i2c_driver); -} - -module_init(tier4_imx490_init); -module_exit(tier4_imx490_exit); - -MODULE_DESCRIPTION("TIERIV Automotive HDR Camera driver"); -MODULE_AUTHOR("Originaly NVIDIA Corporation"); -MODULE_AUTHOR("K.Iwasaki"); -MODULE_AUTHOR("Y.Fujii"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-imx728.c b/drivers/src/tier4-imx728.c deleted file mode 100644 index 4db760e..0000000 --- a/drivers/src/tier4-imx728.c +++ /dev/null @@ -1,1891 +0,0 @@ -/* - * tier4_imx728.c - imx728 sensor driver - * - * Copyright (c) 2022-2023, TIER IV Inc. All rights reserved. - * Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tier4-fpga.h" -#include "tier4-gmsl-link.h" -#include "tier4-gw5300.h" -#include "tier4-hw-model.h" -#include "tier4-isx021-extern.h" -#include "tier4-max9295.h" -#include "tier4-max9296.h" - -MODULE_SOFTDEP("pre: tier4_max9296"); -MODULE_SOFTDEP("pre: tier4_max9295"); -MODULE_SOFTDEP("pre: tier4_gw5300"); -MODULE_SOFTDEP("pre: tier4_fpga"); -MODULE_SOFTDEP("pre: tier4_isx021"); -MODULE_SOFTDEP("pre: tier4_imx490"); - -#define USE_DISTORTION_CORRECTION 1 - -// Register Address - -#define IMX728_DEFAULT_FRAME_LENGTH (2350) - -#define BIT_SHIFT_8 8 -#define BIT_SHIFT_16 16 -#define MASK_1_BIT 0x1 -#define MASK_4_BIT 0xF -#define MASK_8_BIT 0xFF - -#define POWER_ON 1 -#define POWER_OFF 0 - -#define NO_ERROR 0 -//#define NO_C3_CAMERA (-728) - -//#define TIME_120_MILISEC 120000 -//#define TIME_121_MILISEC 121000 - -#define ISP_PRIM_SLAVE_ADDR 0x6D - -//#define TIER4_C3_CAMERA 1 - -#define MAX_NUM_CAMERA 8 - -//#define FSYNC_FREQ_HZ 10 - -enum -{ - IMX728_MODE_3840x2160_CROP_20FPS, - IMX728_MODE_START_STREAM, - IMX728_MODE_STOP_STREAM, -}; - -static const int tier4_imx728_20fps[] = { - 20, -}; -static const struct camera_common_frmfmt tier4_imx728_frmfmt[] = { - { { 3840, 2160 }, tier4_imx728_20fps, 1, 0, IMX728_MODE_3840x2160_CROP_20FPS }, -// { { 3840, 2163 }, tier4_imx728_20fps, 1, 0, IMX728_MODE_3840x2160_CROP_20FPS }, -}; - -const struct of_device_id tier4_imx728_of_match[] = { - { - .compatible = "nvidia,tier4_imx728", - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, tier4_imx728_of_match); - -// If you add new ioctl VIDIOC_S_EXT_CTRLS function, please add new CID to the following table. -// and define the CID number in nvidia/include/media/tegra-v4l2-camera.h - -static const u32 ctrl_cid_list[] = { - TEGRA_CAMERA_CID_GAIN, TEGRA_CAMERA_CID_EXPOSURE, TEGRA_CAMERA_CID_EXPOSURE_SHORT, - TEGRA_CAMERA_CID_FRAME_RATE, TEGRA_CAMERA_CID_HDR_EN, - // TEGRA_CAMERA_CID_DISTORTION_CORRECTION, -}; - -struct tier4_imx728 -{ - struct i2c_client *i2c_client; - const struct i2c_device_id *id; - struct v4l2_subdev *subdev; - struct device *ser_dev; - struct device *dser_dev; - struct device *isp_dev; - struct tier4_gmsl_link_ctx g_ctx; - u32 frame_length; - struct camera_common_data *s_data; - struct tegracam_device *tc_dev; - int trigger_mode; - bool distortion_correction; - bool last_distortion_correction; - bool inhibit_fpga_access; - struct device *fpga_dev; -}; - -static const struct regmap_config tier4_sensor_regmap_config = { - .reg_bits = 16, - .val_bits = 8, - .cache_type = REGCACHE_RBTREE, -}; - -struct st_priv -{ - struct i2c_client *p_client; - struct tier4_imx728 *p_priv; - struct tegracam_device *p_tc_dev; - bool isp_ser_shutdown; - bool des_shutdown; - bool running; -}; - -static struct st_priv wst_priv[MAX_NUM_CAMERA]; - -static struct mutex tier4_imx728_lock; - -static int camera_channel_count = 0; - -// --- module parameter --- - -static int trigger_mode; -static int fsync_mfp = 0; -static int enable_distortion_correction = 1; -static int enable_auto_exposure = 0xCAFE; - - -#define IMX728_MIN_EXPOSURE_TIME 11000 // 11 milisecond -#define IMX728_MAX_EXPOSURE_TIME 33000 // 33 milisecond - -static int shutter_time_min = IMX728_MIN_EXPOSURE_TIME; -static int shutter_time_max = IMX728_MAX_EXPOSURE_TIME; - -module_param(trigger_mode, int, 0644); -module_param(shutter_time_min, int, S_IRUGO | S_IWUSR); -module_param(shutter_time_max, int, S_IRUGO | S_IWUSR); - - -module_param(fsync_mfp, int, S_IRUGO | S_IWUSR); -module_param(enable_distortion_correction, int, S_IRUGO | S_IWUSR); -module_param(enable_auto_exposure, int, S_IRUGO | S_IWUSR); - -// ------------------------ -static char upper(char c) -{ - if ('a' <= c && c <= 'z') - { - c = c - ('a' - 'A'); - } - return c; -} - -static void to_upper_string(char *out, const char *in) -{ - int i; - - i = 0; - while (in[i] != '\0') - { - out[i] = upper(in[i]); - i++; - } -} - -static inline int tier4_imx728_read_reg(struct camera_common_data *s_data, u16 addr, u8 *val) -{ - int err = 0; - u32 reg_val = 0; - - err = regmap_read(s_data->regmap, addr, ®_val); - - if (err) - { - dev_err(s_data->dev, "[%s] : I2C read failed, address=0x%x\n", __func__, addr); - } - else - { - *val = reg_val & 0xFF; - } - return err; -} - -static int tier4_imx728_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) -{ - int err = 0; - - err = regmap_write(s_data->regmap, addr, val); - - if (err) - { - dev_err(s_data->dev, "[%s] : I2C write failed at x%x=[0x%x]\n", __func__, addr, val); - } - - return err; -} - -// ------------------------------------------------ - -static int tier4_imx728_set_fsync_trigger_mode(struct tier4_imx728 *priv, int mode) -{ - int err = 0; - struct device *dev = priv->s_data->dev; - int des_num = 0; - - if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || - (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - priv->inhibit_fpga_access = false; - - dev_info(dev, "[%s] : Set fsync trigger mode.\n", __func__); - - err = tier4_fpga_check_access(priv->fpga_dev); - if (err) - { - priv->inhibit_fpga_access = true; - } - - if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_DISABLE) - { - dev_info(dev, "[%s] : Disabling FPGA fsync.\n", __func__); - - err = tier4_fpga_disable_fsync_mode(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Disabling FPGA fsync failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } - else - { - err = tier4_fpga_enable_fsync_mode(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA generate fsync failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - - if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_AUTO) - { - // Auto Trigger Mode - err = tier4_fpga_set_fsync_auto_trigger(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA Fsync Auto Trigger mode failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - des_num = priv->g_ctx.reg_mux; - err = tier4_fpga_set_fsync_signal_frequency(priv->fpga_dev, des_num, priv->trigger_mode); - if (err) - { - dev_err(dev, "[%s] : Setting the frequency of fsync genrated by FPGA failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } - else if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_MANUAL) - { - // Manual Trigger Mode - dev_info(dev, "[%s] : Enabling FPGA Fsync Manual Trigger mode.\n", __func__); - - err = tier4_fpga_set_fsync_manual_trigger(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA Fsync Maunal Trigger mode failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } - } - } - - err = tier4_max9296_setup_gpi(priv->dser_dev, fsync_mfp); - - if (err) - { - dev_err(dev, "[%s] :tier4_max9296_setup_gpi() failed\n", __func__); - return err; - } - - err = tier4_max9295_setup_gpo(priv->ser_dev); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9295_setup_gpo() failed\n", __func__); - return err; - } - - // Power on GW5300 via Max9295 in C3 camera -// err = tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_IMX728, POWER_ON ); -// if (err) -// { -// dev_err(dev, "[%s] : Power on gw5300 in C3 camaera failed.\n", __func__); -// return err; -// } - - err = tier4_gw5300_c3_setup_sensor_mode(priv->isp_dev, mode); - if (err) - { - dev_err(dev, "[%s] : tier4_gw5300_c3_setup_sensor_mode() failed\n", __func__); - return err; - } - - return err; -} - -static struct mutex serdes_lock__; - -static int tier4_imx728_gmsl_serdes_setup(struct tier4_imx728 *priv) -{ - int err = 0; - int des_err = 0; - struct device *dev; - - if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client) - { - return -EINVAL; - } - - dev = &priv->i2c_client->dev; - - mutex_lock(&serdes_lock__); - - /* For now no separate power on required for serializer device */ - - if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - tier4_max9296_power_on(priv->dser_dev); - } - - /* setup serdes addressing and control pipeline */ - - - err = tier4_max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev); - - if (err) - { - dev_err(dev, "[%s] : GMSL deserializer link config failed\n", __func__); - goto error; - } - - err = tier4_max9295_setup_control(priv->ser_dev); - - /* proceed even if ser setup failed, to setup deser correctly */ - if (err) - { - dev_err(dev, "[%s] : GMSL serializer setup failed\n", __func__); - goto error; - } - - des_err = tier4_max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev); - - if (des_err) - { - dev_err(dev, "[%s] : GMSL deserializer : setup failed\n", __func__); - err = des_err; - } - -error: - mutex_unlock(&serdes_lock__); - return err; -} - -static void tier4_imx728_gmsl_serdes_reset(struct tier4_imx728 *priv) -{ - mutex_lock(&serdes_lock__); - - /* reset serdes addressing and control pipeline */ - tier4_max9295_reset_control(priv->ser_dev); - - tier4_max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev, true); - - if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && - (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - tier4_max9296_power_off(priv->dser_dev); - } - - mutex_unlock(&serdes_lock__); -} - -static int tier4_imx728_power_on(struct camera_common_data *s_data) -{ - int err = 0; - struct camera_common_power_rail *pw = s_data->power; - struct camera_common_pdata *pdata = s_data->pdata; - struct device *dev = s_data->dev; - - if (pdata && pdata->power_on) - { - err = pdata->power_on(pw); - - if (err) - { - dev_err(dev, "[%s] : failed.\n", __func__); - } - else - { - pw->state = SWITCH_ON; - } - return err; - } - - pw->state = SWITCH_ON; - - return err; -} - -static int tier4_imx728_power_off(struct camera_common_data *s_data) -{ - int err = 0; - struct camera_common_power_rail *pw = s_data->power; - struct camera_common_pdata *pdata = s_data->pdata; - struct device *dev = s_data->dev; - - if (pdata && pdata->power_off) - { - err = pdata->power_off(pw); - - if (!err) - { - goto power_off_done; - } - else - { - dev_err(dev, "[%s] : power off failed.\n", __func__); - } - return err; - } - -power_off_done: - pw->state = SWITCH_OFF; - - return err; -} - -static int tier4_imx728_power_get(struct tegracam_device *tc_dev) -{ - struct camera_common_power_rail *pw = tc_dev->s_data->power; - int err = 0; - - pw->state = SWITCH_OFF; - - return err; -} - -static int tier4_imx728_power_put(struct tegracam_device *tc_dev) -{ - if (unlikely(!tc_dev->s_data->power)) - { - return -EFAULT; - } - - return NO_ERROR; -} - -static int tier4_imx728_set_group_hold(struct tegracam_device *tc_dev, bool val) -{ - volatile int err = 0; - - return err; -} - -static int tier4_imx728_set_gain(struct tegracam_device *tc_dev, s64 val) -{ - int err = 0; - - // struct camera_common_data *s_data = tc_dev->s_data; - - // struct device *dev = tc_dev->dev; - - return err; -} - -/* ------------------------------------------------------------------------- */ - -static int tier4_imx728_set_frame_rate(struct tegracam_device *tc_dev, s64 val) -{ - int err = 0; - - struct tier4_imx728 *priv = (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); - // struct device dev = tc_dev->dev; - - /* fixed 20fps */ - priv->frame_length = IMX728_DEFAULT_FRAME_LENGTH; - - return err; -} - -/* ------------------------------------------------------------------------- */ - -static int tier4_imx728_set_exposure(struct tegracam_device *tc_dev, s64 val) -{ - int err = 0; - - struct tier4_imx728 *priv = (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); - tier4_gw5300_c3_set_integration_time_on_aemode(priv->isp_dev, priv->trigger_mode, val, val); - - return err; -} -// -------------------------------------------------------------------------------------- -// Enable Distortion Coreection -// -------------------------------------------------------------------------------------- -#if USE_DISTORTION_CORRECTION - -static int tier4_imx728_set_distortion_correction(struct tegracam_device *tc_dev, bool val) -{ - int err = 0; - struct tier4_imx728 *priv = (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); - - if (priv->last_distortion_correction != val) - { - dev_info(&priv->i2c_client->dev, "[%s] : Setting distortion correction mode :%s.\n", __func__,val?"True":"False"); - - err = tier4_gw5300_c3_set_distortion_correction(priv->isp_dev, val); - if ( err <= 0) - { - dev_info(&priv->i2c_client->dev, "[%s] : Setting distortion correction mode failed.\n", __func__ ); - } - else - { - err = 0; - priv->last_distortion_correction = val; - } - } - - return err; -} -#endif - -// -------------------------------------------------------------------------------------- -// If you add new ioctl VIDIOC_S_EXT_CTRLS function, -// please add the new memeber and the function at the following table. - -static struct tegracam_ctrl_ops tier4_imx728_ctrl_ops = { - .numctrls = ARRAY_SIZE(ctrl_cid_list), - .ctrl_cid_list = ctrl_cid_list, - .set_gain = tier4_imx728_set_gain, - .set_exposure = tier4_imx728_set_exposure, - .set_exposure_short = tier4_imx728_set_exposure, - .set_frame_rate = tier4_imx728_set_frame_rate, - .set_group_hold = tier4_imx728_set_group_hold, - // .set_distortion_correction = tier4_imx728_set_distortion_correction, -}; - -// -------------------------------------------------------------------------------------- - -static struct camera_common_pdata *tier4_imx728_parse_dt(struct tegracam_device *tc_dev) -{ - struct device *dev = tc_dev->dev; - struct device_node *node = dev->of_node; - struct camera_common_pdata *board_priv_pdata; - const struct of_device_id *match; - int err; - - if (!node) - { - return NULL; - } - - match = of_match_device(tier4_imx728_of_match, dev); - - if (!match) - { - dev_err(dev, "[%s] : Failed to find matching dt id\n", __func__); - return NULL; - } - - board_priv_pdata = devm_kzalloc(dev, sizeof(*board_priv_pdata), GFP_KERNEL); - - err = of_property_read_string(node, "mclk", &board_priv_pdata->mclk_name); - - if (err) - { - dev_err(dev, "[%s] : mclk not in DT\n", __func__); - } - - return board_priv_pdata; -} - -/* tier4_imx728_set_mode() can not be needed. But it remains for compatiblity */ - -static int tier4_imx728_set_mode(struct tegracam_device *tc_dev) -{ - volatile int err = 0; - - return err; -} - -static int tier4_imx728_start_one_streaming(struct tegracam_device *tc_dev) -{ - struct tier4_imx728 *priv = (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); - struct device *dev = tc_dev->dev; - int err; - - /* enable serdes streaming */ - - err = tier4_max9295_setup_streaming(priv->ser_dev); - - if (err) - { - goto exit; - } - - err = tier4_max9296_setup_streaming(priv->dser_dev, dev); - - if (err) - { - dev_err(dev, "[%s] : Setup Streaming failed\n", __func__); - goto exit; - } - - dev_info(dev, "[%s] : trigger_mode = %d\n", __func__, trigger_mode); - - priv->trigger_mode = trigger_mode; - - switch (priv->trigger_mode) - { - case GW5300_MASTER_MODE_5FPS: - case GW5300_MASTER_MODE_10FPS: - case GW5300_MASTER_MODE_10FPS_EBD: - case GW5300_MASTER_MODE_20FPS: - case GW5300_MASTER_MODE_20FPS_EBD: - case GW5300_MASTER_MODE_30FPS: - case GW5300_MASTER_MODE_30FPS_EBD: - dev_info(dev, "[%s] : Setting camera sensor to %s\n", __func__, gw5300_mode_name[priv->trigger_mode]); - - err = tier4_gw5300_c3_setup_sensor_mode(priv->isp_dev, priv->trigger_mode); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to %s failed\n", __func__, gw5300_mode_name[priv->trigger_mode]); - return err; - } - - priv->last_distortion_correction = 1; - break; - - case GW5300_SLAVE_MODE_5FPS: - case GW5300_SLAVE_MODE_10FPS: - case GW5300_SLAVE_MODE_10FPS_EBD: - case GW5300_SLAVE_MODE_20FPS: - case GW5300_SLAVE_MODE_20FPS_EBD: - case GW5300_SLAVE_MODE_30FPS: - case GW5300_SLAVE_MODE_30FPS_EBD: - dev_info(dev, "[%s] : Setting camera sensor to %s\n", __func__, gw5300_mode_name[priv->trigger_mode]); - - err = tier4_imx728_set_fsync_trigger_mode(priv, priv->trigger_mode); - if (err) - { - dev_err(dev, "[%s] : setting camera sensor to %s failed\n", __func__, gw5300_mode_name[priv->trigger_mode]); - return err; - } - - priv->last_distortion_correction = 1; - break; - - default: // case of trigger_mode < 0 - dev_err(dev, "[%s] : The camera sensor mode(trigger mode)=%d is invalid.\n", __func__, priv->trigger_mode); - - return err; - } - - usleep_range(500000, 510000); - err = tier4_gw5300_c3_set_auto_exposure(priv->isp_dev, enable_auto_exposure); - if (err <= 0) - { - dev_err(dev, "[%s] : Setting Digital Gain to default value failed\n", __func__); - goto exit; - } - else - { - err = 0; - } - -#if USE_DISTORTION_CORRECTION - - if (priv->last_distortion_correction != enable_distortion_correction) - { - usleep_range(500000, 510000); - //msleep(900); - } - - if (enable_distortion_correction == 0xCAFE) - { - // if not set kernel param, read device tree param - if (priv->distortion_correction == false) - { - err = tier4_imx728_set_distortion_correction(tc_dev, priv->distortion_correction); - - if (err) - { - dev_err(dev, "[%s] : Disabling Distortion Correction failed\n", __func__); - goto exit; - } - msleep(20); - } - }else{ - err = tier4_imx728_set_distortion_correction(tc_dev, enable_distortion_correction==1); - if (err) - { - dev_err(dev, "[%s] : Setup Distortion Correction failed\n", __func__); - goto exit; - } - msleep(20); - } - -#endif - - -// Reset GW5300 via Max9295 in C3 camera -// err = tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_IMX728, POWER_ON ); -// if (err) -// { -// dev_err(dev, "[%s] : Reset gw5300 in C3 camaera failed.\n", __func__); -// goto exit; -// } -// -// usleep_range(500000, 510000); - - err = tier4_max9296_start_streaming(priv->dser_dev, dev); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_start_stream() failed\n", __func__); - return err; - } - - msleep(1000); - tier4_gw5300_c3_set_integration_time_on_aemode(priv->isp_dev, priv->trigger_mode, shutter_time_max, shutter_time_min); - -// Reset GW5300 via Max9295 in C3 camera -// err = tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_IMX728, POWER_ON ); -// if (err) -// { -// dev_err(dev, "[%s] : Reset gw5300 in C3 camaera failed.\n", __func__); -// goto exit; -// } - - dev_info(dev, "[%s] : Camera has started streaming\n", __func__); - - return NO_ERROR; - -exit: - - dev_err(dev, "[%s] : Camera failed to start streaming.\n", __func__); - - return err; -} - -static bool tier4_imx728_is_camera_connected_to_port(int nport) -{ - if (wst_priv[nport].p_client) - { - return true; - } - return false; -} - -static bool tier4_imx728_check_null_tc_dev_for_port(int nport) -{ - if (wst_priv[nport].p_tc_dev == NULL) - { - return true; - } - return false; -} - -static bool tier4_imx728_is_camera_running_on_port(int nport) -{ - if (wst_priv[nport].running) - { - return true; - } - return false; -} - -static bool tier4_imx728_is_current_port(struct tier4_imx728 *priv, int nport) -{ - if (priv->i2c_client == wst_priv[nport].p_client) - { - return true; - } - return false; -} - -static void tier4_imx728_set_running_flag(int nport, bool flag) -{ - wst_priv[nport].running = flag; -} - -static int tier4_imx728_stop_streaming(struct tegracam_device *tc_dev) -{ - struct device *dev = tc_dev->dev; - struct tier4_imx728 *priv = (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); - int i, err = 0; - - mutex_lock(&tier4_imx728_lock); - - for (i = 0; i < camera_channel_count; i++) - { - if (tier4_imx728_is_camera_connected_to_port(i)) - { - if (tier4_imx728_is_current_port(priv, i) && tier4_imx728_is_camera_running_on_port(i)) - { - /* disable serdes streaming */ - err = tier4_max9296_stop_streaming(priv->dser_dev, dev); - if (err) - { - return err; - } - tier4_imx728_set_running_flag(i, false); - break; - } - } - } - - mutex_unlock(&tier4_imx728_lock); - - return NO_ERROR; -} - -/* *************************************************************************** */ -/* 1. In the case where a camera is connected to GMSL A port on a Des. */ -/* */ -/* a > Check if another camera is connected to GMSL B port */ -/* a-1) Connected: */ -/* b > Check if another camera on GMSL B port is running */ -/* b-1) Running: */ -/* c > Check if the camera on GMSL A port is running */ -/* c-1) Running : */ -/* Do nothing and return */ -/* c-2) Not running : */ -/* Start the camera on GMSL A port. */ -/* b-2) Not Running: */ -/* Start the camera on GMSL B port. */ -/* a-2) Not connected : */ -/* b > Check if the camera on GMSL A port is running */ -/* b-1) Running : */ -/* Do nothing and return */ -/* b-2) Not running : */ -/* Start the camera on GMSL A port. */ -/* */ -/* 2. In the case where a camera is connected to GMSL B port on a Des. */ -/* */ -/* a > Check if the camera on GMSL B port is running */ -/* a-1) Running : */ -/* Do nothing and return */ -/* a-2) Not running : */ -/* Start the camera on GMSL B port. */ -/* *************************************************************************** */ - -static int tier4_imx728_start_streaming(struct tegracam_device *tc_dev) -{ - int i, err = 0; - // struct tier4_imx728 *next_client_priv; - struct tier4_imx728 *priv = (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); - struct device *dev = tc_dev->dev; - - mutex_lock(&tier4_imx728_lock); - - for (i = 0; i < camera_channel_count; i++) - { - if (i & 0x1) - { // if i = 1,3,5,7 ( GMSL B port of a Des ) - - if (tier4_imx728_is_camera_connected_to_port(i)) - { // a camera is connected to GMSL B portL - - if ((tier4_imx728_is_current_port(priv, i) == true) && (tier4_imx728_is_camera_running_on_port(i) == false)) - { - err = tier4_imx728_start_one_streaming(wst_priv[i].p_tc_dev); - - if (err) - { - dev_err(dev, "[%s] : Failed to start one streaming.\n", __func__); - goto error_exit; - } - // wst_priv[i].running = true; - tier4_imx728_set_running_flag(i, true); - break; - } - } - } - else - { // if i = 0,2,4,6 ( GMSL A side port of a Des0,Des1,Des2 or Des3 ) - - if ((tier4_imx728_is_camera_connected_to_port(i) == true) && (tier4_imx728_is_current_port(priv, i) == true)) - { - if (tier4_imx728_is_camera_connected_to_port(i + 1) == false) - { // if another one camera( GMSL B port) is not - // connected to Des. - if (tier4_imx728_is_camera_running_on_port(i) == false) - { // and if the camera is not running. - - err = tier4_imx728_start_one_streaming(wst_priv[i].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Failed to start one streaming for next imx728 client.\n", __func__); - goto error_exit; - } - tier4_imx728_set_running_flag(i, true); - } - break; - } - - // two cameras are connected to one Des. - - if (tier4_imx728_check_null_tc_dev_for_port(i + 1)) - { // check if tc_dev is null - dev_err(dev, "[%s] : wst_priv[%d].p_tc_dev is NULL.\n", __func__, i + 1); - err = -EINVAL; - goto error_exit; - } - - if (tier4_imx728_is_camera_running_on_port(i + 1) == false) - { - err = tier4_imx728_start_one_streaming(wst_priv[i + 1].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Failed to start one streaming for the next imx728 client.\n", __func__); - goto error_exit; - } - tier4_imx728_set_running_flag(i + 1, true); - usleep_range(200000, 220000); - //msleep(200); - mutex_unlock(&tier4_imx728_lock); - tier4_imx728_stop_streaming(wst_priv[i + 1].p_tc_dev); - mutex_lock(&tier4_imx728_lock); - tier4_imx728_set_running_flag(i + 1, false); - } - - if (tier4_imx728_is_camera_running_on_port(i) == false) - { - err = tier4_imx728_start_one_streaming(wst_priv[i].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Failed to start one streaming for current imx728 client.\n", __func__); - goto error_exit; - } - tier4_imx728_set_running_flag(i, true); - } - } - } - } // for loop - - err = NO_ERROR; - -error_exit: - - mutex_unlock(&tier4_imx728_lock); - - // tier4_imx728_sensor_mutex_unlock(); - - return err; -} - -static struct camera_common_sensor_ops tier4_imx728_common_ops = { - .numfrmfmts = ARRAY_SIZE(tier4_imx728_frmfmt), - .frmfmt_table = tier4_imx728_frmfmt, - .power_on = tier4_imx728_power_on, - .power_off = tier4_imx728_power_off, - .write_reg = tier4_imx728_write_reg, - .read_reg = tier4_imx728_read_reg, - .parse_dt = tier4_imx728_parse_dt, - .power_get = tier4_imx728_power_get, - .power_put = tier4_imx728_power_put, - .set_mode = tier4_imx728_set_mode, - .start_streaming = tier4_imx728_start_streaming, - .stop_streaming = tier4_imx728_stop_streaming, -}; - -static int tier4_imx728_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - //struct i2c_client *client = v4l2_get_subdevdata(sd); - - return NO_ERROR; -} - -static const struct v4l2_subdev_internal_ops tier4_imx728_subdev_internal_ops = { - .open = tier4_imx728_open, -}; - -static const char *of_stdout_options; - -static int tier4_imx728_board_setup(struct tier4_imx728 *priv) -{ - struct tegracam_device *tc_dev = priv->tc_dev; - struct device *dev = tc_dev->dev; - struct device_node *node = dev->of_node; - struct device_node *ser_node; - struct i2c_client *ser_i2c = NULL; - struct device_node *dser_node; - struct i2c_client *dser_i2c = NULL; - struct device_node *isp_node; - struct i2c_client *isp_i2c = NULL; - struct device_node *fpga_node = NULL; - struct i2c_client *fpga_i2c = NULL; - struct device_node *gmsl; - struct device_node *root_node; - int value = 0xFFFF; - const char *str_value; - const char *str_value1[2]; - int i; - int err; - const char *str_model; - char upper_str_model[64]; - char *str_err; - char *sub_str_err; - - root_node = of_find_node_opts_by_path("/", &of_stdout_options); - - err = of_property_read_string(root_node, "model", &str_model); - - if (err < 0) - { - dev_err(dev, "[%s] : model not found\n", __func__); - goto error; - } - - memset(upper_str_model, 0, 64); - - to_upper_string(upper_str_model, str_model); - - priv->g_ctx.hardware_model = HW_MODEL_UNKNOWN; - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_XAVIER); - if (str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_XAVIER_DEVKIT; - } - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_XAVIER); - if (str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_XAVIER; - } - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ORIN); - - if (str_err) - { - - sub_str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_ORIN); - - if (sub_str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_ORIN; - } - else - { - priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_ORIN_DEVKIT; - } - } - - - dev_info(dev, "[%s] : model=%s\n", __func__, str_model); - dev_info(dev, "[%s] : hardware_model=%d\n", __func__, priv->g_ctx.hardware_model); - - if (priv->g_ctx.hardware_model == HW_MODEL_UNKNOWN) - { - dev_err(dev, "[%s] : Unknown Hardware Sysytem !\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_isp_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : def-addr not found\n", __func__); - goto error; - } - - if (err < 0) - { - dev_err(dev, "[%s] : reg not found\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "def-addr", &priv->g_ctx.sdev_isp_def); - - if (err < 0) - { - dev_err(dev, "[%s] : def-addr not found\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "reg_mux", &priv->g_ctx.reg_mux); - - if (err < 0) - { - dev_err(dev, "[%s] : reg_mux not found\n", __func__); - goto error; - } - -// err = of_property_read_string(node, "fsync-mode", &str_value); -// -// if (err < 0) -// { -// dev_err(dev, "[%s] : No fsync-mode found\n", __func__); -// goto error; -// } -// -// if (!strcmp(str_value, "true")) -// { -// priv->fsync_mode = true; -// } -// else -// { -// priv->fsync_mode = false; -// } - - err = of_property_read_string(node, "distortion-correction", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No distortion-correction found\n", __func__); - goto error; - } - - if (!strcmp(str_value, "true")) - { - priv->distortion_correction = true; - } - else - { - priv->distortion_correction = false; - } - - if (enable_auto_exposure == 0xCAFE) - { - err = of_property_read_string(node, "auto-exposure", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : Inavlid Exposure mode.\n", __func__); - goto error; - } - - enable_auto_exposure = !strcmp(str_value, "true"); - } else { - dev_info(dev, "[%s] : Parameter[enable_auto_exposure] = %d.\n", __func__, enable_auto_exposure); - } - -#if 0 - priv->g_ctx.fpga_generate_fsync = false; - - if (( priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER ) || - ( priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN )) { - - err = of_property_read_string(node, "fpga-generate-fsync", &str_value); - - if ( err < 0) { - if ( err == -EINVAL ) { - dev_info(dev, "[%s] : Parameter of fpga-generate-fsync does not exist.\n", __func__); - } else { - dev_err(dev, "[%s] : Parameter of fpga-generate-fsync is invalid .\n", __func__); - goto error; - } - } else { - if (!strcmp(str_value, "true")) { - priv->g_ctx.fpga_generate_fsync = true; - } - } - } -#endif - - // For Ser node - ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0); - - if (ser_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,gmsl-ser-device"); - goto error; - } - - err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : Serializer reg not found\n", __func__); - goto error; - } - - ser_i2c = of_find_i2c_device_by_node(ser_node); - - of_node_put(ser_node); - - if (ser_i2c == NULL) - { - dev_err(dev, "[%s] : Missing Serializer Dev Handle\n", __func__); - goto error; - } - if (ser_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing serializer driver\n", __func__); - goto error; - } - - priv->ser_dev = &ser_i2c->dev; - - // For ISP node - - isp_node = of_parse_phandle(node, "nvidia,isp-device", 0); - - if (isp_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,isp-device"); - goto error; - } - - err = of_property_read_u32(isp_node, "reg", &priv->g_ctx.sdev_isp_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : ISP reg not found\n", __func__); - goto error; - } - - isp_i2c = of_find_i2c_device_by_node(isp_node); - - of_node_put(isp_node); - - if (isp_i2c == NULL) - { - dev_err(dev, "[%s] : Missing ISP Dev Handle\n", __func__); - goto error; - } - if (isp_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing ISP driver\n", __func__); - goto error; - } - - priv->isp_dev = &isp_i2c->dev; - - err = tier4_gw5300_prim_slave_addr(&priv->g_ctx); - if (err) - { - dev_err(dev, "[%s] : ISP Prim slave address is unavailable, the default address(0x6D) is applied.\n", __func__); - priv->g_ctx.sdev_isp_def = ISP_PRIM_SLAVE_ADDR; - } - - priv->g_ctx.sdev_reg = priv->g_ctx.sdev_isp_reg; - priv->g_ctx.sdev_def = priv->g_ctx.sdev_isp_def; - - // For Dser node - - dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0); - - if (dser_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,gmsl-dser-device"); - goto error; - } - - dser_i2c = of_find_i2c_device_by_node(dser_node); - - of_node_put(dser_node); - - if (dser_i2c == NULL) - { - dev_err(dev, "[%s] : Missing deserializer dev handle\n", __func__); - goto error; - } - - if (dser_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing deserializer driver\n", __func__); - goto error; - } - - priv->dser_dev = &dser_i2c->dev; - - if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || - (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - // for FPGA node - - fpga_node = of_parse_phandle(node, "nvidia,fpga-device", 0); - - if (fpga_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,fpga-device"); - goto error; - } - - err = of_property_read_u32(fpga_node, "reg", &priv->g_ctx.sdev_fpga_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : FPGA reg not found\n", __func__); - goto error; - } - - fpga_i2c = of_find_i2c_device_by_node(fpga_node); - - of_node_put(fpga_node); - - if (fpga_i2c == NULL) - { - dev_err(dev, "[%s] : Missing FPGA Dev Handle\n", __func__); - goto error; - } - if (fpga_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing FPGA driver\n", __func__); - goto error; - } - - priv->fpga_dev = &fpga_i2c->dev; - } - - /* populate g_ctx from DT */ - - gmsl = of_get_child_by_name(node, "gmsl-link"); - - if (gmsl == NULL) - { - dev_err(dev, "[%s] : Missing GMSL-Link device node\n", __func__); - err = -EINVAL; - goto error; - } - - err = of_property_read_string(gmsl, "dst-csi-port", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No dst-csi-port found\n", __func__); - goto error; - } - - priv->g_ctx.dst_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B; - - err = of_property_read_string(gmsl, "src-csi-port", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No src-csi-port found\n", __func__); - goto error; - } - - priv->g_ctx.src_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B; - - err = of_property_read_string(gmsl, "csi-mode", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No csi-mode found\n", __func__); - goto error; - } - - if (!strcmp(str_value, "1x4")) - { - priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE; - } - else if (!strcmp(str_value, "2x4")) - { - priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE; - } - else if (!strcmp(str_value, "4x2")) - { - priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE; - } - else if (!strcmp(str_value, "2x2")) - { - priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE; - } - else - { - dev_err(dev, "[%s] :Invalid csi-mode\n", __func__); - goto error; - } - - err = of_property_read_string(gmsl, "serdes-csi-link", &str_value); - - if (err < 0) - { - dev_err(dev, "[%s] : No serdes-csi-link found\n", __func__); - goto error; - } - - priv->g_ctx.serdes_csi_link = (!strcmp(str_value, "a")) ? GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B; - - err = of_property_read_u32(gmsl, "st-vc", &value); - - if (err < 0) - { - dev_err(dev, "[%s] : No st-vc info\n", __func__); - goto error; - } - - priv->g_ctx.st_vc = value; - - err = of_property_read_u32(gmsl, "vc-id", &value); - - if (err < 0) - { - dev_err(dev, "[%s] : No vc-id info\n", __func__); - goto error; - } - - priv->g_ctx.dst_vc = value; - - err = of_property_read_u32(gmsl, "num-lanes", &value); - - if (err < 0) - { - dev_err(dev, "[%s] : No num-lanes info\n", __func__); - goto error; - } - - priv->g_ctx.num_csi_lanes = value; - - priv->g_ctx.num_streams = of_property_count_strings(gmsl, "streams"); - - if (priv->g_ctx.num_streams <= 0) - { - dev_err(dev, "[%s] : No streams found\n", __func__); - err = -EINVAL; - goto error; - } - - for (i = 0; i < priv->g_ctx.num_streams; i++) - { - of_property_read_string_index(gmsl, "streams", i, &str_value1[i]); - - if (!str_value1[i]) - { - dev_err(dev, "[%s] : Invalid Stream Info\n", __func__); - goto error; - } - - if (!strcmp(str_value1[i], "raw12")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_RAW_12; - } - else if (!strcmp(str_value1[i], "yuv8")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_YUV_8; - } - else if (!strcmp(str_value1[i], "embed")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_EMBED; - } - else if (!strcmp(str_value1[i], "ued-u1")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_UED_U1; - } - else - { - dev_err(dev, "[%s] : Invalid stream data type\n", __func__); - goto error; - } - } - - priv->g_ctx.s_dev = dev; - - return NO_ERROR; - -error: - dev_err(dev, "[%s] : Board Setup failed\n", __func__); - return err; -} - -static int tier4_imx728_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct device *dev = &client->dev; - struct device_node *node = dev->of_node; - struct tegracam_device *tc_dev; - struct tier4_imx728 *priv; - int err = 0; - - dev_info(dev, "[%s] : Probing V4L2 Sensor.\n", __func__); - - if (!IS_ENABLED(CONFIG_OF) || !node) - { - return -EINVAL; - } - - wst_priv[camera_channel_count].p_client = NULL; - wst_priv[camera_channel_count].p_priv = NULL; - wst_priv[camera_channel_count].p_tc_dev = NULL; - - wst_priv[camera_channel_count].isp_ser_shutdown = false; - wst_priv[camera_channel_count].des_shutdown = false; - wst_priv[camera_channel_count].running = false; - - priv = devm_kzalloc(dev, sizeof(struct tier4_imx728), GFP_KERNEL); - - if (!priv) - { - dev_err(dev, "[%s] : Unable to allocate Memory!\n", __func__); - return -ENOMEM; - } - - tc_dev = devm_kzalloc(dev, sizeof(struct tegracam_device), GFP_KERNEL); - - if (!tc_dev) - { - return -ENOMEM; - } - - priv->i2c_client = tc_dev->client = client; - - tc_dev->dev = dev; - - strncpy(tc_dev->name, "imx728", sizeof(tc_dev->name)); - - tc_dev->dev_regmap_config = &tier4_sensor_regmap_config; - tc_dev->sensor_ops = &tier4_imx728_common_ops; - tc_dev->v4l2sd_internal_ops = &tier4_imx728_subdev_internal_ops; - tc_dev->tcctrl_ops = &tier4_imx728_ctrl_ops; - - err = tegracam_device_register(tc_dev); - - if (err) - { - dev_err(dev, "[%s] : Tegra Camera Driver Registration failed\n", __func__); - return err; - } - - priv->tc_dev = tc_dev; - priv->s_data = tc_dev->s_data; - priv->subdev = &tc_dev->s_data->subdev; - - tegracam_set_privdata(tc_dev, (void *)priv); - - priv->g_ctx.sensor_id = SENSOR_ID_IMX728; - - tier4_isx021_sensor_mutex_lock(); - - err = tier4_imx728_board_setup(priv); - - if (err) - { - dev_err(dev, "[%s] : Board Setup failed\n", __func__); - goto err_tegracam_unreg; - } - - /* Pair sensor to serializer dev */ - - err = tier4_max9295_sdev_pair(priv->ser_dev, &priv->g_ctx); - - if (err) - { - dev_err(&client->dev, "[%s] : GMSL Ser Pairing failed\n", __func__); - goto err_tegracam_unreg; - } - /* Register sensor to deserializer dev */ - - err = tier4_max9296_sdev_register(priv->dser_dev, &priv->g_ctx); - - if (err) - { - dev_err(&client->dev, "[%s] : GMSL Deserializer Register failed\n", __func__); - goto err_max9295_unpair; - } - - /* - * gmsl serdes setup - * - * Sensor power on/off should be the right place for serdes - * setup/reset. But the problem is, the total required delay - * in serdes setup/reset exceeds the frame wait timeout, looks to - * be related to multiple channel open and close sequence - * issue (#BUG 200477330). - * Once this bug is fixed, these may be moved to power on/off. - * The delays in serdes is as per guidelines and can't be reduced, - * so it is placed in probe/remove, though for that, deserializer - * would be powered on always post boot, until 1.2v is supplied - * to deserializer from CVB. - */ - - err = tier4_imx728_gmsl_serdes_setup(priv); - - if (err) - { - dev_err(&client->dev, "[%s] : GMSL Serdes setup failed\n", __func__); - goto err_max9296_unreg; - } - - err = tegracam_v4l2subdev_register(tc_dev, true); - - if (err) - { - dev_err(dev, "[%s] : Tegra Camera Subdev Registration failed\n", __func__); - goto err_max9296_unreg; - } - - wst_priv[camera_channel_count].p_client = client; - wst_priv[camera_channel_count].p_priv = priv; - wst_priv[camera_channel_count].p_tc_dev = tc_dev; - - camera_channel_count++; - - tier4_isx021_sensor_mutex_unlock(); - - return NO_ERROR; - -// tier4_isx021_sensor_mutex_unlock(); - -// dev_info(&client->dev, "Detected Tier4 IMX490 sensor\n"); - -err_max9296_unreg: - tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); -err_max9295_unpair: - tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); -err_tegracam_unreg: - tegracam_device_unregister(priv->tc_dev); - - tier4_isx021_sensor_mutex_unlock(); - -// dev_info(dev, "[%s] :camera_channel_count = %d p_client = %p \n", __func__, camera_channel_count, -// wst_priv[camera_channel_count].p_client); - - - return err; - //return NO_ERROR; // err; -} - -static int tier4_imx728_remove(struct i2c_client *client) -{ - struct camera_common_data *s_data = to_camera_common_data(&client->dev); - struct tier4_imx728 *priv = (struct tier4_imx728 *)s_data->priv; - - tier4_imx728_gmsl_serdes_reset(priv); - - tegracam_v4l2subdev_unregister(priv->tc_dev); - - tegracam_device_unregister(priv->tc_dev); - - return NO_ERROR; -} - -static struct mutex tier4_imx728_lock; - -static bool tier4_imx728_is_isp_ser_shutdown(int nport) -{ - if (wst_priv[nport].isp_ser_shutdown) - { - return true; - } - return false; -} - -static bool tier4_imx728_is_des_shutdown(int nport) -{ - if (wst_priv[nport].des_shutdown) - { - return true; - } - return false; -} - -static void tier4_imx728_set_isp_ser_shutdown(int nport, bool val) -{ - wst_priv[nport].isp_ser_shutdown = val; -} - -static void tier4_imx728_set_des_shutdown(int nport, bool val) -{ - wst_priv[nport].des_shutdown = val; -} - -static bool tier4_imx728_is_current_i2c_client(struct i2c_client *client, int nport) -{ - if (client == wst_priv[nport].p_client) - { - return true; - } - return false; -} - -// ---------------------------------------------------------------------------- - -static void tier4_imx728_shutdown(struct i2c_client *client) -{ - struct tier4_imx728 *priv = NULL; - int i; - - tier4_isx021_sensor_mutex_lock(); - - mutex_lock(&tier4_imx728_lock); - - if (!client) - { - goto error_exit; - } - - for (i = 0; i < camera_channel_count; i++) - { - if (tier4_imx728_is_current_i2c_client(client, i)) - { - priv = wst_priv[i].p_priv; - - if (i & 0x1) - { // Even port number( GMSL B port on a Des : i = port_number -1 ) - - if (tier4_imx728_is_camera_connected_to_port(i - 1)) - { // if a camera connected to another(GMSL A)port on a Des. - // a camera is connected to each port of the Des. - if (tier4_imx728_is_isp_ser_shutdown(i - 1)) - { // ISP and Ser on another(GMSL A) port have been already shut down ? - - if (tier4_imx728_is_des_shutdown(i - 1) == false) - { // if Des on another(GMSL A)port is not shutdown yet - tier4_imx728_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx728_set_des_shutdown(i, true); // Des will be shut down - } - else - { // if Des on the another port is already shut down. This is Error case. - tier4_imx728_set_isp_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_imx728_set_des_shutdown(i, false); // Des will not be shutdown - } - } - else - { // The camera ISP and Ser on another(GMSL A) port are not shut down yet. - - if (tier4_imx728_is_des_shutdown(i - 1) == false) - { // if Des is not shut down yet. - tier4_imx728_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx728_set_des_shutdown(i, false); // The Des won't be shut down. - } - else - { // Only Des on another port is already shut down. This is Error case. - tier4_imx728_set_isp_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_imx728_set_des_shutdown(i, false); // Des will not be shut down. - } - } // a camera is connected to only (GMSL B) port on Des. - tier4_imx728_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx728_set_des_shutdown(i, true); // The Des won't be shut down. - } - } - else - { // if ( i & 0x1 ) == 0 - - if (tier4_imx728_is_camera_connected_to_port(i + 1)) - { // Another camera is connected to another(GMSL B) port on the Des - - if (tier4_imx728_is_isp_ser_shutdown(i + 1)) - { // if the ISP and Ser on another port are already shut down - - if (tier4_imx728_is_des_shutdown(i + 1) == false) - { // if Des is not shut down yet. - tier4_imx728_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx728_set_des_shutdown(i, false); // The Des will be shut down. - } - else - { // Des is already shut down. This is Error case. - tier4_imx728_set_isp_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_imx728_set_des_shutdown(i, false); // The Des will not be shut down. - } - } - else - { // The ISP and Ser on another(GMSL B) port are not shut down yet. - - if (tier4_imx728_is_des_shutdown(i + 1) == false) - { // if Des on another(GMSL B) port is not shut down yet. - - tier4_imx728_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx728_set_des_shutdown(i, false); // The Des will not be shut down. - } - else - { // Only Des on another(GMSL B) port is already shut down. - // This is Error case. - tier4_imx728_set_isp_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_imx728_set_des_shutdown(i, false); // The Des will not be shut down. - } - } - } - else - { - tier4_imx728_set_isp_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_imx728_set_des_shutdown(i, true); // The Des will be shut down. - } - } // if ( i & 0x1 ) - // break; - - if (tier4_imx728_is_isp_ser_shutdown(i)) - { - // Reset camera sensor - tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_IMX728, false); - // S/W Reset max9295 - tier4_max9295_reset_control(priv->ser_dev); - } - - if (tier4_imx728_is_des_shutdown(i)) - { - // S/W Reset max9296 - tier4_max9296_reset_control(priv->dser_dev, &client->dev, true); - } - - if (priv == NULL || i >= camera_channel_count) - { - mutex_unlock(&tier4_imx728_lock); - tier4_isx021_sensor_mutex_unlock(); - return; - } - } - - } // for loop - -error_exit: - - mutex_unlock(&tier4_imx728_lock); - - tier4_isx021_sensor_mutex_unlock(); -} -static const struct i2c_device_id tier4_imx728_id[] = { { "tier4_imx728", 0 }, {} }; - -MODULE_DEVICE_TABLE(i2c, tier4_imx728_id); - -static struct i2c_driver tier4_imx728_i2c_driver = { - .driver = { - .name = "tier4_imx728", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(tier4_imx728_of_match), - }, - .probe = tier4_imx728_probe, - .remove = tier4_imx728_remove, - .shutdown = tier4_imx728_shutdown, - .id_table = tier4_imx728_id, -}; - -static int __init tier4_imx728_init(void) -{ - mutex_init(&serdes_lock__); - mutex_init(&tier4_imx728_lock); - - printk(KERN_INFO "TIERIV Automotive HDR Camera driver.\n"); - - return i2c_add_driver(&tier4_imx728_i2c_driver); -} - -static void __exit tier4_imx728_exit(void) -{ - mutex_destroy(&serdes_lock__); - mutex_destroy(&tier4_imx728_lock); - - i2c_del_driver(&tier4_imx728_i2c_driver); -} - -module_init(tier4_imx728_init); -module_exit(tier4_imx728_exit); - -MODULE_DESCRIPTION("TIERIV Automotive HDR Camera driver"); -MODULE_AUTHOR("Originaly NVIDIA Corporation"); -MODULE_AUTHOR("K.Iwasaki"); -MODULE_AUTHOR("Y.Fujii"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-isx021.c b/drivers/src/tier4-isx021.c deleted file mode 100644 index 409e162..0000000 --- a/drivers/src/tier4-isx021.c +++ /dev/null @@ -1,3121 +0,0 @@ -/* - * isx021.c - isx021 sensor driver - * - * Copyright (c) 2022-2023, TIERIV INC. All rights reserved. - * Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// --------------------------------------------------------------- - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 65) -#include -#endif - -#include - -#include "tier4-fpga.h" -#include "tier4-gmsl-link.h" -#include "tier4-hw-model.h" -#include "tier4-max9295.h" -#include "tier4-max9296.h" - -#define USE_FIRMWARE - -//#define USE_I2C_TRANSFER -#define USE_I2C_READ_REG - -#undef SHOW_I2C_READ_MSG - -#define SHOW_I2C_WRITE_MSG -//#undef SHOW_I2C_WRITE_MSG - -#undef USE_CHECK_MODE_SEL - -#undef USE_EMBEDDED_METADAT_HEIGHT_IN_DTB - -MODULE_SOFTDEP("pre: tier4_max9296"); -MODULE_SOFTDEP("pre: tier4_max9295"); -MODULE_SOFTDEP("pre: tier4_fpga"); - -// Register Address - -#define ISX021_SG_MODE_INTERNAL_SYNC 0 - -#define ISX021_SG_MODE_INTERNAL_SYNC 0 - -#define ISX021_MIN_GAIN 0 -#define ISX021_MAX_GAIN 48 - -#define ISX021_MIN_EXPOSURE_TIME 0 -#define ISX021_MID_EXPOSURE_TIME 11010 // 11 milisecond -#define ISX021_MAX_EXPOSURE_TIME 33000 // 33 milisecond - -#define ISX021_GAIN_DEFAULT_VALUE 6 - -#define ISX021_DEFAULT_FRAME_LENGTH (1125) - -// --- Start of Register definition ------------------ - -#define TIER4_ISX021_REG_0_ADDR 0 -#define TIER4_ISX021_REG_1_ADDR 1 -#define TIER4_ISX021_REG_2_ADDR 2 -#define TIER4_ISX021_REG_3_ADDR 3 -#define TIER4_ISX021_REG_4_ADDR 4 -#define TIER4_ISX021_REG_5_ADDR 5 -#define TIER4_ISX021_REG_6_ADDR 6 -#define TIER4_ISX021_REG_7_ADDR 7 -#define TIER4_ISX021_REG_8_ADDR 8 -#define TIER4_ISX021_REG_9_ADDR 9 -#define TIER4_ISX021_REG_10_ADDR 10 -#define TIER4_ISX021_REG_11_ADDR 11 -#define TIER4_ISX021_REG_12_ADDR 12 -#define TIER4_ISX021_REG_13_ADDR 13 - -#define TIER4_ISX021_REG_14_ADDR 14 - -// AE mode - -#define TIER4_ISX021_REG_15_ADDR 15 -#define TIER4_ISX021_REG_16_ADDR 16 -#define TIER4_ISX021_REG_17_ADDR 17 -#define TIER4_ISX021_REG_18_ADDR 18 - -#define TIER4_ISX021_REG_19_ADDR 19 -#define TIER4_ISX021_REG_20_ADDR 20 -#define TIER4_ISX021_REG_21_ADDR 21 -#define TIER4_ISX021_REG_22_ADDR 22 - -// ME mode - -#define TIER4_ISX021_REG_23_ADDR 23 -#define TIER4_ISX021_REG_24_ADDR 24 -#define TIER4_ISX021_REG_25_ADDR 25 -#define TIER4_ISX021_REG_26_ADDR 26 - -#define TIER4_ISX021_REG_27_ADDR 27 -#define TIER4_ISX021_REG_28_ADDR 28 -#define TIER4_ISX021_REG_29_ADDR 29 -#define TIER4_ISX021_REG_30_ADDR 30 - -// Analog Gain - -#define TIER4_ISX021_REG_31_ADDR 31 -#define TIER4_ISX021_REG_32_ADDR 32 - -#define TIER4_ISX021_REG_33_ADDR 33 -#define TIER4_ISX021_REG_34_ADDR 34 - -#define TIER4_ISX021_REG_35_ADDR 35 -#define TIER4_ISX021_REG_36_ADDR 36 - -#define TIER4_ISX021_REG_37_ADDR 37 -#define TIER4_ISX021_REG_38_ADDR 38 - -#define TIER4_ISX021_REG_39_ADDR 39 -#define TIER4_ISX021_REG_40_ADDR 40 - -#define TIER4_ISX021_REG_41_ADDR 41 -#define TIER4_ISX021_REG_42_ADDR 42 - -#define TIER4_ISX021_REG_43_ADDR 43 -#define TIER4_ISX021_REG_44_ADDR 44 - -#define TIER4_ISX021_REG_45_ADDR 45 -#define TIER4_ISX021_REG_46_ADDR 46 - -// Exposure - -#define TIER4_ISX021_REG_47_ADDR 47 -#define TIER4_ISX021_REG_48_ADDR 48 -#define TIER4_ISX021_REG_49_ADDR 49 - -#define TIER4_ISX021_REG_50_ADDR 50 -#define TIER4_ISX021_REG_51_ADDR 51 -#define TIER4_ISX021_REG_52_ADDR 52 -#define TIER4_ISX021_REG_53_ADDR 53 - -#define TIER4_ISX021_REG_54_ADDR 54 -#define TIER4_ISX021_REG_55_ADDR 55 -#define TIER4_ISX021_REG_56_ADDR 56 -#define TIER4_ISX021_REG_57_ADDR 57 - -#define TIER4_ISX021_REG_58_ADDR 58 -#define TIER4_ISX021_REG_59_ADDR 59 -#define TIER4_ISX021_REG_60_ADDR 60 -#define TIER4_ISX021_REG_61_ADDR 61 - -#define TIER4_ISX021_REG_62_ADDR 62 - -#define TIER4_ISX021_REG_63_ADDR 63 -#define TIER4_ISX021_REG_64_ADDR 64 -#define TIER4_ISX021_REG_65_ADDR 65 - -#define TIER4_ISX021_REG_66_ADDR 66 - -// AE mode - -#define TIER4_ISX021_REG_67_ADDR 67 - -#define TIER4_ISX021_REG_68_ADDR 68 -#define TIER4_ISX021_REG_69_ADDR 69 - -#define TIER4_ISX021_REG_70_ADDR 70 - -// Digital Gain - -#define TIER4_ISX021_REG_71_ADDR 71 -#define TIER4_ISX021_REG_72_ADDR 72 - -// Distortion Corretion - -#define TIER4_ISX021_REG_73_ADDR 73 -#define TIER4_ISX021_REG_74_ADDR 74 -#define TIER4_ISX021_REG_75_ADDR 75 -#define TIER4_ISX021_REG_76_ADDR 76 - -// Mode change - -#define TIER4_ISX021_REG_77_ADDR 77 - -#define TIER4_ISX021_REG_78_ADDR 78 - -#define TIER4_ISX021_REG_79_ADDR 79 - -// Embedded data - -#define TIER4_ISX021_REG_80_ADDR 80 -#define TIER4_ISX021_REG_81_ADDR 81 - -#define TIER4_ISX021_REG_82_ADDR 82 - -#define TIER4_ISX021_REG_83_ADDR 83 -#define TIER4_ISX021_REG_84_ADDR 84 -#define TIER4_ISX021_REG_85_ADDR 85 -#define TIER4_ISX021_REG_86_ADDR 86 -#define TIER4_ISX021_REG_87_ADDR 87 -#define TIER4_ISX021_REG_88_ADDR 88 -#define TIER4_ISX021_REG_89_ADDR 89 - -#define TIER4_ISX021_REG_90_ADDR 90 -#define TIER4_ISX021_REG_91_ADDR 91 - -#define TIER4_ISX021_REG_92_ADDR 92 -#define TIER4_ISX021_REG_93_ADDR 93 - -// --- End of Register definition ------------------------ - -#define MAX_NUM_OF_REG (100) - -#define ISX021_AUTO_EXPOSURE_MODE 0x00 -#define ISX021_AE_TIME_UNIT_MICRO_SECOND 0x03 - -#define BIT_SHIFT_8 8 -#define BIT_SHIFT_16 16 -#define MASK_1_BIT 0x1 -#define MASK_4_BIT 0xF -#define MASK_8_BIT 0xFF - -#define NO_ERROR 0 - -#define TIME_1_MS 1000 -#define TIME_2_MS 2000 -#define TIME_5_MS 5000 -#define TIME_10_MS 10000 -#define TIME_20_MS 20000 -#define TIME_30_MS 30000 -#define TIME_35_MS 35000 -#define TIME_40_MS 40000 -#define TIME_50_MS 50000 -#define TIME_60_MS 60000 -#define TIME_70_MS 70000 -#define TIME_80_MS 80000 -#define TIME_100_MS 100000 -#define TIME_120_MS 120000 -#define TIME_121_MS 121000 -#define TIME_200_MS 200000 -#define TIME_250_MS 250000 -#define TIME_300_MS 300000 -#define TIME_500_MS 500000 -#define TIME_800_MS 800000 -#define TIME_1000_MS 1000000 - -#define PLUS_10(x) ((x)+(x)/10) - -#define MAX_NUM_CAMERA 8 - -#define FIRMWARE_BIN_FILE "/lib/firmware/tier4-isx021.bin" - -#define FSYNC_FREQ_HZ 10 - -#define DISABLE_BOTH_EMBEDDED_DATA 0x0 -#define ENABLE_FRONT_EMBEDDED_DATA 0x1 -#define ENABLE_REAR_EMBEDDED_DATA 0x2 -#define ENABLE_BOTH_EMBEDDED_DATA ((ENABLE_FRONT_EMBEDDED_DATA)|(ENABLE_REAR_EMBEDDED_DATA)) - -enum -{ - ISX021_MODE_1920X1280_CROP_30FPS, - ISX021_MODE_1920X1281_CROP_30FPS_FRONT_EMBEDDED_DATA, - ISX021_MODE_1920X1294_CROP_30FPS_REAR_EMBEDDED_DATA, - ISX021_MODE_1920X1295_CROP_30FPS_BOTH_EMBEDDED_DATA, - ISX021_MODE_START_STREAM, - ISX021_MODE_STOP_STREAM -}; - -static const int tier4_isx021_30fps[] = { - 30, -}; -static const struct camera_common_frmfmt tier4_isx021_frmfmt[] = { - { { 1920, 1280 }, tier4_isx021_30fps, 1, 0, ISX021_MODE_1920X1280_CROP_30FPS }, - { { 1920, 1281 }, tier4_isx021_30fps, 1, 0, ISX021_MODE_1920X1281_CROP_30FPS_FRONT_EMBEDDED_DATA }, // added 1 lines of embedded data - { { 1920, 1294 }, tier4_isx021_30fps, 1, 0, ISX021_MODE_1920X1294_CROP_30FPS_REAR_EMBEDDED_DATA }, // added 14 lines of embedded data - { { 1920, 1295 }, tier4_isx021_30fps, 1, 0, ISX021_MODE_1920X1295_CROP_30FPS_BOTH_EMBEDDED_DATA }, // added 15 lines of embedded data -}; - -const struct of_device_id tier4_isx021_of_match[] = { - { - .compatible = "nvidia,tier4_isx021", - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, tier4_isx021_of_match); - -// If you add new ioctl VIDIOC_S_EXT_CTRLS function, please add new CID to the following table. -// and define the CID number in nvidia/include/media/tegra-v4l2-camera.h - -static const u32 ctrl_cid_list[] = { - TEGRA_CAMERA_CID_GAIN, TEGRA_CAMERA_CID_EXPOSURE, TEGRA_CAMERA_CID_EXPOSURE_SHORT, - TEGRA_CAMERA_CID_FRAME_RATE, TEGRA_CAMERA_CID_HDR_EN, - //TEGRA_CAMERA_CID_DISTORTION_CORRECTION, -}; - -struct tier4_isx021 -{ - struct i2c_client *i2c_client; - const struct i2c_device_id *id; - struct v4l2_subdev *subdev; - struct device *ser_dev; - struct device *dser_dev; - struct tier4_gmsl_link_ctx g_ctx; - u32 frame_length; - struct camera_common_data *s_data; - struct tegracam_device *tc_dev; -// bool fsync_mode; - bool distortion_correction; - bool auto_exposure; - u16 *firmware_buffer; - int es_number; - struct device *fpga_dev; - int trigger_mode; - bool inhibit_fpga_access; - int enable_embedded_data; // 0:disable all embedded data 1: enable front embedded data 2:enable rear embedded data 3: enable front and rear embedded data -}; - -static const struct regmap_config tier4_sensor_regmap_config = { - .reg_bits = 16, - .val_bits = 8, - //.cache_type = REGCACHE_RBTREE, - .cache_type = REGCACHE_NONE, -}; - -struct st_priv -{ - struct i2c_client *p_client; - struct tier4_isx021 *p_priv; - struct tegracam_device *p_tc_dev; - bool sensor_ser_shutdown; - bool des_shutdown; - bool running; -}; - -static struct st_priv wst_priv[MAX_NUM_CAMERA]; - -static int camera_channel_count = 0; - -static int trigger_mode = 0xCAFE; -static int enable_auto_exposure = 0xCAFE; -static int enable_distortion_correction = 0xCAFE; -static int shutter_time_min = ISX021_MIN_EXPOSURE_TIME; -static int shutter_time_mid = ISX021_MID_EXPOSURE_TIME; -static int shutter_time_max = ISX021_MAX_EXPOSURE_TIME; -static int fsync_mfp = 0; -// static int debug_i2c_write = 0; - -module_param(trigger_mode, int, S_IRUGO | S_IWUSR); -module_param(enable_auto_exposure, int, S_IRUGO | S_IWUSR); -module_param(enable_distortion_correction, int, S_IRUGO | S_IWUSR); -module_param(shutter_time_min, int, S_IRUGO | S_IWUSR); -module_param(shutter_time_mid, int, S_IRUGO | S_IWUSR); -module_param(shutter_time_max, int, S_IRUGO | S_IWUSR); - -module_param(fsync_mfp, int, S_IRUGO | S_IWUSR); -// module_param(debug_i2c_write, int, S_IRUGO | S_IWUSR); - -static struct mutex tier4_sensor_lock__; - -static struct mutex tier4_isx021_lock; - -void tier4_isx021_sensor_mutex_lock(void) -{ - mutex_lock(&tier4_sensor_lock__); -} -EXPORT_SYMBOL(tier4_isx021_sensor_mutex_lock); - -void tier4_isx021_sensor_mutex_unlock(void) -{ - mutex_unlock(&tier4_sensor_lock__); -} -EXPORT_SYMBOL(tier4_isx021_sensor_mutex_unlock); - -// ------------------------------- - -static char upper(char c) -{ - if ('a' <= c && c <= 'z') - { - c = c - ('a' - 'A'); - } - return c; -} - -static void to_upper_string(char *out, const char *in) -{ - int i; - - i = 0; - while (in[i] != '\0') - { - out[i] = upper(in[i]); - i++; - } -} - -#ifndef USE_I2C_TRANSFER // with regmap functions - -static inline int tier4_isx021_read_reg(struct camera_common_data *s_data, u16 addr, u8 *val) -{ - int err = 0; - u32 reg_val = 0; - struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; - u16 reg_addr = 0; - -#ifdef USE_FIRMWARE - reg_addr = priv->firmware_buffer[addr]; -#else - reg_addr = addr; -#endif - - err = regmap_read(s_data->regmap, reg_addr, ®_val); - - *val = reg_val & 0xFF; - - if (err) - { - dev_err(s_data->dev, "[%s ] : I2C Read register failed at 0x%04X\n", __func__, reg_addr); - } -#ifdef SHOW_I2C_READ_MSG - else - { - dev_info(s_data->dev, "[%s] : I2C Read regiser at %d(0x%04X)=[0x%02X]\n", __func__, addr, reg_addr, reg_val); - } -#endif - - usleep_range(TIME_1_MS, PLUS_10(TIME_1_MS)); - - return err; -} - -static int tier4_isx021_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) -{ - int err = 0; - struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; - u16 reg_addr = 0; - -#ifdef USE_FIRMWARE - reg_addr = priv->firmware_buffer[addr]; -#else - reg_addr = addr; -#endif - - err = regmap_write(s_data->regmap, reg_addr, val); - - if (err) - { - dev_err(s_data->dev, "[%s] : I2C write register failed at %d(0x%04X)=[0x%02X]\n", __func__, addr, reg_addr, val); - } -#ifdef SHOW_I2C_WRITE_MSG - else - { - dev_info(s_data->dev, "[%s] : I2C write register at %d(0x%04X)=[0x%02X]\n", __func__, addr, reg_addr, val); - } -#endif - - usleep_range(TIME_1_MS, PLUS_10(TIME_1_MS)); - - return err; -} - -#ifdef USE_WRITE_AND_VEIFY - -static int tier4_isx021_write_reg_and_verify(struct camera_common_data *s_data, u16 addr, u8 val8) -{ - u32 r_val32; - u8 r_val8; - int err = 0; - struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; - u16 reg_addr = 0; - -#ifdef USE_FIRMWARE - reg_addr = priv->firmware_buffer[addr]; -#else - reg_addr = addr; -#endif - - err = regmap_write(s_data->regmap, reg_addr, val8); - if (err) - { - dev_err(s_data->dev, "[%s] : I2C write register failed at %d(0x%04X)=[0x%02X]\n", __func__, addr, reg_addr, val8); - } - - usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); - - err = regmap_read(s_data->regmap, reg_addr, &r_val32); - - r_val8 = r_val32 & 0xFF; - - if (err) - { - dev_err(s_data->dev, "[%s] : I2C Read register failed at 0x%04X=[0x%02X]\n", __func__, reg_addr, r_val8); - } - - return err; - -} - -#endif // ifdef USE_WRITE_AND_VEIFY - -#else // ifndef USE_I2C_TRANSFER ( with i2c_transfer function ) - -#ifdef USE_I2C_READ_REG - -static int tier4_isx021_read_reg(struct camera_common_data *s_data, u16 addr, u8 *val8 ) // with i2c_tranfer -{ - int err = 0; - u16 reg_addr = 0; - struct i2c_msg msg[2]; - struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; - u8 w_buf[5]; - -#ifdef USE_FIRMWARE - reg_addr = priv->firmware_buffer[addr]; -#else - reg_addr = addr; -#endif - - w_buf[0] = ( reg_addr >> 8 ) & 0xFF; - w_buf[1] = reg_addr & 0xFF; - - msg[0].addr = priv->i2c_client->addr; - msg[0].flags = 0; // I2C Write - msg[0].len = 2; - msg[0].buf = w_buf; - - msg[1].addr = priv->i2c_client->addr; - msg[1].flags = I2C_M_RD; // I2C Read - msg[1].len = 1; - msg[1].buf = val8; - - err = i2c_transfer(priv->i2c_client->adapter, msg, 2); - - if ( err < 0) - { - dev_err(s_data->dev, "[%s ] : I2C Read register failed at 0x%04X\n", __func__, reg_addr); - } - else - { - err = 0; - } - - usleep_range(TIME_1_MS, PLUS_10(TIME_1_MS)); - - return err; -} - -#endif // ifdef USE_I2C_READ_REG - -// ------------------------------------------------------------------- - -static int tier4_isx021_write_reg(struct camera_common_data *s_data, u16 addr, u8 val8 ) // with i2c_tranfer -{ - int err = 0; - u16 reg_addr = 0; - struct i2c_msg msg[2]; - struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; - u8 w_buf[5]; - -#ifdef USE_FIRMWARE - reg_addr = priv->firmware_buffer[addr]; -#else - reg_addr = addr; -#endif - - w_buf[0] = ( reg_addr >> 8 ) & 0xFF; - w_buf[1] = reg_addr & 0xFF; - w_buf[2] = val8 & 0xFF; - - msg[0].addr = priv->i2c_client->addr; - msg[0].flags = 0; // I2C Write - msg[0].len = 3; - msg[0].buf = w_buf; - - err = i2c_transfer(priv->i2c_client->adapter, msg, 1); - - if (err < 0 ) - { - dev_err(s_data->dev, "[%s] : I2C write register failed at %d(0x%04X)=[0x%02X]\n", __func__, addr, reg_addr, val8); - } - else - { - err = 0; - } - - usleep_range(TIME_1_MS, PLUS_10(TIME_1_MS)); - - return err; -} - -#endif // ifndef USE_I2C_TRANSFER - - -// ------------------------------------------------------------------ - -static int tier4_isx021_write_mode_set_f_lock_register(struct camera_common_data *s_data, u8 val8 ) -{ - int err = 0; - - usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_90_ADDR, 0x06); // ACK Response mode - - usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_77_ADDR, val8); - - usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_90_ADDR, 0x02); // NAK Response mode - - return 0; -} -// ------------------------------------------------------------------ - -#ifdef USE_REMAP_REGISTER - -static int tier4_isx021_write_remap_register(struct camera_common_data *s_data, u8 val8 ) -{ - int err = 0; - - usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_90_ADDR, 0x06); // ACK Response mode - - usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_73_ADDR, val8); - - usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_90_ADDR, 0x02); // NAK Response mode - - return 0; -} -#endif - -// ------------------------------------------------------------------- - -static int tier4_isx021_transit_to_streaming_state(struct tegracam_device *tc_dev) -{ - struct camera_common_data *s_data = tc_dev->s_data; - struct device *dev = tc_dev->dev; - int err = 0; - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_62_ADDR, 0x80); // transit to Streaming state - if ( err ) { - dev_err(dev, "[%s] : Write to MODE_SET_F register failed.\n", __func__); - } - usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); - //msleep(120); - - return err; -} - -// ------------------------------------------------------------------- - -static int tier4_isx021_transit_to_startup_state(struct tegracam_device *tc_dev) -{ - struct camera_common_data *s_data = tc_dev->s_data; - struct device *dev = tc_dev->dev; - int err = 0; - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_62_ADDR, 0x00); // transit to Startup state - - if ( err ) { - dev_err(dev, "[%s] : Write to MODE_SET_F register failed.\n", __func__); - } - usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); - //msleep(120); - - return err; -} - -// ------------------------------------------------------------------ - -#ifdef USE_CHECK_MODE_SEL - -static int tier4_isx021_check_mode_sel(struct camera_common_data *s_data, u8 *val8) -{ - //int mode_size = sizeof(remap_mode); - u8 rval8 = 0; - int err = 0; - struct device *dev = s_data->dev; - - err = tier4_isx021_read_reg(s_data, TIER4_ISX021_REG_89_ADDR, &rval8 ); - if (err) - { - dev_err(dev, "[%s] : Write to MODE_SEL register failed.\n", __func__); - return err; - } - - *val8 = rval8; - - return err; -} -#endif // ifdef USE_CHECK_MODE_SEL - -// ------------------------------------------------------------------ - -static int tier4_isx021_set_fsync_trigger_mode(struct tier4_isx021 *priv) -{ - int err = 0; - struct camera_common_data *s_data = priv->s_data; - struct device *dev = s_data->dev; - int des_num = 0; - - dev_info(dev, "[%s] : hardware_model=%d.\n", __func__, priv->g_ctx.hardware_model ); - - if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || - (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - priv->inhibit_fpga_access = false; - - err = tier4_fpga_check_access(priv->fpga_dev); - if (err) - { - priv->inhibit_fpga_access = true; - } - - if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_DISABLE) - { - dev_info(dev, "[%s] : Disabling FPGA fsync.\n", __func__); - - err = tier4_fpga_disable_fsync_mode(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Disabling FPGA generate fsync failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } - else - { - err = tier4_fpga_enable_fsync_mode(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA generate fsync failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - - if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_AUTO) - { - // Auto Trigger Mode - dev_info(dev, "[%s] : Enabling FPGA Fsync Auto Trigger mode.\n", __func__); - - err = tier4_fpga_set_fsync_auto_trigger(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA Fsync Auto Trigger mode failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - - des_num = priv->g_ctx.reg_mux; - err = tier4_fpga_set_fsync_signal_frequency(priv->fpga_dev, des_num, priv->trigger_mode); - if (err) - { - dev_err(dev, "[%s] : Setting the frequency of fsync genrated by FPGA failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } - else if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_MANUAL) - { - // Manual Trigger Mode - dev_info(dev, "[%s] : Enabling FPGA Fsync Manual Trigger mode.\n", __func__); - - err = tier4_fpga_set_fsync_manual_trigger(priv->fpga_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling FPGA Fsync Maunal Trigger mode failed.\n", __func__); - if ( !priv->inhibit_fpga_access ) - { - return err; - } - } - } // if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_MANUAL) - } // else (tier4_fpga_get_fsync_mode() != FPGA_FSYNC_MODE_DISABLE) - } // if (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) - - err = tier4_max9296_setup_gpi(priv->dser_dev, fsync_mfp); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_setup_gpi failed.\n", __func__); - return err; - } - - err = tier4_max9295_setup_gpo(priv->ser_dev); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9295_setup_gpo failed.\n", __func__); - return err; - } - - // transit to Startup state - - err = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); - if (err) - { - dev_err(dev, "[%s] : Time out Error occurred in tier4_isx021_write_register_mode_set_f_lock.\n", __func__); - return err; - } - - usleep_range(TIME_50_MS, PLUS_10(TIME_50_MS)); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_62_ADDR, 0x00); - - if (err) - { - dev_err(dev, "[%s] : tier4_isx021_write_reg failed.\n", __func__); - return err; - } - - usleep_range(TIME_50_MS, PLUS_10(TIME_50_MS)); - - // set FSYNC_FUNCSEL to 0 for FSYNC triggered mode - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_92_ADDR, 0x00); - - if (err) - { - goto error_exit; - } - - usleep_range(TIME_50_MS, PLUS_10(TIME_50_MS)); - - // set FSYNC_DRVABTY to 3 for FSYNC triggered mode - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_93_ADDR, 0xFF); - - if (err) - { - goto error_exit; - } - - usleep_range(TIME_50_MS, PLUS_10(TIME_50_MS)); - - // set SG_MODE_CTL to 0 for transition to FSYNC mode - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_63_ADDR, 0x02); // set FSYNC mode - - if (err) - { - goto error_exit; - } - - usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); - - // set SG_MODE_APL to 0 for transition to FSYNC mode - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_78_ADDR, 0x02); - - if (err) - { - goto error_exit; - } - - usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); - - usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); - -error_exit: - - return err; -} - -/*--------------------------------------------------------------------------*/ - -static int tier4_isx021_set_response_mode(struct tier4_isx021 *priv) -{ - int err = 0; - struct tegracam_device *tc_dev = priv->tc_dev; - struct camera_common_data *s_data = priv->s_data; - struct device *dev = s_data->dev; - u8 r_val; - - err = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); - if (err) - { - dev_err(dev, "[%s] : Write to MODE_SET_F_LOCK register caused Time out.\n", __func__); - return err; - } - - usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); - - err = tier4_isx021_transit_to_startup_state(tc_dev); - if (err) - { - dev_err(dev, "[%s] : Transition to Startup state failed.\n", __func__); - goto error_exit; - } - - usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); // For ES3 and MP - - err = tier4_isx021_read_reg(s_data, TIER4_ISX021_REG_66_ADDR, &r_val); - - if (r_val == 0x04) - { - priv->es_number = 2; - } - else - { - priv->es_number = 3; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_66_ADDR, 0x06); - - usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); // For ES3 and MP - -error_exit: - - return err; -} - -static int tier4_isx021_gmsl_serdes_setup(struct tier4_isx021 *priv) -{ - int err = 0; - int des_err = 0; - struct device *dev; - - if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client) - { - return -EINVAL; - } - - dev = &priv->i2c_client->dev; - - /* For now no separate power on required for serializer device */ - - if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && - (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - tier4_max9296_power_on(priv->dser_dev); - } - /* setup serdes addressing and control pipeline */ - - err = tier4_max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev); - - if (err) - { - dev_err(dev, "[%s] : Configuration of GMSL Deserializer link failed.\n", __func__); - goto error; - } - - err = tier4_max9295_setup_control(priv->ser_dev); - - /* proceed even if ser setup failed, to setup deser correctly */ - if (err) - { - dev_err(dev, "[%s] : Setup for GMSL Serializer failed.\n", __func__); - goto error; - } - - des_err = tier4_max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev); - - if (des_err) - { - dev_err(dev, "[%s] : Setup for GMSL Deserializer failed.\n", __func__); - err = des_err; - } -error: - - return err; -} - -/*--------------------------------------------------------------------------*/ - -static void tier4_isx021_gmsl_serdes_reset(struct tier4_isx021 *priv) -{ - /* reset serdes addressing and control pipeline */ - tier4_max9295_reset_control(priv->ser_dev); - - tier4_max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev, false); - - if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && - (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - tier4_max9296_power_off(priv->dser_dev); - } -} - -/*--------------------------------------------------------------------------*/ - -static int tier4_isx021_power_on(struct camera_common_data *s_data) -{ - int err = 0; - struct camera_common_power_rail *pw = s_data->power; - struct camera_common_pdata *pdata = s_data->pdata; - struct device *dev = s_data->dev; - - if (pdata && pdata->power_on) - { - err = pdata->power_on(pw); - - if (err) - { - dev_err(dev, "[%s] : Turning on the power failed.\n", __func__); - } - else - { - pw->state = SWITCH_ON; - } - return err; - } - - pw->state = SWITCH_ON; - - return err; -} - -/*--------------------------------------------------------------------------*/ - -static int tier4_isx021_power_off(struct camera_common_data *s_data) -{ - int err = 0; - struct camera_common_power_rail *pw = s_data->power; - struct camera_common_pdata *pdata = s_data->pdata; - struct device *dev = s_data->dev; - - if (pdata && pdata->power_off) - { - err = pdata->power_off(pw); - - if (!err) - { - goto power_off_done; - } - else - { - dev_err(dev, "[%s] : Turning off the power failed.\n", __func__); - } - return err; - } - -power_off_done: - pw->state = SWITCH_OFF; - - return err; -} - -/*--------------------------------------------------------------------------*/ - -static int tier4_isx021_power_get(struct tegracam_device *tc_dev) -{ - struct camera_common_power_rail *pw = tc_dev->s_data->power; - int err = 0; - - pw->state = SWITCH_OFF; - - return err; -} - -/*--------------------------------------------------------------------------*/ - -static int tier4_isx021_power_put(struct tegracam_device *tc_dev) -{ - if (unlikely(!tc_dev->s_data->power)) - { - return -EFAULT; - } - - return NO_ERROR; -} - -/*--------------------------------------------------------------------------*/ - -static int tier4_isx021_set_group_hold(struct tegracam_device *tc_dev, bool val) -{ - volatile int err = 0; - - return err; -} - -/*--------------------------------------------------------------------------*/ - -static int tier4_copy_reg_value(struct camera_common_data *s_data, u16 ae_addr, u16 me_addr) -{ - int err = 0; - u8 val8 = 0; - - err = tier4_isx021_read_reg(s_data, ae_addr, &val8); - - if (err) - { - dev_err(s_data->dev, "[%s] : I2C Read Register failed at 0x%x\n", __func__, ae_addr); - } - - err = tier4_isx021_write_reg(s_data, me_addr, val8); - - if (err) - { - dev_err(s_data->dev, "[%s] : I2C write Register failed at 0x%x =[ 0x%x]\n", __func__, me_addr, val8); - } - - return err; -} - -/*--------------------------------------------------------------------------*/ - -static int tier4_isx021_set_gain(struct tegracam_device *tc_dev, s64 val) -{ - int err = 0; - - s64 gain; - u8 digital_gain_low_byte; - u8 digital_gain_high_byte; - - struct camera_common_data *s_data = tc_dev->s_data; - struct device *dev = tc_dev->dev; - - if (val > ISX021_MAX_GAIN) - { - val = ISX021_MAX_GAIN; - } - else if (val < ISX021_MIN_GAIN) - { - val = ISX021_MIN_GAIN; - } - - dev_info(dev, "[%s] :Gain is set to %lld\n", __func__, val); - - gain = 10 * val; - - digital_gain_low_byte = gain & 0xFF; - - digital_gain_high_byte = (gain >> 8) & 0xFF; - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_68_ADDR, 0x01); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_69_ADDR, 0x01); - - if (err) - { - goto fail; - } - - // Shutter 0 value - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_15_ADDR, TIER4_ISX021_REG_23_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_16_ADDR, TIER4_ISX021_REG_24_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_17_ADDR, TIER4_ISX021_REG_25_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_18_ADDR, TIER4_ISX021_REG_26_ADDR); - - if (err) - { - goto fail; - } - - // Shutter 1 value - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_19_ADDR, TIER4_ISX021_REG_27_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_20_ADDR, TIER4_ISX021_REG_28_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_21_ADDR, TIER4_ISX021_REG_29_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_22_ADDR, TIER4_ISX021_REG_30_ADDR); - - if (err) - { - goto fail; - } - - // Set Analog Gain for shutter 0 - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_31_ADDR, digital_gain_low_byte); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_32_ADDR, digital_gain_high_byte); - - if (err) - { - goto fail; - } - - // copy AE Analog gain value to ME analog gain registers for shutter 1 to 3 - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_35_ADDR, TIER4_ISX021_REG_37_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_36_ADDR, TIER4_ISX021_REG_38_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_39_ADDR, TIER4_ISX021_REG_41_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_40_ADDR, TIER4_ISX021_REG_42_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_43_ADDR, TIER4_ISX021_REG_45_ADDR); - - if (err) - { - goto fail; - } - - err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_44_ADDR, TIER4_ISX021_REG_46_ADDR); - - if (err) - { - goto fail; - } - - msleep(100); // For ES3 - - // Change AE mode - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_67_ADDR, 0x03); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_71_ADDR, digital_gain_low_byte); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_72_ADDR, digital_gain_high_byte); - - if (err) - { - goto fail; - } - - return NO_ERROR; - -fail: - dev_err(dev, "[%s] : Gain control Error\n", __func__); - - return err; -} - -/* ------------------------------------------------------------------------- */ - -static int tier4_isx021_set_frame_rate(struct tegracam_device *tc_dev, s64 val) -{ - struct tier4_isx021 *priv = (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); - - /* fixed 10fps */ - priv->frame_length = ISX021_DEFAULT_FRAME_LENGTH; - - return NO_ERROR; -} - -/* ------------------------------------------------------------------------- */ - -static int tier4_isx021_set_auto_exposure(struct tegracam_device *tc_dev) -{ - int err = 0; - struct camera_common_data *s_data = tc_dev->s_data; - - // Change to Auto exposure mode - - msleep(100); // For ES3 - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_67_ADDR, ISX021_AUTO_EXPOSURE_MODE); - - // Set min exposure time unit - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_47_ADDR, ISX021_AE_TIME_UNIT_MICRO_SECOND); - if (err) - { - goto fail; - } - - // Set mid exposure time unit - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_48_ADDR, ISX021_AE_TIME_UNIT_MICRO_SECOND); - if (err) - { - goto fail; - } - - // Set max exposure time unit - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_49_ADDR, ISX021_AE_TIME_UNIT_MICRO_SECOND); - if (err) - { - goto fail; - } - - // Set min exposure time - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_50_ADDR, shutter_time_min & 0xFF); - if (err) - { - goto fail; - } - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_51_ADDR, (shutter_time_min >> 8) & 0xFF); - if (err) - { - goto fail; - } - - // Set mid exposure time - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_54_ADDR, shutter_time_mid & 0xFF); - if (err) - { - goto fail; - } - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_55_ADDR, (shutter_time_mid >> 8) & 0xFF); - if (err) - { - goto fail; - } - - // Set max exposure time - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_58_ADDR, shutter_time_max & 0xFF); - if (err) - { - goto fail; - } - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_59_ADDR, (shutter_time_max >> 8) & 0xFF); - if (err) - { - goto fail; - } - -fail: - - return err; -} - -/* ------------------------------------------------------------------------- */ - -static int tier4_isx021_set_exposure(struct tegracam_device *tc_dev, s64 val) -{ - int err = 0; - - u8 exp_time_byte0; - u8 exp_time_byte1; - u8 exp_time_byte2; - u8 exp_time_byte3; - // struct tier4_isx021 *priv = (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); - struct camera_common_data *s_data = tc_dev->s_data; - - // unit for val is micro-second - - if (val > ISX021_MAX_EXPOSURE_TIME) - { - val = ISX021_MAX_EXPOSURE_TIME; - } - else if (val < ISX021_MIN_EXPOSURE_TIME) - { - val = ISX021_MIN_EXPOSURE_TIME; - } - - exp_time_byte0 = val & 0xFF; - - exp_time_byte1 = (val >> 8) & 0xFF; - - exp_time_byte2 = (val >> 16) & 0xFF; - - exp_time_byte3 = (val >> 24) & 0xFF; - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_48_ADDR, 0x03); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_49_ADDR, 0x03); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_54_ADDR, exp_time_byte0); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_55_ADDR, exp_time_byte1); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_56_ADDR, exp_time_byte2); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_57_ADDR, exp_time_byte3); - - if (err) - { - goto fail; - } - - // Shutter2 - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_58_ADDR, exp_time_byte0); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_59_ADDR, exp_time_byte1); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_60_ADDR, exp_time_byte2); - - if (err) - { - goto fail; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_61_ADDR, exp_time_byte3); - - if (err) - { - goto fail; - } - - return NO_ERROR; - -fail: - - return err; -} -// -------------------------------------------------------------------------------------- -// Enable Distortion Coreection -// -------------------------------------------------------------------------------------- -static int tier4_isx021_enable_distortion_correction(struct tegracam_device *tc_dev, bool is_enabled) -{ - int err = 0; - struct device *dev = tc_dev->dev; - struct camera_common_data *s_data = tc_dev->s_data; - - err = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); - if (err) - { - dev_err(dev, "[%s] : Write to MODE_SET_F_LOCK register caused Time out.\n", __func__); - return err; - } - - usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); - - err = tier4_isx021_transit_to_startup_state(tc_dev); - - if (err) - { - dev_err(dev, "[%s] : Transition to Startup state failed.\n", __func__); - goto error_exit; - } - - usleep_range(TIME_35_MS, PLUS_10(TIME_35_MS)); - //msleep(35); - - if (is_enabled) - { - err = tier4_isx021_write_reg(tc_dev->s_data, TIER4_ISX021_REG_74_ADDR, 0x01); - - usleep_range(TIME_35_MS, PLUS_10(TIME_35_MS)); - //msleep(35); - - err = tier4_isx021_write_reg(tc_dev->s_data, TIER4_ISX021_REG_75_ADDR, 0x01); - if (err) - { - goto error_exit; - } - } - else - { - dev_info(tc_dev->dev, "[%s] : Disabled Distortion Correction.", __func__); - - err = tier4_isx021_write_reg(tc_dev->s_data, TIER4_ISX021_REG_74_ADDR, 0x00); - - usleep_range(TIME_35_MS, PLUS_10(TIME_35_MS)); - //msleep(35); - - err = tier4_isx021_write_reg(tc_dev->s_data, TIER4_ISX021_REG_75_ADDR, 0x00); - if (err) - { - goto error_exit; - } - } - -error_exit: - - if ( err && !is_enabled ) - { - dev_err(tc_dev->dev, "[%s] : Disabling Distortion Correction failed.", __func__); - } else if ( err && is_enabled ) { - - dev_err(tc_dev->dev, "[%s] : Enabling Distortion Correction failed.", __func__); - } - - return err; -} - -// Please refer to the section for embedded data in ISX021 application note - -static int tier4_isx021_setup_embedded_data(struct tegracam_device *tc_dev, int enable_embedded_data ) -{ - - struct camera_common_data *s_data = tc_dev->s_data; - struct device *dev = s_data->dev; - int err = 0; - int rc = 0; - - dev_dbg(dev, "[%s] : Setup for Embedded data.\n", __func__ ); - - err = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); - - if ( err ) { - dev_err(dev, "[%s] : Write to MODE_SET_F_LOCK Register failed\n", __func__); - //goto error_exit; - } - - usleep_range(TIME_100_MS, PLUS_10(TIME_100_MS)); - //msleep(100); - - err = tier4_isx021_transit_to_startup_state(tc_dev); - if (err) - { - dev_err(dev, "[%s] : Transition to Startup state failed.\n", __func__); - goto error_exit; - } - - usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); - //msleep(120); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_91_ADDR, 0x00); // DCROP_ON_APL Regsiter - - if ( err ) { - dev_err(dev, "[%s] : Write to ISX021_DCROP_ON Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_82_ADDR, 0x00); // DCROP_ON register : Enable 0 Padding after Embedded data - - if ( err ) { - dev_err(dev, "[%s] : Write to ISX021_DCROP_ON Register failed.\n", __func__); - goto error_exit; - } - - dev_dbg(dev, "[%s] : enable_embedded_data = %d\n", __func__, enable_embedded_data ); - - // Enable Front Embedded data - - if ( enable_embedded_data & ENABLE_FRONT_EMBEDDED_DATA ) { - - dev_info(dev, "[%s] : Enabling Front Embedded.\n", __func__ ); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_80_ADDR, 0x1); // Enable outputting Front Embedded Data - if ( err ) { - dev_err(dev, "[%s] : Write to IR_DR_I2I_FEBD_EN Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_83_ADDR, 0x1); - if ( err ) { - dev_err(dev, "[%s] : Write to IFD_DATATYPE_FEBD_SEL Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_85_ADDR, 0x1E); // EBD data are encoded as YcbCr(YUV422: applied in this driver ) - - if ( err ) { - dev_err(dev, "[%s] : Write to IFD_DATATYPE_FEBD Register failed.\n", __func__); - goto error_exit; - } - - } - else - { // Diable Front Embedded data - - dev_info(dev, "[%s] : Disabling Front Embedded.\n", __func__ ); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_80_ADDR, 0x0); // Disable outputting Front Embedded Data - if ( err ) { - dev_err(dev, "[%s] : Write to IR_DR_I2I_FEBD_EN Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_83_ADDR, 0x0); // Front Embedded data type is not selected by IR_DR_I2I_FEBD - if ( err ) { - dev_err(dev, "[%s] : Write to IFD_DATATYPE_FEBD_SEL Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_85_ADDR, 0x12); // Default data type for Front Embedded - if ( err ) { - dev_err(dev, "[%s] : Write to IR_DR_I2I_FEBD Register failed.\n", __func__); - goto error_exit; - } - - } - - if ( enable_embedded_data & ENABLE_REAR_EMBEDDED_DATA ) - { // Enable Rear Embedded data - - dev_info(dev, "[%s] : Enabling Rear Embedded.\n", __func__ ); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_81_ADDR, 0x1); // Enable outputting Rear Embedded Data - if ( err ) - { - dev_err(dev, "[%s] : Write to IR_DR_I2I_REBD_EN Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_84_ADDR, 0x0D); - if ( err ) - { - dev_err(dev, "[%s] : Write to IFD_DATATYPE_REBD_SEL Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_86_ADDR, 0x1E); - if ( err ) - { - dev_err(dev, "[%s] : Write to IFD_DATATYPE_REBD Register failed.\n", __func__); - goto error_exit; - } - - } - else - { // Diabled Rear Embedded data - - dev_info(dev, "[%s] : Disabling Rear Embedded.\n", __func__ ); - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_81_ADDR, 0x0); // Disable outputting Rear Embedded Data - if ( err ) { - dev_err(dev, "[%s] : Write to IR_DR_I2I_REBD_EN Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_84_ADDR, 0x0C); - if ( err ) { - dev_err(dev, "[%s] : Write to IFD_DATATYPE_REBD_SEL Register failed.\n", __func__); - goto error_exit; - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_86_ADDR, 0x35); - if ( err ) { - dev_err(dev, "[%s] : Write to IFD_DATATYPE_REBD Register failed.\n", __func__); - goto error_exit; - } - } - - err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_87_ADDR, 0x1E); - if ( err ) { - dev_err(dev, "[%s] : Write to IFD_DATATYPE_VISIBLE Register failed.\n", __func__); - goto error_exit; - } - -error_exit: - -#if 1 - - rc = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); - if ( rc ) - { - dev_err(dev, "[%s] : Write to MODE_SET_F_LOCK Register failed.\n", __func__); - } -#endif - - return ( err | rc ) ; -} - -// -------------------------------------------------------------------------------------- -// If you add new ioctl VIDIOC_S_EXT_CTRLS function, -// please add the new memeber and the function at the following table. - -static struct tegracam_ctrl_ops tier4_isx021_ctrl_ops = { - .numctrls = ARRAY_SIZE(ctrl_cid_list), - .ctrl_cid_list = ctrl_cid_list, - .set_gain = tier4_isx021_set_gain, - .set_exposure = tier4_isx021_set_exposure, - .set_exposure_short = tier4_isx021_set_exposure, - .set_frame_rate = tier4_isx021_set_frame_rate, - .set_group_hold = tier4_isx021_set_group_hold, - // .set_distortion_correction = tier4_isx021_set_distortion_correction, -}; - -// -------------------------------------------------------------------------------------- - -static struct camera_common_pdata *tier4_isx021_parse_dt(struct tegracam_device *tc_dev) -{ - struct device *dev = tc_dev->dev; - struct device_node *node = dev->of_node; - struct camera_common_pdata *board_priv_pdata; - const struct of_device_id *match; - int err; - - if (!node) - { - return NULL; - } - - match = of_match_device(tier4_isx021_of_match, dev); - - if (!match) - { - dev_err(dev, "[%s] : Finding matching dt id failed.\n", __func__); - return NULL; - } - - board_priv_pdata = devm_kzalloc(dev, sizeof(*board_priv_pdata), GFP_KERNEL); - - err = of_property_read_string(node, "mclk", &board_priv_pdata->mclk_name); - - if (err) - { - dev_err(dev, "[%s] : mclk not in DT.\n", __func__); - } - - return board_priv_pdata; -} - -/* tier4_isx021_set_mode() can not be needed. But it remains for compatiblity */ - -static int tier4_isx021_set_mode(struct tegracam_device *tc_dev) -{ - struct tier4_isx021 *priv = (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); - struct camera_common_data *s_data = tc_dev->s_data; - struct device *dev = tc_dev->dev; - - int err = 0; - - switch( s_data->mode ) - { - case ISX021_MODE_1920X1280_CROP_30FPS : - priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; - break; - case ISX021_MODE_1920X1281_CROP_30FPS_FRONT_EMBEDDED_DATA : - priv->enable_embedded_data = ENABLE_FRONT_EMBEDDED_DATA; - break; - case ISX021_MODE_1920X1294_CROP_30FPS_REAR_EMBEDDED_DATA : - priv->enable_embedded_data = ENABLE_REAR_EMBEDDED_DATA; - break; - case ISX021_MODE_1920X1295_CROP_30FPS_BOTH_EMBEDDED_DATA : - priv->enable_embedded_data = ENABLE_BOTH_EMBEDDED_DATA; - break; - default : - priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; - break; - } - - dev_dbg(dev,"[%s]: priv->enable_embedded_data = %d \n",__func__, priv->enable_embedded_data); - - return err; -} - -// ------------------------------------------------------------------- - -static int tier4_isx021_start_one_streaming(struct tegracam_device *tc_dev) -{ - struct tier4_isx021 *priv = (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); - struct device *dev = tc_dev->dev; - int err; - - /* enable serdes streaming */ - - err = tier4_max9295_setup_streaming(priv->ser_dev); - if (err) - { - goto exit; - } - - err = tier4_max9296_setup_streaming(priv->dser_dev, dev); - if (err) - { - dev_err(dev, "[%s] : Setup for Streaming failed.\n", __func__); - goto exit; - } - - err = tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_ISX021, true); - if (err) - { - dev_err(dev, "[%s] : Power on Camera Sensor failed.\n", __func__); - goto exit; - } - if (enable_auto_exposure == 1) - { - priv->auto_exposure = true; - dev_info(dev, "[%s] : Parameter[enable_auto_exposure] = 1.\n", __func__); - } - - if (priv->auto_exposure == true) - { - err = tier4_isx021_set_auto_exposure(tc_dev); - if (err) - { - dev_err(dev, "[%s] : Enabling Auto Exposure failed.\n", __func__); - goto exit; - } - else - { - dev_info(dev, "[%s] : Enabled Auto Exposure.\n", __func__); - } - } - else - { - dev_info(dev, "[%s] : Disabled Auto Exposure.\n", __func__); - } - if (err) - { - dev_err(dev, "[%s] : Setting digital gain to the default value failed.\n", __func__); - } - - dev_info(dev, "[%s] : trigger_mode = %d.\n", __func__, trigger_mode); - - priv->trigger_mode = trigger_mode; - - if (priv->trigger_mode == 1) - { -// priv->fsync_mode = true; - dev_info(dev, "[%s] : Enabled Slave(fsync triggered) mode.\n", __func__); - } - - -// if (priv->fsync_mode == true) - if (priv->trigger_mode == 1) - { - err = tier4_isx021_set_fsync_trigger_mode(priv); - if (err) - { - dev_err(dev, "[%s] : Camera sensor is unable to work with Slave(fsync triggered) mode.\n", __func__); -// goto exit; - } - } - - usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); - - if (enable_distortion_correction == 1) - { - priv->distortion_correction = true; - dev_info(dev, "[%s] : Prameter[enable_distortion_correction] = 1 .\n", __func__); - } - err = tier4_isx021_enable_distortion_correction(tc_dev, priv->distortion_correction); - if (err) - { - dev_err(dev, "[%s] : Enabling Distortion Correction failed.\n", __func__); - goto exit; - } - - err = tier4_isx021_setup_embedded_data(tc_dev, priv->enable_embedded_data ); - if (err) - { - dev_err(dev, "[%s] : Setup for Embedded data failed.\n", __func__); - goto exit; - } - - err = tier4_isx021_transit_to_streaming_state(tc_dev); - if (err) - { - dev_err(dev, "[%s] : Transition to Streaming state failed.\n", __func__); - return err; - } - - usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); - - err = tier4_max9296_start_streaming(priv->dser_dev, dev); - if (err) - { - dev_err(dev, "[%s] : Des(Max9296) failed to start streaming.\n", __func__); - return err; - } - - dev_info(dev, "[%s] : Camera has started streaming.\n", __func__); - - return NO_ERROR; - -exit: - - dev_err(dev, "[%s] : Camera failed to start streaming.\n", __func__); - - return err; -} - -//------------------------------------------------------------------- - -static bool tier4_isx021_is_camera_connected_to_port(int nport) -{ - if (wst_priv[nport].p_client) - { - return true; - } - return false; -} - -static bool tier4_isx021_check_null_tc_dev_for_port(int nport) -{ - if (wst_priv[nport].p_tc_dev == NULL) - { - return true; - } - return false; -} - -static bool tier4_isx021_is_camera_running_on_port(int nport) -{ - if (wst_priv[nport].running) - { - return true; - } - return false; -} - -static bool tier4_isx021_is_current_port(struct tier4_isx021 *priv, int nport) -{ - if (priv->i2c_client == wst_priv[nport].p_client) - { - return true; - } - return false; -} - -static void tier4_isx021_set_running_flag(int nport, bool flag) -{ - wst_priv[nport].running = flag; -} - -// static void tier4_isx021_reset_running_flag(int nport) -//{ -// wst_priv[nport].running = false; -//} - -static int tier4_isx021_stop_streaming(struct tegracam_device *tc_dev) -{ - struct device *dev = tc_dev->dev; - struct tier4_isx021 *priv = (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); - int i, err = 0; - - mutex_lock(&tier4_isx021_lock); - - for (i = 0; i < camera_channel_count; i++) - { - if (tier4_isx021_is_camera_connected_to_port(i)) - { - if (tier4_isx021_is_current_port(priv, i) && tier4_isx021_is_camera_running_on_port(i)) - { - /* disable serdes streaming */ - err = tier4_max9296_stop_streaming(priv->dser_dev, dev); - if (err) - { - return err; - } - tier4_isx021_set_running_flag(i, false); - break; - } - } - } - - mutex_unlock(&tier4_isx021_lock); - - return NO_ERROR; -} - -/* *************************************************************************** */ -/* 1. In the case where a camera is connected to GMSL A port on a Des. */ -/* */ -/* a > Check if another camera is connected to GMSL B port */ -/* a-1) Connected: */ -/* b > Check if another camera on GMSL B port is running */ -/* b-1) Running: */ -/* c > Check if the camera on GMSL A port is running */ -/* c-1) Running : */ -/* Do nothing and return */ -/* c-2) Not running : */ -/* Start the camera on GMSL A port. */ -/* b-2) Not Running: */ -/* Start the camera on GMSL B port. */ -/* a-2) Not connected : */ -/* b > Check if the camera on GMSL A port is running */ -/* b-1) Running : */ -/* Do nothing and return */ -/* b-2) Not running : */ -/* Start the camera on GMSL A port. */ -/* */ -/* 2. In the case where a camera is connected to GMSL B port on a Des. */ -/* */ -/* a > Check if the camera on GMSL B port is running */ -/* a-1) Running : */ -/* Do nothing and return */ -/* a-2) Not running : */ -/* Start the camera on GMSL B port. */ -/* *************************************************************************** */ - -static int tier4_isx021_start_streaming(struct tegracam_device *tc_dev) -{ - int i, err = 0; - // struct tier4_isx021 *next_client_priv; - struct tier4_isx021 *priv = (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); - struct device *dev = tc_dev->dev; - - mutex_lock(&tier4_isx021_lock); - - for (i = 0; i < camera_channel_count; i++) - { - if (i & 0x1) - { // if i = 1,3,5,7 ( GMSL B port of a Des ) - - if (tier4_isx021_is_camera_connected_to_port(i)) - { // a camera is connected to GMSL B portL - - if ((tier4_isx021_is_current_port(priv, i) == true) && (tier4_isx021_is_camera_running_on_port(i) == false)) - { - // err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev, wst_priv[i].p_priv); - err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev); - - if (err) - { - dev_err(dev, "[%s] : Starting one streaming on Camera sensor failed.\n", __func__); - goto error_exit; - } - wst_priv[i].running = true; - break; - } - } - } - else - { // if i = 0,2,4,6 ( GMSL A side port of a Des0,Des1,Des2 or Des3 ) - - if ((tier4_isx021_is_camera_connected_to_port(i) == true) && (tier4_isx021_is_current_port(priv, i) == true)) - { - if (tier4_isx021_is_camera_connected_to_port(i + 1) == false) - { // if another one camera( GMSL B port) - // is not connected to Des - if (tier4_isx021_is_camera_running_on_port(i) == false) - { // and if the camera is not running. - - // err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev, wst_priv[i].p_priv); - err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Starting one streaming for next isx021 client failed.\n", __func__); - goto error_exit; - } - tier4_isx021_set_running_flag(i, true); - } - break; - } - - // two cameras are connected to one Des. - - if (tier4_isx021_check_null_tc_dev_for_port(i + 1)) - { // check if tc_dev is null - dev_err(dev, "[%s] : wst_priv[%d].p_tc_dev is NULL.\n", __func__, i + 1); - err = -EINVAL; - goto error_exit; - } - - if (tier4_isx021_is_camera_running_on_port(i + 1) == false) - { - // err = tier4_isx021_start_one_streaming(wst_priv[i+1].p_tc_dev, wst_priv[i+1].p_priv); - err = tier4_isx021_start_one_streaming(wst_priv[i + 1].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Start one streaming for the next isx021 client failed.\n", __func__); - goto error_exit; - } - tier4_isx021_set_running_flag(i + 1, true); - usleep_range(TIME_200_MS, PLUS_10(TIME_200_MS)); - //msleep(200); - mutex_unlock(&tier4_isx021_lock); // stop streaming on GMSL B port - tier4_isx021_stop_streaming(wst_priv[i + 1].p_tc_dev); - mutex_lock(&tier4_isx021_lock); - } - - if (tier4_isx021_is_camera_running_on_port(i) == false) - { - // err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev, wst_priv[i].p_priv); - err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev); - if (err) - { - dev_err(dev, "[%s] : Starting one streaming for current isx021 client failed.\n", __func__); - goto error_exit; - } - tier4_isx021_set_running_flag(i, true); - } - } - } - } // for loop - - err = NO_ERROR; - -error_exit: - - mutex_unlock(&tier4_isx021_lock); - - // tier4_isx021_sensor_mutex_unlock(); - - return err; -} - -static struct camera_common_sensor_ops tier4_isx021_common_ops = { - .numfrmfmts = ARRAY_SIZE(tier4_isx021_frmfmt), - .frmfmt_table = tier4_isx021_frmfmt, - .power_on = tier4_isx021_power_on, - .power_off = tier4_isx021_power_off, - .write_reg = tier4_isx021_write_reg, - .read_reg = tier4_isx021_read_reg, - .parse_dt = tier4_isx021_parse_dt, - .power_get = tier4_isx021_power_get, - .power_put = tier4_isx021_power_put, - .set_mode = tier4_isx021_set_mode, - .start_streaming = tier4_isx021_start_streaming, - .stop_streaming = tier4_isx021_stop_streaming, -}; - -static int tier4_isx021_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - // struct i2c_client *client = v4l2_get_subdevdata(sd); - - return NO_ERROR; -} - -static const struct v4l2_subdev_internal_ops tier4_isx021_subdev_internal_ops = { - .open = tier4_isx021_open, -}; - -static const char *of_stdout_options; - -static int tier4_isx021_board_setup(struct tier4_isx021 *priv) -{ - struct tegracam_device *tc_dev = priv->tc_dev; - struct device *dev = tc_dev->dev; - struct device_node *node = dev->of_node; - struct device_node *mode_node; - struct device_node *ser_node; - struct device_node *root_node; - struct i2c_client *ser_i2c = NULL; - struct device_node *dser_node; - struct i2c_client *dser_i2c = NULL; - struct device_node *fpga_node = NULL; - struct i2c_client *fpga_i2c = NULL; - struct device_node *gmsl; - int value = 0xFFFF; - const char *str_value; - const char *str_value1[2]; - int i; - int err; - const char *str_model; - char upper_str_model[64]; - char *str_err; - //char *sub_str_err; - - root_node = of_find_node_opts_by_path("/", &of_stdout_options); - err = of_property_read_string(root_node, "model", &str_model); - if (err < 0) - { - dev_err(dev, "[%s] : model not found\n", __func__); - goto error; - } - - memset(upper_str_model, 0, 64); - to_upper_string(upper_str_model, str_model); - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ORIN); - priv->g_ctx.hardware_model = HW_MODEL_UNKNOWN; - - if (str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_ORIN_DEVKIT; - } - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_XAVIER); - if (str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_XAVIER_DEVKIT; - } - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_XAVIER); - if (str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_XAVIER; - } - - str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_ORIN); - if (str_err) - { - priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_ORIN; - } - - dev_info(dev, "[%s] : hardware_model=%d\n", __func__, priv->g_ctx.hardware_model); - dev_info(dev, "[%s] : model string=%s\n", __func__, str_model); - - // priv->g_ctx.debug_i2c_write = debug_i2c_write; - - if (priv->g_ctx.hardware_model == HW_MODEL_UNKNOWN) - { - dev_err(dev, "[%s] : Unknown Hardware Sysytem !\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_reg); - if (err < 0) - { - dev_err(dev, "[%s] : reg not found\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "def-addr", &priv->g_ctx.sdev_def); - if (err < 0) - { - dev_err(dev, "[%s] : def-addr not found\n", __func__); - goto error; - } - - err = of_property_read_u32(node, "reg_mux", &priv->g_ctx.reg_mux); - if (err < 0) - { - dev_err(dev, "[%s] : reg_mux not found\n", __func__); - goto error; - } - -#if 0 - err = of_property_read_string(node, "fsync-mode", &str_value); - if (err < 0) - { - dev_err(dev, "[%s] : No fsync-mode found\n", __func__); - goto error; - } - - if (!strcmp(str_value, "true")) - { - priv->fsync_mode = true; - } - else - { - priv->fsync_mode = false; - } -#endif - - if (enable_distortion_correction == 0xCAFE) - { - // if not set kernel param, read device tree param - err = of_property_read_string(node, "distortion-correction", &str_value); - if (err < 0) - { - dev_err(dev, "[%s] : No distortion-correction found. set enable_distortion-correction = true\n", __func__); - } - else - { - - if (!strcmp(str_value, "true")) - { - enable_distortion_correction = 1; - } - else - { - enable_distortion_correction = 0; - } - } - } - - priv->distortion_correction = enable_distortion_correction != 0 ? true : false; - - if (enable_auto_exposure == 0xCAFE) - { - // if not set kernel param, read device tree param - err = of_property_read_string(node, "auto-exposure", &str_value); - if (err < 0) - { - dev_err(dev, "[%s] : No auto-exposure mode found. set enable_auto_exposure = true\n", __func__); - } - else - { - if (!strcmp(str_value, "true")) - { - enable_auto_exposure = 1; - } - else - { - enable_auto_exposure = 0; - } - } - } - - priv->auto_exposure = enable_auto_exposure != 0 ? true : false; - - mode_node = of_get_child_by_name(node, "mode0"); - - dev_dbg(dev, "[%s] : node->full_name = %s, mode_node->full_name = %s.\n", __func__, node->full_name, mode_node->full_name ); - -#ifdef USE_EMBEDDED_METADAT_HEIGHT_IN_DTB - /* check embedded_metadata_height */ - - err = of_property_read_string(mode_node, "embedded_metadata_height", &str_value); - dev_info(dev, "[%s] : err = %d, embedded_metadata_height = %s\n", __func__, err, str_value ); - - err = kstrtoul(str_value, 10, &u_value); - embedded_metadata_height = u_value; - if (err) - { - embedded_metadata_height = 0; - } - else - { - embedded_metadata_height = u_value; - } - - switch( embedded_metadata_height ) - { - case 0: - priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; - break; - case 1: - priv->enable_embedded_data = ENABLE_FRONT_EMBEDDED_DATA; - break; - case 14: - priv->enable_embedded_data = ENABLE_REAR_EMBEDDED_DATA; - break; - case 15: - priv->enable_embedded_data = ENABLE_BOTH_EMBEDDED_DATA; - break; - default: - priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; - } -#else // ifdef USE_EMBEDDED_METADAT_HEIGHT_IN_DTB - - priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; // priv->enable_embedded_data is defined by camera sensor image mode - -#endif // ifdef USE_EMBEDDED_METADAT_HEIGHT_IN_DTB - - // for Ser node - - ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0); - - if (ser_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,gmsl-ser-device"); - goto error; - } - - err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : Serializer reg not found\n", __func__); - goto error; - } - - ser_i2c = of_find_i2c_device_by_node(ser_node); - - of_node_put(ser_node); - - if (ser_i2c == NULL) - { - dev_err(dev, "[%s] : Missing Serializer Dev Handle\n", __func__); - goto error; - } - - if (ser_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing serializer driver\n", __func__); - goto error; - } - - priv->ser_dev = &ser_i2c->dev; - - // for Dser node - - dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0); - if (dser_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,gmsl-dser-device"); - goto error; - } - - dser_i2c = of_find_i2c_device_by_node(dser_node); - of_node_put(dser_node); - if (dser_i2c == NULL) - { - dev_err(dev, "[%s] : Missing deserializer dev handle\n", __func__); - goto error; - } - - if (dser_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing deserializer driver\n", __func__); - goto error; - } - - priv->dser_dev = &dser_i2c->dev; - - if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || - (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) - { - // for FPGA node - - fpga_node = of_parse_phandle(node, "nvidia,fpga-device", 0); - - if (fpga_node == NULL) - { - dev_err(dev, "[%s] : Missing %s handle\n", __func__, "nvidia,fpga-device"); - goto error; - } - - err = of_property_read_u32(fpga_node, "reg", &priv->g_ctx.sdev_fpga_reg); - - if (err < 0) - { - dev_err(dev, "[%s] : FPGA reg not found\n", __func__); - goto error; - } - - fpga_i2c = of_find_i2c_device_by_node(fpga_node); - - of_node_put(fpga_node); - - if (fpga_i2c == NULL) - { - dev_err(dev, "[%s] : Missing FPGA Dev Handle\n", __func__); - goto error; - } - - if (fpga_i2c->dev.driver == NULL) - { - dev_err(dev, "[%s] : Missing FPGA driver\n", __func__); - goto error; - } - - priv->fpga_dev = &fpga_i2c->dev; - - } - - /* populate g_ctx from DT */ - - gmsl = of_get_child_by_name(node, "gmsl-link"); - - if (gmsl == NULL) - { - dev_err(dev, "[%s] : Missing GMSL-Link device node\n", __func__); - err = -EINVAL; - goto error; - } - - err = of_property_read_string(gmsl, "dst-csi-port", &str_value); - if (err < 0) - { - dev_err(dev, "[%s] : No dst-csi-port found\n", __func__); - goto error; - } - - priv->g_ctx.dst_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B; - - err = of_property_read_string(gmsl, "src-csi-port", &str_value); - if (err < 0) - { - dev_err(dev, "[%s] : No src-csi-port found\n", __func__); - goto error; - } - - priv->g_ctx.src_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B; - - err = of_property_read_string(gmsl, "csi-mode", &str_value); - if (err < 0) - { - dev_err(dev, "[%s] : No csi-mode found\n", __func__); - goto error; - } - - if (!strcmp(str_value, "1x4")) - { - priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE; - } - else if (!strcmp(str_value, "2x4")) - { - priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE; - } - else if (!strcmp(str_value, "4x2")) - { - priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE; - } - else if (!strcmp(str_value, "2x2")) - { - priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE; - } - else - { - dev_err(dev, "[%s] :Invalid csi-mode\n", __func__); - goto error; - } - - err = of_property_read_string(gmsl, "serdes-csi-link", &str_value); - if (err < 0) - { - dev_err(dev, "[%s] : No serdes-csi-link found\n", __func__); - goto error; - } - - priv->g_ctx.serdes_csi_link = (!strcmp(str_value, "a")) ? GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B; - - err = of_property_read_u32(gmsl, "st-vc", &value); - if (err < 0) - { - dev_err(dev, "[%s] : No st-vc info\n", __func__); - goto error; - } - - priv->g_ctx.st_vc = value; - - err = of_property_read_u32(gmsl, "vc-id", &value); - if (err < 0) - { - dev_err(dev, "[%s] : No vc-id info\n", __func__); - goto error; - } - - priv->g_ctx.dst_vc = value; - - err = of_property_read_u32(gmsl, "num-lanes", &value); - if (err < 0) - { - dev_err(dev, "[%s] : No num-lanes info\n", __func__); - goto error; - } - - priv->g_ctx.num_csi_lanes = value; - - priv->g_ctx.num_streams = of_property_count_strings(gmsl, "streams"); - if (priv->g_ctx.num_streams <= 0) - { - dev_err(dev, "[%s] : No streams found\n", __func__); - err = -EINVAL; - goto error; - } - - for (i = 0; i < priv->g_ctx.num_streams; i++) - { - of_property_read_string_index(gmsl, "streams", i, &str_value1[i]); - if (!str_value1[i]) - { - dev_err(dev, "[%s] : Invalid Stream Info\n", __func__); - goto error; - } - - if (!strcmp(str_value1[i], "raw12")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_RAW_12; - } - else if (!strcmp(str_value1[i], "yuv8")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_YUV_8; - } - else if (!strcmp(str_value1[i], "embed")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_EMBED; - } - else if (!strcmp(str_value1[i], "ued-u1")) - { - priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_UED_U1; - } - else - { - dev_err(dev, "[%s] : Invalid stream data type.\n", __func__); - goto error; - } - } - - priv->g_ctx.s_dev = dev; - - return NO_ERROR; - -error: - dev_err(dev, "[%s] : Board Setup failed.\n", __func__); - return err; -} - -static int tier4_isx021_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - int err = 0; - char *path = FIRMWARE_BIN_FILE; - void *firmware_buffer; - - struct device *dev = &client->dev; - struct device_node *node = dev->of_node; - struct tegracam_device *tc_dev; - struct tier4_isx021 *priv; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 65) - loff_t size; -#endif - - tier4_isx021_sensor_mutex_lock(); - -// dev_info(dev, "[%s] : Probing V4L2 Sensor.\n", __func__); - - if (!IS_ENABLED(CONFIG_OF) || !node) - { - err = -EINVAL; - goto errret; - } - - wst_priv[camera_channel_count].p_client = NULL; - wst_priv[camera_channel_count].p_priv = NULL; - wst_priv[camera_channel_count].p_tc_dev = NULL; - wst_priv[camera_channel_count].sensor_ser_shutdown = false; - wst_priv[camera_channel_count].des_shutdown = false; - wst_priv[camera_channel_count].running = false; - - priv = devm_kzalloc(dev, sizeof(struct tier4_isx021), GFP_KERNEL); - - if (!priv) - { - dev_err(dev, "[%s] : Unable to allocate Memory!\n", __func__); - err = -ENOMEM; - goto errret; - } - - tc_dev = devm_kzalloc(dev, sizeof(struct tegracam_device), GFP_KERNEL); - - if (!tc_dev) - { - err = -ENOMEM; - goto errret; - } - - priv->i2c_client = tc_dev->client = client; - - tc_dev->dev = dev; - - strncpy(tc_dev->name, "isx021", sizeof(tc_dev->name)); - - tc_dev->dev_regmap_config = &tier4_sensor_regmap_config; - tc_dev->sensor_ops = &tier4_isx021_common_ops; - tc_dev->v4l2sd_internal_ops = &tier4_isx021_subdev_internal_ops; - tc_dev->tcctrl_ops = &tier4_isx021_ctrl_ops; - - firmware_buffer = devm_kzalloc(dev, sizeof(u16) * MAX_NUM_OF_REG, GFP_KERNEL); - - if (!firmware_buffer) - { - dev_err(dev, "[%s] : Allocating firmware buffer failed.\n", __func__); - err = -ENOMEM; - goto errret; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 65) - err = kernel_read_file_from_path(path, 0, &firmware_buffer, INT_MAX, NULL, - READING_POLICY); // err is errono and number of bytes actually read - if (!err) - { - dev_err(dev, "Loading %s failed with error %d\n", path, err); -#ifdef USE_FIRMWARE - goto errret; -#endif - } -#else - err = kernel_read_file_from_path(path, &firmware_buffer, &size, INT_MAX, - READING_FIRMWARE); // size : number of bytes actually read - if (err) - { - dev_err(dev, "Loading %s failed with error %d\n", path, err); -#ifdef USE_FIRMWARE - goto errret; -#endif - } -#endif - - priv->firmware_buffer = (u16 *)firmware_buffer; - - err = tegracam_device_register(tc_dev); - - if (err) - { - dev_err(dev, "[%s] : Tegra Camera Driver Registration failed.\n", __func__); - goto errret; - } - - priv->tc_dev = tc_dev; - priv->s_data = tc_dev->s_data; - priv->subdev = &tc_dev->s_data->subdev; - - tegracam_set_privdata(tc_dev, (void *)priv); - - err = tier4_isx021_board_setup(priv); - - if (err) - { - dev_err(dev, "[%s] : Board Setup failed.\n", __func__); - goto err_tegracam_unreg; - } - - priv->trigger_mode = trigger_mode; // trigger_mode per camaera - - /* Pair sensor to serializer dev */ - err = tier4_max9295_sdev_pair(priv->ser_dev, &priv->g_ctx); - - if (err) - { - dev_err(&client->dev, "[%s] : GMSL Ser Pairing failed.\n", __func__); - goto err_tegracam_unreg; - } - - /* Register sensor to deserializer dev */ - - //dev_info(dev, "[%s]: Before tier4_max9296_sdev_register() : priv->g_ctx.serdes_csi_link = %u\n" , __func__, priv->g_ctx.serdes_csi_link ); - - //asm("dmb sy"); - - err = tier4_max9296_sdev_register(priv->dser_dev, &priv->g_ctx); - - if (err) - { - dev_err(&client->dev, "[%s] : Failed to register GMSL Deserializer.\n", __func__); - goto err_max9295_unpair; - } - - /* - * gmsl serdes setup - * - * Sensor power on/off should be the right place for serdes - * setup/reset. But the problem is, the total required delay - * in serdes setup/reset exceeds the frame wait timeout, looks to - * be related to multiple channel open and close sequence - * issue (#BUG 200477330). - * Once this bug is fixed, these may be moved to power on/off. - * The delays in serdes is as per guidelines and can't be reduced, - * so it is placed in probe/remove, though for that, deserializer - * would be powered on always post boot, until 1.2v is supplied - * to deserializer from CVB. - */ - - err = tier4_isx021_gmsl_serdes_setup(priv); - if (err) - { - dev_err(&client->dev, "[%s] : Setup for GMSL Serdes failed.\n", __func__); - goto err_max9296_unreg; - } - - err = tegracam_v4l2subdev_register(tc_dev, true); - if (err) - { - dev_err(dev, "[%s] : Tegra Camera Subdev Registration failed.\n", __func__); - goto err_max9296_unreg; - } - - tier4_isx021_sensor_mutex_unlock(); - - err = tier4_isx021_write_reg(tc_dev->s_data, TIER4_ISX021_REG_90_ADDR, 0x06); - - err = tier4_isx021_set_response_mode(priv); - if (err) - { - dev_warn(dev, "[%s] : Transition to response mode failed.\n", __func__); - goto err_tegracam_v4l2_unreg; - } - - dev_info(&client->dev, "Detected ISX021 sensor.\n"); - - wst_priv[camera_channel_count].p_client = client; - wst_priv[camera_channel_count].p_priv = priv; - wst_priv[camera_channel_count].p_tc_dev = tc_dev; - - camera_channel_count++; - - tier4_isx021_sensor_mutex_unlock(); - -#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 65) ) & 0 - - dev_info(&client->dev, "Detected ISX021 sensor\n"); - return NO_ERROR; -#else - return err; -#endif - -err_tegracam_v4l2_unreg: - tegracam_v4l2subdev_unregister(priv->tc_dev); -err_max9296_unreg: - tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); -err_max9295_unpair: - tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); -err_tegracam_unreg: - tegracam_device_unregister(priv->tc_dev); -errret: - tier4_isx021_sensor_mutex_unlock(); - - dev_err(&client->dev, "Detection for ISX021 sensor failed.\n"); - - return err; -} - -static void tier4_isx021_shutdown(struct i2c_client *client); - -static int tier4_isx021_remove(struct i2c_client *client) -{ - struct camera_common_data *s_data = to_camera_common_data(&client->dev); - struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; - - tier4_isx021_shutdown(client); - - tier4_isx021_gmsl_serdes_reset(priv); - - tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); - tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); - - tegracam_v4l2subdev_unregister(priv->tc_dev); - - tegracam_device_unregister(priv->tc_dev); - - return NO_ERROR; -} - -static bool tier4_isx021_is_sensor_ser_shutdown(int nport) -{ - if (wst_priv[nport].sensor_ser_shutdown) - { - return true; - } - return false; -} - -static bool tier4_isx021_is_des_shut_down(int nport) -{ - if (wst_priv[nport].des_shutdown) - { - return true; - } - return false; -} - -static void tier4_isx021_set_sensor_ser_shutdown(int nport, bool val) -{ - wst_priv[nport].sensor_ser_shutdown = val; -} - -static void tier4_isx021_set_des_shutdown(int nport, bool val) -{ - wst_priv[nport].des_shutdown = val; -} - -static bool tier4_isx021_is_current_i2c_client(struct i2c_client *client, int nport) -{ - if (client == wst_priv[nport].p_client) - { - return true; - } - return false; -} - -/** -* The shutdown routine is needed only when you use ROcube and you would like to reboot command on Linux * -* if not so, you don't need shutdown function * -*/ - -static void tier4_isx021_shutdown(struct i2c_client *client) -{ - struct tier4_isx021 *priv = NULL; - int i; - - tier4_isx021_sensor_mutex_unlock(); - - mutex_lock(&tier4_isx021_lock); - - if (!client) - { - goto error_exit; - } - - for (i = 0; i < camera_channel_count; i++) - { - if (tier4_isx021_is_current_i2c_client(client, i)) - { - priv = wst_priv[i].p_priv; - - if (i & 0x1) - { // Even port number( GMSL B port on a Des : i = port_number -1 ) - - if (tier4_isx021_is_camera_connected_to_port(i - 1)) - { // if a camera connected to another(GMSL A)port on a Des. - - if (tier4_isx021_is_sensor_ser_shutdown(i - 1)) - { // ISP and Ser on another(GMSL A) port have been - - if (tier4_isx021_is_des_shut_down(i - 1) == false) - { // if Des on another(GMSL A)port is not shutdown yet - tier4_isx021_set_sensor_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_isx021_set_des_shutdown(i, true); // Des will be shut down - } - else - { // if Des on the another port is already shut down. - tier4_isx021_set_sensor_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_isx021_set_des_shutdown(i, false); // Des will not be shutdown - } - } - else - { // The camera ISP and Ser on another(GMSL A) port - if (tier4_isx021_is_des_shut_down(i - 1) == false) - { // if Des is not shut down yet. - tier4_isx021_set_sensor_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_isx021_set_des_shutdown(i, false); // The Des won't be shut down. - } - else - { // Only Des on another port is already shut down. - tier4_isx021_set_sensor_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_isx021_set_des_shutdown(i, false); // Des will not be shut down. - } - } - } - else - { // a camera is connected to only (GMSL B) port on Des. - tier4_isx021_set_sensor_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_isx021_set_des_shutdown(i, true); // The Des won't be shut down. - } - } - else - { // if ( i & 0x1 ) == 0 : Camera is connected to Odd port number. ( GMSL A potr on a Des : i = port_number -1 - // ) - - if (tier4_isx021_is_camera_connected_to_port(i + 1)) - { // Another camera is connected to - // another(GMSL B) port on the Des - if (tier4_isx021_is_sensor_ser_shutdown(i + 1)) - { // if the ISP and Ser on another port - // are already shut down - if (tier4_isx021_is_des_shut_down(i + 1) == false) - { // if Des is not shut down yet. - tier4_isx021_set_sensor_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_isx021_set_des_shutdown(i, false); // The Des will not be shut down. - } - else - { // Des is already shut down. This is Error case. - tier4_isx021_set_sensor_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_isx021_set_des_shutdown(i, false); // The Des will not be shut down. - } - } - else - { // The ISP and Ser on another(GMSL B) port - // are not shut down yet. - if (tier4_isx021_is_des_shut_down(i + 1) == false) - { // if Des on another(GMSL B) port is not shut down yet. - tier4_isx021_set_sensor_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_isx021_set_des_shutdown(i, false); // The Des will not be shut down. - } - else - { // Only Des on another(GMSL B) port is already shut down. - // This is Error case. - tier4_isx021_set_sensor_ser_shutdown(i, false); // ISP and Ser will not be shut down - tier4_isx021_set_des_shutdown(i, false); // The Des will not be shut down. - } - } - } - else - { - tier4_isx021_set_sensor_ser_shutdown(i, true); // ISP and Ser will be shut down - tier4_isx021_set_des_shutdown(i, true); // The Des will be shut down. - } - } // if ( i & 0x1 ) - // break; - - if (tier4_isx021_is_sensor_ser_shutdown(i)) - { - // Reset camera sensor - tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_ISX021, false); - // S/W Reset max9295 - tier4_max9295_reset_control(priv->ser_dev); - } - - if (tier4_isx021_is_des_shut_down(i)) - { - // S/W Reset max9296 - tier4_max9296_reset_control(priv->dser_dev, &client->dev, true); - } - - if (priv == NULL || i >= camera_channel_count) - { - mutex_unlock(&tier4_isx021_lock); - tier4_isx021_sensor_mutex_unlock(); - return; - } - } - } // for loop - -error_exit: - - mutex_unlock(&tier4_isx021_lock); - - tier4_isx021_sensor_mutex_unlock(); -} - -static const struct i2c_device_id tier4_isx021_id[] = { { "tier4_isx021", 0 }, {} }; - -MODULE_DEVICE_TABLE(i2c, tier4_isx021_id); - -static struct i2c_driver tier4_isx021_i2c_driver = { - .driver = { - .name = "tier4_isx021", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(tier4_isx021_of_match), - }, - .probe = tier4_isx021_probe, - .remove = tier4_isx021_remove, - .shutdown = tier4_isx021_shutdown, - .id_table = tier4_isx021_id, -}; - -static int __init tier4_isx021_init(void) -{ - mutex_init(&tier4_sensor_lock__); - mutex_init(&tier4_isx021_lock); - -// printk(KERN_INFO "TIERIV Automotive HDR Camera driver : %s\n", BUILD_STAMP); - - return i2c_add_driver(&tier4_isx021_i2c_driver); -} - -static void __exit tier4_isx021_exit(void) -{ - mutex_destroy(&tier4_sensor_lock__); - mutex_destroy(&tier4_isx021_lock); - - printk(KERN_INFO "[%s]: Exit TIERIV Automotive HDR Camera driver.\n", __func__); - - i2c_del_driver(&tier4_isx021_i2c_driver); -} - -module_init(tier4_isx021_init); -module_exit(tier4_isx021_exit); - -MODULE_DESCRIPTION("TIERIV Automotive HDR Camera driver"); -MODULE_AUTHOR("K.Iwasaki"); -MODULE_AUTHOR("Y.Fujii"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-max9295.c b/drivers/src/tier4-max9295.c deleted file mode 100644 index 0912dee..0000000 --- a/drivers/src/tier4-max9295.c +++ /dev/null @@ -1,780 +0,0 @@ -/* - * tier4_max9295.c - tier4_max9295 GMSL Serializer driver - * - * Copyright (c) 2022-2023, TIERIV Inc. All rights reserved. - * Copyright (c) 2020, Leopard Imaging Inc. All rights reserved. - * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include -#include - -#include "tier4-max9295.h" -#include "tier4-gmsl-link.h" - -#define MAX9295_SHOW_I2C_WRITE_MSG 1 - -/* register specifics */ - -#define MAX9295_DEV_ADDR 0x0000 -#define MAX9295_PIPE_EN_ADDR 0x0002 -#define MAX9295_CLK_OUTPUT_ADDR 0x0003 -#define MAX9295_CTRL0_ADDR 0x0010 - -#define MAX9295_I2C4_ADDR 0x0044 -#define MAX9295_I2C5_ADDR 0x0045 - -#define MAX9295_CFGV_VIDEO_Y_ADDR 0x0057 -#define MAX9295_CFGV_VIDEO_Z_ADDR 0x005B - -#define MAX9295_VIDEO_TX0_ADDR 0x0110 -#define MAX9295_VIDEO_TX1_ADDR 0x0111 -#define MAX9295_VIDEO_TX2_ADDR 0x0112 -#define MAX9295_SRC_CTRL_ADDR 0x02BF -#define MAX9295_SRC_PWDN_ADDR 0x02BE - -#define MAX9295_GPIO_3_CONFIG_MFP3_ADDR 0x02C7 -#define MAX9295_GPIO_3_GPIO_TX_ID_ADDR 0x02C8 -#define MAX9295_GPIO_3_GPIO_RX_ID_ADDR 0x02C9 -#define MAX9295_GPIO_4_ADDR 0x02CA -#define MAX9295_GPIO_5_ADDR 0x02CD - -#define MAX9295_GPIO_8_ADDR 0x02D6 - -#define MAX9295_CSI_PORT_SEL_ADDR 0x0308 - -#define MAX9295_START_PIPE_ADDR 0x0311 -#define MAX9295_SEND_Z_PIPE_ADDR 0x0312 -#define MAX9295_PIPE_X_DT_ADDR 0x0314 -#define MAX9295_PIPE_Y_DT_ADDR 0x0316 -#define MAX9295_PIPE_Z_DT_ADDR 0x0318 -#define MAX9295_PIPE_U_DT_ADDR 0x031A -#define MAX9295_OVERRIDE_Z_PIPE_ADDR 0x031E - -#define MAX9295_MIPI_RX0_ADDR 0x0330 -#define MAX9295_MIPI_RX1_ADDR 0x0331 -#define MAX9295_MIPI_RX2_ADDR 0x0332 -#define MAX9295_MIPI_RX3_ADDR 0x0333 - -#define MAX9295_REF_VTG0_ADDR 0x03F0 -#define MAX9295_SRC_OUT_RCLK_ADDR 0x03F1 - -#define MAX9295_REG570_ADDR 0x0570 - -#define MAX9295_STREAM_PIPE_UNUSED 0x22 -#define MAX9295_CSI_MODE_1X4 0x00 -#define MAX9295_CSI_MODE_2X2 0x03 -#define MAX9295_CSI_MODE_2X4 0x06 - -#define MAX9295_CSI_PORT_B(num_lanes) (((num_lanes) << 4) & 0xF0) -#define MAX9295_CSI_PORT_A(num_lanes) ((num_lanes)&0x0F) - -#define MAX9295_CSI_1X4_MODE_LANE_MAP1 0xE0 -#define MAX9295_CSI_1X4_MODE_LANE_MAP2 0x04 - -#define MAX9295_CSI_2X4_MODE_LANE_MAP1 0xEE -#define MAX9295_CSI_2X4_MODE_LANE_MAP2 0xE4 - -#define MAX9295_CSI_2X2_MODE_LANE_MAP1 MAX9295_CSI_2X4_MODE_LANE_MAP1 -#define MAX9295_CSI_2X2_MODE_LANE_MAP2 MAX9295_CSI_2X4_MODE_LANE_MAP2 - -#define MAX9295_ST_ID_0 0x0 -#define MAX9295_ST_ID_1 0x1 -#define MAX9295_ST_ID_2 0x2 -#define MAX9295_ST_ID_3 0x3 - -#define MAX9295_PIPE_X_START_B 0x80 -#define MAX9295_PIPE_Y_START_B 0x40 -#define MAX9295_PIPE_Z_START_B 0x20 -#define MAX9295_PIPE_U_START_B 0x10 - -#define MAX9295_PIPE_X_START_A 0x1 -#define MAX9295_PIPE_Y_START_A 0x2 -#define MAX9295_PIPE_Z_START_A 0x4 -#define MAX9295_PIPE_U_START_A 0x8 - -#define MAX9295_START_PORT_A 0x10 -#define MAX9295_START_PORT_B 0x20 - -#define MAX9295_CSI_LN2 0x1 -#define MAX9295_CSI_LN4 0x3 - -#define MAX9295_EN_LINE_INFO 0x40 - -#define MAX9295_VID_TX_EN_X 0x10 -#define MAX9295_VID_TX_EN_Y 0x20 -#define MAX9295_VID_TX_EN_Z 0x40 -#define MAX9295_VID_TX_EN_U 0x80 - -#define MAX9295_VID_INIT 0x3 -#define MAX9295_SRC_RCLK 0x89 - -#define MAX9295_RESET_ALL 0x80 -#define MAX9295_RESET_SRC 0x60 -#define MAX9295_PWDN_GPIO 0x90 - -#define MAX9295_MAX_PIPES 0x4 - -struct tier4_max9295_client_ctx -{ - struct tier4_gmsl_link_ctx *g_ctx; - bool st_done; -}; - -struct tier4_max9295 -{ - struct i2c_client *i2c_client; - struct regmap *regmap; - struct tier4_max9295_client_ctx g_client; - struct mutex lock; - /* primary serializer properties */ - __u32 def_addr; - __u32 pst2_ref; -}; - -#define MAX_CHANNEL_NUM 8 - -/* count channel,the max MAX_CHANNEL_NUM*/ -static __u32 channel_count_isx021; - -static struct tier4_max9295 *prim_priv__[MAX_CHANNEL_NUM]; - -struct map_ctx -{ - u8 dt; - u16 addr; - u8 val; - u8 st_id; -}; - -#if 0 - -static int tier4_max9295_read_reg(struct device *dev, u16 addr, u8 *val) -{ - int err = 0; - u32 reg_val = 0; - struct tier4_max9295 *priv = dev_get_drvdata(dev); - char str_bus_num[4], str_sl_addr[4]; - int len = 0; - - memset(str_bus_num,0,4); - memset(str_sl_addr,0,4); - - err = regmap_read(priv->regmap, addr, ®_val); - - *val = reg_val & 0xFF; - - dev_info(dev, "[%s ] : Max9295 I2C Read at 0x%04X=[0x%02X].\n", __func__, addr, *val ); - - if (( err == 0 ) && ( dev != NULL ) ) { - len = strlen(dev->kobj.name); - if (dev) { - strncpy(str_bus_num, &dev->kobj.name[0], 2); - strncpy(str_sl_addr, &dev->kobj.name[len-2], 2); - } - } - return err; -} -#endif - -static int tier4_max9295_write_reg(struct device *dev, u16 addr, u8 val) -{ - struct tier4_max9295 *priv = dev_get_drvdata(dev); - int err = 0; - // u8 e; - char str_bus_num[4], str_sl_addr[4]; - int len; - - memset(str_bus_num, 0, 4); - memset(str_sl_addr, 0, 4); - - len = strlen(dev->kobj.name); - - if ((err == 0) && (dev != NULL)) - { - strncpy(str_bus_num, &dev->kobj.name[0], 2); - strncpy(str_sl_addr, &dev->kobj.name[len - 2], 2); - } - - err = regmap_write(priv->regmap, addr, val); - - if (err) - { - dev_err(dev, "[%s] : Max9295 I2C write failed Reg at 0x%04X:[0x%02X].\n", __func__, addr, val); - } -#if MAX9295_SHOW_I2C_WRITE_MSG - else - { - dev_info(dev, "[%s] : Max9295 I2C write register at 0x%04X:[0x%02X]\n", __func__, addr, val); - } -#endif - - /* delay before next i2c command as required for SERDES link */ - - usleep_range(100, 110); - //msleep(100); - // tier4_max9295_read_reg(dev, addr, &e); - usleep_range(100, 110); - //msleep(100); - - return err; -} - -int tier4_max9295_setup_streaming(struct device *dev) -{ - struct tier4_max9295 *priv = dev_get_drvdata(dev); - int err = 0; - u32 csi_mode; - u32 lane_map1; - u32 lane_map2; - u32 port; - u32 rx1_lanes; - u32 st_pipe; - u32 pipe_en; - u32 port_sel = 0; - struct tier4_gmsl_link_ctx *g_ctx; - u32 i; - u32 j; - u32 st_en; - - struct map_ctx map_pipe_dtype[] = { - { GMSL_CSI_DT_YUV_8, MAX9295_PIPE_Z_DT_ADDR, 0x1E, // For YUV8 - MAX9295_ST_ID_2 }, - { GMSL_CSI_DT_UED_U1, MAX9295_PIPE_X_DT_ADDR, 0x30, // User defined embedded data type - MAX9295_ST_ID_0 }, - { GMSL_CSI_DT_EMBED, MAX9295_PIPE_Y_DT_ADDR, 0x12, MAX9295_ST_ID_1 }, - }; - - mutex_lock(&priv->lock); - - if (!priv->g_client.g_ctx) - { - dev_err(dev, "[%s] : No sdev client found\n", __func__); - err = -EINVAL; - goto error; - } - - if (priv->g_client.st_done) - { - dev_dbg(dev, "[%s] : Stream setup is already done\n", __func__); - goto error; - } - - g_ctx = priv->g_client.g_ctx; - - switch (g_ctx->csi_mode) - { - case GMSL_CSI_1X4_MODE: - csi_mode = MAX9295_CSI_MODE_1X4; - lane_map1 = MAX9295_CSI_1X4_MODE_LANE_MAP1; - lane_map2 = MAX9295_CSI_1X4_MODE_LANE_MAP2; - rx1_lanes = MAX9295_CSI_LN4; - break; - case GMSL_CSI_2X2_MODE: - csi_mode = MAX9295_CSI_MODE_2X2; - lane_map1 = MAX9295_CSI_2X2_MODE_LANE_MAP1; - lane_map2 = MAX9295_CSI_2X2_MODE_LANE_MAP2; - rx1_lanes = MAX9295_CSI_LN2; - break; - case GMSL_CSI_2X4_MODE: - csi_mode = MAX9295_CSI_MODE_2X4; - lane_map1 = MAX9295_CSI_2X4_MODE_LANE_MAP1; - lane_map2 = MAX9295_CSI_2X4_MODE_LANE_MAP2; - rx1_lanes = MAX9295_CSI_LN4; - break; - default: - dev_err(dev, "[%s] : Invalid csi mode\n", __func__); - err = -EINVAL; - goto error; - } - - port = (g_ctx->src_csi_port == GMSL_CSI_PORT_B) ? MAX9295_CSI_PORT_B(rx1_lanes) : MAX9295_CSI_PORT_A(rx1_lanes); - - tier4_max9295_write_reg(dev, MAX9295_MIPI_RX0_ADDR, csi_mode); - tier4_max9295_write_reg(dev, MAX9295_MIPI_RX1_ADDR, port); - tier4_max9295_write_reg(dev, MAX9295_MIPI_RX2_ADDR, lane_map1); - tier4_max9295_write_reg(dev, MAX9295_MIPI_RX3_ADDR, lane_map2); - - for (i = 0; i < g_ctx->num_streams; i++) - { - struct tier4_gmsl_stream *g_stream = &g_ctx->streams[i]; - - g_stream->st_id_sel = GMSL_ST_ID_UNUSED; - - for (j = 0; j < ARRAY_SIZE(map_pipe_dtype); j++) - { - if (map_pipe_dtype[j].dt == g_stream->st_data_type) - { - /* - * TODO: - * 1) Remove link specific overrides, depends - * on #2. - * 2) Add support for vc id based stream sel - * overrides TX_SRC_SEL. would be useful in - * using same mappings in all ser devs. - */ - if (g_ctx->serdes_csi_link == GMSL_SERDES_CSI_LINK_B) - { - map_pipe_dtype[j].addr += 2; - map_pipe_dtype[j].st_id += 1; - } - - g_stream->st_id_sel = map_pipe_dtype[j].st_id; - - st_en = (map_pipe_dtype[j].addr == MAX9295_PIPE_X_DT_ADDR) ? 0xC0 : 0x40; - - tier4_max9295_write_reg(dev, map_pipe_dtype[j].addr, (st_en | map_pipe_dtype[j].val)); - } - } - } - - for (i = 0; i < g_ctx->num_streams; i++) - if (g_ctx->streams[i].st_id_sel != GMSL_ST_ID_UNUSED) - port_sel |= (1 << g_ctx->streams[i].st_id_sel); - - if (g_ctx->src_csi_port == GMSL_CSI_PORT_B) - { - st_pipe = (MAX9295_PIPE_X_START_B | MAX9295_PIPE_Y_START_B | MAX9295_PIPE_Z_START_B | MAX9295_PIPE_U_START_B); - port_sel |= (MAX9295_EN_LINE_INFO | MAX9295_START_PORT_B); - } - else - { - st_pipe = MAX9295_PIPE_X_START_A | MAX9295_PIPE_Y_START_A | MAX9295_PIPE_Z_START_A | MAX9295_PIPE_U_START_A; - port_sel |= (MAX9295_EN_LINE_INFO | MAX9295_START_PORT_A); - } - - pipe_en = (MAX9295_VID_TX_EN_X | MAX9295_VID_TX_EN_Y | MAX9295_VID_TX_EN_Z | MAX9295_VID_TX_EN_U | MAX9295_VID_INIT); - - tier4_max9295_write_reg(dev, MAX9295_START_PIPE_ADDR, st_pipe); - tier4_max9295_write_reg(dev, MAX9295_CSI_PORT_SEL_ADDR, port_sel); - - tier4_max9295_write_reg(dev, MAX9295_PIPE_EN_ADDR, pipe_en); - - priv->g_client.st_done = true; - -error: - mutex_unlock(&priv->lock); - return err; -} -EXPORT_SYMBOL(tier4_max9295_setup_streaming); - -// ------------------------------------------------------------------ - -int tier4_max9295_control_sensor_power_seq(struct device *dev, __u32 sensor_id, bool power_on) -{ - struct tier4_max9295 *priv = dev_get_drvdata(dev); - struct tier4_gmsl_link_ctx *g_ctx; - int err = 0; - - g_ctx = priv->g_client.g_ctx; - -#if 1 - - msleep(200); - - if (power_on == true) - { // power up camera sensor - - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_8_ADDR, 0x00); - - msleep(100); - - if (sensor_id == SENSOR_ID_ISX021) - { - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_5_ADDR, 0x04); - msleep(100); - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_4_ADDR, 0x10); - msleep(100); - } - else if (sensor_id == SENSOR_ID_IMX728) - { - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_4_ADDR, 0x10); - msleep(100); - } - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_8_ADDR, 0x10); - } - else - { // power down caemra sensor - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_8_ADDR, 0x00); - msleep(100); - if (sensor_id == SENSOR_ID_ISX021) - { - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_5_ADDR, 0x04); - msleep(100); - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_4_ADDR, 0x00); - msleep(100); - } - else if (sensor_id == SENSOR_ID_IMX728) - { - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_4_ADDR, 0x00); - msleep(100); - } - } - - if (err) - { - dev_err(dev, "[%s] : Ppower on/off Camera Sensor or ISP failed.\n", __func__); - } - - msleep(50); -#endif - return err; -} -EXPORT_SYMBOL(tier4_max9295_control_sensor_power_seq); - -int tier4_max9295_setup_gpo(struct device *dev) -{ - int err = 0; - - dev_info(dev, "[%s] : Set up max9295 for fsync trigger mode \n", __func__); - - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_3_CONFIG_MFP3_ADDR, 0x04); - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_3_GPIO_TX_ID_ADDR, 0x00); - err += tier4_max9295_write_reg(dev, MAX9295_GPIO_3_GPIO_RX_ID_ADDR, 0x06); - - return err; -} -EXPORT_SYMBOL(tier4_max9295_setup_gpo); - -int tier4_max9295_setup_control(struct device *dev) -{ - struct tier4_max9295 *priv = dev_get_drvdata(dev); - int err = 0; - struct tier4_gmsl_link_ctx *g_ctx; - u32 offset1 = 0; - u32 offset2 = 0; - u32 i; - - u8 i2c_ovrd[] = { - 0x6B, 0x10, 0x73, 0x11, 0x7B, 0x30, 0x83, 0x30, 0x93, 0x30, 0x9B, 0x30, 0xA3, 0x30, 0xAB, 0x30, 0x8B, 0x30, - }; - - u8 addr_offset[] = { - 0x80, 0x00, 0x00, 0x84, 0x00, 0x01, 0xC0, 0x02, 0x02, 0xC4, 0x02, 0x03, - }; - - mutex_lock(&priv->lock); - - g_ctx = priv->g_client.g_ctx; - - if (prim_priv__[g_ctx->reg_mux] == NULL) - { - err = -EINVAL; - goto error; - } - /* update address reassingment */ - tier4_max9295_write_reg(&prim_priv__[g_ctx->reg_mux]->i2c_client->dev, MAX9295_DEV_ADDR, (g_ctx->ser_reg << 1)); - - msleep(100); - - if (g_ctx->serdes_csi_link == GMSL_SERDES_CSI_LINK_A) - { - err = tier4_max9295_write_reg(dev, MAX9295_CTRL0_ADDR, 0x21); - } - else - { - err = tier4_max9295_write_reg(dev, MAX9295_CTRL0_ADDR, 0x22); - } - - /* check if serializer device exists */ - if (err) - { - dev_err(dev, "[%s]: Ser device not found\n", __func__); - goto error; - } - /* delay to settle link */ - msleep(100); - - /* Set RCLKOUT soruce to the reference PLL clock*/ - err = tier4_max9295_write_reg(dev, MAX9295_CLK_OUTPUT_ADDR, 0x03); - - /* No need?*/ - usleep_range(10000, 11000); - - /* PLL setting & Reset PLL */ - err = tier4_max9295_write_reg(dev, MAX9295_REF_VTG0_ADDR, 0x5A); - usleep_range(10000, 11000); -// err = tier4_max9295_write_reg(dev, MAX9295_REG570_ADDR, 0x0C); - - for (i = 0; i < ARRAY_SIZE(addr_offset); i += 3) - { - if ((g_ctx->ser_reg << 1) == addr_offset[i]) - { - offset1 = addr_offset[i + 1]; - offset2 = addr_offset[i + 2]; - break; - } - } - - if (i == ARRAY_SIZE(addr_offset)) - { - dev_err(dev, "[%s] : Invalid ser slave address\n", __func__); - err = -EINVAL; - goto error; - } - - for (i = 0; i < ARRAY_SIZE(i2c_ovrd); i += 2) - { - /* update address overrides */ - i2c_ovrd[i + 1] += (i < 4) ? offset1 : offset2; - - /* i2c passthrough2 must be configured once for all devices */ - if ((i2c_ovrd[i] == 0x8B) && prim_priv__[g_ctx->reg_mux]->pst2_ref) - continue; - - tier4_max9295_write_reg(dev, i2c_ovrd[i], i2c_ovrd[i + 1]); - } - - /* dev addr pass-through2 ref */ - - prim_priv__[g_ctx->reg_mux]->pst2_ref++; - - tier4_max9295_write_reg(dev, MAX9295_I2C4_ADDR, (g_ctx->sdev_reg << 1)); - tier4_max9295_write_reg(dev, MAX9295_I2C5_ADDR, (g_ctx->sdev_def << 1)); - - tier4_max9295_write_reg(dev, MAX9295_SRC_PWDN_ADDR, MAX9295_PWDN_GPIO); - tier4_max9295_write_reg(dev, MAX9295_SRC_CTRL_ADDR, MAX9295_RESET_SRC); - tier4_max9295_write_reg(dev, MAX9295_SRC_OUT_RCLK_ADDR, MAX9295_SRC_RCLK); - - /* PLL setting & Enable PLL */ - tier4_max9295_write_reg(dev, MAX9295_REF_VTG0_ADDR, 0x59); - - - g_ctx->serdev_found = true; - -error: - - mutex_unlock(&priv->lock); - - return err; -} -EXPORT_SYMBOL(tier4_max9295_setup_control); - -int tier4_max9295_reset_control(struct device *dev) -{ - struct tier4_max9295 *priv = dev_get_drvdata(dev); - int err = 0; - - mutex_lock(&priv->lock); - if (!priv->g_client.g_ctx) - { - dev_err(dev, "[%s] : No sdev client found\n", __func__); - err = -EINVAL; - goto error; - } - - prim_priv__[priv->g_client.g_ctx->reg_mux]->pst2_ref--; - - priv->g_client.st_done = false; - - tier4_max9295_write_reg(dev, MAX9295_DEV_ADDR, (prim_priv__[priv->g_client.g_ctx->reg_mux]->def_addr << 1)); - - tier4_max9295_write_reg(&prim_priv__[priv->g_client.g_ctx->reg_mux]->i2c_client->dev, MAX9295_CTRL0_ADDR, - MAX9295_RESET_ALL); - -error: - mutex_unlock(&priv->lock); - return err; -} -EXPORT_SYMBOL(tier4_max9295_reset_control); - -int tier4_max9295_sdev_pair(struct device *dev, struct tier4_gmsl_link_ctx *g_ctx) -{ - struct tier4_max9295 *priv; - int err = 0; - - if (!dev || !g_ctx || !g_ctx->s_dev) - { - dev_err(dev, "[%s]: Invalid input params\n", __func__); - return -EINVAL; - } - - priv = dev_get_drvdata(dev); - mutex_lock(&priv->lock); - if (priv->g_client.g_ctx) - { - dev_err(dev, "[%s] : Device already paired\n", __func__); - err = -EINVAL; - goto error; - } - priv->g_client.st_done = false; - - priv->g_client.g_ctx = g_ctx; - -error: - mutex_unlock(&priv->lock); - return 0; -} -EXPORT_SYMBOL(tier4_max9295_sdev_pair); - -int tier4_max9295_sdev_unpair(struct device *dev, struct device *s_dev) -{ - struct tier4_max9295 *priv = NULL; - int err = 0; - - if (!dev || !s_dev) - { - dev_err(dev, "[%s] : Invalid input params\n", __func__); - return -EINVAL; - } - - priv = dev_get_drvdata(dev); - - mutex_lock(&priv->lock); - - if (!priv->g_client.g_ctx) - { - dev_err(dev, "[%s] : Device is not paired\n", __func__); - err = -ENOMEM; - goto error; - } - - if (priv->g_client.g_ctx->s_dev != s_dev) - { - dev_err(dev, "[%s] : Invalid device\n", __func__); - err = -EINVAL; - goto error; - } - - priv->g_client.g_ctx = NULL; - priv->g_client.st_done = false; - -error: - mutex_unlock(&priv->lock); - return err; -} -EXPORT_SYMBOL(tier4_max9295_sdev_unpair); - -static struct regmap_config tier4_max9295_regmap_config = { - .reg_bits = 16, - .val_bits = 8, - .cache_type = REGCACHE_RBTREE, -}; - -static int tier4_max9295_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct tier4_max9295 *priv; - int err = 0; - struct device_node *node = client->dev.of_node; - - dev_info(&client->dev, "[%s] : probing GMSL Serializer\n", __func__); - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - priv->i2c_client = client; - priv->regmap = devm_regmap_init_i2c(priv->i2c_client, &tier4_max9295_regmap_config); - if (IS_ERR(priv->regmap)) - { - dev_err(&client->dev, "[%s] : devm_regmap_init() failed: %ld\n", __func__, PTR_ERR(priv->regmap)); - return -ENODEV; - } - - mutex_init(&priv->lock); - - if (of_get_property(node, "is-prim-ser", NULL)) - { - if (prim_priv__[channel_count_isx021] && channel_count_isx021 >= MAX_CHANNEL_NUM) - { - dev_err(&client->dev, "[%s] : prim-ser already exists\n", __func__); - return -EEXIST; - } - - err = of_property_read_u32(node, "reg", &priv->def_addr); - if (err < 0) - { - dev_err(&client->dev, "[%s] : reg not found\n", __func__); - return -EINVAL; - } - - if (priv == NULL) - { - dev_err(&client->dev, "[%s] : priv is NULL\n", __func__); - return err; - } - - prim_priv__[channel_count_isx021] = priv; - - channel_count_isx021++; - } - - dev_set_drvdata(&client->dev, priv); - - /* dev communication gets validated when GMSL link setup is done */ - dev_info(&client->dev, "[%s] : Probing succeeded\n", __func__); - - return err; -} - -static int tier4_max9295_remove(struct i2c_client *client) -{ - struct tier4_max9295 *priv; - - if (channel_count_isx021 > 0) - channel_count_isx021--; - - if (client != NULL) - { - priv = dev_get_drvdata(&client->dev); - mutex_destroy(&priv->lock); - } - - return 0; -} - -static const struct i2c_device_id tier4_max9295_id[] = { - { "tier4_max9295", 0 }, - {}, -}; - -const struct of_device_id tier4_max9295_of_match[] = { - { - .compatible = "nvidia,tier4_max9295", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, tier4_max9295_of_match); -MODULE_DEVICE_TABLE(i2c, tier4_max9295_id); - -static struct i2c_driver tier4_max9295_i2c_driver = { - .driver = { - .name = "tier4_max9295", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(tier4_max9295_of_match), - }, - .probe = tier4_max9295_probe, - .remove = tier4_max9295_remove, - .id_table = tier4_max9295_id, -}; - -static int __init tier4_max9295_init(void) -{ - printk(KERN_INFO "MAX9295 Driver for TIER4 C1 camera : %s\n", BUILD_STAMP); - - return i2c_add_driver(&tier4_max9295_i2c_driver); -} - -static void __exit tier4_max9295_exit(void) -{ - i2c_del_driver(&tier4_max9295_i2c_driver); -} - -module_init(tier4_max9295_init); -module_exit(tier4_max9295_exit); - -MODULE_DESCRIPTION("GMSL Serializer driver tier4_max9295"); -MODULE_AUTHOR("Originaly NVIDIA Corporation"); -MODULE_AUTHOR("K.Iwasaki"); -MODULE_AUTHOR("Y.Fujii"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-max9296.c b/drivers/src/tier4-max9296.c deleted file mode 100644 index 29037e1..0000000 --- a/drivers/src/tier4-max9296.c +++ /dev/null @@ -1,1228 +0,0 @@ -/* - * tier4_max9296.c - tier4_max9296 GMSL Deserializer driver - * - * Copyright (c) 2022, TIER IV Inc. All rights reserved. - * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - - -#include -#include -#include -#include -#include -#include - -#include "tier4-max9296.h" -#include "tier4-gmsl-link.h" -#include "tier4-hw-model.h" - -struct tier4_max9296_source_ctx -{ - struct tier4_gmsl_link_ctx *g_ctx; - bool st_enabled; -}; - -#define _USE_CHECK_LINK_LOCKED_ 1 - -#define MAX9296_SHOW_I2C_WRITE_MSG 1 - -/* register specifics */ - -#define MAX9296_LINK_ADDR 0x0013 - -#define MAX9296_REG5_ADDR 0x0005 -#define MAX9296_CTRL0_ADDR 0x0010 - -#define MAX9296_PIPE_X_ST_SEL_ADDR 0x0050 - -#define MAX9296_GPIO0_CONFIG_MFP0_ADDR 0x02B0 -#define MAX9296_GPIO0_GPIO_TX_ID_ADDR 0x02B1 -#define MAX9296_GPIO0_GPIO_RX_ID_ADDR 0x02B2 - -#define MAX9296_PHY1_CLK_ADDR 0x0320 - -#define MAX9296_DST_CSI_MODE_ADDR 0x0330 -#define MAX9296_PWDN_PHYS_ADDR 0x0332 -#define MAX9296_LANE_MAP1_ADDR 0x0333 -#define MAX9296_LANE_MAP2_ADDR 0x0334 - -#define MAX9296_LANE_CTRL0_ADDR 0x040A -#define MAX9296_TX11_PIPE_X_EN_ADDR 0x040B -#define MAX9296_PIPE_X_SRC_0_MAP_ADDR 0x040D -#define MAX9296_PIPE_X_DST_0_MAP_ADDR 0x040E -#define MAX9296_PIPE_X_SRC_1_MAP_ADDR 0x040F - -#define MAX9296_PIPE_X_DST_1_MAP_ADDR 0x0410 -#define MAX9296_PIPE_X_SRC_2_MAP_ADDR 0x0411 -#define MAX9296_PIPE_X_DST_2_MAP_ADDR 0x0412 - -#define MAX9296_TX45_PIPE_X_DST_CTRL_ADDR 0x042D - -#define MAX9296_LANE_CTRL1_ADDR 0x044A -#define MAX9296_LANE_CTRL2_ADDR 0x048A -#define MAX9296_LANE_CTRL3_ADDR 0x04CA - -/* data defines */ - -#define MAX9296_CSI_MODE_4X2 0x1 -#define MAX9296_CSI_MODE_2X4 0x4 -#define MAX9296_LANE_MAP1_4X2 0x44 -#define MAX9296_LANE_MAP2_4X2 0x44 -#define MAX9296_LANE_MAP1_2X4 0x4E -#define MAX9296_LANE_MAP2_2X4 0xE4 - -#define MAX9296_LANE_CTRL_MAP(num_lanes) (((num_lanes) << 6) & 0xF0) - -#define MAX9296_ALLPHYS_NOSTDBY 0xF0 -#define MAX9296_ST_ID_SEL_INVALID 0xF - -//#define MAX9296_PHY1_CLK 0x32 -#define MAX9296_PHY1_CLK_3100MHZ 0x3F -#define MAX9296_PHY1_CLK_3000MHZ 0x3E -#define MAX9296_PHY1_CLK_2900MHZ 0x3D -#define MAX9296_PHY1_CLK_2800MHZ 0x3C -#define MAX9296_PHY1_CLK_2700MHZ 0x3B -#define MAX9296_PHY1_CLK_2600MHZ 0x3A -#define MAX9296_PHY1_CLK_2500MHZ 0x39 -#define MAX9296_PHY1_CLK_2400MHZ 0x38 -#define MAX9296_PHY1_CLK_2300MHZ 0x37 -#define MAX9296_PHY1_CLK_2200MHZ 0x36 -#define MAX9296_PHY1_CLK_2100MHZ 0x35 -#define MAX9296_PHY1_CLK_2000MHZ 0x34 -#define MAX9296_PHY1_CLK_1900MHZ 0x33 -#define MAX9296_PHY1_CLK_1800MHZ 0x32 -#define MAX9296_PHY1_CLK_1700MHZ 0x31 -#define MAX9296_PHY1_CLK_1600MHZ 0x30 -#define MAX9296_PHY1_CLK_1500MHZ 0x2F -#define MAX9296_PHY1_CLK_1400MHZ 0x2E -#define MAX9296_PHY1_CLK_1300MHZ 0x2D -#define MAX9296_PHY1_CLK_1200MHZ 0x2C -#define MAX9296_PHY1_CLK_1100MHZ 0x2B -#define MAX9296_PHY1_CLK_1000MHZ 0x2A -#define MAX9296_PHY1_CLK_900MHZ 0x29 -#define MAX9296_PHY1_CLK_800MHZ 0x28 -#define MAX9296_PHY1_CLK_700MHZ 0x27 - -#define MAX9296_PHY1_CLK MAX9296_PHY1_CLK_1500MHZ - -#define MAX9296_RESET_ALL 0x80 - -/* Dual GMSL MAX9296A/B */ - -#define MAX9296_MAX_SOURCES 2 - -#define MAX9296_MAX_PIPES 4 - -#define MAX9296_PIPE_X 0 -#define MAX9296_PIPE_Y 1 -#define MAX9296_PIPE_Z 2 -#define MAX9296_PIPE_U 3 -#define MAX9296_PIPE_INVALID 0xF - -#define MAX9296_CSI_CTRL_0 0 -#define MAX9296_CSI_CTRL_1 1 -#define MAX9296_CSI_CTRL_2 2 -#define MAX9296_CSI_CTRL_3 3 - -#define MAX9296_INVAL_ST_ID 0xFF - -/* Use reset value as per spec, confirm with vendor */ - -#define MAX9296_RESET_ST_ID 0x00 - -struct pipe_ctx -{ - u32 id; - u32 dt_type; - u32 dst_csi_ctrl; - u32 st_count; - u32 st_id_sel; -}; - -struct tier4_max9296 -{ - struct i2c_client *i2c_client; - struct regmap *regmap; - u32 num_src; - u32 max_src; - u32 num_src_found; - u32 src_link; - bool splitter_enabled; - - struct tier4_max9296_source_ctx sources[MAX9296_MAX_SOURCES]; - - struct mutex lock; - u32 sdev_ref; - bool lane_setup; - bool link_setup; - struct pipe_ctx pipe[MAX9296_MAX_PIPES]; - u8 csi_mode; - u8 lane_mp1; - u8 lane_mp2; - int reset_gpio; - int pw_ref; - struct regulator *vdd_cam_1v2; -}; - -static int tier4_max9296_read_reg(struct device *dev, u16 addr, u8 *val) -{ - int err = 0; - u32 reg_val = 0; - struct tier4_max9296 *priv = dev_get_drvdata(dev); - char str_bus_num[4], str_sl_addr[4]; - int len; - - memset(str_bus_num, 0, 4); - memset(str_sl_addr, 0, 4); - - err = regmap_read(priv->regmap, addr, ®_val); - *val = reg_val & 0xFF; - - if ((err == 0) && (dev != NULL)) - { - len = strlen(dev->kobj.name); - - if (dev) - { - strncpy(str_bus_num, &dev->kobj.name[0], 2); - strncpy(str_sl_addr, &dev->kobj.name[len - 2], 2); - } - dev_info(dev, "tier4_max9296_read_reg %s 0x%s 0x%x\n", str_bus_num, str_sl_addr, addr); - } - - return err; -} - -static int tier4_max9296_write_reg(struct device *dev, u16 addr, u8 val) -{ - struct tier4_max9296 *priv; - int err; - char str_bus_num[4], str_sl_addr[4]; - int len; - - priv = dev_get_drvdata(dev); - - memset(str_bus_num, 0, 4); - memset(str_sl_addr, 0, 4); - - len = strlen(dev->kobj.name); - - if (dev) - { - strncpy(str_bus_num, &dev->kobj.name[0], 2); - strncpy(str_sl_addr, &dev->kobj.name[len - 2], 2); - } - - err = regmap_write(priv->regmap, addr, val); - - if (err) - { - dev_err(dev, "[%s] : Max9296 I2C write failed Reg at 0x%04X:[0x%02X]\n", __func__, addr, val); - return err; - } -#if MAX9296_SHOW_I2C_WRITE_MSG - else - { - dev_info(dev, "[%s] : Max9296 I2C write register at 0x%04X:[0x%02X]\n", __func__, addr, val); - } -#endif - /* delay before next i2c command as required for SERDES link */ - - usleep_range(100, 110); - - return err; -} - -static int tier4_max9296_get_sdev_idx(struct device *dev, struct device *s_dev, int *idx) -{ - int i; - int err = 0; - struct tier4_max9296 *priv = dev_get_drvdata(dev); - - mutex_lock(&priv->lock); - - for (i = 0; i < priv->max_src; i++) - { - if (priv->sources[i].g_ctx->s_dev == s_dev) - { - break; - } - } - if (i == priv->max_src) - { - dev_err(dev, "[%s] : No sdev found\n", __func__); - err = -EINVAL; - goto ret; - } - - if (idx) - { - *idx = i; - } - -ret: - mutex_unlock(&priv->lock); - return err; -} - -static void tier4_max9296_pipes_reset(struct tier4_max9296 *priv) -{ - /* - * This is default pipes combination. add more mappings - * for other combinations and requirements. - */ - struct pipe_ctx pipe_defaults[] = { { MAX9296_PIPE_X, GMSL_CSI_DT_YUV_8, // For YUV8 - MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID }, - { MAX9296_PIPE_Y, GMSL_CSI_DT_YUV_8, // For YUV8 - MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID }, - { MAX9296_PIPE_Z, GMSL_CSI_DT_EMBED, MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID }, - { MAX9296_PIPE_U, GMSL_CSI_DT_EMBED, MAX9296_CSI_CTRL_1, 0, - MAX9296_INVAL_ST_ID } }; - - /* - * Add DT props for num-streams and stream sequence, and based on that - * set the appropriate pipes defaults. - * For now default it supports "2 RAW12 and 2 EMBED" 1:1 mappings. - */ - memcpy(priv->pipe, pipe_defaults, sizeof(pipe_defaults)); -} - -static void tier4_max9296_reset_ctx(struct tier4_max9296 *priv) -{ - int i; - - priv->link_setup = false; - priv->lane_setup = false; - priv->num_src_found = 0; - priv->src_link = 0; - priv->splitter_enabled = false; - - tier4_max9296_pipes_reset(priv); - - for (i = 0; i < priv->num_src; i++) - { - priv->sources[i].st_enabled = false; - } -} - -int tier4_max9296_power_on(struct device *dev) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - int i, err = 0; - - mutex_lock(&priv->lock); - - if (priv->pw_ref == 0) - { - usleep_range(1, 2); - - for (i = 0; i < priv->max_src; i++) - { - if (priv->sources[i].g_ctx) - { - break; - } - } -// if (priv->reset_gpio) - if (gpio_is_valid(priv->reset_gpio)) - { - gpio_direction_output(priv->reset_gpio, 0); - } - - usleep_range(50, 80); - - if (priv->vdd_cam_1v2) - { - err = regulator_enable(priv->vdd_cam_1v2); - if (unlikely(err)) - goto ret; - } - usleep_range(50, 80); - - /*exit reset mode: XCLR */ -// if (priv->reset_gpio) - if (gpio_is_valid(priv->reset_gpio)) - { - - // gpio_set_value(priv->reset_gpio, 0); - gpio_direction_output(priv->reset_gpio, 0); - - usleep_range(50, 80); - usleep_range(1000000,1100000); - // gpio_set_value(priv->reset_gpio, 1); - - gpio_direction_output(priv->reset_gpio, 1); - - usleep_range(50, 80); - } - - /* delay to settle reset */ - // msleep(1000); - } - - priv->pw_ref++; - -ret: - - mutex_unlock(&priv->lock); - - return err; -} -EXPORT_SYMBOL(tier4_max9296_power_on); - -void tier4_max9296_power_off(struct device *dev) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - - mutex_lock(&priv->lock); - priv->pw_ref--; - - if (priv->pw_ref == 0) - { - /* enter reset mode: XCLR */ - usleep_range(1, 2); - if (priv->reset_gpio) - // gpio_set_value(priv->reset_gpio, 0); - gpio_direction_output(priv->reset_gpio, 0); - - if (priv->vdd_cam_1v2) - regulator_disable(priv->vdd_cam_1v2); - } - - mutex_unlock(&priv->lock); -} -EXPORT_SYMBOL(tier4_max9296_power_off); - -static int tier4_max9296_write_link(struct device *dev, u32 link) -{ - int err = 0; - - if (link == GMSL_SERDES_CSI_LINK_A) - { - err = tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x01); - err |= tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x21); - } - else if (link == GMSL_SERDES_CSI_LINK_B) - { - err = tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x02); - err |= tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x22); - } - else - { - dev_err(dev, "[%s] : Invalid GMSL link\n", __func__); - return -EINVAL; - } - - /* delay to settle link */ - msleep(100); - - return 0; -} - -int tier4_max9296_setup_link(struct device *dev, struct device *s_dev) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - int err = 0; - int i; - - err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_get_sdev_idx failed.\n", __func__); - return err; - } - - // max9296_debug_i2c_write = priv->sources[i].g_ctx->debug_i2c_write; - - mutex_lock(&priv->lock); - - if (!priv->splitter_enabled) - { - err = tier4_max9296_write_link(dev, priv->sources[i].g_ctx->serdes_csi_link); - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_write_link failed.\n", __func__); - goto ret; - } - priv->link_setup = true; - } - -ret: - mutex_unlock(&priv->lock); - - return err; -} -EXPORT_SYMBOL(tier4_max9296_setup_link); - -static int tier4_max9296_link_locked(struct device *dev) -{ - u8 val; - - usleep_range(100, 110); - tier4_max9296_read_reg(dev, MAX9296_LINK_ADDR, &val); - - if (0 == (val & 0x08)) - { - return -EINVAL; - } - return 0; -} - -int tier4_max9296_setup_gpi(struct device *dev, int fsync_mfp) -{ - int err = 0; - u16 gpio_mfp_base; - - dev_info(dev, "[%s] : MFP%d is used for fsync\n", __func__, fsync_mfp); - - gpio_mfp_base = (MAX9296_GPIO0_CONFIG_MFP0_ADDR + 3 * fsync_mfp) & 0xFFFF; - - err += tier4_max9296_write_reg(dev, gpio_mfp_base, 0x03); - err += tier4_max9296_write_reg(dev, gpio_mfp_base + 1, 0x06); - err += tier4_max9296_write_reg(dev, gpio_mfp_base + 2, 0x00); - - return err; -} -EXPORT_SYMBOL(tier4_max9296_setup_gpi); - -int tier4_max9296_setup_control(struct device *dev, struct device *s_dev) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - int err = 0; - int i; - - err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_get_sdev_idx() failed.\n", __func__); - return err; - } - - mutex_lock(&priv->lock); - - if (!priv->link_setup) - { - dev_err(dev, "[%s] : Invalid state\n", __func__); - err = -EINVAL; - goto error; - } - - if (priv->sources[i].g_ctx->serdev_found) - { - priv->num_src_found++; - priv->src_link = priv->sources[i].g_ctx->serdes_csi_link; - } - - /* Enable splitter mode */ - if ((priv->max_src > 1U) && (priv->num_src_found > 0U) && (priv->splitter_enabled == false)) - { - tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x03); - tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x23); - - priv->splitter_enabled = true; - - /* delay to settle link */ - msleep(500); - } - -#if _USE_CHECK_LINK_LOCKED_ - // Check GMSL link - err = tier4_max9296_link_locked(dev); - if (err) - { - // GMSL2 link not locked - dev_info(dev, "[%s]: max9296 link is not locked.\n", __func__); - err = tier4_max9296_write_link(dev, priv->src_link); - if (err) - { - dev_err(dev, "[%s]: tier4_max9296_write_link() failed.\n", __func__); - goto error; - } - } -#endif - - if (!priv->splitter_enabled) - { - tier4_max9296_write_reg(dev, MAX9296_PWDN_PHYS_ADDR, MAX9296_ALLPHYS_NOSTDBY); - priv->splitter_enabled = true; - } - priv->link_setup = true; - - priv->sdev_ref++; - - /* Reset splitter mode if all devices are not found */ - if ((priv->sdev_ref == priv->max_src) && (priv->splitter_enabled == true) && (priv->num_src_found > 0U) && - (priv->num_src_found < priv->max_src)) - { - err = tier4_max9296_write_link(dev, priv->src_link); - if (err) - goto error; - - priv->splitter_enabled = false; - } - -error: - mutex_unlock(&priv->lock); - return err; -} -EXPORT_SYMBOL(tier4_max9296_setup_control); - -int tier4_max9296_reset_control(struct device *dev, struct device *s_dev, bool force_reset) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - int err = 0; - - mutex_lock(&priv->lock); - if (!priv->sdev_ref && force_reset == false) - { - dev_info(dev, "[%s] : dev is already in reset state\n", __func__); - goto ret; - } - - priv->sdev_ref--; - if (priv->sdev_ref == 0 || force_reset == true) - { - tier4_max9296_reset_ctx(priv); - tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, MAX9296_RESET_ALL); - - /* delay to settle reset */ - msleep(100); - } - -ret: - mutex_unlock(&priv->lock); - - return err; -} -EXPORT_SYMBOL(tier4_max9296_reset_control); - -int tier4_max9296_sdev_register(struct device *dev, struct tier4_gmsl_link_ctx *g_ctx) -{ - struct tier4_max9296 *priv = NULL; - int i; - int err = 0; - - if (!dev || !g_ctx || !g_ctx->s_dev) - { - dev_err(dev, "[%s] : Invalid input params\n", __func__); - return -EINVAL; - } - - priv = dev_get_drvdata(dev); - - mutex_lock(&priv->lock); - - if ((g_ctx->hardware_model == HW_MODEL_NVIDIA_ORIN_DEVKIT ) || - (g_ctx->hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN )) - { - for ( i = 0 ; i < MAX9296_MAX_SOURCES ; i++ ) - { - if ( priv->sources[i].g_ctx != NULL ) - { - priv->sources[i].g_ctx->serdes_csi_link = 0; - } - } - } - - if (priv->num_src > priv->max_src) - { - dev_err(dev, "[%s] : MAX9296 inputs size exhausted\n", __func__); - err = -ENOMEM; - goto error; - } - - /* Check csi mode compatibility */ - if (!((priv->csi_mode == MAX9296_CSI_MODE_2X4) ? - ((g_ctx->csi_mode == GMSL_CSI_1X4_MODE) || (g_ctx->csi_mode == GMSL_CSI_2X4_MODE)) : - ((g_ctx->csi_mode == GMSL_CSI_2X2_MODE) || (g_ctx->csi_mode == GMSL_CSI_4X2_MODE)))) - { - dev_err(dev, "[%s] : CSI mode not supported\n", __func__); - err = -EINVAL; - goto error; - } - - asm("dsb sy"); - - for (i = 0; i < priv->num_src; i++) - { -// dev_info(dev, "[%s]: g_ctx->serdes_csi_link = %u priv->sources[%d].g_ctx->serdes_csi_link = %u\n" -// , __func__, g_ctx->serdes_csi_link, i, priv->sources[i].g_ctx->serdes_csi_link ); - -// usleep_range(1000,1100); - - if (g_ctx->serdes_csi_link == priv->sources[i].g_ctx->serdes_csi_link) - { -// WARN_ON(1); - dev_info(dev, "[%s]: g_ctx->serdes_csi_link = %u\n" , __func__, g_ctx->serdes_csi_link ); - dev_err(dev, "[%s] : Serdes CSI link is in use\n", __func__); - err = -EINVAL; - goto error; - } - /* - * All sdevs should have same num-csi-lanes regardless of - * dst csi port selected. - * Later if there is any usecase which requires each port - * to be configured with different num-csi-lanes, then this - * check should be performed per port. - */ - - if (g_ctx->num_csi_lanes != priv->sources[i].g_ctx->num_csi_lanes) - { - dev_err(dev, "[%s] : CSI num lanes mismatch. %d, %d i=%d\n", __func__, g_ctx->num_csi_lanes, - priv->sources[i].g_ctx->num_csi_lanes, i); - err = -EINVAL; - goto error; - } - } - - priv->sources[priv->num_src].g_ctx = g_ctx; - priv->sources[priv->num_src].st_enabled = false; - - priv->num_src++; - -error: - mutex_unlock(&priv->lock); - return err; -} -EXPORT_SYMBOL(tier4_max9296_sdev_register); - -int tier4_max9296_sdev_unregister(struct device *dev, struct device *s_dev) -{ - struct tier4_max9296 *priv = NULL; - int err = 0; - int i = 0; - - if (!dev || !s_dev) - { - dev_err(dev, "[%s] : Invalid input params\n", __func__); - return -EINVAL; - } - - priv = dev_get_drvdata(dev); - mutex_lock(&priv->lock); - - if (priv->num_src == 0) - { - dev_err(dev, "[%s] : No source found\n", __func__); - err = -ENODATA; - goto error; - } - - for (i = 0; i < priv->num_src; i++) - { - if (s_dev == priv->sources[i].g_ctx->s_dev) - { - priv->sources[i].g_ctx = NULL; - priv->num_src--; - break; - } - } - - if (i == priv->num_src) - { - dev_err(dev, "[%s] : Requested device not found\n", __func__); - err = -EINVAL; - goto error; - } - -error: - mutex_unlock(&priv->lock); - return err; -} -EXPORT_SYMBOL(tier4_max9296_sdev_unregister); - -static int tier4_max9296_get_available_pipe(struct device *dev, u32 st_data_type, u32 dst_csi_port) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - int i; - - for (i = 0; i < MAX9296_MAX_PIPES; i++) - { - /* - * TODO: Enable a pipe for multi stream configuration having - * similar stream data type. For now use st_count as a flag - * for 1 to 1 mapping in pipe and stream data type, same can - * be extended as count for many to 1 mapping. Would also need - * few more checks such as input stream id select, dst port etc. - */ - if ((priv->pipe[i].dt_type == st_data_type) && - ((dst_csi_port == GMSL_CSI_PORT_A) ? - (priv->pipe[i].dst_csi_ctrl == MAX9296_CSI_CTRL_0) || (priv->pipe[i].dst_csi_ctrl == MAX9296_CSI_CTRL_1) : - (priv->pipe[i].dst_csi_ctrl == MAX9296_CSI_CTRL_2) || - (priv->pipe[i].dst_csi_ctrl == MAX9296_CSI_CTRL_3)) && - (!priv->pipe[i].st_count)) - break; - } - - if (i == MAX9296_MAX_PIPES) - { - dev_err(dev, "[%s] : All pipes are busy\n", __func__); - return -ENOMEM; - } - - return i; -} - -struct reg_pair -{ - u16 addr; - u8 val; -}; - -static int tier4_max9296_setup_pipeline(struct device *dev, struct tier4_gmsl_link_ctx *g_ctx) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - struct tier4_gmsl_stream *g_stream; - struct reg_pair *map_list; - u32 arr_sz = 0; - int pipe_id = 0; - u32 i = 0; - u32 j = 0; - u32 vc_idx = 0; - - for (i = 0; i < g_ctx->num_streams; i++) - { - /* Base data type mapping: pipeX/RAW12/CSICNTR1 */ - struct reg_pair map_pipe_yuv8[] = { - // for YUV8 - /* addr, val */ - { MAX9296_TX11_PIPE_X_EN_ADDR, 0x7 }, { MAX9296_TX45_PIPE_X_DST_CTRL_ADDR, 0x15 }, - - { MAX9296_PIPE_X_SRC_0_MAP_ADDR, 0x1E }, // for YUV8 - { MAX9296_PIPE_X_DST_0_MAP_ADDR, 0x1E }, // for YUV8 - { MAX9296_PIPE_X_SRC_1_MAP_ADDR, 0x00 }, { MAX9296_PIPE_X_DST_1_MAP_ADDR, 0x00 }, - { MAX9296_PIPE_X_SRC_2_MAP_ADDR, 0x01 }, { MAX9296_PIPE_X_DST_2_MAP_ADDR, 0x01 }, - }; - - /* Base data type mapping: pipeX/EMBED/CSICNTR1 */ - struct reg_pair map_pipe_embed[] = { - /* addr, val */ - { MAX9296_TX11_PIPE_X_EN_ADDR, 0x7 }, { MAX9296_TX45_PIPE_X_DST_CTRL_ADDR, 0x15 }, - { MAX9296_PIPE_X_SRC_0_MAP_ADDR, 0x12 }, { MAX9296_PIPE_X_DST_0_MAP_ADDR, 0x12 }, - { MAX9296_PIPE_X_SRC_1_MAP_ADDR, 0x00 }, { MAX9296_PIPE_X_DST_1_MAP_ADDR, 0x00 }, - { MAX9296_PIPE_X_SRC_2_MAP_ADDR, 0x01 }, { MAX9296_PIPE_X_DST_2_MAP_ADDR, 0x01 }, - }; - - g_stream = &g_ctx->streams[i]; - g_stream->des_pipe = MAX9296_PIPE_INVALID; - - if (g_stream->st_data_type == GMSL_CSI_DT_YUV_8) - { // for YUV8 - map_list = map_pipe_yuv8; // for YUV8 - arr_sz = ARRAY_SIZE(map_pipe_yuv8); // for YUV8 - } - else if (g_stream->st_data_type == GMSL_CSI_DT_EMBED) - { - map_list = map_pipe_embed; - arr_sz = ARRAY_SIZE(map_pipe_embed); - } - else if (g_stream->st_data_type == GMSL_CSI_DT_UED_U1) - { - continue; - } - else - { - dev_err(dev, "[%s] : Invalid data type\n", __func__); - return -EINVAL; - } - - pipe_id = tier4_max9296_get_available_pipe(dev, g_stream->st_data_type, g_ctx->dst_csi_port); - if (pipe_id < 0) - return pipe_id; - - for (j = 0, vc_idx = 3; j < arr_sz; j++, vc_idx += 2) - { - /* update pipe configuration */ - map_list[j].addr += (0x40 * pipe_id); - /* update vc id configuration */ - if (vc_idx < arr_sz) - { - map_list[vc_idx].val |= (g_ctx->dst_vc << 6); - } - tier4_max9296_write_reg(dev, map_list[j].addr, map_list[j].val); - } - - /* Set stream id select input */ - if (g_stream->st_id_sel == GMSL_ST_ID_UNUSED) - { - dev_err(dev, "[%s] : Invalid stream st_id_sel\n", __func__); - return -EINVAL; - } - - g_stream->des_pipe = MAX9296_PIPE_X_ST_SEL_ADDR + pipe_id; - - /* Update pipe internals */ - priv->pipe[pipe_id].st_count++; - priv->pipe[pipe_id].st_id_sel = g_stream->st_id_sel; - } - - return 0; -} - -int tier4_max9296_start_streaming(struct device *dev, struct device *s_dev) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - struct tier4_gmsl_link_ctx *g_ctx; - struct tier4_gmsl_stream *g_stream; - int err = 0; - int i = 0; - - err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_get_sdev_idx failed.\n", __func__); - return err; - } - - mutex_lock(&priv->lock); - - g_ctx = priv->sources[i].g_ctx; - - for (i = 0; i < g_ctx->num_streams; i++) - { - g_stream = &g_ctx->streams[i]; - - if (g_stream->des_pipe != MAX9296_PIPE_INVALID) - { - tier4_max9296_write_reg(dev, g_stream->des_pipe, g_stream->st_id_sel); - } - } - - mutex_unlock(&priv->lock); - - return 0; -} -EXPORT_SYMBOL(tier4_max9296_start_streaming); - -int tier4_max9296_stop_streaming(struct device *dev, struct device *s_dev) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - struct tier4_gmsl_link_ctx *g_ctx; - struct tier4_gmsl_stream *g_stream; - int err = 0; - int i = 0; - - err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); - if (err) - return err; - - mutex_lock(&priv->lock); - g_ctx = priv->sources[i].g_ctx; - - for (i = 0; i < g_ctx->num_streams; i++) - { - g_stream = &g_ctx->streams[i]; - - if (g_stream->des_pipe != MAX9296_PIPE_INVALID) - { - tier4_max9296_write_reg(dev, g_stream->des_pipe, MAX9296_RESET_ST_ID); - } - } - - mutex_unlock(&priv->lock); - - return 0; -} -EXPORT_SYMBOL(tier4_max9296_stop_streaming); - -int tier4_max9296_setup_streaming(struct device *dev, struct device *s_dev) -{ - struct tier4_max9296 *priv = dev_get_drvdata(dev); - struct tier4_gmsl_link_ctx *g_ctx; - int err = 0; - int i = 0; - u16 lane_ctrl_addr; - - err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_get_sdev_idx() failed.\n", __func__); - return err; - } - - mutex_lock(&priv->lock); - if (priv->sources[i].st_enabled) - goto ret; - - g_ctx = priv->sources[i].g_ctx; - - err = tier4_max9296_setup_pipeline(dev, g_ctx); - - if (err) - { - dev_err(dev, "[%s] : tier4_max9296_setup_pipeline() failed.\n", __func__); - goto ret; - } - - /* Derive CSI lane map register */ - switch (g_ctx->dst_csi_port) - { - case GMSL_CSI_PORT_A: - case GMSL_CSI_PORT_D: - lane_ctrl_addr = MAX9296_LANE_CTRL1_ADDR; - break; - case GMSL_CSI_PORT_B: - case GMSL_CSI_PORT_E: - lane_ctrl_addr = MAX9296_LANE_CTRL2_ADDR; - break; - case GMSL_CSI_PORT_C: - lane_ctrl_addr = MAX9296_LANE_CTRL0_ADDR; - break; - case GMSL_CSI_PORT_F: - lane_ctrl_addr = MAX9296_LANE_CTRL3_ADDR; - break; - default: - dev_err(dev, "[%s] : Invalid GMSL CSI port!\n", __func__); - err = -EINVAL; - goto ret; - }; - - /* - * rewrite num_lanes to same dst port should not be an issue, - * as the device compatibility is already - * checked during sdev registration against the des properties. - */ - - tier4_max9296_write_reg(dev, lane_ctrl_addr, MAX9296_LANE_CTRL_MAP(g_ctx->num_csi_lanes - 1)); - - if (!priv->lane_setup) - { - tier4_max9296_write_reg(dev, MAX9296_DST_CSI_MODE_ADDR, priv->csi_mode); - tier4_max9296_write_reg(dev, MAX9296_LANE_MAP1_ADDR, priv->lane_mp1); - tier4_max9296_write_reg(dev, MAX9296_LANE_MAP2_ADDR, priv->lane_mp2); - if (g_ctx->hardware_model == HW_MODEL_NVIDIA_ORIN_DEVKIT) - { - tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, MAX9296_PHY1_CLK_1400MHZ); - } - else if (g_ctx->hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN) - { - tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, MAX9296_PHY1_CLK_1500MHZ); - } - else if (g_ctx->hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) - { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 65) - // RQX-58G L4T 35.4.1 - tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, MAX9296_PHY1_CLK_1600MHZ); -#else // RQX-58G L4T 32.x - tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, MAX9296_PHY1_CLK_1800MHZ); -#endif - } - else - { - tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, MAX9296_PHY1_CLK_1400MHZ); - } - - priv->lane_setup = true; - } - -#if 0 - tier4_max9296_write_reg(dev, MAX9296_REG5_ADDR, 0xC0); // informed from Maxim -#endif - priv->sources[i].st_enabled = true; - -ret: - mutex_unlock(&priv->lock); - return err; -} -EXPORT_SYMBOL(tier4_max9296_setup_streaming); - -const struct of_device_id tier4_max9296_of_match[] = { - { - .compatible = "nvidia,tier4_max9296", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, tier4_max9296_of_match); - -static int tier4_max9296_parse_dt(struct tier4_max9296 *priv, struct i2c_client *client) -{ - struct device_node *node = client->dev.of_node; - int err = 0; - const char *str_value; - int value; - const struct of_device_id *match; - - if (!node) - return -EINVAL; - - match = of_match_device(tier4_max9296_of_match, &client->dev); - if (!match) - { - dev_err(&client->dev, "[%s] : Failed to match device with dt id\n", __func__); - return -EFAULT; - } - - err = of_property_read_string(node, "csi-mode", &str_value); - if (err < 0) - { - dev_err(&client->dev, "[%s] : csi-mode property not found\n", __func__); - return err; - } - - if (!strcmp(str_value, "2x4")) - { - priv->csi_mode = MAX9296_CSI_MODE_2X4; - priv->lane_mp1 = MAX9296_LANE_MAP1_2X4; - priv->lane_mp2 = MAX9296_LANE_MAP2_2X4; - } - else if (!strcmp(str_value, "4x2")) - { - priv->csi_mode = MAX9296_CSI_MODE_4X2; - priv->lane_mp1 = MAX9296_LANE_MAP1_4X2; - priv->lane_mp2 = MAX9296_LANE_MAP2_4X2; - } - else - { - dev_err(&client->dev, "[%s] : Invalid csi mode\n", __func__); - return -EINVAL; - } - - err = of_property_read_u32(node, "max-src", &value); - if (err < 0) - { - dev_err(&client->dev, "[%s] : No max-src info\n", __func__); - return err; - } - - priv->max_src = value; - - priv->reset_gpio = of_get_named_gpio(node, "reset-gpios", 0); - if (priv->reset_gpio < 0) - { - dev_err(&client->dev, "[%s] : reset-gpios not found %d\n", __func__, err); - return err; - } - - /* digital 1.2v */ - if (of_get_property(node, "vdd_cam_1v2-supply", NULL)) - { - priv->vdd_cam_1v2 = regulator_get(&client->dev, "vdd_cam_1v2"); - if (IS_ERR(priv->vdd_cam_1v2)) - { - dev_err(&client->dev, "[%s] : vdd_cam_1v2 regulator get failed\n", __func__); - err = PTR_ERR(priv->vdd_cam_1v2); - priv->vdd_cam_1v2 = NULL; - return err; - } - } - else - { - priv->vdd_cam_1v2 = NULL; - } - - return 0; -} - -static struct regmap_config tier4_max9296_regmap_config = { - .reg_bits = 16, - .val_bits = 8, - .cache_type = REGCACHE_RBTREE, -}; - -static int tier4_max9296_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct tier4_max9296 *priv; - int err = 0; - - dev_info(&client->dev, "[%s]: Probing GMSL deserializer\n", __func__); - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - priv->i2c_client = client; - priv->regmap = devm_regmap_init_i2c(priv->i2c_client, &tier4_max9296_regmap_config); - if (IS_ERR(priv->regmap)) - { - dev_err(&client->dev, "[%s] : devm_regmap_init() failed: %ld\n", __func__, PTR_ERR(priv->regmap)); - return -ENODEV; - } - - err = tier4_max9296_parse_dt(priv, client); - if (err) - { - dev_err(&client->dev, "[%s] : Unable to parse dt\n", __func__); - return -EFAULT; - } - - tier4_max9296_pipes_reset(priv); - - if (priv->max_src > MAX9296_MAX_SOURCES) - { - dev_err(&client->dev, "[%s] : Max sources more than currently supported\n", __func__); - return -EINVAL; - } - - mutex_init(&priv->lock); - - dev_set_drvdata(&client->dev, priv); - - /* dev communication gets validated when GMSL link setup is done */ - dev_info(&client->dev, "[%s] : Probing GMSL Deserializer is done.\n", __func__); - - return err; -} - -static int tier4_max9296_remove(struct i2c_client *client) -{ - struct tier4_max9296 *priv; - - if (client != NULL) - { - priv = dev_get_drvdata(&client->dev); - mutex_destroy(&priv->lock); - } - - return 0; -} - -static const struct i2c_device_id tier4_max9296_id[] = { - { "tier4_max9296", 0 }, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, tier4_max9296_id); - -static struct i2c_driver tier4_max9296_i2c_driver = { - .driver = { - .name = "tier4_max9296", - .owner = THIS_MODULE, - .of_match_table = of_match_ptr(tier4_max9296_of_match), - }, - .probe = tier4_max9296_probe, - .remove = tier4_max9296_remove, - .id_table = tier4_max9296_id, -}; - -static int __init tier4_max9296_init(void) -{ - printk(KERN_INFO "MAX9296 Driver for TIERIV Camera : %s\n", BUILD_STAMP); - return i2c_add_driver(&tier4_max9296_i2c_driver); -} - -static void __exit tier4_max9296_exit(void) -{ - i2c_del_driver(&tier4_max9296_i2c_driver); -} - -module_init(tier4_max9296_init); -module_exit(tier4_max9296_exit); - -MODULE_DESCRIPTION("Dual GMSL Deserializer driver tier4_max9296"); -MODULE_AUTHOR("Originaly NVIDIA Corporation"); -MODULE_AUTHOR("K.Iwasaki"); -MODULE_AUTHOR("Y.Fujii"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/tools/make_overlay_dtb.py b/drivers/tools/make_overlay_dtb.py deleted file mode 100755 index 9491478..0000000 --- a/drivers/tools/make_overlay_dtb.py +++ /dev/null @@ -1,4363 +0,0 @@ -import sys - -str_overlay_header = ''' -/dts-v1/; -/plugin/; - -/ { - overlay-name = "Tier4 ISX021 IMX490 GMSL2 Camera Device Tree Overlay"; - compatible = "nvidia,p2822-0000+p2888-0001"; - jetson-header-name = "Jetson AGX Xavier CSI Connector"; - -''' - -str_fragment0 = ''' - - fragment@0 { - - target-path = \"/i2c@c240000/tca9546@70/i2c@0\"; - - __overlay__ { - - i2c-mux,deselect-on-exit; - #address-cells = <1>; - #size-cells = <0>; - -''' - -str_ser_isp_i2c0 = ''' - - ser_prim: max9295_prim@62 { - compatible = "nvidia,tier4_max9295"; - reg = <0x62>; - is-prim-ser; - }; - ser_a: max9295_a@42 { - compatible = \"nvidia,tier4_max9295\"; - reg = <0x42>; - nvidia,gmsl-dser-device = <&dser>; - }; - ser_b: max9295_b@60 { - compatible = \"nvidia,tier4_max9295\"; - reg = <0x60>; - nvidia,gmsl-dser-device = <&dser>; - }; - isp_prim: gw5300_prim@6d { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6d>; - is-prim-isp; - }; - isp_a: gw5300_a@6e { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6e>; - }; - isp_b: gw5300_b@6f { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6f>; - }; -''' - -str_imx490_b_2c_i2c0 = ''' - - imx490_b@2c { - compatible = \"nvidia,tier4_imx490\"; - def-addr = <0x1a>; - // clocks = <&bpmp_clks 36>, <&bpmp_clks 36>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,isp-device = <&isp_b>; // for C2 camera - nvidia,gmsl-ser-device = <&ser_b>; - nvidia,gmsl-dser-device = <&dser>; - nvidia,fpga-device = <&t4_fpga>; - reg = <0x2c>; - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <0>; - sensor_model =\"imx490\"; - fsync-mode = \"false\"; - distortion-correction = \"false\"; - auto-exposure = \"true\"; - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = "\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode IMX490_MODE_2880X1860_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"2880\"; - active_h = \"1860\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"160704000\"; - serdes_pix_clk_hz = \"1200000000\"; - - gain_factor = \"5\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"1\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"0\"; - max_framerate = \"40954095\"; - step_framerate = \"1\"; - default_framerate = \"0\"; - exposure_factor = \"1000000\"; - min_exp_time = \"0\"; /* us 1 line */ - max_exp_time = \"40954095\"; - step_exp_time = \"1\"; - default_exp_time = \"0\"; /* us */ - embedded_metadata_height = \"0\"; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - imx490_out1: endpoint { - vc-id = <1>; - port-index = <0>; - bus-width = <2>; - remote-endpoint = <&csi_in1>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"b\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <1>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_imx490_a_2b_i2c0 = ''' - - imx490_a@2b { - compatible = \"nvidia,tier4_imx490\"; - def-addr = <0x1a>; - // clocks = <&bpmp_clks 36>, <&bpmp_clks 36>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,isp-device = <&isp_a>; // for C2 camera - nvidia,gmsl-ser-device = <&ser_a>; - nvidia,gmsl-dser-device = <&dser>; - nvidia,fpga-device = <&t4_fpga>; - reg = <0x2b>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <0>; - sensor_model =\"imx490\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - - mode0 {/*mode IMX490_MODE_2880X1860_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"2880\"; - active_h = \"1860\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"160704000\"; - serdes_pix_clk_hz = \"1200000000\"; - - gain_factor = \"5\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"1\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"0\"; - max_framerate = \"40954095\"; - step_framerate = \"1\"; - default_framerate = \"0\"; - exposure_factor = \"1000000\"; - min_exp_time = \"0\"; /* us 1 line */ - max_exp_time = \"40954095\"; - step_exp_time = \"1\"; - default_exp_time = \"0\"; /* us */ - embedded_metadata_height = \"0\"; - }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - imx490_out0: endpoint { - vc-id = <0>; - port-index = <0>; - bus-width = <2>; - remote-endpoint = <&csi_in0>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; /* Port at which sensor is connected to its serializer device. */ - dst-csi-port = \"a\"; /* Destination CSI port on the Jetson side, connected at deserializer. */ - serdes-csi-link = \"a\"; /* GMSL link sensor/serializer connected */ - csi-mode = \"1x4\"; /* to sensor CSI mode. */ - st-vc = <0>; /* Sensor source default VC ID: 0 unless overridden by sensor. */ - vc-id = <0>; /* Destination VC ID, assigned to sensor stream by deserializer. */ - num-lanes = <2>; /* Number of CSI lanes used. */ - streams = \"ued-u1\",\"yuv8\"; /* Types of streams sensor is streaming. */ - }; - }; -''' - -str_isx021_b_1c_i2c0 = ''' - - isx021_b@1c { - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>, - // <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,gmsl-ser-device = <&ser_b>; - nvidia,gmsl-dser-device = <&dser>; - nvidia,fpga-device = <&t4_fpga>; - - compatible = \"nvidia,tier4_isx021\"; - - reg = <0x1c>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <0>; - sensor_model =\"isx021\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode ISX021_MODE_1920X1280_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"1\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"1920\"; - active_h = \"1280\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"94500000\"; - serdes_pix_clk_hz = \"833333333\"; - - gain_factor = \"10\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"3\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"30000000\"; - max_framerate = \"30000000\"; - step_framerate = \"1\"; - default_framerate = \"30000000\"; - exposure_factor = \"1000000\"; - min_exp_time = \"24\"; /* us 1 line */ - max_exp_time = \"33333\"; - step_exp_time = \"1\"; - default_exp_time = \"33333\"; /* us */ - embedded_metadata_height = \"0\"; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - isx021_out1: endpoint { - vc-id = <1>; - port-index = <0>; - bus-width = <2>; - remote-endpoint = <&csi_in1>; - }; - }; - }; - - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"b\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <1>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_isx021_a_1b_i2c0 = ''' - - isx021_a@1b { - - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>, - // <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,gmsl-ser-device = <&ser_a>; - nvidia,gmsl-dser-device = <&dser>; - nvidia,fpga-device = <&t4_fpga>; - - compatible = \"nvidia,tier4_isx021\"; - - reg = <0x1b>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <0>; - sensor_model =\"isx021\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - mode0 {/*mode ISX021_MODE_1920X1280_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"1920\"; - active_h = \"1280\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"94500000\"; - serdes_pix_clk_hz = \"833333333\"; - - gain_factor = \"10\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"3\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"30000000\"; - max_framerate = \"30000000\"; - step_framerate = \"1\"; - default_framerate = \"30000000\"; - exposure_factor = \"1000000\"; - min_exp_time = \"24\"; /* us 1 line */ - max_exp_time = \"33333\"; - step_exp_time = \"1\"; - default_exp_time = \"33333\"; /* us */ - embedded_metadata_height = \"0\"; - }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - isx021_out0: endpoint { - vc-id = <0>; - port-index = <0>; - bus-width = <2>; - remote-endpoint = <&csi_in0>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; /* Port at which sensor is connected to its serializer device. */ - dst-csi-port = \"a\"; /* Destination CSI port on the Jetson side, connected at deserializer. */ - serdes-csi-link = \"a\"; /* GMSL link sensor/serializer connected */ - csi-mode = \"1x4\"; /* to sensor CSI mode. */ - st-vc = <0>; /* Sensor source default VC ID: 0 unless overridden by sensor. */ - vc-id = <0>; /* Destination VC ID, assigned to sensor stream by deserializer. */ - num-lanes = <2>; /* Number of CSI lanes used. */ - streams = \"ued-u1\",\"yuv8\"; /* Types of streams sensor is streaming. */ - }; - }; -''' - -str_fragment1 = ''' - - fragment@1 { - - target-path = \"/i2c@c240000/tca9546@70/i2c@1\"; - - __overlay__ { - - i2c-mux,deselect-on-exit; - #address-cells = <1>; - #size-cells = <0>; -''' - -str_ser_isp_i2c1 = ''' - - ser_prima: max9295_prim@62 { - compatible = "nvidia,tier4_max9295\"; - reg = <0x62>; - is-prim-ser; - }; - ser_c: max9295_a@42 { - compatible = \"nvidia,tier4_max9295\"; - reg = <0x42>; - nvidia,gmsl-dser-device = <&dsera>; - }; - ser_d: max9295_b@60 { - compatible = \"nvidia,tier4_max9295\"; - reg = <0x60>; - nvidia,gmsl-dser-device = <&dsera>; - }; - - isp_prima: gw5300_prim@6d { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6d>; - is-prim-isp; - }; - isp_c: gw5300_a@6e { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6e>; - }; - isp_d: gw5300_b@6f { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6f>; - }; -''' - -str_imx490_d_2c_i2c1 = ''' - - imx490_d@2c { - compatible = \"nvidia,tier4_imx490\"; - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - //clocks = <&bpmp_clks 36>, <&bpmp_clks 36>; - //clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,isp-device = <&isp_d>; // for C2 camera - nvidia,gmsl-ser-device = <&ser_d>; - nvidia,gmsl-dser-device = <&dsera>; - nvidia,fpga-device = <&t4_fpga>; - reg = <0x2c>; - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <1>; - sensor_model =\"imx490\"; - fsync-mode = \"false\"; - distortion-correction = \"false\"; - auto-exposure = \"true\"; - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode IMX490_MODE_2880X1860_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - active_w = \"2880\"; - active_h = \"1860\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"160704000\"; - serdes_pix_clk_hz = \"1200000000\"; - gain_factor = \"5\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"1\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"0\"; - max_framerate = \"40954095\"; - step_framerate = \"1\"; - default_framerate = \"0\"; - exposure_factor = \"1000000\"; - min_exp_time = \"0\"; /* us 1 line */ - max_exp_time = \"40954095\"; - step_exp_time = \"1\"; - default_exp_time = \"0\"; /* us */ - embedded_metadata_height = \"0\"; - }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - imx490_out3: endpoint { - vc-id = <1>; - port-index = <2>; - bus-width = <2>; - remote-endpoint = <&csi_in3>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"b\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <1>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_imx490_c_2b_i2c1 = ''' - - imx490_c@2b { - compatible = \"nvidia,tier4_imx490\"; - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks 36>, <&bpmp_clks 36>; - //clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,isp-device = <&isp_c>; // for C2 camera - nvidia,gmsl-ser-device = <&ser_c>; - nvidia,gmsl-dser-device = <&dsera>; - nvidia,fpga-device = <&t4_fpga>; - reg = <0x2b>; - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <1>; - sensor_model =\"imx490\"; - fsync-mode = \"false\"; - distortion-correction = \"false\"; - auto-exposure = \"true\"; - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode IMX490_MODE_2880X1860_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - active_w = \"2880\"; - active_h = \"1860\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"160704000\"; - serdes_pix_clk_hz = \"1200000000\"; - gain_factor = \"5\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"1\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"0\"; - max_framerate = \"40954095\"; - step_framerate = \"1\"; - default_framerate = \"0\"; - exposure_factor = \"1000000\"; - min_exp_time = \"0\"; /* us 1 line */ - max_exp_time = \"40954095\"; - step_exp_time = \"1\"; - default_exp_time = \"0\"; /* us */ - embedded_metadata_height = \"0\"; - }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - imx490_out2: endpoint { - vc-id = <0>; - port-index = <2>; - bus-width = <2>; - remote-endpoint = <&csi_in2>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; /* Port at which sensor is connected to its serializer device. */ - dst-csi-port = \"a\"; /* Destination CSI port on the Jetson side, connected at deserializer. */ - serdes-csi-link = \"a\"; /* GMSL link sensor/serializer connected */ - csi-mode = \"1x4\"; /* to sensor CSI mode. */ - st-vc = <0>; /* Sensor source default VC ID: 0 unless overridden by sensor. */ - vc-id = <0>; /* Destination VC ID, assigned to sensor stream by deserializer. */ - num-lanes = <2>; /* Number of CSI lanes used. */ - streams = \"ued-u1\",\"yuv8\"; /* Types of streams sensor is streaming. */ - }; - }; -''' - -str_isx021_d_1c_i2c1 = ''' - - isx021_d@1c { - - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>, - // <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>; - clock-names = "extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - - nvidia,gmsl-ser-device = <&ser_d>; - nvidia,gmsl-dser-device = <&dsera>; - nvidia,fpga-device = <&t4_fpga>; - - compatible = \"nvidia,tier4_isx021\"; - - reg = <0x1c>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <1>; - sensor_model =\"isx021\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode ISX021_MODE_1920X1280_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_c\"; - vc_id = \"1\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"1920\"; - active_h = \"1280\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"94500000\"; - serdes_pix_clk_hz = \"833333333\"; - - gain_factor = \"10\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"3\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"30000000\"; - max_framerate = \"30000000\"; - step_framerate = \"1\"; - default_framerate = \"30000000\"; - exposure_factor = \"1000000\"; - min_exp_time = \"24\"; /* us 1 line */ - max_exp_time = \"33333\"; - step_exp_time = \"1\"; - default_exp_time = \"33333\";/* us */ - embedded_metadata_height = \"0\"; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - isx021_out3: endpoint { - vc-id = <1>; - port-index = <2>; - bus-width = <2>; - remote-endpoint = <&csi_in3>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"b\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <1>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_isx021_c_1b_i2c1 = ''' - - isx021_c@1b { - - def-addr = <0x1a>; - - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>, - // <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - - nvidia,gmsl-ser-device = <&ser_c>; - nvidia,gmsl-dser-device = <&dsera>; - nvidia,fpga-device = <&t4_fpga>; - - compatible = \"nvidia,tier4_isx021\"; - - reg = <0x1b>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <1>; - sensor_model =\"isx021\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode ISX021_MODE_1920X1280_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_c\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"1920\"; - active_h = \"1280\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"94500000\"; - serdes_pix_clk_hz = \"833333333\"; - - gain_factor = \"10\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"3\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"30000000\"; - max_framerate = \"30000000\"; - step_framerate = \"1\"; - default_framerate = \"30000000\"; - exposure_factor = \"1000000\"; - min_exp_time = \"24\"; /* us 1 line */ - max_exp_time = \"33333\"; - step_exp_time = \"1\"; - default_exp_time = \"33333\";/* us */ - embedded_metadata_height = \"0\"; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - isx021_out2: endpoint { - vc-id = <0>; - port-index = <2>; - bus-width = <2>; - remote-endpoint = <&csi_in2>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; /* Port at which sensor is connected to its serializer device. */ - dst-csi-port = \"a\"; /* Destination CSI port on the Jetson side, connected at deserializer. */ - serdes-csi-link = \"a\"; /* GMSL link sensor/serializer connected */ - csi-mode = \"1x4\"; /* to sensor CSI mode. */ - st-vc = <0>; /* Sensor source default VC ID: 0 unless overridden by sensor. */ - vc-id = <0>; /* Destination VC ID, assigned to sensor stream by deserializer. */ - num-lanes = <2>; /* Number of CSI lanes used. */ - streams = \"ued-u1\",\"yuv8\"; /* Types of streams sensor is streaming. */ - }; - }; -''' - -str_fragment2 = ''' - - fragment@2 { - - target-path = \"/i2c@c240000/tca9546@70/i2c@2\"; - - __overlay__ { - - i2c-mux,deselect-on-exit; - #address-cells = <1>; - #size-cells = <0>; -''' - -str_ser_isp_i2c2 = ''' - - ser_primb: max9295_prim@62 { - compatible = "nvidia,tier4_max9295\"; - reg = <0x62>; - is-prim-ser; - }; - ser_e: max9295_a@42 { - compatible = \"nvidia,tier4_max9295\"; - reg = <0x42>; - nvidia,gmsl-dser-device = <&dserb>; - }; - ser_f: max9295_b@60 { - compatible = \"nvidia,tier4_max9295\"; - reg = <0x60>; - nvidia,gmsl-dser-device = <&dserb>; - }; - - isp_primb: gw5300_prim@6d { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6d>; - is-prim-isp; - }; - isp_e: gw5300_a@6e { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6e>; - }; - isp_f: gw5300_b@6f { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6f>; - }; -''' - -str_imx490_f_2c_i2c2 = ''' - - imx490_f@2c { - compatible = \"nvidia,tier4_imx490\"; - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - //clocks = <&bpmp_clks 36 >, <&bpmp_clks 36 >; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,isp-device = <&isp_f>; // for C2 camera - nvidia,gmsl-ser-device = <&ser_f>; - nvidia,gmsl-dser-device = <&dserb>; - nvidia,fpga-device = <&t4_fpga>; - reg = <0x2c>; - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <2>; - sensor_model =\"imx490\"; - fsync-mode = \"false\"; - distortion-correction = \"false\"; - auto-exposure = \"true\"; - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode IMX490_MODE_2880X1860_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - active_w = \"2880\"; - active_h = \"1860\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"160704000\"; - serdes_pix_clk_hz = \"1200000000\"; - gain_factor = \"5\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"1\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"0\"; - max_framerate = \"40954095\"; - step_framerate = \"1\"; - default_framerate = \"0\"; - exposure_factor = \"1000000\"; - min_exp_time = \"0\"; /* us 1 line */ - max_exp_time = \"40954095\"; - step_exp_time = \"1\"; - default_exp_time = \"0\"; /* us */ - embedded_metadata_height = \"0\"; - }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - imx490_out5: endpoint { - vc-id = <1>; - port-index = <4>; - bus-width = <2>; - remote-endpoint = <&csi_in5>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"b\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <1>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_imx490_e_2b_i2c2 = ''' - - imx490_e@2b { - compatible = \"nvidia,tier4_imx490\"; - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks 36>, <&bpmp_clks 36>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,isp-device = <&isp_e>; // for C2 camera - nvidia,gmsl-ser-device = <&ser_e>; - nvidia,gmsl-dser-device = <&dserb>; - nvidia,fpga-device = <&t4_fpga>; - reg = <0x2b>; - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <2>; - sensor_model =\"imx490\"; - fsync-mode = \"false\"; - distortion-correction = \"false\"; - auto-exposure = \"true\"; - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode IMX490_MODE_2880X1860_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - active_w = \"2880\"; - active_h = \"1860\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"160704000\"; - serdes_pix_clk_hz = \"1200000000\"; - gain_factor = \"5\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"1\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"0\"; - max_framerate = \"40954095\"; - step_framerate = \"1\"; - default_framerate = \"0\"; - exposure_factor = \"1000000\"; - min_exp_time = \"0\"; /* us 1 line */ - max_exp_time = \"40954095\"; - step_exp_time = \"1\"; - default_exp_time = \"0\"; /* us */ - embedded_metadata_height = \"0\"; - }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - imx490_out4: endpoint { - vc-id = <0>; - port-index = <4>; - bus-width = <2>; - remote-endpoint = <&csi_in4>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"a\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <0>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_isx021_f_1c_i2c2 = ''' - - isx021_f@1c { - - def-addr = <0x1a>; - - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>, - // <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>; - clock-names = "extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - - nvidia,gmsl-ser-device = <&ser_f>; - nvidia,gmsl-dser-device = <&dserb>; - nvidia,fpga-device = <&t4_fpga>; - - compatible = \"nvidia,tier4_isx021\"; - - reg = <0x1c>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <2>; - sensor_model =\"isx021\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - - mode0 {/*mode ISX021_MODE_1920X1280_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_e\"; - vc_id = \"1\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"1920\"; - active_h = \"1280\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"94500000\"; - serdes_pix_clk_hz = \"833333333\"; - - gain_factor = \"10\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"3\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"30000000\"; - max_framerate = \"30000000\"; - step_framerate = \"1\"; - default_framerate = \"30000000\"; - exposure_factor = \"1000000\"; - min_exp_time = \"24\"; /* us 1 line */ - max_exp_time = \"33333\"; - step_exp_time = \"1\"; - default_exp_time = \"33333\";/* us */ - embedded_metadata_height = \"0\"; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - isx021_out5: endpoint { - vc-id = <1>; - port-index = <4>; - bus-width = <2>; - remote-endpoint = <&csi_in5>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"b\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <1>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_isx021_e_1b_i2c2 = ''' - - isx021_e@1b { - - def-addr = <0x1a>; - - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>, - // <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - - nvidia,gmsl-ser-device = <&ser_e>; - nvidia,gmsl-dser-device = <&dserb>; - nvidia,fpga-device = <&t4_fpga>; - - compatible = \"nvidia,tier4_isx021\"; - - reg = <0x1b>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <2>; - sensor_model =\"isx021\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - - mode0 {/*mode ISX021_MODE_1920X1280_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_e\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"1920\"; - active_h = \"1280\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"94500000\"; - serdes_pix_clk_hz = \"833333333\"; - - gain_factor = \"10\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"3\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"30000000\"; - max_framerate = \"30000000\"; - step_framerate = \"1\"; - default_framerate = \"30000000\"; - exposure_factor = \"1000000\"; - min_exp_time = \"24\"; /* us 1 line */ - max_exp_time = \"33333\"; - step_exp_time = \"1\"; - default_exp_time = \"33333\";/* us */ - embedded_metadata_height = \"0\"; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - isx021_out4: endpoint { - vc-id = <0>; - port-index = <4>; - bus-width = <2>; - remote-endpoint = <&csi_in4>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"a\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <0>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_fragment3 = ''' - - fragment@3 { - target-path = \"/i2c@c240000/tca9546@70/i2c@3\"; - __overlay__ { - i2c-mux,deselect-on-exit; - #address-cells = <1>; - #size-cells = <0>; -''' - -str_ser_isp_i2c3 = ''' - - ser_primc: max9295_prim@62 { - compatible = "nvidia,tier4_max9295\"; - reg = <0x62>; - is-prim-ser; - }; - ser_g: max9295_a@42 { - compatible = \"nvidia,tier4_max9295\"; - reg = <0x42>; - nvidia,gmsl-dser-device = <&dserc>; - }; - ser_h: max9295_b@60 { - compatible = \"nvidia,tier4_max9295\"; - reg = <0x60>; - nvidia,gmsl-dser-device = <&dserc>; - }; - isp_primc: gw5300_prim@6d { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6d>; - is-prim-isp; - }; - isp_g: gw5300_a@6e { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6e>; - }; - isp_h: gw5300_b@6f { - compatible = \"nvidia,tier4_gw5300\"; - reg = <0x6f>; - }; -''' - -str_imx490_h_2c_i2c3 = ''' - - imx490_h@2c { - compatible = \"nvidia,tier4_imx490\"; - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - //clocks = <&bpmp_clks 36>, <&bpmp_clks 36>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,isp-device = <&isp_h>; // for C2 camera - nvidia,gmsl-ser-device = <&ser_h>; - nvidia,gmsl-dser-device = <&dserc>; - nvidia,fpga-device = <&t4_fpga>; - reg = <0x2c>; - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <3>; - sensor_model =\"imx490\"; - fsync-mode = \"false\"; - distortion-correction = \"false\"; - auto-exposure = \"true\"; - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode IMX490_MODE_2880X1860_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - active_w = \"2880\"; - active_h = \"1860\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"160704000\"; - serdes_pix_clk_hz = \"1200000000\"; - gain_factor = \"5\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"1\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"0\"; - max_framerate = \"40954095\"; - step_framerate = \"1\"; - default_framerate = \"0\"; - exposure_factor = \"1000000\"; - min_exp_time = \"0\"; /* us 1 line */ - max_exp_time = \"40954095\"; - step_exp_time = \"1\"; - default_exp_time = \"0\"; /* us */ - embedded_metadata_height = \"0\"; - }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - imx490_out7: endpoint { - vc-id = <1>; - port-index = <5>; - bus-width = <2>; - remote-endpoint = <&csi_in7>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"b\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <1>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_imx490_g_2b_i2c3 = ''' - - imx490_g@2b { - compatible = \"nvidia,tier4_imx490\"; - def-addr = <0x1a>; - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks 36>, <&bpmp_clks 36>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - nvidia,isp-device = <&isp_g>; // for C2 camera - nvidia,gmsl-ser-device = <&ser_g>; - nvidia,gmsl-dser-device = <&dserc>; - nvidia,fpga-device = <&t4_fpga>; - reg = <0x2b>; - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <3>; - sensor_model =\"imx490\"; - fsync-mode = \"false\"; - distortion-correction = \"false\"; - auto-exposure = \"true\"; - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - mode0 {/*mode IMX490_MODE_2880X1860_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_a\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - active_w = \"2880\"; - active_h = \"1860\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"160704000\"; - serdes_pix_clk_hz = \"1200000000\"; - gain_factor = \"5\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"1\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"0\"; - max_framerate = \"40954095\"; - step_framerate = \"1\"; - default_framerate = \"0\"; - exposure_factor = \"1000000\"; - min_exp_time = \"0\"; /* us 1 line */ - max_exp_time = \"40954095\"; - step_exp_time = \"1\"; - default_exp_time = \"0\"; /* us */ - embedded_metadata_height = \"0\"; - }; - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - imx490_out6: endpoint { - vc-id = <0>; - port-index = <5>; - bus-width = <2>; - remote-endpoint = <&csi_in6>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"a\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <0>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_isx021_h_1c_i2c3 = ''' - - isx021_h@1c { - - def-addr = <0x1a>; - - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>, - // <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - - nvidia,gmsl-ser-device = <&ser_h>; - nvidia,gmsl-dser-device = <&dserc>; - nvidia,fpga-device = <&t4_fpga>; - - compatible = \"nvidia,tier4_isx021\"; - - reg = <0x1c>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <3>; - sensor_model =\"isx021\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - - mode0 {/*mode ISX021_MODE_1920X1280_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_g\"; - vc_id = \"1\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"1920\"; - active_h = \"1280\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"94500000\"; - serdes_pix_clk_hz = \"833333333\"; - - gain_factor = \"10\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"3\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"30000000\"; - max_framerate = \"30000000\"; - step_framerate = \"1\"; - default_framerate = \"30000000\"; - exposure_factor = \"1000000\"; - min_exp_time = \"24\"; /*us 1 line */ - max_exp_time = \"33333\"; - step_exp_time = \"1\"; - default_exp_time = \"33333\";/* us */ - embedded_metadata_height = \"0\"; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - isx021_out7: endpoint { - vc-id = <1>; - port-index = <5>; - bus-width = <2>; - remote-endpoint = <&csi_in7>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"b\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <1>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_isx021_g_1b_i2c3 = ''' - - isx021_g@1b { - - def-addr = <0x1a>; - - /* Define any required hw resources needed by driver */ - /* ie. clocks, io pins, power sources */ - // clocks = <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>, - // <&bpmp_clks TEGRA194_CLK_EXTPERIPH1>; - clock-names = \"extperiph1\", \"pllp_grtba\"; - mclk = \"extperiph1\"; - - nvidia,gmsl-ser-device = <&ser_g>; - nvidia,gmsl-dser-device = <&dserc>; - nvidia,fpga-device = <&t4_fpga>; - - compatible = \"nvidia,tier4_isx021\"; - - reg = <0x1b>; - - /* Physical dimensions of sensor */ - physical_w = \"15.0\"; - physical_h = \"12.5\"; - reg_mux = <3>; - sensor_model =\"isx021\"; - - fsync-mode = \"false\"; - - distortion-correction = \"false\"; - - auto-exposure = \"true\"; - - /* Defines number of frames to be dropped by driver internally after applying */ - /* sensor crop settings. Some sensors send corrupt frames after applying */ - /* crop co-ordinates */ - post_crop_frame_drop = \"0\"; - - /* Convert Gain to unit of dB (decibel) befor passing to kernel driver */ - use_decibel_gain = \"true\"; - - /* enable CID_SENSOR_MODE_ID for sensor modes selection */ - use_sensor_mode_id = \"true\"; - - /** - * A modeX node is required to support v4l2 driver - * implementation with NVIDIA camera software stack - * - * mclk_khz = \"\"; - * Standard MIPI driving clock, typically 24MHz - * - * num_lanes = \"\"; - * Number of lane channels sensor is programmed to output - * - * tegra_sinterface = \"\"; - * The base tegra serial interface lanes are connected to - * - * vc_id = \"\"; - * The virtual channel id of the sensor. - * - * discontinuous_clk = \"\"; - * The sensor is programmed to use a discontinuous clock on MIPI lanes - * - * dpcm_enable = \"true\"; - * The sensor is programmed to use a DPCM modes - * - * cil_settletime = \"\"; - * MIPI lane settle time value. - * A \"0\" value attempts to autocalibrate based on mclk_khz and pix_clk_hz - * - * active_w = \"\"; - * Pixel active region width - * - * active_h = \"\"; - * Pixel active region height - * - * dynamic_pixel_bit_depth = \"\"; - * sensor dynamic bit depth for sensor mode - * - * csi_pixel_bit_depth = \"\"; - * sensor output bit depth for sensor mode - * - * mode_type=\"\"; - * Sensor mode type, For eg: yuv, Rgb, bayer, bayer_wdr_pwl - * - * pixel_phase=\"\"; - * Pixel phase for sensor mode, For eg: rggb, vyuy, rgb888 - * - * readout_orientation = \"0\"; - * Based on camera module orientation. - * Only change readout_orientation if you specifically - * Program a different readout order for this mode - * - * line_length = \"\"; - * Pixel line length (width) for sensor mode. - * This is used to calibrate features in our camera stack. - * - * pix_clk_hz = \"\"; - * Sensor pixel clock used for calculations like exposure and framerate - * - * - * - * - * inherent_gain = \"\"; - * Gain obtained inherently from mode (ie. pixel binning) - * - * min_gain_val = \"\"; (floor to 6 decimal places) - * max_gain_val = \"\"; (floor to 6 decimal places) - * Gain limits for mode - * if use_decibel_gain = \"true\", please set the gain as decibel - * - * min_exp_time = \"\"; (ceil to integer) - * max_exp_time = \"\"; (ceil to integer) - * Exposure Time limits for mode (us) - * - * - * min_hdr_ratio = \"\"; - * max_hdr_ratio = \"\"; - * HDR Ratio limits for mode - * - * min_framerate = \"\"; - * max_framerate = \"\"; - * Framerate limits for mode (fps) - * - * embedded_metadata_height = \"\"; - * Sensor embedded metadata height in units of rows. - * If sensor does not support embedded metadata value should be 0. - */ - - mode0 {/*mode ISX021_MODE_1920X1280_CROP_30FPS*/ - mclk_khz = \"24000\"; - num_lanes = \"2\"; - tegra_sinterface = \"serial_g\"; - vc_id = \"0\"; - discontinuous_clk = \"no\"; - dpcm_enable = \"false\"; - cil_settletime = \"0\"; - dynamic_pixel_bit_depth = \"16\"; - csi_pixel_bit_depth = \"16\"; - mode_type = \"yuv\"; - pixel_phase = \"uyvy\"; - - active_w = \"1920\"; - active_h = \"1280\"; - readout_orientation = \"0\"; - line_length = \"2250\"; - inherent_gain = \"1\"; - pix_clk_hz = \"94500000\"; - serdes_pix_clk_hz = \"833333333\"; - - gain_factor = \"10\"; - min_gain_val = \"0\"; /* dB */ - max_gain_val = \"300\"; /* dB */ - step_gain_val = \"3\"; /* 0.3 */ - default_gain = \"0\"; - min_hdr_ratio = \"1\"; - max_hdr_ratio = \"1\"; - framerate_factor = \"1000000\"; - min_framerate = \"30000000\"; - max_framerate = \"30000000\"; - step_framerate = \"1\"; - default_framerate = \"30000000\"; - exposure_factor = \"1000000\"; - min_exp_time = \"24\"; /* us 1 line */ - max_exp_time = \"33333\"; - step_exp_time = \"1\"; - default_exp_time = \"33333\";/* us */ - embedded_metadata_height = \"0\"; - }; - - ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - isx021_out6: endpoint { - vc-id = <0>; - port-index = <5>; - bus-width = <2>; - remote-endpoint = <&csi_in6>; - }; - }; - }; - gmsl-link { - src-csi-port = \"b\"; - dst-csi-port = \"a\"; - serdes-csi-link = \"a\"; - csi-mode = \"1x4\"; - st-vc = <0>; - vc-id = <0>; - num-lanes = <2>; - streams = \"ued-u1\",\"yuv8\"; - }; - }; -''' - -str_fragment_vi_0 = ''' - - fragment@4 { - target = <&vi_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@5 { - target = <&vi_in0>; - __overlay__ { - status = \"okay\"; - vc-id = <0>; - port-index = <0>; - bus-width = <2>; - remote-endpoint = <&csi_out0>; - }; - }; -''' - -str_fragment_vi_1 = ''' - - fragment@6 { - target = <&vi_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@7 { - target = <&vi_in1>; - __overlay__ { - status = \"okay\"; - vc-id = <1>; - port-index = <0>; - bus-width = <2>; - remote-endpoint = <&csi_out1>; - }; - }; -''' - -str_fragment_vi_2 = ''' - - fragment@8 { - target = <&vi_port2>; - __overlay__ { - reg = <2>; - status = \"okay\"; - }; - }; - - fragment@9 { - target = <&vi_in2>; - __overlay__ { - status = \"okay\"; - vc-id = <0>; - port-index = <2>; - bus-width = <2>; - remote-endpoint = <&csi_out2>; - }; - }; -''' - -str_fragment_vi_3 = ''' - - fragment@10 { - target = <&vi_port3>; - __overlay__ { - reg = <3>; - status = \"okay\"; - }; - }; - - fragment@11 { - target = <&vi_in3>; - __overlay__ { - status = \"okay\"; - vc-id = <1>; - port-index = <2>; - bus-width = <2>; - remote-endpoint = <&csi_out3>; - }; - }; -''' - -str_fragment_vi_4 = ''' - - fragment@12 { - target = <&vi_port4>; - __overlay__ { - reg = <4>; - status = \"okay\"; - }; - }; - - fragment@13 { - target = <&vi_in4>; - __overlay__ { - status = \"okay\"; - vc-id = <0>; - port-index = <4>; - bus-width = <2>; - remote-endpoint = <&csi_out4>; - }; - }; -''' - -str_fragment_vi_5 = ''' - - fragment@14 { - target = <&vi_port5>; - __overlay__ { - reg = <5>; - status = \"okay\"; - }; - }; - - fragment@15 { - target = <&vi_in5>; - __overlay__ { - status = \"okay\"; - vc-id = <1>; - port-index = <4>; - bus-width = <2>; - remote-endpoint = <&csi_out5>; - }; - }; -''' - -str_fragment_vi_6 = ''' - - fragment@16 { - target = <&vi_port6>; - __overlay__ { - reg = <6>; - status = \"okay\"; - }; - }; - - fragment@17 { - target = <&vi_in6>; - __overlay__ { - status = \"okay\"; - vc-id = <0>; - port-index = <5>; - bus-width = <2>; - remote-endpoint = <&csi_out6>; - }; - }; -''' - -str_fragment_vi_7 = ''' - - fragment@18 { - target = <&vi_port7>; - __overlay__ { - reg = <7>; - status = \"okay\"; - }; - }; - - fragment@19 { - target = <&vi_in7>; - __overlay__ { - status = \"okay\"; - vc-id = <1>; - port-index = <5>; - bus-width = <2>; - remote-endpoint = <&csi_out7>; - }; - }; -''' - -str_fragment_nvcsi_ch0 = ''' - - /* channel 0 */ - fragment@20 { - target = <&csi_chan0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@21 { - target = <&csi_chan0_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@22 { - target = <&csi_chan0_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@23 { - target = <&csi_in0>; - __overlay__ { - status = \"okay\"; - port-index = <0>; - bus-width = <2>; - remote-endpoint = <&imx490_out0>; - }; - }; - - fragment@24 { - target = <&csi_out0>; - __overlay__ { - status = \"okay\"; - remote-endpoint = <&vi_in0>; - }; - }; -''' - -str_fragment_nvcsi_ch1 = ''' - - /* channel 1 */ - fragment@25 { - target = <&csi_chan1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@26 { - target = <&csi_chan1_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@27 { - target = <&csi_chan1_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@28 { - target = <&csi_in1>; - __overlay__ { - status = \"okay\"; - port-index = <0>; - bus-width = <2>; - remote-endpoint = <&imx490_out1>; - }; - }; - - fragment@29 { - target = <&csi_out1>; - __overlay__ { - status = \"okay\"; - remote-endpoint = <&vi_in1>; - }; - }; -''' - -str_fragment_nvcsi_ch2 = ''' - - /* channel 2 */ - fragment@30 { - target = <&csi_chan2>; - __overlay__ { - reg = <2>; - status = \"okay\"; - }; - }; - - fragment@31 { - target = <&csi_chan2_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@32 { - target = <&csi_chan2_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@33 { - target = <&csi_in2>; - __overlay__ { - status = \"okay\"; - port-index = <2>; - bus-width = <2>; - remote-endpoint = <&imx490_out2>; - }; - }; - - fragment@34 { - target = <&csi_out2>; - __overlay__ { - status = \"okay\"; - remote-endpoint = <&vi_in2>; - }; - }; -''' - -str_fragment_nvcsi_ch3 = ''' - - /* channel 3 */ - fragment@35 { - target = <&csi_chan3>; - __overlay__ { - reg = <3>; - status = \"okay\"; - }; - }; - - fragment@36 { - target = <&csi_chan3_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@37 { - target = <&csi_chan3_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@38 { - target = <&csi_in3>; - __overlay__ { - status = \"okay\"; - port-index = <2>; - bus-width = <2>; - remote-endpoint = <&imx490_out3>; - }; - }; - - fragment@39 { - target = <&csi_out3>; - __overlay__ { - status = \"okay\"; - remote-endpoint = <&vi_in3>; - }; - }; -''' - -str_fragment_nvcsi_ch4 = ''' - - /* channel 4 */ - fragment@40 { - target = <&csi_chan4>; - __overlay__ { - reg = <4>; - status = \"okay\"; - }; - }; - - fragment@41 { - target = <&csi_chan4_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@42 { - target = <&csi_chan4_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@43 { - target = <&csi_in4>; - __overlay__ { - status = \"okay\"; - port-index = <4>; - bus-width = <2>; - remote-endpoint = <&imx490_out4>; - }; - }; - - fragment@44 { - target = <&csi_out4>; - __overlay__ { - status = \"okay\"; - remote-endpoint = <&vi_in4>; - }; - }; -''' - -str_fragment_nvcsi_ch5 = ''' - - /* channel 5 */ - fragment@45 { - target = <&csi_chan5>; - __overlay__ { - reg = <5>; - status = \"okay\"; - }; - }; - - fragment@46 { - target = <&csi_chan5_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@47 { - target = <&csi_chan5_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@48 { - target = <&csi_in5>; - __overlay__ { - status = \"okay\"; - port-index = <4>; - bus-width = <2>; - remote-endpoint = <&imx490_out5>; - }; - }; - - fragment@49 { - target = <&csi_out5>; - __overlay__ { - status = \"okay\"; - remote-endpoint = <&vi_in5>; - }; - }; -''' - -str_fragment_nvcsi_ch6 = ''' - - /* channel 6 */ - fragment@50 { - target = <&csi_chan6>; - __overlay__ { - reg = <6>; - status = \"okay\"; - }; - }; - - fragment@51 { - target = <&csi_chan6_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@52 { - target = <&csi_chan6_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@53 { - target = <&csi_in6>; - __overlay__ { - status = \"okay\"; - port-index = <6>; - bus-width = <2>; - remote-endpoint = <&imx490_out6>; - }; - }; - - fragment@54 { - target = <&csi_out6>; - __overlay__ { - status = \"okay\"; - remote-endpoint = <&vi_in6>; - }; - }; -''' - -str_fragment_nvcsi_ch7 = ''' - - /* channel 7 */ - fragment@55 { - target = <&csi_chan7>; - __overlay__ { - reg = <7>; - status = \"okay\"; - }; - }; - - fragment@56 { - target = <&csi_chan7_port0>; - __overlay__ { - reg = <0>; - status = \"okay\"; - }; - }; - - fragment@57 { - target = <&csi_chan7_port1>; - __overlay__ { - reg = <1>; - status = \"okay\"; - }; - }; - - fragment@58 { - target = <&csi_in7>; - __overlay__ { - status = \"okay\"; - port-index = <6>; - bus-width = <2>; - remote-endpoint = <&imx490_out7>; - }; - }; - - fragment@59 { - target = <&csi_out7>; - __overlay__ { - status = \"okay\"; - remote-endpoint = <&vi_in7>; - }; - }; -''' - -str_imx490_cameramodule0 = ''' - - /* camera 0 */ - fragment@60 { - target = <&camera_module0>; - __overlay__ { - status = \"okay\"; - badge = \"imx490_rear_liimx490\"; - position = \"rear\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"imx490 30-002b\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@0/imx490_a@2b\"; - }; - }; - }; -''' - -str_imx490_cameramodule1 = ''' - - fragment@61 { - target = <&camera_module1>; - __overlay__ { - status = \"okay\"; - badge = \"imx490_front_liimx490\"; - position = \"front\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"imx490 30-002c\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@0/imx490_b@2c\"; - }; - }; - }; -''' - -str_imx490_cameramodule2 = ''' - - fragment@62 { - target = <&camera_module2>; - __overlay__ { - status = \"okay\"; - badge = \"imx490_topright_liimx490\"; - position = \"topright\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"imx490 31-002b\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@1/imx490_c@2b\"; - }; - }; - }; -''' - -str_imx490_cameramodule3 = ''' - - fragment@63 { - target = <&camera_module3>; - __overlay__ { - status = \"okay\"; - badge = \"imx490_bottomright_liimx490\"; - position = \"bottomright\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"imx490 31-002c\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@1/imx490_d@2c\"; - }; - }; - }; -''' - -str_imx490_cameramodule4 = ''' - - fragment@64 { - target = <&camera_module4>; - __overlay__ { - status = \"okay\"; - badge = \"imx490_topleft_liimx490\"; - position = \"topleft\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"imx490 32-002b\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@2/imx490_e@2b\"; - }; - }; - }; -''' - -str_imx490_cameramodule5 = ''' - - fragment@65 { - target = <&camera_module5>; - __overlay__ { - status = \"okay\"; - badge = \"imx490_centerright_liimx490\"; - position = \"centerright\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"imx490 32-002c\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@2/imx490_f@2c\"; - }; - }; - }; -''' - -str_imx490_cameramodule6 = ''' - - fragment@66 { - target = <&camera_module6>; - __overlay__ { - status = \"okay\"; - badge = \"imx490_centerleft_liimx490\"; - position = \"centerleft\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"imx490 33-002b\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@3/imx490_g@2b\"; - }; - }; - }; -''' - -str_imx490_cameramodule7 = ''' - - fragment@67 { - target = <&camera_module7>; - __overlay__ { - status = \"okay\"; - badge = \"imx490_bottomleft_liimx490\"; - position = \"bottomleft\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"imx490 33-002c\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@3/imx490_h@2c\"; - }; - }; - }; -''' - -str_isx021_cameramodule0 = ''' - - /* camera 0 */ - fragment@60 { - target = <&camera_module0>; - __overlay__ { - status = \"okay\"; - badge = \"isx021_rear_liisx021\"; - position = \"rear\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"isx021 30-001b\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@0/isx021_a@1b\"; - }; - }; - }; -''' - -str_isx021_cameramodule1 = ''' - - fragment@61 { - target = <&camera_module1>; - __overlay__ { - status = \"okay\"; - badge = \"isx021_front_liisx021\"; - position = \"front\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"isx021 30-001c\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@0/isx021_b@1c\"; - }; - }; - }; -''' - -str_isx021_cameramodule2 = ''' - - fragment@62 { - target = <&camera_module2>; - __overlay__ { - status = \"okay\"; - badge = \"isx021_topright_liisx021\"; - position = \"topright\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"isx021 31-001b\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@1/isx021_c@1b\"; - }; - }; - }; -''' - -str_isx021_cameramodule3 = ''' - - fragment@63 { - target = <&camera_module3>; - __overlay__ { - status = \"okay\"; - badge = \"isx021_bottomright_liisx021\"; - position = \"bottomright\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"isx021 31-001c\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@1/isx021_d@1c\"; - }; - }; - }; -''' - -str_isx021_cameramodule4 = ''' - - fragment@64 { - target = <&camera_module4>; - __overlay__ { - status = \"okay\"; - badge = \"isx021_topleft_liisx021\"; - position = \"topleft\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"isx021 32-001b\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@2/isx021_e@1b\"; - }; - }; - }; -''' - -str_isx021_cameramodule5 = ''' - - fragment@65 { - target = <&camera_module5>; - __overlay__ { - status = \"okay\"; - badge = \"isx021_centerright_liisx021\"; - position = \"centerright\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"isx021 32-001c\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@2/isx021_f@1c\"; - }; - }; - }; -''' - -str_isx021_cameramodule6 = ''' - - fragment@66 { - target = <&camera_module6>; - __overlay__ { - status = \"okay\"; - badge = \"isx021_centerleft_liisx021\"; - position = \"centerleft\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"isx021 33-001b\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@3/isx021_g@1b\"; - }; - }; - }; -''' - -str_isx021_cameramodule7 = ''' - - fragment@67 { - target = <&camera_module7>; - __overlay__ { - status = \"okay\"; - badge = \"isx021_bottomleft_liisx021\"; - position = \"bottomleft\"; - orientation = \"1\"; - drivernode0 { - status = \"okay\"; - pcl_id = \"v4l2_sensor\"; - devname = \"isx021 33-001c\"; - proc-device-tree = \"/proc/device-tree/i2c@c240000/tca9546@70/i2c@3/isx021_h@1c\"; - }; - }; - }; -''' - -str_dser_fragment = ''' - - fragment@68 { - target = <&dser>; - __overlay__ { - compatible = \"nvidia,tier4_max9296\"; - }; - }; - - fragment@69 { - target = <&dsera>; - __overlay__ { - compatible = \"nvidia,tier4_max9296\"; - }; - }; - - fragment@70 { - target = <&dserb>; - __overlay__ { - compatible = \"nvidia,tier4_max9296\"; - }; - }; - - fragment@71 { - target = <&dserc>; - __overlay__ { - compatible = \"nvidia,tier4_max9296\"; - }; - }; - - fragment@72 { - target-path = \"/host1x/vi@15c10000\"; - __overlay__ { - num-channels = <8>; - }; - }; - - fragment@73{ - target-path = "/i2c@3180000"; - __overlay__ { - t4_fpga: tier4_fpga@66 { - compatible = "nvidia,tier4_fpga"; - reg = <0x66>; - generate-fsync = "false"; - status = "okay"; - }; - }; - }; -''' - -str_block_end = ''' - }; - }; -''' - -str_overlay_end = ''' - -}; -''' - -def idenify_camera(cmd_arg): - upper_arg = cmd_arg.upper() - if upper_arg == 'C1' : - return 'C1' - elif upper_arg == 'C2' : - return 'C2' - else : - return 'NC' - -def get_type_of_cameras(l_camera): - - l_camera_type = [None] * 4 - - for i in range(0,4): - k = 2*i - if l_camera[k] == 'C1' or l_camera[k+1] == 'C1' : - l_camera_type[i] = 'c1' - elif l_camera[k] == 'C2' or l_camera[k+1] == 'C2' : - l_camera_type[i] = 'c2' - elif l_camera[k] == 'NC' and l_camera[k+1] == 'NC' : - l_camera_type[i] = 'nc' - - return l_camera_type - -def build_symlink_c1c2(dev_num, v_num, camera_type): - - video_num = v_num + 1 - - str_subsys = 'SUBSYSTEM==\"video4linux\", ATTR{name}==\"vi-output, ' - str_symlink = 'SYMLINK+= \"gmsl/tier4-isx021-imx490-cam' + str(video_num) + '\"\n' - - if camera_type == 'C1' : - - driver_name = [ 'tier4_isx021 30-001b\", ', 'tier4_isx021 30-001c\", ', \ - 'tier4_isx021 31-001b\", ', 'tier4_isx021 31-001c\", ', \ - 'tier4_isx021 32-001b\", ', 'tier4_isx021 32-001c\", ', \ - 'tier4_isx021 33-001b\", ', 'tier4_isx021 33-001c\", ' \ - ] - - elif camera_type == 'C2' : - - driver_name = [ 'tier4_imx490 30-002b\", ', 'tier4_imx490 30-002c\", ', \ - 'tier4_imx490 31-002b\", ', 'tier4_imx490 31-002c\", ', \ - 'tier4_imx490 32-002b\", ', 'tier4_imx490 32-002c\", ', \ - 'tier4_imx490 33-002b\", ', 'tier4_imx490 33-002c\", ' \ - ] - - str_symlink_dev = str_subsys + driver_name[v_num] + str_symlink - - return str_symlink_dev - -def get_des_number( port_num ): # port_num is 0 to 7 - - even_port = port_num & 0x6 - - if even_port == 0 : - rc = 12 # port 1,2 - elif even_port == 2 : - rc = 34 # port 3,4 - elif even_port == 4 : - rc = 56 # port 5,6 - elif even_port == 6 : - rc = 78 # port 7,8 - return rc - -def usage(): - print('************************************************************************') - print('** **') - print('** This is the tool to generate overlay dts and udev file. **') - print('** **') - print('************************************************************************') - print('** **') - print('** Usage : **') - print('** **') - print('** $> python3 make_overaly_dtb2.py camera1 camera2 ... camera8 **') - print('** **') - print('** camera1 : camera connected to port1 **') - print('** camera2 : camera connected to port2 **') - print('** camera3 : camera connected to port3 **') - print('** . **') - print('** . **') - print('** camera8 : camera connected to port8 **') - print('** **') - print('** The camerN shoud be c1, c2 or nc(not connected) **') - print('** **') - print('** Overlay dts will be output to **') - print('** \"tier4-isx021-imx490-xx-yy-zz-uu-overlay-device-tree.dts\" **') - print('** **') - print('** udev file will be generated as **') - print('** \"99-tier4-isx021-imx490-gmsl.rules\" **') - print('** **') - print('************************************************************************') - -def check_last_port(num, camera): - - if num & 0x1 : - if camera[num] == 'C1' : - if camera[num-1] == 'C1' or camera[num-1] == 'NC': - return 0 - else: - return -1 - elif camera[num] == 'C2' : - if camera[num-1] == 'C2' or camera[num-1] == 'NC': - return 0 - else: - return -1 - elif camera[num] == 'NC' : - if camera[num-1] == 'C2' or camera[num-1] == 'NC' or camera[num-1] == 'C1': - return 0 - else: - return -1 - else: - return 0 - -def identify_camera(cmd_arg): - upper_arg = cmd_arg.upper() - if upper_arg == 'C1' : - return 'C1' - elif upper_arg == 'C2' : - return 'C2' - else : - return 'NC' - -# ---- main ---------- - -args = sys.argv - -#print( 'argv = ' + str(args) ) - -#print( 'arg len = ' + str(len(args))) - -total_num_args = len(args) - -found_camera = 0 - -camera = [ 'NC', 'NC', 'NC', 'NC',\ - 'NC', 'NC', 'NC', 'NC' ] - -temp_cam = [None]*8 - -if total_num_args != 9 : - - print(' ***** Error! : ' + args[0] + ' needs 8 arguments. *****\n') - usage() - sys.exit() - -with open( '99-tier4-isx021-imx490-gmsl.rules', 'w', encoding='utf-8') as udev_file: - for i in range(8): - temp_cam[i] = identify_camera(args[i+1]) - if temp_cam[i] == 'NC' : - camera[i] = 'C1' - else : - camera[i] = temp_cam[i] - err = check_last_port(i, camera) - if err == -1 : - if camera[i] == 'C1' : - print(' ***** Error! : port[' + str(i-1) + '] should be C1 or NC. *****\n') - elif camera[i] == 'C2' : - print(' ***** Error! : port[' + str(i-1) + '] should be C2 or NC. *****\n') - usage() - sys.exit() - else: - if camera[i] == 'C1' or camera[i] == 'C2' : - str_line_in_udev = build_symlink_c1c2( i, found_camera, camera[i] ) - udev_file.write(str_line_in_udev) - found_camera += 1 - - if i == 0 : - - if camera[i] == 'C1' : - str_camera1 = str_isx021_a_1b_i2c0 - str_fragment_vi0 = str_fragment_vi_0 - str_fragment_nvcsi0 = str_fragment_nvcsi_ch0.replace('imx490_out0', 'isx021_out0') - str_cameramodule0 = str_isx021_cameramodule0 - elif camera[i] == 'C2' : - str_camera1 = str_imx490_a_2b_i2c0 - str_fragment_vi0 = str_fragment_vi_0 - str_fragment_nvcsi0 = str_fragment_nvcsi_ch0 - str_cameramodule0 = str_imx490_cameramodule0 - else: - str_camera1 = '' - str_fragment_vi0 = '' - str_fragment_nvcsi0 = '' - str_cameramodule0 = '' - - elif i == 1 : - - if camera[i] == 'C1' : - str_camera2 = str_isx021_b_1c_i2c0 - str_fragment_vi1 = str_fragment_vi_1 - str_fragment_nvcsi1 = str_fragment_nvcsi_ch1.replace('imx490_out1', 'isx021_out1') - str_cameramodule1 = str_isx021_cameramodule1 - elif camera[i] == 'C2' : - str_camera2 = str_imx490_b_2c_i2c0 - str_fragment_vi1 = str_fragment_vi_1 - str_fragment_nvcsi1 = str_fragment_nvcsi_ch1 - str_cameramodule1 = str_imx490_cameramodule1 - else: - str_camera2 = '' - str_fragment_vi1 = '' - str_fragment_nvcsi1 = '' - str_cameramodule1 = '' - - elif i == 2 : - - if camera[i] == 'C1' : - str_camera3 = str_isx021_c_1b_i2c1 - str_fragment_vi2 = str_fragment_vi_2 - str_fragment_nvcsi2 = str_fragment_nvcsi_ch2.replace('imx490_out2', 'isx021_out2') - str_cameramodule2 = str_isx021_cameramodule2 - elif camera[i] == 'C2' : - str_camera3 = str_imx490_c_2b_i2c1 - str_fragment_vi2 = str_fragment_vi_2 - str_fragment_nvcsi2 = str_fragment_nvcsi_ch2 - str_cameramodule2 = str_imx490_cameramodule2 - else: - str_camera3 = '' - str_fragment_vi2 = '' - str_fragment_nvcsi2 = '' - str_cameramodule2 = '' - - - elif i == 3 : - - if camera[i] == 'C1' : - str_camera4 = str_isx021_d_1c_i2c1 - str_fragment_vi3 = str_fragment_vi_3 - str_fragment_nvcsi3 = str_fragment_nvcsi_ch3.replace('imx490_out3', 'isx021_out3') - str_cameramodule3 = str_isx021_cameramodule3 - elif camera[i] == 'C2' : - str_camera4 = str_imx490_d_2c_i2c1 - str_fragment_vi3 = str_fragment_vi_3 - str_fragment_nvcsi3 = str_fragment_nvcsi_ch3 - str_cameramodule3 = str_imx490_cameramodule3 - else: - str_camera4 = '' - str_fragment_vi3 = '' - str_fragment_nvcsi3 = '' - str_cameramodule3 = '' - - elif i == 4 : - - if camera[i] == 'C1' : - str_camera5 = str_isx021_e_1b_i2c2 - str_fragment_vi4 = str_fragment_vi_4 - str_fragment_nvcsi4 = str_fragment_nvcsi_ch4.replace('imx490_out4', 'isx021_out4') - str_cameramodule4 = str_isx021_cameramodule4 - elif camera[i] == 'C2' : - str_camera5 = str_imx490_e_2b_i2c2 - str_fragment_vi4 = str_fragment_vi_4 - str_fragment_nvcsi4 = str_fragment_nvcsi_ch4 - str_cameramodule4 = str_imx490_cameramodule4 - else: - str_camera5 = '' - str_fragment_vi4 = '' - str_fragment_nvcsi4 = '' - str_cameramodule4 = '' - - elif i == 5 : - - if camera[i] == 'C1' : - str_camera6 = str_isx021_f_1c_i2c2 - str_fragment_vi5 = str_fragment_vi_5 - str_fragment_nvcsi5 = str_fragment_nvcsi_ch5.replace('imx490_out5', 'isx021_out5') - str_cameramodule5 = str_isx021_cameramodule5 - elif camera[i] == 'C2' : - str_camera6 = str_imx490_f_2c_i2c2 - str_fragment_vi5 = str_fragment_vi_5 - str_fragment_nvcsi5 = str_fragment_nvcsi_ch5 - str_cameramodule5 = str_imx490_cameramodule5 - else: - str_camera6 = '' - str_fragment_vi5 = '' - str_fragment_nvcsi5 = '' - str_cameramodule5 = '' - - elif i == 6 : - - if camera[i] == 'C1' : - str_camera7 = str_isx021_g_1b_i2c3 - str_fragment_vi6 = str_fragment_vi_6 - str_fragment_nvcsi6 = str_fragment_nvcsi_ch6.replace('imx490_out6', 'isx021_out6') - str_cameramodule6 = str_isx021_cameramodule6 - elif camera[i] == 'C2' : - str_camera7 = str_imx490_g_2b_i2c3 - str_fragment_vi6 = str_fragment_vi_6 - str_fragment_nvcsi6 = str_fragment_nvcsi_ch6 - str_cameramodule6 = str_imx490_cameramodule6 - else: - str_camera7 = '' - str_fragment_vi6 = '' - str_fragment_nvcsi6 = '' - str_cameramodule6 = '' - - elif i == 7 : - - if camera[i] == 'C1' : - str_camera8 = str_isx021_h_1c_i2c3 - str_fragment_vi7 = str_fragment_vi_7 - str_fragment_nvcsi7 = str_fragment_nvcsi_ch7.replace('imx490_out7', 'isx021_out7') - str_cameramodule7 = str_isx021_cameramodule7 - elif camera[i] == 'C2' : - str_camera8 = str_imx490_h_2c_i2c3 - str_fragment_vi7 = str_fragment_vi_7 - str_fragment_nvcsi7 = str_fragment_nvcsi_ch7 - str_cameramodule7 = str_imx490_cameramodule7 - else: - str_camera8 = '' - str_fragment_vi7 = '' - str_fragment_nvcsi7 = '' - str_cameramodule7 = '' - -str_i2c0 = str_fragment0 + str_ser_isp_i2c0 + str_camera2 + str_camera1 + str_block_end - -str_i2c1 = str_fragment1 + str_ser_isp_i2c1 + str_camera4 + str_camera3 + str_block_end - -str_i2c2 = str_fragment2 + str_ser_isp_i2c2 + str_camera6 + str_camera5 + str_block_end - -str_i2c3 = str_fragment3 + str_ser_isp_i2c3 + str_camera8 + str_camera7 + str_block_end - -str_whole_i2c = str_i2c0 + str_i2c1 + str_i2c2 + str_i2c3 - -str_whole_dts = str_overlay_header \ - + str_i2c0 + str_i2c1 + str_i2c2 + str_i2c3 \ - + str_fragment_vi0 + str_fragment_vi1 + str_fragment_vi2 + str_fragment_vi3 \ - + str_fragment_vi4 + str_fragment_vi5 + str_fragment_vi6 + str_fragment_vi7 \ - + str_fragment_nvcsi0 + str_fragment_nvcsi1 + str_fragment_nvcsi2 + str_fragment_nvcsi3 \ - + str_fragment_nvcsi4 + str_fragment_nvcsi5 + str_fragment_nvcsi6 + str_fragment_nvcsi7 \ - + str_cameramodule0 + str_cameramodule1 + str_cameramodule2 + str_cameramodule3 \ - + str_cameramodule4 + str_cameramodule5 + str_cameramodule6 + str_cameramodule7 \ - + str_dser_fragment + str_overlay_end - -camera_type = get_type_of_cameras(temp_cam) -#camera_type = get_type_of_cameras(camera) - -overlay_dts_file_name = 'tier4-isx021-imx490-' + str(camera_type[0]) + '-' + str(camera_type[1]) + '-' \ - + str(camera_type[2]) + '-' + str(camera_type[3]) + '-gmsl-device-tree-overlay.dts' - -with open( overlay_dts_file_name, 'w', encoding='utf-8') as overlay_dts_file: - print(str_whole_dts, file=overlay_dts_file ) - diff --git a/pkg/create_deb_pkg.sh b/pkg/create_deb_pkg.sh new file mode 100755 index 0000000..e019271 --- /dev/null +++ b/pkg/create_deb_pkg.sh @@ -0,0 +1,2 @@ +#!/bin/sh +dpkg-buildpackage -b -rfakeroot -us -uc diff --git a/drivers/debian/README.Debian b/pkg/debian/README.Debian similarity index 100% rename from drivers/debian/README.Debian rename to pkg/debian/README.Debian diff --git a/drivers/debian/README.source b/pkg/debian/README.source similarity index 100% rename from drivers/debian/README.source rename to pkg/debian/README.source diff --git a/drivers/debian/changelog b/pkg/debian/changelog similarity index 100% rename from drivers/debian/changelog rename to pkg/debian/changelog diff --git a/drivers/debian/compat b/pkg/debian/compat similarity index 100% rename from drivers/debian/compat rename to pkg/debian/compat diff --git a/drivers/debian/control b/pkg/debian/control similarity index 58% rename from drivers/debian/control rename to pkg/debian/control index 0aa34d1..cdeaeda 100644 --- a/drivers/debian/control +++ b/pkg/debian/control @@ -1,13 +1,13 @@ Source: tier4-camera-gmsl Section: kernel Priority: optional -Maintainer: Yusuke Fujii +Maintainer: Ryo Munakata Build-Depends: debhelper (>=9), dkms Standards-Version: 3.9.6 -Homepage: +Homepage: Package: tier4-camera-gmsl Architecture: arm64 Provides: tier4-camera-gmsl Depends: ${misc:Depends} -Description: Tier4 ISX021 GMSL2 Camera Kernel Module. +Description: V4L2 camera drivers for TIER IV C1/C2/C3 cameras diff --git a/drivers/debian/copyright b/pkg/debian/copyright similarity index 100% rename from drivers/debian/copyright rename to pkg/debian/copyright diff --git a/drivers/debian/dkms b/pkg/debian/dkms similarity index 100% rename from drivers/debian/dkms rename to pkg/debian/dkms diff --git a/drivers/debian/etc/modprobe.d/tier4-imx490.conf b/pkg/debian/etc/modprobe.d/tier4-imx490.conf old mode 100644 new mode 100755 similarity index 88% rename from drivers/debian/etc/modprobe.d/tier4-imx490.conf rename to pkg/debian/etc/modprobe.d/tier4-imx490.conf index 4361487..ac60d93 --- a/drivers/debian/etc/modprobe.d/tier4-imx490.conf +++ b/pkg/debian/etc/modprobe.d/tier4-imx490.conf @@ -23,5 +23,8 @@ options tier4_imx490 trigger_mode=0 enable_auto_exposure=1 enable_distortion_cor # "generate_fsync=0" External pulse is not automatically genereated by FPGA(Default). # "generate_fsync=1" External pulse is automatically genereated by FPGA( not supported yet). # +# Please refer to the following page. +# https://adlink-ros.github.io/roscube-doc/roscube-x/gmsl_camera/frame_sync.html#tier-iv-c1-c2-frame-sync +# options tier4_fpga generate_fsync=0 diff --git a/pkg/debian/etc/modprobe.d/tier4-imx728.conf b/pkg/debian/etc/modprobe.d/tier4-imx728.conf new file mode 100755 index 0000000..089e0ed --- /dev/null +++ b/pkg/debian/etc/modprobe.d/tier4-imx728.conf @@ -0,0 +1,30 @@ +# Configurations: +# "trigger_mode=0" run cameras in master 20fps mode. (Default) +# "trigger_mode=1" run cameras in slave(External pulse sync) 10fps mode. (Not supported yet) +# "trigger_mode=2" run cameras in maste 20fps mode. +# "trigger_mode=3" run cameras in slave(External pulse sync) 20fps mode. (Not supported yet) +# "trigger_mode=4" run cameras in master 30fps mode. (Not supported) +# "trigger_mode=5" run cameras in slave(External pulse sync) 30fps mode. (Not supported) +# +# "trigger_mode=1,3 and 5" are valid for ADLINK RQX-58G and RQX-59G only. +# +# "enable_auto_exposure=0" disable auto-exposure feature. +# "enable_auto_exposure=1" enable auto-exposure feature. (Default) +# +# "enable_distortion_correction=0" disable distortion correction feature. +# "enable_distortion_correction=1" enable distortion correction feature.(Default) +# + +options tier4_imx728 trigger_mode=0 enable_auto_exposure=1 enable_distortion_correction=1 + +# +# The following parameter is valid for ADLINK RQX-58G and RQX-59G only. +# +# "generate_fsync=0" External pulse is not automatically genereated by FPGA(Default). +# "generate_fsync=1" External pulse is automatically genereated by FPGA( not supported yet). +# +# Please refer to the following page. +# https://adlink-ros.github.io/roscube-doc/roscube-x/gmsl_camera/frame_sync.html#tier-iv-c1-c2-frame-sync +# + +options tier4_fpga generate_fsync=0 diff --git a/pkg/debian/etc/modprobe.d/tier4-isx021.conf b/pkg/debian/etc/modprobe.d/tier4-isx021.conf new file mode 100755 index 0000000..2031410 --- /dev/null +++ b/pkg/debian/etc/modprobe.d/tier4-isx021.conf @@ -0,0 +1,26 @@ +# Configurations: +# "trigger_mode=0" run cameras in master mode. (Default) +# "trigger_mode=1" run cameras in slave(External pulse sync) mode, and valid for ADLINK RQX-58G/59G only. +# +# "enable_auto_exposure=0" disable auto-exposure feature. +# "enable_auto_exposure=1" enable auto-exposure feature. (Default) +# +# "enable_distortion_correction=0" disable distortion correction feature. +# "enable_distortion_correction=1" enable distortion correction feature. (Default) +# +options tier4_isx021 trigger_mode=0 enable_auto_exposure=1 enable_distortion_correction=1 + + +# Note: +# The following parameters are valid for RQX-58G and RQX-59G. +# +# "fsync_mode=0" disable FPGA Fsync mode. (Default) +# "fsync_mode=1" enable FPGA Fsync Auto Trigger mode. +# "fsync_mode=2" enable FPGA Fsync Manual Trigger mode. +# +# "fps_cam1_cam2=10" set 10fps for cam1&2 in Fsync Auto Trigger mode. (FPS 1~30) +# "fps_cam3_cam4=10" set 10fps for cam3&4 in Fsync Auto Trigger mode. (FPS 1~30) +# "fps_cam5_cam6=10" set 10fps for cam5&6 in Fsync Auto Trigger mode. (FPS 1~30) +# "fps_cam7_cam8=10" set 10fps for cam7&8 in Fsync Auto Trigger mode. (FPS 1~30) +# +options tier4_fpga fsync_mode=0 fps_cam1_cam2=10 fps_cam3_cam4=10 fps_cam5_cam6=10 fps_cam7_cam8=10 diff --git a/drivers/debian/etc/modules-load.d/tier4-imx490-gmsl.conf b/pkg/debian/etc/modules-load.d/tier4-imx490-gmsl.conf old mode 100644 new mode 100755 similarity index 100% rename from drivers/debian/etc/modules-load.d/tier4-imx490-gmsl.conf rename to pkg/debian/etc/modules-load.d/tier4-imx490-gmsl.conf diff --git a/pkg/debian/etc/modules-load.d/tier4-imx728-gmsl.conf b/pkg/debian/etc/modules-load.d/tier4-imx728-gmsl.conf new file mode 100755 index 0000000..19a6fa8 --- /dev/null +++ b/pkg/debian/etc/modules-load.d/tier4-imx728-gmsl.conf @@ -0,0 +1,7 @@ +tier4-max9295 +tier4-max9296 +tier4-fpga +tier4-gw5300 +tier4-isx021 +tier4-imx490 +tier4-imx728 diff --git a/drivers/debian/etc/modules-load.d/tier4-isx021-gmsl.conf b/pkg/debian/etc/modules-load.d/tier4-isx021-gmsl.conf old mode 100644 new mode 100755 similarity index 100% rename from drivers/debian/etc/modules-load.d/tier4-isx021-gmsl.conf rename to pkg/debian/etc/modules-load.d/tier4-isx021-gmsl.conf diff --git a/drivers/debian/install b/pkg/debian/install similarity index 100% rename from drivers/debian/install rename to pkg/debian/install diff --git a/drivers/debian/postinst b/pkg/debian/postinst similarity index 97% rename from drivers/debian/postinst rename to pkg/debian/postinst index c9cc723..c8b2139 100755 --- a/drivers/debian/postinst +++ b/pkg/debian/postinst @@ -25,6 +25,7 @@ dkms_configure () { case "$1" in configure) + udevadm control --reload dkms_configure ;; diff --git a/drivers/debian/prerm b/pkg/debian/prerm similarity index 70% rename from drivers/debian/prerm rename to pkg/debian/prerm index 3fc3a77..235c257 100755 --- a/drivers/debian/prerm +++ b/pkg/debian/prerm @@ -5,16 +5,6 @@ NAME=tier4-camera-gmsl VERSION=1.5.0 KERNEL_REL=$(uname -r) -ISX021_GMSL_DTBO=$(ls /boot/tier4-isx021-gmsl*) -ISX021_GMSL_DTBO_EXIST=$? - -IMX490_GMSL_DTBO=$(ls /boot/tier4-imx490-gmsl-*) -ISX490_GMSL_DTBO_EXIST=$? - -IMX728_GMSL_DTBO=$(ls /boot/tier4-imx728-gmsl-*) -IMX728_GMSL_DTBO_EXIST=$? - - set -e case "$1" in remove|upgrade|deconfigure) @@ -36,15 +26,9 @@ case "$1" in rm -f /etc/modprobe.d/tier4-imx490.conf rm -f /etc/modprobe.d/tier4-imx728.conf - if [ $ISX021_GMSL_DTBO_EXIST = 0 ]; then - rm -f $ISX021_GMSL_DTBO - fi - if [ $IMX490_GMSL_DTBO_EXIST = 0 ]; then - rm -f $IMX490_GMSL_DTBO - fi - if [ $IMX728_GMSL_DTBO_EXIST = 0 ]; then - rm -f $IMX728_GMSL_DTBO - fi + rm -f /boot/tier4-isx021-* + rm -f /boot/tier4-imx490-* + rm -f /boot/tier4-imx728-* fi ;; diff --git a/drivers/debian/rules b/pkg/debian/rules similarity index 64% rename from drivers/debian/rules rename to pkg/debian/rules index 6f75dce..b2517ec 100755 --- a/drivers/debian/rules +++ b/pkg/debian/rules @@ -7,6 +7,16 @@ dkms_version := $(shell cat dkms.conf | grep ^PACKAGE_VERSION= | cut -d '"' -f 2 dkms_src_dir := $(CURDIR)/debian/${package}/usr/src/tier4-camera-gmsl-$(dkms_version)/ kernel_src_dir ?= /lib/modules/$(kernel_release)/build +UDEV_FILE := ./debian/udev + +ROScube_Orin_word := 590 +ROScube_Orin_Model_word := ROScube-Orin + +dt_model := $(shell cat /proc/device-tree/model | tr -d "\0" ) + +ifeq ($(ROScube_Orin_word), $(findstring $(ROScube_Orin_word),$(dt_model))) + MODEL := $(ROScube_Orin_Model_word) +endif %: dh $@ --with dkms @@ -19,11 +29,18 @@ override_dh_auto_install: # dh_install debian/var ../${package} dh_install debian/usr ../${package} mkdir -p $(dkms_src_dir) - cp -rf $(CURDIR)/src/* $(dkms_src_dir) + cp -rf $(CURDIR)/../src/${package}/* $(dkms_src_dir) + cp -rf $(CURDIR)/../tools/dts_generator/* $(dkms_src_dir) override_dh_usrlocal: override_dh_installudev: + +ifeq ($(MODEL),$(ROScube_Orin_Model_word)) + sed -i -e 's/001b/001d/g' $(UDEV_FILE) + sed -i -e 's/001c/001e/g' $(UDEV_FILE) +endif + dh_installudev --priority 99 override_dh_dkms: diff --git a/drivers/debian/source/format b/pkg/debian/source/format similarity index 100% rename from drivers/debian/source/format rename to pkg/debian/source/format diff --git a/pkg/debian/udev b/pkg/debian/udev new file mode 100644 index 0000000..ea7950f --- /dev/null +++ b/pkg/debian/udev @@ -0,0 +1 @@ +ACTION=="add", SUBSYSTEM=="video4linux", KERNEL=="video*", ATTR{name}=="?*tier4?*", RUN+="/usr/bin/tier4-create-camera-symlink.sh $devnode" diff --git a/drivers/debian/usr/local/bin/run_tier4_isx021_single.sh b/pkg/debian/usr/bin/run_tier4_isx021_single.sh similarity index 100% rename from drivers/debian/usr/local/bin/run_tier4_isx021_single.sh rename to pkg/debian/usr/bin/run_tier4_isx021_single.sh diff --git a/pkg/debian/usr/bin/tier4-create-camera-symlink.sh b/pkg/debian/usr/bin/tier4-create-camera-symlink.sh new file mode 100755 index 0000000..690b160 --- /dev/null +++ b/pkg/debian/usr/bin/tier4-create-camera-symlink.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu + +[ $# -eq 1 ] || exit 1 +[ -e $1 ] || exit 1 + +CAMERA_PATH=$(v4l2-ctl --info -d $1 | grep "Card type" | grep -o "[0-9]\+-[0-9a-f]\+") +CAMERA_OF_NODE=$(cat $(find /sys/devices/ -name ${CAMERA_PATH})/of_node/name) +SENSOR=$(echo $CAMERA_OF_NODE | cut -d _ -f1) + +INDEX=$(printf '%d' "'$(echo ${CAMERA_OF_NODE} | cut -d _ -f2)") +INDEX_START=$(printf '%d' "'a") +NUM_INDEX=$(expr ${INDEX} - ${INDEX_START} + 1) + +GMSL_DIR="/dev/gmsl" +mkdir -p "${GMSL_DIR}" +ln -s $1 "${GMSL_DIR}/tier4-${SENSOR}-cam${NUM_INDEX}" diff --git a/drivers/dkms.conf b/pkg/dkms.conf similarity index 78% rename from drivers/dkms.conf rename to pkg/dkms.conf index 63f166b..766893c 100644 --- a/drivers/dkms.conf +++ b/pkg/dkms.conf @@ -1,9 +1,8 @@ PACKAGE_NAME="tier4-camera-gmsl" PACKAGE_VERSION="1.5.0" -PROCS_NUM=`nproc` -[ $PROCS_NUM -gt 16 ] && PROCS_NUM=16 -MAKE="make all -j$PROCS_NUM" -CLEAN="make clean" + +MAKE="make -f Makefile.dkms all KERNEL_SRC_DIR=/lib/modules/$kernelver/build/" +CLEAN="make -f Makefile.dkms clean KERNEL_SRC_DIR=/lib/modules/$kernelver/build/" BUILT_MODULE_NAME[0]="tier4-isx021" DEST_MODULE_LOCATION[0]="/updates" diff --git a/scripts/c1/reset/READE b/scripts/c1/reset/READE new file mode 100644 index 0000000..3f19f3c --- /dev/null +++ b/scripts/c1/reset/READE @@ -0,0 +1,37 @@ +- reset_single.sh : port 1 の Deser(max9296),Ser(max9295), Camera SensorISX021をリセットする。 + +使い方: sudo ./reset_single.sh + +他のportのDeser,Ser,Camera Sensorをリセットしたい場合は、reset_single.shに以下の変更が必要である。 + +port 2 をリセットしたい場合:i2cset -f -y 30 0x42 --> i2cset -f -y 30 0x60 に変更する。 + +port 3 をリセットしたい場合:i2cset -f -y 30 0x42 --> i2cset -f -y 31 0x42 に変更する。 + +port 4 をリセットしたい場合:i2cset -f -y 30 0x42 --> i2cset -f -y 31 0x60 に変更する。 + +port 5 をリセットしたい場合:i2cset -f -y 30 0x42 --> i2cset -f -y 32 0x42 に変更する。 + +port 6 をリセットしたい場合:i2cset -f -y 30 0x42 --> i2cset -f -y 32 0x60 に変更する。 + +port 7 をリセットしたい場合:i2cset -f -y 30 0x42 --> i2cset -f -y 33 0x42 に変更する。 + +port 8 をリセットしたい場合:i2cset -f -y 30 0x42 --> i2cset -f -y 33 0x60 に変更する。 + + +- reset_dual.sh : ポート1,2 の Deser and Ser, Camera Sensor をリセットする。 + +使い方: sudo ./reset_dual.sh + +port 1とport 2を個別にリセットはできない。理由:Deserが共有のため。 + +他のportのDeser,Ser,Camera Sensorをリセットしたい場合は、reset_dual.shに以下の変更が必要である。 + +port 3,4 をリセットしたい場合: + i2cset -f -y 30 --> i2cset -f -y 31 に変更する。 + +port 5,6 をリセットしたい場合: + i2cset -f -y 30 --> i2cset -f -y 32 に変更する。 + +port 7,8 をリセットしたい場合: + i2cset -f -y 30 --> i2cset -f -y 33 に変更する。 diff --git a/scripts/c1/reset/reset_dual.sh b/scripts/c1/reset/reset_dual.sh new file mode 100755 index 0000000..84439c2 --- /dev/null +++ b/scripts/c1/reset/reset_dual.sh @@ -0,0 +1,155 @@ +#!/bin/bash + +echo 1 > /sys/kernel/debug/bpmp/debug/clk/i2c2/mrq_rate_locked + +echo 400000 > /sys/kernel/debug/bpmp/debug/clk/i2c2/rate + +# if you don't want to show i2cset command on your screen +# comment out the line of "set -x" + +set -x + +i2cset -f -y 30 0x42 0x00 0x10 0x80 i +i2cset -f -y 30 0x62 0x00 0x10 0x80 i +i2cset -f -y 30 0x60 0x00 0x10 0x80 i + +i2cset -f -y 30 0x48 0x00 0x10 0x80 i + +i2cset -f -y 30 0x48 0x00 0x10 0x01 i +i2cset -f -y 30 0x48 0x00 0x10 0x21 i + +i2cset -f -y 30 0x62 0x00 0x00 0x84 i + +i2cset -f -y 30 0x42 0x00 0x10 0x21 i +i2cset -f -y 30 0x42 0x00 0x6B 0x10 i +i2cset -f -y 30 0x42 0x00 0x73 0x11 i +i2cset -f -y 30 0x42 0x00 0x7B 0x31 i +i2cset -f -y 30 0x42 0x00 0x83 0x31 i +i2cset -f -y 30 0x42 0x00 0x93 0x31 i +i2cset -f -y 30 0x42 0x00 0x9B 0x31 i +i2cset -f -y 30 0x42 0x00 0xA3 0x31 i +i2cset -f -y 30 0x42 0x00 0xAB 0x31 i +i2cset -f -y 30 0x42 0x00 0x8B 0x31 i +i2cset -f -y 30 0x42 0x00 0x44 0x36 i +i2cset -f -y 30 0x42 0x00 0x45 0x34 i +i2cset -f -y 30 0x42 0x02 0xBE 0x90 i +i2cset -f -y 30 0x42 0x02 0xBF 0x60 i +i2cset -f -y 30 0x42 0x03 0xF1 0x89 i + +i2cset -f -y 30 0x48 0x00 0x10 0x03 i +i2cset -f -y 30 0x48 0x00 0x10 0x23 i + +i2cset -f -y 30 0x62 0x00 0x00 0xC0 i + +i2cset -f -y 30 0x60 0x00 0x10 0x22 i +i2cset -f -y 30 0x60 0x00 0x6B 0x12 i +i2cset -f -y 30 0x60 0x00 0x73 0x13 i +i2cset -f -y 30 0x60 0x00 0x7B 0x32 i +i2cset -f -y 30 0x60 0x00 0x83 0x32 i +i2cset -f -y 30 0x60 0x00 0x93 0x32 i +i2cset -f -y 30 0x60 0x00 0x9B 0x32 i +i2cset -f -y 30 0x60 0x00 0xA3 0x32 i +i2cset -f -y 30 0x60 0x00 0xAB 0x32 i +i2cset -f -y 30 0x60 0x00 0x44 0x38 i +i2cset -f -y 30 0x60 0x00 0x45 0x34 i +i2cset -f -y 30 0x60 0x02 0xBE 0x90 i +i2cset -f -y 30 0x60 0x02 0xBF 0x60 i +i2cset -f -y 30 0x60 0x03 0xF1 0x89 i + + +i2cset -f -y 30 0x60 0x03 0x30 0x00 i +i2cset -f -y 30 0x60 0x03 0x31 0x30 i + +i2cset -f -y 30 0x42 0x03 0x30 0x00 i + +i2cset -f -y 30 0x60 0x03 0x32 0xE0 i + +i2cset -f -y 30 0x42 0x03 0x31 0x30 i + +i2cset -f -y 30 0x60 0x03 0x33 0x04 i + +i2cset -f -y 30 0x42 0x03 0x32 0xE0 i + +i2cset -f -y 30 0x60 0x03 0x16 0x70 i +#i2cset -f -y 30 0x60 0x03 0x16 0x5E i + +i2cset -f -y 30 0x42 0x03 0x33 0x04 i + +i2cset -f -y 30 0x60 0x03 0x1A 0x5E i + +i2cset -f -y 30 0x42 0x03 0x14 0xF0 i +#i2cset -f -y 30 0x42 0x03 0x14 0xDE i + +i2cset -f -y 30 0x60 0x03 0x11 0xF0 i + +i2cset -f -y 30 0x42 0x03 0x18 0x5E i + +i2cset -f -y 30 0x60 0x03 0x08 0x6A i + +i2cset -f -y 30 0x42 0x03 0x11 0xF0 i + +i2cset -f -y 30 0x60 0x00 0x02 0xF3 i + +i2cset -f -y 30 0x42 0x03 0x08 0x65 i + +i2cset -f -y 30 0x48 0x04 0x0B 0x07 i + +i2cset -f -y 30 0x42 0x00 0x02 0xF3 i + +i2cset -f -y 30 0x48 0x04 0x2D 0x15 i +i2cset -f -y 30 0x48 0x04 0x0D 0x1E i +i2cset -f -y 30 0x48 0x04 0x0E 0x5E i +i2cset -f -y 30 0x48 0x04 0x0F 0x00 i +i2cset -f -y 30 0x48 0x04 0x10 0x40 i +i2cset -f -y 30 0x48 0x04 0x11 0x01 i +i2cset -f -y 30 0x48 0x04 0x12 0x41 i +i2cset -f -y 30 0x48 0x04 0x4A 0x40 i +i2cset -f -y 30 0x48 0x03 0x30 0x04 i +i2cset -f -y 30 0x48 0x03 0x33 0x4E i +i2cset -f -y 30 0x48 0x03 0x34 0xE4 i +i2cset -f -y 30 0x48 0x03 0x20 0x2F i +i2cset -f -y 30 0x48 0x00 0x05 0xC0 i +i2cset -f -y 30 0x48 0x04 0x4B 0x07 i +i2cset -f -y 30 0x48 0x04 0x6D 0x15 i +i2cset -f -y 30 0x48 0x04 0x4D 0x1E i +i2cset -f -y 30 0x48 0x04 0x4E 0x1E i +i2cset -f -y 30 0x48 0x04 0x4F 0x00 i +i2cset -f -y 30 0x48 0x04 0x50 0x00 i +i2cset -f -y 30 0x48 0x04 0x51 0x01 i +i2cset -f -y 30 0x48 0x04 0x52 0x01 i +i2cset -f -y 30 0x48 0x04 0x4A 0x40 i +i2cset -f -y 30 0x48 0x00 0x05 0xC0 i + +i2cset -f -y 30 0x60 0x02 0xD6 0x00 i + +i2cset -f -y 30 0x42 0x02 0xD6 0x00 i + +i2cset -f -y 30 0x60 0x02 0xCD 0x04 i + +i2cset -f -y 30 0x42 0x02 0xCD 0x04 i + +i2cset -f -y 30 0x60 0x02 0xCA 0x10 i + +i2cset -f -y 30 0x42 0x02 0xCA 0x10 i + +i2cset -f -y 30 0x60 0x02 0xD6 0x10 i + +i2cset -f -y 30 0x42 0x02 0xD6 0x10 i + +i2cset -f -y 30 0x1c 0xAB 0xC0 0x00 i +i2cset -f -y 30 0x1c 0xAC 0x4E 0x03 i +i2cset -f -y 30 0x1c 0xAC 0x48 0xE8 i +i2cset -f -y 30 0x1c 0xAC 0x49 0x80 i + +i2cset -f -y 30 0x48 0x00 0x50 0x03 i + +i2cset -f -y 30 0x1b 0xAB 0xC0 0x00 i +i2cset -f -y 30 0x1b 0xAC 0x4E 0x03 i +i2cset -f -y 30 0x1b 0xAC 0x48 0xE8 i +i2cset -f -y 30 0x1b 0xAC 0x49 0x80 i + +i2cset -f -y 30 0x48 0x00 0x51 0x02 i + +echo 136000000 > /sys/kernel/debug/bpmp/debug/clk/i2c2/rate + +echo 0 > /sys/kernel/debug/bpmp/debug/clk/i2c2/mrq_rate_locked diff --git a/scripts/c1/reset/reset_single.sh b/scripts/c1/reset/reset_single.sh new file mode 100755 index 0000000..8bec026 --- /dev/null +++ b/scripts/c1/reset/reset_single.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# if you don't want to show i2cset command on your screen +# comment out the line of "set -x" + +set -x + +echo 1 > /sys/kernel/debug/bpmp/debug/clk/i2c2/mrq_rate_locked + +echo 400000 > /sys/kernel/debug/bpmp/debug/clk/i2c2/rate + +i2cset -f -y 30 0x42 0x00 0x10 0x80 i +i2cset -f -y 30 0x60 0x00 0x10 0x80 i +i2cset -f -y 30 0x48 0x00 0x10 0x80 i + +i2cset -f -y 30 0x48 0x00 0x10 0x01 i +i2cset -f -y 30 0x48 0x00 0x10 0x21 i + +i2cset -f -y 30 0x62 0x00 0x00 0x84 i + +i2cset -f -y 30 0x42 0x00 0x10 0x21 i +i2cset -f -y 30 0x42 0x00 0x6B 0x10 i +i2cset -f -y 30 0x42 0x00 0x73 0x11 i +i2cset -f -y 30 0x42 0x00 0x7B 0x31 i +i2cset -f -y 30 0x42 0x00 0x83 0x31 i +i2cset -f -y 30 0x42 0x00 0x93 0x31 i +i2cset -f -y 30 0x42 0x00 0x9B 0x31 i +i2cset -f -y 30 0x42 0x00 0xA3 0x31 i +i2cset -f -y 30 0x42 0x00 0xAB 0x31 i +i2cset -f -y 30 0x42 0x00 0x8B 0x31 i +i2cset -f -y 30 0x42 0x00 0x44 0x36 i +i2cset -f -y 30 0x42 0x00 0x45 0x34 i +i2cset -f -y 30 0x42 0x02 0xBE 0x90 i +i2cset -f -y 30 0x42 0x02 0xBF 0x60 i +i2cset -f -y 30 0x42 0x03 0xF1 0x89 i + +i2cset -f -y 30 0x48 0x00 0x10 0x03 i +i2cset -f -y 30 0x48 0x00 0x10 0x23 i + +i2cset -f -y 30 0x48 0x00 0x10 0x01 i +i2cset -f -y 30 0x48 0x00 0x10 0x21 i +#i2cset -f -y 30 0x62 0x00 0x00 0xC0 i + +#i2cset -f -y 30 0x60 0x00 0x10 0x22 i + +i2cset -f -y 30 0x42 0x03 0x30 0x00 i +i2cset -f -y 30 0x42 0x03 0x31 0x30 i +i2cset -f -y 30 0x42 0x03 0x32 0xE0 i +i2cset -f -y 30 0x42 0x03 0x33 0x04 i +i2cset -f -y 30 0x42 0x03 0x14 0xF0 i +#i2cset -f -y 30 0x42 0x03 0x14 0xDE i +i2cset -f -y 30 0x42 0x03 0x18 0x5E i +i2cset -f -y 30 0x42 0x03 0x11 0xF0 i +i2cset -f -y 30 0x42 0x03 0x08 0x65 i +i2cset -f -y 30 0x42 0x00 0x02 0xF3 i +i2cset -f -y 30 0x48 0x04 0x0B 0x07 i +i2cset -f -y 30 0x48 0x04 0x2D 0x15 i +i2cset -f -y 30 0x48 0x04 0x0D 0x1E i +i2cset -f -y 30 0x48 0x04 0x0E 0x1E i +i2cset -f -y 30 0x48 0x04 0x0F 0x00 i +i2cset -f -y 30 0x48 0x04 0x10 0x00 i +i2cset -f -y 30 0x48 0x04 0x11 0x01 i +i2cset -f -y 30 0x48 0x04 0x12 0x01 i +i2cset -f -y 30 0x48 0x04 0x4A 0x40 i +i2cset -f -y 30 0x48 0x03 0x30 0x04 i +i2cset -f -y 30 0x48 0x03 0x33 0x4E i +i2cset -f -y 30 0x48 0x03 0x34 0xE4 i +i2cset -f -y 30 0x48 0x03 0x20 0x2F i +i2cset -f -y 30 0x48 0x00 0x05 0xC0 i +i2cset -f -y 30 0x42 0x02 0xD6 0x00 i +i2cset -f -y 30 0x42 0x02 0xCD 0x04 i +i2cset -f -y 30 0x42 0x02 0xCA 0x10 i +i2cset -f -y 30 0x42 0x02 0xD6 0x10 i + +i2cset -f -y 30 0x1b 0xAB 0xC0 0x00 i +i2cset -f -y 30 0x1b 0xAC 0x4E 0x03 i +i2cset -f -y 30 0x1b 0xAC 0x48 0xE8 i +i2cset -f -y 30 0x1b 0xAC 0x49 0x80 i + +i2cset -f -y 30 0x48 0x00 0x50 0x02 i + +echo 136000000 > /sys/kernel/debug/bpmp/debug/clk/i2c2/rate + +echo 0 > /sys/kernel/debug/bpmp/debug/clk/i2c2/mrq_rate_locked + diff --git a/scripts/c2/.integration.sh.swp b/scripts/c2/.integration.sh.swp new file mode 100644 index 0000000..e3d2313 Binary files /dev/null and b/scripts/c2/.integration.sh.swp differ diff --git a/scripts/common/hotplug/camera-hotplug.sh b/scripts/common/hotplug/camera-hotplug.sh index 3918de2..c5fad64 100755 --- a/scripts/common/hotplug/camera-hotplug.sh +++ b/scripts/common/hotplug/camera-hotplug.sh @@ -16,15 +16,14 @@ set -eux mkdir -p overlay cd overlay rm -f *.dts *.dtbo -"../../../../drivers/src/make_overlay_dts_$BOARD.py" "$L4T_REVISION" ${@:3} +"../../../../tools/dts_generator/make_overlay_dts_$BOARD.py" "$L4T_REVISION" ${@:3} dtc -O dtb -o target.dtbo -@ $(ls *.dts) -sudo modprobe -r tier4-isx021 || true -sudo modprobe -r tier4-imx490 || true +sudo modprobe -r tier4_imx728 || true sudo rmdir /sys/kernel/config/device-tree/overlays/camera/ || true sudo mkdir -p /sys/kernel/config/device-tree/overlays/camera/ sudo cp target.dtbo /sys/kernel/config/device-tree/overlays/camera/dtbo echo 1 | sudo tee /sys/kernel/config/device-tree/overlays/camera/status -sudo modprobe tier4-imx490 +sudo modprobe tier4-imx728 diff --git a/scripts/common/hotplug/dtbocfg b/scripts/common/hotplug/dtbocfg index d3cea0f..06207c6 160000 --- a/scripts/common/hotplug/dtbocfg +++ b/scripts/common/hotplug/dtbocfg @@ -1 +1 @@ -Subproject commit d3cea0fea5a59e2b0805f3d17cf33e83dac2c00f +Subproject commit 06207c67bac6978a997b37d6e8843504d6f70a4b diff --git a/scripts/common/trigger/rqx59g/camera_trigger.sh b/scripts/common/trigger/rqx59g/camera_trigger.sh deleted file mode 100755 index 2cdba94..0000000 --- a/scripts/common/trigger/rqx59g/camera_trigger.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash -e -help() -{ - echo "Run GPIO triggering on all four deserializers on ROScube X." - echo - echo "Syntax: scriptTemplate [-r|h]" - echo "Options:" - echo "r Set the frame rate. Default is 10Hz. Maximum is 25Hz, minimum is 1Hz" - echo "h Print this Help." - echo -} -cleanup() -{ - echo "Cleaning up before exit..." - echo 440 > /sys/class/gpio/unexport - echo 397 > /sys/class/gpio/unexport - echo 487 > /sys/class/gpio/unexport - echo 486 > /sys/class/gpio/unexport -} -trap cleanup EXIT -fps=10 -while getopts ":hr:" option; do - case $option in - h) # Display help - help - exit;; - r) # Get frame rate - fps=$OPTARG - if [ $fps -gt 25 ] - then - echo "Frame rate must be less than 25Hz" - exit - fi - if [ $fps -lt 1 ] - then - echo "Frame rate must be more than 1Hz" - exit - fi;; - \?) # Invalid option - echo "Error: Invalid option" - exit;; - esac -done -on_time_milli=10 -let "off_time_milli = 1000 / $fps - $on_time_milli" -echo 440 > /sys/class/gpio/export -sleep $(echo "scale=10; 0.5" | bc) -echo out > /sys/class/gpio/gpio440/direction -sleep $(echo "scale=10; 0.5" | bc) -echo 397 > /sys/class/gpio/export -sleep $(echo "scale=10; 0.5" | bc) -echo out > /sys/class/gpio/gpio397/direction -sleep $(echo "scale=10; 0.5" | bc) -echo 487 > /sys/class/gpio/export -sleep $(echo "scale=10; 0.5" | bc) -echo out > /sys/class/gpio/gpio487/direction -sleep $(echo "scale=10; 0.5" | bc) -echo 486 > /sys/class/gpio/export -sleep $(echo "scale=10; 0.5" | bc) -echo out > /sys/class/gpio/gpio486/direction -sleep $(echo "scale=10; 0.5" | bc) - -while true -do - echo 1 > /sys/class/gpio/gpio440/value - echo 1 > /sys/class/gpio/gpio397/value - echo 1 > /sys/class/gpio/gpio486/value - echo 1 > /sys/class/gpio/gpio487/value - sleep $(echo "scale=10; $on_time_milli/1000" | bc) - echo 0 > /sys/class/gpio/gpio440/value - echo 0 > /sys/class/gpio/gpio397/value - echo 0 > /sys/class/gpio/gpio487/value - echo 0 > /sys/class/gpio/gpio486/value - sleep $(echo "scale=10; $off_time_milli/1000" | bc) -done diff --git a/src/tier4-camera-gmsl/.clang-format b/src/tier4-camera-gmsl/.clang-format new file mode 100755 index 0000000..ccc9b93 --- /dev/null +++ b/src/tier4-camera-gmsl/.clang-format @@ -0,0 +1,743 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# clang-format configuration file. Intended for clang-format >= 11. +# +# For more information, see: +# +# Documentation/process/clang-format.rst +# https://clang.llvm.org/docs/ClangFormat.html +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: false +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: false +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false + +# Taken from: +# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ tools/ \ +# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \ +# | LC_ALL=C sort -u +ForEachMacros: + - '__ata_qc_for_each' + - '__bio_for_each_bvec' + - '__bio_for_each_segment' + - '__evlist__for_each_entry' + - '__evlist__for_each_entry_continue' + - '__evlist__for_each_entry_from' + - '__evlist__for_each_entry_reverse' + - '__evlist__for_each_entry_safe' + - '__for_each_mem_range' + - '__for_each_mem_range_rev' + - '__for_each_thread' + - '__hlist_for_each_rcu' + - '__map__for_each_symbol_by_name' + - '__pci_bus_for_each_res0' + - '__pci_bus_for_each_res1' + - '__pci_dev_for_each_res0' + - '__pci_dev_for_each_res1' + - '__perf_evlist__for_each_entry' + - '__perf_evlist__for_each_entry_reverse' + - '__perf_evlist__for_each_entry_safe' + - '__rq_for_each_bio' + - '__shost_for_each_device' + - '__sym_for_each' + - 'apei_estatus_for_each_section' + - 'ata_for_each_dev' + - 'ata_for_each_link' + - 'ata_qc_for_each' + - 'ata_qc_for_each_raw' + - 'ata_qc_for_each_with_internal' + - 'ax25_for_each' + - 'ax25_uid_for_each' + - 'bio_for_each_bvec' + - 'bio_for_each_bvec_all' + - 'bio_for_each_folio_all' + - 'bio_for_each_integrity_vec' + - 'bio_for_each_segment' + - 'bio_for_each_segment_all' + - 'bio_list_for_each' + - 'bip_for_each_vec' + - 'bond_for_each_slave' + - 'bond_for_each_slave_rcu' + - 'bpf_for_each' + - 'bpf_for_each_reg_in_vstate' + - 'bpf_for_each_reg_in_vstate_mask' + - 'bpf_for_each_spilled_reg' + - 'bpf_object__for_each_map' + - 'bpf_object__for_each_program' + - 'btree_for_each_safe128' + - 'btree_for_each_safe32' + - 'btree_for_each_safe64' + - 'btree_for_each_safel' + - 'card_for_each_dev' + - 'cgroup_taskset_for_each' + - 'cgroup_taskset_for_each_leader' + - 'cpu_aggr_map__for_each_idx' + - 'cpufreq_for_each_efficient_entry_idx' + - 'cpufreq_for_each_entry' + - 'cpufreq_for_each_entry_idx' + - 'cpufreq_for_each_valid_entry' + - 'cpufreq_for_each_valid_entry_idx' + - 'css_for_each_child' + - 'css_for_each_descendant_post' + - 'css_for_each_descendant_pre' + - 'damon_for_each_region' + - 'damon_for_each_region_from' + - 'damon_for_each_region_safe' + - 'damon_for_each_scheme' + - 'damon_for_each_scheme_safe' + - 'damon_for_each_target' + - 'damon_for_each_target_safe' + - 'damos_for_each_filter' + - 'damos_for_each_filter_safe' + - 'data__for_each_file' + - 'data__for_each_file_new' + - 'data__for_each_file_start' + - 'device_for_each_child_node' + - 'displayid_iter_for_each' + - 'dma_fence_array_for_each' + - 'dma_fence_chain_for_each' + - 'dma_fence_unwrap_for_each' + - 'dma_resv_for_each_fence' + - 'dma_resv_for_each_fence_unlocked' + - 'do_for_each_ftrace_op' + - 'drm_atomic_crtc_for_each_plane' + - 'drm_atomic_crtc_state_for_each_plane' + - 'drm_atomic_crtc_state_for_each_plane_state' + - 'drm_atomic_for_each_plane_damage' + - 'drm_client_for_each_connector_iter' + - 'drm_client_for_each_modeset' + - 'drm_connector_for_each_possible_encoder' + - 'drm_exec_for_each_locked_object' + - 'drm_exec_for_each_locked_object_reverse' + - 'drm_for_each_bridge_in_chain' + - 'drm_for_each_connector_iter' + - 'drm_for_each_crtc' + - 'drm_for_each_crtc_reverse' + - 'drm_for_each_encoder' + - 'drm_for_each_encoder_mask' + - 'drm_for_each_fb' + - 'drm_for_each_legacy_plane' + - 'drm_for_each_plane' + - 'drm_for_each_plane_mask' + - 'drm_for_each_privobj' + - 'drm_gem_for_each_gpuva' + - 'drm_gem_for_each_gpuva_safe' + - 'drm_gpuva_for_each_op' + - 'drm_gpuva_for_each_op_from_reverse' + - 'drm_gpuva_for_each_op_safe' + - 'drm_gpuvm_for_each_va' + - 'drm_gpuvm_for_each_va_range' + - 'drm_gpuvm_for_each_va_range_safe' + - 'drm_gpuvm_for_each_va_safe' + - 'drm_mm_for_each_hole' + - 'drm_mm_for_each_node' + - 'drm_mm_for_each_node_in_range' + - 'drm_mm_for_each_node_safe' + - 'dsa_switch_for_each_available_port' + - 'dsa_switch_for_each_cpu_port' + - 'dsa_switch_for_each_cpu_port_continue_reverse' + - 'dsa_switch_for_each_port' + - 'dsa_switch_for_each_port_continue_reverse' + - 'dsa_switch_for_each_port_safe' + - 'dsa_switch_for_each_user_port' + - 'dsa_tree_for_each_cpu_port' + - 'dsa_tree_for_each_user_port' + - 'dsa_tree_for_each_user_port_continue_reverse' + - 'dso__for_each_symbol' + - 'dsos__for_each_with_build_id' + - 'elf_hash_for_each_possible' + - 'elf_symtab__for_each_symbol' + - 'evlist__for_each_cpu' + - 'evlist__for_each_entry' + - 'evlist__for_each_entry_continue' + - 'evlist__for_each_entry_from' + - 'evlist__for_each_entry_reverse' + - 'evlist__for_each_entry_safe' + - 'flow_action_for_each' + - 'for_each_acpi_consumer_dev' + - 'for_each_acpi_dev_match' + - 'for_each_active_dev_scope' + - 'for_each_active_drhd_unit' + - 'for_each_active_iommu' + - 'for_each_active_route' + - 'for_each_aggr_pgid' + - 'for_each_and_bit' + - 'for_each_andnot_bit' + - 'for_each_available_child_of_node' + - 'for_each_bench' + - 'for_each_bio' + - 'for_each_board_func_rsrc' + - 'for_each_btf_ext_rec' + - 'for_each_btf_ext_sec' + - 'for_each_bvec' + - 'for_each_card_auxs' + - 'for_each_card_auxs_safe' + - 'for_each_card_components' + - 'for_each_card_dapms' + - 'for_each_card_pre_auxs' + - 'for_each_card_prelinks' + - 'for_each_card_rtds' + - 'for_each_card_rtds_safe' + - 'for_each_card_widgets' + - 'for_each_card_widgets_safe' + - 'for_each_cgroup_storage_type' + - 'for_each_child_of_node' + - 'for_each_clear_bit' + - 'for_each_clear_bit_from' + - 'for_each_clear_bitrange' + - 'for_each_clear_bitrange_from' + - 'for_each_cmd' + - 'for_each_cmsghdr' + - 'for_each_collection' + - 'for_each_comp_order' + - 'for_each_compatible_node' + - 'for_each_component_dais' + - 'for_each_component_dais_safe' + - 'for_each_conduit' + - 'for_each_console' + - 'for_each_console_srcu' + - 'for_each_cpu' + - 'for_each_cpu_and' + - 'for_each_cpu_andnot' + - 'for_each_cpu_or' + - 'for_each_cpu_wrap' + - 'for_each_dapm_widgets' + - 'for_each_dedup_cand' + - 'for_each_dev_addr' + - 'for_each_dev_scope' + - 'for_each_dma_cap_mask' + - 'for_each_dpcm_be' + - 'for_each_dpcm_be_rollback' + - 'for_each_dpcm_be_safe' + - 'for_each_dpcm_fe' + - 'for_each_drhd_unit' + - 'for_each_dss_dev' + - 'for_each_efi_memory_desc' + - 'for_each_efi_memory_desc_in_map' + - 'for_each_element' + - 'for_each_element_extid' + - 'for_each_element_id' + - 'for_each_endpoint_of_node' + - 'for_each_event' + - 'for_each_event_tps' + - 'for_each_evictable_lru' + - 'for_each_fib6_node_rt_rcu' + - 'for_each_fib6_walker_rt' + - 'for_each_free_mem_pfn_range_in_zone' + - 'for_each_free_mem_pfn_range_in_zone_from' + - 'for_each_free_mem_range' + - 'for_each_free_mem_range_reverse' + - 'for_each_func_rsrc' + - 'for_each_gpiochip_node' + - 'for_each_group_evsel' + - 'for_each_group_evsel_head' + - 'for_each_group_member' + - 'for_each_group_member_head' + - 'for_each_hstate' + - 'for_each_if' + - 'for_each_inject_fn' + - 'for_each_insn' + - 'for_each_insn_prefix' + - 'for_each_intid' + - 'for_each_iommu' + - 'for_each_ip_tunnel_rcu' + - 'for_each_irq_nr' + - 'for_each_lang' + - 'for_each_link_codecs' + - 'for_each_link_cpus' + - 'for_each_link_platforms' + - 'for_each_lru' + - 'for_each_matching_node' + - 'for_each_matching_node_and_match' + - 'for_each_media_entity_data_link' + - 'for_each_mem_pfn_range' + - 'for_each_mem_range' + - 'for_each_mem_range_rev' + - 'for_each_mem_region' + - 'for_each_member' + - 'for_each_memory' + - 'for_each_migratetype_order' + - 'for_each_missing_reg' + - 'for_each_mle_subelement' + - 'for_each_mod_mem_type' + - 'for_each_net' + - 'for_each_net_continue_reverse' + - 'for_each_net_rcu' + - 'for_each_netdev' + - 'for_each_netdev_continue' + - 'for_each_netdev_continue_rcu' + - 'for_each_netdev_continue_reverse' + - 'for_each_netdev_dump' + - 'for_each_netdev_feature' + - 'for_each_netdev_in_bond_rcu' + - 'for_each_netdev_rcu' + - 'for_each_netdev_reverse' + - 'for_each_netdev_safe' + - 'for_each_new_connector_in_state' + - 'for_each_new_crtc_in_state' + - 'for_each_new_mst_mgr_in_state' + - 'for_each_new_plane_in_state' + - 'for_each_new_plane_in_state_reverse' + - 'for_each_new_private_obj_in_state' + - 'for_each_new_reg' + - 'for_each_node' + - 'for_each_node_by_name' + - 'for_each_node_by_type' + - 'for_each_node_mask' + - 'for_each_node_state' + - 'for_each_node_with_cpus' + - 'for_each_node_with_property' + - 'for_each_nonreserved_multicast_dest_pgid' + - 'for_each_numa_hop_mask' + - 'for_each_of_allnodes' + - 'for_each_of_allnodes_from' + - 'for_each_of_cpu_node' + - 'for_each_of_pci_range' + - 'for_each_old_connector_in_state' + - 'for_each_old_crtc_in_state' + - 'for_each_old_mst_mgr_in_state' + - 'for_each_old_plane_in_state' + - 'for_each_old_private_obj_in_state' + - 'for_each_oldnew_connector_in_state' + - 'for_each_oldnew_crtc_in_state' + - 'for_each_oldnew_mst_mgr_in_state' + - 'for_each_oldnew_plane_in_state' + - 'for_each_oldnew_plane_in_state_reverse' + - 'for_each_oldnew_private_obj_in_state' + - 'for_each_online_cpu' + - 'for_each_online_node' + - 'for_each_online_pgdat' + - 'for_each_or_bit' + - 'for_each_path' + - 'for_each_pci_bridge' + - 'for_each_pci_dev' + - 'for_each_pcm_streams' + - 'for_each_physmem_range' + - 'for_each_populated_zone' + - 'for_each_possible_cpu' + - 'for_each_present_blessed_reg' + - 'for_each_present_cpu' + - 'for_each_prime_number' + - 'for_each_prime_number_from' + - 'for_each_probe_cache_entry' + - 'for_each_process' + - 'for_each_process_thread' + - 'for_each_prop_codec_conf' + - 'for_each_prop_dai_codec' + - 'for_each_prop_dai_cpu' + - 'for_each_prop_dlc_codecs' + - 'for_each_prop_dlc_cpus' + - 'for_each_prop_dlc_platforms' + - 'for_each_property_of_node' + - 'for_each_reg' + - 'for_each_reg_filtered' + - 'for_each_reloc' + - 'for_each_reloc_from' + - 'for_each_requested_gpio' + - 'for_each_requested_gpio_in_range' + - 'for_each_reserved_mem_range' + - 'for_each_reserved_mem_region' + - 'for_each_rtd_codec_dais' + - 'for_each_rtd_components' + - 'for_each_rtd_cpu_dais' + - 'for_each_rtd_dais' + - 'for_each_sband_iftype_data' + - 'for_each_script' + - 'for_each_sec' + - 'for_each_set_bit' + - 'for_each_set_bit_from' + - 'for_each_set_bit_wrap' + - 'for_each_set_bitrange' + - 'for_each_set_bitrange_from' + - 'for_each_set_clump8' + - 'for_each_sg' + - 'for_each_sg_dma_page' + - 'for_each_sg_page' + - 'for_each_sgtable_dma_page' + - 'for_each_sgtable_dma_sg' + - 'for_each_sgtable_page' + - 'for_each_sgtable_sg' + - 'for_each_sibling_event' + - 'for_each_sta_active_link' + - 'for_each_subelement' + - 'for_each_subelement_extid' + - 'for_each_subelement_id' + - 'for_each_sublist' + - 'for_each_subsystem' + - 'for_each_supported_activate_fn' + - 'for_each_supported_inject_fn' + - 'for_each_sym' + - 'for_each_test' + - 'for_each_thread' + - 'for_each_token' + - 'for_each_unicast_dest_pgid' + - 'for_each_valid_link' + - 'for_each_vif_active_link' + - 'for_each_vma' + - 'for_each_vma_range' + - 'for_each_vsi' + - 'for_each_wakeup_source' + - 'for_each_zone' + - 'for_each_zone_zonelist' + - 'for_each_zone_zonelist_nodemask' + - 'func_for_each_insn' + - 'fwnode_for_each_available_child_node' + - 'fwnode_for_each_child_node' + - 'fwnode_for_each_parent_node' + - 'fwnode_graph_for_each_endpoint' + - 'gadget_for_each_ep' + - 'genradix_for_each' + - 'genradix_for_each_from' + - 'genradix_for_each_reverse' + - 'hash_for_each' + - 'hash_for_each_possible' + - 'hash_for_each_possible_rcu' + - 'hash_for_each_possible_rcu_notrace' + - 'hash_for_each_possible_safe' + - 'hash_for_each_rcu' + - 'hash_for_each_safe' + - 'hashmap__for_each_entry' + - 'hashmap__for_each_entry_safe' + - 'hashmap__for_each_key_entry' + - 'hashmap__for_each_key_entry_safe' + - 'hctx_for_each_ctx' + - 'hists__for_each_format' + - 'hists__for_each_sort_list' + - 'hlist_bl_for_each_entry' + - 'hlist_bl_for_each_entry_rcu' + - 'hlist_bl_for_each_entry_safe' + - 'hlist_for_each' + - 'hlist_for_each_entry' + - 'hlist_for_each_entry_continue' + - 'hlist_for_each_entry_continue_rcu' + - 'hlist_for_each_entry_continue_rcu_bh' + - 'hlist_for_each_entry_from' + - 'hlist_for_each_entry_from_rcu' + - 'hlist_for_each_entry_rcu' + - 'hlist_for_each_entry_rcu_bh' + - 'hlist_for_each_entry_rcu_notrace' + - 'hlist_for_each_entry_safe' + - 'hlist_for_each_entry_srcu' + - 'hlist_for_each_safe' + - 'hlist_nulls_for_each_entry' + - 'hlist_nulls_for_each_entry_from' + - 'hlist_nulls_for_each_entry_rcu' + - 'hlist_nulls_for_each_entry_safe' + - 'i3c_bus_for_each_i2cdev' + - 'i3c_bus_for_each_i3cdev' + - 'idr_for_each_entry' + - 'idr_for_each_entry_continue' + - 'idr_for_each_entry_continue_ul' + - 'idr_for_each_entry_ul' + - 'in_dev_for_each_ifa_rcu' + - 'in_dev_for_each_ifa_rtnl' + - 'inet_bind_bucket_for_each' + - 'interval_tree_for_each_span' + - 'intlist__for_each_entry' + - 'intlist__for_each_entry_safe' + - 'kcore_copy__for_each_phdr' + - 'key_for_each' + - 'key_for_each_safe' + - 'klp_for_each_func' + - 'klp_for_each_func_safe' + - 'klp_for_each_func_static' + - 'klp_for_each_object' + - 'klp_for_each_object_safe' + - 'klp_for_each_object_static' + - 'kunit_suite_for_each_test_case' + - 'kvm_for_each_memslot' + - 'kvm_for_each_memslot_in_gfn_range' + - 'kvm_for_each_vcpu' + - 'libbpf_nla_for_each_attr' + - 'list_for_each' + - 'list_for_each_codec' + - 'list_for_each_codec_safe' + - 'list_for_each_continue' + - 'list_for_each_entry' + - 'list_for_each_entry_continue' + - 'list_for_each_entry_continue_rcu' + - 'list_for_each_entry_continue_reverse' + - 'list_for_each_entry_from' + - 'list_for_each_entry_from_rcu' + - 'list_for_each_entry_from_reverse' + - 'list_for_each_entry_lockless' + - 'list_for_each_entry_rcu' + - 'list_for_each_entry_reverse' + - 'list_for_each_entry_safe' + - 'list_for_each_entry_safe_continue' + - 'list_for_each_entry_safe_from' + - 'list_for_each_entry_safe_reverse' + - 'list_for_each_entry_srcu' + - 'list_for_each_from' + - 'list_for_each_prev' + - 'list_for_each_prev_safe' + - 'list_for_each_rcu' + - 'list_for_each_reverse' + - 'list_for_each_safe' + - 'llist_for_each' + - 'llist_for_each_entry' + - 'llist_for_each_entry_safe' + - 'llist_for_each_safe' + - 'lwq_for_each_safe' + - 'map__for_each_symbol' + - 'map__for_each_symbol_by_name' + - 'maps__for_each_entry' + - 'maps__for_each_entry_safe' + - 'mas_for_each' + - 'mci_for_each_dimm' + - 'media_device_for_each_entity' + - 'media_device_for_each_intf' + - 'media_device_for_each_link' + - 'media_device_for_each_pad' + - 'media_entity_for_each_pad' + - 'media_pipeline_for_each_entity' + - 'media_pipeline_for_each_pad' + - 'mlx5_lag_for_each_peer_mdev' + - 'msi_domain_for_each_desc' + - 'msi_for_each_desc' + - 'mt_for_each' + - 'nanddev_io_for_each_page' + - 'netdev_for_each_lower_dev' + - 'netdev_for_each_lower_private' + - 'netdev_for_each_lower_private_rcu' + - 'netdev_for_each_mc_addr' + - 'netdev_for_each_synced_mc_addr' + - 'netdev_for_each_synced_uc_addr' + - 'netdev_for_each_uc_addr' + - 'netdev_for_each_upper_dev_rcu' + - 'netdev_hw_addr_list_for_each' + - 'nft_rule_for_each_expr' + - 'nla_for_each_attr' + - 'nla_for_each_nested' + - 'nlmsg_for_each_attr' + - 'nlmsg_for_each_msg' + - 'nr_neigh_for_each' + - 'nr_neigh_for_each_safe' + - 'nr_node_for_each' + - 'nr_node_for_each_safe' + - 'of_for_each_phandle' + - 'of_property_for_each_string' + - 'of_property_for_each_u32' + - 'pci_bus_for_each_resource' + - 'pci_dev_for_each_resource' + - 'pcl_for_each_chunk' + - 'pcl_for_each_segment' + - 'pcm_for_each_format' + - 'perf_config_items__for_each_entry' + - 'perf_config_sections__for_each_entry' + - 'perf_config_set__for_each_entry' + - 'perf_cpu_map__for_each_cpu' + - 'perf_cpu_map__for_each_idx' + - 'perf_evlist__for_each_entry' + - 'perf_evlist__for_each_entry_reverse' + - 'perf_evlist__for_each_entry_safe' + - 'perf_evlist__for_each_evsel' + - 'perf_evlist__for_each_mmap' + - 'perf_hpp_list__for_each_format' + - 'perf_hpp_list__for_each_format_safe' + - 'perf_hpp_list__for_each_sort_list' + - 'perf_hpp_list__for_each_sort_list_safe' + - 'perf_tool_event__for_each_event' + - 'plist_for_each' + - 'plist_for_each_continue' + - 'plist_for_each_entry' + - 'plist_for_each_entry_continue' + - 'plist_for_each_entry_safe' + - 'plist_for_each_safe' + - 'pnp_for_each_card' + - 'pnp_for_each_dev' + - 'protocol_for_each_card' + - 'protocol_for_each_dev' + - 'queue_for_each_hw_ctx' + - 'radix_tree_for_each_slot' + - 'radix_tree_for_each_tagged' + - 'rb_for_each' + - 'rbtree_postorder_for_each_entry_safe' + - 'rdma_for_each_block' + - 'rdma_for_each_port' + - 'rdma_umem_for_each_dma_block' + - 'resort_rb__for_each_entry' + - 'resource_list_for_each_entry' + - 'resource_list_for_each_entry_safe' + - 'rhl_for_each_entry_rcu' + - 'rhl_for_each_rcu' + - 'rht_for_each' + - 'rht_for_each_entry' + - 'rht_for_each_entry_from' + - 'rht_for_each_entry_rcu' + - 'rht_for_each_entry_rcu_from' + - 'rht_for_each_entry_safe' + - 'rht_for_each_from' + - 'rht_for_each_rcu' + - 'rht_for_each_rcu_from' + - 'rq_for_each_bvec' + - 'rq_for_each_segment' + - 'rq_list_for_each' + - 'rq_list_for_each_safe' + - 'sample_read_group__for_each' + - 'scsi_for_each_prot_sg' + - 'scsi_for_each_sg' + - 'sctp_for_each_hentry' + - 'sctp_skb_for_each' + - 'sec_for_each_insn' + - 'sec_for_each_insn_continue' + - 'sec_for_each_insn_from' + - 'sec_for_each_sym' + - 'shdma_for_each_chan' + - 'shost_for_each_device' + - 'sk_for_each' + - 'sk_for_each_bound' + - 'sk_for_each_bound_bhash2' + - 'sk_for_each_entry_offset_rcu' + - 'sk_for_each_from' + - 'sk_for_each_rcu' + - 'sk_for_each_safe' + - 'sk_nulls_for_each' + - 'sk_nulls_for_each_from' + - 'sk_nulls_for_each_rcu' + - 'snd_array_for_each' + - 'snd_pcm_group_for_each_entry' + - 'snd_soc_dapm_widget_for_each_path' + - 'snd_soc_dapm_widget_for_each_path_safe' + - 'snd_soc_dapm_widget_for_each_sink_path' + - 'snd_soc_dapm_widget_for_each_source_path' + - 'strlist__for_each_entry' + - 'strlist__for_each_entry_safe' + - 'sym_for_each_insn' + - 'sym_for_each_insn_continue_reverse' + - 'symbols__for_each_entry' + - 'tb_property_for_each' + - 'tcf_act_for_each_action' + - 'tcf_exts_for_each_action' + - 'ttm_resource_manager_for_each_res' + - 'twsk_for_each_bound_bhash2' + - 'udp_portaddr_for_each_entry' + - 'udp_portaddr_for_each_entry_rcu' + - 'usb_hub_for_each_child' + - 'v4l2_device_for_each_subdev' + - 'v4l2_m2m_for_each_dst_buf' + - 'v4l2_m2m_for_each_dst_buf_safe' + - 'v4l2_m2m_for_each_src_buf' + - 'v4l2_m2m_for_each_src_buf_safe' + - 'virtio_device_for_each_vq' + - 'while_for_each_ftrace_op' + - 'xa_for_each' + - 'xa_for_each_marked' + - 'xa_for_each_range' + - 'xa_for_each_start' + - 'xas_for_each' + - 'xas_for_each_conflict' + - 'xas_for_each_marked' + - 'xbc_array_for_each_value' + - 'xbc_for_each_key_value' + - 'xbc_node_for_each_array_value' + - 'xbc_node_for_each_child' + - 'xbc_node_for_each_key_value' + - 'xbc_node_for_each_subkey' + - 'zorro_for_each_dev' + +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '.*' + Priority: 1 +IncludeIsMainRegex: '(Test)?$' +IndentCaseLabels: false +IndentGotoLabels: false +IndentPPDirectives: None +IndentWidth: 8 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 8 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true + +# Taken from git's rules +PenaltyBreakAssignment: 10 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 10 +PenaltyExcessCharacter: 100 +PenaltyReturnTypeOnItsOwnLine: 60 + +PointerAlignment: Right +ReflowComments: false +SortIncludes: false +SortUsingDeclarations: false +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatementsExceptForEachMacros +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp03 +TabWidth: 8 +UseTab: Always +... diff --git a/src/tier4-camera-gmsl/Makefile b/src/tier4-camera-gmsl/Makefile new file mode 100644 index 0000000..69dace0 --- /dev/null +++ b/src/tier4-camera-gmsl/Makefile @@ -0,0 +1,35 @@ +ARCH = arm64 +KDIR = /lib/modules/$(shell uname -r)/build/ +CROSS_COMPILE = + +ccflags-y += -DBUILD_STAMP="\"`date +'%Y-%m-%d %H:%M:%S'`\"" + +obj-m := tier4-fpga.o tier4-gw5300.o tier4-imx490.o tier4-imx728.o tier4-isx021.o tier4-max9295.o tier4-max9296.o + +all: modules + +modules: + $(MAKE) -C $(KDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) modules + +clean: + $(MAKE) -C $(KDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) clean + +load: modules unload + sudo insmod drivers/src/tier4-fpga.ko + sudo insmod drivers/src/tier4-max9295.ko + sudo insmod drivers/src/tier4-max9296.ko + sudo insmod drivers/src/tier4-gw5300.ko + sudo insmod drivers/src/tier4-isx021.ko + sudo insmod drivers/src/tier4-imx490.ko + sudo insmod drivers/src/tier4-imx728.ko + +unload: + sudo rmmod tier4-imx728 || true + sudo rmmod tier4-imx490 || true + sudo rmmod tier4-isx021 || true + sudo rmmod tier4-gw5300 || true + sudo rmmod tier4-max9296 || true + sudo rmmod tier4-max9295 || true + sudo rmmod tier4-fpga || true + +.PHONY: all modules clean load unload diff --git a/drivers/src/Makefile b/src/tier4-camera-gmsl/Makefile.dkms similarity index 91% rename from drivers/src/Makefile rename to src/tier4-camera-gmsl/Makefile.dkms index f74d4ce..fd6e1cf 100644 --- a/drivers/src/Makefile +++ b/src/tier4-camera-gmsl/Makefile.dkms @@ -3,11 +3,13 @@ ARCH ?= $(shell uname -m | sed -e s/arm.*/arm/ -e s/aarch64.*/arm64/) PWD ?= ${shell pwd} BUILD_DIR ?= $(shell pwd) _BUILD_DIR ?= $(shell readlink -f $(BUILD_DIR)) +EXTRA_MAKE_FLAGS = Xavier_word := Xavier Xavier_other_word_1 := Jetson-AGX Orin_word := Orin Orin_Compatible_word := p3737-0000+p3701-0000nvidia +AGX_Orin_devkit := NVIDIA Jetson AGX Orin Developer Kit ROScube_Xavier_word := 58G ROScube_Xavier_Model_word := ROScube-Xavier ROScube_Orin_word := 590 @@ -67,7 +69,22 @@ endif $(warning MODEL = $(MODEL)) -ifeq ($(L4T_RELEASE_MAIN), R32) +ifeq ($(L4T_RELEASE_MAIN), R36) + EXTRA_CFLAGS += -I /usr/src/nvidia/nvidia-oot/include/ + KBUILD_EXTRA_SYMBOLS += /usr/src/nvidia/nvidia-oot/Module.symvers + EXTRA_MAKE_FLAGS += EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(KBUILD_EXTRA_SYMBOLS)" +endif + +ifeq ($(MODEL),$(Anvil_Model_word)) + KERNELRELEASE := $(shell uname -r) + L4T_RELEASE_MAIN_LOWER = $(shell echo $(L4T_RELEASE_MAIN) | tr A-Z a-z) + TARGET_ISX021_DTS := tier4-isx021-gmsl-device-tree-overlay-anvil-$(L4T_RELEASE_MAIN_LOWER) + TARGET_IMX490_DTS := tier4-imx490-gmsl-device-tree-overlay-anvil-$(L4T_RELEASE_MAIN_LOWER) + TARGET_IMX728_DTS := tier4-imx728-gmsl-device-tree-overlay-anvil-$(L4T_RELEASE_MAIN_LOWER) + TARGET_ISX021_IMX490_DTS := tier4-isx021-imx490-gmsl-device-tree-overlay-anvil-$(L4T_RELEASE_MAIN_LOWER) + TARGET_ISX021_IMX490_IMX728_DTS := tier4-isx021-imx490-imx728-gmsl-device-tree-overlay-anvil-$(L4T_RELEASE_MAIN_LOWER) + MAKE_OVERLAY_DTS_CMD := make_overlay_dts_anvil.py $(L4T_RELEASE_MAIN) +else ifeq ($(L4T_RELEASE_MAIN), R32) ifeq ($(L4T_RELEASE_MAJOR), 5) ifeq ($(MODEL), $(ROScube_Xavier_Model_word)) KERNELRELEASE := 4.9.201-rqx58g @@ -249,14 +266,6 @@ else ifeq ($(L4T_RELEASE_MAIN), R35) TARGET_ISX021_IMX490_DTS := tier4-isx021-imx490-gmsl-device-tree-overlay-eac-5000-r3531 TARGET_ISX021_IMX490_IMX728_DTS := tier4-isx021-imx490-imx728-gmsl-device-tree-overlay-eac-5000-r3531 MAKE_OVERLAY_DTS_CMD := make_overlay_dts_eac-5000.py r35.3.1 - else ifeq ($(MODEL),$(Anvil_Model_word)) - KERNELRELEASE := 5.10.104-tegra - TARGET_ISX021_DTS := tier4-isx021-gmsl-device-tree-overlay-anvil-r35 - TARGET_IMX490_DTS := tier4-imx490-gmsl-device-tree-overlay-anvil-r35 - TARGET_IMX728_DTS := tier4-imx728-gmsl-device-tree-overlay-anvil-r35 - TARGET_ISX021_IMX490_DTS := tier4-isx021-imx490-gmsl-device-tree-overlay-anvil-r35 - TARGET_ISX021_IMX490_IMX728_DTS := tier4-isx021-imx490-imx728-gmsl-device-tree-overlay-anvil-r35 - MAKE_OVERLAY_DTS_CMD := make_overlay_dts_anvil.py r35 else KERNELRELEASE := 5.1.104-unknown TARGET_ISX021_DTS := Unknown @@ -265,6 +274,16 @@ else ifeq ($(L4T_RELEASE_MAIN), R35) TARGET_ISX021_IMX490_DTS := Unknown TARGET_ISX021_IMX490_IMX728_DTS := Unknown endif +else ifeq ($(L4T_RELEASE_MAIN), R36) + ifeq ($(dt_model),$(AGX_Orin_devkit)) + KERNELRELEASE := 5.15.148-tegra + TARGET_ISX021_DTS := tier4-isx021-gmsl-device-tree-overlay-orin-devkit-r36 + TARGET_IMX490_DTS := tier4-imx490-gmsl-device-tree-overlay-orin-devkit-r36 + TARGET_IMX728_DTS := tier4-imx728-gmsl-device-tree-overlay-orin-devkit-r36 + TARGET_ISX021_IMX490_DTS := tier4-isx021-imx490-gmsl-device-tree-overlay-orin-devkit-r36 + TARGET_ISX021_IMX490_IMX728_DTS := tier4-isx021-imx490-imx728-gmsl-device-tree-overlay-orin-devkit-r36 + MAKE_OVERLAY_DTS_CMD := make_overlay_dts_orin-devkit-r36.py r36 + endif else KERNELRELEASE := Unknown TARGET_ISX021_DTS := Unknown @@ -315,7 +334,7 @@ obj-m := tier4-max9295.o tier4-max9296.o tier4-isx021.o tier4-imx490.o tier4-imx all: binary_module modules dtbo modules: - $(MAKE) -C $(KERNEL_SRC_DIR) ARCH=$(ARCH) M=$(BUILD_DIR) src=$(PWD) modules + $(MAKE) -C $(KERNEL_SRC_DIR) ARCH=$(ARCH) M=$(BUILD_DIR) src=$(PWD) $(EXTRA_MAKE_FLAGS) modules binary_module: install -d $(DEST_FIRMWARE_DIR) diff --git a/src/tier4-camera-gmsl/Makefile.r36 b/src/tier4-camera-gmsl/Makefile.r36 new file mode 100644 index 0000000..51af318 --- /dev/null +++ b/src/tier4-camera-gmsl/Makefile.r36 @@ -0,0 +1,37 @@ +ARCH = arm64 +KDIR = /lib/modules/$(shell uname -r)/build/ +CROSS_COMPILE = +EXTRA_CFLAGS = -I /usr/src/nvidia/nvidia-oot/include/ +KBUILD_EXTRA_SYMBOLS = /usr/src/nvidia/nvidia-oot/Module.symvers + +ccflags-y += -DBUILD_STAMP="\"`date +'%Y-%m-%d %H:%M:%S'`\"" + +obj-m := tier4-fpga.o tier4-gw5300.o tier4-imx490.o tier4-imx728.o tier4-isx021.o tier4-max9295.o tier4-max9296.o + +all: modules + +modules: + $(MAKE) -C $(KDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(KBUILD_EXTRA_SYMBOLS)" modules + +clean: + $(MAKE) -C $(KDIR) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) M=$(PWD) clean + +load: modules unload + sudo insmod drivers/src/tier4-fpga.ko + sudo insmod drivers/src/tier4-max9295.ko + sudo insmod drivers/src/tier4-max9296.ko + sudo insmod drivers/src/tier4-gw5300.ko + sudo insmod drivers/src/tier4-isx021.ko + sudo insmod drivers/src/tier4-imx490.ko + sudo insmod drivers/src/tier4-imx728.ko + +unload: + sudo rmmod tier4-imx728 || true + sudo rmmod tier4-imx490 || true + sudo rmmod tier4-isx021 || true + sudo rmmod tier4-gw5300 || true + sudo rmmod tier4-max9296 || true + sudo rmmod tier4-max9295 || true + sudo rmmod tier4-fpga || true + +.PHONY: all modules clean load unload diff --git a/src/tier4-camera-gmsl/tier4-fpga.c b/src/tier4-camera-gmsl/tier4-fpga.c new file mode 100644 index 0000000..8d47e46 --- /dev/null +++ b/src/tier4-camera-gmsl/tier4-fpga.c @@ -0,0 +1,555 @@ +/* + * tier4_fpga.c - tier4_fpga driver + * + * Copyright (c) 2022-2023, TIER IV Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +//#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tier4-gmsl-link.h" +#include "tier4-fpga.h" + +//#define DEBUG_INFO + +#define FPGA_ENABLED 0xF0 +#define FPGA_DISABLED 0xFF +#define NO_ERROR 0 + +#define FPGA_REG_VERSION_ADDR 0x1 +#define FPGA_REG_ENABLE_ADDR 0x4 +//#define FPGA_REG_FREQ_BASE_ADDR 0x8 + +#define FREQ_10HZ 10 +#define FREQ_20HZ 20 +#define FREQ_30HZ 30 + +static int fsync_mode; // 0: disabled, 1: enable auto mode, 2: enable manual mode + +module_param(fsync_mode, int, S_IRUGO | S_IWUSR); + +static int fps_cam1_cam2 = 0xCAFE; +static int fps_cam3_cam4 = 0xCAFE; +static int fps_cam5_cam6 = 0xCAFE; +static int fps_cam7_cam8 = 0xCAFE; + +module_param(fps_cam1_cam2, int, S_IRUGO | S_IWUSR); +module_param(fps_cam3_cam4, int, S_IRUGO | S_IWUSR); +module_param(fps_cam5_cam6, int, S_IRUGO | S_IWUSR); +module_param(fps_cam7_cam8, int, S_IRUGO | S_IWUSR); + +struct tier4_fpga { + struct i2c_client *i2c_client; + struct regmap *regmap; + struct tier4_gmsl_link_ctx g_ctx; + struct mutex lock; + /* FPGA slave address */ + __u32 reg_addr; + // bool generate_fsync; +}; + +//static int generate_fsync; +//module_param(generate_fsync, int, S_IRUGO | S_IWUSR); + +static struct regmap_config tier4_fpga_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +/* count channel */ +static __u32 channel_count_fpga; /* should be 1 */ + +#if 1 +static int tier4_fpga_read_reg(struct device *dev, u16 addr, u8 *val) +{ + int err = 0; + u32 reg_val = 0; + struct tier4_fpga *priv = dev_get_drvdata(dev); + + err = regmap_read(priv->regmap, addr, ®_val); + + *val = reg_val & 0xFF; + + return err; +} +#endif + +static int tier4_fpga_write_reg(struct device *dev, u16 addr, u8 val) +{ + struct tier4_fpga *priv = dev_get_drvdata(dev); + int err = 0; + + err = regmap_write(priv->regmap, addr, val); + + if (err) { + dev_err(dev, + "[%s] FPGA I2C write Reg at 0x%04X:[0x%02X] failed.\n", + __func__, addr, val); + } +#ifdef DEBUG_INFO + else { + dev_info(dev, "[%s] FPGA I2C write Reg at 0x%04X:[0x%02X].\n", + __func__, addr, val); + } +#endif + + /* delay before next i2c command as required for SERDES link */ + usleep_range(200, 220); + // tier4_fpga_read_reg(dev, addr, &e); + // usleep_range(100, 110); + + return err; +} + +int tier4_fpga_get_fsync_mode(void) +{ + return fsync_mode; // 0: disabled, 1: enable auto mode, 2: enable manual mode +} +EXPORT_SYMBOL(tier4_fpga_get_fsync_mode); + +int tier4_fpga_enable_fsync_mode(struct device *dev) +{ + int err = 0; + // u8 val = 0; + + // err = tier4_fpga_read_reg(dev, FPGA_REG_MODE_ADDR, &val); + // if ((val & 0xFF) == FPGA_MODE_FSYNC) { + // // skip writing the same value to reg in order to save the flash write cycles + // dev_info(dev, "[%s] : Keep FSYNC mode enabled.\n", __func__); + // return err; + // } + + err = tier4_fpga_write_reg(dev, FPGA_REG_MODE_ADDR, FPGA_MODE_FSYNC); + if (err) { + dev_err(dev, "[%s] Enabling FSYNC mode failed.\n", __func__); + } +#ifdef DEBUG_INFO + else { + dev_info(dev, "[%s] Enabling FSYNC mode.\n", __func__); + } +#endif + + return err; +} +EXPORT_SYMBOL(tier4_fpga_enable_fsync_mode); + +int tier4_fpga_disable_fsync_mode(struct device *dev) +{ + int err = 0; + // u8 val = 0; + + // err = tier4_fpga_read_reg(dev, FPGA_REG_MODE_ADDR, &val); + // if ((val & 0xFF) == FPGA_MODE_FREE_RUN) { + // // skip writing the same value to reg in order to save the flash write cycles + // dev_info(dev, "[%s] : Keep FSYNC mode disabled.\n", __func__); + // return err; + // } + + err = tier4_fpga_write_reg(dev, FPGA_REG_MODE_ADDR, FPGA_MODE_FREE_RUN); + if (err) { + dev_err(dev, "[%s] Disabling FSYNC mode failed.\n", __func__); + } +#ifdef DEBUG_INFO + else { + dev_info(dev, "[%s] Disabling FSYNC mode.\n", __func__); + } +#endif + return err; +} +EXPORT_SYMBOL(tier4_fpga_disable_fsync_mode); + +int tier4_fpga_set_fsync_auto_trigger(struct device *dev) +{ + int err = 0; + // u8 val = 0; + + // err = tier4_fpga_read_reg(dev, FPGA_REG_FSYNC_TRIG_ADDR, &val); + // if ((val & 0xFF) == FPGA_FSYNC_AUTO) { + // // skip writing the same value to reg in order to save the flash write cycles + // dev_info(dev, "[%s] : Keep FSYNC Auto Trigger mode.\n", __func__); + // return err; + // } + + err = tier4_fpga_write_reg(dev, FPGA_REG_FSYNC_TRIG_ADDR, + FPGA_FSYNC_AUTO); + if (err) { + dev_err(dev, "[%s] Enabling FSYNC Auto Trigger mode failed.\n", + __func__); + } +#ifdef DEBUG_INFO + else { + dev_info(dev, "[%s] Enabling FSYNC Auto Trigger mode.\n", + __func__); + } +#endif + return err; +} +EXPORT_SYMBOL(tier4_fpga_set_fsync_auto_trigger); + +int tier4_fpga_set_fsync_manual_trigger(struct device *dev) +{ + int err = 0; + // u8 val = 0; + + // err = tier4_fpga_read_reg(dev, FPGA_REG_FSYNC_TRIG_ADDR, &val); + // if ((val & 0xFF) == FPGA_FSYNC_MANUAL) { + // // skip writing the same value to reg in order to save the flash write cycles + // dev_info(dev, "[%s] : Keep FSYNC Auto Trigger mode.\n", __func__); + // return err; + // } + + err = tier4_fpga_write_reg(dev, FPGA_REG_FSYNC_TRIG_ADDR, + FPGA_FSYNC_MANUAL); + if (err) { + dev_err(dev, + "[%s] Enabling FSYNC Manual Trigger mode failed.\n", + __func__); + } +#ifdef DEBUG_INFO + else { + dev_info(dev, + "[%s] Enabling FSYNC Manual Trigger mode failed.\n", + __func__); + } +#endif + + return err; +} +EXPORT_SYMBOL(tier4_fpga_set_fsync_manual_trigger); + +// *************** + +int tier4_fpga_check_access(struct device *dev) +{ + int err = 0; + int i; + u8 dummy8 = 0; + + for (i = 0; i < 5; i++) { + err = tier4_fpga_read_reg(dev, FPGA_REG_VERSION_ADDR, &dummy8); + if (!err) { + break; + } + usleep_range(10000, 11000); // sleep 10 msec + } + + if (err) { + dev_err(dev, "[%s] Accessing FPGA failed.\n", __func__); + return err; + } + return NO_ERROR; +} +EXPORT_SYMBOL(tier4_fpga_check_access); + +static int tier4_fpga_get_fps_camx_camy(struct device *dev, int des_number, + int fps, int trigger_mode) +{ + int freq; + char str_fps_camx_camy[15] = "\0"; + +#ifdef DEBUG_INFO + dev_info(dev, "[%s] dns_number=%d trigger_mode=%de.\n", __func__, + des_number, trigger_mode); +#endif + + switch (des_number) { + case 0: + strcpy(str_fps_camx_camy, "fps_cam1_cam2"); + break; + case 1: + strcpy(str_fps_camx_camy, "fps_cam3_cam4"); + break; + case 2: + strcpy(str_fps_camx_camy, "fps_cam5_cam6"); + break; + case 3: + strcpy(str_fps_camx_camy, "fps_cam7_cam8"); + break; + default: + strcpy(str_fps_camx_camy, "fps_cam?_cam?"); + break; + } + + if (trigger_mode == 1) { + if ((fps > 5) && (fps <= 10)) { + freq = fps; + } else { + freq = FREQ_10HZ; + dev_info(dev, "[%s] Invalid %s:%d, Set %s to %d.", + __func__, str_fps_camx_camy, fps, + str_fps_camx_camy, freq); + } + } else if (trigger_mode == 3) { + if ((fps > 10) && (fps <= 20)) { + freq = fps; + } else { + freq = FREQ_20HZ; + dev_info(dev, "[%s] Invalid %s:%d, Set %s to %d.", + __func__, str_fps_camx_camy, fps, + str_fps_camx_camy, freq); + } + } else if (trigger_mode == 5) { + if ((fps > 20) && (fps <= 30)) { + freq = fps; + } else { + freq = FREQ_30HZ; + dev_info(dev, "[%s] Invalid %s:%d, Set %s to %d.", + __func__, str_fps_camx_camy, fps, + str_fps_camx_camy, freq); + } + } + +#ifdef DEBUG_INFO + dev_info(dev, "[%s] freq=%d.\n", __func__, freq); +#endif + + return freq; +} + +// -------------------------------------------- + +int tier4_fpga_set_fsync_signal_frequency(struct device *dev, int des_number, + int trigger_mode) +{ + int err = 0; + u8 val8, addr8; + int freq = 0; + // u8 read_val = 0; + u8 freq_bitmask = 0x3F; // bit[0:5] + + switch (des_number) { + case 0: + freq = tier4_fpga_get_fps_camx_camy( + dev, des_number, fps_cam1_cam2, trigger_mode); + break; + case 1: + freq = tier4_fpga_get_fps_camx_camy( + dev, des_number, fps_cam3_cam4, trigger_mode); + break; + case 2: + freq = tier4_fpga_get_fps_camx_camy( + dev, des_number, fps_cam5_cam6, trigger_mode); + break; + case 3: + freq = tier4_fpga_get_fps_camx_camy( + dev, des_number, fps_cam7_cam8, trigger_mode); + break; + default: + dev_err(dev, "[%s] Invalid des_number(%d)\n", __func__, + des_number); + break; + } + + addr8 = (u8)(FPGA_REG_FREQ_BASE_ADDR + 12 * (des_number)); + val8 = (u8)(freq & freq_bitmask); + +#ifdef DEBUG_INFO + dev_info(dev, "[%s] freq=%d.\n", __func__, freq); +#endif + + // err = tier4_fpga_read_reg(dev, addr8, &read_val); + // if ((read_val & freq_bitmask) == val8) { + // // skip writing the same value to reg in order to save the flash write cycles + // dev_info(dev, "[%s] : Keep the frequency of fsync trigger to %d\n", __func__, val8); + // return err; + // } + + err = tier4_fpga_write_reg(dev, addr8, val8); + + if (err) { + dev_err(dev, + "[%s] Setting the frequency of fsync trigger failed.\n", + __func__); + return err; + } else { + dev_info(dev, + "[%s] Setting the frequency of fsync trigger to %d.\n", + __func__, val8); + } + + return NO_ERROR; +} +EXPORT_SYMBOL(tier4_fpga_set_fsync_signal_frequency); + +int tier4_fpga_get_slave_addr(struct device *dev, + struct tier4_gmsl_link_ctx *g_ctx) +{ + struct tier4_fpga *priv = dev_get_drvdata(dev); + + if (!g_ctx) { + dev_err(dev, "[%s] g_ctx is null\n", __func__); + return -1; + } + + g_ctx->sdev_fpga_reg = priv->reg_addr; + + return 0; +} +EXPORT_SYMBOL(tier4_fpga_get_slave_addr); + +const struct of_device_id tier4_fpga_of_match[] = { + { + .compatible = "nvidia,tier4_fpga", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, tier4_fpga_of_match); + +// ----------------------------------------------------- + +static int tier4_fpga_parse_dt(struct tier4_fpga *priv, + struct i2c_client *client) +{ + struct device_node *node = client->dev.of_node; + int err = 0; + + if (!node) + return -EINVAL; + + err = of_property_read_u32(node, "reg", &priv->reg_addr); + if (err < 0) { + dev_err(&client->dev, "[%s] fpga reg not found\n", __func__); + return -EINVAL; + } + + priv->g_ctx.sdev_fpga_reg = priv->reg_addr; + + return NO_ERROR; +} + +// --------------------------------------------------------- + +static int tier4_fpga_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tier4_fpga *priv; + int err = 0; + int inhibit_fpga_access = 0; + + dev_info(&client->dev, "[%s] probing FPGA\n", __func__); + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + priv->i2c_client = client; + + priv->regmap = devm_regmap_init_i2c(priv->i2c_client, + &tier4_fpga_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&client->dev, "[%s] devm_regmap_init() failed: %ld\n", + __func__, PTR_ERR(priv->regmap)); + return -ENODEV; + } + + err = tier4_fpga_parse_dt(priv, client); + + if (err) { + dev_err(&client->dev, "[%s] Unable to parse fpga dt\n", + __func__); + return -EFAULT; + } + + mutex_init(&priv->lock); + + dev_set_drvdata(&client->dev, priv); + + err = tier4_fpga_check_access(&client->dev); + + if (err) { + inhibit_fpga_access = 1; + } + + // default mode is disabling gnereation of fsync + + err = tier4_fpga_disable_fsync_mode(&client->dev); + + if (err < 0) { + dev_err(&client->dev, + "[%s] Unable to disable generation of fsync.\n", + __func__); + if (inhibit_fpga_access) { + return NO_ERROR; + } else { + return -EINVAL; + } + } + + channel_count_fpga++; + + dev_info(&client->dev, "[%s] Probing FPGA succeeded.\n", __func__); + + return err; +} + +static int tier4_fpga_remove(struct i2c_client *client) +{ + struct tier4_fpga *priv; + + if (channel_count_fpga > 0) + channel_count_fpga--; + + if (client != NULL) { + priv = dev_get_drvdata(&client->dev); + mutex_destroy(&priv->lock); + } + + return 0; +} + +// ---------------------------------------------- + +static const struct i2c_device_id tier4_fpga_id[] = { + { "tier4_fpga", 0 }, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tier4_fpga_id); + +static struct i2c_driver tier4_fpga_i2c_driver = { + .driver = { + .name = "tier4_fpga", + .owner = THIS_MODULE, + }, + .probe = tier4_fpga_probe, + .remove = tier4_fpga_remove, + .id_table = tier4_fpga_id, +}; + +static int __init tier4_fpga_init(void) +{ + printk("FPGA Driver for Tier4 Cameras.\n"); + + return i2c_add_driver(&tier4_fpga_i2c_driver); +} + +static void __exit tier4_fpga_exit(void) +{ + i2c_del_driver(&tier4_fpga_i2c_driver); +} + +module_init(tier4_fpga_init); +module_exit(tier4_fpga_exit); + +MODULE_DESCRIPTION("FPGA driver tier4_fpga"); +MODULE_AUTHOR("Kohji Iwasaki"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-fpga.h b/src/tier4-camera-gmsl/tier4-fpga.h similarity index 83% rename from drivers/src/tier4-fpga.h rename to src/tier4-camera-gmsl/tier4-fpga.h index dc65fab..a34cef0 100644 --- a/drivers/src/tier4-fpga.h +++ b/src/tier4-camera-gmsl/tier4-fpga.h @@ -23,21 +23,21 @@ #define __TIER4_FPGA_H__ -#define FPGA_REG_MODE_ADDR 0x04 -#define FPGA_MODE_FREE_RUN 0xF0 // camera master mode, default 30 FPS -#define FPGA_MODE_FSYNC 0xFF // camera slave mode, triggered by FSYNC signal +#define FPGA_REG_MODE_ADDR 0x04 +#define FPGA_MODE_FREE_RUN 0xF0 // camera master mode, default 30 FPS +#define FPGA_MODE_FSYNC 0xFF // camera slave mode, triggered by FSYNC signal -#define FPGA_REG_FSYNC_TRIG_ADDR 0x05 -#define FPGA_FSYNC_MANUAL 0x00 // manually triggered by external GPIO -#define FPGA_FSYNC_AUTO 0xF0 // automatically triggered by FPGA itself +#define FPGA_REG_FSYNC_TRIG_ADDR 0x05 +#define FPGA_FSYNC_MANUAL 0x00 // manually triggered by external GPIO +#define FPGA_FSYNC_AUTO 0xF0 // automatically triggered by FPGA itself #define FPGA_FSYNC_MODE_DISABLE 0 -#define FPGA_FSYNC_MODE_AUTO 1 -#define FPGA_FSYNC_MODE_MANUAL 2 +#define FPGA_FSYNC_MODE_AUTO 1 +#define FPGA_FSYNC_MODE_MANUAL 2 #define NO_ERROR 0 -#define FPGA_REG_FREQ_BASE_ADDR 0x08 +#define FPGA_REG_FREQ_BASE_ADDR 0x08 #define FPGA_SLAVE_MODE_10FPS 10 #define FPGA_SLAVE_MODE_30FPS 30 @@ -130,7 +130,8 @@ int tier4_fpga_set_fsync_manual_trigger(struct device *dev); * @return 0 for success, or -1 otherwise. */ -int tier4_fpga_set_fsync_signal_frequency(struct device *dev, int des_number, int trigger_mode); +int tier4_fpga_set_fsync_signal_frequency(struct device *dev, int des_number, + int trigger_mode); /** * check access to FPGA. @@ -151,6 +152,7 @@ int tier4_fpga_check_access(struct device *dev); * @return 0 for success, or -1 otherwise. */ -int tier4_fpga_get_slave_addr(struct device *dev, struct tier4_gmsl_link_ctx *g_ctx); +int tier4_fpga_get_slave_addr(struct device *dev, + struct tier4_gmsl_link_ctx *g_ctx); #endif /* __TIER4_FPGA_H__ */ diff --git a/drivers/src/tier4-gmsl-link.h b/src/tier4-camera-gmsl/tier4-gmsl-link.h similarity index 61% rename from drivers/src/tier4-gmsl-link.h rename to src/tier4-camera-gmsl/tier4-gmsl-link.h index 8059589..7b297ed 100644 --- a/drivers/src/tier4-gmsl-link.h +++ b/src/tier4-camera-gmsl/tier4-gmsl-link.h @@ -71,48 +71,46 @@ /** * Holds information about a data stream in a GMSL link (\ref tier4_gmsl_link_ctx). */ -struct tier4_gmsl_stream -{ - __u32 st_id_sel; - __u32 st_data_type; - __u32 des_pipe; +struct tier4_gmsl_stream { + __u32 st_id_sel; + __u32 st_data_type; + __u32 des_pipe; }; /** * Holds the configuration of the GMSL links from a sensor to its serializer to * its deserializer. */ -struct tier4_gmsl_link_ctx -{ - __u32 st_vc; /**< Default sensor virtual channel. */ - __u32 dst_vc; /**< Destination virtual channel (user-defined). */ - __u32 src_csi_port; /**< Sensor to serializer CSI port connection. */ - __u32 dst_csi_port; /**< Deserializer to Jetson CSI port connection. */ - __u32 serdes_csi_link; /**< GMSL link between serializer and deserializer +struct tier4_gmsl_link_ctx { + __u32 st_vc; /**< Default sensor virtual channel. */ + __u32 dst_vc; /**< Destination virtual channel (user-defined). */ + __u32 src_csi_port; /**< Sensor to serializer CSI port connection. */ + __u32 dst_csi_port; /**< Deserializer to Jetson CSI port connection. */ + __u32 serdes_csi_link; /**< GMSL link between serializer and deserializer devices. */ - __u32 num_streams; /**< Number of active streams to be mapped + __u32 num_streams; /**< Number of active streams to be mapped from sensor. */ - __u32 num_csi_lanes; /**< Sensor's CSI lane configuration. */ - __u32 csi_mode; /**< Deserializer CSI mode. */ - __u32 ser_reg; /**< Serializer slave address. */ - __u32 sdev_reg; /**< Sensor proxy slave address. */ - __u32 sdev_def; /**< Sensor default slave address. */ - __u32 reg_mux; - bool serdev_found; /**< Indicates whether the serializer device for + __u32 num_csi_lanes; /**< Sensor's CSI lane configuration. */ + __u32 csi_mode; /**< Deserializer CSI mode. */ + __u32 ser_reg; /**< Serializer slave address. */ + __u32 sdev_reg; /**< Sensor proxy slave address. */ + __u32 sdev_def; /**< Sensor default slave address. */ + __u32 reg_mux; + bool serdev_found; /**< Indicates whether the serializer device for the specified sensor source was found. Set by the serializer driver during setup; used by the deserializer driver to choose certain configuration settings during setup. */ - struct tier4_gmsl_stream streams[GMSL_DEV_MAX_NUM_DATA_STREAMS]; - /*< An array of information about the data streams in the link. */ - __u32 sensor_id; /**< Sensor ID 21:isx021 or 490:imx490 */ - __u32 sdev_isp_reg; /**< Sensor or ISP proxy slave address. */ - __u32 sdev_isp_def; /**< Sensor or ISP default slave address. */ - __u32 sdev_fpga_reg; /**< FPGA default slave address. */ - struct device *s_dev; /**< Sensor device handle. */ - __u32 hardware_model; /**< ROScube, Xavier or Orin . */ -// bool fpga_generate_fsync; /**< Indicates whther FPGA generate fsync or not . */ -// int debug_i2c_write; /**< Debug flag for i2c write */ + struct tier4_gmsl_stream streams[GMSL_DEV_MAX_NUM_DATA_STREAMS]; + /*< An array of information about the data streams in the link. */ + __u32 sensor_id; /**< Sensor ID 21:isx021 or 490:imx490 */ + __u32 sdev_isp_reg; /**< Sensor or ISP proxy slave address. */ + __u32 sdev_isp_def; /**< Sensor or ISP default slave address. */ + __u32 sdev_fpga_reg; /**< FPGA default slave address. */ + struct device *s_dev; /**< Sensor device handle. */ + __u32 hardware_model; /**< ROScube, Xavier or Orin . */ + // bool fpga_generate_fsync; /**< Indicates whther FPGA generate fsync or not . */ + // int debug_i2c_write; /**< Debug flag for i2c write */ }; /** @} */ diff --git a/src/tier4-camera-gmsl/tier4-gw5300.c b/src/tier4-camera-gmsl/tier4-gw5300.c new file mode 100644 index 0000000..c28d743 --- /dev/null +++ b/src/tier4-camera-gmsl/tier4-gw5300.c @@ -0,0 +1,933 @@ +/* + * tier4_gw5300.c - tier4_gw5300 ISP driver + * + * Copyright (c) 2022-2023, TIER IV Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "tier4-gmsl-link.h" +#include "tier4-gw5300.h" + +struct tier4_gw5300 { + struct i2c_client *i2c_client; + struct tier4_gmsl_link_ctx g_client; + struct mutex lock; + /* primary ISP properties */ + __u32 def_addr; +}; + +#define MAX_CHANNEL_NUM 8 + +#define NO_ERROR 0 + +/* count channel,the max MAX_CHANNEL_NUM*/ +static __u32 channel_count_gw5300; + +static struct tier4_gw5300 *prim_priv__[MAX_CHANNEL_NUM]; + +static u8 master_30fps[] = { 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x6A }; + +static u8 master_10fps[] = { 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x00, 0x38 }; + +static u8 slave_10fps[] = { 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x42 }; + +static u8 master_20fps[] = { 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x5A, 0x00, 0x00, 0x00, 0x74 }; + +static u8 slave_20fps[] = { 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x5F, 0x00, 0x00, 0x00, 0x79 }; + +static u8 slave_30fps[] = { 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x55, 0x00, 0x00, 0x00, 0x6F }; + +static u8 master_10fps_slow[] = { 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x17 }; + +static u8 slave_10fps_slow[] = { 0x33, 0x47, 0x0B, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x00, 0x4B, 0x00, 0x00, 0x00, 0x65 }; + +/* + * C3 camera mode support + */ +struct mode_command { + u8 *command; + size_t len; + unsigned int delay_ms; +}; + +#define MODE_CMD(cmd, delay) \ + { \ + .command = (cmd), .len = sizeof(cmd), .delay_ms = delay, \ + } + +#define NUM_VA_ARGS(type, ...) (sizeof((type[]){ __VA_ARGS__ }) / sizeof(type)) + +#define MODE_SEQ(h_line_time_ns, ...) \ + { \ + .commands = (struct mode_command[]){ __VA_ARGS__ }, \ + .len = NUM_VA_ARGS(struct mode_command, __VA_ARGS__), \ + .h_line_ns = (h_line_time_ns) \ + } + +struct mode_sequence { + struct mode_command *commands; + size_t len; + u32 h_line_ns; +}; + +/* + * C3 preset modes + */ + +static u8 c3_master_5fps_cmd[] = { 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, + 0x12, 0x0, 0x80, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x17 }; + +/* mode 0 */ +static struct mode_sequence c3_master_5fps_seq = + MODE_SEQ(40000, MODE_CMD(c3_master_5fps_cmd, 0), ); + +/* mode 4 */ +static u8 c3_master_20fps_cmd[] = { 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, + 0x12, 0x0, 0x80, 0x3, 0x0, 0x0, + 0x0, 0x4b, 0x0, 0x0, 0x0, 0x65 }; +static struct mode_sequence c3_master_20fps_seq = + MODE_SEQ(20000, MODE_CMD(c3_master_20fps_cmd, 0)); + +static u8 c3_master_20fps_ebd_cmd[] = { 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, + 0x12, 0x0, 0x80, 0x3, 0x0, 0x0, + 0x0, 0x50, 0x0, 0x0, 0x0, 0x6a }; + +/* mode 10 */ +static struct mode_sequence c3_master_20fps_ebd_seq = + MODE_SEQ(20000, MODE_CMD(c3_master_20fps_ebd_cmd, 0)); + +static u8 c3_master_30fps_cmd[] = { 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, + 0x12, 0x0, 0x80, 0x3, 0x0, 0x0, + 0x0, 0x1e, 0x0, 0x0, 0x0, 0x38 }; + +/* mode 6 */ +static struct mode_sequence c3_master_30fps_seq = + MODE_SEQ(13890, MODE_CMD(c3_master_30fps_cmd, 0)); + +static u8 c3_master_30fps_ebd_cmd[] = { 0x33, 0x47, 0xb, 0x0, 0x0, 0x0, + 0x12, 0x0, 0x80, 0x3, 0x0, 0x0, + 0x0, 0x28, 0x0, 0x0, 0x0, 0x42 }; + +/* mode 12 */ +static struct mode_sequence c3_master_30fps_ebd_seq = + MODE_SEQ(13890, MODE_CMD(c3_master_30fps_ebd_cmd, 0)); + +/* + * C3 derived modes + */ +static u8 c3_regmap_ffff[] = { 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, + 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, + 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x2, 0x1, 0x25 }; + +static u8 c3_standby_mode[] = { 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, + 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, + 0x0, 0x0, 0x0, 0x4, 0x1b, 0x0, 0x0, + 0xff, 0x0, 0x0, 0x0, 0x2, 0x1, 0x45 }; + +static u8 c3_drive_mode_sel[] = { 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, + 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, + 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, + 0x1, 0x0, 0x0, 0x0, 0x2, 0x1, 0x68 }; + +static u8 c3_master_sync_mode[] = { 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, + 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, + 0x0, 0x0, 0x0, 0x41, 0x0, 0x0, 0x0, + 0x5, 0x0, 0x0, 0x0, 0x2, 0x1, 0x6d }; + +static u8 c3_sensor_streaming[] = { 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, + 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, + 0x0, 0x0, 0x0, 0x4, 0x1b, 0x0, 0x0, + 0x5c, 0x0, 0x0, 0x0, 0x2, 0x1, 0xa2 }; + +static u8 c3_master_sync_mode_2[] = { 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, + 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x34, + 0x0, 0x0, 0x0, 0x4, 0x1b, 0x0, 0x0, + 0xa3, 0x0, 0x0, 0x0, 0x2, 0x1, 0xe9 }; + +/* mode 1 */ +static struct mode_sequence c3_slave_5fps_seq = MODE_SEQ( + 40000, MODE_CMD(c3_master_5fps_cmd, 5000), + + MODE_CMD(c3_regmap_ffff, 500), MODE_CMD(c3_standby_mode, 500), + MODE_CMD(c3_drive_mode_sel, 500), MODE_CMD(c3_master_sync_mode, 500), + MODE_CMD(c3_sensor_streaming, 500), + MODE_CMD(c3_master_sync_mode_2, 500), ); + +static u8 c3_20_to_10fps_cmd_1[] = { + 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, + 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x50, 0x97, 0x0, + 0x0, 0xc4, 0x0, 0x0, 0x0, 0x2, 0x1, 0xd2, +}; + +static u8 c3_20_to_10fps_cmd_2[] = { + 0x33, 0x47, 0x15, 0x0, 0x0, 0x0, 0xe0, 0x0, 0x80, 0x1, + 0x0, 0x0, 0x0, 0x34, 0x0, 0x0, 0x0, 0x51, 0x97, 0x0, + 0x0, 0x09, 0x0, 0x0, 0x0, 0x2, 0x1, 0x18, +}; + +/* mode 2 */ +static struct mode_sequence c3_master_10fps_seq = + MODE_SEQ(20000, MODE_CMD(c3_master_20fps_cmd, 5000), + + MODE_CMD(c3_20_to_10fps_cmd_1, 2000), + MODE_CMD(c3_20_to_10fps_cmd_2, 500), ); + +/* mode 3 */ +static struct mode_sequence c3_slave_10fps_seq = MODE_SEQ( + 20000, MODE_CMD(c3_master_20fps_cmd, 5000), + + MODE_CMD(c3_20_to_10fps_cmd_1, 2000), + MODE_CMD(c3_20_to_10fps_cmd_2, 500), + + MODE_CMD(c3_regmap_ffff, 500), MODE_CMD(c3_standby_mode, 500), + MODE_CMD(c3_drive_mode_sel, 500), MODE_CMD(c3_master_sync_mode, 500), + MODE_CMD(c3_sensor_streaming, 500), + MODE_CMD(c3_master_sync_mode_2, 500), ); + +/* mode 5 */ +static struct mode_sequence c3_slave_20fps_seq = MODE_SEQ( + 20000, MODE_CMD(c3_master_20fps_cmd, 5000), + + MODE_CMD(c3_regmap_ffff, 500), MODE_CMD(c3_standby_mode, 500), + MODE_CMD(c3_drive_mode_sel, 500), MODE_CMD(c3_master_sync_mode, 500), + MODE_CMD(c3_sensor_streaming, 500), + MODE_CMD(c3_master_sync_mode_2, 500), ); + +/* mode 7 */ +static struct mode_sequence c3_slave_30fps_seq = MODE_SEQ( + 13890, MODE_CMD(c3_master_30fps_cmd, 5000), + + MODE_CMD(c3_regmap_ffff, 500), MODE_CMD(c3_standby_mode, 500), + MODE_CMD(c3_drive_mode_sel, 500), MODE_CMD(c3_master_sync_mode, 500), + MODE_CMD(c3_sensor_streaming, 500), + MODE_CMD(c3_master_sync_mode_2, 500), ); + +/* mode 8 */ +static struct mode_sequence c3_master_10fps_ebd_seq = + MODE_SEQ(20000, MODE_CMD(c3_master_20fps_ebd_cmd, 5000), + + MODE_CMD(c3_20_to_10fps_cmd_1, 2000), + MODE_CMD(c3_20_to_10fps_cmd_2, 500), ); + +/* mode 9 */ +static struct mode_sequence c3_slave_10fps_ebd_seq = MODE_SEQ( + 20000, MODE_CMD(c3_master_20fps_ebd_cmd, 5000), + + MODE_CMD(c3_20_to_10fps_cmd_1, 2000), + MODE_CMD(c3_20_to_10fps_cmd_2, 500), + + MODE_CMD(c3_regmap_ffff, 500), MODE_CMD(c3_standby_mode, 500), + MODE_CMD(c3_drive_mode_sel, 500), MODE_CMD(c3_master_sync_mode, 500), + MODE_CMD(c3_sensor_streaming, 500), + MODE_CMD(c3_master_sync_mode_2, 500), ); + +/* mode 11 */ +static struct mode_sequence c3_slave_20fps_ebd_seq = MODE_SEQ( + 20000, MODE_CMD(c3_master_20fps_ebd_cmd, 5000), + + MODE_CMD(c3_20_to_10fps_cmd_1, 2000), + MODE_CMD(c3_20_to_10fps_cmd_2, 500), + + MODE_CMD(c3_regmap_ffff, 500), MODE_CMD(c3_standby_mode, 500), + MODE_CMD(c3_drive_mode_sel, 500), MODE_CMD(c3_master_sync_mode, 500), + MODE_CMD(c3_sensor_streaming, 500), + MODE_CMD(c3_master_sync_mode_2, 500), ); + +/* mode 13 */ +static struct mode_sequence c3_slave_30fps_ebd_seq = MODE_SEQ( + 13890, MODE_CMD(c3_master_30fps_ebd_cmd, 5000), + + MODE_CMD(c3_20_to_10fps_cmd_1, 2000), + MODE_CMD(c3_20_to_10fps_cmd_2, 500), + + MODE_CMD(c3_regmap_ffff, 500), MODE_CMD(c3_standby_mode, 500), + MODE_CMD(c3_drive_mode_sel, 500), MODE_CMD(c3_master_sync_mode, 500), + MODE_CMD(c3_sensor_streaming, 500), + MODE_CMD(c3_master_sync_mode_2, 500), ); + +static struct mode_sequence c3_mode_seqs[GW5300_MODE_MAX]; + +struct map_ctx { + u8 dt; + u16 addr; + u8 val; + u8 st_id; +}; + +#if 0 +static int tier4_gw5300_receive_msg(struct device *dev, u8 *data, int data_size ) +{ + int err = 0; + struct i2c_msg msg; + struct tier4_gw5300 *priv = dev_get_drvdata(dev); + + msg.addr = priv->i2c_client->addr; + msg.flags = I2C_M_RD; // I2C Read + msg.len = data_size; + msg.buf = data; + + err = i2c_transfer(priv->i2c_client->adapter, &msg, 1); + + if (err <= 0 ) { + dev_err(dev, "[%s] : i2c_transer receive message failed : slave addr = 0x%x\n", __func__, msg.addr ); + } + + return err; +} +#endif + +// ------------------------------------------------------------------- + +static int tier4_gw5300_send_and_recv_msg(struct device *dev, u8 *wdata, + int wdata_size, u8 *rdata, + int rdata_size) +{ + int err = 0; + struct i2c_msg msg[2]; + struct tier4_gw5300 *priv = dev_get_drvdata(dev); + + msg[0].addr = priv->i2c_client->addr; + msg[0].flags = 0; // I2C Write + msg[0].len = wdata_size; + msg[0].buf = wdata; + + msg[1].addr = priv->i2c_client->addr; + msg[1].flags = I2C_M_RD; // I2C Read + msg[1].len = rdata_size; + msg[1].buf = rdata; + + err = i2c_transfer(priv->i2c_client->adapter, msg, 2); + + if (err <= 0) { + dev_err(dev, + "[%s] : i2c_transer send message failed. %d: slave addr = 0x%x\n", + __func__, err, msg[0].addr); + } + + return err; // the total number of bytes to have been sent or recived +} + +// ------------------------------------------------------------------- + +static int tier4_gw5300_c3_send_and_recv_msg(struct device *dev, u8 *wdata, + int wdata_size, u8 *rdata, + int rdata_size) +{ + return tier4_gw5300_send_and_recv_msg(dev, wdata, wdata_size, rdata, + rdata_size); +} + +static int +tier4_gw5300_mode_seq_send_and_recv_msg(struct device *dev, + struct mode_sequence *mode_seq, + u8 *rdata, int rdata_size) +{ + int i; + int err = 0; + + for (i = 0; i < mode_seq->len; ++i) { + struct mode_command *cmd = &mode_seq->commands[i]; + + err = tier4_gw5300_send_and_recv_msg( + dev, cmd->command, cmd->len, rdata, rdata_size); + msleep(cmd->delay_ms); + if (err < 0) { + dev_err(dev, "%s: Failed to send a command[%d]: %d\n", + __func__, i, err); + break; + } + } + + return err; +} + +// ------------------------------------------------------------------- + +uint8_t calcCheckSum(const uint8_t *data, size_t size) +{ + uint8_t result = 0; + size_t i = 0; + for (i = 0; i < size; i++) { + result += data[i]; + } + return result; +} + +int tier4_gw5300_set_integration_time_on_aemode(struct device *dev, + u32 h_line_ns, + u32 max_integration_time, + u32 min_integration_time) +{ + u8 buf[6]; + int ret = 0; + + u8 cmd_integration_max[22] = { + 0x33, 0x47, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x80, 0x05, 0x00, 0x15, 0x00, 0x01, 0x00, 0x04, + 0x00, 0x70, 0x03, 0x00, 0x00, 0x00 + }; // val = 0x70, 0x03, 0x00, 0x00 + u8 cmd_integration_min[20] = { + 0x33, 0x47, 0x0d, 0x00, 0x00, 0x00, 0x55, 0x00, 0x80, 0x05, + 0x00, 0x21, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x03, 0x00 + }; //val = 0x70, 0x03 + + const size_t max_val_pos = 17; + const size_t min_val_pos = 17; + uint32_t min_line = + DIV_ROUND_CLOSEST(min_integration_time * 1000, h_line_ns); + uint32_t max_line = + DIV_ROUND_CLOSEST(max_integration_time * 1000, h_line_ns); + uint8_t b1 = max_line & 0xFF; + uint8_t b2 = (max_line >> 8) & 0xFF; + uint8_t b3 = 0; + uint8_t b4 = 0; + + dev_info( + dev, + "%s: integration time(%u[ns/H line]): max=(%d[us], %d[line]) min=(%d[us], %d[line])\n", + __func__, h_line_ns, max_integration_time, max_line, + min_integration_time, min_line); + + cmd_integration_max[max_val_pos] = b1; + cmd_integration_max[max_val_pos + 1] = b2; + cmd_integration_max[max_val_pos + 2] = b3; + cmd_integration_max[max_val_pos + 3] = b4; + cmd_integration_max[sizeof(cmd_integration_max) - 1] = + calcCheckSum(cmd_integration_max, sizeof(cmd_integration_max)); + + b1 = min_line & 0xFF; + b2 = (min_line >> 8) & 0xFF; + + cmd_integration_min[min_val_pos] = b1; + cmd_integration_min[min_val_pos + 1] = b2; + + cmd_integration_min[sizeof(cmd_integration_min) - 1] = + calcCheckSum(cmd_integration_min, sizeof(cmd_integration_min)); + + msleep(20); + ret += tier4_gw5300_send_and_recv_msg(dev, cmd_integration_max, + sizeof(cmd_integration_max), buf, + sizeof(buf)); + msleep(20); + ret += tier4_gw5300_send_and_recv_msg(dev, cmd_integration_min, + sizeof(cmd_integration_min), buf, + sizeof(buf)); + + return ret; +} + +int tier4_gw5300_c2_set_integration_time_on_aemode(struct device *dev, + int trigger_mode, + u32 max_integration_time, + u32 min_integration_time) +{ + size_t h_line_ns = 12500; + + if (trigger_mode == GW5300_MASTER_MODE_10FPS_SLOW || + trigger_mode == GW5300_SLAVE_MODE_10FPS_SLOW) + h_line_ns = 50000; + + return tier4_gw5300_set_integration_time_on_aemode( + dev, h_line_ns, max_integration_time, min_integration_time); +} +EXPORT_SYMBOL(tier4_gw5300_c2_set_integration_time_on_aemode); + +int tier4_gw5300_c3_set_integration_time_on_aemode(struct device *dev, + int trigger_mode, + u32 max_integration_time, + u32 min_integration_time) +{ + return tier4_gw5300_set_integration_time_on_aemode( + dev, c3_mode_seqs[trigger_mode].h_line_ns, max_integration_time, + min_integration_time); +} +EXPORT_SYMBOL(tier4_gw5300_c3_set_integration_time_on_aemode); + +// ------------------------------------------------------------------ + +int tier4_gw5300_set_distortion_correction(struct device *dev, bool val) +{ + int ret = 0; + u8 buf[6]; + u8 cmd_dwp_on[] = { 0x33, 0x47, 0x06, 0x00, 0x00, 0x00, 0x4d, + 0x00, 0x80, 0x04, 0x00, 0x01, 0x52 }; + u8 cmd_dwp_off[] = { 0x33, 0x47, 0x03, 0x00, 0x00, + 0x00, 0x45, 0x00, 0x80, 0x42 }; + + if (val) { + ret += tier4_gw5300_send_and_recv_msg( + dev, cmd_dwp_on, sizeof(cmd_dwp_on), buf, sizeof(buf)); + } else { + ret += tier4_gw5300_send_and_recv_msg(dev, cmd_dwp_off, + sizeof(cmd_dwp_off), buf, + sizeof(buf)); + } + return ret; +} +EXPORT_SYMBOL(tier4_gw5300_set_distortion_correction); + +// ------------------------------------------------------------------ + +int tier4_gw5300_c3_set_distortion_correction(struct device *dev, bool val) +{ + int ret = 0; + u8 buf[6]; + u8 cmd_dwp_on[] = { 0x33, 0x47, 0x6, 0x00, 0x00, 0x00, 0x4d, + 0x00, 0x80, 0x04, 0x00, 0x01, 0x52 }; + u8 cmd_dwp_off[] = { 0x33, 0x47, 0x3, 0x00, 0x00, + 0x00, 0x45, 0x00, 0x80, 0x042 }; + + if (val) { + ret += tier4_gw5300_c3_send_and_recv_msg( + dev, cmd_dwp_on, sizeof(cmd_dwp_on), buf, sizeof(buf)); + } else { + ret += tier4_gw5300_c3_send_and_recv_msg(dev, cmd_dwp_off, + sizeof(cmd_dwp_off), + buf, sizeof(buf)); + } + return ret; +} +EXPORT_SYMBOL(tier4_gw5300_c3_set_distortion_correction); + +// ------------------------------------------------------------------ + +int tier4_gw5300_c3_set_auto_exposure(struct device *dev, bool val) +{ + int ret = 0; + u8 buf[6]; + u8 cmd_auto_exp_on[] = { 0x33, 0x47, 0x0C, 0x00, 0x00, 0x00, 0x55, + 0x00, 0x80, 0x05, 0x00, 0x07, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x00, 0x69 }; + u8 cmd_auto_exp_off[] = { 0x33, 0x47, 0x0C, 0x00, 0x00, 0x00, 0x55, + 0x00, 0x80, 0x05, 0x00, 0x07, 0x00, 0x01, + 0x00, 0x01, 0x00, 0x01, 0x6A }; + + dev_info(dev, "%s: auto exposure is %s\n", __func__, + val ? "on" : "off"); + + if (val) { + ret += tier4_gw5300_c3_send_and_recv_msg( + dev, cmd_auto_exp_on, sizeof(cmd_auto_exp_on), buf, + sizeof(buf)); + } else { + ret += tier4_gw5300_c3_send_and_recv_msg( + dev, cmd_auto_exp_off, sizeof(cmd_auto_exp_off), buf, + sizeof(buf)); + } + return ret; +} +EXPORT_SYMBOL(tier4_gw5300_c3_set_auto_exposure); + +// ------------------------------------------------------------------ + +int tier4_gw5300_check_device(struct device *dev, u8 *rdata, int rdata_size) +{ + int err = 0; + struct i2c_msg msg[2]; + struct tier4_gw5300 *priv = dev_get_drvdata(dev); + + msg[0].addr = priv->i2c_client->addr; + msg[0].flags = I2C_M_RD; // I2C Read + msg[0].len = rdata_size; + msg[0].buf = rdata; + + err = i2c_transfer(priv->i2c_client->adapter, msg, 1); + + if (err <= 0) { + dev_err(dev, + "[%s] : i2c_transer send message failed. : slave addr = 0x%x\n", + __func__, msg[0].addr); + } else { + err = NO_ERROR; + } + + return err; +} +EXPORT_SYMBOL(tier4_gw5300_check_device); + +int tier4_gw5300_prim_slave_addr(struct tier4_gmsl_link_ctx *g_ctx) +{ + if (!g_ctx) { + dev_err(&prim_priv__[channel_count_gw5300 - 1]->i2c_client->dev, + "[%s] : Failed. g_ctx is null\n", __func__); + return -1; + } + + g_ctx->sdev_isp_def = prim_priv__[channel_count_gw5300 - 1]->def_addr; + + return 0; +} +EXPORT_SYMBOL(tier4_gw5300_prim_slave_addr); + +int tier4_gw5300_setup_sensor_mode(struct device *dev, int sensor_mode) +{ + int err = 0; + u8 buf[6]; + + memset(buf, 0x00, 6); + + switch (sensor_mode) { + case GW5300_MASTER_MODE_10FPS: + err = tier4_gw5300_send_and_recv_msg(dev, master_10fps, + sizeof(master_10fps), buf, + sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up Master mode 10fps failed. %d message has been sent to gw5300.\n", + __func__, err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up Master mode 10fps failed. %d message has been sent to gw5300.\n", + __func__, err); + err = -999; + goto error; + } else { + err = 0; + } + break; + + case GW5300_SLAVE_MODE_10FPS: + err = tier4_gw5300_send_and_recv_msg(dev, slave_10fps, + sizeof(slave_10fps), buf, + sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up Slave mode 10fps failed. %d message has been sent to gw5300.\n", + __func__, err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up Slave mode 10fps failed. %d message has been sent to gw5300.\n", + __func__, err); + err = -999; + goto error; + } else { + err = 0; + } + break; + case GW5300_MASTER_MODE_20FPS: + err = tier4_gw5300_send_and_recv_msg(dev, master_20fps, + sizeof(master_20fps), buf, + sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up Master mode 20fps failed. %d message has been sent to gw5300.\n", + __func__, err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up Master mode 20fps failed. %d message has been sent to gw5300.\n", + __func__, err); + err = -999; + goto error; + } else { + err = 0; + } + break; + case GW5300_SLAVE_MODE_20FPS: + err = tier4_gw5300_send_and_recv_msg(dev, slave_20fps, + sizeof(slave_20fps), buf, + sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up Slave mode 20fps failed. %d message has been sent to gw5300.\n", + __func__, err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up Slave mode 20fps failed. %d message has been sent to gw5300.\n", + __func__, err); + err = -999; + goto error; + } else { + err = 0; + } + break; + case GW5300_MASTER_MODE_30FPS: + err = tier4_gw5300_send_and_recv_msg(dev, master_30fps, + sizeof(master_30fps), buf, + sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up Master mode 30fps failed. %d message has been sent to gw5300.\n", + __func__, err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up Master mode 30fps failed. %d message has been sent to gw5300.\n", + __func__, err); + err = -999; + goto error; + } else { + err = 0; + } + break; + + case GW5300_SLAVE_MODE_30FPS: + err = tier4_gw5300_send_and_recv_msg(dev, slave_30fps, + sizeof(slave_30fps), buf, + sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up Slave mode 30fps failed. %d message has been sent to gw5300.\n", + __func__, err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up Slave mode 30fps failed. %d message has been sent to gw5300.\n", + __func__, err); + err = -999; + goto error; + } else { + err = 0; + } + break; + case GW5300_MASTER_MODE_10FPS_SLOW: + err = tier4_gw5300_send_and_recv_msg(dev, master_10fps_slow, + sizeof(master_10fps_slow), + buf, sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up Slow clock Master mode 10fps failed. %d message has been sent to gw5300.\n", + __func__, err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up Slow clock Master mode 10fps failed. %d message has been sent to gw5300.\n", + __func__, err); + err = -999; + goto error; + } else { + err = 0; + } + break; + case GW5300_SLAVE_MODE_10FPS_SLOW: + err = tier4_gw5300_send_and_recv_msg(dev, slave_10fps_slow, + sizeof(slave_10fps_slow), + buf, sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up Slow clock Slave mode 10fps failed. %d message has been sent to gw5300.\n", + __func__, err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up Slow clock Slave mode 10fps failed. %d message has been sent to gw5300.\n", + __func__, err); + err = -999; + goto error; + } else { + err = 0; + } + break; + default: + break; + } + +error: + + return err; +} +EXPORT_SYMBOL(tier4_gw5300_setup_sensor_mode); + +// ----------- for C3 camera ---------- + +int tier4_gw5300_c3_setup_sensor_mode(struct device *dev, int sensor_mode) +{ + int err = 0; + u8 buf[6]; + + memset(buf, 0x00, 6); + + switch (sensor_mode) { + case GW5300_MASTER_MODE_10FPS: + case GW5300_SLAVE_MODE_10FPS: + case GW5300_MASTER_MODE_20FPS: + case GW5300_SLAVE_MODE_20FPS: + case GW5300_MASTER_MODE_30FPS: + case GW5300_SLAVE_MODE_30FPS: + case GW5300_MASTER_MODE_5FPS: + case GW5300_SLAVE_MODE_5FPS: + case GW5300_MASTER_MODE_10FPS_EBD: + case GW5300_SLAVE_MODE_10FPS_EBD: + case GW5300_MASTER_MODE_20FPS_EBD: + case GW5300_SLAVE_MODE_20FPS_EBD: + case GW5300_MASTER_MODE_30FPS_EBD: + case GW5300_SLAVE_MODE_30FPS_EBD: + err = tier4_gw5300_mode_seq_send_and_recv_msg( + dev, &c3_mode_seqs[sensor_mode], buf, sizeof(buf)); + if (err < 0) { + dev_err(dev, + "[%s] : Setting up %s failed. %d message has been sent to gw5300.\n", + __func__, gw5300_mode_name[sensor_mode], err); + goto error; + } else if (err == 0) { // it means that 0 message has been sent. + dev_err(dev, + "[%s] : Setting up %s failed. %d message has been sent to gw5300.\n", + __func__, gw5300_mode_name[sensor_mode], err); + err = -999; + goto error; + } else { + err = 0; + } + break; + default: + break; + } + +error: + + return err; +} +EXPORT_SYMBOL(tier4_gw5300_c3_setup_sensor_mode); + +static int tier4_gw5300_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tier4_gw5300 *priv; + int err = 0; + struct device_node *node = client->dev.of_node; + + dev_info(&client->dev, "[%s] : probing GW5300 ISP\n", __func__); + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + priv->i2c_client = client; + + mutex_init(&priv->lock); + + if (of_get_property(node, "is-prim-isp", NULL)) { + if (prim_priv__[channel_count_gw5300] && + channel_count_gw5300 >= MAX_CHANNEL_NUM) { + dev_err(&client->dev, + "[%s] : prim-isp already exists\n", __func__); + return -EEXIST; + } + + err = of_property_read_u32(node, "reg", &priv->def_addr); + if (err < 0) { + dev_err(&client->dev, "[%s] : reg not found\n", + __func__); + return -EINVAL; + } + + prim_priv__[channel_count_gw5300] = priv; + channel_count_gw5300++; + } + + dev_set_drvdata(&client->dev, priv); + + /* dev communication gets validated when GMSL link setup is done */ + dev_info(&client->dev, "[%s] : Probing succeeded\n", __func__); + + return err; +} + +static int tier4_gw5300_remove(struct i2c_client *client) +{ + struct tier4_gw5300 *priv; + + if (channel_count_gw5300 > 0) + channel_count_gw5300--; + + if (client != NULL) { + priv = dev_get_drvdata(&client->dev); + mutex_destroy(&priv->lock); + } + + return 0; +} + +static const struct i2c_device_id tier4_gw5300_id[] = { + { "tier4_gw5300", 0 }, + {}, +}; + +const struct of_device_id tier4_gw5300_of_match[] = { + { + .compatible = "nvidia,tier4_gw5300", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, tier4_gw5300_of_match); +MODULE_DEVICE_TABLE(i2c, tier4_gw5300_id); + +static struct i2c_driver tier4_gw5300_i2c_driver = { + .driver = { + .name = "tier4_gw5300", + .owner = THIS_MODULE, + }, + .probe = tier4_gw5300_probe, + .remove = tier4_gw5300_remove, + .id_table = tier4_gw5300_id, +}; + +static int __init tier4_gw5300_init(void) +{ + printk(KERN_INFO "ISP Driver for TIERIV Camera.\n"); + + c3_mode_seqs[GW5300_MASTER_MODE_5FPS] = c3_master_5fps_seq; + c3_mode_seqs[GW5300_SLAVE_MODE_5FPS] = c3_slave_5fps_seq; + + c3_mode_seqs[GW5300_MASTER_MODE_10FPS] = c3_master_10fps_seq; + c3_mode_seqs[GW5300_MASTER_MODE_10FPS_EBD] = c3_master_10fps_ebd_seq; + c3_mode_seqs[GW5300_SLAVE_MODE_10FPS] = c3_slave_10fps_seq; + c3_mode_seqs[GW5300_SLAVE_MODE_10FPS_EBD] = c3_slave_10fps_ebd_seq; + + c3_mode_seqs[GW5300_MASTER_MODE_20FPS] = c3_master_20fps_seq; + c3_mode_seqs[GW5300_MASTER_MODE_20FPS_EBD] = c3_master_20fps_ebd_seq; + c3_mode_seqs[GW5300_SLAVE_MODE_20FPS] = c3_slave_20fps_seq; + c3_mode_seqs[GW5300_SLAVE_MODE_20FPS_EBD] = c3_slave_20fps_ebd_seq; + + c3_mode_seqs[GW5300_MASTER_MODE_30FPS] = c3_master_30fps_seq; + c3_mode_seqs[GW5300_MASTER_MODE_30FPS_EBD] = c3_master_30fps_ebd_seq; + c3_mode_seqs[GW5300_SLAVE_MODE_30FPS] = c3_slave_30fps_seq; + c3_mode_seqs[GW5300_SLAVE_MODE_30FPS_EBD] = c3_slave_30fps_ebd_seq; + + return i2c_add_driver(&tier4_gw5300_i2c_driver); +} + +static void __exit tier4_gw5300_exit(void) +{ + i2c_del_driver(&tier4_gw5300_i2c_driver); +} + +module_init(tier4_gw5300_init); +module_exit(tier4_gw5300_exit); + +MODULE_DESCRIPTION("GW5300 ISP driver tier4_gw5300"); +MODULE_AUTHOR("Kohji Iwasaki"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-gw5300.h b/src/tier4-camera-gmsl/tier4-gw5300.h similarity index 61% rename from drivers/src/tier4-gw5300.h rename to src/tier4-camera-gmsl/tier4-gw5300.h index 10ebec9..4fb7353 100644 --- a/drivers/src/tier4-gw5300.h +++ b/src/tier4-camera-gmsl/tier4-gw5300.h @@ -22,40 +22,40 @@ #define __TIER4_GW5300_H__ #define GW5300_MASTER_MODE_10FPS 0 -#define GW5300_SLAVE_MODE_10FPS 1 +#define GW5300_SLAVE_MODE_10FPS 1 #define GW5300_MASTER_MODE_20FPS 2 -#define GW5300_SLAVE_MODE_20FPS 3 +#define GW5300_SLAVE_MODE_20FPS 3 #define GW5300_MASTER_MODE_30FPS 4 -#define GW5300_SLAVE_MODE_30FPS 5 -#define GW5300_SLAVE_MODE_10FPS_SLOW 6 +#define GW5300_SLAVE_MODE_30FPS 5 +#define GW5300_SLAVE_MODE_10FPS_SLOW 6 #define GW5300_MASTER_MODE_10FPS_SLOW 7 #define GW5300_MASTER_MODE_5FPS 8 #define GW5300_SLAVE_MODE_5FPS 9 #define GW5300_MASTER_MODE_10FPS_EBD 10 -#define GW5300_SLAVE_MODE_10FPS_EBD 11 +#define GW5300_SLAVE_MODE_10FPS_EBD 11 #define GW5300_MASTER_MODE_20FPS_EBD 12 -#define GW5300_SLAVE_MODE_20FPS_EBD 13 +#define GW5300_SLAVE_MODE_20FPS_EBD 13 #define GW5300_MASTER_MODE_30FPS_EBD 14 -#define GW5300_SLAVE_MODE_30FPS_EBD 15 +#define GW5300_SLAVE_MODE_30FPS_EBD 15 #define GW5300_MODE_MAX 16 -const char * const gw5300_mode_name[] = { - [GW5300_MASTER_MODE_10FPS] = "Master mode 10FPS", - [GW5300_SLAVE_MODE_10FPS] = "Slave mode 10FPS", - [GW5300_MASTER_MODE_20FPS] = "Master mode 20FPS", - [GW5300_SLAVE_MODE_20FPS] = "Slave mode 20FPS", - [GW5300_MASTER_MODE_30FPS] = "Master mode 30FPS", - [GW5300_SLAVE_MODE_30FPS] = "Slave mode 30FPS", - [GW5300_MASTER_MODE_10FPS_SLOW] = "Master mode 10FPS Slow", - [GW5300_SLAVE_MODE_10FPS_SLOW] = "Slave mode 10FPS Slow", - [GW5300_MASTER_MODE_5FPS] = "Master mode 5FPS", - [GW5300_SLAVE_MODE_5FPS] = "Slave mode 5FPS", - [GW5300_MASTER_MODE_10FPS_EBD] = "Master mode 10FPS with EBD", - [GW5300_SLAVE_MODE_10FPS_EBD] = "Slave mode 10FPS with EBD", - [GW5300_MASTER_MODE_20FPS_EBD] = "Master mode 20FPS with EBD", - [GW5300_SLAVE_MODE_20FPS_EBD] = "Slave mode 20FPS with EBD", - [GW5300_MASTER_MODE_30FPS_EBD] = "Master mode 30FPS with EBD", - [GW5300_SLAVE_MODE_30FPS_EBD] = "Slave mode 30FPS with EBD", +const char *const gw5300_mode_name[] = { + [GW5300_MASTER_MODE_10FPS] = "Master mode 10FPS", + [GW5300_SLAVE_MODE_10FPS] = "Slave mode 10FPS", + [GW5300_MASTER_MODE_20FPS] = "Master mode 20FPS", + [GW5300_SLAVE_MODE_20FPS] = "Slave mode 20FPS", + [GW5300_MASTER_MODE_30FPS] = "Master mode 30FPS", + [GW5300_SLAVE_MODE_30FPS] = "Slave mode 30FPS", + [GW5300_MASTER_MODE_10FPS_SLOW] = "Master mode 10FPS Slow", + [GW5300_SLAVE_MODE_10FPS_SLOW] = "Slave mode 10FPS Slow", + [GW5300_MASTER_MODE_5FPS] = "Master mode 5FPS", + [GW5300_SLAVE_MODE_5FPS] = "Slave mode 5FPS", + [GW5300_MASTER_MODE_10FPS_EBD] = "Master mode 10FPS with EBD", + [GW5300_SLAVE_MODE_10FPS_EBD] = "Slave mode 10FPS with EBD", + [GW5300_MASTER_MODE_20FPS_EBD] = "Master mode 20FPS with EBD", + [GW5300_SLAVE_MODE_20FPS_EBD] = "Slave mode 20FPS with EBD", + [GW5300_MASTER_MODE_30FPS_EBD] = "Master mode 30FPS with EBD", + [GW5300_SLAVE_MODE_30FPS_EBD] = "Slave mode 30FPS with EBD", }; /** @@ -100,9 +100,15 @@ int tier4_gw5300_c3_setup_sensor_mode(struct device *dev, int sensor_mode); * @return 0 for success, or -1 otherwise. */ -int tier4_gw5300_c2_set_integration_time_on_aemode(struct device *dev, int trigger_mode, u32 max_integration_time, u32 min_integration_time); +int tier4_gw5300_c2_set_integration_time_on_aemode(struct device *dev, + int trigger_mode, + u32 max_integration_time, + u32 min_integration_time); -int tier4_gw5300_c3_set_integration_time_on_aemode(struct device *dev, int trigger_mode, u32 max_integration_time, u32 min_integration_time); +int tier4_gw5300_c3_set_integration_time_on_aemode(struct device *dev, + int trigger_mode, + u32 max_integration_time, + u32 min_integration_time); int tier4_gw5300_set_distortion_correction(struct device *dev, bool val); diff --git a/drivers/src/tier4-hw-model.h b/src/tier4-camera-gmsl/tier4-hw-model.h similarity index 97% rename from drivers/src/tier4-hw-model.h rename to src/tier4-camera-gmsl/tier4-hw-model.h index 4149c2c..6a3fa91 100644 --- a/drivers/src/tier4-hw-model.h +++ b/src/tier4-camera-gmsl/tier4-hw-model.h @@ -35,4 +35,4 @@ #define HW_MODEL_ADLINK_ROSCUBE_ORIN 4 #define HW_MODEL_UNKNOWN 0 -#endif // __TIER4_HW_MODEL_H__ +#endif // __TIER4_HW_MODEL_H__ diff --git a/src/tier4-camera-gmsl/tier4-imx490.c b/src/tier4-camera-gmsl/tier4-imx490.c new file mode 100644 index 0000000..c19f30e --- /dev/null +++ b/src/tier4-camera-gmsl/tier4-imx490.c @@ -0,0 +1,1984 @@ +/* + * tier4_imsx490.c - imx490 sensor driver + * + * Copyright (c) 2022-2023, TIER IV Inc. All rights reserved. + * Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tier4-fpga.h" +#include "tier4-gmsl-link.h" +#include "tier4-gw5300.h" +#include "tier4-hw-model.h" +#include "tier4-isx021-extern.h" +#include "tier4-max9295.h" +#include "tier4-max9296.h" + +MODULE_SOFTDEP("pre: tier4_max9296"); +MODULE_SOFTDEP("pre: tier4_max9295"); +MODULE_SOFTDEP("pre: tier4_gw5300"); +MODULE_SOFTDEP("pre: tier4_fpga"); +MODULE_SOFTDEP("pre: tier4_isx021"); + +#define USE_DISTORTION_CORRECTION 1 + +// Register Address + +#define IMX490_DEFAULT_FRAME_LENGTH (2000) + +#define BIT_SHIFT_8 8 +#define BIT_SHIFT_16 16 +#define MASK_1_BIT 0x1 +#define MASK_4_BIT 0xF +#define MASK_8_BIT 0xFF + +#define NO_ERROR 0 +#define NO_C2_CAMERA (-490) + +#define TIME_120_MILISEC 120000 +#define TIME_121_MILISEC 121000 + +#define ISP_PRIM_SLAVE_ADDR 0x6D + +#define TIER4_C2_CAMERA 1 + +#define SENSOR_ID_IMX490 490 + +#define MAX_NUM_CAMERA 8 + +#define FSYNC_FREQ_HZ 10 + +enum { + IMX490_MODE_2880x1860_CROP_30FPS, + IMX490_MODE_START_STREAM, + IMX490_MODE_STOP_STREAM, +}; + +static const int tier4_imx490_30fps[] = { + 30, +}; +static const struct camera_common_frmfmt tier4_imx490_frmfmt[] = { + { { 2880, 1860 }, + tier4_imx490_30fps, + 1, + 0, + IMX490_MODE_2880x1860_CROP_30FPS }, +}; + +const struct of_device_id tier4_imx490_of_match[] = { + { + .compatible = "nvidia,tier4_imx490", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tier4_imx490_of_match); + +// If you add new ioctl VIDIOC_S_EXT_CTRLS function, please add new CID to the following table. +// and define the CID number in nvidia/include/media/tegra-v4l2-camera.h + +static const u32 ctrl_cid_list[] = { + TEGRA_CAMERA_CID_GAIN, TEGRA_CAMERA_CID_EXPOSURE, + TEGRA_CAMERA_CID_EXPOSURE_SHORT, TEGRA_CAMERA_CID_FRAME_RATE, + TEGRA_CAMERA_CID_HDR_EN, + // TEGRA_CAMERA_CID_DISTORTION_CORRECTION, +}; + +struct tier4_imx490 { + struct i2c_client *i2c_client; + const struct i2c_device_id *id; + struct v4l2_subdev *subdev; + struct device *ser_dev; + struct device *dser_dev; + struct device *isp_dev; + struct tier4_gmsl_link_ctx g_ctx; + u32 frame_length; + struct camera_common_data *s_data; + struct tegracam_device *tc_dev; + int trigger_mode; + bool distortion_correction; + bool last_distortion_correction; + bool auto_exposure; + bool inhibit_fpga_access; + struct device *fpga_dev; +}; + +static const struct regmap_config tier4_sensor_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +struct st_priv { + struct i2c_client *p_client; + struct tier4_imx490 *p_priv; + struct tegracam_device *p_tc_dev; + bool isp_ser_shutdown; + bool des_shutdown; + bool running; +}; + +static struct st_priv wst_priv[MAX_NUM_CAMERA]; + +static struct mutex tier4_imx490_lock; + +static int camera_channel_count = 0; + +// --- module parameter --- + +static int trigger_mode; +static int fsync_mfp = 0; +static int enable_distortion_correction = 1; + +#define IMX490_MIN_EXPOSURE_TIME 11000 // 11 milisecond +#define IMX490_MAX_EXPOSURE_TIME 33000 // 33 milisecond + +static int shutter_time_min = IMX490_MIN_EXPOSURE_TIME; +static int shutter_time_max = IMX490_MAX_EXPOSURE_TIME; + +module_param(trigger_mode, int, 0644); +module_param(shutter_time_min, int, S_IRUGO | S_IWUSR); +module_param(shutter_time_max, int, S_IRUGO | S_IWUSR); + +module_param(fsync_mfp, int, S_IRUGO | S_IWUSR); +module_param(enable_distortion_correction, int, S_IRUGO | S_IWUSR); + +// ------------------------ +static char upper(char c) +{ + if ('a' <= c && c <= 'z') { + c = c - ('a' - 'A'); + } + return c; +} + +static void to_upper_string(char *out, const char *in) +{ + int i; + + i = 0; + while (in[i] != '\0') { + out[i] = upper(in[i]); + i++; + } +} + +static inline int tier4_imx490_read_reg(struct camera_common_data *s_data, + u16 addr, u8 *val) +{ + int err = 0; + u32 reg_val = 0; + + err = regmap_read(s_data->regmap, addr, ®_val); + + if (err) { + dev_err(s_data->dev, "[%s] : I2C read failed, address=0x%x\n", + __func__, addr); + } else { + *val = reg_val & 0xFF; + } + return err; +} + +static int tier4_imx490_write_reg(struct camera_common_data *s_data, u16 addr, + u8 val) +{ + int err = 0; + + err = regmap_write(s_data->regmap, addr, val); + + if (err) { + dev_err(s_data->dev, "[%s] : I2C write failed at x%x=[0x%x]\n", + __func__, addr, val); + } + + return err; +} + +// ------------------------------------------------ + +static int tier4_imx490_set_fsync_trigger_mode(struct tier4_imx490 *priv, + int mode) +{ + int err = 0; + struct device *dev = priv->s_data->dev; + int des_num = 0; + + if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || + (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + priv->inhibit_fpga_access = false; + + dev_info(dev, "[%s] : Set fsync trigger mode.\n", __func__); + + err = tier4_fpga_check_access(priv->fpga_dev); + if (err) { + priv->inhibit_fpga_access = true; + } + + if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_DISABLE) { + dev_info(dev, "[%s] : Disabling FPGA fsync.\n", + __func__); + + err = tier4_fpga_disable_fsync_mode(priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Disabling FPGA fsync failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } else { + err = tier4_fpga_enable_fsync_mode(priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA generate fsync failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + + if (tier4_fpga_get_fsync_mode() == + FPGA_FSYNC_MODE_AUTO) { + // Auto Trigger Mode + err = tier4_fpga_set_fsync_auto_trigger( + priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA Fsync Auto Trigger mode failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + des_num = priv->g_ctx.reg_mux; + err = tier4_fpga_set_fsync_signal_frequency( + priv->fpga_dev, des_num, + priv->trigger_mode); + if (err) { + dev_err(dev, + "[%s] : Setting the frequency of fsync genrated by FPGA failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } else if (tier4_fpga_get_fsync_mode() == + FPGA_FSYNC_MODE_MANUAL) { + // Manual Trigger Mode + dev_info( + dev, + "[%s] : Enabling FPGA Fsync Manual Trigger mode.\n", + __func__); + + err = tier4_fpga_set_fsync_manual_trigger( + priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA Fsync Maunal Trigger mode failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } + } + } + + err = tier4_max9296_setup_gpi(priv->dser_dev, fsync_mfp); + + if (err) { + dev_err(dev, "[%s] :tier4_max9296_setup_gpi() failed\n", + __func__); + return err; + } + + err = tier4_max9295_setup_gpo(priv->ser_dev); + + if (err) { + dev_err(dev, "[%s] : tier4_max9295_setup_gpo() failed\n", + __func__); + return err; + } + + err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, mode); + if (err) { + dev_err(dev, "[%s] : tier4_gw5300_setup_sensor_mode() failed\n", + __func__); + return err; + } + + return err; +} + +static struct mutex serdes_lock__; + +static int tier4_imx490_gmsl_serdes_setup(struct tier4_imx490 *priv) +{ + int err = 0; + int des_err = 0; + struct device *dev; + + if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client) { + return -EINVAL; + } + + dev = &priv->i2c_client->dev; + + mutex_lock(&serdes_lock__); + + /* For now no separate power on required for serializer device */ + + if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && + (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + tier4_max9296_power_on(priv->dser_dev); + } + + /* setup serdes addressing and control pipeline */ + + err = tier4_max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev); + + if (err) { + dev_err(dev, "[%s] : GMSL deserializer link config failed\n", + __func__); + goto error; + } + + err = tier4_max9295_setup_control(priv->ser_dev); + + /* proceed even if ser setup failed, to setup deser correctly */ + if (err) { + dev_err(dev, "[%s] : GMSL serializer setup failed\n", __func__); + goto error; + } + + des_err = tier4_max9296_setup_control(priv->dser_dev, + &priv->i2c_client->dev); + + if (des_err) { + dev_err(dev, "[%s] : GMSL deserializer : setup failed\n", + __func__); + err = des_err; + } + +error: + mutex_unlock(&serdes_lock__); + return err; +} + +static void tier4_imx490_gmsl_serdes_reset(struct tier4_imx490 *priv) +{ + mutex_lock(&serdes_lock__); + + /* reset serdes addressing and control pipeline */ + tier4_max9295_reset_control(priv->ser_dev); + + tier4_max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev, + true); + + if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && + (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + tier4_max9296_power_off(priv->dser_dev); + } + + mutex_unlock(&serdes_lock__); +} + +static int tier4_imx490_power_on(struct camera_common_data *s_data) +{ + int err = 0; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + struct device *dev = s_data->dev; + + if (pdata && pdata->power_on) { + err = pdata->power_on(pw); + + if (err) { + dev_err(dev, "[%s] : failed.\n", __func__); + } else { + pw->state = SWITCH_ON; + } + return err; + } + + pw->state = SWITCH_ON; + + return err; +} + +static int tier4_imx490_power_off(struct camera_common_data *s_data) +{ + int err = 0; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + struct device *dev = s_data->dev; + + if (pdata && pdata->power_off) { + err = pdata->power_off(pw); + + if (!err) { + goto power_off_done; + } else { + dev_err(dev, "[%s] : power off failed.\n", __func__); + } + return err; + } + +power_off_done: + pw->state = SWITCH_OFF; + + return err; +} + +static int tier4_imx490_power_get(struct tegracam_device *tc_dev) +{ + struct camera_common_power_rail *pw = tc_dev->s_data->power; + int err = 0; + + pw->state = SWITCH_OFF; + + return err; +} + +static int tier4_imx490_power_put(struct tegracam_device *tc_dev) +{ + if (unlikely(!tc_dev->s_data->power)) { + return -EFAULT; + } + + return NO_ERROR; +} + +static int tier4_imx490_set_group_hold(struct tegracam_device *tc_dev, bool val) +{ + volatile int err = 0; + + return err; +} + +static int tier4_imx490_set_gain(struct tegracam_device *tc_dev, s64 val) +{ + int err = 0; + + // struct camera_common_data *s_data = tc_dev->s_data; + + // struct device *dev = tc_dev->dev; + + return err; +} + +/* ------------------------------------------------------------------------- */ + +static int tier4_imx490_set_frame_rate(struct tegracam_device *tc_dev, s64 val) +{ + int err = 0; + + struct tier4_imx490 *priv = + (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); + // struct device dev = tc_dev->dev; + + /* fixed 30fps */ + priv->frame_length = IMX490_DEFAULT_FRAME_LENGTH; + + return err; +} + +/* ------------------------------------------------------------------------- */ + +static int tier4_imx490_set_auto_exposure(struct tegracam_device *tc_dev) +{ + int err = 0; + //struct tier4_imx490 *priv = (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); + + return err; +} + +/* ------------------------------------------------------------------------- */ + +static int tier4_imx490_set_exposure(struct tegracam_device *tc_dev, s64 val) +{ + int err = 0; + + struct tier4_imx490 *priv = + (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); + tier4_gw5300_c2_set_integration_time_on_aemode( + priv->isp_dev, priv->trigger_mode, val, val); + + return err; +} +// -------------------------------------------------------------------------------------- +// Enable Distortion Coreection +// -------------------------------------------------------------------------------------- +#if USE_DISTORTION_CORRECTION + +static int +tier4_imx490_set_distortion_correction(struct tegracam_device *tc_dev, bool val) +{ + int err = 0; + struct tier4_imx490 *priv = + (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); + + if (priv->last_distortion_correction != val) { + dev_info(&priv->i2c_client->dev, + "[%s] : Setting distortion correction mode :%s.\n", + __func__, val ? "True" : "False"); + + err = tier4_gw5300_set_distortion_correction(priv->isp_dev, + val); + if (err <= 0) { + dev_info( + &priv->i2c_client->dev, + "[%s] : Setting distortion correction mode failed.\n", + __func__); + } else { + err = 0; + priv->last_distortion_correction = val; + } + } + + return err; +} +#endif + +// -------------------------------------------------------------------------------------- +// If you add new ioctl VIDIOC_S_EXT_CTRLS function, +// please add the new memeber and the function at the following table. + +static struct tegracam_ctrl_ops tier4_imx490_ctrl_ops = { + .numctrls = ARRAY_SIZE(ctrl_cid_list), + .ctrl_cid_list = ctrl_cid_list, + .set_gain = tier4_imx490_set_gain, + .set_exposure = tier4_imx490_set_exposure, + .set_exposure_short = tier4_imx490_set_exposure, + .set_frame_rate = tier4_imx490_set_frame_rate, + .set_group_hold = tier4_imx490_set_group_hold, + // .set_distortion_correction = tier4_imx490_set_distortion_correction, +}; + +// -------------------------------------------------------------------------------------- + +static struct camera_common_pdata * +tier4_imx490_parse_dt(struct tegracam_device *tc_dev) +{ + struct device *dev = tc_dev->dev; + struct device_node *node = dev->of_node; + struct camera_common_pdata *board_priv_pdata; + const struct of_device_id *match; + int err; + + if (!node) { + return NULL; + } + + match = of_match_device(tier4_imx490_of_match, dev); + + if (!match) { + dev_err(dev, "[%s] : Failed to find matching dt id\n", + __func__); + return NULL; + } + + board_priv_pdata = + devm_kzalloc(dev, sizeof(*board_priv_pdata), GFP_KERNEL); + + err = of_property_read_string(node, "mclk", + &board_priv_pdata->mclk_name); + + if (err) { + dev_err(dev, "[%s] : mclk not in DT\n", __func__); + } + + return board_priv_pdata; +} + +/* tier4_imx490_set_mode() can not be needed. But it remains for compatiblity */ + +static int tier4_imx490_set_mode(struct tegracam_device *tc_dev) +{ + volatile int err = 0; + + return err; +} + +static int tier4_imx490_start_one_streaming(struct tegracam_device *tc_dev) +{ + struct tier4_imx490 *priv = + (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); + struct device *dev = tc_dev->dev; + int err; + + /* enable serdes streaming */ + + err = tier4_max9295_setup_streaming(priv->ser_dev); + + if (err) { + goto exit; + } + + err = tier4_max9296_setup_streaming(priv->dser_dev, dev); + + if (err) { + dev_err(dev, "[%s] : Setup Streaming failed\n", __func__); + goto exit; + } + + if (priv->auto_exposure == true) { + err = tier4_imx490_set_auto_exposure(tc_dev); + } + + if (err) { + dev_err(dev, + "[%s] : Setting Digital Gain to default value failed\n", + __func__); + goto exit; + } + + dev_info(dev, "[%s] : trigger_mode = %d\n", __func__, trigger_mode); + + priv->trigger_mode = trigger_mode; + + switch (priv->trigger_mode) { + case GW5300_MASTER_MODE_10FPS: + + dev_info(dev, + "[%s] : Setting camera sensor to Master mode 10fps\n", + __func__); + + err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, + GW5300_MASTER_MODE_10FPS); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to Master mode 10fps failed\n", + __func__); + return err; + } + + priv->last_distortion_correction = 1; + + break; + + case GW5300_SLAVE_MODE_10FPS: + + dev_info(dev, + "[%s] : Setting camera sensor to Slave mode 10fps\n", + __func__); + + err = tier4_imx490_set_fsync_trigger_mode( + priv, GW5300_SLAVE_MODE_10FPS); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to Slave mode 10fps failed\n", + __func__); + goto exit; + } + + priv->last_distortion_correction = 1; + + msleep(20); + + break; + + case GW5300_MASTER_MODE_20FPS: + + dev_info(dev, + "[%s] : Setting camera sensor to Master mode 20fps\n", + __func__); + + err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, + GW5300_MASTER_MODE_20FPS); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to Master mode 20fps failed\n", + __func__); + return err; + } + + priv->last_distortion_correction = 1; + + break; + + case GW5300_SLAVE_MODE_20FPS: + + dev_info(dev, + "[%s] : Setting camera sensor to Slave mode 20fps\n", + __func__); + + err = tier4_imx490_set_fsync_trigger_mode( + priv, GW5300_SLAVE_MODE_20FPS); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to Slave mode 20fps failed\n", + __func__); + return err; + } + + priv->last_distortion_correction = 1; + + break; + + case GW5300_MASTER_MODE_30FPS: + + dev_info(dev, + "[%s] : Setting camera sensor to Master mode 30fps\n", + __func__); + + err = tier4_gw5300_setup_sensor_mode(priv->isp_dev, + GW5300_MASTER_MODE_30FPS); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to Master mode 30fps failed\n", + __func__); + return err; + } + + break; + + case GW5300_SLAVE_MODE_30FPS: + + dev_info(dev, + "[%s] : Setting camera sensor to slave mode 30fps\n", + __func__); + + err = tier4_imx490_set_fsync_trigger_mode( + priv, GW5300_SLAVE_MODE_30FPS); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to Slave mode 30fps failed\n", + __func__); + return err; + } + + priv->last_distortion_correction = 1; + + break; + + case GW5300_SLAVE_MODE_10FPS_SLOW: + + err = tier4_imx490_set_fsync_trigger_mode( + priv, GW5300_SLAVE_MODE_10FPS_SLOW); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to Slow clock Slave mode 10fps failed\n", + __func__); + goto exit; + } + + priv->last_distortion_correction = 1; + + msleep(20); + + break; + + case GW5300_MASTER_MODE_10FPS_SLOW: + + err = tier4_gw5300_setup_sensor_mode( + priv->isp_dev, GW5300_MASTER_MODE_10FPS_SLOW); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to Slow clock Master mode 10fps failed\n", + __func__); + return err; + } + + priv->last_distortion_correction = 1; + + break; + + default: // case of trigger_mode < 0 + + dev_err(dev, + "[%s] : The camera sensor mode(fsync mode) is invalid.\n", + __func__); + + return err; + } + +#if USE_DISTORTION_CORRECTION + + if (priv->last_distortion_correction != enable_distortion_correction) { + usleep_range(900000, 910000); + //msleep(900); + } + + if (enable_distortion_correction == 0xCAFE) { + // if not set kernel param, read device tree param + if (priv->distortion_correction == false) { + err = tier4_imx490_set_distortion_correction( + tc_dev, priv->distortion_correction); + + if (err) { + dev_err(dev, + "[%s] : Disabling Distortion Correction failed\n", + __func__); + goto exit; + } + msleep(20); + } + } else { + err = tier4_imx490_set_distortion_correction( + tc_dev, enable_distortion_correction == 1); + if (err) { + dev_err(dev, + "[%s] : Setup Distortion Correction failed\n", + __func__); + goto exit; + } + msleep(20); + } + +#endif + + err = tier4_max9296_start_streaming(priv->dser_dev, dev); + + if (err) { + dev_err(dev, "[%s] : tier4_max9296_start_stream() failed\n", + __func__); + return err; + } + + msleep(200); + + //#if 0 + msleep(1000); + tier4_gw5300_c2_set_integration_time_on_aemode(priv->isp_dev, + priv->trigger_mode, + shutter_time_max, + shutter_time_min); + //#endif + + dev_info(dev, "[%s] : Camera has started streaming\n", __func__); + + return NO_ERROR; + +exit: + + dev_err(dev, "[%s] : Camera failed to start streaming.\n", __func__); + + return err; +} + +static bool tier4_imx490_is_camera_connected_to_port(int nport) +{ + if (wst_priv[nport].p_client) { + return true; + } + return false; +} + +static bool tier4_imx490_check_null_tc_dev_for_port(int nport) +{ + if (wst_priv[nport].p_tc_dev == NULL) { + return true; + } + return false; +} + +static bool tier4_imx490_is_camera_running_on_port(int nport) +{ + if (wst_priv[nport].running) { + return true; + } + return false; +} + +static bool tier4_imx490_is_current_port(struct tier4_imx490 *priv, int nport) +{ + if (priv->i2c_client == wst_priv[nport].p_client) { + return true; + } + return false; +} + +static void tier4_imx490_set_running_flag(int nport, bool flag) +{ + wst_priv[nport].running = flag; +} + +static int tier4_imx490_stop_streaming(struct tegracam_device *tc_dev) +{ + struct device *dev = tc_dev->dev; + struct tier4_imx490 *priv = + (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); + int i, err = 0; + + mutex_lock(&tier4_imx490_lock); + + for (i = 0; i < camera_channel_count; i++) { + if (tier4_imx490_is_camera_connected_to_port(i)) { + if (tier4_imx490_is_current_port(priv, i) && + tier4_imx490_is_camera_running_on_port(i)) { + /* disable serdes streaming */ + err = tier4_max9296_stop_streaming( + priv->dser_dev, dev); + if (err) { + return err; + } + tier4_imx490_set_running_flag(i, false); + break; + } + } + } + + mutex_unlock(&tier4_imx490_lock); + + return NO_ERROR; +} + +/* *************************************************************************** */ +/* 1. In the case where a camera is connected to GMSL A port on a Des. */ +/* */ +/* a > Check if another camera is connected to GMSL B port */ +/* a-1) Connected: */ +/* b > Check if another camera on GMSL B port is running */ +/* b-1) Running: */ +/* c > Check if the camera on GMSL A port is running */ +/* c-1) Running : */ +/* Do nothing and return */ +/* c-2) Not running : */ +/* Start the camera on GMSL A port. */ +/* b-2) Not Running: */ +/* Start the camera on GMSL B port. */ +/* a-2) Not connected : */ +/* b > Check if the camera on GMSL A port is running */ +/* b-1) Running : */ +/* Do nothing and return */ +/* b-2) Not running : */ +/* Start the camera on GMSL A port. */ +/* */ +/* 2. In the case where a camera is connected to GMSL B port on a Des. */ +/* */ +/* a > Check if the camera on GMSL B port is running */ +/* a-1) Running : */ +/* Do nothing and return */ +/* a-2) Not running : */ +/* Start the camera on GMSL B port. */ +/* *************************************************************************** */ + +static int tier4_imx490_start_streaming(struct tegracam_device *tc_dev) +{ + int i, err = 0; + // struct tier4_imx490 *next_client_priv; + struct tier4_imx490 *priv = + (struct tier4_imx490 *)tegracam_get_privdata(tc_dev); + struct device *dev = tc_dev->dev; + + mutex_lock(&tier4_imx490_lock); + + for (i = 0; i < camera_channel_count; i++) { + if (i & 0x1) { // if i = 1,3,5,7 ( GMSL B port of a Des ) + + if (tier4_imx490_is_camera_connected_to_port( + i)) { // a camera is connected to GMSL B portL + + if ((tier4_imx490_is_current_port(priv, i) == + true) && + (tier4_imx490_is_camera_running_on_port( + i) == false)) { + err = tier4_imx490_start_one_streaming( + wst_priv[i].p_tc_dev); + + if (err) { + dev_err(dev, + "[%s] : Failed to start one streaming.\n", + __func__); + goto error_exit; + } + // wst_priv[i].running = true; + tier4_imx490_set_running_flag(i, true); + break; + } + } + } else { // if i = 0,2,4,6 ( GMSL A side port of a Des0,Des1,Des2 or Des3 ) + + if ((tier4_imx490_is_camera_connected_to_port(i) == + true) && + (tier4_imx490_is_current_port(priv, i) == true)) { + if (tier4_imx490_is_camera_connected_to_port( + i + 1) == + false) { // if another one camera( GMSL B port) is not + // connected to Des. + if (tier4_imx490_is_camera_running_on_port( + i) == + false) { // and if the camera is not running. + + err = tier4_imx490_start_one_streaming( + wst_priv[i].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Failed to start one streaming for next imx490 client.\n", + __func__); + goto error_exit; + } + tier4_imx490_set_running_flag( + i, true); + } + break; + } + + // two cameras are connected to one Des. + + if (tier4_imx490_check_null_tc_dev_for_port( + i + 1)) { // check if tc_dev is null + dev_err(dev, + "[%s] : wst_priv[%d].p_tc_dev is NULL.\n", + __func__, i + 1); + err = -EINVAL; + goto error_exit; + } + + if (tier4_imx490_is_camera_running_on_port( + i + 1) == false) { + err = tier4_imx490_start_one_streaming( + wst_priv[i + 1].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Failed to start one streaming for the next imx490 client.\n", + __func__); + goto error_exit; + } + tier4_imx490_set_running_flag(i + 1, + true); + usleep_range(200000, 220000); + //msleep(200); + mutex_unlock(&tier4_imx490_lock); + tier4_imx490_stop_streaming( + wst_priv[i + 1].p_tc_dev); + mutex_lock(&tier4_imx490_lock); + tier4_imx490_set_running_flag(i + 1, + false); + } + + if (tier4_imx490_is_camera_running_on_port(i) == + false) { + err = tier4_imx490_start_one_streaming( + wst_priv[i].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Failed to start one streaming for current imx490 client.\n", + __func__); + goto error_exit; + } + tier4_imx490_set_running_flag(i, true); + } + } + } + } // for loop + + err = NO_ERROR; + +error_exit: + + mutex_unlock(&tier4_imx490_lock); + + // tier4_imx490_sensor_mutex_unlock(); + + return err; +} + +static struct camera_common_sensor_ops tier4_imx490_common_ops = { + .numfrmfmts = ARRAY_SIZE(tier4_imx490_frmfmt), + .frmfmt_table = tier4_imx490_frmfmt, + .power_on = tier4_imx490_power_on, + .power_off = tier4_imx490_power_off, + .write_reg = tier4_imx490_write_reg, + .read_reg = tier4_imx490_read_reg, + .parse_dt = tier4_imx490_parse_dt, + .power_get = tier4_imx490_power_get, + .power_put = tier4_imx490_power_put, + .set_mode = tier4_imx490_set_mode, + .start_streaming = tier4_imx490_start_streaming, + .stop_streaming = tier4_imx490_stop_streaming, +}; + +static int tier4_imx490_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + //struct i2c_client *client = v4l2_get_subdevdata(sd); + + return NO_ERROR; +} + +static const struct v4l2_subdev_internal_ops tier4_imx490_subdev_internal_ops = { + .open = tier4_imx490_open, +}; + +static const char *of_stdout_options; + +static int tier4_imx490_board_setup(struct tier4_imx490 *priv) +{ + struct tegracam_device *tc_dev = priv->tc_dev; + struct device *dev = tc_dev->dev; + struct device_node *node = dev->of_node; + struct device_node *ser_node; + struct i2c_client *ser_i2c = NULL; + struct device_node *dser_node; + struct i2c_client *dser_i2c = NULL; + struct device_node *isp_node; + struct i2c_client *isp_i2c = NULL; + struct device_node *fpga_node = NULL; + struct i2c_client *fpga_i2c = NULL; + struct device_node *gmsl; + struct device_node *root_node; + int value = 0xFFFF; + const char *str_value; + const char *str_value1[2]; + int i; + int err; + const char *str_model; + char upper_str_model[64]; + char *str_err; + char *sub_str_err; + + root_node = of_find_node_opts_by_path("/", &of_stdout_options); + + err = of_property_read_string(root_node, "model", &str_model); + + if (err < 0) { + dev_err(dev, "[%s] : model not found\n", __func__); + goto error; + } + + memset(upper_str_model, 0, 64); + + to_upper_string(upper_str_model, str_model); + + priv->g_ctx.hardware_model = HW_MODEL_UNKNOWN; + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_XAVIER); + if (str_err) { + priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_XAVIER_DEVKIT; + } + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_XAVIER); + if (str_err) { + priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_XAVIER; + } + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ORIN); + + if (str_err) { + sub_str_err = strstr(upper_str_model, + STR_DTB_MODEL_NAME_ROSCUBE_ORIN); + + if (sub_str_err) { + priv->g_ctx.hardware_model = + HW_MODEL_ADLINK_ROSCUBE_ORIN; + } else { + priv->g_ctx.hardware_model = + HW_MODEL_NVIDIA_ORIN_DEVKIT; + } + } + + dev_info(dev, "[%s] : model=%s\n", __func__, str_model); + dev_info(dev, "[%s] : hardware_model=%d\n", __func__, + priv->g_ctx.hardware_model); + + if (priv->g_ctx.hardware_model == HW_MODEL_UNKNOWN) { + dev_err(dev, "[%s] : Unknown Hardware Sysytem !\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_isp_reg); + + if (err < 0) { + dev_err(dev, "[%s] : def-addr not found\n", __func__); + goto error; + } + + if (err < 0) { + dev_err(dev, "[%s] : reg not found\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "def-addr", &priv->g_ctx.sdev_isp_def); + + if (err < 0) { + dev_err(dev, "[%s] : def-addr not found\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "reg_mux", &priv->g_ctx.reg_mux); + + if (err < 0) { + dev_err(dev, "[%s] : reg_mux not found\n", __func__); + goto error; + } + + // err = of_property_read_string(node, "fsync-mode", &str_value); + // + // if (err < 0) + // { + // dev_err(dev, "[%s] : No fsync-mode found\n", __func__); + // goto error; + // } + // + // if (!strcmp(str_value, "true")) + // { + // priv->fsync_mode = true; + // } + // else + // { + // priv->fsync_mode = false; + // } + + err = of_property_read_string(node, "distortion-correction", + &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No distortion-correction found\n", + __func__); + goto error; + } + + if (!strcmp(str_value, "true")) { + priv->distortion_correction = true; + } else { + priv->distortion_correction = false; + } + + err = of_property_read_string(node, "auto-exposure", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : Inavlid Exposure mode.\n", __func__); + goto error; + } + + if (!strcmp(str_value, "true")) { + priv->auto_exposure = true; + } else { + priv->auto_exposure = false; + } + +#if 0 + priv->g_ctx.fpga_generate_fsync = false; + + if (( priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER ) || + ( priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN )) { + + err = of_property_read_string(node, "fpga-generate-fsync", &str_value); + + if ( err < 0) { + if ( err == -EINVAL ) { + dev_info(dev, "[%s] : Parameter of fpga-generate-fsync does not exist.\n", __func__); + } else { + dev_err(dev, "[%s] : Parameter of fpga-generate-fsync is invalid .\n", __func__); + goto error; + } + } else { + if (!strcmp(str_value, "true")) { + priv->g_ctx.fpga_generate_fsync = true; + } + } + } +#endif + + // For Ser node + ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0); + + if (ser_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,gmsl-ser-device"); + goto error; + } + + err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg); + + if (err < 0) { + dev_err(dev, "[%s] : Serializer reg not found\n", __func__); + goto error; + } + + ser_i2c = of_find_i2c_device_by_node(ser_node); + + of_node_put(ser_node); + + if (ser_i2c == NULL) { + dev_err(dev, "[%s] : Missing Serializer Dev Handle\n", + __func__); + goto error; + } + if (ser_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing serializer driver\n", __func__); + goto error; + } + + priv->ser_dev = &ser_i2c->dev; + + // For ISP node + + isp_node = of_parse_phandle(node, "nvidia,isp-device", 0); + + if (isp_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,isp-device"); + goto error; + } + + err = of_property_read_u32(isp_node, "reg", &priv->g_ctx.sdev_isp_reg); + + if (err < 0) { + dev_err(dev, "[%s] : ISP reg not found\n", __func__); + goto error; + } + + isp_i2c = of_find_i2c_device_by_node(isp_node); + + of_node_put(isp_node); + + if (isp_i2c == NULL) { + dev_err(dev, "[%s] : Missing ISP Dev Handle\n", __func__); + goto error; + } + if (isp_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing ISP driver\n", __func__); + goto error; + } + + priv->isp_dev = &isp_i2c->dev; + + err = tier4_gw5300_prim_slave_addr(&priv->g_ctx); + if (err) { + dev_err(dev, + "[%s] : ISP Prim slave address is unavailable, the default address(0x6D) is applied.\n", + __func__); + priv->g_ctx.sdev_isp_def = ISP_PRIM_SLAVE_ADDR; + } + + priv->g_ctx.sdev_reg = priv->g_ctx.sdev_isp_reg; + priv->g_ctx.sdev_def = priv->g_ctx.sdev_isp_def; + + // For Dser node + + dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0); + + if (dser_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,gmsl-dser-device"); + goto error; + } + + dser_i2c = of_find_i2c_device_by_node(dser_node); + + of_node_put(dser_node); + + if (dser_i2c == NULL) { + dev_err(dev, "[%s] : Missing deserializer dev handle\n", + __func__); + goto error; + } + + if (dser_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing deserializer driver\n", __func__); + goto error; + } + + priv->dser_dev = &dser_i2c->dev; + + if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || + (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + // for FPGA node + + fpga_node = of_parse_phandle(node, "nvidia,fpga-device", 0); + + if (fpga_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,fpga-device"); + goto error; + } + + err = of_property_read_u32(fpga_node, "reg", + &priv->g_ctx.sdev_fpga_reg); + + if (err < 0) { + dev_err(dev, "[%s] : FPGA reg not found\n", __func__); + goto error; + } + + fpga_i2c = of_find_i2c_device_by_node(fpga_node); + + of_node_put(fpga_node); + + if (fpga_i2c == NULL) { + dev_err(dev, "[%s] : Missing FPGA Dev Handle\n", + __func__); + goto error; + } + if (fpga_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing FPGA driver\n", __func__); + goto error; + } + + priv->fpga_dev = &fpga_i2c->dev; + } + + /* populate g_ctx from DT */ + + gmsl = of_get_child_by_name(node, "gmsl-link"); + + if (gmsl == NULL) { + dev_err(dev, "[%s] : Missing GMSL-Link device node\n", + __func__); + err = -EINVAL; + goto error; + } + + err = of_property_read_string(gmsl, "dst-csi-port", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No dst-csi-port found\n", __func__); + goto error; + } + + priv->g_ctx.dst_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : + GMSL_CSI_PORT_B; + + err = of_property_read_string(gmsl, "src-csi-port", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No src-csi-port found\n", __func__); + goto error; + } + + priv->g_ctx.src_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : + GMSL_CSI_PORT_B; + + err = of_property_read_string(gmsl, "csi-mode", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No csi-mode found\n", __func__); + goto error; + } + + if (!strcmp(str_value, "1x4")) { + priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE; + } else if (!strcmp(str_value, "2x4")) { + priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE; + } else if (!strcmp(str_value, "4x2")) { + priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE; + } else if (!strcmp(str_value, "2x2")) { + priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE; + } else { + dev_err(dev, "[%s] :Invalid csi-mode\n", __func__); + goto error; + } + + err = of_property_read_string(gmsl, "serdes-csi-link", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No serdes-csi-link found\n", __func__); + goto error; + } + + priv->g_ctx.serdes_csi_link = (!strcmp(str_value, "a")) ? + GMSL_SERDES_CSI_LINK_A : + GMSL_SERDES_CSI_LINK_B; + + err = of_property_read_u32(gmsl, "st-vc", &value); + + if (err < 0) { + dev_err(dev, "[%s] : No st-vc info\n", __func__); + goto error; + } + + priv->g_ctx.st_vc = value; + + err = of_property_read_u32(gmsl, "vc-id", &value); + + if (err < 0) { + dev_err(dev, "[%s] : No vc-id info\n", __func__); + goto error; + } + + priv->g_ctx.dst_vc = value; + + err = of_property_read_u32(gmsl, "num-lanes", &value); + + if (err < 0) { + dev_err(dev, "[%s] : No num-lanes info\n", __func__); + goto error; + } + + priv->g_ctx.num_csi_lanes = value; + + priv->g_ctx.num_streams = of_property_count_strings(gmsl, "streams"); + + if (priv->g_ctx.num_streams <= 0) { + dev_err(dev, "[%s] : No streams found\n", __func__); + err = -EINVAL; + goto error; + } + + for (i = 0; i < priv->g_ctx.num_streams; i++) { + of_property_read_string_index(gmsl, "streams", i, + &str_value1[i]); + + if (!str_value1[i]) { + dev_err(dev, "[%s] : Invalid Stream Info\n", __func__); + goto error; + } + + if (!strcmp(str_value1[i], "raw12")) { + priv->g_ctx.streams[i].st_data_type = + GMSL_CSI_DT_RAW_12; + } else if (!strcmp(str_value1[i], "yuv8")) { + priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_YUV_8; + } else if (!strcmp(str_value1[i], "embed")) { + priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_EMBED; + } else if (!strcmp(str_value1[i], "ued-u1")) { + priv->g_ctx.streams[i].st_data_type = + GMSL_CSI_DT_UED_U1; + } else { + dev_err(dev, "[%s] : Invalid stream data type\n", + __func__); + goto error; + } + } + + priv->g_ctx.s_dev = dev; + + return NO_ERROR; + +error: + dev_err(dev, "[%s] : Board Setup failed\n", __func__); + return err; +} + +static int tier4_imx490_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *node = dev->of_node; + struct tegracam_device *tc_dev; + struct tier4_imx490 *priv; + int err = 0; + + dev_info(dev, "[%s] : Probing V4L2 Sensor.\n", __func__); + + if (!IS_ENABLED(CONFIG_OF) || !node) { + return -EINVAL; + } + + wst_priv[camera_channel_count].p_client = NULL; + wst_priv[camera_channel_count].p_priv = NULL; + wst_priv[camera_channel_count].p_tc_dev = NULL; + + wst_priv[camera_channel_count].isp_ser_shutdown = false; + wst_priv[camera_channel_count].des_shutdown = false; + wst_priv[camera_channel_count].running = false; + + priv = devm_kzalloc(dev, sizeof(struct tier4_imx490), GFP_KERNEL); + + if (!priv) { + dev_err(dev, "[%s] : Unable to allocate Memory!\n", __func__); + return -ENOMEM; + } + + tc_dev = devm_kzalloc(dev, sizeof(struct tegracam_device), GFP_KERNEL); + + if (!tc_dev) { + return -ENOMEM; + } + + priv->i2c_client = tc_dev->client = client; + + tc_dev->dev = dev; + + strncpy(tc_dev->name, "imx490", sizeof(tc_dev->name)); + + tc_dev->dev_regmap_config = &tier4_sensor_regmap_config; + tc_dev->sensor_ops = &tier4_imx490_common_ops; + tc_dev->v4l2sd_internal_ops = &tier4_imx490_subdev_internal_ops; + tc_dev->tcctrl_ops = &tier4_imx490_ctrl_ops; + + err = tegracam_device_register(tc_dev); + + if (err) { + dev_err(dev, "[%s] : Tegra Camera Driver Registration failed\n", + __func__); + return err; + } + + priv->tc_dev = tc_dev; + priv->s_data = tc_dev->s_data; + priv->subdev = &tc_dev->s_data->subdev; + + tegracam_set_privdata(tc_dev, (void *)priv); + + priv->g_ctx.sensor_id = SENSOR_ID_IMX490; + + tier4_isx021_sensor_mutex_lock(); + + err = tier4_imx490_board_setup(priv); + + if (err) { + dev_err(dev, "[%s] : Board Setup failed\n", __func__); + goto err_tegracam_unreg; + } + + /* Pair sensor to serializer dev */ + + err = tier4_max9295_sdev_pair(priv->ser_dev, &priv->g_ctx); + + if (err) { + dev_err(&client->dev, "[%s] : GMSL Ser Pairing failed\n", + __func__); + goto err_tegracam_unreg; + } + /* Register sensor to deserializer dev */ + + err = tier4_max9296_sdev_register(priv->dser_dev, &priv->g_ctx); + + if (err) { + dev_err(&client->dev, + "[%s] : GMSL Deserializer Register failed\n", __func__); + goto err_max9295_unpair; + } + + /* + * gmsl serdes setup + * + * Sensor power on/off should be the right place for serdes + * setup/reset. But the problem is, the total required delay + * in serdes setup/reset exceeds the frame wait timeout, looks to + * be related to multiple channel open and close sequence + * issue (#BUG 200477330). + * Once this bug is fixed, these may be moved to power on/off. + * The delays in serdes is as per guidelines and can't be reduced, + * so it is placed in probe/remove, though for that, deserializer + * would be powered on always post boot, until 1.2v is supplied + * to deserializer from CVB. + */ + + err = tier4_imx490_gmsl_serdes_setup(priv); + + if (err) { + dev_err(&client->dev, "[%s] : GMSL Serdes setup failed\n", + __func__); + goto err_max9296_unreg; + } + + err = tegracam_v4l2subdev_register(tc_dev, true); + + if (err) { + dev_err(dev, "[%s] : Tegra Camera Subdev Registration failed\n", + __func__); + goto err_max9296_unreg; + } + + wst_priv[camera_channel_count].p_client = client; + wst_priv[camera_channel_count].p_priv = priv; + wst_priv[camera_channel_count].p_tc_dev = tc_dev; + + camera_channel_count++; + + tier4_isx021_sensor_mutex_unlock(); + + return NO_ERROR; + + // tier4_isx021_sensor_mutex_unlock(); + + // dev_info(&client->dev, "Detected Tier4 IMX490 sensor\n"); + +err_max9296_unreg: + tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); +err_max9295_unpair: + tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); +err_tegracam_unreg: + tegracam_device_unregister(priv->tc_dev); + + tier4_isx021_sensor_mutex_unlock(); + + // dev_info(dev, "[%s] :camera_channel_count = %d p_client = %p \n", __func__, camera_channel_count, + // wst_priv[camera_channel_count].p_client); + + return err; + //return NO_ERROR; // err; +} + +static void tier4_imx490_shutdown(struct i2c_client *client); + +static int tier4_imx490_remove(struct i2c_client *client) +{ + struct camera_common_data *s_data = to_camera_common_data(&client->dev); + struct tier4_imx490 *priv = (struct tier4_imx490 *)s_data->priv; + + tier4_imx490_shutdown(client); + + tier4_imx490_gmsl_serdes_reset(priv); + + tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); + tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); + + tegracam_v4l2subdev_unregister(priv->tc_dev); + + tegracam_device_unregister(priv->tc_dev); + + return NO_ERROR; +} + +static struct mutex tier4_imx490_lock; + +static bool tier4_imx490_is_isp_ser_shutdown(int nport) +{ + if (wst_priv[nport].isp_ser_shutdown) { + return true; + } + return false; +} + +static bool tier4_imx490_is_des_shutdown(int nport) +{ + if (wst_priv[nport].des_shutdown) { + return true; + } + return false; +} + +static void tier4_imx490_set_isp_ser_shutdown(int nport, bool val) +{ + wst_priv[nport].isp_ser_shutdown = val; +} + +static void tier4_imx490_set_des_shutdown(int nport, bool val) +{ + wst_priv[nport].des_shutdown = val; +} + +static bool tier4_imx490_is_current_i2c_client(struct i2c_client *client, + int nport) +{ + if (client == wst_priv[nport].p_client) { + return true; + } + return false; +} + +// ---------------------------------------------------------------------------- + +static void tier4_imx490_shutdown(struct i2c_client *client) +{ + struct tier4_imx490 *priv = NULL; + int i; + + tier4_isx021_sensor_mutex_lock(); + + mutex_lock(&tier4_imx490_lock); + + if (!client) { + goto error_exit; + } + + for (i = 0; i < camera_channel_count; i++) { + if (tier4_imx490_is_current_i2c_client(client, i)) { + priv = wst_priv[i].p_priv; + + if (i & + 0x1) { // Even port number( GMSL B port on a Des : i = port_number -1 ) + + if (tier4_imx490_is_camera_connected_to_port( + i - + 1)) { // if a camera connected to another(GMSL A)port on a Des. + // a camera is connected to each port of the Des. + if (tier4_imx490_is_isp_ser_shutdown( + i - + 1)) { // ISP and Ser on another(GMSL A) port have been already shut down ? + + if (tier4_imx490_is_des_shutdown( + i - 1) == + false) { // if Des on another(GMSL A)port is not shutdown yet + tier4_imx490_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx490_set_des_shutdown( + i, + true); // Des will be shut down + } else { // if Des on the another port is already shut down. This is Error case. + tier4_imx490_set_isp_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_imx490_set_des_shutdown( + i, + false); // Des will not be shutdown + } + } else { // The camera ISP and Ser on another(GMSL A) port are not shut down yet. + + if (tier4_imx490_is_des_shutdown( + i - 1) == + false) { // if Des is not shut down yet. + tier4_imx490_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx490_set_des_shutdown( + i, + false); // The Des won't be shut down. + } else { // Only Des on another port is already shut down. This is Error case. + tier4_imx490_set_isp_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_imx490_set_des_shutdown( + i, + false); // Des will not be shut down. + } + } // a camera is connected to only (GMSL B) port on Des. + tier4_imx490_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx490_set_des_shutdown( + i, + true); // The Des won't be shut down. + } + } else { // if ( i & 0x1 ) == 0 + + if (tier4_imx490_is_camera_connected_to_port( + i + + 1)) { // Another camera is connected to another(GMSL B) port on the Des + + if (tier4_imx490_is_isp_ser_shutdown( + i + + 1)) { // if the ISP and Ser on another port are already shut down + + if (tier4_imx490_is_des_shutdown( + i + 1) == + false) { // if Des is not shut down yet. + tier4_imx490_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx490_set_des_shutdown( + i, + false); // The Des will be shut down. + } else { // Des is already shut down. This is Error case. + tier4_imx490_set_isp_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_imx490_set_des_shutdown( + i, + false); // The Des will not be shut down. + } + } else { // The ISP and Ser on another(GMSL B) port are not shut down yet. + + if (tier4_imx490_is_des_shutdown( + i + 1) == + false) { // if Des on another(GMSL B) port is not shut down yet. + + tier4_imx490_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx490_set_des_shutdown( + i, + false); // The Des will not be shut down. + } else { // Only Des on another(GMSL B) port is already shut down. + // This is Error case. + tier4_imx490_set_isp_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_imx490_set_des_shutdown( + i, + false); // The Des will not be shut down. + } + } + } else { + tier4_imx490_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx490_set_des_shutdown( + i, + true); // The Des will be shut down. + } + } // if ( i & 0x1 ) + // break; + + if (tier4_imx490_is_isp_ser_shutdown(i)) { + // Reset camera sensor + tier4_max9295_control_sensor_power_seq( + priv->ser_dev, SENSOR_ID_IMX490, false); + // S/W Reset max9295 + tier4_max9295_reset_control(priv->ser_dev); + } + + if (tier4_imx490_is_des_shutdown(i)) { + // S/W Reset max9296 + tier4_max9296_reset_control(priv->dser_dev, + &client->dev, true); + } + + if (priv == NULL || i >= camera_channel_count) { + mutex_unlock(&tier4_imx490_lock); + tier4_isx021_sensor_mutex_unlock(); + return; + } + } + + } // for loop + +error_exit: + + mutex_unlock(&tier4_imx490_lock); + + tier4_isx021_sensor_mutex_unlock(); +} +static const struct i2c_device_id tier4_imx490_id[] = { { "tier4_imx490", 0 }, + {} }; + +MODULE_DEVICE_TABLE(i2c, tier4_imx490_id); + +static struct i2c_driver tier4_imx490_i2c_driver = { + .driver = { + .name = "tier4_imx490", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tier4_imx490_of_match), + }, + .probe = tier4_imx490_probe, + .remove = tier4_imx490_remove, + .shutdown = tier4_imx490_shutdown, + .id_table = tier4_imx490_id, +}; + +static int __init tier4_imx490_init(void) +{ + mutex_init(&serdes_lock__); + mutex_init(&tier4_imx490_lock); + + printk(KERN_INFO "TIERIV Automotive HDR Camera driver.\n"); + + return i2c_add_driver(&tier4_imx490_i2c_driver); +} + +static void __exit tier4_imx490_exit(void) +{ + mutex_destroy(&serdes_lock__); + mutex_destroy(&tier4_imx490_lock); + + i2c_del_driver(&tier4_imx490_i2c_driver); +} + +module_init(tier4_imx490_init); +module_exit(tier4_imx490_exit); + +MODULE_DESCRIPTION("TIERIV Automotive HDR Camera driver"); +MODULE_AUTHOR("Originaly NVIDIA Corporation"); +MODULE_AUTHOR("K.Iwasaki"); +MODULE_AUTHOR("Y.Fujii"); +MODULE_LICENSE("GPL v2"); diff --git a/src/tier4-camera-gmsl/tier4-imx728.c b/src/tier4-camera-gmsl/tier4-imx728.c new file mode 100644 index 0000000..f60a028 --- /dev/null +++ b/src/tier4-camera-gmsl/tier4-imx728.c @@ -0,0 +1,1895 @@ +/* + * tier4_imx728.c - imx728 sensor driver + * + * Copyright (c) 2022-2023, TIER IV Inc. All rights reserved. + * Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tier4-fpga.h" +#include "tier4-gmsl-link.h" +#include "tier4-gw5300.h" +#include "tier4-hw-model.h" +#include "tier4-isx021-extern.h" +#include "tier4-max9295.h" +#include "tier4-max9296.h" + +MODULE_SOFTDEP("pre: tier4_max9296"); +MODULE_SOFTDEP("pre: tier4_max9295"); +MODULE_SOFTDEP("pre: tier4_gw5300"); +MODULE_SOFTDEP("pre: tier4_fpga"); +MODULE_SOFTDEP("pre: tier4_isx021"); +MODULE_SOFTDEP("pre: tier4_imx490"); + +#define USE_DISTORTION_CORRECTION 1 + +// Register Address + +#define IMX728_DEFAULT_FRAME_LENGTH (2350) + +#define BIT_SHIFT_8 8 +#define BIT_SHIFT_16 16 +#define MASK_1_BIT 0x1 +#define MASK_4_BIT 0xF +#define MASK_8_BIT 0xFF + +#define POWER_ON 1 +#define POWER_OFF 0 + +#define NO_ERROR 0 +//#define NO_C3_CAMERA (-728) + +//#define TIME_120_MILISEC 120000 +//#define TIME_121_MILISEC 121000 + +#define ISP_PRIM_SLAVE_ADDR 0x6D + +//#define TIER4_C3_CAMERA 1 + +#define MAX_NUM_CAMERA 8 + +//#define FSYNC_FREQ_HZ 10 + +enum { + IMX728_MODE_3840x2160_CROP_20FPS, + IMX728_MODE_START_STREAM, + IMX728_MODE_STOP_STREAM, +}; + +static const int tier4_imx728_20fps[] = { + 20, +}; +static const struct camera_common_frmfmt tier4_imx728_frmfmt[] = { + { { 3840, 2160 }, + tier4_imx728_20fps, + 1, + 0, + IMX728_MODE_3840x2160_CROP_20FPS }, + // { { 3840, 2163 }, tier4_imx728_20fps, 1, 0, IMX728_MODE_3840x2160_CROP_20FPS }, +}; + +const struct of_device_id tier4_imx728_of_match[] = { + { + .compatible = "nvidia,tier4_imx728", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tier4_imx728_of_match); + +// If you add new ioctl VIDIOC_S_EXT_CTRLS function, please add new CID to the following table. +// and define the CID number in nvidia/include/media/tegra-v4l2-camera.h + +static const u32 ctrl_cid_list[] = { + TEGRA_CAMERA_CID_GAIN, TEGRA_CAMERA_CID_EXPOSURE, + TEGRA_CAMERA_CID_EXPOSURE_SHORT, TEGRA_CAMERA_CID_FRAME_RATE, + TEGRA_CAMERA_CID_HDR_EN, + // TEGRA_CAMERA_CID_DISTORTION_CORRECTION, +}; + +struct tier4_imx728 { + struct i2c_client *i2c_client; + const struct i2c_device_id *id; + struct v4l2_subdev *subdev; + struct device *ser_dev; + struct device *dser_dev; + struct device *isp_dev; + struct tier4_gmsl_link_ctx g_ctx; + u32 frame_length; + struct camera_common_data *s_data; + struct tegracam_device *tc_dev; + int trigger_mode; + bool distortion_correction; + bool last_distortion_correction; + bool inhibit_fpga_access; + struct device *fpga_dev; +}; + +static const struct regmap_config tier4_sensor_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +struct st_priv { + struct i2c_client *p_client; + struct tier4_imx728 *p_priv; + struct tegracam_device *p_tc_dev; + bool isp_ser_shutdown; + bool des_shutdown; + bool running; +}; + +static struct st_priv wst_priv[MAX_NUM_CAMERA]; + +static struct mutex tier4_imx728_lock; + +static int camera_channel_count = 0; + +// --- module parameter --- + +static int trigger_mode; +static int fsync_mfp = 0; +static int enable_distortion_correction = 1; +static int enable_auto_exposure = 0xCAFE; + +#define IMX728_MIN_EXPOSURE_TIME 11000 // 11 milisecond +#define IMX728_MAX_EXPOSURE_TIME 33000 // 33 milisecond + +static int shutter_time_min = IMX728_MIN_EXPOSURE_TIME; +static int shutter_time_max = IMX728_MAX_EXPOSURE_TIME; + +module_param(trigger_mode, int, 0644); +module_param(shutter_time_min, int, S_IRUGO | S_IWUSR); +module_param(shutter_time_max, int, S_IRUGO | S_IWUSR); + +module_param(fsync_mfp, int, S_IRUGO | S_IWUSR); +module_param(enable_distortion_correction, int, S_IRUGO | S_IWUSR); +module_param(enable_auto_exposure, int, S_IRUGO | S_IWUSR); + +// ------------------------ +static char upper(char c) +{ + if ('a' <= c && c <= 'z') { + c = c - ('a' - 'A'); + } + return c; +} + +static void to_upper_string(char *out, const char *in) +{ + int i; + + i = 0; + while (in[i] != '\0') { + out[i] = upper(in[i]); + i++; + } +} + +static inline int tier4_imx728_read_reg(struct camera_common_data *s_data, + u16 addr, u8 *val) +{ + int err = 0; + u32 reg_val = 0; + + err = regmap_read(s_data->regmap, addr, ®_val); + + if (err) { + dev_err(s_data->dev, "[%s] : I2C read failed, address=0x%x\n", + __func__, addr); + } else { + *val = reg_val & 0xFF; + } + return err; +} + +static int tier4_imx728_write_reg(struct camera_common_data *s_data, u16 addr, + u8 val) +{ + int err = 0; + + err = regmap_write(s_data->regmap, addr, val); + + if (err) { + dev_err(s_data->dev, "[%s] : I2C write failed at x%x=[0x%x]\n", + __func__, addr, val); + } + + return err; +} + +// ------------------------------------------------ + +static int tier4_imx728_set_fsync_trigger_mode(struct tier4_imx728 *priv, + int mode) +{ + int err = 0; + struct device *dev = priv->s_data->dev; + int des_num = 0; + + if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || + (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + priv->inhibit_fpga_access = false; + + dev_info(dev, "[%s] : Set fsync trigger mode.\n", __func__); + + err = tier4_fpga_check_access(priv->fpga_dev); + if (err) { + priv->inhibit_fpga_access = true; + } + + if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_DISABLE) { + dev_info(dev, "[%s] : Disabling FPGA fsync.\n", + __func__); + + err = tier4_fpga_disable_fsync_mode(priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Disabling FPGA fsync failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } else { + err = tier4_fpga_enable_fsync_mode(priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA generate fsync failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + + if (tier4_fpga_get_fsync_mode() == + FPGA_FSYNC_MODE_AUTO) { + // Auto Trigger Mode + err = tier4_fpga_set_fsync_auto_trigger( + priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA Fsync Auto Trigger mode failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + des_num = priv->g_ctx.reg_mux; + err = tier4_fpga_set_fsync_signal_frequency( + priv->fpga_dev, des_num, + priv->trigger_mode); + if (err) { + dev_err(dev, + "[%s] : Setting the frequency of fsync genrated by FPGA failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } else if (tier4_fpga_get_fsync_mode() == + FPGA_FSYNC_MODE_MANUAL) { + // Manual Trigger Mode + dev_info( + dev, + "[%s] : Enabling FPGA Fsync Manual Trigger mode.\n", + __func__); + + err = tier4_fpga_set_fsync_manual_trigger( + priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA Fsync Maunal Trigger mode failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } + } + } + + err = tier4_max9296_setup_gpi(priv->dser_dev, fsync_mfp); + + if (err) { + dev_err(dev, "[%s] :tier4_max9296_setup_gpi() failed\n", + __func__); + return err; + } + + err = tier4_max9295_setup_gpo(priv->ser_dev); + + if (err) { + dev_err(dev, "[%s] : tier4_max9295_setup_gpo() failed\n", + __func__); + return err; + } + + // Power on GW5300 via Max9295 in C3 camera + // err = tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_IMX728, POWER_ON ); + // if (err) + // { + // dev_err(dev, "[%s] : Power on gw5300 in C3 camaera failed.\n", __func__); + // return err; + // } + + err = tier4_gw5300_c3_setup_sensor_mode(priv->isp_dev, mode); + if (err) { + dev_err(dev, + "[%s] : tier4_gw5300_c3_setup_sensor_mode() failed\n", + __func__); + return err; + } + + return err; +} + +static struct mutex serdes_lock__; + +static int tier4_imx728_gmsl_serdes_setup(struct tier4_imx728 *priv) +{ + int err = 0; + int des_err = 0; + struct device *dev; + + if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client) { + return -EINVAL; + } + + dev = &priv->i2c_client->dev; + + mutex_lock(&serdes_lock__); + + /* For now no separate power on required for serializer device */ + + if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && + (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + tier4_max9296_power_on(priv->dser_dev); + } + + /* setup serdes addressing and control pipeline */ + + err = tier4_max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev); + + if (err) { + dev_err(dev, "[%s] : GMSL deserializer link config failed\n", + __func__); + goto error; + } + + err = tier4_max9295_setup_control(priv->ser_dev); + + /* proceed even if ser setup failed, to setup deser correctly */ + if (err) { + dev_err(dev, "[%s] : GMSL serializer setup failed\n", __func__); + goto error; + } + + des_err = tier4_max9296_setup_control(priv->dser_dev, + &priv->i2c_client->dev); + + if (des_err) { + dev_err(dev, "[%s] : GMSL deserializer : setup failed\n", + __func__); + err = des_err; + } + +error: + mutex_unlock(&serdes_lock__); + return err; +} + +static void tier4_imx728_gmsl_serdes_reset(struct tier4_imx728 *priv) +{ + mutex_lock(&serdes_lock__); + + /* reset serdes addressing and control pipeline */ + tier4_max9295_reset_control(priv->ser_dev); + + tier4_max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev, + true); + + if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && + (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + tier4_max9296_power_off(priv->dser_dev); + } + + mutex_unlock(&serdes_lock__); +} + +static int tier4_imx728_power_on(struct camera_common_data *s_data) +{ + int err = 0; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + struct device *dev = s_data->dev; + + if (pdata && pdata->power_on) { + err = pdata->power_on(pw); + + if (err) { + dev_err(dev, "[%s] : failed.\n", __func__); + } else { + pw->state = SWITCH_ON; + } + return err; + } + + pw->state = SWITCH_ON; + + return err; +} + +static int tier4_imx728_power_off(struct camera_common_data *s_data) +{ + int err = 0; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + struct device *dev = s_data->dev; + + if (pdata && pdata->power_off) { + err = pdata->power_off(pw); + + if (!err) { + goto power_off_done; + } else { + dev_err(dev, "[%s] : power off failed.\n", __func__); + } + return err; + } + +power_off_done: + pw->state = SWITCH_OFF; + + return err; +} + +static int tier4_imx728_power_get(struct tegracam_device *tc_dev) +{ + struct camera_common_power_rail *pw = tc_dev->s_data->power; + int err = 0; + + pw->state = SWITCH_OFF; + + return err; +} + +static int tier4_imx728_power_put(struct tegracam_device *tc_dev) +{ + if (unlikely(!tc_dev->s_data->power)) { + return -EFAULT; + } + + return NO_ERROR; +} + +static int tier4_imx728_set_group_hold(struct tegracam_device *tc_dev, bool val) +{ + volatile int err = 0; + + return err; +} + +static int tier4_imx728_set_gain(struct tegracam_device *tc_dev, s64 val) +{ + int err = 0; + + // struct camera_common_data *s_data = tc_dev->s_data; + + // struct device *dev = tc_dev->dev; + + return err; +} + +/* ------------------------------------------------------------------------- */ + +static int tier4_imx728_set_frame_rate(struct tegracam_device *tc_dev, s64 val) +{ + int err = 0; + + struct tier4_imx728 *priv = + (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); + // struct device dev = tc_dev->dev; + + /* fixed 20fps */ + priv->frame_length = IMX728_DEFAULT_FRAME_LENGTH; + + return err; +} + +/* ------------------------------------------------------------------------- */ + +static int tier4_imx728_set_exposure(struct tegracam_device *tc_dev, s64 val) +{ + int err = 0; + + struct tier4_imx728 *priv = + (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); + tier4_gw5300_c3_set_integration_time_on_aemode( + priv->isp_dev, priv->trigger_mode, val, val); + + return err; +} +// -------------------------------------------------------------------------------------- +// Enable Distortion Coreection +// -------------------------------------------------------------------------------------- +#if USE_DISTORTION_CORRECTION + +static int +tier4_imx728_set_distortion_correction(struct tegracam_device *tc_dev, bool val) +{ + int err = 0; + struct tier4_imx728 *priv = + (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); + + if (priv->last_distortion_correction != val) { + dev_info(&priv->i2c_client->dev, + "[%s] : Setting distortion correction mode :%s.\n", + __func__, val ? "True" : "False"); + + err = tier4_gw5300_c3_set_distortion_correction(priv->isp_dev, + val); + if (err <= 0) { + dev_info( + &priv->i2c_client->dev, + "[%s] : Setting distortion correction mode failed.\n", + __func__); + } else { + err = 0; + priv->last_distortion_correction = val; + } + } + + return err; +} +#endif + +// -------------------------------------------------------------------------------------- +// If you add new ioctl VIDIOC_S_EXT_CTRLS function, +// please add the new memeber and the function at the following table. + +static struct tegracam_ctrl_ops tier4_imx728_ctrl_ops = { + .numctrls = ARRAY_SIZE(ctrl_cid_list), + .ctrl_cid_list = ctrl_cid_list, + .set_gain = tier4_imx728_set_gain, + .set_exposure = tier4_imx728_set_exposure, + .set_exposure_short = tier4_imx728_set_exposure, + .set_frame_rate = tier4_imx728_set_frame_rate, + .set_group_hold = tier4_imx728_set_group_hold, + // .set_distortion_correction = tier4_imx728_set_distortion_correction, +}; + +// -------------------------------------------------------------------------------------- + +static struct camera_common_pdata * +tier4_imx728_parse_dt(struct tegracam_device *tc_dev) +{ + struct device *dev = tc_dev->dev; + struct device_node *node = dev->of_node; + struct camera_common_pdata *board_priv_pdata; + const struct of_device_id *match; + int err; + + if (!node) { + return NULL; + } + + match = of_match_device(tier4_imx728_of_match, dev); + + if (!match) { + dev_err(dev, "[%s] : Failed to find matching dt id\n", + __func__); + return NULL; + } + + board_priv_pdata = + devm_kzalloc(dev, sizeof(*board_priv_pdata), GFP_KERNEL); + + err = of_property_read_string(node, "mclk", + &board_priv_pdata->mclk_name); + + if (err) { + dev_err(dev, "[%s] : mclk not in DT\n", __func__); + } + + return board_priv_pdata; +} + +/* tier4_imx728_set_mode() can not be needed. But it remains for compatiblity */ + +static int tier4_imx728_set_mode(struct tegracam_device *tc_dev) +{ + volatile int err = 0; + + return err; +} + +static int tier4_imx728_start_one_streaming(struct tegracam_device *tc_dev) +{ + struct tier4_imx728 *priv = + (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); + struct device *dev = tc_dev->dev; + int err; + + /* enable serdes streaming */ + + err = tier4_max9295_setup_streaming(priv->ser_dev); + + if (err) { + goto exit; + } + + err = tier4_max9296_setup_streaming(priv->dser_dev, dev); + + if (err) { + dev_err(dev, "[%s] : Setup Streaming failed\n", __func__); + goto exit; + } + + dev_info(dev, "[%s] : trigger_mode = %d\n", __func__, trigger_mode); + + priv->trigger_mode = trigger_mode; + + switch (priv->trigger_mode) { + case GW5300_MASTER_MODE_5FPS: + case GW5300_MASTER_MODE_10FPS: + case GW5300_MASTER_MODE_10FPS_EBD: + case GW5300_MASTER_MODE_20FPS: + case GW5300_MASTER_MODE_20FPS_EBD: + case GW5300_MASTER_MODE_30FPS: + case GW5300_MASTER_MODE_30FPS_EBD: + dev_info(dev, "[%s] : Setting camera sensor to %s\n", __func__, + gw5300_mode_name[priv->trigger_mode]); + + err = tier4_gw5300_c3_setup_sensor_mode(priv->isp_dev, + priv->trigger_mode); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to %s failed\n", + __func__, gw5300_mode_name[priv->trigger_mode]); + return err; + } + + priv->last_distortion_correction = 1; + break; + + case GW5300_SLAVE_MODE_5FPS: + case GW5300_SLAVE_MODE_10FPS: + case GW5300_SLAVE_MODE_10FPS_EBD: + case GW5300_SLAVE_MODE_20FPS: + case GW5300_SLAVE_MODE_20FPS_EBD: + case GW5300_SLAVE_MODE_30FPS: + case GW5300_SLAVE_MODE_30FPS_EBD: + dev_info(dev, "[%s] : Setting camera sensor to %s\n", __func__, + gw5300_mode_name[priv->trigger_mode]); + + err = tier4_imx728_set_fsync_trigger_mode(priv, + priv->trigger_mode); + if (err) { + dev_err(dev, + "[%s] : setting camera sensor to %s failed\n", + __func__, gw5300_mode_name[priv->trigger_mode]); + return err; + } + + priv->last_distortion_correction = 1; + break; + + default: // case of trigger_mode < 0 + dev_err(dev, + "[%s] : The camera sensor mode(trigger mode)=%d is invalid.\n", + __func__, priv->trigger_mode); + + return err; + } + + usleep_range(500000, 510000); + err = tier4_gw5300_c3_set_auto_exposure(priv->isp_dev, + enable_auto_exposure); + if (err <= 0) { + dev_err(dev, + "[%s] : Setting Digital Gain to default value failed\n", + __func__); + goto exit; + } else { + err = 0; + } + +#if USE_DISTORTION_CORRECTION + + if (priv->last_distortion_correction != enable_distortion_correction) { + usleep_range(500000, 510000); + //msleep(900); + } + + if (enable_distortion_correction == 0xCAFE) { + // if not set kernel param, read device tree param + if (priv->distortion_correction == false) { + err = tier4_imx728_set_distortion_correction( + tc_dev, priv->distortion_correction); + + if (err) { + dev_err(dev, + "[%s] : Disabling Distortion Correction failed\n", + __func__); + goto exit; + } + msleep(20); + } + } else { + err = tier4_imx728_set_distortion_correction( + tc_dev, enable_distortion_correction == 1); + if (err) { + dev_err(dev, + "[%s] : Setup Distortion Correction failed\n", + __func__); + goto exit; + } + msleep(20); + } + +#endif + + // Reset GW5300 via Max9295 in C3 camera + // err = tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_IMX728, POWER_ON ); + // if (err) + // { + // dev_err(dev, "[%s] : Reset gw5300 in C3 camaera failed.\n", __func__); + // goto exit; + // } + // + // usleep_range(500000, 510000); + + err = tier4_max9296_start_streaming(priv->dser_dev, dev); + + if (err) { + dev_err(dev, "[%s] : tier4_max9296_start_stream() failed\n", + __func__); + return err; + } + + msleep(1000); + tier4_gw5300_c3_set_integration_time_on_aemode(priv->isp_dev, + priv->trigger_mode, + shutter_time_max, + shutter_time_min); + + // Reset GW5300 via Max9295 in C3 camera + // err = tier4_max9295_control_sensor_power_seq(priv->ser_dev, SENSOR_ID_IMX728, POWER_ON ); + // if (err) + // { + // dev_err(dev, "[%s] : Reset gw5300 in C3 camaera failed.\n", __func__); + // goto exit; + // } + + dev_info(dev, "[%s] : Camera has started streaming\n", __func__); + + return NO_ERROR; + +exit: + + dev_err(dev, "[%s] : Camera failed to start streaming.\n", __func__); + + return err; +} + +static bool tier4_imx728_is_camera_connected_to_port(int nport) +{ + if (wst_priv[nport].p_client) { + return true; + } + return false; +} + +static bool tier4_imx728_check_null_tc_dev_for_port(int nport) +{ + if (wst_priv[nport].p_tc_dev == NULL) { + return true; + } + return false; +} + +static bool tier4_imx728_is_camera_running_on_port(int nport) +{ + if (wst_priv[nport].running) { + return true; + } + return false; +} + +static bool tier4_imx728_is_current_port(struct tier4_imx728 *priv, int nport) +{ + if (priv->i2c_client == wst_priv[nport].p_client) { + return true; + } + return false; +} + +static void tier4_imx728_set_running_flag(int nport, bool flag) +{ + wst_priv[nport].running = flag; +} + +static int tier4_imx728_stop_streaming(struct tegracam_device *tc_dev) +{ + struct device *dev = tc_dev->dev; + struct tier4_imx728 *priv = + (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); + int i, err = 0; + + mutex_lock(&tier4_imx728_lock); + + for (i = 0; i < camera_channel_count; i++) { + if (tier4_imx728_is_camera_connected_to_port(i)) { + if (tier4_imx728_is_current_port(priv, i) && + tier4_imx728_is_camera_running_on_port(i)) { + /* disable serdes streaming */ + err = tier4_max9296_stop_streaming( + priv->dser_dev, dev); + if (err) { + return err; + } + tier4_imx728_set_running_flag(i, false); + break; + } + } + } + + mutex_unlock(&tier4_imx728_lock); + + return NO_ERROR; +} + +/* *************************************************************************** */ +/* 1. In the case where a camera is connected to GMSL A port on a Des. */ +/* */ +/* a > Check if another camera is connected to GMSL B port */ +/* a-1) Connected: */ +/* b > Check if another camera on GMSL B port is running */ +/* b-1) Running: */ +/* c > Check if the camera on GMSL A port is running */ +/* c-1) Running : */ +/* Do nothing and return */ +/* c-2) Not running : */ +/* Start the camera on GMSL A port. */ +/* b-2) Not Running: */ +/* Start the camera on GMSL B port. */ +/* a-2) Not connected : */ +/* b > Check if the camera on GMSL A port is running */ +/* b-1) Running : */ +/* Do nothing and return */ +/* b-2) Not running : */ +/* Start the camera on GMSL A port. */ +/* */ +/* 2. In the case where a camera is connected to GMSL B port on a Des. */ +/* */ +/* a > Check if the camera on GMSL B port is running */ +/* a-1) Running : */ +/* Do nothing and return */ +/* a-2) Not running : */ +/* Start the camera on GMSL B port. */ +/* *************************************************************************** */ + +static int tier4_imx728_start_streaming(struct tegracam_device *tc_dev) +{ + int i, err = 0; + // struct tier4_imx728 *next_client_priv; + struct tier4_imx728 *priv = + (struct tier4_imx728 *)tegracam_get_privdata(tc_dev); + struct device *dev = tc_dev->dev; + + mutex_lock(&tier4_imx728_lock); + + for (i = 0; i < camera_channel_count; i++) { + if (i & 0x1) { // if i = 1,3,5,7 ( GMSL B port of a Des ) + + if (tier4_imx728_is_camera_connected_to_port( + i)) { // a camera is connected to GMSL B portL + + if ((tier4_imx728_is_current_port(priv, i) == + true) && + (tier4_imx728_is_camera_running_on_port( + i) == false)) { + err = tier4_imx728_start_one_streaming( + wst_priv[i].p_tc_dev); + + if (err) { + dev_err(dev, + "[%s] : Failed to start one streaming.\n", + __func__); + goto error_exit; + } + // wst_priv[i].running = true; + tier4_imx728_set_running_flag(i, true); + break; + } + } + } else { // if i = 0,2,4,6 ( GMSL A side port of a Des0,Des1,Des2 or Des3 ) + + if ((tier4_imx728_is_camera_connected_to_port(i) == + true) && + (tier4_imx728_is_current_port(priv, i) == true)) { + if (tier4_imx728_is_camera_connected_to_port( + i + 1) == + false) { // if another one camera( GMSL B port) is not + // connected to Des. + if (tier4_imx728_is_camera_running_on_port( + i) == + false) { // and if the camera is not running. + + err = tier4_imx728_start_one_streaming( + wst_priv[i].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Failed to start one streaming for next imx728 client.\n", + __func__); + goto error_exit; + } + tier4_imx728_set_running_flag( + i, true); + } + break; + } + + // two cameras are connected to one Des. + + if (tier4_imx728_check_null_tc_dev_for_port( + i + 1)) { // check if tc_dev is null + dev_err(dev, + "[%s] : wst_priv[%d].p_tc_dev is NULL.\n", + __func__, i + 1); + err = -EINVAL; + goto error_exit; + } + + if (tier4_imx728_is_camera_running_on_port( + i + 1) == false) { + err = tier4_imx728_start_one_streaming( + wst_priv[i + 1].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Failed to start one streaming for the next imx728 client.\n", + __func__); + goto error_exit; + } + tier4_imx728_set_running_flag(i + 1, + true); + usleep_range(200000, 220000); + //msleep(200); + mutex_unlock(&tier4_imx728_lock); + tier4_imx728_stop_streaming( + wst_priv[i + 1].p_tc_dev); + mutex_lock(&tier4_imx728_lock); + tier4_imx728_set_running_flag(i + 1, + false); + } + + if (tier4_imx728_is_camera_running_on_port(i) == + false) { + err = tier4_imx728_start_one_streaming( + wst_priv[i].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Failed to start one streaming for current imx728 client.\n", + __func__); + goto error_exit; + } + tier4_imx728_set_running_flag(i, true); + } + } + } + } // for loop + + err = NO_ERROR; + +error_exit: + + mutex_unlock(&tier4_imx728_lock); + + // tier4_imx728_sensor_mutex_unlock(); + + return err; +} + +static struct camera_common_sensor_ops tier4_imx728_common_ops = { + .numfrmfmts = ARRAY_SIZE(tier4_imx728_frmfmt), + .frmfmt_table = tier4_imx728_frmfmt, + .power_on = tier4_imx728_power_on, + .power_off = tier4_imx728_power_off, + .write_reg = tier4_imx728_write_reg, + .read_reg = tier4_imx728_read_reg, + .parse_dt = tier4_imx728_parse_dt, + .power_get = tier4_imx728_power_get, + .power_put = tier4_imx728_power_put, + .set_mode = tier4_imx728_set_mode, + .start_streaming = tier4_imx728_start_streaming, + .stop_streaming = tier4_imx728_stop_streaming, +}; + +static int tier4_imx728_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + //struct i2c_client *client = v4l2_get_subdevdata(sd); + + return NO_ERROR; +} + +static const struct v4l2_subdev_internal_ops tier4_imx728_subdev_internal_ops = { + .open = tier4_imx728_open, +}; + +static const char *of_stdout_options; + +static int tier4_imx728_board_setup(struct tier4_imx728 *priv) +{ + struct tegracam_device *tc_dev = priv->tc_dev; + struct device *dev = tc_dev->dev; + struct device_node *node = dev->of_node; + struct device_node *ser_node; + struct i2c_client *ser_i2c = NULL; + struct device_node *dser_node; + struct i2c_client *dser_i2c = NULL; + struct device_node *isp_node; + struct i2c_client *isp_i2c = NULL; + struct device_node *fpga_node = NULL; + struct i2c_client *fpga_i2c = NULL; + struct device_node *gmsl; + struct device_node *root_node; + int value = 0xFFFF; + const char *str_value; + const char *str_value1[2]; + int i; + int err; + const char *str_model; + char upper_str_model[64]; + char *str_err; + char *sub_str_err; + + root_node = of_find_node_opts_by_path("/", &of_stdout_options); + + err = of_property_read_string(root_node, "model", &str_model); + + if (err < 0) { + dev_err(dev, "[%s] : model not found\n", __func__); + goto error; + } + + memset(upper_str_model, 0, 64); + + to_upper_string(upper_str_model, str_model); + + priv->g_ctx.hardware_model = HW_MODEL_UNKNOWN; + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_XAVIER); + if (str_err) { + priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_XAVIER_DEVKIT; + } + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_XAVIER); + if (str_err) { + priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_XAVIER; + } + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ORIN); + + if (str_err) { + sub_str_err = strstr(upper_str_model, + STR_DTB_MODEL_NAME_ROSCUBE_ORIN); + + if (sub_str_err) { + priv->g_ctx.hardware_model = + HW_MODEL_ADLINK_ROSCUBE_ORIN; + } else { + priv->g_ctx.hardware_model = + HW_MODEL_NVIDIA_ORIN_DEVKIT; + } + } + + dev_info(dev, "[%s] : model=%s\n", __func__, str_model); + dev_info(dev, "[%s] : hardware_model=%d\n", __func__, + priv->g_ctx.hardware_model); + + if (priv->g_ctx.hardware_model == HW_MODEL_UNKNOWN) { + dev_err(dev, "[%s] : Unknown Hardware Sysytem !\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_isp_reg); + + if (err < 0) { + dev_err(dev, "[%s] : def-addr not found\n", __func__); + goto error; + } + + if (err < 0) { + dev_err(dev, "[%s] : reg not found\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "def-addr", &priv->g_ctx.sdev_isp_def); + + if (err < 0) { + dev_err(dev, "[%s] : def-addr not found\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "reg_mux", &priv->g_ctx.reg_mux); + + if (err < 0) { + dev_err(dev, "[%s] : reg_mux not found\n", __func__); + goto error; + } + + // err = of_property_read_string(node, "fsync-mode", &str_value); + // + // if (err < 0) + // { + // dev_err(dev, "[%s] : No fsync-mode found\n", __func__); + // goto error; + // } + // + // if (!strcmp(str_value, "true")) + // { + // priv->fsync_mode = true; + // } + // else + // { + // priv->fsync_mode = false; + // } + + err = of_property_read_string(node, "distortion-correction", + &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No distortion-correction found\n", + __func__); + goto error; + } + + if (!strcmp(str_value, "true")) { + priv->distortion_correction = true; + } else { + priv->distortion_correction = false; + } + + if (enable_auto_exposure == 0xCAFE) { + err = of_property_read_string(node, "auto-exposure", + &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : Inavlid Exposure mode.\n", + __func__); + goto error; + } + + enable_auto_exposure = !strcmp(str_value, "true"); + } else { + dev_info(dev, "[%s] : Parameter[enable_auto_exposure] = %d.\n", + __func__, enable_auto_exposure); + } + +#if 0 + priv->g_ctx.fpga_generate_fsync = false; + + if (( priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER ) || + ( priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN )) { + + err = of_property_read_string(node, "fpga-generate-fsync", &str_value); + + if ( err < 0) { + if ( err == -EINVAL ) { + dev_info(dev, "[%s] : Parameter of fpga-generate-fsync does not exist.\n", __func__); + } else { + dev_err(dev, "[%s] : Parameter of fpga-generate-fsync is invalid .\n", __func__); + goto error; + } + } else { + if (!strcmp(str_value, "true")) { + priv->g_ctx.fpga_generate_fsync = true; + } + } + } +#endif + + // For Ser node + ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0); + + if (ser_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,gmsl-ser-device"); + goto error; + } + + err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg); + + if (err < 0) { + dev_err(dev, "[%s] : Serializer reg not found\n", __func__); + goto error; + } + + ser_i2c = of_find_i2c_device_by_node(ser_node); + + of_node_put(ser_node); + + if (ser_i2c == NULL) { + dev_err(dev, "[%s] : Missing Serializer Dev Handle\n", + __func__); + goto error; + } + if (ser_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing serializer driver\n", __func__); + goto error; + } + + priv->ser_dev = &ser_i2c->dev; + + // For ISP node + + isp_node = of_parse_phandle(node, "nvidia,isp-device", 0); + + if (isp_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,isp-device"); + goto error; + } + + err = of_property_read_u32(isp_node, "reg", &priv->g_ctx.sdev_isp_reg); + + if (err < 0) { + dev_err(dev, "[%s] : ISP reg not found\n", __func__); + goto error; + } + + isp_i2c = of_find_i2c_device_by_node(isp_node); + + of_node_put(isp_node); + + if (isp_i2c == NULL) { + dev_err(dev, "[%s] : Missing ISP Dev Handle\n", __func__); + goto error; + } + if (isp_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing ISP driver\n", __func__); + goto error; + } + + priv->isp_dev = &isp_i2c->dev; + + err = tier4_gw5300_prim_slave_addr(&priv->g_ctx); + if (err) { + dev_err(dev, + "[%s] : ISP Prim slave address is unavailable, the default address(0x6D) is applied.\n", + __func__); + priv->g_ctx.sdev_isp_def = ISP_PRIM_SLAVE_ADDR; + } + + priv->g_ctx.sdev_reg = priv->g_ctx.sdev_isp_reg; + priv->g_ctx.sdev_def = priv->g_ctx.sdev_isp_def; + + // For Dser node + + dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0); + + if (dser_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,gmsl-dser-device"); + goto error; + } + + dser_i2c = of_find_i2c_device_by_node(dser_node); + + of_node_put(dser_node); + + if (dser_i2c == NULL) { + dev_err(dev, "[%s] : Missing deserializer dev handle\n", + __func__); + goto error; + } + + if (dser_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing deserializer driver\n", __func__); + goto error; + } + + priv->dser_dev = &dser_i2c->dev; + + if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || + (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + // for FPGA node + + fpga_node = of_parse_phandle(node, "nvidia,fpga-device", 0); + + if (fpga_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,fpga-device"); + goto error; + } + + err = of_property_read_u32(fpga_node, "reg", + &priv->g_ctx.sdev_fpga_reg); + + if (err < 0) { + dev_err(dev, "[%s] : FPGA reg not found\n", __func__); + goto error; + } + + fpga_i2c = of_find_i2c_device_by_node(fpga_node); + + of_node_put(fpga_node); + + if (fpga_i2c == NULL) { + dev_err(dev, "[%s] : Missing FPGA Dev Handle\n", + __func__); + goto error; + } + if (fpga_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing FPGA driver\n", __func__); + goto error; + } + + priv->fpga_dev = &fpga_i2c->dev; + } + + /* populate g_ctx from DT */ + + gmsl = of_get_child_by_name(node, "gmsl-link"); + + if (gmsl == NULL) { + dev_err(dev, "[%s] : Missing GMSL-Link device node\n", + __func__); + err = -EINVAL; + goto error; + } + + err = of_property_read_string(gmsl, "dst-csi-port", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No dst-csi-port found\n", __func__); + goto error; + } + + priv->g_ctx.dst_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : + GMSL_CSI_PORT_B; + + err = of_property_read_string(gmsl, "src-csi-port", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No src-csi-port found\n", __func__); + goto error; + } + + priv->g_ctx.src_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : + GMSL_CSI_PORT_B; + + err = of_property_read_string(gmsl, "csi-mode", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No csi-mode found\n", __func__); + goto error; + } + + if (!strcmp(str_value, "1x4")) { + priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE; + } else if (!strcmp(str_value, "2x4")) { + priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE; + } else if (!strcmp(str_value, "4x2")) { + priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE; + } else if (!strcmp(str_value, "2x2")) { + priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE; + } else { + dev_err(dev, "[%s] :Invalid csi-mode\n", __func__); + goto error; + } + + err = of_property_read_string(gmsl, "serdes-csi-link", &str_value); + + if (err < 0) { + dev_err(dev, "[%s] : No serdes-csi-link found\n", __func__); + goto error; + } + + priv->g_ctx.serdes_csi_link = (!strcmp(str_value, "a")) ? + GMSL_SERDES_CSI_LINK_A : + GMSL_SERDES_CSI_LINK_B; + + err = of_property_read_u32(gmsl, "st-vc", &value); + + if (err < 0) { + dev_err(dev, "[%s] : No st-vc info\n", __func__); + goto error; + } + + priv->g_ctx.st_vc = value; + + err = of_property_read_u32(gmsl, "vc-id", &value); + + if (err < 0) { + dev_err(dev, "[%s] : No vc-id info\n", __func__); + goto error; + } + + priv->g_ctx.dst_vc = value; + + err = of_property_read_u32(gmsl, "num-lanes", &value); + + if (err < 0) { + dev_err(dev, "[%s] : No num-lanes info\n", __func__); + goto error; + } + + priv->g_ctx.num_csi_lanes = value; + + priv->g_ctx.num_streams = of_property_count_strings(gmsl, "streams"); + + if (priv->g_ctx.num_streams <= 0) { + dev_err(dev, "[%s] : No streams found\n", __func__); + err = -EINVAL; + goto error; + } + + for (i = 0; i < priv->g_ctx.num_streams; i++) { + of_property_read_string_index(gmsl, "streams", i, + &str_value1[i]); + + if (!str_value1[i]) { + dev_err(dev, "[%s] : Invalid Stream Info\n", __func__); + goto error; + } + + if (!strcmp(str_value1[i], "raw12")) { + priv->g_ctx.streams[i].st_data_type = + GMSL_CSI_DT_RAW_12; + } else if (!strcmp(str_value1[i], "yuv8")) { + priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_YUV_8; + } else if (!strcmp(str_value1[i], "embed")) { + priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_EMBED; + } else if (!strcmp(str_value1[i], "ued-u1")) { + priv->g_ctx.streams[i].st_data_type = + GMSL_CSI_DT_UED_U1; + } else { + dev_err(dev, "[%s] : Invalid stream data type\n", + __func__); + goto error; + } + } + + priv->g_ctx.s_dev = dev; + + return NO_ERROR; + +error: + dev_err(dev, "[%s] : Board Setup failed\n", __func__); + return err; +} + +static int tier4_imx728_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *node = dev->of_node; + struct tegracam_device *tc_dev; + struct tier4_imx728 *priv; + int err = 0; + + dev_info(dev, "[%s] : Probing V4L2 Sensor.\n", __func__); + + if (!IS_ENABLED(CONFIG_OF) || !node) { + return -EINVAL; + } + + wst_priv[camera_channel_count].p_client = NULL; + wst_priv[camera_channel_count].p_priv = NULL; + wst_priv[camera_channel_count].p_tc_dev = NULL; + + wst_priv[camera_channel_count].isp_ser_shutdown = false; + wst_priv[camera_channel_count].des_shutdown = false; + wst_priv[camera_channel_count].running = false; + + priv = devm_kzalloc(dev, sizeof(struct tier4_imx728), GFP_KERNEL); + + if (!priv) { + dev_err(dev, "[%s] : Unable to allocate Memory!\n", __func__); + return -ENOMEM; + } + + tc_dev = devm_kzalloc(dev, sizeof(struct tegracam_device), GFP_KERNEL); + + if (!tc_dev) { + return -ENOMEM; + } + + priv->i2c_client = tc_dev->client = client; + + tc_dev->dev = dev; + + strncpy(tc_dev->name, "imx728", sizeof(tc_dev->name)); + + tc_dev->dev_regmap_config = &tier4_sensor_regmap_config; + tc_dev->sensor_ops = &tier4_imx728_common_ops; + tc_dev->v4l2sd_internal_ops = &tier4_imx728_subdev_internal_ops; + tc_dev->tcctrl_ops = &tier4_imx728_ctrl_ops; + + err = tegracam_device_register(tc_dev); + + if (err) { + dev_err(dev, "[%s] : Tegra Camera Driver Registration failed\n", + __func__); + return err; + } + + priv->tc_dev = tc_dev; + priv->s_data = tc_dev->s_data; + priv->subdev = &tc_dev->s_data->subdev; + + tegracam_set_privdata(tc_dev, (void *)priv); + + priv->g_ctx.sensor_id = SENSOR_ID_IMX728; + + tier4_isx021_sensor_mutex_lock(); + + err = tier4_imx728_board_setup(priv); + + if (err) { + dev_err(dev, "[%s] : Board Setup failed\n", __func__); + goto err_tegracam_unreg; + } + + /* Pair sensor to serializer dev */ + + err = tier4_max9295_sdev_pair(priv->ser_dev, &priv->g_ctx); + + if (err) { + dev_err(&client->dev, "[%s] : GMSL Ser Pairing failed\n", + __func__); + goto err_tegracam_unreg; + } + /* Register sensor to deserializer dev */ + + err = tier4_max9296_sdev_register(priv->dser_dev, &priv->g_ctx); + + if (err) { + dev_err(&client->dev, + "[%s] : GMSL Deserializer Register failed\n", __func__); + goto err_max9295_unpair; + } + + /* + * gmsl serdes setup + * + * Sensor power on/off should be the right place for serdes + * setup/reset. But the problem is, the total required delay + * in serdes setup/reset exceeds the frame wait timeout, looks to + * be related to multiple channel open and close sequence + * issue (#BUG 200477330). + * Once this bug is fixed, these may be moved to power on/off. + * The delays in serdes is as per guidelines and can't be reduced, + * so it is placed in probe/remove, though for that, deserializer + * would be powered on always post boot, until 1.2v is supplied + * to deserializer from CVB. + */ + + err = tier4_imx728_gmsl_serdes_setup(priv); + + if (err) { + dev_err(&client->dev, "[%s] : GMSL Serdes setup failed\n", + __func__); + goto err_max9296_unreg; + } + + err = tegracam_v4l2subdev_register(tc_dev, true); + + if (err) { + dev_err(dev, "[%s] : Tegra Camera Subdev Registration failed\n", + __func__); + goto err_max9296_unreg; + } + + wst_priv[camera_channel_count].p_client = client; + wst_priv[camera_channel_count].p_priv = priv; + wst_priv[camera_channel_count].p_tc_dev = tc_dev; + + camera_channel_count++; + + tier4_isx021_sensor_mutex_unlock(); + + return NO_ERROR; + + // tier4_isx021_sensor_mutex_unlock(); + + // dev_info(&client->dev, "Detected Tier4 IMX490 sensor\n"); + +err_max9296_unreg: + tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); +err_max9295_unpair: + tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); +err_tegracam_unreg: + tegracam_device_unregister(priv->tc_dev); + + tier4_isx021_sensor_mutex_unlock(); + + // dev_info(dev, "[%s] :camera_channel_count = %d p_client = %p \n", __func__, camera_channel_count, + // wst_priv[camera_channel_count].p_client); + + return err; + //return NO_ERROR; // err; +} + +static int tier4_imx728_remove(struct i2c_client *client) +{ + struct camera_common_data *s_data = to_camera_common_data(&client->dev); + struct tier4_imx728 *priv = (struct tier4_imx728 *)s_data->priv; + + tier4_imx728_gmsl_serdes_reset(priv); + + tegracam_v4l2subdev_unregister(priv->tc_dev); + + tegracam_device_unregister(priv->tc_dev); + + return NO_ERROR; +} + +static struct mutex tier4_imx728_lock; + +static bool tier4_imx728_is_isp_ser_shutdown(int nport) +{ + if (wst_priv[nport].isp_ser_shutdown) { + return true; + } + return false; +} + +static bool tier4_imx728_is_des_shutdown(int nport) +{ + if (wst_priv[nport].des_shutdown) { + return true; + } + return false; +} + +static void tier4_imx728_set_isp_ser_shutdown(int nport, bool val) +{ + wst_priv[nport].isp_ser_shutdown = val; +} + +static void tier4_imx728_set_des_shutdown(int nport, bool val) +{ + wst_priv[nport].des_shutdown = val; +} + +static bool tier4_imx728_is_current_i2c_client(struct i2c_client *client, + int nport) +{ + if (client == wst_priv[nport].p_client) { + return true; + } + return false; +} + +// ---------------------------------------------------------------------------- + +static void tier4_imx728_shutdown(struct i2c_client *client) +{ + struct tier4_imx728 *priv = NULL; + int i; + + tier4_isx021_sensor_mutex_lock(); + + mutex_lock(&tier4_imx728_lock); + + if (!client) { + goto error_exit; + } + + for (i = 0; i < camera_channel_count; i++) { + if (tier4_imx728_is_current_i2c_client(client, i)) { + priv = wst_priv[i].p_priv; + + if (i & + 0x1) { // Even port number( GMSL B port on a Des : i = port_number -1 ) + + if (tier4_imx728_is_camera_connected_to_port( + i - + 1)) { // if a camera connected to another(GMSL A)port on a Des. + // a camera is connected to each port of the Des. + if (tier4_imx728_is_isp_ser_shutdown( + i - + 1)) { // ISP and Ser on another(GMSL A) port have been already shut down ? + + if (tier4_imx728_is_des_shutdown( + i - 1) == + false) { // if Des on another(GMSL A)port is not shutdown yet + tier4_imx728_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx728_set_des_shutdown( + i, + true); // Des will be shut down + } else { // if Des on the another port is already shut down. This is Error case. + tier4_imx728_set_isp_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_imx728_set_des_shutdown( + i, + false); // Des will not be shutdown + } + } else { // The camera ISP and Ser on another(GMSL A) port are not shut down yet. + + if (tier4_imx728_is_des_shutdown( + i - 1) == + false) { // if Des is not shut down yet. + tier4_imx728_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx728_set_des_shutdown( + i, + false); // The Des won't be shut down. + } else { // Only Des on another port is already shut down. This is Error case. + tier4_imx728_set_isp_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_imx728_set_des_shutdown( + i, + false); // Des will not be shut down. + } + } // a camera is connected to only (GMSL B) port on Des. + tier4_imx728_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx728_set_des_shutdown( + i, + true); // The Des won't be shut down. + } + } else { // if ( i & 0x1 ) == 0 + + if (tier4_imx728_is_camera_connected_to_port( + i + + 1)) { // Another camera is connected to another(GMSL B) port on the Des + + if (tier4_imx728_is_isp_ser_shutdown( + i + + 1)) { // if the ISP and Ser on another port are already shut down + + if (tier4_imx728_is_des_shutdown( + i + 1) == + false) { // if Des is not shut down yet. + tier4_imx728_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx728_set_des_shutdown( + i, + false); // The Des will be shut down. + } else { // Des is already shut down. This is Error case. + tier4_imx728_set_isp_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_imx728_set_des_shutdown( + i, + false); // The Des will not be shut down. + } + } else { // The ISP and Ser on another(GMSL B) port are not shut down yet. + + if (tier4_imx728_is_des_shutdown( + i + 1) == + false) { // if Des on another(GMSL B) port is not shut down yet. + + tier4_imx728_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx728_set_des_shutdown( + i, + false); // The Des will not be shut down. + } else { // Only Des on another(GMSL B) port is already shut down. + // This is Error case. + tier4_imx728_set_isp_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_imx728_set_des_shutdown( + i, + false); // The Des will not be shut down. + } + } + } else { + tier4_imx728_set_isp_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_imx728_set_des_shutdown( + i, + true); // The Des will be shut down. + } + } // if ( i & 0x1 ) + // break; + + if (tier4_imx728_is_isp_ser_shutdown(i)) { + // Reset camera sensor + tier4_max9295_control_sensor_power_seq( + priv->ser_dev, SENSOR_ID_IMX728, false); + // S/W Reset max9295 + tier4_max9295_reset_control(priv->ser_dev); + } + + if (tier4_imx728_is_des_shutdown(i)) { + // S/W Reset max9296 + tier4_max9296_reset_control(priv->dser_dev, + &client->dev, true); + } + + if (priv == NULL || i >= camera_channel_count) { + mutex_unlock(&tier4_imx728_lock); + tier4_isx021_sensor_mutex_unlock(); + return; + } + } + + } // for loop + +error_exit: + + mutex_unlock(&tier4_imx728_lock); + + tier4_isx021_sensor_mutex_unlock(); +} +static const struct i2c_device_id tier4_imx728_id[] = { { "tier4_imx728", 0 }, + {} }; + +MODULE_DEVICE_TABLE(i2c, tier4_imx728_id); + +static struct i2c_driver tier4_imx728_i2c_driver = { + .driver = { + .name = "tier4_imx728", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tier4_imx728_of_match), + }, + .probe = tier4_imx728_probe, + .remove = tier4_imx728_remove, + .shutdown = tier4_imx728_shutdown, + .id_table = tier4_imx728_id, +}; + +static int __init tier4_imx728_init(void) +{ + mutex_init(&serdes_lock__); + mutex_init(&tier4_imx728_lock); + + printk(KERN_INFO "TIERIV Automotive HDR Camera driver.\n"); + + return i2c_add_driver(&tier4_imx728_i2c_driver); +} + +static void __exit tier4_imx728_exit(void) +{ + mutex_destroy(&serdes_lock__); + mutex_destroy(&tier4_imx728_lock); + + i2c_del_driver(&tier4_imx728_i2c_driver); +} + +module_init(tier4_imx728_init); +module_exit(tier4_imx728_exit); + +MODULE_DESCRIPTION("TIERIV Automotive HDR Camera driver"); +MODULE_AUTHOR("Originaly NVIDIA Corporation"); +MODULE_AUTHOR("K.Iwasaki"); +MODULE_AUTHOR("Y.Fujii"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-isx021-extern.h b/src/tier4-camera-gmsl/tier4-isx021-extern.h similarity index 100% rename from drivers/src/tier4-isx021-extern.h rename to src/tier4-camera-gmsl/tier4-isx021-extern.h diff --git a/drivers/src/tier4-isx021.bin b/src/tier4-camera-gmsl/tier4-isx021.bin similarity index 100% rename from drivers/src/tier4-isx021.bin rename to src/tier4-camera-gmsl/tier4-isx021.bin diff --git a/src/tier4-camera-gmsl/tier4-isx021.c b/src/tier4-camera-gmsl/tier4-isx021.c new file mode 100644 index 0000000..1ae1bb9 --- /dev/null +++ b/src/tier4-camera-gmsl/tier4-isx021.c @@ -0,0 +1,3195 @@ +/* + * isx021.c - isx021 sensor driver + * + * Copyright (c) 2022-2023, TIERIV INC. All rights reserved. + * Copyright (c) 2018-2021, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// --------------------------------------------------------------- + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 65) +#include +#endif + +#include + +#include "tier4-fpga.h" +#include "tier4-gmsl-link.h" +#include "tier4-hw-model.h" +#include "tier4-max9295.h" +#include "tier4-max9296.h" + +#define USE_FIRMWARE + +//#define USE_I2C_TRANSFER +#define USE_I2C_READ_REG + +#undef SHOW_I2C_READ_MSG + +#define SHOW_I2C_WRITE_MSG +//#undef SHOW_I2C_WRITE_MSG + +#undef USE_CHECK_MODE_SEL + +#undef USE_EMBEDDED_METADAT_HEIGHT_IN_DTB + +MODULE_SOFTDEP("pre: tier4_max9296"); +MODULE_SOFTDEP("pre: tier4_max9295"); +MODULE_SOFTDEP("pre: tier4_fpga"); + +// Register Address + +#define ISX021_SG_MODE_INTERNAL_SYNC 0 + +#define ISX021_SG_MODE_INTERNAL_SYNC 0 + +#define ISX021_MIN_GAIN 0 +#define ISX021_MAX_GAIN 48 + +#define ISX021_MIN_EXPOSURE_TIME 0 +#define ISX021_MID_EXPOSURE_TIME 11010 // 11 milisecond +#define ISX021_MAX_EXPOSURE_TIME 33000 // 33 milisecond + +#define ISX021_GAIN_DEFAULT_VALUE 6 + +#define ISX021_DEFAULT_FRAME_LENGTH (1125) + +// --- Start of Register definition ------------------ + +#define TIER4_ISX021_REG_0_ADDR 0 +#define TIER4_ISX021_REG_1_ADDR 1 +#define TIER4_ISX021_REG_2_ADDR 2 +#define TIER4_ISX021_REG_3_ADDR 3 +#define TIER4_ISX021_REG_4_ADDR 4 +#define TIER4_ISX021_REG_5_ADDR 5 +#define TIER4_ISX021_REG_6_ADDR 6 +#define TIER4_ISX021_REG_7_ADDR 7 +#define TIER4_ISX021_REG_8_ADDR 8 +#define TIER4_ISX021_REG_9_ADDR 9 +#define TIER4_ISX021_REG_10_ADDR 10 +#define TIER4_ISX021_REG_11_ADDR 11 +#define TIER4_ISX021_REG_12_ADDR 12 +#define TIER4_ISX021_REG_13_ADDR 13 + +#define TIER4_ISX021_REG_14_ADDR 14 + +// AE mode + +#define TIER4_ISX021_REG_15_ADDR 15 +#define TIER4_ISX021_REG_16_ADDR 16 +#define TIER4_ISX021_REG_17_ADDR 17 +#define TIER4_ISX021_REG_18_ADDR 18 + +#define TIER4_ISX021_REG_19_ADDR 19 +#define TIER4_ISX021_REG_20_ADDR 20 +#define TIER4_ISX021_REG_21_ADDR 21 +#define TIER4_ISX021_REG_22_ADDR 22 + +// ME mode + +#define TIER4_ISX021_REG_23_ADDR 23 +#define TIER4_ISX021_REG_24_ADDR 24 +#define TIER4_ISX021_REG_25_ADDR 25 +#define TIER4_ISX021_REG_26_ADDR 26 + +#define TIER4_ISX021_REG_27_ADDR 27 +#define TIER4_ISX021_REG_28_ADDR 28 +#define TIER4_ISX021_REG_29_ADDR 29 +#define TIER4_ISX021_REG_30_ADDR 30 + +// Analog Gain + +#define TIER4_ISX021_REG_31_ADDR 31 +#define TIER4_ISX021_REG_32_ADDR 32 + +#define TIER4_ISX021_REG_33_ADDR 33 +#define TIER4_ISX021_REG_34_ADDR 34 + +#define TIER4_ISX021_REG_35_ADDR 35 +#define TIER4_ISX021_REG_36_ADDR 36 + +#define TIER4_ISX021_REG_37_ADDR 37 +#define TIER4_ISX021_REG_38_ADDR 38 + +#define TIER4_ISX021_REG_39_ADDR 39 +#define TIER4_ISX021_REG_40_ADDR 40 + +#define TIER4_ISX021_REG_41_ADDR 41 +#define TIER4_ISX021_REG_42_ADDR 42 + +#define TIER4_ISX021_REG_43_ADDR 43 +#define TIER4_ISX021_REG_44_ADDR 44 + +#define TIER4_ISX021_REG_45_ADDR 45 +#define TIER4_ISX021_REG_46_ADDR 46 + +// Exposure + +#define TIER4_ISX021_REG_47_ADDR 47 +#define TIER4_ISX021_REG_48_ADDR 48 +#define TIER4_ISX021_REG_49_ADDR 49 + +#define TIER4_ISX021_REG_50_ADDR 50 +#define TIER4_ISX021_REG_51_ADDR 51 +#define TIER4_ISX021_REG_52_ADDR 52 +#define TIER4_ISX021_REG_53_ADDR 53 + +#define TIER4_ISX021_REG_54_ADDR 54 +#define TIER4_ISX021_REG_55_ADDR 55 +#define TIER4_ISX021_REG_56_ADDR 56 +#define TIER4_ISX021_REG_57_ADDR 57 + +#define TIER4_ISX021_REG_58_ADDR 58 +#define TIER4_ISX021_REG_59_ADDR 59 +#define TIER4_ISX021_REG_60_ADDR 60 +#define TIER4_ISX021_REG_61_ADDR 61 + +#define TIER4_ISX021_REG_62_ADDR 62 + +#define TIER4_ISX021_REG_63_ADDR 63 +#define TIER4_ISX021_REG_64_ADDR 64 +#define TIER4_ISX021_REG_65_ADDR 65 + +#define TIER4_ISX021_REG_66_ADDR 66 + +// AE mode + +#define TIER4_ISX021_REG_67_ADDR 67 + +#define TIER4_ISX021_REG_68_ADDR 68 +#define TIER4_ISX021_REG_69_ADDR 69 + +#define TIER4_ISX021_REG_70_ADDR 70 + +// Digital Gain + +#define TIER4_ISX021_REG_71_ADDR 71 +#define TIER4_ISX021_REG_72_ADDR 72 + +// Distortion Corretion + +#define TIER4_ISX021_REG_73_ADDR 73 +#define TIER4_ISX021_REG_74_ADDR 74 +#define TIER4_ISX021_REG_75_ADDR 75 +#define TIER4_ISX021_REG_76_ADDR 76 + +// Mode change + +#define TIER4_ISX021_REG_77_ADDR 77 + +#define TIER4_ISX021_REG_78_ADDR 78 + +#define TIER4_ISX021_REG_79_ADDR 79 + +// Embedded data + +#define TIER4_ISX021_REG_80_ADDR 80 +#define TIER4_ISX021_REG_81_ADDR 81 + +#define TIER4_ISX021_REG_82_ADDR 82 + +#define TIER4_ISX021_REG_83_ADDR 83 +#define TIER4_ISX021_REG_84_ADDR 84 +#define TIER4_ISX021_REG_85_ADDR 85 +#define TIER4_ISX021_REG_86_ADDR 86 +#define TIER4_ISX021_REG_87_ADDR 87 +#define TIER4_ISX021_REG_88_ADDR 88 +#define TIER4_ISX021_REG_89_ADDR 89 + +#define TIER4_ISX021_REG_90_ADDR 90 +#define TIER4_ISX021_REG_91_ADDR 91 + +#define TIER4_ISX021_REG_92_ADDR 92 +#define TIER4_ISX021_REG_93_ADDR 93 + +// --- End of Register definition ------------------------ + +#define MAX_NUM_OF_REG (100) + +#define ISX021_AUTO_EXPOSURE_MODE 0x00 +#define ISX021_AE_TIME_UNIT_MICRO_SECOND 0x03 + +#define BIT_SHIFT_8 8 +#define BIT_SHIFT_16 16 +#define MASK_1_BIT 0x1 +#define MASK_4_BIT 0xF +#define MASK_8_BIT 0xFF + +#define NO_ERROR 0 + +#define TIME_1_MS 1000 +#define TIME_2_MS 2000 +#define TIME_5_MS 5000 +#define TIME_10_MS 10000 +#define TIME_20_MS 20000 +#define TIME_30_MS 30000 +#define TIME_35_MS 35000 +#define TIME_40_MS 40000 +#define TIME_50_MS 50000 +#define TIME_60_MS 60000 +#define TIME_70_MS 70000 +#define TIME_80_MS 80000 +#define TIME_100_MS 100000 +#define TIME_120_MS 120000 +#define TIME_121_MS 121000 +#define TIME_200_MS 200000 +#define TIME_250_MS 250000 +#define TIME_300_MS 300000 +#define TIME_500_MS 500000 +#define TIME_800_MS 800000 +#define TIME_1000_MS 1000000 + +#define PLUS_10(x) ((x) + (x) / 10) + +#define MAX_NUM_CAMERA 8 + +#define FIRMWARE_BIN_FILE "/lib/firmware/tier4-isx021.bin" + +#define FSYNC_FREQ_HZ 10 + +#define DISABLE_BOTH_EMBEDDED_DATA 0x0 +#define ENABLE_FRONT_EMBEDDED_DATA 0x1 +#define ENABLE_REAR_EMBEDDED_DATA 0x2 +#define ENABLE_BOTH_EMBEDDED_DATA \ + ((ENABLE_FRONT_EMBEDDED_DATA) | (ENABLE_REAR_EMBEDDED_DATA)) + +enum { + ISX021_MODE_1920X1280_CROP_30FPS, + ISX021_MODE_1920X1281_CROP_30FPS_FRONT_EMBEDDED_DATA, + ISX021_MODE_1920X1294_CROP_30FPS_REAR_EMBEDDED_DATA, + ISX021_MODE_1920X1295_CROP_30FPS_BOTH_EMBEDDED_DATA, + ISX021_MODE_START_STREAM, + ISX021_MODE_STOP_STREAM +}; + +static const int tier4_isx021_30fps[] = { + 30, +}; +static const struct camera_common_frmfmt tier4_isx021_frmfmt[] = { + { { 1920, 1280 }, + tier4_isx021_30fps, + 1, + 0, + ISX021_MODE_1920X1280_CROP_30FPS }, + { { 1920, 1281 }, + tier4_isx021_30fps, + 1, + 0, + ISX021_MODE_1920X1281_CROP_30FPS_FRONT_EMBEDDED_DATA }, // added 1 lines of embedded data + { { 1920, 1294 }, + tier4_isx021_30fps, + 1, + 0, + ISX021_MODE_1920X1294_CROP_30FPS_REAR_EMBEDDED_DATA }, // added 14 lines of embedded data + { { 1920, 1295 }, + tier4_isx021_30fps, + 1, + 0, + ISX021_MODE_1920X1295_CROP_30FPS_BOTH_EMBEDDED_DATA }, // added 15 lines of embedded data +}; + +const struct of_device_id tier4_isx021_of_match[] = { + { + .compatible = "nvidia,tier4_isx021", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tier4_isx021_of_match); + +// If you add new ioctl VIDIOC_S_EXT_CTRLS function, please add new CID to the following table. +// and define the CID number in nvidia/include/media/tegra-v4l2-camera.h + +static const u32 ctrl_cid_list[] = { + TEGRA_CAMERA_CID_GAIN, TEGRA_CAMERA_CID_EXPOSURE, + TEGRA_CAMERA_CID_EXPOSURE_SHORT, TEGRA_CAMERA_CID_FRAME_RATE, + TEGRA_CAMERA_CID_HDR_EN, + //TEGRA_CAMERA_CID_DISTORTION_CORRECTION, +}; + +struct tier4_isx021 { + struct i2c_client *i2c_client; + const struct i2c_device_id *id; + struct v4l2_subdev *subdev; + struct device *ser_dev; + struct device *dser_dev; + struct tier4_gmsl_link_ctx g_ctx; + u32 frame_length; + struct camera_common_data *s_data; + struct tegracam_device *tc_dev; + // bool fsync_mode; + bool distortion_correction; + bool auto_exposure; + u16 *firmware_buffer; + int es_number; + struct device *fpga_dev; + int trigger_mode; + bool inhibit_fpga_access; + int enable_embedded_data; // 0:disable all embedded data 1: enable front embedded data 2:enable rear embedded data 3: enable front and rear embedded data +}; + +static const struct regmap_config tier4_sensor_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + //.cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_NONE, +}; + +struct st_priv { + struct i2c_client *p_client; + struct tier4_isx021 *p_priv; + struct tegracam_device *p_tc_dev; + bool sensor_ser_shutdown; + bool des_shutdown; + bool running; +}; + +static struct st_priv wst_priv[MAX_NUM_CAMERA]; + +static int camera_channel_count = 0; + +static int trigger_mode = 0xCAFE; +static int enable_auto_exposure = 0xCAFE; +static int enable_distortion_correction = 0xCAFE; +static int shutter_time_min = ISX021_MIN_EXPOSURE_TIME; +static int shutter_time_mid = ISX021_MID_EXPOSURE_TIME; +static int shutter_time_max = ISX021_MAX_EXPOSURE_TIME; +static int fsync_mfp = 0; +// static int debug_i2c_write = 0; + +module_param(trigger_mode, int, S_IRUGO | S_IWUSR); +module_param(enable_auto_exposure, int, S_IRUGO | S_IWUSR); +module_param(enable_distortion_correction, int, S_IRUGO | S_IWUSR); +module_param(shutter_time_min, int, S_IRUGO | S_IWUSR); +module_param(shutter_time_mid, int, S_IRUGO | S_IWUSR); +module_param(shutter_time_max, int, S_IRUGO | S_IWUSR); + +module_param(fsync_mfp, int, S_IRUGO | S_IWUSR); +// module_param(debug_i2c_write, int, S_IRUGO | S_IWUSR); + +static struct mutex tier4_sensor_lock__; + +static struct mutex tier4_isx021_lock; + +void tier4_isx021_sensor_mutex_lock(void) +{ + mutex_lock(&tier4_sensor_lock__); +} +EXPORT_SYMBOL(tier4_isx021_sensor_mutex_lock); + +void tier4_isx021_sensor_mutex_unlock(void) +{ + mutex_unlock(&tier4_sensor_lock__); +} +EXPORT_SYMBOL(tier4_isx021_sensor_mutex_unlock); + +// ------------------------------- + +static char upper(char c) +{ + if ('a' <= c && c <= 'z') { + c = c - ('a' - 'A'); + } + return c; +} + +static void to_upper_string(char *out, const char *in) +{ + int i; + + i = 0; + while (in[i] != '\0') { + out[i] = upper(in[i]); + i++; + } +} + +#ifndef USE_I2C_TRANSFER // with regmap functions + +static inline int tier4_isx021_read_reg(struct camera_common_data *s_data, + u16 addr, u8 *val) +{ + int err = 0; + u32 reg_val = 0; + struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; + u16 reg_addr = 0; + +#ifdef USE_FIRMWARE + reg_addr = priv->firmware_buffer[addr]; +#else + reg_addr = addr; +#endif + usleep_range(TIME_1_MS * 50, PLUS_10(TIME_1_MS * 50)); + + err = regmap_read(s_data->regmap, reg_addr, ®_val); + + *val = reg_val & 0xFF; + + if (err) { + dev_err(s_data->dev, + "[%s ] : I2C Read register failed at 0x%04X\n", + __func__, reg_addr); + } +#ifdef SHOW_I2C_READ_MSG + else { + dev_info(s_data->dev, + "[%s] : I2C Read regiser at %d(0x%04X)=[0x%02X]\n", + __func__, addr, reg_addr, reg_val); + } +#endif + + return err; +} + +static int tier4_isx021_write_reg(struct camera_common_data *s_data, u16 addr, + u8 val) +{ + int err = 0; + struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; + u16 reg_addr = 0; + +#ifdef USE_FIRMWARE + reg_addr = priv->firmware_buffer[addr]; +#else + reg_addr = addr; +#endif + + usleep_range(TIME_1_MS * 50, PLUS_10(TIME_1_MS * 50)); + + err = regmap_write(s_data->regmap, reg_addr, val); + + if (err) { + dev_err(s_data->dev, + "[%s] : I2C write register failed at %d(0x%04X)=[0x%02X]\n", + __func__, addr, reg_addr, val); + } +#ifdef SHOW_I2C_WRITE_MSG + else { + dev_info(s_data->dev, + "[%s] : I2C write register at %d(0x%04X)=[0x%02X]\n", + __func__, addr, reg_addr, val); + } +#endif + + return err; +} + +#ifdef USE_WRITE_AND_VEIFY + +static int tier4_isx021_write_reg_and_verify(struct camera_common_data *s_data, + u16 addr, u8 val8) +{ + u32 r_val32; + u8 r_val8; + int err = 0; + struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; + u16 reg_addr = 0; + +#ifdef USE_FIRMWARE + reg_addr = priv->firmware_buffer[addr]; +#else + reg_addr = addr; +#endif + + err = regmap_write(s_data->regmap, reg_addr, val8); + if (err) { + dev_err(s_data->dev, + "[%s] : I2C write register failed at %d(0x%04X)=[0x%02X]\n", + __func__, addr, reg_addr, val8); + } + + usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); + + err = regmap_read(s_data->regmap, reg_addr, &r_val32); + + r_val8 = r_val32 & 0xFF; + + if (err) { + dev_err(s_data->dev, + "[%s] : I2C Read register failed at 0x%04X=[0x%02X]\n", + __func__, reg_addr, r_val8); + } + + return err; +} + +#endif // ifdef USE_WRITE_AND_VEIFY + +#else // ifndef USE_I2C_TRANSFER ( with i2c_transfer function ) + +#ifdef USE_I2C_READ_REG + +static int tier4_isx021_read_reg(struct camera_common_data *s_data, u16 addr, + u8 *val8) // with i2c_tranfer +{ + int err = 0; + u16 reg_addr = 0; + struct i2c_msg msg[2]; + struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; + u8 w_buf[5]; + +#ifdef USE_FIRMWARE + reg_addr = priv->firmware_buffer[addr]; +#else + reg_addr = addr; +#endif + + w_buf[0] = (reg_addr >> 8) & 0xFF; + w_buf[1] = reg_addr & 0xFF; + + msg[0].addr = priv->i2c_client->addr; + msg[0].flags = 0; // I2C Write + msg[0].len = 2; + msg[0].buf = w_buf; + + msg[1].addr = priv->i2c_client->addr; + msg[1].flags = I2C_M_RD; // I2C Read + msg[1].len = 1; + msg[1].buf = val8; + + err = i2c_transfer(priv->i2c_client->adapter, msg, 2); + + if (err < 0) { + dev_err(s_data->dev, + "[%s ] : I2C Read register failed at 0x%04X\n", + __func__, reg_addr); + } else { + err = 0; + } + + usleep_range(TIME_1_MS, PLUS_10(TIME_1_MS)); + + return err; +} + +#endif // ifdef USE_I2C_READ_REG + +// ------------------------------------------------------------------- + +static int tier4_isx021_write_reg(struct camera_common_data *s_data, u16 addr, + u8 val8) // with i2c_tranfer +{ + int err = 0; + u16 reg_addr = 0; + struct i2c_msg msg[2]; + struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; + u8 w_buf[5]; + +#ifdef USE_FIRMWARE + reg_addr = priv->firmware_buffer[addr]; +#else + reg_addr = addr; +#endif + + w_buf[0] = (reg_addr >> 8) & 0xFF; + w_buf[1] = reg_addr & 0xFF; + w_buf[2] = val8 & 0xFF; + + msg[0].addr = priv->i2c_client->addr; + msg[0].flags = 0; // I2C Write + msg[0].len = 3; + msg[0].buf = w_buf; + + err = i2c_transfer(priv->i2c_client->adapter, msg, 1); + + if (err < 0) { + dev_err(s_data->dev, + "[%s] : I2C write register failed at %d(0x%04X)=[0x%02X]\n", + __func__, addr, reg_addr, val8); + } else { + err = 0; + } + + usleep_range(TIME_1_MS, PLUS_10(TIME_1_MS)); + + return err; +} + +#endif // ifndef USE_I2C_TRANSFER + +// ------------------------------------------------------------------ + +static int +tier4_isx021_write_mode_set_f_lock_register(struct camera_common_data *s_data, + u8 val8) +{ + int err = 0; + + usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_90_ADDR, + 0x06); // ACK Response mode + + usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_77_ADDR, val8); + + usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_90_ADDR, + 0x02); // NAK Response mode + + return 0; +} +// ------------------------------------------------------------------ + +#ifdef USE_REMAP_REGISTER + +static int tier4_isx021_write_remap_register(struct camera_common_data *s_data, + u8 val8) +{ + int err = 0; + + usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_90_ADDR, + 0x06); // ACK Response mode + + usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_73_ADDR, val8); + + usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_90_ADDR, + 0x02); // NAK Response mode + + return 0; +} +#endif + +// ------------------------------------------------------------------- + +static int +tier4_isx021_transit_to_streaming_state(struct tegracam_device *tc_dev) +{ + struct camera_common_data *s_data = tc_dev->s_data; + struct device *dev = tc_dev->dev; + int err = 0; + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_62_ADDR, + 0x80); // transit to Streaming state + if (err) { + dev_err(dev, "[%s] : Write to MODE_SET_F register failed.\n", + __func__); + } + usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); + //msleep(120); + + return err; +} + +// ------------------------------------------------------------------- + +static int tier4_isx021_transit_to_startup_state(struct tegracam_device *tc_dev) +{ + struct camera_common_data *s_data = tc_dev->s_data; + struct device *dev = tc_dev->dev; + int err = 0; + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_62_ADDR, + 0x00); // transit to Startup state + + if (err) { + dev_err(dev, "[%s] : Write to MODE_SET_F register failed.\n", + __func__); + } + usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); + //msleep(120); + + return err; +} + +// ------------------------------------------------------------------ + +#ifdef USE_CHECK_MODE_SEL + +static int tier4_isx021_check_mode_sel(struct camera_common_data *s_data, + u8 *val8) +{ + //int mode_size = sizeof(remap_mode); + u8 rval8 = 0; + int err = 0; + struct device *dev = s_data->dev; + + err = tier4_isx021_read_reg(s_data, TIER4_ISX021_REG_89_ADDR, &rval8); + if (err) { + dev_err(dev, "[%s] : Write to MODE_SEL register failed.\n", + __func__); + return err; + } + + *val8 = rval8; + + return err; +} +#endif // ifdef USE_CHECK_MODE_SEL + +// ------------------------------------------------------------------ + +static int tier4_isx021_set_fsync_trigger_mode(struct tier4_isx021 *priv) +{ + int err = 0; + struct camera_common_data *s_data = priv->s_data; + struct device *dev = s_data->dev; + int des_num = 0; + + dev_info(dev, "[%s] : hardware_model=%d.\n", __func__, + priv->g_ctx.hardware_model); + + if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || + (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + priv->inhibit_fpga_access = false; + + err = tier4_fpga_check_access(priv->fpga_dev); + if (err) { + priv->inhibit_fpga_access = true; + } + + if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_DISABLE) { + dev_info(dev, "[%s] : Disabling FPGA fsync.\n", + __func__); + + err = tier4_fpga_disable_fsync_mode(priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Disabling FPGA generate fsync failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } else { + err = tier4_fpga_enable_fsync_mode(priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA generate fsync failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + + if (tier4_fpga_get_fsync_mode() == + FPGA_FSYNC_MODE_AUTO) { + // Auto Trigger Mode + dev_info( + dev, + "[%s] : Enabling FPGA Fsync Auto Trigger mode.\n", + __func__); + + err = tier4_fpga_set_fsync_auto_trigger( + priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA Fsync Auto Trigger mode failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + + des_num = priv->g_ctx.reg_mux; + err = tier4_fpga_set_fsync_signal_frequency( + priv->fpga_dev, des_num, + priv->trigger_mode); + if (err) { + dev_err(dev, + "[%s] : Setting the frequency of fsync genrated by FPGA failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } else if (tier4_fpga_get_fsync_mode() == + FPGA_FSYNC_MODE_MANUAL) { + // Manual Trigger Mode + dev_info( + dev, + "[%s] : Enabling FPGA Fsync Manual Trigger mode.\n", + __func__); + + err = tier4_fpga_set_fsync_manual_trigger( + priv->fpga_dev); + if (err) { + dev_err(dev, + "[%s] : Enabling FPGA Fsync Maunal Trigger mode failed.\n", + __func__); + if (!priv->inhibit_fpga_access) { + return err; + } + } + } // if (tier4_fpga_get_fsync_mode() == FPGA_FSYNC_MODE_MANUAL) + } // else (tier4_fpga_get_fsync_mode() != FPGA_FSYNC_MODE_DISABLE) + } // if (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) + + err = tier4_max9296_setup_gpi(priv->dser_dev, fsync_mfp); + + if (err) { + dev_err(dev, "[%s] : tier4_max9296_setup_gpi failed.\n", + __func__); + return err; + } + + err = tier4_max9295_setup_gpo(priv->ser_dev); + + if (err) { + dev_err(dev, "[%s] : tier4_max9295_setup_gpo failed.\n", + __func__); + return err; + } + + // transit to Startup state + + err = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); + if (err) { + dev_err(dev, + "[%s] : Time out Error occurred in tier4_isx021_write_register_mode_set_f_lock.\n", + __func__); + return err; + } + + usleep_range(TIME_50_MS, PLUS_10(TIME_50_MS)); + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_62_ADDR, 0x00); + + if (err) { + dev_err(dev, "[%s] : tier4_isx021_write_reg failed.\n", + __func__); + return err; + } + + usleep_range(TIME_50_MS, PLUS_10(TIME_50_MS)); + + // set FSYNC_FUNCSEL to 0 for FSYNC triggered mode + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_92_ADDR, 0x00); + + if (err) { + goto error_exit; + } + + usleep_range(TIME_50_MS, PLUS_10(TIME_50_MS)); + + // set FSYNC_DRVABTY to 3 for FSYNC triggered mode + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_93_ADDR, 0xFF); + + if (err) { + goto error_exit; + } + + usleep_range(TIME_50_MS, PLUS_10(TIME_50_MS)); + + // set SG_MODE_CTL to 0 for transition to FSYNC mode + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_63_ADDR, + 0x02); // set FSYNC mode + + if (err) { + goto error_exit; + } + + usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); + + // set SG_MODE_APL to 0 for transition to FSYNC mode + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_78_ADDR, 0x02); + + if (err) { + goto error_exit; + } + + usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); + + usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); + +error_exit: + + return err; +} + +/*--------------------------------------------------------------------------*/ + +static int tier4_isx021_set_response_mode(struct tier4_isx021 *priv) +{ + int err = 0; + struct tegracam_device *tc_dev = priv->tc_dev; + struct camera_common_data *s_data = priv->s_data; + struct device *dev = s_data->dev; + u8 r_val; + + err = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); + if (err) { + dev_err(dev, + "[%s] : Write to MODE_SET_F_LOCK register caused Time out.\n", + __func__); + return err; + } + + usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); + + err = tier4_isx021_transit_to_startup_state(tc_dev); + if (err) { + dev_err(dev, "[%s] : Transition to Startup state failed.\n", + __func__); + goto error_exit; + } + + usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); // For ES3 and MP + + err = tier4_isx021_read_reg(s_data, TIER4_ISX021_REG_66_ADDR, &r_val); + + if (r_val == 0x04) { + priv->es_number = 2; + } else { + priv->es_number = 3; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_66_ADDR, 0x06); + + usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); // For ES3 and MP + +error_exit: + + return err; +} + +static int tier4_isx021_gmsl_serdes_setup(struct tier4_isx021 *priv) +{ + int err = 0; + int des_err = 0; + struct device *dev; + + if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client) { + return -EINVAL; + } + + dev = &priv->i2c_client->dev; + + /* For now no separate power on required for serializer device */ + + if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && + (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + tier4_max9296_power_on(priv->dser_dev); + } + /* setup serdes addressing and control pipeline */ + + err = tier4_max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev); + + if (err) { + dev_err(dev, + "[%s] : Configuration of GMSL Deserializer link failed.\n", + __func__); + goto error; + } + + err = tier4_max9295_setup_control(priv->ser_dev); + + /* proceed even if ser setup failed, to setup deser correctly */ + if (err) { + dev_err(dev, "[%s] : Setup for GMSL Serializer failed.\n", + __func__); + goto error; + } + + des_err = tier4_max9296_setup_control(priv->dser_dev, + &priv->i2c_client->dev); + + if (des_err) { + dev_err(dev, "[%s] : Setup for GMSL Deserializer failed.\n", + __func__); + err = des_err; + } +error: + + return err; +} + +/*--------------------------------------------------------------------------*/ + +static void tier4_isx021_gmsl_serdes_reset(struct tier4_isx021 *priv) +{ + /* reset serdes addressing and control pipeline */ + tier4_max9295_reset_control(priv->ser_dev); + + tier4_max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev, + false); + + if ((priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_XAVIER) && + (priv->g_ctx.hardware_model != HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + tier4_max9296_power_off(priv->dser_dev); + } +} + +/*--------------------------------------------------------------------------*/ + +static int tier4_isx021_power_on(struct camera_common_data *s_data) +{ + int err = 0; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + struct device *dev = s_data->dev; + + if (pdata && pdata->power_on) { + err = pdata->power_on(pw); + + if (err) { + dev_err(dev, "[%s] : Turning on the power failed.\n", + __func__); + } else { + pw->state = SWITCH_ON; + } + return err; + } + + pw->state = SWITCH_ON; + + return err; +} + +/*--------------------------------------------------------------------------*/ + +static int tier4_isx021_power_off(struct camera_common_data *s_data) +{ + int err = 0; + struct camera_common_power_rail *pw = s_data->power; + struct camera_common_pdata *pdata = s_data->pdata; + struct device *dev = s_data->dev; + + if (pdata && pdata->power_off) { + err = pdata->power_off(pw); + + if (!err) { + goto power_off_done; + } else { + dev_err(dev, "[%s] : Turning off the power failed.\n", + __func__); + } + return err; + } + +power_off_done: + pw->state = SWITCH_OFF; + + return err; +} + +/*--------------------------------------------------------------------------*/ + +static int tier4_isx021_power_get(struct tegracam_device *tc_dev) +{ + struct camera_common_power_rail *pw = tc_dev->s_data->power; + int err = 0; + + pw->state = SWITCH_OFF; + + return err; +} + +/*--------------------------------------------------------------------------*/ + +static int tier4_isx021_power_put(struct tegracam_device *tc_dev) +{ + if (unlikely(!tc_dev->s_data->power)) { + return -EFAULT; + } + + return NO_ERROR; +} + +/*--------------------------------------------------------------------------*/ + +static int tier4_isx021_set_group_hold(struct tegracam_device *tc_dev, bool val) +{ + volatile int err = 0; + + return err; +} + +/*--------------------------------------------------------------------------*/ + +static int tier4_copy_reg_value(struct camera_common_data *s_data, u16 ae_addr, + u16 me_addr) +{ + int err = 0; + u8 val8 = 0; + + err = tier4_isx021_read_reg(s_data, ae_addr, &val8); + + if (err) { + dev_err(s_data->dev, + "[%s] : I2C Read Register failed at 0x%x\n", __func__, + ae_addr); + } + + err = tier4_isx021_write_reg(s_data, me_addr, val8); + + if (err) { + dev_err(s_data->dev, + "[%s] : I2C write Register failed at 0x%x =[ 0x%x]\n", + __func__, me_addr, val8); + } + + return err; +} + +/*--------------------------------------------------------------------------*/ + +static int tier4_isx021_set_gain(struct tegracam_device *tc_dev, s64 val) +{ + int err = 0; + + s64 gain; + u8 digital_gain_low_byte; + u8 digital_gain_high_byte; + + struct camera_common_data *s_data = tc_dev->s_data; + struct device *dev = tc_dev->dev; + + if (val > ISX021_MAX_GAIN) { + val = ISX021_MAX_GAIN; + } else if (val < ISX021_MIN_GAIN) { + val = ISX021_MIN_GAIN; + } + + dev_info(dev, "[%s] :Gain is set to %lld\n", __func__, val); + + gain = 10 * val; + + digital_gain_low_byte = gain & 0xFF; + + digital_gain_high_byte = (gain >> 8) & 0xFF; + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_68_ADDR, 0x01); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_69_ADDR, 0x01); + + if (err) { + goto fail; + } + + // Shutter 0 value + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_15_ADDR, + TIER4_ISX021_REG_23_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_16_ADDR, + TIER4_ISX021_REG_24_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_17_ADDR, + TIER4_ISX021_REG_25_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_18_ADDR, + TIER4_ISX021_REG_26_ADDR); + + if (err) { + goto fail; + } + + // Shutter 1 value + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_19_ADDR, + TIER4_ISX021_REG_27_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_20_ADDR, + TIER4_ISX021_REG_28_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_21_ADDR, + TIER4_ISX021_REG_29_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_22_ADDR, + TIER4_ISX021_REG_30_ADDR); + + if (err) { + goto fail; + } + + // Set Analog Gain for shutter 0 + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_31_ADDR, + digital_gain_low_byte); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_32_ADDR, + digital_gain_high_byte); + + if (err) { + goto fail; + } + + // copy AE Analog gain value to ME analog gain registers for shutter 1 to 3 + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_35_ADDR, + TIER4_ISX021_REG_37_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_36_ADDR, + TIER4_ISX021_REG_38_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_39_ADDR, + TIER4_ISX021_REG_41_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_40_ADDR, + TIER4_ISX021_REG_42_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_43_ADDR, + TIER4_ISX021_REG_45_ADDR); + + if (err) { + goto fail; + } + + err = tier4_copy_reg_value(s_data, TIER4_ISX021_REG_44_ADDR, + TIER4_ISX021_REG_46_ADDR); + + if (err) { + goto fail; + } + + msleep(100); // For ES3 + + // Change AE mode + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_67_ADDR, 0x03); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_71_ADDR, + digital_gain_low_byte); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_72_ADDR, + digital_gain_high_byte); + + if (err) { + goto fail; + } + + return NO_ERROR; + +fail: + dev_err(dev, "[%s] : Gain control Error\n", __func__); + + return err; +} + +/* ------------------------------------------------------------------------- */ + +static int tier4_isx021_set_frame_rate(struct tegracam_device *tc_dev, s64 val) +{ + struct tier4_isx021 *priv = + (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); + + /* fixed 10fps */ + priv->frame_length = ISX021_DEFAULT_FRAME_LENGTH; + + return NO_ERROR; +} + +/* ------------------------------------------------------------------------- */ + +static int tier4_isx021_set_auto_exposure(struct tegracam_device *tc_dev) +{ + int err = 0; + struct camera_common_data *s_data = tc_dev->s_data; + + // Change to Auto exposure mode + + msleep(100); // For ES3 + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_67_ADDR, + ISX021_AUTO_EXPOSURE_MODE); + + // Set min exposure time unit + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_47_ADDR, + ISX021_AE_TIME_UNIT_MICRO_SECOND); + if (err) { + goto fail; + } + + // Set mid exposure time unit + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_48_ADDR, + ISX021_AE_TIME_UNIT_MICRO_SECOND); + if (err) { + goto fail; + } + + // Set max exposure time unit + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_49_ADDR, + ISX021_AE_TIME_UNIT_MICRO_SECOND); + if (err) { + goto fail; + } + + // Set min exposure time + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_50_ADDR, + shutter_time_min & 0xFF); + if (err) { + goto fail; + } + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_51_ADDR, + (shutter_time_min >> 8) & 0xFF); + if (err) { + goto fail; + } + + // Set mid exposure time + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_54_ADDR, + shutter_time_mid & 0xFF); + if (err) { + goto fail; + } + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_55_ADDR, + (shutter_time_mid >> 8) & 0xFF); + if (err) { + goto fail; + } + + // Set max exposure time + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_58_ADDR, + shutter_time_max & 0xFF); + if (err) { + goto fail; + } + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_59_ADDR, + (shutter_time_max >> 8) & 0xFF); + if (err) { + goto fail; + } + +fail: + + return err; +} + +/* ------------------------------------------------------------------------- */ + +static int tier4_isx021_set_exposure(struct tegracam_device *tc_dev, s64 val) +{ + int err = 0; + + u8 exp_time_byte0; + u8 exp_time_byte1; + u8 exp_time_byte2; + u8 exp_time_byte3; + // struct tier4_isx021 *priv = (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); + struct camera_common_data *s_data = tc_dev->s_data; + + // unit for val is micro-second + + if (val > ISX021_MAX_EXPOSURE_TIME) { + val = ISX021_MAX_EXPOSURE_TIME; + } else if (val < ISX021_MIN_EXPOSURE_TIME) { + val = ISX021_MIN_EXPOSURE_TIME; + } + + exp_time_byte0 = val & 0xFF; + + exp_time_byte1 = (val >> 8) & 0xFF; + + exp_time_byte2 = (val >> 16) & 0xFF; + + exp_time_byte3 = (val >> 24) & 0xFF; + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_48_ADDR, 0x03); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_49_ADDR, 0x03); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_54_ADDR, + exp_time_byte0); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_55_ADDR, + exp_time_byte1); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_56_ADDR, + exp_time_byte2); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_57_ADDR, + exp_time_byte3); + + if (err) { + goto fail; + } + + // Shutter2 + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_58_ADDR, + exp_time_byte0); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_59_ADDR, + exp_time_byte1); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_60_ADDR, + exp_time_byte2); + + if (err) { + goto fail; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_61_ADDR, + exp_time_byte3); + + if (err) { + goto fail; + } + + return NO_ERROR; + +fail: + + return err; +} +// -------------------------------------------------------------------------------------- +// Enable Distortion Coreection +// -------------------------------------------------------------------------------------- +static int +tier4_isx021_enable_distortion_correction(struct tegracam_device *tc_dev, + bool is_enabled) +{ + int err = 0; + struct device *dev = tc_dev->dev; + struct camera_common_data *s_data = tc_dev->s_data; + + err = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); + if (err) { + dev_err(dev, + "[%s] : Write to MODE_SET_F_LOCK register caused Time out.\n", + __func__); + return err; + } + + usleep_range(TIME_10_MS, PLUS_10(TIME_10_MS)); + + err = tier4_isx021_transit_to_startup_state(tc_dev); + + if (err) { + dev_err(dev, "[%s] : Transition to Startup state failed.\n", + __func__); + goto error_exit; + } + + usleep_range(TIME_35_MS, PLUS_10(TIME_35_MS)); + //msleep(35); + + if (is_enabled) { + err = tier4_isx021_write_reg(tc_dev->s_data, + TIER4_ISX021_REG_74_ADDR, 0x01); + + usleep_range(TIME_35_MS, PLUS_10(TIME_35_MS)); + //msleep(35); + + err = tier4_isx021_write_reg(tc_dev->s_data, + TIER4_ISX021_REG_75_ADDR, 0x01); + if (err) { + goto error_exit; + } + } else { + dev_info(tc_dev->dev, "[%s] : Disabled Distortion Correction.", + __func__); + + err = tier4_isx021_write_reg(tc_dev->s_data, + TIER4_ISX021_REG_74_ADDR, 0x00); + + usleep_range(TIME_35_MS, PLUS_10(TIME_35_MS)); + //msleep(35); + + err = tier4_isx021_write_reg(tc_dev->s_data, + TIER4_ISX021_REG_75_ADDR, 0x00); + if (err) { + goto error_exit; + } + } + +error_exit: + + if (err && !is_enabled) { + dev_err(tc_dev->dev, + "[%s] : Disabling Distortion Correction failed.", + __func__); + } else if (err && is_enabled) { + dev_err(tc_dev->dev, + "[%s] : Enabling Distortion Correction failed.", + __func__); + } + + return err; +} + +// Please refer to the section for embedded data in ISX021 application note + +static int tier4_isx021_setup_embedded_data(struct tegracam_device *tc_dev, + int enable_embedded_data) +{ + struct camera_common_data *s_data = tc_dev->s_data; + struct device *dev = s_data->dev; + int err = 0; + int rc = 0; + + dev_dbg(dev, "[%s] : Setup for Embedded data.\n", __func__); + + err = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); + + if (err) { + dev_err(dev, + "[%s] : Write to MODE_SET_F_LOCK Register failed\n", + __func__); + //goto error_exit; + } + + usleep_range(TIME_100_MS, PLUS_10(TIME_100_MS)); + //msleep(100); + + err = tier4_isx021_transit_to_startup_state(tc_dev); + if (err) { + dev_err(dev, "[%s] : Transition to Startup state failed.\n", + __func__); + goto error_exit; + } + + usleep_range(TIME_120_MS, PLUS_10(TIME_120_MS)); + //msleep(120); + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_91_ADDR, + 0x00); // DCROP_ON_APL Regsiter + + if (err) { + dev_err(dev, + "[%s] : Write to ISX021_DCROP_ON Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg( + s_data, TIER4_ISX021_REG_82_ADDR, + 0x00); // DCROP_ON register : Enable 0 Padding after Embedded data + + if (err) { + dev_err(dev, + "[%s] : Write to ISX021_DCROP_ON Register failed.\n", + __func__); + goto error_exit; + } + + dev_dbg(dev, "[%s] : enable_embedded_data = %d\n", __func__, + enable_embedded_data); + + // Enable Front Embedded data + + if (enable_embedded_data & ENABLE_FRONT_EMBEDDED_DATA) { + dev_info(dev, "[%s] : Enabling Front Embedded.\n", __func__); + + err = tier4_isx021_write_reg( + s_data, TIER4_ISX021_REG_80_ADDR, + 0x1); // Enable outputting Front Embedded Data + if (err) { + dev_err(dev, + "[%s] : Write to IR_DR_I2I_FEBD_EN Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_83_ADDR, + 0x1); + if (err) { + dev_err(dev, + "[%s] : Write to IFD_DATATYPE_FEBD_SEL Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg( + s_data, TIER4_ISX021_REG_85_ADDR, + 0x1E); // EBD data are encoded as YcbCr(YUV422: applied in this driver ) + + if (err) { + dev_err(dev, + "[%s] : Write to IFD_DATATYPE_FEBD Register failed.\n", + __func__); + goto error_exit; + } + + } else { // Diable Front Embedded data + + dev_info(dev, "[%s] : Disabling Front Embedded.\n", __func__); + + err = tier4_isx021_write_reg( + s_data, TIER4_ISX021_REG_80_ADDR, + 0x0); // Disable outputting Front Embedded Data + if (err) { + dev_err(dev, + "[%s] : Write to IR_DR_I2I_FEBD_EN Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg( + s_data, TIER4_ISX021_REG_83_ADDR, + 0x0); // Front Embedded data type is not selected by IR_DR_I2I_FEBD + if (err) { + dev_err(dev, + "[%s] : Write to IFD_DATATYPE_FEBD_SEL Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg( + s_data, TIER4_ISX021_REG_85_ADDR, + 0x12); // Default data type for Front Embedded + if (err) { + dev_err(dev, + "[%s] : Write to IR_DR_I2I_FEBD Register failed.\n", + __func__); + goto error_exit; + } + } + + if (enable_embedded_data & + ENABLE_REAR_EMBEDDED_DATA) { // Enable Rear Embedded data + + dev_info(dev, "[%s] : Enabling Rear Embedded.\n", __func__); + + err = tier4_isx021_write_reg( + s_data, TIER4_ISX021_REG_81_ADDR, + 0x1); // Enable outputting Rear Embedded Data + if (err) { + dev_err(dev, + "[%s] : Write to IR_DR_I2I_REBD_EN Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_84_ADDR, + 0x0D); + if (err) { + dev_err(dev, + "[%s] : Write to IFD_DATATYPE_REBD_SEL Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_86_ADDR, + 0x1E); + if (err) { + dev_err(dev, + "[%s] : Write to IFD_DATATYPE_REBD Register failed.\n", + __func__); + goto error_exit; + } + + } else { // Diabled Rear Embedded data + + dev_info(dev, "[%s] : Disabling Rear Embedded.\n", __func__); + + err = tier4_isx021_write_reg( + s_data, TIER4_ISX021_REG_81_ADDR, + 0x0); // Disable outputting Rear Embedded Data + if (err) { + dev_err(dev, + "[%s] : Write to IR_DR_I2I_REBD_EN Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_84_ADDR, + 0x0C); + if (err) { + dev_err(dev, + "[%s] : Write to IFD_DATATYPE_REBD_SEL Register failed.\n", + __func__); + goto error_exit; + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_86_ADDR, + 0x35); + if (err) { + dev_err(dev, + "[%s] : Write to IFD_DATATYPE_REBD Register failed.\n", + __func__); + goto error_exit; + } + } + + err = tier4_isx021_write_reg(s_data, TIER4_ISX021_REG_87_ADDR, 0x1E); + if (err) { + dev_err(dev, + "[%s] : Write to IFD_DATATYPE_VISIBLE Register failed.\n", + __func__); + goto error_exit; + } + +error_exit: + +#if 1 + + rc = tier4_isx021_write_mode_set_f_lock_register(s_data, 0x53); + if (rc) { + dev_err(dev, + "[%s] : Write to MODE_SET_F_LOCK Register failed.\n", + __func__); + } +#endif + + return (err | rc); +} + +// -------------------------------------------------------------------------------------- +// If you add new ioctl VIDIOC_S_EXT_CTRLS function, +// please add the new memeber and the function at the following table. + +static struct tegracam_ctrl_ops tier4_isx021_ctrl_ops = { + .numctrls = ARRAY_SIZE(ctrl_cid_list), + .ctrl_cid_list = ctrl_cid_list, + .set_gain = tier4_isx021_set_gain, + .set_exposure = tier4_isx021_set_exposure, + .set_exposure_short = tier4_isx021_set_exposure, + .set_frame_rate = tier4_isx021_set_frame_rate, + .set_group_hold = tier4_isx021_set_group_hold, + // .set_distortion_correction = tier4_isx021_set_distortion_correction, +}; + +// -------------------------------------------------------------------------------------- + +static struct camera_common_pdata * +tier4_isx021_parse_dt(struct tegracam_device *tc_dev) +{ + struct device *dev = tc_dev->dev; + struct device_node *node = dev->of_node; + struct camera_common_pdata *board_priv_pdata; + const struct of_device_id *match; + int err; + + if (!node) { + return NULL; + } + + match = of_match_device(tier4_isx021_of_match, dev); + + if (!match) { + dev_err(dev, "[%s] : Finding matching dt id failed.\n", + __func__); + return NULL; + } + + board_priv_pdata = + devm_kzalloc(dev, sizeof(*board_priv_pdata), GFP_KERNEL); + + err = of_property_read_string(node, "mclk", + &board_priv_pdata->mclk_name); + + if (err) { + dev_err(dev, "[%s] : mclk not in DT.\n", __func__); + } + + return board_priv_pdata; +} + +/* tier4_isx021_set_mode() can not be needed. But it remains for compatiblity */ + +static int tier4_isx021_set_mode(struct tegracam_device *tc_dev) +{ + struct tier4_isx021 *priv = + (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); + struct camera_common_data *s_data = tc_dev->s_data; + struct device *dev = tc_dev->dev; + + int err = 0; + + switch (s_data->mode) { + case ISX021_MODE_1920X1280_CROP_30FPS: + priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; + break; + case ISX021_MODE_1920X1281_CROP_30FPS_FRONT_EMBEDDED_DATA: + priv->enable_embedded_data = ENABLE_FRONT_EMBEDDED_DATA; + break; + case ISX021_MODE_1920X1294_CROP_30FPS_REAR_EMBEDDED_DATA: + priv->enable_embedded_data = ENABLE_REAR_EMBEDDED_DATA; + break; + case ISX021_MODE_1920X1295_CROP_30FPS_BOTH_EMBEDDED_DATA: + priv->enable_embedded_data = ENABLE_BOTH_EMBEDDED_DATA; + break; + default: + priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; + break; + } + + dev_dbg(dev, "[%s]: priv->enable_embedded_data = %d \n", __func__, + priv->enable_embedded_data); + + return err; +} + +// ------------------------------------------------------------------- + +static int tier4_isx021_start_one_streaming(struct tegracam_device *tc_dev) +{ + struct tier4_isx021 *priv = + (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); + struct device *dev = tc_dev->dev; + int err; + + /* enable serdes streaming */ + + err = tier4_max9295_setup_streaming(priv->ser_dev); + if (err) { + goto exit; + } + + err = tier4_max9296_setup_streaming(priv->dser_dev, dev); + if (err) { + dev_err(dev, "[%s] : Setup for Streaming failed.\n", __func__); + goto exit; + } + + err = tier4_max9295_control_sensor_power_seq(priv->ser_dev, + SENSOR_ID_ISX021, true); + if (err) { + dev_err(dev, "[%s] : Power on Camera Sensor failed.\n", + __func__); + goto exit; + } + if (enable_auto_exposure == 1) { + priv->auto_exposure = true; + dev_info(dev, "[%s] : Parameter[enable_auto_exposure] = 1.\n", + __func__); + } + + if (priv->auto_exposure == true) { + err = tier4_isx021_set_auto_exposure(tc_dev); + if (err) { + dev_err(dev, "[%s] : Enabling Auto Exposure failed.\n", + __func__); + goto exit; + } else { + dev_info(dev, "[%s] : Enabled Auto Exposure.\n", + __func__); + } + } else { + dev_info(dev, "[%s] : Disabled Auto Exposure.\n", __func__); + } + if (err) { + dev_err(dev, + "[%s] : Setting digital gain to the default value failed.\n", + __func__); + } + + dev_info(dev, "[%s] : trigger_mode = %d.\n", __func__, trigger_mode); + + priv->trigger_mode = trigger_mode; + + if (priv->trigger_mode == 1) { + // priv->fsync_mode = true; + dev_info(dev, "[%s] : Enabled Slave(fsync triggered) mode.\n", + __func__); + } + + // if (priv->fsync_mode == true) + if (priv->trigger_mode == 1) { + err = tier4_isx021_set_fsync_trigger_mode(priv); + if (err) { + dev_err(dev, + "[%s] : Camera sensor is unable to work with Slave(fsync triggered) mode.\n", + __func__); + // goto exit; + } + } + + usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); + + if (enable_distortion_correction == 1) { + priv->distortion_correction = true; + dev_info( + dev, + "[%s] : Prameter[enable_distortion_correction] = 1 .\n", + __func__); + } + err = tier4_isx021_enable_distortion_correction( + tc_dev, priv->distortion_correction); + if (err) { + dev_err(dev, "[%s] : Enabling Distortion Correction failed.\n", + __func__); + goto exit; + } + + err = tier4_isx021_setup_embedded_data(tc_dev, + priv->enable_embedded_data); + if (err) { + dev_err(dev, "[%s] : Setup for Embedded data failed.\n", + __func__); + goto exit; + } + + err = tier4_isx021_transit_to_streaming_state(tc_dev); + if (err) { + dev_err(dev, "[%s] : Transition to Streaming state failed.\n", + __func__); + return err; + } + + usleep_range(TIME_20_MS, PLUS_10(TIME_20_MS)); + + err = tier4_max9296_start_streaming(priv->dser_dev, dev); + if (err) { + dev_err(dev, "[%s] : Des(Max9296) failed to start streaming.\n", + __func__); + return err; + } + + dev_info(dev, "[%s] : Camera has started streaming.\n", __func__); + + return NO_ERROR; + +exit: + + dev_err(dev, "[%s] : Camera failed to start streaming.\n", __func__); + + return err; +} + +//------------------------------------------------------------------- + +static bool tier4_isx021_is_camera_connected_to_port(int nport) +{ + if (wst_priv[nport].p_client) { + return true; + } + return false; +} + +static bool tier4_isx021_check_null_tc_dev_for_port(int nport) +{ + if (wst_priv[nport].p_tc_dev == NULL) { + return true; + } + return false; +} + +static bool tier4_isx021_is_camera_running_on_port(int nport) +{ + if (wst_priv[nport].running) { + return true; + } + return false; +} + +static bool tier4_isx021_is_current_port(struct tier4_isx021 *priv, int nport) +{ + if (priv->i2c_client == wst_priv[nport].p_client) { + return true; + } + return false; +} + +static void tier4_isx021_set_running_flag(int nport, bool flag) +{ + wst_priv[nport].running = flag; +} + +// static void tier4_isx021_reset_running_flag(int nport) +//{ +// wst_priv[nport].running = false; +//} + +static int tier4_isx021_stop_streaming(struct tegracam_device *tc_dev) +{ + struct device *dev = tc_dev->dev; + struct tier4_isx021 *priv = + (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); + int i, err = 0; + + mutex_lock(&tier4_isx021_lock); + + for (i = 0; i < camera_channel_count; i++) { + if (tier4_isx021_is_camera_connected_to_port(i)) { + if (tier4_isx021_is_current_port(priv, i) && + tier4_isx021_is_camera_running_on_port(i)) { + /* disable serdes streaming */ + err = tier4_max9296_stop_streaming( + priv->dser_dev, dev); + if (err) { + return err; + } + tier4_isx021_set_running_flag(i, false); + break; + } + } + } + + mutex_unlock(&tier4_isx021_lock); + + return NO_ERROR; +} + +/* *************************************************************************** */ +/* 1. In the case where a camera is connected to GMSL A port on a Des. */ +/* */ +/* a > Check if another camera is connected to GMSL B port */ +/* a-1) Connected: */ +/* b > Check if another camera on GMSL B port is running */ +/* b-1) Running: */ +/* c > Check if the camera on GMSL A port is running */ +/* c-1) Running : */ +/* Do nothing and return */ +/* c-2) Not running : */ +/* Start the camera on GMSL A port. */ +/* b-2) Not Running: */ +/* Start the camera on GMSL B port. */ +/* a-2) Not connected : */ +/* b > Check if the camera on GMSL A port is running */ +/* b-1) Running : */ +/* Do nothing and return */ +/* b-2) Not running : */ +/* Start the camera on GMSL A port. */ +/* */ +/* 2. In the case where a camera is connected to GMSL B port on a Des. */ +/* */ +/* a > Check if the camera on GMSL B port is running */ +/* a-1) Running : */ +/* Do nothing and return */ +/* a-2) Not running : */ +/* Start the camera on GMSL B port. */ +/* *************************************************************************** */ + +static int tier4_isx021_start_streaming(struct tegracam_device *tc_dev) +{ + int i, err = 0; + // struct tier4_isx021 *next_client_priv; + struct tier4_isx021 *priv = + (struct tier4_isx021 *)tegracam_get_privdata(tc_dev); + struct device *dev = tc_dev->dev; + + mutex_lock(&tier4_isx021_lock); + + for (i = 0; i < camera_channel_count; i++) { + if (i & 0x1) { // if i = 1,3,5,7 ( GMSL B port of a Des ) + + if (tier4_isx021_is_camera_connected_to_port( + i)) { // a camera is connected to GMSL B portL + + if ((tier4_isx021_is_current_port(priv, i) == + true) && + (tier4_isx021_is_camera_running_on_port( + i) == false)) { + // err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev, wst_priv[i].p_priv); + err = tier4_isx021_start_one_streaming( + wst_priv[i].p_tc_dev); + + if (err) { + dev_err(dev, + "[%s] : Starting one streaming on Camera sensor failed.\n", + __func__); + goto error_exit; + } + wst_priv[i].running = true; + break; + } + } + } else { // if i = 0,2,4,6 ( GMSL A side port of a Des0,Des1,Des2 or Des3 ) + + if ((tier4_isx021_is_camera_connected_to_port(i) == + true) && + (tier4_isx021_is_current_port(priv, i) == true)) { + if (tier4_isx021_is_camera_connected_to_port( + i + 1) == + false) { // if another one camera( GMSL B port) + // is not connected to Des + if (tier4_isx021_is_camera_running_on_port( + i) == + false) { // and if the camera is not running. + + // err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev, wst_priv[i].p_priv); + err = tier4_isx021_start_one_streaming( + wst_priv[i].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Starting one streaming for next isx021 client failed.\n", + __func__); + goto error_exit; + } + tier4_isx021_set_running_flag( + i, true); + } + break; + } + + // two cameras are connected to one Des. + + if (tier4_isx021_check_null_tc_dev_for_port( + i + 1)) { // check if tc_dev is null + dev_err(dev, + "[%s] : wst_priv[%d].p_tc_dev is NULL.\n", + __func__, i + 1); + err = -EINVAL; + goto error_exit; + } + + if (tier4_isx021_is_camera_running_on_port( + i + 1) == false) { + // err = tier4_isx021_start_one_streaming(wst_priv[i+1].p_tc_dev, wst_priv[i+1].p_priv); + err = tier4_isx021_start_one_streaming( + wst_priv[i + 1].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Start one streaming for the next isx021 client failed.\n", + __func__); + goto error_exit; + } + tier4_isx021_set_running_flag(i + 1, + true); + usleep_range(TIME_200_MS, + PLUS_10(TIME_200_MS)); + //msleep(200); + mutex_unlock( + &tier4_isx021_lock); // stop streaming on GMSL B port + tier4_isx021_stop_streaming( + wst_priv[i + 1].p_tc_dev); + mutex_lock(&tier4_isx021_lock); + } + + if (tier4_isx021_is_camera_running_on_port(i) == + false) { + // err = tier4_isx021_start_one_streaming(wst_priv[i].p_tc_dev, wst_priv[i].p_priv); + err = tier4_isx021_start_one_streaming( + wst_priv[i].p_tc_dev); + if (err) { + dev_err(dev, + "[%s] : Starting one streaming for current isx021 client failed.\n", + __func__); + goto error_exit; + } + tier4_isx021_set_running_flag(i, true); + } + } + } + } // for loop + + err = NO_ERROR; + +error_exit: + + mutex_unlock(&tier4_isx021_lock); + + // tier4_isx021_sensor_mutex_unlock(); + + return err; +} + +static struct camera_common_sensor_ops tier4_isx021_common_ops = { + .numfrmfmts = ARRAY_SIZE(tier4_isx021_frmfmt), + .frmfmt_table = tier4_isx021_frmfmt, + .power_on = tier4_isx021_power_on, + .power_off = tier4_isx021_power_off, + .write_reg = tier4_isx021_write_reg, + .read_reg = tier4_isx021_read_reg, + .parse_dt = tier4_isx021_parse_dt, + .power_get = tier4_isx021_power_get, + .power_put = tier4_isx021_power_put, + .set_mode = tier4_isx021_set_mode, + .start_streaming = tier4_isx021_start_streaming, + .stop_streaming = tier4_isx021_stop_streaming, +}; + +static int tier4_isx021_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + // struct i2c_client *client = v4l2_get_subdevdata(sd); + + return NO_ERROR; +} + +static const struct v4l2_subdev_internal_ops tier4_isx021_subdev_internal_ops = { + .open = tier4_isx021_open, +}; + +static const char *of_stdout_options; + +static int tier4_isx021_board_setup(struct tier4_isx021 *priv) +{ + struct tegracam_device *tc_dev = priv->tc_dev; + struct device *dev = tc_dev->dev; + struct device_node *node = dev->of_node; + struct device_node *mode_node; + struct device_node *ser_node; + struct device_node *root_node; + struct i2c_client *ser_i2c = NULL; + struct device_node *dser_node; + struct i2c_client *dser_i2c = NULL; + struct device_node *fpga_node = NULL; + struct i2c_client *fpga_i2c = NULL; + struct device_node *gmsl; + int value = 0xFFFF; + const char *str_value; + const char *str_value1[2]; + int i; + int err; + const char *str_model; + char upper_str_model[64]; + char *str_err; + //char *sub_str_err; + + root_node = of_find_node_opts_by_path("/", &of_stdout_options); + err = of_property_read_string(root_node, "model", &str_model); + if (err < 0) { + dev_err(dev, "[%s] : model not found\n", __func__); + goto error; + } + + memset(upper_str_model, 0, 64); + to_upper_string(upper_str_model, str_model); + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ORIN); + priv->g_ctx.hardware_model = HW_MODEL_UNKNOWN; + + if (str_err) { + priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_ORIN_DEVKIT; + } + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_XAVIER); + if (str_err) { + priv->g_ctx.hardware_model = HW_MODEL_NVIDIA_XAVIER_DEVKIT; + } + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_XAVIER); + if (str_err) { + priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_XAVIER; + } + + str_err = strstr(upper_str_model, STR_DTB_MODEL_NAME_ROSCUBE_ORIN); + if (str_err) { + priv->g_ctx.hardware_model = HW_MODEL_ADLINK_ROSCUBE_ORIN; + } + + dev_info(dev, "[%s] : hardware_model=%d\n", __func__, + priv->g_ctx.hardware_model); + dev_info(dev, "[%s] : model string=%s\n", __func__, str_model); + + // priv->g_ctx.debug_i2c_write = debug_i2c_write; + + if (priv->g_ctx.hardware_model == HW_MODEL_UNKNOWN) { + dev_err(dev, "[%s] : Unknown Hardware Sysytem !\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_reg); + if (err < 0) { + dev_err(dev, "[%s] : reg not found\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "def-addr", &priv->g_ctx.sdev_def); + if (err < 0) { + dev_err(dev, "[%s] : def-addr not found\n", __func__); + goto error; + } + + err = of_property_read_u32(node, "reg_mux", &priv->g_ctx.reg_mux); + if (err < 0) { + dev_err(dev, "[%s] : reg_mux not found\n", __func__); + goto error; + } + +#if 0 + err = of_property_read_string(node, "fsync-mode", &str_value); + if (err < 0) + { + dev_err(dev, "[%s] : No fsync-mode found\n", __func__); + goto error; + } + + if (!strcmp(str_value, "true")) + { + priv->fsync_mode = true; + } + else + { + priv->fsync_mode = false; + } +#endif + + if (enable_distortion_correction == 0xCAFE) { + // if not set kernel param, read device tree param + err = of_property_read_string(node, "distortion-correction", + &str_value); + if (err < 0) { + dev_err(dev, + "[%s] : No distortion-correction found. set enable_distortion-correction = true\n", + __func__); + } else { + if (!strcmp(str_value, "true")) { + enable_distortion_correction = 1; + } else { + enable_distortion_correction = 0; + } + } + } + + priv->distortion_correction = enable_distortion_correction != 0 ? true : + false; + + if (enable_auto_exposure == 0xCAFE) { + // if not set kernel param, read device tree param + err = of_property_read_string(node, "auto-exposure", + &str_value); + if (err < 0) { + dev_err(dev, + "[%s] : No auto-exposure mode found. set enable_auto_exposure = true\n", + __func__); + } else { + if (!strcmp(str_value, "true")) { + enable_auto_exposure = 1; + } else { + enable_auto_exposure = 0; + } + } + } + + priv->auto_exposure = enable_auto_exposure != 0 ? true : false; + + mode_node = of_get_child_by_name(node, "mode0"); + + dev_dbg(dev, + "[%s] : node->full_name = %s, mode_node->full_name = %s.\n", + __func__, node->full_name, mode_node->full_name); + +#ifdef USE_EMBEDDED_METADAT_HEIGHT_IN_DTB + /* check embedded_metadata_height */ + + err = of_property_read_string(mode_node, "embedded_metadata_height", + &str_value); + dev_info(dev, "[%s] : err = %d, embedded_metadata_height = %s\n", + __func__, err, str_value); + + err = kstrtoul(str_value, 10, &u_value); + embedded_metadata_height = u_value; + if (err) { + embedded_metadata_height = 0; + } else { + embedded_metadata_height = u_value; + } + + switch (embedded_metadata_height) { + case 0: + priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; + break; + case 1: + priv->enable_embedded_data = ENABLE_FRONT_EMBEDDED_DATA; + break; + case 14: + priv->enable_embedded_data = ENABLE_REAR_EMBEDDED_DATA; + break; + case 15: + priv->enable_embedded_data = ENABLE_BOTH_EMBEDDED_DATA; + break; + default: + priv->enable_embedded_data = DISABLE_BOTH_EMBEDDED_DATA; + } +#else // ifdef USE_EMBEDDED_METADAT_HEIGHT_IN_DTB + + priv->enable_embedded_data = + DISABLE_BOTH_EMBEDDED_DATA; // priv->enable_embedded_data is defined by camera sensor image mode + +#endif // ifdef USE_EMBEDDED_METADAT_HEIGHT_IN_DTB + + // for Ser node + + ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0); + + if (ser_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,gmsl-ser-device"); + goto error; + } + + err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg); + + if (err < 0) { + dev_err(dev, "[%s] : Serializer reg not found\n", __func__); + goto error; + } + + ser_i2c = of_find_i2c_device_by_node(ser_node); + + of_node_put(ser_node); + + if (ser_i2c == NULL) { + dev_err(dev, "[%s] : Missing Serializer Dev Handle\n", + __func__); + goto error; + } + + if (ser_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing serializer driver\n", __func__); + goto error; + } + + priv->ser_dev = &ser_i2c->dev; + + // for Dser node + + dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0); + if (dser_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,gmsl-dser-device"); + goto error; + } + + dser_i2c = of_find_i2c_device_by_node(dser_node); + of_node_put(dser_node); + if (dser_i2c == NULL) { + dev_err(dev, "[%s] : Missing deserializer dev handle\n", + __func__); + goto error; + } + + if (dser_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing deserializer driver\n", __func__); + goto error; + } + + priv->dser_dev = &dser_i2c->dev; + + if ((priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_XAVIER) || + (priv->g_ctx.hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + // for FPGA node + + fpga_node = of_parse_phandle(node, "nvidia,fpga-device", 0); + + if (fpga_node == NULL) { + dev_err(dev, "[%s] : Missing %s handle\n", __func__, + "nvidia,fpga-device"); + goto error; + } + + err = of_property_read_u32(fpga_node, "reg", + &priv->g_ctx.sdev_fpga_reg); + + if (err < 0) { + dev_err(dev, "[%s] : FPGA reg not found\n", __func__); + goto error; + } + + fpga_i2c = of_find_i2c_device_by_node(fpga_node); + + of_node_put(fpga_node); + + if (fpga_i2c == NULL) { + dev_err(dev, "[%s] : Missing FPGA Dev Handle\n", + __func__); + goto error; + } + + if (fpga_i2c->dev.driver == NULL) { + dev_err(dev, "[%s] : Missing FPGA driver\n", __func__); + goto error; + } + + priv->fpga_dev = &fpga_i2c->dev; + } + + /* populate g_ctx from DT */ + + gmsl = of_get_child_by_name(node, "gmsl-link"); + + if (gmsl == NULL) { + dev_err(dev, "[%s] : Missing GMSL-Link device node\n", + __func__); + err = -EINVAL; + goto error; + } + + err = of_property_read_string(gmsl, "dst-csi-port", &str_value); + if (err < 0) { + dev_err(dev, "[%s] : No dst-csi-port found\n", __func__); + goto error; + } + + priv->g_ctx.dst_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : + GMSL_CSI_PORT_B; + + err = of_property_read_string(gmsl, "src-csi-port", &str_value); + if (err < 0) { + dev_err(dev, "[%s] : No src-csi-port found\n", __func__); + goto error; + } + + priv->g_ctx.src_csi_port = (!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : + GMSL_CSI_PORT_B; + + err = of_property_read_string(gmsl, "csi-mode", &str_value); + if (err < 0) { + dev_err(dev, "[%s] : No csi-mode found\n", __func__); + goto error; + } + + if (!strcmp(str_value, "1x4")) { + priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE; + } else if (!strcmp(str_value, "2x4")) { + priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE; + } else if (!strcmp(str_value, "4x2")) { + priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE; + } else if (!strcmp(str_value, "2x2")) { + priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE; + } else { + dev_err(dev, "[%s] :Invalid csi-mode\n", __func__); + goto error; + } + + err = of_property_read_string(gmsl, "serdes-csi-link", &str_value); + if (err < 0) { + dev_err(dev, "[%s] : No serdes-csi-link found\n", __func__); + goto error; + } + + priv->g_ctx.serdes_csi_link = (!strcmp(str_value, "a")) ? + GMSL_SERDES_CSI_LINK_A : + GMSL_SERDES_CSI_LINK_B; + + err = of_property_read_u32(gmsl, "st-vc", &value); + if (err < 0) { + dev_err(dev, "[%s] : No st-vc info\n", __func__); + goto error; + } + + priv->g_ctx.st_vc = value; + + err = of_property_read_u32(gmsl, "vc-id", &value); + if (err < 0) { + dev_err(dev, "[%s] : No vc-id info\n", __func__); + goto error; + } + + priv->g_ctx.dst_vc = value; + + err = of_property_read_u32(gmsl, "num-lanes", &value); + if (err < 0) { + dev_err(dev, "[%s] : No num-lanes info\n", __func__); + goto error; + } + + priv->g_ctx.num_csi_lanes = value; + + priv->g_ctx.num_streams = of_property_count_strings(gmsl, "streams"); + if (priv->g_ctx.num_streams <= 0) { + dev_err(dev, "[%s] : No streams found\n", __func__); + err = -EINVAL; + goto error; + } + + for (i = 0; i < priv->g_ctx.num_streams; i++) { + of_property_read_string_index(gmsl, "streams", i, + &str_value1[i]); + if (!str_value1[i]) { + dev_err(dev, "[%s] : Invalid Stream Info\n", __func__); + goto error; + } + + if (!strcmp(str_value1[i], "raw12")) { + priv->g_ctx.streams[i].st_data_type = + GMSL_CSI_DT_RAW_12; + } else if (!strcmp(str_value1[i], "yuv8")) { + priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_YUV_8; + } else if (!strcmp(str_value1[i], "embed")) { + priv->g_ctx.streams[i].st_data_type = GMSL_CSI_DT_EMBED; + } else if (!strcmp(str_value1[i], "ued-u1")) { + priv->g_ctx.streams[i].st_data_type = + GMSL_CSI_DT_UED_U1; + } else { + dev_err(dev, "[%s] : Invalid stream data type.\n", + __func__); + goto error; + } + } + + priv->g_ctx.s_dev = dev; + + return NO_ERROR; + +error: + dev_err(dev, "[%s] : Board Setup failed.\n", __func__); + return err; +} + +static int tier4_isx021_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + char *path = FIRMWARE_BIN_FILE; + void *firmware_buffer; + + struct device *dev = &client->dev; + struct device_node *node = dev->of_node; + struct tegracam_device *tc_dev; + struct tier4_isx021 *priv; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 65) + loff_t size; +#endif + + tier4_isx021_sensor_mutex_lock(); + + // dev_info(dev, "[%s] : Probing V4L2 Sensor.\n", __func__); + + if (!IS_ENABLED(CONFIG_OF) || !node) { + err = -EINVAL; + goto errret; + } + + wst_priv[camera_channel_count].p_client = NULL; + wst_priv[camera_channel_count].p_priv = NULL; + wst_priv[camera_channel_count].p_tc_dev = NULL; + wst_priv[camera_channel_count].sensor_ser_shutdown = false; + wst_priv[camera_channel_count].des_shutdown = false; + wst_priv[camera_channel_count].running = false; + + priv = devm_kzalloc(dev, sizeof(struct tier4_isx021), GFP_KERNEL); + + if (!priv) { + dev_err(dev, "[%s] : Unable to allocate Memory!\n", __func__); + err = -ENOMEM; + goto errret; + } + + tc_dev = devm_kzalloc(dev, sizeof(struct tegracam_device), GFP_KERNEL); + + if (!tc_dev) { + err = -ENOMEM; + goto errret; + } + + priv->i2c_client = tc_dev->client = client; + + tc_dev->dev = dev; + + strncpy(tc_dev->name, "isx021", sizeof(tc_dev->name)); + + tc_dev->dev_regmap_config = &tier4_sensor_regmap_config; + tc_dev->sensor_ops = &tier4_isx021_common_ops; + tc_dev->v4l2sd_internal_ops = &tier4_isx021_subdev_internal_ops; + tc_dev->tcctrl_ops = &tier4_isx021_ctrl_ops; + + firmware_buffer = + devm_kzalloc(dev, sizeof(u16) * MAX_NUM_OF_REG, GFP_KERNEL); + + if (!firmware_buffer) { + dev_err(dev, "[%s] : Allocating firmware buffer failed.\n", + __func__); + err = -ENOMEM; + goto errret; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 65) + err = kernel_read_file_from_path( + path, 0, &firmware_buffer, INT_MAX, NULL, + READING_POLICY); // err is errono and number of bytes actually read + if (!err) { + dev_err(dev, "Loading %s failed with error %d\n", path, err); +#ifdef USE_FIRMWARE + goto errret; +#endif + } +#else + err = kernel_read_file_from_path( + path, &firmware_buffer, &size, INT_MAX, + READING_FIRMWARE); // size : number of bytes actually read + if (err) { + dev_err(dev, "Loading %s failed with error %d\n", path, err); +#ifdef USE_FIRMWARE + goto errret; +#endif + } +#endif + + priv->firmware_buffer = (u16 *)firmware_buffer; + + err = tegracam_device_register(tc_dev); + + if (err) { + dev_err(dev, + "[%s] : Tegra Camera Driver Registration failed.\n", + __func__); + goto errret; + } + + priv->tc_dev = tc_dev; + priv->s_data = tc_dev->s_data; + priv->subdev = &tc_dev->s_data->subdev; + + tegracam_set_privdata(tc_dev, (void *)priv); + + err = tier4_isx021_board_setup(priv); + + if (err) { + dev_err(dev, "[%s] : Board Setup failed.\n", __func__); + goto err_tegracam_unreg; + } + + priv->trigger_mode = trigger_mode; // trigger_mode per camaera + + /* Pair sensor to serializer dev */ + err = tier4_max9295_sdev_pair(priv->ser_dev, &priv->g_ctx); + + if (err) { + dev_err(&client->dev, "[%s] : GMSL Ser Pairing failed.\n", + __func__); + goto err_tegracam_unreg; + } + + /* Register sensor to deserializer dev */ + + //dev_info(dev, "[%s]: Before tier4_max9296_sdev_register() : priv->g_ctx.serdes_csi_link = %u\n" , __func__, priv->g_ctx.serdes_csi_link ); + + //asm("dmb sy"); + + err = tier4_max9296_sdev_register(priv->dser_dev, &priv->g_ctx); + + if (err) { + dev_err(&client->dev, + "[%s] : Failed to register GMSL Deserializer.\n", + __func__); + goto err_max9295_unpair; + } + + /* + * gmsl serdes setup + * + * Sensor power on/off should be the right place for serdes + * setup/reset. But the problem is, the total required delay + * in serdes setup/reset exceeds the frame wait timeout, looks to + * be related to multiple channel open and close sequence + * issue (#BUG 200477330). + * Once this bug is fixed, these may be moved to power on/off. + * The delays in serdes is as per guidelines and can't be reduced, + * so it is placed in probe/remove, though for that, deserializer + * would be powered on always post boot, until 1.2v is supplied + * to deserializer from CVB. + */ + + err = tier4_isx021_gmsl_serdes_setup(priv); + if (err) { + dev_err(&client->dev, "[%s] : Setup for GMSL Serdes failed.\n", + __func__); + goto err_max9296_unreg; + } + + err = tegracam_v4l2subdev_register(tc_dev, true); + if (err) { + dev_err(dev, + "[%s] : Tegra Camera Subdev Registration failed.\n", + __func__); + goto err_max9296_unreg; + } + + tier4_isx021_sensor_mutex_unlock(); + + err = tier4_isx021_write_reg(tc_dev->s_data, TIER4_ISX021_REG_90_ADDR, + 0x06); + + err = tier4_isx021_set_response_mode(priv); + if (err) { + dev_warn(dev, "[%s] : Transition to response mode failed.\n", + __func__); + goto err_tegracam_v4l2_unreg; + } + + dev_info(&client->dev, "Detected ISX021 sensor.\n"); + + wst_priv[camera_channel_count].p_client = client; + wst_priv[camera_channel_count].p_priv = priv; + wst_priv[camera_channel_count].p_tc_dev = tc_dev; + + camera_channel_count++; + + tier4_isx021_sensor_mutex_unlock(); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 65)) & 0 + + dev_info(&client->dev, "Detected ISX021 sensor\n"); + return NO_ERROR; +#else + return err; +#endif + +err_tegracam_v4l2_unreg: + tegracam_v4l2subdev_unregister(priv->tc_dev); +err_max9296_unreg: + tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); +err_max9295_unpair: + tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); +err_tegracam_unreg: + tegracam_device_unregister(priv->tc_dev); +errret: + tier4_isx021_sensor_mutex_unlock(); + + dev_err(&client->dev, "Detection for ISX021 sensor failed.\n"); + + return err; +} + +static void tier4_isx021_shutdown(struct i2c_client *client); + +static int tier4_isx021_remove(struct i2c_client *client) +{ + struct camera_common_data *s_data = to_camera_common_data(&client->dev); + struct tier4_isx021 *priv = (struct tier4_isx021 *)s_data->priv; + + tier4_isx021_shutdown(client); + + tier4_isx021_gmsl_serdes_reset(priv); + + tier4_max9296_sdev_unregister(priv->dser_dev, &client->dev); + tier4_max9295_sdev_unpair(priv->ser_dev, &client->dev); + + tegracam_v4l2subdev_unregister(priv->tc_dev); + + tegracam_device_unregister(priv->tc_dev); + + return NO_ERROR; +} + +static bool tier4_isx021_is_sensor_ser_shutdown(int nport) +{ + if (wst_priv[nport].sensor_ser_shutdown) { + return true; + } + return false; +} + +static bool tier4_isx021_is_des_shut_down(int nport) +{ + if (wst_priv[nport].des_shutdown) { + return true; + } + return false; +} + +static void tier4_isx021_set_sensor_ser_shutdown(int nport, bool val) +{ + wst_priv[nport].sensor_ser_shutdown = val; +} + +static void tier4_isx021_set_des_shutdown(int nport, bool val) +{ + wst_priv[nport].des_shutdown = val; +} + +static bool tier4_isx021_is_current_i2c_client(struct i2c_client *client, + int nport) +{ + if (client == wst_priv[nport].p_client) { + return true; + } + return false; +} + +/** +* The shutdown routine is needed only when you use ROcube and you would like to reboot command on Linux * +* if not so, you don't need shutdown function * +*/ + +static void tier4_isx021_shutdown(struct i2c_client *client) +{ + struct tier4_isx021 *priv = NULL; + int i; + + tier4_isx021_sensor_mutex_unlock(); + + mutex_lock(&tier4_isx021_lock); + + if (!client) { + goto error_exit; + } + + for (i = 0; i < camera_channel_count; i++) { + if (tier4_isx021_is_current_i2c_client(client, i)) { + priv = wst_priv[i].p_priv; + + if (i & + 0x1) { // Even port number( GMSL B port on a Des : i = port_number -1 ) + + if (tier4_isx021_is_camera_connected_to_port( + i - + 1)) { // if a camera connected to another(GMSL A)port on a Des. + + if (tier4_isx021_is_sensor_ser_shutdown( + i - + 1)) { // ISP and Ser on another(GMSL A) port have been + + if (tier4_isx021_is_des_shut_down( + i - 1) == + false) { // if Des on another(GMSL A)port is not shutdown yet + tier4_isx021_set_sensor_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_isx021_set_des_shutdown( + i, + true); // Des will be shut down + } else { // if Des on the another port is already shut down. + tier4_isx021_set_sensor_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_isx021_set_des_shutdown( + i, + false); // Des will not be shutdown + } + } else { // The camera ISP and Ser on another(GMSL A) port + if (tier4_isx021_is_des_shut_down( + i - 1) == + false) { // if Des is not shut down yet. + tier4_isx021_set_sensor_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_isx021_set_des_shutdown( + i, + false); // The Des won't be shut down. + } else { // Only Des on another port is already shut down. + tier4_isx021_set_sensor_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_isx021_set_des_shutdown( + i, + false); // Des will not be shut down. + } + } + } else { // a camera is connected to only (GMSL B) port on Des. + tier4_isx021_set_sensor_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_isx021_set_des_shutdown( + i, + true); // The Des won't be shut down. + } + } else { // if ( i & 0x1 ) == 0 : Camera is connected to Odd port number. ( GMSL A potr on a Des : i = port_number -1 + // ) + + if (tier4_isx021_is_camera_connected_to_port( + i + + 1)) { // Another camera is connected to + // another(GMSL B) port on the Des + if (tier4_isx021_is_sensor_ser_shutdown( + i + + 1)) { // if the ISP and Ser on another port + // are already shut down + if (tier4_isx021_is_des_shut_down( + i + 1) == + false) { // if Des is not shut down yet. + tier4_isx021_set_sensor_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_isx021_set_des_shutdown( + i, + false); // The Des will not be shut down. + } else { // Des is already shut down. This is Error case. + tier4_isx021_set_sensor_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_isx021_set_des_shutdown( + i, + false); // The Des will not be shut down. + } + } else { // The ISP and Ser on another(GMSL B) port + // are not shut down yet. + if (tier4_isx021_is_des_shut_down( + i + 1) == + false) { // if Des on another(GMSL B) port is not shut down yet. + tier4_isx021_set_sensor_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_isx021_set_des_shutdown( + i, + false); // The Des will not be shut down. + } else { // Only Des on another(GMSL B) port is already shut down. + // This is Error case. + tier4_isx021_set_sensor_ser_shutdown( + i, + false); // ISP and Ser will not be shut down + tier4_isx021_set_des_shutdown( + i, + false); // The Des will not be shut down. + } + } + } else { + tier4_isx021_set_sensor_ser_shutdown( + i, + true); // ISP and Ser will be shut down + tier4_isx021_set_des_shutdown( + i, + true); // The Des will be shut down. + } + } // if ( i & 0x1 ) + // break; + + if (tier4_isx021_is_sensor_ser_shutdown(i)) { + // Reset camera sensor + tier4_max9295_control_sensor_power_seq( + priv->ser_dev, SENSOR_ID_ISX021, false); + // S/W Reset max9295 + tier4_max9295_reset_control(priv->ser_dev); + } + + if (tier4_isx021_is_des_shut_down(i)) { + // S/W Reset max9296 + tier4_max9296_reset_control(priv->dser_dev, + &client->dev, true); + } + + if (priv == NULL || i >= camera_channel_count) { + mutex_unlock(&tier4_isx021_lock); + tier4_isx021_sensor_mutex_unlock(); + return; + } + } + } // for loop + +error_exit: + + mutex_unlock(&tier4_isx021_lock); + + tier4_isx021_sensor_mutex_unlock(); +} + +static const struct i2c_device_id tier4_isx021_id[] = { { "tier4_isx021", 0 }, + {} }; + +MODULE_DEVICE_TABLE(i2c, tier4_isx021_id); + +static struct i2c_driver tier4_isx021_i2c_driver = { + .driver = { + .name = "tier4_isx021", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tier4_isx021_of_match), + }, + .probe = tier4_isx021_probe, + .remove = tier4_isx021_remove, + .shutdown = tier4_isx021_shutdown, + .id_table = tier4_isx021_id, +}; + +static int __init tier4_isx021_init(void) +{ + mutex_init(&tier4_sensor_lock__); + mutex_init(&tier4_isx021_lock); + + // printk(KERN_INFO "TIERIV Automotive HDR Camera driver : %s\n", BUILD_STAMP); + + return i2c_add_driver(&tier4_isx021_i2c_driver); +} + +static void __exit tier4_isx021_exit(void) +{ + mutex_destroy(&tier4_sensor_lock__); + mutex_destroy(&tier4_isx021_lock); + + printk(KERN_INFO "[%s]: Exit TIERIV Automotive HDR Camera driver.\n", + __func__); + + i2c_del_driver(&tier4_isx021_i2c_driver); +} + +module_init(tier4_isx021_init); +module_exit(tier4_isx021_exit); + +MODULE_DESCRIPTION("TIERIV Automotive HDR Camera driver"); +MODULE_AUTHOR("K.Iwasaki"); +MODULE_AUTHOR("Y.Fujii"); +MODULE_LICENSE("GPL v2"); diff --git a/src/tier4-camera-gmsl/tier4-max9295.c b/src/tier4-camera-gmsl/tier4-max9295.c new file mode 100644 index 0000000..e5f9bfa --- /dev/null +++ b/src/tier4-camera-gmsl/tier4-max9295.c @@ -0,0 +1,780 @@ +/* + * tier4_max9295.c - tier4_max9295 GMSL Serializer driver + * + * Copyright (c) 2022-2023, TIERIV Inc. All rights reserved. + * Copyright (c) 2020, Leopard Imaging Inc. All rights reserved. + * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "tier4-max9295.h" +#include "tier4-gmsl-link.h" + +#define MAX9295_SHOW_I2C_WRITE_MSG 1 + +/* register specifics */ + +#define MAX9295_DEV_ADDR 0x0000 +#define MAX9295_PIPE_EN_ADDR 0x0002 +#define MAX9295_CLK_OUTPUT_ADDR 0x0003 +#define MAX9295_CTRL0_ADDR 0x0010 + +#define MAX9295_I2C4_ADDR 0x0044 +#define MAX9295_I2C5_ADDR 0x0045 + +#define MAX9295_CFGV_VIDEO_Y_ADDR 0x0057 +#define MAX9295_CFGV_VIDEO_Z_ADDR 0x005B + +#define MAX9295_VIDEO_TX0_ADDR 0x0110 +#define MAX9295_VIDEO_TX1_ADDR 0x0111 +#define MAX9295_VIDEO_TX2_ADDR 0x0112 +#define MAX9295_SRC_CTRL_ADDR 0x02BF +#define MAX9295_SRC_PWDN_ADDR 0x02BE + +#define MAX9295_GPIO_3_CONFIG_MFP3_ADDR 0x02C7 +#define MAX9295_GPIO_3_GPIO_TX_ID_ADDR 0x02C8 +#define MAX9295_GPIO_3_GPIO_RX_ID_ADDR 0x02C9 +#define MAX9295_GPIO_4_ADDR 0x02CA +#define MAX9295_GPIO_5_ADDR 0x02CD + +#define MAX9295_GPIO_8_ADDR 0x02D6 + +#define MAX9295_CSI_PORT_SEL_ADDR 0x0308 + +#define MAX9295_START_PIPE_ADDR 0x0311 +#define MAX9295_SEND_Z_PIPE_ADDR 0x0312 +#define MAX9295_PIPE_X_DT_ADDR 0x0314 +#define MAX9295_PIPE_Y_DT_ADDR 0x0316 +#define MAX9295_PIPE_Z_DT_ADDR 0x0318 +#define MAX9295_PIPE_U_DT_ADDR 0x031A +#define MAX9295_OVERRIDE_Z_PIPE_ADDR 0x031E + +#define MAX9295_MIPI_RX0_ADDR 0x0330 +#define MAX9295_MIPI_RX1_ADDR 0x0331 +#define MAX9295_MIPI_RX2_ADDR 0x0332 +#define MAX9295_MIPI_RX3_ADDR 0x0333 + +#define MAX9295_REF_VTG0_ADDR 0x03F0 +#define MAX9295_SRC_OUT_RCLK_ADDR 0x03F1 + +#define MAX9295_REG570_ADDR 0x0570 + +#define MAX9295_STREAM_PIPE_UNUSED 0x22 +#define MAX9295_CSI_MODE_1X4 0x00 +#define MAX9295_CSI_MODE_2X2 0x03 +#define MAX9295_CSI_MODE_2X4 0x06 + +#define MAX9295_CSI_PORT_B(num_lanes) (((num_lanes) << 4) & 0xF0) +#define MAX9295_CSI_PORT_A(num_lanes) ((num_lanes)&0x0F) + +#define MAX9295_CSI_1X4_MODE_LANE_MAP1 0xE0 +#define MAX9295_CSI_1X4_MODE_LANE_MAP2 0x04 + +#define MAX9295_CSI_2X4_MODE_LANE_MAP1 0xEE +#define MAX9295_CSI_2X4_MODE_LANE_MAP2 0xE4 + +#define MAX9295_CSI_2X2_MODE_LANE_MAP1 MAX9295_CSI_2X4_MODE_LANE_MAP1 +#define MAX9295_CSI_2X2_MODE_LANE_MAP2 MAX9295_CSI_2X4_MODE_LANE_MAP2 + +#define MAX9295_ST_ID_0 0x0 +#define MAX9295_ST_ID_1 0x1 +#define MAX9295_ST_ID_2 0x2 +#define MAX9295_ST_ID_3 0x3 + +#define MAX9295_PIPE_X_START_B 0x80 +#define MAX9295_PIPE_Y_START_B 0x40 +#define MAX9295_PIPE_Z_START_B 0x20 +#define MAX9295_PIPE_U_START_B 0x10 + +#define MAX9295_PIPE_X_START_A 0x1 +#define MAX9295_PIPE_Y_START_A 0x2 +#define MAX9295_PIPE_Z_START_A 0x4 +#define MAX9295_PIPE_U_START_A 0x8 + +#define MAX9295_START_PORT_A 0x10 +#define MAX9295_START_PORT_B 0x20 + +#define MAX9295_CSI_LN2 0x1 +#define MAX9295_CSI_LN4 0x3 + +#define MAX9295_EN_LINE_INFO 0x40 + +#define MAX9295_VID_TX_EN_X 0x10 +#define MAX9295_VID_TX_EN_Y 0x20 +#define MAX9295_VID_TX_EN_Z 0x40 +#define MAX9295_VID_TX_EN_U 0x80 + +#define MAX9295_VID_INIT 0x3 +#define MAX9295_SRC_RCLK 0x89 + +#define MAX9295_RESET_ALL 0x80 +#define MAX9295_RESET_SRC 0x60 +#define MAX9295_PWDN_GPIO 0x90 + +#define MAX9295_MAX_PIPES 0x4 + +struct tier4_max9295_client_ctx { + struct tier4_gmsl_link_ctx *g_ctx; + bool st_done; +}; + +struct tier4_max9295 { + struct i2c_client *i2c_client; + struct regmap *regmap; + struct tier4_max9295_client_ctx g_client; + struct mutex lock; + /* primary serializer properties */ + __u32 def_addr; + __u32 pst2_ref; +}; + +#define MAX_CHANNEL_NUM 8 + +/* count channel,the max MAX_CHANNEL_NUM*/ +static __u32 channel_count_isx021; + +static struct tier4_max9295 *prim_priv__[MAX_CHANNEL_NUM]; + +struct map_ctx { + u8 dt; + u16 addr; + u8 val; + u8 st_id; +}; + +#if 0 + +static int tier4_max9295_read_reg(struct device *dev, u16 addr, u8 *val) +{ + int err = 0; + u32 reg_val = 0; + struct tier4_max9295 *priv = dev_get_drvdata(dev); + char str_bus_num[4], str_sl_addr[4]; + int len = 0; + + memset(str_bus_num,0,4); + memset(str_sl_addr,0,4); + + err = regmap_read(priv->regmap, addr, ®_val); + + *val = reg_val & 0xFF; + + dev_info(dev, "[%s ] : Max9295 I2C Read at 0x%04X=[0x%02X].\n", __func__, addr, *val ); + + if (( err == 0 ) && ( dev != NULL ) ) { + len = strlen(dev->kobj.name); + if (dev) { + strncpy(str_bus_num, &dev->kobj.name[0], 2); + strncpy(str_sl_addr, &dev->kobj.name[len-2], 2); + } + } + return err; +} +#endif + +static int tier4_max9295_write_reg(struct device *dev, u16 addr, u8 val) +{ + struct tier4_max9295 *priv = dev_get_drvdata(dev); + int err = 0; + // u8 e; + char str_bus_num[4], str_sl_addr[4]; + int len; + + memset(str_bus_num, 0, 4); + memset(str_sl_addr, 0, 4); + + len = strlen(dev->kobj.name); + + if ((err == 0) && (dev != NULL)) { + strncpy(str_bus_num, &dev->kobj.name[0], 2); + strncpy(str_sl_addr, &dev->kobj.name[len - 2], 2); + } + + err = regmap_write(priv->regmap, addr, val); + + if (err) { + dev_err(dev, + "[%s] : Max9295 I2C write failed Reg at 0x%04X:[0x%02X].\n", + __func__, addr, val); + } +#if MAX9295_SHOW_I2C_WRITE_MSG + else { + dev_info( + dev, + "[%s] : Max9295 I2C write register at 0x%04X:[0x%02X]\n", + __func__, addr, val); + } +#endif + + /* delay before next i2c command as required for SERDES link */ + + usleep_range(100, 110); + //msleep(100); + // tier4_max9295_read_reg(dev, addr, &e); + usleep_range(100, 110); + //msleep(100); + + return err; +} + +int tier4_max9295_setup_streaming(struct device *dev) +{ + struct tier4_max9295 *priv = dev_get_drvdata(dev); + int err = 0; + u32 csi_mode; + u32 lane_map1; + u32 lane_map2; + u32 port; + u32 rx1_lanes; + u32 st_pipe; + u32 pipe_en; + u32 port_sel = 0; + struct tier4_gmsl_link_ctx *g_ctx; + u32 i; + u32 j; + u32 st_en; + + struct map_ctx map_pipe_dtype[] = { + { GMSL_CSI_DT_YUV_8, MAX9295_PIPE_Z_DT_ADDR, 0x1E, // For YUV8 + MAX9295_ST_ID_2 }, + { GMSL_CSI_DT_UED_U1, MAX9295_PIPE_X_DT_ADDR, + 0x30, // User defined embedded data type + MAX9295_ST_ID_0 }, + { GMSL_CSI_DT_EMBED, MAX9295_PIPE_Y_DT_ADDR, 0x12, + MAX9295_ST_ID_1 }, + }; + + mutex_lock(&priv->lock); + + if (!priv->g_client.g_ctx) { + dev_err(dev, "[%s] : No sdev client found\n", __func__); + err = -EINVAL; + goto error; + } + + if (priv->g_client.st_done) { + dev_dbg(dev, "[%s] : Stream setup is already done\n", __func__); + goto error; + } + + g_ctx = priv->g_client.g_ctx; + + switch (g_ctx->csi_mode) { + case GMSL_CSI_1X4_MODE: + csi_mode = MAX9295_CSI_MODE_1X4; + lane_map1 = MAX9295_CSI_1X4_MODE_LANE_MAP1; + lane_map2 = MAX9295_CSI_1X4_MODE_LANE_MAP2; + rx1_lanes = MAX9295_CSI_LN4; + break; + case GMSL_CSI_2X2_MODE: + csi_mode = MAX9295_CSI_MODE_2X2; + lane_map1 = MAX9295_CSI_2X2_MODE_LANE_MAP1; + lane_map2 = MAX9295_CSI_2X2_MODE_LANE_MAP2; + rx1_lanes = MAX9295_CSI_LN2; + break; + case GMSL_CSI_2X4_MODE: + csi_mode = MAX9295_CSI_MODE_2X4; + lane_map1 = MAX9295_CSI_2X4_MODE_LANE_MAP1; + lane_map2 = MAX9295_CSI_2X4_MODE_LANE_MAP2; + rx1_lanes = MAX9295_CSI_LN4; + break; + default: + dev_err(dev, "[%s] : Invalid csi mode\n", __func__); + err = -EINVAL; + goto error; + } + + port = (g_ctx->src_csi_port == GMSL_CSI_PORT_B) ? + MAX9295_CSI_PORT_B(rx1_lanes) : + MAX9295_CSI_PORT_A(rx1_lanes); + + tier4_max9295_write_reg(dev, MAX9295_MIPI_RX0_ADDR, csi_mode); + tier4_max9295_write_reg(dev, MAX9295_MIPI_RX1_ADDR, port); + tier4_max9295_write_reg(dev, MAX9295_MIPI_RX2_ADDR, lane_map1); + tier4_max9295_write_reg(dev, MAX9295_MIPI_RX3_ADDR, lane_map2); + + for (i = 0; i < g_ctx->num_streams; i++) { + struct tier4_gmsl_stream *g_stream = &g_ctx->streams[i]; + + g_stream->st_id_sel = GMSL_ST_ID_UNUSED; + + for (j = 0; j < ARRAY_SIZE(map_pipe_dtype); j++) { + if (map_pipe_dtype[j].dt == g_stream->st_data_type) { + /* + * TODO: + * 1) Remove link specific overrides, depends + * on #2. + * 2) Add support for vc id based stream sel + * overrides TX_SRC_SEL. would be useful in + * using same mappings in all ser devs. + */ + if (g_ctx->serdes_csi_link == + GMSL_SERDES_CSI_LINK_B) { + map_pipe_dtype[j].addr += 2; + map_pipe_dtype[j].st_id += 1; + } + + g_stream->st_id_sel = map_pipe_dtype[j].st_id; + + st_en = (map_pipe_dtype[j].addr == + MAX9295_PIPE_X_DT_ADDR) ? + 0xC0 : + 0x40; + + tier4_max9295_write_reg( + dev, map_pipe_dtype[j].addr, + (st_en | map_pipe_dtype[j].val)); + } + } + } + + for (i = 0; i < g_ctx->num_streams; i++) + if (g_ctx->streams[i].st_id_sel != GMSL_ST_ID_UNUSED) + port_sel |= (1 << g_ctx->streams[i].st_id_sel); + + if (g_ctx->src_csi_port == GMSL_CSI_PORT_B) { + st_pipe = (MAX9295_PIPE_X_START_B | MAX9295_PIPE_Y_START_B | + MAX9295_PIPE_Z_START_B | MAX9295_PIPE_U_START_B); + port_sel |= (MAX9295_EN_LINE_INFO | MAX9295_START_PORT_B); + } else { + st_pipe = MAX9295_PIPE_X_START_A | MAX9295_PIPE_Y_START_A | + MAX9295_PIPE_Z_START_A | MAX9295_PIPE_U_START_A; + port_sel |= (MAX9295_EN_LINE_INFO | MAX9295_START_PORT_A); + } + + pipe_en = + (MAX9295_VID_TX_EN_X | MAX9295_VID_TX_EN_Y | + MAX9295_VID_TX_EN_Z | MAX9295_VID_TX_EN_U | MAX9295_VID_INIT); + + tier4_max9295_write_reg(dev, MAX9295_START_PIPE_ADDR, st_pipe); + tier4_max9295_write_reg(dev, MAX9295_CSI_PORT_SEL_ADDR, port_sel); + + tier4_max9295_write_reg(dev, MAX9295_PIPE_EN_ADDR, pipe_en); + + priv->g_client.st_done = true; + +error: + mutex_unlock(&priv->lock); + return err; +} +EXPORT_SYMBOL(tier4_max9295_setup_streaming); + +// ------------------------------------------------------------------ + +int tier4_max9295_control_sensor_power_seq(struct device *dev, __u32 sensor_id, + bool power_on) +{ + struct tier4_max9295 *priv = dev_get_drvdata(dev); + struct tier4_gmsl_link_ctx *g_ctx; + int err = 0; + + g_ctx = priv->g_client.g_ctx; + +#if 1 + + msleep(200); + + if (power_on == true) { // power up camera sensor + + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_8_ADDR, 0x00); + + msleep(100); + + if (sensor_id == SENSOR_ID_ISX021) { + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_5_ADDR, + 0x04); + msleep(100); + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_4_ADDR, + 0x10); + msleep(100); + } else if (sensor_id == SENSOR_ID_IMX728) { + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_4_ADDR, + 0x10); + msleep(100); + } + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_8_ADDR, 0x10); + } else { // power down caemra sensor + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_8_ADDR, 0x00); + msleep(100); + if (sensor_id == SENSOR_ID_ISX021) { + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_5_ADDR, + 0x04); + msleep(100); + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_4_ADDR, + 0x00); + msleep(100); + } else if (sensor_id == SENSOR_ID_IMX728) { + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_4_ADDR, + 0x00); + msleep(100); + } + } + + if (err) { + dev_err(dev, + "[%s] : Ppower on/off Camera Sensor or ISP failed.\n", + __func__); + } + + msleep(50); +#endif + return err; +} +EXPORT_SYMBOL(tier4_max9295_control_sensor_power_seq); + +int tier4_max9295_setup_gpo(struct device *dev) +{ + int err = 0; + + dev_info(dev, "[%s] : Set up max9295 for fsync trigger mode \n", + __func__); + + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_3_CONFIG_MFP3_ADDR, + 0x04); + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_3_GPIO_TX_ID_ADDR, + 0x00); + err += tier4_max9295_write_reg(dev, MAX9295_GPIO_3_GPIO_RX_ID_ADDR, + 0x06); + + return err; +} +EXPORT_SYMBOL(tier4_max9295_setup_gpo); + +int tier4_max9295_setup_control(struct device *dev) +{ + struct tier4_max9295 *priv = dev_get_drvdata(dev); + int err = 0; + struct tier4_gmsl_link_ctx *g_ctx; + u32 offset1 = 0; + u32 offset2 = 0; + u32 i; + + u8 i2c_ovrd[] = { + 0x6B, 0x10, 0x73, 0x11, 0x7B, 0x30, 0x83, 0x30, 0x93, + 0x30, 0x9B, 0x30, 0xA3, 0x30, 0xAB, 0x30, 0x8B, 0x30, + }; + + u8 addr_offset[] = { + 0x80, 0x00, 0x00, 0x84, 0x00, 0x01, + 0xC0, 0x02, 0x02, 0xC4, 0x02, 0x03, + }; + + mutex_lock(&priv->lock); + + g_ctx = priv->g_client.g_ctx; + + if (prim_priv__[g_ctx->reg_mux] == NULL) { + err = -EINVAL; + goto error; + } + /* update address reassingment */ + tier4_max9295_write_reg(&prim_priv__[g_ctx->reg_mux]->i2c_client->dev, + MAX9295_DEV_ADDR, (g_ctx->ser_reg << 1)); + + msleep(100); + + if (g_ctx->serdes_csi_link == GMSL_SERDES_CSI_LINK_A) { + err = tier4_max9295_write_reg(dev, MAX9295_CTRL0_ADDR, 0x21); + } else { + err = tier4_max9295_write_reg(dev, MAX9295_CTRL0_ADDR, 0x22); + } + + /* check if serializer device exists */ + if (err) { + dev_err(dev, "[%s]: Ser device not found\n", __func__); + goto error; + } + /* delay to settle link */ + msleep(100); + + /* Set RCLKOUT soruce to the reference PLL clock*/ + err = tier4_max9295_write_reg(dev, MAX9295_CLK_OUTPUT_ADDR, 0x03); + + /* No need?*/ + usleep_range(10000, 11000); + + /* PLL setting & Reset PLL */ + err = tier4_max9295_write_reg(dev, MAX9295_REF_VTG0_ADDR, 0x5A); + usleep_range(10000, 11000); + // err = tier4_max9295_write_reg(dev, MAX9295_REG570_ADDR, 0x0C); + + for (i = 0; i < ARRAY_SIZE(addr_offset); i += 3) { + if ((g_ctx->ser_reg << 1) == addr_offset[i]) { + offset1 = addr_offset[i + 1]; + offset2 = addr_offset[i + 2]; + break; + } + } + + if (i == ARRAY_SIZE(addr_offset)) { + dev_err(dev, "[%s] : Invalid ser slave address\n", __func__); + err = -EINVAL; + goto error; + } + + for (i = 0; i < ARRAY_SIZE(i2c_ovrd); i += 2) { + /* update address overrides */ + i2c_ovrd[i + 1] += (i < 4) ? offset1 : offset2; + + /* i2c passthrough2 must be configured once for all devices */ + if ((i2c_ovrd[i] == 0x8B) && + prim_priv__[g_ctx->reg_mux]->pst2_ref) + continue; + + tier4_max9295_write_reg(dev, i2c_ovrd[i], i2c_ovrd[i + 1]); + } + + /* dev addr pass-through2 ref */ + + prim_priv__[g_ctx->reg_mux]->pst2_ref++; + + tier4_max9295_write_reg(dev, MAX9295_I2C4_ADDR, (g_ctx->sdev_reg << 1)); + tier4_max9295_write_reg(dev, MAX9295_I2C5_ADDR, (g_ctx->sdev_def << 1)); + + tier4_max9295_write_reg(dev, MAX9295_SRC_PWDN_ADDR, MAX9295_PWDN_GPIO); + tier4_max9295_write_reg(dev, MAX9295_SRC_CTRL_ADDR, MAX9295_RESET_SRC); + tier4_max9295_write_reg(dev, MAX9295_SRC_OUT_RCLK_ADDR, + MAX9295_SRC_RCLK); + + /* PLL setting & Enable PLL */ + tier4_max9295_write_reg(dev, MAX9295_REF_VTG0_ADDR, 0x59); + + g_ctx->serdev_found = true; + +error: + + mutex_unlock(&priv->lock); + + return err; +} +EXPORT_SYMBOL(tier4_max9295_setup_control); + +int tier4_max9295_reset_control(struct device *dev) +{ + struct tier4_max9295 *priv = dev_get_drvdata(dev); + int err = 0; + + mutex_lock(&priv->lock); + if (!priv->g_client.g_ctx) { + dev_err(dev, "[%s] : No sdev client found\n", __func__); + err = -EINVAL; + goto error; + } + + prim_priv__[priv->g_client.g_ctx->reg_mux]->pst2_ref--; + + priv->g_client.st_done = false; + + tier4_max9295_write_reg( + dev, MAX9295_DEV_ADDR, + (prim_priv__[priv->g_client.g_ctx->reg_mux]->def_addr << 1)); + + tier4_max9295_write_reg( + &prim_priv__[priv->g_client.g_ctx->reg_mux]->i2c_client->dev, + MAX9295_CTRL0_ADDR, MAX9295_RESET_ALL); + +error: + mutex_unlock(&priv->lock); + return err; +} +EXPORT_SYMBOL(tier4_max9295_reset_control); + +int tier4_max9295_sdev_pair(struct device *dev, + struct tier4_gmsl_link_ctx *g_ctx) +{ + struct tier4_max9295 *priv; + int err = 0; + + if (!dev || !g_ctx || !g_ctx->s_dev) { + dev_err(dev, "[%s]: Invalid input params\n", __func__); + return -EINVAL; + } + + priv = dev_get_drvdata(dev); + mutex_lock(&priv->lock); + if (priv->g_client.g_ctx) { + dev_err(dev, "[%s] : Device already paired\n", __func__); + err = -EINVAL; + goto error; + } + priv->g_client.st_done = false; + + priv->g_client.g_ctx = g_ctx; + +error: + mutex_unlock(&priv->lock); + return 0; +} +EXPORT_SYMBOL(tier4_max9295_sdev_pair); + +int tier4_max9295_sdev_unpair(struct device *dev, struct device *s_dev) +{ + struct tier4_max9295 *priv = NULL; + int err = 0; + + if (!dev || !s_dev) { + dev_err(dev, "[%s] : Invalid input params\n", __func__); + return -EINVAL; + } + + priv = dev_get_drvdata(dev); + + mutex_lock(&priv->lock); + + if (!priv->g_client.g_ctx) { + dev_err(dev, "[%s] : Device is not paired\n", __func__); + err = -ENOMEM; + goto error; + } + + if (priv->g_client.g_ctx->s_dev != s_dev) { + dev_err(dev, "[%s] : Invalid device\n", __func__); + err = -EINVAL; + goto error; + } + + priv->g_client.g_ctx = NULL; + priv->g_client.st_done = false; + +error: + mutex_unlock(&priv->lock); + return err; +} +EXPORT_SYMBOL(tier4_max9295_sdev_unpair); + +static struct regmap_config tier4_max9295_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +static int tier4_max9295_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tier4_max9295 *priv; + int err = 0; + struct device_node *node = client->dev.of_node; + + dev_info(&client->dev, "[%s] : probing GMSL Serializer\n", __func__); + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + priv->i2c_client = client; + priv->regmap = devm_regmap_init_i2c(priv->i2c_client, + &tier4_max9295_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&client->dev, "[%s] : devm_regmap_init() failed: %ld\n", + __func__, PTR_ERR(priv->regmap)); + return -ENODEV; + } + + mutex_init(&priv->lock); + + if (of_get_property(node, "is-prim-ser", NULL)) { + if (prim_priv__[channel_count_isx021] && + channel_count_isx021 >= MAX_CHANNEL_NUM) { + dev_err(&client->dev, + "[%s] : prim-ser already exists\n", __func__); + return -EEXIST; + } + + err = of_property_read_u32(node, "reg", &priv->def_addr); + if (err < 0) { + dev_err(&client->dev, "[%s] : reg not found\n", + __func__); + return -EINVAL; + } + + if (priv == NULL) { + dev_err(&client->dev, "[%s] : priv is NULL\n", + __func__); + return err; + } + + prim_priv__[channel_count_isx021] = priv; + + channel_count_isx021++; + } + + dev_set_drvdata(&client->dev, priv); + + /* dev communication gets validated when GMSL link setup is done */ + dev_info(&client->dev, "[%s] : Probing succeeded\n", __func__); + + return err; +} + +static int tier4_max9295_remove(struct i2c_client *client) +{ + struct tier4_max9295 *priv; + + if (channel_count_isx021 > 0) + channel_count_isx021--; + + if (client != NULL) { + priv = dev_get_drvdata(&client->dev); + mutex_destroy(&priv->lock); + } + + return 0; +} + +static const struct i2c_device_id tier4_max9295_id[] = { + { "tier4_max9295", 0 }, + {}, +}; + +const struct of_device_id tier4_max9295_of_match[] = { + { + .compatible = "nvidia,tier4_max9295", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, tier4_max9295_of_match); +MODULE_DEVICE_TABLE(i2c, tier4_max9295_id); + +static struct i2c_driver tier4_max9295_i2c_driver = { + .driver = { + .name = "tier4_max9295", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tier4_max9295_of_match), + }, + .probe = tier4_max9295_probe, + .remove = tier4_max9295_remove, + .id_table = tier4_max9295_id, +}; + +static int __init tier4_max9295_init(void) +{ + printk(KERN_INFO "MAX9295 Driver for TIER4 C1 camera : %s\n", + BUILD_STAMP); + + return i2c_add_driver(&tier4_max9295_i2c_driver); +} + +static void __exit tier4_max9295_exit(void) +{ + i2c_del_driver(&tier4_max9295_i2c_driver); +} + +module_init(tier4_max9295_init); +module_exit(tier4_max9295_exit); + +MODULE_DESCRIPTION("GMSL Serializer driver tier4_max9295"); +MODULE_AUTHOR("Originaly NVIDIA Corporation"); +MODULE_AUTHOR("K.Iwasaki"); +MODULE_AUTHOR("Y.Fujii"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-max9295.h b/src/tier4-camera-gmsl/tier4-max9295.h similarity index 95% rename from drivers/src/tier4-max9295.h rename to src/tier4-camera-gmsl/tier4-max9295.h index 0d3a764..7fd7ca0 100644 --- a/drivers/src/tier4-max9295.h +++ b/src/tier4-camera-gmsl/tier4-max9295.h @@ -73,7 +73,8 @@ int tier4_max9295_reset_control(struct device *dev); * * @return 0 for success, or -1 otherwise. */ -int tier4_max9295_sdev_pair(struct device *dev, struct tier4_gmsl_link_ctx *g_ctx); +int tier4_max9295_sdev_pair(struct device *dev, + struct tier4_gmsl_link_ctx *g_ctx); /** * @brief Unpairs a sensor device from a serializer device. @@ -99,7 +100,8 @@ int tier4_max9295_sdev_unpair(struct device *dev, struct device *s_dev); #if 0 int tier4_max9295_power_up_camera_sensor(struct device *dev); #else -int tier4_max9295_control_sensor_power_seq(struct device *dev, __u32 sensor_id, bool power_on); +int tier4_max9295_control_sensor_power_seq(struct device *dev, __u32 sensor_id, + bool power_on); #endif /** * Pre-sets up the serializer device's internal pipeline for a specified @@ -121,4 +123,4 @@ int tier4_max9295_pre_setup_streaming(struct device *dev); */ int tier4_max9295_setup_streaming(struct device *dev); -#endif // __TIER4_MAX9295_H__ +#endif // __TIER4_MAX9295_H__ diff --git a/src/tier4-camera-gmsl/tier4-max9296.c b/src/tier4-camera-gmsl/tier4-max9296.c new file mode 100644 index 0000000..4b83256 --- /dev/null +++ b/src/tier4-camera-gmsl/tier4-max9296.c @@ -0,0 +1,1207 @@ +/* + * tier4_max9296.c - tier4_max9296 GMSL Deserializer driver + * + * Copyright (c) 2022, TIER IV Inc. All rights reserved. + * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "tier4-max9296.h" +#include "tier4-gmsl-link.h" +#include "tier4-hw-model.h" + +struct tier4_max9296_source_ctx { + struct tier4_gmsl_link_ctx *g_ctx; + bool st_enabled; +}; + +#define _USE_CHECK_LINK_LOCKED_ 1 + +#define MAX9296_SHOW_I2C_WRITE_MSG 1 + +/* register specifics */ + +#define MAX9296_LINK_ADDR 0x0013 + +#define MAX9296_REG5_ADDR 0x0005 +#define MAX9296_CTRL0_ADDR 0x0010 + +#define MAX9296_PIPE_X_ST_SEL_ADDR 0x0050 + +#define MAX9296_GPIO0_CONFIG_MFP0_ADDR 0x02B0 +#define MAX9296_GPIO0_GPIO_TX_ID_ADDR 0x02B1 +#define MAX9296_GPIO0_GPIO_RX_ID_ADDR 0x02B2 + +#define MAX9296_PHY1_CLK_ADDR 0x0320 + +#define MAX9296_DST_CSI_MODE_ADDR 0x0330 +#define MAX9296_PWDN_PHYS_ADDR 0x0332 +#define MAX9296_LANE_MAP1_ADDR 0x0333 +#define MAX9296_LANE_MAP2_ADDR 0x0334 + +#define MAX9296_LANE_CTRL0_ADDR 0x040A +#define MAX9296_TX11_PIPE_X_EN_ADDR 0x040B +#define MAX9296_PIPE_X_SRC_0_MAP_ADDR 0x040D +#define MAX9296_PIPE_X_DST_0_MAP_ADDR 0x040E +#define MAX9296_PIPE_X_SRC_1_MAP_ADDR 0x040F + +#define MAX9296_PIPE_X_DST_1_MAP_ADDR 0x0410 +#define MAX9296_PIPE_X_SRC_2_MAP_ADDR 0x0411 +#define MAX9296_PIPE_X_DST_2_MAP_ADDR 0x0412 + +#define MAX9296_TX45_PIPE_X_DST_CTRL_ADDR 0x042D + +#define MAX9296_LANE_CTRL1_ADDR 0x044A +#define MAX9296_LANE_CTRL2_ADDR 0x048A +#define MAX9296_LANE_CTRL3_ADDR 0x04CA + +/* data defines */ + +#define MAX9296_CSI_MODE_4X2 0x1 +#define MAX9296_CSI_MODE_2X4 0x4 +#define MAX9296_LANE_MAP1_4X2 0x44 +#define MAX9296_LANE_MAP2_4X2 0x44 +#define MAX9296_LANE_MAP1_2X4 0x4E +#define MAX9296_LANE_MAP2_2X4 0xE4 + +#define MAX9296_LANE_CTRL_MAP(num_lanes) (((num_lanes) << 6) & 0xF0) + +#define MAX9296_ALLPHYS_NOSTDBY 0xF0 +#define MAX9296_ST_ID_SEL_INVALID 0xF + +//#define MAX9296_PHY1_CLK 0x32 +#define MAX9296_PHY1_CLK_3100MHZ 0x3F +#define MAX9296_PHY1_CLK_3000MHZ 0x3E +#define MAX9296_PHY1_CLK_2900MHZ 0x3D +#define MAX9296_PHY1_CLK_2800MHZ 0x3C +#define MAX9296_PHY1_CLK_2700MHZ 0x3B +#define MAX9296_PHY1_CLK_2600MHZ 0x3A +#define MAX9296_PHY1_CLK_2500MHZ 0x39 +#define MAX9296_PHY1_CLK_2400MHZ 0x38 +#define MAX9296_PHY1_CLK_2300MHZ 0x37 +#define MAX9296_PHY1_CLK_2200MHZ 0x36 +#define MAX9296_PHY1_CLK_2100MHZ 0x35 +#define MAX9296_PHY1_CLK_2000MHZ 0x34 +#define MAX9296_PHY1_CLK_1900MHZ 0x33 +#define MAX9296_PHY1_CLK_1800MHZ 0x32 +#define MAX9296_PHY1_CLK_1700MHZ 0x31 +#define MAX9296_PHY1_CLK_1600MHZ 0x30 +#define MAX9296_PHY1_CLK_1500MHZ 0x2F +#define MAX9296_PHY1_CLK_1400MHZ 0x2E +#define MAX9296_PHY1_CLK_1300MHZ 0x2D +#define MAX9296_PHY1_CLK_1200MHZ 0x2C +#define MAX9296_PHY1_CLK_1100MHZ 0x2B +#define MAX9296_PHY1_CLK_1000MHZ 0x2A +#define MAX9296_PHY1_CLK_900MHZ 0x29 +#define MAX9296_PHY1_CLK_800MHZ 0x28 +#define MAX9296_PHY1_CLK_700MHZ 0x27 + +#define MAX9296_PHY1_CLK MAX9296_PHY1_CLK_1500MHZ + +#define MAX9296_RESET_ALL 0x80 + +/* Dual GMSL MAX9296A/B */ + +#define MAX9296_MAX_SOURCES 2 + +#define MAX9296_MAX_PIPES 4 + +#define MAX9296_PIPE_X 0 +#define MAX9296_PIPE_Y 1 +#define MAX9296_PIPE_Z 2 +#define MAX9296_PIPE_U 3 +#define MAX9296_PIPE_INVALID 0xF + +#define MAX9296_CSI_CTRL_0 0 +#define MAX9296_CSI_CTRL_1 1 +#define MAX9296_CSI_CTRL_2 2 +#define MAX9296_CSI_CTRL_3 3 + +#define MAX9296_INVAL_ST_ID 0xFF + +/* Use reset value as per spec, confirm with vendor */ + +#define MAX9296_RESET_ST_ID 0x00 + +struct pipe_ctx { + u32 id; + u32 dt_type; + u32 dst_csi_ctrl; + u32 st_count; + u32 st_id_sel; +}; + +struct tier4_max9296 { + struct i2c_client *i2c_client; + struct regmap *regmap; + u32 num_src; + u32 max_src; + u32 num_src_found; + u32 src_link; + bool splitter_enabled; + + struct tier4_max9296_source_ctx sources[MAX9296_MAX_SOURCES]; + + struct mutex lock; + u32 sdev_ref; + bool lane_setup; + bool link_setup; + struct pipe_ctx pipe[MAX9296_MAX_PIPES]; + u8 csi_mode; + u8 lane_mp1; + u8 lane_mp2; + int reset_gpio; + int pw_ref; + struct regulator *vdd_cam_1v2; +}; + +static int tier4_max9296_read_reg(struct device *dev, u16 addr, u8 *val) +{ + int err = 0; + u32 reg_val = 0; + struct tier4_max9296 *priv = dev_get_drvdata(dev); + char str_bus_num[4], str_sl_addr[4]; + int len; + + memset(str_bus_num, 0, 4); + memset(str_sl_addr, 0, 4); + + err = regmap_read(priv->regmap, addr, ®_val); + *val = reg_val & 0xFF; + + if ((err == 0) && (dev != NULL)) { + len = strlen(dev->kobj.name); + + if (dev) { + strncpy(str_bus_num, &dev->kobj.name[0], 2); + strncpy(str_sl_addr, &dev->kobj.name[len - 2], 2); + } + dev_info(dev, "tier4_max9296_read_reg %s 0x%s 0x%x\n", + str_bus_num, str_sl_addr, addr); + } + + return err; +} + +static int tier4_max9296_write_reg(struct device *dev, u16 addr, u8 val) +{ + struct tier4_max9296 *priv; + int err; + char str_bus_num[4], str_sl_addr[4]; + int len; + + priv = dev_get_drvdata(dev); + + memset(str_bus_num, 0, 4); + memset(str_sl_addr, 0, 4); + + len = strlen(dev->kobj.name); + + if (dev) { + strncpy(str_bus_num, &dev->kobj.name[0], 2); + strncpy(str_sl_addr, &dev->kobj.name[len - 2], 2); + } + + err = regmap_write(priv->regmap, addr, val); + + if (err) { + dev_err(dev, + "[%s] : Max9296 I2C write failed Reg at 0x%04X:[0x%02X]\n", + __func__, addr, val); + return err; + } +#if MAX9296_SHOW_I2C_WRITE_MSG + else { + dev_info( + dev, + "[%s] : Max9296 I2C write register at 0x%04X:[0x%02X]\n", + __func__, addr, val); + } +#endif + /* delay before next i2c command as required for SERDES link */ + + usleep_range(100, 110); + + return err; +} + +static int tier4_max9296_get_sdev_idx(struct device *dev, struct device *s_dev, + int *idx) +{ + int i; + int err = 0; + struct tier4_max9296 *priv = dev_get_drvdata(dev); + + mutex_lock(&priv->lock); + + for (i = 0; i < priv->max_src; i++) { + if (priv->sources[i].g_ctx->s_dev == s_dev) { + break; + } + } + if (i == priv->max_src) { + dev_err(dev, "[%s] : No sdev found\n", __func__); + err = -EINVAL; + goto ret; + } + + if (idx) { + *idx = i; + } + +ret: + mutex_unlock(&priv->lock); + return err; +} + +static void tier4_max9296_pipes_reset(struct tier4_max9296 *priv) +{ + /* + * This is default pipes combination. add more mappings + * for other combinations and requirements. + */ + struct pipe_ctx pipe_defaults[] = { + { MAX9296_PIPE_X, GMSL_CSI_DT_YUV_8, // For YUV8 + MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID }, + { MAX9296_PIPE_Y, GMSL_CSI_DT_YUV_8, // For YUV8 + MAX9296_CSI_CTRL_1, 0, MAX9296_INVAL_ST_ID }, + { MAX9296_PIPE_Z, GMSL_CSI_DT_EMBED, MAX9296_CSI_CTRL_1, 0, + MAX9296_INVAL_ST_ID }, + { MAX9296_PIPE_U, GMSL_CSI_DT_EMBED, MAX9296_CSI_CTRL_1, 0, + MAX9296_INVAL_ST_ID } + }; + + /* + * Add DT props for num-streams and stream sequence, and based on that + * set the appropriate pipes defaults. + * For now default it supports "2 RAW12 and 2 EMBED" 1:1 mappings. + */ + memcpy(priv->pipe, pipe_defaults, sizeof(pipe_defaults)); +} + +static void tier4_max9296_reset_ctx(struct tier4_max9296 *priv) +{ + int i; + + priv->link_setup = false; + priv->lane_setup = false; + priv->num_src_found = 0; + priv->src_link = 0; + priv->splitter_enabled = false; + + tier4_max9296_pipes_reset(priv); + + for (i = 0; i < priv->num_src; i++) { + priv->sources[i].st_enabled = false; + } +} + +int tier4_max9296_power_on(struct device *dev) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + int i, err = 0; + + mutex_lock(&priv->lock); + + if (priv->pw_ref == 0) { + usleep_range(1, 2); + + for (i = 0; i < priv->max_src; i++) { + if (priv->sources[i].g_ctx) { + break; + } + } + // if (priv->reset_gpio) + if (gpio_is_valid(priv->reset_gpio)) { + gpio_direction_output(priv->reset_gpio, 0); + } + + usleep_range(50, 80); + + if (priv->vdd_cam_1v2) { + err = regulator_enable(priv->vdd_cam_1v2); + if (unlikely(err)) + goto ret; + } + usleep_range(50, 80); + + /*exit reset mode: XCLR */ + // if (priv->reset_gpio) + if (gpio_is_valid(priv->reset_gpio)) { + // gpio_set_value(priv->reset_gpio, 0); + gpio_direction_output(priv->reset_gpio, 0); + + usleep_range(50, 80); + usleep_range(1000000, 1100000); + // gpio_set_value(priv->reset_gpio, 1); + + gpio_direction_output(priv->reset_gpio, 1); + + usleep_range(50, 80); + } + + /* delay to settle reset */ + // msleep(1000); + } + + priv->pw_ref++; + +ret: + + mutex_unlock(&priv->lock); + + return err; +} +EXPORT_SYMBOL(tier4_max9296_power_on); + +void tier4_max9296_power_off(struct device *dev) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + + mutex_lock(&priv->lock); + priv->pw_ref--; + + if (priv->pw_ref == 0) { + /* enter reset mode: XCLR */ + usleep_range(1, 2); + if (priv->reset_gpio) + // gpio_set_value(priv->reset_gpio, 0); + gpio_direction_output(priv->reset_gpio, 0); + + if (priv->vdd_cam_1v2) + regulator_disable(priv->vdd_cam_1v2); + } + + mutex_unlock(&priv->lock); +} +EXPORT_SYMBOL(tier4_max9296_power_off); + +static int tier4_max9296_write_link(struct device *dev, u32 link) +{ + int err = 0; + + if (link == GMSL_SERDES_CSI_LINK_A) { + err = tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x01); + err |= tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x21); + } else if (link == GMSL_SERDES_CSI_LINK_B) { + err = tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x02); + err |= tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x22); + } else { + dev_err(dev, "[%s] : Invalid GMSL link\n", __func__); + return -EINVAL; + } + + /* delay to settle link */ + msleep(100); + + return 0; +} + +int tier4_max9296_setup_link(struct device *dev, struct device *s_dev) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + int err = 0; + int i; + + err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); + if (err) { + dev_err(dev, "[%s] : tier4_max9296_get_sdev_idx failed.\n", + __func__); + return err; + } + + // max9296_debug_i2c_write = priv->sources[i].g_ctx->debug_i2c_write; + + mutex_lock(&priv->lock); + + if (!priv->splitter_enabled) { + err = tier4_max9296_write_link( + dev, priv->sources[i].g_ctx->serdes_csi_link); + if (err) { + dev_err(dev, + "[%s] : tier4_max9296_write_link failed.\n", + __func__); + goto ret; + } + priv->link_setup = true; + } + +ret: + mutex_unlock(&priv->lock); + + return err; +} +EXPORT_SYMBOL(tier4_max9296_setup_link); + +static int tier4_max9296_link_locked(struct device *dev) +{ + u8 val; + + usleep_range(100, 110); + tier4_max9296_read_reg(dev, MAX9296_LINK_ADDR, &val); + + if (0 == (val & 0x08)) { + return -EINVAL; + } + return 0; +} + +int tier4_max9296_setup_gpi(struct device *dev, int fsync_mfp) +{ + int err = 0; + u16 gpio_mfp_base; + + dev_info(dev, "[%s] : MFP%d is used for fsync\n", __func__, fsync_mfp); + + gpio_mfp_base = (MAX9296_GPIO0_CONFIG_MFP0_ADDR + 3 * fsync_mfp) & + 0xFFFF; + + err += tier4_max9296_write_reg(dev, gpio_mfp_base, 0x03); + err += tier4_max9296_write_reg(dev, gpio_mfp_base + 1, 0x06); + err += tier4_max9296_write_reg(dev, gpio_mfp_base + 2, 0x00); + + return err; +} +EXPORT_SYMBOL(tier4_max9296_setup_gpi); + +int tier4_max9296_setup_control(struct device *dev, struct device *s_dev) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + int err = 0; + int i; + + err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); + + if (err) { + dev_err(dev, "[%s] : tier4_max9296_get_sdev_idx() failed.\n", + __func__); + return err; + } + + mutex_lock(&priv->lock); + + if (!priv->link_setup) { + dev_err(dev, "[%s] : Invalid state\n", __func__); + err = -EINVAL; + goto error; + } + + if (priv->sources[i].g_ctx->serdev_found) { + priv->num_src_found++; + priv->src_link = priv->sources[i].g_ctx->serdes_csi_link; + } + + /* Enable splitter mode */ + if ((priv->max_src > 1U) && (priv->num_src_found > 0U) && + (priv->splitter_enabled == false)) { + tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x03); + tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, 0x23); + + priv->splitter_enabled = true; + + /* delay to settle link */ + msleep(500); + } + +#if _USE_CHECK_LINK_LOCKED_ + // Check GMSL link + err = tier4_max9296_link_locked(dev); + if (err) { + // GMSL2 link not locked + dev_info(dev, "[%s]: max9296 link is not locked.\n", __func__); + err = tier4_max9296_write_link(dev, priv->src_link); + if (err) { + dev_err(dev, + "[%s]: tier4_max9296_write_link() failed.\n", + __func__); + goto error; + } + } +#endif + + if (!priv->splitter_enabled) { + tier4_max9296_write_reg(dev, MAX9296_PWDN_PHYS_ADDR, + MAX9296_ALLPHYS_NOSTDBY); + priv->splitter_enabled = true; + } + priv->link_setup = true; + + priv->sdev_ref++; + + /* Reset splitter mode if all devices are not found */ + if ((priv->sdev_ref == priv->max_src) && + (priv->splitter_enabled == true) && (priv->num_src_found > 0U) && + (priv->num_src_found < priv->max_src)) { + err = tier4_max9296_write_link(dev, priv->src_link); + if (err) + goto error; + + priv->splitter_enabled = false; + } + +error: + mutex_unlock(&priv->lock); + return err; +} +EXPORT_SYMBOL(tier4_max9296_setup_control); + +int tier4_max9296_reset_control(struct device *dev, struct device *s_dev, + bool force_reset) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + int err = 0; + + mutex_lock(&priv->lock); + if (!priv->sdev_ref && force_reset == false) { + dev_info(dev, "[%s] : dev is already in reset state\n", + __func__); + goto ret; + } + + priv->sdev_ref--; + if (priv->sdev_ref == 0 || force_reset == true) { + tier4_max9296_reset_ctx(priv); + tier4_max9296_write_reg(dev, MAX9296_CTRL0_ADDR, + MAX9296_RESET_ALL); + + /* delay to settle reset */ + msleep(100); + } + +ret: + mutex_unlock(&priv->lock); + + return err; +} +EXPORT_SYMBOL(tier4_max9296_reset_control); + +int tier4_max9296_sdev_register(struct device *dev, + struct tier4_gmsl_link_ctx *g_ctx) +{ + struct tier4_max9296 *priv = NULL; + int i; + int err = 0; + + if (!dev || !g_ctx || !g_ctx->s_dev) { + dev_err(dev, "[%s] : Invalid input params\n", __func__); + return -EINVAL; + } + + priv = dev_get_drvdata(dev); + + mutex_lock(&priv->lock); + + if ((g_ctx->hardware_model == HW_MODEL_NVIDIA_ORIN_DEVKIT) || + (g_ctx->hardware_model == HW_MODEL_ADLINK_ROSCUBE_ORIN)) { + for (i = 0; i < MAX9296_MAX_SOURCES; i++) { + if (priv->sources[i].g_ctx != NULL) { + priv->sources[i].g_ctx->serdes_csi_link = 0; + } + } + } + + if (priv->num_src > priv->max_src) { + dev_err(dev, "[%s] : MAX9296 inputs size exhausted\n", + __func__); + err = -ENOMEM; + goto error; + } + + /* Check csi mode compatibility */ + if (!((priv->csi_mode == MAX9296_CSI_MODE_2X4) ? + ((g_ctx->csi_mode == GMSL_CSI_1X4_MODE) || + (g_ctx->csi_mode == GMSL_CSI_2X4_MODE)) : + ((g_ctx->csi_mode == GMSL_CSI_2X2_MODE) || + (g_ctx->csi_mode == GMSL_CSI_4X2_MODE)))) { + dev_err(dev, "[%s] : CSI mode not supported\n", __func__); + err = -EINVAL; + goto error; + } + + asm("dsb sy"); + + for (i = 0; i < priv->num_src; i++) { + // dev_info(dev, "[%s]: g_ctx->serdes_csi_link = %u priv->sources[%d].g_ctx->serdes_csi_link = %u\n" + // , __func__, g_ctx->serdes_csi_link, i, priv->sources[i].g_ctx->serdes_csi_link ); + + // usleep_range(1000,1100); + + if (g_ctx->serdes_csi_link == + priv->sources[i].g_ctx->serdes_csi_link) { + // WARN_ON(1); + dev_info(dev, "[%s]: g_ctx->serdes_csi_link = %u\n", + __func__, g_ctx->serdes_csi_link); + dev_err(dev, "[%s] : Serdes CSI link is in use\n", + __func__); + err = -EINVAL; + goto error; + } + /* + * All sdevs should have same num-csi-lanes regardless of + * dst csi port selected. + * Later if there is any usecase which requires each port + * to be configured with different num-csi-lanes, then this + * check should be performed per port. + */ + + if (g_ctx->num_csi_lanes != + priv->sources[i].g_ctx->num_csi_lanes) { + dev_err(dev, + "[%s] : CSI num lanes mismatch. %d, %d i=%d\n", + __func__, g_ctx->num_csi_lanes, + priv->sources[i].g_ctx->num_csi_lanes, i); + err = -EINVAL; + goto error; + } + } + + priv->sources[priv->num_src].g_ctx = g_ctx; + priv->sources[priv->num_src].st_enabled = false; + + priv->num_src++; + +error: + mutex_unlock(&priv->lock); + return err; +} +EXPORT_SYMBOL(tier4_max9296_sdev_register); + +int tier4_max9296_sdev_unregister(struct device *dev, struct device *s_dev) +{ + struct tier4_max9296 *priv = NULL; + int err = 0; + int i = 0; + + if (!dev || !s_dev) { + dev_err(dev, "[%s] : Invalid input params\n", __func__); + return -EINVAL; + } + + priv = dev_get_drvdata(dev); + mutex_lock(&priv->lock); + + if (priv->num_src == 0) { + dev_err(dev, "[%s] : No source found\n", __func__); + err = -ENODATA; + goto error; + } + + for (i = 0; i < priv->num_src; i++) { + if (s_dev == priv->sources[i].g_ctx->s_dev) { + priv->sources[i].g_ctx = NULL; + priv->num_src--; + break; + } + } + + if (i == priv->num_src) { + dev_err(dev, "[%s] : Requested device not found\n", __func__); + err = -EINVAL; + goto error; + } + +error: + mutex_unlock(&priv->lock); + return err; +} +EXPORT_SYMBOL(tier4_max9296_sdev_unregister); + +static int tier4_max9296_get_available_pipe(struct device *dev, + u32 st_data_type, u32 dst_csi_port) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + int i; + + for (i = 0; i < MAX9296_MAX_PIPES; i++) { + /* + * TODO: Enable a pipe for multi stream configuration having + * similar stream data type. For now use st_count as a flag + * for 1 to 1 mapping in pipe and stream data type, same can + * be extended as count for many to 1 mapping. Would also need + * few more checks such as input stream id select, dst port etc. + */ + if ((priv->pipe[i].dt_type == st_data_type) && + ((dst_csi_port == GMSL_CSI_PORT_A) ? + (priv->pipe[i].dst_csi_ctrl == + MAX9296_CSI_CTRL_0) || + (priv->pipe[i].dst_csi_ctrl == + MAX9296_CSI_CTRL_1) : + (priv->pipe[i].dst_csi_ctrl == + MAX9296_CSI_CTRL_2) || + (priv->pipe[i].dst_csi_ctrl == + MAX9296_CSI_CTRL_3)) && + (!priv->pipe[i].st_count)) + break; + } + + if (i == MAX9296_MAX_PIPES) { + dev_err(dev, "[%s] : All pipes are busy\n", __func__); + return -ENOMEM; + } + + return i; +} + +struct reg_pair { + u16 addr; + u8 val; +}; + +static int tier4_max9296_setup_pipeline(struct device *dev, + struct tier4_gmsl_link_ctx *g_ctx) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + struct tier4_gmsl_stream *g_stream; + struct reg_pair *map_list; + u32 arr_sz = 0; + int pipe_id = 0; + u32 i = 0; + u32 j = 0; + u32 vc_idx = 0; + + for (i = 0; i < g_ctx->num_streams; i++) { + /* Base data type mapping: pipeX/RAW12/CSICNTR1 */ + struct reg_pair map_pipe_yuv8[] = { + // for YUV8 + /* addr, val */ + { MAX9296_TX11_PIPE_X_EN_ADDR, 0x7 }, + { MAX9296_TX45_PIPE_X_DST_CTRL_ADDR, 0x15 }, + + { MAX9296_PIPE_X_SRC_0_MAP_ADDR, 0x1E }, // for YUV8 + { MAX9296_PIPE_X_DST_0_MAP_ADDR, 0x1E }, // for YUV8 + { MAX9296_PIPE_X_SRC_1_MAP_ADDR, 0x00 }, + { MAX9296_PIPE_X_DST_1_MAP_ADDR, 0x00 }, + { MAX9296_PIPE_X_SRC_2_MAP_ADDR, 0x01 }, + { MAX9296_PIPE_X_DST_2_MAP_ADDR, 0x01 }, + }; + + /* Base data type mapping: pipeX/EMBED/CSICNTR1 */ + struct reg_pair map_pipe_embed[] = { + /* addr, val */ + { MAX9296_TX11_PIPE_X_EN_ADDR, 0x7 }, + { MAX9296_TX45_PIPE_X_DST_CTRL_ADDR, 0x15 }, + { MAX9296_PIPE_X_SRC_0_MAP_ADDR, 0x12 }, + { MAX9296_PIPE_X_DST_0_MAP_ADDR, 0x12 }, + { MAX9296_PIPE_X_SRC_1_MAP_ADDR, 0x00 }, + { MAX9296_PIPE_X_DST_1_MAP_ADDR, 0x00 }, + { MAX9296_PIPE_X_SRC_2_MAP_ADDR, 0x01 }, + { MAX9296_PIPE_X_DST_2_MAP_ADDR, 0x01 }, + }; + + g_stream = &g_ctx->streams[i]; + g_stream->des_pipe = MAX9296_PIPE_INVALID; + + if (g_stream->st_data_type == GMSL_CSI_DT_YUV_8) { // for YUV8 + map_list = map_pipe_yuv8; // for YUV8 + arr_sz = ARRAY_SIZE(map_pipe_yuv8); // for YUV8 + } else if (g_stream->st_data_type == GMSL_CSI_DT_EMBED) { + map_list = map_pipe_embed; + arr_sz = ARRAY_SIZE(map_pipe_embed); + } else if (g_stream->st_data_type == GMSL_CSI_DT_UED_U1) { + continue; + } else { + dev_err(dev, "[%s] : Invalid data type\n", __func__); + return -EINVAL; + } + + pipe_id = tier4_max9296_get_available_pipe( + dev, g_stream->st_data_type, g_ctx->dst_csi_port); + if (pipe_id < 0) + return pipe_id; + + for (j = 0, vc_idx = 3; j < arr_sz; j++, vc_idx += 2) { + /* update pipe configuration */ + map_list[j].addr += (0x40 * pipe_id); + /* update vc id configuration */ + if (vc_idx < arr_sz) { + map_list[vc_idx].val |= (g_ctx->dst_vc << 6); + } + tier4_max9296_write_reg(dev, map_list[j].addr, + map_list[j].val); + } + + /* Set stream id select input */ + if (g_stream->st_id_sel == GMSL_ST_ID_UNUSED) { + dev_err(dev, "[%s] : Invalid stream st_id_sel\n", + __func__); + return -EINVAL; + } + + g_stream->des_pipe = MAX9296_PIPE_X_ST_SEL_ADDR + pipe_id; + + /* Update pipe internals */ + priv->pipe[pipe_id].st_count++; + priv->pipe[pipe_id].st_id_sel = g_stream->st_id_sel; + } + + return 0; +} + +int tier4_max9296_start_streaming(struct device *dev, struct device *s_dev) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + struct tier4_gmsl_link_ctx *g_ctx; + struct tier4_gmsl_stream *g_stream; + int err = 0; + int i = 0; + + err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); + + if (err) { + dev_err(dev, "[%s] : tier4_max9296_get_sdev_idx failed.\n", + __func__); + return err; + } + + mutex_lock(&priv->lock); + + g_ctx = priv->sources[i].g_ctx; + + for (i = 0; i < g_ctx->num_streams; i++) { + g_stream = &g_ctx->streams[i]; + + if (g_stream->des_pipe != MAX9296_PIPE_INVALID) { + tier4_max9296_write_reg(dev, g_stream->des_pipe, + g_stream->st_id_sel); + } + } + + mutex_unlock(&priv->lock); + + return 0; +} +EXPORT_SYMBOL(tier4_max9296_start_streaming); + +int tier4_max9296_stop_streaming(struct device *dev, struct device *s_dev) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + struct tier4_gmsl_link_ctx *g_ctx; + struct tier4_gmsl_stream *g_stream; + int err = 0; + int i = 0; + + err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); + if (err) + return err; + + mutex_lock(&priv->lock); + g_ctx = priv->sources[i].g_ctx; + + for (i = 0; i < g_ctx->num_streams; i++) { + g_stream = &g_ctx->streams[i]; + + if (g_stream->des_pipe != MAX9296_PIPE_INVALID) { + tier4_max9296_write_reg(dev, g_stream->des_pipe, + MAX9296_RESET_ST_ID); + } + } + + mutex_unlock(&priv->lock); + + return 0; +} +EXPORT_SYMBOL(tier4_max9296_stop_streaming); + +int tier4_max9296_setup_streaming(struct device *dev, struct device *s_dev) +{ + struct tier4_max9296 *priv = dev_get_drvdata(dev); + struct tier4_gmsl_link_ctx *g_ctx; + int err = 0; + int i = 0; + u16 lane_ctrl_addr; + + err = tier4_max9296_get_sdev_idx(dev, s_dev, &i); + + if (err) { + dev_err(dev, "[%s] : tier4_max9296_get_sdev_idx() failed.\n", + __func__); + return err; + } + + mutex_lock(&priv->lock); + if (priv->sources[i].st_enabled) + goto ret; + + g_ctx = priv->sources[i].g_ctx; + + err = tier4_max9296_setup_pipeline(dev, g_ctx); + + if (err) { + dev_err(dev, "[%s] : tier4_max9296_setup_pipeline() failed.\n", + __func__); + goto ret; + } + + /* Derive CSI lane map register */ + switch (g_ctx->dst_csi_port) { + case GMSL_CSI_PORT_A: + case GMSL_CSI_PORT_D: + lane_ctrl_addr = MAX9296_LANE_CTRL1_ADDR; + break; + case GMSL_CSI_PORT_B: + case GMSL_CSI_PORT_E: + lane_ctrl_addr = MAX9296_LANE_CTRL2_ADDR; + break; + case GMSL_CSI_PORT_C: + lane_ctrl_addr = MAX9296_LANE_CTRL0_ADDR; + break; + case GMSL_CSI_PORT_F: + lane_ctrl_addr = MAX9296_LANE_CTRL3_ADDR; + break; + default: + dev_err(dev, "[%s] : Invalid GMSL CSI port!\n", __func__); + err = -EINVAL; + goto ret; + }; + + /* + * rewrite num_lanes to same dst port should not be an issue, + * as the device compatibility is already + * checked during sdev registration against the des properties. + */ + + tier4_max9296_write_reg( + dev, lane_ctrl_addr, + MAX9296_LANE_CTRL_MAP(g_ctx->num_csi_lanes - 1)); + + if (!priv->lane_setup) { + tier4_max9296_write_reg(dev, MAX9296_DST_CSI_MODE_ADDR, + priv->csi_mode); + tier4_max9296_write_reg(dev, MAX9296_LANE_MAP1_ADDR, + priv->lane_mp1); + tier4_max9296_write_reg(dev, MAX9296_LANE_MAP2_ADDR, + priv->lane_mp2); + if (g_ctx->hardware_model == HW_MODEL_NVIDIA_ORIN_DEVKIT) { + tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, + MAX9296_PHY1_CLK_1400MHZ); + } else if (g_ctx->hardware_model == + HW_MODEL_ADLINK_ROSCUBE_ORIN) { + tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, + MAX9296_PHY1_CLK_1500MHZ); + } else if (g_ctx->hardware_model == + HW_MODEL_ADLINK_ROSCUBE_XAVIER) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 65) + // RQX-58G L4T 35.4.1 + tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, + MAX9296_PHY1_CLK_1600MHZ); +#else // RQX-58G L4T 32.x + tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, + MAX9296_PHY1_CLK_1800MHZ); +#endif + } else { + tier4_max9296_write_reg(dev, MAX9296_PHY1_CLK_ADDR, + MAX9296_PHY1_CLK_1400MHZ); + } + + priv->lane_setup = true; + } + +#if 0 + tier4_max9296_write_reg(dev, MAX9296_REG5_ADDR, 0xC0); // informed from Maxim +#endif + priv->sources[i].st_enabled = true; + +ret: + mutex_unlock(&priv->lock); + return err; +} +EXPORT_SYMBOL(tier4_max9296_setup_streaming); + +const struct of_device_id tier4_max9296_of_match[] = { + { + .compatible = "nvidia,tier4_max9296", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, tier4_max9296_of_match); + +static int tier4_max9296_parse_dt(struct tier4_max9296 *priv, + struct i2c_client *client) +{ + struct device_node *node = client->dev.of_node; + int err = 0; + const char *str_value; + int value; + const struct of_device_id *match; + + if (!node) + return -EINVAL; + + match = of_match_device(tier4_max9296_of_match, &client->dev); + if (!match) { + dev_err(&client->dev, + "[%s] : Failed to match device with dt id\n", __func__); + return -EFAULT; + } + + err = of_property_read_string(node, "csi-mode", &str_value); + if (err < 0) { + dev_err(&client->dev, "[%s] : csi-mode property not found\n", + __func__); + return err; + } + + if (!strcmp(str_value, "2x4")) { + priv->csi_mode = MAX9296_CSI_MODE_2X4; + priv->lane_mp1 = MAX9296_LANE_MAP1_2X4; + priv->lane_mp2 = MAX9296_LANE_MAP2_2X4; + } else if (!strcmp(str_value, "4x2")) { + priv->csi_mode = MAX9296_CSI_MODE_4X2; + priv->lane_mp1 = MAX9296_LANE_MAP1_4X2; + priv->lane_mp2 = MAX9296_LANE_MAP2_4X2; + } else { + dev_err(&client->dev, "[%s] : Invalid csi mode\n", __func__); + return -EINVAL; + } + + err = of_property_read_u32(node, "max-src", &value); + if (err < 0) { + dev_err(&client->dev, "[%s] : No max-src info\n", __func__); + return err; + } + + priv->max_src = value; + + priv->reset_gpio = of_get_named_gpio(node, "reset-gpios", 0); + if (priv->reset_gpio < 0) { + dev_err(&client->dev, "[%s] : reset-gpios not found %d\n", + __func__, err); + return err; + } + + /* digital 1.2v */ + if (of_get_property(node, "vdd_cam_1v2-supply", NULL)) { + priv->vdd_cam_1v2 = regulator_get(&client->dev, "vdd_cam_1v2"); + if (IS_ERR(priv->vdd_cam_1v2)) { + dev_err(&client->dev, + "[%s] : vdd_cam_1v2 regulator get failed\n", + __func__); + err = PTR_ERR(priv->vdd_cam_1v2); + priv->vdd_cam_1v2 = NULL; + return err; + } + } else { + priv->vdd_cam_1v2 = NULL; + } + + return 0; +} + +static struct regmap_config tier4_max9296_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +static int tier4_max9296_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tier4_max9296 *priv; + int err = 0; + + dev_info(&client->dev, "[%s]: Probing GMSL deserializer\n", __func__); + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + priv->i2c_client = client; + priv->regmap = devm_regmap_init_i2c(priv->i2c_client, + &tier4_max9296_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&client->dev, "[%s] : devm_regmap_init() failed: %ld\n", + __func__, PTR_ERR(priv->regmap)); + return -ENODEV; + } + + err = tier4_max9296_parse_dt(priv, client); + if (err) { + dev_err(&client->dev, "[%s] : Unable to parse dt\n", __func__); + return -EFAULT; + } + + tier4_max9296_pipes_reset(priv); + + if (priv->max_src > MAX9296_MAX_SOURCES) { + dev_err(&client->dev, + "[%s] : Max sources more than currently supported\n", + __func__); + return -EINVAL; + } + + mutex_init(&priv->lock); + + dev_set_drvdata(&client->dev, priv); + + /* dev communication gets validated when GMSL link setup is done */ + dev_info(&client->dev, "[%s] : Probing GMSL Deserializer is done.\n", + __func__); + + return err; +} + +static int tier4_max9296_remove(struct i2c_client *client) +{ + struct tier4_max9296 *priv; + + if (client != NULL) { + priv = dev_get_drvdata(&client->dev); + mutex_destroy(&priv->lock); + } + + return 0; +} + +static const struct i2c_device_id tier4_max9296_id[] = { + { "tier4_max9296", 0 }, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, tier4_max9296_id); + +static struct i2c_driver tier4_max9296_i2c_driver = { + .driver = { + .name = "tier4_max9296", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tier4_max9296_of_match), + }, + .probe = tier4_max9296_probe, + .remove = tier4_max9296_remove, + .id_table = tier4_max9296_id, +}; + +static int __init tier4_max9296_init(void) +{ + printk(KERN_INFO "MAX9296 Driver for TIERIV Camera : %s\n", + BUILD_STAMP); + return i2c_add_driver(&tier4_max9296_i2c_driver); +} + +static void __exit tier4_max9296_exit(void) +{ + i2c_del_driver(&tier4_max9296_i2c_driver); +} + +module_init(tier4_max9296_init); +module_exit(tier4_max9296_exit); + +MODULE_DESCRIPTION("Dual GMSL Deserializer driver tier4_max9296"); +MODULE_AUTHOR("Originaly NVIDIA Corporation"); +MODULE_AUTHOR("K.Iwasaki"); +MODULE_AUTHOR("Y.Fujii"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/src/tier4-max9296.h b/src/tier4-camera-gmsl/tier4-max9296.h similarity index 97% rename from drivers/src/tier4-max9296.h rename to src/tier4-camera-gmsl/tier4-max9296.h index 75465e3..970836a 100644 --- a/drivers/src/tier4-max9296.h +++ b/src/tier4-camera-gmsl/tier4-max9296.h @@ -78,7 +78,8 @@ int tier4_max9296_setup_control(struct device *dev, struct device *s_dev); * * @return 0 for success, or -1 otherwise. */ -int tier4_max9296_reset_control(struct device *dev, struct device *s_dev, bool force_reset); +int tier4_max9296_reset_control(struct device *dev, struct device *s_dev, + bool force_reset); /** * @brief Registers a source sensor device with a deserializer device. @@ -93,7 +94,8 @@ int tier4_max9296_reset_control(struct device *dev, struct device *s_dev, bool f * * @return 0 for success, or -1 otherwise. */ -int tier4_max9296_sdev_register(struct device *dev, struct tier4_gmsl_link_ctx *g_ctx); +int tier4_max9296_sdev_register(struct device *dev, + struct tier4_gmsl_link_ctx *g_ctx); /** * Unregisters a source sensor device from its deserializer device. diff --git a/tools/dts_generator/.gitignore b/tools/dts_generator/.gitignore new file mode 100644 index 0000000..82f9275 --- /dev/null +++ b/tools/dts_generator/.gitignore @@ -0,0 +1,162 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/latest/usage/project/#working-with-version-control +.pdm.toml +.pdm-python +.pdm-build/ + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/drivers/src/dts_generator/__init__.py b/tools/dts_generator/dts_generator/__init__.py similarity index 100% rename from drivers/src/dts_generator/__init__.py rename to tools/dts_generator/dts_generator/__init__.py diff --git a/drivers/src/dts_generator/camera.py b/tools/dts_generator/dts_generator/camera.py similarity index 100% rename from drivers/src/dts_generator/camera.py rename to tools/dts_generator/dts_generator/camera.py diff --git a/drivers/src/dts_generator/const.py b/tools/dts_generator/dts_generator/const.py similarity index 100% rename from drivers/src/dts_generator/const.py rename to tools/dts_generator/dts_generator/const.py diff --git a/drivers/src/dts_generator/devicetree.py b/tools/dts_generator/dts_generator/devicetree.py similarity index 97% rename from drivers/src/dts_generator/devicetree.py rename to tools/dts_generator/dts_generator/devicetree.py index 29b555e..d4a1760 100644 --- a/drivers/src/dts_generator/devicetree.py +++ b/tools/dts_generator/dts_generator/devicetree.py @@ -50,7 +50,7 @@ def __init__(self, name: str, label: str = '') -> None: self.footer_str: str = '' def header(self, header: str) -> DeviceTreeNode: - self.header_str = header + self.header_str += header return self def name(self, name: str) -> DeviceTreeNode: @@ -159,12 +159,12 @@ def overlay_target_label(self, label: str) -> FragmentNode: def quote(string: str) -> str: - """Quote a value of devicetree 'string' type""" + """Quote a value of devicetree 'string' type.""" return f'"{string}"' def unquote(string: str) -> str: - """Unquote a value of devicetree 'string' type""" + """Unquote a value of devicetree 'string' type.""" return string.strip('"') diff --git a/drivers/src/dts_generator/gmsl.py b/tools/dts_generator/dts_generator/gmsl.py similarity index 100% rename from drivers/src/dts_generator/gmsl.py rename to tools/dts_generator/dts_generator/gmsl.py diff --git a/drivers/src/dts_generator/media_graph.py b/tools/dts_generator/dts_generator/media_graph.py similarity index 100% rename from drivers/src/dts_generator/media_graph.py rename to tools/dts_generator/dts_generator/media_graph.py diff --git a/drivers/src/dts_generator/options.py b/tools/dts_generator/dts_generator/options.py similarity index 90% rename from drivers/src/dts_generator/options.py rename to tools/dts_generator/dts_generator/options.py index 93def6e..1a4a92c 100644 --- a/drivers/src/dts_generator/options.py +++ b/tools/dts_generator/dts_generator/options.py @@ -5,7 +5,8 @@ import argparse import sys from dataclasses import dataclass -from typing import Any, List, Optional +from enum import Enum +from typing import Any, Dict, List, Optional from . import camera, tegra_nvcsi @@ -56,6 +57,34 @@ def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespac setattr(namespace, 'ordered_args', previous) +class JetsonSoM(Enum): + AGX_Xavier = 1 + AGX_Orin = 2 + + +class Board(Enum): + Xavier_devkit = 1 + Orin_devkit = 2 + ROSCube_58g = 3 + ROSCube_59g = 4 + EAC_5000 = 5 + Anvil = 6 + + @property + def som(self) -> JetsonSoM: + return _board_som[self] + + +_board_som: Dict[Board, JetsonSoM] = { + Board.Xavier_devkit: JetsonSoM.AGX_Xavier, + Board.Orin_devkit: JetsonSoM.AGX_Orin, + Board.ROSCube_58g: JetsonSoM.AGX_Xavier, + Board.ROSCube_59g: JetsonSoM.AGX_Orin, + Board.EAC_5000: JetsonSoM.AGX_Orin, + Board.Anvil: JetsonSoM.AGX_Orin, +} + + @dataclass class GeneratorOptions: args: argparse.Namespace diff --git a/drivers/src/dts_generator/tegra_nvcsi.py b/tools/dts_generator/dts_generator/tegra_nvcsi.py similarity index 75% rename from drivers/src/dts_generator/tegra_nvcsi.py rename to tools/dts_generator/dts_generator/tegra_nvcsi.py index 0df72b4..6db1eb1 100644 --- a/drivers/src/dts_generator/tegra_nvcsi.py +++ b/tools/dts_generator/dts_generator/tegra_nvcsi.py @@ -4,22 +4,31 @@ from . import validate_csi_lanes from .devicetree import FragmentNode +from .options import GeneratorOptions MAX_CHANNELS: Final[int] = 8 -nvcsi_node_fragment = FragmentNode(target_path='/host1x@13e00000/nvcsi@15a00000') \ - .overlay_properties([ - 'status = "okay"', - f'num-channels = <{MAX_CHANNELS}>', - ]) + +def create_nvcsi_node_fragment(opts: GeneratorOptions, index: Optional[int] = None) -> FragmentNode: + target_path = '/host1x@13e00000/nvcsi@15a00000' + if opts.l4t_version.major == 36: + target_path = '/bus@0' + target_path + + return FragmentNode(index=index, target_path=target_path) \ + .overlay_properties([ + 'status = "okay"', + f'num-channels = <{MAX_CHANNELS}>', + ]) class NvcsiChannel: - def __init__(self, channel_index: Any, port_index: Any, bus_width: SupportsInt) -> None: + def __init__(self, opts: GeneratorOptions, channel_index: Any, port_index: Any, bus_width: SupportsInt) -> None: bus_width = int(bus_width) validate_csi_lanes(bus_width) channel_path = f'/host1x@13e00000/nvcsi@15a00000/channel@{channel_index}' + if opts.l4t_version.major == 36: + channel_path = '/bus@0' + channel_path self.channel = FragmentNode(target_path=channel_path) \ .overlay_properties([ diff --git a/drivers/src/dts_generator/tegra_vi.py b/tools/dts_generator/dts_generator/tegra_vi.py similarity index 79% rename from drivers/src/dts_generator/tegra_vi.py rename to tools/dts_generator/dts_generator/tegra_vi.py index 4a79b8e..c3839a2 100644 --- a/drivers/src/dts_generator/tegra_vi.py +++ b/tools/dts_generator/dts_generator/tegra_vi.py @@ -1,20 +1,23 @@ #!/usr/bin/env python3 -from typing import Any, List, Optional, SupportsInt +from typing import List, Optional, SupportsInt from . import StringLike, camera, validate_csi_lanes from .devicetree import FragmentNode +from .options import GeneratorOptions from .tegra_nvcsi import MAX_CHANNELS -vi_node_fragment = FragmentNode(index=None, target_path='/tegra-capture-vi') \ - .overlay_properties([ - 'status = "okay"', - f'num-channels = <{MAX_CHANNELS}>', - ]) + +def create_vi_node_fragment(opts: GeneratorOptions, index: Optional[int] = None) -> FragmentNode: + return FragmentNode(index=index, target_path='/tegra-capture-vi') \ + .overlay_properties([ + 'status = "okay"', + f'num-channels = <{MAX_CHANNELS}>', + ]) class ViPort: - def __init__(self, port_number: StringLike, port_index: StringLike, vc_id: StringLike, bus_width: SupportsInt) -> None: + def __init__(self, opts: GeneratorOptions, port_number: StringLike, port_index: StringLike, vc_id: StringLike, bus_width: SupportsInt) -> None: bus_width = int(bus_width) validate_csi_lanes(bus_width) @@ -41,7 +44,7 @@ def to_list(self) -> List[Optional[FragmentNode]]: class CameraPlatform: @staticmethod - def node_fragment(num_csi_lanes: StringLike, max_lane_speed: StringLike) -> FragmentNode: + def node_fragment(opts: GeneratorOptions, num_csi_lanes: StringLike, max_lane_speed: StringLike) -> FragmentNode: return FragmentNode(target_path='/tegra-camera-platform') \ .overlay_properties([ 'status = "okay"', @@ -58,7 +61,7 @@ def node_fragment(num_csi_lanes: StringLike, max_lane_speed: StringLike) -> Frag # The `position` argument corresponds to the `position` property for `tegra-camera-platform`. # It seems like only Argus makes use of it. @staticmethod - def module_fragment(index: int, cam: Optional[camera.Camera], position: str, + def module_fragment(opts: GeneratorOptions, index: int, cam: Optional[camera.Camera], position: str, i2c_bus_number: StringLike, i2c_bus_path: StringLike ) -> List[Optional[FragmentNode]]: if cam is None: diff --git a/tools/dts_generator/dtsi/tegra-camera-base-r36.dtsi b/tools/dts_generator/dtsi/tegra-camera-base-r36.dtsi new file mode 100644 index 0000000..dac5d60 --- /dev/null +++ b/tools/dts_generator/dtsi/tegra-camera-base-r36.dtsi @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// tegra-camera-base-r36.dtsi +/ { + fragment-camera-module@0 { + target-path = "/tegra-capture-vi"; + __overlay__ { + /* all cameras are disabled by default */ + ports { + vi_port0: port@0 { + reg = <0>; + status = "disabled"; + vi_in0: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port1: port@1 { + reg = <1>; + status = "disabled"; + vi_in1: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port2: port@2 { + reg = <2>; + status = "disabled"; + vi_in2: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port3: port@3 { + reg = <3>; + status = "disabled"; + vi_in3: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port4: port@4 { + reg = <4>; + status = "disabled"; + vi_in4: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port5: port@5 { + reg = <5>; + status = "disabled"; + vi_in5: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port6: port@6 { + reg = <6>; + status = "disabled"; + vi_in6: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port7: port@7 { + reg = <7>; + status = "disabled"; + vi_in7: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + }; + }; + }; + + fragment-camera-module@1 { + target-path = "/"; + __overlay__ { + tcp: tegra-camera-platform { + compatible = "nvidia, tegra-camera-platform"; + /** + * tpg_max_iso = <>; + * Max iso bw for 6 streams of tpg + * streams * nvcsi_freq * PG_bitrate / RG10 * BPP + * 6 * 102Mhz * 32 bits/ 10 bits * 2 Bps + * = 3916.8 MBps + */ + tpg_max_iso = <3916800>; + modules { + cam_module0: module0 { + status = "disabled"; + cam_module0_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module0_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module1: module1 { + status = "disabled"; + cam_module1_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module1_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module2: module2 { + status = "disabled"; + cam_module2_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module2_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module3: module3 { + status = "disabled"; + cam_module3_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module3_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module4: module4 { + status = "disabled"; + cam_module4_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module4_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module5: module5 { + status = "disabled"; + cam_module5_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module5_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module6: module6 { + status = "disabled"; + cam_module6_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module6_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module7: module7 { + status = "disabled"; + cam_module7_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module7_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + }; + }; + }; + }; + + fragment-camera-module@2 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000"; + __overlay__ { + num-tpg-channels = <36>; + csi_chan0: channel@0 { + reg = <0>; + status = "disabled"; + ports { + csi_chan0_port0: port@0 { + reg = <0>; + status = "disabled"; + csi_in0: endpoint@0 { + status = "disabled"; + }; + }; + csi_chan0_port1: port@1 { + reg = <1>; + status = "disabled"; + csi_out0: endpoint@1 { + status = "disabled"; + }; + }; + }; + }; + csi_chan1: channel@1 { + reg = <1>; + status = "disabled"; + ports { + csi_chan1_port0: port@0 { + reg = <0>; + status = "disabled"; + csi_in1: endpoint@2 { + status = "disabled"; + }; + }; + csi_chan1_port1: port@1 { + reg = <1>; + status = "disabled"; + csi_out1: endpoint@3 { + status = "disabled"; + }; + }; + }; + }; + csi_chan2: channel@2 { + reg = <2>; + status = "disabled"; + ports { + csi_chan2_port0: port@0 { + reg = <0>; + status = "disabled"; + csi_in2: endpoint@4 { + status = "disabled"; + }; + }; + csi_chan2_port1: port@1 { + reg = <1>; + status = "disabled"; + csi_out2: endpoint@5 { + status = "disabled"; + }; + }; + }; + }; + csi_chan3: channel@3 { + reg = <3>; + status = "disabled"; + ports { + csi_chan3_port0: port@0 { + reg = <0>; + status = "disabled"; + csi_in3: endpoint@6 { + status = "disabled"; + }; + }; + csi_chan3_port1: port@1 { + reg = <1>; + status = "disabled"; + csi_out3: endpoint@7 { + status = "disabled"; + }; + }; + }; + }; + csi_chan4: channel@4 { + reg = <4>; + status = "disabled"; + ports { + csi_chan4_port0: port@0 { + reg = <0>; + status = "disabled"; + csi_in4: endpoint@8 { + status = "disabled"; + }; + }; + csi_chan4_port1: port@1 { + reg = <1>; + status = "disabled"; + csi_out4: endpoint@9 { + status = "disabled"; + }; + }; + }; + }; + csi_chan5: channel@5 { + reg = <5>; + status = "disabled"; + ports { + csi_chan5_port0: port@0 { + reg = <0>; + status = "disabled"; + csi_in5: endpoint@10 { + status = "disabled"; + }; + }; + csi_chan5_port1: port@1 { + reg = <1>; + status = "disabled"; + csi_out5: endpoint@11 { + status = "disabled"; + }; + }; + }; + }; + csi_chan6: channel@6 { + reg = <6>; + status = "disabled"; + ports { + csi_chan6_port0: port@0 { + reg = <0>; + status = "disabled"; + csi_in6: endpoint@12 { + status = "disabled"; + }; + }; + csi_chan6_port1: port@1 { + reg = <1>; + status = "disabled"; + csi_out6: endpoint@13 { + status = "disabled"; + }; + }; + }; + }; + csi_chan7: channel@7 { + reg = <7>; + status = "disabled"; + ports { + csi_chan7_port0: port@0 { + reg = <0>; + status = "disabled"; + csi_in7: endpoint@14 { + status = "disabled"; + }; + }; + csi_chan7_port1: port@1 { + reg = <1>; + status = "disabled"; + csi_out7: endpoint@15 { + status = "disabled"; + }; + }; + }; + }; + }; + }; +}; +// tegra-camera-base-r36.dtsi diff --git a/drivers/src/make_overlay_dts_anvil.py b/tools/dts_generator/make_overlay_dts_anvil.py similarity index 53% rename from drivers/src/make_overlay_dts_anvil.py rename to tools/dts_generator/make_overlay_dts_anvil.py index dbc4509..79a4208 100755 --- a/drivers/src/make_overlay_dts_anvil.py +++ b/tools/dts_generator/make_overlay_dts_anvil.py @@ -24,6 +24,7 @@ from dts_generator.tegra_vi import CameraPlatform, ViPort PLATFORM_NAME: str = 'Anvil' +TEGRA_CAMERA_BASE_OVERLAY_R36: str = 'dtsi/tegra-camera-base-r36.dtsi' CSI_LANES: int = 4 NUM_GMSL_DESERIALIZERS: int = 4 @@ -32,8 +33,14 @@ PIXEL_CLOCK: int = 350000000 -def build_cameras(camera_list: Iterable[camera.Type], gmsl_dsers: Iterable[FragmentNode]) -> List[camera.Camera]: - dser_label = list(filter(None, [gmsl_dser.target_label for gmsl_dser in gmsl_dsers])) +def build_cameras(camera_list: Iterable[camera.Type], gmsl_dsers: Iterable[DeviceTreeNode]) -> List[camera.Camera]: + def get_label(node: DeviceTreeNode) -> str: + label = node.target_label if isinstance(node, FragmentNode) else node.node_label + if label is None: + raise ValueError('A GMSL deserializer node has no label') + return label + + dser_label = list(filter(None, [get_label(gmsl_dser) for gmsl_dser in gmsl_dsers])) assert len(dser_label) >= 4 c1_cameras = [ @@ -85,36 +92,26 @@ def at(lst: Sequence[T], index: int) -> Optional[T]: return lst[index] if index < len(lst) else None -def generate_jetson_camera_overlay(opts: GeneratorOptions) -> DeviceTreeNode: - num_channels = opts.number_of_cameras - - tegra_vi.vi_node_fragment.overlay_properties([f'num-channels = <{num_channels}>']) - vi_ports = [ - ViPort(port_number=7, port_index=0, vc_id=1, bus_width=CSI_LANES), - ViPort(port_number=6, port_index=0, vc_id=0, bus_width=CSI_LANES), - ViPort(port_number=5, port_index=2, vc_id=1, bus_width=CSI_LANES), - ViPort(port_number=4, port_index=2, vc_id=0, bus_width=CSI_LANES), - ViPort(port_number=3, port_index=4, vc_id=1, bus_width=CSI_LANES), - ViPort(port_number=2, port_index=4, vc_id=0, bus_width=CSI_LANES), - ViPort(port_number=1, port_index=5, vc_id=1, bus_width=CSI_LANES), - ViPort(port_number=0, port_index=5, vc_id=0, bus_width=CSI_LANES), - ][:num_channels] - vi_fragments = sum(map(ViPort.to_list, vi_ports), [tegra_vi.vi_node_fragment]) - - tegra_nvcsi.nvcsi_node_fragment.overlay_properties([f'num-channels = <{num_channels}>']) - nvcsi_channels = [ - NvcsiChannel(channel_index=7, port_index=0, bus_width=CSI_LANES), - NvcsiChannel(channel_index=6, port_index=0, bus_width=CSI_LANES), - NvcsiChannel(channel_index=5, port_index=2, bus_width=CSI_LANES), - NvcsiChannel(channel_index=4, port_index=2, bus_width=CSI_LANES), - NvcsiChannel(channel_index=3, port_index=4, bus_width=CSI_LANES), - NvcsiChannel(channel_index=2, port_index=4, bus_width=CSI_LANES), - NvcsiChannel(channel_index=1, port_index=6, bus_width=CSI_LANES), - NvcsiChannel(channel_index=0, port_index=6, bus_width=CSI_LANES), - ][:num_channels] - nvcsi_fragments = sum(map(NvcsiChannel.to_list, nvcsi_channels), [tegra_nvcsi.nvcsi_node_fragment]) - - gmsl_dsers = [ +gmsl_dsers_nodes = [ + gmsl.Deserializer.node(name='max9296', csi_lanes=CSI_LANES, label='dsera') + .properties([ + f'reset-gpios = <&tca9539_74 0 {const.GPIO_ACTIVE_HIGH}>' + ]), + gmsl.Deserializer.node(name='max9296', csi_lanes=CSI_LANES, label='dserb') + .properties([ + f'reset-gpios = <&tca9539_74 2 {const.GPIO_ACTIVE_HIGH}>' + ]), + gmsl.Deserializer.node(name='max9296', csi_lanes=CSI_LANES, label='dserc') + .properties([ + f'reset-gpios = <&tca9539_74 4 {const.GPIO_ACTIVE_HIGH}>' + ]), + gmsl.Deserializer.node(name='max9296', csi_lanes=CSI_LANES, label='dserd') + .properties([ + f'reset-gpios = <&tca9539_74 6 {const.GPIO_ACTIVE_HIGH}>' + ]), +] + +gmsl_dser_fragments = [ gmsl.Deserializer.fragment(target='dsera', csi_lanes=CSI_LANES) .overlay_properties([ f'reset-gpios = <&tca9539_74 0 {const.GPIO_ACTIVE_HIGH}>' @@ -131,30 +128,76 @@ def generate_jetson_camera_overlay(opts: GeneratorOptions) -> DeviceTreeNode: .overlay_properties([ f'reset-gpios = <&tca9539_74 6 {const.GPIO_ACTIVE_HIGH}>' ]), - ] - cameras = build_cameras(opts.camera_list, gmsl_dsers) +] - graph = MediaGraph(vi_ports, nvcsi_channels, cameras) - graph.connect_all_endpoints() + +def generate_jetson_camera_overlay(opts: GeneratorOptions) -> DeviceTreeNode: + num_channels = opts.number_of_cameras + + vi_node_fragment = tegra_vi.create_vi_node_fragment(opts) \ + .overlay_properties([f'num-channels = <{num_channels}>']) + vi_ports = [ + ViPort(opts, port_number=7, port_index=0, vc_id=1, bus_width=CSI_LANES), + ViPort(opts, port_number=6, port_index=0, vc_id=0, bus_width=CSI_LANES), + ViPort(opts, port_number=5, port_index=2, vc_id=1, bus_width=CSI_LANES), + ViPort(opts, port_number=4, port_index=2, vc_id=0, bus_width=CSI_LANES), + ViPort(opts, port_number=3, port_index=4, vc_id=1, bus_width=CSI_LANES), + ViPort(opts, port_number=2, port_index=4, vc_id=0, bus_width=CSI_LANES), + ViPort(opts, port_number=1, port_index=5, vc_id=1, bus_width=CSI_LANES), + ViPort(opts, port_number=0, port_index=5, vc_id=0, bus_width=CSI_LANES), + ][:num_channels] + vi_fragments = sum(map(ViPort.to_list, vi_ports), [vi_node_fragment]) + + nvcsi_node_fragment = tegra_nvcsi.create_nvcsi_node_fragment(opts) \ + .overlay_properties([f'num-channels = <{num_channels}>']) + nvcsi_channels = [ + NvcsiChannel(opts, channel_index=7, port_index=0, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=6, port_index=0, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=5, port_index=2, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=4, port_index=2, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=3, port_index=4, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=2, port_index=4, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=1, port_index=6, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=0, port_index=6, bus_width=CSI_LANES), + ][:num_channels] + nvcsi_fragments = sum(map(NvcsiChannel.to_list, nvcsi_channels), [nvcsi_node_fragment]) + + root = devicetree.jetson_camera_overlay_root(opts.overlay_name) i2c_bus_number: int = 0x28 i2c_mux_path = '/i2c@31e0000/tca9544@72' + gmsl_dsers: Sequence[DeviceTreeNode] = gmsl_dser_fragments + + if opts.l4t_version.major >= 36: + i2c_mux_path = '/bus@0' + i2c_mux_path + gmsl_dsers = gmsl_dsers_nodes + with open(TEGRA_CAMERA_BASE_OVERLAY_R36, 'r', encoding='utf-8') as tegra_cam_dtsi: + (root + .header('\n' + tegra_cam_dtsi.read()) + .nodes(i2c_mux_and_gmsl_dsers(gmsl_dsers))) + else: + root.nodes(gmsl_dsers) + + cameras = build_cameras(opts.camera_list, gmsl_dsers) + + graph = MediaGraph(vi_ports, nvcsi_channels, cameras) + graph.connect_all_endpoints() tegra_camera_platform_modules = [ - CameraPlatform.module_fragment(index=7, cam=at(cameras, 0), position='bottom', i2c_bus_number=i2c_bus_number + 3, i2c_bus_path=f'{i2c_mux_path}/i2c@3'), - CameraPlatform.module_fragment(index=6, cam=at(cameras, 1), position='top', i2c_bus_number=i2c_bus_number + 3, i2c_bus_path=f'{i2c_mux_path}/i2c@3'), - CameraPlatform.module_fragment(index=5, cam=at(cameras, 2), position='right2', i2c_bus_number=i2c_bus_number + 2, i2c_bus_path=f'{i2c_mux_path}/i2c@2'), - CameraPlatform.module_fragment(index=4, cam=at(cameras, 3), position='left2', i2c_bus_number=i2c_bus_number + 2, i2c_bus_path=f'{i2c_mux_path}/i2c@2'), - CameraPlatform.module_fragment(index=3, cam=at(cameras, 4), position='right', i2c_bus_number=i2c_bus_number + 1, i2c_bus_path=f'{i2c_mux_path}/i2c@1'), - CameraPlatform.module_fragment(index=2, cam=at(cameras, 5), position='left', i2c_bus_number=i2c_bus_number + 1, i2c_bus_path=f'{i2c_mux_path}/i2c@1'), - CameraPlatform.module_fragment(index=1, cam=at(cameras, 6), position='front', i2c_bus_number=i2c_bus_number + 0, i2c_bus_path=f'{i2c_mux_path}/i2c@0'), - CameraPlatform.module_fragment(index=0, cam=at(cameras, 7), position='rear', i2c_bus_number=i2c_bus_number + 0, i2c_bus_path=f'{i2c_mux_path}/i2c@0'), + CameraPlatform.module_fragment(opts, index=7, cam=at(cameras, 0), position='bottom', i2c_bus_number=i2c_bus_number + 3, i2c_bus_path=f'{i2c_mux_path}/i2c@3'), + CameraPlatform.module_fragment(opts, index=6, cam=at(cameras, 1), position='top', i2c_bus_number=i2c_bus_number + 3, i2c_bus_path=f'{i2c_mux_path}/i2c@3'), + CameraPlatform.module_fragment(opts, index=5, cam=at(cameras, 2), position='right2', i2c_bus_number=i2c_bus_number + 2, i2c_bus_path=f'{i2c_mux_path}/i2c@2'), + CameraPlatform.module_fragment(opts, index=4, cam=at(cameras, 3), position='left2', i2c_bus_number=i2c_bus_number + 2, i2c_bus_path=f'{i2c_mux_path}/i2c@2'), + CameraPlatform.module_fragment(opts, index=3, cam=at(cameras, 4), position='right', i2c_bus_number=i2c_bus_number + 1, i2c_bus_path=f'{i2c_mux_path}/i2c@1'), + CameraPlatform.module_fragment(opts, index=2, cam=at(cameras, 5), position='left', i2c_bus_number=i2c_bus_number + 1, i2c_bus_path=f'{i2c_mux_path}/i2c@1'), + CameraPlatform.module_fragment(opts, index=1, cam=at(cameras, 6), position='front', i2c_bus_number=i2c_bus_number + 0, i2c_bus_path=f'{i2c_mux_path}/i2c@0'), + CameraPlatform.module_fragment(opts, index=0, cam=at(cameras, 7), position='rear', i2c_bus_number=i2c_bus_number + 0, i2c_bus_path=f'{i2c_mux_path}/i2c@0'), ] tegra_camera_platform_fragments = sum(tegra_camera_platform_modules, [ - CameraPlatform.node_fragment(num_csi_lanes=TOTAL_CSI_LANES, max_lane_speed=2500000) + CameraPlatform.node_fragment(opts, num_csi_lanes=TOTAL_CSI_LANES, max_lane_speed=2500000) ]) - root = (devicetree.jetson_camera_overlay_root(opts.overlay_name) + (root .nodes(vi_fragments) .nodes(nvcsi_fragments) .nodes(tegra_camera_platform_fragments) @@ -203,13 +246,107 @@ def generate_jetson_camera_overlay(opts: GeneratorOptions) -> DeviceTreeNode: 'reg = <0>', 'i2c-mux,deselect-on-exit', ]) - .overlay_nodes(sum(map(lambda cam: cam.to_list(), cameras[6:8]), [])), - ]) - .nodes(gmsl_dsers)) + .overlay_nodes(sum(map(lambda cam: cam.to_list(), cameras[6:8]), [])) + ])) return root +def i2c_mux_and_gmsl_dsers(gmsl_dsers: Sequence[DeviceTreeNode]) -> List[FragmentNode]: + return ([ + FragmentNode(target_path='/bus@0/i2c@31e0000') + .overlay_nodes([ + DeviceTreeNode('tca9544@72') + .properties([ + 'status = "okay"', + 'compatible = "nxp,pca9544"', + 'reg = <0x72>', + '#address-cells = <1>', + '#size-cells = <0>', + 'vcc-supply = <&vdd_1v8_sys>', + 'vcc_lp = "vcc"', + 'skip_mux_detect = "yes"', + 'force_bus_start = <40>', + ]) + .nodes([ + DeviceTreeNode('i2c@0') + .properties([ + 'status = "okay"', + 'reg = <0>', + 'i2c-mux,deselect-on-exit', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .nodes([ + gmsl_dsers[0] + ]), + DeviceTreeNode('i2c@1') + .properties([ + 'status = "okay"', + 'reg = <1>', + 'i2c-mux,deselect-on-exit', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .nodes([ + gmsl_dsers[1] + ]), + DeviceTreeNode('i2c@2') + .properties([ + 'status = "okay"', + 'reg = <2>', + 'i2c-mux,deselect-on-exit', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .nodes([ + gmsl_dsers[2] + ]), + DeviceTreeNode('i2c@3') + .properties([ + 'status = "okay"', + 'reg = <3>', + 'i2c-mux,deselect-on-exit', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .nodes([ + gmsl_dsers[3] + ]), + ]) + ]), + FragmentNode(target_path='/bus@0/i2c@3180000') + .overlay_properties([ + 'status = "okay"', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .overlay_nodes([ + DeviceTreeNode('tca9539@74', label='tca9539_74') + .properties([ + 'compatible = "ti,tca9539"', + 'gpio-controller', + '#gpio-cells = <2>', + 'ngpios = <16>', + 'reg = <0x74>', + 'status = "okay"', + ]) + .nodes([ + DeviceTreeNode('tca9539_74_outlow') + .properties([ + 'status = "okay"', + 'gpio-hog', + 'output-low', + ]), + DeviceTreeNode('ca9539_74_outhigh') + .properties(['status = "disabled"']), + DeviceTreeNode('tca9539_74_input') + .properties(['status = "disabled"']), + ]) + ]) + ]) + + if __name__ == '__main__': help_desc = 'The Jetson camera devicetree overlay generator for Connect Tech Anvil.' @@ -219,8 +356,8 @@ def generate_jetson_camera_overlay(opts: GeneratorOptions) -> DeviceTreeNode: print(f'Error: {e}', file=sys.stderr) sys.exit(1) - if opts.l4t_version.major != 35: - print(f'Error: {sys.argv[0]} only supports major version R35', file=sys.stderr) + if not 35 <= opts.l4t_version.major <= 36: + print(f'Error: {sys.argv[0]} only supports major version R35 and R36', file=sys.stderr) sys.exit(1) camera_overlay = generate_jetson_camera_overlay(opts) diff --git a/drivers/src/make_overlay_dts_eac-5000.py b/tools/dts_generator/make_overlay_dts_eac-5000.py similarity index 100% rename from drivers/src/make_overlay_dts_eac-5000.py rename to tools/dts_generator/make_overlay_dts_eac-5000.py diff --git a/tools/dts_generator/make_overlay_dts_orin-devkit-r36.py b/tools/dts_generator/make_overlay_dts_orin-devkit-r36.py new file mode 100755 index 0000000..7428492 --- /dev/null +++ b/tools/dts_generator/make_overlay_dts_orin-devkit-r36.py @@ -0,0 +1,327 @@ +#!/usr/bin/env python3 +""" +Jetson camera devicetree overlay generator for Jetson AGX Orin Developer Kit. +""" + +import sys +from typing import Dict, Iterable, List, Optional, Sequence, TypeVar + +from dts_generator import camera +from dts_generator import const +from dts_generator import devicetree +from dts_generator import gmsl +from dts_generator import tegra_nvcsi +from dts_generator import tegra_vi +from dts_generator.devicetree import DeviceTreeNode, FragmentNode +from dts_generator.media_graph import MediaGraph +from dts_generator.options import GeneratorOptions +from dts_generator.tegra_nvcsi import NvcsiChannel +from dts_generator.tegra_vi import CameraPlatform, ViPort + +PLATFORM_NAME: str = 'orin-devkit' +TEGRA_CAMERA_BASE_OVERLAY_R36: str = 'dtsi/tegra-camera-base-r36.dtsi' + +CSI_LANES: int = 4 +NUM_GMSL_DESERIALIZERS: int = 4 +TOTAL_CSI_LANES: int = CSI_LANES * NUM_GMSL_DESERIALIZERS + +PIXEL_CLOCK: int = 350000000 + + +def build_cameras(camera_list: Iterable[camera.Type], gmsl_dsers: Iterable[DeviceTreeNode]) -> List[camera.Camera]: + def get_label(node: DeviceTreeNode) -> str: + label = node.target_label if isinstance(node, FragmentNode) else node.node_label + if label is None: + raise ValueError('A GMSL deserializer node has no label') + return label + + dser_label = list(filter(None, [get_label(gmsl_dser) for gmsl_dser in gmsl_dsers])) + assert len(dser_label) >= 4 + + c1_cameras = [ + camera.C1(index=0, suffix='a', address='1b', vc_id='0', csi_lanes=CSI_LANES, port_index=0, serdes_csi_link='a', dser_label=dser_label[0], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C1(index=1, suffix='b', address='1c', vc_id='1', csi_lanes=CSI_LANES, port_index=0, serdes_csi_link='b', dser_label=dser_label[0], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C1(index=2, suffix='c', address='1b', vc_id='0', csi_lanes=CSI_LANES, port_index=2, serdes_csi_link='a', dser_label=dser_label[1], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C1(index=3, suffix='d', address='1c', vc_id='1', csi_lanes=CSI_LANES, port_index=2, serdes_csi_link='b', dser_label=dser_label[1], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C1(index=4, suffix='e', address='1b', vc_id='0', csi_lanes=CSI_LANES, port_index=4, serdes_csi_link='a', dser_label=dser_label[2], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C1(index=5, suffix='f', address='1c', vc_id='1', csi_lanes=CSI_LANES, port_index=4, serdes_csi_link='b', dser_label=dser_label[2], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C1(index=6, suffix='g', address='1b', vc_id='0', csi_lanes=CSI_LANES, port_index=6, serdes_csi_link='a', dser_label=dser_label[3], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C1(index=7, suffix='h', address='1c', vc_id='1', csi_lanes=CSI_LANES, port_index=6, serdes_csi_link='b', dser_label=dser_label[3], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + ] + + c2_cameras = [ + camera.C2(index=0, suffix='a', address='2b', vc_id='0', csi_lanes=CSI_LANES, port_index=0, serdes_csi_link='a', dser_label=dser_label[0], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C2(index=1, suffix='b', address='2c', vc_id='1', csi_lanes=CSI_LANES, port_index=0, serdes_csi_link='b', dser_label=dser_label[0], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C2(index=2, suffix='c', address='2b', vc_id='0', csi_lanes=CSI_LANES, port_index=2, serdes_csi_link='a', dser_label=dser_label[1], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C2(index=3, suffix='d', address='2c', vc_id='1', csi_lanes=CSI_LANES, port_index=2, serdes_csi_link='b', dser_label=dser_label[1], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C2(index=4, suffix='e', address='2b', vc_id='0', csi_lanes=CSI_LANES, port_index=4, serdes_csi_link='a', dser_label=dser_label[2], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C2(index=5, suffix='f', address='2c', vc_id='1', csi_lanes=CSI_LANES, port_index=4, serdes_csi_link='b', dser_label=dser_label[2], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C2(index=6, suffix='g', address='2b', vc_id='0', csi_lanes=CSI_LANES, port_index=6, serdes_csi_link='a', dser_label=dser_label[3], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C2(index=7, suffix='h', address='2c', vc_id='1', csi_lanes=CSI_LANES, port_index=6, serdes_csi_link='b', dser_label=dser_label[3], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + ] + + c3_cameras = [ + camera.C3(index=0, suffix='a', address='3b', vc_id='0', csi_lanes=CSI_LANES, port_index=0, serdes_csi_link='a', dser_label=dser_label[0], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C3(index=1, suffix='b', address='3c', vc_id='1', csi_lanes=CSI_LANES, port_index=0, serdes_csi_link='b', dser_label=dser_label[0], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C3(index=2, suffix='c', address='3b', vc_id='0', csi_lanes=CSI_LANES, port_index=2, serdes_csi_link='a', dser_label=dser_label[1], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C3(index=3, suffix='d', address='3c', vc_id='1', csi_lanes=CSI_LANES, port_index=2, serdes_csi_link='b', dser_label=dser_label[1], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C3(index=4, suffix='e', address='3b', vc_id='0', csi_lanes=CSI_LANES, port_index=4, serdes_csi_link='a', dser_label=dser_label[2], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C3(index=5, suffix='f', address='3c', vc_id='1', csi_lanes=CSI_LANES, port_index=4, serdes_csi_link='b', dser_label=dser_label[2], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + camera.C3(index=6, suffix='g', address='3b', vc_id='0', csi_lanes=CSI_LANES, port_index=6, serdes_csi_link='a', dser_label=dser_label[3], serdes_pix_clk_hz=PIXEL_CLOCK, primary=True), + camera.C3(index=7, suffix='h', address='3c', vc_id='1', csi_lanes=CSI_LANES, port_index=6, serdes_csi_link='b', dser_label=dser_label[3], serdes_pix_clk_hz=PIXEL_CLOCK, primary=False), + ] + + cameras_map: Dict[camera.Type, Sequence[camera.Camera]] = { + camera.Type.C1: c1_cameras, + camera.Type.C2: c2_cameras, + camera.Type.C3: c3_cameras, + } + + return [cameras_map[cam_type][i] for i, cam_type in enumerate(camera_list)] + + +T = TypeVar('T') + + +def at(lst: Sequence[T], index: int) -> Optional[T]: + return lst[index] if index < len(lst) else None + + +gmsl_dsers_nodes = [ + gmsl.Deserializer.node(name='max9296', csi_lanes=CSI_LANES, label='dsera') + .properties([ + f'reset-gpios = <&gpio 0x3b {const.GPIO_ACTIVE_HIGH}>' + ]), + gmsl.Deserializer.node(name='max9296', csi_lanes=CSI_LANES, label='dserb') + .properties([ + f'reset-gpios = <&gpio 0x3e {const.GPIO_ACTIVE_HIGH}>' + ]), + gmsl.Deserializer.node(name='max9296', csi_lanes=CSI_LANES, label='dserc') + .properties([ + f'reset-gpios = <&gpio 0xa2 {const.GPIO_ACTIVE_HIGH}>' + ]), + gmsl.Deserializer.node(name='max9296', csi_lanes=CSI_LANES, label='dserd') + .properties([ + f'reset-gpios = <&gpio 0xa0 {const.GPIO_ACTIVE_HIGH}>' + ]), +] + + +def generate_jetson_camera_overlay(opts: GeneratorOptions) -> DeviceTreeNode: + num_channels = opts.number_of_cameras + + vi_node_fragment = tegra_vi.create_vi_node_fragment(opts) \ + .overlay_properties([f'num-channels = <{num_channels}>']) + vi_ports = [ + ViPort(opts, port_number=0, port_index=0, vc_id=0, bus_width=CSI_LANES), + ViPort(opts, port_number=1, port_index=0, vc_id=1, bus_width=CSI_LANES), + ViPort(opts, port_number=2, port_index=2, vc_id=0, bus_width=CSI_LANES), + ViPort(opts, port_number=3, port_index=2, vc_id=1, bus_width=CSI_LANES), + ViPort(opts, port_number=4, port_index=4, vc_id=0, bus_width=CSI_LANES), + ViPort(opts, port_number=5, port_index=4, vc_id=1, bus_width=CSI_LANES), + ViPort(opts, port_number=6, port_index=5, vc_id=0, bus_width=CSI_LANES), + ViPort(opts, port_number=7, port_index=5, vc_id=1, bus_width=CSI_LANES), + ][:num_channels] + vi_fragments = sum(map(ViPort.to_list, vi_ports), [vi_node_fragment]) + + nvcsi_node_fragment = tegra_nvcsi.create_nvcsi_node_fragment(opts) \ + .overlay_properties([f'num-channels = <{num_channels}>']) + nvcsi_channels = [ + NvcsiChannel(opts, channel_index=0, port_index=0, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=1, port_index=0, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=2, port_index=2, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=3, port_index=2, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=4, port_index=4, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=5, port_index=4, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=6, port_index=6, bus_width=CSI_LANES), + NvcsiChannel(opts, channel_index=7, port_index=6, bus_width=CSI_LANES), + ][:num_channels] + nvcsi_fragments = sum(map(NvcsiChannel.to_list, nvcsi_channels), [nvcsi_node_fragment]) + + root = devicetree.jetson_camera_overlay_root(opts.overlay_name) + + i2c_bus_number: int = 0x28 + i2c_mux_path = '/i2c@3180000/tca9546@70' + gmsl_dsers: Sequence[DeviceTreeNode] = gmsl_dsers_nodes + + if opts.l4t_version.major >= 36: + i2c_mux_path = '/bus@0' + i2c_mux_path + with open(TEGRA_CAMERA_BASE_OVERLAY_R36, 'r', encoding='utf-8') as tegra_cam_dtsi: + (root + .header('\n' + tegra_cam_dtsi.read()) + .nodes(i2c_mux_and_gmsl_dsers(gmsl_dsers))) + else: + root.nodes(gmsl_dsers) + + cameras = build_cameras(opts.camera_list, gmsl_dsers) + + graph = MediaGraph(vi_ports, nvcsi_channels, cameras) + graph.connect_all_endpoints() + + tegra_camera_platform_modules = [ + CameraPlatform.module_fragment(opts, index=0, cam=at(cameras, 0), position='rear', i2c_bus_number=i2c_bus_number + 0, i2c_bus_path=f'{i2c_mux_path}/i2c@0'), + CameraPlatform.module_fragment(opts, index=1, cam=at(cameras, 1), position='front', i2c_bus_number=i2c_bus_number + 0, i2c_bus_path=f'{i2c_mux_path}/i2c@0'), + CameraPlatform.module_fragment(opts, index=2, cam=at(cameras, 2), position='left', i2c_bus_number=i2c_bus_number + 1, i2c_bus_path=f'{i2c_mux_path}/i2c@1'), + CameraPlatform.module_fragment(opts, index=3, cam=at(cameras, 3), position='right', i2c_bus_number=i2c_bus_number + 1, i2c_bus_path=f'{i2c_mux_path}/i2c@1'), + CameraPlatform.module_fragment(opts, index=4, cam=at(cameras, 4), position='left2', i2c_bus_number=i2c_bus_number + 2, i2c_bus_path=f'{i2c_mux_path}/i2c@2'), + CameraPlatform.module_fragment(opts, index=5, cam=at(cameras, 5), position='right2', i2c_bus_number=i2c_bus_number + 2, i2c_bus_path=f'{i2c_mux_path}/i2c@2'), + CameraPlatform.module_fragment(opts, index=6, cam=at(cameras, 6), position='top', i2c_bus_number=i2c_bus_number + 3, i2c_bus_path=f'{i2c_mux_path}/i2c@3'), + CameraPlatform.module_fragment(opts, index=7, cam=at(cameras, 7), position='bottom', i2c_bus_number=i2c_bus_number + 3, i2c_bus_path=f'{i2c_mux_path}/i2c@3'), + ] + tegra_camera_platform_fragments = sum(tegra_camera_platform_modules, [ + CameraPlatform.node_fragment(opts, num_csi_lanes=TOTAL_CSI_LANES, max_lane_speed=2500000) + ]) + + (root + .nodes(vi_fragments) + .nodes(nvcsi_fragments) + .nodes(tegra_camera_platform_fragments) + .nodes([ + FragmentNode(target_path='/') + .overlay_properties([ + # string list of all the connected cameras + 'tier4,cameras = %s' % devicetree.string_list([cam.name for cam in opts.camera_list]), + ]), + + FragmentNode(target_path=i2c_mux_path) + .overlay_properties([ + 'status = "okay"', + 'compatible = "nxp,pca9546"', + 'reg = <0x70>', + '#address-cells = <1>', + '#size-cells = <0>', + 'vcc-supply = <&vdd_1v8_sys>', + 'skip_mux_detect', + f'force_bus_start = <{i2c_bus_number}>', + ]), + FragmentNode(target_path=f'{i2c_mux_path}/i2c@0') + .overlay_properties([ + 'status = "okay"', + 'reg = <3>', + 'i2c-mux,deselect-on-exit', + ]) + .overlay_nodes(sum(map(lambda cam: cam.to_list(), cameras[0:2]), [])), + FragmentNode(target_path=f'{i2c_mux_path}/i2c@1') + .overlay_properties([ + 'status = "okay"', + 'reg = <2>', + 'i2c-mux,deselect-on-exit', + ]) + .overlay_nodes(sum(map(lambda cam: cam.to_list(), cameras[2:4]), [])), + FragmentNode(target_path=f'{i2c_mux_path}/i2c@2') + .overlay_properties([ + 'status = "okay"', + 'reg = <1>', + 'i2c-mux,deselect-on-exit', + ]) + .overlay_nodes(sum(map(lambda cam: cam.to_list(), cameras[4:6]), [])), + FragmentNode(target_path=f'{i2c_mux_path}/i2c@3') + .overlay_properties([ + 'status = "okay"', + 'reg = <0>', + 'i2c-mux,deselect-on-exit', + ]) + .overlay_nodes(sum(map(lambda cam: cam.to_list(), cameras[6:8]), [])) + ])) + + return root + + +def i2c_mux_and_gmsl_dsers(gmsl_dsers: Sequence[DeviceTreeNode]) -> List[FragmentNode]: + return ([ + FragmentNode(target_path='/bus@0/i2c@3180000') + .overlay_nodes([ + DeviceTreeNode('tca9546@70') + .properties([ + 'status = "okay"', + 'compatible = "nxp,pca9546"', + 'reg = <0x70>', + '#address-cells = <1>', + '#size-cells = <0>', + 'vcc-supply = <&vdd_1v8_sys>', + 'vcc_lp = "vcc"', + 'skip_mux_detect = "yes"', + 'force_bus_start = <40>', + ]) + .nodes([ + DeviceTreeNode('i2c@0') + .properties([ + 'status = "okay"', + 'reg = <0>', + 'i2c-mux,deselect-on-exit', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .nodes([ + gmsl_dsers[0] + ]), + DeviceTreeNode('i2c@1') + .properties([ + 'status = "okay"', + 'reg = <1>', + 'i2c-mux,deselect-on-exit', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .nodes([ + gmsl_dsers[1] + ]), + DeviceTreeNode('i2c@2') + .properties([ + 'status = "okay"', + 'reg = <2>', + 'i2c-mux,deselect-on-exit', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .nodes([ + gmsl_dsers[2] + ]), + DeviceTreeNode('i2c@3') + .properties([ + 'status = "okay"', + 'reg = <3>', + 'i2c-mux,deselect-on-exit', + '#address-cells = <1>', + '#size-cells = <0>', + ]) + .nodes([ + gmsl_dsers[3] + ]), + ]) + ]), + FragmentNode(target_path='/bus@0/gpio@2200000') + .overlay_nodes([ + DeviceTreeNode('camera-control-input') + .properties([ + 'status = "disabled"', + ]), + DeviceTreeNode('camera-control-output-low') + .properties([ + 'status = "okay"', + ]) + ]) + ]) + + +if __name__ == '__main__': + help_desc = 'The Jetson camera devicetree overlay generator for Jetson AGX Orin Developer Kit.' + + try: + opts = GeneratorOptions.parse_args(description=help_desc) + except ValueError as e: + print(f'Error: {e}', file=sys.stderr) + sys.exit(1) + + if not 35 <= opts.l4t_version.major <= 36: + print(f'Error: {sys.argv[0]} only supports major version R35 and R36', file=sys.stderr) + sys.exit(1) + + camera_overlay = generate_jetson_camera_overlay(opts) + + output_path = opts.get_overlay_output_path(PLATFORM_NAME) + if output_path == '-': + print(camera_overlay, end='') + else: + with open(output_path, 'w', encoding='utf-8') as overlay_dts_file: + print(camera_overlay, end='', file=overlay_dts_file) diff --git a/drivers/src/make_overlay_dts_orin-devkit.py b/tools/dts_generator/make_overlay_dts_orin-devkit.py similarity index 100% rename from drivers/src/make_overlay_dts_orin-devkit.py rename to tools/dts_generator/make_overlay_dts_orin-devkit.py diff --git a/drivers/src/make_overlay_dts_roscube-orin.py b/tools/dts_generator/make_overlay_dts_roscube-orin.py similarity index 100% rename from drivers/src/make_overlay_dts_roscube-orin.py rename to tools/dts_generator/make_overlay_dts_roscube-orin.py diff --git a/drivers/src/make_overlay_dts_roscube.py b/tools/dts_generator/make_overlay_dts_roscube.py similarity index 100% rename from drivers/src/make_overlay_dts_roscube.py rename to tools/dts_generator/make_overlay_dts_roscube.py diff --git a/drivers/src/make_overlay_dts_xavier-devkit.py b/tools/dts_generator/make_overlay_dts_xavier-devkit.py similarity index 100% rename from drivers/src/make_overlay_dts_xavier-devkit.py rename to tools/dts_generator/make_overlay_dts_xavier-devkit.py diff --git a/tools/dts_generator/tier4-imx490-gmsl-device-tree-overlay-anvil-r36.dts b/tools/dts_generator/tier4-imx490-gmsl-device-tree-overlay-anvil-r36.dts new file mode 100644 index 0000000..2ea0cb0 --- /dev/null +++ b/tools/dts_generator/tier4-imx490-gmsl-device-tree-overlay-anvil-r36.dts @@ -0,0 +1,2192 @@ +/dts-v1/; +/plugin/; + +/ { + overlay-name = "TIERIV GMSL2 Camera Device Tree Overlay: C2x8"; + jetson-header-name = "Jetson AGX CSI Connector"; + compatible = "nvidia,p2822-0000+p2888-0001", "nvidia,p3509-0000+p3668-0001", "nvidia,p3737-0000+p3701-0000", "nvidia,p3737-0000+p3701-0000", "nvidia,p3737-0000+p3701-0004", "nvidia,p3737-0000+p3701-0005", "nvidia,tegra234", "nvidia,tegra23x"; + + fragment@1 { + target-path = "/tegra-capture-vi"; + + __overlay__ { + status = "okay"; + num-channels = <8>; + }; + }; + + fragment@2 { + target-path = "/tegra-capture-vi/ports/port@7"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@3 { + target-path = "/tegra-capture-vi/ports/port@7/endpoint"; + + __overlay__ { + status = "okay"; + port-index = <0>; + vc-id = <1>; + bus-width = <4>; + remote-endpoint = <&csi_out7>; + }; + }; + + fragment@4 { + target-path = "/tegra-capture-vi/ports/port@6"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@5 { + target-path = "/tegra-capture-vi/ports/port@6/endpoint"; + + __overlay__ { + status = "okay"; + port-index = <0>; + vc-id = <0>; + bus-width = <4>; + remote-endpoint = <&csi_out6>; + }; + }; + + fragment@6 { + target-path = "/tegra-capture-vi/ports/port@5"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@7 { + target-path = "/tegra-capture-vi/ports/port@5/endpoint"; + + __overlay__ { + status = "okay"; + port-index = <2>; + vc-id = <1>; + bus-width = <4>; + remote-endpoint = <&csi_out5>; + }; + }; + + fragment@8 { + target-path = "/tegra-capture-vi/ports/port@4"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@9 { + target-path = "/tegra-capture-vi/ports/port@4/endpoint"; + + __overlay__ { + status = "okay"; + port-index = <2>; + vc-id = <0>; + bus-width = <4>; + remote-endpoint = <&csi_out4>; + }; + }; + + fragment@10 { + target-path = "/tegra-capture-vi/ports/port@3"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@11 { + target-path = "/tegra-capture-vi/ports/port@3/endpoint"; + + __overlay__ { + status = "okay"; + port-index = <4>; + vc-id = <1>; + bus-width = <4>; + remote-endpoint = <&csi_out3>; + }; + }; + + fragment@12 { + target-path = "/tegra-capture-vi/ports/port@2"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@13 { + target-path = "/tegra-capture-vi/ports/port@2/endpoint"; + + __overlay__ { + status = "okay"; + port-index = <4>; + vc-id = <0>; + bus-width = <4>; + remote-endpoint = <&csi_out2>; + }; + }; + + fragment@14 { + target-path = "/tegra-capture-vi/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@15 { + target-path = "/tegra-capture-vi/ports/port@1/endpoint"; + + __overlay__ { + status = "okay"; + port-index = <5>; + vc-id = <1>; + bus-width = <4>; + remote-endpoint = <&csi_out1>; + }; + }; + + fragment@16 { + target-path = "/tegra-capture-vi/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@17 { + target-path = "/tegra-capture-vi/ports/port@0/endpoint"; + + __overlay__ { + status = "okay"; + port-index = <5>; + vc-id = <0>; + bus-width = <4>; + remote-endpoint = <&csi_out0>; + }; + }; + + fragment@18 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000"; + + __overlay__ { + status = "okay"; + num-channels = <8>; + }; + }; + + fragment@19 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@7"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@20 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@7/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@21 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@7/ports/port@0/endpoint@14"; + + __overlay__ { + status = "okay"; + port-index = <0>; + bus-width = <4>; + remote-endpoint = <&cam_out7>; + }; + }; + + fragment@22 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@7/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@23 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@7/ports/port@1/endpoint@15"; + + __overlay__ { + status = "okay"; + port-index = <0>; + bus-width = <4>; + remote-endpoint = <&vi_in7>; + }; + }; + + fragment@24 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@6"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@25 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@6/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@26 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@6/ports/port@0/endpoint@12"; + + __overlay__ { + status = "okay"; + port-index = <0>; + bus-width = <4>; + remote-endpoint = <&cam_out6>; + }; + }; + + fragment@27 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@6/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@28 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@6/ports/port@1/endpoint@13"; + + __overlay__ { + status = "okay"; + port-index = <0>; + bus-width = <4>; + remote-endpoint = <&vi_in6>; + }; + }; + + fragment@29 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@5"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@30 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@5/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@31 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@5/ports/port@0/endpoint@10"; + + __overlay__ { + status = "okay"; + port-index = <2>; + bus-width = <4>; + remote-endpoint = <&cam_out5>; + }; + }; + + fragment@32 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@5/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@33 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@5/ports/port@1/endpoint@11"; + + __overlay__ { + status = "okay"; + port-index = <2>; + bus-width = <4>; + remote-endpoint = <&vi_in5>; + }; + }; + + fragment@34 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@4"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@35 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@4/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@36 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@4/ports/port@0/endpoint@8"; + + __overlay__ { + status = "okay"; + port-index = <2>; + bus-width = <4>; + remote-endpoint = <&cam_out4>; + }; + }; + + fragment@37 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@4/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@38 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@4/ports/port@1/endpoint@9"; + + __overlay__ { + status = "okay"; + port-index = <2>; + bus-width = <4>; + remote-endpoint = <&vi_in4>; + }; + }; + + fragment@39 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@3"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@40 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@3/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@41 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@3/ports/port@0/endpoint@6"; + + __overlay__ { + status = "okay"; + port-index = <4>; + bus-width = <4>; + remote-endpoint = <&cam_out3>; + }; + }; + + fragment@42 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@3/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@43 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@3/ports/port@1/endpoint@7"; + + __overlay__ { + status = "okay"; + port-index = <4>; + bus-width = <4>; + remote-endpoint = <&vi_in3>; + }; + }; + + fragment@44 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@2"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@45 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@2/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@46 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@2/ports/port@0/endpoint@4"; + + __overlay__ { + status = "okay"; + port-index = <4>; + bus-width = <4>; + remote-endpoint = <&cam_out2>; + }; + }; + + fragment@47 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@2/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@48 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@2/ports/port@1/endpoint@5"; + + __overlay__ { + status = "okay"; + port-index = <4>; + bus-width = <4>; + remote-endpoint = <&vi_in2>; + }; + }; + + fragment@49 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@50 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@1/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@51 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@1/ports/port@0/endpoint@2"; + + __overlay__ { + status = "okay"; + port-index = <6>; + bus-width = <4>; + remote-endpoint = <&cam_out1>; + }; + }; + + fragment@52 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@1/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@53 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@1/ports/port@1/endpoint@3"; + + __overlay__ { + status = "okay"; + port-index = <6>; + bus-width = <4>; + remote-endpoint = <&vi_in1>; + }; + }; + + fragment@54 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@55 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@0/ports/port@0"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@56 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@0/ports/port@0/endpoint@0"; + + __overlay__ { + status = "okay"; + port-index = <6>; + bus-width = <4>; + remote-endpoint = <&cam_out0>; + }; + }; + + fragment@57 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@0/ports/port@1"; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@58 { + target-path = "/bus@0/host1x@13e00000/nvcsi@15a00000/channel@0/ports/port@1/endpoint@1"; + + __overlay__ { + status = "okay"; + port-index = <6>; + bus-width = <4>; + remote-endpoint = <&vi_in0>; + }; + }; + + fragment@79 { + target-path = "/tegra-camera-platform"; + + __overlay__ { + status = "okay"; + num_csi_lanes = <16>; + max_lane_speed = <2500000>; + min_bits_per_pixel = <10>; + vi_peak_byte_per_pixel = <2>; + vi_bw_margin_pct = <25>; + isp_peak_byte_per_pixel = <5>; + isp_bw_margin_pct = <25>; + }; + }; + + fragment@63 { + target-path = "/tegra-camera-platform/modules/module7"; + + __overlay__ { + badge = "imx490_bottom"; + position = "bottom"; + orientation = "1"; + status = "okay"; + }; + }; + + fragment@64 { + target-path = "/tegra-camera-platform/modules/module7/drivernode0"; + + __overlay__ { + status = "okay"; + pcl_id = "v4l2_sensor"; + devname = "imx490 43-002c"; + proc-device-tree = "/proc/device-tree/bus@0/i2c@31e0000/tca9544@72/i2c@3/imx490_a@2c"; + }; + }; + + fragment@65 { + target-path = "/tegra-camera-platform/modules/module6"; + + __overlay__ { + badge = "imx490_top"; + position = "top"; + orientation = "1"; + status = "okay"; + }; + }; + + fragment@66 { + target-path = "/tegra-camera-platform/modules/module6/drivernode0"; + + __overlay__ { + status = "okay"; + pcl_id = "v4l2_sensor"; + devname = "imx490 43-002b"; + proc-device-tree = "/proc/device-tree/bus@0/i2c@31e0000/tca9544@72/i2c@3/imx490_b@2b"; + }; + }; + + fragment@67 { + target-path = "/tegra-camera-platform/modules/module5"; + + __overlay__ { + badge = "imx490_right2"; + position = "right2"; + orientation = "1"; + status = "okay"; + }; + }; + + fragment@68 { + target-path = "/tegra-camera-platform/modules/module5/drivernode0"; + + __overlay__ { + status = "okay"; + pcl_id = "v4l2_sensor"; + devname = "imx490 42-002c"; + proc-device-tree = "/proc/device-tree/bus@0/i2c@31e0000/tca9544@72/i2c@2/imx490_c@2c"; + }; + }; + + fragment@69 { + target-path = "/tegra-camera-platform/modules/module4"; + + __overlay__ { + badge = "imx490_left2"; + position = "left2"; + orientation = "1"; + status = "okay"; + }; + }; + + fragment@70 { + target-path = "/tegra-camera-platform/modules/module4/drivernode0"; + + __overlay__ { + status = "okay"; + pcl_id = "v4l2_sensor"; + devname = "imx490 42-002b"; + proc-device-tree = "/proc/device-tree/bus@0/i2c@31e0000/tca9544@72/i2c@2/imx490_d@2b"; + }; + }; + + fragment@71 { + target-path = "/tegra-camera-platform/modules/module3"; + + __overlay__ { + badge = "imx490_right"; + position = "right"; + orientation = "1"; + status = "okay"; + }; + }; + + fragment@72 { + target-path = "/tegra-camera-platform/modules/module3/drivernode0"; + + __overlay__ { + status = "okay"; + pcl_id = "v4l2_sensor"; + devname = "imx490 41-002c"; + proc-device-tree = "/proc/device-tree/bus@0/i2c@31e0000/tca9544@72/i2c@1/imx490_e@2c"; + }; + }; + + fragment@73 { + target-path = "/tegra-camera-platform/modules/module2"; + + __overlay__ { + badge = "imx490_left"; + position = "left"; + orientation = "1"; + status = "okay"; + }; + }; + + fragment@74 { + target-path = "/tegra-camera-platform/modules/module2/drivernode0"; + + __overlay__ { + status = "okay"; + pcl_id = "v4l2_sensor"; + devname = "imx490 41-002b"; + proc-device-tree = "/proc/device-tree/bus@0/i2c@31e0000/tca9544@72/i2c@1/imx490_f@2b"; + }; + }; + + fragment@75 { + target-path = "/tegra-camera-platform/modules/module1"; + + __overlay__ { + badge = "imx490_front"; + position = "front"; + orientation = "1"; + status = "okay"; + }; + }; + + fragment@76 { + target-path = "/tegra-camera-platform/modules/module1/drivernode0"; + + __overlay__ { + status = "okay"; + pcl_id = "v4l2_sensor"; + devname = "imx490 40-002c"; + proc-device-tree = "/proc/device-tree/bus@0/i2c@31e0000/tca9544@72/i2c@0/imx490_g@2c"; + }; + }; + + fragment@77 { + target-path = "/tegra-camera-platform/modules/module0"; + + __overlay__ { + badge = "imx490_rear"; + position = "rear"; + orientation = "1"; + status = "okay"; + }; + }; + + fragment@78 { + target-path = "/tegra-camera-platform/modules/module0/drivernode0"; + + __overlay__ { + status = "okay"; + pcl_id = "v4l2_sensor"; + devname = "imx490 40-002b"; + proc-device-tree = "/proc/device-tree/bus@0/i2c@31e0000/tca9544@72/i2c@0/imx490_h@2b"; + }; + }; + + fragment@80 { + target-path = "/"; + + __overlay__ { + tier4,cameras = "C2", "C2", "C2", "C2", "C2", "C2", "C2", "C2"; + }; + }; + + fragment@81 { + target-path = "/bus@0/i2c@31e0000/tca9544@72"; + + __overlay__ { + status = "okay"; + compatible = "nxp,pca9544"; + reg = <0x72>; + #address-cells = <1>; + #size-cells = <0>; + vcc-supply = <&vdd_1v8_sys>; + skip_mux_detect; + force_bus_start = <40>; + }; + }; + + fragment@82 { + target-path = "/bus@0/i2c@31e0000/tca9544@72/i2c@3"; + + __overlay__ { + status = "okay"; + reg = <3>; + i2c-mux,deselect-on-exit; + + ser7_b: max9295_a@60 { + status = "okay"; + compatible = "nvidia,tier4_max9295"; + reg = <0x60>; + nvidia,gmsl-dser-device = <&dserd>; + vc-id = <1>; + }; + + isp7_b: gw5300_a@6f { + compatible = "nvidia,tier4_gw5300"; + status = "okay"; + reg = <0x6f>; + }; + + imx490_a@2c { + status = "okay"; + compatible = "nvidia,tier4_imx490"; + reg = <0x2c>; + def-addr = <0x1a>; + mclk = "extperiph1"; + clocks = <&bpmp 36U>, <&bpmp 36U>; + clock-names = "extperiph1","pllp_grtba"; + nvidia,isp-device = <&isp7_b>; + nvidia,gmsl-ser-device = <&ser7_b>; + nvidia,gmsl-dser-device = <&dserd>; + physical_w = "15.0"; + physical_h = "12.5"; + sensor_model = "imx490"; + fsync-mode = "false"; + distortion-correction = "false"; + auto-exposure = "true"; + post_crop_frame_drop = "0"; + use_decibel_gain = "true"; + use_sensor_mode_id = "true"; + reg_mux = <3>; + + /* mode IMX490_MODE_2880X1860_CROP_30FPS */ + mode0 { + num_lanes = "4"; + vc_id = "0"; + tegra_sinterface = "serial_g"; + mclk_khz = "24000"; + discontinuous_clk = "no"; + dpcm_enable = "false"; + phy_mode = "DPHY"; + cil_settletime = "0"; + dynamic_pixel_bit_depth = "16"; + csi_pixel_bit_depth = "16"; + mode_type = "yuv"; + pixel_phase = "uyvy"; + active_w = "2880"; + active_h = "1860"; + readout_orientation = "0"; + line_length = "2250"; + inherent_gain = "1"; + pix_clk_hz = "757"; + serdes_pix_clk_hz = "350000000"; + gain_factor = "10"; + min_gain_val = "0"; + max_gain_val = "300"; + step_gain_val = "3"; + default_gain = "0"; + min_hdr_ratio = "1"; + max_hdr_ratio = "1"; + framerate_factor = "1000000"; + min_framerate = "30000000"; + max_framerate = "30000000"; + step_framerate = "1"; + default_framerate = "30000000"; + exposure_factor = "1000000"; + min_exp_time = "24"; + max_exp_time = "33333"; + step_exp_time = "1"; + default_exp_time = "33333"; + embedded_metadata_height = "0"; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cam_out7: endpoint { + vc-id = <1>; + port-index = <0>; + bus-width = <4>; + remote-endpoint = <&csi_in7>; + }; + }; + }; + + gmsl-link { + src-csi-port = "b"; + dst-csi-port = "a"; + serdes-csi-link = "b"; + csi-mode = "1x4"; + st-vc = <1>; + vc-id = <1>; + num-lanes = <4>; + streams = "ued-u1","yuv8"; + }; + }; + + ser6_prim: max9295_prim@62 { + compatible = "nvidia,tier4_max9295"; + reg = <0x62>; + is-prim-ser; + status = "okay"; + }; + + ser6_a: max9295_b@42 { + status = "okay"; + compatible = "nvidia,tier4_max9295"; + reg = <0x42>; + nvidia,gmsl-dser-device = <&dserd>; + vc-id = <0>; + }; + + isp6_prim: gw5300_prim@6d { + status = "okay"; + compatible = "nvidia,tier4_gw5300"; + reg = <0x6d>; + is-prim-isp; + }; + + isp6_a: gw5300_b@6e { + compatible = "nvidia,tier4_gw5300"; + status = "okay"; + reg = <0x6e>; + }; + + imx490_b@2b { + status = "okay"; + compatible = "nvidia,tier4_imx490"; + reg = <0x2b>; + def-addr = <0x1a>; + mclk = "extperiph1"; + clocks = <&bpmp 36U>, <&bpmp 36U>; + clock-names = "extperiph1","pllp_grtba"; + nvidia,isp-device = <&isp6_a>; + nvidia,gmsl-ser-device = <&ser6_a>; + nvidia,gmsl-dser-device = <&dserd>; + physical_w = "15.0"; + physical_h = "12.5"; + sensor_model = "imx490"; + fsync-mode = "false"; + distortion-correction = "false"; + auto-exposure = "true"; + post_crop_frame_drop = "0"; + use_decibel_gain = "true"; + use_sensor_mode_id = "true"; + reg_mux = <3>; + + /* mode IMX490_MODE_2880X1860_CROP_30FPS */ + mode0 { + num_lanes = "4"; + vc_id = "0"; + tegra_sinterface = "serial_g"; + mclk_khz = "24000"; + discontinuous_clk = "no"; + dpcm_enable = "false"; + phy_mode = "DPHY"; + cil_settletime = "0"; + dynamic_pixel_bit_depth = "16"; + csi_pixel_bit_depth = "16"; + mode_type = "yuv"; + pixel_phase = "uyvy"; + active_w = "2880"; + active_h = "1860"; + readout_orientation = "0"; + line_length = "2250"; + inherent_gain = "1"; + pix_clk_hz = "757"; + serdes_pix_clk_hz = "350000000"; + gain_factor = "10"; + min_gain_val = "0"; + max_gain_val = "300"; + step_gain_val = "3"; + default_gain = "0"; + min_hdr_ratio = "1"; + max_hdr_ratio = "1"; + framerate_factor = "1000000"; + min_framerate = "30000000"; + max_framerate = "30000000"; + step_framerate = "1"; + default_framerate = "30000000"; + exposure_factor = "1000000"; + min_exp_time = "24"; + max_exp_time = "33333"; + step_exp_time = "1"; + default_exp_time = "33333"; + embedded_metadata_height = "0"; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cam_out6: endpoint { + vc-id = <0>; + port-index = <0>; + bus-width = <4>; + remote-endpoint = <&csi_in6>; + }; + }; + }; + + gmsl-link { + src-csi-port = "b"; + dst-csi-port = "a"; + serdes-csi-link = "a"; + csi-mode = "1x4"; + st-vc = <0>; + vc-id = <0>; + num-lanes = <4>; + streams = "ued-u1","yuv8"; + }; + }; + }; + }; + + fragment@83 { + target-path = "/bus@0/i2c@31e0000/tca9544@72/i2c@2"; + + __overlay__ { + status = "okay"; + reg = <2>; + i2c-mux,deselect-on-exit; + + ser5_b: max9295_c@60 { + status = "okay"; + compatible = "nvidia,tier4_max9295"; + reg = <0x60>; + nvidia,gmsl-dser-device = <&dserc>; + vc-id = <1>; + }; + + isp5_b: gw5300_c@6f { + compatible = "nvidia,tier4_gw5300"; + status = "okay"; + reg = <0x6f>; + }; + + imx490_c@2c { + status = "okay"; + compatible = "nvidia,tier4_imx490"; + reg = <0x2c>; + def-addr = <0x1a>; + mclk = "extperiph1"; + clocks = <&bpmp 36U>, <&bpmp 36U>; + clock-names = "extperiph1","pllp_grtba"; + nvidia,isp-device = <&isp5_b>; + nvidia,gmsl-ser-device = <&ser5_b>; + nvidia,gmsl-dser-device = <&dserc>; + physical_w = "15.0"; + physical_h = "12.5"; + sensor_model = "imx490"; + fsync-mode = "false"; + distortion-correction = "false"; + auto-exposure = "true"; + post_crop_frame_drop = "0"; + use_decibel_gain = "true"; + use_sensor_mode_id = "true"; + reg_mux = <2>; + + /* mode IMX490_MODE_2880X1860_CROP_30FPS */ + mode0 { + num_lanes = "4"; + vc_id = "0"; + tegra_sinterface = "serial_g"; + mclk_khz = "24000"; + discontinuous_clk = "no"; + dpcm_enable = "false"; + phy_mode = "DPHY"; + cil_settletime = "0"; + dynamic_pixel_bit_depth = "16"; + csi_pixel_bit_depth = "16"; + mode_type = "yuv"; + pixel_phase = "uyvy"; + active_w = "2880"; + active_h = "1860"; + readout_orientation = "0"; + line_length = "2250"; + inherent_gain = "1"; + pix_clk_hz = "757"; + serdes_pix_clk_hz = "350000000"; + gain_factor = "10"; + min_gain_val = "0"; + max_gain_val = "300"; + step_gain_val = "3"; + default_gain = "0"; + min_hdr_ratio = "1"; + max_hdr_ratio = "1"; + framerate_factor = "1000000"; + min_framerate = "30000000"; + max_framerate = "30000000"; + step_framerate = "1"; + default_framerate = "30000000"; + exposure_factor = "1000000"; + min_exp_time = "24"; + max_exp_time = "33333"; + step_exp_time = "1"; + default_exp_time = "33333"; + embedded_metadata_height = "0"; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cam_out5: endpoint { + vc-id = <1>; + port-index = <2>; + bus-width = <4>; + remote-endpoint = <&csi_in5>; + }; + }; + }; + + gmsl-link { + src-csi-port = "b"; + dst-csi-port = "a"; + serdes-csi-link = "b"; + csi-mode = "1x4"; + st-vc = <1>; + vc-id = <1>; + num-lanes = <4>; + streams = "ued-u1","yuv8"; + }; + }; + + ser4_prim: max9295_prim@62 { + compatible = "nvidia,tier4_max9295"; + reg = <0x62>; + is-prim-ser; + status = "okay"; + }; + + ser4_a: max9295_d@42 { + status = "okay"; + compatible = "nvidia,tier4_max9295"; + reg = <0x42>; + nvidia,gmsl-dser-device = <&dserc>; + vc-id = <0>; + }; + + isp4_prim: gw5300_prim@6d { + status = "okay"; + compatible = "nvidia,tier4_gw5300"; + reg = <0x6d>; + is-prim-isp; + }; + + isp4_a: gw5300_d@6e { + compatible = "nvidia,tier4_gw5300"; + status = "okay"; + reg = <0x6e>; + }; + + imx490_d@2b { + status = "okay"; + compatible = "nvidia,tier4_imx490"; + reg = <0x2b>; + def-addr = <0x1a>; + mclk = "extperiph1"; + clocks = <&bpmp 36U>, <&bpmp 36U>; + clock-names = "extperiph1","pllp_grtba"; + nvidia,isp-device = <&isp4_a>; + nvidia,gmsl-ser-device = <&ser4_a>; + nvidia,gmsl-dser-device = <&dserc>; + physical_w = "15.0"; + physical_h = "12.5"; + sensor_model = "imx490"; + fsync-mode = "false"; + distortion-correction = "false"; + auto-exposure = "true"; + post_crop_frame_drop = "0"; + use_decibel_gain = "true"; + use_sensor_mode_id = "true"; + reg_mux = <2>; + + /* mode IMX490_MODE_2880X1860_CROP_30FPS */ + mode0 { + num_lanes = "4"; + vc_id = "0"; + tegra_sinterface = "serial_g"; + mclk_khz = "24000"; + discontinuous_clk = "no"; + dpcm_enable = "false"; + phy_mode = "DPHY"; + cil_settletime = "0"; + dynamic_pixel_bit_depth = "16"; + csi_pixel_bit_depth = "16"; + mode_type = "yuv"; + pixel_phase = "uyvy"; + active_w = "2880"; + active_h = "1860"; + readout_orientation = "0"; + line_length = "2250"; + inherent_gain = "1"; + pix_clk_hz = "757"; + serdes_pix_clk_hz = "350000000"; + gain_factor = "10"; + min_gain_val = "0"; + max_gain_val = "300"; + step_gain_val = "3"; + default_gain = "0"; + min_hdr_ratio = "1"; + max_hdr_ratio = "1"; + framerate_factor = "1000000"; + min_framerate = "30000000"; + max_framerate = "30000000"; + step_framerate = "1"; + default_framerate = "30000000"; + exposure_factor = "1000000"; + min_exp_time = "24"; + max_exp_time = "33333"; + step_exp_time = "1"; + default_exp_time = "33333"; + embedded_metadata_height = "0"; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cam_out4: endpoint { + vc-id = <0>; + port-index = <2>; + bus-width = <4>; + remote-endpoint = <&csi_in4>; + }; + }; + }; + + gmsl-link { + src-csi-port = "b"; + dst-csi-port = "a"; + serdes-csi-link = "a"; + csi-mode = "1x4"; + st-vc = <0>; + vc-id = <0>; + num-lanes = <4>; + streams = "ued-u1","yuv8"; + }; + }; + }; + }; + + fragment@84 { + target-path = "/bus@0/i2c@31e0000/tca9544@72/i2c@1"; + + __overlay__ { + status = "okay"; + reg = <1>; + i2c-mux,deselect-on-exit; + + ser3_b: max9295_e@60 { + status = "okay"; + compatible = "nvidia,tier4_max9295"; + reg = <0x60>; + nvidia,gmsl-dser-device = <&dserb>; + vc-id = <1>; + }; + + isp3_b: gw5300_e@6f { + compatible = "nvidia,tier4_gw5300"; + status = "okay"; + reg = <0x6f>; + }; + + imx490_e@2c { + status = "okay"; + compatible = "nvidia,tier4_imx490"; + reg = <0x2c>; + def-addr = <0x1a>; + mclk = "extperiph1"; + clocks = <&bpmp 36U>, <&bpmp 36U>; + clock-names = "extperiph1","pllp_grtba"; + nvidia,isp-device = <&isp3_b>; + nvidia,gmsl-ser-device = <&ser3_b>; + nvidia,gmsl-dser-device = <&dserb>; + physical_w = "15.0"; + physical_h = "12.5"; + sensor_model = "imx490"; + fsync-mode = "false"; + distortion-correction = "false"; + auto-exposure = "true"; + post_crop_frame_drop = "0"; + use_decibel_gain = "true"; + use_sensor_mode_id = "true"; + reg_mux = <1>; + + /* mode IMX490_MODE_2880X1860_CROP_30FPS */ + mode0 { + num_lanes = "4"; + vc_id = "0"; + tegra_sinterface = "serial_g"; + mclk_khz = "24000"; + discontinuous_clk = "no"; + dpcm_enable = "false"; + phy_mode = "DPHY"; + cil_settletime = "0"; + dynamic_pixel_bit_depth = "16"; + csi_pixel_bit_depth = "16"; + mode_type = "yuv"; + pixel_phase = "uyvy"; + active_w = "2880"; + active_h = "1860"; + readout_orientation = "0"; + line_length = "2250"; + inherent_gain = "1"; + pix_clk_hz = "757"; + serdes_pix_clk_hz = "350000000"; + gain_factor = "10"; + min_gain_val = "0"; + max_gain_val = "300"; + step_gain_val = "3"; + default_gain = "0"; + min_hdr_ratio = "1"; + max_hdr_ratio = "1"; + framerate_factor = "1000000"; + min_framerate = "30000000"; + max_framerate = "30000000"; + step_framerate = "1"; + default_framerate = "30000000"; + exposure_factor = "1000000"; + min_exp_time = "24"; + max_exp_time = "33333"; + step_exp_time = "1"; + default_exp_time = "33333"; + embedded_metadata_height = "0"; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cam_out3: endpoint { + vc-id = <1>; + port-index = <4>; + bus-width = <4>; + remote-endpoint = <&csi_in3>; + }; + }; + }; + + gmsl-link { + src-csi-port = "b"; + dst-csi-port = "a"; + serdes-csi-link = "b"; + csi-mode = "1x4"; + st-vc = <1>; + vc-id = <1>; + num-lanes = <4>; + streams = "ued-u1","yuv8"; + }; + }; + + ser2_prim: max9295_prim@62 { + compatible = "nvidia,tier4_max9295"; + reg = <0x62>; + is-prim-ser; + status = "okay"; + }; + + ser2_a: max9295_f@42 { + status = "okay"; + compatible = "nvidia,tier4_max9295"; + reg = <0x42>; + nvidia,gmsl-dser-device = <&dserb>; + vc-id = <0>; + }; + + isp2_prim: gw5300_prim@6d { + status = "okay"; + compatible = "nvidia,tier4_gw5300"; + reg = <0x6d>; + is-prim-isp; + }; + + isp2_a: gw5300_f@6e { + compatible = "nvidia,tier4_gw5300"; + status = "okay"; + reg = <0x6e>; + }; + + imx490_f@2b { + status = "okay"; + compatible = "nvidia,tier4_imx490"; + reg = <0x2b>; + def-addr = <0x1a>; + mclk = "extperiph1"; + clocks = <&bpmp 36U>, <&bpmp 36U>; + clock-names = "extperiph1","pllp_grtba"; + nvidia,isp-device = <&isp2_a>; + nvidia,gmsl-ser-device = <&ser2_a>; + nvidia,gmsl-dser-device = <&dserb>; + physical_w = "15.0"; + physical_h = "12.5"; + sensor_model = "imx490"; + fsync-mode = "false"; + distortion-correction = "false"; + auto-exposure = "true"; + post_crop_frame_drop = "0"; + use_decibel_gain = "true"; + use_sensor_mode_id = "true"; + reg_mux = <1>; + + /* mode IMX490_MODE_2880X1860_CROP_30FPS */ + mode0 { + num_lanes = "4"; + vc_id = "0"; + tegra_sinterface = "serial_g"; + mclk_khz = "24000"; + discontinuous_clk = "no"; + dpcm_enable = "false"; + phy_mode = "DPHY"; + cil_settletime = "0"; + dynamic_pixel_bit_depth = "16"; + csi_pixel_bit_depth = "16"; + mode_type = "yuv"; + pixel_phase = "uyvy"; + active_w = "2880"; + active_h = "1860"; + readout_orientation = "0"; + line_length = "2250"; + inherent_gain = "1"; + pix_clk_hz = "757"; + serdes_pix_clk_hz = "350000000"; + gain_factor = "10"; + min_gain_val = "0"; + max_gain_val = "300"; + step_gain_val = "3"; + default_gain = "0"; + min_hdr_ratio = "1"; + max_hdr_ratio = "1"; + framerate_factor = "1000000"; + min_framerate = "30000000"; + max_framerate = "30000000"; + step_framerate = "1"; + default_framerate = "30000000"; + exposure_factor = "1000000"; + min_exp_time = "24"; + max_exp_time = "33333"; + step_exp_time = "1"; + default_exp_time = "33333"; + embedded_metadata_height = "0"; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cam_out2: endpoint { + vc-id = <0>; + port-index = <4>; + bus-width = <4>; + remote-endpoint = <&csi_in2>; + }; + }; + }; + + gmsl-link { + src-csi-port = "b"; + dst-csi-port = "a"; + serdes-csi-link = "a"; + csi-mode = "1x4"; + st-vc = <0>; + vc-id = <0>; + num-lanes = <4>; + streams = "ued-u1","yuv8"; + }; + }; + }; + }; + + fragment@85 { + target-path = "/bus@0/i2c@31e0000/tca9544@72/i2c@0"; + + __overlay__ { + status = "okay"; + reg = <0>; + i2c-mux,deselect-on-exit; + + ser1_b: max9295_g@60 { + status = "okay"; + compatible = "nvidia,tier4_max9295"; + reg = <0x60>; + nvidia,gmsl-dser-device = <&dsera>; + vc-id = <1>; + }; + + isp1_b: gw5300_g@6f { + compatible = "nvidia,tier4_gw5300"; + status = "okay"; + reg = <0x6f>; + }; + + imx490_g@2c { + status = "okay"; + compatible = "nvidia,tier4_imx490"; + reg = <0x2c>; + def-addr = <0x1a>; + mclk = "extperiph1"; + clocks = <&bpmp 36U>, <&bpmp 36U>; + clock-names = "extperiph1","pllp_grtba"; + nvidia,isp-device = <&isp1_b>; + nvidia,gmsl-ser-device = <&ser1_b>; + nvidia,gmsl-dser-device = <&dsera>; + physical_w = "15.0"; + physical_h = "12.5"; + sensor_model = "imx490"; + fsync-mode = "false"; + distortion-correction = "false"; + auto-exposure = "true"; + post_crop_frame_drop = "0"; + use_decibel_gain = "true"; + use_sensor_mode_id = "true"; + reg_mux = <0>; + + /* mode IMX490_MODE_2880X1860_CROP_30FPS */ + mode0 { + num_lanes = "4"; + vc_id = "0"; + tegra_sinterface = "serial_g"; + mclk_khz = "24000"; + discontinuous_clk = "no"; + dpcm_enable = "false"; + phy_mode = "DPHY"; + cil_settletime = "0"; + dynamic_pixel_bit_depth = "16"; + csi_pixel_bit_depth = "16"; + mode_type = "yuv"; + pixel_phase = "uyvy"; + active_w = "2880"; + active_h = "1860"; + readout_orientation = "0"; + line_length = "2250"; + inherent_gain = "1"; + pix_clk_hz = "757"; + serdes_pix_clk_hz = "350000000"; + gain_factor = "10"; + min_gain_val = "0"; + max_gain_val = "300"; + step_gain_val = "3"; + default_gain = "0"; + min_hdr_ratio = "1"; + max_hdr_ratio = "1"; + framerate_factor = "1000000"; + min_framerate = "30000000"; + max_framerate = "30000000"; + step_framerate = "1"; + default_framerate = "30000000"; + exposure_factor = "1000000"; + min_exp_time = "24"; + max_exp_time = "33333"; + step_exp_time = "1"; + default_exp_time = "33333"; + embedded_metadata_height = "0"; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cam_out1: endpoint { + vc-id = <1>; + port-index = <6>; + bus-width = <4>; + remote-endpoint = <&csi_in1>; + }; + }; + }; + + gmsl-link { + src-csi-port = "b"; + dst-csi-port = "a"; + serdes-csi-link = "b"; + csi-mode = "1x4"; + st-vc = <1>; + vc-id = <1>; + num-lanes = <4>; + streams = "ued-u1","yuv8"; + }; + }; + + ser0_prim: max9295_prim@62 { + compatible = "nvidia,tier4_max9295"; + reg = <0x62>; + is-prim-ser; + status = "okay"; + }; + + ser0_a: max9295_h@42 { + status = "okay"; + compatible = "nvidia,tier4_max9295"; + reg = <0x42>; + nvidia,gmsl-dser-device = <&dsera>; + vc-id = <0>; + }; + + isp0_prim: gw5300_prim@6d { + status = "okay"; + compatible = "nvidia,tier4_gw5300"; + reg = <0x6d>; + is-prim-isp; + }; + + isp0_a: gw5300_h@6e { + compatible = "nvidia,tier4_gw5300"; + status = "okay"; + reg = <0x6e>; + }; + + imx490_h@2b { + status = "okay"; + compatible = "nvidia,tier4_imx490"; + reg = <0x2b>; + def-addr = <0x1a>; + mclk = "extperiph1"; + clocks = <&bpmp 36U>, <&bpmp 36U>; + clock-names = "extperiph1","pllp_grtba"; + nvidia,isp-device = <&isp0_a>; + nvidia,gmsl-ser-device = <&ser0_a>; + nvidia,gmsl-dser-device = <&dsera>; + physical_w = "15.0"; + physical_h = "12.5"; + sensor_model = "imx490"; + fsync-mode = "false"; + distortion-correction = "false"; + auto-exposure = "true"; + post_crop_frame_drop = "0"; + use_decibel_gain = "true"; + use_sensor_mode_id = "true"; + reg_mux = <0>; + + /* mode IMX490_MODE_2880X1860_CROP_30FPS */ + mode0 { + num_lanes = "4"; + vc_id = "0"; + tegra_sinterface = "serial_g"; + mclk_khz = "24000"; + discontinuous_clk = "no"; + dpcm_enable = "false"; + phy_mode = "DPHY"; + cil_settletime = "0"; + dynamic_pixel_bit_depth = "16"; + csi_pixel_bit_depth = "16"; + mode_type = "yuv"; + pixel_phase = "uyvy"; + active_w = "2880"; + active_h = "1860"; + readout_orientation = "0"; + line_length = "2250"; + inherent_gain = "1"; + pix_clk_hz = "757"; + serdes_pix_clk_hz = "350000000"; + gain_factor = "10"; + min_gain_val = "0"; + max_gain_val = "300"; + step_gain_val = "3"; + default_gain = "0"; + min_hdr_ratio = "1"; + max_hdr_ratio = "1"; + framerate_factor = "1000000"; + min_framerate = "30000000"; + max_framerate = "30000000"; + step_framerate = "1"; + default_framerate = "30000000"; + exposure_factor = "1000000"; + min_exp_time = "24"; + max_exp_time = "33333"; + step_exp_time = "1"; + default_exp_time = "33333"; + embedded_metadata_height = "0"; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + cam_out0: endpoint { + vc-id = <0>; + port-index = <6>; + bus-width = <4>; + remote-endpoint = <&csi_in0>; + }; + }; + }; + + gmsl-link { + src-csi-port = "b"; + dst-csi-port = "a"; + serdes-csi-link = "a"; + csi-mode = "1x4"; + st-vc = <0>; + vc-id = <0>; + num-lanes = <4>; + streams = "ued-u1","yuv8"; + }; + }; + }; + }; + + fragment@59 { + target = <&dsera>; + + __overlay__ { + status = "okay"; + compatible = "nvidia,tier4_max9296"; + reg = <0x48>; + csi-mode = "2x4"; + max-src = <2>; + clk-mhz = <2000>; + reset-gpios = <&tca9539_74 0 0>; + }; + }; + + fragment@60 { + target = <&dserb>; + + __overlay__ { + status = "okay"; + compatible = "nvidia,tier4_max9296"; + reg = <0x48>; + csi-mode = "2x4"; + max-src = <2>; + clk-mhz = <2000>; + reset-gpios = <&tca9539_74 2 0>; + }; + }; + + fragment@61 { + target = <&dserc>; + + __overlay__ { + status = "okay"; + compatible = "nvidia,tier4_max9296"; + reg = <0x48>; + csi-mode = "2x4"; + max-src = <2>; + clk-mhz = <2000>; + reset-gpios = <&tca9539_74 4 0>; + }; + }; + + fragment@62 { + target = <&dserd>; + + __overlay__ { + status = "okay"; + compatible = "nvidia,tier4_max9296"; + reg = <0x48>; + csi-mode = "2x4"; + max-src = <2>; + clk-mhz = <2000>; + reset-gpios = <&tca9539_74 6 0>; + }; + }; + + fragment@86 { + target-path = "/bus@0/i2c@31e0000/"; + + __overlay__ { + + tca9544@72 { + status = "okay"; + compatible = "nxp,pca9544"; + reg = <0x72>; + #address-cells = <1>; + #size-cells = <0>; + vcc-supply = <&vdd_1v8_sys>; + vcc_lp = "vcc"; + skip_mux_detect = "yes"; + force_bus_start = <40>; + + i2c@0 { + status = "okay"; + reg = <0>; + i2c-mux,deselect-on-exit; + #address-cells = <1>; + #size-cells = <0>; + + dsera: max9296@48 { + status = "okay"; + compatible = "nvidia,tier4_max9296"; + reg = <0x48>; + csi-mode = "2x4"; + max-src = <2>; + clk-mhz = <2000>; + }; + }; + + i2c@1 { + status = "okay"; + reg = <1>; + i2c-mux,deselect-on-exit; + #address-cells = <1>; + #size-cells = <0>; + + dserb: max9296@48 { + status = "okay"; + compatible = "nvidia,tier4_max9296"; + reg = <0x48>; + csi-mode = "2x4"; + max-src = <2>; + clk-mhz = <2000>; + }; + }; + + i2c@2 { + status = "okay"; + reg = <2>; + i2c-mux,deselect-on-exit; + #address-cells = <1>; + #size-cells = <0>; + + dserc: max9296@48 { + status = "okay"; + compatible = "nvidia,tier4_max9296"; + reg = <0x48>; + csi-mode = "2x4"; + max-src = <2>; + clk-mhz = <2000>; + }; + }; + + i2c@3 { + status = "okay"; + reg = <3>; + i2c-mux,deselect-on-exit; + #address-cells = <1>; + #size-cells = <0>; + + dserd: max9296@48 { + status = "okay"; + compatible = "nvidia,tier4_max9296"; + reg = <0x48>; + csi-mode = "2x4"; + max-src = <2>; + clk-mhz = <2000>; + }; + }; + }; + }; + }; + + fragment@87 { + target-path = "/bus@0/i2c@3180000"; + + __overlay__ { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + tca9539_74: tca9539@74 { + compatible = "ti,tca9539"; + gpio-controller; + #gpio-cells = <2>; + ngpios = <16>; + reg = <0x74>; + status = "okay"; + + tca9539_74_outlow { + status = "okay"; + gpio-hog; + output-low; + }; + + ca9539_74_outhigh { + status = "disabled"; + }; + + tca9539_74_input { + status = "disabled"; + }; + }; + }; + }; +}; + +/* Generated by TIER IV camera devicetree overlay generation script */ + +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + +/ { + fragment-camera-module@0 { + target-path = "/"; + __overlay__ { + /* all cameras are disabled by default */ + capture_vi_base: tegra-capture-vi { + ports { + vi_port0: port@0 { + status = "disabled"; + vi_in0: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port1: port@1 { + status = "disabled"; + vi_in1: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port2: port@2 { + status = "disabled"; + vi_in2: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port3: port@3 { + status = "disabled"; + vi_in3: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port4: port@4 { + status = "disabled"; + vi_in4: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port5: port@5 { + status = "disabled"; + vi_in5: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port6: port@6 { + status = "disabled"; + vi_in6: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + vi_port7: port@7 { + status = "disabled"; + vi_in7: endpoint { + vc-id = <0>; + status = "disabled"; + }; + }; + }; + }; + + tcp: tegra-camera-platform { + compatible = "nvidia, tegra-camera-platform"; + /** + * tpg_max_iso = <>; + * Max iso bw for 6 streams of tpg + * streams * nvcsi_freq * PG_bitrate / RG10 * BPP + * 6 * 102Mhz * 32 bits/ 10 bits * 2 Bps + * = 3916.8 MBps + */ + tpg_max_iso = <3916800>; + modules { + cam_module0: module0 { + status = "disabled"; + cam_module0_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module0_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module1: module1 { + status = "disabled"; + cam_module1_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module1_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module2: module2 { + status = "disabled"; + cam_module2_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module2_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module3: module3 { + status = "disabled"; + cam_module3_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module3_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module4: module4 { + status = "disabled"; + cam_module4_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module4_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module5: module5 { + status = "disabled"; + cam_module5_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module5_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module6: module6 { + status = "disabled"; + cam_module6_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module6_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + cam_module7: module7 { + status = "disabled"; + cam_module7_drivernode0: drivernode0 { + status = "disabled"; + }; + cam_module7_drivernode1: drivernode1 { + status = "disabled"; + pcl_id = "v4l2_lens"; + }; + }; + }; + }; + + bus@0 { + host1x@13e00000 { + csi_base: nvcsi@15a00000 { + num-tpg-channels = <36>; + csi_chan0: channel@0 { + status = "disabled"; + ports { + csi_chan0_port0: port@0 { + status = "disabled"; + csi_in0: endpoint@0 { + status = "disabled"; + }; + }; + csi_chan0_port1: port@1 { + status = "disabled"; + csi_out0: endpoint@1 { + status = "disabled"; + }; + }; + }; + }; + csi_chan1: channel@1 { + status = "disabled"; + ports { + csi_chan1_port0: port@0 { + status = "disabled"; + csi_in1: endpoint@2 { + status = "disabled"; + }; + }; + csi_chan1_port1: port@1 { + status = "disabled"; + csi_out1: endpoint@3 { + status = "disabled"; + }; + }; + }; + }; + csi_chan2: channel@2 { + status = "disabled"; + ports { + csi_chan2_port0: port@0 { + status = "disabled"; + csi_in2: endpoint@4 { + status = "disabled"; + }; + }; + csi_chan2_port1: port@1 { + status = "disabled"; + csi_out2: endpoint@5 { + status = "disabled"; + }; + }; + }; + }; + csi_chan3: channel@3 { + status = "disabled"; + ports { + csi_chan3_port0: port@0 { + status = "disabled"; + csi_in3: endpoint@6 { + status = "disabled"; + }; + }; + csi_chan3_port1: port@1 { + status = "disabled"; + csi_out3: endpoint@7 { + status = "disabled"; + }; + }; + }; + }; + csi_chan4: channel@4 { + status = "disabled"; + ports { + csi_chan4_port0: port@0 { + status = "disabled"; + csi_in4: endpoint@8 { + status = "disabled"; + }; + }; + csi_chan4_port1: port@1 { + status = "disabled"; + csi_out4: endpoint@9 { + status = "disabled"; + }; + }; + }; + }; + csi_chan5: channel@5 { + status = "disabled"; + ports { + csi_chan5_port0: port@0 { + status = "disabled"; + csi_in5: endpoint@10 { + status = "disabled"; + }; + }; + csi_chan5_port1: port@1 { + status = "disabled"; + csi_out5: endpoint@11 { + status = "disabled"; + }; + }; + }; + }; + csi_chan6: channel@6 { + status = "disabled"; + ports { + csi_chan6_port0: port@0 { + status = "disabled"; + csi_in6: endpoint@10 { + status = "disabled"; + }; + }; + csi_chan6_port1: port@1 { + status = "disabled"; + csi_out6: endpoint@11 { + status = "disabled"; + }; + }; + }; + }; + csi_chan7: channel@7 { + status = "disabled"; + ports { + csi_chan7_port0: port@0 { + status = "disabled"; + csi_in7: endpoint@10 { + status = "disabled"; + }; + }; + csi_chan7_port1: port@1 { + status = "disabled"; + csi_out7: endpoint@11 { + status = "disabled"; + }; + }; + }; + }; + }; + }; + }; + }; + }; +};