diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2ce3afa911471..15e801365ec2d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,25 +13,13 @@ name: Build on: - pull_request: - paths-ignore: - - 'Documentation/**' - - 'tools/ci/docker/linux/**' push: - paths-ignore: - - 'Documentation/**' - branches: - - master - - 'releases/*' - tags: + branches: [master] + pull_request: permissions: contents: read -concurrency: - group: build-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - jobs: Fetch-Source: runs-on: ubuntu-latest @@ -67,13 +55,13 @@ jobs: # Determine the repo and leave that unset to use the normal checkout behavior # of using the merge commit instead of HEAD case $GITHUB_REPOSITORY in - "apache/nuttx") + "tiiuae/nuttx") # OS echo "Triggered by change in OS" APPS_REF=$REF_NAME ;; - "apache/nuttx-apps" ) + "tiiuae/incubator-nuttx-apps" ) # APPS OS_REF=$REF_NAME echo "Triggered by change in APPS" @@ -89,9 +77,9 @@ jobs: echo "app_ref=$APPS_REF" >> $GITHUB_OUTPUT - name: Checkout nuttx repo - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: - repository: apache/nuttx + repository: tiiuae/nuttx ref: ${{ steps.gittargets.outputs.os_ref }} path: sources/nuttx fetch-depth: 1 @@ -99,9 +87,9 @@ jobs: run: git -C sources/nuttx fetch --tags - name: Checkout apps repo - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: - repository: apache/nuttx-apps + repository: tiiuae/incubator-nuttx-apps ref: ${{ steps.gittargets.outputs.apps_ref }} path: sources/apps fetch-depth: 1 @@ -115,71 +103,13 @@ jobs: name: source-bundle path: sources.tar.gz - Linux: - needs: Fetch-Source + Build: runs-on: ubuntu-latest - env: - DOCKER_BUILDKIT: 1 - - strategy: - matrix: - boards: [arm-01, arm-02, arm-03, arm-04, arm-05, arm-06, arm-07, arm-08, arm-09, arm-10, arm-11, arm-12, arm-13, other, risc-v, sim-01, sim-02, xtensa, codechecker] - - steps: - - name: Download Source Artifact - uses: actions/download-artifact@v3 - with: - name: source-bundle - path: . - - - name: Extract sources - run: tar zxf sources.tar.gz - - - name: Docker Login - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Docker Pull - run: docker pull ghcr.io/apache/nuttx/apache-nuttx-ci-linux - - - name: Export NuttX Repo SHA - run: echo "nuttx_sha=`git -C sources/nuttx rev-parse HEAD`" >> $GITHUB_ENV - - - name: Run builds - uses: ./sources/nuttx/.github/actions/ci-container - env: - BLOBDIR: /tools/blobs - with: - run: | - echo "::add-matcher::sources/nuttx/.github/gcc.json" - export ARTIFACTDIR=`pwd`/buildartifacts - git config --global --add safe.directory /github/workspace/sources/nuttx - git config --global --add safe.directory /github/workspace/sources/apps - cd sources/nuttx/tools/ci - if [ "X${{matrix.boards}}" = "Xcodechecker" ]; then - ./cibuild.sh -c -A -R --codechecker testlist/${{matrix.boards}}.dat - else - ./cibuild.sh -c -A -R testlist/${{matrix.boards}}.dat - fi - - - uses: actions/upload-artifact@v3 - if: ${{ always() }} - with: - name: linux-builds - path: buildartifacts/ - continue-on-error: true - - macOS: - permissions: - contents: none - runs-on: macos-13 needs: Fetch-Source strategy: + fail-fast: false matrix: - boards: [macos, sim-01, sim-02] + boards: [ssrc-arm, ssrc-riscv] steps: - name: Download Source Artifact uses: actions/download-artifact@v3 @@ -190,32 +120,11 @@ jobs: - name: Extract sources run: tar zxf sources.tar.gz - - name: Restore Tools Cache - id: cache-tools - uses: actions/cache@v3 - env: - cache-name: ${{ runner.os }}-cache-tools - with: - path: ./sources/tools - key: ${{ runner.os }}-tools-${{ hashFiles('./sources/nuttx/tools/ci/cibuild.sh') }} - - - name: Export NuttX Repo SHA - run: echo "nuttx_sha=`git -C sources/nuttx rev-parse HEAD`" >> $GITHUB_ENV - - # Released version of Cython has issues with Python 11. Set runner to use Python 3.10 - # https://github.com/cython/cython/issues/4500 - - uses: actions/setup-python@v5 - with: - python-version: '3.10' - - name: Run Builds + # cibuild.sh -i installs the tools for us + - name: Run builds run: | echo "::add-matcher::sources/nuttx/.github/gcc.json" export ARTIFACTDIR=`pwd`/buildartifacts cd sources/nuttx/tools/ci ./cibuild.sh -i -c -A -R testlist/${{matrix.boards}}.dat - - uses: actions/upload-artifact@v3 - with: - name: macos-builds - path: buildartifacts/ - continue-on-error: true diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 6032d1960bc08..ca0cd858f63b8 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -32,7 +32,7 @@ jobs: - name: Checkout nuttx repo uses: actions/checkout@v4 with: - repository: apache/nuttx + repository: tiiuae/nuttx path: nuttx fetch-depth: 0 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000000..abcd35cf08c12 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,72 @@ +name: "CodeQL" + +on: + push: + branches: [master] + pull_request: + branches: [master] + workflow_dispatch: + +jobs: + analyze: + name: Analyze (${{ matrix.language }}/${{ matrix.config}}) + runs-on: 'ubuntu-latest' + timeout-minutes: 60 + permissions: + # required for all workflows + security-events: write + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: c-cpp + build-mode: manual + config: icicle:nsh + - language: c-cpp + build-mode: manual + config: imx93-evk:nsh + - language: python + build-mode: none + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Checkout apps + uses: actions/checkout@v4 + with: + repository: 'tiiuae/incubator-nuttx-apps.git' + path: 'apps' + ref: 'master' + - name: Install tools + run: | + mv apps ../apps + sudo apt-get install kconfig-frontends + mkdir -p ../bin + cd ../bin + wget https://static.dev.sifive.com/dev-tools/freedom-tools/v2020.12/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz + wget https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-elf.tar.xz + tar xvf riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14.tar.gz + tar xvf arm-gnu-toolchain-13.2.rel1-x86_64-aarch64-none-elf.tar.xz + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + - if: matrix.build-mode == 'manual' + run: | + export PATH=$PATH:$PWD/../bin/riscv64-unknown-elf-toolchain-10.2.0-2020.12.8-x86_64-linux-ubuntu14/bin/ + export PATH=$PATH:$PWD/../bin/arm-gnu-toolchain-13.2.Rel1-x86_64-aarch64-none-elf/bin + ./tools/configure.sh ${{matrix.config}} + make + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/docker_linux.yml b/.github/workflows/docker_linux.yml index 514e7b72d0a7a..7fc5b8ae8c595 100644 --- a/.github/workflows/docker_linux.yml +++ b/.github/workflows/docker_linux.yml @@ -77,7 +77,7 @@ jobs: run: | df -h - name: Push Linux image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: tools/ci/docker/linux platforms: linux/amd64 diff --git a/Documentation/ReleaseNotes/NuttX-12.4.0 b/Documentation/ReleaseNotes/NuttX-12.4.0 new file mode 100644 index 0000000000000..6a2c70734e406 --- /dev/null +++ b/Documentation/ReleaseNotes/NuttX-12.4.0 @@ -0,0 +1,519 @@ +NuttX-12.4.0 +------------ + +What's New In This Release +Improvements to Core OS +sched +* [#10919](https://github.com/apache/nuttx/pull/10919) sched: assert: move the backtrace dump after the stack dump +* [#11195](https://github.com/apache/nuttx/pull/11195) sched: assert: restore assertion registers to array of last registers +* [#10858](https://github.com/apache/nuttx/pull/10858) sched: assert.c: Print process name in assert dump +* [#11131](https://github.com/apache/nuttx/pull/11131) sched: Check for zero sleep time and yield CPU +* [#11226](https://github.com/apache/nuttx/pull/11226) sched: delete check when pick nexttcb in readytorun list +* [#11038](https://github.com/apache/nuttx/pull/11038) sched: env_dup: fix issue about USE_AFTER_FREE +* [#11102](https://github.com/apache/nuttx/pull/11102) sched: explicitly select the cpuload clock source configuration +* [#10816](https://github.com/apache/nuttx/pull/10816) sched: Fix dependencies of CONFIG_SCHED_CPULOAD_ settings +* [#11036](https://github.com/apache/nuttx/pull/11036) sched: Follow o_cloexe semantics when calling the exec function +* [#10867](https://github.com/apache/nuttx/pull/10867) sched: format: modify spin_lock_irqsave format +* [#11018](https://github.com/apache/nuttx/pull/11018) sched: group/killchildren: replace syscall(2) to kernel api +* [#10605](https://github.com/apache/nuttx/pull/10605) sched: Implement ticket spinlock +* [#10827](https://github.com/apache/nuttx/pull/10827) sched: Improve adjtime() functionality +* [#11231](https://github.com/apache/nuttx/pull/11231) sched: lock refine: remove sched_[un]lock in xxx_waitsample +* [#11302](https://github.com/apache/nuttx/pull/11302) sched: misc/rwlock:Implementing read/write locks. +* [#11347](https://github.com/apache/nuttx/pull/11347) sched: Print more information in assert +* [#11017](https://github.com/apache/nuttx/pull/11017) sched: pthread/barrierwait: replace syscall(2) to kernel api +* [#10929](https://github.com/apache/nuttx/pull/10929) sched: Remove the unused tcb argument from group_setupidlefiles +* [#10776](https://github.com/apache/nuttx/pull/10776) sched: rw spinlock +* [#11124](https://github.com/apache/nuttx/pull/11124) sched: rw spinlocks: cosmetic changes +* [#11191](https://github.com/apache/nuttx/pull/11191) sched: sem_holder.c: When accessing SEM_WAITLIST, use holder's addrenv +* [#11257](https://github.com/apache/nuttx/pull/11257) sched: semaphore: Move POSIX regulated parts of semaphores into libc +* [#11252](https://github.com/apache/nuttx/pull/11252) sched: sigaction: Expand si_user for non-kernel signals +* [#10970](https://github.com/apache/nuttx/pull/10970) sched: smp call exit immediately when cpuset change to 0. +* [#10861](https://github.com/apache/nuttx/pull/10861) sched: spinlock: Add spin_lock_init and spin_is_locked macro +* [#11348](https://github.com/apache/nuttx/pull/11348) sched: Stack recored:Add maximum stack statistics when the task is running +* [#9163](https://github.com/apache/nuttx/pull/9163) sched: Stop the sched timer when possible to save the power in tickless mode +* [#10934](https://github.com/apache/nuttx/pull/10934) sched: support smp function call +* [#11032](https://github.com/apache/nuttx/pull/11032) sched: task: [posix]spawn: Simplify how spawn attributes are handled +* [#11241](https://github.com/apache/nuttx/pull/11241) sched: task: pthread_cancelpt: Fix nxtask_delete from another task group +* [#11165](https://github.com/apache/nuttx/pull/11165) sched: task: pthread_cancelpt: Move cancel point handling to libc, data to TLS +* [#11097](https://github.com/apache/nuttx/pull/11097) sched: task: Remove spawn_proxyattrs as obsolete implementation +* [#11177](https://github.com/apache/nuttx/pull/11177) sched: taskfiles: skip unnecessary file open/close operations to improve performance +* [#11250](https://github.com/apache/nuttx/pull/11250) sched: taskspawn: fix spawn fail if enable FDCHECK +* [#10834](https://github.com/apache/nuttx/pull/10834) sched: timer: handle perf count overflow + +mm +* [#11068](https://github.com/apache/nuttx/pull/11068) mm: both use spin_lock_irqxx() when operated delaylist +* [#11183](https://github.com/apache/nuttx/pull/11183) mm: free delay list when exceeding specified count +* [#11258](https://github.com/apache/nuttx/pull/11258) mm: kmap: Finalize kmap implementation for RISC-V +* [#10837](https://github.com/apache/nuttx/pull/10837) mm: kmap: Fix bug in kmm_unmap +* [#10876](https://github.com/apache/nuttx/pull/10876) mm: kmap: Fix several issues with the kmm_map interface +* [#11114](https://github.com/apache/nuttx/pull/11114) mm: kmap: Fix bad dependency to ARCH_VMA_MAPPING +* [#11092](https://github.com/apache/nuttx/pull/11092) mm: improve SMP performance +* [#11152](https://github.com/apache/nuttx/pull/11152) mm: record the maximum system memory usage +* [#11168](https://github.com/apache/nuttx/pull/11168) mm: Remove mm_spinlock +* [#10984](https://github.com/apache/nuttx/pull/10984) mm: Replace enter_critical_section with spin_irqsave + +libs +* [#11408](https://github.com/apache/nuttx/pull/11408) libc: add fgetwc, getwc, ungetwc wchar api implementation +* [#10602](https://github.com/apache/nuttx/pull/10602) libc: add support for custom streams with fopencookie() +* [#11011](https://github.com/apache/nuttx/pull/11011) libc: add support for memory buffer stream with fmemopen() +* [#11274](https://github.com/apache/nuttx/pull/11274) libc: add support for open_memstream +* [#11288](https://github.com/apache/nuttx/pull/11288) libc: arm: add support of PACBTI +* [#10969](https://github.com/apache/nuttx/pull/10969) libc: Change errno to set_errno and get_errno +* [#11294](https://github.com/apache/nuttx/pull/11294) libc: Fix -nan issue with f32 +* [#11198](https://github.com/apache/nuttx/pull/11198) libc: Fix improper handling of 64 bit types for libvsprintf +* [#11322](https://github.com/apache/nuttx/pull/11322) libc: Handle PCREL_HI20/LO12_I/S relocations correctly +* [#10994](https://github.com/apache/nuttx/pull/10994) libc: Improve stdio unlock version function +* [#11364](https://github.com/apache/nuttx/pull/11364) libc: lib_slcd: fix encode/decode of binary nibble to/from ascii hex +* [#11035](https://github.com/apache/nuttx/pull/11035) libc: localtime: fix the timezone error caused by minor error +* [#11281](https://github.com/apache/nuttx/pull/11281) libc: machine/arm: align related implementations of armv7 architecture +* [#10927](https://github.com/apache/nuttx/pull/10927) libc: machine: Remove FAR from sparc +* [#11133](https://github.com/apache/nuttx/pull/11133) libc: realpath: allocate link buffer of pseudofs to save stack +* [#10913](https://github.com/apache/nuttx/pull/10913) libc: Refine the implementation of fopen/fdopen +* [#10993](https://github.com/apache/nuttx/pull/10993) libc: Remove the unused lib_libdtoa.c +* [#11137](https://github.com/apache/nuttx/pull/11137) libc: Solve some problems encountered during cmake compilation +* [#10992](https://github.com/apache/nuttx/pull/10992) libc: stdio: Change FILE buffer field from "unsigned char *" to "char *" +* [#11063](https://github.com/apache/nuttx/pull/11063) libc: stdlib/lib_exit.c: fix multiple definition of __dso_handle and sethost.sh: add MSYS environmen for msys2 +* [#11447](https://github.com/apache/nuttx/pull/11447) libc: stream: add stream interface +* [#11350](https://github.com/apache/nuttx/pull/11350) libc: Support gdbstub kernal debugging +* [#11346](https://github.com/apache/nuttx/pull/11346) libc: Supports storing coredump into block devices +* [#10862](https://github.com/apache/nuttx/pull/10862) libc: memfd: shm_unlink or unlink anonymous file +* [#10891](https://github.com/apache/nuttx/pull/10891) libc: memfd: turn a runtime error into a linker error +* [#10972](https://github.com/apache/nuttx/pull/10972) libds: add missing observer_b16.c to cmake build +* [#10915](https://github.com/apache/nuttx/pull/10915) libdsp: lib_observer.c: use float numbers for some calculations +* [#10979](https://github.com/apache/nuttx/pull/10979) libdsp: update LP_FILTER comment +* [#11256](https://github.com/apache/nuttx/pull/11256) libm: Fix an issue that public header files are not exported +* [#11162](https://github.com/apache/nuttx/pull/11162) libm: newlib: Change the download site to https +* [#11386](https://github.com/apache/nuttx/pull/11386) libs: log2ceil: Move implementation of log2ceil to a common place +* [#11043](https://github.com/apache/nuttx/pull/11043) libs: modlib: optimize code and add arch api for allocating data section +* [#11394](https://github.com/apache/nuttx/pull/11394) libxx: cmake: remove useless code +* [#11050](https://github.com/apache/nuttx/pull/11050) libxx: Silence warnings when building libcxx. +* [#11301](https://github.com/apache/nuttx/pull/11301) libxx: upgrade llvm version to 17.0.6 +* [#10860](https://github.com/apache/nuttx/pull/10860) libxx: Use gnu++20 option only if using libcxx +misc +* [#11242](https://github.com/apache/nuttx/pull/11242) Revert "libc/lib_bzero:Add bzero prototype." +* [#10881](https://github.com/apache/nuttx/pull/10881) arm, arm64, xtensa, libxx: Change sed -r to sed -E to support macOS +* [#11027](https://github.com/apache/nuttx/pull/11027) assert: rename __ASSERT to __ASSERT__ to avoid conflict +* [#11025](https://github.com/apache/nuttx/pull/11025) audio: add amr format support +* [#11055](https://github.com/apache/nuttx/pull/11055) binfmt/elf: Select ARCH_USE_TEXT_HEAP if ARCH_HAVE_TEXT_HEAP +* [#11238](https://github.com/apache/nuttx/pull/11238) clock.h: use CONFIG_DEBUG_SCHED to test init ticks +* [#10924](https://github.com/apache/nuttx/pull/10924) crypto/rsa_verify: export rsa verify via /dev/crypto +* [#10978](https://github.com/apache/nuttx/pull/10978) debug/assert: decouple configuration of show file name feature +* [#10809](https://github.com/apache/nuttx/pull/10809) dma: support source/destination address auto step +* [#10870](https://github.com/apache/nuttx/pull/10870) fixedmath: add abs and sign operations +* [#11111](https://github.com/apache/nuttx/pull/11111) ioctl: add definitions related to ethtool +* [#11121](https://github.com/apache/nuttx/pull/11121) ioctl: add SIOCGIWNAME support +* [#11026](https://github.com/apache/nuttx/pull/11026) kernel: replace all sem_* to nxsem_*: in kernel space +* [#10849](https://github.com/apache/nuttx/pull/10849) langinfo: The character U+ff0c "," could be confused with the ASCII character U… +* [#11243](https://github.com/apache/nuttx/pull/11243) list: search prev item in reverse order +* [#11221](https://github.com/apache/nuttx/pull/11221) poll: pollsetup should notify only one fd passed by caller +* [#10892](https://github.com/apache/nuttx/pull/10892) refine: move BIT Macro to nuttx/bits.h +* [#11218](https://github.com/apache/nuttx/pull/11218) spinlock: Move the inclusion of stdatomic.h to source file +* [#10869](https://github.com/apache/nuttx/pull/10869) sys/types: supporting 32-bit IDs for gid_t/uid_t +* [#11207](https://github.com/apache/nuttx/pull/11207) tcbinfo:remove total_num form tcbinfo. +* [#11298](https://github.com/apache/nuttx/pull/11298) video: Update v4l2m2m interface & create videoio.h +* [#11362](https://github.com/apache/nuttx/pull/11362) virtio.h: add virtio_has_feature api for virtio driver +Build System +Improvements +* [#11007](https://github.com/apache/nuttx/pull/11007) Revert "make/archive: Use the full path name when matching or storing… +* [#11047](https://github.com/apache/nuttx/pull/11047) applications: Move the test tools in the system to the testing +* [#11395](https://github.com/apache/nuttx/pull/11395) cmake: build file support with libcxx 17.0.6 +* [#10982](https://github.com/apache/nuttx/pull/10982) cmake: correct cmake rule file name +* [#11375](https://github.com/apache/nuttx/pull/11375) cmake: fix NUTTX_COMMON_DIR +* [#11031](https://github.com/apache/nuttx/pull/11031) cmake: init RISC-V cmake qemu-rv build +* [#10843](https://github.com/apache/nuttx/pull/10843) cmake: raise error if previous make build was not cleaned +* [#10879](https://github.com/apache/nuttx/pull/10879) fix: TreeNode has same attribute with NodeMixin +* [#10968](https://github.com/apache/nuttx/pull/10968) nuttx: generate nuttx.map file when enable debug link map. +* [#11303](https://github.com/apache/nuttx/pull/11303) sh: Enhanced compilation system +* [#11432](https://github.com/apache/nuttx/pull/11432) tools: config.mk: whether verbosity is enabled or not, should use bash +* [#11098](https://github.com/apache/nuttx/pull/11098) tools: configure.c and tools/sethost.sh Add CONFIG_EXPERIMENTAL for configure windows native +Architectural Support +New Architecture Support +* [#11319](https://github.com/apache/nuttx/pull/11319) arm:imxrt: Add support for imxrt1170 Soc and imxrt1170-evk board +* [#11371](https://github.com/apache/nuttx/pull/11371) riscv: Add support for Bouffalo Lab BL808 SoC (T-Head C906) + +Architecture Improvements +* [#10836](https://github.com/apache/nuttx/pull/10836) arch: add a flag indicating that the chip doesn't support DMA transfer from/to FLASH +* [#10759](https://github.com/apache/nuttx/pull/10759) arch: add use_data to g_tcbinfo +* [#11190](https://github.com/apache/nuttx/pull/11190) arch: dumponexit: unify dump on exit to common code +* [#10828](https://github.com/apache/nuttx/pull/10828) arch: simplify ARCH_PERF_EVENTS related code +* [#11160](https://github.com/apache/nuttx/pull/11160) arch: textheap: add _heapmember declare for text and data heap +arm + * [#11282](https://github.com/apache/nuttx/pull/11282) clang: replace deprecated parameter +* [#11170](https://github.com/apache/nuttx/pull/11170) Let's old arm's arm_doirq return register context like armv7-a +* [#11413](https://github.com/apache/nuttx/pull/11413) debug:fix gdbstub clear fpb & dwt when already use jtag/swo bug +* [#11166](https://github.com/apache/nuttx/pull/11166) armv8-m: Fix typo error for NVIC_SYSHCON_HARDFAULTPENDED + +* [#11118](https://github.com/apache/nuttx/pull/11118) cxd56xx: Support to get gnss firmware version + +* [#11398](https://github.com/apache/nuttx/pull/11398) imxrt: Extend FlexIO support to 117x +* [#11436](https://github.com/apache/nuttx/pull/11436) imxrt: flexio move ifdef guard lower +* [#11012](https://github.com/apache/nuttx/pull/11012) imxrt: NXP I2C non-DMA end only on stop with end of packet +* [#11000](https://github.com/apache/nuttx/pull/11000) imxrt: nxp lpi2c calculated timeout can not be 0 +* [#11033](https://github.com/apache/nuttx/pull/11033) imxrt: NXP lpi2c DMA transaction only need the status conditioned +* [#11164](https://github.com/apache/nuttx/pull/11164) imxrt: NXP Serial Do not wait on TXDMA semaphore +* [#11070](https://github.com/apache/nuttx/pull/11070) imxrt: NXP Serial overcome race where DMA has not fetched TCD again +* [#11020](https://github.com/apache/nuttx/pull/11020) imxrt: serial Ensure the cache is updated if the DMA has updated again + +* [#11199](https://github.com/apache/nuttx/pull/11199) imx6: Replace cpu_start_t with start_t + +* [#10877](https://github.com/apache/nuttx/pull/10877) mx8mp: Add support for SPI + +* [#11203](https://github.com/apache/nuttx/pull/11203) nRF91: initial support for GNSS +* [#11308](https://github.com/apache/nuttx/pull/11308) nrf{52|53|91}: add missing support for 1 Mbps UART baud +* [#10826](https://github.com/apache/nuttx/pull/10826) nrf{52|53|91}: add support for up_perf +* [#10830](https://github.com/apache/nuttx/pull/10830) nrf{52|53|91}: fixes for timer + +* [#11172](https://github.com/apache/nuttx/pull/11172) rp2040: pwm: Fix errors at CONFIG_PWM_NCHANNELS=1 + +* [#10817](https://github.com/apache/nuttx/pull/10817) sama5: Sort SAMA5D2 adc/tsd dma +* [#10806](https://github.com/apache/nuttx/pull/10806) sama5: TSD trigger and pressure scaling issues +* [#11307](https://github.com/apache/nuttx/pull/11307) samd212: invert tx and rx in spi_dma_setup +* [#11212](https://github.com/apache/nuttx/pull/11212) samd212: sam_dmac: Fix compilation and fix SAM_DMAC_CHINTENCLR settings +* [#10855](https://github.com/apache/nuttx/pull/10855) samv7: channel gain switching in aefc +* [#11312](https://github.com/apache/nuttx/pull/11312) samv7: sam_emac: Implement errata workaround for KSZ8061 PHY + +* [#10847](https://github.com/apache/nuttx/pull/10847) {stm32|stm32f7|at32|samv7|imxrt}: fix for adc_setup +* [#11211](https://github.com/apache/nuttx/pull/11211) stm32: Add support for Ethernet packet timestamping and PTP timer +* [#11175](https://github.com/apache/nuttx/pull/11175) stm32: foc: add support for board-specific ioctl +* [#10833](https://github.com/apache/nuttx/pull/10833) stm32: Initialize LED driver during late initialization for nucleo-f446re +* [#11181](https://github.com/apache/nuttx/pull/11181) stm32: stm32/stm32_adc.c: protect irq_attach with refcounter +* [#11194](https://github.com/apache/nuttx/pull/11194) stm32: stm32_foc.c: rename some macros +* [#11194](https://github.com/apache/nuttx/pull/11194) stm32: stm32_eth: Fix excessively long critical section in ifdown handlerm +* [#10865](https://github.com/apache/nuttx/pull/10865) stm32: UART needs to be disabled before changing setup + +* [#10824](https://github.com/apache/nuttx/pull/10824) stm32l4: ADC: Adds low level operations to start and stop DMA. +* [#11154](https://github.com/apache/nuttx/pull/11154) stm32h7: serial: Do not wait on TXDMA semaphore +* [#11323](https://github.com/apache/nuttx/pull/11323) stm32h7: serial refactor out tx dma semaphore +* [#11332](https://github.com/apache/nuttx/pull/11332) stm32h7: serial Remove .txdmasem = SEM_INITIALIZER(1) bad cherry-pick +* [#10841](https://github.com/apache/nuttx/pull/10841) stm32h7: stm32_oneshot.c: Fix format warnings. +* [#11334](https://github.com/apache/nuttx/pull/11334) stm32h7: stm32h7_adc: Dynamically set clock prescaler and BOOST +* [#11367](https://github.com/apache/nuttx/pull/11367) stm32u5: fix EXTICR2,3,4 register offsets + +* [#10846](https://github.com/apache/nuttx/pull/10846) s32k1xx: Fix LPUART inversion warnings & config. +* [#10844](https://github.com/apache/nuttx/pull/10844) s32k1xx: Fix warnings in PWM code. +* [#11099](https://github.com/apache/nuttx/pull/11099) s32kxxx: flexcan doesn't set srr bit for extended frames +* [#11325](https://github.com/apache/nuttx/pull/11325) s32k3xx: NXP S32K3xx Fixes stuttering output +* [#11106](https://github.com/apache/nuttx/pull/11106) s32k3xx: serial ensure the cache is updated if the DMA has updated again +arm64 +* [#10888](https://github.com/apache/nuttx/pull/10888) Add support for FIQ interrupts +* [#11352](https://github.com/apache/nuttx/pull/11352) coredump: support arm64 coredump +* [#11200](https://github.com/apache/nuttx/pull/11200) Disable ARCH_HAVE_FORK for arm64 as a precaution +* [#11429](https://github.com/apache/nuttx/pull/11429) Fix GICv2 detection +* [#10966](https://github.com/apache/nuttx/pull/10966) Remove unnecessary code in arm64_cpu_idle.S +* [#11037](https://github.com/apache/nuttx/pull/11037) support relocate for aarch64 +* [#10917](https://github.com/apache/nuttx/pull/10917) support up_coherent_dcache function +* [#10918](https://github.com/apache/nuttx/pull/10918) target cpuid calculation error in arm64_gic_raise_sgi function +* [#11182](https://github.com/apache/nuttx/pull/11182) the bug of sscanf exception output in arm64 platform +* [#11245](https://github.com/apache/nuttx/pull/11245) vector: no need to save x0 to sp +* [#10904](https://github.com/apache/nuttx/pull/10904) XN should only be set when the attribute MT_EXECUTE_NEVER is set +risc-v +* [#10856](https://github.com/apache/nuttx/pull/10856) addrenv: utils: Determine page table flags by type of vaddr +* [#11113](https://github.com/apache/nuttx/pull/11113) addrenv: Fix static page table mapping (paddr instead of vaddr) +* [#10838](https://github.com/apache/nuttx/pull/10838) addrenv: Fix the user VMA end address +* [#10829](https://github.com/apache/nuttx/pull/10829) addrenv: Fix two SHM related issues +* [#11389](https://github.com/apache/nuttx/pull/11389) arch_elf: Check for _HI20 relocation validity +* [#11437](https://github.com/apache/nuttx/pull/11437) espressif: mcuboot: Fix dependency of the Espressif's port MCUboot. +* [#11034](https://github.com/apache/nuttx/pull/11034) espressif: Update esp-hal-3rdparty version +* [#11024](https://github.com/apache/nuttx/pull/11024) litex/litex_emac: Add support for KSZ8061 ethernet PHY. +* [#11029](https://github.com/apache/nuttx/pull/11029) litex/litex-emac: Add support for phy interrupts. +* [#11028](https://github.com/apache/nuttx/pull/11028) litex/litex_gpio: Fix ISR dispatch when using higher GPIO indexes. +* [#11365](https://github.com/apache/nuttx/pull/11365) mmu: Extend MMU Flags to 64-bit for T-Head C906 and Svpbmt +* [#11283](https://github.com/apache/nuttx/pull/11283) mpfs: corespi: Round up divider to prevent overlock of SPI +* [#10822](https://github.com/apache/nuttx/pull/10822) mpfs: corespi: Several speed optimizations to the FPGA driver +* [#10921](https://github.com/apache/nuttx/pull/10921) mpfs: ethernet: Fix RX/TX buffer and descriptor handling +* [#11405](https://github.com/apache/nuttx/pull/11405) mpfs: ethernet: Remove DMA_ENABLE hack +* [#10922](https://github.com/apache/nuttx/pull/10922) mpfs: entrypoints: Fix potential R_RISCV_JAL linker error +* [#11247](https://github.com/apache/nuttx/pull/11247) mpfs: ihc: cleanup DEBUGASSERTs and irq enabling +* [#11355](https://github.com/apache/nuttx/pull/11355) mpfs: mpfs_head.S: Change j/jal to tail call +* [#10923](https://github.com/apache/nuttx/pull/10923) mpfs: mpfs_head.S: Simplify clearing PMP +* [#11233](https://github.com/apache/nuttx/pull/11233) mpfs: opensbi: update opensbi to version 1.3.1 +* [#11404](https://github.com/apache/nuttx/pull/11404) mpfs: usb: Use kernel memory instead of user memory for DMA +* [#11403](https://github.com/apache/nuttx/pull/11403) mpfs: pmpcfg: Move PMPCFG registers to common location +* [#10875](https://github.com/apache/nuttx/pull/10875) pgalloc.h: Return kernel vaddr for kernel RAM paddr +* [#11374](https://github.com/apache/nuttx/pull/11374) riscv_pmp.c: Revert LOG2_CEIL back to run-time log2ceil function +* [#11001](https://github.com/apache/nuttx/pull/11001) Simplify PMP configuration and code +* [#11441](https://github.com/apache/nuttx/pull/11441) Update mode.h to add CSR_TVEC +sim +* [#10930](https://github.com/apache/nuttx/pull/10930) crypto: Use mbedtls default configuration without special check +* [#11381](https://github.com/apache/nuttx/pull/11381) sim_lcd: add open & close +* [#11122](https://github.com/apache/nuttx/pull/11122) sim_netdriver: some sim defconfig have problems when using the network +* [#11246](https://github.com/apache/nuttx/pull/11246) sim support 16bbp +* [#11237](https://github.com/apache/nuttx/pull/11237) simwifi: Connect the wifi whose ssid contains the special charaters. +* [#11235](https://github.com/apache/nuttx/pull/11235) simwifi: Escapes the special characters of ssid in the scan results. +* [#11069](https://github.com/apache/nuttx/pull/11069) simwifi: Fix the error of the need length for scan bssinfo. +* [#11112](https://github.com/apache/nuttx/pull/11112) simwifi: For scan results, parse and translate the Chinese ssid encoded by the wpa_cli. +* [#11066](https://github.com/apache/nuttx/pull/11066) simwifi: host wlan0 obtains ip and set dns for wlan0 in the defwan wlan0 +* [#11108](https://github.com/apache/nuttx/pull/11108) simwifi: Transfer the special characters in ssid. +* [#11104](https://github.com/apache/nuttx/pull/11104) simwifi: Support that get the connected Chinese essid. +* [#11051](https://github.com/apache/nuttx/pull/11051) simwifi: Support that simwifi connects to the hidden ssid. +* [#11171](https://github.com/apache/nuttx/pull/11171) Replace [enter|leave]_critical_section with up_irq_[save|restore] +* [#11219](https://github.com/apache/nuttx/pull/11219) Remove the wrong comment from up_allocate_heap +* [#11205](https://github.com/apache/nuttx/pull/11205) usb_rawgadget: remove halt operation +* [#10910](https://github.com/apache/nuttx/pull/10910) Update Fix more generic for platforms that do not have execinfo.h +* [#11030](https://github.com/apache/nuttx/pull/11030) wifidriver: Fix the scan error. +* [#10886](https://github.com/apache/nuttx/pull/10886) wifidriver: Support the sim wifi. +x86_64 +* [#10899](https://github.com/apache/nuttx/pull/10899) Fix idle stack assignment +xtensa +* [#11141](https://github.com/apache/nuttx/pull/11141) esp32: ble: Enable the BLE interrupt during an SPI flash operation +* [#10859](https://github.com/apache/nuttx/pull/10859) esp32: ble: Fix task_create_wrapper CPU core ID passed as argument +* [#10851](https://github.com/apache/nuttx/pull/10851) esp32: irq: Fix erroneous interrupt allocation for each CPU core +* [#11139](https://github.com/apache/nuttx/pull/11139) esp32s2: Add rtc heap support +* [#11300](https://github.com/apache/nuttx/pull/11300) esp32s2: Add RTC support +* [#11138](https://github.com/apache/nuttx/pull/11138) esp32s2: Add SPI slave support +* [#10850](https://github.com/apache/nuttx/pull/10850) esp32s2: add UART RS485 support +* [#10823](https://github.com/apache/nuttx/pull/10823) esp32s2: Add support to TWAI/CANBus controller +* [#11431](https://github.com/apache/nuttx/pull/11431) esp32s2: Add xtwdt and rwdt support +* [#10873](https://github.com/apache/nuttx/pull/10873) esp32s2: ESP32-S3 I2C improvements +* [#11259](https://github.com/apache/nuttx/pull/11259) esp32s3: Add rtc heap support +* [#11180](https://github.com/apache/nuttx/pull/11180) esp32s3: Add RWDT support +* [#11287](https://github.com/apache/nuttx/pull/11287) esp32s3: Add SPIRAM high memory support +* [#11179](https://github.com/apache/nuttx/pull/11179) esp32s3: Add XTWDT support +* [#10854](https://github.com/apache/nuttx/pull/10854) esp32s3: ble: enable the BLE interrupt during a SPI flash operation +* [#11331](https://github.com/apache/nuttx/pull/11331) esp32s3: enable LIBC_ARCH_ATOMIC +* [#11299](https://github.com/apache/nuttx/pull/11299) esp32s3: Fix esp32s3 mcuboot ota crash +* [#11136](https://github.com/apache/nuttx/pull/11136) esp32s3: Fix issue regarding IRAM-enabled ISRs by fixing the linker +* [#11285](https://github.com/apache/nuttx/pull/11285) esp32s3: Fix some ESP32S3 module reboot and QVL issues +* [#10882](https://github.com/apache/nuttx/pull/10882) esp32s3: Fix the os halt issue when esp32s3 wlan has high-speed or long time d… +* [#11427](https://github.com/apache/nuttx/pull/11427) esp32s3: Fixed bbpll not calibrated from bootloader issue +* [#11328](https://github.com/apache/nuttx/pull/11328) esp32s3: GPIO clear pending interrupt status before enable IRQ +* [#11329](https://github.com/apache/nuttx/pull/11329) esp32s3: QSPI disable DMA when sending command to slave +* [#11286](https://github.com/apache/nuttx/pull/11286) esp32s3: Invalidate cache if the flash address used has a cache mapping. +* [#11144](https://github.com/apache/nuttx/pull/11144) esp32s3: Support malloc from external RAM and internal RAM +* [#11157](https://github.com/apache/nuttx/pull/11157) esp32s3: Support multiple PHY init data bin +* [#11434](https://github.com/apache/nuttx/pull/11434) esp32s3: Support reading encrypted partitions +* [#11052](https://github.com/apache/nuttx/pull/11052) esp32s3: Support to read data from flash to PSRAM +* [#11340](https://github.com/apache/nuttx/pull/11340) esp32s3: Tasks use SPIRAM as stack can do SPI flash read/write/erase/map/unmap +* [#11428](https://github.com/apache/nuttx/pull/11428) espressif/rmt: Implement a common RMT (Remote Control) driver for xtensa-based devices. +Driver Support +New Driver Support +* [#10770](https://github.com/apache/nuttx/pull/10770) drivers: add regmap subsystems support. +* [#10902](https://github.com/apache/nuttx/pull/10902) motor: Add stepper interface +* [#11253](https://github.com/apache/nuttx/pull/11253) mtd: Adds support to W25Q20CL memory. +* [#11149](https://github.com/apache/nuttx/pull/11149) mtd: mx25rxx: add support for MX25L25673G chip +* [#11422](https://github.com/apache/nuttx/pull/11422) net: ksz9477: Add simple port-based static VLAN configuration +* [#11339](https://github.com/apache/nuttx/pull/11339) net: lan9250: Add LAN9250 driver(SPI and QSPI mode) +* [#11280](https://github.com/apache/nuttx/pull/11280) sensors: Add support for MS5607 +* [#10864](https://github.com/apache/nuttx/pull/10864) sensors: max31865:RTD-to-Digital Converter +* [#10914](https://github.com/apache/nuttx/pull/10914) stepper: add DRV8825 +* [#11228](https://github.com/apache/nuttx/pull/11228) tee: add optee client driver module +Drivers Improvements +* [#11071](https://github.com/apache/nuttx/pull/11071) Kconfigs: rename {Rpmsg|rpmsg} to RPMGS +* [#11061](https://github.com/apache/nuttx/pull/11061) can: Add new ioctls +* [#10845](https://github.com/apache/nuttx/pull/10845) foc: foc_dummy.c: update dummy device state only if dev opened +* [#11176](https://github.com/apache/nuttx/pull/11176) foc: return scaling factor for phase currents and BEMF via ioctl +* [#10808](https://github.com/apache/nuttx/pull/10808) ioexpander: Minor fix for ioexpander driver +* [#11147](https://github.com/apache/nuttx/pull/11147) lcd: add stride support for LCD driver +* [#11185](https://github.com/apache/nuttx/pull/11185) lcd: change lcd stride from pixel to bytes +* [#10926](https://github.com/apache/nuttx/pull/10926) math: mpi: add mpi driver in math +* [#11240](https://github.com/apache/nuttx/pull/11240) misc: Rpmsgblk function optimization +* [#11220](https://github.com/apache/nuttx/pull/11220) mmcsd: mmcsd_sdinitialize should save csd register into priv->csd +* [#10909](https://github.com/apache/nuttx/pull/10909) mtd: filemtd:Fix teardown return error number EINVAL +* [#11041](https://github.com/apache/nuttx/pull/11041) mtd: get mtd_geometry_s.model for mtd partition and optimize code +* [#11187](https://github.com/apache/nuttx/pull/11187) mtd: s25fl1: fix compile warnings caused by incorrect variable print format +* [#11370](https://github.com/apache/nuttx/pull/11370) mtd: w25q: add nxsig_usleep to busy waiting in w25qxxxjv_erase_sector() +* [#11391](https://github.com/apache/nuttx/pull/11391) net: qemu/wifi: Add the virtual wifi function on the emulator. +* [#11216](https://github.com/apache/nuttx/pull/11216) net: skeleton.c doesn't compile without this patch if ioctls are enabled +* [#10907](https://github.com/apache/nuttx/pull/10907) note: Change 0/1 to false/true +* [#11153](https://github.com/apache/nuttx/pull/11153) note: delete sched_note_flatten +* [#10840](https://github.com/apache/nuttx/pull/10840) note: optimize note performance +* [#10920](https://github.com/apache/nuttx/pull/10920) note: remove remaining event code +* [#11074](https://github.com/apache/nuttx/pull/11074) power: pm: use pm_staytimeout() in greedy_governor_activity() +* [#11132](https://github.com/apache/nuttx/pull/11132) rptun: check the status before stop remote proc +* [#11222](https://github.com/apache/nuttx/pull/11222) rtc: RTC driver improvement +* [#10831](https://github.com/apache/nuttx/pull/10831) rtt: make RTT console optional +* [#11296](https://github.com/apache/nuttx/pull/11296) segger: rtt: correct macro name to avoid unable to change default mode +* [#11419](https://github.com/apache/nuttx/pull/11419) sensors: mx56xx: Add support for second order compensation +* [#11426](https://github.com/apache/nuttx/pull/11426) sensors: mx56xx: Fix threshold and calculation +* [#11178](https://github.com/apache/nuttx/pull/11178) serial: uart_tcsendbreak: Remove cancel point, as tcsendbreak is not one +* [#11402](https://github.com/apache/nuttx/pull/11402) syslog: ramlog: improve ramlog performance +* [#11392](https://github.com/apache/nuttx/pull/11392) syslog: ramlog: multi readers +* [#10890](https://github.com/apache/nuttx/pull/10890) syslog: ramlog: remove sched_[un]lock and rl_nwaiters +* [#11186](https://github.com/apache/nuttx/pull/11186) timers: Rewrite adjtime() implementation to work for RTC and tickless kernel +* [#11356](https://github.com/apache/nuttx/pull/11356) usbdev: Add callback for CONFIG_USBDEV_SOFINTERRUPT +* [#11042](https://github.com/apache/nuttx/pull/11042) usbdev: config USBDEV_TRACE_INITIALIDSET when disbale USBDEV_TRACE +* [#11161](https://github.com/apache/nuttx/pull/11161) usbdev: Solve some problems of USB hotplug +* [#10985](https://github.com/apache/nuttx/pull/10985) usrsock: Make the field of usrsock_request native alignment +* [#11103](https://github.com/apache/nuttx/pull/11103) usrsock: rpmsg_server: Keep msg order in recursive call +* [#11107](https://github.com/apache/nuttx/pull/11107) usrsock: socket fallback with ENETDOWN +* [#10874](https://github.com/apache/nuttx/pull/10874) video: fb: Add fb_register_device +* [#10812](https://github.com/apache/nuttx/pull/10812) video: goldfish: Remove the vsync residual code +* [#11380](https://github.com/apache/nuttx/pull/11380) video: goldfish: optimize goldfish fb register +* [#11249](https://github.com/apache/nuttx/pull/11249) video: video.c: modify set_buf call seqence in start_capture function. +* [#11224](https://github.com/apache/nuttx/pull/11224) video: wait when the vsync queue is full in FBIO_WAITFORVSYNC +* [#11382](https://github.com/apache/nuttx/pull/11382) virtio: Support for setting MAC addresses of the virtio-net interfaces +* [#11385](https://github.com/apache/nuttx/pull/11385) virtio: virtio-gpu: convert virito-gpu fb_register to virtio_gpu_fb_register +* [#11201](https://github.com/apache/nuttx/pull/11201) virtio: Virtio Qemu 8.1.2 issues fix +* [#11013](https://github.com/apache/nuttx/pull/11013) wireless: bluetooth: Add option to set the HCI TX thread affinity while running with SMP enabled +* [#11072](https://github.com/apache/nuttx/pull/11072) wireless: bluetooth: rpmsg depends on RPTUN + +Board Support +New Board Support +arm +* [#10987](https://github.com/apache/nuttx/pull/10987) gd32f4: add gd32f470i board support +* [#11094](https://github.com/apache/nuttx/pull/11094) stm32: add support to LINUM-STM32H753BI board +* [#10990](https://github.com/apache/nuttx/pull/10990) stm32: add support to STM32F401RC-RS485 board +* [#11358](https://github.com/apache/nuttx/pull/11358) stm32h7: linum-stm32h753bi: Add modbus example using usart6 +* [#11276](https://github.com/apache/nuttx/pull/11276) seeed-xiao-rp2040: Add initial board support + +xtensa +* [#10976](https://github.com/apache/nuttx/pull/10976) Add ESP32-2432S028 board +* [#10928](https://github.com/apache/nuttx/pull/10928) esp32s3-box: Support hardware version 3 + +risc-v +* [#11379](https://github.com/apache/nuttx/pull/11379) Initial support for CanMV-k230 board +* [#11377](https://github.com/apache/nuttx/pull/11377) Add support for PINE64 Ox64 BL808 SBC + +Board Improvements +* [#11056](https://github.com/apache/nuttx/pull/11056) Modify test "ramtest" path +* [#11192](https://github.com/apache/nuttx/pull/11192) remove obsolete CONFIG_EXAMPLES_FOC_IPHASE_ADC option + +arm +* [#11101](https://github.com/apache/nuttx/pull/11101) cxd56xx: Add cxd5610 gnss driver + +* [#11373](https://github.com/apache/nuttx/pull/11373) gd32f4xx: change gd32f470z board code + +* [#11193](https://github.com/apache/nuttx/pull/11193) imx6: Fix sabre-6quad:libcxx + +* [#11310](https://github.com/apache/nuttx/pull/11310) nrf52: nrf52832-dk: add timer example +* [#10835](https://github.com/apache/nuttx/pull/10835) nrf52: remove CONFIG_ARMV7M_SYSTICK form tickless configs + +* [#11150](https://github.com/apache/nuttx/pull/11150) sama5: Add QSPI support SAMA5 +* [#11151](https://github.com/apache/nuttx/pull/11151) sama5: sama5d2-xult: add support for QSPI flash and nxffs + +* [#11117](https://github.com/apache/nuttx/pull/11117) stm32: b-g431b-esc1: don't use CONFIG_STM32_USE_LEGACY_PINMAP=y +* [#11306](https://github.com/apache/nuttx/pull/11306) stm32h7: fix config conflict +* [#11214](https://github.com/apache/nuttx/pull/11214) stm32h7: linum-stm32h753bi: Add support to RTC and alarm +* [#11167](https://github.com/apache/nuttx/pull/11167) stm32h7: linum-stm32h753bi: Added suport to userlerds library. +* [#11265](https://github.com/apache/nuttx/pull/11265) stm32f4: stm32f401rc-rs485: Add sdcard support +* [#11217](https://github.com/apache/nuttx/pull/11217) stm32f4: stm32f401rc-rs485: Add buttons support +* [#11169](https://github.com/apache/nuttx/pull/11169) stm32f4: stm32f401rc-rs485: add support to userleds +* [#11255](https://github.com/apache/nuttx/pull/11255) stm32f4: stm32f401rc-rs485: Fix f401rc flash size +risc-v +* [#10736](https://github.com/apache/nuttx/pull/10736) esp32c3: pm: Let PM_PROCFS depend on FS_PROCFS_REGISTER +* [#11418](https://github.com/apache/nuttx/pull/11418) esp32c6: Add ostest defconfig +* [#11096](https://github.com/apache/nuttx/pull/11096) mpfs: Add option for board specific PMP configuration +* [#11262](https://github.com/apache/nuttx/pull/11262) qemu-rv: rv-virt/knsh: Set correct RAM_START and RAM_SIZE +* [#11397](https://github.com/apache/nuttx/pull/11397) qemu-rv: Virtio sound +sim +* [#10960](https://github.com/apache/nuttx/pull/10960) fix Cygwin/MSYS2 ld: unrecognized option '-z' +* [#11290](https://github.com/apache/nuttx/pull/11290) nxscope: remove CONFIG_ALLSYMS=y +xtensa +* [#11142](https://github.com/apache/nuttx/pull/11142) esp32: Add LVGL defconfig +* [#11229](https://github.com/apache/nuttx/pull/11229) esp32: Add support enconder to ESP32-2432S028 +* [#10961](https://github.com/apache/nuttx/pull/10961) esp32: Add wifishare board config and documentation +* [#10996](https://github.com/apache/nuttx/pull/10996) esp32: Rename Shift game to Brickmatch and add an board example to esp32-devkitc +* [#11417](https://github.com/apache/nuttx/pull/11417) esp32<|s2|s3>_board_spiflash: Fix error message about SmartFS init +* [#11425](https://github.com/apache/nuttx/pull/11425) esp32s2: Increase init task stack size to 3072 +* [#11156](https://github.com/apache/nuttx/pull/11156) esp32s3: Link stack checking function and data to SRAM when enable flash or PSRAM driver +* [#11342](https://github.com/apache/nuttx/pull/11342) esp32s3: add esp32s3-devkit:toywasm kconfig +* [#11295](https://github.com/apache/nuttx/pull/11295) esp32s3: Add rtc defconfig +* [#10885](https://github.com/apache/nuttx/pull/10885) ESP32S3-EYE: GPIO and button support +* [#10884](https://github.com/apache/nuttx/pull/10884) ESP32-S3-EYE: I2C, SPI and LCD support +* [#10883](https://github.com/apache/nuttx/pull/10883) ESP32-S3-EYE: Wifi +File System +Improvements +* [#10995](https://github.com/apache/nuttx/pull/10995) Change inode_checkflags to static function +* [#11445](https://github.com/apache/nuttx/pull/11445) Fix hostfs after uid/gid changes +* [#11433](https://github.com/apache/nuttx/pull/11433) fat: Fix number of data clusters usable for fat driver +* [#11196](https://github.com/apache/nuttx/pull/11196) fat: fix ubsan warning of shift-out-of-bounds +* [#10706](https://github.com/apache/nuttx/pull/10706) fs_epoll: several epoll problems fix +* [#11125](https://github.com/apache/nuttx/pull/11125) fs_files.c: make sure that fs_getfilep is not interrupted when holding mutex +* [#11349](https://github.com/apache/nuttx/pull/11349) fs_gettype:add zipfs magic +* [#11446](https://github.com/apache/nuttx/pull/11446) hostfs:fix structure layout inconsistency in hostfs +* [#11090](https://github.com/apache/nuttx/pull/11090) inode: Change inode_unlink to static function +* [#11188](https://github.com/apache/nuttx/pull/11188) inode: check file list before memcpy +* [#11140](https://github.com/apache/nuttx/pull/11140) inode: improve the performance of get file pointer +* [#11318](https://github.com/apache/nuttx/pull/11318) proc: Fix groupfd to get fd by group instead of current tcb +* [#11449](https://github.com/apache/nuttx/pull/11449) procfs add poll support +* [#11360](https://github.com/apache/nuttx/pull/11360) procfs/cpuinfo: Zero copylen in cpuinfo_read +* [#11039](https://github.com/apache/nuttx/pull/11039) rename: fix use after free issue about rename +* [#11451](https://github.com/apache/nuttx/pull/11451) smartfs: Add necessary aligned access in smartfs_rename() +* [#11248](https://github.com/apache/nuttx/pull/11248) spiffs: correct mutex lock cycle of spiffs +* [#10804](https://github.com/apache/nuttx/pull/10804) support zipfs,can mount zipfile +* [#11232](https://github.com/apache/nuttx/pull/11232) tmpfs: fix an integer overflow +* [#10880](https://github.com/apache/nuttx/pull/10880) vfs: add munmap logic to pseudofs + +Networking +Improvements +* [#10813](https://github.com/apache/nuttx/pull/10813) Add CONFIG_NET_ICMPv6_ROUTER_LIFETIME +* [#10893](https://github.com/apache/nuttx/pull/10893) allow icmpv6 and udp to find the dev by the ifindex with s_boundto. +* [#10916](https://github.com/apache/nuttx/pull/10916) Fix RNDIS compilation error +* [#10819](https://github.com/apache/nuttx/pull/10819) local: Fix the problem that local udp socketpair cannot release fifo files. +* [#11443](https://github.com/apache/nuttx/pull/11443) local: make the call return of each process consistent with linux +* [#11015](https://github.com/apache/nuttx/pull/11015) local: Support SO_SNDBUF option in getsockopt +* [#11289](https://github.com/apache/nuttx/pull/11289) loopback: Fix flags of lo device +* [#11324](https://github.com/apache/nuttx/pull/11324) icmpv6:Optimize the process of obtaining the IPv6 address through RA. +* [#11010](https://github.com/apache/nuttx/pull/11010) icmpv6: Fix net mask logic in icmpv6_setaddresses +* [#11197](https://github.com/apache/nuttx/pull/11197) igmp: call IFF_SET_IPv4 when igmp_send +* [#11384](https://github.com/apache/nuttx/pull/11384) ipv6: Fix source address with many addresses in same network +* [#11378](https://github.com/apache/nuttx/pull/11378) ipv6: Move xxx_ipv6multicast from arch to common code +* [#10894](https://github.com/apache/nuttx/pull/10894) netdb: When set a dns nameserver which already exists, retrun OK +* [#11076](https://github.com/apache/nuttx/pull/11076) netconfig: Enable SOCK_CLOEXEC for ioctl sockets +* [#11396](https://github.com/apache/nuttx/pull/11396) netdev: Modify the logic for setting the IFF_RUNNING status of interfaces. +* [#11110](https://github.com/apache/nuttx/pull/11110) Simplify getting value for different domain +* [#11054](https://github.com/apache/nuttx/pull/11054) Support multiple IPv6 address per netdev +* [#11406](https://github.com/apache/nuttx/pull/11406) tcp: Recover from iob shortage with TCP_WRITE_BUFFERS +* [#11126](https://github.com/apache/nuttx/pull/11126) tcp: Support initial sequence number described in RFC 6528 +* [#11009](https://github.com/apache/nuttx/pull/11009) tun: Fix the error of calling tun_close when tun_txavail or tun_txavail_work is executed +* [#10986](https://github.com/apache/nuttx/pull/10986) tun: Fix the error of calling tun_close when tun_txavail or tun_txavail_work is executed +* [#11372](https://github.com/apache/nuttx/pull/11372) udp: Add check when sending too big packet without IP frag +* [#11210](https://github.com/apache/nuttx/pull/11210) udp: Add support for SO_TIMESTAMP +* [#11120](https://github.com/apache/nuttx/pull/11120) udp: modify ipv4 multicast to allow different conn to join simultaneously +* [#10878](https://github.com/apache/nuttx/pull/10878) usersock: Return -ENOSUPP directly if domain isn't equal to PF_INET/PF_INET6 +Security Issues Fixed In This Release +Compatibility Concerns +* [#10605](https://github.com/apache/nuttx/pull/10605)  Implement ticket spinlock + +A proposal to slove #1488 + +Implement ticket spinlock. + + +* [#10861](https://github.com/apache/nuttx/pull/10861) spinlock: Add spin_lock_init and spin_is_locked macro + +align with Linux api naming. + + +* [#11102](https://github.com/apache/nuttx/pull/11102) sched: explicitly select the cpuload clock source configuration + +Different configurations require different dependencies. +Explicitly select dependencies to avoid automatically selecting +inappropriate configurations. + +* [#11334](https://github.com/apache/nuttx/pull/11334) stm32h7_adc: Dynamically set clock prescaler and BOOST + +First commit is aligning naming and is a breaking change. + +* [#10827](https://github.com/apache/nuttx/pull/10827) Improve adjtime() functionality + +Prior pull request #9084 and issue #8858 added basic adjtime() +support for the SAMv7 platform. + +This pull request adds support for STM32 platform. + +In addition I have made a few changes to the adjtime() configuration +options: + +1) Previously adjustments less than 1 microsecond per tick would be +   completely ignored. Now they are applied over a shorter period at +   a rate of 1 us per tick. + +2) Previously CLOCK_ADJTIME_PERIOD was in units of 1/100th of second. +   Change to milliseconds to be more generally useful unit. +   Change setting name to CLOCK_ADJTIME_PERIOD_MS to make the unit change +   easier to notice. + +3) Previously CLOCK_ADJTIME_SLEWLIMIT was in percentage. +   Most clock crystals have better accuracy than 1%, so the minimum slew +   rate was excessive. Change to CLOCK_ADJTIME_SLEWLIMIT_PPM with setting +   value in parts per million. + +4) No need to use floating point math in clock_adjtime.c. + +Impact + +Users who have used CLOCK_ADJTIME_PERIOD and CLOCK_ADJTIME_SLEWLIMIT  +settings should update their configuration. New CLOCK_ADJTIME_PERIOD_MS is +10x the old period value, and new CLOCK_ADJTIME_SLEWLIMIT_PPM is 10000 times +the old slewlimit. \ No newline at end of file diff --git a/Documentation/platforms/arm64/imx9/boards/imx93-evk/README.txt b/Documentation/platforms/arm64/imx9/boards/imx93-evk/README.txt new file mode 100644 index 0000000000000..1a377d76f0f0d --- /dev/null +++ b/Documentation/platforms/arm64/imx9/boards/imx93-evk/README.txt @@ -0,0 +1,145 @@ +README.txt +========== + +The kit i.MX93 Evaluation Kit has a pre-installed Linux image which contains +u-boot and the i.MX93 reference Linux installation. + +u-boot is required to boot NuttX (for now) as it initializes the hardware for +us, i.e. DDR, clocks, I/O muxes etc. + +========================================== + +How to run nuttx on i.MX93 Evaluation Kit. + +========================================== + +Below is a set of instructions on how to run NuttX on the i.MX93 EVK + +========================================== + +Pre-requisites + +========================================== + +- imx93_ca55.JLinkScript which is a custom file, put it wherever you want + +========================================== + +U-Boot configuration + +========================================== + +Two things need to be configured on u-boot before NuttX can be loaded: + +- u-boot data cache must be turned off +- u-boot must stop to the u-boot console, i.e. the Linux payload must not be loaded + +Manual option: + +1. Disable u-boot autostart (needs to be done only once): + + Hit any key to stop autoboot: 0 + u-boot=> setenv bootdelay -1 + u-boot=> saveenv + Saving Environment to MMC... Writing to MMC(0)... OK + u-boot=> reset + +2. On every boot, the data cache must be disabled for options 2 and 3 to work + + u-boot=> dcache off + +Automated option: + +1. Replace the default bootcmd to disable dcache automatically: + + u-boot=> setenv bootcmd dcache off + u-boot=> saveenv + Saving Environment to MMC... Writing to MMC(0)... OK + u-boot=> reset + +To restore the default bootcmd which starts Linux automatically: + + u-boot=> setenv bootcmd run distro_bootcmd;run bsp_bootcmd + u-boot=> saveenv + Saving Environment to MMC... Writing to MMC(0)... OK + u-boot=> reset + +The default bootcmd is: + +u-boot=> env print bootcmd +bootcmd=run distro_bootcmd;run bsp_bootcmd + +========================================== + +Loading and running the NuttX image + +========================================== + +You have three options: + +1 - Load via u-boot from SD-card +2 - Load via gdb +3 - Load via JLink + +========================================== + +Option 1: load via u-boot from SD-card: + +========================================== + +1. Build nuttx, and move nuttx.bin to SD-card + +2. Load from SD-card and start nuttx payload + + u-boot=> dcache off; fatload mmc 1 0x80000000 nuttx.bin; go 0x80000000 + +========================================== + +Option 2: start via gdb: + +========================================== + +1. Start JLinkGDBServer + + JLinkGDBServer -device CORTEX-A55 -JLinkScriptFile /imx93_ca55.JLinkScript + +2. Start gdb + + $ aarch64-none-elf-gdb + + 2.1 Attach and load nuttx + + (gdb) target remote localhost:2331 + (gdb) set mem inaccessible-by-default off + (gdb) load /nuttx + (gdb) monitor go + +========================================== + +Option 3: load with JLink: + +========================================== + +1. Start JLink + + $ JLinkExe -device CORTEX-A55 -if JTAG -jtagconf -1,-1 -speed 4000 -JLinkScriptFile /imx93_ca55.JLinkScript + + 1.1 Add -AutoConnect 1 to connect automatically + + $ JLinkExe -device CORTEX-A55 -if JTAG -jtagconf -1,-1 -speed 4000 -JLinkScriptFile /imx93_ca55.JLinkScript -AutoConnect 1 + +2. Connect JLink + + 2.1 Connect to the debugger + + Type "connect" to establish a target connection, '?' for help + J-Link>connect + + You should now have a JLink prompt. + + Cortex-A55 identified. + J-Link> + +3. Load nuttx. Note that JLink expects the .elf extension, the default build output of nuttx is just "nuttx" without the extension, so it must be added to the file... + + J-Link>LoadFile /nuttx.elf diff --git a/Documentation/platforms/arm64/imx9/boards/imx93-evk/index.rst b/Documentation/platforms/arm64/imx9/boards/imx93-evk/index.rst new file mode 100644 index 0000000000000..97ed448898f19 --- /dev/null +++ b/Documentation/platforms/arm64/imx9/boards/imx93-evk/index.rst @@ -0,0 +1,6 @@ +========== +imx93-evk +========== + +.. include:: README.txt + :literal: diff --git a/Documentation/platforms/arm64/imx9/index.rst b/Documentation/platforms/arm64/imx9/index.rst new file mode 100644 index 0000000000000..4b1e5b7412014 --- /dev/null +++ b/Documentation/platforms/arm64/imx9/index.rst @@ -0,0 +1,12 @@ +========= +NXP i.MX9 +========= + +Supported Boards +================ + +.. toctree:: + :glob: + :maxdepth: 1 + + boards/*/* diff --git a/arch/arm/src/armv7-a/CMakeLists.txt b/arch/arm/src/armv7-a/CMakeLists.txt index 543cc6e235616..72c05b46f053c 100644 --- a/arch/arm/src/armv7-a/CMakeLists.txt +++ b/arch/arm/src/armv7-a/CMakeLists.txt @@ -75,8 +75,14 @@ else() endif() if(CONFIG_ARCH_ADDRENV) - list(APPEND SRCS arm_addrenv.c arm_addrenv_utils.c arm_addrenv_perms.c - arm_pgalloc.c) + list( + APPEND + SRCS + arm_addrenv.c + arm_addrenv_utils.c + arm_addrenv_perms.c + arm_pgalloc.c + arm_addrenv_pgmap.c) if(CONFIG_ARCH_STACK_DYNAMIC) list(APPEND SRCS arm_addrenv_ustack.c) endif() diff --git a/arch/arm/src/armv7-a/Make.defs b/arch/arm/src/armv7-a/Make.defs index 6ea56bba38849..3bdcd77a86d6b 100644 --- a/arch/arm/src/armv7-a/Make.defs +++ b/arch/arm/src/armv7-a/Make.defs @@ -66,6 +66,7 @@ endif ifeq ($(CONFIG_ARCH_ADDRENV),y) CMN_CSRCS += arm_addrenv.c arm_addrenv_utils.c arm_addrenv_perms.c arm_pgalloc.c + CMN_CSRCS += arm_addrenv_pgmap.c ifeq ($(CONFIG_ARCH_STACK_DYNAMIC),y) CMN_CSRCS += arm_addrenv_ustack.c endif diff --git a/arch/arm/src/armv7-a/arm_addrenv_pgmap.c b/arch/arm/src/armv7-a/arm_addrenv_pgmap.c new file mode 100644 index 0000000000000..3ced8813fecbd --- /dev/null +++ b/arch/arm/src/armv7-a/arm_addrenv_pgmap.c @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/arm/src/armv7-a/arm_addrenv_pgmap.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "pgalloc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_addrenv_page_vaddr + * + * Description: + * Find the kernel virtual address associated with physical page. + * + * Input Parameters: + * page - The page physical address. + * + * Returned Value: + * Page kernel virtual address on success; NULL on failure. + * + ****************************************************************************/ + +uintptr_t up_addrenv_page_vaddr(uintptr_t page) +{ + return arm_pgvaddr(page); +} + +/**************************************************************************** + * Name: up_addrenv_page_wipe + * + * Description: + * Wipe a page of physical memory, first mapping it into kernel virtual + * memory. + * + * Input Parameters: + * page - The page physical address. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void up_addrenv_page_wipe(uintptr_t page) +{ + uintptr_t vaddr = arm_pgvaddr(page); + memset((void *)vaddr, 0, MM_PGSIZE); +} diff --git a/arch/arm/src/imxrt/imxrt_enet.c b/arch/arm/src/imxrt/imxrt_enet.c index df8a72489c835..e4c8889ceb4d0 100644 --- a/arch/arm/src/imxrt/imxrt_enet.c +++ b/arch/arm/src/imxrt/imxrt_enet.c @@ -200,6 +200,8 @@ # error "Need at least one RX buffer" #endif +#define nitems(_a) (sizeof(_a) / sizeof(0[(_a)])) + /* From ref manual TDSR/RDSR description * For optimal performance the pointer should be 512-bit aligned, that is, * evenly divisible by 64. @@ -250,8 +252,25 @@ * ...and further PHY descriptions here. */ -#if defined(CONFIG_ETH0_PHY_KSZ8081) -# define BOARD_PHY_NAME "KSZ8081" +#if defined(CONFIG_ETH0_PHY_MULTI) +# if !defined(BOARD_ETH0_PHY_LIST) +# error "CONFIG_ETH0_PHY_MULTI requires board.h to define BOARD_ETH0_PHY_LIST!" +# endif +# define BOARD_PHY_NAME g_board_phys[priv->current_phy].name +# define BOARD_PHYID1 g_board_phys[priv->current_phy].id1 +# define BOARD_PHYID2 g_board_phys[priv->current_phy].id2 +# define BOARD_PHY_STATUS g_board_phys[priv->current_phy].status +# define BOARD_PHY_ADDR priv->current_phy_address +# define BOARD_PHY_10BASET(s) (imxrt_phy_status(priv, (s), g_board_phys[priv->current_phy].mbps10) != 0) +# define BOARD_PHY_100BASET(s) (imxrt_phy_status(priv, (s), g_board_phys[priv->current_phy].mbps100) != 0) +# define BOARD_PHY_ISDUPLEX(s) (imxrt_phy_status(priv, (s), g_board_phys[priv->current_phy].duplex) != 0) +# define BOARD_PHY_ISCLAUSE45() (g_board_phys[priv->current_phy].clause == 45) +# define CLAUSE45 +# define MMD1 1 +# define MMD1_PMA_STATUS1 1 +# define MMD1_PS1_RECEIVE_LINK_STATUS (1 << 2) +#elif defined(CONFIG_ETH0_PHY_KSZ8081) +# define BOARD_PHY_NAME MII_KSZ8081_NAME # define BOARD_PHYID1 MII_PHYID1_KSZ8081 # define BOARD_PHYID2 MII_PHYID2_KSZ8081 # define BOARD_PHY_STATUS MII_KSZ8081_PHYCTRL1 @@ -260,7 +279,7 @@ # define BOARD_PHY_100BASET(s) (((s) & MII_PHYCTRL1_MODE_100HDX) != 0) # define BOARD_PHY_ISDUPLEX(s) (((s) & MII_PHYCTRL1_MODE_DUPLEX) != 0) #elif defined(CONFIG_ETH0_PHY_LAN8720) -# define BOARD_PHY_NAME "LAN8720" +# define BOARD_PHY_NAME MII_LAN8720_NAME # define BOARD_PHYID1 MII_PHYID1_LAN8720 # define BOARD_PHYID2 MII_PHYID2_LAN8720 # define BOARD_PHY_STATUS MII_LAN8720_SCSR @@ -269,7 +288,7 @@ # define BOARD_PHY_100BASET(s) (((s)&MII_LAN8720_SPSCR_100MBPS) != 0) # define BOARD_PHY_ISDUPLEX(s) (((s)&MII_LAN8720_SPSCR_DUPLEX) != 0) #elif defined(CONFIG_ETH0_PHY_LAN8742A) -# define BOARD_PHY_NAME "LAN8742A" +# define BOARD_PHY_NAME MII_LAN8742A_NAME # define BOARD_PHYID1 MII_PHYID1_LAN8742A # define BOARD_PHYID2 MII_PHYID2_LAN8742A # define BOARD_PHY_STATUS MII_LAN8740_SCSR @@ -278,7 +297,7 @@ # define BOARD_PHY_100BASET(s) (((s)&MII_LAN8720_SPSCR_100MBPS) != 0) # define BOARD_PHY_ISDUPLEX(s) (((s)&MII_LAN8720_SPSCR_DUPLEX) != 0) #elif defined(CONFIG_ETH0_PHY_DP83825I) -# define BOARD_PHY_NAME "DP83825I" +# define BOARD_PHY_NAME MII_DP83825I_NAME # define BOARD_PHYID1 MII_PHYID1_DP83825I # define BOARD_PHYID2 MII_PHYID2_DP83825I # define BOARD_PHY_STATUS MII_DP83825I_PHYSTS @@ -287,7 +306,7 @@ # define BOARD_PHY_100BASET(s) (((s) & MII_DP83825I_PHYSTS_SPEED) == 0) # define BOARD_PHY_ISDUPLEX(s) (((s) & MII_DP83825I_PHYSTS_DUPLEX) != 0) #elif defined(CONFIG_ETH0_PHY_TJA1103) -# define BOARD_PHY_NAME "TJA1103" +# define BOARD_PHY_NAME MII_TJA1103_NAME # define BOARD_PHYID1 MII_PHYID1_TJA1103 # define BOARD_PHYID2 MII_PHYID2_TJA1103 # define BOARD_PHY_STATUS MII_TJA110X_BSR @@ -300,7 +319,7 @@ # define MMD1_PMA_STATUS1 1 # define MMD1_PS1_RECEIVE_LINK_STATUS (1 << 2) #elif defined(CONFIG_ETH0_PHY_YT8512) -# define BOARD_PHY_NAME "YT8512" +# define BOARD_PHY_NAME MII_YT8512_NAME # define BOARD_PHYID1 MII_PHYID1_YT8512 # define BOARD_PHYID2 MII_PHYID2_YT8512 # define BOARD_PHY_STATUS MII_YT8512_PHYSTS @@ -375,6 +394,10 @@ struct imxrt_driver_s struct enet_desc_s *txdesc; /* A pointer to the list of TX descriptor */ struct enet_desc_s *rxdesc; /* A pointer to the list of RX descriptors */ +#if defined(CONFIG_ETH0_PHY_MULTI) + uint8_t current_phy; /* The index of the PHY being used */ + uint8_t current_phy_address; /* The address of the PHY being used */ +#endif /* This holds the information visible to the NuttX network */ struct net_driver_s dev; /* Interface understood by the network */ @@ -384,6 +407,15 @@ struct imxrt_driver_s * Private Data ****************************************************************************/ +/* BOARD_ETH0_PHY_LIST provided by the board.h for CONFIG_ETH0_PHY_MULTI */ + +#if defined(CONFIG_ETH0_PHY_MULTI) +const struct phy_desc_s g_board_phys[] = + { + BOARD_ETH0_PHY_LIST + }; +#endif + static struct imxrt_driver_s g_enet[CONFIG_IMXRT_ENET_NETHIFS]; /* The DMA descriptors */ @@ -470,6 +502,13 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, /* PHY/MII support */ +#if defined(CONFIG_ETH0_PHY_MULTI) +static int imxrt_phy_is(struct imxrt_driver_s *priv, const char *name); +static int imxrt_phy_status(struct imxrt_driver_s *priv, int phydata, + uint16_t mask); +static int imxrt_determine_phy(struct imxrt_driver_s *priv); +#endif + #if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) static int imxrt_phyintenable(struct imxrt_driver_s *priv); #endif @@ -1377,6 +1416,15 @@ static int imxrt_ifup_action(struct net_driver_s *dev, bool resetphy) /* Configure the PHY */ +#if defined(CONFIG_ETH0_PHY_MULTI) + ret = imxrt_determine_phy(priv); + if (ret < 0) + { + nerr("ERROR: Failed to determine the PHY: %d\n", ret); + return ret; + } +#endif + ret = imxrt_initphy(priv, resetphy); if (ret < 0) { @@ -1872,7 +1920,11 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) struct mii_ioctl_data_s *req = (struct mii_ioctl_data_s *)((uintptr_t)arg); #if defined(CLAUSE45) - if (MII_MSR == req->reg_num) + if ( +# if defined(CONFIG_ETH0_PHY_MULTI) + BOARD_PHY_ISCLAUSE45() && +# endif + MII_MSR == req->reg_num) { ret = imxrt_readmmd(priv, req->phy_id, MMD1, MMD1_PMA_STATUS1, &req->val_out); @@ -1926,46 +1978,60 @@ static int imxrt_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) #if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) static int imxrt_phyintenable(struct imxrt_driver_s *priv) { +#if defined(CONFIG_ETH0_PHY_KSZ8051) || defined(CONFIG_ETH0_PHY_KSZ8061) || \ + defined(CONFIG_ETH0_PHY_KSZ8081) || defined(CONFIG_ETH0_PHY_DP83825I) || \ + defined(CONFIG_ETH0_YT8512) || defined(CONFIG_ETH0_PHY_MULTI) + uint16_t phyval; int ret; -#if defined(CONFIG_ETH0_PHY_KSZ8051) || defined(CONFIG_ETH0_PHY_KSZ8061) || \ - defined(CONFIG_ETH0_PHY_KSZ8081) || defined(CONFIG_ETH0_PHY_DP83825I) + /* Compile time Kzxxxx defaults */ - /* Read the interrupt status register in order to clear any pending - * interrupts - */ + uint16_t mask = MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN; + uint8_t rreg = MII_KSZ8081_INT; + uint8_t wreg = rreg; - ret = imxrt_readmii(priv, priv->phyaddr, MII_KSZ8081_INT, &phyval); - if (ret == OK) - { - /* Enable link up/down interrupts */ + /* Compile time YT8512 defaults */ +# if defined(CONFIG_ETH0_YT8512) + mask = MII_YT8512_IMR_LD_EN | MII_YT8512_IMR_LU_EN; + rreg = MII_YT8512_ISR; + wreg = MII_YT8512_IMR; +# endif - ret = imxrt_writemii(priv, priv->phyaddr, MII_KSZ8081_INT, - (MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN)); + /* Run time YT8512 defaults */ +# if defined(CONFIG_ETH0_PHY_MULTI) + if (imxrt_phy_is(priv, MII_YT8512_NAME)) + { + mask = MII_YT8512_IMR_LD_EN | MII_YT8512_IMR_LU_EN; + rreg = MII_YT8512_ISR; + wreg = MII_YT8512_IMR; } - - return ret; -#elif defined(CONFIG_ETH0_YT8512) + else if (!(imxrt_phy_is(priv, MII_KSZ8051_NAME) || + imxrt_phy_is(priv, MII_KSZ8061_NAME) || + imxrt_phy_is(priv, MII_KSZ8081_NAME) || + imxrt_phy_is(priv, MII_DP83825I_NAME))) + { + return -ENOSYS; + } +# endif /* Read the interrupt status register in order to clear any pending * interrupts */ - ret = imxrt_readmii(priv, priv->phyaddr, MII_YT8512_ISR, &phyval); + ret = imxrt_readmii(priv, priv->phyaddr, rreg, &phyval); if (ret == OK) { /* Enable link up/down interrupts */ - ret = imxrt_writemii(priv, priv->phyaddr, MII_YT8512_IMR, - (MII_YT8512_IMR_LD_EN | MII_YT8512_IMR_LU_EN)); + ret = imxrt_writemii(priv, priv->phyaddr, wreg, mask); } return ret; #else # error Unrecognized PHY return -ENOSYS; -#endif +# endif } #endif @@ -2121,6 +2187,126 @@ static int imxrt_readmii(struct imxrt_driver_s *priv, uint8_t phyaddr, return OK; } +#if defined(CONFIG_ETH0_PHY_MULTI) +/**************************************************************************** + * Function: imxrt_determine_phy + * + * Description: + * Uses the board.h supplied PHY list to determine which PHY + * is populated on this board. + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * + * Returned Value: + * Zero on success, a -ENOENT errno value on failure. + * + ****************************************************************************/ + +static int imxrt_determine_phy(struct imxrt_driver_s *priv) +{ + uint16_t phydata = 0xffff; + uint8_t phyaddr = 0; + uint8_t last_phyaddr = 0; + int retries; + int ret; + + for (priv->current_phy = 0; priv->current_phy < nitems(g_board_phys); + priv->current_phy++) + { + priv->current_phy_address = + (uint8_t) g_board_phys[priv->current_phy].address_lo; + last_phyaddr = g_board_phys[priv->current_phy].address_high == 0xffff ? + priv->current_phy_address : + (uint8_t) g_board_phys[priv->current_phy].address_high; + + for (phyaddr = priv->current_phy_address; phyaddr <= last_phyaddr; + phyaddr++) + { + retries = 0; + do + { + nxsig_usleep(100); + phydata = 0xffff; + ret = imxrt_readmii(priv, phyaddr, MII_PHYID1, &phydata); + } + while ((ret < 0 || phydata == 0xffff) && ++retries < 3); + + if (retries <= 3 && ret == 0 && + phydata == g_board_phys[priv->current_phy].id1) + { + do + { + nxsig_usleep(100); + phydata = 0xffff; + ret = imxrt_readmii(priv, phyaddr, MII_PHYID2, &phydata); + } + while ((ret < 0 || phydata == 0xffff) && ++retries < 3); + if (retries <= 3 && ret == 0 && + (phydata & 0xfff0) == + (g_board_phys[priv->current_phy].id2 & 0xfff0)) + { + return OK; + } + } + } + } + + return -ENOENT; +} + +/**************************************************************************** + * Function: imxrt_phy_is + * + * Description: + * Compares the name with the current selected PHY's name + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * name - a pointer to comapre to. + * + * Returned Value: + * 1 on match, a 0 on no match. + * + ****************************************************************************/ + +static int imxrt_phy_is(struct imxrt_driver_s *priv, const char *name) +{ + return strcmp(g_board_phys[priv->current_phy].name, name) == 0; +} + +/**************************************************************************** + * Function: imxrt_phy_status + * + * Description: + * Compares the name with the current selected PHY's name. + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * phydata - last read phy data - may be ignored if there is no + * status register defined by the current PHY. + * mask - A value to and with phydata if a status register is + * defined. Or the value retunred if no status register is + * defined. + * + * Returned Value: + * mask or (phydat & mask) + * + ****************************************************************************/ + +static int imxrt_phy_status(struct imxrt_driver_s *priv, int phydata, + uint16_t mask) +{ + int rv = mask; + if (g_board_phys[priv->current_phy].status != 0xffff) + { + rv &= phydata; + } + + return rv; +} +#endif + #if 0 #if defined(CLAUSE45) /**************************************************************************** @@ -2416,213 +2602,265 @@ static inline int imxrt_initphy(struct imxrt_driver_s *priv, bool renogphy) return -ENXIO; } -#ifdef CONFIG_ETH0_PHY_KSZ8081 - /* Reset PHY */ +#if defined(CONFIG_ETH0_PHY_KSZ8081) || defined(CONFIG_ETH0_PHY_MULTI) +# if defined(CONFIG_ETH0_PHY_MULTI) + if (imxrt_phy_is(priv, MII_KSZ8081_NAME)) + { +# endif + /* Reset PHY */ - imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET); + imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET); - /* Set RMII mode */ + /* Set RMII mode */ - ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata); - if (ret < 0) - { - nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n"); - return ret; - } + ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata); + if (ret < 0) + { + nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n"); + return ret; + } - /* Indicate 50MHz clock */ + /* Indicate 50MHz clock */ - imxrt_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, - (phydata | (1 << 7))); + imxrt_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, + (phydata | (1 << 7))); - /* Switch off NAND Tree mode (in case it was set via pinning) */ + /* Switch off NAND Tree mode (in case it was set via pinning) */ - ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_OMSO, &phydata); - if (ret < 0) - { - nerr("ERROR: Failed to read MII_KSZ8081_OMSO: %d\n", ret); - return ret; - } + ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_OMSO, &phydata); + if (ret < 0) + { + nerr("ERROR: Failed to read MII_KSZ8081_OMSO: %d\n", ret); + return ret; + } - imxrt_writemii(priv, phyaddr, MII_KSZ8081_OMSO, - (phydata & ~(1 << 5))); + imxrt_writemii(priv, phyaddr, MII_KSZ8081_OMSO, + (phydata & ~(1 << 5))); - /* Set Ethernet led to green = activity and yellow = link and */ + /* Set Ethernet led to green = activity and yellow = link and */ - ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata); - if (ret < 0) - { - nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n"); - return ret; + ret = imxrt_readmii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, &phydata); + if (ret < 0) + { + nerr("ERROR: Failed to read MII_KSZ8081_PHYCTRL2\n"); + return ret; + } + + imxrt_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, + (phydata | (1 << 4))); + + imxrt_writemii(priv, phyaddr, MII_ADVERTISE, + MII_ADVERTISE_100BASETXFULL | + MII_ADVERTISE_100BASETXHALF | + MII_ADVERTISE_10BASETXFULL | + MII_ADVERTISE_10BASETXHALF | + MII_ADVERTISE_CSMA); +# if defined(CONFIG_ETH0_PHY_MULTI) } - imxrt_writemii(priv, phyaddr, MII_KSZ8081_PHYCTRL2, - (phydata | (1 << 4))); +# endif +#endif +#if defined (CONFIG_ETH0_PHY_LAN8720) || \ + defined (CONFIG_ETH0_PHY_LAN8742A) || \ + defined (CONFIG_ETH0_PHY_MULTI) - imxrt_writemii(priv, phyaddr, MII_ADVERTISE, - MII_ADVERTISE_100BASETXFULL | - MII_ADVERTISE_100BASETXHALF | - MII_ADVERTISE_10BASETXFULL | - MII_ADVERTISE_10BASETXHALF | - MII_ADVERTISE_CSMA); +# if defined(CONFIG_ETH0_PHY_MULTI) + if (imxrt_phy_is(priv, MII_LAN8720_NAME) || + imxrt_phy_is(priv, MII_LAN8742A_NAME)) + { +# endif -#elif defined (CONFIG_ETH0_PHY_LAN8720) || defined (CONFIG_ETH0_PHY_LAN8742A) - /* Make sure that PHY comes up in correct mode when it's reset */ + /* Make sure that PHY comes up in correct mode when it's reset */ - imxrt_writemii(priv, phyaddr, MII_LAN8720_MODES, - MII_LAN8720_MODES_RESV | MII_LAN8720_MODES_ALL | - MII_LAN8720_MODES_PHYAD(BOARD_PHY_ADDR)); + imxrt_writemii(priv, phyaddr, MII_LAN8720_MODES, + MII_LAN8720_MODES_RESV | MII_LAN8720_MODES_ALL | + MII_LAN8720_MODES_PHYAD(BOARD_PHY_ADDR)); - /* ...and reset PHY */ + /* ...and reset PHY */ - imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET); + imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET); -#elif defined (CONFIG_ETH0_PHY_DP83825I) +# if defined(CONFIG_ETH0_PHY_MULTI) + } +# endif +#endif +#if defined (CONFIG_ETH0_PHY_DP83825I) || defined (CONFIG_ETH0_PHY_MULTI) - /* Reset PHY */ +#if defined(CONFIG_ETH0_PHY_MULTI) + if (imxrt_phy_is(priv, MII_DP83825I_NAME)) + { +#endif - imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET); + /* Reset PHY */ - /* Set RMII mode and Indicate 50MHz clock */ + imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET); - imxrt_writemii(priv, phyaddr, MII_DP83825I_RCSR, - MII_DP83825I_RCSC_ELAST_2 | MII_DP83825I_RCSC_RMIICS); + /* Set RMII mode and Indicate 50MHz clock */ - imxrt_writemii(priv, phyaddr, MII_ADVERTISE, - MII_ADVERTISE_100BASETXFULL | - MII_ADVERTISE_100BASETXHALF | - MII_ADVERTISE_10BASETXFULL | - MII_ADVERTISE_10BASETXHALF | - MII_ADVERTISE_CSMA); + imxrt_writemii(priv, phyaddr, MII_DP83825I_RCSR, + MII_DP83825I_RCSC_ELAST_2 | + MII_DP83825I_RCSC_RMIICS); -#elif defined (CONFIG_ETH0_PHY_YT8512) + imxrt_writemii(priv, phyaddr, MII_ADVERTISE, + MII_ADVERTISE_100BASETXFULL | + MII_ADVERTISE_100BASETXHALF | + MII_ADVERTISE_10BASETXFULL | + MII_ADVERTISE_10BASETXHALF | + MII_ADVERTISE_CSMA); - /* Reset PHY */ +# if defined(CONFIG_ETH0_PHY_MULTI) + } +# endif +#endif - imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET); +#if defined(CONFIG_ETH0_PHY_YT8512) || defined(CONFIG_ETH0_PHY_MULTI) +# if defined(CONFIG_ETH0_PHY_MULTI) + if (!imxrt_phy_is(priv, MII_YT8512_NAME)) + { +# endif + /* Reset PHY */ + + imxrt_writemii(priv, phyaddr, MII_MCR, MII_MCR_RESET); - /* Config LEDs */ + /* Config LEDs */ - imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET, - MII_YT8512_LED0); + imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET, + MII_YT8512_LED0); - imxrt_readmii(priv, phyaddr, MII_YT8512_DEBUG_DATA, &phydata); + imxrt_readmii(priv, phyaddr, MII_YT8512_DEBUG_DATA, &phydata); - imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET, - MII_YT8512_LED0); + imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET, + MII_YT8512_LED0); - imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_DATA, 0x331); + imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_DATA, 0x331); - imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET, - MII_YT8512_LED1); + imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET, + MII_YT8512_LED1); - imxrt_readmii(priv, phyaddr, MII_YT8512_DEBUG_DATA, &phydata); + imxrt_readmii(priv, phyaddr, MII_YT8512_DEBUG_DATA, &phydata); - imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET, - MII_YT8512_LED1); + imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_ADDR_OFFSET, + MII_YT8512_LED1); - imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_DATA, 0x30); + imxrt_writemii(priv, phyaddr, MII_YT8512_DEBUG_DATA, 0x30); - /* Set negotiation */ + /* Set negotiation */ - imxrt_writemii(priv, phyaddr, MII_ADVERTISE, - MII_ADVERTISE_100BASETXFULL | - MII_ADVERTISE_100BASETXHALF | - MII_ADVERTISE_10BASETXFULL | - MII_ADVERTISE_10BASETXHALF | - MII_ADVERTISE_CSMA); + imxrt_writemii(priv, phyaddr, MII_ADVERTISE, + MII_ADVERTISE_100BASETXFULL | + MII_ADVERTISE_100BASETXHALF | + MII_ADVERTISE_10BASETXFULL | + MII_ADVERTISE_10BASETXHALF | + MII_ADVERTISE_CSMA); +# if defined(CONFIG_ETH0_PHY_MULTI) + } +# endif #endif -#if !defined(CONFIG_ETH0_PHY_TJA1103) - /* Start auto negotiation */ +#if !defined(CONFIG_ETH0_PHY_TJA1103) +#if defined(CONFIG_ETH0_PHY_MULTI) + if (!imxrt_phy_is(priv, MII_TJA1103_NAME)) + { +#endif + /* Start auto negotiation */ - ninfo("%s: Start Autonegotiation...\n", BOARD_PHY_NAME); - imxrt_writemii(priv, phyaddr, MII_MCR, - (MII_MCR_ANRESTART | MII_MCR_ANENABLE)); + ninfo("%s: Start Autonegotiation...\n", BOARD_PHY_NAME); + imxrt_writemii(priv, phyaddr, MII_MCR, + (MII_MCR_ANRESTART | MII_MCR_ANENABLE)); - /* Wait for auto negotiation to complete */ + /* Wait for auto negotiation to complete */ - for (retries = 0; retries < LINK_NLOOPS; retries++) - { - ret = imxrt_readmii(priv, phyaddr, MII_MSR, &phydata); - if (ret < 0) + for (retries = 0; retries < LINK_NLOOPS; retries++) { - nerr("ERROR: Failed to read %s MII_MSR: %d\n", - BOARD_PHY_NAME, ret); - return ret; + ret = imxrt_readmii(priv, phyaddr, MII_MSR, &phydata); + if (ret < 0) + { + nerr("ERROR: Failed to read %s MII_MSR: %d\n", + BOARD_PHY_NAME, ret); + return ret; + } + + if (phydata & MII_MSR_ANEGCOMPLETE) + { + break; + } + + nxsig_usleep(LINK_WAITUS); } if (phydata & MII_MSR_ANEGCOMPLETE) { - break; + ninfo("%s: Autonegotiation complete\n", BOARD_PHY_NAME); + ninfo("%s: MII_MSR: %04x\n", BOARD_PHY_NAME, phydata); } + else + { + /* TODO: Autonegotiation has right now failed. Maybe the Eth + * cable is not connected. PHY chip have mechanisms to + * configure link OK. We should leave autconf on, and find a + * way to re-configure MCU whenever the link is ready. + */ - nxsig_usleep(LINK_WAITUS); - } - - if (phydata & MII_MSR_ANEGCOMPLETE) - { - ninfo("%s: Autonegotiation complete\n", BOARD_PHY_NAME); - ninfo("%s: MII_MSR: %04x\n", BOARD_PHY_NAME, phydata); - } - else - { - /* TODO: Autonegotiation has right now failed. Maybe the Eth cable - * is not connected. PHY chip have mechanisms to configure link - * OK. We should leave autconf on, and find a way to re-configure - * MCU whenever the link is ready. - */ - - ninfo("%s: Autonegotiation failed [%d] (is cable plugged-in ?), " - "default to 10Mbs mode\n", \ - BOARD_PHY_NAME, retries); + ninfo("%s: Autonegotiation failed [%d] (is cable plugged-in ?)" + ", default to 10Mbs mode\n", + BOARD_PHY_NAME, retries); - /* Stop auto negotiation */ + /* Stop auto negotiation */ - imxrt_writemii(priv, phyaddr, MII_MCR, 0); + imxrt_writemii(priv, phyaddr, MII_MCR, 0); + } +# if defined(CONFIG_ETH0_PHY_MULTI) } +# endif #endif } #if !defined(CONFIG_ETH0_PHY_TJA1103) - /* When we get here we have a (negotiated) speed and duplex. This is also - * the point we enter if renegotiation is turned off, so have multiple - * attempts at reading the status register in case the PHY isn't awake - * properly. - */ - - retries = 0; - do +# if defined(CONFIG_ETH0_PHY_MULTI) + if (!imxrt_phy_is(priv, MII_TJA1103_NAME)) { - phydata = 0xffff; - ret = imxrt_readmii(priv, phyaddr, BOARD_PHY_STATUS, &phydata); - } - while ((ret < 0 || phydata == 0xffff) && ++retries < 3); - - /* If we didn't successfully read anything and we haven't tried a physical - * renegotiation then lets do that - */ +# endif + /* When we get here we have a (negotiated) speed and duplex. This + * is also the point we enter if renegotiation is turned off, so have + * multiple attempts at reading the status register in case the PHY + * isn't awake properly. + */ - if (retries >= 3) - { - if (renogphy == false) + retries = 0; + do { - /* Give things one more chance with renegotiation turned on */ - - return imxrt_initphy(priv, true); + phydata = 0xffff; + ret = imxrt_readmii(priv, phyaddr, BOARD_PHY_STATUS, &phydata); } - else + while ((ret < 0 || phydata == 0xffff) && ++retries < 3); + + /* If we didn't successfully read anything and we haven't tried + * a physical renegotiation then lets do that + */ + + if (retries >= 3) { - /* That didn't end well, just give up */ + if (renogphy == false) + { + /* Give things one more chance with renegotiation turned on */ - nerr("ERROR: Failed to read %s BOARD_PHY_STATUS[%02x]: %d\n", - BOARD_PHY_NAME, BOARD_PHY_STATUS, ret); - return ret; + return imxrt_initphy(priv, true); + } + else + { + /* That didn't end well, just give up */ + + nerr("ERROR: Failed to read %s BOARD_PHY_STATUS[%02x]: %d\n", + BOARD_PHY_NAME, BOARD_PHY_STATUS, ret); + return ret; + } } - } - ninfo("%s: BOARD_PHY_STATUS: %04x\n", BOARD_PHY_NAME, phydata); + ninfo("%s: BOARD_PHY_STATUS: %04x\n", BOARD_PHY_NAME, phydata); +# if defined(CONFIG_ETH0_PHY_MULTI) + } +# endif #endif /* Set up the transmit and receive control registers based on the diff --git a/arch/arm/src/imxrt/imxrt_start.c b/arch/arm/src/imxrt/imxrt_start.c index cc51d70e4ebac..107e03dae1879 100644 --- a/arch/arm/src/imxrt/imxrt_start.c +++ b/arch/arm/src/imxrt/imxrt_start.c @@ -149,11 +149,16 @@ void __start(void) const register uint32_t *src; register uint32_t *dest; - /* Make sure that interrupts are disabled and set SP */ + /* Make sure that interrupts are disabled and set MSP */ __asm__ __volatile__ ("\tcpsid i\n"); __asm__ __volatile__ ("MSR MSP, %0\n" : : "r" (IDLE_STACK) :); + /* Make sure that we use MSP from now on */ + + __asm__ __volatile__ ("MSR CONTROL, %0\n" : : "r" (0) :); + __asm__ __volatile__ ("ISB SY\n"); + /* Make sure VECTAB is set to NuttX vector table * and not the one from the boot ROM and have consistency * with debugger that automatically set the VECTAB diff --git a/arch/arm/src/stm32f7/stm32_ethernet.c b/arch/arm/src/stm32f7/stm32_ethernet.c index 9771561a20d9d..c4ba77579a0e2 100644 --- a/arch/arm/src/stm32f7/stm32_ethernet.c +++ b/arch/arm/src/stm32f7/stm32_ethernet.c @@ -3132,7 +3132,9 @@ static inline int stm32_dm9161(struct stm32_ethmac_s *priv) static int stm32_phyinit(struct stm32_ethmac_s *priv) { +#ifdef CONFIG_STM32F7_AUTONEG volatile uint32_t timeout; +#endif uint32_t regval; uint16_t phyval; int ret; diff --git a/arch/arm/src/stm32f7/stm32_foc.c b/arch/arm/src/stm32f7/stm32_foc.c index f644bd370ead1..0e6cdfa0ae93a 100644 --- a/arch/arm/src/stm32f7/stm32_foc.c +++ b/arch/arm/src/stm32f7/stm32_foc.c @@ -718,6 +718,7 @@ static struct foc_lower_ops_s g_stm32_foc_ops = .start = stm32_foc_start, .pwm_duty_set = stm32_foc_pwm_duty_set, .pwm_off = stm32_foc_pwm_off, + .info_get = stm32_foc_info_get, .ioctl = stm32_foc_ioctl, .bind = stm32_foc_bind, .fault_clear = stm32_foc_fault_clear, diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index a37e03aa694ba..30ccf1bde1760 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -91,6 +91,15 @@ config ARCH_CHIP_IMX8 ---help--- NXP i.MX8 (ARMv8a) applications processors +config ARCH_CHIP_IMX9 + bool "NXP i.MX9 Platform (ARMv8.2a)" + select ARCH_HAVE_ADDRENV + select ARCH_HAVE_I2CRESET + select ARCH_HAVE_IRQTRIGGER + select ARCH_NEED_ADDRENV_MAPPING + ---help--- + NXP i.MX9 (ARMv8.2a) applications processors + config ARCH_CHIP_ARM64_CUSTOM bool "Custom ARM64 chip" select ARCH_CHIP_CUSTOM @@ -137,6 +146,15 @@ config ARCH_HAVE_EL3 runing at EL3 is not necessary and system register for EL3 is not accessible +config ARCH_ARM64_EXCEPTION_LEVEL + int "Exception level to operate" + default 1 + range 1 3 + ---help--- + Default exception level is EL1 for the NuttX OS. However, + if NuttX works as the primary bootloader, this may be set + to EL3. Other levels are not supported at the moment. + config ARCH_SET_VMPIDR_EL2 bool "Set VMPIDR_EL2 at EL2 stage" ---help--- @@ -181,6 +199,18 @@ config ARCH_CORTEX_A53 select ARCH_HAVE_TESTSET select ARM_HAVE_NEON +config ARCH_CORTEX_A55 + bool + default n + select ARCH_ARMV8A + select ARCH_HAVE_TRUSTZONE + select ARCH_DCACHE + select ARCH_ICACHE + select ARCH_HAVE_MMU + select ARCH_HAVE_FPU + select ARCH_HAVE_TESTSET + select ARM_HAVE_NEON + config ARCH_CORTEX_A57 bool default n @@ -229,6 +259,7 @@ config ARCH_CHIP default "goldfish" if ARCH_CHIP_GOLDFISH default "fvp-v8r" if ARCH_CHIP_FVP_ARMV8R default "imx8" if ARCH_CHIP_IMX8 + default "imx9" if ARCH_CHIP_IMX9 config ARM_HAVE_NEON bool @@ -311,6 +342,10 @@ if ARCH_CHIP_IMX8 source "arch/arm64/src/imx8/Kconfig" endif +if ARCH_CHIP_IMX9 +source "arch/arm64/src/imx9/Kconfig" +endif + if ARCH_CHIP_GOLDFISH source "arch/arm64/src/goldfish/Kconfig" endif diff --git a/arch/arm64/include/imx9/chip.h b/arch/arm64/include/imx9/chip.h new file mode 100644 index 0000000000000..ddb9a58e7eefa --- /dev/null +++ b/arch/arm64/include/imx9/chip.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * arch/arm64/include/imx9/chip.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_INCLUDE_IMX9_CHIP_H +#define __ARCH_ARM64_INCLUDE_IMX9_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Cache line sizes (in bytes)for the i.MX9 (Cortex-A55) */ + +#define ARMV8A_DCACHE_LINESIZE 64 /* 64 bytes (16 words) */ +#define ARMV8A_ICACHE_LINESIZE 64 /* 64 bytes (16 words) */ + +/* Number of bytes in x kibibytes/mebibytes/gibibytes */ + +#define KB(x) ((x) << 10) +#define MB(x) (KB(x) << 10) +#define GB(x) (MB(UINT64_C(x)) << 10) + +#if defined(CONFIG_ARCH_CHIP_IMX93) + +#if CONFIG_ARM_GIC_VERSION == 3 || CONFIG_ARM_GIC_VERSION == 4 + +#define CONFIG_GICD_BASE 0x48000000 +#define CONFIG_GICR_BASE 0x48040000 +#define CONFIG_GICR_OFFSET 0x20000 + +#else + +#error CONFIG_ARM_GIC_VERSION should be 2, 3 or 4 + +#endif /* CONFIG_ARM_GIC_VERSION */ + +#define CONFIG_RAMBANK1_ADDR 0x80000000 +#define CONFIG_RAMBANK1_SIZE MB(128) + +#define CONFIG_DEVICEIO_BASEADDR 0x40000000 +#define CONFIG_DEVICEIO_SIZE MB(512) + +#define MPID_TO_CLUSTER_ID(mpid) ((mpid) & ~0xff) + +#define IMX9_GPIO_NPORTS 4 + +#endif + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +#ifdef __ASSEMBLY__ + +.macro get_cpu_id xreg0 + mrs \xreg0, mpidr_el1 + ubfx \xreg0, \xreg0, #0, #8 +.endm + +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM64_INCLUDE_IMX9_CHIP_H */ diff --git a/arch/arm64/include/imx9/imx93_irq.h b/arch/arm64/include/imx9/imx93_irq.h new file mode 100644 index 0000000000000..010a1b3e25e20 --- /dev/null +++ b/arch/arm64/include/imx9/imx93_irq.h @@ -0,0 +1,298 @@ +/**************************************************************************** + * arch/arm64/include/imx9/imx93_irq.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_INCLUDE_IMX9_IMX93_IRQ_H +#define __ARCH_ARM64_INCLUDE_IMX9_IMX93_IRQ_H + +#define IMX9_IRQ_RESERVED32 (IMX9_IRQ_EXT + 0) /* Exception condition notification while boot */ +#define IMX9_IRQ_RESERVED33 (IMX9_IRQ_EXT + 1) /* DAP interrupt */ +#define IMX9_IRQ_RESERVED34 (IMX9_IRQ_EXT + 2) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED35 (IMX9_IRQ_EXT + 3) /* CTI trigger outputs from CM33 platform */ +#define IMX9_IRQ_RESERVED36 (IMX9_IRQ_EXT + 4) /* CTI trigger outputs from CA55 platform */ +#define IMX9_IRQ_RESERVED37 (IMX9_IRQ_EXT + 5) /* Performance Unit Interrupts from CA55 platform */ +#define IMX9_IRQ_RESERVED38 (IMX9_IRQ_EXT + 6) /* ECC error from CA55 platform cache */ +#define IMX9_IRQ_RESERVED39 (IMX9_IRQ_EXT + 7) /* 1-bit or 2-bit ECC or Parity error from CA55 platform cache */ +#define IMX9_IRQ_CAN1 (IMX9_IRQ_EXT + 8) /* CAN1 interrupt */ +#define IMX9_IRQ_CAN1_ERROR (IMX9_IRQ_EXT + 9) /* CAN1 error interrupt */ +#define IMX9_IRQ_GPIO1_0 (IMX9_IRQ_EXT + 10) /* General Purpose Input/Output 1 interrupt 0 */ +#define IMX9_IRQ_GPIO1_1 (IMX9_IRQ_EXT + 11) /* General Purpose Input/Output 1 interrupt 1 */ +#define IMX9_IRQ_I3C1 (IMX9_IRQ_EXT + 12) /* Improved Inter-Integrated Circuit 1 interrupt */ +#define IMX9_IRQ_LPI2C1 (IMX9_IRQ_EXT + 13) /* Low Power Inter-Integrated Circuit module 1 */ +#define IMX9_IRQ_LPI2C2 (IMX9_IRQ_EXT + 14) /* Low Power Inter-Integrated Circuit module 2 */ +#define IMX9_IRQ_LPIT1 (IMX9_IRQ_EXT + 15) /* Low Power Periodic Interrupt Timer 1 */ +#define IMX9_IRQ_LPSPI1 (IMX9_IRQ_EXT + 16) /* Low Power Serial Peripheral Interface 1 */ +#define IMX9_IRQ_LPSPI2 (IMX9_IRQ_EXT + 17) /* Low Power Serial Peripheral Interface 2 */ +#define IMX9_IRQ_LPTMR1 (IMX9_IRQ_EXT + 18) /* Low Power Timer 1 */ +#define IMX9_IRQ_LPUART1 (IMX9_IRQ_EXT + 19) /* Low Power UART 1 */ +#define IMX9_IRQ_LPUART2 (IMX9_IRQ_EXT + 20) /* Low Power UART 2 */ +#define IMX9_IRQ_MU1_A (IMX9_IRQ_EXT + 21) /* Messaging Unit 1 - Side A (to communicate with M7 core) */ +#define IMX9_IRQ_MU1_B (IMX9_IRQ_EXT + 22) /* Messaging Unit 1 - Side B (to communicate with M33 core) */ +#define IMX9_IRQ_MU2_A (IMX9_IRQ_EXT + 23) /* Messaging Unit 2 - Side A (to communicate with M7 core) */ +#define IMX9_IRQ_MU2_B (IMX9_IRQ_EXT + 24) /* Messaging Unit 2 - Side B (to communicate with A55 core) */ +#define IMX9_IRQ_RESERVED57 (IMX9_IRQ_EXT + 25) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED58 (IMX9_IRQ_EXT + 26) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED59 (IMX9_IRQ_EXT + 27) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED60 (IMX9_IRQ_EXT + 28) /* Edgelock Trust MUA RX full interrupt */ +#define IMX9_IRQ_RESERVED61 (IMX9_IRQ_EXT + 29) /* Edgelock Trust MUA TX empty interrupt */ +#define IMX9_IRQ_RESERVED62 (IMX9_IRQ_EXT + 30) /* Edgelock Apps Core MUA RX full interrupt */ +#define IMX9_IRQ_RESERVED63 (IMX9_IRQ_EXT + 31) /* Edgelock Apps Core MUA TX empty interrupt */ +#define IMX9_IRQ_RESERVED64 (IMX9_IRQ_EXT + 32) /* Edgelock Realtime Core MUA RX full interrupt */ +#define IMX9_IRQ_RESERVED65 (IMX9_IRQ_EXT + 33) /* Edgelock Realtime Core MUA TX empty interrupt */ +#define IMX9_IRQ_RESERVED66 (IMX9_IRQ_EXT + 34) /* Edgelock secure interrupt */ +#define IMX9_IRQ_RESERVED67 (IMX9_IRQ_EXT + 35) /* Edgelock non-secure interrupt */ +#define IMX9_IRQ_TPM1 (IMX9_IRQ_EXT + 36) /* Timer PWM module 1 */ +#define IMX9_IRQ_TPM2 (IMX9_IRQ_EXT + 37) /* Timer PWM module 2 */ +#define IMX9_IRQ_WDOG1 (IMX9_IRQ_EXT + 38) /* Watchdog 1 Interrupt */ +#define IMX9_IRQ_WDOG2 (IMX9_IRQ_EXT + 39) /* Watchdog 2 Interrupt */ +#define IMX9_IRQ_TRDC (IMX9_IRQ_EXT + 40) /* AONMIX TRDC transfer error interrupt */ +#define IMX9_IRQ_RESERVED73 (IMX9_IRQ_EXT + 41) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED74 (IMX9_IRQ_EXT + 42) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED75 (IMX9_IRQ_EXT + 43) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED76 (IMX9_IRQ_EXT + 44) /* Reserved interrupt */ +#define IMX9_IRQ_SAI1 (IMX9_IRQ_EXT + 45) /* Serial Audio Interface 1 */ +#define IMX9_IRQ_RESERVED78 (IMX9_IRQ_EXT + 46) /* M33 PS Tag/Data Parity Error */ +#define IMX9_IRQ_RESERVED79 (IMX9_IRQ_EXT + 47) /* M33 TCM ECC interrupt */ +#define IMX9_IRQ_RESERVED80 (IMX9_IRQ_EXT + 48) /* M33 TCM Error interrupt */ +#define IMX9_IRQ_RESERVED81 (IMX9_IRQ_EXT + 49) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED82 (IMX9_IRQ_EXT + 50) /* Reserved interrupt */ +#define IMX9_IRQ_CAN2 (IMX9_IRQ_EXT + 51) /* CAN2 interrupt */ +#define IMX9_IRQ_CAN2_ERROR (IMX9_IRQ_EXT + 52) /* CAN2 error interrupt */ +#define IMX9_IRQ_FLEXIO1 (IMX9_IRQ_EXT + 53) /* Flexible IO 1 interrupt */ +#define IMX9_IRQ_FLEXIO2 (IMX9_IRQ_EXT + 54) /* Flexible IO 2 interrupt */ +#define IMX9_IRQ_FLEXSPI1 (IMX9_IRQ_EXT + 55) /* FlexSPI controller interface interrupt 1 */ +#define IMX9_IRQ_RESERVED88 (IMX9_IRQ_EXT + 56) /* Reserved interrupt */ +#define IMX9_IRQ_GPIO2_0 (IMX9_IRQ_EXT + 57) /* General Purpose Input/Output 2 interrupt 0 */ +#define IMX9_IRQ_GPIO2_1 (IMX9_IRQ_EXT + 58) /* General Purpose Input/Output 2 interrupt 1 */ +#define IMX9_IRQ_GPIO3_0 (IMX9_IRQ_EXT + 59) /* General Purpose Input/Output 3 interrupt 0 */ +#define IMX9_IRQ_GPIO3_1 (IMX9_IRQ_EXT + 60) /* General Purpose Input/Output 3 interrupt 1 */ +#define IMX9_IRQ_I3C2 (IMX9_IRQ_EXT + 61) /* Improved Inter-Integrated Circuit 2 interrupt */ +#define IMX9_IRQ_LPI2C3 (IMX9_IRQ_EXT + 62) /* Low Power Inter-Integrated Circuit module 3 */ +#define IMX9_IRQ_LPI2C4 (IMX9_IRQ_EXT + 63) /* Low Power Inter-Integrated Circuit module 4 */ +#define IMX9_IRQ_LPIT2 (IMX9_IRQ_EXT + 64) /* Low Power Periodic Interrupt Timer 2 */ +#define IMX9_IRQ_LPSPI3 (IMX9_IRQ_EXT + 65) /* Low Power Serial Peripheral Interface 3 */ +#define IMX9_IRQ_LPSPI4 (IMX9_IRQ_EXT + 66) /* Low Power Serial Peripheral Interface 4 */ +#define IMX9_IRQ_LPTMR2 (IMX9_IRQ_EXT + 67) /* Low Power Timer 2 */ +#define IMX9_IRQ_LPUART3 (IMX9_IRQ_EXT + 68) /* Low Power UART 3 */ +#define IMX9_IRQ_LPUART4 (IMX9_IRQ_EXT + 69) /* Low Power UART 4 */ +#define IMX9_IRQ_LPUART5 (IMX9_IRQ_EXT + 70) /* Low Power UART 5 */ +#define IMX9_IRQ_LPUART6 (IMX9_IRQ_EXT + 71) /* Low Power UART 6 */ +#define IMX9_IRQ_RESERVED104 (IMX9_IRQ_EXT + 72) /* MTR Master error interrupt */ +#define IMX9_IRQ_RESERVED105 (IMX9_IRQ_EXT + 73) /* BBNSM Non-Secure interrupt */ +#define IMX9_IRQ_RESERVED106 (IMX9_IRQ_EXT + 74) /* System Counter compare interrupt */ +#define IMX9_IRQ_TPM3 (IMX9_IRQ_EXT + 75) /* Timer PWM module 3 */ +#define IMX9_IRQ_TPM4 (IMX9_IRQ_EXT + 76) /* Timer PWM module 4 */ +#define IMX9_IRQ_TPM5 (IMX9_IRQ_EXT + 77) /* Timer PWM module 5 */ +#define IMX9_IRQ_TPM6 (IMX9_IRQ_EXT + 78) /* Timer PWM module 6 */ +#define IMX9_IRQ_WDOG3 (IMX9_IRQ_EXT + 79) /* Watchdog 3 Interrupt */ +#define IMX9_IRQ_WDOG4 (IMX9_IRQ_EXT + 80) /* Watchdog 4 Interrupt */ +#define IMX9_IRQ_WDOG5 (IMX9_IRQ_EXT + 81) /* Watchdog 5 Interrupt */ +#define IMX9_IRQ_RESERVED114 (IMX9_IRQ_EXT + 82) /* WAKEUPMIX TRDC transfer error interrupt */ +#define IMX9_IRQ_TEMPMON (IMX9_IRQ_EXT + 83) /* TempSensor interrupt */ +#define IMX9_IRQ_RESERVED116 (IMX9_IRQ_EXT + 84) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED117 (IMX9_IRQ_EXT + 85) /* Reserved interrupt */ +#define IMX9_IRQ_USDHC1 (IMX9_IRQ_EXT + 86) /* ultra Secure Digital Host Controller interrupt 1 */ +#define IMX9_IRQ_USDHC2 (IMX9_IRQ_EXT + 87) /* ultra Secure Digital Host Controller interrupt 2 */ +#define IMX9_IRQ_RESERVED120 (IMX9_IRQ_EXT + 88) /* MEGAMIX TRDC transfer error interrupt */ +#define IMX9_IRQ_RESERVED121 (IMX9_IRQ_EXT + 89) /* NIC_WRAPPER TRDC transfer error interrupt */ +#define IMX9_IRQ_RESERVED122 (IMX9_IRQ_EXT + 90) /* DRAM controller Performance Monitor Interrupt */ +#define IMX9_IRQ_RESERVED123 (IMX9_IRQ_EXT + 91) /* DRAM controller Critical Interrupt */ +#define IMX9_IRQ_RESERVED124 (IMX9_IRQ_EXT + 92) /* DRAM Phy Critical Interrupt */ +#define IMX9_IRQ_RESERVED125 (IMX9_IRQ_EXT + 93) /* Reserved interrupt */ +#define IMX9_IRQ_DMA3_ERROR (IMX9_IRQ_EXT + 94) /* eDMA1 error interrupt */ +#define IMX9_IRQ_DMA3_0 (IMX9_IRQ_EXT + 95) /* eDMA1 channel 0 interrupt */ +#define IMX9_IRQ_DMA3_1 (IMX9_IRQ_EXT + 96) /* eDMA1 channel 1 interrupt */ +#define IMX9_IRQ_DMA3_2 (IMX9_IRQ_EXT + 97) /* eDMA1 channel 2 interrupt */ +#define IMX9_IRQ_DMA3_3 (IMX9_IRQ_EXT + 98) /* eDMA1 channel 3 interrupt */ +#define IMX9_IRQ_DMA3_4 (IMX9_IRQ_EXT + 99) /* eDMA1 channel 4 interrupt */ +#define IMX9_IRQ_DMA3_5 (IMX9_IRQ_EXT + 100) /* eDMA1 channel 5 interrupt */ +#define IMX9_IRQ_DMA3_6 (IMX9_IRQ_EXT + 101) /* eDMA1 channel 6 interrupt */ +#define IMX9_IRQ_DMA3_7 (IMX9_IRQ_EXT + 102) /* eDMA1 channel 7 interrupt */ +#define IMX9_IRQ_DMA3_8 (IMX9_IRQ_EXT + 103) /* eDMA1 channel 8 interrupt */ +#define IMX9_IRQ_DMA3_9 (IMX9_IRQ_EXT + 104) /* eDMA1 channel 9 interrupt */ +#define IMX9_IRQ_DMA3_10 (IMX9_IRQ_EXT + 105) /* eDMA1 channel 10 interrupt */ +#define IMX9_IRQ_DMA3_11 (IMX9_IRQ_EXT + 106) /* eDMA1 channel 11 interrupt */ +#define IMX9_IRQ_DMA3_12 (IMX9_IRQ_EXT + 107) /* eDMA1 channel 12 interrupt */ +#define IMX9_IRQ_DMA3_13 (IMX9_IRQ_EXT + 108) /* eDMA1 channel 13 interrupt */ +#define IMX9_IRQ_DMA3_14 (IMX9_IRQ_EXT + 109) /* eDMA1 channel 14 interrupt */ +#define IMX9_IRQ_DMA3_15 (IMX9_IRQ_EXT + 110) /* eDMA1 channel 15 interrupt */ +#define IMX9_IRQ_DMA3_16 (IMX9_IRQ_EXT + 111) /* eDMA1 channel 16 interrupt */ +#define IMX9_IRQ_DMA3_17 (IMX9_IRQ_EXT + 112) /* eDMA1 channel 17 interrupt */ +#define IMX9_IRQ_DMA3_18 (IMX9_IRQ_EXT + 113) /* eDMA1 channel 18 interrupt */ +#define IMX9_IRQ_DMA3_19 (IMX9_IRQ_EXT + 114) /* eDMA1 channel 19 interrupt */ +#define IMX9_IRQ_DMA3_20 (IMX9_IRQ_EXT + 115) /* eDMA1 channel 20 interrupt */ +#define IMX9_IRQ_DMA3_21 (IMX9_IRQ_EXT + 116) /* eDMA1 channel 21 interrupt */ +#define IMX9_IRQ_DMA3_22 (IMX9_IRQ_EXT + 117) /* eDMA1 channel 22 interrupt */ +#define IMX9_IRQ_DMA3_23 (IMX9_IRQ_EXT + 118) /* eDMA1 channel 23 interrupt */ +#define IMX9_IRQ_DMA3_24 (IMX9_IRQ_EXT + 119) /* eDMA1 channel 24 interrupt */ +#define IMX9_IRQ_DMA3_25 (IMX9_IRQ_EXT + 120) /* eDMA1 channel 25 interrupt */ +#define IMX9_IRQ_DMA3_26 (IMX9_IRQ_EXT + 121) /* eDMA1 channel 26 interrupt */ +#define IMX9_IRQ_DMA3_27 (IMX9_IRQ_EXT + 122) /* eDMA1 channel 27 interrupt */ +#define IMX9_IRQ_DMA3_28 (IMX9_IRQ_EXT + 123) /* eDMA1 channel 28 interrupt */ +#define IMX9_IRQ_DMA3_29 (IMX9_IRQ_EXT + 124) /* eDMA1 channel 29 interrupt */ +#define IMX9_IRQ_DMA3_30 (IMX9_IRQ_EXT + 125) /* eDMA1 channel 30 interrupt */ +#define IMX9_IRQ_RESERVED158 (IMX9_IRQ_EXT + 126) /* Reserved interrupt */ +#define IMX9_IRQ_DMA4_ERROR (IMX9_IRQ_EXT + 127) /* eDMA2 error interrupt */ +#define IMX9_IRQ_DMA4_0_1 (IMX9_IRQ_EXT + 128) /* eDMA2 channel 0/1 interrupt */ +#define IMX9_IRQ_DMA4_2_3 (IMX9_IRQ_EXT + 129) /* eDMA2 channel 2/3 interrupt */ +#define IMX9_IRQ_DMA4_4_5 (IMX9_IRQ_EXT + 130) /* eDMA2 channel 4/5 interrupt */ +#define IMX9_IRQ_DMA4_6_7 (IMX9_IRQ_EXT + 131) /* eDMA2 channel 6/7 interrupt */ +#define IMX9_IRQ_DMA4_8_9 (IMX9_IRQ_EXT + 132) /* eDMA2 channel 8/9 interrupt */ +#define IMX9_IRQ_DMA4_10_11 (IMX9_IRQ_EXT + 133) /* eDMA2 channel 10/11 interrupt */ +#define IMX9_IRQ_DMA4_12_13 (IMX9_IRQ_EXT + 134) /* eDMA2 channel 12/13 interrupt */ +#define IMX9_IRQ_DMA4_14_15 (IMX9_IRQ_EXT + 135) /* eDMA2 channel 14/15 interrupt */ +#define IMX9_IRQ_DMA4_16_17 (IMX9_IRQ_EXT + 136) /* eDMA2 channel 16/17 interrupt */ +#define IMX9_IRQ_DMA4_18_19 (IMX9_IRQ_EXT + 137) /* eDMA2 channel 18/19 interrupt */ +#define IMX9_IRQ_DMA4_20_21 (IMX9_IRQ_EXT + 138) /* eDMA2 channel 20/21 interrupt */ +#define IMX9_IRQ_DMA4_22_23 (IMX9_IRQ_EXT + 139) /* eDMA2 channel 22/23 interrupt */ +#define IMX9_IRQ_DMA4_24_25 (IMX9_IRQ_EXT + 140) /* eDMA2 channel 24/25 interrupt */ +#define IMX9_IRQ_DMA4_26_27 (IMX9_IRQ_EXT + 141) /* eDMA2 channel 26/27 interrupt */ +#define IMX9_IRQ_DMA4_28_29 (IMX9_IRQ_EXT + 142) /* eDMA2 channel 28/29 interrupt */ +#define IMX9_IRQ_DMA4_30_31 (IMX9_IRQ_EXT + 143) /* eDMA2 channel 30/31 interrupt */ +#define IMX9_IRQ_DMA4_32_33 (IMX9_IRQ_EXT + 144) /* eDMA2 channel 32/33 interrupt */ +#define IMX9_IRQ_DMA4_34_35 (IMX9_IRQ_EXT + 145) /* eDMA2 channel 34/35 interrupt */ +#define IMX9_IRQ_DMA4_36_37 (IMX9_IRQ_EXT + 146) /* eDMA2 channel 36/37 interrupt */ +#define IMX9_IRQ_DMA4_38_39 (IMX9_IRQ_EXT + 147) /* eDMA2 channel 38/39 interrupt */ +#define IMX9_IRQ_DMA4_40_41 (IMX9_IRQ_EXT + 148) /* eDMA2 channel 40/41 interrupt */ +#define IMX9_IRQ_DMA4_42_43 (IMX9_IRQ_EXT + 149) /* eDMA2 channel 42/43 interrupt */ +#define IMX9_IRQ_DMA4_44_45 (IMX9_IRQ_EXT + 150) /* eDMA2 channel 44/45 interrupt */ +#define IMX9_IRQ_DMA4_46_47 (IMX9_IRQ_EXT + 151) /* eDMA2 channel 46/47 interrupt */ +#define IMX9_IRQ_DMA4_48_49 (IMX9_IRQ_EXT + 152) /* eDMA2 channel 48/49 interrupt */ +#define IMX9_IRQ_DMA4_50_51 (IMX9_IRQ_EXT + 153) /* eDMA2 channel 50/51 interrupt */ +#define IMX9_IRQ_DMA4_52_53 (IMX9_IRQ_EXT + 154) /* eDMA2 channel 52/53 interrupt */ +#define IMX9_IRQ_DMA4_54_55 (IMX9_IRQ_EXT + 155) /* eDMA2 channel 54/55 interrupt */ +#define IMX9_IRQ_DMA4_56_57 (IMX9_IRQ_EXT + 156) /* eDMA2 channel 56/57 interrupt */ +#define IMX9_IRQ_DMA4_58_59 (IMX9_IRQ_EXT + 157) /* eDMA2 channel 58/59 interrupt */ +#define IMX9_IRQ_DMA4_60_61 (IMX9_IRQ_EXT + 158) /* eDMA2 channel 60/61 interrupt */ +#define IMX9_IRQ_DMA4_62_63 (IMX9_IRQ_EXT + 159) /* eDMA2 channel 62/63 interrupt */ +#define IMX9_IRQ_RESERVED192 (IMX9_IRQ_EXT + 160) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED193 (IMX9_IRQ_EXT + 161) /* Edgelock Group 1 reset source */ +#define IMX9_IRQ_RESERVED194 (IMX9_IRQ_EXT + 162) /* Edgelock Group 2 reset source */ +#define IMX9_IRQ_RESERVED195 (IMX9_IRQ_EXT + 163) /* Edgelock Group 2 reset source */ +#define IMX9_IRQ_RESERVED196 (IMX9_IRQ_EXT + 164) /* JTAGSW DAP MDM-AP SRC reset source */ +#define IMX9_IRQ_RESERVED197 (IMX9_IRQ_EXT + 165) /* JTAGC SRC reset source */ +#define IMX9_IRQ_RESERVED198 (IMX9_IRQ_EXT + 166) /* CM33 SYSREQRST SRC reset source */ +#define IMX9_IRQ_RESERVED199 (IMX9_IRQ_EXT + 167) /* CM33 LOCKUP SRC reset source */ +#define IMX9_IRQ_RESERVED200 (IMX9_IRQ_EXT + 168) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED201 (IMX9_IRQ_EXT + 169) /* Reserved interrupt */ +#define IMX9_IRQ_SAI2 (IMX9_IRQ_EXT + 170) /* Serial Audio Interface 2 */ +#define IMX9_IRQ_SAI3 (IMX9_IRQ_EXT + 171) /* Serial Audio Interface 3 */ +#define IMX9_IRQ_ISI (IMX9_IRQ_EXT + 172) /* ISI interrupt */ +#define IMX9_IRQ_RESERVED205 (IMX9_IRQ_EXT + 173) /* PXP interrupt 0 */ +#define IMX9_IRQ_RESERVED206 (IMX9_IRQ_EXT + 174) /* PXP interrupt 1 */ +#define IMX9_IRQ_CSI (IMX9_IRQ_EXT + 175) /* CSI interrupt */ +#define IMX9_IRQ_RESERVED208 (IMX9_IRQ_EXT + 176) /* LCDIF Sync Interrupt */ +#define IMX9_IRQ_DSI (IMX9_IRQ_EXT + 177) /* MIPI DSI Interrupt Request */ +#define IMX9_IRQ_RESERVED210 (IMX9_IRQ_EXT + 178) /* Machine learning processor interrupt */ +#define IMX9_IRQ_ENET_MAC0_RX_TX_D ONE1 (IMX9_IRQ_EXT + 179) /* MAC 0 Receive/ Trasmit Frame/ Buffer Done */ +#define IMX9_IRQ_ENET_MAC0_RX_TX_D ONE2 (IMX9_IRQ_EXT + 180) /* MAC 0 Receive/ Trasmit Frame/ Buffer Done */ +#define IMX9_IRQ_ENET (IMX9_IRQ_EXT + 181) /* MAC 0 IRQ */ +#define IMX9_IRQ_ENET_1588 (IMX9_IRQ_EXT + 182) /* MAC 0 1588 Timer Interrupt - synchronous */ +#define IMX9_IRQ_ENET_QOS_PMT (IMX9_IRQ_EXT + 183) /* ENET QOS PMT interrupt */ +#define IMX9_IRQ_ENET_QOS (IMX9_IRQ_EXT + 184) /* ENET QOS interrupt */ +#define IMX9_IRQ_RESERVED217 (IMX9_IRQ_EXT + 185) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED218 (IMX9_IRQ_EXT + 186) /* Reserved interrupt */ +#define IMX9_IRQ_USB1 (IMX9_IRQ_EXT + 187) /* USB-1 Wake-up Interrupt */ +#define IMX9_IRQ_USB2 (IMX9_IRQ_EXT + 188) /* USB-2 Wake-up Interrupt */ +#define IMX9_IRQ_GPIO4_0 (IMX9_IRQ_EXT + 189) /* General Purpose Input/Output 4 interrupt 0 */ +#define IMX9_IRQ_GPIO4_1 (IMX9_IRQ_EXT + 190) /* General Purpose Input/Output 4 interrupt 1 */ +#define IMX9_IRQ_LPSPI5 (IMX9_IRQ_EXT + 191) /* Low Power Serial Peripheral Interface 5 */ +#define IMX9_IRQ_LPSPI6 (IMX9_IRQ_EXT + 192) /* Low Power Serial Peripheral Interface 6 */ +#define IMX9_IRQ_LPSPI7 (IMX9_IRQ_EXT + 193) /* Low Power Serial Peripheral Interface 7 */ +#define IMX9_IRQ_LPSPI8 (IMX9_IRQ_EXT + 194) /* Low Power Serial Peripheral Interface 8 */ +#define IMX9_IRQ_LPI2C5 (IMX9_IRQ_EXT + 195) /* Low Power Inter-Integrated Circuit module 5 */ +#define IMX9_IRQ_LPI2C6 (IMX9_IRQ_EXT + 196) /* Low Power Inter-Integrated Circuit module 6 */ +#define IMX9_IRQ_LPI2C7 (IMX9_IRQ_EXT + 197) /* Low Power Inter-Integrated Circuit module 7 */ +#define IMX9_IRQ_LPI2C8 (IMX9_IRQ_EXT + 198) /* Low Power Inter-Integrated Circuit module 8 */ +#define IMX9_IRQ_PDM_HWVAD_ERROR (IMX9_IRQ_EXT + 199) /* PDM interrupt */ +#define IMX9_IRQ_PDM_HWVAD_EVENT (IMX9_IRQ_EXT + 200) /* PDM interrupt */ +#define IMX9_IRQ_PDM_ERROR (IMX9_IRQ_EXT + 201) /* PDM interrupt */ +#define IMX9_IRQ_PDM_EVENT (IMX9_IRQ_EXT + 202) /* PDM interrupt */ +#define IMX9_IRQ_RESERVED235 (IMX9_IRQ_EXT + 203) /* AUDIO XCVR interrupt */ +#define IMX9_IRQ_RESERVED236 (IMX9_IRQ_EXT + 204) /* AUDIO XCVR interrupt */ +#define IMX9_IRQ_USDHC3 (IMX9_IRQ_EXT + 205) /* ultra Secure Digital Host Controller interrupt 3 */ +#define IMX9_IRQ_RESERVED238 (IMX9_IRQ_EXT + 206) /* OCRAM MECC interrupt */ +#define IMX9_IRQ_RESERVED239 (IMX9_IRQ_EXT + 207) /* OCRAM MECC interrupt */ +#define IMX9_IRQ_RESERVED240 (IMX9_IRQ_EXT + 208) /* HSIOMIX TRDC transfer error interrupt */ +#define IMX9_IRQ_RESERVED241 (IMX9_IRQ_EXT + 209) /* MEDIAMIX TRDC transfer error interrupt */ +#define IMX9_IRQ_LPUART7 (IMX9_IRQ_EXT + 210) /* Low Power UART 7 */ +#define IMX9_IRQ_LPUART8 (IMX9_IRQ_EXT + 211) /* Low Power UART 8 */ +#define IMX9_IRQ_RESERVED244 (IMX9_IRQ_EXT + 212) /* CM33 MCM interrupt */ +#define IMX9_IRQ_RESERVED245 (IMX9_IRQ_EXT + 213) /* SFA interrupt */ +#define IMX9_IRQ_RESERVED246 (IMX9_IRQ_EXT + 214) /* GIC600 INTERRUPT */ +#define IMX9_IRQ_RESERVED247 (IMX9_IRQ_EXT + 215) /* GIC600 INTERRUPT */ +#define IMX9_IRQ_RESERVED248 (IMX9_IRQ_EXT + 216) /* GIC600 INTERRUPT */ +#define IMX9_IRQ_RESERVED249 (IMX9_IRQ_EXT + 217) /* ADC interrupt */ +#define IMX9_IRQ_RESERVED250 (IMX9_IRQ_EXT + 218) /* ADC interrupt */ +#define IMX9_IRQ_RESERVED251 (IMX9_IRQ_EXT + 219) /* ADC interrupt */ +#define IMX9_IRQ_RESERVED252 (IMX9_IRQ_EXT + 220) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED253 (IMX9_IRQ_EXT + 221) /* I3C1 wakeup irq after double sync */ +#define IMX9_IRQ_RESERVED254 (IMX9_IRQ_EXT + 222) /* I3C2 wakeup irq after double sync */ +#define IMX9_IRQ_RESERVED255 (IMX9_IRQ_EXT + 223) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED256 (IMX9_IRQ_EXT + 224) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED257 (IMX9_IRQ_EXT + 225) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED258 (IMX9_IRQ_EXT + 226) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED259 (IMX9_IRQ_EXT + 227) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED260 (IMX9_IRQ_EXT + 228) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED261 (IMX9_IRQ_EXT + 229) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED262 (IMX9_IRQ_EXT + 230) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED263 (IMX9_IRQ_EXT + 231) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED264 (IMX9_IRQ_EXT + 232) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED265 (IMX9_IRQ_EXT + 233) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED266 (IMX9_IRQ_EXT + 234) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED267 (IMX9_IRQ_EXT + 235) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED268 (IMX9_IRQ_EXT + 236) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED269 (IMX9_IRQ_EXT + 237) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED270 (IMX9_IRQ_EXT + 238) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED271 (IMX9_IRQ_EXT + 239) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED272 (IMX9_IRQ_EXT + 240) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED273 (IMX9_IRQ_EXT + 241) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED274 (IMX9_IRQ_EXT + 242) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED275 (IMX9_IRQ_EXT + 243) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED276 (IMX9_IRQ_EXT + 244) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED277 (IMX9_IRQ_EXT + 245) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED278 (IMX9_IRQ_EXT + 246) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED279 (IMX9_IRQ_EXT + 247) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED280 (IMX9_IRQ_EXT + 248) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED281 (IMX9_IRQ_EXT + 249) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED282 (IMX9_IRQ_EXT + 250) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED283 (IMX9_IRQ_EXT + 251) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED284 (IMX9_IRQ_EXT + 252) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED285 (IMX9_IRQ_EXT + 253) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED286 (IMX9_IRQ_EXT + 254) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED287 (IMX9_IRQ_EXT + 255) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED288 (IMX9_IRQ_EXT + 256) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED289 (IMX9_IRQ_EXT + 257) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED290 (IMX9_IRQ_EXT + 258) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED291 (IMX9_IRQ_EXT + 259) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED292 (IMX9_IRQ_EXT + 260) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED293 (IMX9_IRQ_EXT + 261) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED294 (IMX9_IRQ_EXT + 262) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED295 (IMX9_IRQ_EXT + 263) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED296 (IMX9_IRQ_EXT + 264) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED297 (IMX9_IRQ_EXT + 265) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED298 (IMX9_IRQ_EXT + 266) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED299 (IMX9_IRQ_EXT + 267) /* Reserved interrupt */ +#define IMX9_IRQ_RESERVED300 (IMX9_IRQ_EXT + 268) /* ADC Asynchronous Interrupt */ + +/* Total amount of entries in system vector table */ + +#define NR_IRQS (301) + +#endif /* __ARCH_ARM64_INCLUDE_IMX9_IMX93_IRQ_H */ diff --git a/arch/arm64/include/imx9/irq.h b/arch/arm64/include/imx9/irq.h new file mode 100644 index 0000000000000..5e96f56a7957a --- /dev/null +++ b/arch/arm64/include/imx9/irq.h @@ -0,0 +1,70 @@ +/**************************************************************************** + * arch/arm64/include/imx9/irq.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This file should never be included directly but, rather, + * only indirectly through nuttx/irq.h + */ + +#ifndef __ARCH_ARM64_INCLUDE_IMX9_IRQ_H +#define __ARCH_ARM64_INCLUDE_IMX9_IRQ_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_IMX93) +# include +#else +# error "Unrecognized i.MX9 architecture" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IMX9_IRQ_SOFTWARE0 (0) /* Cortex-A55 Software Generated Interrupt 0 */ +#define IMX9_IRQ_SOFTWARE1 (1) /* Cortex-A55 Software Generated Interrupt 1 */ +#define IMX9_IRQ_SOFTWARE2 (2) /* Cortex-A55 Software Generated Interrupt 2 */ +#define IMX9_IRQ_SOFTWARE3 (3) /* Cortex-A55 Software Generated Interrupt 3 */ +#define IMX9_IRQ_SOFTWARE4 (4) /* Cortex-A55 Software Generated Interrupt 4 */ +#define IMX9_IRQ_SOFTWARE5 (5) /* Cortex-A55 Software Generated Interrupt 5 */ +#define IMX9_IRQ_SOFTWARE6 (6) /* Cortex-A55 Software Generated Interrupt 6 */ +#define IMX9_IRQ_SOFTWARE7 (7) /* Cortex-A55 Software Generated Interrupt 7 */ +#define IMX9_IRQ_SOFTWARE8 (8) /* Cortex-A55 Software Generated Interrupt 8 */ +#define IMX9_IRQ_SOFTWARE9 (9) /* Cortex-A55 Software Generated Interrupt 9 */ +#define IMX9_IRQ_SOFTWARE10 (10) /* Cortex-A55 Software Generated Interrupt 10 */ +#define IMX9_IRQ_SOFTWARE11 (11) /* Cortex-A55 Software Generated Interrupt 11 */ +#define IMX9_IRQ_SOFTWARE12 (12) /* Cortex-A55 Software Generated Interrupt 12 */ +#define IMX9_IRQ_SOFTWARE13 (13) /* Cortex-A55 Software Generated Interrupt 13 */ +#define IMX9_IRQ_SOFTWARE14 (14) /* Cortex-A55 Software Generated Interrupt 14 */ +#define IMX9_IRQ_SOFTWARE15 (15) /* Cortex-A55 Software Generated Interrupt 15 */ +#define IMX9_IRQ_VIRTUALMAINTENANCE (25) /* Cortex-A55 Virtual Maintenance Interrupt */ +#define IMX9_IRQ_HYPERVISORTIMER (26) /* Cortex-A55 Hypervisor Timer Interrupt */ +#define IMX9_IRQ_VIRTUALTIMER (27) /* Cortex-A55 Virtual Timer Interrupt */ +#define IMX9_IRQ_LEGACYFASTINT (28) /* Cortex-A55 Legacy nFIQ signal Interrupt */ +#define IMX9_IRQ_SECUREPHYTIMER (29) /* Cortex-A55 Secure Physical Timer Interrupt */ +#define IMX9_IRQ_NONSECUREPHYTIMER (30) /* Cortex-A55 Non-secure Physical Timer Interrupt */ +#define IMX9_IRQ_LEGACYIRQ (31) /* Cortex-A55 Legacy nIRQ Interrupt */ + +#define IMX9_IRQ_EXT (32) /* Vector number of the first ext int */ + +#endif /* __ARCH_ARM64_INCLUDE_IMX9_IRQ_H */ diff --git a/arch/arm64/src/Makefile b/arch/arm64/src/Makefile index fc1b4c9ffa053..efc08d9a76bd1 100644 --- a/arch/arm64/src/Makefile +++ b/arch/arm64/src/Makefile @@ -54,7 +54,7 @@ CSRCS = $(CHIP_CSRCS) $(CMN_CSRCS) COBJS = $(CSRCS:.c=$(OBJEXT)) SRCS = $(ASRCS) $(CSRCS) -OBJS = $(AOBJS) $(COBJS) +OBJS = $(AOBJS) $(COBJS) $(HEAD_OBJ) # User-mode objects diff --git a/arch/arm64/src/common/Make.defs b/arch/arm64/src/common/Make.defs index 9576ed59bb275..4bb12ec7eb457 100644 --- a/arch/arm64/src/common/Make.defs +++ b/arch/arm64/src/common/Make.defs @@ -54,6 +54,7 @@ CMN_CSRCS += arm64_perf.c arm64_tcbinfo.c CMN_CSRCS += arm64_arch_timer.c arm64_cache.c CMN_CSRCS += arm64_doirq.c arm64_fatal.c CMN_CSRCS += arm64_syscall.c +CMN_CSRCS += arm64_modifyreg8.c arm64_modifyreg16.c arm64_modifyreg32.c # Use common heap allocation for now (may need to be customized later) CMN_CSRCS += arm64_allocateheap.c diff --git a/arch/arm64/src/common/arm64_arch.h b/arch/arm64/src/common/arm64_arch.h index 789ebebff0c1c..36d155be85cee 100644 --- a/arch/arm64/src/common/arm64_arch.h +++ b/arch/arm64/src/common/arm64_arch.h @@ -118,6 +118,8 @@ #define SPSR_MODE_EL1H (0x5) #define SPSR_MODE_EL2T (0x8) #define SPSR_MODE_EL2H (0x9) +#define SPSR_MODE_EL3T (0xc) +#define SPSR_MODE_EL3H (0xd) #define SPSR_MODE_MASK (0xf) /* CurrentEL: Current Exception Level */ @@ -479,10 +481,18 @@ static inline void arch_nop(void) ::: "memory"); \ }) +/* Non-atomic modification of registers */ + #define modreg8(v,m,a) putreg8((getreg8(a) & ~(m)) | ((v) & (m)), (a)) #define modreg16(v,m,a) putreg16((getreg16(a) & ~(m)) | ((v) & (m)), (a)) #define modreg32(v,m,a) putreg32((getreg32(a) & ~(m)) | ((v) & (m)), (a)) +/* Atomic modification of registers */ + +void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits); +void modifyreg16(unsigned int addr, uint16_t clearbits, uint16_t setbits); +void modifyreg32(unsigned int addr, uint32_t clearbits, uint32_t setbits); + /**************************************************************************** * Name: * arch_get_exception_depth diff --git a/arch/arm64/src/common/arm64_boot.c b/arch/arm64/src/common/arm64_boot.c index 42df595307555..a82028857c370 100644 --- a/arch/arm64/src/common/arm64_boot.c +++ b/arch/arm64/src/common/arm64_boot.c @@ -78,6 +78,11 @@ void arm64_boot_el3_init(void) reg = 0U; /* Reset */ reg |= SCR_NS_BIT; /* EL2 / EL3 non-secure */ reg |= (SCR_RES1 | /* RES1 */ +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + SCR_IRQ_BIT | /* Route IRQs to EL3 */ + SCR_FIQ_BIT | /* Route FIQs to EL3 */ + SCR_EA_BIT | /* Route EAs to EL3 */ +#endif SCR_RW_BIT | /* EL2 execution state is AArch64 */ SCR_ST_BIT | /* Do not trap EL1 accesses to timer */ SCR_HCE_BIT | /* Do not trap HVC */ diff --git a/arch/arm64/src/common/arm64_copystate.c b/arch/arm64/src/common/arm64_copystate.c index 47ddd39568aa7..8f3716f915e20 100644 --- a/arch/arm64/src/common/arm64_copystate.c +++ b/arch/arm64/src/common/arm64_copystate.c @@ -60,13 +60,13 @@ int arch_save_fpucontext(void *saveregs) { irqstate_t flags; - uint64_t *p_save; + uintptr_t p_save; /* Take a snapshot of the thread context right now */ flags = enter_critical_section(); - p_save = saveregs + XCPTCONTEXT_GP_SIZE; + p_save = (uintptr_t)saveregs + XCPTCONTEXT_GP_SIZE; arm64_fpu_save((struct fpu_reg *)p_save); ARM64_DSB(); diff --git a/arch/arm64/src/common/arm64_fork.c b/arch/arm64/src/common/arm64_fork.c index aea3d570442d8..8398058b61467 100644 --- a/arch/arm64/src/common/arm64_fork.c +++ b/arch/arm64/src/common/arm64_fork.c @@ -225,7 +225,11 @@ pid_t arm64_fork(const struct fork_s *context) pforkctx->regs[REG_X28] = context->regs[FORK_REG_X28]; pforkctx->regs[REG_X29] = newfp; +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + pforkctx->spsr = SPSR_MODE_EL3H; +#else pforkctx->spsr = SPSR_MODE_EL1H; +#endif #ifdef CONFIG_SUPPRESS_INTERRUPTS pforkctx->spsr |= (DAIF_IRQ_BIT | DAIF_FIQ_BIT); diff --git a/arch/arm64/src/common/arm64_fpu.c b/arch/arm64/src/common/arm64_fpu.c index c8202b57a6243..69b458a9c524f 100644 --- a/arch/arm64/src/common/arm64_fpu.c +++ b/arch/arm64/src/common/arm64_fpu.c @@ -430,8 +430,10 @@ void arm64_fpu_disable(void) bool up_fpucmp(const void *saveregs1, const void *saveregs2) { - const uint64_t *regs1 = saveregs1 + XCPTCONTEXT_GP_SIZE; - const uint64_t *regs2 = saveregs2 + XCPTCONTEXT_GP_SIZE; + const uint64_t *regs1 = (uint64_t *)((uintptr_t)saveregs1 + + XCPTCONTEXT_GP_SIZE); + const uint64_t *regs2 = (uint64_t *)((uintptr_t)saveregs2 + + XCPTCONTEXT_GP_SIZE); /* Only compare callee-saved registers, caller-saved registers do not * need to be preserved. diff --git a/arch/arm64/src/common/arm64_gicv3.c b/arch/arm64/src/common/arm64_gicv3.c index f040b37aee803..28d91d02ed171 100644 --- a/arch/arm64/src/common/arm64_gicv3.c +++ b/arch/arm64/src/common/arm64_gicv3.c @@ -71,6 +71,9 @@ #define SMP_FUNC_CALL_IPI GIC_IRQ_SGI3 +#define PENDING_GRP1NS_INTID 1021 +#define SPURIOUS_INT 1023 + /*************************************************************************** * Private Data ***************************************************************************/ @@ -765,7 +768,7 @@ uint64_t * arm64_decodeirq(uint64_t * regs) * interrupt. */ - DEBUGASSERT(irq < NR_IRQS || irq == 1023); + DEBUGASSERT(irq < NR_IRQS || irq == SPURIOUS_INT); if (irq < NR_IRQS) { /* Dispatch the interrupt */ @@ -789,11 +792,33 @@ uint64_t * arm64_decodefiq(uint64_t * regs) irq = arm64_gic_get_active_fiq(); +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + /* FIQ is group0 interrupt */ + + if (irq == PENDING_GRP1NS_INTID) + { + /* irq 1021 indicates that the irq being acked is expected at EL1/EL2. + * However, EL3 has no interrupts, only FIQs, see: + * 'Arm® Generic Interrupt Controller, Architecture Specification GIC + * architecture version 3 and version 4' Arm IHI 0069G (ID011821) + * 'Table 4-3 Interrupt signals for two Security states when EL3 is + * using AArch64 state' + * + * Thus we know there's an interrupt so let's handle it from group1. + */ + + regs = arm64_decodeirq(regs); + arm64_gic_eoi_fiq(irq); + + return regs; + } +#endif + /* Ignore spurions IRQs. ICCIAR will report 1023 if there is no pending * interrupt. */ - DEBUGASSERT(irq < NR_IRQS || irq == 1023); + DEBUGASSERT(irq < NR_IRQS || irq == SPURIOUS_INT); if (irq < NR_IRQS) { /* Dispatch the interrupt */ diff --git a/arch/arm64/src/common/arm64_head.S b/arch/arm64/src/common/arm64_head.S index 18ea5c97ea72f..55a89ec06eaf4 100644 --- a/arch/arm64/src/common/arm64_head.S +++ b/arch/arm64/src/common/arm64_head.S @@ -89,6 +89,8 @@ label: .asciz msg; \ * This must be the very first address in the loaded image. * It should be loaded at any 4K-aligned address. */ + + .section .start, "ax" .globl __start; __start: @@ -233,6 +235,15 @@ switch_el: bl arm64_boot_el3_init +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + msr SPSel, #1 + + /* Set SP_EL3 (with SPSel = 1) */ + + mov sp, x24 + b el3_boot +#endif + /* Get next EL */ adr x0, switch_el @@ -266,6 +277,8 @@ switch_el: msr SPSel, #1 msr DAIFClr, #(DAIFCLR_ABT_BIT) + +el3_boot: isb jump_to_c_entry: diff --git a/arch/arm64/src/common/arm64_initialstate.c b/arch/arm64/src/common/arm64_initialstate.c index 0dc836e7a4725..1e4d776004e20 100644 --- a/arch/arm64/src/common/arm64_initialstate.c +++ b/arch/arm64/src/common/arm64_initialstate.c @@ -56,7 +56,7 @@ void arm64_new_task(struct tcb_s * tcb) { - char *stack_ptr = tcb->stack_base_ptr + tcb->adj_stack_size; + uint64_t stack_ptr = (uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size; struct regs_context *pinitctx; #ifdef CONFIG_ARCH_FPU @@ -67,16 +67,20 @@ void arm64_new_task(struct tcb_s * tcb) /* set fpu context */ arm64_init_fpu(tcb); - stack_ptr = (char *)pfpuctx; + stack_ptr = (uintptr_t)pfpuctx; #endif pinitctx = STACK_PTR_TO_FRAME(struct regs_context, stack_ptr); memset(pinitctx, 0, sizeof(struct regs_context)); pinitctx->elr = (uint64_t)tcb->start; - /* Keep using SP_EL1 */ + /* Keep using SP_EL1 or SP_EL3 */ +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + pinitctx->spsr = SPSR_MODE_EL3H; +#else pinitctx->spsr = SPSR_MODE_EL1H; +#endif #ifdef CONFIG_SUPPRESS_INTERRUPTS pinitctx->spsr |= (DAIF_IRQ_BIT | DAIF_FIQ_BIT); diff --git a/arch/arm64/src/common/arm64_internal.h b/arch/arm64/src/common/arm64_internal.h index a1a98d456fab3..a68b356e53708 100644 --- a/arch/arm64/src/common/arm64_internal.h +++ b/arch/arm64/src/common/arm64_internal.h @@ -308,6 +308,10 @@ void arm64_pginitialize(void); uint64_t * arm64_syscall_switch(uint64_t *regs); int arm64_syscall(uint64_t *regs); +/* Low level serial output **************************************************/ + +void arm64_lowputc(char ch); + #ifdef USE_SERIALDRIVER /**************************************************************************** * Name: arm64_serialinit diff --git a/arch/arm64/src/common/arm64_mmu.c b/arch/arm64/src/common/arm64_mmu.c index d4b949bbf9804..e83dfa519b14b 100644 --- a/arch/arm64/src/common/arm64_mmu.c +++ b/arch/arm64/src/common/arm64_mmu.c @@ -523,6 +523,40 @@ static void setup_page_tables(void) } } +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 +static void enable_mmu_el3(unsigned int flags) +{ + uint64_t value; + UNUSED(flags); + + /* Set MAIR, TCR and TBBR registers */ + + write_sysreg(MEMORY_ATTRIBUTES, mair_el3); + write_sysreg(get_tcr(3), tcr_el3); + write_sysreg((uint64_t)base_xlat_table, ttbr0_el3); + + /* Ensure these changes are seen before MMU is enabled */ + + ARM64_DSB(); + ARM64_ISB(); + + /* Enable the MMU and data cache */ + + value = read_sysreg(sctlr_el3); + write_sysreg((value | SCTLR_M_BIT +#ifndef CONFIG_ARM64_DCACHE_DISABLE + | SCTLR_C_BIT +#endif + ), sctlr_el3); + + /* Ensure the MMU enable takes effect immediately */ + + ARM64_ISB(); +#ifdef CONFIG_MMU_DEBUG + sinfo("MMU enabled with dcache\n"); +#endif +} +#else static void enable_mmu_el1(unsigned int flags) { uint64_t value; @@ -532,7 +566,7 @@ static void enable_mmu_el1(unsigned int flags) write_sysreg(MEMORY_ATTRIBUTES, mair_el1); write_sysreg(get_tcr(1), tcr_el1); - write_sysreg(((uint64_t)base_xlat_table), ttbr0_el1); + write_sysreg((uint64_t)base_xlat_table, ttbr0_el1); /* Ensure these changes are seen before MMU is enabled */ @@ -554,6 +588,7 @@ static void enable_mmu_el1(unsigned int flags) sinfo("MMU enabled with dcache\n"); #endif } +#endif /*************************************************************************** * Public Functions @@ -587,19 +622,30 @@ int arm64_mmu_set_memregion(const struct arm_mmu_region *region) int arm64_mmu_init(bool is_primary_core) { uint64_t val; + uint64_t el; unsigned flags = 0; - /* Current MMU code supports only EL1 */ + /* Current MMU code supports EL1 and EL3 */ - __asm__ volatile ("mrs %0, CurrentEL" : "=r" (val)); + __asm__ volatile ("mrs %0, CurrentEL" : "=r" (el)); - __MMU_ASSERT(GET_EL(val) == MODE_EL1, +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + __MMU_ASSERT(GET_EL(el) == MODE_EL3, + "Exception level not EL3, MMU not enabled!\n"); + + /* Ensure that MMU is already not enabled */ + + __asm__ volatile ("mrs %0, sctlr_el3" : "=r" (val)); + __MMU_ASSERT((val & SCTLR_M_BIT) == 0, "MMU is already enabled\n"); +#else + __MMU_ASSERT(GET_EL(el) == MODE_EL1, "Exception level not EL1, MMU not enabled!\n"); /* Ensure that MMU is already not enabled */ __asm__ volatile ("mrs %0, sctlr_el1" : "=r" (val)); __MMU_ASSERT((val & SCTLR_M_BIT) == 0, "MMU is already enabled\n"); +#endif #ifdef CONFIG_MMU_DEBUG sinfo("xlat tables:\n"); @@ -616,9 +662,13 @@ int arm64_mmu_init(bool is_primary_core) setup_page_tables(); } - /* currently only EL1 is supported */ + /* Currently EL1 and EL3 are supported */ +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + enable_mmu_el3(flags); +#else enable_mmu_el1(flags); +#endif return 0; } diff --git a/arch/arm64/src/common/arm64_modifyreg16.c b/arch/arm64/src/common/arm64_modifyreg16.c new file mode 100644 index 0000000000000..3c1fd2e498fad --- /dev/null +++ b/arch/arm64/src/common/arm64_modifyreg16.c @@ -0,0 +1,57 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_modifyreg16.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "arm64_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modifyreg16 + * + * Description: + * Atomically modify the specified bits in a memory mapped register + * + ****************************************************************************/ + +void modifyreg16(unsigned int addr, uint16_t clearbits, uint16_t setbits) +{ + irqstate_t flags; + uint16_t regval; + + flags = spin_lock_irqsave(NULL); + regval = getreg16(addr); + regval &= ~clearbits; + regval |= setbits; + putreg16(regval, addr); + spin_unlock_irqrestore(NULL, flags); +} diff --git a/arch/arm64/src/common/arm64_modifyreg32.c b/arch/arm64/src/common/arm64_modifyreg32.c new file mode 100644 index 0000000000000..c3fc742739c1b --- /dev/null +++ b/arch/arm64/src/common/arm64_modifyreg32.c @@ -0,0 +1,57 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_modifyreg32.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "arm64_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modifyreg32 + * + * Description: + * Atomically modify the specified bits in a memory mapped register + * + ****************************************************************************/ + +void modifyreg32(unsigned int addr, uint32_t clearbits, uint32_t setbits) +{ + irqstate_t flags; + uint32_t regval; + + flags = spin_lock_irqsave(NULL); + regval = getreg32(addr); + regval &= ~clearbits; + regval |= setbits; + putreg32(regval, addr); + spin_unlock_irqrestore(NULL, flags); +} diff --git a/arch/arm64/src/common/arm64_modifyreg8.c b/arch/arm64/src/common/arm64_modifyreg8.c new file mode 100644 index 0000000000000..cb230b257ea8e --- /dev/null +++ b/arch/arm64/src/common/arm64_modifyreg8.c @@ -0,0 +1,57 @@ +/**************************************************************************** + * arch/arm64/src/common/arm64_modifyreg8.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "arm64_internal.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modifyreg8 + * + * Description: + * Atomically modify the specified bits in a memory mapped register + * + ****************************************************************************/ + +void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits) +{ + irqstate_t flags; + uint8_t regval; + + flags = spin_lock_irqsave(NULL); + regval = getreg8(addr); + regval &= ~clearbits; + regval |= setbits; + putreg8(regval, addr); + spin_unlock_irqrestore(NULL, flags); +} diff --git a/arch/arm64/src/common/arm64_schedulesigaction.c b/arch/arm64/src/common/arm64_schedulesigaction.c index 255a564e42a3e..eee31cd17f82a 100644 --- a/arch/arm64/src/common/arm64_schedulesigaction.c +++ b/arch/arm64/src/common/arm64_schedulesigaction.c @@ -74,7 +74,11 @@ void arm64_init_signal_process(struct tcb_s *tcb, struct regs_context *regs) /* Keep using SP_EL1 */ +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + psigctx->spsr = SPSR_MODE_EL3H | DAIF_FIQ_BIT | DAIF_IRQ_BIT; +#else psigctx->spsr = SPSR_MODE_EL1H | DAIF_FIQ_BIT | DAIF_IRQ_BIT; +#endif psigctx->sp_elx = (uint64_t)stack_ptr; psigctx->sp_el0 = (uint64_t)psigctx; psigctx->exe_depth = 1; diff --git a/arch/arm64/src/common/arm64_vector_table.S b/arch/arm64/src/common/arm64_vector_table.S index 1f9fd33243ec0..e7b1eb005624d 100644 --- a/arch/arm64/src/common/arm64_vector_table.S +++ b/arch/arm64/src/common/arm64_vector_table.S @@ -69,8 +69,13 @@ stp x30, \xreg0, [sp, #8 * REG_X30] /* ELR and SPSR */ +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + mrs \xreg0, elr_el3 + mrs \xreg1, spsr_el3 +#else mrs \xreg0, elr_el1 mrs \xreg1, spsr_el1 +#endif stp \xreg0, \xreg1, [sp, #8 * REG_ELR] /* increment exception depth */ @@ -246,8 +251,13 @@ arm64_exit_exc_fpu_done: /* restore spsr and elr at el1*/ ldp x0, x1, [sp, #8 * REG_ELR] +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + msr elr_el3, x0 + msr spsr_el3, x1 +#else msr elr_el1, x0 msr spsr_el1, x1 +#endif /* decrement exception depth */ diff --git a/arch/arm64/src/common/arm64_vectors.S b/arch/arm64/src/common/arm64_vectors.S index e6541b519c57e..799b533ff2e50 100644 --- a/arch/arm64/src/common/arm64_vectors.S +++ b/arch/arm64/src/common/arm64_vectors.S @@ -92,8 +92,13 @@ SECTION_FUNC(text, up_saveusercontext) stp x30, x4, [x0, #8 * REG_X30] /* ELR and SPSR */ +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + mrs x4, elr_el3 + mrs x5, spsr_el3 +#else mrs x4, elr_el1 mrs x5, spsr_el1 +#endif stp x4, x5, [x0, #8 * REG_ELR] arm64_exception_context_save x4 x5 x0 @@ -181,7 +186,11 @@ GTEXT(arm64_sync_exc) SECTION_FUNC(text, arm64_sync_exc) /* checking the EC value to see which exception need to be handle */ +#if CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3 + mrs x0, esr_el3 +#else mrs x0, esr_el1 +#endif lsr x1, x0, #26 #ifdef CONFIG_ARCH_FPU diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig new file mode 100644 index 0000000000000..3f012563c9bbc --- /dev/null +++ b/arch/arm64/src/imx9/Kconfig @@ -0,0 +1,1010 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_CHIP_IMX9 + +menu "i.MX9 Chip Selection" + +choice + prompt "i.MX9 Core Configuration" + default ARCH_CHIP_IMX93 + +config ARCH_CHIP_IMX93 + bool "i.MX9 Application Processor" + select ARCH_HAVE_MULTICPU + select ARMV8A_HAVE_GICv3 + select ARCH_CORTEX_A55 + select ARCH_HAVE_PSCI if !IMX9_BOOTLOADER + select ARCH_HAVE_PWM_MULTICHAN + select ARCH_HAVE_RESET + +endchoice # i.MX9 Chip Selection + +endmenu # "i.MX9 Chip Selection" + +config IMX9_DMA_ALLOC + bool "Enable DMA capable memory allocator" + depends on GRAN + default y if CONFIG_FAT_DMAMEMORY + +menu "DMA Allocator Configuration" + depends on IMX9_DMA_ALLOC + +config IMX9_DMA_ALLOC_POOL_SIZE + int "DMA allocator memory pool size in bytes" + default 4096 + +config IMX9_DMA_ALLOC_SECT + string "Section for DMA allocator memory pool, default is .bss" + default ".bss" + +endmenu # DMA Allocator Configuration + +config IMX9_FLEXIO_PWM + bool + select PWM_MULTICHAN + default n + +config IMX9_BOOTLOADER + bool "Bootloader" + select ARM64_DECODEFIQ + default n + ---help--- + Configure NuttX as the bootloader. NuttX will be compiled + into OCRAM. It will run in EL3 secure state. + +config BOOTLOADER_SYS_CLOCK + int "Bootloader system clock for timer" + default 1700000000 + depends on IMX9_BOOTLOADER + ---help--- + If the sysclk is set to a certain value, this should be it. + The value is used by the timer interrupt infrastructure. + +menu "i.MX9 Peripheral Selection" + +config IMX9_EDMA + bool "eDMA" + default n + select ARCH_DMA + +menu "USDHC" + +config IMX9_USDHC + bool + default n + select ARCH_HAVE_SDIO_PREFLIGHT + +config IMX9_USDHC1 + bool "USDHC1" + default n + select ARCH_HAVE_SDIO + select IMX9_USDHC + ---help--- + Support USDHC host controller 1 + +config IMX9_USDHC2 + bool "USDHC2" + default n + select ARCH_HAVE_SDIO + select IMX9_USDHC + ---help--- + Support USDHC host controller 2 + +menu "USDHC Configuration" + depends on IMX9_USDHC + +config IMX9_USDHC_DMA + bool "Support DMA data transfers" + default y + select SDIO_DMA + ---help--- + Support DMA data transfers. + Enable SD card DMA data transfers. This is marginally optional. + For most usages, SD accesses will cause data overruns if used without + DMA. + +choice + prompt "Bus width for USDHC1" + default IMX9_USDHC1_WIDTH_D1_ONLY + depends on IMX9_USDHC1 + +config IMX9_USDHC1_WIDTH_D1_ONLY + bool "One bit" + +config IMX9_USDHC1_WIDTH_D1_D4 + bool "Four bit" + +config IMX9_USDHC1_WIDTH_D1_D8 + bool "Eight bit" + +endchoice + +config IMX9_USDHC1_INVERT_CD + bool "Invert the USDHC1 CD" + default n + depends on IMX9_USDHC1 + ---help--- + If the board defines PIN_USDHC1_CD the CD_B input to the USDHC it is + assumed to be active low. Selecting IMX9_USDHC1_INVERT_CD will make it + active high. + + If the board defines PIN_USDHC1_CD_GPIO it is assumed to be active low. + Selecting IMX9_USDHC1_INVERT_CD will make it active high. + +choice + depends on IMX9_USDHC2 + prompt "Bus width for USDHC2" + default IMX9_USDHC2_WIDTH_D1_D4 + +config IMX9_USDHC2_WIDTH_D1_ONLY + bool "One bit" + +config IMX9_USDHC2_WIDTH_D1_D4 + bool "Four bit" + +endchoice + +config IMX9_USDHC2_INVERT_CD + bool "Invert the USDHC2 CD" + default n + depends on IMX9_USDHC2 + ---help--- + If the board defines PIN_USDHC2_CD the CD_B input to the USDHC it is + assumed to be active low. Selecting IMX9_USDHC_INVERT_CD will make it + active high. + + If the board defines PIN_USDHC2_CD_GPIO it is assumed to be active low. + Selecting IMX9_USDHC2_INVERT_CD will make it active high. + +endmenu # USDHC Configuration + +endmenu # USDHC + +menu "LPUART" + +config IMX9_LPUART + bool + default n + select ARCH_HAVE_SERIAL_TERMIOS + +config IMX9_LPUART1 + bool "LPUART1" + default n + select IMX9_LPUART + select LPUART1_SERIALDRIVER + +config IMX9_LPUART2 + bool "LPUART2" + default n + select IMX9_LPUART + select LPUART2_SERIALDRIVER + +config IMX9_LPUART3 + bool "LPUART3" + default n + select IMX9_LPUART + select LPUART3_SERIALDRIVER + +config IMX9_LPUART4 + bool "LPUART4" + default n + select IMX9_LPUART + select LPUART4_SERIALDRIVER + +config IMX9_LPUART5 + bool "LPUART5" + default n + select IMX9_LPUART + select LPUART5_SERIALDRIVER + +config IMX9_LPUART6 + bool "LPUART6" + default n + select IMX9_LPUART + select LPUART6_SERIALDRIVER + +config IMX9_LPUART7 + bool "LPUART7" + default n + select IMX9_LPUART + select LPUART7_SERIALDRIVER + +config IMX9_LPUART8 + bool "LPUART8" + default n + select IMX9_LPUART + select LPUART8_SERIALDRIVER + +menu "LPUART Configuration" + depends on IMX9_LPUART + +config IMX9_LPUART_INVERT + bool "Signal Invert Support" + default n + +config IMX9_LPUART_SINGLEWIRE + bool "Signal Wire Support" + default n + +config IMX9_SERIAL_RXDMA_BUFFER_SIZE + int "RX DMA buffer size" + default 64 + depends on LPUART1_RXDMA || LPUART2_RXDMA || LPUART3_RXDMA || LPUART4_RXDMA || \ + LPUART5_RXDMA || LPUART6_RXDMA || LPUART7_RXDMA || LPUART8_RXDMA + ---help--- + The DMA buffer size when using RX DMA to emulate a FIFO. + + When streaming data, the generic serial layer will be called + every time the FIFO receives half this number of bytes. + + Value given here will be rounded up to next multiple of 64 bytes. + +endmenu # LPUART Configuration + +endmenu # LPUART + +config IMX9_FLEXIO1_PWM + depends on PWM + bool "Enable FLEXIO1 based PWM generation" + select IMX9_FLEXIO_PWM + default n + +config IMX9_FLEXIO2_PWM + depends on PWM + bool "Enable FLEXIO2 based PWM generation" + select IMX9_FLEXIO_PWM + default n + +config IMX9_FLEXIO1_PWM_NCHANNELS + depends on IMX9_FLEXIO1_PWM + int "Number of channels for FLEXIO1" + default 4 + range 1 7 + +config IMX9_FLEXIO1_PWM_CHANNEL_PINS + depends on IMX9_FLEXIO1_PWM + hex "FlexIO outputs used for FLEXIO1 timers" + default 0x0000000007060504 + +config IMX9_FLEXIO2_PWM_NCHANNELS + depends on IMX9_FLEXIO2_PWM + int "Number of channels for FLEXIO2" + default 1 + range 1 7 + +config IMX9_FLEXIO2_PWM_CHANNEL_PINS + depends on IMX9_FLEXIO2_PWM + hex "FlexIO outputs used for FLEXIO2 timers" + default 0x0000000000000000 + +config IMX9_TPM_PWM + bool + select PWM_MULTICHAN + default n + +config IMX9_TPM1_PWM + depends on PWM + bool "Enable TPM1 based PWM generation" + select IMX9_TPM_PWM + default n + +config IMX9_TPM1_PWM_NCHANNELS + depends on IMX9_TPM1_PWM + int "Number of channels for TPM1" + default 1 + +config IMX9_TPM1_PWM_CHMUX + depends on IMX9_TPM1_PWM + hex "Channel mux for TPM1" + default 0x03020100 + +config IMX9_TPM2_PWM + depends on PWM + bool "Enable TPM2 based PWM generation" + select IMX9_TPM_PWM + default n + +config IMX9_TPM2_PWM_NCHANNELS + depends on IMX9_TPM2_PWM + int "Number of channels for TPM2" + default 1 + +config IMX9_TPM2_PWM_CHMUX + depends on IMX9_TPM2_PWM + hex "Channel mux for TPM2" + default 0x03020100 + +config IMX9_TPM3_PWM + depends on PWM + bool "Enable TPM3 based PWM generation" + select IMX9_TPM_PWM + default n + +config IMX9_TPM3_PWM_NCHANNELS + depends on IMX9_TPM3_PWM + int "Number of channels for TPM3" + default 1 + +config IMX9_TPM3_PWM_CHMUX + depends on IMX9_TPM3_PWM + hex "Channel mux for TPM3" + default 0x03020100 + +config IMX9_TPM4_PWM + depends on PWM + bool "Enable TPM4 based PWM generation" + select IMX9_TPM_PWM + default n + +config IMX9_TPM4_PWM_NCHANNELS + depends on IMX9_TPM4_PWM + int "Number of channels for TPM4" + default 1 + +config IMX9_TPM4_PWM_CHMUX + depends on IMX9_TPM4_PWM + hex "Channel mux for TPM4" + default 0x03020100 + +config IMX9_TPM5_PWM + depends on PWM + bool "Enable TPM5 based PWM generation" + select IMX9_TPM_PWM + default n + +config IMX9_TPM5_PWM_NCHANNELS + depends on IMX9_TPM5_PWM + int "Number of channels for TPM5" + default 1 + +config IMX9_TPM5_PWM_CHMUX + depends on IMX9_TPM5_PWM + hex "Channel mux for TPM5" + default 0x03020100 + +config IMX9_TPM6_PWM + depends on PWM + bool "Enable TPM6 based PWM generation" + select IMX9_TPM_PWM + default n + +config IMX9_TPM6_PWM_NCHANNELS + depends on IMX9_TPM6_PWM + int "Number of channels for TPM6" + default 1 + +config IMX9_TPM6_PWM_CHMUX + depends on IMX9_TPM6_PWM + hex "Channel mux for TPM6" + default 0x03020100 + +config IMX9_USBDEV + bool + default n + select USBDEV + +config IMX9_USBDEV_USBC1 + bool "USB Device using controller 1" + default n + select IMX9_USBDEV + +config IMX9_USBDEV_USBC2 + depends on !IMX9_USBDEV_USBC1 + bool "USB Device using controller 2" + default n + select IMX9_USBDEV + +if IMX9_USBDEV + +menu "USB device controller driver (DCD) options" + +config IMX9_USBDEV_NOVBUS + bool "No USB VBUS sensing" + default n + +config IMX9_USBDEV_FRAME_INTERRUPT + bool "USB frame interrupt" + default n + ---help--- + Handle USB Start-Of-Frame events. Enable reading SOF from interrupt + handler vs. simply reading on demand. Probably a bad idea... Unless + there is some issue with sampling the SOF from hardware asynchronously. + +config IMX9_USBDEV_REGDEBUG + bool "Register level debug" + depends on DEBUG_USB_INFO + default n + ---help--- + Output detailed register-level USB device debug information. Requires + also CONFIG_DEBUG_USB_INFO. + +endmenu # USB device controller driver (DCD) options + +endif # IMX9_USBDEV + +config IMX9_ENET + bool "Ethernet" + default n + select ARCH_HAVE_PHY + select ARCH_HAVE_NETDEV_STATISTICS + +config IMX9_GPIO_IRQ + bool "GPIO Interrupt Support" + default n + +config IMX9_LPI2C + bool "LPI2C support" + default n + +config IMX9_LPSPI + bool "LPSPI support" + default n + +menu "LPI2C Peripherals" + +menuconfig IMX9_LPI2C1 + bool "LPI2C1" + default n + select IMX9_LPI2C + +if IMX9_LPI2C1 + +config IMX9_LPI2C1_BUSYIDLE + int "Bus idle timeout period in clock cycles" + default 0 + +config IMX9_LPI2C1_DMA + bool "Enable DMA for I2C1" + default n + depends on IMX9_LPI2C_DMA + +config IMX9_LPI2C1_FILTSCL + int "I2C master digital glitch filters for SCL input in clock cycles" + default 0 + +config IMX9_LPI2C1_FILTSDA + int "I2C master digital glitch filters for SDA input in clock cycles" + default 0 + +endif # IMX9_LPI2C1 + +menuconfig IMX9_LPI2C2 + bool "LPI2C2" + default n + select IMX9_LPI2C + +if IMX9_LPI2C2 + +config IMX9_LPI2C2_BUSYIDLE + int "Bus idle timeout period in clock cycles" + default 0 + +config IMX9_LPI2C2_DMA + bool "Enable DMA for I2C2" + default n + depends on IMX9_LPI2C_DMA + +config IMX9_LPI2C2_FILTSCL + int "I2C master digital glitch filters for SCL input in clock cycles" + default 0 + +config IMX9_LPI2C2_FILTSDA + int "I2C master digital glitch filters for SDA input in clock cycles" + default 0 + +endif # IMX9_LPI2C2 + +menuconfig IMX9_LPI2C3 + bool "LPI2C3" + default n + select IMX9_LPI2C + +if IMX9_LPI2C3 + +config IMX9_LPI2C3_BUSYIDLE + int "Bus idle timeout period in clock cycles" + default 0 + +config IMX9_LPI2C3_DMA + bool "Enable DMA for I2C3" + default n + depends on IMX9_LPI2C_DMA + +config IMX9_LPI2C3_FILTSCL + int "I2C master digital glitch filters for SCL input in clock cycles" + default 0 + +config IMX9_LPI2C3_FILTSDA + int "I2C master digital glitch filters for SDA input in clock cycles" + default 0 + +endif # IMX9_LPI2C3 + +menuconfig IMX9_LPI2C4 + bool "LPI2C4" + default n + select IMX9_LPI2C + +if IMX9_LPI2C4 + +config IMX9_LPI2C4_BUSYIDLE + int "Bus idle timeout period in clock cycles" + default 0 + +config IMX9_LPI2C4_DMA + bool "Enable DMA for I2C4" + default n + depends on IMX9_LPI2C_DMA + +config IMX9_LPI2C4_FILTSCL + int "I2C master digital glitch filters for SCL input in clock cycles" + default 0 + +config IMX9_LPI2C4_FILTSDA + int "I2C master digital glitch filters for SDA input in clock cycles" + default 0 + +endif # IMX9_LPI2C4 + +menuconfig IMX9_LPI2C5 + bool "LPI2C5" + default n + select IMX9_LPI2C + +if IMX9_LPI2C5 + +config IMX9_LPI2C5_BUSYIDLE + int "Bus idle timeout period in clock cycles" + default 0 + +config IMX9_LPI2C5_FILTSCL + int "I2C master digital glitch filters for SCL input in clock cycles" + default 0 + +config IMX9_LPI2C5_FILTSDA + int "I2C master digital glitch filters for SDA input in clock cycles" + default 0 + +endif # IMX9_LPI2C5 + +menuconfig IMX9_LPI2C6 + bool "LPI2C6" + default n + select IMX9_LPI2C + +if IMX9_LPI2C6 + +config IMX9_LPI2C6_BUSYIDLE + int "Bus idle timeout period in clock cycles" + default 0 + +config IMX9_LPI2C6_FILTSCL + int "I2C master digital glitch filters for SCL input in clock cycles" + default 0 + +config IMX9_LPI2C6_FILTSDA + int "I2C master digital glitch filters for SDA input in clock cycles" + default 0 + +endif # IMX9_LPI2C6 + +menuconfig IMX9_LPI2C7 + bool "LPI2C7" + default n + select IMX9_LPI2C + +if IMX9_LPI2C7 + +config IMX9_LPI2C7_BUSYIDLE + int "Bus idle timeout period in clock cycles" + default 0 + +config IMX9_LPI2C7_FILTSCL + int "I2C master digital glitch filters for SCL input in clock cycles" + default 0 + +config IMX9_LPI2C7_FILTSDA + int "I2C master digital glitch filters for SDA input in clock cycles" + default 0 + +endif # IMX9_LPI2C7 + +menuconfig IMX9_LPI2C8 + bool "LPI2C8" + default n + select IMX9_LPI2C + +if IMX9_LPI2C8 + +config IMX9_LPI2C8_BUSYIDLE + int "Bus idle timeout period in clock cycles" + default 0 + +config IMX9_LPI2C8_FILTSCL + int "I2C master digital glitch filters for SCL input in clock cycles" + default 0 + +config IMX9_LPI2C8_FILTSDA + int "I2C master digital glitch filters for SDA input in clock cycles" + default 0 + +endif # IMX9_LPI2C8 + +endmenu # LPI2C Peripherals + +menu "LPSPI Peripherals" + +menuconfig IMX9_LPSPI1 + bool "LPSPI1" + default n + select IMX9_LPSPI + +menuconfig IMX9_LPSPI2 + bool "LPSPI2" + default n + select IMX9_LPSPI + +menuconfig IMX9_LPSPI3 + bool "LPSPI3" + default n + select IMX9_LPSPI + +menuconfig IMX9_LPSPI4 + bool "LPSPI4" + default n + select IMX9_LPSPI + +menuconfig IMX9_LPSPI5 + bool "LPSPI5" + default n + select IMX9_LPSPI + +menuconfig IMX9_LPSPI6 + bool "LPSPI6" + default n + select IMX9_LPSPI + +menuconfig IMX9_LPSPI7 + bool "LPSPI7" + default n + select IMX9_LPSPI + +menuconfig IMX9_LPSPI8 + bool "LPSPI8" + default n + select IMX9_LPSPI + +endmenu # LPSPI Peripherals + +menu "eDMA Configuration" + depends on IMX9_EDMA + +config IMX9_EDMA_NTCD + int "Number of transfer descriptors" + default 0 + ---help--- + Number of pre-allocated transfer descriptors. Needed for scatter- + gather DMA. Make to be set to zero to disable in-memory TCDs in + which case only the TCD channel registers will be used and scatter- + will not be supported. + +config IMX9_EDMA_ELINK + bool "Channeling Linking" + default n + ---help--- + This option enables optional minor or major loop channel linking: + + Minor loop channel linking: As the channel completes the minor + loop, this flag enables linking to another channel. The link target + channel initiates a channel service request via an internal + mechanism that sets the TCDn_CSR[START] bit of the specified + channel. + + If minor loop channel linking is disabled, this link mechanism is + suppressed in favor of the major loop channel linking. + + Major loop channel linking: As the channel completes the minor + loop, this option enables the linking to another channel. The link + target channel initiates a channel service request via an internal + mechanism that sets the TCDn_CSR[START] bit of the linked channel. + +config IMX9_EDMA_ERCA + bool "Round Robin Channel Arbitration" + default n + ---help--- + Normally, a fixed priority arbitration is used for channel + selection. If this option is selected, round robin arbitration is + used for channel selection. + +config IMX9_EDMA_HOE + bool "Halt On Error" + default y + ---help--- + Any error causes the HALT bit to set. Subsequently, all service + requests are ignored until the HALT bit is cleared. + +config IMX9_EDMA_CLM + bool "Continuous Link Mode" + default n + ---help--- + By default, A minor loop channel link made to itself goes through + channel arbitration before being activated again. If this option is + selected, a minor loop channel link made to itself does not go + through channel arbitration before being activated again. Upon minor + loop completion, the channel activates again if that channel has a + minor loop channel link enabled and the link channel is itself. This + effectively applies the minor loop offsets and restarts the next + minor loop. + +config IMX9_EDMA_EMLIM + bool "Minor Loop Mapping" + default n + ---help--- + Normally TCD word 2 is a 32-bit NBYTES field. When this option is + enabled, TCD word 2 is redefined to include individual enable fields, + an offset field, and the NBYTES field. The individual enable fields + allow the minor loop offset to be applied to the source address, the + destination address, or both. The NBYTES field is reduced when either + offset is enabled. + +config IMX9_EDMA_EDBG + bool "Enable Debug" + default n + ---help--- + When in debug mode, the DMA stalls the start of a new channel. Executing + channels are allowed to complete. Channel execution resumes when the + system exits debug mode or the EDBG bit is cleared + +endmenu # eDMA Global Configuration + +menu "LPI2C Configuration" + depends on IMX9_LPI2C + +config IMX9_LPI2C_DMA + bool "I2C DMA Support" + default n + depends on IMX9_LPI2C && IMX9_EDMA && !I2C_POLLED + ---help--- + This option enables the DMA for I2C transfers. + Note: The user can define CONFIG_I2C_DMAPRIO: a custom priority value + for the I2C dma streams, else the default priority level is set to + medium. + +config IMX9_LPI2C_DMA_MAXMSG + int "Maximum number messages that will be DMAed" + default 8 + depends on IMX9_LPI2C_DMA + ---help--- + This option set the mumber of mesg that can be in a transfer. + It is used to allocate space for the 16 bit LPI2C commands + that will be DMA-ed to the LPI2C device. + +config IMX9_LPI2C_DYNTIMEO + bool "Use dynamic timeouts" + default n + depends on IMX9_LPI2C + +config IMX9_LPI2C_DYNTIMEO_USECPERBYTE + int "Timeout Microseconds per Byte" + default 500 + depends on IMX9_LPI2C_DYNTIMEO + +config IMX9_LPI2C_DYNTIMEO_STARTSTOP + int "Timeout for Start/Stop (Milliseconds)" + default 1000 + depends on IMX9_LPI2C_DYNTIMEO + +config IMX9_LPI2C_TIMEOSEC + int "Timeout seconds" + default 0 + depends on IMX9_LPI2C + +config IMX9_LPI2C_TIMEOMS + int "Timeout Milliseconds" + default 500 + depends on IMX9_LPI2C && !IMX9_LPI2C_DYNTIMEO + +config IMX9_LPI2C_TIMEOTICKS + int "Timeout for Done and Stop (ticks)" + default 500 + depends on IMX9_LPI2C && !IMX9_LPI2C_DYNTIMEO + +endmenu # LPI2C Configuration + +menu "LPSPI Configuration" + depends on IMX9_LPSPI + +config IMX9_LPSPI_DMA + bool "LPSPI DMA" + depends on IMX9_EDMA + default n + ---help--- + Use DMA to improve LPSPI transfer performance. + +config IMX9_LPSPI_DMATHRESHOLD + int "LPSPI DMA threshold" + default 4 + depends on IMX9_LPSPI_DMA + ---help--- + When SPI DMA is enabled, small DMA transfers will still be performed + by polling logic. But we need a threshold value to determine what + is small. + +config IMX9_LPSPI_DMA_BUFFER_SIZE + int "LPSPI DMA buffer size" + default 4096 + depends on IMX9_LPSPI_DMA + ---help--- + Set the LPSPI driver DMA buffer size. + +config IMX9_LPSPI1_DMA + bool "LPSPI1 DMA" + default n + depends on IMX9_LPSPI1 && IMX9_LPSPI_DMA + ---help--- + Use DMA to improve LPSPI1 transfer performance. + +config IMX9_LPSPI2_DMA + bool "LPSPI2 DMA" + default n + depends on IMX9_LPSPI2 && IMX9_LPSPI_DMA + ---help--- + Use DMA to improve LPSPI2 transfer performance. + +config IMX9_LPSPI3_DMA + bool "LPSPI3 DMA" + default n + depends on IMX9_LPSPI3 && IMX9_LPSPI_DMA + ---help--- + Use DMA to improve LPSPI3 transfer performance. + +config IMX9_LPSPI4_DMA + bool "LPSPI4 DMA" + default n + depends on IMX9_LPSPI4 && IMX9_LPSPI_DMA + ---help--- + Use DMA to improve SPI4 transfer performance. + +config IMX9_LPSPI5_DMA + bool "LPSPI5 DMA" + default n + depends on IMX9_LPSPI5 && IMX9_LPSPI_DMA + ---help--- + Use DMA to improve SPI5 transfer performance. + +config IMX9_LPSPI6_DMA + bool "LPSPI6 DMA" + default n + depends on IMX9_LPSPI6 && IMX9_LPSPI_DMA + ---help--- + Use DMA to improve SPI6 transfer performance. + +config IMX9_LPSPI7_DMA + bool "LPSPI7 DMA" + default n + depends on IMX9_LPSPI7 && IMX9_LPSPI_DMA + ---help--- + Use DMA to improve SPI7 transfer performance. + +config IMX9_LPSPI8_DMA + bool "LPSPI8 DMA" + default n + depends on IMX9_LPSPI8 && IMX9_LPSPI_DMA + ---help--- + Use DMA to improve SPI8 transfer performance. + +endmenu # LPSPI Configuration + +menu "Ethernet Configuration" + depends on IMX9_ENET + +config IMX9_ENET1 + bool "Ethernet MAC (non-QoS)" + depends on IMX9_ENET + default y + +config IMX9_ENET_NRXBUFFERS + int "Number of Rx buffers" + default 6 + +config IMX9_ENET_NTXBUFFERS + int "Number of Tx buffers" + default 2 + +config IMX9_ENET_USE_OTP_MAC + bool "Use MAC address from OCOTP" + default n + depends on IMX9_ENET + +config IMX9_ENET1_OTP_MAC_ADDR + hex "MAC address offset in OCOTP" + default 0x4ec + depends on IMX9_ENET_USE_OTP_MAC + +config IMX9_ENET1_PROMISCUOUS + bool "Set promiscuous mode" + depends on IMX9_ENET1 + default n + +choice + prompt "i.MX9 ENET1 interface type" + default IMX9_ENET1_RMII + depends on IMX9_ENET1 + +config IMX9_ENET1_RMII + bool "RMII" + +config IMX9_ENET1_RGMII + bool "RGMII" + +endchoice + +config IMX9_ENET1_PHY_AUTONEG + bool "ENET1 PHY autonegotiation enable" + default y + ---help--- + Enable PHY autonegotiation. If set to n, configure the speed + and duplex mode manually. Note that only disabling this doesn't + disable the autonegotiation completely; it just sets the MAC + speed and duplex, and disables autonegotiation advertisement + for other than the configured mode. To disable autonegotiation + completely, also set the FORCE_SPEED flag. + +choice + prompt "Select ENET1 PHY link duplex mode" + default IMX9_ENET1_PHY_FD + depends on !IMX9_ENET1_PHY_AUTONEG + +config IMX9_ENET1_PHY_FD + bool "Full Duplex" + +config IMX9_ENET1_PHY_HD + bool "Half Duplex" +endchoice + +choice + prompt "Select ENET1 PHY link speed" + default IMX9_ENET1_PHY_100MBPS if IMX9_ENET1_RMII + default IMX9_ENET1_PHY_1000MBPS if IMX9_ENET1_RGMII + depends on !IMX9_ENET1_PHY_AUTONEG + +config IMX9_ENET1_PHY_10MBPS + bool "10 MBPS" + +config IMX9_ENET1_PHY_100MBPS + bool "100 MBPS" + +config IMX9_ENET1_PHY_1000MBPS + bool "1000 MBPS" + depends on IMX9_ENET1_RGMII +endchoice + +config IMX9_ENET1_PHY_FORCE_SPEED + bool "Disable PHY autonegotiation and force speed and duplex" + depends on !IMX9_ENET1_PHY_AUTONEG + default n + ---help--- + This disables PHY autonegotiation completely. Note that + if the link partner has got autonegotiation enabled, the + duplex mode is not auto-detected by the link partner. Only + enable if you really know what you are doing! + +config IMX9_ENET1_PHYINIT + bool "Board-specific PHY Initialization for ENET1" + default n + ---help--- + Some boards require specialized initialization of the PHY before it + can be used. This may include such things as configuring GPIOs, + resetting the PHY, etc. If CONFIG_IMX9_ENET_PHYINIT is defined in + the configuration then the board specific logic must provide + imx9_phy_boardinitialize(); The i.MX9 ENET driver will call this + function one time before it first uses the PHY. + +endmenu # IMX9_ENET + +endmenu # iMX Peripheral Selection + +endif # ARCH_CHIP_IMX9 diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs new file mode 100644 index 0000000000000..38466ba3704aa --- /dev/null +++ b/arch/arm64/src/imx9/Make.defs @@ -0,0 +1,69 @@ +############################################################################ +# arch/arm64/src/imx9/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include common/Make.defs + +# i.MX9-specific C source files + +CHIP_CSRCS = imx9_boot.c imx9_ccm.c imx9_clockconfig.c imx9_gpio.c imx9_iomuxc.c + +ifeq ($(CONFIG_ARCH_CHIP_IMX93),y) + CHIP_CSRCS += imx9_lpuart.c imx9_lowputc.c +endif + +ifeq ($(CONFIG_IMX9_GPIO_IRQ),y) + CHIP_CSRCS += imx9_gpioirq.c +endif + +ifeq ($(CONFIG_IMX9_FLEXIO_PWM),y) + CHIP_CSRCS += imx9_flexio_pwm.c +endif + +ifeq ($(CONFIG_IMX9_TPM_PWM),y) + CHIP_CSRCS += imx9_tpm_pwm.c +endif + +ifeq ($(CONFIG_IMX9_USBDEV),y) + CHIP_CSRCS += imx9_usbdev.c +endif + +ifeq ($(CONFIG_IMX9_LPI2C),y) + CHIP_CSRCS += imx9_lpi2c.c +endif + +ifeq ($(CONFIG_IMX9_LPSPI),y) + CHIP_CSRCS += imx9_lpspi.c +endif + +ifeq ($(CONFIG_IMX9_EDMA), y) + CHIP_CSRCS += imx9_edma.c +endif + +ifeq ($(CONFIG_IMX9_DMA_ALLOC),y) + CHIP_CSRCS += imx9_dma_alloc.c +endif + +ifeq ($(CONFIG_IMX9_ENET),y) + CHIP_CSRCS += imx9_enet.c +endif + +ifeq ($(CONFIG_IMX9_USDHC),y) + CHIP_CSRCS += imx9_usdhc.c +endif diff --git a/arch/arm64/src/imx9/chip.h b/arch/arm64/src/imx9/chip.h new file mode 100644 index 0000000000000..f9792f5518e30 --- /dev/null +++ b/arch/arm64/src/imx9/chip.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * arch/arm64/src/imx9/chip.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_CHIP_H +#define __ARCH_ARM64_SRC_IMX9_CHIP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifndef __ASSEMBLY__ +# include +# include +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Macro Definitions + ****************************************************************************/ + +#endif /* __ARCH_ARM64_SRC_IMX9_CHIP_H */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h b/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h new file mode 100644 index 0000000000000..a86f4e72f200f --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h @@ -0,0 +1,711 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_CCM_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_CCM_H + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define IMX9_CCM_CR_CTRL_OFFSET(n) (0x0000 + ((n) << 7)) /* Clock root control (CLOCK_ROOTn_CONTROL, n=0..94) */ +#define IMX9_CCM_CR_CTRL_SET_OFFSET(n) (0x0004 + ((n) << 7)) /* Clock root control (CLOCK_ROOTn_CONTROL_SET, n=0..94) */ +#define IMX9_CCM_CR_CTRL_CLR_OFFSET(n) (0x0008 + ((n) << 7)) /* Clock root control (CLOCK_ROOTn_CONTROL_CLR, n=0..94) */ +#define IMX9_CCM_CR_CTRL_TOG_OFFSET(n) (0x000c + ((n) << 7)) /* Clock root control (CLOCK_ROOTn_CONTROL_TOG, n=0..94) */ +#define IMX9_CCM_CR_STAT0_OFFSET(n) (0x0020 + ((n) << 7)) /* Clock root working status (CLOCK_ROOTn_STATUS0, n=0..94) */ +#define IMX9_CCM_CR_AUTH_OFFSET(n) (0x0030 + ((n) << 7)) /* Clock root access control (CLOCK_ROOTn_AUTHEN, n=0..94) */ +#define IMX9_CCM_CR_AUTH_SET_OFFSET(n) (0x0034 + ((n) << 7)) /* Clock root access control (CLOCK_ROOTn_AUTHEN_SET, n=0..94) */ +#define IMX9_CCM_CR_AUTH_CLR_OFFSET(n) (0x0038 + ((n) << 7)) /* Clock root access control (CLOCK_ROOTn_AUTHEN_CLR, n=0..94) */ +#define IMX9_CCM_CR_AUTH_TOG_OFFSET(n) (0x003c + ((n) << 7)) /* Clock root access control (CLOCK_ROOTn_AUTHEN_TOG, n=0..94) */ + +#define IMX9_CCM_GPR_SH_OFFSET(n) (0x4800 + ((n) << 5)) /* General Purpose Register (GPR_SHAREDn, n=0..7) */ +#define IMX9_CCM_GPR_SH_SET_OFFSET(n) (0x4804 + ((n) << 5)) /* General Purpose Register (GPR_SHAREDn_SET, n=0..7) */ +#define IMX9_CCM_GPR_SH_CLR_OFFSET(n) (0x4808 + ((n) << 5)) /* General Purpose Register (GPR_SHAREDn_CLR, n=0..7) */ +#define IMX9_CCM_GPR_SH_TOG_OFFSET(n) (0x480c + ((n) << 5)) /* General Purpose Register (GPR_SHAREDn_TOG, n=0..7) */ +#define IMX9_CCM_GPR_SH_AUTH_OFFSET(n) (0x4810 + ((n) << 5)) /* General Purpose Register (GPR_SHAREDn_AUTHEN, n=0..7) */ +#define IMX9_CCM_GPR_SH_AUTH_SET_OFFSET(n) (0x4814 + ((n) << 5)) /* General Purpose Register (GPR_SHAREDn_AUTHEN_SET, n=0..7) */ +#define IMX9_CCM_GPR_SH_AUTH_CLR_OFFSET(n) (0x4818 + ((n) << 5)) /* General Purpose Register (GPR_SHAREDn_AUTHEN_CLR, n=0..7) */ +#define IMX9_CCM_GPR_SH_AUTH_TOG_OFFSET(n) (0x481c + ((n) << 5)) /* General Purpose Register (GPR_SHAREDn_AUTHEN_TOG, n=0..7) */ + +#define IMX9_CCM_GPR_PR_OFFSET(n) (0x4c00 + (((n)-1) << 5)) /* General Purpose Register (GPR_PRIVATEn, n=1..7) */ +#define IMX9_CCM_GPR_PR_SET_OFFSET(n) (0x4c04 + (((n)-1) << 5)) /* General Purpose Register (GPR_PRIVATEn_SET, n=1..7) */ +#define IMX9_CCM_GPR_PR_CLR_OFFSET(n) (0x4c08 + (((n)-1) << 5)) /* General Purpose Register (GPR_PRIVATEn_CLR, n=1..7) */ +#define IMX9_CCM_GPR_PR_TOG_OFFSET(n) (0x4c0c + (((n)-1) << 5)) /* General Purpose Register (GPR_PRIVATEn_TOG, n=1..7) */ +#define IMX9_CCM_GPR_PR_AUTH_OFFSET(n) (0x4c10 + (((n)-1) << 5)) /* General Purpose Register (GPR_PRIVATEn_AUTHEN, n=1..7) */ +#define IMX9_CCM_GPR_PR_AUTH_SET_OFFSET(n) (0x4c14 + (((n)-1) << 5)) /* General Purpose Register (GPR_PRIVATEn_AUTHEN_SET, n=1..7) */ +#define IMX9_CCM_GPR_PR_AUTH_CLR_OFFSET(n) (0x4c18 + (((n)-1) << 5)) /* General Purpose Register (GPR_PRIVATEn_AUTHEN_CLR, n=1..7) */ +#define IMX9_CCM_GPR_PR_AUTH_TOG_OFFSET(n) (0x4c1c + (((n)-1) << 5)) /* General Purpose Register (GPR_PRIVATEn_AUTHEN_TOG, n=1..7) */ + +#define IMX9_CCM_OSCPLL_DIR_OFFSET(n) (0x5000 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..18) */ +#define IMX9_CCM_OSCPLL_LPM_STAT0_OFFSET(n) (0x5004 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..18) */ +#define IMX9_CCM_OSCPLL_LPM_STAT1_OFFSET(n) (0x5008 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..18) */ +#define IMX9_CCM_OSCPLL_LPM0_OFFSET(n) (0x5010 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..18) */ +#define IMX9_CCM_OSCPLL_LPM1_OFFSET(n) (0x5014 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..18) */ +#define IMX9_CCM_OSCPLL_LPM_CUR_OFFSET(n) (0x501C + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..18) */ +#define IMX9_CCM_OSCPLL_STAT0_OFFSET(n) (0x5020 + ((n) << 6)) /* Clock source working status (OSCPLLn_STATUS0, n=0..18) */ +#define IMX9_CCM_OSCPLL_STAT1_OFFSET(n) (0x5024 + ((n) << 6)) /* Clock source low power status (OSCPLLn_STATUS1, n=0..18) */ +#define IMX9_CCM_OSCPLL_AUTH_OFFSET(n) (0x5030 + ((n) << 6)) /* Clock source access control (OSCPLLn_AUTHEN, n=0..18) */ + +#define IMX9_CCM_LPCG_DIR_OFFSET(n) (0x8000 + ((n) << 6)) /* LPCG direct control (LPCGn_DIRECT, n=0..126) */ +#define IMX9_CCM_LPCG_LPM_STAT0_OFFSET(n) (0x8004 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..126) */ +#define IMX9_CCM_LPCG_LPM_STAT1_OFFSET(n) (0x8008 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..126) */ +#define IMX9_CCM_LPCG_LPM0_OFFSET(n) (0x8010 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..126) */ +#define IMX9_CCM_LPCG_LPM1_OFFSET(n) (0x8014 + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..126) */ +#define IMX9_CCM_LPCG_LPM_CUR_OFFSET(n) (0x801C + ((n) << 6)) /* Clock source direct control (OSCPLLn_DIRECT, n=0..126) */ +#define IMX9_CCM_LPCG_STAT0_OFFSET(n) (0x8020 + ((n) << 6)) /* LPCG working status (LPCGn_STATUS0, n=0..126) */ +#define IMX9_CCM_LPCG_STAT1_OFFSET(n) (0x8024 + ((n) << 6)) /* LPCG low power status (LPCGn_STATUS1, n=0..126) */ +#define IMX9_CCM_LPCG_AUTH_OFFSET(n) (0x8030 + ((n) << 6)) /* LPCG access control (LPCGn_AUTHEN, n=0..126) */ + +/* Register addresses *******************************************************/ + +#define IMX9_CCM_CR_CTRL(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_CTRL_OFFSET(n)) +#define IMX9_CCM_CR_CTRL_SET(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_CTRL_SET_OFFSET(n)) +#define IMX9_CCM_CR_CTRL_CLR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_CTRL_CLR_OFFSET(n)) +#define IMX9_CCM_CR_CTRL_TOG(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_CTRL_TOG_OFFSET(n)) +#define IMX9_CCM_CR_STAT0(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_STAT0_OFFSET(n)) +#define IMX9_CCM_CR_AUTH(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_AUTH_OFFSET(n)) +#define IMX9_CCM_CR_AUTH_SET(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_AUTH_SET_OFFSET(n)) +#define IMX9_CCM_CR_AUTH_CLR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_AUTH_CLR_OFFSET(n)) +#define IMX9_CCM_CR_AUTH_TOG(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_CR_AUTH_TOG_OFFSET(n)) + +#define IMX9_CCM_GPR_SH(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_SH_OFFSET(n)) +#define IMX9_CCM_GPR_SH_SET(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_SH_SET_OFFSET(n)) +#define IMX9_CCM_GPR_SH_CLR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_SH_CLR_OFFSET(n)) +#define IMX9_CCM_GPR_SH_TOG(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_SH_TOG_OFFSET(n)) +#define IMX9_CCM_GPR_SH_AUTH(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_SH_AUTH_OFFSET(n)) +#define IMX9_CCM_GPR_SH_AUTH_SET(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_SH_AUTH_SET_OFFSET(n)) +#define IMX9_CCM_GPR_SH_AUTH_CLR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_SH_AUTH_CLR_OFFSET(n)) +#define IMX9_CCM_GPR_SH_AUTH_TOG(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_SH_AUTH_TOG_OFFSET(n)) + +#define IMX9_CCM_GPR_PR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_PR_OFFSET(n)) +#define IMX9_CCM_GPR_PR_SET(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_PR_SET_OFFSET(n)) +#define IMX9_CCM_GPR_PR_CLR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_PR_CLR_OFFSET(n)) +#define IMX9_CCM_GPR_PR_TOG(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_PR_TOG_OFFSET(n)) +#define IMX9_CCM_GPR_PR_AUTH(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_PR_AUTH_OFFSET(n)) +#define IMX9_CCM_GPR_PR_AUTH_SET(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_PR_AUTH_SET_OFFSET(n)) +#define IMX9_CCM_GPR_PR_AUTH_CLR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_PR_AUTH_CLR_OFFSET(n)) +#define IMX9_CCM_GPR_PR_AUTH_TOG(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_GPR_PR_AUTH_TOG_OFFSET(n)) + +#define IMX9_CCM_OSCPLL_DIR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_DIR_OFFSET(n)) +#define IMX9_CCM_OSCPLL_LPM_STAT0(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_LPM_STAT0_OFFSET(n)) +#define IMX9_CCM_OSCPLL_LPM_STAT1(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_LPM_STAT1_OFFSET(n)) +#define IMX9_CCM_OSCPLL_LPM0(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_LPM0_OFFSET(n)) +#define IMX9_CCM_OSCPLL_LPM1(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_LPM1_OFFSET(n)) +#define IMX9_CCM_OSCPLL_LPM_CUR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_LPM1_OFFSET(n)) +#define IMX9_CCM_OSCPLL_STAT0(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_STAT0_OFFSET(n)) +#define IMX9_CCM_OSCPLL_STAT1(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_STAT1_OFFSET(n)) +#define IMX9_CCM_OSCPLL_AUTH(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_OSCPLL_AUTH_OFFSET(n)) + +#define IMX9_CCM_LPCG_DIR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_DIR_OFFSET(n)) +#define IMX9_CCM_LPCG_LPM_STAT0(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_LPM_STAT0_OFFSET(n)) +#define IMX9_CCM_LPCG_LPM_STAT1(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_LPM_STAT1_OFFSET(n)) +#define IMX9_CCM_LPCG_LPM0(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_LPM0_OFFSET(n)) +#define IMX9_CCM_LPCG_LPM1(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_LPM1_OFFSET(n)) +#define IMX9_CCM_LPCG_LPM_CUR(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_LPM1_OFFSET(n)) +#define IMX9_CCM_LPCG_STAT0(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_STAT0_OFFSET(n)) +#define IMX9_CCM_LPCG_STAT1(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_STAT1_OFFSET(n)) +#define IMX9_CCM_LPCG_AUTH(n) (IMX9_CCM_CTRL_BASE + IMX9_CCM_LPCG_AUTH_OFFSET(n)) + +/* Register bit definitions *************************************************/ + +/* Clock root control (CLOCK_ROOTn_CONTROL, n=0..94) */ + +#define CCM_CR_CTRL_DIV_SHIFT (0) /* Bits 0-7: Divide selected clock by DIV+1 (DIV) */ +#define CCM_CR_CTRL_DIV_MASK (0xff << CCM_CR_CTRL_DIV_SHIFT) +# define CCM_CR_CTRL_DIV(n) (((n)-1) << CCM_CR_CTRL_DIV_SHIFT) /* Divide selected clock by n */ + +#define CCM_CR_CTRL_MUX_SHIFT (8) /* Bits 8-9: Select clock from 8 clock sources (MUX) */ +#define CCM_CR_CTRL_MUX_MASK (0x03 << CCM_CR_CTRL_MUX_SHIFT) +# define CCM_CR_CTRL_MUX_SRCSEL(n) ((n) << CCM_CR_CTRL_MUX_SHIFT) /* Select clock source n */ + + /* Bits 11-23: Reserved */ +#define CCM_CR_CTRL_OFF (1 << 24) /* Bit 24: Shutdown clock root (OFF) */ + /* Bits 25-31: Reserved */ + +/* Clock root working status (CLOCK_ROOTn_STATUS0, n=0..94) */ + +#define CCM_CR_STAT0_DIV_SHIFT (0) /* Bits 0-7: Current clock root DIV setting (DIV) */ +#define CCM_CR_STAT0_DIV_MASK (0xff << CCM_CR_STAT0_DIV_SHIFT) +#define CCM_CR_STAT0_MUX_SHIFT (8) /* Bits 8-9: Current clock root MUX setting (MUX) */ +#define CCM_CR_STAT0_MUX_MASK (0x03 << CCM_CR_STAT0_MUX_SHIFT) + /* Bits 11-23: Reserved */ +#define CCM_CR_STAT0_OFF (1 << 24) /* Bit 24: Current clock root OFF setting (OFF) */ + /* Bits 25-27: Reserved */ +#define CCM_CR_STAT0_SLICE_BUSY (1 << 28) /* Bit 28: Clock generation logic is applying the new setting (SLICE_BUSY) */ +#define CCM_CR_STAT0_CHANGING (1 << 31) /* Bit 31: Clock generation logic is updating currently (CHANGING) */ + +/* Clock root access control (CLOCK_ROOTn_AUTHEN, n=0..94) */ + +#define CCM_CR_AUTH_TZ_USER (1 << 8) /* Bit 8: Clock root can be changed in user mode (TZ_USER) */ +#define CCM_CR_AUTH_TZ_NS (1 << 9) /* Bit 9: Clock root can be changed in non-secure mode (TZ_NS) */ + /* Bit 10: Reserved */ +#define CCM_CR_AUTH_LOCK_TZ (1 << 11) /* Bit 1: Lock TrustZone settings (LOCK_TZ) */ + /* Bits 12-14: Reserved */ +#define CCM_CR_AUTH_LOCK_LIST (1 << 12) /* Bit 15: Lock whitelist settings (LOCK_LIST) */ +#define CCM_CR_AUTH_WHITE_LIST_SHIFT (16) /* Bits 16-31: Allow domains to change clock (WHITE_LIST) */ +#define CCM_CR_AUTH_WHITE_LIST_MASK (0xffff << CCM_CR_AUTH_WHITE_LIST_SHIFT) + +/* General Purpose Register (GPR_SHAREDn, n=0..7) */ + +#define CCM_GPR_SH_GPR_SHIFT (0) /* Bits 0-31: General purpose register, shared for all CPU domains (GPR) */ +#define CCM_GPR_SH_GPR_MASK (0xffffffff << CCM_GPR_SH_GPR_SHIFT) +#define CCM_GPR_A55_CLK_SEL_SHIFT (0) +#define CCM_GPR_A55_CLK_SEL_MASK (0x01 << CCM_GPR_A55_CLK_SEL_SHIFT) +#define CCM_GPR_A55_CLK_SEL_CCM (0 << 0) +#define CCM_GPR_A55_CLK_SEL_PLL (1 << 0) + +/* General Purpose Register (GPR_SHAREDn_AUTHEN, n=0..7) */ + +#define CCM_GPR_SH_AUTH_TZ_USER (1 << 8) /* Bit 8: Clock root can be changed in user mode (TZ_USER) */ +#define CCM_GPR_SH_AUTH_TZ_NS (1 << 9) /* Bit 9: Clock root can be changed in non-secure mode (TZ_NS) */ + /* Bit 10: Reserved */ +#define CCM_GPR_SH_AUTH_LOCK_TZ (1 << 11) /* Bit 1: Lock TrustZone settings (LOCK_TZ) */ + /* Bits 12-14: Reserved */ +#define CCM_GPR_SH_AUTH_LOCK_LIST (1 << 12) /* Bit 15: Lock whitelist settings (LOCK_LIST) */ +#define CCM_GPR_SH_AUTH_WHITE_LIST_SHIFT (16) /* Bits 16-31: Allow domains to change clock (WHITE_LIST) */ +#define CCM_GPR_SH_AUTH_WHITE_LIST_MASK (0xffff << CCM_GPR_SH_AUTH_WHITE_LIST_SHIFT) + +/* General Purpose Register (GPR_PRIVATEn, n=1..7) */ + +#define CCM_GPR_PR_GPR_SHIFT (0) /* Bits 0-31: General purpose register, with dedicated bits for each domain (GPR) */ +#define CCM_GPR_PR_GPR_MASK (0xffffffff << CCM_GPR_PR_GPR_SHIFT) + +/* General Purpose Register (GPR_PRIVATEn_AUTHEN, n=1..7) */ + +#define CCM_GPR_PR_AUTH_TZ_USER (1 << 8) /* Bit 8: Clock root can be changed in user mode (TZ_USER) */ +#define CCM_GPR_PR_AUTH_TZ_NS (1 << 9) /* Bit 9: Clock root can be changed in non-secure mode (TZ_NS) */ + /* Bit 10: Reserved */ +#define CCM_GPR_PR_AUTH_LOCK_TZ (1 << 11) /* Bit 1: Lock TrustZone settings (LOCK_TZ) */ + /* Bits 12-14: Reserved */ +#define CCM_GPR_PR_AUTH_LOCK_LIST (1 << 12) /* Bit 15: Lock whitelist settings (LOCK_LIST) */ +#define CCM_GPR_PR_AUTH_WHITE_LIST_SHIFT (16) /* Bits 16-31: Allow domains to change clock (WHITE_LIST) */ +#define CCM_GPR_PR_AUTH_WHITE_LIST_MASK (0xffff << CCM_CR_AUTH_WHITE_LIST_SHIFT) + +/* Clock source direct control (OSCPLLn_DIRECT, n=0..18) */ + +#define CCM_OSCPLL_DIR_ON (1 << 0) /* Bit 0: Turn on clock source (ON) */ + /* Bits 1-31: Reserved */ + +/* Clock source LPM status (OSCPLLn_LPM_STATUS0/1, n=0..18) */ + +#define CCM_OSCPLL_LPM_STAT_CPU_MODE_SHIFT (0) /* Bits 0-1: Current mode of CPU */ +#define CCM_OSCPLL_LPM_STAT_CPU_MODE_MASK (0x03 << CCM_OSCPLL_LPM_STAT_CPU_MODE_SHIFT) +#define CCM_OSCPLL_LPM_STAT_CPU_TRANS_REQ_SHIFT (2) /* Bit 2: Domain request pending */ +#define CCM_OSCPLL_LPM_STAT_CPU_TRANS_REQ_MASK (0x01 << CCM_OSCPLL_LPM_STAT_CPU_TRANS_REQ_SHIFT) +# define CCM_OSCPLL_LPM_STAT_ON (0) /* CPU is in RUN mode */ +# define CCM_OSCPLL_LPM_STAT_WAIT (1) /* CPU is in WAIT mode */ +# define CCM_OSCPLL_LPM_STAT_STOP (2) /* CPU is in STOP mode */ +# define CCM_OSCPLL_LPM_STAT_SUSPED (3) /* CPU is in SUSPEND mode */ + +/* CPU domain[n] from OSCPLLn_LPM_STATUS0/1 */ + +#define CCM_OSCPLL_LPM_STAT_CPU_DOMAIN_SHIFT (4) +#define CCM_OSCPLL_LPM_STAT_CPU_DOMAIN(n) ((n) * CCM_OSCPLL_LPM_STAT_CPU_DOMAIN_SHIFT) +#define CCM_OSCPLL_LPM_STAT_CPU_MODE_GET(n, v) (((v) >> CCM_OSCPLL_LPM_STAT_CPU_DOMAIN(n)) & CCM_OSCPLL_LPM_STAT_CPU_MODE_MASK) + +/* Clock source LPM mode (OSCPLLn_LPM_0/1 and _CUR, n=0..18) */ + +#define CCM_OSCPLL_LPM_MODE_SHIFT (0) /* Bits 0-2: Current mode of CPU */ +#define CCM_OSCPLL_LPM_MODE_MASK (0x07 << CCM_OSCPLL_LPM_MODE_SHIFT) +# define CCM_OSCPLL_LPM_MODE_OFF (0) /* Clock is off during all modes */ +# define CCM_OSCPLL_LPM_MODE_RUN (1) /* Clock is on in run mode, but off in WAIT and STOP modes */ +# define CCM_OSCPLL_LPM_MODE_RUNWAIT (2) /* Clock is on in run and wait modes, but off in STOP modes */ +# define CCM_OSCPLL_LPM_MODE_RUNWAITSTOP (3) /* Clock is on during all modes, except SUSPEND mode */ +# define CCM_OSCPLL_LPM_MODE_ALL (4) /* Clock is on during all modes */ + +/* CPU domain[n] from OSCPLLn_LPM_0/1 */ + +#define CCM_OSCPLL_LPM_MODE_CPU_DOMAIN_SHIFT (4) +#define CCM_OSCPLL_LPM_MODE_CPU_DOMAIN(n) ((n) * CCM_OSCPLL_LPM_MODE_CPU_DOMAIN_SHIFT) +#define CCM_OSCPLL_LPM_MODE_CPU_MODE_SET(n, v) ((v) & CCM_OSCPLL_LPM_MODE_MASK << CCM_LPCG_LPM_MODE_CPU_DOMAIN(n)) +#define CCM_OSCPLL_LPM_MODE_CPU_MODE_GET(n, v) (((v) >> CCM_LPCG_LPM_STAT_CPU_DOMAIN(n)) & CCM_OSCPLL_LPM_MODE_MASK) + +/* Clock source working status (OSCPLLn_STATUS0, n=0..18) */ + +#define CCM_OSCPLL_STAT0_ON (1 << 0) /* Bit 0: Clock source is turned on (ON) */ + /* Bits 1-3: Reserved */ +#define CCM_OSCPLL_STAT0_STATUS_EARLY (1 << 4) /* Bit 4: Clock source is active (STATUS_EARLY) */ +#define CCM_OSCPLL_STAT0_STATUS_LATE (1 << 5) /* Bit 5: Clock source is ready to use (STATUS_LATE) */ + /* Bits 6-11: Reserved */ +#define CCM_OSCPLL_STAT0_IN_USE (1 << 12) /* Bit 28: Indicates whether the clock source is being used by active clock roots (IN_USE) */ + /* Bits 16-31: Reserved */ + +/* Clock source low power status (OSCPLLn_STATUS1, n=0..18) */ + +#define CCM_OSCPLL_STAT1_DOM_ACTIVE_SHIFT (0) /* Bits 0-15: Domain active */ +#define CCM_OSCPLL_STAT1_DOM_ACTIVE_MASK (0xffff << CCM_OSCPLL_STAT1_DOM_ACTIVE_SHIFT) +#define CCM_OSCPLL_STAT1_DOM_ENABLE_SHIFT (16) /* Bits 16-32: Domain enabled */ +#define CCM_OSCPLL_STAT1_DOM_ENABLE_MASK (0xffff << CCM_OSCPLL_STAT1_DOM_ENABLE_SHIFT) + +/* Clock source access control (OSCPLLn_AUTHEN, n=0..18) */ + +#define CCM_OSCPLL_AUTH_CPULPM (1 << 2) /* Bit 2: CPU Low Power Mode (CPULPM) */ +#define CCM_OSCPLL_AUTH_AUTO_CTRL (1 << 3) /* Bit 2: Auto mode (AUTO_CTRL) */ +#define CCM_OSCPLL_AUTH_LOCK_MODE (1 << 7) /* Bit 7: Lock low power and access mode (LOCK_MODE) */ +#define CCM_OSCPLL_AUTH_TZ_USER (1 << 8) /* Bit 8: Clock source can be changed in user mode (TZ_USER) */ +#define CCM_OSCPLL_AUTH_TZ_NS (1 << 9) /* Bit 9: Clock source can be changed in non-secure mode (TZ_NS) */ + /* Bit 10: Reserved */ +#define CCM_OSCPLL_AUTH_LOCK_TZ (1 << 11) /* Bit 11: Lock TrustZone settings (LOCK_TZ) */ + /* Bits 12-14: Reserved */ +#define CCM_OSCPLL_AUTH_LOCK_LIST (1 << 15) /* Bit 15: Lock whitelist settings (LOCK_LIST) */ +#define CCM_OSCPLL_AUTH_WHITE_LIST_SHIFT (16) /* Bits 16-31: Allow domains to change clock (WHITE_LIST) */ +#define CCM_OSCPLL_AUTH_WHITE_LIST_MASK (0xffff << CCM_OSCPLL_AUTH_WHITE_LIST_SHIFT) + +/* LPCG direct control (LPCGn_DIRECT, n=0..126) */ + +#define CCM_LPCG_DIR_ON (1 << 0) /* Bit 0: LPCG on (ON) */ + /* Bit 1: Reserved */ +#define CCM_LPCG_ACK_TIMEOUT_EN (1 << 2) /* Bit 2: Ack timeout enable */ + /* Bits 3-31: Reserved */ + +/* Clock source LPM status (LPCGn_LPM_STATUS0/1, n=0..18) */ + +#define CCM_LPCG_LPM_STAT_CPU_MODE_SHIFT (0) /* Bits 0-1: Current mode of CPU */ +#define CCM_LPCG_LPM_STAT_CPU_MODE_MASK (0x03 << CCM_LPCG_LPM_STAT_CPU_MODE_SHIFT) +#define CCM_LPCG_LPM_STAT_CPU_TRANS_REQ_SHIFT (2) /* Bit 2: Domain request pending */ +#define CCM_LPCG_LPM_STAT_CPU_TRANS_REQ_MASK (0x01 << CCM_LPCG_LPM_STAT_CPU_TRANS_REQ_SHIFT) +# define CCM_LPCG_LPM_STAT_ON (0) /* CPU is in RUN mode */ +# define CCM_LPCG_LPM_STAT_WAIT (1) /* CPU is in WAIT mode */ +# define CCM_LPCG_LPM_STAT_STOP (2) /* CPU is in STOP mode */ +# define CCM_LPCG_LPM_STAT_SUSPED (3) /* CPU is in SUSPEND mode */ + +/* CPU domain[n] from OSCPLLn_LPM_STATUS0/1 */ + +#define CCM_LPCG_LPM_STAT_CPU_DOMAIN_SHIFT (4) +#define CCM_LPCG_LPM_STAT_CPU_DOMAIN(n) ((n) * CCM_LPCG_LPM_STAT_CPU_DOMAIN_SHIFT) +#define CCM_LPCG_LPM_STAT_CPU_MODE_GET(n, v) (((v) >> CCM_LPCG_LPM_STAT_CPU_DOMAIN(n)) & CCM_LPCG_LPM_STAT_CPU_MODE_MASK) + +/* Clock source LPM mode (LPCGn_LPM_0/1 and _CUR, n=0..18) */ + +#define CCM_LPCG_LPM_MODE_SHIFT (0) /* Bits 0-2: Current mode of CPU */ +#define CCM_LPCG_LPM_MODE_MASK (0x07 << CCM_LPCG_LPM_MODE_SHIFT) +# define CCM_LPCG_LPM_MODE_OFF (0) /* Clock is off during all modes */ +# define CCM_LPCG_LPM_MODE_RUN (1) /* Clock is on in run mode, but off in WAIT and STOP modes */ +# define CCM_LPCG_LPM_MODE_RUNWAIT (2) /* Clock is on in run and wait modes, but off in STOP modes */ +# define CCM_LPCG_LPM_MODE_RUNWAITSTOP (3) /* Clock is on during all modes, except SUSPEND mode */ +# define CCM_LPCG_LPM_MODE_ALL (4) /* Clock is on during all modes */ + +/* CPU domain[n] from LPCGn_LPM_0/1 */ + +#define CCM_LPCG_LPM_MODE_CPU_DOMAIN_SHIFT (4) +#define CCM_LPCG_LPM_MODE_CPU_DOMAIN(n) ((n) * CCM_LPCG_LPM_MODE_CPU_DOMAIN_SHIFT) +#define CCM_LPCG_LPM_MODE_CPU_MODE_SET(n, v) ((v) & CCM_LPCG_LPM_MODE_MASK << CCM_LPCG_LPM_MODE_CPU_DOMAIN(n)) +#define CCM_LPCG_LPM_MODE_CPU_MODE_GET(n, v) (((v) >> CCM_LPCG_LPM_MODE_CPU_DOMAIN(n)) & CCM_LPCG_LPM_MODE_MASK) + +/* LPCG working status (LPCGn_STATUS0, n=0..126) */ + +#define CCM_LPCG_STAT0_ON (1 << 0) /* Bit 0: Clock source is turned on (ON) */ + /* Bits 1-31 Reserved */ + +/* LPCG low power status (LPCGn_STATUS1, n=0..126) */ + +#define CCM_LPCG_STAT0_ACTIVE_DOMAIN_SHIFT (8) /* Bits 8-11: Domains that own this clock source according to whitelist (ACTIVE_DOMAIN) */ +#define CCM_LPCG_STAT0_ACTIVE_DOMAIN_MASK (0x0f << CCM_LPCG_STAT0_ACTIVE_DOMAIN_SHIFT) +#define CCM_LPCG_STAT0_DOMAIN_ENABLE_SHIFT (8) /* Bits 12-15: Enable status from each domain (DOMAIN_ENABLE) */ +#define CCM_LPCG_STAT0_DOMAIN_ENABLE_MASK (0x0f << CCM_LPCG_STAT0_DOMAIN_ENABLE_SHIFT) + /* Bits 16-31: Reserved */ + +/* LPCG access control (LPCGn_AUTHEN, n=0..126) */ + +#define CCM_LPCG_AUTH_CPULPM (1 << 2) /* Bit 2: CPU Low Power Mode (CPULPM) */ +#define CCM_LPCG_AUTH_LOCK_MODE (1 << 7) /* Bit 7: Lock low power and access mode (LOCK_MODE) */ +#define CCM_LPCG_AUTH_TZ_USER (1 << 8) /* Bit 8: Clock source can be changed in user mode (TZ_USER) */ +#define CCM_LPCG_AUTH_TZ_NS (1 << 9) /* Bit 9: Clock source can be changed in non-secure mode (TZ_NS) */ + /* Bit 10: Reserved */ +#define CCM_LPCG_AUTH_LOCK_TZ (1 << 11) /* Bit 11: Lock TrustZone settings (LOCK_TZ) */ + /* Bits 12-14: Reserved */ +#define CCM_LPCG_AUTH_LOCK_LIST (1 << 15) /* Bit 15: Lock whitelist settings (LOCK_LIST) */ +#define CCM_LPCG_AUTH_WHITE_LIST_SHIFT (16) /* Bits 16-31: Allow domains to change clock (WHITE_LIST) */ +#define CCM_LPCG_AUTH_WHITE_LIST_MASK (0xffff << CCM_LPCG_AUTH_WHITE_LIST_SHIFT) + +/* Clock roots */ + +#define CCM_CR_A55PERIPH 0 /* CLOCK Root Arm A55 Periph. */ +#define CCM_CR_A55MTRBUS 1 /* CLOCK Root Arm A55 MTR BUS. */ +#define CCM_CR_A55 2 /* CLOCK Root Arm A55. */ +#define CCM_CR_M33 3 /* CLOCK Root M33. */ +#define CCM_CR_SENTINEL 4 /* CLOCK Root Sentinel. */ +#define CCM_CR_BUSWAKEUP 5 /* CLOCK Root Bus Wakeup. */ +#define CCM_CR_BUSAON 6 /* CLOCK Root Bus Aon. */ +#define CCM_CR_WAKEUPAXI 7 /* CLOCK Root Wakeup Axi. */ +#define CCM_CR_SWOTRACE 8 /* CLOCK Root Swo Trace. */ +#define CCM_CR_M33SYSTICK 9 /* CLOCK Root M33 Systick. */ +#define CCM_CR_FLEXIO1 10 /* CLOCK Root Flexio1. */ +#define CCM_CR_FLEXIO2 11 /* CLOCK Root Flexio2. */ +#define CCM_CR_LPIT1 12 /* CLOCK Root Lpit1. */ +#define CCM_CR_LPIT2 13 /* CLOCK Root Lpit2. */ +#define CCM_CR_LPTMR1 14 /* CLOCK Root Lptmr1. */ +#define CCM_CR_LPTMR2 15 /* CLOCK Root Lptmr2. */ +#define CCM_CR_TPM1 16 /* CLOCK Root Tpm1. */ +#define CCM_CR_TPM2 17 /* CLOCK Root Tpm2. */ +#define CCM_CR_TPM3 18 /* CLOCK Root Tpm3. */ +#define CCM_CR_TPM4 19 /* CLOCK Root Tpm4. */ +#define CCM_CR_TPM5 20 /* CLOCK Root Tpm5. */ +#define CCM_CR_TPM6 21 /* CLOCK Root Tpm6. */ +#define CCM_CR_FLEXSPI1 22 /* CLOCK Root Flexspi1. */ +#define CCM_CR_CAN1 23 /* CLOCK Root Can1. */ +#define CCM_CR_CAN2 24 /* CLOCK Root Can2. */ +#define CCM_CR_LPUART1 25 /* CLOCK Root Lpuart1. */ +#define CCM_CR_LPUART2 26 /* CLOCK Root Lpuart2. */ +#define CCM_CR_LPUART3 27 /* CLOCK Root Lpuart3. */ +#define CCM_CR_LPUART4 28 /* CLOCK Root Lpuart4. */ +#define CCM_CR_LPUART5 29 /* CLOCK Root Lpuart5. */ +#define CCM_CR_LPUART6 30 /* CLOCK Root Lpuart6. */ +#define CCM_CR_LPUART7 31 /* CLOCK Root Lpuart7. */ +#define CCM_CR_LPUART8 32 /* CLOCK Root Lpuart8. */ +#define CCM_CR_LPI2C1 33 /* CLOCK Root Lpi2c1. */ +#define CCM_CR_LPI2C2 34 /* CLOCK Root Lpi2c2. */ +#define CCM_CR_LPI2C3 35 /* CLOCK Root Lpi2c3. */ +#define CCM_CR_LPI2C4 36 /* CLOCK Root Lpi2c4. */ +#define CCM_CR_LPI2C5 37 /* CLOCK Root Lpi2c5. */ +#define CCM_CR_LPI2C6 38 /* CLOCK Root Lpi2c6. */ +#define CCM_CR_LPI2C7 39 /* CLOCK Root Lpi2c7. */ +#define CCM_CR_LPI2C8 40 /* CLOCK Root Lpi2c8. */ +#define CCM_CR_LPSPI1 41 /* CLOCK Root Lpspi1. */ +#define CCM_CR_LPSPI2 42 /* CLOCK Root Lpspi2. */ +#define CCM_CR_LPSPI3 43 /* CLOCK Root Lpspi3. */ +#define CCM_CR_LPSPI4 44 /* CLOCK Root Lpspi4. */ +#define CCM_CR_LPSPI5 45 /* CLOCK Root Lpspi5. */ +#define CCM_CR_LPSPI6 46 /* CLOCK Root Lpspi6. */ +#define CCM_CR_LPSPI7 47 /* CLOCK Root Lpspi7. */ +#define CCM_CR_LPSPI8 48 /* CLOCK Root Lpspi8. */ +#define CCM_CR_I3C1 49 /* CLOCK Root I3c1. */ +#define CCM_CR_I3C2 50 /* CLOCK Root I3c2. */ +#define CCM_CR_USDHC1 51 /* CLOCK Root Usdhc1. */ +#define CCM_CR_USDHC2 52 /* CLOCK Root Usdhc2. */ +#define CCM_CR_USDHC3 53 /* CLOCK Root Usdhc3. */ +#define CCM_CR_SAI1 54 /* CLOCK Root Sai1. */ +#define CCM_CR_SAI2 55 /* CLOCK Root Sai2. */ +#define CCM_CR_SAI3 56 /* CLOCK Root Sai3. */ +#define CCM_CR_CCMCKO1 57 /* CLOCK Root Ccm Cko1. */ +#define CCM_CR_CCMCKO2 58 /* CLOCK Root Ccm Cko2. */ +#define CCM_CR_CCMCKO3 59 /* CLOCK Root Ccm Cko3. */ +#define CCM_CR_CCMCKO4 60 /* CLOCK Root Ccm Cko4. */ +#define CCM_CR_HSIO 61 /* CLOCK Root Hsio. */ +#define CCM_CR_HSIOUSBTEST60M 62 /* CLOCK Root Hsio Usb Test 60M. */ +#define CCM_CR_HSIOACSCAN80M 63 /* CLOCK Root Hsio Acscan 80M. */ +#define CCM_CR_HSIOACSCAN480M 64 /* CLOCK Root Hsio Acscan 480M. */ +#define CCM_CR_NIC 65 /* CLOCK Root Nic. */ +#define CCM_CR_NICAPB 66 /* CLOCK Root Nic Apb. */ +#define CCM_CR_MLAPB 67 /* CLOCK Root Ml Apb. */ +#define CCM_CR_ML 68 /* CLOCK Root Ml. */ +#define CCM_CR_MEDIAAXI 69 /* CLOCK Root Media Axi. */ +#define CCM_CR_MEDIAAPB 70 /* CLOCK Root Media Apb. */ +#define CCM_CR_MEDIALDB 71 /* CLOCK Root Media Ldb. */ +#define CCM_CR_MEDIADISPPIX 72 /* CLOCK Root Media Disp Pix. */ +#define CCM_CR_CAMPIX 73 /* CLOCK Root Cam Pix. */ +#define CCM_CR_MIPITESTBYTE 74 /* CLOCK Root Mipi Test Byte. */ +#define CCM_CR_MIPIPHYCFG 75 /* CLOCK Root Mipi Phy Cfg. */ +#define CCM_CR_DRAMALT 76 /* CLOCK Root Dram Alt. */ +#define CCM_CR_DRAMAPB 77 /* CLOCK Root Dram Apb. */ +#define CCM_CR_ADC 78 /* CLOCK Root Adc. */ +#define CCM_CR_PDM 79 /* CLOCK Root Pdm. */ +#define CCM_CR_TSTMR1 80 /* CLOCK Root Tstmr1. */ +#define CCM_CR_TSTMR2 81 /* CLOCK Root Tstmr2. */ +#define CCM_CR_MQS1 82 /* CLOCK Root MQS1. */ +#define CCM_CR_MQS2 83 /* CLOCK Root MQS2. */ +#define CCM_CR_AUDIOXCVR 84 /* CLOCK Root Audio XCVR. */ +#define CCM_CR_SPDIF 85 /* CLOCK Root Spdif. */ +#define CCM_CR_ENET 86 /* CLOCK Root Enet. */ +#define CCM_CR_ENETTIMER1 87 /* CLOCK Root Enet Timer1. */ +#define CCM_CR_ENETTIMER2 88 /* CLOCK Root Enet Timer2. */ +#define CCM_CR_ENETREF 89 /* CLOCK Root Enet Ref. */ +#define CCM_CR_ENETREFPHY 90 /* CLOCK Root Enet Ref Phy. */ +#define CCM_CR_I3C1SLOW 91 /* CLOCK Root I3c1Slow. */ +#define CCM_CR_I3C2SLOW 92 /* CLOCK Root I3c2Slow. */ +#define CCM_CR_USBPHYBURUNIN 93 /* CLOCK Root Usb Phy Burunin. */ +#define CCM_CR_PALCAMESCAN 94 /* CLOCK Root Pal Came Scan. */ + +/* Clock gates */ + +#define CCM_LPCG_A55 0 +#define CCM_LPCG_CM33 1 +#define CCM_LPCG_ARM_TROUT 2 +#define CCM_LPCG_SENTINEL 3 +#define CCM_LPCG_SIM_WAKEUP 4 +#define CCM_LPCG_SIM_AON 5 +#define CCM_LPCG_SIM_MEGA 6 +#define CCM_LPCG_ANADIG 7 +#define CCM_LPCG_SRC 8 +#define CCM_LPCG_CCM 9 +#define CCM_LPCG_GPC 10 +#define CCM_LPCG_ADC1 11 +#define CCM_LPCG_WDOG1 12 +#define CCM_LPCG_WDOG2 13 +#define CCM_LPCG_WDOG3 14 +#define CCM_LPCG_WDOG4 15 +#define CCM_LPCG_WDOG5 16 +#define CCM_LPCG_SEMA1 17 +#define CCM_LPCG_SEMA2 18 +#define CCM_LPCG_MU_A 19 +#define CCM_LPCG_MU_B 20 +#define CCM_LPCG_EDMA3 21 +#define CCM_LPCG_EDMA4 22 +#define CCM_LPCG_ROMCP_A55 23 +#define CCM_LPCG_ROMCP_M33 24 +#define CCM_LPCG_FLEXSPI1 25 +#define CCM_LPCG_AON_TRDC 26 +#define CCM_LPCG_WKUP_TRDC 27 +#define CCM_LPCG_OCOTP 28 +#define CCM_LPCG_BBSM_HP 29 +#define CCM_LPCG_BBSM 30 +#define CCM_LPCG_CSTRACE 31 +#define CCM_LPCG_CSSWO 32 +#define CCM_LPCG_IOMUXC 33 +#define CCM_LPCG_GPIO1 34 +#define CCM_LPCG_GPIO2 35 +#define CCM_LPCG_GPIO3 36 +#define CCM_LPCG_GPIO4 37 +#define CCM_LPCG_FLEXIO1 38 +#define CCM_LPCG_FLEXIO2 39 +#define CCM_LPCG_LPIT1 40 +#define CCM_LPCG_LPIT2 41 +#define CCM_LPCG_LPTMR1 42 +#define CCM_LPCG_LPTMR2 43 +#define CCM_LPCG_TPM1 44 +#define CCM_LPCG_TPM2 45 +#define CCM_LPCG_TPM3 46 +#define CCM_LPCG_TPM4 47 +#define CCM_LPCG_TPM5 48 +#define CCM_LPCG_TPM6 49 +#define CCM_LPCG_CAN1 50 +#define CCM_LPCG_CAN2 51 +#define CCM_LPCG_LPUART1 52 +#define CCM_LPCG_LPUART2 53 +#define CCM_LPCG_LPUART3 54 +#define CCM_LPCG_LPUART4 55 +#define CCM_LPCG_LPUART5 56 +#define CCM_LPCG_LPUART6 57 +#define CCM_LPCG_LPUART7 58 +#define CCM_LPCG_LPUART8 59 +#define CCM_LPCG_LPI2C1 60 +#define CCM_LPCG_LPI2C2 61 +#define CCM_LPCG_LPI2C3 62 +#define CCM_LPCG_LPI2C4 63 +#define CCM_LPCG_LPI2C5 64 +#define CCM_LPCG_LPI2C6 65 +#define CCM_LPCG_LPI2C7 66 +#define CCM_LPCG_LPI2C8 67 +#define CCM_LPCG_LPSPI1 68 +#define CCM_LPCG_LPSPI2 69 +#define CCM_LPCG_LPSPI3 70 +#define CCM_LPCG_LPSPI4 71 +#define CCM_LPCG_LPSPI5 72 +#define CCM_LPCG_LPSPI6 73 +#define CCM_LPCG_LPSPI7 74 +#define CCM_LPCG_LPSPI8 75 +#define CCM_LPCG_I3C1 76 +#define CCM_LPCG_I3C2 77 +#define CCM_LPCG_USDHC1 78 +#define CCM_LPCG_USDHC2 79 +#define CCM_LPCG_USDHC3 80 +#define CCM_LPCG_SAI1 81 +#define CCM_LPCG_SAI2 82 +#define CCM_LPCG_SAI3 83 +#define CCM_LPCG_SSI_W2AO 84 +#define CCM_LPCG_SSI_AO2W 85 +#define CCM_LPCG_MIPI_CSI 86 +#define CCM_LPCG_MIPI_DSI 87 +#define CCM_LPCG_LVDS 88 +#define CCM_LPCG_LCDIF 89 +#define CCM_LPCG_PXP 90 +#define CCM_LPCG_ISI 91 +#define CCM_LPCG_NIC_MEDIA 92 +#define CCM_LPCG_DDR_DFI 93 +#define CCM_LPCG_DDR_CTL 94 +#define CCM_LPCG_DDR_DFI_CTL 95 +#define CCM_LPCG_DDR_SSI 96 +#define CCM_LPCG_DDR_BYPASS 97 +#define CCM_LPCG_DDR_APB 98 +#define CCM_LPCG_DDR_DRAMPLL 99 +#define CCM_LPCG_DDR_CLK_CTL 100 +#define CCM_LPCG_NIC_CENTRAL 101 +#define CCM_LPCG_GIC600 102 +#define CCM_LPCG_NIC_APB 103 +#define CCM_LPCG_USB_CONTROLLER 104 +#define CCM_LPCG_USB_TEST_60M 105 +#define CCM_LPCG_HSIO_TROUT_24M 106 +#define CCM_LPCG_PDM 107 +#define CCM_LPCG_MQS1 108 +#define CCM_LPCG_MQS2 109 +#define CCM_LPCG_AUD_XCVR 110 +#define CCM_LPCG_NICMIX_MECC 111 +#define CCM_LPCG_SPDIF 112 +#define CCM_LPCG_SSI_ML2NIC 113 +#define CCM_LPCG_SSI_MED2NIC 114 +#define CCM_LPCG_SSI_HSIO2NIC 115 +#define CCM_LPCG_SSI_W2NIC 116 +#define CCM_LPCG_SSI_NIC2W 117 +#define CCM_LPCG_SSI_NIC2DDR 118 +#define CCM_LPCG_HSIO_32K 119 +#define CCM_LPCG_ENET1 120 +#define CCM_LPCG_ENET_QOS 121 +#define CCM_LPCG_SYS_CNT 122 +#define CCM_LPCG_TSTMR1 123 +#define CCM_LPCG_TSTMR2 124 +#define CCM_LPCG_TMC 125 +#define CCM_LPCG_PMRO 126 + +/* Shared register indices */ + +#define CCM_SHARED_EXT_CLK 0 +#define CCM_SHARED_A55_CLK 1 +#define CCM_SHARED_DRAM_CLK 2 + +/* Other parameters */ + +#define ROOT_MUX_MAX 4 /* Count of root clock MUX options */ +#define CCM_CR_COUNT 94 /* Count of clock roots */ +#define CCM_LPCG_COUNT 126 /* Counte of clock gates */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* NOTE: The PLL input (IN) clocks are not available in clock tree */ + +enum ccm_clock_name_e +{ + OSC_24M = 0, /* 24MHZ OSCILLATOR. */ + ARM_PLL = 1, /* ARM PLL */ + ARM_PLLOUT = 2, /* ARM PLL OUT */ + SYS_PLL1_IN = 3, /* SYSTEM PLL1 IN */ + SYS_PLL1PFD0_IN = 4, /* SYSTEM PLL1 PFD0 IN */ + SYS_PLL1PFD0 = 5, /* SYSTEM PLL1 PFD0 */ + SYS_PLL1PFD0DIV2 = 6, /* SYSTEM PLL1 PFD0 DIV2 */ + SYS_PLL1PFD1_IN = 7, /* SYSTEM PLL1 PFD1 IN */ + SYS_PLL1PFD1 = 8, /* SYSTEM PLL1 PFD1 */ + SYS_PLL1PFD1DIV2 = 9, /* SYSTEM PLL1 PFD1 DIV2 */ + SYS_PLL1PFD2_IN = 10, /* SYSTEM PLL1 PFD2 IN */ + SYS_PLL1PFD2 = 11, /* SYSTEM PLL1 PFD2 */ + SYS_PLL1PFD2DIV2 = 12, /* SYSTEM PLL1 PFD2 DIV2 */ + AUDIO_PLL1 = 13, /* AUDIO PLL1 */ + AUDIO_PLL1OUT = 14, /* AUDIO PLL1 OUT */ + DRAM_PLL = 15, /* DRAM PLL */ + DRAM_PLLOUT = 16, /* DRAM PLL OUT */ + VIDEO_PLL1 = 17, /* VIDEO PLL1 */ + VIDEO_PLL1OUT = 18, /* VIDEO PLL1 OUT */ + EXT = 19, /* EXT */ +}; + +/* This contains a simple LUT to find the corresponding MUX index per root */ + +static const int g_ccm_root_mux[][ROOT_MUX_MAX] = +{ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Arm A55 Periph */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Arm A55 MTR BUS */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Arm A55 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* M33 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Sentinel */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Bus Wakeup */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Bus Aon */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Wakeup Axi */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Swo Trace */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* M33 Systick */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Flexio1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Flexio2 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpit1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpit2 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lptmr1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lptmr2 */ + {OSC_24M, SYS_PLL1PFD0, AUDIO_PLL1OUT, EXT}, /* Tpm1 */ + {OSC_24M, SYS_PLL1PFD0, AUDIO_PLL1OUT, EXT}, /* Tpm2 */ + {OSC_24M, SYS_PLL1PFD0, AUDIO_PLL1OUT, EXT}, /* Tpm3 */ + {OSC_24M, SYS_PLL1PFD0, AUDIO_PLL1OUT, EXT}, /* Tpm4 */ + {OSC_24M, SYS_PLL1PFD0, AUDIO_PLL1OUT, EXT}, /* Tpm5 */ + {OSC_24M, SYS_PLL1PFD0, AUDIO_PLL1OUT, EXT}, /* Tpm6 */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Flexspi1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Can1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Can2 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpuart1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpuart2 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpuart3 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpuart4 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpuart5 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpuart6 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpuart7 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpuart8 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpi2c1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpi2c2 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpi2c3 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpi2c4 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpi2c5 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpi2c6 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpi2c7 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpi2c8 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpspi1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpspi2 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpspi3 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpspi4 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpspi5 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpspi6 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpspi7 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Lpspi8 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* I3c1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* I3c2 */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Usdhc1 */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Usdhc2 */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Usdhc3 */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, EXT}, /* Sai1 */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, EXT}, /* Sai2 */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, EXT}, /* Sai3 */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, AUDIO_PLL1OUT}, /* Ccm Cko1 */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, VIDEO_PLL1OUT}, /* Ccm Cko2 */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, AUDIO_PLL1OUT}, /* Ccm Cko3 */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, VIDEO_PLL1OUT}, /* Ccm Cko4 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Hsio */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Hsio Usb Test 60M */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Hsio Acscan 80M */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, SYS_PLL1PFD2}, /* Hsio Acscan 480M */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Nic */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Nic Apb */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Ml Apb */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Ml */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Media Axi */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Media Apb */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, SYS_PLL1PFD0}, /* Media Ldb */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, SYS_PLL1PFD0}, /* Media Disp Pix */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, SYS_PLL1PFD0}, /* Cam Pix */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, SYS_PLL1PFD0}, /* Mipi Test Byte */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, SYS_PLL1PFD0}, /* Mipi Phy Cfg */ + {OSC_24M, SYS_PLL1PFD0, SYS_PLL1PFD1, SYS_PLL1PFD2}, /* Dram Alt */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, SYS_PLL1PFD2DIV2}, /* Dram Apb */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Adc */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, EXT}, /* Pdm */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Tstmr1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Tstmr2 */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, EXT}, /* Mqs1 */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, EXT}, /* Mqs2 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, SYS_PLL1PFD2DIV2}, /* Audio XCVR */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, EXT}, /* Spdif */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, SYS_PLL1PFD2DIV2}, /* Enet */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Enet Timer1 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Enet Timer2 */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, SYS_PLL1PFD2DIV2}, /* Enet Ref */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Enet Ref Phy */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* I3c1 Slow */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* I3c2 Slow */ + {OSC_24M, SYS_PLL1PFD0DIV2, SYS_PLL1PFD1DIV2, VIDEO_PLL1OUT}, /* Usb Phy Burunin */ + {OSC_24M, AUDIO_PLL1OUT, VIDEO_PLL1OUT, SYS_PLL1PFD2}, /* Pal Came Scan */ +}; + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_CCM_H */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_dmamux.h b/arch/arm64/src/imx9/hardware/imx93/imx93_dmamux.h new file mode 100644 index 0000000000000..6301856ba547d --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_dmamux.h @@ -0,0 +1,209 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx93/imx93_dmamux.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_DMAMUX_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_DMAMUX_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "imx93_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Identify channel MUX from 9th bit */ + +#define EDMA3_MUX_ID 0x0000 +#define EDMA4_MUX_ID 0x0100 +#define EDMA_MUX_ID_MASK 0xff00 +#define EDMA_MUX_MASK 0x00ff + +/* eDMA3 MUXs */ + +#define DMA_REQUEST_DISABLED (0) /**< Channel disabled */ +#define DMA_REQUEST_MUXCAN1 (1 | EDMA3_MUX_ID) /**< CAN1 */ +#define DMA_REQUEST_MUXGPIO1_0 (3 | EDMA3_MUX_ID) /**< GPIO1 channel 0 */ +#define DMA_REQUEST_MUXGPIO1_1 (4 | EDMA3_MUX_ID) /**< GPIO1 channel 1 */ +#define DMA_REQUEST_MUXI3C1TOBUS (5 | EDMA3_MUX_ID) /**< I3C1 To-bus Request */ +#define DMA_REQUEST_MUXI3C1FROMBUS (6 | EDMA3_MUX_ID) /**< I3C1 From-bus Request */ +#define DMA_REQUEST_MUXLPI2C1TX (7 | EDMA3_MUX_ID) /**< LPI2C1 */ +#define DMA_REQUEST_MUXLPI2C1RX (8 | EDMA3_MUX_ID) /**< LPI2C1 */ +#define DMA_REQUEST_MUXLPI2C2TX (9 | EDMA3_MUX_ID) /**< LPI2C2 */ +#define DMA_REQUEST_MUXLPI2C2RX (10 | EDMA3_MUX_ID) /**< LPI2C2 */ +#define DMA_REQUEST_MUXLPSPI1TX (11 | EDMA3_MUX_ID) /**< LPSPI1 Transmit */ +#define DMA_REQUEST_MUXLPSPI1RX (12 | EDMA3_MUX_ID) /**< LPSPI1 Receive */ +#define DMA_REQUEST_MUXLPSPI2TX (13 | EDMA3_MUX_ID) /**< LPSPI2 Transmit */ +#define DMA_REQUEST_MUXLPSPI2RX (14 | EDMA3_MUX_ID) /**< LPSPI2 Receive */ +#define DMA_REQUEST_MUXLPTMR1 (15 | EDMA3_MUX_ID) /**< LPTMR1 Request */ +#define DMA_REQUEST_MUXLPUART1TX (16 | EDMA3_MUX_ID) /**< LPUART1 Transmit */ +#define DMA_REQUEST_MUXLPUART1RX (17 | EDMA3_MUX_ID) /**< LPUART1 Receive */ +#define DMA_REQUEST_MUXLPUART2TX (18 | EDMA3_MUX_ID) /**< LPUART2 Transmit */ +#define DMA_REQUEST_MUXLPUART2RX (19 | EDMA3_MUX_ID) /**< LPUART2 Receive */ +#define DMA_REQUEST_MUXEDGELOCK (20 | EDMA3_MUX_ID) /**< Edgelock enclave DMA Request */ +#define DMA_REQUEST_MUXSAI1TX (21 | EDMA3_MUX_ID) /**< SAI1 Transmit */ +#define DMA_REQUEST_MUXSAI1RX (22 | EDMA3_MUX_ID) /**< SAI1 Receive */ +#define DMA_REQUEST_MUXTPM1_0_2 (23 | EDMA3_MUX_ID) /**< TPM1 request 0 and request 2 */ +#define DMA_REQUEST_MUXTPM1_1_3 (24 | EDMA3_MUX_ID) /**< TPM1 request 1 and request 3 */ +#define DMA_REQUEST_MUXTPM1OVERFLOW (25 | EDMA3_MUX_ID) /**< TPM1 Overflow request */ +#define DMA_REQUEST_MUXTPM2_0_2 (26 | EDMA3_MUX_ID) /**< TPM2 request 0 and request 2 */ +#define DMA_REQUEST_MUXTPM2_1_3 (27 | EDMA3_MUX_ID) /**< TPM2 request 1 and request 3 */ +#define DMA_REQUEST_MUXTPM2OVERFLOW (28 | EDMA3_MUX_ID) /**< TPM2 Overflow request */ +#define DMA_REQUEST_MUXPDM (29 | EDMA3_MUX_ID) /**< PDM */ +#define DMA_REQUEST_MUXADC1 (30 | EDMA3_MUX_ID) /**< ADC1 */ + +#define DMA3_REQUEST_MUX_COUNT (31) + +/* eDMA4 MUXs */ + +#define DMA_REQUEST_MUXCAN2 (1 | EDMA4_MUX_ID) /**< CAN2 */ +#define DMA_REQUEST_MUXGPIO2_0 (2 | EDMA4_MUX_ID) /**< GPIO2 channel 0 */ +#define DMA_REQUEST_MUXGPIO2_1 (3 | EDMA4_MUX_ID) /**< GPIO2 channel 1 */ +#define DMA_REQUEST_MUXGPIO3_0 (4 | EDMA4_MUX_ID) /**< GPIO3 channel 0 */ +#define DMA_REQUEST_MUXGPIO3_1 (5 | EDMA4_MUX_ID) /**< GPIO3 channel 1 */ +#define DMA_REQUEST_MUXI3C2TOBUS (6 | EDMA4_MUX_ID) /**< I3C2 To-bus Request */ +#define DMA_REQUEST_MUXI3C2FROMBUS (7 | EDMA4_MUX_ID) /**< I3C2 From-bus Request */ +#define DMA_REQUEST_MUXLPI2C3TX (8 | EDMA4_MUX_ID) /**< LPI2C3 */ +#define DMA_REQUEST_MUXLPI2C3RX (9 | EDMA4_MUX_ID) /**< LPI2C3 */ +#define DMA_REQUEST_MUXLPI2C4TX (10 | EDMA4_MUX_ID) /**< LPI2C4 */ +#define DMA_REQUEST_MUXLPI2C4RX (11 | EDMA4_MUX_ID) /**< LPI2C4 */ +#define DMA_REQUEST_MUXLPSPI3TX (12 | EDMA4_MUX_ID) /**< LPSPI3 Transmit */ +#define DMA_REQUEST_MUXLPSPI3RX (13 | EDMA4_MUX_ID) /**< LPSPI3 Receive */ +#define DMA_REQUEST_MUXLPSPI4TX (14 | EDMA4_MUX_ID) /**< LPSPI4 Transmit */ +#define DMA_REQUEST_MUXLPSPI4RX (15 | EDMA4_MUX_ID) /**< LPSPI4 Receive */ +#define DMA_REQUEST_MUXLPTMR2 (16 | EDMA4_MUX_ID) /**< LPTMR2 Request */ +#define DMA_REQUEST_MUXLPUART3TX (17 | EDMA4_MUX_ID) /**< LPUART3 Transmit */ +#define DMA_REQUEST_MUXLPUART3RX (18 | EDMA4_MUX_ID) /**< LPUART3 Receive */ +#define DMA_REQUEST_MUXLPUART4TX (19 | EDMA4_MUX_ID) /**< LPUART4 Transmit */ +#define DMA_REQUEST_MUXLPUART4RX (20 | EDMA4_MUX_ID) /**< LPUART4 Receive */ +#define DMA_REQUEST_MUXLPUART5TX (21 | EDMA4_MUX_ID) /**< LPUART5 Transmit */ +#define DMA_REQUEST_MUXLPUART5RX (22 | EDMA4_MUX_ID) /**< LPUART5 Receive */ +#define DMA_REQUEST_MUXLPUART6TX (23 | EDMA4_MUX_ID) /**< LPUART6 Transmit */ +#define DMA_REQUEST_MUXLPUART6RX (24 | EDMA4_MUX_ID) /**< LPUART6 Receive */ +#define DMA_REQUEST_MUXTPM3_0_2 (25 | EDMA4_MUX_ID) /**< TPM3 request 0 and request 2 */ +#define DMA_REQUEST_MUXTPM3_1_3 (26 | EDMA4_MUX_ID) /**< TPM3 request 1 and request 3 */ +#define DMA_REQUEST_MUXTPM3OVERFLOW (27 | EDMA4_MUX_ID) /**< TPM3 Overflow request */ +#define DMA_REQUEST_MUXTPM4_0_2 (28 | EDMA4_MUX_ID) /**< TPM4 request 0 and request 2 */ +#define DMA_REQUEST_MUXTPM4_1_3 (29 | EDMA4_MUX_ID) /**< TPM4 request 1 and request 3 */ +#define DMA_REQUEST_MUXTPM4OVERFLOW (30 | EDMA4_MUX_ID) /**< TPM4 Overflow request */ +#define DMA_REQUEST_MUXTPM5_0_2 (31 | EDMA4_MUX_ID) /**< TPM5 request 0 and request 2 */ +#define DMA_REQUEST_MUXTPM5_1_3 (32 | EDMA4_MUX_ID) /**< TPM5 request 1 and request 3 */ +#define DMA_REQUEST_MUXTPM5OVERFLOW (33 | EDMA4_MUX_ID) /**< TPM5 Overflow request */ +#define DMA_REQUEST_MUXTPM6_0_2 (34 | EDMA4_MUX_ID) /**< TPM6 request 0 and request 2 */ +#define DMA_REQUEST_MUXTPM6_1_3 (35 | EDMA4_MUX_ID) /**< TPM6 request 1 and request 3 */ +#define DMA_REQUEST_MUXTPM6OVERFLOW (36 | EDMA4_MUX_ID) /**< TPM6 Overflow request */ +#define DMA_REQUEST_MUXFLEXIO1_0 (37 | EDMA4_MUX_ID) /**< FlexIO1 Request0 */ +#define DMA_REQUEST_MUXFLEXIO1_1 (38 | EDMA4_MUX_ID) /**< FlexIO1 Request1 */ +#define DMA_REQUEST_MUXFLEXIO1_2 (39 | EDMA4_MUX_ID) /**< FlexIO1 Request2 */ +#define DMA_REQUEST_MUXFLEXIO1_3 (40 | EDMA4_MUX_ID) /**< FlexIO1 Request3 */ +#define DMA_REQUEST_MUXFLEXIO1_4 (41 | EDMA4_MUX_ID) /**< FlexIO1 Request4 */ +#define DMA_REQUEST_MUXFLEXIO1_5 (42 | EDMA4_MUX_ID) /**< FlexIO1 Request5 */ +#define DMA_REQUEST_MUXFLEXIO1_6 (43 | EDMA4_MUX_ID) /**< FlexIO1 Request6 */ +#define DMA_REQUEST_MUXFLEXIO1_7 (44 | EDMA4_MUX_ID) /**< FlexIO1 Request7 */ +#define DMA_REQUEST_MUXFLEXIO2_0 (45 | EDMA4_MUX_ID) /**< FlexIO2 Request0 */ +#define DMA_REQUEST_MUXFLEXIO2_1 (46 | EDMA4_MUX_ID) /**< FlexIO2 Request1 */ +#define DMA_REQUEST_MUXFLEXIO2_2 (47 | EDMA4_MUX_ID) /**< FlexIO2 Request2 */ +#define DMA_REQUEST_MUXFLEXIO2_3 (48 | EDMA4_MUX_ID) /**< FlexIO2 Request3 */ +#define DMA_REQUEST_MUXFLEXIO2_4 (49 | EDMA4_MUX_ID) /**< FlexIO2 Request4 */ +#define DMA_REQUEST_MUXFLEXIO2_5 (50 | EDMA4_MUX_ID) /**< FlexIO2 Request5 */ +#define DMA_REQUEST_MUXFLEXIO2_6 (51 | EDMA4_MUX_ID) /**< FlexIO2 Request6 */ +#define DMA_REQUEST_MUXFLEXIO2_7 (52 | EDMA4_MUX_ID) /**< FlexIO2 Request7 */ +#define DMA_REQUEST_MUXFLEXSPI1TX (53 | EDMA4_MUX_ID) /**< FlexSPI1 Transmit */ +#define DMA_REQUEST_MUXFLEXSPI1RX (54 | EDMA4_MUX_ID) /**< FlexSPI1 Receive */ +#define DMA_REQUEST_MUXSAI2TX (58 | EDMA4_MUX_ID) /**< SAI2 Transmit */ +#define DMA_REQUEST_MUXSAI2RX (59 | EDMA4_MUX_ID) /**< SAI2 Receive */ +#define DMA_REQUEST_MUXSAI3TX (60 | EDMA4_MUX_ID) /**< SAI3 Transmit */ +#define DMA_REQUEST_MUXSAI3RX (61 | EDMA4_MUX_ID) /**< SAI3 Receive */ +#define DMA_REQUEST_MUXGPIO4_0 (62 | EDMA4_MUX_ID) /**< GPIO4 channel 0 */ +#define DMA_REQUEST_MUXGPIO4_1 (63 | EDMA4_MUX_ID) /**< GPIO4 channel 1 */ +#define DMA_REQUEST_MUXSPDIF (65 | EDMA4_MUX_ID) /**< SPDIF */ +#define DMA_REQUEST_MUXSPDIF_1 (66 | EDMA4_MUX_ID) /**< SPDIF */ +#define DMA_REQUEST_MUXENET (67 | EDMA4_MUX_ID) /**< ENET */ +#define DMA_REQUEST_MUXENET_1 (68 | EDMA4_MUX_ID) /**< ENET */ +#define DMA_REQUEST_MUXENET_2 (69 | EDMA4_MUX_ID) /**< ENET */ +#define DMA_REQUEST_MUXENET_3 (70 | EDMA4_MUX_ID) /**< ENET */ +#define DMA_REQUEST_MUXLPI2C5TX (71 | EDMA4_MUX_ID) /**< LPI2C5 */ +#define DMA_REQUEST_MUXLPI2C5RX (72 | EDMA4_MUX_ID) /**< LPI2C5 */ +#define DMA_REQUEST_MUXLPI2C6TX (73 | EDMA4_MUX_ID) /**< LPI2C6 */ +#define DMA_REQUEST_MUXLPI2C6RX (74 | EDMA4_MUX_ID) /**< LPI2C6 */ +#define DMA_REQUEST_MUXLPI2C7TX (75 | EDMA4_MUX_ID) /**< LPI2C7 */ +#define DMA_REQUEST_MUXLPI2C7RX (76 | EDMA4_MUX_ID) /**< LPI2C7 */ +#define DMA_REQUEST_MUXLPI2C8TX (77 | EDMA4_MUX_ID) /**< LPI2C8 */ +#define DMA_REQUEST_MUXLPI2C8RX (78 | EDMA4_MUX_ID) /**< LPI2C8 */ +#define DMA_REQUEST_MUXLPSPI5TX (79 | EDMA4_MUX_ID) /**< LPSPI5 Transmit */ +#define DMA_REQUEST_MUXLPSPI5RX (80 | EDMA4_MUX_ID) /**< LPSPI5 Receive */ +#define DMA_REQUEST_MUXLPSPI6TX (81 | EDMA4_MUX_ID) /**< LPSPI6 Transmit */ +#define DMA_REQUEST_MUXLPSPI6RX (82 | EDMA4_MUX_ID) /**< LPSPI6 Receive */ +#define DMA_REQUEST_MUXLPSPI7TX (83 | EDMA4_MUX_ID) /**< LPSPI7 Transmit */ +#define DMA_REQUEST_MUXLPSPI7RX (84 | EDMA4_MUX_ID) /**< LPSPI7 Receive */ +#define DMA_REQUEST_MUXLPSPI8TX (85 | EDMA4_MUX_ID) /**< LPSPI8 Transmit */ +#define DMA_REQUEST_MUXLPSPI8RX (86 | EDMA4_MUX_ID) /**< LPSPI8 Receive */ +#define DMA_REQUEST_MUXLPUART7TX (87 | EDMA4_MUX_ID) /**< LPUART7 Transmit */ +#define DMA_REQUEST_MUXLPUART7RX (88 | EDMA4_MUX_ID) /**< LPUART7 Receive */ +#define DMA_REQUEST_MUXLPUART8TX (89 | EDMA4_MUX_ID) /**< LPUART8 Transmit */ +#define DMA_REQUEST_MUXLPUART8RX (90 | EDMA4_MUX_ID) /**< LPUART8 Receive */ +#define DMA_REQUEST_MUXENET_QOS (91 | EDMA4_MUX_ID) /**< ENET_QOS */ +#define DMA_REQUEST_MUXENET_QOS_1 (92 | EDMA4_MUX_ID) /**< ENET_QOS */ +#define DMA_REQUEST_MUXENET_QOS_2 (93 | EDMA4_MUX_ID) /**< ENET_QOS */ +#define DMA_REQUEST_MUXENET_QOS_3 (94 | EDMA4_MUX_ID) /**< ENET_QOS */ + +#define DMA4_REQUEST_MUX_COUNT (95) + +/* Combined MUX count (eDMA3 and eDMA4) */ + +#define DMA_REQUEST_MUX_COUNT (DMA3_REQUEST_MUX_COUNT + DMA4_REQUEST_MUX_COUNT) + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_dmamux_get_dmabase + * + * Description: + * Get DMA engine base address from MUX identifier. + * + * Input Parameters: + * dmamux - The DMA MUX identifier. + * + * Returned Value: + * Base address of the associated DMA engine. + * + ****************************************************************************/ + +static inline uintptr_t imx9_dmamux_get_dmabase(uint16_t dmamux) +{ + if ((dmamux & EDMA_MUX_ID_MASK) == EDMA3_MUX_ID) + { + return IMX9_DMA3_BASE; + } + else + { + return IMX9_DMA4_BASE; + } +} + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_DMAMUX_H */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_edma.h b/arch/arm64/src/imx9/hardware/imx93/imx93_edma.h new file mode 100644 index 0000000000000..968b6e09db3fe --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_edma.h @@ -0,0 +1,436 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx93/imx93_edma.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_EDMA_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_EDMA_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "imx93_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* eDMA3 / eDMA4 Register Offsets */ + +#define IMX9_EDMA_CSR_OFFSET (0x000000) /* Management Page Control Register (CSR) */ +#define IMX9_EDMA_ES_OFFSET (0x000004) /* Management Page Error Status Register (ES) */ +#define IMX9_EDMA_CH_GRPRI_OFFSET(n) (0x000100 + ((n) << 2)) /* Channel n Arbitration Group Register (CHn_GRPRI) */ + +/* eDMA3 only */ + +#define IMX9_EDMA_INT_OFFSET (0x000008) /* Management Page Interrupt Request Status Register (INT) */ +#define IMX9_EDMA_HRS_OFFSET (0x00000c) /* Management Page Hardware Request Status Register (HRS) */ + +/* eDMA4 only */ + +#define IMX9_EDMA_INT_LOW_OFFSET (0x000008) /* Management Page Interrupt Request Status Register (INT_LOW) */ +#define IMX9_EDMA_INT_HIGH_OFFSET (0x00000c) /* Management Page Interrupt Request Status Register (INT_HIGH) */ +#define IMX9_EDMA_HRS_LOW_OFFSET (0x000010) /* Management Page Hardware Request Status Register (HRS_LOW) */ +#define IMX9_EDMA_HRS_HIGH_OFFSET (0x000014) /* Management Page Hardware Request Status Register (HRS_HIGH) */ + +/* eDMA3 / eDMA4 Register Addresses */ + +#define IMX9_EDMA_CSR(n) ((n) + IMX9_EDMA_CSR_OFFSET) +#define IMX9_EDMA_ES(n) ((n) + IMX9_EDMA_ES_OFFSET) +#define IMX9_EDMA_CH_GRPRI(n,c) ((n) + IMX9_EDMA_CH_GRPRI_OFFSET(n)) + +/* eDMA3 only */ + +#define IMX9_EDMA_INT (IMX9_DMA3_BASE + IMX9_EDMA_INT_OFFSET) +#define IMX9_EDMA_HRS (IMX9_DMA3_BASE + IMX9_EDMA_HRS_OFFSET) + +/* eDMA4 only */ + +#define IMX9_EDMA_INT_LOW (IMX9_DMA4_BASE + IMX9_EDMA_INT_LOW_OFFSET) +#define IMX9_EDMA_INT_HIGH (IMX9_DMA4_BASE + IMX9_EDMA_INT_HIGH_OFFSET) +#define IMX9_EDMA_HRS_LOW (IMX9_DMA4_BASE + IMX9_EDMA_HRS_LOW_OFFSET) +#define IMX9_EDMA_HRS_HIGH (IMX9_DMA4_BASE + IMX9_EDMA_HRS_HIGH_OFFSET) + +/* eDMA Transfer Control Descriptor (TCD) Register Offsets */ + +#define IMX9_EDMA_CH_CSR_OFFSET (0x000000) /* Channel Control and Status Register (CH0_CSR) */ +#define IMX9_EDMA_CH_ES_OFFSET (0x000004) /* Channel Error Status Register (CH0_ES) */ +#define IMX9_EDMA_CH_INT_OFFSET (0x000008) /* Channel Interrupt Status Register (CH0_INT) */ +#define IMX9_EDMA_CH_SBR_OFFSET (0x00000c) /* Channel System Bus Register (CH0_SBR) */ +#define IMX9_EDMA_CH_PRI_OFFSET (0x000010) /* Channel Priority Register (CH0_PRI) */ +#define IMX9_EDMA_CH_MUX_OFFSET (0x000014) /* Channel Multiplexor Configuration (CH0_MUX) (eDMA4 only) */ +#define IMX9_EDMA_CH_MATTR_OFFSET (0x000018) /* Memory Attributes Register (CH0_MATTR) (eDMA4 only) */ +#define IMX9_EDMA_TCD_SADDR_OFFSET (0x000020) /* TCD Source Address Register (TCD0_SADDR) */ +#define IMX9_EDMA_TCD_SOFF_OFFSET (0x000024) /* TCD Signed Source Address Offset Register (TCD0_SOFF) */ +#define IMX9_EDMA_TCD_ATTR_OFFSET (0x000026) /* TCD Transfer Attributes (TCD0_ATTR) */ +#define IMX9_EDMA_TCD_NBYTES_OFFSET (0x000028) /* TCD Transfer Size (TCD0_NBYTES) */ +#define IMX9_EDMA_TCD_SLAST_SDA_OFFSET (0x00002c) /* TCD Last Source Address Adjustment / Store DADDR Address Register (TCD0_SLAST_SDA) */ +#define IMX9_EDMA_TCD_DADDR_OFFSET (0x000030) /* TCD Destination Address Register (TCD0_DADDR) */ +#define IMX9_EDMA_TCD_DOFF_OFFSET (0x000034) /* TCD Signed Destination Address Offset Register (TCD0_DOFF) */ +#define IMX9_EDMA_TCD_CITER_OFFSET (0x000036) /* TCD Current Major Loop Count Register (TCD0_CITER) */ +#define IMX9_EDMA_TCD_DLAST_SGA_OFFSET (0x000038) /* TCD Last Destination Address Adjustment / Scatter Gather Address Register (TCD0_DLAST_SGA)*/ +#define IMX9_EDMA_TCD_CSR_OFFSET (0x00003c) /* TCD Control and Status Register (TCD0_CSR) */ +#define IMX9_EDMA_TCD_BITER_OFFSET (0x00003e) /* TCD Beginning Major Loop Count Register (TCD0_BITER) */ + +/* eDMA 3 and eDMA 4 have TCD instance offsets, but same base offset */ + +#define IMX9_EDMA_TCD_BASE_OFFSET (0x10000) /* Offset to TCD for both eDMA3/4 */ +#define IMX9_EDMA3_TCD_INST_OFFSET (0x10000) /* Per instance TCD offset for eDMA3 */ +#define IMX9_EDMA4_TCD_INST_OFFSET (0x8000) /* Per instance TCD offset for eDMA4 */ +#define IMX9_EDMA_TCD_BASE(n) ((n) + IMX9_EDMA_TCD_BASE_OFFSET) +#define IMX9_EDMA_TCD_INST_OFFSET(n) ((n) == IMX9_DMA3_BASE ? IMX9_EDMA3_TCD_INST_OFFSET : IMX9_EDMA4_TCD_INST_OFFSET) +#define IMX9_EDMA_TCD(n,t) (IMX9_EDMA_TCD_BASE(n) + (t) * IMX9_EDMA_TCD_INST_OFFSET(n)) + +/* eDMA Transfer Control Descriptor (TCD) Register Addresses ****************/ + +#define IMX9_EDMA_CH_CSR(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_CH_CSR_OFFSET) +#define IMX9_EDMA_CH_ES(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_CH_ES_OFFSET) +#define IMX9_EDMA_CH_INT(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_CH_INT_OFFSET) +#define IMX9_EDMA_CH_SBR(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_CH_SBR_OFFSET) +#define IMX9_EDMA_CH_PRI(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_CH_PRI_OFFSET) +#define IMX9_EDMA_CH_MUX(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_CH_MUX_OFFSET) +#define IMX9_EDMA_TCD_SADDR(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_SADDR_OFFSET) +#define IMX9_EDMA_TCD_SOFF(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_SOFF_OFFSET) +#define IMX9_EDMA_TCD_ATTR(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_ATTR_OFFSET) +#define IMX9_EDMA_TCD_NBYTES(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_NBYTES_OFFSET) +#define IMX9_EDMA_TCD_SLAST_SDA(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_SLAST_SDA_OFFSET) +#define IMX9_EDMA_TCD_DADDR(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_DADDR_OFFSET) +#define IMX9_EDMA_TCD_DOFF(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_DOFF_OFFSET) +#define IMX9_EDMA_TCD_CITER(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_CITER_OFFSET) +#define IMX9_EDMA_TCD_DLAST_SGA(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_DLAST_SGA_OFFSET) +#define IMX9_EDMA_TCD_CSR(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_CSR_OFFSET) +#define IMX9_EDMA_TCD_BITER(n,t) (IMX9_EDMA_TCD(n,t) + IMX9_EDMA_TCD_BITER_OFFSET) + +/* eDMA Register Bitfield Definitions ***************************************/ + +/* Management Page Control Register (CSR) */ + + /* Bit 0: Reserved */ +#define EDMA_CSR_EDBG (1 << 1) /* Bit 1: Enable Debug (EDBG) */ +#define EDMA_CSR_ERCA (1 << 2) /* Bit 2: Enable Round Robin Channel Arbitration (ERCA) */ + /* Bit 3: Reserved */ +#define EDMA_CSR_HAE (1 << 4) /* Bit 4: Halt After Error (HAE) */ +#define EDMA_CSR_HALT (1 << 5) /* Bit 5: Halt DMA Operations (HALT) */ +#define EDMA_CSR_GCLC (1 << 6) /* Bit 6: Global Channel Linking Control (GCLC) */ +#define EDMA_CSR_GMRC (1 << 7) /* Bit 7: Global Master ID Replication Control (GMRC) */ +#define EDMA_CSR_ECX (1 << 8) /* Bit 8: Cancel Transfer With Error (ECX) */ +#define EDMA_CSR_CX (1 << 9) /* Bit 9: Cancel Transfer (CX) */ + /* Bits 10-23: Reserved */ +#define EDMA_CSR_ACTIVE_ID_SHIFT (24) /* Bits 24-28: Active Channel ID (ACTIVE_ID) */ +#define EDMA_CSR_ACTIVE_ID_MASK (0x1f << EDMA_CSR_ACTIVE_ID_SHIFT) + /* Bits 29-30: Reserved */ +#define EDMA_CSR_ACTIVE (1 << 31) /* Bit 31: DMA Active Status (ACTIVE) */ + +/* Management Page Error Status Register (ES) */ + +#define EDMA_ES_DBE (1 << 0) /* Bit 0: Destination Bus Error (DBE) */ +#define EDMA_ES_SBE (1 << 1) /* Bit 1: Source Bus Error (SBE) */ +#define EDMA_ES_SGE (1 << 2) /* Bit 2: Scatter/Gather Configuration Error (SGE) */ +#define EDMA_ES_NCE (1 << 3) /* Bit 3: NBYTES/CITER Configuration Error (NCE) */ +#define EDMA_ES_DOE (1 << 4) /* Bit 4: Destination Offset Error (DOE) */ +#define EDMA_ES_DAE (1 << 5) /* Bit 5: Destination Address Error (DAE) */ +#define EDMA_ES_SOE (1 << 6) /* Bit 6: Source Offset Error (SOE) */ +#define EDMA_ES_SAE (1 << 7) /* Bit 7: Source Address Error (SAE) */ +#define EDMA_ES_ECX (1 << 8) /* Bit 8: Transfer Canceled (ECX) */ + /* Bits 9-23: Reserved */ +#define EDMA_ES_ERRCHN_SHIFT (24) /* Bits 24-28: Error Channel Number or Canceled Channel Number (ERRCHN) */ +#define EDMA_ES_ERRCHN_MASK (0x1f << EDMA_ES_ERRCHN_SHIFT) + /* Bits 29-30: Reserved */ +#define EDMA_ES_VLD (1 << 31) /* Bit 31: Logical OR of all ERR status fields (VALID) */ + +/* Management Page Interrupt Request Status Register (INT) */ + +#define EDMA_INT(n) (1 << (n)) /* Bit n: Interrupt Request Status (INT) */ + +/* Management Page Hardware Request Status Register (HRS) */ + +#define EDMA_HRS(n) (1 << (n)) /* Bit n: Hardware Request Status (HRS) */ + +/* Channel n Arbitration Group Register (CHn_GRPRI) */ + +#define EDMA_CH_GRPRI_SHIFT (0) /* Bits 0-4: Arbitration Group For Channel n (GRPRI) */ +#define EDMA_CH_GRPRI_MASK (0x1f << EDMA_CH_GRPRI_SHIFT) + /* Bits 5-31: Reserved */ + +/* eDMA Transfer Control Descriptor (TCD) Bitfield Definitions **************/ + +/* Channel n Control and Status Register (CHn_CSR) */ + +#define EDMA_CH_CSR_ERQ (1 << 0) /* Bit 0: Enable DMA Request (ERQ) */ +#define EDMA_CH_CSR_EARQ (1 << 1) /* Bit 1: Enable Asynchronous DMA Request in Stop Mode for Channel (EARQ) */ +#define EDMA_CH_CSR_EEI (1 << 2) /* Bit 2: Enable Error Interrupt (EEI) */ +#define EDMA_CH_CSR_EBW (1 << 3) /* Bit 3: Enable Buffered Writes (EBW) */ + /* Bit 4-29: Reserved */ +#define EDMA_CH_CSR_DONE (1 << 30) /* Bit 30: Channel Done (DONE) */ +#define EDMA_CH_CSR_ACTIVE (1 << 31) /* Bit 31: CHannel Active (ACTIVE) */ + +/* Channel n Error Status Register (CHn_ES) */ + +#define EDMA_CH_ES_DBE (1 << 0) /* Bit 0: Destination Bus Error (DBE) */ +#define EDMA_CH_ES_SBE (1 << 1) /* Bit 1: Source Bus Error (SBE) */ +#define EDMA_CH_ES_SGE (1 << 2) /* Bit 2: Scatter/Gather Configuration Error (SGE) */ +#define EDMA_CH_ES_NCE (1 << 3) /* Bit 3: NBYTES/CITER Configuration Error (NCE) */ +#define EDMA_CH_ES_DOE (1 << 4) /* Bit 4: Destination Offset Error (DOE) */ +#define EDMA_CH_ES_DAE (1 << 5) /* Bit 5: Destination Address Error (DAE) */ +#define EDMA_CH_ES_SOE (1 << 6) /* Bit 6: Source Offset Error (SOE) */ +#define EDMA_CH_ES_SAE (1 << 7) /* Bit 7: Source Address Error (SAE) */ + /* Bit 8-30: Reserved */ +#define EDMA_CH_ES_ERR (1 << 31) /* Bit 31: Error in this channel (ERR) */ + +/* Channel n Interrupt Status Register (CHn_INT) */ + +#define EDMA_CH_INT (1 << 0) /* Bit 0: Interrupt Request (INT) */ + /* Bits 1-31: Reserved */ + +/* Channel n System Bus Register (CHn_SBR) */ + +#define EDMA_CH_SBR_MID_SHIFT (0) /* Bits 0-3: Master ID (MID) */ +#define EDMA_CH_SBR_MID_MASK (0x0f << EDMA_CH_SBR_MID_SHIFT) + /* Bits 4-13: Reserved */ +#define EDMA_CH_SBR_SEC (1 << 14) /* Bit 14: Security Level (SEC) */ +#define EDMA_CH_SBR_PAL (1 << 15) /* Bit 15: Privileged Access Level (PAL) */ +#define EDMA_CH_SBR_EMI (1 << 16) /* Bit 16: Enable Master ID Replication (EMI) */ +#define EDMA_CH_SBR_ATTR_SHIFT (17) /* Bits 17-19: Attribute Output (ATTR) */ +#define EDMA_CH_SBR_ATTR_MASK (0x07 << EDMA_CH_SBR_ATTR_SHIFT) + /* Bits 20-31: Reserved */ + +/* Channel n Priority Register (CHn_PRI) */ + +#define EDMA_CH_PRI_APL_SHIFT (0) /* Bits 0-2: Arbitration Priority Level (APL) */ +#define EDMA_CH_PRI_APL_MASK (0x07 << EDMA_CH_PRI_APL_SHIFT) + /* Bits 3-29: Reserved */ +#define EDMA_CH_PRI_DPA (1 << 30) /* Bit 30: Disable Preempt Ability (DPA) */ +#define EDMA_CH_PRI_ECP (1 << 31) /* Bit 31: Enable Channel Preemption (ECP) */ + +/* Channel Multiplexor Configuration (CHn_MUX) */ + +#define EDMA_CH_SRC_SHIFT (0) /* Bits 0-6: Service Request Source */ +#define EDMA_CH_SRC_MASK (0x7f << EDMA_CH_SRC_SHIFT) + +/* TCDn Source Address Register (TCDn_SADDR) */ + +#define EDMA_TCD_SADDR_SHIFT (0) /* Bits 0-31: Source Address (SADDR) */ +#define EDMA_TCD_SADDR_MASK (0xffffffff << EDMA_TCD_SADDR_SHIFT) + +/* TCDn Signed Source Address Offset Register (TCDn_SOFF) */ + +#define EDMA_TCD_SOFF_SHIFT (0) /* Bits 0-31: Source Address Signed Offset (SOFF) */ +#define EDMA_TCD_SOFF_MASK (0xffffffff << EDMA_TCD_SOFF_SHIFT) + +/* TCDn Transfer Attributes (TCDn_ATTR) */ + +#define EDMA_TCD_ATTR_DSIZE_SHIFT (0) /* Bits 0-2: Destination Data Transfer Size (DSIZE) */ +#define EDMA_TCD_ATTR_DSIZE_MASK (0x07 << EDMA_TCD_ATTR_DSIZE_SHIFT) +#define EDMA_TCD_ATTR_DSIZE(n) (((n) << EDMA_TCD_ATTR_DSIZE_SHIFT) & EDMA_TCD_ATTR_DSIZE_MASK) +#define EDMA_TCD_ATTR_DMOD_SHIFT (3) /* Bits 3-7: Destination Address Modulo (DMOD) */ +#define EDMA_TCD_ATTR_DMOD_MASK (0x1f << EDMA_TCD_ATTR_DMOD_SHIFT) +#define EDMA_TCD_ATTR_DMOD(n) (((n) << EDMA_TCD_ATTR_DMOD_SHIFT) & EDMA_TCD_ATTR_DMOD_MASK) +#define EDMA_TCD_ATTR_SSIZE_SHIFT (8) /* Bits 8-10: Source Data Transfer Size (SSIZE) */ +#define EDMA_TCD_ATTR_SSIZE_MASK (0x07 << EDMA_TCD_ATTR_SSIZE_SHIFT) +#define EDMA_TCD_ATTR_SSIZE(n) (((n) << EDMA_TCD_ATTR_SSIZE_SHIFT) & EDMA_TCD_ATTR_SSIZE_MASK) +# define EDMA_TCD_ATTR_SSIZE_8BIT (0x00 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 8-bit */ +# define EDMA_TCD_ATTR_SSIZE_16BIT (0x01 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 16-bit */ +# define EDMA_TCD_ATTR_SSIZE_32BIT (0x02 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 32-bit */ +# define EDMA_TCD_ATTR_SSIZE_64BIT (0x03 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 64-bit */ +# define EDMA_TCD_ATTR_SSIZE_16BYTE (0x04 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 16-byte */ +# define EDMA_TCD_ATTR_SSIZE_32BYTE (0x05 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 32-byte */ +# define EDMA_TCD_ATTR_SSIZE_64BYTE (0x06 << EDMA_TCD_ATTR_SSIZE_SHIFT) /* 64-byte */ + +#define EDMA_TCD_ATTR_SMOD_SHIFT (11) /* Bits 11-15: Source Address Modulo (SMOD) */ +#define EDMA_TCD_ATTR_SMOD_MASK (0x1f << EDMA_TCD_ATTR_SMOD_SHIFT) +#define EDMA_TCD_ATTR_SMOD(n) (((n) << EDMA_TCD_ATTR_SMOD_SHIFT) & EDMA_TCD_ATTR_SMOD_MASK) + +/* TCDn Transfer Size (TCDn_NBYTES) */ + +#define EDMA_TCD_NBYTES_SHIFT (0) /* Bits 0-29: Number of Bytes to Transfer per Service Request (NBYTES) */ +#define EDMA_TCD_NBYTES_MASK (0x3fffffff << EDMA_TCD_NBYTES_SHIFT) +#define EDMA_TCD_NBYTES_MASK_MLOFF (0x03ff << EDMA_TCD_NBYTES_SHIFT) +#define EDMA_TCD_NBYTES_MLOFF_SHIFT (10) /* Bits 10-29: Minor Loop Offset (MLOFF) */ +#define EDMA_TCD_NBYTES_MLOFF_MASK (0x0fffff << EDMA_TCD_NBYTES_MLOFF_SHIFT) +#define EDMA_TCD_NBYTES_DMLOE (1 << 30) /* Bit 30: Destination Minor Loop Offset Enable (DMLOE) */ +#define EDMA_TCD_NBYTES_SMLOE (1 << 31) /* Bit 31: Source Minor Loop Offset Enable (SMLOE) */ + +/* TCDn Last Source Address Adjustment / Store DADDR Address Register + * (TCDn_SLAST_SDA) + */ + +#define EDMA_TCD_SLAST_SDA_SHIFT (0) /* Bits 0-31: Last Source Address Adjustment / Store DADDR Address (SLAST_SDA) */ +#define EDMA_TCD_SLAST_SDA_MASK (0xffffffff << EDMA_TCD_SLAST_SDA_SHIFT) + +/* TCDn Destination Address Register (TCDn_DADDR) */ + +#define EDMA_TCD_DADDR_SHIFT (0) /* Bits 0-31: Destination Address (DADDR) */ +#define EDMA_TCD_DADDR_MASK (0xffffffff << EDMA_TCD_DADDR_SHIFT) + +/* TCDn Signed Destination Address Offset Register (TCDn_DOFF) */ + +#define EDMA_TCD_DOFF_SHIFT (0) /* Bits 0-15: Destination Address Signed Offset (DOFF) */ +#define EDMA_TCD_DOFF_MASK (0xffff << EDMA_TCD_DOFF_SHIFT) + +/* TCDn Current Major Loop Count Register (TCDn_CITER) */ + +#define EDMA_TCD_CITER_SHIFT (0) /* Bits 0-14: Current Major Iteration Count (CITER) */ +#define EDMA_TCD_CITER_MASK (0x7fff << EDMA_TCD_CITER_SHIFT) +#define EDMA_TCD_CITER_MASK_ELINK (0x01ff << EDMA_TCD_CITER_SHIFT) +#define EDMA_TCD_CITER_LINKCH_SHIFT (9) /* Bits 9-13: Minor Loop Link Channel Number (LINKCH) */ +#define EDMA_TCD_CITER_LINKCH_MASK (0x1f << EDMA_TCD_CITER_LINKCH_SHIFT) +#define EDMA_TCD_CITER_LINKCH(n) (((n) << EDMA_TCD_CITER_LINKCH_SHIFT) & EDMA_TCD_CITER_LINKCH_SHIFT) +#define EDMA_TCD_CITER_ELINK (1 << 15) /* Bit 15: Enable Link (ELINK) */ + +/* TCDn Last Destination Address Adjustment / Scatter Gather Address Register + * (TCDn_DLAST_SGA) + */ + +#define EDMA_TCD_DLAST_SGA_SHIFT (0) /* Bits 0-31: Last Destination Address Adjustment / Scatter Gather Address (DLAST_SGA) */ +#define EDMA_TCD_DLAST_SGA_MASK (0xffffffff << EDMA_TCD_DLAST_SGA_SHIFT) + +/* TCDn Control and Status Register (TCDn_CSR) */ + +#define EDMA_TCD_CSR_START (1 << 0) /* Bit 0: Channel Start (START) */ +#define EDMA_TCD_CSR_INTMAJOR (1 << 1) /* Bit 1: Enable Interrupt if Major count complete (INTMAJOR) */ +#define EDMA_TCD_CSR_INTHALF (1 << 2) /* Bit 2: Enable Interrupt if Major Count Half-complete (INTHALF) */ +#define EDMA_TCD_CSR_DREQ (1 << 3) /* Bit 3: Disable Request (DREQ) */ +#define EDMA_TCD_CSR_ESG (1 << 4) /* Bit 4: Enable Scatter/Gather Processing (ESG) */ +#define EDMA_TCD_CSR_MAJORELINK (1 << 5) /* Bit 5: Enable Link When Major Loop Complete (MAJORELINK) */ +#define EDMA_TCD_CSR_EEOP (1 << 6) /* Bit 6: Enable End-Of-Packet Processing (EEOP) */ +#define EDMA_TCD_CSR_ESDA (1 << 7) /* Bit 7: Enable Store Destination Address (ESDA) */ +#define EDMA_TCD_CSR_MAJORLINKCH_SHIFT (8) /* Bits 8-12: Major Loop Link Channel Number (MAJORLINKCH) */ +#define EDMA_TCD_CSR_MAJORLINKCH_MASK (0x1f << EDMA_TCD_CSR_MAJORLINKCH_SHIFT) +#define EDMA_TCD_CSR_MAJORLINKCH(n) (((n) << EDMA_TCD_CSR_MAJORLINKCH_SHIFT) & EDMA_TCD_CSR_MAJORLINKCH_MASK) + /* Bit 13: Reserved */ +#define EDMA_TCD_CSR_BWC_SHIFT (14) /* Bits 14-15: Bandwidth Control (BWC) */ +#define EDMA_TCD_CSR_BWC_MASK (0x03 << EDMA_TCD_CSR_BWC_SHIFT) +# define EDMA_TCD_CSR_BWC_NOSTALL (0x00 << EDMA_TCD_CSR_BWC_SHIFT) /* No eDMA engine stalls */ +# define EDMA_TCD_CSR_BWC_HPE (0x01 << EDMA_TCD_CSR_BWC_SHIFT) /* Enable eDMA master high-priority elevation (HPE) mode */ +# define EDMA_TCD_CSR_BWC_4CYCLES (0x02 << EDMA_TCD_CSR_BWC_SHIFT) /* eDMA engine stalls for 4 cycles after each R/W */ +# define EDMA_TCD_CSR_BWC_8CYCLES (0x03 << EDMA_TCD_CSR_BWC_SHIFT) /* eDMA engine stalls for 8 cycles after each R/W */ + +/* TCDn Beginning Major Loop Count Register (TCDn_BITER) */ + +#define EDMA_TCD_BITER_SHIFT (0) /* Bits 0-14: Starting Major Iteration Count (BITER) */ +#define EDMA_TCD_BITER_MASK (0x7fff << EDMA_TCD_BITER_SHIFT) +#define EDMA_TCD_BITER_MASK_ELINK (0x01ff << EDMA_TCD_BITER_SHIFT) +#define EDMA_TCD_BITER_LINKCH_SHIFT (9) /* Bits 9-13: Link Channel Number (LINKCH) */ +#define EDMA_TCD_BITER_LINKCH_MASK (0x1f << EDMA_TCD_BITER_LINKCH_SHIFT) +#define EDMA_TCD_BITER_LINKCH(n) (((n) << EDMA_TCD_BITER_LINKCH_SHIFT) & EDMA_TCD_BITER_LINKCH_MASK) +#define EDMA_TCD_BITER_ELINK (1 << 15) /* Bit 15: Enable Link (ELINK) */ + +/* Amount of channels */ + +#define DMA3_CHANNEL_COUNT (31) +#define DMA4_CHANNEL_COUNT (64) +#define IMX9_EDMA_NCHANNELS (DMA3_CHANNEL_COUNT + DMA4_CHANNEL_COUNT) + +/* Amount of interrupt sources */ + +#define DMA3_IRQ_COUNT (32) /* Error interrupt not counted */ +#define DMA4_IRQ_COUNT (32) /* Error interrupt not counted */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* In-memory representation of the 32-byte Transfer Control Descriptor + * (TCD) + */ + +struct imx9_edmatcd_s +{ + uint32_t saddr; /* Offset: 0x0000 TCD Source Address */ + uint16_t soff; /* Offset: 0x0004 TCD Signed Source Address Offset */ + uint16_t attr; /* Offset: 0x0006 TCD Transfer Attributes */ + uint32_t nbytes; /* Offset: 0x0008 TCD Signed Minor Loop Offset / Byte Count */ + uint32_t slast; /* Offset: 0x000c TCD Last Source Address Adjustment */ + uint32_t daddr; /* Offset: 0x0010 TCD Destination Address */ + uint16_t doff; /* Offset: 0x0014 TCD Signed Destination Address Offset */ + uint16_t citer; /* Offset: 0x0016 TCD Current Minor Loop Link, Major Loop Count */ + uint32_t dlastsga; /* Offset: 0x0018 TCD Last Destination Address Adjustment/Scatter Gather Address */ + uint16_t csr; /* Offset: 0x001c TCD Control and Status */ + uint16_t biter; /* Offset: 0x001e TCD Beginning Minor Loop Link, Major Loop Count */ +}; + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_edma_tcdhasmux + * + * Description: + * Check if DMA TCD has TCD.MUX register. + * + * Input Parameters: + * dmabase - The eDMA base. + * + * Returned Value: + * true if TCD.MUX exists; false if not. + * + ****************************************************************************/ + +static inline bool imx9_edma_tcdhasmux(uintptr_t dmabase) +{ + /* Only eDMA4 has TCD.MUX register */ + + return dmabase == IMX9_DMA4_BASE ? true : false; +} + +/**************************************************************************** + * Name: imx9_edma_choffset + * + * Description: + * Channel offset in global channel list for dma base. + * + * Input Parameters: + * base - The eDMA base. + * + * Returned Value: + * Channel offset. + * + ****************************************************************************/ + +static inline uint32_t imx9_edma_choffset(uintptr_t base) +{ + return base == IMX9_DMA3_BASE ? 0 : DMA3_CHANNEL_COUNT; +} + +/**************************************************************************** + * Name: imx9_edma_chmax + * + * Description: + * Max channel in global channel list for dma base. + * + * Input Parameters: + * base - The eDMA base. + * + * Returned Value: + * Channel max. + * + ****************************************************************************/ + +static inline uint32_t imx9_edma_chmax(uintptr_t base) +{ + return base == IMX9_DMA3_BASE ? DMA3_CHANNEL_COUNT : IMX9_EDMA_NCHANNELS; +} + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_EDMA_H */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_gpio.h b/arch/arm64/src/imx9/hardware/imx93/imx93_gpio.h new file mode 100644 index 0000000000000..e00856d6780ac --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_gpio.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx93/imx93_gpio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_GPIO_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "imx93_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IMX9_GPIO_VERID_OFFSET (0x0000) /* Version ID */ +#define IMX9_GPIO_PARAM_OFFSET (0x0004) /* Parameter */ +#define IMX9_GPIO_LOCK_OFFSET (0x000c) /* Lock */ +#define IMX9_GPIO_PCNS_OFFSET (0x0010) /* Pin Control Nonsecure */ +#define IMX9_GPIO_ICNS_OFFSET (0x0014) /* Interrupt Control Nonsecure */ +#define IMX9_GPIO_PCNP_OFFSET (0x0018) /* Pin Control Nonprivilege */ +#define IMX9_GPIO_ICNP_OFFSET (0x001c) /* Interrupt Control Nonprivilege */ +#define IMX9_GPIO_PDOR_OFFSET (0x0040) /* Port Data Output */ +#define IMX9_GPIO_PSOR_OFFSET (0x0044) /* Port Set Output */ +#define IMX9_GPIO_PCOR_OFFSET (0x0048) /* Port Clear Output */ +#define IMX9_GPIO_PTOR_OFFSET (0x004c) /* Port Toggle Output */ +#define IMX9_GPIO_PDIR_OFFSET (0x0050) /* Port Data Input */ +#define IMX9_GPIO_PDDR_OFFSET (0x0054) /* Port Data Direction */ +#define IMX9_GPIO_PIDR_OFFSET (0x0058) /* Port Input Disable */ +#define IMX9_GPIO_P0DR_OFFSET (0x0060) /* Pin Data (0-31 at offsets of n * 4h) */ +#define IMX9_GPIO_ICR0_OFFSET (0x0080) /* Interrupt Control (0-31 at offsets of n * 4h) */ +#define IMX9_GPIO_GICLR_OFFSET (0x0100) /* Global Interrupt Control Low */ +#define IMX9_GPIO_GICHR_OFFSET (0x0104) /* Global Interrupt Control High */ +#define IMX9_GPIO_ISFR0_OFFSET (0x0120) /* Interrupt Status Flag */ +#define IMX9_GPIO_ISFR1_OFFSET (0x0124) /* Interrupt Status Flag */ + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_GPIO_H */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_iomux.h b/arch/arm64/src/imx9/hardware/imx93/imx93_iomux.h new file mode 100644 index 0000000000000..afa9b388f7832 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_iomux.h @@ -0,0 +1,604 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx93/imx93_iomux.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_IOMUX_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_IOMUX_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets */ + +#define IOMUXC_MUX_CTL_DAP_TDI_OFFSET (0x0000) +#define IOMUXC_MUX_CTL_DAP_TMS_SWDIO_OFFSET (0x0004) +#define IOMUXC_MUX_CTL_DAP_TCLK_SWCLK_OFFSET (0x0008) +#define IOMUXC_MUX_CTL_DAP_TDO_TRACESWO_OFFSET (0x000C) +#define IOMUXC_MUX_CTL_GPIO_IO00_OFFSET (0x0010) +#define IOMUXC_MUX_CTL_GPIO_IO01_OFFSET (0x0014) +#define IOMUXC_MUX_CTL_GPIO_IO02_OFFSET (0x0018) +#define IOMUXC_MUX_CTL_GPIO_IO03_OFFSET (0x001C) +#define IOMUXC_MUX_CTL_GPIO_IO04_OFFSET (0x0020) +#define IOMUXC_MUX_CTL_GPIO_IO05_OFFSET (0x0024) +#define IOMUXC_MUX_CTL_GPIO_IO06_OFFSET (0x0028) +#define IOMUXC_MUX_CTL_GPIO_IO07_OFFSET (0x002C) +#define IOMUXC_MUX_CTL_GPIO_IO08_OFFSET (0x0030) +#define IOMUXC_MUX_CTL_GPIO_IO09_OFFSET (0x0034) +#define IOMUXC_MUX_CTL_GPIO_IO10_OFFSET (0x0038) +#define IOMUXC_MUX_CTL_GPIO_IO11_OFFSET (0x003C) +#define IOMUXC_MUX_CTL_GPIO_IO12_OFFSET (0x0040) +#define IOMUXC_MUX_CTL_GPIO_IO13_OFFSET (0x0044) +#define IOMUXC_MUX_CTL_GPIO_IO14_OFFSET (0x0048) +#define IOMUXC_MUX_CTL_GPIO_IO15_OFFSET (0x004C) +#define IOMUXC_MUX_CTL_GPIO_IO16_OFFSET (0x0050) +#define IOMUXC_MUX_CTL_GPIO_IO17_OFFSET (0x0054) +#define IOMUXC_MUX_CTL_GPIO_IO18_OFFSET (0x0058) +#define IOMUXC_MUX_CTL_GPIO_IO19_OFFSET (0x005C) +#define IOMUXC_MUX_CTL_GPIO_IO20_OFFSET (0x0060) +#define IOMUXC_MUX_CTL_GPIO_IO21_OFFSET (0x0064) +#define IOMUXC_MUX_CTL_GPIO_IO22_OFFSET (0x0068) +#define IOMUXC_MUX_CTL_GPIO_IO23_OFFSET (0x006C) +#define IOMUXC_MUX_CTL_GPIO_IO24_OFFSET (0x0070) +#define IOMUXC_MUX_CTL_GPIO_IO25_OFFSET (0x0074) +#define IOMUXC_MUX_CTL_GPIO_IO26_OFFSET (0x0078) +#define IOMUXC_MUX_CTL_GPIO_IO27_OFFSET (0x007C) +#define IOMUXC_MUX_CTL_GPIO_IO28_OFFSET (0x0080) +#define IOMUXC_MUX_CTL_GPIO_IO29_OFFSET (0x0084) +#define IOMUXC_MUX_CTL_CCM_CLKO1_OFFSET (0x0088) +#define IOMUXC_MUX_CTL_CCM_CLKO2_OFFSET (0x008C) +#define IOMUXC_MUX_CTL_CCM_CLKO3_OFFSET (0x0090) +#define IOMUXC_MUX_CTL_CCM_CLKO4_OFFSET (0x0094) +#define IOMUXC_MUX_CTL_ENET1_MDC_OFFSET (0x0098) +#define IOMUXC_MUX_CTL_ENET1_MDIO_OFFSET (0x009C) +#define IOMUXC_MUX_CTL_ENET1_TD3_OFFSET (0x00A0) +#define IOMUXC_MUX_CTL_ENET1_TD2_OFFSET (0x00A4) +#define IOMUXC_MUX_CTL_ENET1_TD1_OFFSET (0x00A8) +#define IOMUXC_MUX_CTL_ENET1_TD0_OFFSET (0x00AC) +#define IOMUXC_MUX_CTL_ENET1_TX_CTL_OFFSET (0x00B0) +#define IOMUXC_MUX_CTL_ENET1_TXC_OFFSET (0x00B4) +#define IOMUXC_MUX_CTL_ENET1_RX_CTL_OFFSET (0x00B8) +#define IOMUXC_MUX_CTL_ENET1_RXC_OFFSET (0x00BC) +#define IOMUXC_MUX_CTL_ENET1_RD0_OFFSET (0x00C0) +#define IOMUXC_MUX_CTL_ENET1_RD1_OFFSET (0x00C4) +#define IOMUXC_MUX_CTL_ENET1_RD2_OFFSET (0x00C8) +#define IOMUXC_MUX_CTL_ENET1_RD3_OFFSET (0x00CC) +#define IOMUXC_MUX_CTL_ENET2_MDC_OFFSET (0x00D0) +#define IOMUXC_MUX_CTL_ENET2_MDIO_OFFSET (0x00D4) +#define IOMUXC_MUX_CTL_ENET2_TD3_OFFSET (0x00D8) +#define IOMUXC_MUX_CTL_ENET2_TD2_OFFSET (0x00DC) +#define IOMUXC_MUX_CTL_ENET2_TD1_OFFSET (0x00E0) +#define IOMUXC_MUX_CTL_ENET2_TD0_OFFSET (0x00E4) +#define IOMUXC_MUX_CTL_ENET2_TX_CTL_OFFSET (0x00E8) +#define IOMUXC_MUX_CTL_ENET2_TXC_OFFSET (0x00EC) +#define IOMUXC_MUX_CTL_ENET2_RX_CTL_OFFSET (0x00F0) +#define IOMUXC_MUX_CTL_ENET2_RXC_OFFSET (0x00F4) +#define IOMUXC_MUX_CTL_ENET2_RD0_OFFSET (0x00F8) +#define IOMUXC_MUX_CTL_ENET2_RD1_OFFSET (0x00FC) +#define IOMUXC_MUX_CTL_ENET2_RD2_OFFSET (0x0100) +#define IOMUXC_MUX_CTL_ENET2_RD3_OFFSET (0x0104) +#define IOMUXC_MUX_CTL_SD1_CLK_OFFSET (0x0108) +#define IOMUXC_MUX_CTL_SD1_CMD_OFFSET (0x010C) +#define IOMUXC_MUX_CTL_SD1_DATA0_OFFSET (0x0110) +#define IOMUXC_MUX_CTL_SD1_DATA1_OFFSET (0x0114) +#define IOMUXC_MUX_CTL_SD1_DATA2_OFFSET (0x0118) +#define IOMUXC_MUX_CTL_SD1_DATA3_OFFSET (0x011C) +#define IOMUXC_MUX_CTL_SD1_DATA4_OFFSET (0x0120) +#define IOMUXC_MUX_CTL_SD1_DATA5_OFFSET (0x0124) +#define IOMUXC_MUX_CTL_SD1_DATA6_OFFSET (0x0128) +#define IOMUXC_MUX_CTL_SD1_DATA7_OFFSET (0x012C) +#define IOMUXC_MUX_CTL_SD1_STROBE_OFFSET (0x0130) +#define IOMUXC_MUX_CTL_SD2_VSELECT_OFFSET (0x0134) +#define IOMUXC_MUX_CTL_SD3_CLK_OFFSET (0x0138) +#define IOMUXC_MUX_CTL_SD3_CMD_OFFSET (0x013C) +#define IOMUXC_MUX_CTL_SD3_DATA0_OFFSET (0x0140) +#define IOMUXC_MUX_CTL_SD3_DATA1_OFFSET (0x0144) +#define IOMUXC_MUX_CTL_SD3_DATA2_OFFSET (0x0148) +#define IOMUXC_MUX_CTL_SD3_DATA3_OFFSET (0x014C) +#define IOMUXC_MUX_CTL_SD2_CD_B_OFFSET (0x0150) +#define IOMUXC_MUX_CTL_SD2_CLK_OFFSET (0x0154) +#define IOMUXC_MUX_CTL_SD2_CMD_OFFSET (0x0158) +#define IOMUXC_MUX_CTL_SD2_DATA0_OFFSET (0x015C) +#define IOMUXC_MUX_CTL_SD2_DATA1_OFFSET (0x0160) +#define IOMUXC_MUX_CTL_SD2_DATA2_OFFSET (0x0164) +#define IOMUXC_MUX_CTL_SD2_DATA3_OFFSET (0x0168) +#define IOMUXC_MUX_CTL_SD2_RESET_B_OFFSET (0x016C) +#define IOMUXC_MUX_CTL_I2C1_SCL_OFFSET (0x0170) +#define IOMUXC_MUX_CTL_I2C1_SDA_OFFSET (0x0174) +#define IOMUXC_MUX_CTL_I2C2_SCL_OFFSET (0x0178) +#define IOMUXC_MUX_CTL_I2C2_SDA_OFFSET (0x017C) +#define IOMUXC_MUX_CTL_UART1_RXD_OFFSET (0x0180) +#define IOMUXC_MUX_CTL_UART1_TXD_OFFSET (0x0184) +#define IOMUXC_MUX_CTL_UART2_RXD_OFFSET (0x0188) +#define IOMUXC_MUX_CTL_UART2_TXD_OFFSET (0x018C) +#define IOMUXC_MUX_CTL_PDM_CLK_OFFSET (0x0190) +#define IOMUXC_MUX_CTL_PDM_BIT_STREAM0_OFFSET (0x0194) +#define IOMUXC_MUX_CTL_PDM_BIT_STREAM1_OFFSET (0x0198) +#define IOMUXC_MUX_CTL_SAI1_TXFS_OFFSET (0x019C) +#define IOMUXC_MUX_CTL_SAI1_TXC_OFFSET (0x01A0) +#define IOMUXC_MUX_CTL_SAI1_TXD0_OFFSET (0x01A4) +#define IOMUXC_MUX_CTL_SAI1_RXD0_OFFSET (0x01A8) +#define IOMUXC_MUX_CTL_WDOG_ANY_OFFSET (0x01AC) + +#define IOMUXC_PAD_CTL_DAP_TDI_OFFSET (0x01B0) +#define IOMUXC_PAD_CTL_DAP_TMS_SWDIO_OFFSET (0x01B4) +#define IOMUXC_PAD_CTL_DAP_TCLK_SWCLK_OFFSET (0x01B8) +#define IOMUXC_PAD_CTL_DAP_TDO_TRACESWO_OFFSET (0x01BC) +#define IOMUXC_PAD_CTL_GPIO_IO00_OFFSET (0x01C0) +#define IOMUXC_PAD_CTL_GPIO_IO01_OFFSET (0x01C4) +#define IOMUXC_PAD_CTL_GPIO_IO02_OFFSET (0x01C8) +#define IOMUXC_PAD_CTL_GPIO_IO03_OFFSET (0x01CC) +#define IOMUXC_PAD_CTL_GPIO_IO04_OFFSET (0x01D0) +#define IOMUXC_PAD_CTL_GPIO_IO05_OFFSET (0x01D4) +#define IOMUXC_PAD_CTL_GPIO_IO06_OFFSET (0x01D8) +#define IOMUXC_PAD_CTL_GPIO_IO07_OFFSET (0x01DC) +#define IOMUXC_PAD_CTL_GPIO_IO08_OFFSET (0x01E0) +#define IOMUXC_PAD_CTL_GPIO_IO09_OFFSET (0x01E4) +#define IOMUXC_PAD_CTL_GPIO_IO10_OFFSET (0x01E8) +#define IOMUXC_PAD_CTL_GPIO_IO11_OFFSET (0x01EC) +#define IOMUXC_PAD_CTL_GPIO_IO12_OFFSET (0x01F0) +#define IOMUXC_PAD_CTL_GPIO_IO13_OFFSET (0x01F4) +#define IOMUXC_PAD_CTL_GPIO_IO14_OFFSET (0x01F8) +#define IOMUXC_PAD_CTL_GPIO_IO15_OFFSET (0x01FC) +#define IOMUXC_PAD_CTL_GPIO_IO16_OFFSET (0x0200) +#define IOMUXC_PAD_CTL_GPIO_IO17_OFFSET (0x0204) +#define IOMUXC_PAD_CTL_GPIO_IO18_OFFSET (0x0208) +#define IOMUXC_PAD_CTL_GPIO_IO19_OFFSET (0x020C) +#define IOMUXC_PAD_CTL_GPIO_IO20_OFFSET (0x0210) +#define IOMUXC_PAD_CTL_GPIO_IO21_OFFSET (0x0214) +#define IOMUXC_PAD_CTL_GPIO_IO22_OFFSET (0x0218) +#define IOMUXC_PAD_CTL_GPIO_IO23_OFFSET (0x021C) +#define IOMUXC_PAD_CTL_GPIO_IO24_OFFSET (0x0220) +#define IOMUXC_PAD_CTL_GPIO_IO25_OFFSET (0x0224) +#define IOMUXC_PAD_CTL_GPIO_IO26_OFFSET (0x0228) +#define IOMUXC_PAD_CTL_GPIO_IO27_OFFSET (0x022C) +#define IOMUXC_PAD_CTL_GPIO_IO28_OFFSET (0x0230) +#define IOMUXC_PAD_CTL_GPIO_IO29_OFFSET (0x0234) +#define IOMUXC_PAD_CTL_CCM_CLKO1_OFFSET (0x0238) +#define IOMUXC_PAD_CTL_CCM_CLKO2_OFFSET (0x023C) +#define IOMUXC_PAD_CTL_CCM_CLKO3_OFFSET (0x0240) +#define IOMUXC_PAD_CTL_CCM_CLKO4_OFFSET (0x0244) +#define IOMUXC_PAD_CTL_ENET1_MDC_OFFSET (0x0248) +#define IOMUXC_PAD_CTL_ENET1_MDIO_OFFSET (0x024C) +#define IOMUXC_PAD_CTL_ENET1_TD3_OFFSET (0x0250) +#define IOMUXC_PAD_CTL_ENET1_TD2_OFFSET (0x0254) +#define IOMUXC_PAD_CTL_ENET1_TD1_OFFSET (0x0258) +#define IOMUXC_PAD_CTL_ENET1_TD0_OFFSET (0x025C) +#define IOMUXC_PAD_CTL_ENET1_TX_CTL_OFFSET (0x0260) +#define IOMUXC_PAD_CTL_ENET1_TXC_OFFSET (0x0264) +#define IOMUXC_PAD_CTL_ENET1_RX_CTL_OFFSET (0x0268) +#define IOMUXC_PAD_CTL_ENET1_RXC_OFFSET (0x026C) +#define IOMUXC_PAD_CTL_ENET1_RD0_OFFSET (0x0270) +#define IOMUXC_PAD_CTL_ENET1_RD1_OFFSET (0x0274) +#define IOMUXC_PAD_CTL_ENET1_RD2_OFFSET (0x0278) +#define IOMUXC_PAD_CTL_ENET1_RD3_OFFSET (0x027C) +#define IOMUXC_PAD_CTL_ENET2_MDC_OFFSET (0x0280) +#define IOMUXC_PAD_CTL_ENET2_MDIO_OFFSET (0x0284) +#define IOMUXC_PAD_CTL_ENET2_TD3_OFFSET (0x0288) +#define IOMUXC_PAD_CTL_ENET2_TD2_OFFSET (0x028C) +#define IOMUXC_PAD_CTL_ENET2_TD1_OFFSET (0x01B0) +#define IOMUXC_PAD_CTL_ENET2_TD0_OFFSET (0x01B0) +#define IOMUXC_PAD_CTL_ENET2_TX_CTL_OFFSET (0x01B0) +#define IOMUXC_PAD_CTL_ENET2_TXC_OFFSET (0x029C) +#define IOMUXC_PAD_CTL_ENET2_RX_CTL_OFFSET (0x02A0) +#define IOMUXC_PAD_CTL_ENET2_RXC_OFFSET (0x02A4) +#define IOMUXC_PAD_CTL_ENET2_RD0_OFFSET (0x02A8) +#define IOMUXC_PAD_CTL_ENET2_RD1_OFFSET (0x02AC) +#define IOMUXC_PAD_CTL_ENET2_RD2_OFFSET (0x02B0) +#define IOMUXC_PAD_CTL_ENET2_RD3_OFFSET (0x02B4) +#define IOMUXC_PAD_CTL_SD1_CLK_OFFSET (0x02B8) +#define IOMUXC_PAD_CTL_SD1_CMD_OFFSET (0x02BC) +#define IOMUXC_PAD_CTL_SD1_DATA0_OFFSET (0x02C0) +#define IOMUXC_PAD_CTL_SD1_DATA1_OFFSET (0x02C4) +#define IOMUXC_PAD_CTL_SD1_DATA2_OFFSET (0x02C8) +#define IOMUXC_PAD_CTL_SD1_DATA3_OFFSET (0x02CC) +#define IOMUXC_PAD_CTL_SD1_DATA4_OFFSET (0x02D0) +#define IOMUXC_PAD_CTL_SD1_DATA5_OFFSET (0x02D4) +#define IOMUXC_PAD_CTL_SD1_DATA6_OFFSET (0x02D8) +#define IOMUXC_PAD_CTL_SD1_DATA7_OFFSET (0x02DC) +#define IOMUXC_PAD_CTL_SD1_STROBE_OFFSET (0x02E0) +#define IOMUXC_PAD_CTL_SD2_VSELECT_OFFSET (0x02E4) +#define IOMUXC_PAD_CTL_SD3_CLK_OFFSET (0x02E8) +#define IOMUXC_PAD_CTL_SD3_CMD_OFFSET (0x02EC) +#define IOMUXC_PAD_CTL_SD3_DATA0_OFFSET (0x02F0) +#define IOMUXC_PAD_CTL_SD3_DATA1_OFFSET (0x02F4) +#define IOMUXC_PAD_CTL_SD3_DATA2_OFFSET (0x02F8) +#define IOMUXC_PAD_CTL_SD3_DATA3_OFFSET (0x02FC) +#define IOMUXC_PAD_CTL_SD2_CD_B_OFFSET (0x0300) +#define IOMUXC_PAD_CTL_SD2_CLK_OFFSET (0x0304) +#define IOMUXC_PAD_CTL_SD2_CMD_OFFSET (0x0308) +#define IOMUXC_PAD_CTL_SD2_DATA0_OFFSET (0x030C) +#define IOMUXC_PAD_CTL_SD2_DATA1_OFFSET (0x0310) +#define IOMUXC_PAD_CTL_SD2_DATA2_OFFSET (0x0314) +#define IOMUXC_PAD_CTL_SD2_DATA3_OFFSET (0x0318) +#define IOMUXC_PAD_CTL_SD2_RESET_B_OFFSET (0x031C) +#define IOMUXC_PAD_CTL_I2C1_SCL_OFFSET (0x0320) +#define IOMUXC_PAD_CTL_I2C1_SDA_OFFSET (0x0324) +#define IOMUXC_PAD_CTL_I2C2_SCL_OFFSET (0x0328) +#define IOMUXC_PAD_CTL_I2C2_SDA_OFFSET (0x032C) +#define IOMUXC_PAD_CTL_UART1_RXD_OFFSET (0x0330) +#define IOMUXC_PAD_CTL_UART1_TXD_OFFSET (0x0334) +#define IOMUXC_PAD_CTL_UART2_RXD_OFFSET (0x0338) +#define IOMUXC_PAD_CTL_UART2_TXD_OFFSET (0x033C) +#define IOMUXC_PAD_CTL_PDM_CLK_OFFSET (0x0340) +#define IOMUXC_PAD_CTL_PDM_BIT_STREAM0_OFFSET (0x0344) +#define IOMUXC_PAD_CTL_PDM_BIT_STREAM1_OFFSET (0x0348) +#define IOMUXC_PAD_CTL_SAI1_TXFS_OFFSET (0x034C) +#define IOMUXC_PAD_CTL_SAI1_TXC_OFFSET (0x0350) +#define IOMUXC_PAD_CTL_SAI1_TXD0_OFFSET (0x0354) +#define IOMUXC_PAD_CTL_SAI1_RXD0_OFFSET (0x0358) +#define IOMUXC_PAD_CTL_WDOG_ANY_OFFSET (0x035C) + +#define CAN1_IPP_IND_CANRX_SELECT_INPUT_OFFSET (0x0360) +#define CAN2_IPP_IND_CANRX_SELECT_INPUT_OFFSET (0x0364) +#define CCMSRCGPCMIX_EXT1_CLK_SELECT_INPUT_OFFSET (0x0368) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_0_OFFSET (0x036C) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_1_OFFSET (0x0370) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_2_OFFSET (0x0374) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_3_OFFSET (0x0378) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_4_OFFSET (0x037C) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_5_OFFSET (0x0380) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_6_OFFSET (0x0384) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_7_OFFSET (0x0388) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_8_OFFSET (0x038C) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_9_OFFSET (0x0390) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_10_OFFSET (0x0394) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_11_OFFSET (0x0398) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_13_OFFSET (0x039C) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_14_OFFSET (0x03A0) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_15_OFFSET (0x03A4) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_16_OFFSET (0x03A8) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_17_OFFSET (0x03AC) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_18_OFFSET (0x03B0) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_20_OFFSET (0x03B4) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_22_OFFSET (0x03B8) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_23_OFFSET (0x03BC) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_24_OFFSET (0x03C0) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_25_OFFSET (0x03C4) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_27_OFFSET (0x03C8) +#define I3C2_PIN_SCL_IN_SELECT_INPUT_OFFSET (0x03CC) +#define I3C2_PIN_SDA_IN_SELECT_INPUT_OFFSET (0x03D0) +#define JTAG_MUX_TCK_SELECT_INPUT_OFFSET (0x03D4) +#define JTAG_MUX_TDI_SELECT_INPUT_OFFSET (0x03D8) +#define JTAG_MUX_TMS_SELECT_INPUT_OFFSET (0x03DC) +#define LP12C3_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET (0x03E0) +#define LPI12C3_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET (0x03E4) +#define LP12C5_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET (0x03E8) +#define LP12C5_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET (0x03EC) +#define LPI2C6_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET (0x03F0) +#define LPI2C6_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET (0x03F4) +#define LPI2C7_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET (0x03F8) +#define LPI2C7_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET (0x03FC) +#define LPI2C8_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET (0x0400) +#define LPI2C8_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET (0x0404) +#define LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_O_OFFSET (0x0408) +#define LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_1_OFFSET (0x040C) +#define LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_2_OFFSET (0x0410) +#define LPUART3_IPP_IND_LPUART_CTS_N_SELECT_INP_OFFSET (0x0414) +#define LPUART3_IPP_IND_LPUART_RXD_SELECT_INPUT_OFFSET (0x0418) +#define LPUART3_IPP_IND_LPUART_TXD_SELECT_INPUT_OFFSET (0x041C) +#define LPUART4_IPP_IND_LPUART_CTS_N_SELECT_INP_OFFSET (0x0420) +#define LPUART4_IPP_IND_LPUART_RXD_SELECT_INPUT_OFFSET (0x0424) +#define LPUART4_IPP_IND_LPUART_TXD_SELECT_INPUT_OFFSET (0x0428) +#define LPUARTS_IPP_IND_LPUART_CTS_N_SELECT_INP_OFFSET (0x042C) +#define LPUARTS_IPP_IND_LPUART_RXD_SELECT_INPUT_OFFSET (0x0430) +#define LPUARTS_IPP_IND_LPUART_TXD_SELECT_INPUT_OFFSET (0x0434) +#define SAI1_IPP_IND_SAI_MCLK_SELECT_INPUT_OFFSET (0x0448) +#define SAI3_IPP_IND_SAI_RXBCLK_SELECT_INPUT_OFFSET (0x044c) +#define SAI3_IPP_IND_SAI_RXSYNC_SELECT_INPUT_OFFSET (0x0450) +#define SPDIF_SPDIF_I_SELECT_INPUT_OFFSET (0x0454) +#define USDHC3_IPP_CARD_CLK_IN_SELECT_INPUT_OFFSET (0x0458) +#define USDHC3_IPP_CMD_IN_SELECT_INPUT_OFFSET (0x045C) +#define USDHC3_IPP_DATO_IN_SELECT_INPUT_OFFSET (0x0460) +#define USDHC3_IPP_DAT1_IN_SELECT_INPUT_OFFSET (0x0464) +#define USDHC3_IPP_DAT2_IN_SELECT_INPUT_OFFSET (0x0468) +#define USDHC3_IPP_DAT3_IN_SELECT_INPUT_OFFSET (0x046C) + +/* Register addresses */ + +#define IOMUXC_MUX_CTL_DAP_TDI (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_DAP_TDI_OFFSET) +#define IOMUXC_MUX_CTL_DAP_TMS_SWDIO (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_DAP_TMS_SWDIO_OFFSET) +#define IOMUXC_MUX_CTL_DAP_TCLK_SWCLK (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_DAP_TCLK_SWCLK_OFFSET) +#define IOMUXC_MUX_CTL_DAP_TDO_TRACESWO (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_DAP_TDO_TRACESWO_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO00 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO00_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO01 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO01_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO02 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO02_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO03 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO03_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO04 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO04_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO05 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO05_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO06 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO06_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO07 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO07_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO08 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO08_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO09 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO09_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO10 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO10_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO11 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO11_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO12 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO12_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO13 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO13_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO14 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO14_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO15 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO15_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO16 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO16_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO17 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO17_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO18 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO18_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO19 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO19_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO20 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO20_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO21 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO21_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO22 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO22_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO23 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO23_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO24 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO24_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO25 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO25_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO26 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO26_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO27 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO27_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO28 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO28_OFFSET) +#define IOMUXC_MUX_CTL_GPIO_IO29 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_GPIO_IO29_OFFSET) +#define IOMUXC_MUX_CTL_CCM_CLKO1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_CCM_CLKO1_OFFSET) +#define IOMUXC_MUX_CTL_CCM_CLKO2 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_CCM_CLKO2_OFFSET) +#define IOMUXC_MUX_CTL_CCM_CLKO3 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_CCM_CLKO3_OFFSET) +#define IOMUXC_MUX_CTL_CCM_CLKO4 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_CCM_CLKO4_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_MDC (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_MDC_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_MDIO (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_MDIO_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_TD3 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_TD3_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_TD2 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_TD2_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_TD1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_TD1_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_TD0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_TD0_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_TX_CTL (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_TX_CTL_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_TXC (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_TXC_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_RX_CTL (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_RX_CTL_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_RXC (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_RXC_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_RD0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_RD0_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_RD1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_RD1_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_RD2 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_RD2_OFFSET) +#define IOMUXC_MUX_CTL_ENET1_RD3 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET1_RD3_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_MDC (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_MDC_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_MDIO (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_MDIO_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_TD3 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_TD3_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_TD2 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_TD2_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_TD1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_TD1_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_TD0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_TD0_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_TX_CTL (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_TX_CTL_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_TXC (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_TXC_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_RX_CTL (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_RX_CTL_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_RXC (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_RXC_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_RD0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_RD0_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_RD1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_RD1_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_RD2 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_RD2_OFFSET) +#define IOMUXC_MUX_CTL_ENET2_RD3 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_ENET2_RD3_OFFSET) +#define IOMUXC_MUX_CTL_SD1_CLK (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_CLK_OFFSET) +#define IOMUXC_MUX_CTL_SD1_CMD (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_CMD_OFFSET) +#define IOMUXC_MUX_CTL_SD1_DATA0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_DATA0_OFFSET) +#define IOMUXC_MUX_CTL_SD1_DATA1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_DATA1_OFFSET) +#define IOMUXC_MUX_CTL_SD1_DATA2 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_DATA2_OFFSET) +#define IOMUXC_MUX_CTL_SD1_DATA3 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_DATA3_OFFSET) +#define IOMUXC_MUX_CTL_SD1_DATA4 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_DATA4_OFFSET) +#define IOMUXC_MUX_CTL_SD1_DATA5 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_DATA5_OFFSET) +#define IOMUXC_MUX_CTL_SD1_DATA6 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_DATA6_OFFSET) +#define IOMUXC_MUX_CTL_SD1_DATA7 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_DATA7_OFFSET) +#define IOMUXC_MUX_CTL_SD1_STROBE (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD1_STROBE_OFFSET) +#define IOMUXC_MUX_CTL_SD2_VSELECT (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_VSELECT_OFFSET) +#define IOMUXC_MUX_CTL_SD3_CLK (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD3_CLK_OFFSET) +#define IOMUXC_MUX_CTL_SD3_CMD (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD3_CMD_OFFSET) +#define IOMUXC_MUX_CTL_SD3_DATA0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD3_DATA0_OFFSET) +#define IOMUXC_MUX_CTL_SD3_DATA1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD3_DATA1_OFFSET) +#define IOMUXC_MUX_CTL_SD3_DATA2 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD3_DATA2_OFFSET) +#define IOMUXC_MUX_CTL_SD3_DATA3 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD3_DATA3_OFFSET) +#define IOMUXC_MUX_CTL_SD2_CD_B (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_CD_B_OFFSET) +#define IOMUXC_MUX_CTL_SD2_CLK (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_CLK_OFFSET) +#define IOMUXC_MUX_CTL_SD2_CMD (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_CMD_OFFSET) +#define IOMUXC_MUX_CTL_SD2_DATA0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_DATA0_OFFSET) +#define IOMUXC_MUX_CTL_SD2_DATA1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_DATA1_OFFSET) +#define IOMUXC_MUX_CTL_SD2_DATA2 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_DATA2_OFFSET) +#define IOMUXC_MUX_CTL_SD2_DATA3 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_DATA3_OFFSET) +#define IOMUXC_MUX_CTL_SD2_RESET_B (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SD2_RESET_B_OFFSET) +#define IOMUXC_MUX_CTL_I2C1_SCL (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_I2C1_SCL_OFFSET) +#define IOMUXC_MUX_CTL_I2C1_SDA (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_I2C1_SDA_OFFSET) +#define IOMUXC_MUX_CTL_I2C2_SCL (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_I2C2_SCL_OFFSET) +#define IOMUXC_MUX_CTL_I2C2_SDA (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_I2C2_SDA_OFFSET) +#define IOMUXC_MUX_CTL_UART1_RXD (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_UART1_RXD_OFFSET) +#define IOMUXC_MUX_CTL_UART1_TXD (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_UART1_TXD_OFFSET) +#define IOMUXC_MUX_CTL_UART2_RXD (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_UART2_RXD_OFFSET) +#define IOMUXC_MUX_CTL_UART2_TXD (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_UART2_TXD_OFFSET) +#define IOMUXC_MUX_CTL_PDM_CLK (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_PDM_CLK_OFFSET) +#define IOMUXC_MUX_CTL_PDM_BIT_STREAM0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_PDM_BIT_STREAM0_OFFSET) +#define IOMUXC_MUX_CTL_PDM_BIT_STREAM1 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_PDM_BIT_STREAM1_OFFSET) +#define IOMUXC_MUX_CTL_SAI1_TXFS (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SAI1_TXFS_OFFSET) +#define IOMUXC_MUX_CTL_SAI1_TXC (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SAI1_TXC_OFFSET) +#define IOMUXC_MUX_CTL_SAI1_TXD0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SAI1_TXD0_OFFSET) +#define IOMUXC_MUX_CTL_SAI1_RXD0 (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_SAI1_RXD0_OFFSET) +#define IOMUXC_MUX_CTL_WDOG_ANY (IMX9_IOMUXC1_BASE + IOMUXC_MUX_CTL_WDOG_ANY_OFFSET) + +#define IOMUXC_PAD_CTL_DAP_TDI (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_DAP_TDI_OFFSET) +#define IOMUXC_PAD_CTL_DAP_TMS_SWDIO (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_DAP_TMS_SWDIO_OFFSET) +#define IOMUXC_PAD_CTL_DAP_TCLK_SWCLK (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_DAP_TCLK_SWCLK_OFFSET) +#define IOMUXC_PAD_CTL_DAP_TDO_TRACESWO (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_DAP_TDO_TRACESWO_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO00 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO00_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO01 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO01_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO02 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO02_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO03 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO03_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO04 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO04_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO05 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO05_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO06 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO06_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO07 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO07_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO08 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO08_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO09 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO09_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO10 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO10_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO11 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO11_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO12 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO12_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO13 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO13_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO14 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO14_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO15 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO15_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO16 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO16_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO17 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO17_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO18 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO18_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO19 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO19_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO20 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO20_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO21 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO21_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO22 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO22_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO23 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO23_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO24 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO24_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO25 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO25_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO26 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO26_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO27 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO27_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO28 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO28_OFFSET) +#define IOMUXC_PAD_CTL_GPIO_IO29 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_GPIO_IO29_OFFSET) +#define IOMUXC_PAD_CTL_CCM_CLKO1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_CCM_CLKO1_OFFSET) +#define IOMUXC_PAD_CTL_CCM_CLKO2 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_CCM_CLKO2_OFFSET) +#define IOMUXC_PAD_CTL_CCM_CLKO3 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_CCM_CLKO3_OFFSET) +#define IOMUXC_PAD_CTL_CCM_CLKO4 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_CCM_CLKO4_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_MDC (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_MDC_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_MDIO (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_MDIO_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_TD3 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_TD3_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_TD2 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_TD2_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_TD1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_TD1_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_TD0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_TD0_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_TX_CTL (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_TX_CTL_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_TXC (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_TXC_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_RX_CTL (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_RX_CTL_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_RXC (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_RXC_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_RD0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_RD0_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_RD1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_RD1_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_RD2 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_RD2_OFFSET) +#define IOMUXC_PAD_CTL_ENET1_RD3 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET1_RD3_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_MDC (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_MDC_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_MDIO (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_MDIO_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_TD3 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_TD3_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_TD2 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_TD2_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_TD1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_TD1_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_TD0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_TD0_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_TX_CTL (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_TX_CTL_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_TXC (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_TXC_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_RX_CTL (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_RX_CTL_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_RXC (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_RXC_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_RD0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_RD0_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_RD1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_RD1_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_RD2 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_RD2_OFFSET) +#define IOMUXC_PAD_CTL_ENET2_RD3 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_ENET2_RD3_OFFSET) +#define IOMUXC_PAD_CTL_SD1_CLK (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_CLK_OFFSET) +#define IOMUXC_PAD_CTL_SD1_CMD (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_CMD_OFFSET) +#define IOMUXC_PAD_CTL_SD1_DATA0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_DATA0_OFFSET) +#define IOMUXC_PAD_CTL_SD1_DATA1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_DATA1_OFFSET) +#define IOMUXC_PAD_CTL_SD1_DATA2 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_DATA2_OFFSET) +#define IOMUXC_PAD_CTL_SD1_DATA3 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_DATA3_OFFSET) +#define IOMUXC_PAD_CTL_SD1_DATA4 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_DATA4_OFFSET) +#define IOMUXC_PAD_CTL_SD1_DATA5 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_DATA5_OFFSET) +#define IOMUXC_PAD_CTL_SD1_DATA6 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_DATA6_OFFSET) +#define IOMUXC_PAD_CTL_SD1_DATA7 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_DATA7_OFFSET) +#define IOMUXC_PAD_CTL_SD1_STROBE (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD1_STROBE_OFFSET) +#define IOMUXC_PAD_CTL_SD2_VSELECT (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_VSELECT_OFFSET) +#define IOMUXC_PAD_CTL_SD3_CLK (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD3_CLK_OFFSET) +#define IOMUXC_PAD_CTL_SD3_CMD (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD3_CMD_OFFSET) +#define IOMUXC_PAD_CTL_SD3_DATA0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD3_DATA0_OFFSET) +#define IOMUXC_PAD_CTL_SD3_DATA1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD3_DATA1_OFFSET) +#define IOMUXC_PAD_CTL_SD3_DATA2 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD3_DATA2_OFFSET) +#define IOMUXC_PAD_CTL_SD3_DATA3 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD3_DATA3_OFFSET) +#define IOMUXC_PAD_CTL_SD2_CD_B (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_CD_B_OFFSET) +#define IOMUXC_PAD_CTL_SD2_CLK (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_CLK_OFFSET) +#define IOMUXC_PAD_CTL_SD2_CMD (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_CMD_OFFSET) +#define IOMUXC_PAD_CTL_SD2_DATA0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_DATA0_OFFSET) +#define IOMUXC_PAD_CTL_SD2_DATA1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_DATA1_OFFSET) +#define IOMUXC_PAD_CTL_SD2_DATA2 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_DATA2_OFFSET) +#define IOMUXC_PAD_CTL_SD2_DATA3 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_DATA3_OFFSET) +#define IOMUXC_PAD_CTL_SD2_RESET_B (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SD2_RESET_B_OFFSET) +#define IOMUXC_PAD_CTL_I2C1_SCL (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_I2C1_SCL_OFFSET) +#define IOMUXC_PAD_CTL_I2C1_SDA (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_I2C1_SDA_OFFSET) +#define IOMUXC_PAD_CTL_I2C2_SCL (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_I2C2_SCL_OFFSET) +#define IOMUXC_PAD_CTL_I2C2_SDA (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_I2C2_SDA_OFFSET) +#define IOMUXC_PAD_CTL_UART1_RXD (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_UART1_RXD_OFFSET) +#define IOMUXC_PAD_CTL_UART1_TXD (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_UART1_TXD_OFFSET) +#define IOMUXC_PAD_CTL_UART2_RXD (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_UART2_RXD_OFFSET) +#define IOMUXC_PAD_CTL_UART2_TXD (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_UART2_TXD_OFFSET) +#define IOMUXC_PAD_CTL_PDM_CLK (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_PDM_CLK_OFFSET) +#define IOMUXC_PAD_CTL_PDM_BIT_STREAM0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_PDM_BIT_STREAM0_OFFSET) +#define IOMUXC_PAD_CTL_PDM_BIT_STREAM1 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_PDM_BIT_STREAM1_OFFSET) +#define IOMUXC_PAD_CTL_SAI1_TXFS (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SAI1_TXFS_OFFSET) +#define IOMUXC_PAD_CTL_SAI1_TXC (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SAI1_TXC_OFFSET) +#define IOMUXC_PAD_CTL_SAI1_TXD0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SAI1_TXD0_OFFSET) +#define IOMUXC_PAD_CTL_SAI1_RXD0 (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_SAI1_RXD0_OFFSET) +#define IOMUXC_PAD_CTL_WDOG_ANY (IMX9_IOMUXC1_BASE + IOMUXC_PAD_CTL_WDOG_ANY_OFFSET) + +#define CAN1_IPP_IND_CANRX_SELECT_INPUT (IMX9_IOMUXC1_BASE + CAN1_IPP_IND_CANRX_SELECT_INPUT_OFFSET) +#define CAN2_IPP_IND_CANRX_SELECT_INPUT (IMX9_IOMUXC1_BASE + CAN2_IPP_IND_CANRX_SELECT_INPUT_OFFSET) +#define CCMSRCGPCMIX_EXT1_CLK_SELECT_INPUT (IMX9_IOMUXC1_BASE + CCMSRCGPCMIX_EXT1_CLK_SELECT_INPUT_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_0 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_0_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_1 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_1_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_2 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_2_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_3 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_3_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_4 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_4_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_5 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_5_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_6 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_6_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_7 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_7_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_8 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_8_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_9 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_9_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_10 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_10_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_11 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_11_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_13 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_13_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_14 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_14_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_15 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_15_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_16 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_16_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_17 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_17_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_18 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_18_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_20 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_20_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_22 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_22_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_23 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_23_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_24 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_24_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_25 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_25_OFFSET) +#define FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_27 (IMX9_IOMUXC1_BASE + FLEXIO1_IPP_IND_FLEXIO_SELECT_INPUT_27_OFFSET) +#define I3C2_PIN_SCL_IN_SELECT_INPUT (IMX9_IOMUXC1_BASE + 13C2_PIN_SCL_IN_SELECT_INPUT_OFFSET) +#define I3C2_PIN_SDA_IN_SELECT_INPUT (IMX9_IOMUXC1_BASE + 13C2_PIN_SDA_IN_SELECT_INPUT_OFFSET) +#define JTAG_MUX_TCK_SELECT_INPUT (IMX9_IOMUXC1_BASE + JTAG_MUX_TCK_SELECT_INPUT_OFFSET) +#define JTAG_MUX_TDI_SELECT_INPUT (IMX9_IOMUXC1_BASE + JTAG_MUX_TDI_SELECT_INPUT_OFFSET) +#define JTAG_MUX_TMS_SELECT_INPUT (IMX9_IOMUXC1_BASE + JTAG_MUX_TMS_SELECT_INPUT_OFFSET) +#define LP12C3_IPP_IND_LPI2C_SCL_SELECT_INPUT (IMX9_IOMUXC1_BASE + LP12C3_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET) +#define LPI12C3_IPP_IND_LPI2C_SDA_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPI12C3_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET) +#define LP12C5_IPP_IND_LPI2C_SCL_SELECT_INPUT (IMX9_IOMUXC1_BASE + LP12C5_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET) +#define LP12C5_IPP_IND_LPI2C_SDA_SELECT_INPUT (IMX9_IOMUXC1_BASE + LP12C5_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET) +#define LPI2C6_IPP_IND_LPI2C_SCL_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPI2C6_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET) +#define LPI2C6_IPP_IND_LPI2C_SDA_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPI2C6_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET) +#define LPI2C7_IPP_IND_LPI2C_SCL_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPI2C7_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET) +#define LPI2C7_IPP_IND_LPI2C_SDA_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPI2C7_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET) +#define LPI2C8_IPP_IND_LPI2C_SCL_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPI2C8_IPP_IND_LPI2C_SCL_SELECT_INPUT_OFFSET) +#define LPI2C8_IPP_IND_LPI2C_SDA_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPI2C8_IPP_IND_LPI2C_SDA_SELECT_INPUT_OFFSET) +#define LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_O (IMX9_IOMUXC1_BASE + LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_O_OFFSET) +#define LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_1 (IMX9_IOMUXC1_BASE + LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_1_OFFSET) +#define LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_2 (IMX9_IOMUXC1_BASE + LPTMR2_IPP_IND_LPTIMER_SELECT_INPUT_2_OFFSET) +#define LPUART3_IPP_IND_LPUART_CTS_N_SELECT_INP (IMX9_IOMUXC1_BASE + LPUART3_IPP_IND_LPUART_CTS_N_SELECT_INP_OFFSET) +#define LPUART3_IPP_IND_LPUART_RXD_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPUART3_IPP_IND_LPUART_RXD_SELECT_INPUT_OFFSET) +#define LPUART3_IPP_IND_LPUART_TXD_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPUART3_IPP_IND_LPUART_TXD_SELECT_INPUT_OFFSET) +#define LPUART4_IPP_IND_LPUART_CTS_N_SELECT_INP (IMX9_IOMUXC1_BASE + LPUART4_IPP_IND_LPUART_CTS_N_SELECT_INP_OFFSET) +#define LPUART4_IPP_IND_LPUART_RXD_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPUART4_IPP_IND_LPUART_RXD_SELECT_INPUT_OFFSET) +#define LPUART4_IPP_IND_LPUART_TXD_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPUART4_IPP_IND_LPUART_TXD_SELECT_INPUT_OFFSET) +#define LPUARTS_IPP_IND_LPUART_CTS_N_SELECT_INP (IMX9_IOMUXC1_BASE + LPUARTS_IPP_IND_LPUART_CTS_N_SELECT_INP_OFFSET) +#define LPUARTS_IPP_IND_LPUART_RXD_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPUARTS_IPP_IND_LPUART_RXD_SELECT_INPUT_OFFSET) +#define LPUARTS_IPP_IND_LPUART_TXD_SELECT_INPUT (IMX9_IOMUXC1_BASE + LPUARTS_IPP_IND_LPUART_TXD_SELECT_INPUT_OFFSET) +#define SAI1_IPP_IND_SAI_MCLK_SELECT_INPUT (IMX9_IOMUXC1_BASE + SAI1_IPP_IND_SAI_MCLK_SELECT_INPUT_OFFSET) +#define SAI3_IPP_IND_SAI_RXBCLK_SELECT_INPUT (IMX9_IOMUXC1_BASE + SAI3_IPP_IND_SAI_RXBCLK_SELECT_INPUT_OFFSET) +#define SAI3_IPP_IND_SAI_RXSYNC_SELECT_INPUT (IMX9_IOMUXC1_BASE + SAI3_IPP_IND_SAI_RXSYNC_SELECT_INPUT_OFFSET) +#define SPDIF_SPDIF_I_SELECT_INPUT (IMX9_IOMUXC1_BASE + SPDIF_SPDIF_I_SELECT_INPUT_OFFSET) +#define USDHC3_IPP_CARD_CLK_IN_SELECT_INPUT (IMX9_IOMUXC1_BASE + USDHC3_IPP_CARD_CLK_IN_SELECT_INPUT_OFFSET) +#define USDHC3_IPP_CMD_IN_SELECT_INPUT (IMX9_IOMUXC1_BASE + USDHC3_IPP_CMD_IN_SELECT_INPUT_OFFSET) +#define USDHC3_IPP_DATO_IN_SELECT_INPUT (IMX9_IOMUXC1_BASE + USDHC3_IPP_DATO_IN_SELECT_INPUT_OFFSET) +#define USDHC3_IPP_DAT1_IN_SELECT_INPUT (IMX9_IOMUXC1_BASE + USDHC3_IPP_DAT1_IN_SELECT_INPUT_OFFSET) +#define USDHC3_IPP_DAT2_IN_SELECT_INPUT (IMX9_IOMUXC1_BASE + USDHC3_IPP_DAT2_IN_SELECT_INPUT_OFFSET) +#define USDHC3_IPP_DAT3_IN_SELECT_INPUT (IMX9_IOMUXC1_BASE + USDHC3_IPP_DAT3_IN_SELECT_INPUT_OFFSET) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_IOMUX_H */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h b/arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h new file mode 100644 index 0000000000000..050602fc0af0d --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h @@ -0,0 +1,174 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_MEMORYMAP_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_MEMORYMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IMX9_GIC_DISTRIBUTOR_BASE (0x48000000UL) +#define IMX9_GIC_REDISTRIBUTOR_BASE (0x48040000UL) +#define IMX9_ANA_OSC_BASE (0x44480000UL) +#define IMX9_AXBS_BASE (0x44510000UL) +#define IMX9_BBNSM_BASE (0x44440000UL) +#define IMX9_BLK_CTRL_BBSMMIX1_BASE (0x44410000UL) +#define IMX9_BLK_CTRL_MLMIX_BASE (0x4A810000UL) +#define IMX9_BLK_CTRL_NIC_WRAPPER1_BASE (0x49000000UL) +#define IMX9_BLK_CTRL_NS_AONMIX1_BASE (0x44210000UL) +#define IMX9_BLK_CTRL_S_AONMIX2_BASE (0x444F0000UL) +#define IMX9_BLK_CTRL_WAKEUPMIX1_BASE (0x42420000UL) +#define IMX9_CAN1_BASE (0x443A0000UL) +#define IMX9_CAN2_BASE (0x425B0000UL) +#define IMX9_CCM_CTRL_BASE (0x44450000UL) +#define IMX9_CM33_MCM_BASE (0x44420000UL) +#define IMX9_DDR_CTRL_BASE (0x4E300000UL) +#define IMX9_BLK_CTRL_DDRMIX_BASE (0x4E010000UL) +#define IMX9_DMA3_BASE (0x44000000UL) +#define IMX9_DMA4_BASE (0x42000000UL) +#define IMX9_PMRO_BASE (0x44484000UL) +#define IMX9_ENET_BASE (0x42890000UL) +#define IMX9_ENET_QOS_BASE (0x428A0000UL) +#define IMX9_FLEXIO1_BASE (0x425C0000UL) +#define IMX9_FLEXIO2_BASE (0x425D0000UL) +#define IMX9_FLEXSPI_BASE (0x425E0000UL) +#define IMX9_FLEXSPI_ARDF_BASE (0x47420000UL) +#define IMX9_FLEXSPI_ATDF_BASE (0x47430000UL) +#define IMX9_GPC_CTRL_CM33_BASE (0x44470000UL) +#define IMX9_GPC_CTRL_CA55_0_BASE (0x44470800UL) +#define IMX9_GPC_CTRL_CA55_1_BASE (0x44471000UL) +#define IMX9_GPC_CTRL_CA55_CLUSTER_BASE (0x44471800UL) +#define IMX9_SAI1_BASE (0x443B0000UL) +#define IMX9_SAI2_BASE (0x42650000UL) +#define IMX9_SAI3_BASE (0x42660000UL) +#define IMX9_I3C1_BASE (0x44330000UL) +#define IMX9_I3C2_BASE (0x42520000UL) +#define IMX9_IOMUXC1_BASE (0x443C0000UL) +#define IMX9_ISI_BASE (0x4AE40000UL) +#define IMX9_LCDIF_BASE (0x4AE30000UL) +#define IMX9_LPI2C1_BASE (0x44340000UL) +#define IMX9_LPI2C2_BASE (0x44350000UL) +#define IMX9_LPI2C3_BASE (0x42530000UL) +#define IMX9_LPI2C4_BASE (0x42540000UL) +#define IMX9_LPI2C5_BASE (0x426B0000UL) +#define IMX9_LPI2C6_BASE (0x426C0000UL) +#define IMX9_LPI2C7_BASE (0x426D0000UL) +#define IMX9_LPI2C8_BASE (0x426E0000UL) +#define IMX9_LPIT1_BASE (0x442F0000UL) +#define IMX9_LPIT2_BASE (0x424C0000UL) +#define IMX9_LPSPI1_BASE (0x44360000UL) +#define IMX9_LPSPI2_BASE (0x44370000UL) +#define IMX9_LPSPI3_BASE (0x42550000UL) +#define IMX9_LPSPI4_BASE (0x42560000UL) +#define IMX9_LPSPI5_BASE (0x426F0000UL) +#define IMX9_LPSPI6_BASE (0x42700000UL) +#define IMX9_LPSPI7_BASE (0x42710000UL) +#define IMX9_LPSPI8_BASE (0x42720000UL) +#define IMX9_LPTMR1_BASE (0x44300000UL) +#define IMX9_LPTMR2_BASE (0x424D0000UL) +#define IMX9_LPUART1_BASE (0x44380000UL) +#define IMX9_LPUART2_BASE (0x44390000UL) +#define IMX9_LPUART3_BASE (0x42570000UL) +#define IMX9_LPUART4_BASE (0x42580000UL) +#define IMX9_LPUART5_BASE (0x42590000UL) +#define IMX9_LPUART6_BASE (0x425A0000UL) +#define IMX9_LPUART7_BASE (0x42690000UL) +#define IMX9_LPUART8_BASE (0x426A0000UL) +#define IMX9_M33_CACHE_MCM_BASE (0x44401000UL) +#define IMX9_BLK_CTRL_MEDIAMIX_BASE (0x4AC10000UL) +#define IMX9_MIPI_CSI_CSR_BASE (0x4AE00000UL) +#define IMX9_MIPI_DSI_BASE (0x4AE10000UL) +#define IMX9_MU1__MUB_BASE (0x44230000UL) +#define IMX9_MU2__MUB_BASE (0x42440000UL) +#define IMX9_NPU_BASE (0x4A900000UL) +#define IMX9_OCOTP_BASE (0x47518000UL) +#define IMX9_OCRAM_MECC1_BASE (0x490A0000UL) +#define IMX9_FLEXSPI_OTFAD1_BASE (0x425E0C00UL) +#define IMX9_PDM_BASE (0x44520000UL) +#define IMX9_ARMPLL_BASE (0x44481000UL) +#define IMX9_AUDIOPLL_BASE (0x44481200UL) +#define IMX9_DRAMPLL_BASE (0x44481300UL) +#define IMX9_SYSPLL_BASE (0x44481100UL) +#define IMX9_VIDEOPLL_BASE (0x44481400UL) +#define IMX9_PXP_BASE (0x4AE20000UL) +#define IMX9_GPIO1_BASE (0x47400000UL) +#define IMX9_GPIO2_BASE (0x43810000UL) +#define IMX9_GPIO3_BASE (0x43820000UL) +#define IMX9_GPIO4_BASE (0x43830000UL) +#define IMX9_ROMCP1_BASE (0x44430000UL) +#define IMX9_ROMCP2_BASE (0x42640000UL) +#define IMX9_ADC1_BASE (0x44530000UL) +#define IMX9_SEMA42_1_BASE (0x44260000UL) +#define IMX9_SEMA42_2_BASE (0x42450000UL) +#define IMX9_SFA_BASE (0x44483000UL) +#define IMX9_SPDIF_BASE (0x42680000UL) +#define IMX9_SRC_SENTINEL_SLICE_BASE (0x44460400UL) +#define IMX9_SRC_AON_SLICE_BASE (0x44460800UL) +#define IMX9_SRC_WKUP_SLICE_BASE (0x44460C00UL) +#define IMX9_SRC_DDR_SLICE_BASE (0x44461000UL) +#define IMX9_SRC_DPHY_SLICE_BASE (0x44461400UL) +#define IMX9_SRC_ML_SLICE_BASE (0x44461800UL) +#define IMX9_SRC_NIC_SLICE_BASE (0x44461C00UL) +#define IMX9_SRC_HSIO_SLICE_BASE (0x44462000UL) +#define IMX9_SRC_MEDIA_SLICE_BASE (0x44462400UL) +#define IMX9_SRC_M33P_SLICE_BASE (0x44462800UL) +#define IMX9_SRC_A55C0_SLICE_BASE (0x44462C00UL) +#define IMX9_SRC_A55C1_SLICE_BASE (0x44463000UL) +#define IMX9_SRC_A55P_SLICE_BASE (0x44463400UL) +#define IMX9_M33_PCF1_BASE (0x443E0000UL) +#define IMX9_M33_PSF1_BASE (0x443F0000UL) +#define IMX9_SYS_CTR_COMPARE_BASE (0x442A0000UL) +#define IMX9_SYS_CTR_CONTROL_BASE (0x44290000UL) +#define IMX9_SYS_CTR_READ_BASE (0x442B0000UL) +#define IMX9_TMU_BASE (0x44482000UL) +#define IMX9_TPM1_BASE (0x44310000UL) +#define IMX9_TPM2_BASE (0x44320000UL) +#define IMX9_TPM3_BASE (0x424E0000UL) +#define IMX9_TPM4_BASE (0x424F0000UL) +#define IMX9_TPM5_BASE (0x42500000UL) +#define IMX9_TPM6_BASE (0x42510000UL) +#define IMX9_TRDC1_BASE (0x44270000UL) +#define IMX9_TRDC2_BASE (0x42460000UL) +#define IMX9_TRGMUX_BASE (0x44531000UL) +#define IMX9_TSTMR1_BASE (0x442C0000UL) +#define IMX9_TSTMR2_BASE (0x42480000UL) +#define IMX9_USB_OTG1_BASE (0x4C100000UL) +#define IMX9_USB_OTG2_BASE (0x4C200000UL) +#define IMX9_USBNC_OTG1_BASE (0x4C100200UL) +#define IMX9_USBNC_OTG2_BASE (0x4C200200UL) +#define IMX9_USDHC1_BASE (0x42850000UL) +#define IMX9_USDHC2_BASE (0x42860000UL) +#define IMX9_USDHC3_BASE (0x428B0000UL) +#define IMX9_WDOG1_BASE (0x442D0000UL) +#define IMX9_WDOG2_BASE (0x442E0000UL) +#define IMX9_WDOG3_BASE (0x42490000UL) +#define IMX9_WDOG4_BASE (0x424A0000UL) +#define IMX9_WDOG5_BASE (0x424B0000UL) +#define IMX9_LPCAC_PC_BASE (0x44400000UL) +#define IMX9_LPCAC_PS_BASE (0x44400800UL) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_MEMORYMAP_H */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_pinmux.h b/arch/arm64/src/imx9/hardware/imx93/imx93_pinmux.h new file mode 100644 index 0000000000000..2a3487d98530a --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_pinmux.h @@ -0,0 +1,634 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx93/imx93_pinmux.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_PINMUX_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_PINMUX_H + +#define IOMUXC_PAD_DAP_TDI_JTAG_MUX_TDI IOMUX_PADCFG(0x443c0000, 0x0, 0x443c03d8, 0x00000000, 0x443c01b0) +#define IOMUXC_PAD_DAP_TDI_MQS2_LEFT IOMUX_PADCFG(0x443c0000, 0x1, 0x00000000, 0x00000000, 0x443c01b0) +#define IOMUXC_PAD_DAP_TDI_CAN2_TX IOMUX_PADCFG(0x443c0000, 0x3, 0x00000000, 0x00000000, 0x443c01b0) +#define IOMUXC_PAD_DAP_TDI_FLEXIO2_FLEXIO30 IOMUX_PADCFG(0x443c0000, 0x4, 0x00000000, 0x00000000, 0x443c01b0) +#define IOMUXC_PAD_DAP_TDI_GPIO3_IO28 IOMUX_PADCFG(0x443c0000, 0x5, 0x00000000, 0x00000000, 0x443c01b0) +#define IOMUXC_PAD_DAP_TDI_LPUART5_RX IOMUX_PADCFG(0x443c0000, 0x6, 0x443c0430, 0x00000000, 0x443c01b0) +#define IOMUXC_PAD_DAP_TMS_SWDIO_JTAG_MUX_TMS IOMUX_PADCFG(0x443c0004, 0x0, 0x443c03dc, 0x00000000, 0x443c01b4) +#define IOMUXC_PAD_DAP_TMS_SWDIO_FLEXIO2_FLEXIO31 IOMUX_PADCFG(0x443c0004, 0x4, 0x00000000, 0x00000000, 0x443c01b4) +#define IOMUXC_PAD_DAP_TMS_SWDIO_GPIO3_IO29 IOMUX_PADCFG(0x443c0004, 0x5, 0x00000000, 0x00000000, 0x443c01b4) +#define IOMUXC_PAD_DAP_TMS_SWDIO_LPUART5_RTS_B IOMUX_PADCFG(0x443c0004, 0x6, 0x00000000, 0x00000000, 0x443c01b4) +#define IOMUXC_PAD_DAP_TCLK_SWCLK_JTAG_MUX_TCK IOMUX_PADCFG(0x443c0008, 0x0, 0x443c03d4, 0x00000000, 0x443c01b8) +#define IOMUXC_PAD_DAP_TCLK_SWCLK_FLEXIO1_FLEXIO30 IOMUX_PADCFG(0x443c0008, 0x4, 0x00000000, 0x00000000, 0x443c01b8) +#define IOMUXC_PAD_DAP_TCLK_SWCLK_GPIO3_IO30 IOMUX_PADCFG(0x443c0008, 0x5, 0x00000000, 0x00000000, 0x443c01b8) +#define IOMUXC_PAD_DAP_TCLK_SWCLK_LPUART5_CTS_B IOMUX_PADCFG(0x443c0008, 0x6, 0x443c042c, 0x00000000, 0x443c01b8) +#define IOMUXC_PAD_DAP_TDO_TRACESWO_JTAG_MUX_TDO IOMUX_PADCFG(0x443c000c, 0x0, 0x00000000, 0x00000000, 0x443c01bc) +#define IOMUXC_PAD_DAP_TDO_TRACESWO_MQS2_RIGHT IOMUX_PADCFG(0x443c000c, 0x1, 0x00000000, 0x00000000, 0x443c01bc) +#define IOMUXC_PAD_DAP_TDO_TRACESWO_CAN2_RX IOMUX_PADCFG(0x443c000c, 0x3, 0x443c0364, 0x00000000, 0x443c01bc) +#define IOMUXC_PAD_DAP_TDO_TRACESWO_FLEXIO1_FLEXIO31 IOMUX_PADCFG(0x443c000c, 0x4, 0x00000000, 0x00000000, 0x443c01bc) +#define IOMUXC_PAD_DAP_TDO_TRACESWO_GPIO3_IO31 IOMUX_PADCFG(0x443c000c, 0x5, 0x00000000, 0x00000000, 0x443c01bc) +#define IOMUXC_PAD_DAP_TDO_TRACESWO_LPUART5_TX IOMUX_PADCFG(0x443c000c, 0x6, 0x443c0434, 0x00000000, 0x443c01bc) +#define IOMUXC_PAD_GPIO_IO00_GPIO2_IO00 IOMUX_PADCFG(0x443c0010, 0x0, 0x00000000, 0x00000000, 0x443c01c0) +#define IOMUXC_PAD_GPIO_IO00_LPI2C3_SDA IOMUX_PADCFG(0x443c0010, 0x1, 0x443c03e4, 0x00000000, 0x443c01c0) +#define IOMUXC_PAD_GPIO_IO00_MEDIAMIX_CAM_CLK IOMUX_PADCFG(0x443c0010, 0x2, 0x00000000, 0x00000000, 0x443c01c0) +#define IOMUXC_PAD_GPIO_IO00_MEDIAMIX_DISP_CLK IOMUX_PADCFG(0x443c0010, 0x3, 0x00000000, 0x00000000, 0x443c01c0) +#define IOMUXC_PAD_GPIO_IO00_LPSPI6_PCS0 IOMUX_PADCFG(0x443c0010, 0x4, 0x00000000, 0x00000000, 0x443c01c0) +#define IOMUXC_PAD_GPIO_IO00_LPUART5_TX IOMUX_PADCFG(0x443c0010, 0x5, 0x443c0434, 0x00000001, 0x443c01c0) +#define IOMUXC_PAD_GPIO_IO00_LPI2C5_SDA IOMUX_PADCFG(0x443c0010, 0x6, 0x443c03ec, 0x00000000, 0x443c01c0) +#define IOMUXC_PAD_GPIO_IO00_FLEXIO1_FLEXIO00 IOMUX_PADCFG(0x443c0010, 0x7, 0x443c036c, 0x00000000, 0x443c01c0) +#define IOMUXC_PAD_GPIO_IO01_GPIO2_IO01 IOMUX_PADCFG(0x443c0014, 0x0, 0x00000000, 0x00000000, 0x443c01c4) +#define IOMUXC_PAD_GPIO_IO01_LPI2C3_SCL IOMUX_PADCFG(0x443c0014, 0x1, 0x443c03e0, 0x00000000, 0x443c01c4) +#define IOMUXC_PAD_GPIO_IO01_MEDIAMIX_CAM_DATA00 IOMUX_PADCFG(0x443c0014, 0x2, 0x00000000, 0x00000000, 0x443c01c4) +#define IOMUXC_PAD_GPIO_IO01_MEDIAMIX_DISP_DE IOMUX_PADCFG(0x443c0014, 0x3, 0x00000000, 0x00000000, 0x443c01c4) +#define IOMUXC_PAD_GPIO_IO01_LPSPI6_SIN IOMUX_PADCFG(0x443c0014, 0x4, 0x00000000, 0x00000000, 0x443c01c4) +#define IOMUXC_PAD_GPIO_IO01_LPUART5_RX IOMUX_PADCFG(0x443c0014, 0x5, 0x443c0430, 0x00000001, 0x443c01c4) +#define IOMUXC_PAD_GPIO_IO01_LPI2C5_SCL IOMUX_PADCFG(0x443c0014, 0x6, 0x443c03e8, 0x00000000, 0x443c01c4) +#define IOMUXC_PAD_GPIO_IO01_FLEXIO1_FLEXIO01 IOMUX_PADCFG(0x443c0014, 0x7, 0x443c0370, 0x00000000, 0x443c01c4) +#define IOMUXC_PAD_GPIO_IO02_GPIO2_IO02 IOMUX_PADCFG(0x443c0018, 0x0, 0x00000000, 0x00000000, 0x443c01c8) +#define IOMUXC_PAD_GPIO_IO02_LPI2C4_SDA IOMUX_PADCFG(0x443c0018, 0x1, 0x00000000, 0x00000000, 0x443c01c8) +#define IOMUXC_PAD_GPIO_IO02_MEDIAMIX_CAM_VSYNC IOMUX_PADCFG(0x443c0018, 0x2, 0x00000000, 0x00000000, 0x443c01c8) +#define IOMUXC_PAD_GPIO_IO02_MEDIAMIX_DISP_VSYNC IOMUX_PADCFG(0x443c0018, 0x3, 0x00000000, 0x00000000, 0x443c01c8) +#define IOMUXC_PAD_GPIO_IO02_LPSPI6_SOUT IOMUX_PADCFG(0x443c0018, 0x4, 0x00000000, 0x00000000, 0x443c01c8) +#define IOMUXC_PAD_GPIO_IO02_LPUART5_CTS_B IOMUX_PADCFG(0x443c0018, 0x5, 0x443c042c, 0x00000001, 0x443c01c8) +#define IOMUXC_PAD_GPIO_IO02_LPI2C6_SDA IOMUX_PADCFG(0x443c0018, 0x6, 0x443c03f4, 0x00000000, 0x443c01c8) +#define IOMUXC_PAD_GPIO_IO02_FLEXIO1_FLEXIO02 IOMUX_PADCFG(0x443c0018, 0x7, 0x443c0374, 0x00000000, 0x443c01c8) +#define IOMUXC_PAD_GPIO_IO03_GPIO2_IO03 IOMUX_PADCFG(0x443c001c, 0x0, 0x00000000, 0x00000000, 0x443c01cc) +#define IOMUXC_PAD_GPIO_IO03_LPI2C4_SCL IOMUX_PADCFG(0x443c001c, 0x1, 0x00000000, 0x00000000, 0x443c01cc) +#define IOMUXC_PAD_GPIO_IO03_MEDIAMIX_CAM_HSYNC IOMUX_PADCFG(0x443c001c, 0x2, 0x00000000, 0x00000000, 0x443c01cc) +#define IOMUXC_PAD_GPIO_IO03_MEDIAMIX_DISP_HSYNC IOMUX_PADCFG(0x443c001c, 0x3, 0x00000000, 0x00000000, 0x443c01cc) +#define IOMUXC_PAD_GPIO_IO03_LPSPI6_SCK IOMUX_PADCFG(0x443c001c, 0x4, 0x00000000, 0x00000000, 0x443c01cc) +#define IOMUXC_PAD_GPIO_IO03_LPUART5_RTS_B IOMUX_PADCFG(0x443c001c, 0x5, 0x00000000, 0x00000000, 0x443c01cc) +#define IOMUXC_PAD_GPIO_IO03_LPI2C6_SCL IOMUX_PADCFG(0x443c001c, 0x6, 0x443c03f0, 0x00000000, 0x443c01cc) +#define IOMUXC_PAD_GPIO_IO03_FLEXIO1_FLEXIO03 IOMUX_PADCFG(0x443c001c, 0x7, 0x443c0378, 0x00000000, 0x443c01cc) +#define IOMUXC_PAD_GPIO_IO04_GPIO2_IO04 IOMUX_PADCFG(0x443c0020, 0x0, 0x00000000, 0x00000000, 0x443c01d0) +#define IOMUXC_PAD_GPIO_IO04_TPM3_CH0 IOMUX_PADCFG(0x443c0020, 0x1, 0x00000000, 0x00000000, 0x443c01d0) +#define IOMUXC_PAD_GPIO_IO04_PDM_CLK IOMUX_PADCFG(0x443c0020, 0x2, 0x00000000, 0x00000000, 0x443c01d0) +#define IOMUXC_PAD_GPIO_IO04_MEDIAMIX_DISP_DATA00 IOMUX_PADCFG(0x443c0020, 0x3, 0x00000000, 0x00000000, 0x443c01d0) +#define IOMUXC_PAD_GPIO_IO04_LPSPI7_PCS0 IOMUX_PADCFG(0x443c0020, 0x4, 0x00000000, 0x00000000, 0x443c01d0) +#define IOMUXC_PAD_GPIO_IO04_LPUART6_TX IOMUX_PADCFG(0x443c0020, 0x5, 0x00000000, 0x00000000, 0x443c01d0) +#define IOMUXC_PAD_GPIO_IO04_LPI2C6_SDA IOMUX_PADCFG(0x443c0020, 0x6, 0x443c03f4, 0x00000001, 0x443c01d0) +#define IOMUXC_PAD_GPIO_IO04_FLEXIO1_FLEXIO04 IOMUX_PADCFG(0x443c0020, 0x7, 0x443c037c, 0x00000000, 0x443c01d0) +#define IOMUXC_PAD_GPIO_IO05_GPIO2_IO05 IOMUX_PADCFG(0x443c0024, 0x0, 0x00000000, 0x00000000, 0x443c01d4) +#define IOMUXC_PAD_GPIO_IO05_TPM4_CH0 IOMUX_PADCFG(0x443c0024, 0x1, 0x00000000, 0x00000000, 0x443c01d4) +#define IOMUXC_PAD_GPIO_IO05_PDM_BIT_STREAM00 IOMUX_PADCFG(0x443c0024, 0x2, 0x443c0438, 0x00000000, 0x443c01d4) +#define IOMUXC_PAD_GPIO_IO05_MEDIAMIX_DISP_DATA01 IOMUX_PADCFG(0x443c0024, 0x3, 0x00000000, 0x00000000, 0x443c01d4) +#define IOMUXC_PAD_GPIO_IO05_LPSPI7_SIN IOMUX_PADCFG(0x443c0024, 0x4, 0x00000000, 0x00000000, 0x443c01d4) +#define IOMUXC_PAD_GPIO_IO05_LPUART6_RX IOMUX_PADCFG(0x443c0024, 0x5, 0x00000000, 0x00000000, 0x443c01d4) +#define IOMUXC_PAD_GPIO_IO05_LPI2C6_SCL IOMUX_PADCFG(0x443c0024, 0x6, 0x443c03f0, 0x00000001, 0x443c01d4) +#define IOMUXC_PAD_GPIO_IO05_FLEXIO1_FLEXIO05 IOMUX_PADCFG(0x443c0024, 0x7, 0x443c0380, 0x00000000, 0x443c01d4) +#define IOMUXC_PAD_GPIO_IO06_GPIO2_IO06 IOMUX_PADCFG(0x443c0028, 0x0, 0x00000000, 0x00000000, 0x443c01d8) +#define IOMUXC_PAD_GPIO_IO06_TPM5_CH0 IOMUX_PADCFG(0x443c0028, 0x1, 0x00000000, 0x00000000, 0x443c01d8) +#define IOMUXC_PAD_GPIO_IO06_PDM_BIT_STREAM01 IOMUX_PADCFG(0x443c0028, 0x2, 0x443c043c, 0x00000000, 0x443c01d8) +#define IOMUXC_PAD_GPIO_IO06_MEDIAMIX_DISP_DATA02 IOMUX_PADCFG(0x443c0028, 0x3, 0x00000000, 0x00000000, 0x443c01d8) +#define IOMUXC_PAD_GPIO_IO06_LPSPI7_SOUT IOMUX_PADCFG(0x443c0028, 0x4, 0x00000000, 0x00000000, 0x443c01d8) +#define IOMUXC_PAD_GPIO_IO06_LPUART6_CTS_B IOMUX_PADCFG(0x443c0028, 0x5, 0x00000000, 0x00000000, 0x443c01d8) +#define IOMUXC_PAD_GPIO_IO06_LPI2C7_SDA IOMUX_PADCFG(0x443c0028, 0x6, 0x443c03fc, 0x00000000, 0x443c01d8) +#define IOMUXC_PAD_GPIO_IO06_FLEXIO1_FLEXIO06 IOMUX_PADCFG(0x443c0028, 0x7, 0x443c0384, 0x00000000, 0x443c01d8) +#define IOMUXC_PAD_GPIO_IO07_GPIO2_IO07 IOMUX_PADCFG(0x443c002c, 0x0, 0x00000000, 0x00000000, 0x443c01dc) +#define IOMUXC_PAD_GPIO_IO07_LPSPI3_PCS1 IOMUX_PADCFG(0x443c002c, 0x1, 0x00000000, 0x00000000, 0x443c01dc) +#define IOMUXC_PAD_GPIO_IO07_MEDIAMIX_CAM_DATA01 IOMUX_PADCFG(0x443c002c, 0x2, 0x00000000, 0x00000000, 0x443c01dc) +#define IOMUXC_PAD_GPIO_IO07_MEDIAMIX_DISP_DATA03 IOMUX_PADCFG(0x443c002c, 0x3, 0x00000000, 0x00000000, 0x443c01dc) +#define IOMUXC_PAD_GPIO_IO07_LPSPI7_SCK IOMUX_PADCFG(0x443c002c, 0x4, 0x00000000, 0x00000000, 0x443c01dc) +#define IOMUXC_PAD_GPIO_IO07_LPUART6_RTS_B IOMUX_PADCFG(0x443c002c, 0x5, 0x00000000, 0x00000000, 0x443c01dc) +#define IOMUXC_PAD_GPIO_IO07_LPI2C7_SCL IOMUX_PADCFG(0x443c002c, 0x6, 0x443c03f8, 0x00000000, 0x443c01dc) +#define IOMUXC_PAD_GPIO_IO07_FLEXIO1_FLEXIO07 IOMUX_PADCFG(0x443c002c, 0x7, 0x443c0388, 0x00000000, 0x443c01dc) +#define IOMUXC_PAD_GPIO_IO08_GPIO2_IO08 IOMUX_PADCFG(0x443c0030, 0x0, 0x00000000, 0x00000000, 0x443c01e0) +#define IOMUXC_PAD_GPIO_IO08_LPSPI3_PCS0 IOMUX_PADCFG(0x443c0030, 0x1, 0x00000000, 0x00000000, 0x443c01e0) +#define IOMUXC_PAD_GPIO_IO08_MEDIAMIX_CAM_DATA02 IOMUX_PADCFG(0x443c0030, 0x2, 0x00000000, 0x00000000, 0x443c01e0) +#define IOMUXC_PAD_GPIO_IO08_MEDIAMIX_DISP_DATA04 IOMUX_PADCFG(0x443c0030, 0x3, 0x00000000, 0x00000000, 0x443c01e0) +#define IOMUXC_PAD_GPIO_IO08_TPM6_CH0 IOMUX_PADCFG(0x443c0030, 0x4, 0x00000000, 0x00000000, 0x443c01e0) +#define IOMUXC_PAD_GPIO_IO08_LPUART7_TX IOMUX_PADCFG(0x443c0030, 0x5, 0x00000000, 0x00000000, 0x443c01e0) +#define IOMUXC_PAD_GPIO_IO08_LPI2C7_SDA IOMUX_PADCFG(0x443c0030, 0x6, 0x443c03fc, 0x00000001, 0x443c01e0) +#define IOMUXC_PAD_GPIO_IO08_FLEXIO1_FLEXIO08 IOMUX_PADCFG(0x443c0030, 0x7, 0x443c038c, 0x00000000, 0x443c01e0) +#define IOMUXC_PAD_GPIO_IO09_GPIO2_IO09 IOMUX_PADCFG(0x443c0034, 0x0, 0x00000000, 0x00000000, 0x443c01e4) +#define IOMUXC_PAD_GPIO_IO09_LPSPI3_SIN IOMUX_PADCFG(0x443c0034, 0x1, 0x00000000, 0x00000000, 0x443c01e4) +#define IOMUXC_PAD_GPIO_IO09_MEDIAMIX_CAM_DATA03 IOMUX_PADCFG(0x443c0034, 0x2, 0x00000000, 0x00000000, 0x443c01e4) +#define IOMUXC_PAD_GPIO_IO09_MEDIAMIX_DISP_DATA05 IOMUX_PADCFG(0x443c0034, 0x3, 0x00000000, 0x00000000, 0x443c01e4) +#define IOMUXC_PAD_GPIO_IO09_TPM3_EXTCLK IOMUX_PADCFG(0x443c0034, 0x4, 0x00000000, 0x00000000, 0x443c01e4) +#define IOMUXC_PAD_GPIO_IO09_LPUART7_RX IOMUX_PADCFG(0x443c0034, 0x5, 0x00000000, 0x00000000, 0x443c01e4) +#define IOMUXC_PAD_GPIO_IO09_LPI2C7_SCL IOMUX_PADCFG(0x443c0034, 0x6, 0x443c03f8, 0x00000001, 0x443c01e4) +#define IOMUXC_PAD_GPIO_IO09_FLEXIO1_FLEXIO09 IOMUX_PADCFG(0x443c0034, 0x7, 0x443c0390, 0x00000000, 0x443c01e4) +#define IOMUXC_PAD_GPIO_IO10_GPIO2_IO10 IOMUX_PADCFG(0x443c0038, 0x0, 0x00000000, 0x00000000, 0x443c01e8) +#define IOMUXC_PAD_GPIO_IO10_LPSPI3_SOUT IOMUX_PADCFG(0x443c0038, 0x1, 0x00000000, 0x00000000, 0x443c01e8) +#define IOMUXC_PAD_GPIO_IO10_MEDIAMIX_CAM_DATA04 IOMUX_PADCFG(0x443c0038, 0x2, 0x00000000, 0x00000000, 0x443c01e8) +#define IOMUXC_PAD_GPIO_IO10_MEDIAMIX_DISP_DATA06 IOMUX_PADCFG(0x443c0038, 0x3, 0x00000000, 0x00000000, 0x443c01e8) +#define IOMUXC_PAD_GPIO_IO10_TPM4_EXTCLK IOMUX_PADCFG(0x443c0038, 0x4, 0x00000000, 0x00000000, 0x443c01e8) +#define IOMUXC_PAD_GPIO_IO10_LPUART7_CTS_B IOMUX_PADCFG(0x443c0038, 0x5, 0x00000000, 0x00000000, 0x443c01e8) +#define IOMUXC_PAD_GPIO_IO10_LPI2C8_SDA IOMUX_PADCFG(0x443c0038, 0x6, 0x443c0404, 0x00000000, 0x443c01e8) +#define IOMUXC_PAD_GPIO_IO10_FLEXIO1_FLEXIO10 IOMUX_PADCFG(0x443c0038, 0x7, 0x443c0394, 0x00000000, 0x443c01e8) +#define IOMUXC_PAD_GPIO_IO11_GPIO2_IO11 IOMUX_PADCFG(0x443c003c, 0x0, 0x00000000, 0x00000000, 0x443c01ec) +#define IOMUXC_PAD_GPIO_IO11_LPSPI3_SCK IOMUX_PADCFG(0x443c003c, 0x1, 0x00000000, 0x00000000, 0x443c01ec) +#define IOMUXC_PAD_GPIO_IO11_MEDIAMIX_CAM_DATA05 IOMUX_PADCFG(0x443c003c, 0x2, 0x00000000, 0x00000000, 0x443c01ec) +#define IOMUXC_PAD_GPIO_IO11_MEDIAMIX_DISP_DATA07 IOMUX_PADCFG(0x443c003c, 0x3, 0x00000000, 0x00000000, 0x443c01ec) +#define IOMUXC_PAD_GPIO_IO11_TPM5_EXTCLK IOMUX_PADCFG(0x443c003c, 0x4, 0x00000000, 0x00000000, 0x443c01ec) +#define IOMUXC_PAD_GPIO_IO11_LPUART7_RTS_B IOMUX_PADCFG(0x443c003c, 0x5, 0x00000000, 0x00000000, 0x443c01ec) +#define IOMUXC_PAD_GPIO_IO11_LPI2C8_SCL IOMUX_PADCFG(0x443c003c, 0x6, 0x443c0400, 0x00000000, 0x443c01ec) +#define IOMUXC_PAD_GPIO_IO11_FLEXIO1_FLEXIO11 IOMUX_PADCFG(0x443c003c, 0x7, 0x443c0398, 0x00000000, 0x443c01ec) +#define IOMUXC_PAD_GPIO_IO12_GPIO2_IO12 IOMUX_PADCFG(0x443c0040, 0x0, 0x00000000, 0x00000000, 0x443c01f0) +#define IOMUXC_PAD_GPIO_IO12_TPM3_CH2 IOMUX_PADCFG(0x443c0040, 0x1, 0x00000000, 0x00000000, 0x443c01f0) +#define IOMUXC_PAD_GPIO_IO12_PDM_BIT_STREAM02 IOMUX_PADCFG(0x443c0040, 0x2, 0x443c0440, 0x00000000, 0x443c01f0) +#define IOMUXC_PAD_GPIO_IO12_MEDIAMIX_DISP_DATA08 IOMUX_PADCFG(0x443c0040, 0x3, 0x00000000, 0x00000000, 0x443c01f0) +#define IOMUXC_PAD_GPIO_IO12_LPSPI8_PCS0 IOMUX_PADCFG(0x443c0040, 0x4, 0x00000000, 0x00000000, 0x443c01f0) +#define IOMUXC_PAD_GPIO_IO12_LPUART8_TX IOMUX_PADCFG(0x443c0040, 0x5, 0x00000000, 0x00000000, 0x443c01f0) +#define IOMUXC_PAD_GPIO_IO12_LPI2C8_SDA IOMUX_PADCFG(0x443c0040, 0x6, 0x443c0404, 0x00000001, 0x443c01f0) +#define IOMUXC_PAD_GPIO_IO12_SAI3_RX_SYNC IOMUX_PADCFG(0x443c0040, 0x7, 0x443c0450, 0x00000000, 0x443c01f0) +#define IOMUXC_PAD_GPIO_IO13_GPIO2_IO13 IOMUX_PADCFG(0x443c0044, 0x0, 0x00000000, 0x00000000, 0x443c01f4) +#define IOMUXC_PAD_GPIO_IO13_TPM4_CH2 IOMUX_PADCFG(0x443c0044, 0x1, 0x00000000, 0x00000000, 0x443c01f4) +#define IOMUXC_PAD_GPIO_IO13_PDM_BIT_STREAM03 IOMUX_PADCFG(0x443c0044, 0x2, 0x443c0444, 0x00000000, 0x443c01f4) +#define IOMUXC_PAD_GPIO_IO13_MEDIAMIX_DISP_DATA09 IOMUX_PADCFG(0x443c0044, 0x3, 0x00000000, 0x00000000, 0x443c01f4) +#define IOMUXC_PAD_GPIO_IO13_LPSPI8_SIN IOMUX_PADCFG(0x443c0044, 0x4, 0x00000000, 0x00000000, 0x443c01f4) +#define IOMUXC_PAD_GPIO_IO13_LPUART8_RX IOMUX_PADCFG(0x443c0044, 0x5, 0x00000000, 0x00000000, 0x443c01f4) +#define IOMUXC_PAD_GPIO_IO13_LPI2C8_SCL IOMUX_PADCFG(0x443c0044, 0x6, 0x443c0400, 0x00000001, 0x443c01f4) +#define IOMUXC_PAD_GPIO_IO13_FLEXIO1_FLEXIO13 IOMUX_PADCFG(0x443c0044, 0x7, 0x443c039c, 0x00000000, 0x443c01f4) +#define IOMUXC_PAD_GPIO_IO14_GPIO2_IO14 IOMUX_PADCFG(0x443c0048, 0x0, 0x00000000, 0x00000000, 0x443c01f8) +#define IOMUXC_PAD_GPIO_IO14_LPUART3_TX IOMUX_PADCFG(0x443c0048, 0x1, 0x443c041c, 0x00000000, 0x443c01f8) +#define IOMUXC_PAD_GPIO_IO14_MEDIAMIX_CAM_DATA06 IOMUX_PADCFG(0x443c0048, 0x2, 0x00000000, 0x00000000, 0x443c01f8) +#define IOMUXC_PAD_GPIO_IO14_MEDIAMIX_DISP_DATA10 IOMUX_PADCFG(0x443c0048, 0x3, 0x00000000, 0x00000000, 0x443c01f8) +#define IOMUXC_PAD_GPIO_IO14_LPSPI8_SOUT IOMUX_PADCFG(0x443c0048, 0x4, 0x00000000, 0x00000000, 0x443c01f8) +#define IOMUXC_PAD_GPIO_IO14_LPUART8_CTS_B IOMUX_PADCFG(0x443c0048, 0x5, 0x00000000, 0x00000000, 0x443c01f8) +#define IOMUXC_PAD_GPIO_IO14_LPUART4_TX IOMUX_PADCFG(0x443c0048, 0x6, 0x443c0428, 0x00000000, 0x443c01f8) +#define IOMUXC_PAD_GPIO_IO14_FLEXIO1_FLEXIO14 IOMUX_PADCFG(0x443c0048, 0x7, 0x443c03a0, 0x00000000, 0x443c01f8) +#define IOMUXC_PAD_GPIO_IO15_GPIO2_IO15 IOMUX_PADCFG(0x443c004c, 0x0, 0x00000000, 0x00000000, 0x443c01fc) +#define IOMUXC_PAD_GPIO_IO15_LPUART3_RX IOMUX_PADCFG(0x443c004c, 0x1, 0x443c0418, 0x00000000, 0x443c01fc) +#define IOMUXC_PAD_GPIO_IO15_MEDIAMIX_CAM_DATA07 IOMUX_PADCFG(0x443c004c, 0x2, 0x00000000, 0x00000000, 0x443c01fc) +#define IOMUXC_PAD_GPIO_IO15_MEDIAMIX_DISP_DATA11 IOMUX_PADCFG(0x443c004c, 0x3, 0x00000000, 0x00000000, 0x443c01fc) +#define IOMUXC_PAD_GPIO_IO15_LPSPI8_SCK IOMUX_PADCFG(0x443c004c, 0x4, 0x00000000, 0x00000000, 0x443c01fc) +#define IOMUXC_PAD_GPIO_IO15_LPUART8_RTS_B IOMUX_PADCFG(0x443c004c, 0x5, 0x00000000, 0x00000000, 0x443c01fc) +#define IOMUXC_PAD_GPIO_IO15_LPUART4_RX IOMUX_PADCFG(0x443c004c, 0x6, 0x443c0424, 0x00000000, 0x443c01fc) +#define IOMUXC_PAD_GPIO_IO15_FLEXIO1_FLEXIO15 IOMUX_PADCFG(0x443c004c, 0x7, 0x443c03a4, 0x00000000, 0x443c01fc) +#define IOMUXC_PAD_GPIO_IO16_GPIO2_IO16 IOMUX_PADCFG(0x443c0050, 0x0, 0x00000000, 0x00000000, 0x443c0200) +#define IOMUXC_PAD_GPIO_IO16_SAI3_TX_BCLK IOMUX_PADCFG(0x443c0050, 0x1, 0x00000000, 0x00000000, 0x443c0200) +#define IOMUXC_PAD_GPIO_IO16_PDM_BIT_STREAM02 IOMUX_PADCFG(0x443c0050, 0x2, 0x443c0440, 0x00000001, 0x443c0200) +#define IOMUXC_PAD_GPIO_IO16_MEDIAMIX_DISP_DATA12 IOMUX_PADCFG(0x443c0050, 0x3, 0x00000000, 0x00000000, 0x443c0200) +#define IOMUXC_PAD_GPIO_IO16_LPUART3_CTS_B IOMUX_PADCFG(0x443c0050, 0x4, 0x443c0414, 0x00000000, 0x443c0200) +#define IOMUXC_PAD_GPIO_IO16_LPSPI4_PCS2 IOMUX_PADCFG(0x443c0050, 0x5, 0x00000000, 0x00000000, 0x443c0200) +#define IOMUXC_PAD_GPIO_IO16_LPUART4_CTS_B IOMUX_PADCFG(0x443c0050, 0x6, 0x443c0420, 0x00000000, 0x443c0200) +#define IOMUXC_PAD_GPIO_IO16_FLEXIO1_FLEXIO16 IOMUX_PADCFG(0x443c0050, 0x7, 0x443c03a8, 0x00000000, 0x443c0200) +#define IOMUXC_PAD_GPIO_IO17_GPIO2_IO17 IOMUX_PADCFG(0x443c0054, 0x0, 0x00000000, 0x00000000, 0x443c0204) +#define IOMUXC_PAD_GPIO_IO17_SAI3_MCLK IOMUX_PADCFG(0x443c0054, 0x1, 0x00000000, 0x00000000, 0x443c0204) +#define IOMUXC_PAD_GPIO_IO17_MEDIAMIX_CAM_DATA08 IOMUX_PADCFG(0x443c0054, 0x2, 0x00000000, 0x00000000, 0x443c0204) +#define IOMUXC_PAD_GPIO_IO17_MEDIAMIX_DISP_DATA13 IOMUX_PADCFG(0x443c0054, 0x3, 0x00000000, 0x00000000, 0x443c0204) +#define IOMUXC_PAD_GPIO_IO17_LPUART3_RTS_B IOMUX_PADCFG(0x443c0054, 0x4, 0x00000000, 0x00000000, 0x443c0204) +#define IOMUXC_PAD_GPIO_IO17_LPSPI4_PCS1 IOMUX_PADCFG(0x443c0054, 0x5, 0x00000000, 0x00000000, 0x443c0204) +#define IOMUXC_PAD_GPIO_IO17_LPUART4_RTS_B IOMUX_PADCFG(0x443c0054, 0x6, 0x00000000, 0x00000000, 0x443c0204) +#define IOMUXC_PAD_GPIO_IO17_FLEXIO1_FLEXIO17 IOMUX_PADCFG(0x443c0054, 0x7, 0x443c03ac, 0x00000000, 0x443c0204) +#define IOMUXC_PAD_GPIO_IO18_GPIO2_IO18 IOMUX_PADCFG(0x443c0058, 0x0, 0x00000000, 0x00000000, 0x443c0208) +#define IOMUXC_PAD_GPIO_IO18_SAI3_RX_BCLK IOMUX_PADCFG(0x443c0058, 0x1, 0x443c044c, 0x00000000, 0x443c0208) +#define IOMUXC_PAD_GPIO_IO18_MEDIAMIX_CAM_DATA09 IOMUX_PADCFG(0x443c0058, 0x2, 0x00000000, 0x00000000, 0x443c0208) +#define IOMUXC_PAD_GPIO_IO18_MEDIAMIX_DISP_DATA14 IOMUX_PADCFG(0x443c0058, 0x3, 0x00000000, 0x00000000, 0x443c0208) +#define IOMUXC_PAD_GPIO_IO18_LPSPI5_PCS0 IOMUX_PADCFG(0x443c0058, 0x4, 0x00000000, 0x00000000, 0x443c0208) +#define IOMUXC_PAD_GPIO_IO18_LPSPI4_PCS0 IOMUX_PADCFG(0x443c0058, 0x5, 0x00000000, 0x00000000, 0x443c0208) +#define IOMUXC_PAD_GPIO_IO18_TPM5_CH2 IOMUX_PADCFG(0x443c0058, 0x6, 0x00000000, 0x00000000, 0x443c0208) +#define IOMUXC_PAD_GPIO_IO18_FLEXIO1_FLEXIO18 IOMUX_PADCFG(0x443c0058, 0x7, 0x443c03b0, 0x00000000, 0x443c0208) +#define IOMUXC_PAD_GPIO_IO19_GPIO2_IO19 IOMUX_PADCFG(0x443c005c, 0x0, 0x00000000, 0x00000000, 0x443c020c) +#define IOMUXC_PAD_GPIO_IO19_SAI3_RX_SYNC IOMUX_PADCFG(0x443c005c, 0x1, 0x443c0450, 0x00000001, 0x443c020c) +#define IOMUXC_PAD_GPIO_IO19_PDM_BIT_STREAM03 IOMUX_PADCFG(0x443c005c, 0x2, 0x443c0444, 0x00000001, 0x443c020c) +#define IOMUXC_PAD_GPIO_IO19_MEDIAMIX_DISP_DATA15 IOMUX_PADCFG(0x443c005c, 0x3, 0x00000000, 0x00000000, 0x443c020c) +#define IOMUXC_PAD_GPIO_IO19_LPSPI5_SIN IOMUX_PADCFG(0x443c005c, 0x4, 0x00000000, 0x00000000, 0x443c020c) +#define IOMUXC_PAD_GPIO_IO19_LPSPI4_SIN IOMUX_PADCFG(0x443c005c, 0x5, 0x00000000, 0x00000000, 0x443c020c) +#define IOMUXC_PAD_GPIO_IO19_TPM6_CH2 IOMUX_PADCFG(0x443c005c, 0x6, 0x00000000, 0x00000000, 0x443c020c) +#define IOMUXC_PAD_GPIO_IO19_SAI3_TX_DATA00 IOMUX_PADCFG(0x443c005c, 0x7, 0x00000000, 0x00000000, 0x443c020c) +#define IOMUXC_PAD_GPIO_IO20_GPIO2_IO20 IOMUX_PADCFG(0x443c0060, 0x0, 0x00000000, 0x00000000, 0x443c0210) +#define IOMUXC_PAD_GPIO_IO20_SAI3_RX_DATA00 IOMUX_PADCFG(0x443c0060, 0x1, 0x00000000, 0x00000000, 0x443c0210) +#define IOMUXC_PAD_GPIO_IO20_PDM_BIT_STREAM00 IOMUX_PADCFG(0x443c0060, 0x2, 0x443c0438, 0x00000001, 0x443c0210) +#define IOMUXC_PAD_GPIO_IO20_MEDIAMIX_DISP_DATA16 IOMUX_PADCFG(0x443c0060, 0x3, 0x00000000, 0x00000000, 0x443c0210) +#define IOMUXC_PAD_GPIO_IO20_LPSPI5_SOUT IOMUX_PADCFG(0x443c0060, 0x4, 0x00000000, 0x00000000, 0x443c0210) +#define IOMUXC_PAD_GPIO_IO20_LPSPI4_SOUT IOMUX_PADCFG(0x443c0060, 0x5, 0x00000000, 0x00000000, 0x443c0210) +#define IOMUXC_PAD_GPIO_IO20_TPM3_CH1 IOMUX_PADCFG(0x443c0060, 0x6, 0x00000000, 0x00000000, 0x443c0210) +#define IOMUXC_PAD_GPIO_IO20_FLEXIO1_FLEXIO20 IOMUX_PADCFG(0x443c0060, 0x7, 0x443c03b4, 0x00000000, 0x443c0210) +#define IOMUXC_PAD_GPIO_IO21_GPIO2_IO21 IOMUX_PADCFG(0x443c0064, 0x0, 0x00000000, 0x00000000, 0x443c0214) +#define IOMUXC_PAD_GPIO_IO21_SAI3_TX_DATA00 IOMUX_PADCFG(0x443c0064, 0x1, 0x00000000, 0x00000000, 0x443c0214) +#define IOMUXC_PAD_GPIO_IO21_PDM_CLK IOMUX_PADCFG(0x443c0064, 0x2, 0x00000000, 0x00000000, 0x443c0214) +#define IOMUXC_PAD_GPIO_IO21_MEDIAMIX_DISP_DATA17 IOMUX_PADCFG(0x443c0064, 0x3, 0x00000000, 0x00000000, 0x443c0214) +#define IOMUXC_PAD_GPIO_IO21_LPSPI5_SCK IOMUX_PADCFG(0x443c0064, 0x4, 0x00000000, 0x00000000, 0x443c0214) +#define IOMUXC_PAD_GPIO_IO21_LPSPI4_SCK IOMUX_PADCFG(0x443c0064, 0x5, 0x00000000, 0x00000000, 0x443c0214) +#define IOMUXC_PAD_GPIO_IO21_TPM4_CH1 IOMUX_PADCFG(0x443c0064, 0x6, 0x00000000, 0x00000000, 0x443c0214) +#define IOMUXC_PAD_GPIO_IO21_SAI3_RX_BCLK IOMUX_PADCFG(0x443c0064, 0x7, 0x443c044c, 0x00000001, 0x443c0214) +#define IOMUXC_PAD_GPIO_IO22_GPIO2_IO22 IOMUX_PADCFG(0x443c0068, 0x0, 0x00000000, 0x00000000, 0x443c0218) +#define IOMUXC_PAD_GPIO_IO22_USDHC3_CLK IOMUX_PADCFG(0x443c0068, 0x1, 0x443c0458, 0x00000000, 0x443c0218) +#define IOMUXC_PAD_GPIO_IO22_SPDIF_IN IOMUX_PADCFG(0x443c0068, 0x2, 0x443c0454, 0x00000000, 0x443c0218) +#define IOMUXC_PAD_GPIO_IO22_MEDIAMIX_DISP_DATA18 IOMUX_PADCFG(0x443c0068, 0x3, 0x00000000, 0x00000000, 0x443c0218) +#define IOMUXC_PAD_GPIO_IO22_TPM5_CH1 IOMUX_PADCFG(0x443c0068, 0x4, 0x00000000, 0x00000000, 0x443c0218) +#define IOMUXC_PAD_GPIO_IO22_TPM6_EXTCLK IOMUX_PADCFG(0x443c0068, 0x5, 0x00000000, 0x00000000, 0x443c0218) +#define IOMUXC_PAD_GPIO_IO22_LPI2C5_SDA IOMUX_PADCFG(0x443c0068, 0x6, 0x443c03ec, 0x00000001, 0x443c0218) +#define IOMUXC_PAD_GPIO_IO22_FLEXIO1_FLEXIO22 IOMUX_PADCFG(0x443c0068, 0x7, 0x443c03b8, 0x00000000, 0x443c0218) +#define IOMUXC_PAD_GPIO_IO23_GPIO2_IO23 IOMUX_PADCFG(0x443c006c, 0x0, 0x00000000, 0x00000000, 0x443c021c) +#define IOMUXC_PAD_GPIO_IO23_USDHC3_CMD IOMUX_PADCFG(0x443c006c, 0x1, 0x443c045c, 0x00000000, 0x443c021c) +#define IOMUXC_PAD_GPIO_IO23_SPDIF_OUT IOMUX_PADCFG(0x443c006c, 0x2, 0x00000000, 0x00000000, 0x443c021c) +#define IOMUXC_PAD_GPIO_IO23_MEDIAMIX_DISP_DATA19 IOMUX_PADCFG(0x443c006c, 0x3, 0x00000000, 0x00000000, 0x443c021c) +#define IOMUXC_PAD_GPIO_IO23_TPM6_CH1 IOMUX_PADCFG(0x443c006c, 0x4, 0x00000000, 0x00000000, 0x443c021c) +#define IOMUXC_PAD_GPIO_IO23_LPI2C5_SCL IOMUX_PADCFG(0x443c006c, 0x6, 0x443c03e8, 0x00000001, 0x443c021c) +#define IOMUXC_PAD_GPIO_IO23_FLEXIO1_FLEXIO23 IOMUX_PADCFG(0x443c006c, 0x7, 0x443c03bc, 0x00000000, 0x443c021c) +#define IOMUXC_PAD_GPIO_IO24_GPIO2_IO24 IOMUX_PADCFG(0x443c0070, 0x0, 0x00000000, 0x00000000, 0x443c0220) +#define IOMUXC_PAD_GPIO_IO24_USDHC3_DATA0 IOMUX_PADCFG(0x443c0070, 0x1, 0x443c0460, 0x00000000, 0x443c0220) +#define IOMUXC_PAD_GPIO_IO24_MEDIAMIX_DISP_DATA20 IOMUX_PADCFG(0x443c0070, 0x3, 0x00000000, 0x00000000, 0x443c0220) +#define IOMUXC_PAD_GPIO_IO24_TPM3_CH3 IOMUX_PADCFG(0x443c0070, 0x4, 0x00000000, 0x00000000, 0x443c0220) +#define IOMUXC_PAD_GPIO_IO24_JTAG_MUX_TDO IOMUX_PADCFG(0x443c0070, 0x5, 0x00000000, 0x00000000, 0x443c0220) +#define IOMUXC_PAD_GPIO_IO24_LPSPI6_PCS1 IOMUX_PADCFG(0x443c0070, 0x6, 0x00000000, 0x00000000, 0x443c0220) +#define IOMUXC_PAD_GPIO_IO24_FLEXIO1_FLEXIO24 IOMUX_PADCFG(0x443c0070, 0x7, 0x443c03c0, 0x00000000, 0x443c0220) +#define IOMUXC_PAD_GPIO_IO25_GPIO2_IO25 IOMUX_PADCFG(0x443c0074, 0x0, 0x00000000, 0x00000000, 0x443c0224) +#define IOMUXC_PAD_GPIO_IO25_USDHC3_DATA1 IOMUX_PADCFG(0x443c0074, 0x1, 0x443c0464, 0x00000000, 0x443c0224) +#define IOMUXC_PAD_GPIO_IO25_CAN2_TX IOMUX_PADCFG(0x443c0074, 0x2, 0x00000000, 0x00000000, 0x443c0224) +#define IOMUXC_PAD_GPIO_IO25_MEDIAMIX_DISP_DATA21 IOMUX_PADCFG(0x443c0074, 0x3, 0x00000000, 0x00000000, 0x443c0224) +#define IOMUXC_PAD_GPIO_IO25_TPM4_CH3 IOMUX_PADCFG(0x443c0074, 0x4, 0x00000000, 0x00000000, 0x443c0224) +#define IOMUXC_PAD_GPIO_IO25_JTAG_MUX_TCK IOMUX_PADCFG(0x443c0074, 0x5, 0x443c03d4, 0x00000001, 0x443c0224) +#define IOMUXC_PAD_GPIO_IO25_LPSPI7_PCS1 IOMUX_PADCFG(0x443c0074, 0x6, 0x00000000, 0x00000000, 0x443c0224) +#define IOMUXC_PAD_GPIO_IO25_FLEXIO1_FLEXIO25 IOMUX_PADCFG(0x443c0074, 0x7, 0x443c03c4, 0x00000000, 0x443c0224) +#define IOMUXC_PAD_GPIO_IO26_GPIO2_IO26 IOMUX_PADCFG(0x443c0078, 0x0, 0x00000000, 0x00000000, 0x443c0228) +#define IOMUXC_PAD_GPIO_IO26_USDHC3_DATA2 IOMUX_PADCFG(0x443c0078, 0x1, 0x443c0468, 0x00000000, 0x443c0228) +#define IOMUXC_PAD_GPIO_IO26_PDM_BIT_STREAM01 IOMUX_PADCFG(0x443c0078, 0x2, 0x443c043c, 0x00000001, 0x443c0228) +#define IOMUXC_PAD_GPIO_IO26_MEDIAMIX_DISP_DATA22 IOMUX_PADCFG(0x443c0078, 0x3, 0x00000000, 0x00000000, 0x443c0228) +#define IOMUXC_PAD_GPIO_IO26_TPM5_CH3 IOMUX_PADCFG(0x443c0078, 0x4, 0x00000000, 0x00000000, 0x443c0228) +#define IOMUXC_PAD_GPIO_IO26_JTAG_MUX_TDI IOMUX_PADCFG(0x443c0078, 0x5, 0x443c03d8, 0x00000001, 0x443c0228) +#define IOMUXC_PAD_GPIO_IO26_LPSPI8_PCS1 IOMUX_PADCFG(0x443c0078, 0x6, 0x00000000, 0x00000000, 0x443c0228) +#define IOMUXC_PAD_GPIO_IO26_SAI3_TX_SYNC IOMUX_PADCFG(0x443c0078, 0x7, 0x00000000, 0x00000000, 0x443c0228) +#define IOMUXC_PAD_GPIO_IO27_GPIO2_IO27 IOMUX_PADCFG(0x443c007c, 0x0, 0x00000000, 0x00000000, 0x443c022c) +#define IOMUXC_PAD_GPIO_IO27_USDHC3_DATA3 IOMUX_PADCFG(0x443c007c, 0x1, 0x443c046c, 0x00000000, 0x443c022c) +#define IOMUXC_PAD_GPIO_IO27_CAN2_RX IOMUX_PADCFG(0x443c007c, 0x2, 0x443c0364, 0x00000001, 0x443c022c) +#define IOMUXC_PAD_GPIO_IO27_MEDIAMIX_DISP_DATA23 IOMUX_PADCFG(0x443c007c, 0x3, 0x00000000, 0x00000000, 0x443c022c) +#define IOMUXC_PAD_GPIO_IO27_TPM6_CH3 IOMUX_PADCFG(0x443c007c, 0x4, 0x00000000, 0x00000000, 0x443c022c) +#define IOMUXC_PAD_GPIO_IO27_JTAG_MUX_TMS IOMUX_PADCFG(0x443c007c, 0x5, 0x443c03dc, 0x00000001, 0x443c022c) +#define IOMUXC_PAD_GPIO_IO27_LPSPI5_PCS1 IOMUX_PADCFG(0x443c007c, 0x6, 0x00000000, 0x00000000, 0x443c022c) +#define IOMUXC_PAD_GPIO_IO27_FLEXIO1_FLEXIO27 IOMUX_PADCFG(0x443c007c, 0x7, 0x443c03c8, 0x00000000, 0x443c022c) +#define IOMUXC_PAD_GPIO_IO28_GPIO2_IO28 IOMUX_PADCFG(0x443c0080, 0x0, 0x00000000, 0x00000000, 0x443c0230) +#define IOMUXC_PAD_GPIO_IO28_LPI2C3_SDA IOMUX_PADCFG(0x443c0080, 0x1, 0x443c03e4, 0x00000001, 0x443c0230) +#define IOMUXC_PAD_GPIO_IO28_FLEXIO1_FLEXIO28 IOMUX_PADCFG(0x443c0080, 0x7, 0x00000000, 0x00000000, 0x443c0230) +#define IOMUXC_PAD_GPIO_IO29_GPIO2_IO29 IOMUX_PADCFG(0x443c0084, 0x0, 0x00000000, 0x00000000, 0x443c0234) +#define IOMUXC_PAD_GPIO_IO29_LPI2C3_SCL IOMUX_PADCFG(0x443c0084, 0x1, 0x443c03e0, 0x00000001, 0x443c0234) +#define IOMUXC_PAD_GPIO_IO29_FLEXIO1_FLEXIO29 IOMUX_PADCFG(0x443c0084, 0x7, 0x00000000, 0x00000000, 0x443c0234) +#define IOMUXC_PAD_CCM_CLKO1_CCMSRCGPCMIX_CLKO1 IOMUX_PADCFG(0x443c0088, 0x0, 0x00000000, 0x00000000, 0x443c0238) +#define IOMUXC_PAD_CCM_CLKO1_FLEXIO1_FLEXIO26 IOMUX_PADCFG(0x443c0088, 0x4, 0x00000000, 0x00000000, 0x443c0238) +#define IOMUXC_PAD_CCM_CLKO1_GPIO3_IO26 IOMUX_PADCFG(0x443c0088, 0x5, 0x00000000, 0x00000000, 0x443c0238) +#define IOMUXC_PAD_CCM_CLKO2_GPIO3_IO27 IOMUX_PADCFG(0x443c008c, 0x5, 0x00000000, 0x00000000, 0x443c023c) +#define IOMUXC_PAD_CCM_CLKO2_CCMSRCGPCMIX_CLKO2 IOMUX_PADCFG(0x443c008c, 0x0, 0x00000000, 0x00000000, 0x443c023c) +#define IOMUXC_PAD_CCM_CLKO2_FLEXIO1_FLEXIO27 IOMUX_PADCFG(0x443c008c, 0x4, 0x443c03c8, 0x00000001, 0x443c023c) +#define IOMUXC_PAD_CCM_CLKO3_CCMSRCGPCMIX_CLKO3 IOMUX_PADCFG(0x443c0090, 0x0, 0x00000000, 0x00000000, 0x443c0240) +#define IOMUXC_PAD_CCM_CLKO3_FLEXIO2_FLEXIO28 IOMUX_PADCFG(0x443c0090, 0x4, 0x00000000, 0x00000000, 0x443c0240) +#define IOMUXC_PAD_CCM_CLKO3_GPIO4_IO28 IOMUX_PADCFG(0x443c0090, 0x5, 0x00000000, 0x00000000, 0x443c0240) +#define IOMUXC_PAD_CCM_CLKO4_CCMSRCGPCMIX_CLKO4 IOMUX_PADCFG(0x443c0094, 0x0, 0x00000000, 0x00000000, 0x443c0244) +#define IOMUXC_PAD_CCM_CLKO4_FLEXIO2_FLEXIO29 IOMUX_PADCFG(0x443c0094, 0x4, 0x00000000, 0x00000000, 0x443c0244) +#define IOMUXC_PAD_CCM_CLKO4_GPIO4_IO29 IOMUX_PADCFG(0x443c0094, 0x5, 0x00000000, 0x00000000, 0x443c0244) +#define IOMUXC_PAD_ENET1_MDC_ENET_QOS_MDC IOMUX_PADCFG(0x443c0098, 0x0, 0x00000000, 0x00000000, 0x443c0248) +#define IOMUXC_PAD_ENET1_MDC_LPUART3_DCB_B IOMUX_PADCFG(0x443c0098, 0x1, 0x00000000, 0x00000000, 0x443c0248) +#define IOMUXC_PAD_ENET1_MDC_I3C2_SCL IOMUX_PADCFG(0x443c0098, 0x2, 0x443c03cc, 0x00000000, 0x443c0248) +#define IOMUXC_PAD_ENET1_MDC_HSIOMIX_OTG_ID1 IOMUX_PADCFG(0x443c0098, 0x3, 0x00000000, 0x00000000, 0x443c0248) +#define IOMUXC_PAD_ENET1_MDC_FLEXIO2_FLEXIO00 IOMUX_PADCFG(0x443c0098, 0x4, 0x00000000, 0x00000000, 0x443c0248) +#define IOMUXC_PAD_ENET1_MDC_GPIO4_IO00 IOMUX_PADCFG(0x443c0098, 0x5, 0x00000000, 0x00000000, 0x443c0248) +#define IOMUXC_PAD_ENET1_MDIO_ENET_QOS_MDIO IOMUX_PADCFG(0x443c009c, 0x0, 0x00000000, 0x00000000, 0x443c024c) +#define IOMUXC_PAD_ENET1_MDIO_LPUART3_RIN_B IOMUX_PADCFG(0x443c009c, 0x1, 0x00000000, 0x00000000, 0x443c024c) +#define IOMUXC_PAD_ENET1_MDIO_I3C2_SDA IOMUX_PADCFG(0x443c009c, 0x2, 0x443c03d0, 0x00000000, 0x443c024c) +#define IOMUXC_PAD_ENET1_MDIO_HSIOMIX_OTG_PWR1 IOMUX_PADCFG(0x443c009c, 0x3, 0x00000000, 0x00000000, 0x443c024c) +#define IOMUXC_PAD_ENET1_MDIO_FLEXIO2_FLEXIO01 IOMUX_PADCFG(0x443c009c, 0x4, 0x00000000, 0x00000000, 0x443c024c) +#define IOMUXC_PAD_ENET1_MDIO_GPIO4_IO01 IOMUX_PADCFG(0x443c009c, 0x5, 0x00000000, 0x00000000, 0x443c024c) +#define IOMUXC_PAD_ENET1_TD3_ENET_QOS_RGMII_TD3 IOMUX_PADCFG(0x443c00a0, 0x0, 0x00000000, 0x00000000, 0x443c0250) +#define IOMUXC_PAD_ENET1_TD3_CAN2_TX IOMUX_PADCFG(0x443c00a0, 0x2, 0x00000000, 0x00000000, 0x443c0250) +#define IOMUXC_PAD_ENET1_TD3_HSIOMIX_OTG_ID2 IOMUX_PADCFG(0x443c00a0, 0x3, 0x00000000, 0x00000000, 0x443c0250) +#define IOMUXC_PAD_ENET1_TD3_FLEXIO2_FLEXIO02 IOMUX_PADCFG(0x443c00a0, 0x4, 0x00000000, 0x00000000, 0x443c0250) +#define IOMUXC_PAD_ENET1_TD3_GPIO4_IO02 IOMUX_PADCFG(0x443c00a0, 0x5, 0x00000000, 0x00000000, 0x443c0250) +#define IOMUXC_PAD_ENET1_TD2_ENET_QOS_RGMII_TD2 IOMUX_PADCFG(0x443c00a4, 0x0, 0x00000000, 0x00000000, 0x443c0254) +#define IOMUXC_PAD_ENET1_TD2_CCM_ENET_QOS_CLOCK_GENERATE_REF_CLK IOMUX_PADCFG(0x443c00a4, 0x1, 0x00000000, 0x00000000, 0x443c0254) +#define IOMUXC_PAD_ENET1_TD2_CAN2_RX IOMUX_PADCFG(0x443c00a4, 0x2, 0x443c0364, 0x00000002, 0x443c0254) +#define IOMUXC_PAD_ENET1_TD2_HSIOMIX_OTG_OC2 IOMUX_PADCFG(0x443c00a4, 0x3, 0x00000000, 0x00000000, 0x443c0254) +#define IOMUXC_PAD_ENET1_TD2_FLEXIO2_FLEXIO03 IOMUX_PADCFG(0x443c00a4, 0x4, 0x00000000, 0x00000000, 0x443c0254) +#define IOMUXC_PAD_ENET1_TD2_GPIO4_IO03 IOMUX_PADCFG(0x443c00a4, 0x5, 0x00000000, 0x00000000, 0x443c0254) +#define IOMUXC_PAD_ENET1_TD1_ENET_QOS_RGMII_TD1 IOMUX_PADCFG(0x443c00a8, 0x0, 0x00000000, 0x00000000, 0x443c0258) +#define IOMUXC_PAD_ENET1_TD1_LPUART3_RTS_B IOMUX_PADCFG(0x443c00a8, 0x1, 0x00000000, 0x00000000, 0x443c0258) +#define IOMUXC_PAD_ENET1_TD1_I3C2_PUR IOMUX_PADCFG(0x443c00a8, 0x2, 0x00000000, 0x00000000, 0x443c0258) +#define IOMUXC_PAD_ENET1_TD1_HSIOMIX_OTG_OC1 IOMUX_PADCFG(0x443c00a8, 0x3, 0x00000000, 0x00000000, 0x443c0258) +#define IOMUXC_PAD_ENET1_TD1_FLEXIO2_FLEXIO04 IOMUX_PADCFG(0x443c00a8, 0x4, 0x00000000, 0x00000000, 0x443c0258) +#define IOMUXC_PAD_ENET1_TD1_GPIO4_IO04 IOMUX_PADCFG(0x443c00a8, 0x5, 0x00000000, 0x00000000, 0x443c0258) +#define IOMUXC_PAD_ENET1_TD1_I3C2_PUR_B IOMUX_PADCFG(0x443c00a8, 0x6, 0x00000000, 0x00000000, 0x443c0258) +#define IOMUXC_PAD_ENET1_TD0_ENET_QOS_RGMII_TD0 IOMUX_PADCFG(0x443c00ac, 0x0, 0x00000000, 0x00000000, 0x443c025c) +#define IOMUXC_PAD_ENET1_TD0_LPUART3_TX IOMUX_PADCFG(0x443c00ac, 0x1, 0x443c041c, 0x00000001, 0x443c025c) +#define IOMUXC_PAD_ENET1_TD0_FLEXIO2_FLEXIO05 IOMUX_PADCFG(0x443c00ac, 0x4, 0x00000000, 0x00000000, 0x443c025c) +#define IOMUXC_PAD_ENET1_TD0_GPIO4_IO05 IOMUX_PADCFG(0x443c00ac, 0x5, 0x00000000, 0x00000000, 0x443c025c) +#define IOMUXC_PAD_ENET1_TX_CTL_ENET_QOS_RGMII_TX_CTL IOMUX_PADCFG(0x443c00b0, 0x0, 0x00000000, 0x00000000, 0x443c0260) +#define IOMUXC_PAD_ENET1_TX_CTL_LPUART3_DTR_B IOMUX_PADCFG(0x443c00b0, 0x1, 0x00000000, 0x00000000, 0x443c0260) +#define IOMUXC_PAD_ENET1_TX_CTL_FLEXIO2_FLEXIO06 IOMUX_PADCFG(0x443c00b0, 0x4, 0x00000000, 0x00000000, 0x443c0260) +#define IOMUXC_PAD_ENET1_TX_CTL_GPIO4_IO06 IOMUX_PADCFG(0x443c00b0, 0x5, 0x00000000, 0x00000000, 0x443c0260) +#define IOMUXC_PAD_ENET1_TXC_CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK IOMUX_PADCFG(0x443c00b4, 0x0, 0x00000000, 0x00000000, 0x443c0264) +#define IOMUXC_PAD_ENET1_TXC_ENET_QOS_TX_ER IOMUX_PADCFG(0x443c00b4, 0x1, 0x00000000, 0x00000000, 0x443c0264) +#define IOMUXC_PAD_ENET1_TXC_FLEXIO2_FLEXIO07 IOMUX_PADCFG(0x443c00b4, 0x4, 0x00000000, 0x00000000, 0x443c0264) +#define IOMUXC_PAD_ENET1_TXC_GPIO4_IO07 IOMUX_PADCFG(0x443c00b4, 0x5, 0x00000000, 0x00000000, 0x443c0264) +#define IOMUXC_PAD_ENET1_RX_CTL_ENET_QOS_RGMII_RX_CTL IOMUX_PADCFG(0x443c00b8, 0x0, 0x00000000, 0x00000000, 0x443c0268) +#define IOMUXC_PAD_ENET1_RX_CTL_LPUART3_DSR_B IOMUX_PADCFG(0x443c00b8, 0x1, 0x00000000, 0x00000000, 0x443c0268) +#define IOMUXC_PAD_ENET1_RX_CTL_HSIOMIX_OTG_PWR2 IOMUX_PADCFG(0x443c00b8, 0x3, 0x00000000, 0x00000000, 0x443c0268) +#define IOMUXC_PAD_ENET1_RX_CTL_FLEXIO2_FLEXIO08 IOMUX_PADCFG(0x443c00b8, 0x4, 0x00000000, 0x00000000, 0x443c0268) +#define IOMUXC_PAD_ENET1_RX_CTL_GPIO4_IO08 IOMUX_PADCFG(0x443c00b8, 0x5, 0x00000000, 0x00000000, 0x443c0268) +#define IOMUXC_PAD_ENET1_RXC_CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK IOMUX_PADCFG(0x443c00bc, 0x0, 0x00000000, 0x00000000, 0x443c026c) +#define IOMUXC_PAD_ENET1_RXC_ENET_QOS_RX_ER IOMUX_PADCFG(0x443c00bc, 0x1, 0x00000000, 0x00000000, 0x443c026c) +#define IOMUXC_PAD_ENET1_RXC_FLEXIO2_FLEXIO09 IOMUX_PADCFG(0x443c00bc, 0x4, 0x00000000, 0x00000000, 0x443c026c) +#define IOMUXC_PAD_ENET1_RXC_GPIO4_IO09 IOMUX_PADCFG(0x443c00bc, 0x5, 0x00000000, 0x00000000, 0x443c026c) +#define IOMUXC_PAD_ENET1_RD0_ENET_QOS_RGMII_RD0 IOMUX_PADCFG(0x443c00c0, 0x0, 0x00000000, 0x00000000, 0x443c0270) +#define IOMUXC_PAD_ENET1_RD0_LPUART3_RX IOMUX_PADCFG(0x443c00c0, 0x1, 0x443c0418, 0x00000001, 0x443c0270) +#define IOMUXC_PAD_ENET1_RD0_FLEXIO2_FLEXIO10 IOMUX_PADCFG(0x443c00c0, 0x4, 0x00000000, 0x00000000, 0x443c0270) +#define IOMUXC_PAD_ENET1_RD0_GPIO4_IO10 IOMUX_PADCFG(0x443c00c0, 0x5, 0x00000000, 0x00000000, 0x443c0270) +#define IOMUXC_PAD_ENET1_RD1_ENET_QOS_RGMII_RD1 IOMUX_PADCFG(0x443c00c4, 0x0, 0x00000000, 0x00000000, 0x443c0274) +#define IOMUXC_PAD_ENET1_RD1_LPUART3_CTS_B IOMUX_PADCFG(0x443c00c4, 0x1, 0x443c0414, 0x00000001, 0x443c0274) +#define IOMUXC_PAD_ENET1_RD1_LPTMR2_ALT1 IOMUX_PADCFG(0x443c00c4, 0x3, 0x443c0408, 0x00000000, 0x443c0274) +#define IOMUXC_PAD_ENET1_RD1_FLEXIO2_FLEXIO11 IOMUX_PADCFG(0x443c00c4, 0x4, 0x00000000, 0x00000000, 0x443c0274) +#define IOMUXC_PAD_ENET1_RD1_GPIO4_IO11 IOMUX_PADCFG(0x443c00c4, 0x5, 0x00000000, 0x00000000, 0x443c0274) +#define IOMUXC_PAD_ENET1_RD2_ENET_QOS_RGMII_RD2 IOMUX_PADCFG(0x443c00c8, 0x0, 0x00000000, 0x00000000, 0x443c0278) +#define IOMUXC_PAD_ENET1_RD2_LPTMR2_ALT2 IOMUX_PADCFG(0x443c00c8, 0x3, 0x443c040c, 0x00000000, 0x443c0278) +#define IOMUXC_PAD_ENET1_RD2_FLEXIO2_FLEXIO12 IOMUX_PADCFG(0x443c00c8, 0x4, 0x00000000, 0x00000000, 0x443c0278) +#define IOMUXC_PAD_ENET1_RD2_GPIO4_IO12 IOMUX_PADCFG(0x443c00c8, 0x5, 0x00000000, 0x00000000, 0x443c0278) +#define IOMUXC_PAD_ENET1_RD3_ENET_QOS_RGMII_RD3 IOMUX_PADCFG(0x443c00cc, 0x0, 0x00000000, 0x00000000, 0x443c027c) +#define IOMUXC_PAD_ENET1_RD3_FLEXSPI1_TESTER_TRIGGER IOMUX_PADCFG(0x443c00cc, 0x2, 0x00000000, 0x00000000, 0x443c027c) +#define IOMUXC_PAD_ENET1_RD3_LPTMR2_ALT3 IOMUX_PADCFG(0x443c00cc, 0x3, 0x443c0410, 0x00000000, 0x443c027c) +#define IOMUXC_PAD_ENET1_RD3_FLEXIO2_FLEXIO13 IOMUX_PADCFG(0x443c00cc, 0x4, 0x00000000, 0x00000000, 0x443c027c) +#define IOMUXC_PAD_ENET1_RD3_GPIO4_IO13 IOMUX_PADCFG(0x443c00cc, 0x5, 0x00000000, 0x00000000, 0x443c027c) +#define IOMUXC_PAD_ENET2_MDC_ENET1_MDC IOMUX_PADCFG(0x443c00d0, 0x0, 0x00000000, 0x00000000, 0x443c0280) +#define IOMUXC_PAD_ENET2_MDC_LPUART4_DCB_B IOMUX_PADCFG(0x443c00d0, 0x1, 0x00000000, 0x00000000, 0x443c0280) +#define IOMUXC_PAD_ENET2_MDC_SAI2_RX_SYNC IOMUX_PADCFG(0x443c00d0, 0x2, 0x00000000, 0x00000000, 0x443c0280) +#define IOMUXC_PAD_ENET2_MDC_FLEXIO2_FLEXIO14 IOMUX_PADCFG(0x443c00d0, 0x4, 0x00000000, 0x00000000, 0x443c0280) +#define IOMUXC_PAD_ENET2_MDC_GPIO4_IO14 IOMUX_PADCFG(0x443c00d0, 0x5, 0x00000000, 0x00000000, 0x443c0280) +#define IOMUXC_PAD_ENET2_MDIO_ENET1_MDIO IOMUX_PADCFG(0x443c00d4, 0x0, 0x00000000, 0x00000000, 0x443c0284) +#define IOMUXC_PAD_ENET2_MDIO_LPUART4_RIN_B IOMUX_PADCFG(0x443c00d4, 0x1, 0x00000000, 0x00000000, 0x443c0284) +#define IOMUXC_PAD_ENET2_MDIO_SAI2_RX_BCLK IOMUX_PADCFG(0x443c00d4, 0x2, 0x00000000, 0x00000000, 0x443c0284) +#define IOMUXC_PAD_ENET2_MDIO_FLEXIO2_FLEXIO15 IOMUX_PADCFG(0x443c00d4, 0x4, 0x00000000, 0x00000000, 0x443c0284) +#define IOMUXC_PAD_ENET2_MDIO_GPIO4_IO15 IOMUX_PADCFG(0x443c00d4, 0x5, 0x00000000, 0x00000000, 0x443c0284) +#define IOMUXC_PAD_ENET2_TD3_SAI2_RX_DATA00 IOMUX_PADCFG(0x443c00d8, 0x2, 0x00000000, 0x00000000, 0x443c0288) +#define IOMUXC_PAD_ENET2_TD3_FLEXIO2_FLEXIO16 IOMUX_PADCFG(0x443c00d8, 0x4, 0x00000000, 0x00000000, 0x443c0288) +#define IOMUXC_PAD_ENET2_TD3_GPIO4_IO16 IOMUX_PADCFG(0x443c00d8, 0x5, 0x00000000, 0x00000000, 0x443c0288) +#define IOMUXC_PAD_ENET2_TD3_ENET1_RGMII_TD3 IOMUX_PADCFG(0x443c00d8, 0x0, 0x00000000, 0x00000000, 0x443c0288) +#define IOMUXC_PAD_ENET2_TD2_ENET1_RGMII_TD2 IOMUX_PADCFG(0x443c00dc, 0x0, 0x00000000, 0x00000000, 0x443c028c) +#define IOMUXC_PAD_ENET2_TD2_ENET1_TX_CLK IOMUX_PADCFG(0x443c00dc, 0x1, 0x00000000, 0x00000000, 0x443c028c) +#define IOMUXC_PAD_ENET2_TD2_SAI2_RX_DATA01 IOMUX_PADCFG(0x443c00dc, 0x2, 0x00000000, 0x00000000, 0x443c028c) +#define IOMUXC_PAD_ENET2_TD2_FLEXIO2_FLEXIO17 IOMUX_PADCFG(0x443c00dc, 0x4, 0x00000000, 0x00000000, 0x443c028c) +#define IOMUXC_PAD_ENET2_TD2_GPIO4_IO17 IOMUX_PADCFG(0x443c00dc, 0x5, 0x00000000, 0x00000000, 0x443c028c) +#define IOMUXC_PAD_ENET2_TD1_ENET1_RGMII_TD1 IOMUX_PADCFG(0x443c00e0, 0x0, 0x00000000, 0x00000000, 0x443c0290) +#define IOMUXC_PAD_ENET2_TD1_LPUART4_RTS_B IOMUX_PADCFG(0x443c00e0, 0x1, 0x00000000, 0x00000000, 0x443c0290) +#define IOMUXC_PAD_ENET2_TD1_SAI2_RX_DATA02 IOMUX_PADCFG(0x443c00e0, 0x2, 0x00000000, 0x00000000, 0x443c0290) +#define IOMUXC_PAD_ENET2_TD1_FLEXIO2_FLEXIO18 IOMUX_PADCFG(0x443c00e0, 0x4, 0x00000000, 0x00000000, 0x443c0290) +#define IOMUXC_PAD_ENET2_TD1_GPIO4_IO18 IOMUX_PADCFG(0x443c00e0, 0x5, 0x00000000, 0x00000000, 0x443c0290) +#define IOMUXC_PAD_ENET2_TD0_ENET1_RGMII_TD0 IOMUX_PADCFG(0x443c00e4, 0x0, 0x00000000, 0x00000000, 0x443c0294) +#define IOMUXC_PAD_ENET2_TD0_LPUART4_TX IOMUX_PADCFG(0x443c00e4, 0x1, 0x443c0428, 0x00000001, 0x443c0294) +#define IOMUXC_PAD_ENET2_TD0_SAI2_RX_DATA03 IOMUX_PADCFG(0x443c00e4, 0x2, 0x00000000, 0x00000000, 0x443c0294) +#define IOMUXC_PAD_ENET2_TD0_FLEXIO2_FLEXIO19 IOMUX_PADCFG(0x443c00e4, 0x4, 0x00000000, 0x00000000, 0x443c0294) +#define IOMUXC_PAD_ENET2_TD0_GPIO4_IO19 IOMUX_PADCFG(0x443c00e4, 0x5, 0x00000000, 0x00000000, 0x443c0294) +#define IOMUXC_PAD_ENET2_TX_CTL_ENET1_RGMII_TX_CTL IOMUX_PADCFG(0x443c00e8, 0x0, 0x00000000, 0x00000000, 0x443c0298) +#define IOMUXC_PAD_ENET2_TX_CTL_LPUART4_DTR_B IOMUX_PADCFG(0x443c00e8, 0x1, 0x00000000, 0x00000000, 0x443c0298) +#define IOMUXC_PAD_ENET2_TX_CTL_SAI2_TX_SYNC IOMUX_PADCFG(0x443c00e8, 0x2, 0x00000000, 0x00000000, 0x443c0298) +#define IOMUXC_PAD_ENET2_TX_CTL_FLEXIO2_FLEXIO20 IOMUX_PADCFG(0x443c00e8, 0x4, 0x00000000, 0x00000000, 0x443c0298) +#define IOMUXC_PAD_ENET2_TX_CTL_GPIO4_IO20 IOMUX_PADCFG(0x443c00e8, 0x5, 0x00000000, 0x00000000, 0x443c0298) +#define IOMUXC_PAD_ENET2_TXC_ENET1_RGMII_TXC IOMUX_PADCFG(0x443c00ec, 0x0, 0x00000000, 0x00000000, 0x443c029c) +#define IOMUXC_PAD_ENET2_TXC_ENET1_TX_ER IOMUX_PADCFG(0x443c00ec, 0x1, 0x00000000, 0x00000000, 0x443c029c) +#define IOMUXC_PAD_ENET2_TXC_SAI2_TX_BCLK IOMUX_PADCFG(0x443c00ec, 0x2, 0x00000000, 0x00000000, 0x443c029c) +#define IOMUXC_PAD_ENET2_TXC_FLEXIO2_FLEXIO21 IOMUX_PADCFG(0x443c00ec, 0x4, 0x00000000, 0x00000000, 0x443c029c) +#define IOMUXC_PAD_ENET2_TXC_GPIO4_IO21 IOMUX_PADCFG(0x443c00ec, 0x5, 0x00000000, 0x00000000, 0x443c029c) +#define IOMUXC_PAD_ENET2_RX_CTL_ENET1_RGMII_RX_CTL IOMUX_PADCFG(0x443c00f0, 0x0, 0x00000000, 0x00000000, 0x443c02a0) +#define IOMUXC_PAD_ENET2_RX_CTL_LPUART4_DSR_B IOMUX_PADCFG(0x443c00f0, 0x1, 0x00000000, 0x00000000, 0x443c02a0) +#define IOMUXC_PAD_ENET2_RX_CTL_SAI2_TX_DATA00 IOMUX_PADCFG(0x443c00f0, 0x2, 0x00000000, 0x00000000, 0x443c02a0) +#define IOMUXC_PAD_ENET2_RX_CTL_FLEXIO2_FLEXIO22 IOMUX_PADCFG(0x443c00f0, 0x4, 0x00000000, 0x00000000, 0x443c02a0) +#define IOMUXC_PAD_ENET2_RX_CTL_GPIO4_IO22 IOMUX_PADCFG(0x443c00f0, 0x5, 0x00000000, 0x00000000, 0x443c02a0) +#define IOMUXC_PAD_ENET2_RXC_ENET1_RGMII_RXC IOMUX_PADCFG(0x443c00f4, 0x0, 0x00000000, 0x00000000, 0x443c02a4) +#define IOMUXC_PAD_ENET2_RXC_ENET1_RX_ER IOMUX_PADCFG(0x443c00f4, 0x1, 0x00000000, 0x00000000, 0x443c02a4) +#define IOMUXC_PAD_ENET2_RXC_SAI2_TX_DATA01 IOMUX_PADCFG(0x443c00f4, 0x2, 0x00000000, 0x00000000, 0x443c02a4) +#define IOMUXC_PAD_ENET2_RXC_FLEXIO2_FLEXIO23 IOMUX_PADCFG(0x443c00f4, 0x4, 0x00000000, 0x00000000, 0x443c02a4) +#define IOMUXC_PAD_ENET2_RXC_GPIO4_IO23 IOMUX_PADCFG(0x443c00f4, 0x5, 0x00000000, 0x00000000, 0x443c02a4) +#define IOMUXC_PAD_ENET2_RD0_ENET1_RGMII_RD0 IOMUX_PADCFG(0x443c00f8, 0x0, 0x00000000, 0x00000000, 0x443c02a8) +#define IOMUXC_PAD_ENET2_RD0_LPUART4_RX IOMUX_PADCFG(0x443c00f8, 0x1, 0x443c0424, 0x00000001, 0x443c02a8) +#define IOMUXC_PAD_ENET2_RD0_SAI2_TX_DATA02 IOMUX_PADCFG(0x443c00f8, 0x2, 0x00000000, 0x00000000, 0x443c02a8) +#define IOMUXC_PAD_ENET2_RD0_FLEXIO2_FLEXIO24 IOMUX_PADCFG(0x443c00f8, 0x4, 0x00000000, 0x00000000, 0x443c02a8) +#define IOMUXC_PAD_ENET2_RD0_GPIO4_IO24 IOMUX_PADCFG(0x443c00f8, 0x5, 0x00000000, 0x00000000, 0x443c02a8) +#define IOMUXC_PAD_ENET2_RD1_ENET1_RGMII_RD1 IOMUX_PADCFG(0x443c00fc, 0x0, 0x00000000, 0x00000000, 0x443c02ac) +#define IOMUXC_PAD_ENET2_RD1_SPDIF_IN IOMUX_PADCFG(0x443c00fc, 0x1, 0x443c0454, 0x00000001, 0x443c02ac) +#define IOMUXC_PAD_ENET2_RD1_SAI2_TX_DATA03 IOMUX_PADCFG(0x443c00fc, 0x2, 0x00000000, 0x00000000, 0x443c02ac) +#define IOMUXC_PAD_ENET2_RD1_FLEXIO2_FLEXIO25 IOMUX_PADCFG(0x443c00fc, 0x4, 0x00000000, 0x00000000, 0x443c02ac) +#define IOMUXC_PAD_ENET2_RD1_GPIO4_IO25 IOMUX_PADCFG(0x443c00fc, 0x5, 0x00000000, 0x00000000, 0x443c02ac) +#define IOMUXC_PAD_ENET2_RD2_ENET1_RGMII_RD2 IOMUX_PADCFG(0x443c0100, 0x0, 0x00000000, 0x00000000, 0x443c02b0) +#define IOMUXC_PAD_ENET2_RD2_LPUART4_CTS_B IOMUX_PADCFG(0x443c0100, 0x1, 0x443c0420, 0x00000001, 0x443c02b0) +#define IOMUXC_PAD_ENET2_RD2_SAI2_MCLK IOMUX_PADCFG(0x443c0100, 0x2, 0x00000000, 0x00000000, 0x443c02b0) +#define IOMUXC_PAD_ENET2_RD2_MQS2_RIGHT IOMUX_PADCFG(0x443c0100, 0x3, 0x00000000, 0x00000000, 0x443c02b0) +#define IOMUXC_PAD_ENET2_RD2_FLEXIO2_FLEXIO26 IOMUX_PADCFG(0x443c0100, 0x4, 0x00000000, 0x00000000, 0x443c02b0) +#define IOMUXC_PAD_ENET2_RD2_GPIO4_IO26 IOMUX_PADCFG(0x443c0100, 0x5, 0x00000000, 0x00000000, 0x443c02b0) +#define IOMUXC_PAD_ENET2_RD3_ENET1_RGMII_RD3 IOMUX_PADCFG(0x443c0104, 0x0, 0x00000000, 0x00000000, 0x443c02b4) +#define IOMUXC_PAD_ENET2_RD3_SPDIF_OUT IOMUX_PADCFG(0x443c0104, 0x1, 0x00000000, 0x00000000, 0x443c02b4) +#define IOMUXC_PAD_ENET2_RD3_SPDIF_IN IOMUX_PADCFG(0x443c0104, 0x2, 0x443c0454, 0x00000002, 0x443c02b4) +#define IOMUXC_PAD_ENET2_RD3_MQS2_LEFT IOMUX_PADCFG(0x443c0104, 0x3, 0x00000000, 0x00000000, 0x443c02b4) +#define IOMUXC_PAD_ENET2_RD3_FLEXIO2_FLEXIO27 IOMUX_PADCFG(0x443c0104, 0x4, 0x00000000, 0x00000000, 0x443c02b4) +#define IOMUXC_PAD_ENET2_RD3_GPIO4_IO27 IOMUX_PADCFG(0x443c0104, 0x5, 0x00000000, 0x00000000, 0x443c02b4) +#define IOMUXC_PAD_SD1_CLK_FLEXIO1_FLEXIO08 IOMUX_PADCFG(0x443c0108, 0x4, 0x443c038c, 0x00000001, 0x443c02b8) +#define IOMUXC_PAD_SD1_CLK_GPIO3_IO08 IOMUX_PADCFG(0x443c0108, 0x5, 0x00000000, 0x00000000, 0x443c02b8) +#define IOMUXC_PAD_SD1_CLK_USDHC1_CLK IOMUX_PADCFG(0x443c0108, 0x0, 0x00000000, 0x00000000, 0x443c02b8) +#define IOMUXC_PAD_SD1_CMD_USDHC1_CMD IOMUX_PADCFG(0x443c010c, 0x0, 0x00000000, 0x00000000, 0x443c02bc) +#define IOMUXC_PAD_SD1_CMD_FLEXIO1_FLEXIO09 IOMUX_PADCFG(0x443c010c, 0x4, 0x443c0390, 0x00000001, 0x443c02bc) +#define IOMUXC_PAD_SD1_CMD_GPIO3_IO09 IOMUX_PADCFG(0x443c010c, 0x5, 0x00000000, 0x00000000, 0x443c02bc) +#define IOMUXC_PAD_SD1_DATA0_USDHC1_DATA0 IOMUX_PADCFG(0x443c0110, 0x0, 0x00000000, 0x00000000, 0x443c02c0) +#define IOMUXC_PAD_SD1_DATA0_FLEXIO1_FLEXIO10 IOMUX_PADCFG(0x443c0110, 0x4, 0x443c0394, 0x00000001, 0x443c02c0) +#define IOMUXC_PAD_SD1_DATA0_GPIO3_IO10 IOMUX_PADCFG(0x443c0110, 0x5, 0x00000000, 0x00000000, 0x443c02c0) +#define IOMUXC_PAD_SD1_DATA1_USDHC1_DATA1 IOMUX_PADCFG(0x443c0114, 0x0, 0x00000000, 0x00000000, 0x443c02c4) +#define IOMUXC_PAD_SD1_DATA1_FLEXIO1_FLEXIO11 IOMUX_PADCFG(0x443c0114, 0x4, 0x443c0398, 0x00000001, 0x443c02c4) +#define IOMUXC_PAD_SD1_DATA1_GPIO3_IO11 IOMUX_PADCFG(0x443c0114, 0x5, 0x00000000, 0x00000000, 0x443c02c4) +#define IOMUXC_PAD_SD1_DATA1_CCMSRCGPCMIX_INT_BOOT IOMUX_PADCFG(0x443c0114, 0x6, 0x00000000, 0x00000000, 0x443c02c4) +#define IOMUXC_PAD_SD1_DATA2_USDHC1_DATA2 IOMUX_PADCFG(0x443c0118, 0x0, 0x00000000, 0x00000000, 0x443c02c8) +#define IOMUXC_PAD_SD1_DATA2_FLEXIO1_FLEXIO12 IOMUX_PADCFG(0x443c0118, 0x4, 0x00000000, 0x00000000, 0x443c02c8) +#define IOMUXC_PAD_SD1_DATA2_GPIO3_IO12 IOMUX_PADCFG(0x443c0118, 0x5, 0x00000000, 0x00000000, 0x443c02c8) +#define IOMUXC_PAD_SD1_DATA2_CCMSRCGPCMIX_PMIC_READY IOMUX_PADCFG(0x443c0118, 0x6, 0x00000000, 0x00000000, 0x443c02c8) +#define IOMUXC_PAD_SD1_DATA3_USDHC1_DATA3 IOMUX_PADCFG(0x443c011c, 0x0, 0x00000000, 0x00000000, 0x443c02cc) +#define IOMUXC_PAD_SD1_DATA3_FLEXSPI1_A_SS1_B IOMUX_PADCFG(0x443c011c, 0x1, 0x00000000, 0x00000000, 0x443c02cc) +#define IOMUXC_PAD_SD1_DATA3_FLEXIO1_FLEXIO13 IOMUX_PADCFG(0x443c011c, 0x4, 0x443c039c, 0x00000001, 0x443c02cc) +#define IOMUXC_PAD_SD1_DATA3_GPIO3_IO13 IOMUX_PADCFG(0x443c011c, 0x5, 0x00000000, 0x00000000, 0x443c02cc) +#define IOMUXC_PAD_SD1_DATA4_USDHC1_DATA4 IOMUX_PADCFG(0x443c0120, 0x0, 0x00000000, 0x00000000, 0x443c02d0) +#define IOMUXC_PAD_SD1_DATA4_FLEXSPI1_A_DATA04 IOMUX_PADCFG(0x443c0120, 0x1, 0x00000000, 0x00000000, 0x443c02d0) +#define IOMUXC_PAD_SD1_DATA4_FLEXIO1_FLEXIO14 IOMUX_PADCFG(0x443c0120, 0x4, 0x443c03a0, 0x00000001, 0x443c02d0) +#define IOMUXC_PAD_SD1_DATA4_GPIO3_IO14 IOMUX_PADCFG(0x443c0120, 0x5, 0x00000000, 0x00000000, 0x443c02d0) +#define IOMUXC_PAD_SD1_DATA5_USDHC1_DATA5 IOMUX_PADCFG(0x443c0124, 0x0, 0x00000000, 0x00000000, 0x443c02d4) +#define IOMUXC_PAD_SD1_DATA5_FLEXSPI1_A_DATA05 IOMUX_PADCFG(0x443c0124, 0x1, 0x00000000, 0x00000000, 0x443c02d4) +#define IOMUXC_PAD_SD1_DATA5_USDHC1_RESET_B IOMUX_PADCFG(0x443c0124, 0x2, 0x00000000, 0x00000000, 0x443c02d4) +#define IOMUXC_PAD_SD1_DATA5_FLEXIO1_FLEXIO15 IOMUX_PADCFG(0x443c0124, 0x4, 0x443c03a4, 0x00000001, 0x443c02d4) +#define IOMUXC_PAD_SD1_DATA5_GPIO3_IO15 IOMUX_PADCFG(0x443c0124, 0x5, 0x00000000, 0x00000000, 0x443c02d4) +#define IOMUXC_PAD_SD1_DATA6_USDHC1_DATA6 IOMUX_PADCFG(0x443c0128, 0x0, 0x00000000, 0x00000000, 0x443c02d8) +#define IOMUXC_PAD_SD1_DATA6_FLEXSPI1_A_DATA06 IOMUX_PADCFG(0x443c0128, 0x1, 0x00000000, 0x00000000, 0x443c02d8) +#define IOMUXC_PAD_SD1_DATA6_USDHC1_CD_B IOMUX_PADCFG(0x443c0128, 0x2, 0x00000000, 0x00000000, 0x443c02d8) +#define IOMUXC_PAD_SD1_DATA6_FLEXIO1_FLEXIO16 IOMUX_PADCFG(0x443c0128, 0x4, 0x443c03a8, 0x00000001, 0x443c02d8) +#define IOMUXC_PAD_SD1_DATA6_GPIO3_IO16 IOMUX_PADCFG(0x443c0128, 0x5, 0x00000000, 0x00000000, 0x443c02d8) +#define IOMUXC_PAD_SD1_DATA7_USDHC1_DATA7 IOMUX_PADCFG(0x443c012c, 0x0, 0x00000000, 0x00000000, 0x443c02dc) +#define IOMUXC_PAD_SD1_DATA7_FLEXSPI1_A_DATA07 IOMUX_PADCFG(0x443c012c, 0x1, 0x00000000, 0x00000000, 0x443c02dc) +#define IOMUXC_PAD_SD1_DATA7_USDHC1_WP IOMUX_PADCFG(0x443c012c, 0x2, 0x00000000, 0x00000000, 0x443c02dc) +#define IOMUXC_PAD_SD1_DATA7_FLEXIO1_FLEXIO17 IOMUX_PADCFG(0x443c012c, 0x4, 0x443c03ac, 0x00000001, 0x443c02dc) +#define IOMUXC_PAD_SD1_DATA7_GPIO3_IO17 IOMUX_PADCFG(0x443c012c, 0x5, 0x00000000, 0x00000000, 0x443c02dc) +#define IOMUXC_PAD_SD1_STROBE_USDHC1_STROBE IOMUX_PADCFG(0x443c0130, 0x0, 0x00000000, 0x00000000, 0x443c02e0) +#define IOMUXC_PAD_SD1_STROBE_FLEXSPI1_A_DQS IOMUX_PADCFG(0x443c0130, 0x1, 0x00000000, 0x00000000, 0x443c02e0) +#define IOMUXC_PAD_SD1_STROBE_FLEXIO1_FLEXIO18 IOMUX_PADCFG(0x443c0130, 0x4, 0x443c03b0, 0x00000001, 0x443c02e0) +#define IOMUXC_PAD_SD1_STROBE_GPIO3_IO18 IOMUX_PADCFG(0x443c0130, 0x5, 0x00000000, 0x00000000, 0x443c02e0) +#define IOMUXC_PAD_SD2_VSELECT_USDHC2_VSELECT IOMUX_PADCFG(0x443c0134, 0x0, 0x00000000, 0x00000000, 0x443c02e4) +#define IOMUXC_PAD_SD2_VSELECT_USDHC2_WP IOMUX_PADCFG(0x443c0134, 0x1, 0x00000000, 0x00000000, 0x443c02e4) +#define IOMUXC_PAD_SD2_VSELECT_LPTMR2_ALT3 IOMUX_PADCFG(0x443c0134, 0x2, 0x443c0410, 0x00000001, 0x443c02e4) +#define IOMUXC_PAD_SD2_VSELECT_FLEXIO1_FLEXIO19 IOMUX_PADCFG(0x443c0134, 0x4, 0x00000000, 0x00000000, 0x443c02e4) +#define IOMUXC_PAD_SD2_VSELECT_GPIO3_IO19 IOMUX_PADCFG(0x443c0134, 0x5, 0x00000000, 0x00000000, 0x443c02e4) +#define IOMUXC_PAD_SD2_VSELECT_CCMSRCGPCMIX_EXT_CLK1 IOMUX_PADCFG(0x443c0134, 0x6, 0x443c0368, 0x00000000, 0x443c02e4) +#define IOMUXC_PAD_SD3_CLK_USDHC3_CLK IOMUX_PADCFG(0x443c0138, 0x0, 0x443c0458, 0x00000001, 0x443c02e8) +#define IOMUXC_PAD_SD3_CLK_FLEXSPI1_A_SCLK IOMUX_PADCFG(0x443c0138, 0x1, 0x00000000, 0x00000000, 0x443c02e8) +#define IOMUXC_PAD_SD3_CLK_FLEXIO1_FLEXIO20 IOMUX_PADCFG(0x443c0138, 0x4, 0x443c03b4, 0x00000001, 0x443c02e8) +#define IOMUXC_PAD_SD3_CLK_GPIO3_IO20 IOMUX_PADCFG(0x443c0138, 0x5, 0x00000000, 0x00000000, 0x443c02e8) +#define IOMUXC_PAD_SD3_CMD_USDHC3_CMD IOMUX_PADCFG(0x443c013c, 0x0, 0x443c045c, 0x00000001, 0x443c02ec) +#define IOMUXC_PAD_SD3_CMD_FLEXSPI1_A_SS0_B IOMUX_PADCFG(0x443c013c, 0x1, 0x00000000, 0x00000000, 0x443c02ec) +#define IOMUXC_PAD_SD3_CMD_FLEXIO1_FLEXIO21 IOMUX_PADCFG(0x443c013c, 0x4, 0x00000000, 0x00000000, 0x443c02ec) +#define IOMUXC_PAD_SD3_CMD_GPIO3_IO21 IOMUX_PADCFG(0x443c013c, 0x5, 0x00000000, 0x00000000, 0x443c02ec) +#define IOMUXC_PAD_SD3_DATA0_USDHC3_DATA0 IOMUX_PADCFG(0x443c0140, 0x0, 0x443c0460, 0x00000001, 0x443c02f0) +#define IOMUXC_PAD_SD3_DATA0_FLEXSPI1_A_DATA00 IOMUX_PADCFG(0x443c0140, 0x1, 0x00000000, 0x00000000, 0x443c02f0) +#define IOMUXC_PAD_SD3_DATA0_FLEXIO1_FLEXIO22 IOMUX_PADCFG(0x443c0140, 0x4, 0x443c03b8, 0x00000001, 0x443c02f0) +#define IOMUXC_PAD_SD3_DATA0_GPIO3_IO22 IOMUX_PADCFG(0x443c0140, 0x5, 0x00000000, 0x00000000, 0x443c02f0) +#define IOMUXC_PAD_SD3_DATA1_USDHC3_DATA1 IOMUX_PADCFG(0x443c0144, 0x0, 0x443c0464, 0x00000001, 0x443c02f4) +#define IOMUXC_PAD_SD3_DATA1_FLEXSPI1_A_DATA01 IOMUX_PADCFG(0x443c0144, 0x1, 0x00000000, 0x00000000, 0x443c02f4) +#define IOMUXC_PAD_SD3_DATA1_FLEXIO1_FLEXIO23 IOMUX_PADCFG(0x443c0144, 0x4, 0x443c03bc, 0x00000001, 0x443c02f4) +#define IOMUXC_PAD_SD3_DATA1_GPIO3_IO23 IOMUX_PADCFG(0x443c0144, 0x5, 0x00000000, 0x00000000, 0x443c02f4) +#define IOMUXC_PAD_SD3_DATA2_USDHC3_DATA2 IOMUX_PADCFG(0x443c0148, 0x0, 0x443c0468, 0x00000001, 0x443c02f8) +#define IOMUXC_PAD_SD3_DATA2_FLEXSPI1_A_DATA02 IOMUX_PADCFG(0x443c0148, 0x1, 0x00000000, 0x00000000, 0x443c02f8) +#define IOMUXC_PAD_SD3_DATA2_FLEXIO1_FLEXIO24 IOMUX_PADCFG(0x443c0148, 0x4, 0x443c03c0, 0x00000001, 0x443c02f8) +#define IOMUXC_PAD_SD3_DATA2_GPIO3_IO24 IOMUX_PADCFG(0x443c0148, 0x5, 0x00000000, 0x00000000, 0x443c02f8) +#define IOMUXC_PAD_SD3_DATA3_USDHC3_DATA3 IOMUX_PADCFG(0x443c014c, 0x0, 0x443c046c, 0x00000001, 0x443c02fc) +#define IOMUXC_PAD_SD3_DATA3_FLEXSPI1_A_DATA03 IOMUX_PADCFG(0x443c014c, 0x1, 0x00000000, 0x00000000, 0x443c02fc) +#define IOMUXC_PAD_SD3_DATA3_FLEXIO1_FLEXIO25 IOMUX_PADCFG(0x443c014c, 0x4, 0x443c03c4, 0x00000001, 0x443c02fc) +#define IOMUXC_PAD_SD3_DATA3_GPIO3_IO25 IOMUX_PADCFG(0x443c014c, 0x5, 0x00000000, 0x00000000, 0x443c02fc) +#define IOMUXC_PAD_SD2_CD_B_USDHC2_CD_B IOMUX_PADCFG(0x443c0150, 0x0, 0x00000000, 0x00000000, 0x443c0300) +#define IOMUXC_PAD_SD2_CD_B_ENET_QOS_1588_EVENT0_IN IOMUX_PADCFG(0x443c0150, 0x1, 0x00000000, 0x00000000, 0x443c0300) +#define IOMUXC_PAD_SD2_CD_B_I3C2_SCL IOMUX_PADCFG(0x443c0150, 0x2, 0x443c03cc, 0x00000001, 0x443c0300) +#define IOMUXC_PAD_SD2_CD_B_FLEXIO1_FLEXIO00 IOMUX_PADCFG(0x443c0150, 0x4, 0x443c036c, 0x00000001, 0x443c0300) +#define IOMUXC_PAD_SD2_CD_B_GPIO3_IO00 IOMUX_PADCFG(0x443c0150, 0x5, 0x00000000, 0x00000000, 0x443c0300) +#define IOMUXC_PAD_SD2_CLK_USDHC2_CLK IOMUX_PADCFG(0x443c0154, 0x0, 0x00000000, 0x00000000, 0x443c0304) +#define IOMUXC_PAD_SD2_CLK_ENET_QOS_1588_EVENT0_OUT IOMUX_PADCFG(0x443c0154, 0x1, 0x00000000, 0x00000000, 0x443c0304) +#define IOMUXC_PAD_SD2_CLK_I3C2_SDA IOMUX_PADCFG(0x443c0154, 0x2, 0x443c03d0, 0x00000001, 0x443c0304) +#define IOMUXC_PAD_SD2_CLK_FLEXIO1_FLEXIO01 IOMUX_PADCFG(0x443c0154, 0x4, 0x443c0370, 0x00000001, 0x443c0304) +#define IOMUXC_PAD_SD2_CLK_GPIO3_IO01 IOMUX_PADCFG(0x443c0154, 0x5, 0x00000000, 0x00000000, 0x443c0304) +#define IOMUXC_PAD_SD2_CLK_CCMSRCGPCMIX_OBSERVE0 IOMUX_PADCFG(0x443c0154, 0x6, 0x00000000, 0x00000000, 0x443c0304) +#define IOMUXC_PAD_SD2_CMD_USDHC2_CMD IOMUX_PADCFG(0x443c0158, 0x0, 0x00000000, 0x00000000, 0x443c0308) +#define IOMUXC_PAD_SD2_CMD_ENET1_1588_EVENT0_IN IOMUX_PADCFG(0x443c0158, 0x1, 0x00000000, 0x00000000, 0x443c0308) +#define IOMUXC_PAD_SD2_CMD_I3C2_PUR IOMUX_PADCFG(0x443c0158, 0x2, 0x00000000, 0x00000000, 0x443c0308) +#define IOMUXC_PAD_SD2_CMD_I3C2_PUR_B IOMUX_PADCFG(0x443c0158, 0x3, 0x00000000, 0x00000000, 0x443c0308) +#define IOMUXC_PAD_SD2_CMD_FLEXIO1_FLEXIO02 IOMUX_PADCFG(0x443c0158, 0x4, 0x443c0374, 0x00000001, 0x443c0308) +#define IOMUXC_PAD_SD2_CMD_GPIO3_IO02 IOMUX_PADCFG(0x443c0158, 0x5, 0x00000000, 0x00000000, 0x443c0308) +#define IOMUXC_PAD_SD2_CMD_CCMSRCGPCMIX_OBSERVE1 IOMUX_PADCFG(0x443c0158, 0x6, 0x00000000, 0x00000000, 0x443c0308) +#define IOMUXC_PAD_SD2_DATA0_USDHC2_DATA0 IOMUX_PADCFG(0x443c015c, 0x0, 0x00000000, 0x00000000, 0x443c030c) +#define IOMUXC_PAD_SD2_DATA0_ENET1_1588_EVENT0_OUT IOMUX_PADCFG(0x443c015c, 0x1, 0x00000000, 0x00000000, 0x443c030c) +#define IOMUXC_PAD_SD2_DATA0_CAN2_TX IOMUX_PADCFG(0x443c015c, 0x2, 0x00000000, 0x00000000, 0x443c030c) +#define IOMUXC_PAD_SD2_DATA0_FLEXIO1_FLEXIO03 IOMUX_PADCFG(0x443c015c, 0x4, 0x443c0378, 0x00000001, 0x443c030c) +#define IOMUXC_PAD_SD2_DATA0_GPIO3_IO03 IOMUX_PADCFG(0x443c015c, 0x5, 0x00000000, 0x00000000, 0x443c030c) +#define IOMUXC_PAD_SD2_DATA0_CCMSRCGPCMIX_OBSERVE2 IOMUX_PADCFG(0x443c015c, 0x6, 0x00000000, 0x00000000, 0x443c030c) +#define IOMUXC_PAD_SD2_DATA1_USDHC2_DATA1 IOMUX_PADCFG(0x443c0160, 0x0, 0x00000000, 0x00000000, 0x443c0310) +#define IOMUXC_PAD_SD2_DATA1_ENET1_1588_EVENT1_IN IOMUX_PADCFG(0x443c0160, 0x1, 0x00000000, 0x00000000, 0x443c0310) +#define IOMUXC_PAD_SD2_DATA1_CAN2_RX IOMUX_PADCFG(0x443c0160, 0x2, 0x443c0364, 0x00000003, 0x443c0310) +#define IOMUXC_PAD_SD2_DATA1_FLEXIO1_FLEXIO04 IOMUX_PADCFG(0x443c0160, 0x4, 0x443c037c, 0x00000001, 0x443c0310) +#define IOMUXC_PAD_SD2_DATA1_GPIO3_IO04 IOMUX_PADCFG(0x443c0160, 0x5, 0x00000000, 0x00000000, 0x443c0310) +#define IOMUXC_PAD_SD2_DATA1_CCMSRCGPCMIX_WAIT IOMUX_PADCFG(0x443c0160, 0x6, 0x00000000, 0x00000000, 0x443c0310) +#define IOMUXC_PAD_SD2_DATA2_USDHC2_DATA2 IOMUX_PADCFG(0x443c0164, 0x0, 0x00000000, 0x00000000, 0x443c0314) +#define IOMUXC_PAD_SD2_DATA2_ENET1_1588_EVENT1_OUT IOMUX_PADCFG(0x443c0164, 0x1, 0x00000000, 0x00000000, 0x443c0314) +#define IOMUXC_PAD_SD2_DATA2_MQS2_RIGHT IOMUX_PADCFG(0x443c0164, 0x2, 0x00000000, 0x00000000, 0x443c0314) +#define IOMUXC_PAD_SD2_DATA2_FLEXIO1_FLEXIO05 IOMUX_PADCFG(0x443c0164, 0x4, 0x443c0380, 0x00000001, 0x443c0314) +#define IOMUXC_PAD_SD2_DATA2_GPIO3_IO05 IOMUX_PADCFG(0x443c0164, 0x5, 0x00000000, 0x00000000, 0x443c0314) +#define IOMUXC_PAD_SD2_DATA2_CCMSRCGPCMIX_STOP IOMUX_PADCFG(0x443c0164, 0x6, 0x00000000, 0x00000000, 0x443c0314) +#define IOMUXC_PAD_SD2_DATA3_USDHC2_DATA3 IOMUX_PADCFG(0x443c0168, 0x0, 0x00000000, 0x00000000, 0x443c0318) +#define IOMUXC_PAD_SD2_DATA3_LPTMR2_ALT1 IOMUX_PADCFG(0x443c0168, 0x1, 0x443c0408, 0x00000001, 0x443c0318) +#define IOMUXC_PAD_SD2_DATA3_MQS2_LEFT IOMUX_PADCFG(0x443c0168, 0x2, 0x00000000, 0x00000000, 0x443c0318) +#define IOMUXC_PAD_SD2_DATA3_FLEXIO1_FLEXIO06 IOMUX_PADCFG(0x443c0168, 0x4, 0x443c0384, 0x00000001, 0x443c0318) +#define IOMUXC_PAD_SD2_DATA3_GPIO3_IO06 IOMUX_PADCFG(0x443c0168, 0x5, 0x00000000, 0x00000000, 0x443c0318) +#define IOMUXC_PAD_SD2_DATA3_CCMSRCGPCMIX_EARLY_RESET IOMUX_PADCFG(0x443c0168, 0x6, 0x00000000, 0x00000000, 0x443c0318) +#define IOMUXC_PAD_SD2_RESET_B_USDHC2_RESET_B IOMUX_PADCFG(0x443c016c, 0x0, 0x00000000, 0x00000000, 0x443c031c) +#define IOMUXC_PAD_SD2_RESET_B_LPTMR2_ALT2 IOMUX_PADCFG(0x443c016c, 0x1, 0x443c040c, 0x00000001, 0x443c031c) +#define IOMUXC_PAD_SD2_RESET_B_FLEXIO1_FLEXIO07 IOMUX_PADCFG(0x443c016c, 0x4, 0x443c0388, 0x00000001, 0x443c031c) +#define IOMUXC_PAD_SD2_RESET_B_GPIO3_IO07 IOMUX_PADCFG(0x443c016c, 0x5, 0x00000000, 0x00000000, 0x443c031c) +#define IOMUXC_PAD_SD2_RESET_B_CCMSRCGPCMIX_SYSTEM_RESET IOMUX_PADCFG(0x443c016c, 0x6, 0x00000000, 0x00000000, 0x443c031c) +#define IOMUXC_PAD_I2C1_SCL_LPI2C1_SCL IOMUX_PADCFG(0x443c0170, 0x0, 0x00000000, 0x00000000, 0x443c0320) +#define IOMUXC_PAD_I2C1_SCL_I3C1_SCL IOMUX_PADCFG(0x443c0170, 0x1, 0x00000000, 0x00000000, 0x443c0320) +#define IOMUXC_PAD_I2C1_SCL_LPUART1_DCB_B IOMUX_PADCFG(0x443c0170, 0x2, 0x00000000, 0x00000000, 0x443c0320) +#define IOMUXC_PAD_I2C1_SCL_TPM2_CH0 IOMUX_PADCFG(0x443c0170, 0x3, 0x00000000, 0x00000000, 0x443c0320) +#define IOMUXC_PAD_I2C1_SCL_GPIO1_IO00 IOMUX_PADCFG(0x443c0170, 0x5, 0x00000000, 0x00000000, 0x443c0320) +#define IOMUXC_PAD_I2C1_SDA_LPI2C1_SDA IOMUX_PADCFG(0x443c0174, 0x0, 0x00000000, 0x00000000, 0x443c0324) +#define IOMUXC_PAD_I2C1_SDA_I3C1_SDA IOMUX_PADCFG(0x443c0174, 0x1, 0x00000000, 0x00000000, 0x443c0324) +#define IOMUXC_PAD_I2C1_SDA_LPUART1_RIN_B IOMUX_PADCFG(0x443c0174, 0x2, 0x00000000, 0x00000000, 0x443c0324) +#define IOMUXC_PAD_I2C1_SDA_TPM2_CH1 IOMUX_PADCFG(0x443c0174, 0x3, 0x00000000, 0x00000000, 0x443c0324) +#define IOMUXC_PAD_I2C1_SDA_GPIO1_IO01 IOMUX_PADCFG(0x443c0174, 0x5, 0x00000000, 0x00000000, 0x443c0324) +#define IOMUXC_PAD_I2C2_SCL_LPI2C2_SCL IOMUX_PADCFG(0x443c0178, 0x0, 0x00000000, 0x00000000, 0x443c0328) +#define IOMUXC_PAD_I2C2_SCL_I3C1_PUR IOMUX_PADCFG(0x443c0178, 0x1, 0x00000000, 0x00000000, 0x443c0328) +#define IOMUXC_PAD_I2C2_SCL_LPUART2_DCB_B IOMUX_PADCFG(0x443c0178, 0x2, 0x00000000, 0x00000000, 0x443c0328) +#define IOMUXC_PAD_I2C2_SCL_TPM2_CH2 IOMUX_PADCFG(0x443c0178, 0x3, 0x00000000, 0x00000000, 0x443c0328) +#define IOMUXC_PAD_I2C2_SCL_SAI1_RX_SYNC IOMUX_PADCFG(0x443c0178, 0x4, 0x00000000, 0x00000000, 0x443c0328) +#define IOMUXC_PAD_I2C2_SCL_GPIO1_IO02 IOMUX_PADCFG(0x443c0178, 0x5, 0x00000000, 0x00000000, 0x443c0328) +#define IOMUXC_PAD_I2C2_SCL_I3C1_PUR_B IOMUX_PADCFG(0x443c0178, 0x6, 0x00000000, 0x00000000, 0x443c0328) +#define IOMUXC_PAD_I2C2_SDA_LPI2C2_SDA IOMUX_PADCFG(0x443c017c, 0x0, 0x00000000, 0x00000000, 0x443c032c) +#define IOMUXC_PAD_I2C2_SDA_LPUART2_RIN_B IOMUX_PADCFG(0x443c017c, 0x2, 0x00000000, 0x00000000, 0x443c032c) +#define IOMUXC_PAD_I2C2_SDA_TPM2_CH3 IOMUX_PADCFG(0x443c017c, 0x3, 0x00000000, 0x00000000, 0x443c032c) +#define IOMUXC_PAD_I2C2_SDA_SAI1_RX_BCLK IOMUX_PADCFG(0x443c017c, 0x4, 0x00000000, 0x00000000, 0x443c032c) +#define IOMUXC_PAD_I2C2_SDA_GPIO1_IO03 IOMUX_PADCFG(0x443c017c, 0x5, 0x00000000, 0x00000000, 0x443c032c) +#define IOMUXC_PAD_UART1_RXD_LPUART1_RX IOMUX_PADCFG(0x443c0180, 0x0, 0x00000000, 0x00000000, 0x443c0330) +#define IOMUXC_PAD_UART1_RXD_S400_UART_RX IOMUX_PADCFG(0x443c0180, 0x1, 0x00000000, 0x00000000, 0x443c0330) +#define IOMUXC_PAD_UART1_RXD_LPSPI2_SIN IOMUX_PADCFG(0x443c0180, 0x2, 0x00000000, 0x00000000, 0x443c0330) +#define IOMUXC_PAD_UART1_RXD_TPM1_CH0 IOMUX_PADCFG(0x443c0180, 0x3, 0x00000000, 0x00000000, 0x443c0330) +#define IOMUXC_PAD_UART1_RXD_GPIO1_IO04 IOMUX_PADCFG(0x443c0180, 0x5, 0x00000000, 0x00000000, 0x443c0330) +#define IOMUXC_PAD_UART1_TXD_LPUART1_TX IOMUX_PADCFG(0x443c0184, 0x0, 0x00000000, 0x00000000, 0x443c0334) +#define IOMUXC_PAD_UART1_TXD_S400_UART_TX IOMUX_PADCFG(0x443c0184, 0x1, 0x00000000, 0x00000000, 0x443c0334) +#define IOMUXC_PAD_UART1_TXD_LPSPI2_PCS0 IOMUX_PADCFG(0x443c0184, 0x2, 0x00000000, 0x00000000, 0x443c0334) +#define IOMUXC_PAD_UART1_TXD_TPM1_CH1 IOMUX_PADCFG(0x443c0184, 0x3, 0x00000000, 0x00000000, 0x443c0334) +#define IOMUXC_PAD_UART1_TXD_GPIO1_IO05 IOMUX_PADCFG(0x443c0184, 0x5, 0x00000000, 0x00000000, 0x443c0334) +#define IOMUXC_PAD_UART2_RXD_LPUART2_RX IOMUX_PADCFG(0x443c0188, 0x0, 0x00000000, 0x00000000, 0x443c0338) +#define IOMUXC_PAD_UART2_RXD_LPUART1_CTS_B IOMUX_PADCFG(0x443c0188, 0x1, 0x00000000, 0x00000000, 0x443c0338) +#define IOMUXC_PAD_UART2_RXD_LPSPI2_SOUT IOMUX_PADCFG(0x443c0188, 0x2, 0x00000000, 0x00000000, 0x443c0338) +#define IOMUXC_PAD_UART2_RXD_TPM1_CH2 IOMUX_PADCFG(0x443c0188, 0x3, 0x00000000, 0x00000000, 0x443c0338) +#define IOMUXC_PAD_UART2_RXD_SAI1_MCLK IOMUX_PADCFG(0x443c0188, 0x4, 0x443c0448, 0x00000000, 0x443c0338) +#define IOMUXC_PAD_UART2_RXD_GPIO1_IO06 IOMUX_PADCFG(0x443c0188, 0x5, 0x00000000, 0x00000000, 0x443c0338) +#define IOMUXC_PAD_UART2_TXD_LPUART2_TX IOMUX_PADCFG(0x443c018c, 0x0, 0x00000000, 0x00000000, 0x443c033c) +#define IOMUXC_PAD_UART2_TXD_LPUART1_RTS_B IOMUX_PADCFG(0x443c018c, 0x1, 0x00000000, 0x00000000, 0x443c033c) +#define IOMUXC_PAD_UART2_TXD_LPSPI2_SCK IOMUX_PADCFG(0x443c018c, 0x2, 0x00000000, 0x00000000, 0x443c033c) +#define IOMUXC_PAD_UART2_TXD_TPM1_CH3 IOMUX_PADCFG(0x443c018c, 0x3, 0x00000000, 0x00000000, 0x443c033c) +#define IOMUXC_PAD_UART2_TXD_GPIO1_IO07 IOMUX_PADCFG(0x443c018c, 0x5, 0x00000000, 0x00000000, 0x443c033c) +#define IOMUXC_PAD_PDM_CLK_PDM_CLK IOMUX_PADCFG(0x443c0190, 0x0, 0x00000000, 0x00000000, 0x443c0340) +#define IOMUXC_PAD_PDM_CLK_MQS1_LEFT IOMUX_PADCFG(0x443c0190, 0x1, 0x00000000, 0x00000000, 0x443c0340) +#define IOMUXC_PAD_PDM_CLK_LPTMR1_ALT1 IOMUX_PADCFG(0x443c0190, 0x4, 0x00000000, 0x00000000, 0x443c0340) +#define IOMUXC_PAD_PDM_CLK_GPIO1_IO08 IOMUX_PADCFG(0x443c0190, 0x5, 0x00000000, 0x00000000, 0x443c0340) +#define IOMUXC_PAD_PDM_CLK_CAN1_TX IOMUX_PADCFG(0x443c0190, 0x6, 0x00000000, 0x00000000, 0x443c0340) +#define IOMUXC_PAD_PDM_BIT_STREAM0_PDM_BIT_STREAM00 IOMUX_PADCFG(0x443c0194, 0x0, 0x443c0438, 0x00000002, 0x443c0344) +#define IOMUXC_PAD_PDM_BIT_STREAM0_MQS1_RIGHT IOMUX_PADCFG(0x443c0194, 0x1, 0x00000000, 0x00000000, 0x443c0344) +#define IOMUXC_PAD_PDM_BIT_STREAM0_LPSPI1_PCS1 IOMUX_PADCFG(0x443c0194, 0x2, 0x00000000, 0x00000000, 0x443c0344) +#define IOMUXC_PAD_PDM_BIT_STREAM0_TPM1_EXTCLK IOMUX_PADCFG(0x443c0194, 0x3, 0x00000000, 0x00000000, 0x443c0344) +#define IOMUXC_PAD_PDM_BIT_STREAM0_LPTMR1_ALT2 IOMUX_PADCFG(0x443c0194, 0x4, 0x00000000, 0x00000000, 0x443c0344) +#define IOMUXC_PAD_PDM_BIT_STREAM0_GPIO1_IO09 IOMUX_PADCFG(0x443c0194, 0x5, 0x00000000, 0x00000000, 0x443c0344) +#define IOMUXC_PAD_PDM_BIT_STREAM0_CAN1_RX IOMUX_PADCFG(0x443c0194, 0x6, 0x443c0360, 0x00000000, 0x443c0344) +#define IOMUXC_PAD_PDM_BIT_STREAM1_PDM_BIT_STREAM01 IOMUX_PADCFG(0x443c0198, 0x0, 0x443c043c, 0x00000002, 0x443c0348) +#define IOMUXC_PAD_PDM_BIT_STREAM1_NMI_GLUE_NMI IOMUX_PADCFG(0x443c0198, 0x1, 0x00000000, 0x00000000, 0x443c0348) +#define IOMUXC_PAD_PDM_BIT_STREAM1_LPSPI2_PCS1 IOMUX_PADCFG(0x443c0198, 0x2, 0x00000000, 0x00000000, 0x443c0348) +#define IOMUXC_PAD_PDM_BIT_STREAM1_TPM2_EXTCLK IOMUX_PADCFG(0x443c0198, 0x3, 0x00000000, 0x00000000, 0x443c0348) +#define IOMUXC_PAD_PDM_BIT_STREAM1_LPTMR1_ALT3 IOMUX_PADCFG(0x443c0198, 0x4, 0x00000000, 0x00000000, 0x443c0348) +#define IOMUXC_PAD_PDM_BIT_STREAM1_GPIO1_IO10 IOMUX_PADCFG(0x443c0198, 0x5, 0x00000000, 0x00000000, 0x443c0348) +#define IOMUXC_PAD_PDM_BIT_STREAM1_CCMSRCGPCMIX_EXT_CLK1 IOMUX_PADCFG(0x443c0198, 0x6, 0x443c0368, 0x00000001, 0x443c0348) +#define IOMUXC_PAD_SAI1_TXFS_SAI1_TX_SYNC IOMUX_PADCFG(0x443c019c, 0x0, 0x00000000, 0x00000000, 0x443c034c) +#define IOMUXC_PAD_SAI1_TXFS_SAI1_TX_DATA01 IOMUX_PADCFG(0x443c019c, 0x1, 0x00000000, 0x00000000, 0x443c034c) +#define IOMUXC_PAD_SAI1_TXFS_LPSPI1_PCS0 IOMUX_PADCFG(0x443c019c, 0x2, 0x00000000, 0x00000000, 0x443c034c) +#define IOMUXC_PAD_SAI1_TXFS_LPUART2_DTR_B IOMUX_PADCFG(0x443c019c, 0x3, 0x00000000, 0x00000000, 0x443c034c) +#define IOMUXC_PAD_SAI1_TXFS_MQS1_LEFT IOMUX_PADCFG(0x443c019c, 0x4, 0x00000000, 0x00000000, 0x443c034c) +#define IOMUXC_PAD_SAI1_TXFS_GPIO1_IO11 IOMUX_PADCFG(0x443c019c, 0x5, 0x00000000, 0x00000000, 0x443c034c) +#define IOMUXC_PAD_SAI1_TXC_SAI1_TX_BCLK IOMUX_PADCFG(0x443c01a0, 0x0, 0x00000000, 0x00000000, 0x443c0350) +#define IOMUXC_PAD_SAI1_TXC_LPUART2_CTS_B IOMUX_PADCFG(0x443c01a0, 0x1, 0x00000000, 0x00000000, 0x443c0350) +#define IOMUXC_PAD_SAI1_TXC_LPSPI1_SIN IOMUX_PADCFG(0x443c01a0, 0x2, 0x00000000, 0x00000000, 0x443c0350) +#define IOMUXC_PAD_SAI1_TXC_LPUART1_DSR_B IOMUX_PADCFG(0x443c01a0, 0x3, 0x00000000, 0x00000000, 0x443c0350) +#define IOMUXC_PAD_SAI1_TXC_CAN1_RX IOMUX_PADCFG(0x443c01a0, 0x4, 0x443c0360, 0x00000001, 0x443c0350) +#define IOMUXC_PAD_SAI1_TXC_GPIO1_IO12 IOMUX_PADCFG(0x443c01a0, 0x5, 0x00000000, 0x00000000, 0x443c0350) +#define IOMUXC_PAD_SAI1_TXD0_SAI1_TX_DATA00 IOMUX_PADCFG(0x443c01a4, 0x0, 0x00000000, 0x00000000, 0x443c0354) +#define IOMUXC_PAD_SAI1_TXD0_LPUART2_RTS_B IOMUX_PADCFG(0x443c01a4, 0x1, 0x00000000, 0x00000000, 0x443c0354) +#define IOMUXC_PAD_SAI1_TXD0_LPSPI1_SCK IOMUX_PADCFG(0x443c01a4, 0x2, 0x00000000, 0x00000000, 0x443c0354) +#define IOMUXC_PAD_SAI1_TXD0_LPUART1_DTR_B IOMUX_PADCFG(0x443c01a4, 0x3, 0x00000000, 0x00000000, 0x443c0354) +#define IOMUXC_PAD_SAI1_TXD0_CAN1_TX IOMUX_PADCFG(0x443c01a4, 0x4, 0x00000000, 0x00000000, 0x443c0354) +#define IOMUXC_PAD_SAI1_TXD0_GPIO1_IO13 IOMUX_PADCFG(0x443c01a4, 0x5, 0x00000000, 0x00000000, 0x443c0354) +#define IOMUXC_PAD_SAI1_RXD0_SAI1_RX_DATA00 IOMUX_PADCFG(0x443c01a8, 0x0, 0x00000000, 0x00000000, 0x443c0358) +#define IOMUXC_PAD_SAI1_RXD0_SAI1_MCLK IOMUX_PADCFG(0x443c01a8, 0x1, 0x443c0448, 0x00000001, 0x443c0358) +#define IOMUXC_PAD_SAI1_RXD0_LPSPI1_SOUT IOMUX_PADCFG(0x443c01a8, 0x2, 0x00000000, 0x00000000, 0x443c0358) +#define IOMUXC_PAD_SAI1_RXD0_LPUART2_DSR_B IOMUX_PADCFG(0x443c01a8, 0x3, 0x00000000, 0x00000000, 0x443c0358) +#define IOMUXC_PAD_SAI1_RXD0_MQS1_RIGHT IOMUX_PADCFG(0x443c01a8, 0x4, 0x00000000, 0x00000000, 0x443c0358) +#define IOMUXC_PAD_SAI1_RXD0_GPIO1_IO14 IOMUX_PADCFG(0x443c01a8, 0x5, 0x00000000, 0x00000000, 0x443c0358) +#define IOMUXC_PAD_WDOG_ANY_WDOG1_WDOG_ANY IOMUX_PADCFG(0x443c01ac, 0x0, 0x00000000, 0x00000000, 0x443c035c) +#define IOMUXC_PAD_WDOG_ANY_GPIO1_IO15 IOMUX_PADCFG(0x443c01ac, 0x5, 0x00000000, 0x00000000, 0x443c035c) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_PINMUX_H */ diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h b/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h new file mode 100644 index 0000000000000..fb0a5af737360 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h @@ -0,0 +1,195 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx93/imx93_pll.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_PLL_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_PLL_H + +/* All registers besides STATUS have SET, CLR, TGL and VAL shadow registers */ + +#define PLL_REG_VAL_OFFSET (0x00) +#define PLL_REG_SET_OFFSET (0x04) +#define PLL_REG_CLR_OFFSET (0x08) +#define PLL_REG_TGL_OFFSET (0x0c) + +/* User can access the individual registers via these macros */ + +#define PLL_VAL(n) ((n) + PLL_REG_VAL_OFFSET) /* Same as the register itself */ +#define PLL_SET(n) ((n) + PLL_REG_SET_OFFSET) +#define PLL_CLR(n) ((n) + PLL_REG_CLR_OFFSET) +#define PLL_TGL(n) ((n) + PLL_REG_TGL_OFFSET) + +/* Common offsets for all PLL registers, existence depends on the register + * itself + */ + +#define PLL_CTRL_OFFSET (0x00) /* PLL Control */ +#define PLL_SPREAD_SPECTRUM_OFFSET (0x30) /* Spread Spectrum */ +#define PLL_NUMERATOR_OFFSET (0x40) /* Numerator */ +#define PLL_DENOMINATOR_OFFSET (0x50) /* Denominator */ +#define PLL_DIV_OFFSET (0x60) /* PLL Dividers */ +#define PLL_DFS_CTRL_0_OFFSET (0x70) /* DFS Control */ +#define PLL_DFS_DIV_0_OFFSET (0x80) /* DFS Division_0 */ +#define PLL_DFS_CTRL_1_OFFSET (0x90) /* DFS Control */ +#define PLL_DFS_DIV_1_OFFSET (0xa0) /* DFS Division_1 */ +#define PLL_DFS_CTRL_2_OFFSET (0xb0) /* DFS Control */ +#define PLL_DFS_DIV_2_OFFSET (0xc0) /* DFS Division_2 */ +#define PLL_PLL_STATUS_OFFSET (0xf0) /* PLL Status */ +#define PLL_DFS_STATUS_OFFSET (0xf4) /* DFS Status */ + +/* Register addresses */ + +#define PLL_CTRL(n) ((n) + PLL_CTRL_OFFSET) +#define PLL_SPREAD_SPECTRUM(n) ((n) + PLL_SPREAD_SPECTRUM_OFFSET) +#define PLL_NUMERATOR(n) ((n) + PLL_NUMERATOR_OFFSET) +#define PLL_DENOMINATOR(n) ((n) + PLL_DENOMINATOR_OFFSET) +#define PLL_DIV(n) ((n) + PLL_DIV_OFFSET) +#define PLL_DFS_CTRL_0(n) ((n) + PLL_DFS_CTRL_0_OFFSET) +#define PLL_DFS_DIV_0(n) ((n) + PLL_DFS_DIV_0_OFFSET) +#define PLL_DFS_CTRL_1(n) ((n) + PLL_DFS_CTRL_1_OFFSET) +#define PLL_DFS_DIV_1(n) ((n) + PLL_DFS_DIV_1_OFFSET) +#define PLL_DFS_CTRL_2(n) ((n) + PLL_DFS_CTRL_2_OFFSET) +#define PLL_DFS_DIV_2(n) ((n) + PLL_DFS_DIV_2_OFFSET) +#define PLL_PLL_STATUS(n) ((n) + PLL_PLL_STATUS_OFFSET) +#define PLL_DFS_STATUS(n) ((n) + PLL_DFS_STATUS_OFFSET) + +/* SYSPLL registers */ + +#define SYSPLL_CTRL (IMX9_SYSPLL_BASE + PLL_CTRL_OFFSET) +#define SYSPLL_SPREAD_SPECTRUM (IMX9_SYSPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET) +#define SYSPLL_NUMERATOR (IMX9_SYSPLL_BASE + PLL_NUMERATOR_OFFSET) +#define SYSPLL_DENOMINATOR (IMX9_SYSPLL_BASE + PLL_DENOMINATOR_OFFSET) +#define SYSPLL_DIV (IMX9_SYSPLL_BASE + PLL_DIV_OFFSET) +#define SYSPLL_DFS_CTRL_0 (IMX9_SYSPLL_BASE + PLL_DFS_CTRL_0_OFFSET) +#define SYSPLL_DFS_DIV_0 (IMX9_SYSPLL_BASE + PLL_DFS_DIV_0_OFFSET) +#define SYSPLL_DFS_CTRL_1 (IMX9_SYSPLL_BASE + PLL_DFS_CTRL_1_OFFSET) +#define SYSPLL_DFS_DIV_1 (IMX9_SYSPLL_BASE + PLL_DFS_DIV_1_OFFSET) +#define SYSPLL_DFS_CTRL_2 (IMX9_SYSPLL_BASE + PLL_DFS_CTRL_2_OFFSET) +#define SYSPLL_DFS_DIV_2 (IMX9_SYSPLL_BASE + PLL_DFS_DIV_2_OFFSET) +#define SYSPLL_PLL_STATUS (IMX9_SYSPLL_BASE + PLL_PLL_STATUS_OFFSET) +#define SYSPLL_DFS_STATUS (IMX9_SYSPLL_BASE + PLL_DFS_STATUS_OFFSET) + +/* ARMPLL registers */ + +#define ARMPLL_CTRL (IMX9_ARMPLL_BASE + PLL_CTRL_OFFSET) +#define ARMPLL_DIV (IMX9_ARMPLL_BASE + PLL_DIV_OFFSET) +#define ARMPLL_PLL_STATUS (IMX9_ARMPLL_BASE + PLL_PLL_STATUS_OFFSET) + +/* AUDIOPLL registers */ + +#define AUDIOPLL_CTRL (IMX9_AUDIOPLL_BASE + PLL_CTRL_OFFSET) +#define AUDIOPLL_SPREAD_SPECTRUM (IMX9_AUDIOPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET) +#define AUDIOPLL_NUMERATOR (IMX9_AUDIOPLL_BASE + PLL_NUMERATOR_OFFSET) +#define AUDIOPLL_DENOMINATOR (IMX9_AUDIOPLL_BASE + PLL_DENOMINATOR_OFFSET) +#define AUDIOPLL_DIV (IMX9_AUDIOPLL_BASE + PLL_DIV_OFFSET) +#define AUDIOPLL_PLL_STATUS (IMX9_AUDIOPLL_BASE + PLL_PLL_STATUS_OFFSET) + +/* DRAMPLL registers */ + +#define DRAMPLL_CTRL (IMX9_AUDIOPLL_BASE + PLL_CTRL_OFFSET) +#define DRAMPLL_SPREAD_SPECTRUM (IMX9_AUDIOPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET) +#define DRAMPLL_NUMERATOR (IMX9_AUDIOPLL_BASE + PLL_NUMERATOR_OFFSET) +#define DRAMPLL_DENOMINATOR (IMX9_AUDIOPLL_BASE + PLL_DENOMINATOR_OFFSET) +#define DRAMPLL_DIV (IMX9_AUDIOPLL_BASE + PLL_DIV_OFFSET) +#define DRAMPLL_PLL_STATUS (IMX9_AUDIOPLL_BASE + PLL_PLL_STATUS_OFFSET) + +/* VIDEOPLL registers */ + +#define VIDEOPLL_CTRL (IMX9_VIDEOPLL_BASE + PLL_CTRL_OFFSET) +#define VIDEOPLL_SPREAD_SPECTRUM (IMX9_VIDEOPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET) +#define VIDEOPLL_NUMERATOR (IMX9_VIDEOPLL_BASE + PLL_NUMERATOR_OFFSET) +#define VIDEOPLL_DENOMINATOR (IMX9_VIDEOPLL_BASE + PLL_DENOMINATOR_OFFSET) +#define VIDEOPLL_DIV (IMX9_VIDEOPLL_BASE + PLL_DIV_OFFSET) +#define VIDEOPLL_PLL_STATUS (IMX9_VIDEOPLL_BASE + PLL_PLL_STATUS_OFFSET) + +/* PLL Control (CTRL) */ + +#define PLL_CTRL_POWERUP (1 << 0) /* Bit 0: Power up PLL */ +#define PLL_CTRL_CLKMUX_EN (1 << 1) /* Bit 1: Enable CLKMUX output */ +#define PLL_CTRL_CLKMUX_BYPASS (1 << 2) /* Bit 2: Enable CLKMUX bypass */ +#define PLL_CTRL_SPREADCTL (1 << 8) /* Bit 8: Modulation Type Select */ +#define PLL_CTRL_HW_CTRL_SEL (1 << 16) /* Bit 16: Hardware Control Select */ +#define PLL_CTRL_LOCK_BYPASS (1 << 31) /* Bit 31: Lock bypass */ + +/* Spread Spectrum (SPREAD_SPECTRUM) */ + +#define PLL_SPREAD_SPECTRUM_STEP_SHIFT (0) /* Bits 14-0: Set spread spectrum step */ +#define PLL_SPREAD_SPECTRUM_STEP_MASK (0x7fff << PLL_SPREAD_SPECTRUM_STEP_SHIFT) +#define PLL_SPREAD_SPECTRUM_STEP(n) (((n) << PLL_SPREAD_SPECTRUM_STEP_SHIFT) & PLL_SPREAD_SPECTRUM_STEP_MASK) +#define PLL_SPREAD_SPECTRUM_ENABLE (1 << 15) /* Bit 15: Enable spread spectrum */ +#define PLL_SPREAD_SPECTRUM_STOP_SHIFT (16) /* Bits 16-31: Set spread spectrum stop */ +#define PLL_SPREAD_SPECTRUM_STOP_MASK (0xffff << PLL_SPREAD_SPECTRUM_STOP_SHIFT) +#define PLL_SPREAD_SPECTRUM_STOP(n) (((n) << PLL_SPREAD_SPECTRUM_STOP_SHIFT) & PLL_SPREAD_SPECTRUM_STOP_MASK) + +/* Numerator (NUMERATOR) */ + +#define PLL_NUMERATOR_MFN_SHIFT (2) /* Bits 2-31: Numerator MFN value */ +#define PLL_NUMERATOR_MFN_MASK (0x3fffffff << PLL_NUMERATOR_MFN_SHIFT) +#define PLL_NUMERATOR_MFN(n) (((n) << PLL_NUMERATOR_MFN_SHIFT) & PLL_NUMERATOR_MFN_MASK) + +/* Denominator (DENOMINATOR) */ + +#define PLL_DENOMINATOR_MFD_SHIFT (0) /* Bits 0-29: Denominator MFD value */ +#define PLL_DENOMINATOR_MFD_MASK (0x3fffffff << PLL_DENOMINATOR_MFD_SHIFT) +#define PLL_DENOMINATOR_MFD(n) (((n) << PLL_DENOMINATOR_MFD_SHIFT) & PLL_DENOMINATOR_MFD_MASK) + +/* PLL Dividers (DIV) */ + +#define PLL_DIV_ODIV_SHIFT (0) /* Bits 0-7: Output Frequency Divider for Clock Output */ +#define PLL_DIV_ODIV_MASK (0xff << PLL_DIV_ODIV_SHIFT) +#define PLL_DIV_ODIV(n) (((n) << PLL_DIV_ODIV_SHIFT) & PLL_DIV_ODIV_MASK) +#define PLL_DIV_RDIV_SHIFT (13) /* Bits 13-15: Input Clock Predivider */ +#define PLL_DIV_RDIV_MASK (0x7 << PLL_DIV_RDIV_SHIFT) +#define PLL_DIV_RDIV(n) (((n) << PLL_DIV_RDIV_SHIFT) & PLL_DIV_RDIV_MASK) +#define PLL_DIV_MFI_SHIFT (16) /* Bits 16-24: Integer Portion of Loop Divider */ +#define PLL_DIV_MFI_MASK (0x1ff << PLL_DIV_MFI_SHIFT) +#define PLL_DIV_MFI(n) (((n) << PLL_DIV_MFI_SHIFT) & PLL_DIV_MFI_MASK) + +/* DFS Control (DFS_CTRL_0 - DFS_CTRL_2) */ + +#define PLL_DFS_HW_CTRL_SEL (1 << 16) /* Bit 16: Hardware Control Select */ +#define PLL_DFS_BYPASS_EN (1 << 23) /* Bit 23: Bypass Enable */ +#define PLL_DFS_CLKOUT_DIVBY2_EN (1 << 29) /* Bit 29: DFS Clock Output Divide by 2 Enable */ +#define PLL_DFS_CLKOUT_EN (1 << 30) /* Bit 30: DFS Clock Output Enable */ +#define PLL_DFS_ENABLE (1 << 31) /* Bit 31: DFS Block Enable */ + +/* DFS Division_a (DFS_DIV_0 - DFS_DIV_2) */ + +#define PLL_DFS_MFN_SHIFT (0) /* Bits 0-2: MFN */ +#define PLL_DFS_MFN_MASK (0x7 << PLL_DFS_MFN_SHIFT) +#define PLL_DFS_MFN(n) (((n) << PLL_DFS_MFN_SHIFT) & PLL_DFS_MFN_MASK) +#define PLL_DFS_MFI_SHIFT (8) /* Bits 8-15: MFI */ +#define PLL_DFS_MFI_MASK (0xff << PLL_DFS_MFI_SHIFT) +#define PLL_DFS_MFI(n) (((n) << PLL_DFS_MFI_SHIFT) & PLL_DFS_MFI_MASK) + +/* PLL Dividers (DIV) */ + +#define PLL_PLL_STATUS_PLL_LOCK (1 << 0) /* Bit 0: PLL is locked */ +#define PLL_PLL_STATUS_PLL_LOL (1 << 1) /* Bit 1: PLL lock is lost */ +#define PLL_PLL_STATUS_ANA_MFN_SHIFT (2) +#define PLL_PLL_STATUS_ANA_MFN_MASK (0x3fffffff << PLL_PLL_STATUS_ANA_MFN_SHIFT) +#define PLL_PLL_STATUS_ANA_MFN(n) (((n) << PLL_PLL_STATUS_ANA_MFN_SHIFT) & PLL_PLL_STATUS_ANA_MFN_MASK) + +/* DFS Status (DFS_STATUS) */ + +#define PLL_DFS_STATUS_DFS_OK_SHIFT (0) /* Bits 0-2: DFS OK status */ +#define PLL_DFS_STATUS_DFS_OK_MASK (0x7 << PLL_DFS_STATUS_DFS_OK_SHIFT) +#define PLL_DFS_STATUS_DFS_OK(n) (((n) << PLL_DFS_STATUS_DFS_OK_SHIFT) & PLL_DFS_STATUS_DFS_OK_MASK) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX93_IMX93_PLL_H_*/ diff --git a/arch/arm64/src/imx9/hardware/imx9_ccm.h b/arch/arm64/src/imx9/hardware/imx9_ccm.h new file mode 100644 index 0000000000000..f4a68a0a31514 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_ccm.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_ccm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_CCM_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_CCM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/imx9_memorymap.h" + +#if defined(CONFIG_ARCH_CHIP_IMX93) +# include "hardware/imx93/imx93_ccm.h" +# include "hardware/imx93/imx93_pll.h" +#else +# error Unrecognized i.MX9 architecture +#endif + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_CCM_H_ */ diff --git a/arch/arm64/src/imx9/hardware/imx9_dmamux.h b/arch/arm64/src/imx9/hardware/imx9_dmamux.h new file mode 100644 index 0000000000000..c9a7e6bbc9331 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_dmamux.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_dmamux.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_DMAMUX_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_DMAMUX_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_IMX93) +# include "hardware/imx93/imx93_dmamux.h" +#else +# error Unrecognized i.MX9 architecture +#endif + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_DMAMUX_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_edma.h b/arch/arm64/src/imx9/hardware/imx9_edma.h new file mode 100644 index 0000000000000..d08610e7b5e1f --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_edma.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_edma.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_EDMA_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_EDMA_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_IMX93) +# include "hardware/imx93/imx93_edma.h" +#else +# error Unrecognized i.MX9 architecture +#endif + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_EDMA_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_enet.h b/arch/arm64/src/imx9/hardware/imx9_enet.h new file mode 100644 index 0000000000000..67a7493722d5b --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_enet.h @@ -0,0 +1,646 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_enet.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_ENET_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_ENET_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define IMX9_ENET_EIR_OFFSET 0x0004 /* Interrupt Event Register */ +#define IMX9_ENET_EIMR_OFFSET 0x0008 /* Interrupt Mask Register */ +#define IMX9_ENET_RDAR_OFFSET 0x0010 /* Receive Descriptor Active Register */ +#define IMX9_ENET_TDAR_OFFSET 0x0014 /* Transmit Descriptor Active Register */ +#define IMX9_ENET_ECR_OFFSET 0x0024 /* Ethernet Control Register */ +#define IMX9_ENET_MMFR_OFFSET 0x0040 /* MII Management Frame Register */ +#define IMX9_ENET_MSCR_OFFSET 0x0044 /* MII Speed Control Register */ +#define IMX9_ENET_MIBC_OFFSET 0x0064 /* MIB Control Register */ +#define IMX9_ENET_RCR_OFFSET 0x0084 /* Receive Control Register */ +#define IMX9_ENET_TCR_OFFSET 0x00c4 /* Transmit Control Register */ +#define IMX9_ENET_PALR_OFFSET 0x00e4 /* Physical Address Lower Register */ +#define IMX9_ENET_PAUR_OFFSET 0x00e8 /* Physical Address Upper Register */ +#define IMX9_ENET_OPD_OFFSET 0x00ec /* Opcode/Pause Duration Register */ +#define IMX9_ENET_TXIC_OFFSET 0x00f0 /* Transmit Interrupt Coalescing Register */ +#define IMX9_ENET_RXIC_OFFSET 0x0100 /* Receive Interrupt Coalescing Register */ +#define IMX9_ENET_IAUR_OFFSET 0x0118 /* Descriptor Individual Upper Address Register */ +#define IMX9_ENET_IALR_OFFSET 0x011c /* Descriptor Individual Lower Address Register */ +#define IMX9_ENET_GAUR_OFFSET 0x0120 /* Descriptor Group Upper Address Register */ +#define IMX9_ENET_GALR_OFFSET 0x0124 /* Descriptor Group Lower Address Register */ +#define IMX9_ENET_TFWR_OFFSET 0x0144 /* Transmit FIFO Watermark Register */ +#define IMX9_ENET_RDSR1_OFFSET 0x0160 /* Receive Descriptor Ring 1 Start Register */ +#define IMX9_ENET_TDSR1_OFFSET 0x0164 /* Transmit Buffer Descriptor Ring 1 Start Register */ +#define IMX9_ENET_MRBR1_OFFSET 0x0168 /* Maximum Receive Buffer Size Register - Ring 1 */ +#define IMX9_ENET_RDSR2_OFFSET 0x0170 /* Receive Descriptor Ring 2 Start Register */ +#define IMX9_ENET_TDSR2_OFFSET 0x0174 /* Transmit Buffer Descriptor Ring 2 Start Register */ +#define IMX9_ENET_MRBR2_OFFSET 0x0178 /* Maximum Receive Buffer Size Register - Ring 2 */ +#define IMX9_ENET_RDSR_OFFSET 0x0180 /* Receive Descriptor Ring Start Register */ +#define IMX9_ENET_TDSR_OFFSET 0x0184 /* Transmit Buffer Descriptor Ring Start Register */ +#define IMX9_ENET_MRBR_OFFSET 0x0188 /* Maximum Receive Buffer Size Register */ +#define IMX9_ENET_RSFL_OFFSET 0x0190 /* Receive FIFO Section Full Threshold */ +#define IMX9_ENET_RSEM_OFFSET 0x0194 /* Receive FIFO Section Empty Threshold */ +#define IMX9_ENET_RAEM_OFFSET 0x0198 /* Receive FIFO Almost Empty Threshold */ +#define IMX9_ENET_RAFL_OFFSET 0x019c /* Receive FIFO Almost Full Threshold */ +#define IMX9_ENET_TSEM_OFFSET 0x01a0 /* Transmit FIFO Section Empty Threshold */ +#define IMX9_ENET_TAEM_OFFSET 0x01a4 /* Transmit FIFO Almost Empty Threshold */ +#define IMX9_ENET_TAFL_OFFSET 0x01a8 /* Transmit FIFO Almost Full Threshold */ +#define IMX9_ENET_TIPG_OFFSET 0x01ac /* Transmit Inter-Packet Gap */ +#define IMX9_ENET_FTRL_OFFSET 0x01b0 /* Frame Truncation Length */ +#define IMX9_ENET_TACC_OFFSET 0x01c0 /* Transmit Accelerator Function Configuration */ +#define IMX9_ENET_RACC_OFFSET 0x01c4 /* Receive Accelerator Function Configuration */ + +#define IMX9_ENET_ATCR_OFFSET 0x0400 /* Timer Control Register */ +#define IMX9_ENET_ATVR_OFFSET 0x0404 /* Timer Value Register */ +#define IMX9_ENET_ATOFF_OFFSET 0x0408 /* Timer Offset Register */ +#define IMX9_ENET_ATPER_OFFSET 0x040c /* Timer Period Register */ +#define IMX9_ENET_ATCOR_OFFSET 0x0410 /* Timer Correction Register */ +#define IMX9_ENET_ATINC_OFFSET 0x0414 /* Time-Stamping Clock Period Register */ +#define IMX9_ENET_ATSTMP_OFFSET 0x0418 /* Timestamp of Last Transmitted Frame */ + +#define IMX9_ENET_TGSR_OFFSET 0x0604 /* Timer Global Status Register */ +#define IMX9_ENET_TCSR0_OFFSET 0x0608 /* Timer Control Status Register */ +#define IMX9_ENET_TCCR0_OFFSET 0x060c /* Timer Compare Capture Register */ +#define IMX9_ENET_TCSR1_OFFSET 0x0610 /* Timer Control Status Register */ +#define IMX9_ENET_TCCR1_OFFSET 0x0614 /* Timer Compare Capture Register */ +#define IMX9_ENET_TCSR2_OFFSET 0x0618 /* Timer Control Status Register */ +#define IMX9_ENET_TCCR2_OFFSET 0x061c /* Timer Compare Capture Register */ +#define IMX9_ENET_TCSR3_OFFSET 0x0620 /* Timer Control Status Register */ +#define IMX9_ENET_TCCR3_OFFSET 0x0624 /* Timer Compare Capture Register */ + +/* Register Addresses *******************************************************/ + +#define IMX9_ENET_EIR (IMX9_ENET_BASE+IMX9_ENET_EIR_OFFSET) +#define IMX9_ENET_EIMR (IMX9_ENET_BASE+IMX9_ENET_EIMR_OFFSET) +#define IMX9_ENET_RDAR (IMX9_ENET_BASE+IMX9_ENET_RDAR_OFFSET) +#define IMX9_ENET_TDAR (IMX9_ENET_BASE+IMX9_ENET_TDAR_OFFSET) +#define IMX9_ENET_ECR (IMX9_ENET_BASE+IMX9_ENET_ECR_OFFSET) +#define IMX9_ENET_MMFR (IMX9_ENET_BASE+IMX9_ENET_MMFR_OFFSET) +#define IMX9_ENET_MSCR (IMX9_ENET_BASE+IMX9_ENET_MSCR_OFFSET) +#define IMX9_ENET_MIBC (IMX9_ENET_BASE+IMX9_ENET_MIBC_OFFSET) +#define IMX9_ENET_RCR (IMX9_ENET_BASE+IMX9_ENET_RCR_OFFSET) +#define IMX9_ENET_TCR (IMX9_ENET_BASE+IMX9_ENET_TCR_OFFSET) +#define IMX9_ENET_PALR (IMX9_ENET_BASE+IMX9_ENET_PALR_OFFSET) +#define IMX9_ENET_PAUR (IMX9_ENET_BASE+IMX9_ENET_PAUR_OFFSET) +#define IMX9_ENET_OPD (IMX9_ENET_BASE+IMX9_ENET_OPD_OFFSET) +#define IMX9_ENET_IAUR (IMX9_ENET_BASE+IMX9_ENET_IAUR_OFFSET) +#define IMX9_ENET_IALR (IMX9_ENET_BASE+IMX9_ENET_IALR_OFFSET) +#define IMX9_ENET_GAUR (IMX9_ENET_BASE+IMX9_ENET_GAUR_OFFSET) +#define IMX9_ENET_GALR (IMX9_ENET_BASE+IMX9_ENET_GALR_OFFSET) +#define IMX9_ENET_TFWR (IMX9_ENET_BASE+IMX9_ENET_TFWR_OFFSET) +#define IMX9_ENET_RDSR (IMX9_ENET_BASE+IMX9_ENET_RDSR_OFFSET) +#define IMX9_ENET_TDSR (IMX9_ENET_BASE+IMX9_ENET_TDSR_OFFSET) +#define IMX9_ENET_MRBR (IMX9_ENET_BASE+IMX9_ENET_MRBR_OFFSET) +#define IMX9_ENET_RSFL (IMX9_ENET_BASE+IMX9_ENET_RSFL_OFFSET) +#define IMX9_ENET_RSEM (IMX9_ENET_BASE+IMX9_ENET_RSEM_OFFSET) +#define IMX9_ENET_RAEM (IMX9_ENET_BASE+IMX9_ENET_RAEM_OFFSET) +#define IMX9_ENET_RAFL (IMX9_ENET_BASE+IMX9_ENET_RAFL_OFFSET) +#define IMX9_ENET_TSEM (IMX9_ENET_BASE+IMX9_ENET_TSEM_OFFSET) +#define IMX9_ENET_TAEM (IMX9_ENET_BASE+IMX9_ENET_TAEM_OFFSET) +#define IMX9_ENET_TAFL (IMX9_ENET_BASE+IMX9_ENET_TAFL_OFFSET) +#define IMX9_ENET_TIPG (IMX9_ENET_BASE+IMX9_ENET_TIPG_OFFSET) +#define IMX9_ENET_FTRL (IMX9_ENET_BASE+IMX9_ENET_FTRL_OFFSET) +#define IMX9_ENET_TACC (IMX9_ENET_BASE+IMX9_ENET_TACC_OFFSET) +#define IMX9_ENET_RACC (IMX9_ENET_BASE+IMX9_ENET_RACC_OFFSET) + +#define IMX9_ENET_ATCR (IMX9_ENET_BASE+IMX9_ENET_ATCR_OFFSET) +#define IMX9_ENET_ATVR (IMX9_ENET_BASE+IMX9_ENET_ATVR_OFFSET) +#define IMX9_ENET_ATOFF (IMX9_ENET_BASE+IMX9_ENET_ATOFF_OFFSET) +#define IMX9_ENET_ATPER (IMX9_ENET_BASE+IMX9_ENET_ATPER_OFFSET) +#define IMX9_ENET_ATCOR (IMX9_ENET_BASE+IMX9_ENET_ATCOR_OFFSET) +#define IMX9_ENET_ATINC (IMX9_ENET_BASE+IMX9_ENET_ATINC_OFFSET) +#define IMX9_ENET_ATSTMP (IMX9_ENET_BASE+IMX9_ENET_ATSTMP_OFFSET) + +#define IMX9_ENET_TGSR (IMX9_ENET_BASE+IMX9_ENET_TGSR_OFFSET) +#define IMX9_ENET_TCSR0 (IMX9_ENET_BASE+IMX9_ENET_TCSR0_OFFSET) +#define IMX9_ENET_TCCR0 (IMX9_ENET_BASE+IMX9_ENET_TCCR0_OFFSET) +#define IMX9_ENET_TCSR1 (IMX9_ENET_BASE+IMX9_ENET_TCSR1_OFFSET) +#define IMX9_ENET_TCCR1 (IMX9_ENET_BASE+IMX9_ENET_TCCR1_OFFSET) +#define IMX9_ENET_TCSR2 (IMX9_ENET_BASE+IMX9_ENET_TCSR2_OFFSET) +#define IMX9_ENET_TCCR2 (IMX9_ENET_BASE+IMX9_ENET_TCCR2_OFFSET) +#define IMX9_ENET_TCSR3 (IMX9_ENET_BASE+IMX9_ENET_TCSR3_OFFSET) +#define IMX9_ENET_TCCR3 (IMX9_ENET_BASE+IMX9_ENET_TCCR3_OFFSET) + +/* Register Bit Definitions *************************************************/ + +/* Interrupt Event Register, Interrupt Mask Register */ + +#define ENET_RXB1 (1 << 0) /* Receive buffer interrupt, class 1 */ +#define ENET_RXF1 (1 << 1) /* Receive frame interrupt, class 1 */ +#define ENET_TXB1 (1 << 2) /* Transmit buffer interrupt, class 1 */ +#define ENET_TXF1 (1 << 3) /* Transmit frame interrupt, class 1 */ +#define ENET_RXB2 (1 << 4) /* Receive buffer interrupt, class 2 */ +#define ENET_RXF2 (1 << 5) /* Receive frame interrupt, class 2 */ +#define ENET_TXB2 (1 << 6) /* Transmit buffer interrupt, class 2 */ +#define ENET_TXF2 (1 << 7) /* Transmit frame interrupt, class 2 */ +#define ENET_RXFLUSH_0 (1 << 12) /* RX DMA Ring 0 flush indication */ +#define ENET_RXFLUSH_1 (1 << 13) /* RX DMA Ring 1 flush indication */ +#define ENET_RXFLUSH_2 (1 << 14) /* RX DMA Ring 2 flush indication */ +#define ENET_INT_TS_TIMER (1 << 15) /* Bit 15: Timestamp timer */ +#define ENET_INT_TS_AVAIL (1 << 16) /* Bit 16: Transmit timestamp available */ +#define ENET_INT_WAKEUP (1 << 17) /* Bit 17: Node wake-up request indication */ +#define ENET_INT_PLR (1 << 18) /* Bit 18: Payload receive error */ +#define ENET_INT_UN (1 << 19) /* Bit 19: Transmit FIFO underrun */ +#define ENET_INT_RL (1 << 20) /* Bit 20: Collision Retry Limit */ +#define ENET_INT_LC (1 << 21) /* Bit 21: Late Collision */ +#define ENET_INT_EBERR (1 << 22) /* Bit 22: Ethernet Bus Error */ +#define ENET_INT_MII (1 << 23) /* Bit 23: MII Interrupt */ +#define ENET_INT_RXB (1 << 24) /* Bit 24: Receive Buffer Interrupt */ +#define ENET_INT_RXF (1 << 25) /* Bit 25: Receive Frame Interrupt */ +#define ENET_INT_TXB (1 << 26) /* Bit 26: Transmit Buffer Interrupt */ +#define ENET_INT_TXF (1 << 27) /* Bit 27: Transmit Frame Interrupt */ +#define ENET_INT_GRA (1 << 28) /* Bit 28: Graceful Stop Complete */ +#define ENET_INT_BABT (1 << 29) /* Bit 29: Babbling Transmit Error */ +#define ENET_INT_BABR (1 << 30) /* Bit 30: Babbling Receive Error */ + /* Bit 31: Reserved */ + +/* Receive Descriptor Active Register */ + + /* Bits 0-23: Reserved */ +#define ENET_RDAR (1 << 24) /* Bit 24: Receive descriptor active */ + /* Bits 25-31: Reserved */ + +/* Transmit Descriptor Active Register */ + + /* Bits 0-23: Reserved */ +#define ENET_TDAR (1 << 24) /* Bit 24: Transmit descriptor active */ + /* Bits 25-31: Reserved */ + +/* Ethernet Control Register */ + +#define ENET_ECR_RESET (1 << 0) /* Bit 0: Ethernet MAC reset */ +#define ENET_ECR_ETHEREN (1 << 1) /* Bit 1: Ethernet enable */ +#define ENET_ECR_MAGICEN (1 << 2) /* Bit 2: Magic packet detection enable */ +#define ENET_ECR_SLEEP (1 << 3) /* Bit 3: Sleep mode enable */ +#define ENET_ECR_EN1588 (1 << 4) /* Bit 4: EN1588 enable */ +#define ENET_ECR_SPEED (1 << 5) /* Bit 5: 10/100-Mbit/s or 1000-Mbit/s mode */ +#define ENET_ECR_DBGEN (1 << 6) /* Bit 6: Debug enable */ + /* Bit 7: Reserved, always write 0 */ +#define ENET_ECR_DBSWP (1 << 8) /* Bit 8: Swap bytes; always write 1 after reset */ +#define ENET_ECR_SVLANEN (1 << 9) /* Bit 9: S-VLAN enable */ +#define ENET_ECR_VLANUSE2ND (1 << 10) /* Bit 10: VLAN use second tag */ +#define ENET_ECR_SVLANDBL (1 << 11) /* Bit 11: S-VLAN double tag */ +#define ENET_ECR_TXC_DLY (1 << 16) /* Bit 16: Transmit clock delay */ +#define ENET_ECR_RXC_DLY (1 << 17) /* Bit 17: Receive clock delay */ + /* Bits 12-15: Reserved, always write 0 */ +#define ENET_ECR_RESV_MASK (0x3ffff << 18) /* Reserved, always write 0x1c00 */ + +/* MII Management Frame Register */ + +#define ENET_MMFR_DATA_SHIFT (0) /* Bits 0-15: Management frame data */ +#define ENET_MMFR_DATA_MASK (0xffff << ENET_MMFR_DATA_SHIFT) +#define ENET_MMFR_TA_SHIFT (16) /* Bits 16-17: Turn around */ +#define ENET_MMFR_TA_MASK (0x3 << ENET_MMFR_TA_SHIFT) +#define ENET_MMFR_RA_SHIFT (18) /* Bits 18-22: Register address */ +#define ENET_MMFR_RA_MASK (0x1f << ENET_MMFR_RA_SHIFT) +#define ENET_MMFR_PA_SHIFT (23) /* Bits 23-27: PHY address */ +#define ENET_MMFR_PA_MASK (0x1f << ENET_MMFR_PA_SHIFT) +#define ENET_MMFR_OP_SHIFT (28) /* Bits 28-29: Operation code */ +#define ENET_MMFR_OP_MASK (0x3 << ENET_MMFR_OP_SHIFT) +# define ENET_MMFR_OP_WRNOTMII (0 << ENET_MMFR_OP_SHIFT) /* Write frame, not MII compliant */ +# define ENET_MMFR_OP_WRMII (1 << ENET_MMFR_OP_SHIFT) /* Write frame, MII management frame */ +# define ENET_MMFR_OP_RDMII (2 << ENET_MMFR_OP_SHIFT) /* Read frame, MII management frame */ +# define ENET_MMFR_OP_RDNOTMII (3 << ENET_MMFR_OP_SHIFT) /* Read frame, not MII compliant */ + +#define ENET_MMFR_ST_SHIFT (30) /* Bits 30-31: Start of frame delimiter */ +#define ENET_MMFR_ST_MASK (0x3 << ENET_MMFR_ST_SHIFT) + +/* MII Speed Control Register */ + + /* Bit 0: Reserved */ +#define ENET_MSCR_MII_SPEED_SHIFT (1) /* Bits 1-6: MII speed */ +#define ENET_MSCR_MII_SPEED_MASK (0x3f << ENET_MSCR_MII_SPEED_SHIFT) +# define ENET_MSCR_MII_SPEED_25MHz (0x4) /* Optimum value for IPS bus 25 MHz clock */ +# define ENET_MSCR_MII_SPEED_33MHz (0x6) /* Optimum value for IPS bus 33 MHz clock */ +# define ENET_MSCR_MII_SPEED_40MHz (0x7) /* Optimum value for IPS bus 40 MHz clock */ +# define ENET_MSCR_MII_SPEED_50MHz (0x9) /* Optimum value for IPS bus 50 MHz clock */ +# define ENET_MSCR_MII_SPEED_66MHz (0xd) /* Optimum value for IPS bus 60 MHz clock */ +#define ENET_MSCR_DIS_PRE (1 << 7) /* Bit 7: Disable preamble */ +#define ENET_MSCR_HOLDTIME_SHIFT (8) /* Bits 8-10: Holdtime on MDIO output */ +#define ENET_MSCR_HOLDTIME_MASK (0x7 << ENET_MSCR_HOLDTIME_SHIFT) +# define ENET_MSCR_HOLDTIME_1CYCLE (0 << ENET_MSCR_HOLDTIME_SHIFT) /* 1 internal module clock cycle */ +# define ENET_MSCR_HOLDTIME_2CYCLES (1 << ENET_MSCR_HOLDTIME_SHIFT) /* 2 internal module clock cycles */ +# define ENET_MSCR_HOLDTIME_3CYCLES (2 << ENET_MSCR_HOLDTIME_SHIFT) /* 3 internal module clock cycles */ +# define ENET_MSCR_HOLDTIME_8CYCLES (7 << ENET_MSCR_HOLDTIME_SHIFT) /* 8 internal module clock cycles */ + +/* MIB Control Register */ + + /* Bits 0-28: Reserved */ +#define ENET_MIBC_MIB_CLEAR (1 << 29) /* Bit 29: MIB clear */ +#define ENET_MIBC_MIB_IDLE (1 << 30) /* Bit 30: MIB idle */ +#define ENET_MIBC_MIB_DIS (1 << 31) /* Bit 31: Disable MIB logic */ + +/* Receive Control Register */ + +#define ENET_RCR_LOOP (1 << 0) /* Bit 0: Internal loopback */ +#define ENET_RCR_DRT (1 << 1) /* Bit 1: Disable receive on transmit */ +#define ENET_RCR_MII_MODE (1 << 2) /* Bit 2: Media independent interface mode */ +#define ENET_RCR_PROM (1 << 3) /* Bit 3: Promiscuous mode */ +#define ENET_RCR_BC_REJ (1 << 4) /* Bit 4: Broadcast frame reject */ +#define ENET_RCR_FCE (1 << 5) /* Bit 5: Flow control enable */ +#define ENET_RCR_RGMII_EN (1 << 6) /* Bit 6: RGMII mode enable */ + /* Bit 7: Reserved */ +#define ENET_RCR_RMII_MODE (1 << 8) /* Bit 8: RGMII mode enable */ +#define ENET_RCR_RMII_10T (1 << 9) /* Bit 9: Enables 10-Mbps mode of the RMII */ + /* Bits 10-11: Reserved */ +#define ENET_RCR_PADEN (1 << 12) /* Bit 12: Enable frame padding remove on receive */ +#define ENET_RCR_PAUFWD (1 << 13) /* Bit 13: Terminate/forward pause frames */ +#define ENET_RCR_CRCFWD (1 << 14) /* Bit 14: Terminate/forward received CRC */ +#define ENET_RCR_CFEN (1 << 15) /* Bit 15: MAC control frame enable */ +#define ENET_RCR_MAX_FL_SHIFT (16) /* Bits 16-29: Maximum frame length */ +#define ENET_RCR_MAX_FL_MASK (0x3fff << ENET_RCR_MAX_FL_SHIFT) +#define ENET_RCR_NLC (1 << 30) /* Bit 30: Payload length check disable */ +#define ENET_RCR_GRS (1 << 31) /* Bit 31: Graceful receive stopped */ + +/* Transmit Control Register */ + +#define ENET_TCR_GTS (1 << 0) /* Bit 0: Graceful transmit stop */ + /* Bit 1: Reserved */ +#define ENET_TCR_FDEN (1 << 2) /* Bit 2: Full duplex enable */ +#define ENET_TCR_TFC_PAUSE (1 << 3) /* Bit 3: Transmit frame control pause */ +#define ENET_TCR_RFC_PAUSE (1 << 4) /* Bit 4: Receive frame control pause */ +#define ENET_TCR_ADDSEL_SHIFT (5) /* Bits 5-7: Source MAC address select on transmit */ +#define ENET_TCR_ADDSEL_MASK (0x7 << ENET_TCR_ADDSEL_SHIFT) +#define ENET_TCR_ADDSEL_PADDR12 (0 << ENET_TCR_ADDSEL_SHIFT) +#define ENET_TCR_ADDINS (1 << 8) /* Bit 8: Set MAC address on transmit */ +#define ENET_TCR_CRCFWD (1 << 9) /* Bit 9: Forward frame from application with CRC */ + /* Bits 10-31: Reserved, 10 must be written to 0 */ + +/* Physical Address Lower/Upper Register (32-bits of 48-address) */ + +/* Physical Address Upper Register */ + +#define ENET_PAUR_TYPE_SHIFT (0) /* Bits 0-15: Type field in PAUSE frame */ +#define ENET_PAUR_TYPE_MASK (0xffff << ENET_PAUR_TYPE_MASK) +#define ENET_PAUR_PADDR2_SHIFT (16) /* Bits 16-31: Bytes 4 and 5 of the 6-byte address */ +#define ENET_PAUR_PADDR2_MASK (0xffff << ENET_PAUR_PADDR2_SHIFT) + +/* Opcode/Pause Duration Register */ + +#define ENET_OPD_PAUSE_DUR_SHIFT (0) /* Bits 0-15: Pause duration */ +#define ENET_OPD_PAUSE_DUR_MASK (0xffff << ENET_OPD_PAUSE_DUR_SHIFT) +#define ENET_OPD_OPCODE_SHIFT (16) /* Bits 16-31: Opcode field in PAUSE frames */ +#define ENET_OPD_OPCODE_MASK (0xffff << ENET_OPD_OPCODE_SHIFT) + +/* Descriptor Individual Upper/Lower Address Register + * (64-bit address in two 32-bit registers) + */ + +/* Descriptor Group Upper/Lower Address Register + * (64-bit address in two 32-bit registers) + */ + +/* Transmit Interrupt Coalescing Register */ + +#define ENET_TXIC_ICTT_SHIFT (0) /* Bits 0-15: Interrupt coalescing timer threshold */ +#define ENET_TXIC_ICTT_SHIFT_MASK (0xffff << ENET_TXIC_ICTT_SHIFT) + /* Bits 16-19: Reserved */ +#define ENET_TXIC_ICFT_SHIFT (20) /* Bits 0-15: Interrupt coalescing timer threshold */ +#define ENET_TXIC_ICFT_SHIFT_MASK (0xff << ENET_TXIC_ICFT_SHIFT) +#define ENET_TXIC_ICTT_ICCS (1 << 30) /* Bit 30: Interrupt Coalescing Timer Clock Source Select */ +#define ENET_TXIC_ICTT_ICEN (1 << 31) /* Bit 31: Eable/disabel Interrupt Coalescing */ + +/* Receive Interrupt Coalescing Register */ + +#define ENET_RXIC_ICTT_SHIFT (0) /* Bits 0-15: Interrupt coalescing timer threshold */ +#define ENET_RXIC_ICTT_SHIFT_MASK (0xffff << ENET_TXIC_ICTT_SHIFT) + /* Bits 16-19: Reserved */ +#define ENET_RXIC_ICFT_SHIFT (20) /* Bits 0-15: Interrupt coalescing timer threshold */ +#define ENET_RXIC_ICFT_SHIFT_MASK (0xff << ENET_TXIC_ICFT_SHIFT) +#define ENET_RXIC_ICTT_ICCS (1 << 30) /* Bit 30: Interrupt Coalescing Timer Clock Source Select */ +#define ENET_RXIC_ICTT_ICEN (1 << 31) /* Bit 31: Eable/disabel Interrupt Coalescing */ + +/* Transmit FIFO Watermark Register */ + +#define ENET_TFWR_TFWR_SHIFT (0) /* Bits 0-5: Transmit FIFO write */ + /* Bits 6-7: Reserved */ +#define ENET_TFWR_TFWR_MASK (0x3f << ENET_TFWR_TFWR_SHIFT) +#define ENET_TFWR_STRFWD (1 << 8) /* Bit 8: Store and forward enable */ + /* Bits 9-31: Reserved */ + +/* Receive Descriptor Ring Start Register */ + + /* Bits 0-2: Reserved */ +#define ENET_RDSR_SHIFT (3) /* Bits 3-31: Start of the receive buffer descriptor queue */ +#define ENET_RDSR_MASK (0xfffffff8) + +/* Transmit Buffer Descriptor Ring Start Register */ + + /* Bits 0-2: Reserved */ +#define ENET_TDSR_SHIFT (3) /* Bits 3-31: Start of the transmit buffer descriptor queue */ +#define ENET_TDSR_MASK (0xfffffff8) + +/* Maximum Receive Buffer Size Register */ + + /* Bits 14-31: Reserved */ +#define ENET_MRBR_SHIFT (4) /* Bits 4-13: Receive buffer size in bytes */ +#define ENET_MRBR_MASK (0x3ff << ENET_MRBR_SHIFT) + /* Bits 0-3: Reserved */ + +/* Receive FIFO Section Full Threshold */ + + /* Bits 10-31: Reserved */ +#define ENET_RSFL_SHIFT (0) /* Bits 0-9: Value of receive FIFO section full threshold */ +#define ENET_RSFL_MASK (0x3ff << ENET_RSFL_SHIFT) + +/* Receive FIFO Section Empty Threshold */ + +#define ENET_RSEM_RX_EMPTY_SHIFT (0) /* Bits 0-9: Value of the receive FIFO section empty threshold */ +#define ENET_RSEM_RX_EMPTY_MASK (0x3ff << ENET_RSEM_RX_EMPTY_SHIFT) + /* Bits 10-15: Reserved */ +#define ENET_RSEM_SEC_EMPTY_SHIFT (16) /* Bits 16-20: RX Status FIFO Section Empty Threshold */ +#define ENET_RSEM_SEC_EMPTY_MASK (0x1f << ENET_RSEM_SEC_EMPTY_SHIFT) + +/* Receive FIFO Almost Empty Threshold */ + +#define ENET_RAEM_SHIFT (0) /* Bits 0-9: Value of the receive FIFO almost empty threshold */ +#define ENET_RAEM_MASK (0x3ff << ENET_RAEM_SHIFT) + /* Bits 10-31: Reserved */ + +/* Receive FIFO Almost Full Threshold */ + +#define ENET_RAFL_SHIFT (0) /* Bits 0-9: Value of the receive FIFO almost full threshold */ +#define ENET_RAFL_MASK (0x3ff << ENET_RAFL_SHIFT) + /* Bits 10-31: Reserved */ + +/* Transmit FIFO Section Empty Threshold */ + +#define ENET_TSEM_SHIFT (0) /* Bits 0-9: Value of the transmit FIFO section empty threshold */ +#define ENET_TSEM_MASK (0x3ff << ENET_TSEM_SHIFT) + /* Bits 10-31: Reserved */ + +/* Transmit FIFO Almost Empty Threshold */ + +#define ENET_TAEM_SHIFT (0) /* Bits 0-9: Value of the transmit FIFO section empty threshold */ +#define ENET_TAEM_MASK (0x3ff << ENET_TAEM_SHIFT) + /* Bits 10-31: Reserved */ + +/* Transmit FIFO Almost Full Threshold */ + +#define ENET_TAFL_SHIFT (0) /* Bits 0-9: Value of the transmit FIFO section empty threshold */ +#define ENET_TAFL_MASK (0x3ff << ENET_TAFL_SHIFT) + /* Bits 10-31: Reserved */ + +/* Transmit Inter-Packet Gap */ + +#define ENET_TIPG_SHIFT (0) /* Bits 0-4: Value of the transmit FIFO section empty threshold */ +#define ENET_TIPG_MASK (0x1f << ENET_TIPG_SHIFT) + /* Bits 5-31: Reserved */ + +/* Frame Truncation Length */ + +#define ENET_FTRL_SHIFT (0) /* Bits 0-13: Value of the transmit FIFO section empty threshold */ +#define ENET_FTRL_MASK (0x3fff << ENET_FTRL_SHIFT) + /* Bits 14-31: Reserved */ + +/* Transmit Accelerator Function Configuration */ + +#define ENET_TACC_SHIFT16 (1 << 0) /* Bit 0: TX FIFO shift-16 */ + /* Bits 1-2: Reserved */ +#define ENET_TACC_IPCHK (1 << 3) /* Bit 3: Enables insertion of IP header checksum */ +#define ENET_TACC_PROCHK (1 << 4) /* Bit 4: Enables insertion of protocol checksum */ + /* Bits 5-31: Reserved */ + +/* Receive Accelerator Function Configuration */ + +#define ENET_RACC_PADREM (1 << 0) /* Bit 0: Enable padding removal for short IP frames */ +#define ENET_RACC_IPDIS (1 << 1) /* Bit 1: Enable discard of frames with wrong IPv4 header checksum */ +#define ENET_RACC_PRODIS (1 << 2) /* Bit 2: Enable discard of frames with wrong protocol checksum */ + /* Bits 3-5: Reserved */ +#define ENET_RACC_LINEDIS (1 << 6) /* Bit 6: Enable discard of frames with MAC layer errors */ +#define ENET_RACC_SHIFT16 (1 << 7) /* Bit 7: RX FIFO shift-16 */ + /* Bits 8-31: Reserved */ + +/* Timer Control Register */ + +#define ENET_ATCR_EN (1 << 0) /* Bit 0: Enable timer */ + /* Bit 1: Reserved */ +#define ENET_ATCR_OFFEN (1 << 2) /* Bit 2: Enable one-shot offset event */ +#define ENET_ATCR_OFFRST (1 << 3) /* Bit 3: Reset timer on offset event */ +#define ENET_ATCR_PEREN (1 << 4) /* Bit 4: Enable periodical event */ + /* Bits 5-6: Reserved */ +#define ENET_ATCR_PINPER (1 << 7) /* Bit 7: Enables event signal output assertion on period event */ + /* Bit 8: Reserved */ +#define ENET_ATCR_RESTART (1 << 9) /* Bit 9: Reset timer */ + /* Bit 10: Reserved */ +#define ENET_ATCR_CAPTURE (1 << 11) /* Bit 11: Capture timer value */ + /* Bit 12: Reserved */ +#define ENET_ATCR_SLAVE (1 << 13) /* Bit 13: Enable timer slave mode */ + /* Bits 14-31: Reserved */ + +/* Timer Value Register (32-bit timer value) */ + +/* Timer Offset Register (32-bit offset value) */ + +/* Timer Period Register (32-bit timer period) */ + +/* Timer Correction Register */ + +#define ENET_ATCOR_MASK (0x7fffffff) /* Bits 0-3: Correction counter wrap-around value */ + /* Bit 31: Reserved */ + +/* Time-Stamping Clock Period Register */ + +#define ENET_ATINC_INC_SHIFT (0) /* Bits 0-6: Clock period of the timestamping clock (ts_clk) in nanoseconds */ +#define ENET_ATINC_INC_MASK (0x7f << ENET_ATINC_INC_SHIFT) + /* Bit 7: Reserved */ +#define ENET_ATINC_INC_CORR_SHIFT (8) /* Bits 8-14: Correction increment value */ +#define ENET_ATINC_INC_CORR_MASK (0x7f << ENET_ATINC_INC_CORR_SHIFT) + /* Bits 15-31: Reserved */ + +/* Timestamp of Last Transmitted Frame (32-bit timestamp) */ + +/* Timer Global Status Register */ + +#define ENET_TGSR_TF0 (1 << 0) /* Bit 0: Copy of Timer Flag for channel 0 */ +#define ENET_TGSR_TF1 (1 << 1) /* Bit 1: Copy of Timer Flag for channel 1 */ +#define ENET_TGSR_TF2 (1 << 2) /* Bit 2: Copy of Timer Flag for channel 2 */ +#define ENET_TGSR_TF3 (1 << 3) /* Bit 3: Copy of Timer Flag for channel 3 */ + /* Bits 4-31: Reserved */ + +/* Timer Control Status Register n */ + +#define ENET_TCSR_TDRE (1 << 0) /* Bit 0: Timer DMA Request Enable */ + /* Bit 1: Reserved */ +#define ENET_TCSR_TMODE_SHIFT (2) /* Bits 2-5: Timer Mode */ +#define ENET_TCSR_TMODE_MASK (0xf << ENET_TCSR_TMODE_SHIFT) +# define ENET_TCSR_TMODE_DISABLED (0 << ENET_TCSR_TMODE_SHIFT) /* Disabled */ +# define ENET_TCSR_TMODE_ICRISING (1 << ENET_TCSR_TMODE_SHIFT) /* Input Capture on rising edge */ +# define ENET_TCSR_TMODE_ICFALLLING (2 << ENET_TCSR_TMODE_SHIFT) /* Input Capture on falling edge */ +# define ENET_TCSR_TMODE_ICBOTH (3 << ENET_TCSR_TMODE_SHIFT) /* Input Capture on both edges */ +# define ENET_TCSR_TMODE_OCSW (4 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, S/W only */ +# define ENET_TCSR_TMODE_OCTOGGLE (5 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, toggle on compare */ +# define ENET_TCSR_TMODE_OCCLR (6 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, clear on compare */ +# define ENET_TCSR_TMODE_OCSET (7 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, set on compare */ +# define ENET_TCSR_TMODE_OCSETCLR (9 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, set on compare, clear on overflow */ +# define ENET_TCSR_TMODE_OCCLRSET (10 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, clear on compare, set on overflow */ +# define ENET_TCSR_TMODE_PCPULSEL (14 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, pulse low on compare */ +# define ENET_TCSR_TMODE_PCPULSEH (15 << ENET_TCSR_TMODE_SHIFT) /* Output Compare, pulse high on compare */ + +#define ENET_TCSR_TIE (1 << 6) /* Bit 6: Timer interrupt enable */ +#define ENET_TCSR_TF (1 << 7) /* Bit 7: Timer Flag */ + /* Bits 8-31: Reserved */ + +/* Timer Compare Capture Register (32-bit compare value) */ + +/* Buffer Descriptors *******************************************************/ + +/* Endian-independent descriptor offsets */ + +#define DESC_STATUS1_OFFSET (0) +#define DESC_LENGTH_OFFSET (2) +#define DESC_DATAPTR_OFFSET (4) +#define DESC_LEGACY_LEN (8) + +#define DESC_STATUS2_OFFSET (8) +#define DESC_LENPROTO_OFFSET (12) +#define DESC_CHECKSUM_OFFSET (14) +#define DESC_BDU_OFFSET (16) +#define DESC_TIMESTAMP_OFFSET (20) +#define DESC_ENHANCED_LEN (32) + +/* Legacy/Common TX Buffer Descriptor Bit Definitions. */ + +#define IMX9_USE_DBSWAP + +# define TXDESC_TC (1 << 10) /* Common */ +# define TXDESC_L (1 << 11) /* Common */ +# define TXDESC_TO2 (1 << 12) /* Common */ +# define TXDESC_W (1 << 13) /* Common */ +# define TXDESC_TO1 (1 << 14) /* Common */ +# define TXDESC_R (1 << 15) /* Common */ + +/* Enhanced TX Buffer Descriptor Bit Definitions */ + +# define TXDESC_TSE (1 << 8) +# define TXDESC_OE (1 << 9) +# define TXDESC_LCE (1 << 10) +# define TXDESC_FE (1 << 11) +# define TXDESC_EE (1 << 12) +# define TXDESC_UE (1 << 13) +# define TXDESC_TXE (1 << 15) + +# define TDXESC_FTYPE_N (0 << 20) +# define TDXESC_FTYPE_A (1 << 20) +# define TDXESC_FTYPE_B (2 << 20) +# define TXDESC_UTLT (1 << 24) +# define TXDESC_IINS (1 << 27) +# define TXDESC_PINS (1 << 28) +# define TXDESC_TS (1 << 29) +# define TXDESC_INT (1 << 30) + +# define TXDESC_BDU (1 << 31) + +/* Legacy (and Common) RX Buffer Descriptor Bit Definitions */ + +# define RXDESC_TR (1 << 0) +# define RXDESC_OV (1 << 1) +# define RXDESC_CR (1 << 2) +# define RXDESC_NO (1 << 4) +# define RXDESC_LG (1 << 5) +# define RXDESC_MC (1 << 6) +# define RXDESC_BC (1 << 7) +# define RXDESC_M (1 << 8) +# define RXDESC_L (1 << 11) +# define RXDESC_R02 (1 << 12) +# define RXDESC_W (1 << 13) +# define RXDESC_R01 (1 << 14) +# define RXDESC_E (1 << 15) + +/* Enhanced (only) RX Buffer Descriptor Bit Definitions */ + +# define RXDESC_FRAG (1 << 0) +# define RXDESC_IPV6 (1 << 1) +# define RXDESC_VLAN (1 << 2) +# define RXDESC_PCR (1 << 4) +# define RXDESC_ICE (1 << 5) +# define RXDESC_INT (1 << 23) +# define RXDESC_UC (1 << 24) +# define RXDESC_CE (1 << 25) +# define RXDESC_PE (1 << 26) +# define RXDESC_ME (1 << 31) + +# define RXDESC_BDU (1 << 31) + +#define RXDESC_STATUS1_ERRORS (RXDESC_TR | RXDESC_OV | RXDESC_CR | RXDESC_NO | RXDESC_LG) +#define RXDESC_STATUS2_ERRORS (RXDESC_CE | RXDESC_PE | RXDESC_ME) + +#define TXDESC_STATUS2_ERRORS (TXDESC_TSE | TXDESC_OE | TXDESC_LCE | TXDESC_FE | TXDESC_EE | TXDESC_UE | TXDESC_TXE) + +/* From ref manual TDSR/RDSR description + * For optimal performance the pointer should be 512-bit aligned, that is, + * evenly divisible by 64. NOTE: This is also cache-line size + */ + +#define ENET_ALIGN 64 +#define ENET_ALIGN_MASK (ENET_ALIGN - 1) +#define ENET_ALIGN_UP(n) (((n) + ENET_ALIGN_MASK) & ~ENET_ALIGN_MASK) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Buffer Descriptors *******************************************************/ + +/* Little endian descriptor order, with ECR[DBSWP] = 1 */ + +struct enet_desc_s +{ + uint16_t length; /* Data length */ + uint16_t status1; /* Control and status */ + uint32_t data; /* Buffer address */ + uint32_t status2; /* Extended status */ + uint16_t checksum; /* Payload checksum */ + uint16_t lenproto; /* Header length + Protocol type */ + uint32_t bdu; /* BDU */ + uint32_t timestamp; /* Time stamp */ + uint32_t reserved1; /* unused */ + uint32_t reserved2; /* unused */ +}; + +/* This is a 64-byte descriptor pair used for TX. Two descriptors are used + * for each TX transmission to match descriptors used for a single + * transmission on a a single cache line + */ + +struct enet_txdesc_s +{ + struct enet_desc_s d1; + struct enet_desc_s d2; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM_SRC_IMX9_HARDWARE_IMX9_ENET_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_flexio.h b/arch/arm64/src/imx9/hardware/imx9_flexio.h new file mode 100644 index 0000000000000..2d1c9cabe5410 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_flexio.h @@ -0,0 +1,823 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_flexio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_FLEXIO_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_FLEXIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/imx9_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IMX9_FLEXIO_VERID_OFFSET 0x0000 /* Version ID Register, offset: 0x0 */ +#define IMX9_FLEXIO_PARAM_OFFSET 0x0004 /* Parameter Register, offset: 0x4 */ +#define IMX9_FLEXIO_CTRL_OFFSET 0x0008 /* FlexIO Control Register, offset: 0x8 */ +#define IMX9_FLEXIO_PIN_OFFSET 0x000c /* Pin State Register, offset: 0xC */ +#define IMX9_FLEXIO_SHIFTSTAT_OFFSET 0x0010 /* Shifter Status Register, offset: 0x10 */ +#define IMX9_FLEXIO_SHIFTERR_OFFSET 0x0014 /* Shifter Error Register, offset: 0x14 */ +#define IMX9_FLEXIO_TIMSTAT_OFFSET 0x0018 /* Timer Status Register, offset: 0x18 */ +#define IMX9_FLEXIO_SHIFTSIEN_OFFSET 0x0020 /* Shifter Status Interrupt Enable, offset: 0x20 */ +#define IMX9_FLEXIO_SHIFTEIEN_OFFSET 0x0024 /* Shifter Error Interrupt Enable, offset: 0x24 */ +#define IMX9_FLEXIO_TIMIEN_OFFSET 0x0028 /* Timer Interrupt Enable Register, offset: 0x28 */ +#define IMX9_FLEXIO_SHIFTSDEN_OFFSET 0x0030 /* Shifter Status DMA Enable, offset: 0x30 */ +#define IMX9_FLEXIO_SHIFTSTATE_OFFSET 0x0040 /* Shifter State Register, offset: 0x40 */ +#define IMX9_FLEXIO_TRGSTAT_OFFSET 0x0048 /* Trigger Status */ +#define IMX9_FLEXIO_TRIGIEN_OFFSET 0x004c /* External Trigger Interrupt Enable */ +#define IMX9_FLEXIO_PINSTAT_OFFSET 0x0050 /* Pin Status */ +#define IMX9_FLEXIO_PINIEN_OFFSET 0x0054 /* Pin Interrupt Enable */ +#define IMX9_FLEXIO_PINREN_OFFSET 0x0058 /* Pin Rising Edge Enable */ +#define IMX9_FLEXIO_PINFEN_OFFSET 0x005c /* Pin Falling Edge Enable */ +#define IMX9_FLEXIO_PINOUTD_OFFSET 0x0060 /* Pin Output Data */ +#define IMX9_FLEXIO_PINOUTE_OFFSET 0x0064 /* Pin Output Enable */ +#define IMX9_FLEXIO_PINOUTDIS_OFFSET 0x0068 /* Pin Output Disable */ +#define IMX9_FLEXIO_PINOUTCLR_OFFSET 0x006c /* Pin Output Clear */ +#define IMX9_FLEXIO_PINOUTSET_OFFSET 0x0070 /* Pin Output Set */ +#define IMX9_FLEXIO_PINOUTTOG_OFFSET 0x0074 /* Pin Output Toggle */ +#define IMX9_FLEXIO_SHIFTCTL0_OFFSET 0x0080 /* Shifter Control N Register, array offset: 0x80, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTCTL1_OFFSET 0x0084 +#define IMX9_FLEXIO_SHIFTCTL2_OFFSET 0x0088 +#define IMX9_FLEXIO_SHIFTCTL3_OFFSET 0x008c +#define IMX9_FLEXIO_SHIFTCTL4_OFFSET 0x0090 +#define IMX9_FLEXIO_SHIFTCTL5_OFFSET 0x0094 +#define IMX9_FLEXIO_SHIFTCTL6_OFFSET 0x0098 +#define IMX9_FLEXIO_SHIFTCTL7_OFFSET 0x009c +#define IMX9_FLEXIO_SHIFTCFG0_OFFSET 0x0100 /* Shifter Configuration N Register, array offset: 0x100, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTCFG1_OFFSET 0x0104 +#define IMX9_FLEXIO_SHIFTCFG2_OFFSET 0x0108 +#define IMX9_FLEXIO_SHIFTCFG3_OFFSET 0x010c +#define IMX9_FLEXIO_SHIFTCFG4_OFFSET 0x0110 +#define IMX9_FLEXIO_SHIFTCFG5_OFFSET 0x0114 +#define IMX9_FLEXIO_SHIFTCFG6_OFFSET 0x0118 +#define IMX9_FLEXIO_SHIFTCFG7_OFFSET 0x011c +#define IMX9_FLEXIO_SHIFTBUF0_OFFSET 0x0200 /* Shifter Buffer N Register, array offset: 0x200, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUF1_OFFSET 0x0204 +#define IMX9_FLEXIO_SHIFTBUF2_OFFSET 0x0208 +#define IMX9_FLEXIO_SHIFTBUF3_OFFSET 0x020c +#define IMX9_FLEXIO_SHIFTBUF4_OFFSET 0x0210 +#define IMX9_FLEXIO_SHIFTBUF5_OFFSET 0x0214 +#define IMX9_FLEXIO_SHIFTBUF6_OFFSET 0x0218 +#define IMX9_FLEXIO_SHIFTBUF7_OFFSET 0x021c +#define IMX9_FLEXIO_SHIFTBUFBIS0_OFFSET 0x0280 /* Shifter Buffer N Bit Swapped Register, array offset: 0x280, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFBIS1_OFFSET 0x0284 +#define IMX9_FLEXIO_SHIFTBUFBIS2_OFFSET 0x0288 +#define IMX9_FLEXIO_SHIFTBUFBIS3_OFFSET 0x028c +#define IMX9_FLEXIO_SHIFTBUFBIS4_OFFSET 0x0290 +#define IMX9_FLEXIO_SHIFTBUFBIS5_OFFSET 0x0294 +#define IMX9_FLEXIO_SHIFTBUFBIS6_OFFSET 0x0298 +#define IMX9_FLEXIO_SHIFTBUFBIS7_OFFSET 0x029c +#define IMX9_FLEXIO_SHIFTBUFBYS0_OFFSET 0x0300 /* Shifter Buffer N Byte Swapped Register, array offset: 0x300, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFBYS1_OFFSET 0x0304 +#define IMX9_FLEXIO_SHIFTBUFBYS2_OFFSET 0x0308 +#define IMX9_FLEXIO_SHIFTBUFBYS3_OFFSET 0x030c +#define IMX9_FLEXIO_SHIFTBUFBYS4_OFFSET 0x0310 +#define IMX9_FLEXIO_SHIFTBUFBYS5_OFFSET 0x0314 +#define IMX9_FLEXIO_SHIFTBUFBYS6_OFFSET 0x0318 +#define IMX9_FLEXIO_SHIFTBUFBYS7_OFFSET 0x031c +#define IMX9_FLEXIO_SHIFTBUFBBS0_OFFSET 0x0380 /* Shifter Buffer N Bit Byte Swapped Register, array offset: 0x380, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFBBS1_OFFSET 0x0384 +#define IMX9_FLEXIO_SHIFTBUFBBS2_OFFSET 0x0388 +#define IMX9_FLEXIO_SHIFTBUFBBS3_OFFSET 0x038c +#define IMX9_FLEXIO_SHIFTBUFBBS4_OFFSET 0x0390 +#define IMX9_FLEXIO_SHIFTBUFBBS5_OFFSET 0x0394 +#define IMX9_FLEXIO_SHIFTBUFBBS6_OFFSET 0x0398 +#define IMX9_FLEXIO_SHIFTBUFBBS7_OFFSET 0x039c +#define IMX9_FLEXIO_TIMCTL0_OFFSET 0x0400 /* Timer Control N Register, array offset: 0x400, array step: 0x4 */ +#define IMX9_FLEXIO_TIMCTL1_OFFSET 0x0404 +#define IMX9_FLEXIO_TIMCTL2_OFFSET 0x0408 +#define IMX9_FLEXIO_TIMCTL3_OFFSET 0x040c +#define IMX9_FLEXIO_TIMCTL4_OFFSET 0x0410 +#define IMX9_FLEXIO_TIMCTL5_OFFSET 0x0414 +#define IMX9_FLEXIO_TIMCTL6_OFFSET 0x0418 +#define IMX9_FLEXIO_TIMCTL7_OFFSET 0x041c +#define IMX9_FLEXIO_TIMCTL_OFFSET(x) (IMX9_FLEXIO_TIMCTL0_OFFSET + (x) * 4) +#define IMX9_FLEXIO_TIMCFG0_OFFSET 0x0480 /* Timer Configuration N Register, array offset: 0x480, array step: 0x4 */ +#define IMX9_FLEXIO_TIMCFG1_OFFSET 0x0484 +#define IMX9_FLEXIO_TIMCFG2_OFFSET 0x0488 +#define IMX9_FLEXIO_TIMCFG3_OFFSET 0x048c +#define IMX9_FLEXIO_TIMCFG4_OFFSET 0x0490 +#define IMX9_FLEXIO_TIMCFG5_OFFSET 0x0494 +#define IMX9_FLEXIO_TIMCFG6_OFFSET 0x0498 +#define IMX9_FLEXIO_TIMCFG7_OFFSET 0x049c +#define IMX9_FLEXIO_TIMCFG_OFFSET(x) (IMX9_FLEXIO_TIMCFG0_OFFSET + (x) * 4) +#define IMX9_FLEXIO_TIMCMP0_OFFSET 0x0500 /* Timer Compare N Register, array offset: 0x500, array step: 0x4 */ +#define IMX9_FLEXIO_TIMCMP1_OFFSET 0x0504 +#define IMX9_FLEXIO_TIMCMP2_OFFSET 0x0508 +#define IMX9_FLEXIO_TIMCMP3_OFFSET 0x050c +#define IMX9_FLEXIO_TIMCMP4_OFFSET 0x0510 +#define IMX9_FLEXIO_TIMCMP5_OFFSET 0x0514 +#define IMX9_FLEXIO_TIMCMP6_OFFSET 0x0518 +#define IMX9_FLEXIO_TIMCMP7_OFFSET 0x051c +#define IMX9_FLEXIO_TIMCMP_OFFSET(x) (IMX9_FLEXIO_TIMCMP0_OFFSET + (x) * 4) +#define IMX9_FLEXIO_SHIFTBUFNBS0_OFFSET 0x0680 /* Shifter Buffer N Nibble Byte Swapped Register, array offset: 0x680, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFNBS1_OFFSET 0x0684 +#define IMX9_FLEXIO_SHIFTBUFNBS2_OFFSET 0x0688 +#define IMX9_FLEXIO_SHIFTBUFNBS3_OFFSET 0x068c +#define IMX9_FLEXIO_SHIFTBUFNBS4_OFFSET 0x0690 +#define IMX9_FLEXIO_SHIFTBUFNBS5_OFFSET 0x0694 +#define IMX9_FLEXIO_SHIFTBUFNBS6_OFFSET 0x0698 +#define IMX9_FLEXIO_SHIFTBUFNBS7_OFFSET 0x069c +#define IMX9_FLEXIO_SHIFTBUFHWS0_OFFSET 0x0700 /* Shifter Buffer N Half Word Swapped Register, array offset: 0x700, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFHWS1_OFFSET 0x0704 +#define IMX9_FLEXIO_SHIFTBUFHWS2_OFFSET 0x0708 +#define IMX9_FLEXIO_SHIFTBUFHWS3_OFFSET 0x070c +#define IMX9_FLEXIO_SHIFTBUFHWS4_OFFSET 0x0710 +#define IMX9_FLEXIO_SHIFTBUFHWS5_OFFSET 0x0714 +#define IMX9_FLEXIO_SHIFTBUFHWS6_OFFSET 0x0718 +#define IMX9_FLEXIO_SHIFTBUFHWS7_OFFSET 0x071c +#define IMX9_FLEXIO_SHIFTBUFNIS0_OFFSET 0x0780 /* Shifter Buffer N Nibble Swapped Register, array offset: 0x780, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFNIS1_OFFSET 0x0784 +#define IMX9_FLEXIO_SHIFTBUFNIS2_OFFSET 0x0788 +#define IMX9_FLEXIO_SHIFTBUFNIS3_OFFSET 0x078c +#define IMX9_FLEXIO_SHIFTBUFNIS4_OFFSET 0x0790 +#define IMX9_FLEXIO_SHIFTBUFNIS5_OFFSET 0x0794 +#define IMX9_FLEXIO_SHIFTBUFNIS6_OFFSET 0x0798 +#define IMX9_FLEXIO_SHIFTBUFNIS7_OFFSET 0x079c +#define IMX9_FLEXIO_SHIFTBUFOES0_OFFSET 0x0800 /* Shifter Buffer N Odd Even Swapped, array offset: 0x800, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFOES1_OFFSET 0x0804 +#define IMX9_FLEXIO_SHIFTBUFOES2_OFFSET 0x0808 +#define IMX9_FLEXIO_SHIFTBUFOES3_OFFSET 0x080c +#define IMX9_FLEXIO_SHIFTBUFOES4_OFFSET 0x0810 +#define IMX9_FLEXIO_SHIFTBUFOES5_OFFSET 0x0814 +#define IMX9_FLEXIO_SHIFTBUFOES6_OFFSET 0x0818 +#define IMX9_FLEXIO_SHIFTBUFOES7_OFFSET 0x081c +#define IMX9_FLEXIO_SHIFTBUFEOS0_OFFSET 0x0880 /* Shifter Buffer N Even Odd Swapped, array offset: 0x880, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFEOS1_OFFSET 0x0884 +#define IMX9_FLEXIO_SHIFTBUFEOS2_OFFSET 0x0888 +#define IMX9_FLEXIO_SHIFTBUFEOS3_OFFSET 0x088c +#define IMX9_FLEXIO_SHIFTBUFEOS4_OFFSET 0x0890 +#define IMX9_FLEXIO_SHIFTBUFEOS5_OFFSET 0x0894 +#define IMX9_FLEXIO_SHIFTBUFEOS6_OFFSET 0x0898 +#define IMX9_FLEXIO_SHIFTBUFEOS7_OFFSET 0x089c +#define IMX9_FLEXIO_SHIFTBUFHBS0_OFFSET 0x0900 /* Shifter Buffer N Halfword Byte Swapped, array offset: 0x900, array step: 0x4 */ +#define IMX9_FLEXIO_SHIFTBUFHBS1_OFFSET 0x0904 +#define IMX9_FLEXIO_SHIFTBUFHBS2_OFFSET 0x0908 +#define IMX9_FLEXIO_SHIFTBUFHBS3_OFFSET 0x090c +#define IMX9_FLEXIO_SHIFTBUFHBS4_OFFSET 0x0910 +#define IMX9_FLEXIO_SHIFTBUFHBS5_OFFSET 0x0914 +#define IMX9_FLEXIO_SHIFTBUFHBS6_OFFSET 0x0918 +#define IMX9_FLEXIO_SHIFTBUFHBS7_OFFSET 0x091c + +/* VERID - Version ID Register */ + +#define FLEXIO_VERID_FEATURE_MASK (0xffffu) +#define FLEXIO_VERID_FEATURE_SHIFT (0u) + +/* FEATURE - Feature Specification Number + * 0b0000000000000000..Standard features implemented. + * 0b0000000000000001..Supports state, logic and parallel modes. + */ + +#define FLEXIO_VERID_FEATURE(x) ((((uint32_t)(x)) << FLEXIO_VERID_FEATURE_SHIFT) & FLEXIO_VERID_FEATURE_MASK) + +#define FLEXIO_VERID_MINOR_MASK (0xff0000u) +#define FLEXIO_VERID_MINOR_SHIFT (16u) + +/* MINOR - Minor Version Number */ + +#define FLEXIO_VERID_MINOR(x) ((((uint32_t)(x)) << FLEXIO_VERID_MINOR_SHIFT) & FLEXIO_VERID_MINOR_MASK) + +#define FLEXIO_VERID_MAJOR_MASK (0xff000000u) +#define FLEXIO_VERID_MAJOR_SHIFT (24u) + +/* MAJOR - Major Version Number */ +#define FLEXIO_VERID_MAJOR(x) ((((uint32_t)(x)) << FLEXIO_VERID_MAJOR_SHIFT) & FLEXIO_VERID_MAJOR_MASK) + +/* PARAM - Parameter Register */ + +#define FLEXIO_PARAM_SHIFTER_MASK (0xffu) +#define FLEXIO_PARAM_SHIFTER_SHIFT (0u) + +/* SHIFTER - Shifter Number */ +#define FLEXIO_PARAM_SHIFTER(x) ((((uint32_t)(x)) << FLEXIO_PARAM_SHIFTER_SHIFT) & FLEXIO_PARAM_SHIFTER_MASK) + +#define FLEXIO_PARAM_TIMER_MASK (0xff00u) +#define FLEXIO_PARAM_TIMER_SHIFT (8u) + +/* TIMER - Timer Number */ + +#define FLEXIO_PARAM_TIMER(x) ((((uint32_t)(x)) << FLEXIO_PARAM_TIMER_SHIFT) & FLEXIO_PARAM_TIMER_MASK) + +#define FLEXIO_PARAM_PIN_MASK (0xff0000u) +#define FLEXIO_PARAM_PIN_SHIFT (16u) + +/* PIN - Pin Number */ +#define FLEXIO_PARAM_PIN(x) ((((uint32_t)(x)) << FLEXIO_PARAM_PIN_SHIFT) & FLEXIO_PARAM_PIN_MASK) + +#define FLEXIO_PARAM_TRIGGER_MASK (0xff000000u) +#define FLEXIO_PARAM_TRIGGER_SHIFT (24u) + +/* TRIGGER - Trigger Number */ + +#define FLEXIO_PARAM_TRIGGER(x) ((((uint32_t)(x)) << FLEXIO_PARAM_TRIGGER_SHIFT) & FLEXIO_PARAM_TRIGGER_MASK) + +/* CTRL - FlexIO Control Register */ + +#define FLEXIO_CTRL_FLEXEN_MASK (0x1u) +#define FLEXIO_CTRL_FLEXEN_SHIFT (0u) + +/* FLEXEN - FlexIO Enable + * 0b0..FlexIO module is disabled. + * 0b1..FlexIO module is enabled. + */ + +#define FLEXIO_CTRL_FLEXEN(x) ((((uint32_t)(x)) << FLEXIO_CTRL_FLEXEN_SHIFT) & FLEXIO_CTRL_FLEXEN_MASK) + +#define FLEXIO_CTRL_SWRST_MASK (0x2u) +#define FLEXIO_CTRL_SWRST_SHIFT (1u) + +/* SWRST - Software Reset + * 0b0..Software reset is disabled + * 0b1..Software reset is enabled, all FlexIO registers except the Control + * Register are reset. + */ + +#define FLEXIO_CTRL_SWRST(x) ((((uint32_t)(x)) << FLEXIO_CTRL_SWRST_SHIFT) & FLEXIO_CTRL_SWRST_MASK) + +#define FLEXIO_CTRL_FASTACC_MASK (0x4u) +#define FLEXIO_CTRL_FASTACC_SHIFT (2u) + +/* FASTACC - Fast Access + * 0b0..Configures for normal register accesses to FlexIO + * 0b1..Configures for fast register accesses to FlexIO + */ + +#define FLEXIO_CTRL_FASTACC(x) ((((uint32_t)(x)) << FLEXIO_CTRL_FASTACC_SHIFT) & FLEXIO_CTRL_FASTACC_MASK) + +#define FLEXIO_CTRL_DBGE_MASK (0x40000000u) +#define FLEXIO_CTRL_DBGE_SHIFT (30u) + +/* DBGE - Debug Enable + * 0b0..FlexIO is disabled in debug modes. + * 0b1..FlexIO is enabled in debug modes + */ + +#define FLEXIO_CTRL_DBGE(x) ((((uint32_t)(x)) << FLEXIO_CTRL_DBGE_SHIFT) & FLEXIO_CTRL_DBGE_MASK) + +#define FLEXIO_CTRL_DOZEN_MASK (0x80000000u) +#define FLEXIO_CTRL_DOZEN_SHIFT (31u) + +/* DOZEN - Doze Enable + * 0b0..FlexIO enabled in Doze modes. + * 0b1..FlexIO disabled in Doze modes. + */ + +#define FLEXIO_CTRL_DOZEN(x) ((((uint32_t)(x)) << FLEXIO_CTRL_DOZEN_SHIFT) & FLEXIO_CTRL_DOZEN_MASK) + +/* PIN - Pin State Register */ + +#define FLEXIO_PIN_PDI_MASK (0xffffffffu) /* Merged from fields with different position or width, of widths (16, 32), largest definition used */ +#define FLEXIO_PIN_PDI_SHIFT (0u) + +/* PDI - Pin Data Input */ + +#define FLEXIO_PIN_PDI(x) ((((uint32_t)(x)) << FLEXIO_PIN_PDI_SHIFT) & FLEXIO_PIN_PDI_MASK) /* Merged from fields with different position or width, of widths (16, 32), largest definition used */ + +/* SHIFTSTAT - Shifter Status Register */ + +#define FLEXIO_SHIFTSTAT_SSF_MASK (0xffu) +#define FLEXIO_SHIFTSTAT_SSF_SHIFT (0u) + +/* SSF - Shifter Status Flag */ + +#define FLEXIO_SHIFTSTAT_SSF(x) ((((uint32_t)(x)) << FLEXIO_SHIFTSTAT_SSF_SHIFT) & FLEXIO_SHIFTSTAT_SSF_MASK) + +/* SHIFTERR - Shifter Error Register */ + +#define FLEXIO_SHIFTERR_SEF_MASK (0xffu) +#define FLEXIO_SHIFTERR_SEF_SHIFT (0u) + +/* SEF - Shifter Error Flags */ + +#define FLEXIO_SHIFTERR_SEF(x) ((((uint32_t)(x)) << FLEXIO_SHIFTERR_SEF_SHIFT) & FLEXIO_SHIFTERR_SEF_MASK) + +/* TIMSTAT - Timer Status Register */ + +#define FLEXIO_TIMSTAT_TSF_MASK (0xffu) +#define FLEXIO_TIMSTAT_TSF_SHIFT (0u) + +/* TSF - Timer Status Flags */ + +#define FLEXIO_TIMSTAT_TSF(x) ((((uint32_t)(x)) << FLEXIO_TIMSTAT_TSF_SHIFT) & FLEXIO_TIMSTAT_TSF_MASK) + +/* SHIFTSIEN - Shifter Status Interrupt Enable */ + +#define FLEXIO_SHIFTSIEN_SSIE_MASK (0xffu) +#define FLEXIO_SHIFTSIEN_SSIE_SHIFT (0u) + +/* SSIE - Shifter Status Interrupt Enable */ + +#define FLEXIO_SHIFTSIEN_SSIE(x) ((((uint32_t)(x)) << FLEXIO_SHIFTSIEN_SSIE_SHIFT) & FLEXIO_SHIFTSIEN_SSIE_MASK) + +/* SHIFTEIEN - Shifter Error Interrupt Enable */ + +#define FLEXIO_SHIFTEIEN_SEIE_MASK (0xffu) +#define FLEXIO_SHIFTEIEN_SEIE_SHIFT (0u) + +/* SEIE - Shifter Error Interrupt Enable */ + +#define FLEXIO_SHIFTEIEN_SEIE(x) ((((uint32_t)(x)) << FLEXIO_SHIFTEIEN_SEIE_SHIFT) & FLEXIO_SHIFTEIEN_SEIE_MASK) + +/* TIMIEN - Timer Interrupt Enable Register */ + +#define FLEXIO_TIMIEN_TEIE_MASK (0xffu) +#define FLEXIO_TIMIEN_TEIE_SHIFT (0u) + +/* TEIE - Timer Status Interrupt Enable */ + +#define FLEXIO_TIMIEN_TEIE(x) ((((uint32_t)(x)) << FLEXIO_TIMIEN_TEIE_SHIFT) & FLEXIO_TIMIEN_TEIE_MASK) + +/* SHIFTSDEN - Shifter Status DMA Enable */ + +#define FLEXIO_SHIFTSDEN_SSDE_MASK (0xffu) +#define FLEXIO_SHIFTSDEN_SSDE_SHIFT (0u) + +/* SSDE - Shifter Status DMA Enable */ + +#define FLEXIO_SHIFTSDEN_SSDE(x) ((((uint32_t)(x)) << FLEXIO_SHIFTSDEN_SSDE_SHIFT) & FLEXIO_SHIFTSDEN_SSDE_MASK) + +/* TIMERSDEN - Timer Status DMA Enable */ + +#define FLEXIO_TIMERSDEN_TSDE_MASK (0xffu) +#define FLEXIO_TIMERSDEN_TSDE_SHIFT (0u) + +/* TSDE - Timer Status DMA Enable */ + +#define FLEXIO_TIMERSDEN_TSDE(x) ((((uint32_t)(x)) << FLEXIO_TIMERSDEN_TSDE_SHIFT) & FLEXIO_TIMERSDEN_TSDE_MASK) + +/* SHIFTSTATE - Shifter State Register */ + +#define FLEXIO_SHIFTSTATE_STATE_MASK (0x7u) +#define FLEXIO_SHIFTSTATE_STATE_SHIFT (0u) + +/* STATE - Current State Pointer */ + +#define FLEXIO_SHIFTSTATE_STATE(x) ((((uint32_t)(x)) << FLEXIO_SHIFTSTATE_STATE_SHIFT) & FLEXIO_SHIFTSTATE_STATE_MASK) + +/* TRGSTAT - Trigger Status */ + +#define FLEXIO_TRGSTAT_ETSF_MASK (0xfu) +#define FLEXIO_TRGSTAT_ETSF_SHIFT (0u) + +#define FLEXIO_TRGSTAT_ETSF(x) ((((uint32_t)(x)) << FLEXIO_TRGSTAT_ETSF_SHIFT) & FLEXIO_TRGSTAT_ETSF_MASK) + +/* TRIGIEN - External Trigger Interrupt Enable */ + +#define FLEXIO_TRIGIEN_TRIE_MASK (0xfu) +#define FLEXIO_TRIGIEN_TRIE_SHIFT (0u) + +#define FLEXIO_TRIGIEN_TRIE(x) ((((uint32_t)(x)) << FLEXIO_TRIGIEN_TRIE_SHIFT) & FLEXIO_TRIGIEN_TRIE_MASK) + +/* SHIFTCTL - Shifter Control N Register */ + +#define FLEXIO_SHIFTCTL_SMOD_MASK (0x7u) +#define FLEXIO_SHIFTCTL_SMOD_SHIFT (0u) + +/* SMOD - Shifter Mode + * 0b000..Disabled. + * 0b001..Receive mode. Captures the current Shifter content into the + * SHIFTBUF on expiration of the Timer. + * 0b010..Transmit mode. Load SHIFTBUF contents into the Shifter on + * expiration of the Timer. + * 0b011..Reserved. + * 0b100..Match Store mode. Shifter data is compared to SHIFTBUF content on + * expiration of the Timer. + * 0b101..Match Continuous mode. Shifter data is continuously compared to + * SHIFTBUF contents. + * 0b110..State mode. SHIFTBUF contents are used for storing programmable + * state attributes. + * 0b111..Logic mode. SHIFTBUF contents are used for implementing + * programmable logic look up table. + */ + +#define FLEXIO_SHIFTCTL_SMOD(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCTL_SMOD_SHIFT) & FLEXIO_SHIFTCTL_SMOD_MASK) + +#define FLEXIO_SHIFTCTL_PINPOL_MASK (0x80u) +#define FLEXIO_SHIFTCTL_PINPOL_SHIFT (7u) + +/* PINPOL - Shifter Pin Polarity + * 0b0..Pin is active high + * 0b1..Pin is active low + */ + +#define FLEXIO_SHIFTCTL_PINPOL(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCTL_PINPOL_SHIFT) & FLEXIO_SHIFTCTL_PINPOL_MASK) + +#define FLEXIO_SHIFTCTL_PINSEL_MASK (0x1f00u) /* Merged from fields with different position or width, of widths (4, 5), largest definition used */ +#define FLEXIO_SHIFTCTL_PINSEL_SHIFT (8u) + +/* PINSEL - Shifter Pin Select */ + +#define FLEXIO_SHIFTCTL_PINSEL(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCTL_PINSEL_SHIFT) & FLEXIO_SHIFTCTL_PINSEL_MASK) /* Merged from fields with different position or width, of widths (4, 5), largest definition used */ + +#define FLEXIO_SHIFTCTL_PINCFG_MASK (0x30000u) +#define FLEXIO_SHIFTCTL_PINCFG_SHIFT (16u) + +/* PINCFG - Shifter Pin Configuration + * 0b00..Shifter pin output disabled + * 0b01..Shifter pin open drain or bidirectional output enable + * 0b10..Shifter pin bidirectional output data + * 0b11..Shifter pin output + */ + +#define FLEXIO_SHIFTCTL_PINCFG(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCTL_PINCFG_SHIFT) & FLEXIO_SHIFTCTL_PINCFG_MASK) + +#define FLEXIO_SHIFTCTL_TIMPOL_MASK (0x800000u) +#define FLEXIO_SHIFTCTL_TIMPOL_SHIFT (23u) + +/* TIMPOL - Timer Polarity + * 0b0..Shift on posedge of Shift clock + * 0b1..Shift on negedge of Shift clock + */ + +#define FLEXIO_SHIFTCTL_TIMPOL(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCTL_TIMPOL_SHIFT) & FLEXIO_SHIFTCTL_TIMPOL_MASK) + +#define FLEXIO_SHIFTCTL_TIMSEL_MASK (0x7000000u) +#define FLEXIO_SHIFTCTL_TIMSEL_SHIFT (24u) + +/* TIMSEL - Timer Select */ + +#define FLEXIO_SHIFTCTL_TIMSEL(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCTL_TIMSEL_SHIFT) & FLEXIO_SHIFTCTL_TIMSEL_MASK) + +/* The count of FLEXIO_SHIFTCTL */ + +#define FLEXIO_SHIFTCTL_COUNT (8u) + +/* SHIFTCFG - Shifter Configuration N Register */ + +#define FLEXIO_SHIFTCFG_SSTART_MASK (0x3u) +#define FLEXIO_SHIFTCFG_SSTART_SHIFT (0u) + +/* SSTART - Shifter Start bit + * 0b00..Start bit disabled for transmitter/receiver/match store, + * transmitter loads data on enable + * 0b01..Start bit disabled for transmitter/receiver/match store, + * transmitter loads data on first shift + * 0b10..Transmitter outputs start bit value 0 before loading data on first + * shift, receiver/match store sets error flag if start bit is not 0 + * 0b11..Transmitter outputs start bit value 1 before loading data on first + * shift, receiver/match store sets error flag if start bit is not 1 + */ + +#define FLEXIO_SHIFTCFG_SSTART(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCFG_SSTART_SHIFT) & FLEXIO_SHIFTCFG_SSTART_MASK) + +#define FLEXIO_SHIFTCFG_SSTOP_MASK (0x30u) +#define FLEXIO_SHIFTCFG_SSTOP_SHIFT (4u) + +/* SSTOP - Shifter Stop bit + * 0b00..Stop bit disabled for transmitter/receiver/match store + * 0b01..Reserved for transmitter/receiver/match store + * 0b10..Transmitter outputs stop bit value 0 on store, receiver/match store + * sets error flag if stop bit is not 0 + * 0b11..Transmitter outputs stop bit value 1 on store, receiver/match store + * sets error flag if stop bit is not 1 + */ + +#define FLEXIO_SHIFTCFG_SSTOP(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCFG_SSTOP_SHIFT) & FLEXIO_SHIFTCFG_SSTOP_MASK) + +#define FLEXIO_SHIFTCFG_INSRC_MASK (0x100u) +#define FLEXIO_SHIFTCFG_INSRC_SHIFT (8u) + +/* INSRC - Input Source + * 0b0..Pin + * 0b1..Shifter N+1 Output + */ + +#define FLEXIO_SHIFTCFG_INSRC(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCFG_INSRC_SHIFT) & FLEXIO_SHIFTCFG_INSRC_MASK) + +/* LATST - Late Store */ + +#define FLEXIO_SHIFTCFG_LATST_MASK (0x200u) +#define FLEXIO_SHIFTCFG_LATST_SHIFT (9u) + +#define FLEXIO_SHIFTCFG_LATST(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCFG_LATST_SHIFT) & FLEXIO_SHIFTCFG_LATST_MASK) + +/* SSIZE - Shifter Size */ + +#define FLEXIO_SHIFTCFG_SSIZE_MASK (0x1000u) +#define FLEXIO_SHIFTCFG_SSIZE_SHIFT (12u) + +#define FLEXIO_SHIFTCFG_SSIZE(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCFG_SSIZE_SHIFT) & FLEXIO_SHIFTCFG_SSIZE_MASK) + +#define FLEXIO_SHIFTCFG_PWIDTH_MASK (0x1f0000u) /* Merged from fields with different position or width, of widths (4, 5), largest definition used */ +#define FLEXIO_SHIFTCFG_PWIDTH_SHIFT (16u) + +/* PWIDTH - Parallel Width */ + +#define FLEXIO_SHIFTCFG_PWIDTH(x) ((((uint32_t)(x)) << FLEXIO_SHIFTCFG_PWIDTH_SHIFT) & FLEXIO_SHIFTCFG_PWIDTH_MASK) /* Merged from fields with different position or width, of widths (4, 5), largest definition used */ + +/* The count of FLEXIO_SHIFTCFG */ + +#define FLEXIO_SHIFTCFG_COUNT (8u) + +/* SHIFTBUF - Shifter Buffer N Register */ + +#define FLEXIO_SHIFTBUF_SHIFTBUF_MASK (0xffffffffu) +#define FLEXIO_SHIFTBUF_SHIFTBUF_SHIFT (0u) + +/* SHIFTBUF - Shift Buffer */ + +#define FLEXIO_SHIFTBUF_SHIFTBUF(x) ((((uint32_t)(x)) << FLEXIO_SHIFTBUF_SHIFTBUF_SHIFT) & FLEXIO_SHIFTBUF_SHIFTBUF_MASK) + +/* The count of FLEXIO_SHIFTBUF */ + +#define FLEXIO_SHIFTBUF_COUNT (8u) + +/* SHIFTBUFBIS - Shifter Buffer N Bit Swapped Register */ + +#define FLEXIO_SHIFTBUFBIS_SHIFTBUFBIS_MASK (0xffffffffu) +#define FLEXIO_SHIFTBUFBIS_SHIFTBUFBIS_SHIFT (0u) + +/* SHIFTBUFBIS - Shift Buffer */ + +#define FLEXIO_SHIFTBUFBIS_SHIFTBUFBIS(x) ((((uint32_t)(x)) << FLEXIO_SHIFTBUFBIS_SHIFTBUFBIS_SHIFT) & FLEXIO_SHIFTBUFBIS_SHIFTBUFBIS_MASK) + +/* The count of FLEXIO_SHIFTBUFBIS */ + +#define FLEXIO_SHIFTBUFBIS_COUNT (8u) + +/* SHIFTBUFBYS - Shifter Buffer N Byte Swapped Register */ + +#define FLEXIO_SHIFTBUFBYS_SHIFTBUFBYS_MASK (0xffffffffu) +#define FLEXIO_SHIFTBUFBYS_SHIFTBUFBYS_SHIFT (0u) + +/* SHIFTBUFBYS - Shift Buffer */ + +#define FLEXIO_SHIFTBUFBYS_SHIFTBUFBYS(x) ((((uint32_t)(x)) << FLEXIO_SHIFTBUFBYS_SHIFTBUFBYS_SHIFT) & FLEXIO_SHIFTBUFBYS_SHIFTBUFBYS_MASK) + +/* The count of FLEXIO_SHIFTBUFBYS */ + +#define FLEXIO_SHIFTBUFBYS_COUNT (8u) + +/* SHIFTBUFBBS - Shifter Buffer N Bit Byte Swapped Register */ + +#define FLEXIO_SHIFTBUFBBS_SHIFTBUFBBS_MASK (0xffffffffu) +#define FLEXIO_SHIFTBUFBBS_SHIFTBUFBBS_SHIFT (0u) + +/* SHIFTBUFBBS - Shift Buffer */ + +#define FLEXIO_SHIFTBUFBBS_SHIFTBUFBBS(x) ((((uint32_t)(x)) << FLEXIO_SHIFTBUFBBS_SHIFTBUFBBS_SHIFT) & FLEXIO_SHIFTBUFBBS_SHIFTBUFBBS_MASK) + +/* The count of FLEXIO_SHIFTBUFBBS */ + +#define FLEXIO_SHIFTBUFBBS_COUNT (8u) + +/* TIMCTL - Timer Control N Register */ + +#define FLEXIO_TIMCTL_TIMOD_MASK (0x3u) +#define FLEXIO_TIMCTL_TIMOD_SHIFT (0u) + +/* TIMOD - Timer Mode + * 0b000..Timer Disabled. + * 0b001..Dual 8-bit counters baud mode. + * 0b010..Dual 8-bit counters PWM high mode. + * 0b011..Single 16-bit counter mode. + * 0b100..Single 16-bit counter disable mode. + * 0b101..Dual 8-bit counters word mode. + * 0b110..Dual 8-bit counters PWM low mode. + * 0b111..Single 16-bit input capture mode. + */ + +#define FLEXIO_TIMCTL_TIMOD(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_TIMOD_SHIFT) & FLEXIO_TIMCTL_TIMOD_MASK) + +#define FLEXIO_TIMCTL_PINPOL_MASK (0x80u) +#define FLEXIO_TIMCTL_PINPOL_SHIFT (7u) + +/* PINPOL - Timer Pin Polarity + * 0b0..Pin is active high + * 0b1..Pin is active low + */ + +#define FLEXIO_TIMCTL_PINPOL(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_PINPOL_SHIFT) & FLEXIO_TIMCTL_PINPOL_MASK) + +#define FLEXIO_TIMCTL_PINSEL_MASK (0x1f00u) /* Merged from fields with different position or width, of widths (4, 5), largest definition used */ +#define FLEXIO_TIMCTL_PINSEL_SHIFT (8u) + +/* PINSEL - Timer Pin Select */ + +#define FLEXIO_TIMCTL_PINSEL(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_PINSEL_SHIFT) & FLEXIO_TIMCTL_PINSEL_MASK) /* Merged from fields with different position or width, of widths (4, 5), largest definition used */ + +#define FLEXIO_TIMCTL_PINCFG_MASK (0x30000u) +#define FLEXIO_TIMCTL_PINCFG_SHIFT (16u) + +/* PINCFG - Timer Pin Configuration + * 0b00..Timer pin output disabled + * 0b01..Timer pin open drain or bidirectional output enable + * 0b10..Timer pin bidirectional output data + * 0b11..Timer pin output + */ + +#define FLEXIO_TIMCTL_PINCFG(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_PINCFG_SHIFT) & FLEXIO_TIMCTL_PINCFG_MASK) + +#define FLEXIO_TIMCTL_TRGSRC_MASK (0x400000u) +#define FLEXIO_TIMCTL_TRGSRC_SHIFT (22u) + +/* TRGSRC - Trigger Source + * 0b0..External trigger selected + * 0b1..Internal trigger selected + */ + +#define FLEXIO_TIMCTL_TRGSRC(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_TRGSRC_SHIFT) & FLEXIO_TIMCTL_TRGSRC_MASK) + +#define FLEXIO_TIMCTL_TRGPOL_MASK (0x800000u) +#define FLEXIO_TIMCTL_TRGPOL_SHIFT (23u) + +/* TRGPOL - Trigger Polarity + * 0b0..Trigger active high + * 0b1..Trigger active low + */ + +#define FLEXIO_TIMCTL_TRGPOL(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_TRGPOL_SHIFT) & FLEXIO_TIMCTL_TRGPOL_MASK) + +#define FLEXIO_TIMCTL_TRGSEL_MASK (0x3f000000u) /* Merged from fields with different position or width, of widths (5, 6), largest definition used */ +#define FLEXIO_TIMCTL_TRGSEL_SHIFT (24u) + +/* TRGSEL - Trigger Select */ + +#define FLEXIO_TIMCTL_TRGSEL(x) ((((uint32_t)(x)) << FLEXIO_TIMCTL_TRGSEL_SHIFT) & FLEXIO_TIMCTL_TRGSEL_MASK) /* Merged from fields with different position or width, of widths (5, 6), largest definition used */ + +/* The count of FLEXIO_TIMCTL */ + +#define FLEXIO_TIMCTL_COUNT (8u) + +/* TIMCFG - Timer Configuration N Register */ + +#define FLEXIO_TIMCFG_TSTART_MASK (0x2u) +#define FLEXIO_TIMCFG_TSTART_SHIFT (1u) + +/* TSTART - Timer Start Bit + * 0b0..Start bit disabled + * 0b1..Start bit enabled + */ + +#define FLEXIO_TIMCFG_TSTART(x) ((((uint32_t)(x)) << FLEXIO_TIMCFG_TSTART_SHIFT) & FLEXIO_TIMCFG_TSTART_MASK) + +#define FLEXIO_TIMCFG_TSTOP_MASK (0x30u) +#define FLEXIO_TIMCFG_TSTOP_SHIFT (4u) + +/* TSTOP - Timer Stop Bit + * 0b00..Stop bit disabled + * 0b01..Stop bit is enabled on timer compare + * 0b10..Stop bit is enabled on timer disable + * 0b11..Stop bit is enabled on timer compare and timer disable + */ + +#define FLEXIO_TIMCFG_TSTOP(x) ((((uint32_t)(x)) << FLEXIO_TIMCFG_TSTOP_SHIFT) & FLEXIO_TIMCFG_TSTOP_MASK) + +#define FLEXIO_TIMCFG_TIMENA_MASK (0x700u) +#define FLEXIO_TIMCFG_TIMENA_SHIFT (8u) + +/* TIMENA - Timer Enable + * 0b000..Timer always enabled + * 0b001..Timer enabled on Timer N-1 enable + * 0b010..Timer enabled on Trigger high + * 0b011..Timer enabled on Trigger high and Pin high + * 0b100..Timer enabled on Pin rising edge + * 0b101..Timer enabled on Pin rising edge and Trigger high + * 0b110..Timer enabled on Trigger rising edge + * 0b111..Timer enabled on Trigger rising or falling edge + */ + +#define FLEXIO_TIMCFG_TIMENA(x) ((((uint32_t)(x)) << FLEXIO_TIMCFG_TIMENA_SHIFT) & FLEXIO_TIMCFG_TIMENA_MASK) + +#define FLEXIO_TIMCFG_TIMDIS_MASK (0x7000u) +#define FLEXIO_TIMCFG_TIMDIS_SHIFT (12u) + +/* TIMDIS - Timer Disable + * 0b000..Timer never disabled + * 0b001..Timer disabled on Timer N-1 disable + * 0b010..Timer disabled on Timer compare (upper 8-bits match and decrement) + * 0b011..Timer disabled on Timer compare (upper 8-bits match and decrement) + * and Trigger Low + * 0b100..Timer disabled on Pin rising or falling edge + * 0b101..Timer disabled on Pin rising or falling edge provided Trigger is + * high + * 0b110..Timer disabled on Trigger falling edge + * 0b111..Reserved + */ + +#define FLEXIO_TIMCFG_TIMDIS(x) ((((uint32_t)(x)) << FLEXIO_TIMCFG_TIMDIS_SHIFT) & FLEXIO_TIMCFG_TIMDIS_MASK) + +#define FLEXIO_TIMCFG_TIMRST_MASK (0x70000u) +#define FLEXIO_TIMCFG_TIMRST_SHIFT (16u) + +/* TIMRST - Timer Reset + * 0b000..Timer never reset + * 0b001..Reserved + * 0b010..Timer reset on Timer Pin equal to Timer Output + * 0b011..Timer reset on Timer Trigger equal to Timer Output + * 0b100..Timer reset on Timer Pin rising edge + * 0b101..Reserved + * 0b110..Timer reset on Trigger rising edge + * 0b111..Timer reset on Trigger rising or falling edge + */ + +#define FLEXIO_TIMCFG_TIMRST(x) ((((uint32_t)(x)) << FLEXIO_TIMCFG_TIMRST_SHIFT) & FLEXIO_TIMCFG_TIMRST_MASK) + +#define FLEXIO_TIMCFG_TIMDEC_MASK (0x300000u) +#define FLEXIO_TIMCFG_TIMDEC_SHIFT (20U) + +/* TIMDEC - Timer Decrement + * 0b00..Decrement counter on FlexIO clock, Shift clock equals Timer output. + * 0b01..Decrement counter on Trigger input (both edges), Shift clock equals + * Timer output. + * 0b10..Decrement counter on Pin input (both edges), Shift clock equals Pin + * input. + * 0b11..Decrement counter on Trigger input (both edges), Shift clock equals + * Trigger input. + */ + +#define FLEXIO_TIMCFG_TIMDEC(x) ((((uint32_t)(x)) << FLEXIO_TIMCFG_TIMDEC_SHIFT) & FLEXIO_TIMCFG_TIMDEC_MASK) + +#define FLEXIO_TIMCFG_TIMOUT_MASK (0x3000000u) +#define FLEXIO_TIMCFG_TIMOUT_SHIFT (24u) + +/* TIMOUT - Timer Output + * 0b00..Timer output is logic one when enabled and is not affected by timer + * reset + * 0b01..Timer output is logic zero when enabled and is not affected by + * timer reset + * 0b10..Timer output is logic one when enabled and on timer reset + * 0b11..Timer output is logic zero when enabled and on timer reset + */ + +#define FLEXIO_TIMCFG_TIMOUT(x) ((((uint32_t)(x)) << FLEXIO_TIMCFG_TIMOUT_SHIFT) & FLEXIO_TIMCFG_TIMOUT_MASK) + +/* The count of FLEXIO_TIMCFG */ + +#define FLEXIO_TIMCFG_COUNT (8u) + +/* TIMCMP - Timer Compare N Register */ + +#define FLEXIO_TIMCMP_CMP_MASK (0xffffu) +#define FLEXIO_TIMCMP_CMP_SHIFT (0u) + +/* CMP - Timer Compare Value */ + +#define FLEXIO_TIMCMP_CMP(x) ((((uint32_t)(x)) << FLEXIO_TIMCMP_CMP_SHIFT) & FLEXIO_TIMCMP_CMP_MASK) + +/* The count of FLEXIO_TIMCMP */ + +#define FLEXIO_TIMCMP_COUNT (8u) + +/* SHIFTBUFNBS - Shifter Buffer N Nibble Byte Swapped Register */ + +#define FLEXIO_SHIFTBUFNBS_SHIFTBUFNBS_MASK (0xffffffffu) +#define FLEXIO_SHIFTBUFNBS_SHIFTBUFNBS_SHIFT (0u) + +/* SHIFTBUFNBS - Shift Buffer */ + +#define FLEXIO_SHIFTBUFNBS_SHIFTBUFNBS(x) ((((uint32_t)(x)) << FLEXIO_SHIFTBUFNBS_SHIFTBUFNBS_SHIFT) & FLEXIO_SHIFTBUFNBS_SHIFTBUFNBS_MASK) + +/* The count of FLEXIO_SHIFTBUFNBS */ + +#define FLEXIO_SHIFTBUFNBS_COUNT (8u) + +/* SHIFTBUFHWS - Shifter Buffer N Half Word Swapped Register */ + +#define FLEXIO_SHIFTBUFHWS_SHIFTBUFHWS_MASK (0xffffffffu) +#define FLEXIO_SHIFTBUFHWS_SHIFTBUFHWS_SHIFT (0u) + +/* SHIFTBUFHWS - Shift Buffer */ + +#define FLEXIO_SHIFTBUFHWS_SHIFTBUFHWS(x) ((((uint32_t)(x)) << FLEXIO_SHIFTBUFHWS_SHIFTBUFHWS_SHIFT) & FLEXIO_SHIFTBUFHWS_SHIFTBUFHWS_MASK) + +/* The count of FLEXIO_SHIFTBUFHWS */ + +#define FLEXIO_SHIFTBUFHWS_COUNT (8u) + +/* SHIFTBUFNIS - Shifter Buffer N Nibble Swapped Register */ + +#define FLEXIO_SHIFTBUFNIS_SHIFTBUFNIS_MASK (0xffffffffu) +#define FLEXIO_SHIFTBUFNIS_SHIFTBUFNIS_SHIFT (0u) + +/* SHIFTBUFNIS - Shift Buffer */ + +#define FLEXIO_SHIFTBUFNIS_SHIFTBUFNIS(x) ((((uint32_t)(x)) << FLEXIO_SHIFTBUFNIS_SHIFTBUFNIS_SHIFT) & FLEXIO_SHIFTBUFNIS_SHIFTBUFNIS_MASK) + +/* The count of FLEXIO_SHIFTBUFNIS */ + +#define FLEXIO_SHIFTBUFNIS_COUNT (8u) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_FLEXIO_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_gpio.h b/arch/arm64/src/imx9/hardware/imx9_gpio.h new file mode 100644 index 0000000000000..b13be0eaf6b6a --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_gpio.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_gpio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMX9_HARDWARE_IMX9_GPIO_H +#define __ARCH_ARM_SRC_IMX9_HARDWARE_IMX9_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_IMX93) +# include "hardware/imx93/imx93_gpio.h" +#else +# error Unrecognized i.MX9 architecture +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define GPIO1 0 /* Port 1 index */ +#define GPIO2 1 /* Port 2 index */ +#define GPIO3 2 /* Port 3 index */ +#define GPIO4 3 /* Port 4 index */ +#define GPIO5 4 /* Port 5 index */ +#define GPIO6 5 /* Port 6 index */ +#define GPIO7 6 /* Port 7 index */ +#define GPIO8 7 /* Port 8 index */ +#define GPIO9 8 /* Port 9 index */ +#define GPIO10 9 /* Port 10 index */ +#define GPIO11 10 /* Port 11 index */ +#define GPIO12 11 /* Port 12 index */ +#define GPIO13 12 /* Port 13 index */ + +#define IMX9_GPIO_NPINS 32 /* Up to 32 pins per port */ + +/* Register bit definitions *************************************************/ + +/* Most registers are laid out simply with one bit per pin */ + +#define GPIO_PIN(n) (1 << (n)) /* Bit n: Pin n, n=0-31 */ + +/* ICRN Register */ + +#define IMX9_GPIO_ICRN_ISF (1 << 24) /* Bit 24: Interrupt Status Flag */ +#define IMX9_GPIO_ICRN_LK (1 << 23) /* Bit 23: Lock Register */ +#define IMX9_GPIO_ICRN_IRQS (1 << 20) /* Bit 20: Configures the selected interrupt, or DMA request. */ +#define IMX9_GPIO_ICRN_SHIFT (16) /* Bits 16-19: Interrupt Configuration */ +#define IMX9_GPIO_ICRN_MASK (0xf << IMX9_GPIO_ICRN_SHIFT) +# define IMX9_GPIO_ICRN_DISABLED (0 << IMX9_GPIO_ICRN_SHIFT) /* Interrupt Status Flag (ISF) is disabled */ +# define IMX9_GPIO_ICRN_DMARISING (1 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag and DMA request on rising edge */ +# define IMX9_GPIO_ICRN_DMAFALLING (2 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag and DMA request on falling edge */ +# define IMX9_GPIO_ICRN_DMABOTH (3 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag and DMA request on either edge */ +# define IMX9_GPIO_ICRN_ISFRISING (5 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag sets on rising edge */ +# define IMX9_GPIO_ICRN_ISFFALLING (6 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag sets on falling edge */ +# define IMX9_GPIO_ICRN_ISFBOTH (7 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag sets on either edge */ +# define IMX9_GPIO_ICRN_ZERO (8 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt when logic 0 */ +# define IMX9_GPIO_ICRN_RISING (9 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt on rising-edge */ +# define IMX9_GPIO_ICRN_FALLING (10 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt on falling-edge */ +# define IMX9_GPIO_ICRN_BOTH (11 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt on either edge */ +# define IMX9_GPIO_ICRN_ONE (12 << IMX9_GPIO_ICRN_SHIFT) /* ISF flag and Interrupt when logic 1 */ + +/* Global Interrupt Control Low Register */ + +#define IMX9_GPIO_GICLR_GIWD_SHIFT (0) /* Bits 0-15: Global Interrupt Write Data */ +#define IMX9_GPIO_GICLR_GIWD_MASK (0xffff << IMX9_GPIO_GICLR_GIWD_SHIFT) +# define IMX9_GPIO_GICLR_GIWD_PIN(n) ((uint32_t)(n) << IMX9_GPIO_GICLR_GIWD_SHIFT) /* Pin n=0..15 */ + +#define IMX9_GPIO_GICLR_GIWE_SHIFT (16) /* Bits 16-31: Global Interrupt Write Enable */ +#define IMX9_GPIO_GICLR_GIWE_MASK (0xffff << IMX9_GPIO_GICLR_GIWE_SHIFT) +# define IMX9_GPIO_GICLR_GIWE_PIN(n) ((uint32_t)(n) << IMX9_GPIO_GICLR_GIWE_SHIFT) /* Pin n=0..15 */ + +/* Global Interrupt Control High Register */ + +#define IMX9_GPIO_GICHR_GIWD_SHIFT (0) /* Bits 0-15: Global Interrupt Write Data */ +#define IMX9_GPIO_GICHR_GIWD_MASK (0xffff << IMX9_GPIO_GICHR_GIWD_SHIFT) +# define IMX9_GPIO_GICHR_GIWD_PIN(n) ((uint32_t)((n) - 16) << IMX9_GPIO_GICHR_GIWD_SHIFT) /* Pin n=16..31 */ + +#define IMX9_GPIO_GICHR_GIWE_SHIFT (16) /* Bits 16-31: Global Interrupt Write Enable */ +#define IMX9_GPIO_GICHR_GIWE_MASK (0xffff << IMX9_GPIO_GICHR_GIWE_SHIFT) +# define IMX9_GPIO_GICHR_GIWE_PIN(n) ((uint32_t)((n) - 16) << IMX9_GPIO_GICHR_GIWE_SHIFT) /* Pin n=16..31 */ + +/* Interrupt Status Flag Register */ + +#define IMX9_GPIO_ISFR(n) (1 << (n)) /* Interrupt Status Flag, n=0-31 */ + +#endif /* __ARCH_ARM_SRC_IMX9_HARDWARE_IMX9_GPIO_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_iomuxc.h b/arch/arm64/src/imx9/hardware/imx9_iomuxc.h new file mode 100644 index 0000000000000..6e6fe9979c509 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_iomuxc.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_iomuxc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_IOMUXC_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_IOMUXC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_IMX93) +# include "hardware/imx93/imx93_iomux.h" +#else +# error Unrecognized i.MX9 architecture +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Pad muxing */ + +#define IOMUXC_MUX_MODE_SHIFT (0) /* MODE: pin alternate function */ +#define IOMUXC_MUX_MODE_MASK (0x03 << IOMUXC_MUX_MODE_SHIFT) +#define IOMUXC_MUX_MODE_ALT0 (0 << IOMUXC_MUX_MODE_SHIFT) +#define IOMUXC_MUX_MODE_ALT1 (1 << IOMUXC_MUX_MODE_SHIFT) +#define IOMUXC_MUX_MODE_ALT2 (2 << IOMUXC_MUX_MODE_SHIFT) +#define IOMUXC_MUX_MODE_ALT3 (3 << IOMUXC_MUX_MODE_SHIFT) +#define IOMUXC_MUX_MODE_ALT4 (4 << IOMUXC_MUX_MODE_SHIFT) +#define IOMUXC_MUX_MODE_ALT5 (5 << IOMUXC_MUX_MODE_SHIFT) +#define IOMUXC_MUX_MODE_ALT6 (6 << IOMUXC_MUX_MODE_SHIFT) + +#define IOMUXC_MUX_SION_SHIFT (4) /* SION: Force input path */ +#define IPMUXC_MUX_SION_MASK (0x01 << IOMUXC_MUX_SION_SHIFT) +#define IOMUXC_MUX_SION_OFF (0 << IOMUXC_MUX_SION_SHIFT) +#define IOMUXC_MUX_SION_ON (1 << IOMUXC_MUX_SION_SHIFT) + +/* Pad control */ + +#define IOMUXC_PAD_DSE_SHIFT (1) /* DSE: Drive strength */ +#define IOMUXC_PAD_DSE_MASK (0x3f << IOMUXC_PAD_DSE_SHIFT) +#define IOMUXC_PAD_DSE_X0 (0x00 << IOMUXC_PAD_DSE_SHIFT) +#define IOMUXC_PAD_DSE_X1 (0x01 << IOMUXC_PAD_DSE_SHIFT) +#define IOMUXC_PAD_DSE_X2 (0x03 << IOMUXC_PAD_DSE_SHIFT) +#define IOMUXC_PAD_DSE_X3 (0x07 << IOMUXC_PAD_DSE_SHIFT) +#define IOMUXC_PAD_DSE_X4 (0x0f << IOMUXC_PAD_DSE_SHIFT) +#define IOMUXC_PAD_DSE_X5 (0x1f << IOMUXC_PAD_DSE_SHIFT) +#define IOMUXC_PAD_DSE_X6 (0x3f << IOMUXC_PAD_DSE_SHIFT) + +#define IOMUXC_PAD_FSEL_SHIFT (7) /* FSEL: Slew rate control */ +#define IOMUXC_PAD_FSEL_MASK (0x02 << IOMUXC_PAD_FSEL_SHIFT) +#define IOMUXC_PAD_FSEL_SLOW (0 << IOMUXC_PAD_FSEL_SHIFT) +#define IOMUXC_PAD_FSEL_SSLOW (1 << IOMUXC_PAD_FSEL_SHIFT) /* Slightly slow */ +#define IOMUXC_PAD_FSEL_SFAST (2 << IOMUXC_PAD_FSEL_SHIFT) /* Slightly fast */ +#define IOMUXC_PAD_FSEL_FAST (3 << IOMUXC_PAD_FSEL_SHIFT) + +#define IOMUXC_PAD_PU_SHIFT (9) /* PU: Pull-up */ +#define IOMUXC_PAD_PU_MASK (0x01 << IOMUXC_PAD_PU_SHIFT) +#define IOMUXC_PAD_PU_OFF (0 << IOMUXC_PAD_PU_SHIFT) +#define IOMUXC_PAD_PU_ON (1 << IOMUXC_PAD_PU_SHIFT) + +#define IOMUXC_PAD_PD_SHIFT (10) /* PD: Pull-down */ +#define IOMUXC_PAD_PD_MASK (0x01 << IOMUXC_PAD_PD_SHIFT) +#define IOMUXC_PAD_PD_OFF (0 << IOMUXC_PAD_PD_SHIFT) +#define IOMUXC_PAD_PD_ON (1 << IOMUXC_PAD_PD_SHIFT) + +#define IOMUXC_PAD_OD_SHIFT (11) /* OD: Open-drain */ +#define IOMUXC_PAD_OD_MASK (0x01 << IOMUXC_PAD_OD_SHIFT) +#define IOMUXC_PAD_OD_DISABE (0 << IOMUXC_PAD_OD_SHIFT) +#define IOMUXC_PAD_OD_ENABLE (1 << IOMUXC_PAD_OD_SHIFT) + +#define IOMUXC_PAD_HYS_SHIFT (12) /* HYS: Enable schmitt-trigger on input */ +#define IOMUXC_PAD_HYS_MASK (0x01 << IOMUXC_PAD_HYS_SHIFT) +#define IOMUXC_PAD_HYS_ST_OFF (0 << IOMUXC_PAD_HYS_SHIFT) /* Schmitt-trigger off */ +#define IOMUXC_PAD_HYS_ST_ON (1 << IOMUXC_PAD_HYS_SHIFT) /* Schmitt-trigger on */ + +#define IOMUXC_PAD_APC_SHIFT (24) /* APC: Access control */ +#define IOMUXC_PAD_APC_MASK (0xff << IOMUXC_PAD_APC_SHIFT) + +/* Daisy chain control, 2 bits seems to be enough */ + +#define IOMUXC_DSY_SHIFT (0) +#define IOMUXC_DSY_MASK (0x03 << IOMUXC_DSY_SHIFT) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_IOMUXC_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_lpi2c.h b/arch/arm64/src/imx9/hardware/imx9_lpi2c.h new file mode 100644 index 0000000000000..1c7e47aa88833 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_lpi2c.h @@ -0,0 +1,622 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_lpi2c.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPI2C_H_ +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPI2C_H_ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define IMX9_LPI2C_VERID_OFFSET 0x0000 /* Version ID Register offset */ +#define IMX9_LPI2C_PARAM_OFFSET 0x0004 /* Parameter Register offset */ +#define IMX9_LPI2C_MCR_OFFSET 0x0010 /* Master Control Register offset */ +#define IMX9_LPI2C_MSR_OFFSET 0x0014 /* Master Status Register offset */ +#define IMX9_LPI2C_MIER_OFFSET 0x0018 /* Master Interrupt Enable Register offset */ +#define IMX9_LPI2C_MDER_OFFSET 0x001c /* Master DMA Enable Register offset */ +#define IMX9_LPI2C_MCFGR0_OFFSET 0x0020 /* Master Config Register 0 offset */ +#define IMX9_LPI2C_MCFGR1_OFFSET 0x0024 /* Master Config Register 1 offset */ +#define IMX9_LPI2C_MCFGR2_OFFSET 0x0028 /* Master Config Register 2 offset */ +#define IMX9_LPI2C_MCFGR3_OFFSET 0x002c /* Master Config Register 3 offset */ +#define IMX9_LPI2C_MDMR_OFFSET 0x0040 /* Master Data Match Register offset */ +#define IMX9_LPI2C_MCCR0_OFFSET 0x0048 /* Master Clock Configuration Register 0 offset */ +#define IMX9_LPI2C_MCCR1_OFFSET 0x0050 /* Master Clock Configuration Register 1 offset */ +#define IMX9_LPI2C_MFCR_OFFSET 0x0058 /* Master FIFO Control Register offset */ +#define IMX9_LPI2C_MFSR_OFFSET 0x005C /* Master FIFO Status Register offset */ +#define IMX9_LPI2C_MTDR_OFFSET 0x0060 /* Master Transmit Data Register offset */ +#define IMX9_LPI2C_MRDR_OFFSET 0x0070 /* Master Receive Data Register offset */ +#define IMX9_LPI2C_SCR_OFFSET 0x0110 /* Slave Control Register offset */ +#define IMX9_LPI2C_SSR_OFFSET 0x0114 /* Slave Status Register offset */ +#define IMX9_LPI2C_SIER_OFFSET 0x0118 /* Slave Interrupt Enable Register offset */ +#define IMX9_LPI2C_SDER_OFFSET 0x011c /* Slave DMA Enable Register offset */ +#define IMX9_LPI2C_SCFGR1_OFFSET 0x0124 /* Slave Config Register 1 offset */ +#define IMX9_LPI2C_SCFGR2_OFFSET 0x0128 /* Slave Config Register 2 offset */ +#define IMX9_LPI2C_SAMR_OFFSET 0x0140 /* Slave Address Match Register offset */ +#define IMX9_LPI2C_SASR_OFFSET 0x0150 /* Slave Address Status Register offset */ +#define IMX9_LPI2C_STAR_OFFSET 0x0154 /* Slave Transmit ACK Register offset */ +#define IMX9_LPI2C_STDR_OFFSET 0x0160 /* Slave Transmit Data Register offset */ +#define IMX9_LPI2C_SRDR_OFFSET 0x0170 /* Slave Receive Data Register offset */ + +/* Register addresses *******************************************************/ + +/* LPI2C1 Registers */ + +#define IMX9_LPI2C1_VERID (IMX9_LPI2C1_BASE + IMX9_LPI2C_VERID_OFFSET) /* Version ID Register */ +#define IMX9_LPI2C1_PARAM (IMX9_LPI2C1_BASE + IMX9_LPI2C_PARAM_OFFSET) /* Parameter Register */ +#define IMX9_LPI2C1_MCR (IMX9_LPI2C1_BASE + IMX9_LPI2C_MCR_OFFSET) /* Master Control Register */ +#define IMX9_LPI2C1_MSR (IMX9_LPI2C1_BASE + IMX9_LPI2C_MSR_OFFSET) /* Master Status Register */ +#define IMX9_LPI2C1_MIER (IMX9_LPI2C1_BASE + IMX9_LPI2C_MIER_OFFSET) /* Master Interrupt Enable Register */ +#define IMX9_LPI2C1_MDER (IMX9_LPI2C1_BASE + IMX9_LPI2C_MDER_OFFSET) /* Master DMA Enable Register */ +#define IMX9_LPI2C1_MCFGR0 (IMX9_LPI2C1_BASE + IMX9_LPI2C_MCFGR0_OFFSET) /* Master Config Register 0 */ +#define IMX9_LPI2C1_MCFGR1 (IMX9_LPI2C1_BASE + IMX9_LPI2C_MCFGR1_OFFSET) /* Master Config Register 1 */ +#define IMX9_LPI2C1_MCFGR2 (IMX9_LPI2C1_BASE + IMX9_LPI2C_MCFGR2_OFFSET) /* Master Config Register 2 */ +#define IMX9_LPI2C1_MCFGR3 (IMX9_LPI2C1_BASE + IMX9_LPI2C_MCFGR3_OFFSET) /* Master Config Register 3 */ +#define IMX9_LPI2C1_MDMR (IMX9_LPI2C1_BASE + IMX9_LPI2C_MDMR_OFFSET) /* Master Data Match Register */ +#define IMX9_LPI2C1_MCCR0 (IMX9_LPI2C1_BASE + IMX9_LPI2C_MCCR0_OFFSET) /* Master Clock Configuration Register 0 */ +#define IMX9_LPI2C1_MCCR1 (IMX9_LPI2C1_BASE + IMX9_LPI2C_MCCR1_OFFSET) /* Master Clock Configuration Register 1 */ +#define IMX9_LPI2C1_MFCR (IMX9_LPI2C1_BASE + IMX9_LPI2C_MFCR_OFFSET) /* Master FIFO Control Register */ +#define IMX9_LPI2C1_MFSR (IMX9_LPI2C1_BASE + IMX9_LPI2C_MFSR_OFFSET) /* Master FIFO Status Register */ +#define IMX9_LPI2C1_MTDR (IMX9_LPI2C1_BASE + IMX9_LPI2C_MTDR_OFFSET) /* Master Transmit Data Register */ +#define IMX9_LPI2C1_MRDR (IMX9_LPI2C1_BASE + IMX9_LPI2C_MRDR_OFFSET) /* Master Receive Data Register */ +#define IMX9_LPI2C1_SCR (IMX9_LPI2C1_BASE + IMX9_LPI2C_SCR_OFFSET) /* Slave Control Register */ +#define IMX9_LPI2C1_SSR (IMX9_LPI2C1_BASE + IMX9_LPI2C_SSR_OFFSET) /* Slave Status Register */ +#define IMX9_LPI2C1_SIER (IMX9_LPI2C1_BASE + IMX9_LPI2C_SIER_OFFSET) /* Slave Interrupt Enable Register */ +#define IMX9_LPI2C1_SDER (IMX9_LPI2C1_BASE + IMX9_LPI2C_SDER_OFFSET) /* Slave DMA Enable Register */ +#define IMX9_LPI2C1_SCFGR1 (IMX9_LPI2C1_BASE + IMX9_LPI2C_SCFGR1_OFFSET) /* Slave Config Register 1 */ +#define IMX9_LPI2C1_SCFGR2 (IMX9_LPI2C1_BASE + IMX9_LPI2C_SCFGR2_OFFSET) /* Slave Config Register 2 */ +#define IMX9_LPI2C1_SAMR (IMX9_LPI2C1_BASE + IMX9_LPI2C_SAMR_OFFSET) /* Slave Address Match Register */ +#define IMX9_LPI2C1_SASR (IMX9_LPI2C1_BASE + IMX9_LPI2C_SASR_OFFSET) /* Slave Address Status Register */ +#define IMX9_LPI2C1_STAR (IMX9_LPI2C1_BASE + IMX9_LPI2C_STAR_OFFSET) /* Slave Transmit ACK Register */ +#define IMX9_LPI2C1_STDR (IMX9_LPI2C1_BASE + IMX9_LPI2C_STDR_OFFSET) /* Slave Transmit Data Register */ +#define IMX9_LPI2C1_SRDR (IMX9_LPI2C1_BASE + IMX9_LPI2C_SRDR_OFFSET) /* Slave Receive Data Register */ + +/* LPI2C2 Registers */ + +#define IMX9_LPI2C2_VERID (IMX9_LPI2C2_BASE + IMX9_LPI2C_VERID_OFFSET) /* Version ID Register */ +#define IMX9_LPI2C2_PARAM (IMX9_LPI2C2_BASE + IMX9_LPI2C_PARAM_OFFSET) /* Parameter Register */ +#define IMX9_LPI2C2_MCR (IMX9_LPI2C2_BASE + IMX9_LPI2C_MCR_OFFSET) /* Master Control Register */ +#define IMX9_LPI2C2_MSR (IMX9_LPI2C2_BASE + IMX9_LPI2C_MSR_OFFSET) /* Master Status Register */ +#define IMX9_LPI2C2_MIER (IMX9_LPI2C2_BASE + IMX9_LPI2C_MIER_OFFSET) /* Master Interrupt Enable Register */ +#define IMX9_LPI2C2_MDER (IMX9_LPI2C2_BASE + IMX9_LPI2C_MDER_OFFSET) /* Master DMA Enable Register */ +#define IMX9_LPI2C2_MCFGR0 (IMX9_LPI2C2_BASE + IMX9_LPI2C_MCFGR0_OFFSET) /* Master Config Register 0 */ +#define IMX9_LPI2C2_MCFGR1 (IMX9_LPI2C2_BASE + IMX9_LPI2C_MCFGR1_OFFSET) /* Master Config Register 1 */ +#define IMX9_LPI2C2_MCFGR2 (IMX9_LPI2C2_BASE + IMX9_LPI2C_MCFGR2_OFFSET) /* Master Config Register 2 */ +#define IMX9_LPI2C2_MCFGR3 (IMX9_LPI2C2_BASE + IMX9_LPI2C_MCFGR3_OFFSET) /* Master Config Register 3 */ +#define IMX9_LPI2C2_MDMR (IMX9_LPI2C2_BASE + IMX9_LPI2C_MDMR_OFFSET) /* Master Data Match Register */ +#define IMX9_LPI2C2_MCCR0 (IMX9_LPI2C2_BASE + IMX9_LPI2C_MCCR0_OFFSET) /* Master Clock Configuration Register 0 */ +#define IMX9_LPI2C2_MCCR1 (IMX9_LPI2C2_BASE + IMX9_LPI2C_MCCR1_OFFSET) /* Master Clock Configuration Register 1 */ +#define IMX9_LPI2C2_MFCR (IMX9_LPI2C2_BASE + IMX9_LPI2C_MFCR_OFFSET) /* Master FIFO Control Register */ +#define IMX9_LPI2C2_MFSR (IMX9_LPI2C2_BASE + IMX9_LPI2C_MFSR_OFFSET) /* Master FIFO Status Register */ +#define IMX9_LPI2C2_MTDR (IMX9_LPI2C2_BASE + IMX9_LPI2C_MTDR_OFFSET) /* Master Transmit Data Register */ +#define IMX9_LPI2C2_MRDR (IMX9_LPI2C2_BASE + IMX9_LPI2C_MRDR_OFFSET) /* Master Receive Data Register */ +#define IMX9_LPI2C2_SCR (IMX9_LPI2C2_BASE + IMX9_LPI2C_SCR_OFFSET) /* Slave Control Register */ +#define IMX9_LPI2C2_SSR (IMX9_LPI2C2_BASE + IMX9_LPI2C_SSR_OFFSET) /* Slave Status Register */ +#define IMX9_LPI2C2_SIER (IMX9_LPI2C2_BASE + IMX9_LPI2C_SIER_OFFSET) /* Slave Interrupt Enable Register */ +#define IMX9_LPI2C2_SDER (IMX9_LPI2C2_BASE + IMX9_LPI2C_SDER_OFFSET) /* Slave DMA Enable Register */ +#define IMX9_LPI2C2_SCFGR1 (IMX9_LPI2C2_BASE + IMX9_LPI2C_SCFGR1_OFFSET) /* Slave Config Register 1 */ +#define IMX9_LPI2C2_SCFGR2 (IMX9_LPI2C2_BASE + IMX9_LPI2C_SCFGR2_OFFSET) /* Slave Config Register 2 */ +#define IMX9_LPI2C2_SAMR (IMX9_LPI2C2_BASE + IMX9_LPI2C_SAMR_OFFSET) /* Slave Address Match Register */ +#define IMX9_LPI2C2_SASR (IMX9_LPI2C2_BASE + IMX9_LPI2C_SASR_OFFSET) /* Slave Address Status Register */ +#define IMX9_LPI2C2_STAR (IMX9_LPI2C2_BASE + IMX9_LPI2C_STAR_OFFSET) /* Slave Transmit ACK Register */ +#define IMX9_LPI2C2_STDR (IMX9_LPI2C2_BASE + IMX9_LPI2C_STDR_OFFSET) /* Slave Transmit Data Register */ +#define IMX9_LPI2C2_SRDR (IMX9_LPI2C2_BASE + IMX9_LPI2C_SRDR_OFFSET) /* Slave Receive Data Register */ + +/* LPI2C3 Registers */ + +#define IMX9_LPI2C3_VERID (IMX9_LPI2C3_BASE + IMX9_LPI2C_VERID_OFFSET) /* Version ID Register */ +#define IMX9_LPI2C3_PARAM (IMX9_LPI2C3_BASE + IMX9_LPI2C_PARAM_OFFSET) /* Parameter Register */ +#define IMX9_LPI2C3_MCR (IMX9_LPI2C3_BASE + IMX9_LPI2C_MCR_OFFSET) /* Master Control Register */ +#define IMX9_LPI2C3_MSR (IMX9_LPI2C3_BASE + IMX9_LPI2C_MSR_OFFSET) /* Master Status Register */ +#define IMX9_LPI2C3_MIER (IMX9_LPI2C3_BASE + IMX9_LPI2C_MIER_OFFSET) /* Master Interrupt Enable Register */ +#define IMX9_LPI2C3_MDER (IMX9_LPI2C3_BASE + IMX9_LPI2C_MDER_OFFSET) /* Master DMA Enable Register */ +#define IMX9_LPI2C3_MCFGR0 (IMX9_LPI2C3_BASE + IMX9_LPI2C_MCFGR0_OFFSET) /* Master Config Register 0 */ +#define IMX9_LPI2C3_MCFGR1 (IMX9_LPI2C3_BASE + IMX9_LPI2C_MCFGR1_OFFSET) /* Master Config Register 1 */ +#define IMX9_LPI2C3_MCFGR2 (IMX9_LPI2C3_BASE + IMX9_LPI2C_MCFGR2_OFFSET) /* Master Config Register 2 */ +#define IMX9_LPI2C3_MCFGR3 (IMX9_LPI2C3_BASE + IMX9_LPI2C_MCFGR3_OFFSET) /* Master Config Register 3 */ +#define IMX9_LPI2C3_MDMR (IMX9_LPI2C3_BASE + IMX9_LPI2C_MDMR_OFFSET) /* Master Data Match Register */ +#define IMX9_LPI2C3_MCCR0 (IMX9_LPI2C3_BASE + IMX9_LPI2C_MCCR0_OFFSET) /* Master Clock Configuration Register 0 */ +#define IMX9_LPI2C3_MCCR1 (IMX9_LPI2C3_BASE + IMX9_LPI2C_MCCR1_OFFSET) /* Master Clock Configuration Register 1 */ +#define IMX9_LPI2C3_MFCR (IMX9_LPI2C3_BASE + IMX9_LPI2C_MFCR_OFFSET) /* Master FIFO Control Register */ +#define IMX9_LPI2C3_MFSR (IMX9_LPI2C3_BASE + IMX9_LPI2C_MFSR_OFFSET) /* Master FIFO Status Register */ +#define IMX9_LPI2C3_MTDR (IMX9_LPI2C3_BASE + IMX9_LPI2C_MTDR_OFFSET) /* Master Transmit Data Register */ +#define IMX9_LPI2C3_MRDR (IMX9_LPI2C3_BASE + IMX9_LPI2C_MRDR_OFFSET) /* Master Receive Data Register */ +#define IMX9_LPI2C3_SCR (IMX9_LPI2C3_BASE + IMX9_LPI2C_SCR_OFFSET) /* Slave Control Register */ +#define IMX9_LPI2C3_SSR (IMX9_LPI2C3_BASE + IMX9_LPI2C_SSR_OFFSET) /* Slave Status Register */ +#define IMX9_LPI2C3_SIER (IMX9_LPI2C3_BASE + IMX9_LPI2C_SIER_OFFSET) /* Slave Interrupt Enable Register */ +#define IMX9_LPI2C3_SDER (IMX9_LPI2C3_BASE + IMX9_LPI2C_SDER_OFFSET) /* Slave DMA Enable Register */ +#define IMX9_LPI2C3_SCFGR1 (IMX9_LPI2C3_BASE + IMX9_LPI2C_SCFGR1_OFFSET) /* Slave Config Register 1 */ +#define IMX9_LPI2C3_SCFGR2 (IMX9_LPI2C3_BASE + IMX9_LPI2C_SCFGR2_OFFSET) /* Slave Config Register 2 */ +#define IMX9_LPI2C3_SAMR (IMX9_LPI2C3_BASE + IMX9_LPI2C_SAMR_OFFSET) /* Slave Address Match Register */ +#define IMX9_LPI2C3_SASR (IMX9_LPI2C3_BASE + IMX9_LPI2C_SASR_OFFSET) /* Slave Address Status Register */ +#define IMX9_LPI2C3_STAR (IMX9_LPI2C3_BASE + IMX9_LPI2C_STAR_OFFSET) /* Slave Transmit ACK Register */ +#define IMX9_LPI2C3_STDR (IMX9_LPI2C3_BASE + IMX9_LPI2C_STDR_OFFSET) /* Slave Transmit Data Register */ +#define IMX9_LPI2C3_SRDR (IMX9_LPI2C3_BASE + IMX9_LPI2C_SRDR_OFFSET) /* Slave Receive Data Register */ + +/* LPI2C4 Registers */ + +#define IMX9_LPI2C4_VERID (IMX9_LPI2C4_BASE + IMX9_LPI2C_VERID_OFFSET) /* Version ID Register */ +#define IMX9_LPI2C4_PARAM (IMX9_LPI2C4_BASE + IMX9_LPI2C_PARAM_OFFSET) /* Parameter Register */ +#define IMX9_LPI2C4_MCR (IMX9_LPI2C4_BASE + IMX9_LPI2C_MCR_OFFSET) /* Master Control Register */ +#define IMX9_LPI2C4_MSR (IMX9_LPI2C4_BASE + IMX9_LPI2C_MSR_OFFSET) /* Master Status Register */ +#define IMX9_LPI2C4_MIER (IMX9_LPI2C4_BASE + IMX9_LPI2C_MIER_OFFSET) /* Master Interrupt Enable Register */ +#define IMX9_LPI2C4_MDER (IMX9_LPI2C4_BASE + IMX9_LPI2C_MDER_OFFSET) /* Master DMA Enable Register */ +#define IMX9_LPI2C4_MCFGR0 (IMX9_LPI2C4_BASE + IMX9_LPI2C_MCFGR0_OFFSET) /* Master Config Register 0 */ +#define IMX9_LPI2C4_MCFGR1 (IMX9_LPI2C4_BASE + IMX9_LPI2C_MCFGR1_OFFSET) /* Master Config Register 1 */ +#define IMX9_LPI2C4_MCFGR2 (IMX9_LPI2C4_BASE + IMX9_LPI2C_MCFGR2_OFFSET) /* Master Config Register 2 */ +#define IMX9_LPI2C4_MCFGR3 (IMX9_LPI2C4_BASE + IMX9_LPI2C_MCFGR3_OFFSET) /* Master Config Register 3 */ +#define IMX9_LPI2C4_MDMR (IMX9_LPI2C4_BASE + IMX9_LPI2C_MDMR_OFFSET) /* Master Data Match Register */ +#define IMX9_LPI2C4_MCCR0 (IMX9_LPI2C4_BASE + IMX9_LPI2C_MCCR0_OFFSET) /* Master Clock Configuration Register 0 */ +#define IMX9_LPI2C4_MCCR1 (IMX9_LPI2C4_BASE + IMX9_LPI2C_MCCR1_OFFSET) /* Master Clock Configuration Register 1 */ +#define IMX9_LPI2C4_MFCR (IMX9_LPI2C4_BASE + IMX9_LPI2C_MFCR_OFFSET) /* Master FIFO Control Register */ +#define IMX9_LPI2C4_MFSR (IMX9_LPI2C4_BASE + IMX9_LPI2C_MFSR_OFFSET) /* Master FIFO Status Register */ +#define IMX9_LPI2C4_MTDR (IMX9_LPI2C4_BASE + IMX9_LPI2C_MTDR_OFFSET) /* Master Transmit Data Register */ +#define IMX9_LPI2C4_MRDR (IMX9_LPI2C4_BASE + IMX9_LPI2C_MRDR_OFFSET) /* Master Receive Data Register */ +#define IMX9_LPI2C4_SCR (IMX9_LPI2C4_BASE + IMX9_LPI2C_SCR_OFFSET) /* Slave Control Register */ +#define IMX9_LPI2C4_SSR (IMX9_LPI2C4_BASE + IMX9_LPI2C_SSR_OFFSET) /* Slave Status Register */ +#define IMX9_LPI2C4_SIER (IMX9_LPI2C4_BASE + IMX9_LPI2C_SIER_OFFSET) /* Slave Interrupt Enable Register */ +#define IMX9_LPI2C4_SDER (IMX9_LPI2C4_BASE + IMX9_LPI2C_SDER_OFFSET) /* Slave DMA Enable Register */ +#define IMX9_LPI2C4_SCFGR1 (IMX9_LPI2C4_BASE + IMX9_LPI2C_SCFGR1_OFFSET) /* Slave Config Register 1 */ +#define IMX9_LPI2C4_SCFGR2 (IMX9_LPI2C4_BASE + IMX9_LPI2C_SCFGR2_OFFSET) /* Slave Config Register 2 */ +#define IMX9_LPI2C4_SAMR (IMX9_LPI2C4_BASE + IMX9_LPI2C_SAMR_OFFSET) /* Slave Address Match Register */ +#define IMX9_LPI2C4_SASR (IMX9_LPI2C4_BASE + IMX9_LPI2C_SASR_OFFSET) /* Slave Address Status Register */ +#define IMX9_LPI2C4_STAR (IMX9_LPI2C4_BASE + IMX9_LPI2C_STAR_OFFSET) /* Slave Transmit ACK Register */ +#define IMX9_LPI2C4_STDR (IMX9_LPI2C4_BASE + IMX9_LPI2C_STDR_OFFSET) /* Slave Transmit Data Register */ +#define IMX9_LPI2C4_SRDR (IMX9_LPI2C4_BASE + IMX9_LPI2C_SRDR_OFFSET) /* Slave Receive Data Register */ + +/* Register bit definitions *************************************************/ + +/* LPI2C Version ID Register */ + +#define LPI2C_VERID_FEATURE_SHIFT (0) +#define LPI2C_VERID_FEATURE_MASK (0xffff << LPI2C_VERID_FEATURE_SHIFT) +#define LPI2C_VERID_MINOR_SHIFT (16) +#define LPI2C_VERID_MINOR_MASK (0xff << LPI2C_VERID_MINOR_SHIFT) +#define LPI2C_VERID_MAJOR_SHIFT (24) +#define LPI2C_VERID_MAJOR_MASK (0xff << LPI2C_VERID_MAJOR_SHIFT) + +/* LPI2C Parameter Register */ + +#define LPI2C_PARAM_MTXFIFO_MASK (0x0f) /* Config number of words in master transmit fifo to 2^MTXFIFO (pow(2,MTXFIFO )) */ +# define LPI2C_PARAM_MTXFIFO_1_WORDS (0) +# define LPI2C_PARAM_MTXFIFO_2_WORDS (1) +# define LPI2C_PARAM_MTXFIFO_4_WORDS (2) +# define LPI2C_PARAM_MTXFIFO_8_WORDS (3) +# define LPI2C_PARAM_MTXFIFO_16_WORDS (4) +# define LPI2C_PARAM_MTXFIFO_32_WORDS (5) +# define LPI2C_PARAM_MTXFIFO_64_WORDS (6) +# define LPI2C_PARAM_MTXFIFO_128_WORDS (7) +# define LPI2C_PARAM_MTXFIFO_256_WORDS (8) +# define LPI2C_PARAM_MTXFIFO_512_WORDS (9) +# define LPI2C_PARAM_MTXFIFO_1024_WORDS (10) +# define LPI2C_PARAM_MTXFIFO_2048_WORDS (11) +# define LPI2C_PARAM_MTXFIFO_4096_WORDS (12) +# define LPI2C_PARAM_MTXFIFO_8192_WORDS (13) +# define LPI2C_PARAM_MTXFIFO_16384_WORDS (14) +# define LPI2C_PARAM_MTXFIFO_32768_WORDS (15) + +#define LPI2C_PARAM_MRXFIFO_SHIFT (8) +#define LPI2C_PARAM_MRXFIFO_MASK (0x0f << LPI2C_PARAM_MRXFIFO_SHIFT) /* Config number of words in master receive fifo 2^MRXFIFO (pow(2,MTRFIFO )) */ +# define LPI2C_PARAM_MRXFIFO_1_WORDS (0 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_2_WORDS (1 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_4_WORDS (2 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_8_WORDS (3 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_16_WORDS (4 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_32_WORDS (5 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_64_WORDS (6 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_128_WORDS (7 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_256_WORDS (8 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_512_WORDS (9 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_1024_WORDS (10 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_2048_WORDS (11 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_4096_WORDS (12 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_8192_WORDS (13 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_16384_WORDS (14 << LPI2C_PARAM_MRXFIFO_SHIFT) +# define LPI2C_PARAM_MRXFIFO_32768_WORDS (15 << LPI2C_PARAM_MRXFIFO_SHIFT) + +/* LPI2C Master Control Register */ + +#define LPI2C_MCR_MEN (1 << 0) /* Master Enable Bit */ +#define LPI2C_MCR_RST (1 << 1) /* Software Reset Bit */ +#define LPI2C_MCR_DOZEN (1 << 2) /* Doze Mode Enable Bit */ +#define LPI2C_MCR_DBGEN (1 << 3) /* Debug Enable Bit */ + /* Bits 7-4 Reserved */ +#define LPI2C_MCR_RTF (1 << 8) /* Reset Transmit FIFO Bit */ +#define LPI2C_MCR_RRF (1 << 9) /* Reset Receive FIFO Bit */ + /* Bits 31-10 Reserved */ + +/* LPI2C Master Status Register */ + +#define LPI2C_MSR_TDF (1 << 0) /* Transmit Data Flag Bit */ +#define LPI2C_MSR_RDF (1 << 1) /* Receive Data Flag Bit */ + /* Bits 7-2 Reserved */ +#define LPI2C_MSR_EPF (1 << 8) /* End Packet Flag Bit */ +#define LPI2C_MSR_SDF (1 << 9) /* STOP Detect Flag Bit */ +#define LPI2C_MSR_NDF (1 << 10) /* NACK Detect Flag Bit */ +#define LPI2C_MSR_ALF (1 << 11) /* Arbitration Lost Flag Bit */ +#define LPI2C_MSR_FEF (1 << 12) /* FIFO Error Flag Bit */ +#define LPI2C_MSR_PLTF (1 << 13) /* Pin Low Timeout Flag Bit */ +#define LPI2C_MSR_DMF (1 << 14) /* Data Match Flag Bit */ + /* Bits 23-15 Reserved */ +#define LPI2C_MSR_MBF (1 << 24) /* Master Busy Flag Bit */ +#define LPI2C_MSR_BBF (1 << 25) /* Bus Busy Flag Bit */ + /* Bits 31-26 Reserved */ +#define LPI2C_MSR_ERROR_MASK (LPI2C_MSR_NDF | LPI2C_MSR_ALF | \ + LPI2C_MSR_FEF) + +/* LPI2C Master Interrupt Enable Register */ + +#define LPI2C_MIER_TDIE (1 << 0) /* Transmit Data Interrupt Enable Bit */ +#define LPI2C_MIER_RDIE (1 << 1) /* Receive Data Interrupt Enable Bit */ + /* Bits 7-2 Reserved */ +#define LPI2C_MIER_EPIE (1 << 8) /* End Packet Interrupt Enable Bit */ +#define LPI2C_MIER_SDIE (1 << 9) /* STOP Detect Interrupt Enable Bit */ +#define LPI2C_MIER_NDIE (1 << 10) /* NACK Detect Interrupt Enable Bit */ +#define LPI2C_MIER_ALIE (1 << 11) /* Arbitration Lost Interrupt Enable Bit */ +#define LPI2C_MIER_FEIE (1 << 12) /* FIFO Error Interrupt Enable Bit */ +#define LPI2C_MIER_PLTIE (1 << 13) /* Pin Low Timeout Interrupt Enable Bit */ +#define LPI2C_MIER_DMIE (1 << 14) /* Data Match Interrupt Enable Bit */ + /* Bits 31-15 Reserved */ + +/* LPI2C Master DMA Enable Register */ + +#define LPI2C_MDER_TDDE (1 << 0) /* Transmit Data DMA Enable Bit */ +#define LPI2C_MDER_RDDE (1 << 1) /* Transmit Data DMA Enable Bit */ + /* Bits 31-2 Reserved */ + +/* LPI2C Master Config Register 0 */ + +#define LPI2C_MCFG0_HREN (1 << 0) /* Host Request Enable Bit */ +#define LPI2C_MCFG0_HRPOL (1 << 1) /* Host Request Polarity Bit */ +#define LPI2C_MCFG0_HRSEL (1 << 2) /* Host Request Select Bit */ + /* Bits 7-3 Reserved */ +#define LPI2C_MCFG0_CIRFIFO (1 << 8) /* Circular FIFO Enable Bit */ +#define LPI2C_MCFG0_RDMO (1 << 9) /* Receive Data Match Only Bit */ + /* Bits 31-10 Reserved */ + +/* LPI2C Master Config Register 1 */ + +#define LPI2C_MCFGR1_PRESCALE_MASK (7 << 0) /* Clock Prescaler Bit Mask */ +#define LPI2C_MCFGR1_PRESCALE(n) ((n) & LPI2C_MCFGR1_PRESCALE_MASK) +# define LPI2C_MCFGR1_PRESCALE_1 (0) +# define LPI2C_MCFGR1_PRESCALE_2 (1) +# define LPI2C_MCFGR1_PRESCALE_4 (2) +# define LPI2C_MCFGR1_PRESCALE_8 (3) +# define LPI2C_MCFGR1_PRESCALE_16 (4) +# define LPI2C_MCFGR1_PRESCALE_32 (5) +# define LPI2C_MCFGR1_PRESCALE_64 (6) +# define LPI2C_MCFGR1_PRESCALE_128 (7) +#define LPI2C_MCFGR1_AUTOSTOP (1 << 8) /* Automatic STOP Generation Bit */ +#define LPI2C_MCFGR1_IGNACK (1 << 9) /* Ignore NACK Bit */ +#define LPI2C_MCFGR1_TIMECFG (1 << 10) /* Timeout Configuration Bit */ + /* Bits 15-11 Reserved */ +#define LPI2C_MCFGR1_MATCFG_SHIFT (16) +#define LPI2C_MCFGR1_MATCFG_MASK (7 << LPI2C_MCFGR1_MATCFG_SHIFT) /* Match Configuration Bit Mask */ +#define LPI2C_MCFGR1_MATCFG(n) (((n) << LPI2C_MCFGR1_MATCFG_SHIFT) & LPI2C_MCFGR1_MATCFG_MASK) +# define LPI2C_MCFGR1_MATCFG_DISABLE (0 << LPI2C_MCFGR1_MATCFG_SHIFT) + /* LPI2C_MCFG1_MATCFG = 001b Reserved */ +# define LPI2C_MCFGR1_MATCFG2 (2 << LPI2C_MCFGR1_MATCFG_SHIFT) +# define LPI2C_MCFGR1_MATCFG3 (3 << LPI2C_MCFGR1_MATCFG_SHIFT) +# define LPI2C_MCFGR1_MATCFG4 (4 << LPI2C_MCFGR1_MATCFG_SHIFT) +# define LPI2C_MCFGR1_MATCFG5 (5 << LPI2C_MCFGR1_MATCFG_SHIFT) +# define LPI2C_MCFGR1_MATCFG6 (6 << LPI2C_MCFGR1_MATCFG_SHIFT) +# define LPI2C_MCFGR1_MATCFG7 (7 << LPI2C_MCFGR1_MATCFG_SHIFT) + /* Bits 23-19 Reserved */ +#define LPI2C_MCFGR1_PINCFG_SHIFT (24) +#define LPI2C_MCFGR1_PINCFG_MASK (7 << LPI2C_MCFGR1_PINCFG_SHIFT) /* Pin Configuration Bit Mask */ +#define LPI2C_MCFGR1_PINCFG(n) (((n) << LPI2C_MCFGR1_PINCFG_SHIFT) & LPI2C_MCFGR1_PINCFG_MASK) +# define LPI2C_MCFGR1_PINCFG0 (0 << LPI2C_MCFGR1_PINCFG_SHIFT) +# define LPI2C_MCFGR1_PINCFG1 (1 << LPI2C_MCFGR1_PINCFG_SHIFT) +# define LPI2C_MCFGR1_PINCFG2 (2 << LPI2C_MCFGR1_PINCFG_SHIFT) +# define LPI2C_MCFGR1_PINCFG3 (3 << LPI2C_MCFGR1_PINCFG_SHIFT) +# define LPI2C_MCFGR1_PINCFG4 (4 << LPI2C_MCFGR1_PINCFG_SHIFT) +# define LPI2C_MCFGR1_PINCFG5 (5 << LPI2C_MCFGR1_PINCFG_SHIFT) +# define LPI2C_MCFGR1_PINCFG6 (6 << LPI2C_MCFGR1_PINCFG_SHIFT) +# define LPI2C_MCFGR1_PINCFG7 (7 << LPI2C_MCFGR1_PINCFG_SHIFT) + /* Bits 31-27 Reserved */ + +/* LPI2C Master Config Register 2 */ + +#define LPI2C_MCFG2_BUSIDLE_MASK (0xfff << 0) /* Bus Idle Timeout Period in Clock Cycles */ +#define LPI2C_MCFG2_BUSIDLE_DISABLE (0) +#define LPI2C_MCFG2_BUSIDLE(n) ((n) & LPI2C_MCFG2_BUSIDLE_MASK) + /* Bits 15-12 Reserved */ +#define LPI2C_MCFG2_FILTSCL_SHIFT (16) +#define LPI2C_MCFG2_FILTSCL_MASK (15 << LPI2C_MCFG2_FILTSCL_SHIFT) /* Glitch Filter SCL */ +#define LPI2C_MCFG2_FILTSCL_DISABLE (0 << LPI2C_MCFG2_FILTSCL_SHIFT) +#define LPI2C_MCFG2_FILTSCL_CYCLES(n) (((n) << LPI2C_MCFG2_FILTSCL_SHIFT) & LPI2C_MCFG2_FILTSCL_MASK) + /* Bits 23-20 Reserved */ +#define LPI2C_MCFG2_FILTSDA_SHIFT (24) +#define LPI2C_MCFG2_FILTSDA_MASK (15 << LPI2C_MCFG2_FILTSDA_SHIFT) /* Glitch Filter SDA */ +#define LPI2C_MCFG2_FILTSDA_DISABLE (0 << LPI2C_MCFG2_FILTSDA_SHIFT) +#define LPI2C_MCFG2_FILTSDA_CYCLES(n) (((n) << LPI2C_MCFG2_FILTSDA_SHIFT) & LPI2C_MCFG2_FILTSDA_MASK) + /* Bits 31-28 Reserved */ + +/* LPI2C Master Config Register 3 */ + + /* Bits 7-0 Reserved */ +#define LPI2C_MCFG3_PINLOW_SHIFT (8) +#define LPI2C_MCFG3_PINLOW_MASK (0xfff << LPI2C_MCFG3_PINLOW_SHIFT) /* Configure The Pin Low Timeout in Clock Cycles */ +#define LPI2C_MCFG3_PINLOW_CYCLES(n) (((n) << LPI2C_MCFG3_PINLOW_SHIFT) & LPI2C_MCFG3_PINLOW_MASK) + /* Bits 31-20 Reserved */ + +/* LPI2C Master Data Match Register */ + +#define LPI2C_MDMR_MATCH0_SHIFT (0) +#define LPI2C_MDMR_MATCH0_MASK (0xff << LPI2C_MDMR_MATCH0_SHIFT) /* Match 0 Value */ +#define LPI2C_MDMR_MATCH0(n) (((n) << LPI2C_MDMR_MATCH0_SHIFT) & LPI2C_MDMR_MATCH0_MASK) + /* Bits 15-8 Reserved */ +#define LPI2C_MDMR_MATCH1_SHIFT (16) +#define LPI2C_MDMR_MATCH1_MASK (0xff << LPI2C_MDMR_MATCH1_SHIFT) /* Match 1 Value */ +#define LPI2C_MDMR_MATCH1(n) (((n) << LPI2C_MDMR_MATCH1_SHIFT) & LPI2C_MDMR_MATCH1_MASK) + /* Bits 31-24 Reserved */ + +/* LPI2C Master Clock Configuration Register 0 */ + +#define LPI2C_MCCR0_CLKLO_SHIFT (0) +#define LPI2C_MCCR0_CLKLO_MASK (0x3f << LPI2C_MCCR0_CLKLO_SHIFT) /* Clock Low Period */ +#define LPI2C_MCCR0_CLKLO(n) (((n) << LPI2C_MCCR0_CLKLO_SHIFT) & LPI2C_MCCR0_CLKLO_MASK) + /* Bits 7-6 Reserved */ +#define LPI2C_MCCR0_CLKHI_SHIFT (8) +#define LPI2C_MCCR0_CLKHI_MASK (0x3f << LPI2C_MCCR0_CLKHI_SHIFT) /* Clock High Period */ +#define LPI2C_MCCR0_CLKHI(n) (((n) << LPI2C_MCCR0_CLKHI_SHIFT) & LPI2C_MCCR0_CLKHI_MASK) + /* Bits 15-14 Reserved */ +#define LPI2C_MCCR0_SETHOLD_SHIFT (16) +#define LPI2C_MCCR0_SETHOLD_MASK (0x3f << LPI2C_MCCR0_SETHOLD_SHIFT) /* Setup Hold Delay */ +#define LPI2C_MCCR0_SETHOLD(n) (((n) << LPI2C_MCCR0_SETHOLD_SHIFT) & LPI2C_MCCR0_SETHOLD_MASK) + /* Bits 23-22 Reserved */ +#define LPI2C_MCCR0_DATAVD_SHIFT (24) +#define LPI2C_MCCR0_DATAVD_MASK (0x3f << LPI2C_MCCR0_DATAVD_SHIFT) /* Setup Hold Delay */ +#define LPI2C_MCCR0_DATAVD(n) (((n) << LPI2C_MCCR0_DATAVD_SHIFT) & LPI2C_MCCR0_DATAVD_MASK) + /* Bits 31-30 Reserved */ + +/* LPI2C Master Clock Configuration Register 1 */ + +#define LPI2C_MCCR1_CLKLO_SHIFT (0) +#define LPI2C_MCCR1_CLKLO_MASK (0x3f << LPI2C_MCCR1_CLKLO_SHIFT) /* Clock Low Period */ +#define LPI2C_MCCR1_CLKLO(n) (((n) << LPI2C_MCCR1_CLKLO_SHIFT) & LPI2C_MCCR1_CLKLO_MASK) + /* Bits 7-6 Reserved */ +#define LPI2C_MCCR1_CLKHI_SHIFT (8) +#define LPI2C_MCCR1_CLKHI_MASK (0x3f << LPI2C_MCCR1_CLKHI_SHIFT) /* Clock High Period */ +#define LPI2C_MCCR1_CLKHI(n) (((n) << LPI2C_MCCR1_CLKHI_SHIFT) & LPI2C_MCCR1_CLKHI_MASK) + /* Bits 15-14 Reserved */ +#define LPI2C_MCCR1_SETHOLD_SHIFT (16) +#define LPI2C_MCCR1_SETHOLD_MASK (0x3f << LPI2C_MCCR1_SETHOLD_SHIFT) /* Setup Hold Delay */ +#define LPI2C_MCCR1_SETHOLD(n) (((n) << LPI2C_MCCR1_SETHOLD_SHIFT) & LPI2C_MCCR1_SETHOLD_MASK) + + /* Bits 23-22 Reserved */ +#define LPI2C_MCCR1_DATAVD_SHIFT (24) +#define LPI2C_MCCR1_DATAVD_MASK (0x3f << LPI2C_MCCR1_DATAVD_SHIFT) /* Setup Hold Delay */ +#define LPI2C_MCCR1_DATAVD(n) (((n) << LPI2C_MCCR1_DATAVD_SHIFT) & LPI2C_MCCR1_DATAVD_MASK) + + /* Bits 31-30 Reserved */ + +/* LPI2C Master FIFO Control Register */ + +#define LPI2C_MFCR_TXWATER_SHIFT (0) +#define LPI2C_MFCR_TXWATER_MASK (3 << LPI2C_MFCR_TXWATER_SHIFT) /* Transmit FIFO Watermark*/ + +#define LPI2C_MFCR_TXWATER(n) (((n) << LPI2C_MFCR_TXWATER_SHIFT) & LPI2C_MFCR_TXWATER_MASK) /* Transmit FIFO Watermark */ + + /* Bits 15-2 Reserved */ +#define LPI2C_MFCR_RXWATER_SHIFT (16) +#define LPI2C_MFCR_RXWATER_MASK (3 << LPI2C_MFCR_RXWATER_SHIFT) /* Receive FIFO Watermark */ + +#define LPI2C_MFCR_RXWATER(n) (((n) << LPI2C_MFCR_RXWATER_SHIFT) & LPI2C_MFCR_RXWATER_MASK) /* Transmit FIFO Watermark */ + + /* Bits 31-18 Reserved */ + +/* LPI2C Master FIFO Status Register */ + +#define LPI2C_MFSR_TXCOUNT_SHIFT (0) +#define LPI2C_MFSR_TXCOUNT_MASK (3 << LPI2C_MFSR_TXCOUNT_SHIFT) /* Transmit FIFO Count */ + + /* Bits 15-2 Reserved */ +#define LPI2C_MFSR_RXCOUNT_SHIFT (16) +#define LPI2C_MFSR_RXCOUNT_MASK (3 << LPI2C_MFSR_RXCOUNT_SHIFT) /* Receive FIFO Count */ + + /* Bits 31-18 Reserved */ + +/* LPI2C Master Transmit Data Register */ + +#define LPI2C_MTDR_DATA_SHIFT (0) +#define LPI2C_MTDR_DATA_MASK (0xff << LPI2C_MTDR_DATA_SHIFT) /* Transmit Data */ +#define LPI2C_MTDR_DATA(n) ((n) & LPI2C_MTDR_DATA_MASK) +#define LPI2C_MTDR_CMD_SHIFT (8) +#define LPI2C_MTDR_CMD_MASK (7 << LPI2C_MTDR_CMD_SHIFT) /* Command Data */ +#define LPI2C_MTDR_CMD(n) (((n) << LPI2C_MTDR_CMD_SHIFT) & LPI2C_MTDR_CMD_MASK) +# define LPI2C_MTDR_CMD_TXD (0 << LPI2C_MTDR_CMD_SHIFT) +# define LPI2C_MTDR_CMD_RXD (1 << LPI2C_MTDR_CMD_SHIFT) +# define LPI2C_MTDR_CMD_STOP (2 << LPI2C_MTDR_CMD_SHIFT) +# define LPI2C_MTDR_CMD_RXD_DISC (3 << LPI2C_MTDR_CMD_SHIFT) +# define LPI2C_MTDR_CMD_START (4 << LPI2C_MTDR_CMD_SHIFT) +# define LPI2C_MTDR_CMD_START_NACK (5 << LPI2C_MTDR_CMD_SHIFT) +# define LPI2C_MTDR_CMD_START_HI (6 << LPI2C_MTDR_CMD_SHIFT) +# define LPI2C_MTDR_CMD_START_HI_NACK (7 << LPI2C_MTDR_CMD_SHIFT) + + /* Bits 31-11 Reserved */ + +/* LPI2C Master Receive Data Register */ + +#define LPI2C_MRDR_DATA_SHIFT (0) +#define LPI2C_MRDR_DATA_MASK (0xff << LPI2C_MRDR_DATA_SHIFT) /* Receive Data */ + + /* Bits 13-8 Reserved */ +#define LPI2C_MRDR_RXEMPTY_SHIFT (14) +#define LPI2C_MRDR_RXEMPTY_MASK (1 << LPI2C_MRDR_RXEMPTY_SHIFT) /* Rx Empty */ + + /* Bits 31-15 Reserved */ + +/* LPI2C Slave Control Register */ + +#define LPI2C_SCR_SEN (1 << 0) /* Slave Enable Bit */ +#define LPI2C_SCR_RST (1 << 1) /* Software Reset Bit */ + /* Bits 3-2 Reserved */ +#define LPI2C_SCR_FILTEN (1 << 4) /* Filter Enable Bit */ +#define LPI2C_SCR_FILTDZ (1 << 5) /* Filter Doze Enable Bit */ + /* Bits 7-4 Reserved */ +#define LPI2C_SCR_RTF (1 << 8) /* Reset Transmit FIFO Bit */ +#define LPI2C_SCR_RRF (1 << 9) /* Reset Receive FIFO Bit */ + /* Bits 31-10 Reserved */ + +/* LPI2C Slave Status Register */ + +#define LPI2C_SSR_TDF (1 << 0) /* Transmit Data Flag Bit */ +#define LPI2C_SSR_RDF (1 << 1) /* Receive Data Flag Bit */ +#define LPI2C_SSR_AVF (1 << 2) /* Address Valid Flag Bit */ +#define LPI2C_SSR_TAF (1 << 3) /* Transmit ACK Flag Bit */ + /* Bits 7-4 Reserved */ +#define LPI2C_SSR_RSF (1 << 8) /* Repeated Start Flag Bit */ +#define LPI2C_SSR_SDF (1 << 9) /* STOP Detect Flag Bit */ +#define LPI2C_SSR_BEF (1 << 10) /* Bit Error Flag Bit */ +#define LPI2C_SSR_FEF (1 << 11) /* FIFO Error Flag Bit */ +#define LPI2C_SSR_AM0F (1 << 12) /* Address Match 0 Flag Bit */ +#define LPI2C_SSR_AM1F (1 << 13) /* Address Match 1 Flag Bit */ +#define LPI2C_SSR_GCF (1 << 14) /* General Call Flag Bit */ +#define LPI2C_SSR_SARF (1 << 15) /* SMBus Alert Response Flag Bit */ + /* Bits 23-16 Reserved */ +#define LPI2C_MSR_SBF (1 << 24) /* Slave Busy Flag Bit */ +#define LPI2C_MSR_BBF (1 << 25) /* Bus Busy Flag Bit */ + /* Bits 31-26 Reserved */ + +/* LPI2C Slave Interrupt Enable Register */ + +#define LPI2C_SIER_TDIE (1 << 0) /* Transmit Data Interrupt Enable Bit */ +#define LPI2C_SIER_RDIE (1 << 1) /* Receive Data Interrupt Enable Bit */ +#define LPI2C_SIER_AVIE (1 << 2) /* Address Valid Interrupt Enable Bit */ +#define LPI2C_SIER_TAIE (1 << 3) /* Transmit ACK Interrupt Enable Bit */ + /* Bits 7-4 Reserved */ +#define LPI2C_SIER_RSIE (1 << 8) /* Repeated Start Interrupt Enable Bit */ +#define LPI2C_SIER_SDIE (1 << 9) /* STOP Detect Interrupt Enable Bit */ +#define LPI2C_SIER_BEIE (1 << 10) /* Bit Error Interrupt Enable Bit */ +#define LPI2C_SIER_FEIE (1 << 11) /* FIFO Error Interrupt Enable Bit */ +#define LPI2C_SIER_AM0IE (1 << 12) /* Address Match 0 Interrupt Enable Bit */ +#define LPI2C_SIER_AM1IE (1 << 13) /* Address Match 1 Interrupt Enable Bit */ +#define LPI2C_SIER_GCIE (1 << 14) /* General Call Interrupt Enable Bit */ +#define LPI2C_SIER_SARIE (1 << 15) /* SMBus Alert Response Interrupt Enable Bit */ + /* Bits 31-16 Reserved */ + +/* LPI2C Slave DMA Enable Register */ + +#define LPI2C_SDER_TDDE (1 << 0) /* Transmit Data DMA Enable Bit */ +#define LPI2C_SDER_RDDE (1 << 1) /* Transmit Data DMA Enable Bit */ +#define LPI2C_SDER_AVDE (1 << 2) /* Address Valid DMA Enable Bit */ + /* Bits 31-3 Reserved */ + +/* LPI2C Slave Configuration Register 1 */ + +#define LPI2C_SCFGR1_ADRSTALL (1 << 0) /* Address SCL Stall */ +#define LPI2C_SCFGR1_RXSTALL (1 << 1) /* RX SCL Stall */ +#define LPI2C_SCFGR1_TXSTALL (1 << 2) /* TX Data SCL Stall */ +#define LPI2C_SCFGR1_ACKSTALL (1 << 3) /* ACK SCL Stall */ + /* Bits 7-4 Reserved */ +#define LPI2C_SCFGR1_GCEN (1 << 8) /* General Call Enable */ +#define LPI2C_SCFGR1_SAEN (1 << 9) /* SMBus Alert Enable */ +#define LPI2C_SCFGR1_TXCFG (1 << 10) /* Transmit Flag Configuration */ +#define LPI2C_SCFGR1_RXCFG (1 << 11) /* Receive Data Configuration */ +#define LPI2C_SCFGR1_IFNACK (1 << 12) /* Ignore NACK */ +#define LPI2C_SCFGR1_HSMEN (1 << 13) /* High Speed Mode Enable */ + /* Bits 15-14 Reserved */ +#define LPI2C_SCFG1_ADDRCFG_SHIFT (16) +#define LPI2C_SCFG1_ADDRCFG_MASK (7 << LPI2C_SCFG1_ADDRCFG_SHIFT) /* Address Configuration Bit Mask */ +#define LPI2C_SCFG1_ADDRCFG(n) (((n) << LPI2C_SCFG1_ADDRCFG_SHIFT) & LPI2C_SCFG1_ADDRCFG_MASK) +# define LPI2C_SCFG1_ADDRCFG0 (0 << LPI2C_SCFG1_ADDRCFG_SHIFT) +# define LPI2C_SCFG1_ADDRCFG1 (2 << LPI2C_SCFG1_ADDRCFG_SHIFT) +# define LPI2C_SCFG1_ADDRCFG2 (2 << LPI2C_SCFG1_ADDRCFG_SHIFT) +# define LPI2C_SCFG1_ADDRCFG3 (3 << LPI2C_SCFG1_ADDRCFG_SHIFT) +# define LPI2C_SCFG1_ADDRCFG4 (4 << LPI2C_SCFG1_ADDRCFG_SHIFT) +# define LPI2C_SCFG1_ADDRCFG5 (5 << LPI2C_SCFG1_ADDRCFG_SHIFT) +# define LPI2C_SCFG1_ADDRCFG6 (6 << LPI2C_SCFG1_ADDRCFG_SHIFT) +# define LPI2C_SCFG1_ADDRCFG7 (7 << LPI2C_SCFG1_ADDRCFG_SHIFT) + /* Bits 31-19 Reserved */ + +/* LPI2C Slave Configuration Register 2 */ + +#define LPI2C_SCFG2_CLKHOLD_MASK (15 << 0) /* Clock Hold Time */ +#define LPI2C_SCFG2_CLKHOLD(n) ((n) & LPI2C_SCFG2_CLKHOLD_MASK) + /* Bits 7-4 Reserved */ +#define LPI2C_SCFG2_DATAVD_SHIFT (8) +#define LPI2C_SCFG2_DATAVD_MASK (0x3f << LPI2C_SCFG2_DATAVD_SHIFT) /* Data Valid Delay */ +#define LPI2C_SCFG2_DATAVD(n) (((n) << LPI2C_SCFG2_DATAVD_SHIFT) & LPI2C_SCFG2_DATAVD_MASK) + /* Bits 15-14 Reserved */ +#define LPI2C_SCFG2_FILTSCL_SHIFT (16) +#define LPI2C_SCFG2_FILTSCL_MASK (15 << LPI2C_SCFG2_FILTSCL_SHIFT) /* Glitch Filter SCL */ +#define LPI2C_SCFG2_FILTSCL_DISABLE (0 << LPI2C_SCFG2_FILTSCL_SHIFT) +#define LPI2C_SCFG2_FILTSCL_CYCLES(n) (((n) << LPI2C_SCFG2_FILTSCL_SHIFT) & LPI2C_SCFG2_FILTSCL_MASK) + /* Bits 23-20 Reserved */ +#define LPI2C_SCFG2_FILTSDA_SHIFT (24) +#define LPI2C_SCFG2_FILTSDA_MASK (15 << LPI2C_SCFG2_FILTSDA_SHIFT) /* Glitch Filter SDA */ +#define LPI2C_SCFG2_FILTSDA_DISABLE (0 << LPI2C_SCFG2_FILTSDA_SHIFT) +#define LPI2C_SCFG2_FILTSDA_CYCLES(n) (((n) << LPI2C_SCFG2_FILTSDA_SHIFT) & LPI2C_SCFG2_FILTSDA_MASK) + /* Bits 31-28 Reserved */ + +/* LPI2C Slave Address Match Register */ + + /* Bit 0 Reserved */ +#define LPI2C_SAMR_ADDR0_SHIFT (1) +#define LPI2C_SAMR_ADDR0_MASK (0x3ff << LPI2C_SAMR_ADDR0_SHIFT) /* Address 0 Value */ +#define LPI2C_SAMR_ADDR0(n) (((n) << LPI2C_SAMR_ADDR0_SHIFT) & LPI2C_SAMR_ADDR0_MASK) + /* Bits 16-11 Reserved */ +#define LPI2C_SAMR_ADDR1_SHIFT (17) +#define LPI2C_SAMR_ADDR1_MASK (0x3ff << LPI2C_SAMR_ADDR1_SHIFT) /* Address 1 Value */ +#define LPI2C_SAMR_ADDR1(n) (((n) << LPI2C_SAMR_ADDR1_SHIFT) & LPI2C_SAMR_ADDR1_MASK) + /* Bits 31-27 Reserved */ + +/* LPI2C Slave Address Status Register */ + +#define LPI2C_SASR_RADDR_MASK (0x7ff << 0) /* Received Address */ + +/* Bits 16-11 + * Reserved + */ + +#define LPI2C_SASR_ANV (1 << 14) /* Address Not Valid */ + /* Bits 31-15 Reserved */ + +/* LPI2C Slave Transmit ACK Register */ + +#define LPI2C_STAR_TXNACK (1 << 0) /* Transmit NACK */ + /* Bits 31-1 Reserved */ + +/* LPI2C Slave Transmit Data Register */ + +#define LPI2C_STDR_DATA_SHIFT (0) +#define LPI2C_STDR_DATA_MASK (0xff << LPI2C_STDR_DATA_SHIFT) /* Transmit Data */ +#define LPI2C_STDR_DATA(n) (((n) << LPI2C_STDR_DATA_SHIFT) & LPI2C_STDR_DATA_MASK) + /* Bits 31-8 Reserved */ + +/* LPI2C Slave Receive Data Register */ + +#define LPI2C_SRDR_DATA_SHIFT (0) +#define LPI2C_SRDR_DATA_MASK (0xff << LPI2C_SRDR_DATA_SHIFT) /* Receive Data */ +#define LPI2C_SRDR_DATA(n) (((n) << LPI2C_SRDR_DATA_SHIFT) & LPI2C_SRDR_DATA_MASK) + /* Bits 13-8 Reserved */ +#define LPI2C_STAR_SOF (1 << 14) /* RX Empty */ +#define LPI2C_STAR_RXEMPTY (1 << 15) /* Start Of Frame */ + /* Bits 31-16 Reserved */ + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPI2C_H_ */ diff --git a/arch/arm64/src/imx9/hardware/imx9_lpit.h b/arch/arm64/src/imx9/hardware/imx9_lpit.h new file mode 100644 index 0000000000000..5d1d32b494396 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_lpit.h @@ -0,0 +1,125 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_lpit.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPIT_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPIT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define IMX9_LPIT_VERID_OFFSET 0x0000 /* Version ID */ +#define IMX9_LPIT_PARAM_OFFSET 0x0004 /* Parameter */ +#define IMX9_LPIT_MCR_OFFSET 0x0008 /* Module Control */ +#define IMX9_LPIT_MSR_OFFSET 0x000c /* Module Status Register */ +#define IMX9_LPIT_MIER_OFFSET 0x0010 /* Moduel Interrupt Enable */ +#define IMX9_LPIT_SETTEN_OFFSET 0x0014 /* Set Timer Enable */ +#define IMX9_LPIT_CLRTEN_OFFSET 0x0018 /* Clear Timer Enable */ +#define IMX9_LPIT_TVAL0_OFFSET 0x0020 /* Timer Channel 0 Value */ +#define IMX9_LPIT_CVAL0_OFFSET 0x0024 /* Current Timer Channel 0 Value */ +#define IMX9_LPIT_TCTRL0_OFFSET 0x0028 /* Timer Channel 0 Control */ +#define IMX9_LPIT_TVAL1_OFFSET 0x0030 /* Timer Channel 1 Value */ +#define IMX9_LPIT_CVAL1_OFFSET 0x0034 /* Current Timer Channel 1 Value */ +#define IMX9_LPIT_TCTRL1_OFFSET 0x0048 /* Timer Channel 1 Control */ +#define IMX9_LPIT_TVAL2_OFFSET 0x0040 /* Timer Channel 2 Value */ +#define IMX9_LPIT_CVAL2_OFFSET 0x0044 /* Current Timer Channel 2 Value */ +#define IMX9_LPIT_TCTRL2_OFFSET 0x0048 /* Timer Channel 2 Control */ +#define IMX9_LPIT_TVAL3_OFFSET 0x0050 /* Timer Channel 3 Value */ +#define IMX9_LPIT_CVAL3_OFFSET 0x0054 /* Current Timer Channel 3 Value */ +#define IMX9_LPIT_TCTRL3_OFFSET 0x0058 /* Timer Channel 3 Control */ + +/* Register access */ + +#define LPIT_VERID(n) ((n) + IMX9_LPIT_VERID_OFFSET) +#define LPIT_PARAM(n) ((n) + IMX9_LPIT_PARAM_OFFSET) +#define LPIT_MCR(n) ((n) + IMX9_LPIT_MCR_OFFSET) +#define LPIT_MSR(n) ((n) + IMX9_LPIT_MSR_OFFSET) +#define LPIT_MIER(n) ((n) + IMX9_LPIT_MIER_OFFSET) +#define LPIT_SETTEN(n) ((n) + IMX9_LPIT_SETTEN_OFFSET) +#define LPIT_CLRTEN(n) ((n) + IMX9_LPIT_CLRTEN_OFFSET) +#define LPIT_TVAL0(n) ((n) + IMX9_LPIT_TVAL0_OFFSET) +#define LPIT_CVAL0(n) ((n) + IMX9_LPIT_CVAL0_OFFSET) +#define LPIT_TCTRL0(n) ((n) + IMX9_LPIT_TCTRL0_OFFSET) +#define LPIT_TVAL1(n) ((n) + IMX9_LPIT_TVAL1_OFFSET) +#define LPIT_CVAL1(n) ((n) + IMX9_LPIT_CVAL1_OFFSET) +#define LPIT_TCTRL1(n) ((n) + IMX9_LPIT_TCTRL1_OFFSET) +#define LPIT_TVAL2(n) ((n) + IMX9_LPIT_TVAL2_OFFSET) +#define LPIT_CVAL2(n) ((n) + IMX9_LPIT_CVAL2_OFFSET) +#define LPIT_TCTRL2(n) ((n) + IMX9_LPIT_TCTRL2_OFFSET) +#define LPIT_TVAL3(n) ((n) + IMX9_LPIT_TVAL3_OFFSET) +#define LPIT_CVAL3(n) ((n) + IMX9_LPIT_CVAL3_OFFSET) +#define LPIT_TCTRL3(n) ((n) + IMX9_LPIT_TCTRL3_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +#define LPIT_PARAM_EXT_TRIG_SHIFT (8) /* Bit[15:8]: Number of External Trigger Inputs */ +#define LPIT_PARAM_EXT_TRIG_MASK (0xff << LPIT_PARAM_EXT_TRIG_SHIFT) + +#define LPIT_PARAM_CHANNEL_SHIFT (0) /* Bit[7:0]: Number of Timer Channels */ +#define LPIT_PARAM_CHANNEL_MASK (0xff << LPIT_PARAM_CHANNEL_SHIFT) + +#define LPIT_MCR_DBG_EN (1 << 3) /* Stop Timer when in Debug Mode */ +#define LPIT_MCR_DOZE_EN (1 << 2) /* DOZE Mode Enable */ +#define LPIT_MCR_SW_RST (1 << 1) /* Software Reset Bit */ +#define LPIT_MCR_M_CEN (1 << 0) /* Module Clock Enable */ + +#define LPIT_MSR_TIF3 (1 << 3) /* Channel 3 Timer Interrupt Flag */ +#define LPIT_MSR_TIF2 (1 << 2) /* Channel 2 Timer Interrupt Flag */ +#define LPIT_MSR_TIF1 (1 << 1) /* Channel 1 Timer Interrupt Flag */ +#define LPIT_MSR_TIF0 (1 << 0) /* Channel 0 Timer Interrupt Flag */ + +#define LPIT_MIER_TIE3 (1 << 3) /* Channel 3 Timer Interrupt Enable */ +#define LPIT_MIER_TIE2 (1 << 2) /* Channel 2 Timer Interrupt Enable */ +#define LPIT_MIER_TIE1 (1 << 1) /* Channel 1 Timer Interrupt Enable */ +#define LPIT_MIER_TIE0 (1 << 0) /* Channel 0 Timer Interrupt Enable */ + +#define LPIT_TCTRL_TRG_SEL_SHIFT (27) /* Bit[27:24]: Trigger Select */ +#define LPIT_TCTRL_TRG_SEL_MASK (0xf << LPIT_TCTRL_TRG_SEL_SHIFT) +#define LPIT_TCTRL_TRG_SEL_CHAN0 (0 << LPIT_TCTRL_TRG_SEL_SHIFT) +#define LPIT_TCTRL_TRG_SEL_CHAN1 (1 << LPIT_TCTRL_TRG_SEL_SHIFT) +#define LPIT_TCTRL_TRG_SEL_CHAN2 (2 << LPIT_TCTRL_TRG_SEL_SHIFT) +#define LPIT_TCTRL_TRG_SEL_CHAN3 (3 << LPIT_TCTRL_TRG_SEL_SHIFT) + +#define LPIT_TCTRL_TRG_SRC_SHIFT (23) /* Bit23: Trigger Source */ +#define LPIT_TCTRL_TRG_SRC_MASK (1 << LPIT_TCTRL_TRG_SRC_SHIFT) +#define LPIT_TCTRL_TRG_SRC_EXTER (0 << LPIT_TCTRL_TRG_SRC_SHIFT) /* external */ +#define LPIT_TCTRL_TRG_SRC_INTER (1 << LPIT_TCTRL_TRG_SRC_SHIFT) /* internal */ + +#define LPIT_TCTRL_TROT (1 << 18) /* Timer Reload On Trigger */ +#define LPIT_TCTRL_TSOI (1 << 17) /* Timer Stop On Interrupt */ +#define LPIT_TCTRL_TSOT (1 << 16) /* Timer Start On Trigger */ + +#define LPIT_TCTRL_MODE_SHIFT (2) +#define LPIT_TCTRL_MODE_MASK (3 << LPIT_TCTRL_MODE_SHIFT) +#define LPIT_TCTRL_MODE_32PC (0 << LPIT_TCTRL_MODE_SHIFT) /* 32 Bit periodic Counter */ +#define LPIT_TCTRL_MODE_D16PC (1 << LPIT_TCTRL_MODE_SHIFT) /* Dual 16-bit periodic Counter */ +#define LPIT_TCTRL_MODE_32TA (2 << LPIT_TCTRL_MODE_SHIFT) /* 32 bit Trigger Accumulator */ +#define LPIT_TCTRL_MODE_32TIC (3 << LPIT_TCTRL_MODE_SHIFT) /* 32 bit Trigger Input Capture */ + +#define LPIT_TCTRL_CHAIN (1 << 1) /* Chain Channel */ +#define LPIT_TCTRL_T_EN (1 << 0) /* Timer Enable */ + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPIT_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_lpspi.h b/arch/arm64/src/imx9/hardware/imx9_lpspi.h new file mode 100644 index 0000000000000..06f7b02dc5227 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_lpspi.h @@ -0,0 +1,351 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_lpspi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPSPI_H_ +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPSPI_H_ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register offsets *********************************************************/ + +#define IMX9_LPSPI_VERID_OFFSET (0x0000) /* Version ID Register (VERID) */ +#define IMX9_LPSPI_PARAM_OFFSET (0x0004) /* Parameter Register (PARAM) */ +#define IMX9_LPSPI_CR_OFFSET (0x0010) /* Control Register (CR) */ +#define IMX9_LPSPI_SR_OFFSET (0x0014) /* Status Register (SR) */ +#define IMX9_LPSPI_IER_OFFSET (0x0018) /* Interrupt Enable Register (IER) */ +#define IMX9_LPSPI_DER_OFFSET (0x001c) /* DMA Enable Register (DER) */ +#define IMX9_LPSPI_CFGR0_OFFSET (0x0020) /* Configuration Register 0 (CFGR0) */ +#define IMX9_LPSPI_CFGR1_OFFSET (0x0024) /* Configuration Register 1 (CFGR1) */ +#define IMX9_LPSPI_DMR0_OFFSET (0x0030) /* Data Match Register 0 (DMR0) */ +#define IMX9_LPSPI_DMR1_OFFSET (0x0034) /* Data Match Register 1 (DMR1) */ +#define IMX9_LPSPI_CCR_OFFSET (0x0040) /* Clock Configuration Register (CCR) */ +#define IMX9_LPSPI_CCR1_OFFSET (0x0044) /* Clock Configuration Register 1 (CCR1) */ +#define IMX9_LPSPI_FCR_OFFSET (0x0058) /* FIFO Control Register (FCR) */ +#define IMX9_LPSPI_FSR_OFFSET (0x005c) /* FIFO Status Register (FSR) */ +#define IMX9_LPSPI_TCR_OFFSET (0x0060) /* Transmit Command Register (TCR) */ +#define IMX9_LPSPI_TDR_OFFSET (0x0064) /* Transmit Data Register (TDR) */ +#define IMX9_LPSPI_RSR_OFFSET (0x0070) /* Receive Status Register (RSR) */ +#define IMX9_LPSPI_RDR_OFFSET (0x0074) /* Receive Data Register (RDR) */ +#define IMX9_LPSPI_RDROR_OFFSET (0x0078) /* Receive Data Read Only Register (RDROR) */ +#define IMX9_LPSPI_TCBR_OFFSET (0x03fc) /* Transmit Command Burst Register (TCBR) */ + +#define IMX9_LPSPI_TDBR_OFFSET(n) (0x0400 + ((n) << 2)) /* Transmit Data Burst Register n=0..127 (TDBRn) */ +#define IMX9_LPSPI_RDBR_OFFSET(n) (0x0600 + ((n) << 2)) /* Receive Data Burst Register n=0..127 (RDBRn) */ + +/* Register addresses *******************************************************/ + +#define IMX9_LPSPI0_VERID(n) ((n) + IMX9_LPSPI_VERID_OFFSET) +#define IMX9_LPSPI0_PARAM(n) ((n) + IMX9_LPSPI_PARAM_OFFSET) +#define IMX9_LPSPI0_CR(n) ((n) + IMX9_LPSPI_CR_OFFSET) +#define IMX9_LPSPI0_SR(n) ((n) + IMX9_LPSPI_SR_OFFSET) +#define IMX9_LPSPI0_IER(n) ((n) + IMX9_LPSPI_IER_OFFSET) +#define IMX9_LPSPI0_DER(n) ((n) + IMX9_LPSPI_DER_OFFSET) +#define IMX9_LPSPI0_CFGR0(n) ((n) + IMX9_LPSPI_CFGR0_OFFSET) +#define IMX9_LPSPI0_CFGR1(n) ((n) + IMX9_LPSPI_CFGR1_OFFSET) +#define IMX9_LPSPI0_DMR0(n) ((n) + IMX9_LPSPI_DMR0_OFFSET) +#define IMX9_LPSPI0_DMR1(n) ((n) + IMX9_LPSPI_DMR1_OFFSET) +#define IMX9_LPSPI0_CCR(n) ((n) + IMX9_LPSPI_CCR_OFFSET) +#define IMX9_LPSPI0_CCR1(n) ((n) + IMX9_LPSPI_CCR1_OFFSET) +#define IMX9_LPSPI0_FCR(n) ((n) + IMX9_LPSPI_FCR_OFFSET) +#define IMX9_LPSPI0_FSR(n) ((n) + IMX9_LPSPI_FSR_OFFSET) +#define IMX9_LPSPI0_TCR(n) ((n) + IMX9_LPSPI_TCR_OFFSET) +#define IMX9_LPSPI0_TDR(n) ((n) + IMX9_LPSPI_TDR_OFFSET) +#define IMX9_LPSPI0_RSR(n) ((n) + IMX9_LPSPI_RSR_OFFSET) +#define IMX9_LPSPI0_RDR(n) ((n) + IMX9_LPSPI_RDR_OFFSET) +#define IMX9_LPSPI0_RDROR(n) ((n) + IMX9_LPSPI_RDROR_OFFSET) +#define IMX9_LPSPI0_TCBR(n) ((n) + IMX9_LPSPI_TCBR_OFFSET) +#define IMX9_LPSPI0_TDBR(n,v) ((n) + IMX9_LPSPI_TDBR_OFFSET(v)) +#define IMX9_LPSPI0_RDBR(n,v) ((n) + IMX9_LPSPI_RDBR_OFFSET(v)) + +/* Register bit definitions *************************************************/ + +/* Version ID Register (VERID) */ + +#define LPSPI_VERID_FEATURE_SHIFT (0) /* Bits 0-15: Module Identification Number (FEATURE) */ +#define LPSPI_VERID_FEATURE_MASK (0xffff << LPSPI_VERID_FEATURE_SHIFT) +#define LPSPI_VERID_MINOR_SHIFT (16) /* Bits 16-23: Minor Version Number (MINOR) */ +#define LPSPI_VERID_MINOR_MASK (0xff << LPSPI_VERID_MINOR_SHIFT) +#define LPSPI_VERID_MAJOR_SHIFT (24) /* Bits 24-31: Major Version Number (MAJOR) */ +#define LPSPI_VERID_MAJOR_MASK (0xff << LPSPI_VERID_MAJOR_SHIFT) + +/* Parameter Register (PARAM) */ + +#define LPSPI_PARAM_TXFIFO_SHIFT (0) /* Bits 0-7: Transmit FIFO Size (TXFIFO) */ +#define LPSPI_PARAM_TXFIFO_MASK (0xff << LPSPI_PARAM_TXFIFO_SHIFT) +#define LPSPI_PARAM_RXFIFO_SHIFT (8) /* Bits 8-15: Receive FIFO Size (RXFIFO) */ +#define LPSPI_PARAM_RXFIFO_MASK (0xff << LPSPI_PARAM_RXFIFO_SHIFT) +#define LPSPI_PARAM_PCSNUM_SHIFT (16) /* Bits 16-23: PCS Number (PCSNUM) */ +#define LPSPI_PARAM_PCSNUM_MASK (0xff << LPSPI_PARAM_PCSNUM_SHIFT) + /* Bits 24-31: Reserved */ + +/* Control Register (CR) */ + +#define LPSPI_CR_MEN (1 << 0) /* Bit 0: Module Enable (MEN) */ +#define LPSPI_CR_RST (1 << 1) /* Bit 1: Software Reset (RST) */ + /* Bit 2: Reserved */ +#define LPSPI_CR_DBGEN (1 << 3) /* Bit 3: Debug Enable (DBGEN) */ + /* Bits 4-7: Reserved */ +#define LPSPI_CR_RTF (1 << 8) /* Bit 8: Reset Transmit FIFO (RTF) */ +#define LPSPI_CR_RRF (1 << 9) /* Bit 9: Reset Receive FIFO (RRF) */ + /* Bits 10-31: Reserved */ + +/* Status Register (SR) */ + +#define LPSPI_SR_TDF (1 << 0) /* Bit 0: Transmit Data Flag (TDF) */ +#define LPSPI_SR_RDF (1 << 1) /* Bit 1: Receive Data Flag (RDF) */ + /* Bits 2-7: Reserved */ +#define LPSPI_SR_WCF (1 << 8) /* Bit 8: Word Complete Flag (WCF) */ +#define LPSPI_SR_FCF (1 << 9) /* Bit 9: Frame Complete Flag (FCF) */ +#define LPSPI_SR_TCF (1 << 10) /* Bit 10: Transfer Complete Flag (TCF) */ +#define LPSPI_SR_TEF (1 << 11) /* Bit 11: Transmit Error Flag (TEF) */ +#define LPSPI_SR_REF (1 << 12) /* Bit 12: Receive Error Flag (REF) */ +#define LPSPI_SR_DMF (1 << 13) /* Bit 13: Data Match Flag (DMF) */ + /* Bits 14-23: Reserved */ +#define LPSPI_SR_MBF (1 << 24) /* Bit 24: Module Busy Flag (MBF) */ + /* Bits 25-31: Reserved */ + +/* Interrupt Enable Register (IER) */ + +#define LPSPI_IER_TDIE (1 << 0) /* Bit 0: Transmit Data Interrupt Enable (TDIE) */ +#define LPSPI_IER_RDIE (1 << 1) /* Bit 1: Receive Data Interrupt Enable (RDIE) */ + /* Bits 2-7: Reserved */ +#define LPSPI_IER_WCIE (1 << 8) /* Bit 8: Word Complete Interrupt Enable (WCIE) */ +#define LPSPI_IER_FCIE (1 << 9) /* Bit 9: Frame Complete Interrupt Enable (FCIE) */ +#define LPSPI_IER_TCIE (1 << 10) /* Bit 10: Transfer Complete Interrupt Enable (TCIE) */ +#define LPSPI_IER_TEIE (1 << 11) /* Bit 11: Transmit Error Interrupt Enable (TEIE) */ +#define LPSPI_IER_REIE (1 << 12) /* Bit 12: Receive Error Interrupt Enable (REIE) */ +#define LPSPI_IER_DMIE (1 << 13) /* Bit 13: Data Match Interrupt Enable (DMIE) */ + /* Bits 14-31: Reserved */ + +/* DMA Enable Register (DER) */ + +#define LPSPI_DER_TDDE (1 << 0) /* Bit 0: Transmit Data DMA Enable (TDDE) */ +#define LPSPI_DER_RDDE (1 << 1) /* Bit 1: Receive Data DMA Enable (RDDE) */ + /* Bits 2-31: Reserved */ + +/* Configuration Register 0 (CFGR0) */ + +#define LPSPI_CFGR0_HREN (1 << 0) /* Bit 0: Host Request Enable (HREN) */ +#define LPSPI_CFGR0_HRPOL (1 << 1) /* Bit 1: Host Request Polarity (HRPOL) */ +# define LPSPI_CFGR0_HRPOL_HIGH (0 << 1) /* HREQ pin or input trigger is active high */ +# define LPSPI_CFGR0_HRPOL_LOW (1 << 1) /* HREQ pin or input trigger is active low */ +#define LPSPI_CFGR0_HRSEL (1 << 2) /* Bit 2: Host Request Select (HRSEL) */ +# define LPSPI_CFGR0_HRSEL_HREQ (0 << 2) /* Host request input is the LPSPI_HREQ pin */ +# define LPSPI_CFGR0_HRSEL_INTR (1 << 2) /* Host request input is the input trigger */ +#define LPSPI_CFGR0_HRDIR (1 << 3) /* Bit 3: Host Request Direction (HRDIR) */ +# define LPSPI_CFGR0_HRDIR_INPUT (0 << 3) /* HREQ pin is configured as input */ +# define LPSPI_CFGR0_HRDIR_OUTPUT (1 << 3) /* HREQ pin is configured as output */ + /* Bits 4-7: Reserved */ +#define LPSPI_CFGR0_CIRFIFO (1 << 8) /* Bit 8: Circular FIFO Enable (CIRCFIFO) */ +#define LPSPI_CFGR0_RDMO (1 << 9) /* Bit 9: Receive Data Match Only (RDMO) */ +# define LPSPI_CFGR0_RDMO_FIFO (0 << 9) /* Received data is stored in the receive FIFO as in normal operations */ +# define LPSPI_CFGR0_RDMO_DMF (1 << 9) /* Received data is discarded unless the Data Match Flag (DMF) is set */ + /* Bits 10-31: Reserved */ + +/* Configuration Register 1 (CFGR1) */ + +#define LPSPI_CFGR1_MASTER (1 << 0) /* Bit 0: Master Mode (MASTER) */ +#define LPSPI_CFGR1_SAMPLE (1 << 1) /* Bit 1: Sample Point (SAMPLE) */ +# define LPSPI_CFGR1_SAMPLE_SCK (0 << 1) /* Input data is sampled on SCK edge */ +# define LPSPI_CFGR1_SAMPLE_DELAY (1 << 1) /* Input data is sampled on delayed SCK edge */ +#define LPSPI_CFGR1_AUTOPCS (1 << 2) /* Bit 2: Automatic PCS (AUTOPCS) */ +#define LPSPI_CFGR1_NOSTALL (1 << 3) /* Bit 3: No Stall (NOSTALL) */ +#define LPSPI_CFGR1_PARTIAL (1 << 4) /* Bit 4: Partial Enable (PARTIAL) */ + /* Bits 5-7: Reserved */ +#define LPSPI_CFGR1_PCSPOL_SHIFT (8) /* Bits 8-15: Peripheral Chip Select Polarity (PCSPOL) */ +#define LPSPI_CFGR1_PCSPOL_MASK (0xff << LPSPI_CFGR1_PCSPOL_SHIFT) +# define LPSPI_CFGR1_PCSPOL_LOW(n) (0 << (LPSPI_CFGR1_PCSPOL_SHIFT + (n))) /* The Peripheral Chip Select PCS[n] pin is active low */ +# define LPSPI_CFGR1_PCSPOL_HIGH(n) (1 << (LPSPI_CFGR1_PCSPOL_SHIFT + (n))) /* The Peripheral Chip Select PCS[n] pin is active high */ + +#define LPSPI_CFGR1_MATCFG_SHIFT (16) /* Bits 16-18: Match Configuration (MATCFG) */ +#define LPSPI_CFGR1_MATCFG_MASK (0x07 << LPSPI_CFGR1_MATCFG_SHIFT) +#define LPSPI_CFGR1_MATCFG_DIS (0x00 << LPSPI_CFGR1_MATCFG_SHIFT) /* Match is disabled */ + + /* Bits 19-23: Reserved */ +#define LPSPI_CFGR1_PINCFG_SHIFT (24) /* Bits 24-25: Pin Configuration (PINCFG) */ +#define LPSPI_CFGR1_PINCFG_MASK (0x03 << LPSPI_CFGR1_PINCFG_SHIFT) +# define LPSPI_CFGR1_PINCFG_SIN_SOUT (0x00 << LPSPI_CFGR1_PINCFG_SHIFT) /* SIN is used for input data and SOUT is used for output data */ +# define LPSPI_CFGR1_PINCFG_SIN_SIN (0x01 << LPSPI_CFGR1_PINCFG_SHIFT) /* SIN is used for both input and output data */ +# define LPSPI_CFGR1_PINCFG_SOUT_SOUT (0x02 << LPSPI_CFGR1_PINCFG_SHIFT) /* SOUT is used for both input and output data */ +# define LPSPI_CFGR1_PINCFG_SOUT_SIN (0x03 << LPSPI_CFGR1_PINCFG_SHIFT) /* SOUT is used for input data and SIN is used for output data */ +# define LPSPI_CFGR1_PINCFG(n) ((n) << LPSPI_CFGR1_PINCFG_SHIFT) + +#define LPSPI_CFGR1_OUTCFG (1 << 26) /* Bit 26: Output Config (OUTCFG) */ +# define LPSPI_CFGR1_OUTCFG_RETAIN (0 << 26) /* Output data retains last value when chip select is negated */ +# define LPSPI_CFGR1_OUTCFG_TRISTATE (1 << 26) /* Output data is tristated when chip select is negated */ +#define LPSPI_CFGR1_PCSCFG_SHIFT (27) /* Bits 27-28: Peripheral Chip Select Configuration (PCSCFG) */ +#define LPSPI_CFGR1_PCSCFG_MASK (0x03 << LPSPI_CFGR1_PCSCFG_SHIFT) +# define LPSPI_CFGR1_PCSCFG_PCS (0x00 << LPSPI_CFGR1_PCSCFG_SHIFT) /* PCS[2:7] are configured for chip select function */ +# define LPSPI_CFGR1_PCSCFG_4BIT (0x01 << LPSPI_CFGR1_PCSCFG_SHIFT) /* PCS[2:3] are configured for half-duplex 4-bit transfers */ +# define LPSPI_CFGR1_PCSCFG_8BIT (0x03 << LPSPI_CFGR1_PCSCFG_SHIFT) /* PCS[2:7] are configured for half-duplex 4-bit and 8-bit transfers */ + + /* Bits 29-31: Reserved */ + +/* Data Match Register 0 (DMR0) */ + +#define LPSPI_DMR0_MATCH0_SHIFT (0) /* Bits 0-31: Match 0 Value (MATCH0) */ +#define LPSPI_DMR0_MATCH0_MASK (0xffffffff << LPSPI_DMR0_MATCH0_SHIFT) + +/* Data Match Register 0 (DMR1) */ + +#define LPSPI_DMR1_MATCH1_SHIFT (0) /* Bits 0-31: Match 1 Value (MATCH1) */ +#define LPSPI_DMR1_MATCH1_MASK (0xffffffff << LPSPI_DMR1_MATCH1_SHIFT) + +/* Clock Configuration Register (CCR) */ + +#define LPSPI_CCR_SCKDIV_SHIFT (0) /* Bits 0-7: SCK Divider (SCKDIV) */ +#define LPSPI_CCR_SCKDIV_MASK (0xff << LPSPI_CCR_SCKDIV_SHIFT) +# define LPSPI_CCR_SCKDIV(n) (((uint32_t)(n) << LPSPI_CCR_SCKDIV_SHIFT) & LPSPI_CCR_SCKDIV_MASK) +#define LPSPI_CCR_DBT_SHIFT (8) /* Bits 8-15: Delay Between Transfers (DBT) */ +#define LPSPI_CCR_DBT_MASK (0xff << LPSPI_CCR_DBT_SHIFT) +# define LPSPI_CCR_DBT(n) (((uint32_t)(n) << LPSPI_CCR_DBT_SHIFT) & LPSPI_CCR_DBT_MASK) +#define LPSPI_CCR_PCSSCK_SHIFT (16) /* Bits 16-23: PCS-to-SCK Delay (PCSSCK) */ +#define LPSPI_CCR_PCSSCK_MASK (0xff << LPSPI_CCR_PCSSCK_SHIFT) +# define LPSPI_CCR_PCSSCK(n) (((uint32_t)(n) << LPSPI_CCR_PCSSCK_SHIFT) & LPSPI_CCR_PCSSCK_MASK) +#define LPSPI_CCR_SCKPCS_SHIFT (24) /* Bits 24-31: SCK-to-PCS Delay (SCKPCS) */ +#define LPSPI_CCR_SCKPCS_MASK (0xff << LPSPI_CCR_SCKPCS_SHIFT) +# define LPSPI_CCR_SCKPCS(n) (((uint32_t)(n) << LPSPI_CCR_SCKPCS_SHIFT) & LPSPI_CCR_SCKPCS_MASK) + +/* Clock Configuration Register 1 (CCR1) */ + +#define LPSPI_CCR1_SCKSET_SHIFT (0) /* Bits 0-7: SCK Setup (SCKSET) */ +#define LPSPI_CCR1_SCKSET_MASK (0xff << LPSPI_CCR1_SCKSET_SHIFT) +#define LPSPI_CCR1_SCKHLD_SHIFT (8) /* Bits 8-15: SCK Hold (SCKHLD) */ +#define LPSPI_CCR1_SCKHLD_MASK (0xff << LPSPI_CCR1_SCKHLD_SHIFT) +#define LPSPI_CCR1_PCSPCS_SHIFT (16) /* Bits 16-23: PCS to PCS Delay (PCSPCS) */ +#define LPSPI_CCR1_PCSPCS_MASK (0xff << LPSPI_CCR1_PCSPCS_SHIFT) +#define LPSPI_CCR1_SCKSCK_SHIFT (24) /* Bits 24-31: SCK Inter-Frame Delay (SCKSCK) */ +#define LPSPI_CCR1_SCKSCK_MASK (0xff << LPSPI_CCR1_SCKSCK_SHIFT) + +/* FIFO Control Register (FCR) */ + +#define LPSPI_FCR_TXWATER_SHIFT (0) /* Bits 0-1: Transmit FIFO Watermark (TXWATER) */ +#define LPSPI_FCR_TXWATER_MASK (0x03 << LPSPI_FCR_TXWATER_SHIFT) +# define LPSPI_FCR_TXWATER(n) ((uint32_t)(n) << LPSPI_FCR_TXWATER_SHIFT) + /* Bits 2-15: Reserved */ +#define LPSPI_FCR_RXWATER_SHIFT (16) /* Bits 16-17: Receive FIFO Watermark (RXWATER) */ +#define LPSPI_FCR_RXWATER_MASK (0x03 << LPSPI_FCR_RXWATER_SHIFT) +# define LPSPI_FCR_RXWATER(n) ((uint32_t)(n) << LPSPI_FCR_RXWATER_SHIFT) + /* Bits 18-31: Reserved */ + +/* FIFO Status Register (FSR) */ + +#define LPSPI_FSR_TXCOUNT_SHIFT (0) /* Bits 0-2: Transmit FIFO Count (TXCOUNT) */ +#define LPSPI_FSR_TXCOUNT_MASK (0x07 << LPSPI_FSR_TXCOUNT_SHIFT) + /* Bits 3-15: Reserved */ +#define LPSPI_FSR_RXCOUNT_SHIFT (16) /* Bits 16-18: Receive FIFO Count (RXCOUNT) */ +#define LPSPI_FSR_RXCOUNT_MASK (0x07 << LPSPI_FSR_RXCOUNT_SHIFT) + /* Bits 19-31: Reserved */ + +/* Transmit Command Register (TCR) */ + +#define LPSPI_TCR_FRAMESZ_SHIFT (0) /* Bits 0-11: Frame Size (FRAMESZ) */ +#define LPSPI_TCR_FRAMESZ_MASK (0x0fff << LPSPI_TCR_FRAMESZ_SHIFT) +# define LPSPI_TCR_FRAMESZ(n) ((uint32_t)(n) << LPSPI_TCR_FRAMESZ_SHIFT) + /* Bits 12-15: Reserved */ +#define LPSPI_TCR_WIDTH_SHIFT (16) /* Bits 16-17: Transfer Width (WIDTH) */ +#define LPSPI_TCR_WIDTH_MASK (0x03 << LPSPI_TCR_WIDTH_SHIFT) +# define LPSPI_TCR_WIDTH_1BIT (0x00 << LPSPI_TCR_WIDTH_SHIFT) /* 1 bit transfer */ +# define LPSPI_TCR_WIDTH_2BIT (0x01 << LPSPI_TCR_WIDTH_SHIFT) /* 2 bit transfer */ +# define LPSPI_TCR_WIDTH_4BIT (0x02 << LPSPI_TCR_WIDTH_SHIFT) /* 4 bit transfer */ +# define LPSPI_TCR_WIDTH_8BIT (0x03 << LPSPI_TCR_WIDTH_SHIFT) /* 8 bit transfer */ + +#define LPSPI_TCR_TXMSK (1 << 18) /* Bit 18: Transmit Data Mask (TXMSK) */ +#define LPSPI_TCR_RXMSK (1 << 19) /* Bit 19: Receive Data Mask (RXMSK) */ +#define LPSPI_TCR_CONTC (1 << 20) /* Bit 20: Continuing Command (CONTC) */ +#define LPSPI_TCR_CONT (1 << 21) /* Bit 21: Continuous Transfer (CONT) */ +#define LPSPI_TCR_BYSW (1 << 22) /* Bit 22: Byte Swap (BYSW) */ +#define LPSPI_TCR_LSBF (1 << 23) /* Bit 23: LSB First (LSBF) */ +# define LPSPI_TCR_MSBF (0 << 23) /* MSB First */ +#define LPSPI_TCR_PCS_SHIFT (24) /* Bits 24-26: Peripheral Chip Select (PCS) */ +#define LPSPI_TCR_PCS_MASK (0x07 << LPSPI_TCR_PCS_SHIFT) +# define LPSPI_TCR_PCS_0 (0x00 << LPSPI_TCR_PCS_SHIFT) /* Transfer using PCS[0] */ +# define LPSPI_TCR_PCS_1 (0x01 << LPSPI_TCR_PCS_SHIFT) /* Transfer using PCS[1] */ +# define LPSPI_TCR_PCS_2 (0x02 << LPSPI_TCR_PCS_SHIFT) /* Transfer using PCS[2] */ +# define LPSPI_TCR_PCS_3 (0x03 << LPSPI_TCR_PCS_SHIFT) /* Transfer using PCS[3] */ +# define LPSPI_TCR_PCS_4 (0x04 << LPSPI_TCR_PCS_SHIFT) /* Transfer using PCS[4] */ +# define LPSPI_TCR_PCS_5 (0x05 << LPSPI_TCR_PCS_SHIFT) /* Transfer using PCS[5] */ +# define LPSPI_TCR_PCS_6 (0x06 << LPSPI_TCR_PCS_SHIFT) /* Transfer using PCS[6] */ +# define LPSPI_TCR_PCS_7 (0x07 << LPSPI_TCR_PCS_SHIFT) /* Transfer using PCS[7] */ + +#define LPSPI_TCR_PRESCALE_SHIFT (27) /* Bits 27-29: Prescaler Value (PRESCALE) */ +#define LPSPI_TCR_PRESCALE_MASK (0x07 << LPSPI_TCR_PRESCALE_SHIFT) +# define LPSPI_TCR_PRESCALE_DIV1 (0x00 << LPSPI_TCR_PRESCALE_SHIFT) /* Divide by 1 */ +# define LPSPI_TCR_PRESCALE_DIV2 (0x01 << LPSPI_TCR_PRESCALE_SHIFT) /* Divide by 2 */ +# define LPSPI_TCR_PRESCALE_DIV4 (0x02 << LPSPI_TCR_PRESCALE_SHIFT) /* Divide by 4 */ +# define LPSPI_TCR_PRESCALE_DIV8 (0x03 << LPSPI_TCR_PRESCALE_SHIFT) /* Divide by 8 */ +# define LPSPI_TCR_PRESCALE_DIV16 (0x04 << LPSPI_TCR_PRESCALE_SHIFT) /* Divide by 16 */ +# define LPSPI_TCR_PRESCALE_DIV32 (0x05 << LPSPI_TCR_PRESCALE_SHIFT) /* Divide by 32 */ +# define LPSPI_TCR_PRESCALE_DIV64 (0x06 << LPSPI_TCR_PRESCALE_SHIFT) /* Divide by 64 */ +# define LPSPI_TCR_PRESCALE_DIV128 (0x07 << LPSPI_TCR_PRESCALE_SHIFT) /* Divide by 128 */ +# define LPSPI_TCR_PRESCALE(n) ((n) << LPSPI_TCR_PRESCALE_SHIFT) + +#define LPSPI_TCR_CPHA (1 << 30) /* Bit 30: Clock Phase (CPHA) */ +# define LPSPI_TCR_CPHA_CAPTURED (0 << 30) /* Data is captured on the leading edge of SCK and changed on the following edge of SCK */ +# define LPSPI_TCR_CPHA_CHANGED (1 << 30) /* Data is changed on the leading edge of SCK and captured on the following edge of SCK */ +#define LPSPI_TCR_CPOL (1 << 31) /* Bit 31: Clock Polarity (CPOL) */ +# define LPSPI_TCR_CPOL_LOW (0 << 31) /* The inactive state value of SCK is low */ +# define LPSPI_TCR_CPOL_HIGH (1 << 31) /* The inactive state value of SCK is high */ + +/* Transmit Data Register (TDR) */ + +#define LPSPI_TDR_DATA_SHIFT (0) /* Bits 0-31: Transmit Data (DATA) */ +#define LPSPI_TDR_DATA_MASK (0xffffffff << LPSPI_TDR_DATA_SHIFT) + +/* Receive Status Register (RSR) */ + +#define LPSPI_RSR_SOF (1 << 0) /* Bit 0: Start Of Frame (SOF) */ +#define LPSPI_RSR_RXEMPTY (1 << 1) /* Bit 1: RX FIFO Empty (RXEMPTY) */ + /* Bits 2-31: Reserved */ + +/* Receive Data Register (RDR) */ + +#define LPSPI_RDR_DATA_SHIFT (0) /* Bits 0-31: Receive Data (DATA) */ +#define LPSPI_RDR_DATA_MASK (0xffffffff << LPSPI_RDR_DATA_SHIFT) + +/* Receive Data Read Only Register (RDROR) */ + +#define LPSPI_RDROR_DATA_SHIFT (0) /* Bits 0-31: Receive Data (DATA) */ +#define LPSPI_RDROR_DATA_MASK (0xffffffff << LPSPI_RDROR_DATA_SHIFT) + +/* Transmit Command Burst Register (TCBR) */ + +#define LPSPI_TCBR_DATA_SHIFT (0) /* Bits 0-31: Command Data (DATA) */ +#define LPSPI_TCBR_DATA_MASK (0xffffffff << LPSPI_TCBR_DATA_SHIFT) + +/* Transmit Data Burst Register (TDBR) */ + +#define LPSPI_TDBR_DATA_SHIFT (0) /* Bits 0-31: Data (DATA) */ +#define LPSPI_TDBR_DATA_MASK (0xffffffff << LPSPI_TDBR_DATA_SHIFT) + +/* Receive Data Burst Register (RDBR) */ + +#define LPSPI_RDBR_DATA_SHIFT (0) /* Bits 0-31: Data (DATA) */ +#define LPSPI_RDBR_DATA_MASK (0xffffffff << LPSPI_RDBR_DATA_SHIFT) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPSPI_H_ */ diff --git a/arch/arm64/src/imx9/hardware/imx9_lptmr.h b/arch/arm64/src/imx9/hardware/imx9_lptmr.h new file mode 100644 index 0000000000000..73efc0d5a6961 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_lptmr.h @@ -0,0 +1,100 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_lptmr.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPTMR_H_ +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPTMR_H_ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define IMX9_LPTMR_CSR_OFFSET 0x0000 /* Control Status */ +#define IMX9_LPTMR_PSR_OFFSET 0x0004 /* Prescale */ +#define IMX9_LPTMR_CMR_OFFSET 0x0008 /* Compare */ +#define IMX9_LPTMR_CNR_OFFSET 0x000c /* Counter */ + +/* Register Address *********************************************************/ + +#define LPTMR_CSR(n) ((n) + IMX9_LPTMR_CSR_OFFSET) +#define LPTMR_PSR(n) ((n) + IMX9_LPTMR_PSR_OFFSET) +#define LPTMR_CMR(n) ((n) + IMX9_LPTMR_CMR_OFFSET) +#define LPTMR_CNR(n) ((n) + IMX9_LPTMR_CNR_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +#define LPTMR_CSR_TDRE (1 << 8) /* Timer DMA Request Enable */ +#define LPTMR_CSR_TCF (1 << 7) /* Timer Compare Flag */ +#define LPTMR_CSR_TIE (1 << 6) /* Timer Interrupt Enable */ + +#define LPTMR_CSR_TPS_SHIFT (4) /* Bit[5:4]: Timer Pin Select */ +#define LPTMR_CSR_TPS_MASK (3 << LPTMR_CSR_TPS_SHIFT) +#define LPTMR_CSR_TPS0 (0 << LPTMR_CSR_TPS_SHIFT) +#define LPTMR_CSR_TPS1 (1 << LPTMR_CSR_TPS_SHIFT) +#define LPTMR_CSR_TPS2 (2 << LPTMR_CSR_TPS_SHIFT) +#define LPTMR_CSR_TPS3 (3 << LPTMR_CSR_TPS_SHIFT) + +#define LPTMR_CSR_TPP (1 << 3) /* Timer Pin Polarity */ +#define LPTMR_CSR_TFC (1 << 2) /* Timer Free-Running Counter */ +#define LPTMR_CSR_TMS (1 << 1) /* Timer Mode Select */ +#define LPTMR_CSR_TEN (1 << 0) /* Timer Enable */ + +#define LPTMR_PSR_PRESCALE_SHIFT (3) /* Bit[6:3]: Prescale Value */ +#define LPTMR_PSR_PRESCALE_MASK (0xf << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV2 (0 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV4 (1 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV8 (2 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV16 (3 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV32 (4 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV64 (5 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV128 (6 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV256 (7 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV512 (8 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV1024 (9 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV2048 (10 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV4096 (11 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV8192 (12 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV16384 (13 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV32768 (14 << LPTMR_PSR_PRESCALE_SHIFT) +#define LPTMR_PSR_PRESCALE_DIV65536 (15 << LPTMR_PSR_PRESCALE_SHIFT) + +#define LPTMR_PSR_PBYP (1 << 2) /* Prescaler Bypass */ + +/* Clock sources (module clock / root clock) + * ipg_clk_irclk -> lptmrx_clk_root + * ipg_clk_1khz -> 32k_clk_root + * ipg_clk_32khz -> 32k_clk_root + * ipg_clk_ercl -> 32k_clk_root + */ + +#define LPTMR_PSR_PCS_SHIFT (0) /* Bit[1:0]: Prescaler Clock Select */ +#define LPTMR_PSR_PCS_MASK (3 << LPTMR_PSR_PCS_SHIFT) +#define LPTMR_PSR_PCS_REF_INT (0 << LPTMR_PSR_PCS_SHIFT) /* Internal reference clock */ +#define LPTMR_PSR_PCS_LPO (1 << LPTMR_PSR_PCS_SHIFT) /* LPO 1K Hz */ +#define LPTMR_PSR_PCS_RTC (2 << LPTMR_PSR_PCS_SHIFT) /* RTC 32768 Hz */ +#define LPTMR_PSR_PCS_REF_EXT (3 << LPTMR_PSR_PCS_SHIFT) /* External reference clock */ +# define LPTMR_PSR_PCS_SOSC LPTMR_PSR_PCS_RFOSC + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPTMR_H_ */ diff --git a/arch/arm64/src/imx9/hardware/imx9_lpuart.h b/arch/arm64/src/imx9/hardware/imx9_lpuart.h new file mode 100644 index 0000000000000..c688d5966a14e --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_lpuart.h @@ -0,0 +1,313 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_lpuart.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPUART_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPUART_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* LPUART Register Offsets **************************************************/ + +#define IMX9_LPUART_VERID_OFFSET (0x00) /* Version ID Register (VERID) */ +#define IMX9_LPUART_PARAM_OFFSET (0x04) /* Parameter Register (PARAM) */ +#define IMX9_LPUART_GLOBAL_OFFSET (0x08) /* LPUART Global Register (GLOBAL) */ +#define IMX9_LPUART_PINCFG_OFFSET (0x0c) /* LPUART Pin Configuration Register (PINCFG) */ +#define IMX9_LPUART_BAUD_OFFSET (0x10) /* LPUART Baud Rate Register (BAUD) */ +#define IMX9_LPUART_STAT_OFFSET (0x14) /* LPUART Status Register (STAT) */ +#define IMX9_LPUART_CTRL_OFFSET (0x18) /* LPUART Control Register (CTRL) */ +#define IMX9_LPUART_DATA_OFFSET (0x1c) /* LPUART Data Register (DATA) */ +#define IMX9_LPUART_MATCH_OFFSET (0x20) /* LPUART Match Address Register (MATCH) */ +#define IMX9_LPUART_MODIR_OFFSET (0x24) /* LPUART Modem IrDA Register (MODIR) */ +#define IMX9_LPUART_FIFO_OFFSET (0x28) /* LPUART FIFO Register (FIFO) */ +#define IMX9_LPUART_WATER_OFFSET (0x2c) /* LPUART Watermark Register (WATER) */ +#define IMX9_LPUART_DATARO_OFFSET (0x30) /* Data read-only Register (DATARO) */ + +/* Register bit definitions *************************************************/ + +/* Version ID Register (VERID) */ + +#define LPUART_VERID_FEATURE_SHIFT (0) /* Bits 0-15: Feature Identification Number (FEATURE) */ +#define LPUART_VERID_FEATURE_MASK (0xffff << LPUART_VERID_FEATURE_SHIFT) +# define LPUART_VERID_FEATURE_STD (1 << LPUART_VERID_FEATURE_SHIFT) /* Standard feature set */ +# define LPUART_VERID_FEATURE_MODEM (3 << LPUART_VERID_FEATURE_SHIFT) /* MODEM/IrDA support */ + +#define LPUART_VERID_MINOR_SHIFT (16) /* Bits 16-23: Minor Version Number (MINOR) */ +#define LPUART_VERID_MINOR_MASK (0xff << LPUART_VERID_MINOR_SHIFT) +#define LPUART_VERID_MAJOR_SHIFT (24) /* Bits 24-31: Major Version Number (MAJOR) */ +#define LPUART_VERID_MAJOR_MASK (0xff << LPUART_VERID_MAJOR_SHIFT) + +/* Parameter Register (PARAM) */ + +#define LPUART_PARAM_TXFIFO_SHIFT (0) /* Bits 0-7: Transmit FIFO Size (TXFIFO) */ +#define LPUART_PARAM_TXFIFO_MASK (0xff << LPUART_PARAM_TXFIFO_SHIFT) +#define LPUART_PARAM_RXFIFO_SHIFT (8) /* Bits 8-15: Receive FIFO Size (RXFIFO) */ +#define LPUART_PARAM_RXFIFO_MASK (0xff << LPUART_PARAM_RXFIFO_SHIFT) + /* Bits 16-31: Reserved */ + +/* LPUART Global Register (GLOBAL) */ + + /* Bit 0: Reserved */ +#define LPUART_GLOBAL_RST (1 << 1) /* Bit 1: Software Reset (RST) */ + /* Bits 2-31: Reserved */ + +/* LPUART Pin Configuration Register (PINCFG) */ + +#define LPUART_PINCFG_TRGSEL_SHIFT (0) /* Bits 0-1: Trigger Select (TRGSEL) */ +#define LPUART_PINCFG_TRGSEL_MASK (0x03 << LPUART_PINCFG_TRGSEL_SHIFT) +# define LPUART_PINCFG_TRGSEL_DISABLE (0 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger disabled */ +# define LPUART_PINCFG_TRGSEL_RXD (1 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used instead of RXD pin */ +# define LPUART_PINCFG_TRGSEL_CTSB (2 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used instead of CTS_B pin */ +# define LPUART_PINCFG_TRGSEL_TXDMOD (3 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used to modulate the TXD output */ + + /* Bits 2-31: Reserved */ + +/* LPUART Baud Rate Register (BAUD) */ + +#define LPUART_BAUD_SBR_SHIFT (0) /* Bits 0-12: Baud Rate Modulo Divisor (SBR) */ +#define LPUART_BAUD_SBR_MASK (0x1fff << LPUART_BAUD_SBR_SHIFT) +# define LPUART_BAUD_SBR(n) ((n) << LPUART_BAUD_SBR_SHIFT) +#define LPUART_BAUD_SBNS (1 << 13) /* Bit 13: Stop Bit Number Select (SBNS) */ +#define LPUART_BAUD_RXEDGIE (1 << 14) /* Bit 14: RX Input Active Edge Interrupt Enable (RXEDGIE) */ +#define LPUART_BAUD_LBKDIE (1 << 15) /* Bit 15: LIN Break Detect Interrupt Enable (LBKDIE) */ +#define LPUART_BAUD_RESYNCDIS (1 << 16) /* Bit 16: Resynchronization Disable (RESYNCDIS) */ +#define LPUART_BAUD_BOTHEDGE (1 << 17) /* Bit 17: Both Edge Sampling (BOTHEDGE) */ +#define LPUART_BAUD_MATCFG_SHIFT (18) /* Bits 18-19: Match Configuration (MATCFG) */ +#define LPUART_BAUD_MATCFG_MASK (0x03 << LPUART_BAUD_MATCFG_SHIFT) +# define LPUART_BAUD_MATCFG_ADDR (0 << LPUART_BAUD_MATCFG_SHIFT) /* Address Match Wakeup */ +# define LPUART_BAUD_MATCFG_IDLE (1 << LPUART_BAUD_MATCFG_SHIFT) /* Idle Match Wakeup */ +# define LPUART_BAUD_MATCFG_ONOFF (2 << LPUART_BAUD_MATCFG_SHIFT) /* Match On and Match Off */ +# define LPUART_BAUD_MATCFG_RWUENAB (3 << LPUART_BAUD_MATCFG_SHIFT) /* Enables RWU on Data Match and Match On/Off for transmitter CTS input */ + + /* Bit 20: Reserved */ +#define LPUART_BAUD_RDMAE (1 << 21) /* Bit 21: Receiver Full DMA Enable (RDMAE) */ + /* Bit 22: Reserved */ +#define LPUART_BAUD_TDMAE (1 << 23) /* Bit 23: Transmitter DMA Enable (TDMAE) */ +#define LPUART_BAUD_OSR_SHIFT (24) /* Bits 24-29: Oversampling Ratio (OSR) */ +#define LPUART_BAUD_OSR_MASK (0x1f << LPUART_BAUD_OSR_SHIFT) +# define LPUART_BAUD_OSR(n) (((n) - 1) << LPUART_BAUD_OSR_SHIFT) /* n=4..32 */ + +#define LPUART_BAUD_M10 (1 << 29) /* Bit 29: 10-bit Mode Select (M10) */ +#define LPUART_BAUD_MAEN2 (1 << 30) /* Bit 30: Match Address Mode Enable 2 (MAEN2) */ +#define LPUART_BAUD_MAEN1 (1 << 31) /* Bit 31: Match Address Mode Enable 1 (MAEN1) */ + +/* LPUART Status Register (STAT) */ + +#define LPUART_STAT_LBKFE (1 << 0) /* Bit 0: LIN Break Flag Enable (LBKFE) */ +#define LPUART_STAT_AME (1 << 1) /* Bit 1: Address Mark Enable (AME) */ + /* Bits 2-13: Reserved */ +#define LPUART_STAT_MA2F (1 << 14) /* Bit 14: Match 2 Flag (MA2F) */ +#define LPUART_STAT_MA1F (1 << 15) /* Bit 15: Match 1 Flag (MA1F) */ +#define LPUART_STAT_PF (1 << 16) /* Bit 16: Parity Error Flag (PF) */ +#define LPUART_STAT_FE (1 << 17) /* Bit 17: Framing Error Flag (FE) */ +#define LPUART_STAT_NF (1 << 18) /* Bit 18: Noise Flag (NF) */ +#define LPUART_STAT_OR (1 << 19) /* Bit 19: Receiver Overrun Flag (OR) */ +#define LPUART_STAT_IDLE (1 << 20) /* Bit 20: Idle Line Flag (IDLE) */ +#define LPUART_STAT_RDRF (1 << 21) /* Bit 21: Receive Data Register Full Flag (RDRF) */ +#define LPUART_STAT_TC (1 << 22) /* Bit 22: Transmission Complete Flag (TC) */ +#define LPUART_STAT_TDRE (1 << 23) /* Bit 23: Transmit Data Register Empty Flag (TDRE) */ +#define LPUART_STAT_RAF (1 << 24) /* Bit 24: Receiver Active Flag (RAF) */ +#define LPUART_STAT_LBKDE (1 << 25) /* Bit 25: LIN Break Detection Enable (LBKDE) */ +#define LPUART_STAT_BRK13 (1 << 26) /* Bit 26: Break Character Generation Length (BRK13) */ +#define LPUART_STAT_RWUID (1 << 27) /* Bit 27: Receive Wake Up Idle Detect (RWUID) */ +#define LPUART_STAT_RXINV (1 << 28) /* Bit 28: Receive Data Inversion (RXINV) */ +#define LPUART_STAT_MSBF (1 << 29) /* Bit 29: MSB First (MSBF) */ +#define LPUART_STAT_RXEDGIF (1 << 30) /* Bit 30: RXD Pin Active Edge Interrupt Flag (RXEDGIF) */ +#define LPUART_STAT_LBKDIF (1 << 31) /* Bit 31: LIN Break Detect Interrupt Flag (LBKDIF) */ + +/* LPUART Control Register (CTRL) */ + +#define LPUART_CTRL_PT (1 << 0) /* Bit 0: Parity Type */ +# define LPUART_CTRL_PT_EVEN (0 << 0) /* Even parity */ +# define LPUART_CTRL_PT_ODD (1 << 0) /* Odd parity */ +#define LPUART_CTRL_PE (1 << 1) /* Bit 1: Parity Enable */ +#define LPUART_CTRL_ILT (1 << 2) /* Bit 2: Idle Line Type Select */ +#define LPUART_CTRL_WAKE (1 << 3) /* Bit 3: Receiver Wakeup Method Select */ +#define LPUART_CTRL_M (1 << 4) /* Bit 4: 9-Bit or 8-Bit Mode Select */ +#define LPUART_CTRL_RSRC (1 << 5) /* Bit 5: Receiver Source Select */ +#define LPUART_CTRL_DOZEEN (1 << 6) /* Bit 6: Doze Enable */ +#define LPUART_CTRL_LOOPS (1 << 7) /* Bit 7: Loop Mode Select */ +#define LPUART_CTRL_IDLECFG_SHIFT (8) /* Bits 8-10: Idle Configuration */ +#define LPUART_CTRL_IDLECFG_MASK (0x07 << LPUART_CTRL_IDLECFG_SHIFT) +# define LPUART_CTRL_IDLECFG_1 (0 << LPUART_CTRL_IDLECFG_SHIFT) /* 1 idle character */ +# define LPUART_CTRL_IDLECFG_2 (1 << LPUART_CTRL_IDLECFG_SHIFT) /* 2 idle characters */ +# define LPUART_CTRL_IDLECFG_4 (2 << LPUART_CTRL_IDLECFG_SHIFT) /* 4 idle characters */ +# define LPUART_CTRL_IDLECFG_8 (3 << LPUART_CTRL_IDLECFG_SHIFT) /* 8 idle characters */ +# define LPUART_CTRL_IDLECFG_16 (4 << LPUART_CTRL_IDLECFG_SHIFT) /* 6 idle characters */ +# define LPUART_CTRL_IDLECFG_32 (5 << LPUART_CTRL_IDLECFG_SHIFT) /* 32 idle characters */ +# define LPUART_CTRL_IDLECFG_64 (6 << LPUART_CTRL_IDLECFG_SHIFT) /* 64 idle characters */ +# define LPUART_CTRL_IDLECFG_128 (7 << LPUART_CTRL_IDLECFG_SHIFT) /* 128 idle characters */ + +#define LPUART_CTRL_M7 (1 << 11) /* Bit 11: 7-Bit Mode Select (M7) */ + /* Bits 12-13: Reserved */ +#define LPUART_CTRL_MA2IE (1 << 14) /* Bit 14: Match 2 Interrupt Enable (MA2IE) */ +#define LPUART_CTRL_MA1IE (1 << 15) /* Bit 15: Match 1 Interrupt Enable (MA1IE) */ +#define LPUART_CTRL_SBK (1 << 16) /* Bit 16: Send Break (SBK) */ +#define LPUART_CTRL_RWU (1 << 17) /* Bit 17: Receiver Wakeup Control (RWU) */ +#define LPUART_CTRL_RE (1 << 18) /* Bit 18: Receiver Enable (RE) */ +#define LPUART_CTRL_TE (1 << 19) /* Bit 19: Transmitter Enable (TE) */ +#define LPUART_CTRL_ILIE (1 << 20) /* Bit 20: Idle Line Interrupt Enable (ILIE) */ +#define LPUART_CTRL_RIE (1 << 21) /* Bit 21: Receiver Interrupt Enable (RIE) */ +#define LPUART_CTRL_TCIE (1 << 22) /* Bit 22: Transmission Complete Interrupt Enable (TCIE) */ +#define LPUART_CTRL_TIE (1 << 23) /* Bit 23: Transmit Interrupt Enable (TIE) */ +#define LPUART_CTRL_PEIE (1 << 24) /* Bit 24: Parity Error Interrupt Enable (PEIE) */ +#define LPUART_CTRL_FEIE (1 << 25) /* Bit 25: Framing Error Interrupt Enable (FEIE) */ +#define LPUART_CTRL_NEIE (1 << 26) /* Bit 26: Noise Error Interrupt Enable (NEIE) */ +#define LPUART_CTRL_ORIE (1 << 27) /* Bit 27: Overrun Interrupt Enable (ORIE) */ +#define LPUART_CTRL_TXINV (1 << 28) /* Bit 28: Transmit Data Inversion (TXINV) */ +#define LPUART_CTRL_TXDIR (1 << 29) /* Bit 29: TXD Pin Direction in Single-Wire Mode (TXDIR) */ +#define LPUART_CTRL_R9T8 (1 << 30) /* Bit 30: Receive Bit 9 / Transmit Bit 8 (R9T8) */ +#define LPUART_CTRL_R8T9 (1 << 31) /* Bit 31: Receive Bit 8 / Transmit Bit 9 (R8T9) */ + +#define LPUART_ALL_INTS (LPUART_CTRL_ORIE | LPUART_CTRL_NEIE | LPUART_CTRL_FEIE | \ + LPUART_CTRL_PEIE | LPUART_CTRL_TIE | LPUART_CTRL_TCIE | \ + LPUART_CTRL_RIE | LPUART_CTRL_ILIE | LPUART_CTRL_MA1IE | \ + LPUART_CTRL_MA2IE) + +/* LPUART Data Register (DATA) */ + +#define LPUART_DATA_SHIFT (0) /* Bits 0-9: Data bits 0-9 (DATA)*/ +#define LPUART_DATA_MASK (0x03ff << LPUART_DATA_SHIFT) +#define LPUART_DATA_LINBRK (1 << 10) /* Bit 10: LIN Break (LINBRK) */ +#define LPUART_DATA_STATUS_SHIFT (11) /* Bits 11-15: Status */ +#define LPUART_DATA_IDLINE (1 << 11) /* Bit 11: Idle Line (IDLINE) */ +#define LPUART_DATA_RXEMPT (1 << 12) /* Bit 12: Receive Buffer Empty (RXEMPT) */ +#define LPUART_DATA_FRETSC (1 << 13) /* Bit 13: Frame Error / Transmit Special Character (FRETSC) */ +#define LPUART_DATA_PARITYE (1 << 14) /* Bit 14: Parity Error (PARITYE) */ +#define LPUART_DATA_NOISY (1 << 15) /* Bit 15: Noisy Data Received (NOISY) */ + /* Bits 16-31: Reserved */ + +/* LPUART Match Address Register (MATCH) */ + +#define LPUART_MATCH_MA1_SHIFT (0) /* Bits 0-9: Match Address 1 (MA1) */ +#define LPUART_MATCH_MA1_MASK (0x03ff << LPUART_MATCH_MA1_SHIFT) +# define LPUART_MATCH_MA1(n) ((n) << LPUART_MATCH_MA1_SHIFT) + /* Bits 10-15: Reserved */ +#define LPUART_MATCH_MA2_SHIFT (16) /* Bits 16-25: Match Address 2 (MA2) */ +#define LPUART_MATCH_MA2_MASK (0x03ff << LPUART_MATCH_MA2_SHIFT) +# define LPUART_MATCH_MA2(n) ((n) << LPUART_MATCH_MA2_SHIFT) + /* Bits 26-31: Reserved */ + +/* LPUART Modem IrDA Register (MODIR) */ + +#define LPUART_MODIR_TXCTSE (1 << 0) /* Bit 0: Transmitter clear-to-send enable (TXCTSE) */ +#define LPUART_MODIR_TXRTSE (1 << 1) /* Bit 1: Transmitter request-to-send enable (TXRTSE) */ +#define LPUART_MODIR_TXRTSPOL (1 << 2) /* Bit 2: Transmitter request-to-send polarity (TXRTSPOL) */ +#define LPUART_MODIR_RXRTSE (1 << 3) /* Bit 3: Receiver request-to-send enable (RXRTSE) */ +#define LPUART_MODIR_TXCTSC (1 << 4) /* Bit 4: Transmit CTS Configuration (TXCTSC) */ +# define LPUART_MODIR_TXCTSC_START (0 << 4) /* CTS sampled at start of character */ +# define LPUART_MODIR_TXCTSC_IDLE (1 << 4) /* CTS sampled when transmitter idle */ +#define LPUART_MODIR_TXCTSSRC (1 << 5) /* Bit 5: Transmit CTS Source (TXCTSSRC) */ +# define LPUART_MODIR_TXCTSSRC_CTSB (0 << 5) /* CTS input is CTS_B pin */ +# define LPUART_MODIR_TXCTSSRC_RXMAT (1 << 5) /* CTS input is receiver address match result */ + /* Bits 6-7: Reserved */ +#define LPUART_MODIR_RTSWATER_SHIFT (8) /* Bits 8-9: Receive RTS Configuration (RTSWATER) */ +#define LPUART_MODIR_RTSWATER_MASK (0x03 << LPUART_MODIR_RTSWATER_SHIFT) +# define LPUART_MODIR_RTSWATER(n) ((n) << LPUART_MODIR_RTSWATER_SHIFT) + /* Bits 10-15: Reserved */ +#define LPUART_MODIR_TNP_SHIFT (16) /* Bits 16-17: Transmitter narrow pulse (TNP) */ +#define LPUART_MODIR_TNP_MASK (0x03 << LPUART_MODIR_TNP_SHIFT) +# define LPUART_MODIR_TNP(n) (((n) - 1) << LPUART_MODIR_TNP_SHIFT) /* n/OSR */ + +#define LPUART_MODIR_IREN (1 << 18) /* Bit 18: Infrared enable (IREN) */ + /* Bits 19-31: Reserved */ + +/* LPUART FIFO Register (FIFO) */ + +#define LPUART_FIFO_RXFIFOSIZE_SHIFT (0) /* Bits 0-2: Receive FIFO Buffer Depth (RXFIFOSIZE) */ +#define LPUART_FIFO_RXFIFOSIZE_MASK (0x07 << LPUART_FIFO_RXFIFOSIZE_SHIFT) +# define LPUART_FIFO_RXFIFOSIZE_1 (0 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 1 dataword */ +# define LPUART_FIFO_RXFIFOSIZE_4 (1 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 4 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_8 (2 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 8 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_16 (3 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 16 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_32 (4 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 32 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_64 (5 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 64 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_128 (6 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 128 datawords */ +# define LPUART_FIFO_RXFIFOSIZE_256 (7 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 256 datawords */ + +#define LPUART_FIFO_RXFE (1 << 3) /* Bit 3: Receive FIFO Enable (RXFE) */ +#define LPUART_FIFO_TXFIFOSIZE_SHIFT (4) /* Bits 4-6: Transmit FIFO Buffer Depth (TXFIFOSIZE) */ +#define LPUART_FIFO_TXFIFOSIZE_MASK (0x07 << LPUART_FIFO_TXFIFOSIZE_SHIFT) +# define LPUART_FIFO_TXFIFOSIZE_1 (0 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 1 dataword */ +# define LPUART_FIFO_TXFIFOSIZE_4 (1 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 4 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_8 (2 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 8 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_16 (3 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 16 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_32 (4 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 32 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_64 (5 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 64 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_128 (6 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 128 datawords */ +# define LPUART_FIFO_TXFIFOSIZE_256 (7 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 256 datawords */ + +#define LPUART_FIFO_TXFE (1 << 7) /* Bit 7: Transmit FIFO Enable (TXFE) */ +#define LPUART_FIFO_RXUFE (1 << 8) /* Bit 8: Receive FIFO Underflow Interrupt Enable (RXUFE) */ +#define LPUART_FIFO_TXOFE (1 << 9) /* Bit 9: Transmit FIFO Overflow Interrupt Enable (TXOFE) */ +#define LPUART_FIFO_RXIDEN_SHIFT (10) /* Bits 10-12: Receiver Idle Empty Enable (RXIDEN) */ +#define LPUART_FIFO_RXIDEN_MASK (0x07 << LPUART_FIFO_RXIDEN_SHIFT) +# define LPUART_FIFO_RXIDEN_DISABLE (0 << LPUART_FIFO_RXIDEN_SHIFT) /* Disable RDRF assertion when receiver is idle */ +# define LPUART_FIFO_RXIDEN_1 (1 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 1 character */ +# define LPUART_FIFO_RXIDEN_2 (2 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 2 characters */ +# define LPUART_FIFO_RXIDEN_4 (3 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 4 characters */ +# define LPUART_FIFO_RXIDEN_8 (4 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 8 characters */ +# define LPUART_FIFO_RXIDEN_16 (5 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 16 characters */ +# define LPUART_FIFO_RXIDEN_32 (6 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 32 characters */ +# define LPUART_FIFO_RXIDEN_64 (7 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 64 characters */ + + /* Bit 13: Reserved */ +#define LPUART_FIFO_RXFLUSH (1 << 14) /* Bit 14: Receive FIFO Flush (RXFLUSH) */ +#define LPUART_FIFO_TXFLUSH (1 << 15) /* Bit 15: Transmit FIFO Flush (TXFLUSH) */ +#define LPUART_FIFO_RXUF (1 << 16) /* Bit 16: Receiver FIFO Underflow Flag (RXUF) */ +#define LPUART_FIFO_TXOF (1 << 17) /* Bit 17: Transmitter FIFO Overflow Flag (TXOF) */ + /* Bits 18-21: Reserved */ +#define LPUART_FIFO_RXEMPT (1 << 22) /* Bit 22: Receive Buffer/FIFO Empty (RXEMPT) */ +#define LPUART_FIFO_TXEMPT (1 << 23) /* Bit 23: Transmit Buffer/FIFO Empty (TXEMPT) */ + /* Bits 24-31: Reserved */ + +/* LPUART Watermark Register (WATER) */ + +#define LPUART_WATER_TXWATER_SHIFT (0) /* Bits 0-1: Transmit Watermark (TXWATER) */ +#define LPUART_WATER_TXWATER_MASK (0x03 << LPUART_WATER_TXWATER_SHIFT) +# define LPUART_WATER_TXWATER(n) ((n) << LPUART_WATER_TXWATER_SHIFT) + /* Bits 2-7: Reserved */ +#define LPUART_WATER_TXCOUNT_SHIFT (8) /* Bits 8-10: Transmit Counter (TXCOUNT) */ +#define LPUART_WATER_TXCOUNT_MASK (0x07 << LPUART_WATER_TXCOUNT_SHIFT) +# define LPUART_WATER_TXCOUNT(n) ((n) << LPUART_WATER_TXCOUNT_SHIFT) + /* Bits 11-15: Reserved */ +#define LPUART_WATER_RXWATER_SHIFT (16) /* Bits 16-17: Receive Watermark (RXWATER) */ +#define LPUART_WATER_RXWATER_MASK (0x03 << LPUART_WATER_RXWATER_SHIFT) +# define LPUART_WATER_RXWATER(n) ((n) << LPUART_WATER_RXWATER_SHIFT) + /* Bits 18-23: Reserved */ +#define LPUART_WATER_RXCOUNT_SHIFT (24) /* Bits 24-26: Receive Counter (RXCOUNT) */ +#define LPUART_WATER_RXCOUNT_MASK (0x07 << LPUART_WATER_RXCOUNT_SHIFT) +# define LPUART_WATER_RXCOUNT(n) ((n) << LPUART_WATER_RXCOUNT_SHIFT) + /* Bits 27-31: Reserved */ + +/* Data read-only Register (DATARO) */ + +#define LPUART_DATARO_DATA_SHIFT (0) /* Bits 0-15: Receive Data (DATA) */ +#define LPUART_DATARO_DATA_MASK (0xffff << LPUART_DATARO_DATA_SHIFT) + /* Bits 16-31: Reserved */ + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPUART_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_memorymap.h b/arch/arm64/src/imx9/hardware/imx9_memorymap.h new file mode 100644 index 0000000000000..cf682d25a211b --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_memorymap.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_memorymap.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMX9_HARDWARE_IMX9_MEMORYMAP_H +#define __ARCH_ARM_SRC_IMX9_HARDWARE_IMX9_MEMORYMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_IMX93) +# include "hardware/imx93/imx93_memorymap.h" +#else +# error Unrecognized i.MX9 architecture +#endif + +#endif /* __ARCH_ARM_SRC_IMX9_HARDWARE_IMX9_MEMORYMAP_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_pinmux.h b/arch/arm64/src/imx9/hardware/imx9_pinmux.h new file mode 100644 index 0000000000000..689485dff6db7 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_pinmux.h @@ -0,0 +1,36 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_pinmux.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_PINMUX_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_PINMUX_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_ARCH_CHIP_IMX93) +# include "hardware/imx93/imx93_pinmux.h" +#else +# error Unrecognized i.MX9 architecture +#endif + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_PINMUX_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_tpm.h b/arch/arm64/src/imx9/hardware/imx9_tpm.h new file mode 100644 index 0000000000000..0b6c3b5dc84eb --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_tpm.h @@ -0,0 +1,206 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_tpm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_TPM_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_TPM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define IMX9_TPM_VERID_OFFSET 0x0000 /* Version ID */ +#define IMX9_TPM_PARAM_OFFSET 0x0004 /* Parameter */ +#define IMX9_TPM_GLOBAL_OFFSET 0x0008 /* TPM Global */ +#define IMX9_TPM_SC_OFFSET 0x0010 /* Status and Control */ +#define IMX9_TPM_CNT_OFFSET 0x0014 /* Counter */ +#define IMX9_TPM_MOD_OFFSET 0x0018 /* Modulo */ +#define IMX9_TPM_STATUS_OFFSET 0x001c /* Capture and Compare Status */ +#define IMX9_TPM_CXSC_OFFSET(ch) (0x0020 + (ch) * 8) /* Channel Status and Control */ +#define IMX9_TPM_CXV_OFFSET(ch) (0x0024 + (ch) * 8) /* Channel Value */ +#define IMX9_TPM_C1SC_OFFSET 0x0028 /* Channel n Status and Control */ +#define IMX9_TPM_C1V_OFFSET 0x002c /* Channel n Value */ +#define IMX9_TPM_C2SC_OFFSET 0x0030 /* Channel n Status and Control */ +#define IMX9_TPM_C2V_OFFSET 0x0034 /* Channel n Value */ +#define IMX9_TPM_C3SC_OFFSET 0x0038 /* Channel n Status and Control */ +#define IMX9_TPM_C3V_OFFSET 0x003c /* Channel n Value */ +#define IMX9_TPM_COMBINE_OFFSET 0x0064 /* Combine Channel */ +#define IMX9_TPM_TRIG_OFFSET 0x006c /* Channel Trigger */ +#define IMX9_TPM_POL_OFFSET 0x0070 /* Channel Polarity */ +#define IMX9_TPM_FILTER_OFFSET 0x0078 /* Filter Control */ +#define IMX9_TPM_QDCTRL_OFFSET 0x0080 /* Quadrature Decoder Control and Status */ +#define IMX9_TPM_CONF_OFFSET 0x0084 /* Configuration */ + +/* Register Bitfield Definitions ********************************************/ + +/* PARAM */ + +#define TPM_PARAM_WIDTH_SHIFT (16) /* Bit[23:16]: Width of the counter and timer channels */ +#define TPM_PARAM_WIDTH_MASK (0xff << TPM_PARAM_WIDTH_SHIFT) + +#define TPM_PARAM_TRIG_SHIFT (8) /* Bit[15:8]: Number of triggers that TPM implements */ +#define TPM_PARAM_TRIG_MASK (0xff << LPIT_PARAM_TRIG_SHIFT) + +#define TPM_PARAM_CHAN_SHIFT (0) /* Bit[7:0]: Number of timer channels */ +#define TPM_PARAM_CHAN_MASK (0xff << TPM_PARAM_CHAN_SHIFT) + +/* GLOBAL */ + +#define TPM_GLOBAL_RST_SHIFT (1) /* Bit[1]: Software Reset */ +#define TPM_GLOBAL_RST_MASK (0x1 << TPM_GLOBAL_RST_SHIFT) + +#define TPM_GLOBAL_NOUPDATE_SHIFT (0) /* Bit[0]: Block updates to internal registers */ +#define TPM_GLOBAL_NOUPDATE_MASK (0x1 << TPM_GLOBAL_NOUPDATE_SHIFT) + +/* SC */ + +#define TPM_SC_DMA_SHIFT (8) /* Bit[8]: DMA Enable */ +#define TPM_SC_DMA_MASK (0x1 << TPM_SC_DMA_SHIFT) + +#define TPM_SC_TOF_SHIFT (7) /* Bit[7]: Timer Overflow Flag */ +#define TPM_SC_TOF_MASK (0x1 << TPM_SC_TOF_SHIFT) + +#define TPM_SC_TOIE_SHIFT (6) /* Bit[6]: Timer Overflow Interrupt Enable */ +#define TPM_SC_TOIE_MASK (0x1 << TPM_SC_TOIE_SHIFT) + +#define TPM_SC_CPWMS_SHIFT (5) /* Bit[5]: Center-Aligned PWM Select */ +#define TPM_SC_CPWMS_MASK (0x1 << TPM_SC_CPWMS_SHIFT) + +#define TPM_SC_CMOD_SHIFT (3) /* Bit[4:3]: Clock Mode Selection */ +#define TPM_SC_CMOD_MASK (0x3 << TPM_SC_CMOD_SHIFT) + +#define TPM_SC_PS_SHIFT (0) /* Bit[2:0]: Prescale Factor Selection */ +#define TPM_SC_PS_MASK (0x7 << TPM_SC_PS_SHIFT) + +/* STATUS */ + +#define TPM_STATUS_TOF_SHIFT (8) /* Bit[8]: Timer Overflow Flag */ +#define TPM_STATUS_TOF_MASK (0x1 << TPM_STATUS_TOF_SHIFT) + +#define TPM_STATUS_CH3F_SHIFT (3) /* Bit[3]: Channel 3 Flag */ +#define TPM_STATUS_CH3F_MASK (0x1 << TPM_STATUS_CH3F_SHIFT) + +#define TPM_STATUS_CH2F_SHIFT (2) /* Bit[2]: Channel 2 Flag */ +#define TPM_STATUS_CH2F_MASK (0x1 << TPM_STATUS_CH2F_SHIFT) + +#define TPM_STATUS_CH1F_SHIFT (1) /* Bit[1]: Channel 1 Flag */ +#define TPM_STATUS_CH1F_MASK (0x1 << TPM_STATUS_CH1F_SHIFT) + +#define TPM_STATUS_CH0F_SHIFT (0) /* Bit[0]: Channel 0 Flag */ +#define TPM_STATUS_CH0F_MASK (0x1 << TPM_STATUS_CH0F_SHIFT) + +/* C0SC - C3SC */ + +#define TPM_CXSC_CHF_SHIFT (7) /* Bit[7]: Channel Flag */ +#define TPM_CXSC_CHF_MASK (0x1 << TPM_CXSC_CHF_SHIFT) + +#define TPM_CXSC_CHIE_SHIFT (6) /* Bit[6]: Channel Interrupt Enable */ +#define TPM_CXSC_CHIE_MASK (0x1 << TPM_CXSC_CHIE_SHIFT) + +#define TPM_CXSC_MSB_SHIFT (5) /* Bit[5]: Channel Mode Select B */ +#define TPM_CXSC_MSB_MASK (0x1 << TPM_CXSC_MSB_SHIFT) + +#define TPM_CXSC_MSA_SHIFT (4) /* Bit[4]: Channel Mode Select A */ +#define TPM_CXSC_MSA_MASK (0x1 << TPM_CXSC_MSA_SHIFT) + +#define TPM_CXSC_ELSB_SHIFT (3) /* Bit[3]: Edge or Level Select B */ +#define TPM_CXSC_ELSB_MASK (0x1 << TPM_CXSC_ELSB_SHIFT) + +#define TPM_CXSC_ELSA_SHIFT (2) /* Bit[2]: Edge or Level Select A */ +#define TPM_CXSC_ELSA_MASK (0x1 << TPM_CXSC_ELSA_SHIFT) + +#define TPM_CXSC_DMA_SHIFT (0) /* Bit[0]: DMA Enable */ +#define TPM_CXSC_DMA_MASK (0x1 << TPM_CXSC_DMA_SHIFT) + +/* COMBINE */ + +#define TPM_COMBINE_COMSWAP1_SHIFT (9) /* Bit[9]: Combine Channels 2 and 3 Swap */ +#define TPM_COMBINE_COMSWAP1_MASK (0x1 << TPM_COMBINE_COMSWAP1_SHIFT) + +#define TPM_COMBINE_COMBINE1_SHIFT (8) /* Bit[8]: Combine Channels 2 and 3 */ +#define TPM_COMBINE_COMBINE1_MASK (0x1 << TPM_COMBINE_COMBINE1_SHIFT) + +#define TPM_COMBINE_COMSWAP0_SHIFT (1) /* Bit[1]: Combine Channel 0 and 1 Swap */ +#define TPM_COMBINE_COMSWAP0_MASK (0x1 << TPM_COMBINE_COMSWAP0_SHIFT) + +#define TPM_COMBINE_COMBINE0_SHIFT (0) /* Bit[0]: Combine Channels 0 and 1 */ +#define TPM_COMBINE_COMBINE0_MASK (0x1 << TPM_COMBINE_COMBINE0_SHIFT) + +/* TRIG */ + +#define TPM_TRIG_TRIGX_MASK(ch) (0x1 << (ch)) /* Channel trigger configure */ + +/* POL */ + +#define TPM_POL_POLX_MASK(ch) (0x1 < (ch)) /* Channel polarity active low */ + +/* FILTER */ + +#define TPM_FILTER_CHXFVAL_MASK(ch) (0xf << ((ch) * 4))) /* Channel filter value */ + +/* QDCTRL */ + +#define TPM_QDCTRL_QUADMODE_SHIFT (3) /* Bit[3]: Quadrature Decoder Mode */ +#define TPM_QDCTRL_QUADMODE_MASK (0x1 << TPM_QDCTRL_QUADMODE_SHIFT) + +#define TPM_QDCTRL_QUADIR_SHIFT (2) /* Bit[2]: Counter Direction */ +#define TPM_QDCTRL_QUADIR_MASK (0x1 << TPM_QDCTRL_QUADIR_SHIFT) + +#define TPM_QDCTRL_TOFDIR_SHIFT (1) /* Bit[1]: Timer Overflow Direction */ +#define TPM_QDCTRL_TOFDIR_MASK (0x1 << TPM_QDCTRL_TOFDIR_SHIFT) + +#define TPM_QDCTRL_QUADEN_SHIFT (0) /* Bit[0]: Quadrature Decoder Enable */ +#define TPM_QDCTRL_QUADEN_MASK (0x1 << TPM_QDCTRL_QUADEN_SHIFT) + +/* CONF */ + +#define TPM_CONF_TRGSEL_SHIFT (24) /* Bit[25:24]: Trigger Select */ +#define TPM_CONF_TRGSEL_MASK (0x3 << TPM_CONF_TRGSEL_SHIFT) + +#define TPM_CONF_TRGSRC_SHIFT (23) /* Bit[23]: Trigger Source select */ +#define TPM_CONF_TRGSRC_MASK (0x1 << TPM_CONF_TRGSRC_SHIFT) + +#define TPM_CONF_TRGPOL_SHIFT (22) /* Bit[22]: Trigger Polarity */ +#define TPM_CONF_TRGPOL_MASK (0x1 << TPM_CONF_TRGPOL_SHIFT) + +#define TPM_CONF_CPOT_SHIFT (19) /* Bit[19]: Counter Pause on Trigger */ +#define TPM_CONF_CPOT_MASK (0x1 << TPM_CONF_CPOT_SHIFT) + +#define TPM_CONF_CROT_SHIFT (18) /* Bit[18]: Counter Reload on Trigger */ +#define TPM_CONF_CROT_MASK (0x1 << TPM_CONF_CROT_SHIFT) + +#define TPM_CONF_CSOO_SHIFT (17) /* Bit[17]: Counter Stop on Overflow */ +#define TPM_CONF_CSOO_MASK (0x1 << TPM_CONF_CSOO_SHIFT) + +#define TPM_CONF_CSOT_SHIFT (16) /* Bit[16]: Counter Start on Trigger */ +#define TPM_CONF_CSOT_MASK (0x1 << TPM_CONF_CSOT_SHIFT) + +#define TPM_CONF_DBGMODE_SHIFT (6) /* Bit[7:6]: Debug Mode */ +#define TPM_CONF_DBGMODE_MASK (0x3 << TPM_CONF_DBGMODE_SHIFT) + +#define TPM_CONF_DOZEEN_SHIFT (5) /* Bit[5]: Doze Enable */ +#define TPM_CONF_DOZEEN_MASK (0x1 << TPM_CONF_DOZEEN_SHIFT) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_TPM_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_usbotg.h b/arch/arm64/src/imx9/hardware/imx9_usbotg.h new file mode 100644 index 0000000000000..c59119e8dd9f5 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_usbotg.h @@ -0,0 +1,665 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_usbotg.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_USBOTG_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_USBOTG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IMX9_EHCI_NRHPORT 1 + +#define IMX9_USBOTG_ID_OFFSET 0x000 /* Identification */ +#define IMX9_USBHOST_HWGENERAL_OFFSET 0x004 /* Hardware General */ +#define IMX9_USBHOST_HWHOST_OFFSET 0x008 /* Host Hardware Parameters */ +#define IMX9_USBHOST_HWDEVICE_OFFSET 0x00c /* Device Hardware Parameters */ +#define IMX9_USBHOST_HWTXBUF_OFFSET 0x010 /* TX Buffer Hardware Parameters */ +#define IMX9_USBHOST_HWRXBUF_OFFSET 0x014 /* RX Buffer Hardware Parameters */ +#define IMX9_USBHOST_GPTIMER0LD_OFFSET 0x080 /* General Purpose Timer #0 Load */ +#define IMX9_USBHOST_GPTIMER0CTRL_OFFSET 0x084 /* General Purpose Timer #0 Controller */ +#define IMX9_USBHOST_GPTIMER1LD_OFFSET 0x088 /* General Purpose Timer #1 Load */ +#define IMX9_USBHOST_GPTIMER1CTRL_OFFSET 0x08c /* General Purpose Timer #1 Controller */ +#define IMX9_USBHOST_SBUSCFG_OFFSET 0x090 /* System Bus Config */ + +/* Device/host capability registers */ + +#define IMX9_USBOTG_CAPLENGTH_OFFSET 0x100 /* Capability register length (8-bit) */ +#define IMX9_USBHOST_HCIVERSION_OFFSET 0x102 /* Host interface version number (16-bit) */ +#define IMX9_USBHOST_HCSPARAMS_OFFSET 0x104 /* Host controller structural parameters */ +#define IMX9_USBHOST_HCCPARAMS_OFFSET 0x108 /* Host controller capability parameters */ +#define IMX9_USBDEV_DCIVERSION_OFFSET 0x120 /* Device interface version number */ +#define IMX9_USBDEV_DCCPARAMS_OFFSET 0x124 /* Device controller capability parameters */ + +/* Device/host/OTG operational registers */ + +#define IMX9_USBOTG_USBCMD_OFFSET 0x140 /* USB command (both) */ +#define IMX9_USBOTG_USBSTS_OFFSET 0x144 /* USB status (both) */ +#define IMX9_USBOTG_USBINTR_OFFSET 0x148 /* USB interrupt enable (both) */ +#define IMX9_USBOTG_FRINDEX_OFFSET 0x14c /* USB frame index (both) */ +#define IMX9_USBOTG_DEVICEADDR_OFFSET 0x154 /* USB device address (device) */ +#define IMX9_USBOTG_ASYNCLISTADDR_OFFSET 0x158 /* Next asynchronous list address (host) */ +#define IMX9_USBOTG_ENDPOINTLIST_OFFSET 0x158 /* Address of endpoint list in memory (device) */ +#define IMX9_USBOTG_BURSTSIZE_OFFSET 0x160 /* Programmable burst size (both) */ +#define IMX9_USBOTG_TXFILLTUNING_OFFSET 0x164 /* Host transmit pre-buffer packet tuning (host) */ +#define IMX9_USBOTG_ENDPTNAK_OFFSET 0x178 /* Endpoint NAK (device) */ +#define IMX9_USBOTG_ENDPTNAKEN_OFFSET 0x17c /* Endpoint NAK Enable (device) */ +#define IMX9_USBOTG_CONFIGFLAG_OFFSET 0x180 /* Configured flag register (not used in lpc313x) */ +#define IMX9_USBOTG_PORTSC1_OFFSET 0x184 /* Port status/control 1 (both) */ +#define IMX9_USBOTG_OTGSC_OFFSET 0x1a4 /* OTG status and control (otg) */ +#define IMX9_USBOTG_USBMODE_OFFSET 0x1a8 /* USB device mode (both) */ + +#define IMX9_USBDEV_USBCMD_OFFSET 0x140 /* USB command (both) */ +#define IMX9_USBDEV_USBSTS_OFFSET 0x144 /* USB status (both) */ +#define IMX9_USBDEV_USBINTR_OFFSET 0x148 /* USB interrupt enable (both) */ +#define IMX9_USBDEV_FRINDEX_OFFSET 0x14c /* USB frame index (both) */ +#define IMX9_USBDEV_DEVICEADDR_OFFSET 0x154 /* USB device address (device) */ +#define IMX9_USBDEV_ENDPOINTLIST_OFFSET 0x158 /* Address of endpoint list in memory (device) */ +#define IMX9_USBDEV_BURSTSIZE_OFFSET 0x160 /* Programmable burst size (both) */ +#define IMX9_USBDEV_ENDPTNAK_OFFSET 0x178 /* Endpoint NAK (device) */ +#define IMX9_USBDEV_ENDPTNAKEN_OFFSET 0x17c /* Endpoint NAK Enable (device) */ +#define IMX9_USBDEV_PORTSC1_OFFSET 0x184 /* Port status/control 1 (both) */ +#define IMX9_USBDEV_USBMODE_OFFSET 0x1a8 /* USB device mode (both) */ + +#define IMX9_USBHOST_USBCMD_OFFSET 0x140 /* USB command (both) */ +#define IMX9_USBHOST_USBSTS_OFFSET 0x144 /* USB status (both) */ +#define IMX9_USBHOST_USBINTR_OFFSET 0x148 /* USB interrupt enable (both) */ +#define IMX9_USBHOST_FRINDEX_OFFSET 0x14c /* USB frame index (both) */ +#define IMX9_USBHOST_PERIODICLIST_OFFSET 0x154 /* Frame list base address (host) */ +#define IMX9_USBHOST_ASYNCLISTADDR_OFFSET 0x158 /* Next asynchronous list address (host) */ +#define IMX9_USBHOST_TTCTRL_OFFSET 0x15c /* Asynchronous buffer status for embedded TT (host) */ +#define IMX9_USBHOST_BURSTSIZE_OFFSET 0x160 /* Programmable burst size (both) */ +#define IMX9_USBHOST_TXFILLTUNING_OFFSET 0x164 /* Host transmit pre-buffer packet tuning (host) */ +#define IMX9_USBHOST_PORTSC1_OFFSET 0x184 /* Port status/control 1 (both) */ +#define IMX9_USBHOST_USBMODE_OFFSET 0x1a8 /* USB device mode (both) */ + +/* Device endpoint registers */ + +#define IMX9_USBDEV_ENDPTSETUPSTAT_OFFSET 0x1ac /* Endpoint setup status */ +#define IMX9_USBDEV_ENDPTPRIME_OFFSET 0x1b0 /* Endpoint initialization */ +#define IMX9_USBDEV_ENDPTFLUSH_OFFSET 0x1b4 /* Endpoint de-initialization */ +#define IMX9_USBDEV_ENDPTSTATUS_OFFSET 0x1b8 /* Endpoint status */ +#define IMX9_USBDEV_ENDPTCOMPLETE_OFFSET 0x1bc /* Endpoint complete */ + +#define IMX9_USBDEV_ENDPTCTRL_OFFSET(n) (IMX9_USBDEV_ENDPTCTRL0_OFFSET + ((n) * 4)) +#define IMX9_USBDEV_ENDPTCTRL0_OFFSET 0x1c0 /* Endpoint control 0 */ +#define IMX9_USBDEV_ENDPTCTRL1_OFFSET 0x1c4 /* Endpoint control 1 */ +#define IMX9_USBDEV_ENDPTCTRL2_OFFSET 0x1c8 /* Endpoint control 2 */ +#define IMX9_USBDEV_ENDPTCTRL3_OFFSET 0x1cc /* Endpoint control 3 */ +#define IMX9_USBDEV_ENDPTCTRL4_OFFSET 0x1d0 /* Endpoint control 4 */ +#define IMX9_USBDEV_ENDPTCTRL5_OFFSET 0x1d4 /* Endpoint control 5 */ +#define IMX9_USBDEV_ENDPTCTRL6_OFFSET 0x1d8 /* Endpoint control 6 */ +#define IMX9_USBDEV_ENDPTCTRL7_OFFSET 0x1dc /* Endpoint control 7 */ + +/* USB Non-core memory map & register definition */ + +#define IMX9_USBNC_CTRL1_OFFSET 0x0200 /* USB OTG Control Register 1 */ +#define IMX9_USBNC_CTRL2_OFFSET 0x0204 /* USB OTG Control Register 2 */ +#define IMX9_USBNC_UTMIPHY_CFG1_OFFSET 0x0230 /* PHY Configure 1 */ + +/* USBOTG register bit definitions ******************************************/ + +/* Device/host capability registers */ + +/* CAPLENGTH */ + +#define USBOTG_CAPLENGTH_SHIFT (0) /* Bits 0-7: Offset from register base to operational regs */ +#define USBOTG_CAPLENGTH_MASK (0xff << USBOTG_CAPLENGTH_SHIFT) + +/* HCIVERSION */ + +#define USBHOST_HCIVERSION_SHIFT (0) /* Bits 0-15: BCD encoding of the EHCI revision number */ +#define USBHOST_HCIVERSION_MASK (0xffff << USBHOST_HCIVERSION_SHIFT) + +/* HCSPARAMS */ + +#define USBHOST_HCSPARAMS_NTT_SHIFT (24) /* Bits 24-27: Number of Transaction Translators */ +#define USBHOST_HCSPARAMS_NTT_MASK (0xf << USBHOST_HCSPARAMS_NTT_SHIFT) +#define USBHOST_HCSPARAMS_NPTT_SHIFT (20) /* Bits 20-23: Number of Ports per Transaction Translator */ +#define USBHOST_HCSPARAMS_NPTT_MASK (15 << USBHOST_HCSPARAMS_NPTT_SHIFT) +#define USBHOST_HCSPARAMS_PI (1 << 16) /* Bit 16: Port indicators */ +#define USBHOST_HCSPARAMS_NCC_SHIFT (12) /* Bits 12-15: Number of Companion Controller */ +#define USBHOST_HCSPARAMS_NCC_MASK (0xf << USBHOST_HCSPARAMS_NCC_SHIFT) +#define USBHOST_HCSPARAMS_NPCC_SHIFT (8) /* Bits 8-11: Number of Ports per Companion Controller */ +#define USBHOST_HCSPARAMS_NPCC_MASK (0xf << USBHOST_HCSPARAMS_NPCC_SHIFT) +#define USBHOST_HCSPARAMS_PPC (1 << 4) /* Bit 4: Port Power Control */ +#define USBHOST_HCSPARAMS_NPORTS_SHIF (0) /* Bits 0-3: Number of downstream ports */ +#define USBHOST_HCSPARAMS_NPORTS_MASK (0xf << USBHOST_HCSPARAMS_NPORTS_SHIFT) + +/* HCCPARAMS */ + +#define USBHOST_HCCPARAMS_EECP_SHIFT (8) /* Bits 8-15: EHCI Extended Capabilities Pointer */ +#define USBHOST_HCCPARAMS_EECP_MASK (0xff << USBHOST_HCCPARAMS_EECP_SHIFT) +#define USBHOST_HCCPARAMS_IST_SHIFT (4) /* Bits 4-7: Isochronous Scheduling Threshold */ +#define USBHOST_HCCPARAMS_IST_MASK (0xf << USBHOST_HCCPARAMS_IST_SHIFT) +#define USBHOST_HCCPARAMS_ASP (1 << 2) /* Bit 2: Asynchronous Schedule Park Capability */ +#define USBHOST_HCCPARAMS_PFL (1 << 1) /* Bit 1: Programmable Frame List Flag */ +#define USBHOST_HCCPARAMS_ADC (1 << 0) /* Bit 0: 64-bit Addressing Capability */ + +/* DCIVERSION */ + +#define USBDEV_DCIVERSION_SHIFT (0) /* Bits 0-15: BCD encoding of the device interface */ +#define USBDEV_DCIVERSION_MASK (0xffff << USBDEV_DCIVERSION_SHIFT) + +/* DCCPARAMS */ + +#define USBDEV_DCCPARAMS_HC (1 << 8) /* Bit 8: Host Capable */ +#define USBDEV_DCCPARAMS_DC (1 << 7) /* Bit 7: Device Capable */ +#define USBDEV_DCCPARAMS_DEN_SHIFT (0) /* Bits 0-4: DEN Device Endpoint Number */ +#define USBDEV_DCCPARAMS_DEN_MASK (0x1f << USBDEV_DCCPARAMS_DEN_SHIFT) + +/* Device/host operational registers */ + +/* USB Command register USBCMD -- Device Mode */ + +#define USBDEV_USBCMD_ITC_SHIFT (16) /* Bits 16-23: Interrupt threshold control */ +#define USBDEV_USBCMD_ITC_MASK (0xff << USBDEV_USBCMD_ITC_SHIFT) +# define USBDEV_USBCMD_ITCIMME (0 << USBDEV_USBCMD_ITC_SHIFT) /* Immediate (no threshold) */ +# define USBDEV_USBCMD_ITC1UF (1 << USBDEV_USBCMD_ITC_SHIFT) /* 1 micro frame */ +# define USBDEV_USBCMD_ITC2UF (2 << USBDEV_USBCMD_ITC_SHIFT) /* 2 micro frames */ +# define USBDEV_USBCMD_ITC4UF (4 << USBDEV_USBCMD_ITC_SHIFT) /* 4 micro frames */ +# define USBDEV_USBCMD_ITC8UF (8 << USBDEV_USBCMD_ITC_SHIFT) /* 8 micro frames */ +# define USBDEV_USBCMD_ITC16UF (16 << USBDEV_USBCMD_ITC_SHIFT) /* 16 micro frames */ +# define USBDEV_USBCMD_ITC32UF (32 << USBDEV_USBCMD_ITC_SHIFT) /* 32 micro frames */ +# define USBDEV_USBCMD_ITC64UF (64 << USBDEV_USBCMD_ITC_SHIFT) /* 64 micro frames */ + +#define USBDEV_USBCMD_ATDTW (1 << 14) /* Bit 14: Add dTD trip wire */ +#define USBDEV_USBCMD_SUTW (1 << 13) /* Bit 13: Setup trip wire */ +#define USBDEV_USBCMD_RST (1 << 1) /* Bit 1: 1 Controller reset */ +#define USBDEV_USBCMD_RS (1 << 0) /* Bit 0: 0 Run/Stop */ + +/* USB Command register USBCMD -- Host Mode */ + +#define USBHOST_USBCMD_ITC_SHIFT (16) /* Bits 16-13: Interrupt threshold control */ +#define USBHOST_USBCMD_ITC_MASK (0xff << USBHOST_USBCMD_ITC_SHIFT) +# define USBHOST_USBCMD_ITCIMMED (0 << USBHOST_USBCMD_ITC_SHIFT) /* Immediate (no threshold) */ +# define USBHOST_USBCMD_ITC1UF (1 << USBHOST_USBCMD_ITC_SHIFT) /* 1 micro frame */ +# define USBHOST_USBCMD_ITC2UF (2 << USBHOST_USBCMD_ITC_SHIFT) /* 2 micro frames */ +# define USBHOST_USBCMD_ITC4UF (4 << USBHOST_USBCMD_ITC_SHIFT) /* 4 micro frames */ +# define USBHOST_USBCMD_ITC8UF (8 << USBHOST_USBCMD_ITC_SHIFT) /* 8 micro frames */ +# define USBHOST_USBCMD_ITC16UF (16 << USBHOST_USBCMD_ITC_SHIFT) /* 16 micro frames */ +# define USBHOST_USBCMD_ITC32UF (32 << USBHOST_USBCMD_ITC_SHIFT) /* 32 micro frames */ +# define USBHOST_USBCMD_ITC64UF (64 << USBHOST_USBCMD_ITC_SHIFT) /* 64 micro frames */ + +#define USBHOST_USBCMD_FS2 (1 << 15) /* Bit 15: Bit 2 of the Frame List Size bits */ +#define USBHOST_USBCMD_ASPE (1 << 11) /* Bit 11: Asynchronous Schedule Park Mode Enable */ +#define USBHOST_USBCMD_ASP_SHIFT (8) /* Bits 8-9: Asynchronous schedule park mode */ +#define USBHOST_USBCMD_ASP_MASK (0x3 << USBHOST_USBCMD_ASP_SHIFT) +#define USBHOST_USBCMD_IAA (1 << 6) /* Bit 6: Interrupt next asynchronous schedule */ +#define USBHOST_USBCMD_ASE (1 << 5) /* Bit 5: Skips processing asynchronous schedule */ +#define USBHOST_USBCMD_PSE (1 << 4) /* Bit 4: Skips processing periodic schedule */ +#define USBHOST_USBCMD_FS1 (1 << 3) /* Bit 3: Bit 1 of the Frame List Size bits */ +#define USBHOST_USBCMD_FS0 (1 << 2) /* Bit 2: Bit 0 of the Frame List Size bits */ +#define USBHOST_USBCMD_RST (1 << 1) /* Bit 1: Controller reset */ +#define USBHOST_USBCMD_RS (1 << 0) /* Bit 0: Run/Stop */ + +/* USB Status register USBSTS -- Device Mode */ + +#define USBDEV_USBSTS_NAKI (1 << 16) /* Bit 16: NAK interrupt bit */ +#define USBDEV_USBSTS_SLI (1 << 8) /* Bit 8: DCSuspend */ +#define USBDEV_USBSTS_SRI (1 << 7) /* Bit 7: SOF received */ +#define USBDEV_USBSTS_URI (1 << 6) /* Bit 6: USB reset received */ +#define USBDEV_USBSTS_PCI (1 << 2) /* Bit 2: Port change detect */ +#define USBDEV_USBSTS_UEI (1 << 1) /* Bit 1: USB error interrupt */ +#define USBDEV_USBSTS_UI (1 << 0) /* Bit 0: USB interrupt */ + +/* USB Status register USBSTS -- Host Mode */ + +#define USBHOST_USBSTS_UPI (1 << 19) /* Bit 19: USB host periodic interrupt */ +#define USBHOST_USBSTS_UAI (1 << 18) /* Bit 18: USB host asynchronous interrupt */ +#define USBHOST_USBSTS_AS (1 << 15) /* Bit 15: Asynchronous schedule status */ +#define USBHOST_USBSTS_PS (1 << 14) /* Bit 14: Periodic schedule status */ +#define USBHOST_USBSTS_RCL (1 << 13) /* Bit 13: Reclamation */ +#define USBHOST_USBSTS_HCH (1 << 12) /* Bit 12: HCHalted */ +#define USBHOST_USBSTS_SRI (1 << 7) /* Bit 7: SOF received */ +#define USBHOST_USBSTS_AAI (1 << 5) /* Bit 5: Interrupt on async advance */ +#define USBHOST_USBSTS_FRI (1 << 3) /* Bit 3: Frame list roll-over */ +#define USBHOST_USBSTS_PCI (1 << 2) /* Bit 2: Port change detect */ +#define USBHOST_USBSTS_UEI (1 << 1) /* Bit 1: USB error interrupt */ +#define USBHOST_USBSTS_UI (1 << 0) /* Bit 0: USB interrupt */ + +/* USB interrupt register USBINTR -- Device Mode */ + +#define USBDEV_USBINTR_NAKE (1 << 16) /* Bit 16: NAK interrupt enable */ +#define USBDEV_USBINTR_SLE (1 << 8) /* Bit 8: Sleep enable */ +#define USBDEV_USBINTR_SRE (1 << 7) /* Bit 7: SOF received enable */ +#define USBDEV_USBINTR_URE (1 << 6) /* Bit 6: USB reset enable */ +#define USBDEV_USBINTR_PCE (1 << 2) /* Bit 2: Port change detect enable */ +#define USBDEV_USBINTR_UEE (1 << 1) /* Bit 1: USB error interrupt enable */ +#define USBDEV_USBINTR_UE (1 << 0) /* Bit 0: USB interrupt enable */ + +/* USB interrupt register USBINTR (address 0x19000148) -- Host Mode */ + +#define USBHOST_USBINTR_UPIE (1 << 19) /* Bit 19: USB host periodic interrupt enable */ +#define USBHOST_USBINTR_UAIE (1 << 18) /* Bit 18: USB host asynchronous interrupt enable */ +#define USBHOST_USBINTR_SRE (1 << 7) /* Bit 7: SOF timer interrupt enable */ +#define USBHOST_USBINTR_AAE (1 << 5) /* Bit 5: Interrupt on asynchronous advance enable */ +#define USBHOST_USBINTR_FRE (1 << 3) /* Bit 3: Frame list rollover enable */ +#define USBHOST_USBINTR_PCE (1 << 2) /* Bit 2: Port change detect enable */ +#define USBHOST_USBINTR_UEE (1 << 1) /* Bit 1: USB error interrupt enable */ +#define USBHOST_USBINTR_UE (1 << 0) /* Bit 0: USB interrupt enable */ + +/* Frame index register FRINDEX -- Device Mode */ + +#define USBDEV_FRINDEX_LFN_SHIFT (3) /* Bits 3-13: Frame number of last frame transmitted */ +#define USBDEV_FRINDEX_LFN_MASK (0x7ff << USBDEV_FRINDEX_LFN_SHIFT) +#define USBDEV_FRINDEX_CUFN_SHIFT (0) /* Bits 0-2: Current micro frame number */ +#define USBDEV_FRINDEX_CUFN_MASK (7 << USBDEV_FRINDEX_CUFN_SHIFT) + +/* Frame index register FRINDEX -- Host Mode */ + +#define USBHOST_FRINDEX_FLI_SHIFT (3) /* Bits 3-13: Frame list current index */ +#define USBHOST_FRINDEX_FLI_MASK(n) (0x7ff << ((n) + USBHOST_FRINDEX_FLI_SHIFT - 1) +#define USBHOST_FRINDEX_CUFN_SHIFT (0) /* Bits 0-2: Current micro frame number */ +#define USBHOST_FRINDEX_CUFN_MASK (0x7 << USBHOST_FRINDEX_CUFN_SHIFT) + +/* USB Device Address register DEVICEADDR -- Device Mode */ + +#define USBDEV_DEVICEADDR_SHIFT (25) /* Bits 25-31: USBADR USB device address */ +#define USBDEV_DEVICEADDR_MASK (0x7f << USBDEV_DEVICEADDR_SHIFT) +#define USBDEV_DEVICEADDR_USBADRA (1 << 24) /* Bit 24: Device address advance */ + +/* USB Periodic List Base register PERIODICLIST -- Host Mode */ + +#define USBHOST_PERIODICLIST_BASEADR_SHIFT (12) /* Bits 12-31: Base Address (Low) */ +#define USBHOST_PERIODICLIST_BASEADR_MASK (0xfffff << USBHOST_PERIODICLIST_PERBASE_SHIFT) + +/* USB Asynchronous List Address register ASYNCLISTADDR -- Host Mode */ + +#define USBHOST_ASYNCLISTADDR_ASYBASE_SHIFT (5) /* Bits 5-31: Link pointer (Low) LPL */ +#define USBHOST_ASYNCLISTADDR_ASYBASE_MASK (0x07ffffff << USBHOST_ASYNCLISTADDR_ASYBASE_SHIFT) + +/* USB Endpoint List Address register ENDPOINTLISTADDR -- Device Mode */ + +#define USBDEV_ENDPOINTLIST_EPBASE_SHIFT (11) /* Bits 11-31: Endpoint list pointer (low) */ +#define USBDEV_ENDPOINTLIST_EPBASE_MASK (0x1fffff << USBDEV_ENDPOINTLIST_EPBASE_SHIFT) + +/* USB burst size register BURSTSIZE -- Device/Host Mode */ + +#define USBDEV_BURSTSIZE_TXPBURST_SHIFT (8) /* Bits 8-15: Programmable TX burst length */ +#define USBDEV_BURSTSIZE_TXPBURST_MASK (0xff << USBDEV_BURSTSIZE_TXPBURST_SHIFT) +#define USBDEV_BURSTSIZE_RXPBURST_SHIFT (0) /* Bits 0-7: RXPBURST Programmable RX burst length */ +#define USBDEV_BURSTSIZE_RXPBURST_MASK (0xff << USBDEV_BURSTSIZE_RXPBURST_SHIFT) + +#define USBHOST_BURSTSIZE_TXPBURST_SHIFT (8) /* Bits 8-15: Programmable TX burst length */ +#define USBHOST_BURSTSIZE_TXPBURST_MASK (0xff << USBHOST_BURSTSIZE_TXPBURST_SHIFT) +#define USBHOST_BURSTSIZE_RXPBURST_SHIFT (0) /* Bits 0-7: RXPBURST Programmable RX burst length */ +#define USBHOST_BURSTSIZE_RXPBURST_MASK (0xff << USBHOST_BURSTSIZE_RXPBURST_SHIFT) + +/* USB Transfer buffer Fill Tuning register TXFIFOFILLTUNING -- Host Mode */ + +#define USBHOST_TXFILLTUNING_FIFOTHRES_SHIFT (16) /* Bits 16-21: Scheduler overhead */ +#define USBHOST_TXFILLTUNING_FIFOTHRES_MASK (0x3f << USBHOST_TXFILLTUNING_FIFOTHRES_SHIFT) +#define USBHOST_TXFILLTUNING_SCHEATLTH_SHIFT (8) /* Bits 8-12: Scheduler health counter */ +#define USBHOST_TXFILLTUNING_SCHEATLTH_MASK (0x1f << USBHOST_TXFILLTUNING_SCHEATLTH_SHIFT) +#define USBHOST_TXFILLTUNING_SCHOH_SHIFT (0) /* Bits 0-7: FIFO burst threshold */ +#define USBHOST_TXFILLTUNING_SCHOH_MASK (0x7f << USBHOST_TXFILLTUNING_SCHOH_SHIFT) + +/* USB endpoint NAK register ENDPTNAK -- Device Mode */ + +#define USBDEV_ENDPTNAK_EPTN_SHIFT (16) /* Bits 16-23: Tx endpoint NAK */ +#define USBDEV_ENDPTNAK_EPTN_MASK (0xff << USBDEV_ENDPTNAK_EPTN_SHIFT) +#define USBDEV_ENDPTNAK_EPRN_SHIFT (0) /* Bits 0-7: Rx endpoint NAK */ +#define USBDEV_ENDPTNAK_EPRN_MASK (0xff << USBDEV_ENDPTNAK_EPRN_SHIFT) + +/* USB Endpoint NAK Enable register ENDPTNAKEN -- Device Mode */ + +#define USBDEV_ENDPTNAK_EPTNE_SHIFT (16) /* Bits 16-23: Tx endpoint NAK enable */ +#define USBDEV_ENDPTNAK_EPTNE_MASK (0xff << USBDEV_ENDPTNAK_EPTNE_SHIFT) +#define USBDEV_ENDPTNAK_EPRNE_SHIFT (0) /* Bits 0-7: Rx endpoint NAK enable */ +#define USBDEV_ENDPTNAK_EPRNE_MASK (0xff << USBDEV_ENDPTNAK_EPRNE_SHIFT) + +/* Configure Flag register CONFIGFLAG -- Not used, returns 1 */ + +#define USBDEV_CONFIGFLAG_CF (1) + +/* Port Status and Control register PRTSC1 -- Device Mode */ + +#define USBDEV_PRTSC1_PSPD_SHIFT (26) /* Bits 26-27: Port speed */ +#define USBDEV_PRTSC1_PSPD_MASK (0x3 << USBDEV_PRTSC1_PSPD_SHIFT) +# define USBDEV_PRTSC1_PSPD_FS (0 << USBDEV_PRTSC1_PSPD_SHIFT) /* Full-speed */ +# define USBDEV_PRTSC1_PSPD_LS (1 << USBDEV_PRTSC1_PSPD_SHIFT) /* Low-speed */ +# define USBDEV_PRTSC1_PSPD_HS (2 << USBDEV_PRTSC1_PSPD_SHIFT) /* High-speed */ + +#define USBDEV_PRTSC1_PFSC (1 << 24) /* Bit 24: Port force full speed connect */ +#define USBDEV_PRTSC1_PHCD (1 << 23) /* Bit 23: PHY low power suspend - clock disable (PLPSCD) */ +#define USBDEV_PRTSC1_PTC_SHIFT (16) /* Bits 16-19: 19: Port test control */ +#define USBDEV_PRTSC1_PTC_MASK (0xf << USBDEV_PRTSC1_PTC_SHIFT) +# define USBDEV_PRTSC1_PTC_DISABLE (0 << USBDEV_PRTSC1_PTC_SHIFT) /* TEST_MODE_DISABLE */ +# define USBDEV_PRTSC1_PTC_JSTATE (1 << USBDEV_PRTSC1_PTC_SHIFT) /* J_STATE */ +# define USBDEV_PRTSC1_PTC_KSTATE (2 << USBDEV_PRTSC1_PTC_SHIFT) /* K_STATE */ +# define USBDEV_PRTSC1_PTC_SE0 (3 << USBDEV_PRTSC1_PTC_SHIFT) /* SE0 (host)/NAK (device) */ +# define USBDEV_PRTSC1_PTC_PACKET (4 << USBDEV_PRTSC1_PTC_SHIFT) /* Packet */ +# define USBDEV_PRTSC1_PTC_HS (5 << USBDEV_PRTSC1_PTC_SHIFT) /* FORCE_ENABLE_HS */ +# define USBDEV_PRTSC1_PTC_FS (6 << USBDEV_PRTSC1_PTC_SHIFT) /* FORCE_ENABLE_FS */ + +#define USBDEV_PRTSC1_PIC_SHIFT (14) /* Bits 14-15: Port indicator control */ +#define USBDEV_PRTSC1_PIC_MASK (0x3 << USBDEV_PRTSC1_PIC_SHIFT) +# define USBDEV_PRTSC1_PIC_OFF (0 << USBDEV_PRTSC1_PIC_SHIFT) /* 00 Port indicators are off */ +# define USBDEV_PRTSC1_PIC_AMBER (1 << USBDEV_PRTSC1_PIC_SHIFT) /* 01 amber */ +# define USBDEV_PRTSC1_PIC_GREEN (2 << USBDEV_PRTSC1_PIC_SHIFT) /* 10 green */ + +#define USBDEV_PRTSC1_HSP (1 << 9) /* Bit 9: High-speed status */ +#define USBDEV_PRTSC1_PR (1 << 8) /* Bit 8: Port reset */ +#define USBDEV_PRTSC1_SUSP (1 << 7) /* Bit 7: Suspend */ +#define USBDEV_PRTSC1_FPR (1 << 6) /* Bit 6: Force port resume */ +#define USBDEV_PRTSC1_PEC (1 << 3) /* Bit 3: Port enable/disable change */ +#define USBDEV_PRTSC1_PE (1 << 2) /* Bit 2: Port enable */ +#define USBDEV_PRTSC1_CCS (1 << 0) /* Bit 0: Current connect status */ + +/* Port Status and Control register PRTSC1 -- Host Mode */ + +#define USBHOST_PRTSC1_PSPD_SHIFT (26) /* Bits 26-27: Port speed */ +#define USBHOST_PRTSC1_PSPD_MASK (0x3 << USBHOST_PRTSC1_PSPD_SHIFT) +# define USBHOST_PRTSC1_PSPD_FS (0 << USBHOST_PRTSC1_PSPD_SHIFT) /* Full-speed */ +# define USBHOST_PRTSC1_PSPD_LS (1 << USBHOST_PRTSC1_PSPD_SHIFT) /* Low-speed */ +# define USBHOST_PRTSC1_PSPD_HS (2 << USBHOST_PRTSC1_PSPD_SHIFT) /* High-speed */ + +#define USBHOST_PRTSC1_PFSC (1 << 24) /* Bit 24: Port force full speed connect */ +#define USBHOST_PRTSC1_PHCD (1 << 23) /* Bit 23: PHY low power suspend - clock disable (PLPSCD) */ +#define USBHOST_PRTSC1_WKOC (1 << 22) /* Bit 22: Wake on over-current enable (WKOC_E) */ +#define USBHOST_PRTSC1_WKDC (1 << 21) /* Bit 21: Wake on disconnect enable (WKDSCNNT_E) */ +#define USBHOST_PRTSC1_WKCN (1 << 20) /* Bit 20: Wake on connect enable (WKCNNT_E) */ +#define USBHOST_PRTSC1_PTC_SHIFT (16) /* Bits 16-19: Port test control */ +#define USBHOST_PRTSC1_PTC_MASK (0xf << USBHOST_PRTSC1_PTC_SHIFT) +# define USBHOST_PRTSC1_PTC_DISABLE (0 << USBHOST_PRTSC1_PTC_SHIFT) /* 0000 TEST_MODE_DISABLE */ +# define USBHOST_PRTSC1_PTC_JSTATE (1 << USBHOST_PRTSC1_PTC_SHIFT) /* 0001 J_STATE */ +# define USBHOST_PRTSC1_PTC_KSTATE (2 << USBHOST_PRTSC1_PTC_SHIFT) /* 0010 K_STATE */ +# define USBHOST_PRTSC1_PTC_SE0 (3 << USBHOST_PRTSC1_PTC_SHIFT) /* 0011 SE0 (host)/NAK (device) */ +# define USBHOST_PRTSC1_PTC_PACKET (4 << USBHOST_PRTSC1_PTC_SHIFT) /* 0100 Packet */ +# define USBHOST_PRTSC1_PTC_HS (5 << USBHOST_PRTSC1_PTC_SHIFT) /* 0101 FORCE_ENABLE_HS */ +# define USBHOST_PRTSC1_PTC_FS (6 << USBHOST_PRTSC1_PTC_SHIFT) /* 0110 FORCE_ENABLE_FS */ +# define USBHOST_PRTSC1_PTC_LS (7 << USBHOST_PRTSC1_PTC_SHIFT) /* 0111 FORCE_ENABLE_LS */ + +#define USBHOST_PRTSC1_PIC_SHIFT (14) /* Bits 14-15: Port indicator control */ +#define USBHOST_PRTSC1_PIC_MASK (0x3 << USBHOST_PRTSC1_PIC_SHIFT) +# define USBHOST_PRTSC1_PIC_OFF (0 << USBHOST_PRTSC1_PIC_SHIFT) /* 00 Port indicators are off */ +# define USBHOST_PRTSC1_PIC_AMBER (1 << USBHOST_PRTSC1_PIC_SHIFT) /* 01 Amber */ +# define USBHOST_PRTSC1_PIC_GREEN (2 << USBHOST_PRTSC1_PIC_SHIFT) /* 10 Green */ + +#define USBHOST_PRTSC1_PP (1 << 12) /* Bit 12: Port power control */ +#define USBHOST_PRTSC1_LS_SHIFT (10) /* Bits 10-11: Line status */ +#define USBHOST_PRTSC1_LS_MASK (0x3 << USBHOST_PRTSC1_LS_SHIFT) +# define USBHOST_PRTSC1_LS_SE0 (0 << USBHOST_PRTSC1_LS_SHIFT) /* SE0 (USB_DP and USB_DM LOW) */ +# define USBHOST_PRTSC1_LS_JSTATE (2 << USBHOST_PRTSC1_LS_SHIFT) /* J-state (USB_DP HIGH and USB_DM LOW) */ +# define USBHOST_PRTSC1_LS_KSTATE (1 << USBHOST_PRTSC1_LS_SHIFT) /* K-state (USB_DP LOW and USB_DM HIGH) */ + +#define USBHOST_PRTSC1_HSP (1 << 9) /* Bit 9: High-speed status */ +#define USBHOST_PRTSC1_PR (1 << 8) /* Bit 8: Port reset */ +#define USBHOST_PRTSC1_SUSP (1 << 7) /* Bit 7: Suspend */ +#define USBHOST_PRTSC1_FPR (1 << 6) /* Bit 6: Force port resume */ +#define USBHOST_PRTSC1_OCC (1 << 5) /* Bit 5: Over-current change */ +#define USBHOST_PRTSC1_OCA (1 << 4) /* Bit 4: Over-current active */ +#define USBHOST_PRTSC1_PEC (1 << 3) /* Bit 3: Port disable/enable change */ +#define USBHOST_PRTSC1_PE (1 << 2) /* Bit 2: Port enable */ +#define USBHOST_PRTSC1_CSC (1 << 1) /* Bit 1: Connect status change */ +#define USBHOST_PRTSC1_CCS (1 << 0) /* Bit 0: Current connect status */ + +/* OTG Status and Control register (OTGSC) */ + +/* OTG interrupt enable */ + +#define USBOTG_OTGSC_DPIE (1 << 30) /* Bit 30: Data pulse interrupt enable */ +#define USBOTG_OTGSC_1MSE (1 << 29) /* Bit 29: 1 millisecond timer interrupt enable */ +#define USBOTG_OTGSC_BSEIE (1 << 28) /* Bit 28: B-session end interrupt enable */ +#define USBOTG_OTGSC_BSVIE (1 << 27) /* Bit 27: B-session valid interrupt enable */ +#define USBOTG_OTGSC_ASVIE (1 << 26) /* Bit 26: A-session valid interrupt enable */ +#define USBOTG_OTGSC_AVVIE (1 << 25) /* Bit 25: A-VBUS valid interrupt enable */ +#define USBOTG_OTGSC_IDIE (1 << 24) /* Bit 24: USB ID interrupt enable */ + +/* OTG interrupt status */ + +#define USBOTG_OTGSC_DPIS (1 << 22) /* Bit 22: Data pulse interrupt status */ +#define USBOTG_OTGSC_1MSS (1 << 21) /* Bit 21: 1 millisecond timer interrupt status */ +#define USBOTG_OTGSC_BSEIS (1 << 20) /* Bit 20: B-Session end interrupt status */ +#define USBOTG_OTGSC_BSVIS (1 << 19) /* Bit 19: B-Session valid interrupt status */ +#define USBOTG_OTGSC_ASVIS (1 << 18) /* Bit 18: A-Session valid interrupt status */ +#define USBOTG_OTGSC_AVVIS (1 << 17) /* Bit 17: A-VBUS valid interrupt status */ +#define USBOTG_OTGSC_IDIS (1 << 16) /* Bit 16: USB ID interrupt status */ + +/* OTG status inputs */ + +#define USBOTG_OTGSC_DPS (1 << 14) /* Bit 14: Data bus pulsing status */ +#define USBOTG_OTGSC_1MST (1 << 13) /* Bit 13: 1 millisecond timer toggle */ +#define USBOTG_OTGSC_BSE (1 << 12) /* Bit 12: B-session end */ +#define USBOTG_OTGSC_BSV (1 << 11) /* Bit 11: B-session valid */ +#define USBOTG_OTGSC_ASV (1 << 10) /* Bit 10: A-session valid */ +#define USBOTG_OTGSC_AVV (1 << 9) /* Bit 9: A-VBUS valid */ +#define USBOTG_OTGSC_ID (1 << 8) /* Bit 8: USB ID */ + +/* OTG controls */ + +#define USBOTG_OTGSC_IDPU (1 << 5) /* Bit 5: ID pull-up */ +#define USBOTG_OTGSC_DP (1 << 4) /* Bit 4: Data pulsing */ +#define USBOTG_OTGSC_OT (1 << 3) /* Bit 3: OTG termination */ +#define USBOTG_OTGSC_VC (1 << 1) /* Bit 1: VBUS_Charge */ +#define USBOTG_OTGSC_VD (1 << 0) /* Bit 0: VBUS_Discharge */ + +/* USB Mode register USBMODE -- Device Mode */ + +#define USBDEV_USBMODE_SDIS (1 << 4) /* Bit 4: Stream disable mode */ +#define USBDEV_USBMODE_SLOM (1 << 3) /* Bit 3: Setup Lockout mode */ +#define USBDEV_USBMODE_ES (1 << 2) /* Bit 2: Endian select */ +#define USBDEV_USBMODE_CM_SHIFT (0) /* Bits 0-1: Controller mode */ +#define USBDEV_USBMODE_CM_MASK (0x3 << USBDEV_USBMODE_CM_SHIFT) +# define USBDEV_USBMODE_CM_IDLE (0 << USBDEV_USBMODE_CM_SHIFT) /* Idle */ +# define USBDEV_USBMODE_CM_DEVICE (2 << USBDEV_USBMODE_CM_SHIFT) /* Device controller */ +# define USBDEV_USBMODE_CM_HOST (3 << USBDEV_USBMODE_CM_SHIFT) /* Host controller */ + +/* USB Mode register USBMODE -- Host Mode */ + +#define USBHOST_USBMODE_SDIS (1 << 4) /* Bit 4: Stream disable mode */ +#define USBHOST_USBMODE_ES (1 << 2) /* Bit 2: Endian select */ +#define USBHOST_USBMODE_CM_SHIFT (0) /* Bits 0-1: Controller mode */ +#define USBHOST_USBMODE_CM_MASK (0x3 << USBHOST_USBMODE_CM_SHIFT) +# define USBHOST_USBMODE_CM_IDLE (0 << USBHOST_USBMODE_CM_SHIFT) /* Idle */ +# define USBHOST_USBMODE_CM_DEVICE (2 << USBHOST_USBMODE_CM_SHIFT) /* Device controller */ +# define USBHOST_USBMODE_CM_HOST (3 << USBHOST_USBMODE_CM_SHIFT) /* Host controller */ + +/* Device endpoint registers */ + +/* USB Endpoint Setup Status register ENDPTSETUPSTAT */ + +#define USBDEV_ENDPTSETSTAT_STAT15 (1 << 15) /* Bit 15: Setup EP status for logical EP 15 */ +#define USBDEV_ENDPTSETSTAT_STAT14 (1 << 14) /* Bit 14: Setup EP status for logical EP 14 */ +#define USBDEV_ENDPTSETSTAT_STAT13 (1 << 13) /* Bit 13: Setup EP status for logical EP 13 */ +#define USBDEV_ENDPTSETSTAT_STAT12 (1 << 12) /* Bit 12: Setup EP status for logical EP 12 */ +#define USBDEV_ENDPTSETSTAT_STAT11 (1 << 11) /* Bit 11: Setup EP status for logical EP 11 */ +#define USBDEV_ENDPTSETSTAT_STAT10 (1 << 10) /* Bit 10: Setup EP status for logical EP 10 */ +#define USBDEV_ENDPTSETSTAT_STAT9 (1 << 9) /* Bit 9: Setup EP status for logical EP 9 */ +#define USBDEV_ENDPTSETSTAT_STAT8 (1 << 8) /* Bit 8: Setup EP status for logical EP 8 */ +#define USBDEV_ENDPTSETSTAT_STAT7 (1 << 7) /* Bit 7: Setup EP status for logical EP 7 */ +#define USBDEV_ENDPTSETSTAT_STAT6 (1 << 6) /* Bit 6: Setup EP status for logical EP 6 */ +#define USBDEV_ENDPTSETSTAT_STAT5 (1 << 5) /* Bit 5: Setup EP status for logical EP 5 */ +#define USBDEV_ENDPTSETSTAT_STAT4 (1 << 4) /* Bit 4: Setup EP status for logical EP 4 */ +#define USBDEV_ENDPTSETSTAT_STAT3 (1 << 3) /* Bit 3: Setup EP status for logical EP 3 */ +#define USBDEV_ENDPTSETSTAT_STAT2 (1 << 2) /* Bit 2: Setup EP status for logical EP 2 */ +#define USBDEV_ENDPTSETSTAT_STAT1 (1 << 1) /* Bit 1: Setup EP status for logical EP 1 */ +#define USBDEV_ENDPTSETSTAT_STAT0 (1 << 0) /* Bit 0: Setup EP status for logical EP 0 */ + +/* USB Endpoint Prime register ENDPTPRIME */ + +#define USBDEV_ENDPTPRIM_PETB7 (1 << 23) /* Bit 23: Prime EP xmt buffer for physical IN EP 7 */ +#define USBDEV_ENDPTPRIM_PETB6 (1 << 22) /* Bit 22: Prime EP xmt buffer for physical IN EP 6 */ +#define USBDEV_ENDPTPRIM_PETB5 (1 << 21) /* Bit 21: Prime EP xmt buffer for physical IN EP 5 */ +#define USBDEV_ENDPTPRIM_PETB4 (1 << 20) /* Bit 20: Prime EP xmt buffer for physical IN EP 4 */ +#define USBDEV_ENDPTPRIM_PETB3 (1 << 19) /* Bit 19: Prime EP xmt buffer for physical IN EP 3 */ +#define USBDEV_ENDPTPRIM_PETB2 (1 << 18) /* Bit 18: Prime EP xmt buffer for physical IN EP 2 */ +#define USBDEV_ENDPTPRIM_PETB1 (1 << 17) /* Bit 17: Prime EP xmt buffer for physical IN EP 1 */ +#define USBDEV_ENDPTPRIM_PETB0 (1 << 16) /* Bit 16: Prime EP xmt buffer for physical IN EP 0 */ +#define USBDEV_ENDPTPRIM_PERB7 (1 << 7) /* Bit 7: Prime EP recv buffer for physical OUT EP 7 */ +#define USBDEV_ENDPTPRIM_PERB6 (1 << 6) /* Bit 6: Prime EP recv buffer for physical OUT EP 6 */ +#define USBDEV_ENDPTPRIM_PERB5 (1 << 5) /* Bit 5: Prime EP recv buffer for physical OUT EP 5 */ +#define USBDEV_ENDPTPRIM_PERB4 (1 << 4) /* Bit 4: Prime EP recv buffer for physical OUT EP 4 */ +#define USBDEV_ENDPTPRIM_PERB3 (1 << 3) /* Bit 3: Prime EP recv buffer for physical OUT EP 3 */ +#define USBDEV_ENDPTPRIM_PERB2 (1 << 2) /* Bit 2: Prime EP recv buffer for physical OUT EP 2 */ +#define USBDEV_ENDPTPRIM_PERB1 (1 << 1) /* Bit 1: Prime EP recv buffer for physical OUT EP 1 */ +#define USBDEV_ENDPTPRIM_PERB0 (1 << 0) /* Bit 0: Prime EP recv buffer for physical OUT EP 0 */ + +/* USB Endpoint Flush register ENDPTFLUSH */ + +#define USBDEV_ENDPTFLUSH_FETB7 (1 << 23) /* Bit 23: Flush EP xmt buffer for physical IN EP 7 */ +#define USBDEV_ENDPTFLUSH_FETB6 (1 << 22) /* Bit 22: Flush EP xmt buffer for physical IN EP 6 */ +#define USBDEV_ENDPTFLUSH_FETB5 (1 << 21) /* Bit 21: Flush EP xmt buffer for physical IN EP 5 */ +#define USBDEV_ENDPTFLUSH_FETB4 (1 << 20) /* Bit 20: Flush EP xmt buffer for physical IN EP 4 */ +#define USBDEV_ENDPTFLUSH_FETB3 (1 << 19) /* Bit 19: Flush EP xmt buffer for physical IN EP 3 */ +#define USBDEV_ENDPTFLUSH_FETB2 (1 << 18) /* Bit 18: Flush EP xmt buffer for physical IN EP 2 */ +#define USBDEV_ENDPTFLUSH_FETB1 (1 << 17) /* Bit 17: Flush EP xmt buffer for physical IN EP 1 */ +#define USBDEV_ENDPTFLUSH_FETB0 (1 << 16) /* Bit 16: Flush EP xmt buffer for physical IN EP 0 */ +#define USBDEV_ENDPTFLUSH_FERB7 (1 << 7) /* Bit 7: Flush EP recv buffer for physical OUT EP 7 */ +#define USBDEV_ENDPTFLUSH_FERB6 (1 << 6) /* Bit 6: Flush EP recv buffer for physical OUT EP 6 */ +#define USBDEV_ENDPTFLUSH_FERB5 (1 << 5) /* Bit 5: Flush EP recv buffer for physical OUT EP 5 */ +#define USBDEV_ENDPTFLUSH_FERB4 (1 << 4) /* Bit 4: Flush EP recv buffer for physical OUT EP 4 */ +#define USBDEV_ENDPTFLUSH_FERB3 (1 << 3) /* Bit 3: Flush EP recv buffer for physical OUT EP 3 */ +#define USBDEV_ENDPTFLUSH_FERB2 (1 << 2) /* Bit 2: Flush EP recv buffer for physical OUT EP 2 */ +#define USBDEV_ENDPTFLUSH_FERB1 (1 << 1) /* Bit 1: Flush EP recv buffer for physical OUT EP 1 */ +#define USBDEV_ENDPTFLUSH_FERB0 (1 << 0) /* Bit 0: Flush EP recv buffer for physical OUT EP 0 */ + +/* USB Endpoint Status register ENDPTSTATUS */ + +#define USBDEV_ENDPTSTATUS_ETBR7 (1 << 23) /* Bit 23: EP xmt buffer ready for physical IN EP 7 */ +#define USBDEV_ENDPTSTATUS_ETBR6 (1 << 22) /* Bit 22: EP xmt buffer ready for physical IN EP 6 */ +#define USBDEV_ENDPTSTATUS_ETBR5 (1 << 21) /* Bit 21: EP xmt buffer ready for physical IN EP 5 */ +#define USBDEV_ENDPTSTATUS_ETBR4 (1 << 20) /* Bit 20: EP xmt buffer ready for physical IN EP 4 */ +#define USBDEV_ENDPTSTATUS_ETBR3 (1 << 19) /* Bit 19: EP xmt buffer ready for physical IN EP 3 */ +#define USBDEV_ENDPTSTATUS_ETBR2 (1 << 18) /* Bit 18: EP xmt buffer ready for physical IN EP 2 */ +#define USBDEV_ENDPTSTATUS_ETBR1 (1 << 17) /* Bit 17: EP xmt buffer ready for physical IN EP 1 */ +#define USBDEV_ENDPTSTATUS_ETBR0 (1 << 16) /* Bit 16: EP xmt buffer ready for physical IN EP 0 */ +#define USBDEV_ENDPTSTATUS_ERBR7 (1 << 7) /* Bit 7: EP recv buffer ready for physical OUT EP 7 */ +#define USBDEV_ENDPTSTATUS_ERBR6 (1 << 6) /* Bit 6: EP recv buffer ready for physical OUT EP 6 */ +#define USBDEV_ENDPTSTATUS_ERBR5 (1 << 5) /* Bit 5: EP recv buffer ready for physical OUT EP 5 */ +#define USBDEV_ENDPTSTATUS_ERBR4 (1 << 4) /* Bit 4: EP recv buffer ready for physical OUT EP 4 */ +#define USBDEV_ENDPTSTATUS_ERBR3 (1 << 3) /* Bit 3: EP recv buffer ready for physical OUT EP 3 */ +#define USBDEV_ENDPTSTATUS_ERBR2 (1 << 2) /* Bit 2: EP recv buffer ready for physical OUT EP 2 */ +#define USBDEV_ENDPTSTATUS_ERBR1 (1 << 1) /* Bit 1: EP recv buffer ready for physical OUT EP 1 */ +#define USBDEV_ENDPTSTATUS_ERBR0 (1 << 0) /* Bit 0: EP recv buffer ready for physical OUT EP 0 */ + +/* USB Endpoint Complete register ENDPTCOMPLETE */ + +#define USBDEV_ENDPTCOMPLETE_ETCE7 (1 << 23) /* Bit 23: EP xmt complete event for physical IN EP 7 */ +#define USBDEV_ENDPTCOMPLETE_ETCE6 (1 << 22) /* Bit 22: EP xmt complete event for physical IN EP 6 */ +#define USBDEV_ENDPTCOMPLETE_ETCE5 (1 << 21) /* Bit 21: EP xmt complete event for physical IN EP 5 */ +#define USBDEV_ENDPTCOMPLETE_ETCE4 (1 << 20) /* Bit 20: EP xmt complete event for physical IN EP 4 */ +#define USBDEV_ENDPTCOMPLETE_ETCE3 (1 << 19) /* Bit 19: EP xmt complete event for physical IN EP 3 */ +#define USBDEV_ENDPTCOMPLETE_ETCE2 (1 << 18) /* Bit 18: EP xmt complete event for physical IN EP 2 */ +#define USBDEV_ENDPTCOMPLETE_ETCE1 (1 << 17) /* Bit 17: EP xmt complete event for physical IN EP 1 */ +#define USBDEV_ENDPTCOMPLETE_ETCE0 (1 << 16) /* Bit 16: EP xmt complete event for physical IN EP 0 */ +#define USBDEV_ENDPTCOMPLETE_ERCE7 (1 << 7) /* Bit 7: EP recv complete event for physical OUT EP 7 */ +#define USBDEV_ENDPTCOMPLETE_ERCE6 (1 << 6) /* Bit 6: EP recv complete event for physical OUT EP 6 */ +#define USBDEV_ENDPTCOMPLETE_ERCE5 (1 << 5) /* Bit 5: EP recv complete event for physical OUT EP 5 */ +#define USBDEV_ENDPTCOMPLETE_ERCE4 (1 << 4) /* Bit 4: EP recv complete event for physical OUT EP 4 */ +#define USBDEV_ENDPTCOMPLETE_ERCE3 (1 << 3) /* Bit 3: EP recv complete event for physical OUT EP 3 */ +#define USBDEV_ENDPTCOMPLETE_ERCE2 (1 << 2) /* Bit 2: EP recv complete event for physical OUT EP 2 */ +#define USBDEV_ENDPTCOMPLETE_ERCE1 (1 << 1) /* Bit 1: EP recv complete event for physical OUT EP 1 */ +#define USBDEV_ENDPTCOMPLETE_ERCE0 (1 << 0) /* Bit 0: EP recv complete event for physical OUT EP 0 */ + +/* USB Endpoint 0 Control register ENDPTCTRL0 */ + +#define USBDEV_ENDPTCTRL0_TXE (1 << 23) /* Bit 23: Tx endpoint enable */ +#define USBDEV_ENDPTCTRL0_TXT_SHIFT (18) /* Bits 18-19: Tx endpoint type */ +#define USBDEV_ENDPTCTRL0_TXT_MASK (0x3 << USBDEV_ENDPTCTRL0_TXT_SHIFT) +# define USBDEV_ENDPTCTRL0_TXT_CTRL (0 << USBDEV_ENDPTCTRL0_TXT_SHIFT) /* Control */ + +#define USBDEV_ENDPTCTRL0_TXS (1 << 16) /* Bit 16: Tx endpoint stall */ +#define USBDEV_ENDPTCTRL0_RXE (1 << 7) /* Bit 7: Rx endpoint enable */ +#define USBDEV_ENDPTCTRL0_RXT_SHIFT (2) /* Bits 2-3: Endpoint type */ +#define USBDEV_ENDPTCTR0L_RXT_MASK (0x3 << USBDEV_ENDPTCTRL0_RXT_SHIFT) +# define USBDEV_ENDPTCTRL0_RXT_CTRL (0 << USBDEV_ENDPTCTRL0_RXT_SHIFT) /* Control */ + +#define USBDEV_ENDPTCTRL0_RXS (1 << 0) /* Bit 0: Rx endpoint stall */ + +/* USB Endpoint 1-7 control registers ENDPTCTRL1-ENDPPTCTRL7 */ + +#define USBDEV_ENDPTCTRL_TXE (1 << 23) /* Bit 23: Tx endpoint enable */ +#define USBDEV_ENDPTCTRL_TXR (1 << 22) /* Bit 22: Tx data toggle reset */ +#define USBDEV_ENDPTCTRL_TXI (1 << 21) /* Bit 21: Tx data toggle inhibit */ +#define USBDEV_ENDPTCTRL_TXT_SHIFT (18) /* Bits 18-19: Tx endpoint type */ +#define USBDEV_ENDPTCTRL_TXT_MASK (0x3 << USBDEV_ENDPTCTRL_TXT_SHIFT) +# define USBDEV_ENDPTCTRL_TXT_CTRL (0 << USBDEV_ENDPTCTRL_TXT_SHIFT) /* Control */ +# define USBDEV_ENDPTCTRL_TXT_ISOC (1 << USBDEV_ENDPTCTRL_TXT_SHIFT) /* Isochronous */ +# define USBDEV_ENDPTCTRL_TXT_BULK (2 << USBDEV_ENDPTCTRL_TXT_SHIFT) /* Bulk */ +# define USBDEV_ENDPTCTRL_TXT_INTR (3 << USBDEV_ENDPTCTRL_TXT_SHIFT) /* Interrupt */ + +#define USBDEV_ENDPTCTRL_TXS (1 << 16) /* Bit 16: Tx endpoint stall */ +#define USBDEV_ENDPTCTRL_RXE (1 << 7) /* Bit 7: Rx endpoint enable */ +#define USBDEV_ENDPTCTRL_RXR (1 << 6) /* Bit 6: Rx data toggle reset */ +#define USBDEV_ENDPTCTRL_RXI (1 << 5) /* Bit 5: Rx data toggle inhibit */ +#define USBDEV_ENDPTCTRL_RXT_SHIFT (2) /* Bits 2-3: Endpoint type */ +#define USBDEV_ENDPTCTRL_RXT_MASK (0x3 << USBDEV_ENDPTCTRL_RXT_SHIFT) +# define USBDEV_ENDPTCTRL_RXT_CTRL (0 << USBDEV_ENDPTCTRL_RXT_SHIFT) /* Control */ +# define USBDEV_ENDPTCTRL_RXT_ISOC (1 << USBDEV_ENDPTCTRL_RXT_SHIFT) /* Isochronous */ +# define USBDEV_ENDPTCTRL_RXT_BULK (2 << USBDEV_ENDPTCTRL_RXT_SHIFT) /* Bulk */ +# define USBDEV_ENDPTCTRL_RXT_INTR (3 << USBDEV_ENDPTCTRL_RXT_SHIFT) /* Interrupt */ + +#define USBDEV_ENDPTCTRL_RXS (1 << 0) /* Bit 0: Rx endpoint stall */ + +/* Device non-core registers */ + +/* USB OTG Control register 1 */ + +#define USBNC_CTRL1_WIR (1 << 31) /* Bit 31: Wake-up Interrupt Request */ +#define USBNC_CTRL1_WKUP_DPDM_EN (1 << 29) /* Bit 29: Wake-up on DP/DM change enable */ +#define USBNC_CTRL1_WKUP_VBUS_EN (1 << 17) /* Bit 17: Wake-up on VBUS change enable */ +#define USBNC_CTRL1_WKUP_ID_EN (1 << 16) /* Bit 16: Wake-up on ID change enable */ +#define USBNC_CTRL1_WKUP_SW (1 << 15) /* Bit 15: Software Wake-up */ +#define USBNC_CTRL1_WKUP_SW_EN (1 << 14) /* Bit 14: Software Wake-up Enable */ +#define USBNC_CTRL1_WIE (1 << 10) /* Bit 10: Wake-up Interrupt Enable */ +#define USBNC_CTRL1_PWR_POL (1 << 9) /* Bit 9: Power Polarity */ +#define USBNC_CTRL1_OVER_CUR_POL (1 << 8) /* Bit 8: Polarity of Overcurrent */ +#define USBNC_CTRL1_OVER_CUR_DIS (1 << 7) /* Bit 7: Disable Overcurrent Detection */ + +/* USB OTG Control register 2 */ + +#define USBNC_CTRL2_UTMI_CLK_VLD (1 << 31) /* Bit 31: UTMI clock to the USB PHY is valid */ +#define USBNC_CTRL2_SHORT_PKT_EN (1 << 23) /* Bit 23: Short Packet Interrupt enable */ +#define USBNC_CTRL2_LOWSPEED_EN (1 << 3) /* Bit 3: Low speed enable */ +#define USBNC_CTRL2_AUTURESUME_EN (1 << 2) /* Bit 2: Auto Resume Enable */ +#define USBNC_CTRL2_VBUS_SOURCE_SEL_MASK (0x3) /* Bits 0-1: VBUS source select at VBUS wakeup event */ + +/* PHY Configure 1 -- internal control register bits of the PHY clock */ + +#define USBNC_UTMIPHY_CFG1_TXPREEMPPULSETUNE0 (1 << 30) /* Bit 30: HS Transmitter Pre-Emphasis Duration Control */ +#define USBNC_UTMIPHY_CFG1_TXPREEMPAMPTUNE0_SHIFT (28) /* Bits 28-29: HS Transmitter Pre-Emphasis Current Control */ +#define USBNC_UTMIPHY_CFG1_TXPREEMPAMPTUNE0_MASK (0x3 << 28) +#define USBNC_UTMIPHY_CFG1_TXRESTUNE0_SHIFT (26) /* Bits 26-27: USB Source Impedance Adjustment */ +#define USBNC_UTMIPHY_CFG1_TXRESTUNE0_MASK (0x3 << 26) +#define USBNC_UTMIPHY_CFG1_TXRISETUNE0_SHIFT (24) /* Bits 24-25: HS Transmitter Rise/Fall Time Adjustment */ +#define USBNC_UTMIPHY_CFG1_TXRISETUNE0_MASK (0x3 << 24) +#define USBNC_UTMIPHY_CFG1_TXVREFTUNE0_SHIFT (20) /* Bits 20-23: HS DC Voltage Level Adjustment */ +#define USBNC_UTMIPHY_CFG1_TXVREFTUNE0_MASK (0xf << 20) +#define USBNC_UTMIPHY_CFG1_TXFSLSTUNE0_SHIFT (16) /* Bits 16-19: FS/LS Source Impedance Adjustment */ +#define USBNC_UTMIPHY_CFG1_TXFSLSTUNE0_MASK (0xf << 16) +#define USBNC_UTMIPHY_CFG1_PHY_POR_SW (1 << 15) /* Bit 15 : PHY software POR */ +#define USBNC_UTMIPHY_CFG1_TXHSXVTUNE_SHIFT (13) /* Bits 13-14: Transmitter High-Speed Crossover Adjustment */ +#define USBNC_UTMIPHY_CFG1_TXHSXVTUNE_MASK (0x3 << 13) +#define USBNC_UTMIPHY_CFG1_OTGTUNE0_SHIFT (10) /* Bits 10-12: VBUS Valid Threshold Adjustment */ +#define USBNC_UTMIPHY_CFG1_OTGTUNE0_MASK (0x7 << 10) +#define USBNC_UTMIPHY_CFG1_SQRXTUNE0_SHIFT (7) /* Bits 7-9: Squelch Threshold Adjustment */ +#define USBNC_UTMIPHY_CFG1_SQRXTUNE0_MASK (0x7 << 7) +#define USBNC_UTMIPHY_CFG1_COMPDISTUNE0_SHIFT (4) /* Bits 4-6: Disconnect Threshold Adjustment */ +#define USBNC_UTMIPHY_CFG1_COMPDISTUNE0_MASK (0x7 << 4) + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_USBOTG_H */ diff --git a/arch/arm64/src/imx9/hardware/imx9_usdhc.h b/arch/arm64/src/imx9/hardware/imx9_usdhc.h new file mode 100644 index 0000000000000..0ef608feb9ebd --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_usdhc.h @@ -0,0 +1,704 @@ +/**************************************************************************** + * arch/arm64/src/imx9/hardware/imx9_usdhc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_USDHC_H +#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_USDHC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define IMX9_USDHC_DSADDR_OFFSET 0x0000 /* DMA System Address Register */ +#define IMX9_USDHC_BLKATTR_OFFSET 0x0004 /* Block Attributes Register */ +#define IMX9_USDHC_CMDARG_OFFSET 0x0008 /* Command Argument Register */ +#define IMX9_USDHC_XFERTYP_OFFSET 0x000c /* Transfer Type Register */ +#define IMX9_USDHC_CMDRSP0_OFFSET 0x0010 /* Command Response 0 */ +#define IMX9_USDHC_CMDRSP1_OFFSET 0x0014 /* Command Response 1 */ +#define IMX9_USDHC_CMDRSP2_OFFSET 0x0018 /* Command Response 2 */ +#define IMX9_USDHC_CMDRSP3_OFFSET 0x001c /* Command Response 3 */ +#define IMX9_USDHC_DATAPORT_OFFSET 0x0020 /* Buffer Data Port Register */ +#define IMX9_USDHC_PRSSTAT_OFFSET 0x0024 /* Present State Register */ +#define IMX9_USDHC_PROCTL_OFFSET 0x0028 /* Protocol Control Register */ +#define IMX9_USDHC_SYSCTL_OFFSET 0x002c /* System Control Register */ +#define IMX9_USDHC_IRQSTAT_OFFSET 0x0030 /* Interrupt Status Register */ +#define IMX9_USDHC_IRQSTATEN_OFFSET 0x0034 /* Interrupt Status Enable Register */ +#define IMX9_USDHC_IRQSIGEN_OFFSET 0x0038 /* Interrupt Signal Enable Register */ +#define IMX9_USDHC_AC12ERR_OFFSET 0x003c /* Auto CMD12 Error Status Register */ +#define IMX9_USDHC_HTCAPBLT_OFFSET 0x0040 /* Host Controller Capabilities */ +#define IMX9_USDHC_WML_OFFSET 0x0044 /* Watermark Level Register */ +#define IMX9_USDHC_MIX_OFFSET 0x0048 /* Mixer Control Register */ +#define IMX9_USDHC_FEVT_OFFSET 0x0050 /* Force Event Register */ +#define IMX9_USDHC_ADMAES_OFFSET 0x0054 /* ADMA Error Status Register */ +#define IMX9_USDHC_ADSADDR_OFFSET 0x0058 /* ADMA System Address Register */ +#define IMX9_USDHC_DLL_CONTROL_OFFSET 0x0060 /* DLL Control Register */ +#define IMX9_USDHC_DLL_STATUS_OFFSET 0x0064 /* DLL Status Register */ +#define IMX9_USDHC_CLK_TUNE_CTRL_OFFSET 0x0068 /* Clock turing control Register */ +#define IMX9_USDHC_VENDOR_OFFSET 0x00c0 /* Vendor Specific Register */ +#define IMX9_USDHC_MMCBOOT_OFFSET 0x00c4 /* MMC Boot Register */ +#define IMX9_USDHC_VENDOR2_OFFSET 0x00c8 /* Vendor 2 Register */ +#define IMX9_USDHC_TC_OFFSET 0x00cc /* Tuning Control Register */ +#define IMX9_USDHC_CQVER_OFFSET 0x0100 /* Command Queuing Version */ +#define IMX9_USDHC_CQCAP_OFFSET 0x0104 /* Command Queuing Capabilities */ +#define IMX9_USDHC_CQCFG_OFFSET 0x0108 /* Command Queuing Configuration */ +#define IMX9_USDHC_CQCTL_OFFSET 0x010c /* Command Queuing Control */ +#define IMX9_USDHC_CQIS_OFFSET 0x0110 /* Command Queuing Interrupt Status */ +#define IMX9_USDHC_CQISTE_OFFSET 0x0114 /* Command Queuing Interrupt Status Enable */ +#define IMX9_USDHC_CQISGE_OFFSET 0x0118 /* Command Queuing Interrupt Signal Enable */ +#define IMX9_USDHC_CQIC_OFFSET 0x011c /* Command Queuing Interrupt Coalescing */ +#define IMX9_USDHC_CQTDLBA_OFFSET 0x0120 /* Command Queuing Task Descriptor List Base Address */ +#define IMX9_USDHC_CQTDLBAU_OFFSET 0x0124 /* Command Queuing Task Descriptor List Base Address Upper 32 Bits */ +#define IMX9_USDHC_CQTDBR_OFFSET 0x0128 /* Command Queuing Task Doorbell */ +#define IMX9_USDHC_CQTCN_OFFSET 0x012c /* Command Queuing Task Completion Notification */ +#define IMX9_USDHC_CQDQS_OFFSET 0x0130 /* Command Queuing Device Queue Status */ +#define IMX9_USDHC_CQDPT_OFFSET 0x0134 /* Command Queuing Device Pending Tasks */ +#define IMX9_USDHC_CQTCLR_OFFSET 0x0138 /* Command Queuing Task Clear */ +#define IMX9_USDHC_CQSSC1_OFFSET 0x0140 /* Command Queuing Send Status Configuration 1 */ +#define IMX9_USDHC_CQSSC2_OFFSET 0x0144 /* Command Queuing Send Status Configuration 2 */ +#define IMX9_USDHC_CQCRDCT_OFFSET 0x0148 /* Command Queuing Command Response for Direct-Command Task */ +#define IMX9_USDHC_CQRMEM_OFFSET 0x0150 /* Command Queuing Response Mode Error Mask */ +#define IMX9_USDHC_CQTERRI_OFFSET 0x0154 /* Command Queuing Task Error Information */ +#define IMX9_USDHC_CQCRI_OFFSET 0x0158 /* Command Queuing Command Response Index */ +#define IMX9_USDHC_CQCRA_OFFSET 0x015c /* Command Queuing Command Response Argument */ + +/* Register Addresses *******************************************************/ + +/* For USDHC1 ... */ + +#define IMX9_USDHC1_DSADDR (IMX9_USDHC1_BASE + IMX9_USDHC_DSADDR_OFFSET) +#define IMX9_USDHC1_BLKATTR (IMX9_USDHC1_BASE + IMX9_USDHC_BLKATTR_OFFSET) +#define IMX9_USDHC1_CMDARG (IMX9_USDHC1_BASE + IMX9_USDHC_CMDARG_OFFSET) +#define IMX9_USDHC1_XFERTYP (IMX9_USDHC1_BASE + IMX9_USDHC_XFERTYP_OFFSET) +#define IMX9_USDHC1_CMDRSP0 (IMX9_USDHC1_BASE + IMX9_USDHC_CMDRSP0_OFFSET) +#define IMX9_USDHC1_CMDRSP1 (IMX9_USDHC1_BASE + IMX9_USDHC_CMDRSP1_OFFSET) +#define IMX9_USDHC1_CMDRSP2 (IMX9_USDHC1_BASE + IMX9_USDHC_CMDRSP2_OFFSET) +#define IMX9_USDHC1_CMDRSP3 (IMX9_USDHC1_BASE + IMX9_USDHC_CMDRSP3_OFFSET) +#define IMX9_USDHC1_DATAPORT (IMX9_USDHC1_BASE + IMX9_USDHC_DATAPORT_OFFSET) +#define IMX9_USDHC1_PRSSTAT (IMX9_USDHC1_BASE + IMX9_USDHC_PRSSTAT_OFFSET) +#define IMX9_USDHC1_PROCTL (IMX9_USDHC1_BASE + IMX9_USDHC_PROCTL_OFFSET) +#define IMX9_USDHC1_SYSCTL (IMX9_USDHC1_BASE + IMX9_USDHC_SYSCTL_OFFSET) +#define IMX9_USDHC1_IRQSTAT (IMX9_USDHC1_BASE + IMX9_USDHC_IRQSTAT_OFFSET) +#define IMX9_USDHC1_IRQSTATEN (IMX9_USDHC1_BASE + IMX9_USDHC_IRQSTATEN_OFFSET) +#define IMX9_USDHC1_IRQSIGEN (IMX9_USDHC1_BASE + IMX9_USDHC_IRQSIGEN_OFFSET) +#define IMX9_USDHC1_AC12ERR (IMX9_USDHC1_BASE + IMX9_USDHC_AC12ERR_OFFSET) +#define IMX9_USDHC1_HTCAPBLT (IMX9_USDHC1_BASE + IMX9_USDHC_HTCAPBLT_OFFSET) +#define IMX9_USDHC1_WML (IMX9_USDHC1_BASE + IMX9_USDHC_WML_OFFSET) +#define IMX9_USDHC1_MIX (IMX9_USDHC1_BASE + IMX9_USDHC_MIX_OFFSET) +#define IMX9_USDHC1_FEVT (IMX9_USDHC1_BASE + IMX9_USDHC_FEVT_OFFSET) +#define IMX9_USDHC1_ADMAES (IMX9_USDHC1_BASE + IMX9_USDHC_ADMAES_OFFSET) +#define IMX9_USDHC1_ADSADDR (IMX9_USDHC1_BASE + IMX9_USDHC_ADSADDR_OFFSET) +#define IMX9_USDHC1_DLL_CONTROL (IMX9_USDHC1_BASE + IMX9_USDHC_DLL_CONTROL_OFFSET) +#define IMX9_USDHC1_DLL_STATUS (IMX9_USDHC1_BASE + IMX9_USDHC_DLL_STATUS) +#define IMX9_USDHC1_CLK_TUNE_CTRL (IMX9_USDHC1_BASE + IMX9_USDHC_CLK_TUNE_CTRL) +#define IMX9_USDHC1_VENDOR (IMX9_USDHC1_BASE + IMX9_USDHC_VENDOR_OFFSET) +#define IMX9_USDHC1_MMCBOOT (IMX9_USDHC1_BASE + IMX9_USDHC_MMCBOOT_OFFSET) +#define IMX9_USDHC1_VENDOR2 (IMX9_USDHC1_BASE + IMX9_USDHC_VENDOR2_OFFSET) +#define IMX9_USDHC1_TC (IMX9_USDHC1_BASE + IMX9_USDHC_TC_OFFSET) +#define IMX9_USDHC1_CQVER (IMX9_USDHC1_BASE + IMX9_USDHC_CQVER_OFFSET) +#define IMX9_USDHC1_CQCAP (IMX9_USDHC1_BASE + IMX9_USDHC_CQCAP_OFFSET) +#define IMX9_USDHC1_CQCFG (IMX9_USDHC1_BASE + IMX9_USDHC_CQCFG_OFFSET) +#define IMX9_USDHC1_CQCTL (IMX9_USDHC1_BASE + IMX9_USDHC_CQCTL_OFFSET) +#define IMX9_USDHC1_CQIS (IMX9_USDHC1_BASE + IMX9_USDHC_CQIS_OFFSET) +#define IMX9_USDHC1_CQISTE (IMX9_USDHC1_BASE + IMX9_USDHC_CQISTE_OFFSET) +#define IMX9_USDHC1_CQISGE (IMX9_USDHC1_BASE + IMX9_USDHC_CQISGE_OFFSET) +#define IMX9_USDHC1_CQIC (IMX9_USDHC1_BASE + IMX9_USDHC_CQIC_OFFSET) +#define IMX9_USDHC1_CQTDLBA (IMX9_USDHC1_BASE + IMX9_USDHC_CQTDLBA_OFFSET) +#define IMX9_USDHC1_CQTDLBAU (IMX9_USDHC1_BASE + IMX9_USDHC_CQTDLBAU_OFFSET) +#define IMX9_USDHC1_CQTDBR (IMX9_USDHC1_BASE + IMX9_USDHC_CQTDBR_OFFSET) +#define IMX9_USDHC1_CQTCN (IMX9_USDHC1_BASE + IMX9_USDHC_CQTCN_OFFSET) +#define IMX9_USDHC1_CQDQS (IMX9_USDHC1_BASE + IMX9_USDHC_CQDQS_OFFSET) +#define IMX9_USDHC1_CQDPT (IMX9_USDHC1_BASE + IMX9_USDHC_CQDPT_OFFSET) +#define IMX9_USDHC1_CQTCL (IMX9_USDHC1_BASE + IMX9_USDHC_CQTCLR_OFFSET) +#define IMX9_USDHC1_CQSSC1 (IMX9_USDHC1_BASE + IMX9_USDHC_CQSSC1_OFFSET) +#define IMX9_USDHC1_CQSSC2 (IMX9_USDHC1_BASE + IMX9_USDHC_CQSSC2_OFFSET) +#define IMX9_USDHC1_CQCRDCT (IMX9_USDHC1_BASE + IMX9_USDHC_CQCRDCT_OFFSET) +#define IMX9_USDHC1_CQRMEM (IMX9_USDHC1_BASE + IMX9_USDHC_CQRMEM_OFFSET) +#define IMX9_USDHC1_CQTERRI (IMX9_USDHC1_BASE + IMX9_USDHC_CQTERRI_OFFSET) +#define IMX9_USDHC1_CQCRI (IMX9_USDHC1_BASE + IMX9_USDHC_CQCRI_OFFSET) +#define IMX9_USDHC1_CQCRA (IMX9_USDHC1_BASE + IMX9_USDHC_CQCRA_OFFSET) + +/* For USDHC2 ... */ + +#define IMX9_USDHC2_DSADDR (IMX9_USDHC2_BASE + IMX9_USDHC_DSADDR_OFFSET) +#define IMX9_USDHC2_BLKATTR (IMX9_USDHC2_BASE + IMX9_USDHC_BLKATTR_OFFSET) +#define IMX9_USDHC2_CMDARG (IMX9_USDHC2_BASE + IMX9_USDHC_CMDARG_OFFSET) +#define IMX9_USDHC2_XFERTYP (IMX9_USDHC2_BASE + IMX9_USDHC_XFERTYP_OFFSET) +#define IMX9_USDHC2_CMDRSP0 (IMX9_USDHC2_BASE + IMX9_USDHC_CMDRSP0_OFFSET) +#define IMX9_USDHC2_CMDRSP1 (IMX9_USDHC2_BASE + IMX9_USDHC_CMDRSP1_OFFSET) +#define IMX9_USDHC2_CMDRSP2 (IMX9_USDHC2_BASE + IMX9_USDHC_CMDRSP2_OFFSET) +#define IMX9_USDHC2_CMDRSP3 (IMX9_USDHC2_BASE + IMX9_USDHC_CMDRSP3_OFFSET) +#define IMX9_USDHC2_DATAPORT (IMX9_USDHC2_BASE + IMX9_USDHC_DATPORT_OFFSET) +#define IMX9_USDHC2_PRSSTAT (IMX9_USDHC2_BASE + IMX9_USDHC_PRSSTAT_OFFSET) +#define IMX9_USDHC2_PROCTL (IMX9_USDHC2_BASE + IMX9_USDHC_PROCTL_OFFSET) +#define IMX9_USDHC2_SYSCTL (IMX9_USDHC2_BASE + IMX9_USDHC_SYSCTL_OFFSET) +#define IMX9_USDHC2_IRQSTAT (IMX9_USDHC2_BASE + IMX9_USDHC_IRQSTAT_OFFSET) +#define IMX9_USDHC2_IRQSTATEN (IMX9_USDHC2_BASE + IMX9_USDHC_IRQSTATEN_OFFSET) +#define IMX9_USDHC2_IRQSIGEN (IMX9_USDHC2_BASE + IMX9_USDHC_IRQSIGEN_OFFSET) +#define IMX9_USDHC2_AC12ERR (IMX9_USDHC2_BASE + IMX9_USDHC_AC12ERR_OFFSET) +#define IMX9_USDHC2_HTCAPBLT (IMX9_USDHC2_BASE + IMX9_USDHC_HTCAPBLT_OFFSET) +#define IMX9_USDHC2_WML (IMX9_USDHC2_BASE + IMX9_USDHC_WML_OFFSET) +#define IMX9_USDHC2_MIX (IMX9_USDHC2_BASE + IMX9_USDHC_MIX_OFFSET) +#define IMX9_USDHC2_FEVT (IMX9_USDHC2_BASE + IMX9_USDHC_FEVT_OFFSET) +#define IMX9_USDHC2_ADMAES (IMX9_USDHC2_BASE + IMX9_USDHC_ADMAES_OFFSET) +#define IMX9_USDHC2_ADSADDR (IMX9_USDHC2_BASE + IMX9_USDHC_ADSADDR_OFFSET) +#define IMX9_USDHC2_DLL_CONTROL (IMX9_USDHC2_BASE + IMX9_USDHC_DLL_CONTROL_OFFSET) +#define IMX9_USDHC2_DLL_STATUS (IMX9_USDHC2_BASE + IMX9_USDHC_DLL_STATUS) +#define IMX9_USDHC2_CLK_TUNE_CTRL (IMX9_USDHC2_BASE + IMX9_USDHC_CLK_TUNE_CTRL) +#define IMX9_USDHC2_VENDOR (IMX9_USDHC2_BASE + IMX9_USDHC_VENDOR_OFFSET) +#define IMX9_USDHC2_MMCBOOT (IMX9_USDHC2_BASE + IMX9_USDHC_MMCBOOT_OFFSET) +#define IMX9_USDHC2_VENDOR2 (IMX9_USDHC2_BASE + IMX9_USDHC_VENDOR2_OFFSET) +#define IMX9_USDHC2_TC (IMX9_USDHC2_BASE + IMX9_USDHC_TC_OFFSET) +#define IMX9_USDHC2_CQVER (IMX9_USDHC2_BASE + IMX9_USDHC_CQVER_OFFSET) +#define IMX9_USDHC2_CQCAP (IMX9_USDHC2_BASE + IMX9_USDHC_CQCAP_OFFSET) +#define IMX9_USDHC2_CQCFG (IMX9_USDHC2_BASE + IMX9_USDHC_CQCFG_OFFSET) +#define IMX9_USDHC2_CQCTL (IMX9_USDHC2_BASE + IMX9_USDHC_CQCTL_OFFSET) +#define IMX9_USDHC2_CQIS (IMX9_USDHC2_BASE + IMX9_USDHC_CQIS_OFFSET) +#define IMX9_USDHC2_CQISTE (IMX9_USDHC2_BASE + IMX9_USDHC_CQISTE_OFFSET) +#define IMX9_USDHC2_CQISGE (IMX9_USDHC2_BASE + IMX9_USDHC_CQISGE_OFFSET) +#define IMX9_USDHC2_CQIC (IMX9_USDHC2_BASE + IMX9_USDHC_CQIC_OFFSET) +#define IMX9_USDHC2_CQTDLBA (IMX9_USDHC2_BASE + IMX9_USDHC_CQTDLBA_OFFSET) +#define IMX9_USDHC2_CQTDLBAU (IMX9_USDHC2_BASE + IMX9_USDHC_CQTDLBAU_OFFSET) +#define IMX9_USDHC2_CQTDBR (IMX9_USDHC2_BASE + IMX9_USDHC_CQTDBR_OFFSET) +#define IMX9_USDHC2_CQTCN (IMX9_USDHC2_BASE + IMX9_USDHC_CQTCN_OFFSET) +#define IMX9_USDHC2_CQDQS (IMX9_USDHC2_BASE + IMX9_USDHC_CQDQS_OFFSET) +#define IMX9_USDHC2_CQDPT (IMX9_USDHC2_BASE + IMX9_USDHC_CQDPT_OFFSET) +#define IMX9_USDHC2_CQTCL (IMX9_USDHC2_BASE + IMX9_USDHC_CQTCLR_OFFSET) +#define IMX9_USDHC2_CQSSC1 (IMX9_USDHC2_BASE + IMX9_USDHC_CQSSC1_OFFSET) +#define IMX9_USDHC2_CQSSC2 (IMX9_USDHC2_BASE + IMX9_USDHC_CQSSC2_OFFSET) +#define IMX9_USDHC2_CQCRDCT (IMX9_USDHC2_BASE + IMX9_USDHC_CQCRDCT_OFFSET) +#define IMX9_USDHC2_CQRMEM (IMX9_USDHC2_BASE + IMX9_USDHC_CQRMEM_OFFSET) +#define IMX9_USDHC2_CQTERRI (IMX9_USDHC2_BASE + IMX9_USDHC_CQTERRI_OFFSET) +#define IMX9_USDHC2_CQCRI (IMX9_USDHC2_BASE + IMX9_USDHC_CQCRI_OFFSET) +#define IMX9_USDHC2_CQCRA (IMX9_USDHC2_BASE + IMX9_USDHC_CQCRA_OFFSET) + +/* Register Bit Definitions *************************************************/ + +/* DMA System Address Register */ + +#define USDHC_DSADDR_SHIFT (0) /* Bits 2-31: DMA System Address */ +#define USDHC_DSADDR_MASK (0xfffffffc) /* Bits 0-1: 32 bit aligned, low bits Reserved */ + +/* Block Attributes Register */ + +#define USDHC_BLKATTR_SIZE_SHIFT (0) /* Bits 0-12: Transfer Block Size */ +#define USDHC_BLKATTR_SIZE_MASK (0x1fff << USDHC_BLKATTR_SIZE_SHIFT) +# define USDHC_BLKATTR_SIZE(n) ((n) << USDHC_BLKATTR_SIZE_SHIFT) + /* Bits 13-15: Reserved */ +#define USDHC_BLKATTR_CNT_SHIFT (16) /* Bits 16-31: Blocks Count For Current Transfer */ +#define USDHC_BLKATTR_CNT_MASK (0xffff << USDHC_BLKATTR_CNT_SHIFT) +# define USDHC_BLKATTR_CNT(n) ((n) << USDHC_BLKATTR_CNT_SHIFT) + +/* Command Argument Register (32-bit cmd/arg data) */ + +/* Transfer Type Register */ + +#define USDHC_XFERTYP_DMAEN (1 << 0) /* Bit 0: Enable DMA functionality */ +#define USDHC_XFERTYP_BCEN (1 << 1) /* Bit 1: Enable the Block Count register */ +#define USDHC_XFERTYP_AC12EN (1 << 2) /* Bit 2: Enable automatic CMD12 */ +#define USDHC_XFERTYP_DDREN (1 << 3) /* Bit 3: Dual data rate mode selection */ +#define USDHC_XFERTYP_DTDSEL (1 << 4) /* Bit 4: The direction of DATA line data transfers */ +#define USDHC_XFERTYP_MSBSEL (1 << 5) /* Bit 5: Enable multiple block DATA line data transfers */ +#define USDHC_XFERTYP_NIBBLE_POS (1 << 6) /* Bit 6: The nibble position */ +#define USDHC_XFERTYP_AC23EN (1 << 7) /* Bit 7: Enable automatic CMD23 */ + /* Bits 8-15: Reserved */ +#define USDHC_XFERTYP_RSPTYP_SHIFT (16) /* Bits 16-17: Response Type Select */ +#define USDHC_XFERTYP_RSPTYP_MASK (3 << USDHC_XFERTYP_RSPTYP_SHIFT) +# define USDHC_XFERTYP_RSPTYP_NONE (0 << USDHC_XFERTYP_RSPTYP_SHIFT) /* No response */ +# define USDHC_XFERTYP_RSPTYP_LEN136 (1 << USDHC_XFERTYP_RSPTYP_SHIFT) /* Response length 136 */ +# define USDHC_XFERTYP_RSPTYP_LEN48 (2 << USDHC_XFERTYP_RSPTYP_SHIFT) /* Response length 48 */ +# define USDHC_XFERTYP_RSPTYP_LEN48BSY (3 << USDHC_XFERTYP_RSPTYP_SHIFT) /* Response length 48, check busy */ + + /* Bit 18: Reserved */ +#define USDHC_XFERTYP_CCCEN (1 << 19) /* Bit 19: Command CRC Check Enable */ +#define USDHC_XFERTYP_CICEN (1 << 20) /* Bit 20: Command Index Check Enable */ +#define USDHC_XFERTYP_DPSEL (1 << 21) /* Bit 21: Data Present Select */ +#define USDHC_XFERTYP_CMDTYP_SHIFT (22) /* Bits 22-23: Command Type */ +#define USDHC_XFERTYP_CMDTYP_MASK (3 << USDHC_XFERTYP_CMDTYP_SHIFT) +# define USDHC_XFERTYP_CMDTYP_NORMAL (0 << USDHC_XFERTYP_CMDTYP_SHIFT) /* Normal other commands */ +# define USDHC_XFERTYP_CMDTYP_SUSPEND (1 << USDHC_XFERTYP_CMDTYP_SHIFT) /* Suspend CMD52 for writing bus suspend in CCCR */ +# define USDHC_XFERTYP_CMDTYP_RESUME (2 << USDHC_XFERTYP_CMDTYP_SHIFT) /* Resume CMD52 for writing function select in CCCR */ +# define USDHC_XFERTYP_CMDTYP_ABORT (3 << USDHC_XFERTYP_CMDTYP_SHIFT) /* Abort CMD12, CMD52 for writing I/O abort in CCCR */ + +#define USDHC_XFERTYP_CMDINX_SHIFT (24) /* Bits 24-29: Command Index */ +#define USDHC_XFERTYP_CMDINX_MASK (0x3f << USDHC_XFERTYP_CMDINX_SHIFT) + /* Bits 30-31: Reserved */ + +/* Command Response 0-3 (32-bit response data) */ + +/* Buffer Data Port Register (32-bit data content) */ + +/* Present State Register */ + +#define USDHC_PRSSTAT_CIHB (1 << 0) /* Bit 0: Command Inhibit (CMD) */ +#define USDHC_PRSSTAT_CDIHB (1 << 1) /* Bit 1: Command Inhibit (DAT) */ +#define USDHC_PRSSTAT_DLA (1 << 2) /* Bit 2: Data Line Active */ +#define USDHC_PRSSTAT_SDSTB (1 << 3) /* Bit 3: SD Clock Stable */ + /* Bits 4-7: Reserved */ +#define USDHC_PRSSTAT_WTA (1 << 8) /* Bit 8: Write Transfer Active */ +#define USDHC_PRSSTAT_RTA (1 << 9) /* Bit 9: Read Transfer Active */ +#define USDHC_PRSSTAT_BWEN (1 << 10) /* Bit 10: Buffer Write Enable */ +#define USDHC_PRSSTAT_BREN (1 << 11) /* Bit 11: Buffer Read Enable */ +#define USDHC_PRSSTAT_RTR (1 << 12) /* Bit 12: Retuning request */ + /* Bits 13-14: Reserved */ +#define USDHC_PRSSTAT_TSCD (1 << 15) /* Bit 15: Tape Select Change Done */ +#define USDHC_PRSSTAT_CINS (1 << 16) /* Bit 16: Card Inserted */ + /* Bit 17: Reserved */ +#define USDHC_PRSSTAT_CDPL (1 << 18) /* Bit 18: Card Detect Pin Level */ +#define USDHC_PRSSTAT_WPSPL (1 << 19) /* Bit 19: Write Protect Switch Pin Level */ + /* Bits 20-22: Reserved */ +#define USDHC_PRSSTAT_CLSL (1 << 23) /* Bit 23: CMD Line Signal Level */ +#define USDHC_PRSSTAT_DLSL_SHIFT (24) /* Bits 24-31: DAT Line Signal Level */ +#define USDHC_PRSSTAT_DLSL_MASK (0xff << USDHC_PRSSTAT_DLSL_SHIFT) +# define USDHC_PRSSTAT_DLSL_DAT0 (0x01 << USDHC_PRSSTAT_DLSL_SHIFT) +# define USDHC_PRSSTAT_DLSL_DAT1 (0x02 << USDHC_PRSSTAT_DLSL_SHIFT) +# define USDHC_PRSSTAT_DLSL_DAT2 (0x04 << USDHC_PRSSTAT_DLSL_SHIFT) +# define USDHC_PRSSTAT_DLSL_DAT3 (0x08 << USDHC_PRSSTAT_DLSL_SHIFT) +# define USDHC_PRSSTAT_DLSL_DAT4 (0x10 << USDHC_PRSSTAT_DLSL_SHIFT) +# define USDHC_PRSSTAT_DLSL_DAT5 (0x20 << USDHC_PRSSTAT_DLSL_SHIFT) +# define USDHC_PRSSTAT_DLSL_DAT6 (0x40 << USDHC_PRSSTAT_DLSL_SHIFT) +# define USDHC_PRSSTAT_DLSL_DAT7 (0x80 << USDHC_PRSSTAT_DLSL_SHIFT) + +/* Protocol Control Register */ + + /* Bit 0: Reserved */ +#define USDHC_PROCTL_DTW_SHIFT (1) /* Bits 1-2: Data Transfer Width */ +#define USDHC_PROCTL_DTW_MASK (3 << USDHC_PROCTL_DTW_SHIFT) +# define USDHC_PROCTL_DTW_1BIT (0 << USDHC_PROCTL_DTW_SHIFT) /* 1-bit mode */ +# define USDHC_PROCTL_DTW_4BIT (1 << USDHC_PROCTL_DTW_SHIFT) /* 4-bit mode */ +# define USDHC_PROCTL_DTW_8BIT (2 << USDHC_PROCTL_DTW_SHIFT) /* 8-bit mode */ + +#define USDHC_PROCTL_D3CD (1 << 3) /* Bit 3: DAT3 as Card Detection Pin */ +#define USDHC_PROCTL_EMODE_SHIFT (4) /* Bits 4-5: Endian mode */ +#define USDHC_PROCTL_EMODE_MASK (3 << USDHC_PROCTL_EMODE_SHIFT) +# define USDHC_PROCTL_EMODE_BE (0 << USDHC_PROCTL_EMODE_SHIFT)/* Big endian mode */ +# define USDHC_PROCTL_EMODE_HWBE (1 << USDHC_PROCTL_EMODE_SHIFT)/* Half word big endian mode */ +# define USDHC_PROCTL_EMODE_LE (2 << USDHC_PROCTL_EMODE_SHIFT)/* Little endian mode */ + /* Bits 6-7: Reserved */ +#define USDHC_PROCTL_DMAS_SHIFT (8) /* Bits 8-9: DMA Select */ +#define USDHC_PROCTL_DMAS_MASK (3 << USDHC_PROCTL_DMAS_SHIFT) +# define USDHC_PROCTL_DMAS_NODMA (0 << USDHC_PROCTL_DMAS_SHIFT) /* No DMA or simple DMA is selected */ +# define USDHC_PROCTL_DMAS_ADMA1 (1 << USDHC_PROCTL_DMAS_SHIFT) /* ADMA1 is selected */ +# define USDHC_PROCTL_DMAS_ADMA2 (2 << USDHC_PROCTL_DMAS_SHIFT) /* ADMA2 is selected */ + + /* Bits 10-25: Reserved */ +#define USDHC_PROCTL_SABGREQ (1 << 16) /* Bit 16: Stop At Block Gap Request */ +#define USDHC_PROCTL_CREQ (1 << 17) /* Bit 17: Continue Request */ +#define USDHC_PROCTL_RWCTL (1 << 18) /* Bit 18: Read Wait Control */ +#define USDHC_PROCTL_IABG (1 << 19) /* Bit 19: Interrupt At Block Gap */ +#define USDHC_PROCTL_RDDONENO8CLK (1 << 20) /* Bit 20: Read done to 8 clock */ +#define USDHC_PROCTL_RESV2023 (4 << 21) /* Bits 21-23: Reserved, write as 0x100 */ +#define USDHC_PROCTL_WECINT (1 << 24) /* Bit 24: Wakeup Event Enable On Card Interrupt */ +#define USDHC_PROCTL_WECINS (1 << 25) /* Bit 25: Wakeup Event Enable On SD Card Insertion */ +#define USDHC_PROCTL_WECRM (1 << 26) /* Bit 26: Wakeup Event Enable On SD Card Removal */ + /* Bits 27-29: Reserved */ +#define USDHC_PROTCTL_NEBLKRD (1 << 30) /* Bit 30: Non-exect block read */ + /* Bit 31: Reserved */ + +/* System Control Register */ + +#define USDHC_SYSCTL_RES0 (0x0F << 0) /* Bit 0-3: Reserved, set to 1 */ +#define USDHC_SYSCTL_DVS_SHIFT (4) /* Bits 4-7: Divisor */ +#define USDHC_SYSCTL_DVS_MASK (0x0f << USDHC_SYSCTL_DVS_SHIFT) +# define USDHC_SYSCTL_DVS_DIV(n) (((n) - 1) << USDHC_SYSCTL_DVS_SHIFT) /* Divide by n, n=1,2,15,16 */ + +#define USDHC_SYSCTL_SDCLKFS_SHIFT (8) /* Bits 8-15: SDCLK Frequency Select */ +#define USDHC_SYSCTL_SDCLKFS_MASK (0xff << USDHC_SYSCTL_SDCLKFS_SHIFT) +# define USDHC_SYSCTL_SDCLKFS_BYPASS (0x00 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Bypass the prescaler */ +# define USDHC_SYSCTL_SDCLKFS_DIV2 (0x01 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 2 */ +# define USDHC_SYSCTL_SDCLKFS_DIV4 (0x02 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 4 */ +# define USDHC_SYSCTL_SDCLKFS_DIV8 (0x04 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 8 */ +# define USDHC_SYSCTL_SDCLKFS_DIV16 (0x08 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 16 */ +# define USDHC_SYSCTL_SDCLKFS_DIV32 (0x10 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 32 */ +# define USDHC_SYSCTL_SDCLKFS_DIV64 (0x20 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 64 */ +# define USDHC_SYSCTL_SDCLKFS_DIV128 (0x40 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 128 */ +# define USDHC_SYSCTL_SDCLKFS_DIV256 (0x80 << USDHC_SYSCTL_SDCLKFS_SHIFT) /* Base clock / 256 */ + +#define USDHC_SYSCTL_DTOCV_SHIFT (16) /* Bits 16-19: Data Timeout Counter Value */ +#define USDHC_SYSCTL_DTOCV_MASK (0xf << USDHC_SYSCTL_DTOCV_SHIFT) +# define USDHC_SYSCTL_DTOCV_PWR32 (0x0 << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x 2^32 */ +# define USDHC_SYSCTL_DTOCV_PWR33 (0x1 << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x 2^33 */ +# define USDHC_SYSCTL_DTOCV_PWR18 (0x2 << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x 2^18 */ +# define USDHC_SYSCTL_DTOCV_PWR19 (0x3 << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x 2^19 */ +# define USDHC_SYSCTL_DTOCV_PWR29 (0xd << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x 2^29 */ +# define USDHC_SYSCTL_DTOCV_PWR30 (0xe << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x 2^30 */ +# define USDHC_SYSCTL_DTOCV_PWR31 (0xf << USDHC_SYSCTL_DTOCV_SHIFT) /* SDCLK x 2^31 */ + + /* Bits 20-21: Reserved */ +#define USDHC_SYSCTL_RSTF (1 << 22) /* Bit 24: Reset the async FIFO */ +#define USDHC_SYSCTL_IPPRSTN (1 << 23) /* Bit 23: Card /reset (default 1) */ +#define USDHC_SYSCTL_RSTA (1 << 24) /* Bit 24: Software Reset For ALL */ +#define USDHC_SYSCTL_RSTC (1 << 25) /* Bit 25: Software Reset For CMD Line */ +#define USDHC_SYSCTL_RSTD (1 << 26) /* Bit 26: Software Reset For DAT Line */ +#define USDHC_SYSCTL_INITA (1 << 27) /* Bit 27: Initialization Active */ +#define USDHC_SYSCTL_RSTT (1 << 28) /* Bit 28: Reset tuning */ + /* Bits 29-31: Reserved */ + +/* Interrupt Status Register, Interrupt Status Enable Register and + * Interrupt Signal Enable Register + * Common interrupt bit definitions + */ + +#define USDHC_INT_CC (1 << 0) /* Bit 0: Command Complete */ +#define USDHC_INT_TC (1 << 1) /* Bit 1: Transfer Complete */ +#define USDHC_INT_BGE (1 << 2) /* Bit 2: Block Gap Event */ +#define USDHC_INT_DINT (1 << 3) /* Bit 3: DMA Interrupt */ +#define USDHC_INT_BWR (1 << 4) /* Bit 4: Buffer Write Ready */ +#define USDHC_INT_BRR (1 << 5) /* Bit 5: Buffer Read Ready */ +#define USDHC_INT_CINS (1 << 6) /* Bit 6: Card Insertion */ +#define USDHC_INT_CRM (1 << 7) /* Bit 7: Card Removal */ +#define USDHC_INT_CINT (1 << 8) /* Bit 8: Card Interrupt */ + /* Bits 9-11: Reserved */ +#define USDHC_INT_RTR (1 << 12) /* Bit 12: Re-tuning event */ +#define USDHC_INT_TP (1 << 13) /* Bit 13: Tuning pass */ +#define USDHC_INT_CQI (1 << 14) /* Bit 14: Command queuing interrupt */ +#define USDHC_INT_STATUS (1 << 15) /* Bit 15: Error Interrupt Status / Reserved */ +#define USDHC_INT_CTOE (1 << 16) /* Bit 16: Command Timeout Error */ +#define USDHC_INT_CCE (1 << 17) /* Bit 17: Command CRC Error */ +#define USDHC_INT_CEBE (1 << 18) /* Bit 18: Command End Bit Error */ +#define USDHC_INT_CIE (1 << 19) /* Bit 19: Command Index Error */ +#define USDHC_INT_DTOE (1 << 20) /* Bit 20: Data Timeout Error */ +#define USDHC_INT_DCE (1 << 21) /* Bit 21: Data CRC Error */ +#define USDHC_INT_DEBE (1 << 22) /* Bit 22: Data End Bit Error */ + /* Bit 23: Reserved */ +#define USDHC_INT_AC12E (1 << 24) /* Bit 24: Auto CMD12 Error */ + /* Bit 25: Reserved */ +#define USDHC_INT_TNE (1 << 26) /* Bit 26: Tuning error */ + /* Bit 27: Reserved */ +#define USDHC_INT_DMAE (1 << 28) /* Bit 28: DMA Error */ + /* Bits 29-31: Reserved */ +#define USDHC_INT_ALL 0x117f01ff + +/* Auto CMD12 Error Status Register */ + +#define USDHC_AC12ERR_NE (1 << 0) /* Bit 0: Auto CMD12 Not Executed */ +#define USDHC_AC12ERR_TOE (1 << 1) /* Bit 1: Auto CMD12/23 Timeout Error */ +#define USDHC_AC12ERR_CE (1 << 2) /* Bit 2: Auto CMD12/23 CRC Error */ +#define USDHC_AC12ERR_EBE (1 << 3) /* Bit 3: Auto CMD12/23 End Bit Error */ +#define USDHC_AC12ERR_IE (1 << 4) /* Bit 4: Auto CMD12/23 Index Error */ + /* Bits 5-6: Reserved */ +#define USDHC_AC12ERR_CNI (1 << 7) /* Bit 7: Command Not Issued By Auto CMD12 Error */ + /* Bits 8-21: Reserved */ +#define USDHC_AC12ERR_EXECUTE_TUNING (1 << 22) /* Bit 22: Execute Tuning */ +#define USDHC_AC12ERR_SMP_CLK_SEL (1 << 23) /* Bit 23: Sample clock sel */ + /* Bits 24-31: Reserved */ + +/* Host Controller Capabilities */ + +#define USDHC_HTCAPBLT_SDR50 (1 << 0) /* Bit 0: SDR50 support indication */ +#define USDHC_HTCAPBLT_SDR104 (1 << 1) /* Bit 1: SDR104 support indication */ +#define USDHC_HTCAPBLT_DDR50 (1 << 2) /* Bit 2: DDR50 support indication */ + /* Bits 3-7: Reserved */ + /* Bits 8-12: Reserved */ +#define USDHC_HTCAPBLT_USE_TUNING_SDR50 (1 << 13) /* Bit 13: Use tuning for SDR50 */ +#define USDHC_HTCAPBLT_MBL_SHIFT (16) /* Bits 16-18: Max Block Length */ +#define USDHC_HTCAPBLT_MBL_MASK (7 << USDHC_HTCAPBLT_MBL_SHIFT) +# define USDHC_HTCAPBLT_MBL_512BYTES (0 << USDHC_HTCAPBLT_MBL_SHIFT) +# define USDHC_HTCAPBLT_MBL_1KB (1 << USDHC_HTCAPBLT_MBL_SHIFT) +# define USDHC_HTCAPBLT_MBL_2KB (2 << USDHC_HTCAPBLT_MBL_SHIFT) +# define USDHC_HTCAPBLT_MBL_4KB (3 << USDHC_HTCAPBLT_MBL_SHIFT) + /* Bit 19: Reserved */ +#define USDHC_HTCAPBLT_ADMAS (1 << 20) /* Bit 20: ADMA Support */ +#define USDHC_HTCAPBLT_HSS (1 << 21) /* Bit 21: High Speed Support */ +#define USDHC_HTCAPBLT_DMAS (1 << 22) /* Bit 22: DMA Support */ +#define USDHC_HTCAPBLT_SRS (1 << 23) /* Bit 23: Suspend/Resume Support */ +#define USDHC_HTCAPBLT_VS33 (1 << 24) /* Bit 24: Voltage Support 3.3 V */ +#define USDHC_HTCAPBLT_VS30 (1 << 25) /* Bit 25: Voltage Support 3.0 V */ + /* Bits 26-31: Reserved */ + +/* Watermark Level Register */ + +#define USDHC_WML_RD_SHIFT (0) /* Bits 0-7: Read Watermark Level */ +#define USDHC_WML_RD_MASK (0xff << USDHC_WML_RDWML_SHIFT) +# define USDHC_WML_RD(n) ((n) << SDHC_WML_RDWML_SHIFT) + /* Bits 8-15: Reserved */ +#define USDHC_WML_WR_SHIFT (16) /* Bits 16-23: Write Watermark Level */ +#define USDHC_WML_WR_MASK (0xff << USDHC_WML_WRWML_SHIFT) +# define USDHC_WML_WR(n) ((n) << SDHC_WML_WRWML_SHIFT) + /* Bits 24-31: Reserved */ + +/* Mixer Control Register */ + +#define USDHC_MC_DEFAULTVAL (0x80000000) /* Bit 31 is always set */ +#define USDHC_MC_DMAEN (1 << 0) /* Bit 0: DMA Enable */ +#define USDHC_MC_BCEN (1 << 1) /* Bit 1: Block Count Enable */ +#define USDHC_MC_AC12EN (1 << 2) /* Bit 2: Auto CMD12 Enable */ +#define USDHC_MC_DDR_EN (1 << 3) /* Bit 3: DDR mode enable */ +#define USDHC_MC_DTDSEL (1 << 4) /* Bit 4: Data Transfer direction select */ +#define USDHC_MC_MSBSEL (1 << 5) /* Bit 5: Multi/single block select */ +#define USDHC_MC_NIBBLE_POS (1 << 6) /* Bit 6: Nibble position for DDR 4 bit */ +#define USDHC_MC_AC23EN (1 << 7) /* Bit 7: Auto CMD23 Enable */ + /* Bits 8-21: Reserved */ +#define USDHC_MC_EXE_TUNE (1 << 22) /* Bit 22: Execute Tuning */ +#define USDHC_MC_SMP_CLK_SEL (1 << 23) /* Bit 23: SMP Clock Sel */ +#define USDHC_MC_AUTO_TUNE_EN (1 << 24) /* Bit 24: Auto tune enable */ +#define USDHC_MC_FBCLK_SEL (1 << 25) /* Bit 25: Feedback clock source selection */ +#define USDHC_MC_HS400EN (1 << 26) /* Bit 26: Enable HS400 mode */ +#define USDHC_MC_EHS400EN (1 << 27) /* Bit 27: Enable enhance HS400 mode */ + /* Bits 28-31: reserved */ + +/* Force Event Register */ + +#define USDHC_FEVT_AC12NE (1 << 0) /* Bit 0: Force Event Auto Command 12 Not Executed */ +#define USDHC_FEVT_AC12TOE (1 << 1) /* Bit 1: Force Event Auto Command 12 Time Out Error */ +#define USDHC_FEVT_AC12CE (1 << 2) /* Bit 2: Force Event Auto Command 12 CRC Error */ +#define USDHC_FEVT_AC12EBE (1 << 3) /* Bit 3: Force Event Auto Command 12 End Bit Error */ +#define USDHC_FEVT_AC12IE (1 << 4) /* Bit 4: Force Event Auto Command 12 Index Error */ + /* Bits 5-6: Reserved */ +#define USDHC_FEVT_CNIBAC12E (1 << 7) /* Bit 7: Force Event Command Not Executed By Auto Command 12 Error */ + /* Bits 8-15: Reserved */ +#define USDHC_FEVT_CTOE (1 << 16) /* Bit 16: Force Event Command Time Out Error */ +#define USDHC_FEVT_CCE (1 << 17) /* Bit 17: Force Event Command CRC Error */ +#define USDHC_FEVT_CEBE (1 << 18) /* Bit 18: Force Event Command End Bit Error */ +#define USDHC_FEVT_CIE (1 << 19) /* Bit 19: Force Event Command Index Error */ +#define USDHC_FEVT_DTOE (1 << 20) /* Bit 20: Force Event Data Time Out Error */ +#define USDHC_FEVT_DCE (1 << 21) /* Bit 21: Force Event Data CRC Error */ +#define USDHC_FEVT_DEBE (1 << 22) /* Bit 22: Force Event Data End Bit Error */ + /* Bit 23: Reserved */ +#define USDHC_FEVT_AC12E (1 << 24) /* Bit 24: Force Event Auto Command 12 Error */ + /* Bit 25: Reserved */ +#define USDHC_FEVT_TTNE (1 << 26) /* Bit 26: Force tuning error */ + /* Bit 27: reserved */ +#define USDHC_FEVT_DMAE (1 << 28) /* Bit 28: Force Event DMA Error */ + /* Bits 29-30: Reserved */ +#define USDHC_FEVT_CINT (1 << 31) /* Bit 31: Force Event Card Interrupt */ + +/* ADMA Error Status Register */ + +#define USDHC_ADMAES_SHIFT (0) /* Bits 0-1: ADMA Error State (when ADMA Error is occurred) */ +#define USDHC_ADMAES_MASK (3 << USDHC_ADMAES_ADMAES_SHIFT) +# define USDHC_ADMAES_STOP (0 << USDHC_ADMAES_ADMAES_SHIFT) /* Stop DMA */ +# define USDHC_ADMAES_FDS (1 << USDHC_ADMAES_ADMAES_SHIFT) /* Fetch descriptor */ +# define USDHC_ADMAES_CADR (2 << USDHC_ADMAES_ADMAES_SHIFT) /* Change address */ +# define USDHC_ADMAES_TFR (3 << USDHC_ADMAES_ADMAES_SHIFT) /* Transfer data */ + +#define USDHC_ADMAES_LME (1 << 2) /* Bit 2: ADMA Length Mismatch Error */ +#define USDHC_ADMAES_DCE (1 << 3) /* Bit 3: ADMA Descriptor Error */ + /* Bits 4-31: Reserved */ + +/* ADMA System Address Register */ + +#define USDHC_ADSADDR_SHIFT (0) /* Bits 1-31: ADMA System Address */ +#define USDHC_ADSADDR_MASK (0xfffffffc) /* Bits 0-1: Reserved */ + +/* Delay Line Control */ + +#define USDHC_DL_CTRL_EN (1 << 0) /* Bit 0: Delay Line enable */ +#define USDHC_DL_CTRL_RST (1 << 1) /* Bit 1: Delay line reset */ +#define USDHC_DL_CTRL_SLV_FORCE_UP (1 << 2) /* Bit 2: SLV Force update */ +#define USDHC_DL_SLV_DLY_TGT0_SHIFT (3) /* Bits 3-6: Delay Target 0 */ +#define USDHC_DL_SLV_DLY_TGT0_MASK (0xf << USDHC_DL_SLV_DLY_TGT0_SHIFT) +# define USDHC_DL_SLV_DLY_TGT0(n) ((n) << USDHC_DL_SLV_DLY_TGT0_SHIFT) +#define USDHC_DL_CTRL_SLV_UPD (1 << 7) /* Bit 7: Delay Control Gate update */ +#define USDHC_DL_CTRL_SLV_OVR (1 << 8) /* Bit 8: Delay Control Gate override */ +#define USDHC_DL_CTRL_OVR_VAL_SHIFT (9) /* Bits 9-15: Override Value */ +#define USDHC_DL_CTRL_OVR_VAL_MASK (0x7f << USDHC_DL_CTRL_OVR_VAL_SHIFT) +# define USDHC_DL_CTRL_OVR_VAL(n) ((n) << USDHC_DL_CTRL_OVR_VAL_SHIFT) +#define USDHC_DL_SLV_DLY_TGT1_SHIFT (16) /* Bits 16-18: Delay Target 1 */ +#define USDHC_DL_SLV_DLY_TGT1_MASK (0x7 << USDHC_DL_SLV_DLY_TGT1_SHIFT) +# define USDHC_DL_SLV_DLY_TGT1(n) ((n) << USDHC_DL_SLV_DLY_TGT1_SHIFT) + /* Bit 19: Reserved */ +#define USDHC_DL_CTRL_SLV_UPDINT_SHIFT (20) /* Bits 20-27: DLL Control SLV Update Interval */ +#define USDHC_DL_CTRL_SLV_UPDINT_MASK (0xff << USDHC_DL_CTRL_SLV_UPDINT_SHIFT) +# define USDHC_DL_CTRL_SLV_UPDINT(n) ((n) << USDHC_DL_CTRL_SLV_UPDINT_SHIFT) +#define USDHC_DL_CTRL_REF_UPDINT_SHIFT (28) /* Bits 28-31: DLL Control Reference Update Interval */ +#define USDHC_DL_CTRL_REF_UPDINT_MASK (0xf << USDHC_DL_CTRL_REF_UPDINT_SHIFT) +# define USDHC_DL_CTRL_REF_UPDINT(n) ((n)<< USDHC_DL_CTRL_REF_UPDINT_SHIFT) + +/* Delay Line Status */ + +#define USDHC_DL_STAT_SLV_LOCK (1 << 0) /* Bit 0: Slave delay-line lock status */ +#define USDHC_DL_STAT_REF_LOCK (1 << 1) /* Bit 1: Reference delay-line lock status */ +#define USDHC_DL_STAT_SLV_SEL_SHIFT (2) /* Bits 2-8: Slave delay line select status */ +#define USDHC_DL_STAT_SLV_SEL_MASK (0x7f << USDHC_DL_STAT_SLV_SEL_SHIFT) +# define USDHC_DL_STAT_SLV_SEL(n) ((n) << USDHC_DL_STAT_SLV_SEL_SHIFT) +#define USDHC_DL_STAT_REF_SEL_SHIFT (9) /* Bits 9-15: Reference delay line select taps */ +#define USDHC_DL_STAT_REF_SEL_MASK (0x7f << USDHC_DL_STAT_REF_SEL_SHIFT) +# define USDHC_DL_STAT_REF_SEL(n) ((n) << USDHC_DL_STAT_REF_SEL_SHIFT) + /* Bits 16-31: Reserved */ + +/* Clk tuning control and status */ + +#define USDHC_CLKTUNE_CS_DCS_POST_SHIFT (0) /* Bits 0-3: Set delay cells between CLK_OUT and CLK_POST*/ +#define USDHC_CLKTUNE_CS_DCS_POST_MASK (0xf << USDHC_CLKTUNE_CS_DCS_POST_SHIFT) +# define USDHC_CLKTUNE_CS_DCS_POST(n) ((n) << USDHC_CLKTUNE_CS_DCS_POST_SHIFT) +#define USDHC_CLKTUNE_CS_DCS_OUT_SHIFT (4) /* Bits 4-7: Set delay cells between CLK_PRE and CLK_OUT */ +#define USDHC_CLKTUNE_CS_DCS_OUT_MASK (0xf << USDHC_CLKTUNE_CS_DCS_OUT_SHIFT) +# define USDHC_CLKTUNE_CS_DCS_OUT(n) ((n) << USDHC_CLKTUNE_CS_DCS_OUT_SHIFT) +#define USDHC_CLKTUNE_CS_DCS_PRE_SHIFT (8) /* Bits 8-14: Set celay cells between the feedback clock and CLK_PRE */ +#define USDHC_CLKTUNE_CS_DCS_PRE_MASK (0x7f << USDHC_CLKTUNE_CS_DCS_PRE_SHIFT) +# define USDHC_CLKTUNE_CS_DCS_PRE(n) ((n) << USDHC_CLKTUNE_CS_DCS_PRE_SHIFT) +#define USDHC_CLKTUNE_CS_NXT_ERR (1 << 15) /* Bit 15: NXT error */ +#define USDHC_CLKTUNE_CS_TS_POST_SHIFT (16) /* Bits 16-19: Delay cells between CLK_OUT and CLK_POST */ +#define USDHC_CLKTUNE_CS_TS_POST_MASK (0xf << USDHC_CLKTUNE_CS_TS_POST_SHIFT) +# define USDHC_CLKTUNE_CS_TS_POST(n) ((n) << USDHC_CLKTUNE_CS_TS_POST_SHIFT) +#define USDHC_CLKTUNE_CS_TS_OUT_SHIFT (20) /* Bits 20-23: Delay cells between CLK_PRE and CLK_OUT */ +#define USDHC_CLKTUNE_CS_TS_OUT_MASK (0xf << USDHC_CLKTUNE_CS_TS_OUT_SHIFT) +# define USDHC_CLKTUNE_CS_TS_OUT(n) ((n) << USDHC_CLKTUNE_CS_TS_OUT_SHIFT) +#define USDHC_CLKTUNE_CS_TS_PRE_SHIFT (24) /* Bits 24-30: Delay cells between the feedback clock and CLK_PRE */ +#define USDHC_CLKTUNE_CS_TS_PRE_MASK (0x7f << USDHC_CLKTUNE_CS_TS_PRE_SHIFT) +# define USDHC_CLKTUNE_CS_TS_PRE_OUT(n) ((n) << USDHC_CLKTUNE_CS_TS_PRE_SHIFT) +#define USDHC_CLKTUNE_CS_PRE_ERR (1 << 31) /* Bit 31: PRE error */ + +/* Strobe DLL control */ + +/* Strobe DLL status */ + +/* Vendor Specific Register */ + + /* Bit 0: Reserved */ +#define USHDC_VENDOR_VSELECT (1 << 1) /* Bit 1: Voltage selection */ + /* Bit 2: Reserved */ +#define USDHC_VENDOR_CHKBUSY_ON (1 << 3) /* Bit 3: Enable Check busy */ + /* Bit 4-7: Reserved */ +#define USDHC_VENDOR_FRC_SDCLK_ON (1 << 8) /* Bit 8: Force clock active */ + /* Bits 9-14: Reserved */ +#define USDHC_VENDOR_CRC_CHECK_OFF (1 << 15) /* Bit 15: Switch off CRC checking */ + /* Bits 16:30 Reserved */ +#define USHDC_VENDOR_DEFAULTVAL (0x20000000) /* Bit 29 is always set */ +#define USDHC_VENDOR_CMDBYTEACC_ON (1 << 31) /* Bit 31: Enable command byte access */ + +/* MMC Boot Register */ + +#define USDHC_MMCBOOT_DTOCVACK_SHIFT (0) /* Bits 0-3: Boot ACK time out counter value */ +#define USDHC_MMCBOOT_DTOCVACK_MASK (0xf << USDHC_MMCBOOT_DTOCVACK_SHIFT) +# define USDHC_MMCBOOT_DTOCVACK_PWR32 (0x0 << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^32 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR33 (0x1 << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^33 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR18 (0x2 << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^18 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR19 (0x3 << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^19 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR20 (0x4 << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^20 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR21 (0x5 << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^21 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR22 (0x6 << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^22 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR23 (0x7 << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^23 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR30 (0xe << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^30 */ +# define USDHC_MMCBOOT_DTOCVACK_PWR31 (0xf << USDHC_MMCBOOT_DTOCVACK_SHIFT) /* SDCLK x 2^31 */ + +#define USDHC_MMCBOOT_BOOTACK (1 << 4) /* Bit 4: Boot ack mode select */ +#define USDHC_MMCBOOT_BOOTMODE (1 << 5) /* Bit 5: Boot mode select */ +#define USDHC_MMCBOOT_BOOTEN (1 << 6) /* Bit 6: Boot mode enable */ +#define USDHC_MMCBOOT_AUTOSABGEN (1 << 7) /* Bit 7: Enable auto stop at block gap function */ +#define USDHC_MMCBOOT_DISABLETO (1 << 8) /* Bit 8: Timeout enable */ + /* Bits 9-15: Reserved */ +#define USDHC_MMCBOOT_BOOTBLKCNT_SHIFT (16) /* Bits 16-31: Stop at block gap value of automatic mode */ +#define USDHC_MMCBOOT_BOOTBLKCNT_MASK (0xffff << USDHC_MMCBOOT_BOOTBLKCNT_SHIFT) +#define USDHC_MMCBOOT_BOOTBLKCNT(n) ((n) << USDHC_MMCBOOT_BOOTBLKCNT_SHIFT) + +/* Vendor specific register 2 */ + + /* Bits 0-2: Reserved */ +#define USDHC_VS2_CARDINTD3 (1 << 3) /* Bit 3: Card interrupt detection test */ +#define USDHC_VS2_TUNINGBITEN_SHIFT (4) /* Bits 4-5: Tuning bit enable */ +#define USDHC_VS2_TUNINGBITEN_MASK (0x3 << USDHC_VS2_TUNINGBITEN_SHIFT) +# define USDHC_VS2_TUNINGBITEN_30 (0 << USDHC_VS2_TUNINGBITEN_SHIFT) /* Enable Tuning circuit for DATA[3:0] */ +# define USDHC_VS2_TUNINGBITEN_70 (1 << USDHC_VS2_TUNINGBITEN_SHIFT) /* Enable Tuning circuit for DATA[7:0] */ +# define USDHC_VS2_TUNINGBITEN_0 (2 << USDHC_VS2_TUNINGBITEN_SHIFT) /* Enable Tuning circuit for DATA[0] */ + +#define USDHC_VS2_TUNINGCMDEN (1 << 6) /* Bit 6: Tuning CMD enable */ + /* Bits 7-9: Reserved */ +#define USDHC_VS2_HS400WRCLKSEN (1 << 10) /* Bit 10: HS400 write clock stop enable */ +#define USDHC_VS2_HS400RDCLKSEN (1 << 11) /* Bit 11: HS400 read clock stop enable */ +#define USDHC_VS2_ACMD23ARGU2 (1 << 12) /* Bit 12: Argument 2 register enable for ACMD23 */ + /* Bit 13: Reserved */ +#define USDHC_VS2_BUSRESET (1 << 14) /* Bit 14: Bus reset (undocumented!) */ +#define USDHC_VS2_32KCLKEN (1 << 15) /* Bit 15: Use low power clock for card detection */ +#define USDHC_VS2_FBCLK_TAP_SEL_SHIFT (16) /* Bits 16-31: Enable extra delay on internal feedback clock */ +#define USDHC_VS2_FBCLK_TAP_SEL_MASK (0xffff << USDHC_VS2_FBCLK_TAP_SEL_SHIFT) +#define USDHC_VS2_FBCLK_TAP_SEL(n) ((n) << USDHC_VS2_FBCLK_TAP_SEL_SHIFT) + +/* Tuning Control Register */ + +#define USDHC_TC_STARTTAP_SHIFT (0) /* Bits 0-6: Start TAP for CMD19 tuning */ +#define USDHC_TC_STARTTAP_MASK (0x7f << USDHC_TC_STARTTAP_SHIFT) +# define USDHC_TC_STARTTAP(n) ((n) << USDHC_TC_STARTTAP_SHIFT) +#define USDHC_TC_DIS_CMD (1 << 7) /* Bit 7: Disable command check for standard tuning */ +#define USDHC_TC_COUNT_SHIFT (8) /* Bits 8-15: Count for CMD19 tuning */ +#define USDHC_TC_COUNT_MASK (0xff << USDHC_TC_COUNT_SHIFT) +# define USDHC_TC_COUNT(n) ((n) << USDHC_TC_COUNT_SHIFT) + /* Bit 19: Reserved */ +#define USDHC_TC_WINDOW_SHIFT (20) /* Bits 20-22: Tuning window */ +#define USDHC_TC_WINDOW_MASK (0x7 << USDHC_TC_WINDOWS_SHIFT) +# define USDHC_TC_WINDOW(n) ((n) << USDHC_TC_WINDOW_SHIFT) + /* Bit 23: Reserved */ +#define USDHC_TC_TUNINGEN (1 << 24) /* Bit 24: Tuning enable */ + /* Bits 25-31: Reserved */ + +/* Command Queuing Version */ + +/* Command Queuing Capabilities */ + +/* Command Queuing Configuration */ + +/* Command Queuing Control */ + +/* Command Queuing Interrupt Status */ + +/* Command Queuing Interrupt Status Enable */ + +/* Command Queuing Interrupt Signal Enable */ + +/* Command Queuing Interrupt Coalescing */ + +/* Command Queuing Task Descriptor List Base Address */ + +/* Command Queuing Task Descriptor List Base Address Upper 32 Bits */ + +/* Command Queuing Task Doorbell */ + +/* Command Queuing Task Completion Notification */ + +/* Command Queuing Device Queue Status */ + +/* Command Queuing Device Pending Tasks */ + +/* Command Queuing Task Clear */ + +/* Command Queuing Send Status Configuration 1 */ + +/* Command Queuing Send Status Configuration 2 */ + +/* Command Queuing Command Response for Direct-Command Task */ + +/* Command Queuing Response Mode Error Mask */ + +/* Command Queuing Task Error Information */ + +/* Command Queuing Command Response Index */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_USDHC_H */ diff --git a/arch/arm64/src/imx9/imx9_boot.c b/arch/arm64/src/imx9/imx9_boot.c new file mode 100644 index 0000000000000..a35947fedfc8b --- /dev/null +++ b/arch/arm64/src/imx9/imx9_boot.c @@ -0,0 +1,141 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_boot.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#ifdef CONFIG_PAGING +# include +#endif + +#include +#include "arm64_arch.h" +#include "arm64_internal.h" +#include "arm64_mmu.h" + +#include "imx9_boot.h" +#include "imx9_clockconfig.h" +#include "imx9_serial.h" +#include "imx9_gpio.h" +#include "imx9_lowputc.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct arm_mmu_region g_mmu_regions[] = +{ + MMU_REGION_FLAT_ENTRY("DEVICE_REGION", + CONFIG_DEVICEIO_BASEADDR, CONFIG_DEVICEIO_SIZE, + MT_DEVICE_NGNRNE | MT_RW | MT_SECURE), + + MMU_REGION_FLAT_ENTRY("DRAM0_S0", + CONFIG_RAMBANK1_ADDR, CONFIG_RAMBANK1_SIZE, + MT_NORMAL | MT_RW | MT_SECURE), +}; + +const struct arm_mmu_config g_mmu_config = +{ + .num_regions = nitems(g_mmu_regions), + .mmu_regions = g_mmu_regions, +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm64_el_init + * + * Description: + * The function called from arm64_head.S at very early stage for these + * platform, it's use to: + * - Handling special hardware initialize routine which is need to + * run at high ELs + * - Initialize system software such as hypervisor or security firmware + * which is need to run at high ELs + * + ****************************************************************************/ + +void arm64_el_init(void) +{ +#if (CONFIG_ARCH_ARM64_EXCEPTION_LEVEL == 3) + /* At EL3, cntfrq_el0 is uninitialized. It must be set. */ + + write_sysreg(CONFIG_BOOTLOADER_SYS_CLOCK, cntfrq_el0); +#endif +} + +/**************************************************************************** + * Name: arm64_chip_boot + * + * Description: + * Complete boot operations started in arm64_head.S + * + ****************************************************************************/ + +void arm64_chip_boot(void) +{ + /* MAP IO and DRAM, enable MMU. */ + + arm64_mmu_init(true); + + /* Initialize system clocks to some sensible state */ + + imx9_clockconfig(); + + /* Do UART early initialization & pin muxing */ + +#ifdef CONFIG_IMX9_LPUART + imx9_lowsetup(); +#endif + +#if defined(CONFIG_SMP) || defined(CONFIG_ARCH_HAVE_PSCI) + arm64_psci_init("smc"); +#endif + + /* Initialize pin interrupt support */ + +#ifdef CONFIG_IMX9_GPIO_IRQ + imx9_gpioirq_initialize(); +#endif + + /* Perform board-specific device initialization. This would include + * configuration of board specific resources such as GPIOs, LEDs, etc. + */ + + imx9_board_initialize(); + +#ifdef USE_EARLYSERIALINIT + /* Perform early serial initialization if we are going to use the serial + * driver. + */ + + arm64_earlyserialinit(); +#endif +} diff --git a/arch/arm64/src/imx9/imx9_boot.h b/arch/arm64/src/imx9/imx9_boot.h new file mode 100644 index 0000000000000..cfd10b7e1b2b1 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_boot.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_boot.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_BOOT_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_BOOT_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: imx9_board_initialize + * + * Description: + * All i.MX9 architectures must provide the following entry point. This + * entry point is called in the initialization phase -- after + * imx_memory_initialize and after all memory has been configured and + * mapped but before any devices have been initialized. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imx9_board_initialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_BOOT_H */ diff --git a/arch/arm64/src/imx9/imx9_ccm.c b/arch/arm64/src/imx9/imx9_ccm.c new file mode 100644 index 0000000000000..1d8cef9562462 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_ccm.c @@ -0,0 +1,197 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_ccm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include "barriers.h" + +#include "arm64_internal.h" +#include "imx9_ccm.h" + +#include "hardware/imx9_ccm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define mb() \ + do \ + { \ + ARM64_DSB(); \ + ARM64_ISB(); \ + } \ + while (0) + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_ccm_configure_root_clock + * + * Description: + * Change root clock source and divider. Leaves the clock running state + * unaltered. + * + * Input Parameters: + * root - The root clock index. + * src - The root clock MUX source. + * div - The root clock divider. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int imx9_ccm_configure_root_clock(int root, int src, uint32_t div) +{ + uint32_t value; + int i; + + if (root >= CCM_CR_COUNT || div == 0 || div > 255) + { + return -EINVAL; + } + + /* Find the corresponding MUX register value for root and source */ + + for (i = 0; i < ROOT_MUX_MAX; i++) + { + if (g_ccm_root_mux[root][i] == src) + { + break; + } + } + + if (i == ROOT_MUX_MAX) + { + return -EINVAL; + } + + /* Set the new value */ + + value = CCM_CR_CTRL_MUX_SRCSEL(i) | CCM_CR_CTRL_DIV(div); + putreg32(value, IMX9_CCM_CR_CTRL(root)); + mb(); + + /* Wait for the clock state change */ + + while (getreg32(IMX9_CCM_CR_STAT0(root)) & CCM_CR_STAT0_CHANGING); + + return OK; +} + +/**************************************************************************** + * Name: imx9_ccm_root_clock_on + * + * Description: + * Enable / disable root clock. + * + * Input Parameters: + * root - The root clock index. + * enabled - True enables the clock; false disables it. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int imx9_ccm_root_clock_on(int root, bool enabled) +{ + if (root >= CCM_CR_COUNT) + { + return -EINVAL; + } + + if (enabled) + { + putreg32(CCM_CR_CTRL_OFF, IMX9_CCM_CR_CTRL_CLR(root)); + } + else + { + putreg32(CCM_CR_CTRL_OFF, IMX9_CCM_CR_CTRL_SET(root)); + } + + mb(); + + /* Wait for the clock state change */ + + while (getreg32(IMX9_CCM_CR_STAT0(root)) & CCM_CR_STAT0_CHANGING); + + return OK; +} + +/**************************************************************************** + * Name: imx9_ccm_gate_on + * + * Description: + * Enable / disable clock. + * + * Input Parameters: + * gate - The clock gate index. + * enabled - True enables the clock; false disables it. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int imx9_ccm_gate_on(int gate, bool enabled) +{ + uint32_t value; + + if (gate >= CCM_LPCG_COUNT) + { + return -EINVAL; + } + + /* Make sure direct mode is on, which is what we support */ + + value = getreg32(IMX9_CCM_LPCG_AUTH(gate)); + if (value & CCM_LPCG_AUTH_CPULPM) + { + value &= ~CCM_LPCG_AUTH_CPULPM; + putreg32(value, IMX9_CCM_LPCG_AUTH(gate)); + mb(); + } + + value = enabled ? 1 : 0; + putreg32(value, IMX9_CCM_LPCG_DIR(gate)); + mb(); + + /* Wait for the clock state change */ + + while ((getreg32(IMX9_CCM_LPCG_STAT0(gate)) & CCM_LPCG_STAT0_ON) != value); + + return OK; +} diff --git a/arch/arm64/src/imx9/imx9_ccm.h b/arch/arm64/src/imx9/imx9_ccm.h new file mode 100644 index 0000000000000..fa2017b314a54 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_ccm.h @@ -0,0 +1,88 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_ccm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_CCM_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_CCM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Name: imx9_ccm_configure_root_clock + * + * Description: + * Change root clock source and divider. Leaves the clock running state + * unaltered. + * + * Input Parameters: + * root - The root clock index. + * src - The root clock MUX source. + * div - The root clock divider. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int imx9_ccm_configure_root_clock(int root, int src, uint32_t div); + +/**************************************************************************** + * Name: imx9_ccm_root_clock_on + * + * Description: + * Enable / disable root clock. + * + * Input Parameters: + * root - The root clock index. + * enabled - True enables the clock; false disables it. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int imx9_ccm_root_clock_on(int root, bool enabled); + +/**************************************************************************** + * Name: imx9_ccm_gate_on + * + * Description: + * Enable / disable clock. + * + * Input Parameters: + * gate - The clock gate index. + * enabled - True enables the clock; false disables it. + * + * Returned Value: + * Zero (OK) is returned on success. A negated errno value is returned on + * failure. + * + ****************************************************************************/ + +int imx9_ccm_gate_on(int gate, bool enabled); + +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_CCM_H */ diff --git a/arch/arm64/src/imx9/imx9_clockconfig.c b/arch/arm64/src/imx9/imx9_clockconfig.c new file mode 100644 index 0000000000000..156e1f5a2a966 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_clockconfig.c @@ -0,0 +1,526 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_clockconfig.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include + +#include + +#include "barriers.h" + +#include "arm64_internal.h" +#include "imx9_ccm.h" +#include "imx9_clockconfig.h" + +#include "hardware/imx9_ccm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The base oscillator frequency is 24MHz */ + +#define XTAL_FREQ 24000000u + +/* Common barrier */ + +#define mb() \ + do \ + { \ + ARM64_DSB(); \ + ARM64_ISB(); \ + } \ + while (0) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_IMX9_BOOTLOADER +static int pll_init(uintptr_t reg, bool frac, struct pll_parms_s *parm) +{ + uint32_t val; + + /* Bypass and disable PLL */ + + putreg32(PLL_CTRL_CLKMUX_BYPASS, PLL_SET(PLL_CTRL(reg))); + putreg32(PLL_CTRL_CLKMUX_EN | PLL_CTRL_POWERUP, PLL_CLR(PLL_CTRL(reg))); + + /* Set the integer dividers */ + + val = PLL_DIV_RDIV(parm->rdiv) | + PLL_DIV_MFI(parm->mfi) | + PLL_DIV_ODIV(parm->odiv); + + putreg32(val, PLL_DIV(reg)); + + /* Disable spread spectrum */ + + putreg32(PLL_SPREAD_SPECTRUM_ENABLE, PLL_CLR(PLL_SPREAD_SPECTRUM(reg))); + + /* Set the fractional parts */ + + if (frac) + { + putreg32(PLL_NUMERATOR_MFN(parm->mfn), PLL_NUMERATOR(reg)); + putreg32(PLL_DENOMINATOR_MFD(parm->mfd), PLL_DENOMINATOR(reg)); + } + + /* Power it back up and wait for lock */ + + putreg32(PLL_CTRL_POWERUP, PLL_SET(PLL_CTRL(reg))); + mb(); + + while (!(getreg32(PLL_PLL_STATUS(reg)) & PLL_PLL_STATUS_PLL_LOCK)); + + /* Enable PLL and its output */ + + putreg32(PLL_CTRL_CLKMUX_EN, PLL_SET(PLL_CTRL(reg))); + putreg32(PLL_CTRL_CLKMUX_BYPASS, PLL_CLR(PLL_CTRL(reg))); + mb(); + + return OK; +} + +static int pll_pfd_init(uintptr_t reg, int pfd, struct pfd_parms_s *pfdparm) +{ + uint32_t ctrl; + uint32_t div; + uint32_t val; + + /* Determine the PFD register set */ + + switch (pfd) + { + case 0: + ctrl = PLL_DFS_CTRL_0(reg); + div = PLL_DFS_DIV_0(reg); + break; + + case 1: + ctrl = PLL_DFS_CTRL_1(reg); + div = PLL_DFS_DIV_1(reg); + break; + + case 2: + ctrl = PLL_DFS_CTRL_2(reg); + div = PLL_DFS_DIV_2(reg); + break; + + default: + return -EINVAL; + } + + /* Bypass and disable DFS */ + + putreg32(PLL_DFS_BYPASS_EN, PLL_SET(ctrl)); + putreg32(PLL_DFS_CLKOUT_EN | PLL_DFS_CLKOUT_DIVBY2_EN | PLL_DFS_ENABLE, + PLL_CLR(ctrl)); + + /* Set the divider */ + + val = PLL_DFS_MFI(pfdparm->mfi) | PLL_DFS_MFN(pfdparm->mfn); + putreg32(val, PLL_VAL(div)); + + /* Enable (or disable) the divby2 output */ + + if (pfdparm->divby2_en) + { + putreg32(PLL_DFS_CLKOUT_DIVBY2_EN, PLL_SET(ctrl)); + } + else + { + putreg32(PLL_DFS_CLKOUT_DIVBY2_EN, PLL_CLR(ctrl)); + } + + /* Enable DFS and wait for lock */ + + putreg32(PLL_DFS_ENABLE, PLL_SET(ctrl)); + mb(); + + /* Wait until the clock output is valid */ + + while (!(getreg32(PLL_DFS_STATUS(reg)) & (1 << pfd))); + + /* Then disable bypass */ + + putreg32(PLL_DFS_BYPASS_EN, PLL_CLR(ctrl)); + mb(); + + return OK; +} +#endif + +static uint32_t calculate_vco_freq(const struct pll_parms_s *parm, bool frac) +{ + /* Base clock is common for all VCO:s */ + + if (frac) + { + return (uint64_t)XTAL_FREQ * (parm->mfi * parm->mfd + parm->mfn) / + parm->mfd / parm->rdiv; + } + else + { + return (uint64_t)XTAL_FREQ * parm->mfi / parm->rdiv; + } +} + +static uint32_t vco_freq_out(uintptr_t reg, bool frac) +{ + struct pll_parms_s parm; + uint32_t ctrl; + uint32_t status; + uint32_t div; + + /* Check if the PLL on or off */ + + ctrl = getreg32(PLL_CTRL(reg)); + if ((ctrl & PLL_CTRL_POWERUP) == 0) + { + return 0; + } + + /* Check if the PLL is stable */ + + status = getreg32(PLL_PLL_STATUS(reg)); + if ((status & PLL_PLL_STATUS_PLL_LOCK) == 0) + { + return 0; + } + + /* Populate the integer and fractional PLL parameters */ + + div = getreg32(PLL_DIV(reg)); + parm.rdiv = (div & PLL_DIV_RDIV_MASK) >> PLL_DIV_RDIV_SHIFT; + parm.mfi = (div & PLL_DIV_MFI_MASK) >> PLL_DIV_MFI_SHIFT; + + /* RDIV values 0 and 1 both mean a divisor of 1 */ + + if (parm.rdiv == 0) + { + parm.rdiv = 1; + } + + if (frac) + { + /* Fill the fractional parameters */ + + parm.mfn = getreg32(PLL_NUMERATOR(reg)) & PLL_NUMERATOR_MFN_MASK; + parm.mfn >>= PLL_NUMERATOR_MFN_SHIFT; + parm.mfd = getreg32(PLL_DENOMINATOR(reg)) & PLL_DENOMINATOR_MFD_MASK; + parm.mfd >>= PLL_DENOMINATOR_MFD_SHIFT; + } + + return calculate_vco_freq(&parm, frac); +} + +static uint32_t pll_freq_out(uintptr_t reg, bool frac) +{ + uint32_t ctrl; + uint32_t div; + uint32_t vco; + + /* Read the MUX control register and check if bypass mode is enabled */ + + ctrl = getreg32(PLL_CTRL(reg)); + if (ctrl & PLL_CTRL_CLKMUX_BYPASS) + { + return XTAL_FREQ; + } + + /* If the mux is disabled output frequency is 0 */ + + if ((ctrl & PLL_CTRL_CLKMUX_EN) == 0) + { + return 0; + } + + /* Get input VCO frequency */ + + vco = vco_freq_out(reg, frac); + if (vco == 0) + { + /* The VCO is off or unstable */ + + return 0; + } + + /* Calculate the output clock divider */ + + div = (getreg32(PLL_DIV(reg)) & PLL_DIV_ODIV_MASK) >> PLL_DIV_ODIV_SHIFT; + + /* According to spec, div0 = 2 and div1 = 3 */ + + if (div == 0) + { + div = 2; + } + else if (div == 1) + { + div = 3; + } + + return vco / div; +} + +static uint32_t pll_pfd_freq_out(uintptr_t reg, int pfd, int div2) +{ + struct pfd_parms_s parm; + uint32_t ctrl; + uint32_t div; + uint32_t vco; + + /* Read the correct PFD register set */ + + switch (pfd) + { + case 0: + ctrl = getreg32(PLL_DFS_CTRL_0(reg)); + div = getreg32(PLL_DFS_DIV_0(reg)); + break; + + case 1: + ctrl = getreg32(PLL_DFS_CTRL_1(reg)); + div = getreg32(PLL_DFS_DIV_1(reg)); + break; + + case 2: + ctrl = getreg32(PLL_DFS_CTRL_2(reg)); + div = getreg32(PLL_DFS_DIV_2(reg)); + break; + + default: + return 0; + } + + /* Get input VCO frequency */ + + vco = vco_freq_out(reg, true); + if (vco == 0) + { + /* The VCO is off or unstable */ + + return 0; + } + + /* If the DFS part is bypassed, the output is the VCO directly */ + + if (ctrl & PLL_DFS_BYPASS_EN) + { + return vco; + } + + /* Check if the DFS part is disabled */ + + if ((ctrl & PLL_DFS_ENABLE) == 0) + { + return 0; + } + + /* Populate the DFS parameters */ + + parm.mfi = (div & PLL_DFS_MFI_MASK) >> PLL_DFS_MFI_SHIFT; + parm.mfn = (div & PLL_DFS_MFN_MASK) >> PLL_DFS_MFN_SHIFT; + + return ((uint64_t)vco * 5) / (parm.mfi * 5 + parm.mfn) / div2; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_clockconfig + * + * Description: + * Called to initialize the i.IMX9. This does whatever setup is needed to + * put the SoC in a usable state. This includes the initialization of + * clocking using the settings in board.h. + * + ****************************************************************************/ + +void imx9_clockconfig(void) +{ +#ifdef CONFIG_IMX9_BOOTLOADER + struct imx9_pll_cfg_s pll_cfgs[] = PLL_CFGS; + struct imx9_pfd_cfg_s pfd_cfgs[] = PFD_CFGS; + struct imx9_pll_cfg_s pll_arm = ARMPLL_CFG; + int i; + + /* Set the CPU clock */ + + putreg32(CCM_GPR_A55_CLK_SEL_PLL, IMX9_CCM_GPR_SH_CLR(CCM_SHARED_A55_CLK)); + pll_init(pll_arm.reg, pll_arm.frac, &pll_arm.parms); + putreg32(CCM_GPR_A55_CLK_SEL_PLL, IMX9_CCM_GPR_SH_SET(CCM_SHARED_A55_CLK)); + + /* Run the PLL configuration */ + + for (i = 0; i < nitems(pll_cfgs); i++) + { + struct imx9_pll_cfg_s *cfg = &pll_cfgs[i]; + pll_init(cfg->reg, cfg->frac, &cfg->parms); + } + + /* Run the PFD configuration */ + + for (i = 0; i < nitems(pfd_cfgs); i++) + { + struct imx9_pfd_cfg_s *cfg = &pfd_cfgs[i]; + pll_pfd_init(cfg->reg, cfg->pfd, &cfg->parms); + } +#endif +} + +/**************************************************************************** + * Name: imx9_get_clock + * + * Description: + * This function returns the clock frequency of the specified functional + * clock. + * + * Input Parameters: + * clkname - Identifies the clock of interest + * frequency - The location where the peripheral clock frequency will be + * returned + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. -ENODEV is returned if the clock is not enabled or is not + * being clocked. + * + ****************************************************************************/ + +int imx9_get_clock(int clkname, uint32_t *frequency) +{ + switch (clkname) + { + case OSC_24M: + *frequency = XTAL_FREQ; + break; + + case ARM_PLL: + *frequency = pll_freq_out(IMX9_ARMPLL_BASE, false); + break; + + case SYS_PLL1_IN: + *frequency = pll_freq_out(IMX9_SYSPLL_BASE, false); + break; + + case SYS_PLL1PFD0: + *frequency = pll_pfd_freq_out(IMX9_SYSPLL_BASE, 0, 1); + break; + + case SYS_PLL1PFD0DIV2: + *frequency = pll_pfd_freq_out(IMX9_SYSPLL_BASE, 0, 2); + break; + + case SYS_PLL1PFD1: + *frequency = pll_pfd_freq_out(IMX9_SYSPLL_BASE, 1, 1); + break; + + case SYS_PLL1PFD1DIV2: + *frequency = pll_pfd_freq_out(IMX9_SYSPLL_BASE, 1, 2); + break; + + case SYS_PLL1PFD2: + *frequency = pll_pfd_freq_out(IMX9_SYSPLL_BASE, 2, 1); + break; + + case SYS_PLL1PFD2DIV2: + *frequency = pll_pfd_freq_out(IMX9_SYSPLL_BASE, 2, 2); + break; + + case AUDIO_PLL1OUT: + *frequency = pll_freq_out(IMX9_AUDIOPLL_BASE, true); + break; + + case DRAM_PLLOUT: + *frequency = pll_freq_out(IMX9_DRAMPLL_BASE, true); + break; + + case VIDEO_PLL1OUT: + *frequency = pll_freq_out(IMX9_VIDEOPLL_BASE, true); + break; + + default: + return -ENODEV; + } + + return OK; +} + +/**************************************************************************** + * Name: imx9_get_rootclock + * + * Description: + * This function returns the clock frequency of the specified root + * functional clock. + * + * Input Parameters: + * clkroot - Identifies the peripheral clock of interest + * frequency - The location where the peripheral clock frequency will be + * returned + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. -ENODEV is returned if the clock is not enabled or is not + * being clocked. + * + ****************************************************************************/ + +int imx9_get_rootclock(int clkroot, uint32_t *frequency) +{ + uint32_t reg; + uint32_t div; + uint32_t mux; + int clk_name; + + if (clkroot <= CCM_CR_COUNT) + { + reg = getreg32(IMX9_CCM_CR_CTRL(clkroot)); + + if ((reg & CCM_CR_CTRL_OFF) == CCM_CR_CTRL_OFF) + { + *frequency = 0; + } + else + { + mux = (reg & CCM_CR_CTRL_MUX_MASK) >> CCM_CR_CTRL_MUX_SHIFT; + clk_name = g_ccm_root_mux[clkroot][mux]; + imx9_get_clock(clk_name, frequency); + div = ((reg & CCM_CR_CTRL_DIV_MASK) >> CCM_CR_CTRL_DIV_SHIFT) + 1; + *frequency = *frequency / div; + } + + return OK; + } + + return -ENODEV; +} diff --git a/arch/arm64/src/imx9/imx9_clockconfig.h b/arch/arm64/src/imx9/imx9_clockconfig.h new file mode 100644 index 0000000000000..cf8ffc1f45441 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_clockconfig.h @@ -0,0 +1,169 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_clockconfig.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_CLOCKCONFIG_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_CLOCKCONFIG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PLL_PARMS(_rdiv, _odiv, _mfi, _mfn, _mfd) \ + { \ + .rdiv = (_rdiv), \ + .odiv = (_odiv), \ + .mfi = (_mfi), \ + .mfn = (_mfn), \ + .mfd = (_mfd), \ + } + +#define PLL_CFG(_reg, _frac, _parms) \ + { \ + .reg = (_reg), \ + .frac = (_frac), \ + .parms = _parms, \ + } + +#define PFD_PARMS(_mfi, _mfn, _div2) \ + { \ + .mfi = (_mfi), \ + .mfn = (_mfn), \ + .divby2_en = (_div2) \ + } + +#define PFD_CFG(_reg, _pfd, _parms) \ + { \ + .reg = (_reg), \ + .pfd = (_pfd), \ + .parms = _parms, \ + } + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct pll_parms_s +{ + /* Integer part (DIV) */ + + struct + { + uint32_t rdiv; /* Input clock divider */ + uint32_t odiv; /* PLL output divider */ + uint32_t mfi; /* PLL integer divider */ + }; + + /* Fractional part (NUMERATOR / DENOMINATOR) */ + + struct + { + uint32_t mfn; /* PLL fractional divider numerator */ + uint32_t mfd; /* PLL fractional divider denominator */ + }; +}; + +struct pfd_parms_s +{ + uint32_t mfi; /* PLL integer divider */ + uint32_t mfn; /* PLL fractional divider numerator */ + bool divby2_en; /* Enable the divide-by-2 output */ +}; + +struct imx9_pll_cfg_s +{ + uintptr_t reg; /* The PLL register base */ + bool frac; /* Fractional PLL ? */ + struct pll_parms_s parms; /* The PLL parameters */ +}; + +struct imx9_pfd_cfg_s +{ + uintptr_t reg; /* The PLL register base */ + int pfd; /* The PFD number */ + struct pfd_parms_s parms; /* The PFD parameters */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_clockconfig + * + * Description: + * Called to initialize the i.IMX9. This does whatever setup is needed to + * put the SoC in a usable state. This includes the initialization of + * clocking using the settings in board.h. + * + ****************************************************************************/ + +void imx9_clockconfig(void); + +/**************************************************************************** + * Name: imx9_get_clock + * + * Description: + * This function returns the clock frequency of the specified functional + * clock. + * + * Input Parameters: + * clkname - Identifies the clock of interest + * frequency - The location where the peripheral clock frequency will be + * returned + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. -ENODEV is returned if the clock is not enabled or is not + * being clocked. + * + ****************************************************************************/ + +int imx9_get_clock(int clkname, uint32_t *frequency); + +/**************************************************************************** + * Name: imx9_get_rootclock + * + * Description: + * This function returns the clock frequency of the specified root + * functional clock. + * + * Input Parameters: + * clkroot - Identifies the peripheral clock of interest + * frequency - The location where the peripheral clock frequency will be + * returned + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. -ENODEV is returned if the clock is not enabled or is not + * being clocked. + * + ****************************************************************************/ + +int imx9_get_rootclock(int clkroot, uint32_t *frequency); + +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_CLOCKCONFIG_H */ diff --git a/arch/arm64/src/imx9/imx9_dma_alloc.c b/arch/arm64/src/imx9/imx9_dma_alloc.c new file mode 100644 index 0000000000000..172e2276dbe00 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_dma_alloc.c @@ -0,0 +1,157 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_dma_alloc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include + +#if defined(CONFIG_IMX9_DMA_ALLOC) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* DMA buffers must be aligned with the D-Cache line boundaries to facilitate + * cache operations on the DMA buffers when the D-Cache is enabled. + */ + +#define DMA_ALIGN ARMV8A_DCACHE_LINESIZE +#define DMA_ALIGN_MASK (DMA_ALIGN - 1) +#define DMA_ALIGN_UP(n) (((n) + DMA_ALIGN_MASK) & ~DMA_ALIGN_MASK) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static GRAN_HANDLE dma_allocator; + +/* The DMA heap size constrains the total number of things that can be + * ready to do DMA at a time. + * + * For example, FAT DMA depends on one sector-sized buffer per filesystem + * plus one sector-sized buffer per file. + * + * We use a fundamental alignment / granule size of 64B; it fulfills the + * requirement for any DMA engine. + */ + +static uint8_t g_dma_heap[CONFIG_IMX9_DMA_ALLOC_POOL_SIZE] +aligned_data(DMA_ALIGN) locate_data(CONFIG_IMX9_DMA_ALLOC_SECT); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_dma_alloc_init + * + * Description: + * Initialize the DMA memory allocator. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int imx9_dma_alloc_init(void) +{ + /* Allocate 64B granules with 64B alignment */ + + /* REVISIT: Use 256B granule size to get 8K maximum allocation. This is a + * limitation in the granule allocator itself. + */ + + dma_allocator = gran_initialize(g_dma_heap, sizeof(g_dma_heap), 8, 6); + + if (dma_allocator == NULL) + { + return -ENOMEM; + } + + return OK; +} + +/**************************************************************************** + * Name: imx9_dma_alloc + * + * Description: + * Allocate a contiguous block of physical memory for DMA. + * + * Input Parameters: + * size - Size of the requested block in bytes. + * + * Returned Value: + * Physical address of the first page on success; NULL on failure. + * + ****************************************************************************/ + +void *imx9_dma_alloc(size_t size) +{ + return gran_alloc(dma_allocator, size); +} + +/**************************************************************************** + * Name: imx9_dma_free + * + * Description: + * Free a previously allocated DMA memory block. + * + * Input Parameters: + * memory - Physical address of the first page of DMA memory. + * size - Size of the allocated block in bytes. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void imx9_dma_free(void *memory, size_t size) +{ + gran_free(dma_allocator, memory, size); +} + +#ifdef CONFIG_FAT_DMAMEMORY +FAR void *fat_dma_alloc(size_t size) +{ + return imx9_dma_alloc(size); +} + +void fat_dma_free(FAR void *memory, size_t size) +{ + imx9_dma_free(memory, size); +} +#endif + +#endif /* CONFIG_IMX9_DMA_ALLOC */ diff --git a/arch/arm64/src/imx9/imx9_dma_alloc.h b/arch/arm64/src/imx9/imx9_dma_alloc.h new file mode 100644 index 0000000000000..d0c78ec451eb0 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_dma_alloc.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_dma_alloc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_DMA_ALLOC_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_DMA_ALLOC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_dma_alloc_init + * + * Description: + * Initialize the DMA memory allocator. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +int imx9_dma_alloc_init(void); + +/**************************************************************************** + * Name: imx9_dma_alloc + * + * Description: + * Allocate a contiguous block of physical memory for DMA. + * + * Input Parameters: + * size - Size of the requested block in bytes. + * + * Returned Value: + * Physical address of the first page on success; NULL on failure. + * + ****************************************************************************/ + +void *imx9_dma_alloc(size_t size); + +/**************************************************************************** + * Name: imx9_dma_free + * + * Description: + * Free a previously allocated DMA memory block. + * + * Input Parameters: + * memory - Physical address of the first page of DMA memory. + * size - Size of the allocated block in bytes. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void imx9_dma_free(void *memory, size_t size); + +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_DMA_ALLOC_H */ diff --git a/arch/arm64/src/imx9/imx9_edma.c b/arch/arm64/src/imx9/imx9_edma.c new file mode 100644 index 0000000000000..67a2cd3ef362f --- /dev/null +++ b/arch/arm64/src/imx9/imx9_edma.c @@ -0,0 +1,1509 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_edma.c + * + * Copyright (C) 2019, 2021, 2023 Gregory Nutt. All rights reserved. + * Copyright 2022 NXP + * Authors: Gregory Nutt + * David Sidrane + * Peter van der Perk + * + * This file was leveraged from the NuttX S32K3 port. Portions of that eDMA + * logic derived from NXP sample code which has a compatible BSD 3-clause + * license: + * + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "arm64_internal.h" +#include "sched/sched.h" + +#include "chip.h" +#include "imx9_edma.h" +#include "imx9_ccm.h" + +#include "hardware/imx9_ccm.h" +#include "hardware/imx9_edma.h" +#include "hardware/imx9_dmamux.h" + +#ifdef CONFIG_IMX9_EDMA + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* TCD Alignment. + * + * eDMA TCDs must be aligned with the D-Cache line boundaries to facilitate + * cache operations on the TCDs when the D-Cache is enabled. + * + * NOTE: The TCDs are 32-bytes in length. We implicitly assume that the + * D-Cache line size is also 32-bits. Otherwise, padding would be required + * at the ends of the TCDS and buffers to protect data after the end of from + * invalidation. + */ + +#define EDMA_ALIGN ARMV8A_DCACHE_LINESIZE +#define EDMA_ALIGN_MASK (EDMA_ALIGN - 1) +#define EDMA_ALIGN_UP(n) (((n) + EDMA_ALIGN_MASK) & ~EDMA_ALIGN_MASK) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* State of a DMA channel */ + +enum imx9_dmastate_e +{ + IMX9_DMA_IDLE = 0, /* No DMA in progress */ + IMX9_DMA_CONFIGURED, /* DMA configured, but not yet started */ + IMX9_DMA_ACTIVE /* DMA has been started and is in progress */ +}; + +/* This structure describes one DMA channel */ + +struct imx9_dmach_s +{ + uintptr_t base; /* DMA engine base address */ + uint32_t flags; /* DMA channel flags */ + bool inuse; /* true: The DMA channel is in use */ + uint8_t dmamux; /* DMAMUX channel number */ + uint8_t chan; /* DMA channel number (either eDMA3 or eDMA4) */ + uint8_t state; /* Channel state. See enum imx9_dmastate_e */ + edma_callback_t callback; /* Callback invoked when the DMA completes */ + void *arg; /* Argument passed to callback function */ +#if CONFIG_IMX9_EDMA_NTCD > 0 + /* That TCD list is linked through the DLAST SGA field. The first transfer + * to be performed is at the head of the list. Subsequent TCDs are added + * at the tail of the list. + */ + + struct imx9_edmatcd_s *head; /* First TCD in the list */ + struct imx9_edmatcd_s *tail; /* Last TCD in the list */ +#endif +}; + +/* This structure describes the state of the eDMA controller */ + +struct imx9_edma_s +{ + /* These mutex protect the DMA channel and descriptor tables */ + + mutex_t chlock; /* Protects channel table */ +#if CONFIG_IMX9_EDMA_NTCD > 0 + sem_t dsem; /* Supports wait for free descriptors */ +#endif + + /* This array describes each DMA channel */ + + struct imx9_dmach_s dmach[IMX9_EDMA_NCHANNELS]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The state of the eDMA */ + +static struct imx9_edma_s g_edma = +{ + .chlock = NXMUTEX_INITIALIZER, +#if CONFIG_IMX9_EDMA_NTCD > 0 + .dsem = SEM_INITIALIZER(CONFIG_IMX9_EDMA_NTCD), +#endif +}; + +#if CONFIG_IMX9_EDMA_NTCD > 0 +/* This is a singly-linked list of free TCDs */ + +static sq_queue_t g_tcd_free; + +/* This is a pool of pre-allocated TCDs */ + +static struct imx9_edmatcd_s g_tcd_pool[CONFIG_IMX9_EDMA_NTCD] + aligned_data(EDMA_ALIGN); +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_tcd_alloc + * + * Description: + * Allocate an in-memory, TCD + * + ****************************************************************************/ + +#if CONFIG_IMX9_EDMA_NTCD > 0 +static struct imx9_edmatcd_s *imx9_tcd_alloc(void) +{ + struct imx9_edmatcd_s *tcd; + irqstate_t flags; + + /* Take the 'dsem'. When we hold the the 'dsem', then we know that one + * TCD is reserved for us in the free list. + * + * NOTE: We use a critical section here because we may block waiting for + * the 'dsem'. The critical section will be suspended while we are + * waiting. + */ + + flags = enter_critical_section(); + nxsem_wait_uninterruptible(&g_edma.dsem); + + /* Now there should be a TCD in the free list reserved just for us */ + + tcd = (struct imx9_edmatcd_s *)sq_remfirst(&g_tcd_free); + DEBUGASSERT(tcd != NULL); + + leave_critical_section(flags); + return tcd; +} +#endif + +/**************************************************************************** + * Name: imx9_tcd_free + * + * Description: + * Free an in-memory, TCD + * + ****************************************************************************/ + +#if CONFIG_IMX9_EDMA_NTCD > 0 +static void imx9_tcd_free(struct imx9_edmatcd_s *tcd) +{ + irqstate_t flags; + + /* Add the the TCD to the end of the free list and post the 'dsem', + * possibly waking up another thread that might be waiting for + * a TCD. + */ + + flags = spin_lock_irqsave(NULL); + sq_addlast((sq_entry_t *)tcd, &g_tcd_free); + nxsem_post(&g_edma.dsem); + spin_unlock_irqrestore(NULL, flags); +} +#endif + +/**************************************************************************** + * Name: imx9_tcd_initialize() + * + * Description: + * Initialize the TCD free list from the pool of pre-allocated TCDs. + * + * Assumptions: + * Called early in the initialization sequence so no special protection is + * necessary. + * + ****************************************************************************/ + +#if CONFIG_IMX9_EDMA_NTCD > 0 +static inline void imx9_tcd_initialize(void) +{ + sq_entry_t *tcd; + int i; + + /* Add each pre-allocated TCD to the tail of the TCD free list */ + + sq_init(&g_tcd_free); + for (i = 0; i < CONFIG_IMX9_EDMA_NTCD; i++) + { + tcd = (sq_entry_t *)&g_tcd_pool[i]; + sq_addlast(tcd, &g_tcd_free); + } +} +#endif + +/**************************************************************************** + * Name: imx9_tcd_chanlink + * + * Description: + * This function configures either a minor link or a major link. The minor + * link means the channel link is triggered every time CITER decreases by 1 + * The major link means that the channel link is triggered when the CITER + * is exhausted. + * + * NOTE: Users should ensure that DONE flag is cleared before calling this + * interface, or the configuration is invalid. + * + * Input Parameters: + * tcd - Point to the TCD structure. + * type - Channel link type. + * chan - The linked channel number. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_EDMA_ELINK +static inline void imx9_tcd_chanlink(uint8_t flags, + struct imx9_dmach_s *linkch, + struct imx9_edmatcd_s *tcd) +{ + uint16_t regval16; + + flags &= EDMA_CONFIG_LINKTYPE_MASK; + + if (linkch == NULL || flags == EDMA_CONFIG_LINKTYPE_LINKNONE) + { + /* No link or no link channel provided */ + + /* Disable minor links */ + + /* Disable major link */ + + tcd->csr &= ~EDMA_TCD_CSR_MAJORELINK; + } + else if (flags == EDMA_CONFIG_LINKTYPE_MINORLINK) /* Minor link config */ + { + /* Enable minor link */ + + tcd->citer |= EDMA_TCD_CITER_ELINK; + tcd->biter |= EDMA_TCD_BITER_ELINK; + + /* Set linked channel */ + + regval16 = tcd->citer; + regval16 &= ~EDMA_TCD_CITER_LINKCH_MASK; + regval16 |= EDMA_TCD_CITER_LINKCH(linkch->chan); + tcd->citer = regval16; + + regval16 = tcd->biter; + regval16 &= ~EDMA_TCD_BITER_LINKCH_MASK; + regval16 |= EDMA_TCD_BITER_LINKCH(linkch->chan); + tcd->biter = regval16; + } + else /* if (flags == EDMA_CONFIG_LINKTYPE_MAJORLINK) Major link config */ + { + /* Enable major link */ + + regval16 = tcd->csr; + regval16 |= EDMA_TCD_CSR_MAJORELINK; + tcd->csr = regval16; + + /* Set major linked channel */ + + regval16 &= ~EDMA_TCD_CSR_MAJORLINKCH_MASK; + regval16 |= EDMA_TCD_CSR_MAJORLINKCH(linkch->chan); + tcd->csr = regval16; + } +} +#endif + +/**************************************************************************** + * Name: imx9_tcd_configure + * + * Description: + * Configure all TCD registers to the specified values. 'tcd' is an + * 'overlay' that may refer either to either the TCD register set or to an + * in-memory TCD structure. + * + ****************************************************************************/ + +static inline void imx9_tcd_configure(struct imx9_edmatcd_s *tcd, + const struct imx9_edma_xfrconfig_s *config) +{ + tcd->saddr = config->saddr; + tcd->soff = config->soff; + tcd->attr = EDMA_TCD_ATTR_SSIZE(config->ssize) | /* Transfer Attributes */ + EDMA_TCD_ATTR_DSIZE(config->dsize); +#ifdef CONFIG_IMX9_EDMA_MOD + tcd->attr |= EDMA_TCD_ATTR_SMOD(config->smod) | /* Transfer Attributes */ + EDMA_TCD_ATTR_DMOD(config->dmod); +#endif + tcd->nbytes = config->nbytes; + tcd->slast = config->flags & EDMA_CONFIG_LOOPSRC ? + -(config->iter * config->nbytes) : 0; + + tcd->daddr = config->daddr; + tcd->doff = config->doff; + tcd->citer = config->iter & EDMA_TCD_CITER_MASK; + tcd->biter = config->iter & EDMA_TCD_BITER_MASK; + tcd->csr = config->flags & EDMA_CONFIG_LOOP_MASK ? + 0 : EDMA_TCD_CSR_DREQ; + tcd->csr |= config->flags & EDMA_CONFIG_INTHALF ? + EDMA_TCD_CSR_INTHALF : 0; + tcd->dlastsga = config->flags & EDMA_CONFIG_LOOPDEST ? + -(config->iter * config->nbytes) : 0; + + /* And special case flags */ + +#ifdef CONFIG_IMX9_EDMA_ELINK + /* Configure major/minor link mapping */ + + imx9_tcd_chanlink(config->flags, (struct imx9_dmach_s *)config->linkch, + tcd); +#endif +} + +/**************************************************************************** + * Name: imx9_tcd_instantiate + * + * Description: + * Copy an in-memory TCD into eDMA channel TCD registers + * + ****************************************************************************/ + +#if CONFIG_IMX9_EDMA_NTCD > 0 +static void imx9_tcd_instantiate(struct imx9_dmach_s *dmach, + const struct imx9_edmatcd_s *tcd) +{ + uintptr_t base = IMX9_EDMA_TCD(dmach->base, dmach->chan); + + /* Push tcd into hardware TCD register */ + + /* Clear DONE bit first, otherwise ESG cannot be set */ + + putreg16(0, base + IMX9_EDMA_TCD_CSR_OFFSET); + + putreg32(tcd->saddr, base + IMX9_EDMA_TCD_SADDR_OFFSET); + putreg16(tcd->soff, base + IMX9_EDMA_TCD_SOFF_OFFSET); + putreg16(tcd->attr, base + IMX9_EDMA_TCD_ATTR_OFFSET); + putreg32(tcd->nbytes, base + IMX9_EDMA_TCD_NBYTES_OFFSET); + putreg32(tcd->slast, base + IMX9_EDMA_TCD_SLAST_SDA_OFFSET); + putreg32(tcd->daddr, base + IMX9_EDMA_TCD_DADDR_OFFSET); + putreg16(tcd->doff, base + IMX9_EDMA_TCD_DOFF_OFFSET); + putreg16(tcd->citer, base + IMX9_EDMA_TCD_CITER_OFFSET); + putreg32(tcd->dlastsga, base + IMX9_EDMA_TCD_DLAST_SGA_OFFSET); + + putreg16(tcd->csr, base + IMX9_EDMA_TCD_CSR_OFFSET); + + putreg16(tcd->biter, base + IMX9_EDMA_TCD_BITER_OFFSET); +} +#endif + +/**************************************************************************** + * Name: imx9_dmaterminate + * + * Description: + * Terminate the DMA transfer and disable the DMA channel + * + ****************************************************************************/ + +static void imx9_dmaterminate(struct imx9_dmach_s *dmach, int result) +{ + uintptr_t base = IMX9_EDMA_TCD(dmach->base, dmach->chan); +#if CONFIG_IMX9_EDMA_NTCD > 0 + struct imx9_edmatcd_s *tcd; + struct imx9_edmatcd_s *next; +#endif + edma_callback_t callback; + void *arg; + + /* Disable channel IRQ requests */ + + putreg32(EDMA_CH_INT, base + IMX9_EDMA_CH_INT_OFFSET); + + /* Clear CSR to disable channel. Because if the given channel started, + * transfer CSR will be not zero. Because if it is the last transfer, DREQ + * will be set. If not, ESG will be set. + */ + + putreg32(0, base + IMX9_EDMA_CH_CSR_OFFSET); + + putreg16(0, base + IMX9_EDMA_TCD_CSR_OFFSET); + + /* Cancel next TCD transfer. */ + + putreg32(0, base + IMX9_EDMA_TCD_DLAST_SGA_OFFSET); + +#if CONFIG_IMX9_EDMA_NTCD > 0 + /* Return all allocated TCDs to the free list */ + + for (tcd = dmach->head; tcd != NULL; tcd = next) + { + /* If channel looped to itself we are done + * if not continue to free tcds in chain + */ + + next = dmach->flags & EDMA_CONFIG_LOOPDEST ? + NULL : (struct imx9_edmatcd_s *)((uintptr_t)tcd->dlastsga); + + imx9_tcd_free(tcd); + } + + dmach->head = NULL; + dmach->tail = NULL; +#endif + + /* Perform the DMA complete callback */ + + callback = dmach->callback; + arg = dmach->arg; + + dmach->callback = NULL; + dmach->arg = NULL; + dmach->state = IMX9_DMA_IDLE; + + if (callback) + { + callback((DMACH_HANDLE)dmach, arg, true, result); + } +} + +/**************************************************************************** + * Name: imx9_edma_intstatus + * + * Description: + * DMA interrupt status per eDMA engine and channel. + * + ****************************************************************************/ + +static inline uint32_t imx9_edma_intstatus(uintptr_t base, uint8_t chan) +{ + /* The status register varies depending on eDMA instance and channel */ + +#ifdef IMX9_DMA3_BASE + /* eDMA3 uses the normal INT register */ + + if (base == IMX9_DMA3_BASE) + { + return getreg32(IMX9_EDMA_INT); + } +#endif + +#ifdef IMX9_DMA4_BASE + /* eDMA4 has two INT status registers, holding 32 statuses each */ + + if (chan > 31) + { + return getreg32(IMX9_EDMA_INT_HIGH); + } + + return getreg32(IMX9_EDMA_INT_LOW); +#endif +} + +/**************************************************************************** + * Name: imx9_edma_isr + * + * Description: + * DMA interrupt service routine. The vector handler calls this with the + * appropriate parameters. + * + ****************************************************************************/ + +static int imx9_edma_isr(int irq, void *context, void *arg) +{ + struct imx9_dmach_s *dmach; + uintptr_t base; + uint32_t regval32; + uint32_t errval32; + uint8_t chan; + int result; + + /* 'arg' should the DMA channel instance. */ + + dmach = (struct imx9_dmach_s *)arg; + DEBUGASSERT(dmach != NULL); + + chan = dmach->chan; + base = IMX9_EDMA_TCD(dmach->base, dmach->chan); + + /* Get the eDMA Error Status register value. */ + + errval32 = getreg32(base + IMX9_EDMA_CH_ES_OFFSET); + + if (errval32 & EDMA_CH_ES_ERR) + { + DEBUGASSERT(dmach->state == IMX9_DMA_ACTIVE); + + /* Clear the error */ + + putreg32(EDMA_CH_ES_ERR, base + IMX9_EDMA_CH_ES_OFFSET); + + /* Clear the pending eDMA channel interrupt */ + + putreg32(EDMA_CH_INT, base + IMX9_EDMA_CH_INT_OFFSET); + + imx9_dmaterminate(dmach, -EIO); + return OK; + } + + /* Check for an eDMA pending interrupt on this channel */ + + regval32 = imx9_edma_intstatus(dmach->base, dmach->chan); + if ((regval32 & EDMA_INT(chan % 31)) != 0) + { + /* An interrupt is pending. + * This should only happen if the channel is active. + */ + + DEBUGASSERT(dmach->state == IMX9_DMA_ACTIVE); + + /* Clear the pending eDMA channel interrupt */ + + putreg32(EDMA_CH_INT, base + IMX9_EDMA_CH_INT_OFFSET); + + /* Get the eDMA TCD Control and Status register value. */ + + regval32 = getreg32(base + IMX9_EDMA_CH_CSR_OFFSET); + + /* Check if transfer has finished. */ + + if ((regval32 & EDMA_CH_CSR_DONE) != 0) + { + /* Clear the pending DONE interrupt status. */ + + regval32 |= EDMA_CH_CSR_DONE; + putreg32(regval32, base + IMX9_EDMA_CH_CSR_OFFSET); + result = OK; + } + else + { + /* Perform the half or end-of-major-cycle DMA callback */ + + if (dmach->callback != NULL) + { + dmach->callback((DMACH_HANDLE)dmach, dmach->arg, false, OK); + } + + return OK; + } + + /* Terminate the transfer when it is done. */ + + if ((dmach->flags & EDMA_CONFIG_LOOP_MASK) == 0) + { + imx9_dmaterminate(dmach, result); + } + else if (dmach->callback != NULL) + { + dmach->callback((DMACH_HANDLE)dmach, dmach->arg, true, result); + } + } + + return OK; +} + +/**************************************************************************** + * Name: imx9_edma_interrupt + * + * Description: + * DMA interrupt handler. This function clears the channel major + * interrupt flag and calls the callback function if it is not NULL. + * + * NOTE: For the case using TCD queue, when the major iteration count is + * exhausted, additional operations are performed. These include the + * final address adjustments and reloading of the BITER field into the + * CITER. Assertion of an optional interrupt request also occurs at this + * time, as does a possible fetch of a new TCD from memory using the + * scatter/gather address pointer included in the descriptor (if scatter/ + * gather is enabled). + * + ****************************************************************************/ + +static int imx9_edma_interrupt(int irq, void *context, void *arg) +{ + struct imx9_dmach_s *dmach = (struct imx9_dmach_s *)arg; + +#ifdef IMX9_DMA3_BASE + if ((irq >= IMX9_IRQ_DMA3_0) && (irq <= IMX9_IRQ_DMA3_30)) + { + /* eDMA3 interrupt has a single source */ + + imx9_edma_isr(irq, context, dmach); + } +#endif + +#ifdef IMX9_DMA4_BASE + if ((irq >= IMX9_IRQ_DMA4_0_1) && (irq <= IMX9_IRQ_DMA4_62_63)) + { + /* eDMA4 interrupt has two sources */ + + imx9_edma_isr(irq, context, dmach); + imx9_edma_isr(irq, context, dmach + 1); + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: imx9_edma_configure + * + * Description: + * Configure eDMA instance. + * + ****************************************************************************/ + +static void imx9_edma_configure(uintptr_t base) +{ + uint32_t regval; + + /* Configure the eDMA controllers */ + + regval = getreg32(IMX9_EDMA_CSR(base)); + regval &= ~(EDMA_CSR_EDBG | EDMA_CSR_ERCA | EDMA_CSR_HAE | EDMA_CSR_GCLC | + EDMA_CSR_GMRC); + +#ifdef CONFIG_IMX9_EDMA_EDBG + regval |= EDMA_CSR_EDBG; /* Enable Debug */ +#endif +#ifdef CONFIG_IMX9_EDMA_ERCA + regval |= EDMA_CSR_ERCA; /* Enable Round Robin Channel Arbitration */ +#endif +#ifdef CONFIG_IMX9_EDMA_ERGA + regval |= EDMA_CSR_ERGA; /* Enable Round Robin Group Arbitration */ +#endif +#ifdef CONFIG_IMX9_EDMA_HOE + regval |= EDMA_CSR_HAE; /* Halt On Error */ +#endif +#ifdef CONFIG_IMX9_EDMA_CLM + regval |= EDMA_CSR_GCLC; /* Continuous Link Mode / Global Channel Linking Control */ +#endif +#ifdef CONFIG_IMX9_EDMA_EMLIM + regval |= EDMA_CSR_GMRC; /* Enable Minor Loop Mapping / Global Master ID Replication Control */ +#endif + + putreg32(regval, IMX9_EDMA_CSR(base)); +} + +/**************************************************************************** + * Name: imx9_find_free_ch + * + * Description: + * Configure eDMA instance. + * + ****************************************************************************/ + +static struct imx9_dmach_s * imx9_find_free_ch(uint16_t dmamux) +{ + struct imx9_dmach_s *candidate; + uintptr_t base; + unsigned int chndx; + + /* eDMA base for MUX */ + + base = imx9_dmamux_get_dmabase(dmamux); + +#ifdef IMX9_DMA3_BASE + /* For eDMA3 the channel must match the MUX number */ + + if (base == IMX9_DMA3_BASE) + { + chndx = dmamux & EDMA_MUX_MASK; + candidate = &g_edma.dmach[chndx]; + if (!candidate->inuse) + { + return candidate; + } + } +#endif + +#ifdef IMX9_DMA4_BASE + /* For eDMA4 any free channel is good */ + + if (base == IMX9_DMA4_BASE) + { + unsigned int offset; + unsigned int max; + + /* Iterate relevant channel range from the global LUT */ + + offset = imx9_edma_choffset(base); + max = imx9_edma_chmax(base); + + for (chndx = offset; chndx < max; chndx++) + { + candidate = &g_edma.dmach[chndx]; + if (!candidate->inuse) + { + return candidate; + } + } + } +#endif + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_dma_initialize + * + * Description: + * Initialize the DMA subsystem + * + * Returned Value: + * None + * + ****************************************************************************/ + +void weak_function arm64_dma_initialize(void) +{ + struct imx9_dmach_s *dmach; + uintptr_t base; + int chan; + int i; + + dmainfo("Initialize eDMA\n"); + + /* Enable root clock */ + + imx9_ccm_configure_root_clock(CCM_CR_WAKEUPAXI, SYS_PLL1PFD0, 4); + + /* Configure the instances */ + + dmach = &g_edma.dmach[0]; + +#ifdef IMX9_DMA3_BASE + /* Enable peripheral clock */ + + imx9_ccm_gate_on(CCM_LPCG_EDMA3, true); + + imx9_edma_configure(IMX9_DMA3_BASE); + + /* Initialize the channel */ + + for (i = 0; i < DMA3_CHANNEL_COUNT; i++, dmach++) + { + dmach->base = IMX9_DMA3_BASE; + dmach->chan = i; + + irq_attach(IMX9_IRQ_DMA3_0 + i, imx9_edma_interrupt, dmach); + } +#endif + +#ifdef IMX9_DMA4_BASE + /* Enable peripheral clock */ + + imx9_ccm_gate_on(CCM_LPCG_EDMA4, true); + + imx9_edma_configure(IMX9_DMA4_BASE); + + /* Initialize the channel */ + + for (i = 0; i < DMA4_CHANNEL_COUNT; i++, dmach++) + { + dmach->base = IMX9_DMA4_BASE; + dmach->chan = i; + + /* Attach interrupt for every second channel */ + + if ((i & 0x01) == 0) + { + irq_attach(IMX9_IRQ_DMA4_0_1 + (i >> 1), imx9_edma_interrupt, + dmach); + } + } +#endif + +#if CONFIG_IMX9_EDMA_NTCD > 0 + /* Initialize the list of free TCDs from the pool of pre-allocated TCDs. */ + + imx9_tcd_initialize(); +#endif + + /* Disable all DMA channel interrupts at the eDMA controller */ + + for (i = 0; i < IMX9_EDMA_NCHANNELS; i++) + { + /* DMA engine base and TCD channel */ + + base = g_edma.dmach[i].base; + chan = g_edma.dmach[i].chan; + + /* Disable all DMA channels and DMA channel interrupts */ + + putreg32(0, IMX9_EDMA_TCD(base, chan) + IMX9_EDMA_CH_CSR_OFFSET); + + /* Set all TCD CSR, biter and citer entries to 0 so that + * will be 0 when DONE is not set so that imx9_dmach_getcount + * reports 0. + */ + + putreg16(0, IMX9_EDMA_TCD(base, chan) + IMX9_EDMA_TCD_CSR_OFFSET); + putreg16(0, IMX9_EDMA_TCD(base, chan) + IMX9_EDMA_TCD_CITER_OFFSET); + putreg16(0, IMX9_EDMA_TCD(base, chan) + IMX9_EDMA_TCD_BITER_OFFSET); + } + +#ifdef IMX9_DMA3_BASE + /* Clear all pending DMA channel interrupts */ + + putreg32(0xffffffff, IMX9_EDMA_INT); + + /* Enable the channel interrupts at the NVIC (still disabled at the eDMA + * controller). + */ + + for (i = 0; i < DMA3_IRQ_COUNT; i++) + { + up_enable_irq(IMX9_IRQ_DMA3_0 + i); + } +#endif + +#ifdef IMX9_DMA4_BASE + /* Clear all pending DMA channel interrupts */ + + putreg32(0xffffffff, IMX9_EDMA_INT_LOW); + putreg32(0xffffffff, IMX9_EDMA_INT_HIGH); + + /* Enable the channel interrupts at the NVIC (still disabled at the eDMA + * controller). + */ + + for (i = 0; i < DMA4_IRQ_COUNT; i++) + { + up_enable_irq(IMX9_IRQ_DMA4_0_1 + i); + } +#endif +} + +/**************************************************************************** + * Name: imx9_dmach_alloc + * + * Allocate a DMA channel. This function sets aside a DMA channel, + * initializes the DMAMUX for the channel, then gives the caller exclusive + * access to the DMA channel. + * + * Input Parameters: + * + * dmamux - DMAMUX configuration see DMAMUX channel configuration register + * bit-field definitions in hardware/imx9_dmamux.h. + * Settings include: + * + * DMAMUX_CHCFG_SOURCE Chip-specific DMA source (required) + * DMAMUX_CHCFG_TRIG DMA Channel Trigger Enable (optional) + * DMAMUX_CHCFG_ENBL DMA Mux Channel Enable (required) + * + * A value of zero will disable the DMAMUX channel. + * dchpri - DCHPRI channel priority configuration. See DCHPRI channel + * configuration register bit-field definitions in + * hardware/imx9_edma.h. Meaningful settings include: + * + * EDMA_DCHPRI_CHPRI Channel Arbitration Priority + * DCHPRI_DPA Disable Preempt Ability + * DCHPRI_ECP Enable Channel Preemption + * + * The power-on default, 0x05, is a reasonable choice. + * + * Returned Value: + * If a DMA channel is available, this function returns a non-NULL, void* + * DMA channel handle. NULL is returned on any failure. + * + ****************************************************************************/ + +DMACH_HANDLE imx9_dmach_alloc(uint16_t dmamux, uint8_t dchpri) +{ + struct imx9_dmach_s *dmach; + uintptr_t base; + int ret; + + /* Search for an available DMA channel */ + + dmach = NULL; + ret = nxmutex_lock(&g_edma.chlock); + if (ret < 0) + { + return NULL; + } + + /* Find channel for this DMA MUX */ + + dmach = imx9_find_free_ch(dmamux); + if (dmach) + { + dmach->inuse = true; + dmach->state = IMX9_DMA_IDLE; + dmach->dmamux = dmamux & EDMA_MUX_MASK; + + /* TCD register base */ + + base = IMX9_EDMA_TCD(dmach->base, dmach->chan); + + /* Clear any pending interrupts on the channel */ + + putreg32(0, base + IMX9_EDMA_CH_CSR_OFFSET); + + /* Make sure that the channel is disabled. */ + + putreg32(EDMA_CH_INT, base + IMX9_EDMA_CH_INT_OFFSET); + + /* Set the DMAMUX source */ + + if (imx9_edma_tcdhasmux(dmach->base)) + { + dmainfo("CH%d: MUX:%u->%p\n", dmach->chan, dmach->dmamux, + (void *)(base + IMX9_EDMA_CH_MUX_OFFSET)); + putreg8(dmach->dmamux, base + IMX9_EDMA_CH_MUX_OFFSET); + } + } + + nxmutex_unlock(&g_edma.chlock); + + /* Show the result of the allocation */ + + if (dmach != NULL) + { + dmainfo("CH%d: returning dmach: %p\n", dmach->chan, dmach); + } + else + { + dmaerr("ERROR: Failed allocate eDMA channel\n"); + } + + return (DMACH_HANDLE)dmach; +} + +/**************************************************************************** + * Name: imx9_dmach_free + * + * Description: + * Release a DMA channel. NOTE: The 'handle' used in this argument must + * NEVER be used again until imx9_dmach_alloc() is called again to + * re-gain a valid handle. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imx9_dmach_free(DMACH_HANDLE handle) +{ + struct imx9_dmach_s *dmach = (struct imx9_dmach_s *)handle; + uintptr_t base = IMX9_EDMA_TCD(dmach->base, dmach->chan); + + dmainfo("dmach: %p\n", dmach); + DEBUGASSERT(dmach != NULL && dmach->inuse && + dmach->state != IMX9_DMA_ACTIVE); + + /* Mark the channel no longer in use. Clearing the inuse flag is an atomic + * operation and so should be safe. + */ + + dmach->flags = 0; + dmach->inuse = false; /* No longer in use */ + dmach->state = IMX9_DMA_IDLE; /* Better not be active! */ + + /* Make sure that the channel is disabled. */ + + putreg32(EDMA_CH_INT, base + IMX9_EDMA_CH_INT_OFFSET); + + /* Disable the associated DMAMUX */ + + if (imx9_edma_tcdhasmux(dmach->base)) + { + putreg8(0, base + IMX9_EDMA_CH_MUX_OFFSET); + } +} + +/**************************************************************************** + * Name: imx9_dmach_xfrsetup + * + * Description: + * This function adds the eDMA transfer to the DMA sequence. The request + * is setup according to the content of the transfer configuration + * structure. For "normal" DMA, imx9_dmach_xfrsetup is called only once. + * Scatter/gather DMA is accomplished by calling this function repeatedly, + * once for each transfer in the sequence. Scatter/gather DMA processing + * is enabled automatically when the second transfer configuration is + * received. + * + * This function may be called multiple times to handle multiple, + * discontinuous transfers (scatter-gather) + * + * Input Parameters: + * handle - DMA channel handle created by imx9_dmach_alloc() + * config - A DMA transfer configuration instance, populated by the + * The content of 'config' describes the transfer + * + * Returned Value + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int imx9_dmach_xfrsetup(DMACH_HANDLE *handle, + const struct imx9_edma_xfrconfig_s *config) +{ + struct imx9_dmach_s *dmach = (struct imx9_dmach_s *)handle; + uintptr_t base = IMX9_EDMA_TCD(dmach->base, dmach->chan); +#if CONFIG_IMX9_EDMA_NTCD > 0 + struct imx9_edmatcd_s *tcd; + struct imx9_edmatcd_s *prev; + uint16_t mask = config->flags & EDMA_CONFIG_INTMAJOR ? 0 : + EDMA_TCD_CSR_INTMAJOR; + uint16_t regval16; +#else + uint32_t regval32; +#endif + + DEBUGASSERT(dmach != NULL); + dmainfo("dmach%u: %p config: %p\n", dmach->chan, dmach, config); + + dmach->flags = config->flags; + +#if CONFIG_IMX9_EDMA_NTCD > 0 + /* Scatter/gather DMA is supported */ + + /* Allocate a TCD, waiting if necessary */ + + tcd = imx9_tcd_alloc(); + + /* Configure current TCD block transfer. */ + + imx9_tcd_configure(tcd, config); + + /* Enable the interrupt when the major iteration count completes for this + * TCD. For "normal" DMAs, this will correspond to the DMA DONE + * interrupt; for scatter gather DMAs, multiple interrupts will be + * generated with the final being the DONE interrupt. + */ + + tcd->csr |= EDMA_TCD_CSR_INTMAJOR; + + /* Is this the first descriptor in the list? */ + + if (dmach->head == NULL) + { + /* Yes.. add it to the list */ + + dmach->head = tcd; + dmach->tail = tcd; + + /* And instantiate the first TCD in the DMA channel TCD registers. */ + + imx9_tcd_instantiate(dmach, tcd); + } + else + { + /* Cannot mix transfer types */ + + if (dmach->flags & EDMA_CONFIG_LOOP_MASK) + { + imx9_tcd_free(tcd); + return -EINVAL; + } + + /* Chain from previous descriptor in the list. */ + + /* Enable scatter/gather feature in the previous TCD. */ + + prev = dmach->tail; + regval16 = prev->csr; + regval16 &= ~(EDMA_TCD_CSR_DREQ | mask); + regval16 |= EDMA_TCD_CSR_ESG; + prev->csr = regval16; + + prev->dlastsga = (uint32_t)((uintptr_t)tcd); + dmach->tail = tcd; + + /* Clean cache associated with the previous TCD memory */ + + up_clean_dcache((uintptr_t)prev, + (uintptr_t)prev + sizeof(struct imx9_edmatcd_s)); + + /* Check if the TCD block in the DMA channel registers is the same as + * the previous previous TCD. This can happen if the previous TCD was + * the first TCD and has already be loaded into the TCD registers. + */ + + if (dmach->head == prev) + { + /* Enable scatter/gather also in the TCD registers. */ + + regval16 = getreg16(base + IMX9_EDMA_TCD_CSR_OFFSET); + regval16 &= ~(EDMA_TCD_CSR_DREQ | mask); + regval16 |= EDMA_TCD_CSR_ESG; + putreg16(regval16, base + IMX9_EDMA_TCD_CSR_OFFSET); + + putreg32((uint32_t)((uintptr_t)tcd), + base + IMX9_EDMA_TCD_DLAST_SGA_OFFSET); + } + } + + /* Clean cache associated with the TCD memory */ + + up_clean_dcache((uintptr_t)tcd, + (uintptr_t)tcd + sizeof(struct imx9_edmatcd_s)); +#else + + /* Scatter/gather DMA is NOT supported */ + + /* Check if eDMA is busy: if the channel has started transfer, CSR will be + * non-zero. + */ + + regval32 = getreg32(base + IMX9_EDMA_CH_CSR_OFFSET); + + if (regval32 != 0 && (regval32 & EDMA_CH_CSR_DONE) == 0) + { + return -EBUSY; + } + + /* Configure channel TCD registers to the values specified in config. */ + + imx9_tcd_configure((struct imx9_edmatcd_s *) + (base + IMX9_EDMA_TCD_SADDR_OFFSET), config); + + /* Enable the DONE interrupt when the major iteration count completes. */ + + modifyreg16(base + IMX9_EDMA_TCD_CSR_OFFSET, 0, EDMA_TCD_CSR_INTMAJOR); +#endif + + dmach->state = IMX9_DMA_CONFIGURED; + return OK; +} + +/**************************************************************************** + * Name: imx9_dmach_start + * + * Description: + * Start the DMA transfer. This function should be called after the final + * call to imx9_dmach_xfrsetup() in order to avoid race conditions. + * + * At the conclusion of each major DMA loop, a callback to the user + * provided function is made: |For "normal" DMAs, this will correspond to + * the DMA DONE interrupt; for scatter gather DMAs, + * this will be generated with the final TCD. + * + * At the conclusion of the DMA, the DMA channel is reset, all TCDs are + * freed, and the callback function is called with the the success/fail + * result of the DMA. + * + * NOTE: On Rx DMAs (peripheral-to-memory or memory-to-memory), it is + * necessary to invalidate the destination memory. That is not done + * automatically by the DMA module. Invalidation of the destination memory + * regions is the responsibility of the caller. + * + * Input Parameters: + * handle - DMA channel handle created by imx9_dmach_alloc() + * callback - The callback to be invoked when the DMA is completes or is + * aborted. + * arg - An argument that accompanies the callback + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int imx9_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, + void *arg) +{ + struct imx9_dmach_s *dmach = (struct imx9_dmach_s *)handle; + uintptr_t base = IMX9_EDMA_TCD(dmach->base, dmach->chan); + irqstate_t flags; + uint32_t regval; + uint8_t chan; + + DEBUGASSERT(dmach != NULL && dmach->state == IMX9_DMA_CONFIGURED); + chan = dmach->chan; + dmainfo("dmach%u: %p callback: %p arg: %p\n", chan, dmach, callback, arg); + + /* Save the callback info. This will be invoked when the DMA completes */ + + flags = spin_lock_irqsave(NULL); + dmach->callback = callback; + dmach->arg = arg; + +#if CONFIG_IMX9_EDMA_NTCD > 0 + /* Although it is not recommended, it might be possible to call this + * function multiple times while adding TCDs on the fly. + */ + + if (dmach->state != IMX9_DMA_ACTIVE) +#endif + { + dmach->state = IMX9_DMA_ACTIVE; + + regval = getreg32(base + IMX9_EDMA_CH_CSR_OFFSET); + regval |= EDMA_CH_CSR_ERQ | EDMA_CH_CSR_EEI; + putreg32(regval, base + IMX9_EDMA_CH_CSR_OFFSET); + } + + spin_unlock_irqrestore(NULL, flags); + return OK; +} + +/**************************************************************************** + * Name: imx9_dmach_stop + * + * Description: + * Cancel the DMA. After imx9_dmach_stop() is called, the DMA channel + * is reset, all TCDs are freed, and imx9_dmarx/txsetup() must be called + * before imx9_dmach_start() can be called again. + * + * Input Parameters: + * handle - DMA channel handle created by imx9_dmach_alloc() + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void imx9_dmach_stop(DMACH_HANDLE handle) +{ + struct imx9_dmach_s *dmach = (struct imx9_dmach_s *)handle; + irqstate_t flags; + + dmainfo("dmach: %p\n", dmach); + DEBUGASSERT(dmach != NULL); + + flags = spin_lock_irqsave(NULL); + imx9_dmaterminate(dmach, -EINTR); + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: imx9_dmach_getcount + * + * Description: + * This function checks the TCD (Task Control Descriptor) status for a + * specified eDMA channel and returns the the number of major loop counts + * that have not finished. + * + * NOTES: + * 1. This function can only be used to get unfinished major loop count of + * transfer without the next TCD, or it might be inaccuracy. + * 2. The unfinished/remaining transfer bytes cannot be obtained directly + * from registers while the channel is running. + * + * Because to calculate the remaining bytes, the initial NBYTES configured + * in DMA_TCDn_NBYTES_MLNO register is needed while the eDMA IP does not + * support getting it while a channel is active. In another words, the + * NBYTES value reading is always the actual (decrementing) NBYTES value + * the dma_engine is working with while a channel is running. + * Consequently, to get the remaining transfer bytes, a software-saved + * initial value of NBYTES (for example copied before enabling the channel) + * is needed. The formula to calculate it is shown below: + * + * RemainingBytes = RemainingMajorLoopCount * + * NBYTES(initially configured) + * + * Input Parameters: + * handle - DMA channel handle created by imx9_dmach_alloc() + * + * Returned Value: + * Major loop count which has not been transferred yet for the current TCD. + * + ****************************************************************************/ + +unsigned int imx9_dmach_getcount(DMACH_HANDLE *handle) +{ + struct imx9_dmach_s *dmach = (struct imx9_dmach_s *)handle; + uintptr_t base = IMX9_EDMA_TCD(dmach->base, dmach->chan); + unsigned int remaining = 0; + uintptr_t regval32; + uint16_t regval16; + + DEBUGASSERT(dmach != NULL); + + /* If the DMA is done, then the remaining count is zero */ + + regval32 = getreg32(base + IMX9_EDMA_CH_CSR_OFFSET); + + if ((regval32 & EDMA_CH_CSR_DONE) == 0) + { + /* Calculate the unfinished bytes */ + + regval16 = getreg16(base + IMX9_EDMA_TCD_CITER_OFFSET); + + if ((regval16 & EDMA_TCD_CITER_ELINK) != 0) + { + remaining = (regval16 & EDMA_TCD_CITER_MASK_ELINK) >> + EDMA_TCD_CITER_SHIFT; + } + else + { + remaining = (regval16 & EDMA_TCD_CITER_MASK) >> + EDMA_TCD_CITER_SHIFT; + } + } + + return remaining; +} + +/**************************************************************************** + * Name: imx9_dmach_idle + * + * Description: + * This function checks if the dma is idle + * + * Returned Value: + * 0 - if idle + * !0 - not + * + ****************************************************************************/ + +unsigned int imx9_dmach_idle(DMACH_HANDLE handle) +{ + struct imx9_dmach_s *dmach = (struct imx9_dmach_s *)handle; + return dmach->state == IMX9_DMA_IDLE ? 0 : -1; +} + +/**************************************************************************** + * Name: imx9_dmasample + * + * Description: + * Sample DMA register contents + * + * Assumptions: + * - DMA handle allocated by imx9_dmach_alloc() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imx9_dmasample(DMACH_HANDLE handle, struct imx9_dmaregs_s *regs) +{ + struct imx9_dmach_s *dmach = (struct imx9_dmach_s *)handle; + unsigned int chan; + irqstate_t flags; + uintptr_t base = IMX9_EDMA_TCD(dmach->base, dmach->chan); + + DEBUGASSERT(dmach != NULL && regs != NULL); + chan = dmach->chan; + regs->chan = chan; + + /* eDMA Global Registers */ + + flags = spin_lock_irqsave(NULL); + + /* REVISIT: eDMA4 does not show INT_HIGH / HRS_HIGH values correctly */ + + regs->cr = getreg32(IMX9_EDMA_CSR(base)); /* Control */ + regs->es = getreg32(IMX9_EDMA_ES(base)); /* Error Status */ + regs->req = getreg32(IMX9_EDMA_INT); /* Interrupt Request */ + regs->hrs = getreg32(IMX9_EDMA_HRS); /* Hardware Request Status */ + + /* eDMA TCD */ + + regs->saddr = getreg32(base + IMX9_EDMA_TCD_SADDR_OFFSET); + regs->soff = getreg16(base + IMX9_EDMA_TCD_SOFF_OFFSET); + regs->attr = getreg16(base + IMX9_EDMA_TCD_ATTR_OFFSET); + regs->nbml = getreg32(base + IMX9_EDMA_TCD_NBYTES_OFFSET); + regs->slast = getreg32(base + IMX9_EDMA_TCD_SLAST_SDA_OFFSET); + regs->daddr = getreg32(base + IMX9_EDMA_TCD_DADDR_OFFSET); + regs->doff = getreg16(base + IMX9_EDMA_TCD_DOFF_OFFSET); + regs->citer = getreg16(base + IMX9_EDMA_TCD_CITER_OFFSET); + regs->dlastsga = getreg32(base + IMX9_EDMA_TCD_DLAST_SGA_OFFSET); + regs->csr = getreg16(base + IMX9_EDMA_TCD_CSR_OFFSET); + regs->biter = getreg16(base + IMX9_EDMA_TCD_BITER_OFFSET); + + /* DMAMUX registers */ + + if (imx9_edma_tcdhasmux(dmach->base)) + { + regs->dmamux = getreg32(base + IMX9_EDMA_CH_MUX_OFFSET); + } + else + { + regs->dmamux = 0; + } + + spin_unlock_irqrestore(NULL, flags); +} +#endif /* CONFIG_DEBUG_DMA */ + +/**************************************************************************** + * Name: imx9_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + * Assumptions: + * - DMA handle allocated by imx9_dmach_alloc() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imx9_dmadump(const struct imx9_dmaregs_s *regs, const char *msg) +{ + unsigned int chan; + + DEBUGASSERT(regs != NULL && msg != NULL); + + chan = regs->chan; + DEBUGASSERT(chan < IMX9_EDMA_NCHANNELS); + + dmainfo("%s\n", msg); + dmainfo(" eDMA Global Registers:\n"); + dmainfo(" CR: %08x\n", (unsigned int)regs->cr); + dmainfo(" ES: %08x\n", (unsigned int)regs->es); + dmainfo(" INT: %08x\n", (unsigned int)regs->req); + dmainfo(" EARS: %08x\n", (unsigned int)regs->hrs); + + /* eDMA Channel registers */ + + dmainfo(" eDMA Channel %u Registers:\n", chan); + dmainfo(" DCHPRI: %02x\n", regs->dchpri); + + /* eDMA TCD */ + + dmainfo(" eDMA Channel %u TCD Registers:\n", chan); + dmainfo(" SADDR: %08x\n", (unsigned int)regs->saddr); + dmainfo(" SOFF: %04x\n", (unsigned int)regs->soff); + dmainfo(" ATTR: %04x\n", (unsigned int)regs->attr); + dmainfo(" NBML: %05x\n", (unsigned int)regs->nbml); + dmainfo(" SLAST: %05x\n", (unsigned int)regs->slast); + dmainfo(" DADDR: %05x\n", (unsigned int)regs->daddr); + dmainfo(" DOFF: %04x\n", (unsigned int)regs->doff); + dmainfo(" CITER: %04x\n", (unsigned int)regs->citer); + dmainfo(" DLASTSGA: %08x\n", (unsigned int)regs->dlastsga); + dmainfo(" CSR: %04x\n", (unsigned int)regs->csr); + dmainfo(" BITER: %04x\n", (unsigned int)regs->biter); + + /* DMAMUX registers */ + + dmainfo(" DMAMUX Channel %u Registers:\n", chan); + dmainfo(" DMAMUX: %08x\n", (unsigned int)regs->dmamux); +} +#endif /* CONFIG_DEBUG_DMA */ +#endif /* CONFIG_IMX9_EDMA */ diff --git a/arch/arm64/src/imx9/imx9_edma.h b/arch/arm64/src/imx9/imx9_edma.h new file mode 100644 index 0000000000000..4f3a4ac73eafa --- /dev/null +++ b/arch/arm64/src/imx9/imx9_edma.h @@ -0,0 +1,482 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_edma.h + * + * Copyright (C) 2019, 2021, 2023 Gregory Nutt. All rights reserved. + * Copyright 2022 NXP + * Authors: Gregory Nutt + * David Sidrane + * Peter van der Perk + * + * This file was leveraged from the NuttX S32K1 port. Portions of that eDMA + * logic derived from NXP sample code which has a compatible BSD 3-clause + * license: + * + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_EDMA_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_EDMA_H + +/* General Usage: + * + * 1. Allocate a DMA channel + * + * DMACH_HANDLE handle; + * handle = edma_dmach_alloc(dmamux, dchpri); + * + * Where 'dmamux' is the channel DMAMUX configuration register setting and + * 'dchpri' is the channel DCHPRIO priority register setting. + * + * 2. Create the transfer configuration: + * + * struct imx9_edma_xfrconfig_s config; + * config.saddr = ..; + * config.daddr = ..; + * etc. + * + * 3. Setup the transfer in hardware: + * + * int ret; + * ret = imx9_dmach_xfrsetup(handle, &config); + * + * 4. If you are setting up a scatter gather DMA + * (with CONFIG_IMX9_EDMA_NTCD > 0), then repeat steps 2 and 3 for + * each segment of the transfer. + * + * 5. Start the DMA: + * + * ret = imx9_dmach_start(handle, my_callback_func, priv); + * + * Where my_callback_func() is called when the DMA completes or an error + * occurs. 'priv' represents some internal driver state that will be + * provided with the callback. + * + * 6. If you need to stop the DMA and free resources (such as if a timeout + * occurs), then: + * + * i mxrt_dmach_stop(handle); + * + * 7. The callback will be received when the DMA completes (or an error + * occurs). After that, you may free the DMA channel, or re-use it on + * subsequent DMAs. + * + * imx9_dmach_free(handle); + * + * Almost non-invasive debug instrumentation is available. You may call + * imx9_dmasample() to save the current state of the eDMA registers at + * any given point in time. At some later, postmortem analysis, you can + * dump the content of the buffered registers with imx9_dmadump(). + * imx9_dmasample() is also available for monitoring DMA progress. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration flags. + * + * REVISIT: Many missing options that should be represented as flags: + * 1. Bandwidth + * 2. Source/Destination modulo + */ + +#define EDMA_CONFIG_LINKTYPE_SHIFT (0) /* Bits 0-1: Link type */ +#define EDMA_CONFIG_LINKTYPE_MASK (3 << EDMA_CONFIG_LINKTYPE_SHIFT) +# define EDMA_CONFIG_LINKTYPE_LINKNONE (0 << EDMA_CONFIG_LINKTYPE_SHIFT) /* No channel link */ +# define EDMA_CONFIG_LINKTYPE_MINORLINK (1 << EDMA_CONFIG_LINKTYPE_SHIFT) /* Channel link after each minor loop */ +# define EDMA_CONFIG_LINKTYPE_MAJORLINK (2 << EDMA_CONFIG_LINKTYPE_SHIFT) /* Channel link when major loop count exhausted */ + +#define EDMA_CONFIG_LOOP_SHIFT (2) /* Bits 2: Loop type */ +#define EDMA_CONFIG_LOOP_MASK (3 << EDMA_CONFIG_LOOP_SHIFT) +# define EDMA_CONFIG_LOOPNONE (0 << EDMA_CONFIG_LOOP_SHIFT) /* No looping */ +# define EDMA_CONFIG_LOOPSRC (1 << EDMA_CONFIG_LOOP_SHIFT) /* Source looping */ +# define EDMA_CONFIG_LOOPDEST (2 << EDMA_CONFIG_LOOP_SHIFT) /* Dest looping */ + +#define EDMA_CONFIG_INTHALF (1 << 4) /* Bits 4: Int on HALF */ +#define EDMA_CONFIG_INTMAJOR (1 << 5) /* Bits 5: Int on all Major completion + * Default is only on last completion + * if using scatter gather + */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef void *DMACH_HANDLE; +typedef void (*edma_callback_t)(DMACH_HANDLE handle, + void *arg, bool done, int result); + +/* eDMA transfer type */ + +enum imx9_edma_xfrtype_e +{ + EDMA_MEM2MEM = 0, /* Transfer from memory to memory */ + EDMA_PERIPH2MEM, /* Transfer from peripheral to memory */ + EDMA_MEM2PERIPH, /* Transfer from memory to peripheral */ +}; + +/* eDMA transfer sises */ + +enum imx9_edma_sizes_e +{ + EDMA_8BIT = 0, /* Transfer data size 8 */ + EDMA_16BIT = 1, /* Transfer data size 16 */ + EDMA_32BIT = 2, /* Transfer data size 32 */ + EDMA_64BIT = 3, /* Transfer data size 64 */ + EDMA_16BYTE = 4, /* Transfer data size 16-byte */ + EDMA_32BYTE = 5, /* Transfer data size 32-byte */ + EDMA_64BYTE = 6, /* Transfer data size 64-byte */ +}; + +/* This structure holds the source/destination transfer attribute + * configuration. + */ + +struct imx9_edma_xfrconfig_s +{ + uintptr_t saddr; /* Source data address. */ + uintptr_t daddr; /* Destination data address. */ + int16_t soff; /* Sign-extended offset for current source address. */ + int16_t doff; /* Sign-extended offset for current destination address. */ + uint16_t iter; /* Major loop iteration count. */ + uint8_t flags; /* See EDMA_CONFIG_* definitions */ + uint8_t ssize; /* Source data transfer size (see TCD_ATTR_SIZE_* definitions in rdware/. */ + uint8_t dsize; /* Destination data transfer size. */ +#ifdef CONFIG_IMX9_EDMA_EMLIM + uint16_t nbytes; /* Bytes to transfer in a minor loop */ +#else + uint32_t nbytes; /* Bytes to transfer in a minor loop */ +#endif +#ifdef CONFIG_IMX9_EDMA_MOD + uint8_t smod; + uint8_t dmod; +#endif +#ifdef CONFIG_IMX9_EDMA_BWC + uint8_t bwc; +#endif +#ifdef CONFIG_IMX9_EDMA_ELINK + DMACH_HANDLE linkch; /* Link channel (With EDMA_CONFIG_LINKTYPE_* flags) */ +#endif +}; + +/* The following is used for sampling DMA registers when CONFIG DEBUG_DMA + * is selected + */ + +#ifdef CONFIG_DEBUG_DMA +struct imx9_dmaregs_s +{ + uint8_t chan; /* Sampled channel */ + + /* eDMA Global Registers */ + + uint32_t cr; /* Control */ + uint32_t es; /* Error Status */ + uint32_t req; /* Interrupt Request */ + uint32_t hrs; /* Hardware Request Status */ + + /* eDMA Channel registers */ + + uint8_t dchpri; /* Channel priority */ + + /* eDMA TCD */ + + uint32_t saddr; /* TCD Source Address */ + uint16_t soff; /* TCD Signed Source Address Offset */ + uint16_t attr; /* TCD Transfer Attributes */ + uint32_t nbml; /* TCD Signed Minor Loop Offset / Byte Count */ + uint32_t slast; /* TCD Last Source Address Adjustment */ + uint32_t daddr; /* TCD Destination Address */ + uint16_t doff; /* TCD Signed Destination Address Offset */ + uint16_t citer; /* TCD Current Minor Loop Link, Major Loop Count */ + uint32_t dlastsga; /* TCD Last Destination Address Adjustment/Scatter Gather Address */ + uint16_t csr; /* TCD Control and Status */ + uint16_t biter; /* TCD Beginning Minor Loop Link, Major Loop Count */ + + /* DMAMUX registers */ + + uint32_t dmamux; /* Channel configuration */ +}; +#endif /* CONFIG_DEBUG_DMA */ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_dmach_alloc + * + * Allocate a DMA channel. This function sets aside a DMA channel, + * initializes the DMAMUX for the channel, then gives the caller exclusive + * access to the DMA channel. + * + * Input Parameters: + * dmamux - DMAMUX configuration see DMAMUX channel configuration register + * bit-field definitions in hardware/imx9_dmamux.h. + * Settings include: + * + * DMAMUX_CHCFG_SOURCE Chip-specific DMA source (required) + * DMAMUX_CHCFG_TRIG DMA Channel Trigger Enable (optional) + * DMAMUX_CHCFG_ENBL DMA Mux Channel Enable (required) + * + * A value of zero will disable the DMAMUX channel. + * dchpri - DCHPRI channel priority configuration. See DCHPRI channel + * configuration register bit-field definitions in + * hardware/imx9_edma.h. Meaningful settings include: + * + * EDMA_DCHPRI_CHPRI Channel Arbitration Priority + * DCHPRI_DPA Disable Preempt Ability + * DCHPRI_ECP Enable Channel Preemption + * + * The power-on default, 0x05, is a reasonable choice. + * + * Returned Value: + * If a DMA channel is available, this function returns a non-NULL, void* + * DMA channel handle. NULL is returned on any failure. + * + ****************************************************************************/ + +DMACH_HANDLE imx9_dmach_alloc(uint16_t dmamux, uint8_t dchpri); + +/**************************************************************************** + * Name: imx9_dmach_free + * + * Description: + * Release a DMA channel. + * NOTE: The 'handle' used in this argument must NEVER be used again + * until imx9_dmach_alloc() is called again to re-gain a valid handle. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imx9_dmach_free(DMACH_HANDLE handle); + +/**************************************************************************** + * Name: imx9_dmach_xfrsetup + * + * Description: + * This function adds the eDMA transfer to the DMA sequence. The request + * is setup according to the content of the transfer configuration + * structure. For "normal" DMA, imx9_dmach_xfrsetup is called only + * once. + * Scatter/gather DMA is accomplished by calling this function repeatedly, + * once for each transfer in the sequence. Scatter/gather DMA processing + * is enabled automatically when the second transfer configuration is + * received. + * + * This function may be called multiple times to handle multiple, + * discontinuous transfers (scatter-gather) + * + * Input Parameters: + * handle - DMA channel handle created by imx9_dmach_alloc() + * config - A DMA transfer configuration instance, populated by the + * The content of 'config' describes the transfer + * + * Returned Value + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int imx9_dmach_xfrsetup(DMACH_HANDLE *handle, + const struct imx9_edma_xfrconfig_s *config); + +/**************************************************************************** + * Name: imx9_dmach_start + * + * Description: + * Start the DMA transfer by enabling the channel DMA request. + * This function should be called after the final call to + * imx9_dmasetup() in order to avoid race conditions. + * + * At the conclusion of each major DMA loop, a callback to the + * user-provided function is made: |For "normal" DMAs, this will + * correspond to the DMA DONE interrupt; for scatter gather DMAs, multiple + * interrupts will be generated with the final being the DONE interrupt. + * + * At the conclusion of the DMA, the DMA channel is reset, all TCDs are + * freed, and the callback function is called with the the success/fail + * result of the DMA. + * + * NOTE: + * On Rx DMAs (peripheral-to-memory or memory-to-memory), it is necessary + * to invalidate the destination memory. That is not done automatically + * by the DMA module. Invalidation of the destination memory regions is + * the responsibility of the caller. + * + * Input Parameters: + * handle - DMA channel handle created by imx9_dmach_alloc() + * callback - The callback to be invoked when the DMA is completes or is + * aborted. + * arg - An argument that accompanies the callback + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +int imx9_dmach_start(DMACH_HANDLE handle, edma_callback_t callback, + void *arg); + +/**************************************************************************** + * Name: imx9_dmach_stop + * + * Description: + * Cancel the DMA. After imx9_dmach_stop() is called, the DMA channel + * is reset, all TCDs are freed, and imx9_dmarx/txsetup() must be called + * before imx9_dmach_start() can be called again + * + * Input Parameters: + * handle - DMA channel handle created by imx9_dmach_alloc() + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void imx9_dmach_stop(DMACH_HANDLE handle); + +/**************************************************************************** + * Name: imx9_dmach_getcount + * + * Description: + * This function checks the TCD (Task Control Descriptor) status for a + * specified eDMA channel and returns the the number of major loop counts + * that have not finished. + * + * NOTES: + * 1. This function can only be used to get unfinished major loop count of + * transfer without the next TCD, or it might be inaccuracy. + * 2. The unfinished/remaining transfer bytes cannot be obtained directly + * from registers while the channel is running. + * + * Because to calculate the remaining bytes, the initial NBYTES configured + * in DMA_TCDn_NBYTES_MLNO register is needed while the eDMA IP does not + * support getting it while a channel is active. In another words, the + * NBYTES value reading is always the actual (decrementing) NBYTES value + * the dma_engine is working with while a channel is running. + * Consequently, to get the remaining transfer bytes, a software-saved + * initial value of NBYTES (for example copied before enabling the channel) + * is needed. The formula to calculate it is shown below: + * + * RemainingBytes = RemainingMajorLoopCount * NBYTES(initially configured) + * + * Input Parameters: + * handle - DMA channel handle created by imx9_dmach_alloc() + * + * Returned Value: + * Major loop count which has not been transferred yet for the current TCD. + * + ****************************************************************************/ + +unsigned int imx9_dmach_getcount(DMACH_HANDLE *handle); + +/**************************************************************************** + * Name: imx9_dmach_idle + * + * Description: + * This function checks if the dma is idle + * + * Returned Value: + * 0 - if idle + * !0 - not + * + ****************************************************************************/ + +unsigned int imx9_dmach_idle(DMACH_HANDLE handle); + +/**************************************************************************** + * Name: imx9_dmasample + * + * Description: + * Sample DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imx9_dmasample(DMACH_HANDLE handle, struct imx9_dmaregs_s *regs); +#else +# define imx9_dmasample(handle,regs) +#endif + +/**************************************************************************** + * Name: imx9_dmadump + * + * Description: + * Dump previously sampled DMA register contents + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void imx9_dmadump(const struct imx9_dmaregs_s *regs, const char *msg); +#else +# define imx9_dmadump(handle,regs,msg) +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_EDMA_H */ diff --git a/arch/arm64/src/imx9/imx9_enet.c b/arch/arm64/src/imx9/imx9_enet.c new file mode 100644 index 0000000000000..b6a501362bfc5 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_enet.c @@ -0,0 +1,3215 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_enet.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_NET_PKT +# include +#endif + +#include + +#include "arm64_internal.h" +#include "chip.h" +#include "hardware/imx9_enet.h" +#include "imx9_enet.h" + +#include "imx9_ccm.h" +#include "imx9_iomuxc.h" +#include "hardware/imx9_ccm.h" +#include "hardware/imx9_pinmux.h" + +#ifdef CONFIG_IMX9_ENET + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* If processing is not done at the interrupt level, then work queue support + * is required. + */ + +#if !defined(CONFIG_SCHED_LPWORK) +# error LPWORK queue support is required +#endif + +#define ETHWORK LPWORK + +/* We need at least two TX buffers for reliable operation */ + +#if CONFIG_IMX9_ENET_NTXBUFFERS < 1 +#define IMX9_ENET_NTXBUFFERS 1 +#else +#define IMX9_ENET_NTXBUFFERS CONFIG_IMX9_ENET_NTXBUFFERS +#endif + +/* We need an even number of RX buffers, since RX descriptors are + * freed for the DMA in pairs due to two descriptors always fitting + * in one cache line (cahce line size is 64, descriptor size is 32) + */ + +#if CONFIG_IMX9_ENET_NRXBUFFERS < 2 +#define IMX9_ENET_NRXBUFFERS 2 +#elif CONFIG_IMX9_ENET_NRXBUFFERS & 1 +#define IMX9_ENET_NRXBUFFERS (CONFIG_IMX9_ENET_NRXBUFFERS + 1) +#else +#define IMX9_ENET_NRXBUFFERS CONFIG_IMX9_ENET_NRXBUFFERS +#endif + +#define nitems(_a) (sizeof(_a) / sizeof(0[(_a)])) + +#define ALIGNED_BUFSIZE ENET_ALIGN_UP(CONFIG_NET_ETH_PKTSIZE + \ + CONFIG_NET_GUARDSIZE) + +/* TX timeout = 1 second */ + +#define IMX9_TXTIMEOUT (CLK_TCK) +#define MII_MAXPOLLS (0x1ffff) +#define LINK_WAITUS (100 * 1000) +#define LINK_NLOOPS (50) + +/* PHY reset tim in loop counts */ + +#define PHY_RESET_WAIT_COUNT (10) + +/* Estimate the MII_SPEED in order to get an MDC close to 2.5MHz, + * based on the internal module (ENET) clock: + + * MII clock frequency = 133 MHz / ((26 + 1) x 2) = 2.5 MHz + * + * TODO: This is hard-coded for now, could be properly calculated + */ + +#define IMX9_MII_SPEED 26 + +/* Interrupt groups */ + +#define RX_INTERRUPTS (ENET_INT_RXF | ENET_INT_RXB) +#define TX_INTERRUPTS ENET_INT_TXF +#define ERROR_INTERRUPTS (ENET_INT_UN | ENET_INT_RL | ENET_INT_LC | \ + ENET_INT_EBERR | ENET_INT_BABT | ENET_INT_BABR) + +/* The subset of errors that require us to reset the hardware - this list + * may need to be revisited if it's found that some error above leads to a + * locking up of the Ethernet interface. + */ + +#define CRITICAL_ERROR (ENET_INT_UN | ENET_INT_RL | ENET_INT_EBERR) + +/* This is a helper pointer for accessing + * the contents of the Ethernet header + */ + +#define BUF ((struct eth_hdr_s *)priv->dev.d_buf) + +#define IMX93_OCOTP_UID_OFFSET 0xc0 + +#define MMD1 1 +#define MMD1_PMA_STATUS1 1 +#define MMD1_PS1_RECEIVE_LINK_STATUS (1 << 2) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum phy_type_t +{ + PHY_NONE = 0, + PHY_RMII = 1, + PHY_RGMII = 2, +}; + +/* The imx9_driver_s encapsulates all state information for + * a single hardware interface + */ + +struct imx9_driver_s +{ + struct net_driver_s dev; /* Interface understood by the network */ + const uint32_t base; /* Base address of ENET controller */ + const int clk_gate; /* Enet clock gate */ + const int irq; /* Enet interrupt */ + const struct phy_desc_s * phy_list; /* Supported PHYs for this IF */ + const int n_phys; /* Number of supported PHYs */ + struct enet_txdesc_s * const txdesc; /* A pointer to the list of TX descriptor */ + struct enet_desc_s * const rxdesc; /* A pointer to the list of RX descriptors */ + const uintptr_t buffer_pool; /* DMA buffer pool */ +#ifdef CONFIG_IMX9_ENET_USE_OTP_MAC + const off_t otp_mac_off; /* MAC address offset in OTP */ +#endif + const bool promiscuous; /* Set promiscuous mode */ + const enum phy_type_t phy_type; /* PHY type */ + const bool autoneg; /* Phy autonegotiation enabled */ + const bool force_speed; /* Disable autonegotiation and force speed */ + bool full_duplex; /* Manually set to full duplex mode */ + bool s_10mbps; /* Manually set to 10 MBPS */ + bool s_100mbps; /* Manually set to 100 M0BPS */ + bool s_1000mbps; /* Manually set to 1GBPS */ + const struct phy_desc_s * cur_phy; /* Currently selected phy */ + bool bifup; /* true:ifup false:ifdown */ + uint8_t txhead; /* The next TX descriptor to use */ + uint8_t rxtail; /* The next RX descriptor to use */ + uint8_t phyaddr; /* Selected PHY address */ + struct wdog_s txtimeout; /* TX timeout timer */ + uint32_t ints; /* Enabled interrupts */ + struct work_s irqwork; /* For deferring interrupt work to the work queue */ + struct work_s pollwork; /* For deferring poll work to the work queue */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Utility functions */ + +static inline uint32_t imx9_enet_getreg32(struct imx9_driver_s *priv, + uint32_t offset); +static inline void imx9_enet_putreg32(struct imx9_driver_s *priv, + uint32_t value, uint32_t offset); + +static inline void imx9_enet_modifyreg32(struct imx9_driver_s *priv, + unsigned int offset, + uint32_t clearbits, + uint32_t setbits); + +/* Common TX logic */ + +static bool imx9_txringfull(struct imx9_driver_s *priv); +static int imx9_transmit(struct imx9_driver_s *priv, + uint32_t *buf_swap); +static int imx9_txpoll(struct net_driver_s *dev); + +/* Interrupt handling */ + +static void imx9_dispatch(struct imx9_driver_s *priv); +static void imx9_receive(struct imx9_driver_s *priv); +static void imx9_txdone(struct imx9_driver_s *priv); + +static void imx9_enet_interrupt_work(void *arg); +static int imx9_enet_interrupt(int irq, void *context, void *arg); + +/* Watchdog timer expirations */ + +static void imx9_txtimeout_work(void *arg); +static void imx9_txtimeout_expiry(wdparm_t arg); + +/* NuttX callback functions */ + +static int imx9_ifup(struct net_driver_s *dev); +static int imx9_ifdown(struct net_driver_s *dev); + +static void imx9_txavail_work(void *arg); +static int imx9_txavail(struct net_driver_s *dev); + +/* Internal ifup function that allows phy reset to be optional */ + +static int imx9_ifup_action(struct net_driver_s *dev, bool resetphy); + +#ifdef CONFIG_NET_MCASTGROUP +static int imx9_addmac(struct net_driver_s *dev, const uint8_t *mac); +static int imx9_rmmac(struct net_driver_s *dev, const uint8_t *mac); +#endif + +#ifdef CONFIG_NETDEV_IOCTL +static int imx9_ioctl(struct net_driver_s *dev, int cmd, + unsigned long arg); +#endif + +/* PHY/MII support */ + +static int imx9_phy_is(struct imx9_driver_s *priv, const char *name); +static int imx9_determine_phy(struct imx9_driver_s *priv); + +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +static int imx9_phyintenable(struct imx9_driver_s *priv); +#endif +static inline void imx9_initmii(struct imx9_driver_s *priv); +static int imx9_writemii(struct imx9_driver_s *priv, uint8_t regaddr, + uint16_t data); +static int imx9_readmii(struct imx9_driver_s *priv, uint8_t regaddr, + uint16_t *data); +static int imx9_initphy(struct imx9_driver_s *priv, bool renogphy); + +static int imx9_readmmd(struct imx9_driver_s *priv, uint8_t mmd, + uint16_t regaddr, uint16_t *data); +#if 0 +static int imx9_writemmd(struct imx9_driver_s *priv, uint8_t mmd, + uint16_t regaddr, uint16_t data); +#endif + +/* Initialization */ + +static void imx9_initbuffers(struct imx9_driver_s *priv); +static void imx9_reset(struct imx9_driver_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_IMX9_ENET1 + +/* If the board didn't provide a list of known PHYs, we can still work with + * autonegotiation disabled and setting the speed manually + */ + +#ifndef BOARD_ENET1_PHY_LIST +#define BOARD_ENET1_PHY_LIST {} +#endif + +static const struct phy_desc_s g_enet1_phy_list[] = BOARD_ENET1_PHY_LIST; + +/* The DMA descriptors */ + +static struct enet_txdesc_s g_enet1_tx_desc_pool[IMX9_ENET_NTXBUFFERS] + aligned_data(ENET_ALIGN); +static struct enet_desc_s g_enet1_rx_desc_pool[IMX9_ENET_NRXBUFFERS] + aligned_data(ENET_ALIGN); + +/* The DMA buffers */ + +static uint8_t g_enet_1_buffer_pool + [IMX9_ENET_NTXBUFFERS + IMX9_ENET_NRXBUFFERS][ALIGNED_BUFSIZE] + aligned_data(ENET_ALIGN); +#endif + +static struct imx9_driver_s g_enet[] = +{ +#ifdef CONFIG_IMX9_ENET1 + { + .dev = + { + .d_ifup = imx9_ifup, + .d_ifdown = imx9_ifdown, + .d_txavail = imx9_txavail, + +# ifdef CONFIG_NET_MCASTGROUP + .d_addmac = imx9_addmac, + .d_rmmac = imx9_rmmac, +# endif + +# ifdef CONFIG_NETDEV_IOCTL + .d_ioctl = imx9_ioctl, +# endif + }, + .base = IMX9_ENET_BASE, + .clk_gate = CCM_LPCG_ENET1, + .irq = IMX9_IRQ_ENET, + .phy_list = g_enet1_phy_list, + .n_phys = nitems(g_enet1_phy_list), + .txdesc = g_enet1_tx_desc_pool, + .rxdesc = g_enet1_rx_desc_pool, + .buffer_pool = (const uintptr_t)g_enet_1_buffer_pool, + +# ifdef CONFIG_IMX9_ENET_USE_OTP_MAC + .otp_mac_off = CONFIG_IMX9_ENET1_OTP_MAC_ADDR, +# endif + +# ifdef CONFIG_IMX9_ENET1_PROMISCUOUS + .promiscuous = trued +# endif + +# ifdef CONFIG_IMX9_ENET1_RGMII + .phy_type = PHY_RGMII, +# elif defined(CONFIG_IMX9_ENET1_RMII) + .phy_type = PHY_RMII, +# else +# error PHY must be RGMII or RMII +# endif + + /* Duplex: default to FD */ + +# if defined(CONFIG_IMX9_ENET1_PHY_FD) || defined(CONFIG_IMX9_ENET1_PHY_AUTONEG) + .full_duplex = true, +# endif + + /* 10 mbps, default to false */ + +# ifdef CONFIG_IMX9_ENET1_PHY_10MBPS + .s_10mbps = true, +# endif + + /* 100 mbps, default to true */ + +# if defined(CONFIG_IMX9_ENET1_PHY_100MBPS) || defined(CONFIG_IMX9_ENET1_PHY_AUTONEG) + .s_100mbps = true, +# endif + + /* 1000 mbps, default to false */ + +# ifdef CONFIG_IMX9_ENET1_PHY_1000MBPS + .s_1000mbps = true, +# endif + +# ifdef CONFIG_IMX9_ENET1_PHY_AUTONEG + .autoneg = true, +# else +# ifdef CONFIG_IMX9_ENET1_PHY_FORCE_SPEED + .force_speed = true, +# endif +# endif + }, +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_enet_getreg32 + * + * Description: + * Get the contents of the ENET register at offset + * + * Input Parameters: + * priv - private ENET device structure + * offset - offset to the register of interest + * + * Returned Value: + * The contents of the 32-bit register + * + ****************************************************************************/ + +static inline uint32_t imx9_enet_getreg32(struct imx9_driver_s *priv, + uint32_t offset) +{ + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: imx9_enet_putreg32 + * + * Description: + * Atomically modify the specified bits in a memory mapped register + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * clearbits - the 32-bit value to be written as 0s + * setbits - the 32-bit value to be written as 1s + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void imx9_enet_modifyreg32(struct imx9_driver_s *priv, + unsigned int offset, + uint32_t clearbits, + uint32_t setbits) +{ + modifyreg32(priv->base + offset, clearbits, setbits); +} + +/**************************************************************************** + * Name: imx9_enet_putreg32 + * + * Description: + * Write a 16-bit value to the ENET register at offset + * + * Input Parameters: + * priv - private SPI device structure + * value - the 32-bit value to be written + * offset - offset to the register of interest + * + * Returned Value: + * The contents of the 32-bit register + * + ****************************************************************************/ + +static inline void imx9_enet_putreg32(struct imx9_driver_s *priv, + uint32_t value, uint32_t offset) +{ + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * Function: dump_descriptor + * + * Description: + * Can be used for debugging; dumps the content of a DMA descriptor + * + * Input Parameters: + * desc - Pointer to DMA descriptor + * + * Returned Value: + * None + * + ****************************************************************************/ + +inline static void dump_descriptor(struct enet_desc_s *desc) +{ + _alert("length %d\n", desc->length); + _alert("status1 0x%04x\n", desc->status1); + _alert("data 0x%08x\n", desc->data); + _alert("status2 0x%08x\n", desc->status2); + _alert("checksum 0x%08x\n", desc->checksum); + _alert("lenproto 0x%08x\n", desc->lenproto); + _alert("bdu 0x%08x\n", desc->bdu); + _alert("timestamp 0x%08x\n", desc->timestamp); +} + +/**************************************************************************** + * Function: imx9_txringfull + * + * Description: + * Check if all of the TX descriptors are in use. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * true is the TX ring is full; false if there are free slots at the + * head index. + * + ****************************************************************************/ + +static bool imx9_txringfull(struct imx9_driver_s *priv) +{ + struct enet_desc_s *txdesc = &priv->txdesc[priv->txhead].d1; + struct enet_desc_s *txdesc2 = &priv->txdesc[priv->txhead].d2; + + up_invalidate_dcache((uintptr_t)txdesc, + (uintptr_t)txdesc + sizeof(struct enet_txdesc_s)); + + return (txdesc2->status1 & TXDESC_R) != 0; +} + +/**************************************************************************** + * Function: imx9_transmit + * + * Description: + * Start hardware transmission. Called either from the txdone interrupt + * handling or from watchdog based polling. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int imx9_transmit(struct imx9_driver_s *priv, uint32_t *buf_swap) +{ + struct enet_desc_s *txdesc = &priv->txdesc[priv->txhead].d1; + struct enet_desc_s *txdesc2 = &priv->txdesc[priv->txhead].d2; + int split; + uint32_t buf = (uintptr_t)priv->dev.d_buf; + int len = priv->dev.d_len; + + DEBUGASSERT(len > 0 && buf != 0); + DEBUGASSERT((buf & ENET_ALIGN_MASK) == 0); + + if (imx9_txringfull(priv)) + { + /* Ring is full; this can only happen if transmit is called directly + * from the receive path. The buffer is lost. + */ + + nerr("TX ring full, packet lost\n"); + NETDEV_TXERRORS(&priv->dev); + return -EBUSY; + } + + if (len > ALIGNED_BUFSIZE) + { + nerr("TX frame too large %d, max %d\n", len, + ALIGNED_BUFSIZE); + } + + /* We are done with the provided buffer after transmit */ + + priv->dev.d_buf = NULL; + priv->dev.d_len = 0; + + /* Increment statistics */ + + NETDEV_TXPACKETS(&priv->dev); + + /* Optimize the two-descriptor usage; if possible, align the second part + * on 64-byte boundary. Note that 0-length buffers are not accepted by + * the DMA, so we must put some data to both descriptors. + */ + + split = len > 64 ? 64 : 1; + + txdesc->length = split; + txdesc->status2 = TXDESC_TS /* | TXDESC_IINS | TXDESC_PINS */; + txdesc->bdu = 0x00000000; + + txdesc2->length = len - split; + txdesc2->status2 = TXDESC_TS | TXDESC_INT /* | TXDESC_IINS | TXDESC_PINS */; + txdesc2->bdu = 0x00000000; + + if (buf_swap) + { + /* Data was written into the RX buffer, so swap the TX and RX buffers */ + + DEBUGASSERT(*buf_swap == buf); + *buf_swap = txdesc->data; + txdesc->data = buf; + } + else + { + DEBUGASSERT(txdesc->data == buf); + } + + txdesc2->data = buf + split; + + ARM64_DSB(); + + /* Make sure the buffer data is in memory */ + + up_clean_dcache(buf, buf + len); + + /* Descriptors & buffer data are ready to send */ + + txdesc2->status1 = (txdesc2->status1 & TXDESC_W) | + (TXDESC_TC | TXDESC_L | TXDESC_R); + + /* Proceed to next descriptors */ + + priv->txhead++; + if (priv->txhead >= IMX9_ENET_NTXBUFFERS) + { + priv->txhead = 0; + } + + /* If all TX descriptors are in-flight, then we have to disable receive + * interrupts too. This is because receive events can trigger more un- + * stoppable transmit events. + */ + + if (imx9_txringfull(priv)) + { + priv->ints &= ~RX_INTERRUPTS; + } + + /* Enable TX interrupts */ + + priv->ints |= TX_INTERRUPTS; + imx9_enet_putreg32(priv, priv->ints, IMX9_ENET_EIMR_OFFSET); + + /* The latter descriptor was update first. This ensures that the DMA + * won't start before all the descriptor data has been updated and it + * is safe to clean the cache + */ + + ARM64_DMB(); + txdesc->status1 = TXDESC_R; + ARM64_DSB(); + + /* Make sure the descriptors are written from cache to memory */ + + up_clean_dcache((uintptr_t)txdesc, + (uintptr_t)txdesc + sizeof(struct enet_txdesc_s)); + + /* Start the TX transfer (if it was not already waiting for buffers) */ + + imx9_enet_putreg32(priv, ENET_TDAR, IMX9_ENET_TDAR_OFFSET); + + /* Setup the TX timeout watchdog (perhaps restarting the timer) */ + + wd_start(&priv->txtimeout, IMX9_TXTIMEOUT, + imx9_txtimeout_expiry, (wdparm_t)priv); + + return OK; +} + +/**************************************************************************** + * Function: imx9_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. When the preceding TX packet send timesout and the interface is reset + * 3. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int imx9_txpoll(struct net_driver_s *dev) +{ + struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; + + /* Send the packet */ + + imx9_transmit(priv, NULL); + + /* Check if the next TX descriptor is owned by the Ethernet DMA or + * CPU. We cannot perform the TX poll if we are unable to accept + * another packet for transmission. + */ + + if (imx9_txringfull(priv)) + { + return -EBUSY; + } + + /* Return 0 to continue polling */ + + return 0; +} + +/**************************************************************************** + * Function: imx9_dopoll + * + * Description: + * The function is called in order to perform an out-of-sequence TX poll. + * This is done: + * + * 1. After completion of a transmission (stm32_txdone), + * 2. When new TX data is available (stm32_txavail_process), and + * 3. After a TX timeout to restart the sending process + * (stm32_txtimeout_process). + * + * Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void imx9_dopoll(struct imx9_driver_s *priv) +{ + struct net_driver_s *dev = &priv->dev; + struct enet_desc_s *txdesc; + struct enet_desc_s *txdesc2; + + /* Check if the next TX descriptor is owned by the Ethernet DMA or + * CPU. We cannot perform the TX poll if we are unable to accept + * another packet for transmission. + */ + + if (!imx9_txringfull(priv)) + { + DEBUGASSERT(dev->d_len == 0 && dev->d_buf == NULL); + + txdesc = &priv->txdesc[priv->txhead].d1; + txdesc2 = &priv->txdesc[priv->txhead].d2; + + /* Debug: check for any errors in the previously sent descriptors. + * Note: cache line was invalidated in the imx9_txringfull already + */ + + if ((txdesc->status2 & TXDESC_STATUS2_ERRORS) != 0) + { + nerr("d1 status1 %x, status2 %x\n", txdesc->status1 & TXDESC_TXE, + txdesc->status2 & TXDESC_STATUS2_ERRORS); + } + + if ((txdesc2->status2 & TXDESC_STATUS2_ERRORS) != 0) + { + nerr("d2 status1 %x, status2 %x\n", txdesc2->status1 & TXDESC_TXE, + txdesc2->status2 & TXDESC_STATUS2_ERRORS); + } + + /* Poll for new data */ + + dev->d_buf = (uint8_t *)(uintptr_t)txdesc->data; + devif_poll(dev, imx9_txpoll); + dev->d_buf = NULL; + dev->d_len = 0; + } + else + { + nerr("TX ring full\n"); + } +} + +/**************************************************************************** + * Function: imx9_dispatch + * + * Description: + * A new Rx packet was received; dispatch that packet to the network layer + * as necessary. + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static inline void imx9_dispatch(struct imx9_driver_s *priv) +{ + /* Update statistics */ + + NETDEV_RXPACKETS(&priv->dev); + +#ifdef CONFIG_NET_PKT + /* When packet sockets are enabled, feed the frame into the tap */ + + pkt_input(&priv->dev); +#endif + +#ifdef CONFIG_NET_IPv4 + /* Check for an IPv4 packet */ + + if (BUF->type == HTONS(ETHTYPE_IP)) + { + ninfo("IPv4 frame\n"); + NETDEV_RXIPV4(&priv->dev); + + /* Receive an IPv4 packet from the network device */ + + ipv4_input(&priv->dev); + } + else +#endif +#ifdef CONFIG_NET_IPv6 + /* Check for an IPv6 packet */ + + if (BUF->type == HTONS(ETHTYPE_IP6)) + { + ninfo("IPv6 frame\n"); + NETDEV_RXIPV6(&priv->dev); + + /* Give the IPv6 packet to the network layer */ + + ipv6_input(&priv->dev); + } + else +#endif +#ifdef CONFIG_NET_ARP + /* Check for an ARP packet */ + + if (BUF->type == HTONS(ETHTYPE_ARP)) + { + NETDEV_RXARP(&priv->dev); + arp_input(&priv->dev); + } +#endif + else + { + priv->dev.d_buf = NULL; + priv->dev.d_len = 0; + NETDEV_RXDROPPED(&priv->dev); + } +} + +inline static bool imx9_rxdesc_full(struct enet_desc_s *rxdesc) +{ + up_invalidate_dcache((uintptr_t)rxdesc, + (uintptr_t)rxdesc + sizeof(struct enet_desc_s)); + + /* Check if the data buffer associated with the descriptor has + * been filled or reception terminated for errors + */ + + return (rxdesc->status1 & RXDESC_E) == 0; +} + +/**************************************************************************** + * Function: imx9_receive + * + * Description: + * An interrupt was received indicating the availability of a new RX packet + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void imx9_receive(struct imx9_driver_s *priv) +{ + static uint32_t swap_data[2]; + int tail = priv->rxtail; + int swap_d_n; + struct enet_desc_s *rxdesc; + bool received; + + /* Loop while there are received packets to be processed */ + + do + { + rxdesc = &priv->rxdesc[tail]; + received = imx9_rxdesc_full(rxdesc); + if (received) + { + /* Copy the buffer pointer to priv->dev.d_buf. Set amount of data + * in priv->dev.d_len + */ + + DEBUGASSERT(priv->dev.d_buf == NULL); + + if ((rxdesc->status1 & RXDESC_STATUS1_ERRORS) != 0 || + (rxdesc->status2 & RXDESC_STATUS2_ERRORS) != 0) + { + nerr("status1 %x, status2 %x", + rxdesc->status1 & RXDESC_STATUS1_ERRORS, + rxdesc->status2 & RXDESC_STATUS2_ERRORS); + } + + DEBUGASSERT(rxdesc->length > 0 && + ((uintptr_t)rxdesc->data & ENET_ALIGN_MASK) == 0); + + priv->dev.d_len = rxdesc->length; + priv->dev.d_buf = (uint8_t *)(uintptr_t)rxdesc->data; + + /* Invalidate the buffer so that the correct packet will be re-read + * from memory when the packet content is accessed. + */ + + up_invalidate_dcache((uintptr_t)priv->dev.d_buf, + (uintptr_t)priv->dev.d_buf + priv->dev.d_len); + + /* Dispatch (or drop) the newly received packet */ + + imx9_dispatch(priv); + + /* If the dispatch resulted in data that should + * be sent out on the network, the field d_len will set to a + * value > 0. In this case imx9_transmit will just directly use + * the provided buffer to transmit, and swap the rx / tx buffers + */ + + swap_d_n = tail & 1; + swap_data[swap_d_n] = rxdesc->data; + if (priv->dev.d_len > 0) + { + /* And send the packet */ + + imx9_transmit(priv, &swap_data[swap_d_n]); + + /* Assume that the upper levels didn't write to the tx buffer + * beyond the d_len, so the transmit buffer cache is clean. + * If this wouldn't be the case, we'd have to invalidate here! + * up_invalidate_dcache(swap_data[swap_d_n], + * swap_data[swap_d_n] + ALIGNED_BUFSIZE); + */ + } + + /* We are done with the buffers - let's not leave the pointers + * laying around + */ + + priv->dev.d_buf = NULL; + priv->dev.d_len = 0; + + /* RX descriptor size is 32 bytes, but the cache line size is 64. + * This means that we can only free the rx descriptors in pairs. + * If we are the second descriptor of the pair, we update both + */ + + if (swap_d_n == 1) + { + /* First update the second descriptor - RX DMA may not start + * before both are updated + */ + + rxdesc->data = swap_data[1]; + rxdesc->length = 0; + rxdesc->status2 = RXDESC_INT; + rxdesc->bdu = 0x00000000; + rxdesc->status1 = (rxdesc->status1 & RXDESC_W) | RXDESC_E; + + /* Now update the first descriptor of the pair */ + + rxdesc -= 1; + rxdesc->data = swap_data[0]; + rxdesc->length = 0; + rxdesc->status2 = RXDESC_INT; + rxdesc->bdu = 0x00000000; + + /* Make sure both descriptors are fully updated before updating + * the first descriptor's status1; this allows DMA to proceed + * to this descriptor pair. + */ + + ARM64_DMB(); + rxdesc->status1 = RXDESC_E; + ARM64_DSB(); + + up_clean_dcache((uintptr_t)&rxdesc[(-1)], + (uintptr_t)&rxdesc[(-1)] + + 2 * sizeof(rxdesc[0])); + + /* Indicate that we produced empty receive buffers */ + + imx9_enet_putreg32(priv, ENET_RDAR, IMX9_ENET_RDAR_OFFSET); + } + + tail++; + if (tail >= IMX9_ENET_NRXBUFFERS) + { + tail = 0; + } + } + } + while (received); + + /* Update the index to the next empty descriptor */ + + priv->rxtail = tail; +} + +/**************************************************************************** + * Function: imx9_txdone + * + * Description: + * An interrupt was received indicating that the last TX packet(s) is done + * + * Input Parameters: + * priv - Reference to the driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * The network is locked. + * + ****************************************************************************/ + +static void imx9_txdone(struct imx9_driver_s *priv) +{ + DEBUGASSERT(priv->dev.d_len == 0 && priv->dev.d_buf == NULL); + + /* Cancel the timeout watchdog */ + + wd_cancel(&priv->txtimeout); + + /* Update statistics */ + + NETDEV_TXDONE(&priv->dev); + + priv->ints |= RX_INTERRUPTS; + imx9_enet_putreg32(priv, priv->ints, IMX9_ENET_EIMR_OFFSET); + + /* Poll the network for new XMIT data */ + + imx9_dopoll(priv); +} + +/**************************************************************************** + * Function: imx9_enet_interrupt_work + * + * Description: + * Perform interrupt related work from the worker thread + * + * Input Parameters: + * arg - The argument passed when work_queue() was called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static void imx9_enet_interrupt_work(void *arg) +{ + struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; + uint32_t pending; +#ifdef CONFIG_NET_MCASTGROUP + uint32_t gaurstore; + uint32_t galrstore; +#endif + + /* Process pending Ethernet interrupts */ + + net_lock(); + + /* Get the set of unmasked, pending interrupt. */ + + pending = imx9_enet_getreg32(priv, IMX9_ENET_EIR_OFFSET) & priv->ints; + + /* Clear the pending interrupts */ + + imx9_enet_putreg32(priv, pending, IMX9_ENET_EIR_OFFSET); + + /* Check for errors */ + + if (pending & ERROR_INTERRUPTS) + { + /* An error has occurred, update statistics */ + + NETDEV_ERRORS(&priv->dev); + + nerr("pending %" PRIx32 " ints %" PRIx32 "\n", pending, priv->ints); + } + + if (pending & CRITICAL_ERROR) + { + nerr("Critical error, restarting Ethernet interface\n"); + + /* Bring the Ethernet chip down and back up but with no need to + * reset/renegotiate the phy. + */ + +#ifdef CONFIG_NET_MCASTGROUP + /* Just before we pull the rug lets make sure we retain the + * multicast hash table. + */ + + gaurstore = imx9_enet_getreg32(priv, IMX9_ENET_GAUR_OFFSET); + galrstore = imx9_enet_getreg32(priv, IMX9_ENET_GALR_OFFSET); +#endif + + imx9_ifdown(&priv->dev); + imx9_ifup_action(&priv->dev, false); + +#ifdef CONFIG_NET_MCASTGROUP + /* Now write the multicast table back */ + + imx9_enet_putreg32(priv, gaurstore, IMX9_ENET_GAUR_OFFSET); + imx9_enet_putreg32(priv, galrstore, IMX9_ENET_GALR_OFFSET); +#endif + + /* Then poll the network for new XMIT data */ + + imx9_dopoll(priv); + } + else + { + /* Check for the receipt of a packet */ + + if ((pending & ENET_INT_RXF) != 0) + { + /* A packet has been received, call imx9_receive() to handle the + * packet. + */ + + imx9_receive(priv); + } + + /* Check if a packet transmission has completed */ + + if ((pending & ENET_INT_TXF) != 0) + { + /* Call imx9_txdone to handle the end of transfer */ + + imx9_txdone(priv); + } + } + + net_unlock(); + + /* Re-enable Ethernet interrupts */ + + imx9_enet_putreg32(priv, priv->ints, IMX9_ENET_EIMR_OFFSET); +} + +/**************************************************************************** + * Function: imx9_enet_interrupt + * + * Description: + * Three interrupt sources will vector to this function: + * 1. Ethernet MAC transmit interrupt handler + * 2. Ethernet MAC receive interrupt handler + * 3. + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + * Assumptions: + * + ****************************************************************************/ + +static int imx9_enet_interrupt(int irq, void *context, void *arg) +{ + register struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; + + /* Mask all the interrupts */ + + imx9_enet_putreg32(priv, 0, IMX9_ENET_EIMR_OFFSET); + + /* Schedule to perform the interrupt processing on the worker thread. */ + + work_queue(ETHWORK, &priv->irqwork, imx9_enet_interrupt_work, priv, 0); + return OK; +} + +/**************************************************************************** + * Function: imx9_txtimeout_work + * + * Description: + * Perform TX timeout related work from the worker thread + * + * Input Parameters: + * arg - The argument passed when work_queue() as called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * + ****************************************************************************/ + +static void imx9_txtimeout_work(void *arg) +{ + struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; + + /* Increment statistics and dump debug info */ + + nerr("Resetting interface\n"); + + /* Take the interface down and bring it back up. That is the most + * aggressive hardware reset. + */ + + NETDEV_TXTIMEOUTS(&priv->dev); + imx9_ifdown(&priv->dev); + imx9_ifup_action(&priv->dev, false); + + /* Then poll the network for new XMIT data */ + + net_lock(); + imx9_dopoll(priv); + net_unlock(); +} + +/**************************************************************************** + * Function: imx9_txtimeout_expiry + * + * Description: + * Our TX watchdog timed out. Called from the timer interrupt handler. + * The last TX never completed. Reset the hardware and start again. + * + * Input Parameters: + * arg - The argument + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * + ****************************************************************************/ + +static void imx9_txtimeout_expiry(wdparm_t arg) +{ + struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; + + /* Disable further Ethernet interrupts. This will prevent some race + * conditions with interrupt work. + */ + + imx9_enet_putreg32(priv, 0, IMX9_ENET_EIMR_OFFSET); + priv->ints = 0; + + /* Schedule to perform the TX timeout processing on the worker thread, + * canceling any pending interrupt work. + */ + + work_queue(ETHWORK, &priv->irqwork, imx9_txtimeout_work, priv, 0); +} + +/**************************************************************************** + * Function: imx9_ifup_action + * + * Description: + * Internal action routine to bring up the Ethernet interface + * which makes the resetting of the phy (which takes considerable time) + * optional. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * resetphy - Flag indicating if Phy is to be reset. If not then the + * phy configuration is just re-loaded into the ethernet + * interface + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int imx9_ifup_action(struct net_driver_s *dev, bool resetphy) +{ + struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; + uint8_t *mac = dev->d_mac.ether.ether_addr_octet; + uint32_t ecr; + int ret; + + ninfo("Bringing up: %u.%u.%u.%u\n", + ip4_addr1(dev->d_ipaddr), ip4_addr2(dev->d_ipaddr), + ip4_addr3(dev->d_ipaddr), ip4_addr4(dev->d_ipaddr)); + + /* Initialize ENET buffers */ + + imx9_initbuffers(priv); + + /* Configure the MII interface */ + + imx9_initmii(priv); + + /* Take MAC out of reset */ + + ecr = ENET_ECR_EN1588 | ENET_ECR_DBSWP; + imx9_enet_putreg32(priv, ecr, IMX9_ENET_ECR_OFFSET); + + /* Enable store and forward mode */ + + imx9_enet_putreg32(priv, ENET_TFWR_STRFWD, IMX9_ENET_TFWR_OFFSET); + + /* Set the MAC address */ + + imx9_enet_putreg32(priv, (mac[0] << 24) | (mac[1] << 16) | + (mac[2] << 8) | mac[3], IMX9_ENET_PALR_OFFSET); + imx9_enet_putreg32(priv, (mac[4] << 24) | (mac[5] << 16), + IMX9_ENET_PAUR_OFFSET); + + /* Configure the PHY */ + + ret = imx9_determine_phy(priv); + if (ret < 0) + { + nwarn("Unrecognized PHY\n"); + } + + ret = imx9_initphy(priv, resetphy); + if (ret < 0) + { + nerr("ERROR: Failed to configure the PHY: %d\n", ret); + return ret; + } + + /* Set the RX buffer size */ + + imx9_enet_putreg32(priv, ALIGNED_BUFSIZE, IMX9_ENET_MRBR_OFFSET); + + /* Point to the start of the circular RX buffer descriptor queue */ + + imx9_enet_putreg32(priv, (uint32_t)(uintptr_t)priv->rxdesc, + IMX9_ENET_RDSR_OFFSET); + + /* Point to the start of the circular TX buffer descriptor queue */ + + imx9_enet_putreg32(priv, (uint32_t)(uintptr_t)priv->txdesc, + IMX9_ENET_TDSR_OFFSET); + + /* Mask and clear all ENET interrupts */ + + imx9_enet_putreg32(priv, 0, IMX9_ENET_EIMR_OFFSET); + + imx9_enet_putreg32(priv, 0xffffffff, IMX9_ENET_EIR_OFFSET); + + /* Set 1GBPS if link is set to that */ + + if (priv->s_1000mbps) + { + ecr |= ENET_ECR_SPEED; + } + + /* And enable the MAC */ + + ecr |= ENET_ECR_ETHEREN; + + imx9_enet_putreg32(priv, ecr, IMX9_ENET_ECR_OFFSET); + + /* Enable RX and error interrupts at the controller */ + + priv->ints = RX_INTERRUPTS | ERROR_INTERRUPTS; + imx9_enet_putreg32(priv, priv->ints, IMX9_ENET_EIMR_OFFSET); + + /* Mark the interface "up" and enable interrupts */ + + priv->bifup = true; + up_enable_irq(priv->irq); + + /* Indicate that there have been empty receive buffers produced */ + + imx9_enet_putreg32(priv, ENET_RDAR, IMX9_ENET_RDAR_OFFSET); + + return OK; +} + +/**************************************************************************** + * Function: imx9_ifup + * + * Description: + * NuttX Callback: Bring up the Ethernet interface when an IP address is + * provided + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int imx9_ifup(struct net_driver_s *dev) +{ + /* The externally available ifup action includes resetting the phy */ + + return imx9_ifup_action(dev, true); +} + +/**************************************************************************** + * Function: imx9_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int imx9_ifdown(struct net_driver_s *dev) +{ + struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; + + ninfo("Taking down: %u.%u.%u.%u\n", + ip4_addr1(dev->d_ipaddr), ip4_addr2(dev->d_ipaddr), + ip4_addr3(dev->d_ipaddr), ip4_addr4(dev->d_ipaddr)); + + /* Cancel the TX timeout timers */ + + wd_cancel(&priv->txtimeout); + + /* Flush and disable the Ethernet interrupts */ + + up_disable_irq(priv->irq); + + imx9_enet_putreg32(priv, 0, IMX9_ENET_EIMR_OFFSET); + priv->ints = 0; + + /* Put the EMAC in its reset, non-operational state. This should be + * a known configuration that will guarantee the imx9_ifup() always + * successfully brings the interface back up. + */ + + imx9_reset(priv); + + /* Clear any pending interrupts */ + + imx9_enet_putreg32(priv, 0xffffffff, IMX9_ENET_EIR_OFFSET); + + /* Mark the device "down" */ + + priv->bifup = false; + + return OK; +} + +/**************************************************************************** + * Function: imx9_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void imx9_txavail_work(void *arg) +{ + struct imx9_driver_s *priv = (struct imx9_driver_s *)arg; + + /* Ignore the notification if the interface is not yet up */ + + net_lock(); + if (priv->bifup) + { + /* Poll the network for new XMIT data */ + + imx9_dopoll(priv); + } + + net_unlock(); +} + +/**************************************************************************** + * Function: imx9_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int imx9_txavail(struct net_driver_s *dev) +{ + struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; + + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&priv->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(ETHWORK, &priv->pollwork, imx9_txavail_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Function: imx9_calcethcrc + * + * Description: + * Function to calculate the CRC used by IMX9 to check an Ethernet frame + * + * Input Parameters: + * data - the data to be checked + * length - length of the data + * + * Returned Value: + * crc32 + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_MCASTGROUP +static uint32_t imx9_calcethcrc(const uint8_t *data, size_t length) +{ + uint32_t crc = 0xffffffffu; + uint32_t count1 = 0; + uint32_t count2 = 0; + + /* Calculates the CRC-32 polynomial on the multicast group address. */ + + for (count1 = 0; count1 < length; count1++) + { + uint8_t c = data[count1]; + + for (count2 = 0; count2 < 0x08u; count2++) + { + if ((c ^ crc) & 1U) + { + crc >>= 1U; + c >>= 1U; + crc ^= 0xedb88320u; + } + else + { + crc >>= 1U; + c >>= 1U; + } + } + } + + return crc; +} +#endif + +/**************************************************************************** + * Function: imx9_enet_hash_index + * + * Description: + * Function to find the hash index for multicast address filter + * + * Input Parameters: + * mac - The MAC address + * + * Returned Value: + * hash index + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_MCASTGROUP +static uint32_t imx9_enet_hash_index(const uint8_t *mac) +{ + uint32_t crc; + uint32_t hashindex; + + ninfo("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + crc = imx9_calcethcrc(mac, 6); + hashindex = (crc >> 26) & 0x3f; + + return hashindex; +} +#endif + +/**************************************************************************** + * Function: imx9_addmac + * + * Description: + * NuttX Callback: Add the specified MAC address to the hardware multicast + * address filtering + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be added + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_MCASTGROUP +static int imx9_addmac(struct net_driver_s *dev, const uint8_t *mac) +{ + uint32_t hashindex; + uint32_t temp; + uint32_t registeraddress; + struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; + + hashindex = imx9_enet_hash_index(mac); + + /* Add the MAC address to the hardware multicast routing table */ + + if (hashindex > 31) + { + registeraddress = IMX9_ENET_GAUR_OFFSET; + hashindex -= 32; + } + else + { + registeraddress = IMX9_ENET_GALR_OFFSET; + } + + temp = imx9_enet_getreg32(priv, registeraddress); + temp |= 1 << hashindex; + imx9_enet_putreg32(priv, temp, registeraddress); + + return OK; +} +#endif + +/**************************************************************************** + * Function: imx9_rmmac + * + * Description: + * NuttX Callback: Remove the specified MAC address from the hardware + * multicast address filtering + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be removed + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_MCASTGROUP +static int imx9_rmmac(struct net_driver_s *dev, const uint8_t *mac) +{ + uint32_t hashindex; + uint32_t temp; + uint32_t registeraddress; + struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; + + /* Remove the MAC address from the hardware multicast routing table */ + + hashindex = imx9_enet_hash_index(mac); + + if (hashindex > 31) + { + registeraddress = IMX9_ENET_GAUR_OFFSET; + hashindex -= 32; + } + else + { + registeraddress = IMX9_ENET_GALR_OFFSET; + } + + temp = imx9_enet_getreg32(priv, registeraddress); + temp &= ~(1 << hashindex); + imx9_enet_putreg32(priv, temp, registeraddress); + + return OK; +} +#endif + +/**************************************************************************** + * Function: imx9_ioctl + * + * Description: + * PHY ioctl command handler + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - ioctl command + * arg - Argument accompanying the command + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int imx9_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) +{ +#ifdef CONFIG_NETDEV_PHY_IOCTL + struct imx9_driver_s *priv = (struct imx9_driver_s *)dev; +#endif + int ret; + + switch (cmd) + { +#ifdef CONFIG_NETDEV_PHY_IOCTL +#ifdef CONFIG_ARCH_PHY_INTERRUPT + case SIOCMIINOTIFY: /* Set up for PHY event notifications */ + { + struct mii_ioctl_notify_s *req = + (struct mii_ioctl_notify_s *)((uintptr_t)arg); + + ret = phy_notify_subscribe(dev->d_ifname, req->pid, &req->event); + if (ret == OK) + { + /* Enable PHY link up/down interrupts */ + + ret = imx9_phyintenable(priv); + } + } + break; +#endif + + case SIOCGMIIPHY: /* Get MII PHY address */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + req->phy_id = priv->phyaddr; + ret = OK; + } + break; + + case SIOCGMIIREG: /* Get register from MII PHY */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + if (priv->cur_phy && priv->cur_phy->clause == 45 && + MII_MSR == req->reg_num) + { + ret = imx9_readmmd(priv, MMD1, MMD1_PMA_STATUS1, + &req->val_out); + } + else + { + ret = imx9_readmii(priv, req->reg_num, &req->val_out); + } + } + break; + + case SIOCSMIIREG: /* Set register in MII PHY */ + { + struct mii_ioctl_data_s *req = + (struct mii_ioctl_data_s *)((uintptr_t)arg); + ret = imx9_writemii(priv, req->reg_num, req->val_in); + } + break; +#endif /* CONFIG_NETDEV_PHY_IOCTL */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Function: imx9_phyintenable + * + * Description: + * Enable link up/down PHY interrupts. The interrupt protocol is like this: + * + * - Interrupt status is cleared when the interrupt is enabled. + * - Interrupt occurs. Interrupt is disabled (at the processor level) when + * is received. + * - Interrupt status is cleared when the interrupt is re-enabled. + * + * Input Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno (-ETIMEDOUT) on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT) +static int imx9_phyintenable(struct imx9_driver_s *priv) +{ + uint16_t phyval; + int ret; + uint16_t mask; + uint8_t rreg; + uint8_t wreg; + + if (imx9_phy_is(priv, MII_YT8512_NAME)) + { + mask = MII_YT8512_IMR_LD_EN | MII_YT8512_IMR_LU_EN; + rreg = MII_YT8512_ISR; + wreg = MII_YT8512_IMR; + } + else if (imx9_phy_is(priv, MII_KSZ8051_NAME) || + imx9_phy_is(priv, MII_KSZ8061_NAME) || + imx9_phy_is(priv, MII_KSZ8081_NAME) || + imx9_phy_is(priv, MII_DP83825I_NAME)) + { + mask = MII_KSZ80X1_INT_LDEN | MII_KSZ80X1_INT_LUEN; + rreg = MII_KSZ8081_INT; + wreg = rreg; + } + else + { + return -ENOSYS; + } + + /* Read the interrupt status register in order to clear any pending + * interrupts + */ + + ret = imx9_readmii(priv, rreg, &phyval); + if (ret == OK) + { + /* Enable link up/down interrupts */ + + ret = imx9_writemii(priv, wreg, mask); + } + + return ret; +} +#endif + +/**************************************************************************** + * Function: imx9_initmii + * + * Description: + * Configure the MII interface + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void imx9_initmii(struct imx9_driver_s *priv) +{ + /* Speed is based on the peripheral (bus) clock; hold time is 2 module + * clock. This hold time value may need to be increased on some platforms + */ + + imx9_enet_putreg32(priv, ENET_MSCR_HOLDTIME_2CYCLES | + IMX9_MII_SPEED << ENET_MSCR_MII_SPEED_SHIFT, + IMX9_ENET_MSCR_OFFSET); +} + +/**************************************************************************** + * Function: imx9_writemii + * + * Description: + * Write a 16-bit value to a PHY register. + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * phyaddr - The PHY address + * regaddr - The PHY register address + * data - The data to write to the PHY register + * + * Returned Value: + * Zero on success, a negated errno value on failure. + * + ****************************************************************************/ + +static int imx9_writemii(struct imx9_driver_s *priv, + uint8_t regaddr, uint16_t data) +{ + int timeout; + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* Initiate the MII Management write */ + + imx9_enet_putreg32(priv, data | + 2 << ENET_MMFR_TA_SHIFT | + (uint32_t)regaddr << ENET_MMFR_RA_SHIFT | + (uint32_t)priv->phyaddr << ENET_MMFR_PA_SHIFT | + ENET_MMFR_OP_WRMII | + 1 << ENET_MMFR_ST_SHIFT, + IMX9_ENET_MMFR_OFFSET); + + /* Wait for the transfer to complete */ + + for (timeout = 0; timeout < MII_MAXPOLLS; timeout++) + { + if ((imx9_enet_getreg32(priv, IMX9_ENET_EIR_OFFSET) & + ENET_INT_MII) != 0) + { + break; + } + } + + /* Check for a timeout */ + + if (timeout == MII_MAXPOLLS) + { + return -ETIMEDOUT; + } + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + return OK; +} + +/**************************************************************************** + * Function: imx9_reademii + * + * Description: + * Read a 16-bit value from a PHY register. + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * regaddr - The PHY register address + * data - A pointer to the location to return the data + * + * Returned Value: + * Zero on success, a negated errno value on failure. + * + ****************************************************************************/ + +static int imx9_readmii(struct imx9_driver_s *priv, + uint8_t regaddr, uint16_t *data) +{ + int timeout; + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* Initiate the MII Management read */ + + imx9_enet_putreg32(priv, 2 << ENET_MMFR_TA_SHIFT | + (uint32_t)regaddr << ENET_MMFR_RA_SHIFT | + (uint32_t)priv->phyaddr << ENET_MMFR_PA_SHIFT | + ENET_MMFR_OP_RDMII | + 1 << ENET_MMFR_ST_SHIFT, + IMX9_ENET_MMFR_OFFSET); + + /* Wait for the transfer to complete */ + + for (timeout = 0; timeout < MII_MAXPOLLS; timeout++) + { + if ((imx9_enet_getreg32(priv, IMX9_ENET_EIR_OFFSET) & + ENET_INT_MII) != 0) + { + break; + } + } + + /* Check for a timeout */ + + if (timeout >= MII_MAXPOLLS) + { + nerr("ERROR: Timed out waiting for transfer to complete\n"); + return -ETIMEDOUT; + } + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* And return the MII data */ + + *data = (uint16_t)(imx9_enet_getreg32(priv, IMX9_ENET_MMFR_OFFSET) & + ENET_MMFR_DATA_MASK); + return OK; +} + +/**************************************************************************** + * Function: imx9_read_phy_status + * + * Description: + * Read the phy status from the current phy + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * + * Returned Value: + * 0 on success, -1 on any error + * + ****************************************************************************/ + +int imx9_read_phy_status(struct imx9_driver_s *priv) +{ + int ret; + int retries; + uint16_t page = 0; + uint16_t prev_page; + uint16_t page_reg; + uint16_t mask; + uint16_t status; + + if (priv->cur_phy == NULL) + { + /* We don't support guessing the link speed based ou our and link + * partner's capabilities. For now, user must manually set the + * speed and duplex if the phy is unknown + */ + + nerr("Unknown PHY, can't read link speed\n"); + return ERROR; + } + + /* Special handling for rtl8211f, which needs to chage page */ + + if (imx9_phy_is(priv, GMII_RTL8211F_NAME)) + { + page_reg = GMII_RTL8211F_PAGSR; + page = 0xa43; + } + + if (page) + { + /* Get current page */ + + ret = imx9_readmii(priv, page_reg, &prev_page); + + /* Set page */ + + if (ret >= 0) + { + ninfo("Changing PHY page from 0x%x to 0x%x\n", prev_page, page); + ret = imx9_writemii(priv, page_reg, page); + if (ret < 0) + { + return ERROR; + } + } + } + + retries = 0; + do + { + status = 0xffff; + ret = imx9_readmii(priv, priv->cur_phy->status, &status); + } + while ((ret < 0 || status == 0xffff) && ++retries < 3); + + if (status != 0xffff) + { + ninfo("%s: PHY status %x: %04x\n", priv->cur_phy->name, + priv->cur_phy->status, status); + + /* Set the current link information */ + + mask = priv->cur_phy->speed_mask; + + priv->full_duplex = (status & priv->cur_phy->duplex) != 0; + priv->s_10mbps = (status & mask) == priv->cur_phy->mbps10; + priv->s_100mbps = (status & mask) == priv->cur_phy->mbps100; + priv->s_1000mbps = (status & mask) == priv->cur_phy->mbps1000; + } + + if (page) + { + /* Restore original page */ + + ninfo("Restoring PHY page to 0x%x\n", prev_page); + imx9_writemii(priv, page_reg, prev_page); + } + + return OK; +} + +/**************************************************************************** + * Function: imx9_determine_phy + * + * Description: + * Uses the board.h supplied PHY list to determine which PHY + * is populated on this board. + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * + * Returned Value: + * Zero on success, a -ENOENT errno value on failure. + * + ****************************************************************************/ + +static int imx9_determine_phy(struct imx9_driver_s *priv) +{ + int i; + uint16_t phydata = 0xffff; + uint8_t last_phyaddr = 0; + int retries; + int ret; + + for (i = 0; i < priv->n_phys; i++) + { + priv->phyaddr = (uint8_t)priv->phy_list[i].address_lo; + last_phyaddr = priv->phy_list[i].address_high == 0xffff ? + priv->phyaddr : + (uint8_t)priv->phy_list[i].address_high; + + for (; priv->phyaddr <= last_phyaddr; priv->phyaddr++) + { + retries = 0; + do + { + nxsig_usleep(100); + phydata = 0xffff; + ret = imx9_readmii(priv, MII_PHYID1, &phydata); + ninfo("phy %s addr %d received PHYID1 %x\n", + priv->phy_list[i].name, priv->phyaddr, + phydata); + } + while ((ret < 0 || phydata == 0xffff) && ++retries < 3); + + if (retries <= 3 && ret == 0 && + phydata == priv->phy_list[i].id1) + { + do + { + nxsig_usleep(100); + phydata = 0xffff; + ret = imx9_readmii(priv, MII_PHYID2, &phydata); + ninfo("phy %s addr %d received PHYID2 %x\n", + priv->phy_list[i].name, priv->phyaddr, + phydata); + } + while ((ret < 0 || phydata == 0xffff) && ++retries < 3); + if (retries <= 3 && ret == 0 && + (phydata & 0xfff0) == + (priv->phy_list[i].id2 & 0xfff0)) + { + priv->cur_phy = & priv->phy_list[i]; + ninfo("Found phy %s addr %d\n", + priv->cur_phy->name, priv->phyaddr); + return OK; + } + } + } + } + + nerr("No PHY found\n"); + + priv->cur_phy = NULL; + return -ENOENT; +} + +/**************************************************************************** + * Function: imx9_phy_is + * + * Description: + * Compares the name with the current selected PHY's name + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * name - a pointer to comapre to. + * + * Returned Value: + * 1 on match, a 0 on no match. + * + ****************************************************************************/ + +static int imx9_phy_is(struct imx9_driver_s *priv, const char *name) +{ + return priv->cur_phy && strcmp(priv->cur_phy->name, name) == 0; +} + +#if 0 +/**************************************************************************** + * Function: imx9_writemmd + * + * Description: + * Write a 16-bit value to a the selected MMD PHY register. + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * mmd - The Selected MMD Space + * regaddr - The PHY register address + * data - The data to write to the PHY register + * + * Returned Value: + * Zero on success, a negated errno value on failure. + * + ****************************************************************************/ + +static int imx9_writemmd(struct imx9_driver_s *priv, + uint8_t mmd, uint16_t regaddr, uint16_t data) +{ + int timeout; + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* Initiate the MMD Management write - Address Phase */ + + imx9_enet_putreg32(priv, + 0 << ENET_MMFR_ST_SHIFT | + ENET_MMFR_OP_WRNOTMII | + (uint32_t)mmd << ENET_MMFR_RA_SHIFT | + (uint32_t)priv->phyaddr << ENET_MMFR_PA_SHIFT | + 2 << ENET_MMFR_TA_SHIFT | + regaddr, + IMX9_ENET_MMFR_OFFSET); + + /* Wait for the transfer to complete */ + + for (timeout = 0; timeout < MII_MAXPOLLS; timeout++) + { + if ((imx9_enet_getreg32(priv, IMX9_ENET_EIR_OFFSET) & + ENET_INT_MII) != 0) + { + break; + } + } + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* Check for a timeout */ + + if (timeout == MII_MAXPOLLS) + { + return -ETIMEDOUT; + } + + /* Initiate the MMD Management write - Data Phase */ + + imx9_enet_putreg32(priv, + 0 << ENET_MMFR_ST_SHIFT | + ENET_MMFR_OP_WRMII | + (uint32_t)mmd << ENET_MMFR_RA_SHIFT | + (uint32_t)priv->phyaddr << ENET_MMFR_PA_SHIFT | + 2 << ENET_MMFR_TA_SHIFT | + data, + IMX9_ENET_MMFR_OFFSET); + + /* Wait for the transfer to complete */ + + for (timeout = 0; timeout < MII_MAXPOLLS; timeout++) + { + if ((imx9_enet_getreg32(priv, IMX9_ENET_EIR_OFFSET) & + ENET_INT_MII) != 0) + { + break; + } + } + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* Check for a timeout */ + + if (timeout == MII_MAXPOLLS) + { + return -ETIMEDOUT; + } + + return OK; +} +#endif + +/**************************************************************************** + * Function: imx9_reademmd + * + * Description: + * Read a 16-bit value from a PHY register. + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * mmd - The Selected MMD Space + * regaddr - The PHY register address + * data - A pointer to the location to return the data + * + * Returned Value: + * Zero on success, a negated errno value on failure. + * + ****************************************************************************/ + +static int imx9_readmmd(struct imx9_driver_s *priv, + uint8_t mmd, uint16_t regaddr, uint16_t *data) +{ + int timeout; + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* Initiate the MMD Management read - Address Phase */ + + imx9_enet_putreg32(priv, + 0 << ENET_MMFR_ST_SHIFT | + ENET_MMFR_OP_WRNOTMII | + (uint32_t)mmd << ENET_MMFR_RA_SHIFT | + (uint32_t)priv->phyaddr << ENET_MMFR_PA_SHIFT | + 2 << ENET_MMFR_TA_SHIFT | + regaddr, + IMX9_ENET_MMFR_OFFSET); + + /* Wait for the transfer to complete */ + + for (timeout = 0; timeout < MII_MAXPOLLS; timeout++) + { + if ((imx9_enet_getreg32(priv, IMX9_ENET_EIR_OFFSET) & + ENET_INT_MII) != 0) + { + break; + } + } + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* Check for a timeout */ + + if (timeout >= MII_MAXPOLLS) + { + nerr("ERROR: Timed out waiting for transfer to complete\n"); + return -ETIMEDOUT; + } + + /* Initiate the MMD Management read - Data Phase */ + + imx9_enet_putreg32(priv, + 0 << ENET_MMFR_ST_SHIFT | + ENET_MMFR_OP_RDNOTMII | + (uint32_t)mmd << ENET_MMFR_RA_SHIFT | + (uint32_t)priv->phyaddr << ENET_MMFR_PA_SHIFT | + 2 << ENET_MMFR_TA_SHIFT, + IMX9_ENET_MMFR_OFFSET); + + /* Wait for the transfer to complete */ + + for (timeout = 0; timeout < MII_MAXPOLLS; timeout++) + { + if ((imx9_enet_getreg32(priv, IMX9_ENET_EIR_OFFSET) & + ENET_INT_MII) != 0) + { + break; + } + } + + /* Clear the MII interrupt bit */ + + imx9_enet_putreg32(priv, ENET_INT_MII, IMX9_ENET_EIR_OFFSET); + + /* Check for a timeout */ + + if (timeout == MII_MAXPOLLS) + { + return -ETIMEDOUT; + } + + /* And return the MII data */ + + *data = (uint16_t)(imx9_enet_getreg32(priv, IMX9_ENET_MMFR_OFFSET) & + ENET_MMFR_DATA_MASK); + return OK; +} + +int imx9_reset_phy(struct imx9_driver_s *priv) +{ + int timeout; + int ret; + int result; + uint16_t mcr; + + /* Reset the PHY */ + + ret = imx9_writemii(priv, MII_MCR, MII_MCR_RESET); + + if (ret < 0) + { + nerr("ERROR: mpfs_phywrite failed: %d\n", ret); + } + + /* Wait for the PHY reset to complete */ + + ret = -ETIMEDOUT; + for (timeout = 0; timeout < PHY_RESET_WAIT_COUNT; timeout++) + { + nxsig_usleep(100); + result = imx9_readmii(priv, MII_MCR, &mcr); + if (result < 0) + { + nerr("ERROR: Failed to read the MCR register: %d\n", ret); + ret = result; + } + else if ((mcr & MII_MCR_RESET) == 0) + { + ninfo("MII reset complete: %x\n", mcr); + ret = OK; + break; + } + else + { + nerr("MCR data %x\n", mcr); + } + } + + return ret; +} + +/**************************************************************************** + * Function: imx9_phy_set_speed + * + * Description: + * Set or start to autonegotiate the link speed + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * autonegotiate - true: autonegotiate with default advertisement + * false: autonegotiate, but disable other speeds + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on any + * failure; + * + * Assumptions: + * + ****************************************************************************/ + +static int imx9_phy_set_speed(struct imx9_driver_s *priv, bool autonegotiate) +{ + uint16_t advertise; + uint16_t mcr; + uint16_t force_mcr; + uint16_t btcr; + int ret; + + /* Read initial MCR and take link down */ + + ret = imx9_readmii(priv, MII_MCR, &mcr); + + if (ret < 0) + { + nerr("ERROR: Failed to read MCR register: %d\n", ret); + return ret; + } + + ret = imx9_writemii(priv, MII_MCR, mcr | MII_MCR_PDOWN); + + /* If we are trying to manually set the speed, disable advertisement of the + * other ones. In case we want to force the speed setting on the PHY, + * set the speed in MCR and disable autonegotiation completely. + */ + + force_mcr = mcr; + if (!autonegotiate) + { + /* Read the Auto_negotiation Advertisement Register defaults */ + + ret = imx9_readmii(priv, MII_ADVERTISE, &advertise); + + if (ret < 0) + { + nerr("ERROR: Failed to read ADVERTISE register: %d\n", ret); + return ret; + } + + if (priv->phy_type == PHY_RGMII) + { + ret = imx9_readmii(priv, GMII_1000BTCR, &btcr); + if (ret < 0) + { + nerr("ERROR: Failed to read GMII_1000BTCR register\n"); + return ret; + } + } + + if (priv->full_duplex) + { + advertise &= ~(MII_ADVERTISE_1000XHALF | + MII_ADVERTISE_100BASETXHALF | + MII_ADVERTISE_10BASETXHALF); + btcr &= ~GMII_1000BTCR_1000BASETHALF; + force_mcr |= MII_MCR_FULLDPLX; + } + else + { + advertise &= ~(MII_ADVERTISE_1000XFULL | + MII_ADVERTISE_100BASETXFULL | + MII_ADVERTISE_10BASETXFULL); + btcr &= ~GMII_1000BTCR_1000BASETFULL; + force_mcr &= ~MII_MCR_FULLDPLX; + } + + if (priv->s_10mbps) + { + advertise &= ~(MII_ADVERTISE_100BASETXFULL | + MII_ADVERTISE_100BASETXHALF | + MII_ADVERTISE_1000XFULL | + MII_ADVERTISE_1000XHALF); + btcr &= ~(GMII_1000BTCR_1000BASETHALF | + GMII_1000BTCR_1000BASETFULL); + force_mcr &= ~(MII_MCR_SPEED100 | GMII_MCR_SPEED1000); + } + + if (priv->s_100mbps) + { + advertise &= ~(MII_ADVERTISE_10BASETXFULL | + MII_ADVERTISE_10BASETXHALF | + MII_ADVERTISE_1000XFULL | + MII_ADVERTISE_1000XHALF); + btcr &= ~(GMII_1000BTCR_1000BASETHALF | + GMII_1000BTCR_1000BASETFULL); + force_mcr &= ~GMII_MCR_SPEED1000; + force_mcr |= MII_MCR_SPEED100; + } + + if (priv->s_1000mbps) + { + advertise &= ~(MII_ADVERTISE_10BASETXFULL | + MII_ADVERTISE_10BASETXHALF | + MII_ADVERTISE_100BASETXFULL | + MII_ADVERTISE_100BASETXHALF); + force_mcr &= ~MII_MCR_SPEED100; + force_mcr |= GMII_MCR_SPEED1000; + } + + ret = imx9_writemii(priv, MII_ADVERTISE, advertise); + + if (ret < 0) + { + nerr("ERROR: Failed to write ADVERTISE register\n"); + return ret; + } + + if (priv->phy_type == PHY_RGMII) + { + ret = imx9_writemii(priv, GMII_1000BTCR, btcr); + if (ret < 0) + { + nerr("ERROR: Failed to write GMII_1000BTCR register\n"); + return ret; + } + } + } + + /* Enable autonegotiation and take link back up */ + + if (!priv->force_speed) + { + mcr |= (MII_MCR_ANENABLE | MII_MCR_ANRESTART); + } + else + { + mcr = force_mcr & (~(MII_MCR_ANENABLE | MII_MCR_ANRESTART)); + } + + ret = imx9_writemii(priv, MII_MCR, mcr); + if (ret < 0) + { + nerr("ERROR: Failed to write MCR register: %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Function: imx9_phy_wait_autoneg_complete + * + * Description: + * Wait for autonegotiation to complete + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on any + * failure; + * + * Assumptions: + * + ****************************************************************************/ + +static int imx9_phy_wait_autoneg_complete(struct imx9_driver_s *priv) +{ + int ret; + uint16_t msr; + int timeout; + + /* Wait for autonegotiation to complete */ + + for (timeout = 0; timeout < LINK_NLOOPS; timeout++) + { + ret = imx9_readmii(priv, MII_MSR, &msr); + if (ret < 0) + { + nerr("ERROR: Failed to read MSR register: %d\n", ret); + return ret; + } + + /* Check for completion of autonegotiation */ + + if ((msr & MII_MSR_ANEGCOMPLETE) != 0) + { + /* Yes break out of the loop */ + + ninfo("Autonegotiate complete, MSR %x\n", msr); + break; + } + + nxsig_usleep(LINK_WAITUS); + } + + if (timeout == LINK_NLOOPS) + { + ninfo("Autonegotiate failed, MSR %x\n", msr); + return -ETIMEDOUT; + } + + return imx9_read_phy_status(priv); +} + +/**************************************************************************** + * Function: imx9_initphy + * + * Description: + * Configure the PHY + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * renogphy - Flag indicating if to perform negotiation of the link + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on any + * failure; + * + * Assumptions: + * + ****************************************************************************/ + +static inline int imx9_initphy(struct imx9_driver_s *priv, bool renogphy) +{ + uint32_t rcr; + uint32_t tcr; + uint32_t racc; + uint16_t phydata; + int retries; + int ret; + const char *phy_name = priv->cur_phy ? priv->cur_phy->name : "Unknown"; + + if (renogphy) + { + /* Loop until we successfully communicate + * with the PHY. This is 'standard stuff' that should work for any PHY + * - we are not communicating with it's 'special' registers + * at this point. + */ + + ninfo("%s: Try phyaddr: %u\n", phy_name, priv->phyaddr); + + /* Try to read PHYID1 few times using this address */ + + retries = 0; + do + { + nxsig_usleep(LINK_WAITUS); + + ninfo("%s: Read PHYID1, retries=%d\n", phy_name, retries + 1); + + phydata = 0xffff; + ret = imx9_readmii(priv, MII_PHYID1, &phydata); + } + while ((ret < 0 || phydata == 0xffff) && ++retries < 3); + + if (retries >= 3) + { + nerr("ERROR: Failed to read %s PHYID1 at address %d\n", + phy_name, priv->phyaddr); + return -ENOENT; + } + + ninfo("%s: Using PHY address %u\n", phy_name, priv->phyaddr); + + /* Verify PHYID1. Compare OUI bits 3-18 */ + + ninfo("%s: PHYID1: %04x\n", phy_name, phydata); + if (priv->cur_phy && phydata != priv->cur_phy->id1) + { + nerr("ERROR: PHYID1=%04x incorrect for %s. Expected %04x\n", + phydata, phy_name, priv->cur_phy->id1); + return -ENXIO; + } + + /* Read PHYID2 */ + + ret = imx9_readmii(priv, MII_PHYID2, &phydata); + if (ret < 0) + { + nerr("ERROR: Failed to read %s PHYID2: %d\n", phy_name, ret); + return ret; + } + + ninfo("%s: PHYID2: %04x\n", phy_name, phydata); + + /* Verify PHYID2: Compare OUI bits 19-24 and the 6-bit model number + * (ignoring the 4-bit revision number). + */ + + if (priv->cur_phy && + (phydata & 0xfff0) != (priv->cur_phy->id2 & 0xfff0)) + { + nerr("ERROR: PHYID2=%04x incorrect for %s. Expected %04x\n", + (phydata & 0xfff0), phy_name, + (priv->cur_phy->id2 & 0xfff0)); + return -ENXIO; + } + + if (imx9_phy_is(priv, MII_LAN8720_NAME) || + imx9_phy_is(priv, MII_LAN8742A_NAME)) + { + /* Make sure that PHY comes up in correct mode when it's reset */ + + imx9_writemii(priv, MII_LAN8720_MODES, + MII_LAN8720_MODES_RESV | MII_LAN8720_MODES_ALL | + MII_LAN8720_MODES_PHYAD(priv->phyaddr)); + } + + ret = imx9_reset_phy(priv); + if (ret < 0) + { + nerr("ERROR: PHY reset failed: %d\n", ret); + return ret; + } + + ret = imx9_phy_set_speed(priv, priv->autoneg); + + if (ret < 0) + { + nerr("ERROR: PHY setting speed failed: %d\n", ret); + return ret; + } + + /* If this is an unknown phy, we can't read the current link speed. In + * that case, just set the default speed and duplex settings. + */ + + if (!priv->cur_phy || !priv->autoneg) + { + nwarn("Can't read PHY status, using default speed and duplex\n"); + imx9_phy_set_speed(priv, false); + } + else + { + ret = imx9_phy_wait_autoneg_complete(priv); + if (ret < 0) + { + return ret; + } + } + } + + /* Set up the transmit and receive control registers based on the + * configuration and the auto negotiation results. + */ + + rcr = (ENET_RCR_CRCFWD | ((CONFIG_NET_ETH_PKTSIZE + CONFIG_NET_GUARDSIZE) + << ENET_RCR_MAX_FL_SHIFT) | + ENET_RCR_FCE | ENET_RCR_MII_MODE); + + if (priv->phy_type == PHY_RGMII) + { + rcr |= ENET_RCR_RGMII_EN; + } + else + { + rcr |= ENET_RCR_RMII_MODE; + } + + if (priv->promiscuous) + { + rcr |= ENET_RCR_PROM; + } + + tcr = 0; + + imx9_enet_putreg32(priv, tcr, IMX9_ENET_TCR_OFFSET); + + /* Enable Discard Of Frames With MAC Layer Errors. + * Enable Discard Of Frames With Wrong Protocol Checksum. + * Bit 1: Enable discard of frames with wrong IPv4 header checksum. + */ + + racc = ENET_RACC_PRODIS | ENET_RACC_LINEDIS | ENET_RACC_IPDIS; + imx9_enet_putreg32(priv, racc, IMX9_ENET_RACC_OFFSET); + + /* Setup half or full duplex */ + + if (priv->full_duplex) + { + /* Full duplex */ + + ninfo("%s: Full duplex\n", phy_name); + tcr |= ENET_TCR_FDEN; + } + else + { + /* Half duplex */ + + ninfo("%s: Half duplex\n", phy_name); + rcr |= ENET_RCR_DRT; + } + + if (priv->s_10mbps) + { + /* 10 Mbps */ + + ninfo("%s: 10 Base-T\n", phy_name); + rcr |= ENET_RCR_RMII_10T; + } + else if (priv->s_100mbps) + { + /* 100 Mbps */ + + ninfo("%s: 100 Base-T\n", phy_name); + } + else if (priv->s_1000mbps) + { + /* 1000 Mbps */ + + ninfo("%s: 1000 Base-T\n", phy_name); + } + else + { + /* This might happen if Autonegotiation did not complete(?) */ + + nerr("ERROR: No 10-, 100-, or 1000-BaseT reported: PHY STATUS=%04x\n", + phydata); + return -EIO; + } + + imx9_enet_putreg32(priv, rcr, IMX9_ENET_RCR_OFFSET); + imx9_enet_putreg32(priv, tcr, IMX9_ENET_TCR_OFFSET); + return OK; +} + +/**************************************************************************** + * Function: imx9_initbuffers + * + * Description: + * Initialize ENET buffers and descriptors + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void imx9_initbuffers(struct imx9_driver_s *priv) +{ + uintptr_t addr; + int i; + + /* Get the beginning of the first aligned buffer */ + + addr = priv->buffer_pool; + + /* Then fill in the TX descriptors */ + + memset(priv->txdesc, 0, IMX9_ENET_NTXBUFFERS * sizeof(priv->txdesc[0])); + + for (i = 0; i < IMX9_ENET_NTXBUFFERS; i++) + { + priv->txdesc[i].d1.data = addr; + priv->txdesc[i].d1.bdu = TXDESC_BDU; + + priv->txdesc[i].d2.bdu = TXDESC_BDU; + addr += ALIGNED_BUFSIZE; + } + + /* Then fill in the RX descriptors */ + + memset(priv->rxdesc, 0, IMX9_ENET_NRXBUFFERS * sizeof(priv->rxdesc[0])); + + for (i = 0; i < IMX9_ENET_NRXBUFFERS; i++) + { + priv->rxdesc[i].status1 = RXDESC_E; + priv->rxdesc[i].data = addr; + priv->rxdesc[i].status2 = RXDESC_INT; + addr += ALIGNED_BUFSIZE; + } + + /* Set the wrap bit in the last descriptors to form a ring */ + + priv->txdesc[IMX9_ENET_NTXBUFFERS - 1].d2.status1 |= TXDESC_W; + priv->rxdesc[IMX9_ENET_NRXBUFFERS - 1].status1 |= RXDESC_W; + + ARM64_DSB(); + + up_clean_dcache((uintptr_t)priv->txdesc, + (uintptr_t)priv->txdesc + + IMX9_ENET_NTXBUFFERS * sizeof(priv->txdesc[0])); + up_clean_dcache((uintptr_t)priv->rxdesc, + (uintptr_t)priv->rxdesc + + IMX9_ENET_NRXBUFFERS * sizeof(priv->rxdesc[0])); + + /* We start with RX descriptor 0 and with no TX descriptors in use */ + + priv->txhead = 0; + priv->rxtail = 0; +} + +/**************************************************************************** + * Function: imx9_reset + * + * Description: + * Put the EMAC in the non-operational, reset state + * + * Input Parameters: + * priv - Reference to the private ENET driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void imx9_reset(struct imx9_driver_s *priv) +{ + /* Set the reset bit and wait for the enable to clear */ + + imx9_enet_putreg32(priv, ENET_ECR_RESET, IMX9_ENET_ECR_OFFSET); + + while (imx9_enet_getreg32(priv, IMX9_ENET_ECR_OFFSET) & ENET_ECR_ETHEREN) + { + asm volatile ("nop"); + } +} + +/**************************************************************************** + * Function: imx9_enet_mux_io + * + * Description: + * Mux all the IO pins + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static void imx9_enet_mux_io(void) +{ +#ifdef CONFIG_IMX9_ENET1 + imx9_iomux_configure(MUX_ENET1_MDIO); + imx9_iomux_configure(MUX_ENET1_MDC); + + imx9_iomux_configure(MUX_ENET1_RX_DATA00); + imx9_iomux_configure(MUX_ENET1_RX_DATA01); + + imx9_iomux_configure(MUX_ENET1_TX_DATA00); + imx9_iomux_configure(MUX_ENET1_TX_DATA01); + +# if defined(CONFIG_IMX9_ENET1_RGMII) + imx9_iomux_configure(MUX_ENET1_RX_DATA02); + imx9_iomux_configure(MUX_ENET1_RX_DATA03); + imx9_iomux_configure(MUX_ENET1_TX_DATA02); + imx9_iomux_configure(MUX_ENET1_TX_DATA03); + imx9_iomux_configure(MUX_ENET1_RXC); + imx9_iomux_configure(MUX_ENET1_TX_CTL); + imx9_iomux_configure(MUX_ENET1_RX_CTL); +# else /* RMII */ + imx9_iomux_configure(MUX_ENET1_TX_EN); + imx9_iomux_configure(MUX_ENET1_REF_CLK); + imx9_iomux_configure(MUX_ENET1_CRS_DV); +# endif + +# ifdef MUX_ENET1_RX_ER + imx9_iomux_configure(MUX_ENET1_RX_ER); +# endif +#endif +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Function: imx9_netinitialize + * + * Description: + * Initialize the Ethernet controller and driver + * + * Input Parameters: + * intf - In the case where there are multiple EMACs, this value + * identifies which EMAC is to be initialized. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int imx9_netinitialize(int intf) +{ + struct imx9_driver_s *priv; + uint32_t uidl; + uint32_t uidml; + uint8_t *mac; + int ret; + + /* Get the interface structure associated with this interface number. */ + + priv = &g_enet[intf]; + + /* Disable the ENET clock */ + + imx9_ccm_gate_on(priv->clk_gate, false); + + /* Enet ref to 125 MHz */ + + imx9_ccm_configure_root_clock(CCM_CR_ENETREF, SYS_PLL1PFD0DIV2, 2); + + /* Enet timer 1 to 125MHz */ + + imx9_ccm_configure_root_clock(CCM_CR_ENETTIMER1, SYS_PLL1PFD0DIV2, 2); + + /* Enet ref clock to 25 MHz */ + + imx9_ccm_configure_root_clock(CCM_CR_ENETREFPHY, SYS_PLL1PFD0DIV2, 20); + + /* Enable the ENET clock */ + + imx9_ccm_gate_on(priv->clk_gate, true); + + /* Attach the Ethernet interrupt handler */ + + if (irq_attach(priv->irq, imx9_enet_interrupt, priv)) + { + /* We could not attach the ISR to the interrupt */ + + nerr("ERROR: Failed to attach EMACTX IRQ\n"); + return -EAGAIN; + } + + /* TODO: 1588 features */ + + /* Attach the Ethernet MAC IEEE 1588 timer interrupt handler */ + +#if 0 + if (irq_attach(IMX9_IRQ_ENET_1588, imx9_enet_interrupt, priv)) + { + /* We could not attach the ISR to the interrupt */ + + nerr("ERROR: Failed to attach EMACTMR IRQ\n"); + return -EAGAIN; + } +#endif + +#ifdef CONFIG_IMX9_ENET_USE_OTP_MAC + + /* Boards like the imx93-evk have a unique (official) + * MAC address stored in OTP. + */ + + uidl = getreg32(IMX9_OCOTP_BASE + priv->otp_mac_off); + uidml = getreg32(IMX9_OCOTP_BASE + priv->otp_mac_off + 4); + mac = priv->dev.d_mac.ether.ether_addr_octet; + + mac[0] = (uidml & 0x0000ff00) >> 8; + mac[1] = (uidml & 0x000000ff) >> 0; + mac[2] = (uidl & 0xff000000) >> 24; + mac[3] = (uidl & 0x00ff0000) >> 16; + mac[4] = (uidl & 0x0000ff00) >> 8; + mac[5] = (uidl & 0x000000ff) >> 0; + +#else + + /* Determine a semi-unique MAC address from MCU UID + * We use UID Low and Mid Low registers to get 64 bits, from which we keep + * 40 bits. We then force locally administered bits in mac[0] based on + * interface number (0x2,0x6,0xa,0xe for if 0,1,2,3) + */ + + uidl = getreg32(IMX9_OCOTP_BASE + IMX93_OCOTP_UID_OFFSET); + uidml = getreg32(IMX9_OCOTP_BASE + IMX93_OCOTP_UID_OFFSET + 4); + mac = priv->dev.d_mac.ether.ether_addr_octet; + + mac[0] = (0x2 | (intf << 2)); + mac[1] = (uidml & 0x000000ff); + mac[2] = (uidl & 0xff000000) >> 24; + mac[3] = (uidl & 0x00ff0000) >> 16; + mac[4] = (uidl & 0x0000ff00) >> 8; + mac[5] = (uidl & 0x000000ff); + +#endif + +#ifdef CONFIG_IMX9_ENET_PHYINIT + /* Perform any necessary, one-time, board-specific PHY initialization */ + + ret = imx9_phy_boardinitialize(intf); + if (ret < 0) + { + nerr("ERROR: Failed to initialize the PHY: %d\n", ret); + return ret; + } +#endif + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling imx9_ifdown(). + */ + + imx9_ifdown(&priv->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + netdev_register(&priv->dev, NET_LL_ETHERNET); + + UNUSED(ret); + return OK; +} + +/**************************************************************************** + * Name: arm_netinitialize + * + * Description: + * Initialize the first network interface. If there are more than one + * interface in the chip, then board-specific logic will have to provide + * this function to determine which, if any, Ethernet controllers should + * be initialized. + * + ****************************************************************************/ + +#if !defined(CONFIG_NETDEV_LATEINIT) +void arm64_netinitialize(void) +{ + int i; + + /* Configure all ENET/MII pins */ + + imx9_enet_mux_io(); + + /* Initialize all IFs */ + + for (i = 0; i < nitems(g_enet); i++) + { + imx9_netinitialize(i); + } +} +#endif + +#endif /* CONFIG_IMX9_ENET */ diff --git a/arch/arm64/src/imx9/imx9_enet.h b/arch/arm64/src/imx9/imx9_enet.h new file mode 100644 index 0000000000000..e37cdc6464a8a --- /dev/null +++ b/arch/arm64/src/imx9/imx9_enet.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_enet.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_ENET_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_ENET_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "hardware/imx9_enet.h" + +#ifdef CONFIG_IMX9_ENET + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Definitions for use with imx9_phy_boardinitialize */ + +#define EMAC_INTF 0 + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Function: imx9_netinitialize + * + * Description: + * Initialize the Ethernet controller and driver + * + * Input Parameters: + * intf - In the case where there are multiple EMACs, this value + * identifies which EMAC is to be initialized. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +int imx9_netinitialize(int intf); + +/**************************************************************************** + * Function: imx9_phy_boardinitialize + * + * Description: + * Some boards require specialized initialization of the PHY before it can + * be used. This may include such things as configuring GPIOs, resetting + * the PHY, etc. If CONFIG_IMX9_ENET_PHYINIT is defined in the + * configuration then the board specific logic must provide + * imx9_phyinitialize(); The i.MX RT Ethernet driver will call this + * function one time before it first uses the PHY. + * + * Input Parameters: + * intf - Always zero for now. + * + * Returned Value: + * OK on success; Negated errno on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_ENET_PHYINIT +int imx9_phy_boardinitialize(int intf); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_IMX9_ENET */ +#endif /* __ARCH_ARM_SRC_IMX9_IMX9_ENET_H */ diff --git a/arch/arm64/src/imx9/imx9_flexio_pwm.c b/arch/arm64/src/imx9/imx9_flexio_pwm.c new file mode 100644 index 0000000000000..1e93a1ffdc45c --- /dev/null +++ b/arch/arm64/src/imx9/imx9_flexio_pwm.c @@ -0,0 +1,755 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_flexio_pwm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "imx9_flexio_pwm.h" +#include "arm64_arch.h" +#include "imx9_ccm.h" +#include "imx9_iomuxc.h" +#include "hardware/imx9_ccm.h" +#include "hardware/imx9_pinmux.h" +#include "hardware/imx9_flexio.h" + +#ifdef CONFIG_IMX9_FLEXIO_PWM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PIN_FOR_TIMER(priv, timer) ((uint8_t)(priv->pins >> (timer * 8))) + +#ifdef CONFIG_IMX9_FLEXIO1_PWM +# if (CONFIG_PWM_NCHANNELS < CONFIG_IMX9_FLEXIO1_PWM_NCHANNELS) +# error CONFIG_PWM_NCHANNELS < CONFIG_IMX9_FLEXIO1_PWM_NCHANNELS +# endif +#endif + +#ifdef CONFIG_IMX9_FLEXIO2_PWM +# if (CONFIG_PWM_NCHANNELS < CONFIG_IMX9_FLEXIO2_PWM_NCHANNELS) +# error CONFIG_PWM_NCHANNELS < CONFIG_IMX9_FLEXIO2_PWM_NCHANNELS +# endif +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the state of one PWM timer */ + +struct imx9_pwmtimer_s +{ + const struct pwm_ops_s *ops; /* PWM operations */ + const flexio_pwm_id_t id; /* PWM_FLEXIO1 or PWM_FLEXIO2 */ + const int nchannels; /* Number of channels used */ + const uintptr_t base; /* The base address of the FLEXIO */ + const uint64_t pins; /* Mapping of timer outputs to flexio outputs */ + const int int_trigger; /* Uses flex-io internal timer for frequency */ + int trigger_ch; /* Trigger channel */ + unsigned frequency; /* Current frequency setting */ + int period; /* PWM period in ticks of functional clock */ +}; + +/**************************************************************************** + * Static Function Prototypes + ****************************************************************************/ + +/* PWM driver methods */ + +static int pwm_setup(struct pwm_lowerhalf_s *dev); +static int pwm_shutdown(struct pwm_lowerhalf_s *dev); + +static int pwm_start(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info); + +static int pwm_stop(struct pwm_lowerhalf_s *dev); +static int pwm_ioctl(struct pwm_lowerhalf_s *dev, + int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the list of lower half PWM driver methods used by the upper half + * driver + */ + +static const struct pwm_ops_s g_pwmops = +{ + .setup = pwm_setup, + .shutdown = pwm_shutdown, + .start = pwm_start, + .stop = pwm_stop, + .ioctl = pwm_ioctl, +}; + +static struct imx9_pwmtimer_s g_pwmdev[] = +{ +#ifdef CONFIG_IMX9_FLEXIO1_PWM + { + .ops = &g_pwmops, + .id = PWM_FLEXIO1, + .nchannels = CONFIG_IMX9_FLEXIO1_PWM_NCHANNELS, + .base = IMX9_FLEXIO1_BASE, + .pins = CONFIG_IMX9_FLEXIO1_PWM_CHANNEL_PINS, + .int_trigger = 1, + }, +#endif + +#ifdef CONFIG_IMX9_FLEXIO2_PWM + { + .ops = &g_pwmops, + .id = PWM_FLEXIO2, + .nchannels = CONFIG_IMX9_FLEXIO2_PWM_NCHANNELS, + .base = IMX9_FLEXIO2_BASE, + .pins = CONFIG_IMX9_FLEXIO2_PWM_CHANNEL_PINS, + .int_trigger = 1, + }, +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: flexio_getreg + * + * Description: + * Read the value of a flex-io register. + * + * Input Parameters: + * priv - A reference to the PWM block + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +static inline uint32_t flexio_getreg(struct imx9_pwmtimer_s *priv, + int offset) +{ + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: flexio_putreg + * + * Description: + * Read the value of an PWM timer register. + * + * Input Parameters: + * priv - A reference to the PWM block status + * offset - The offset to the register to read + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void flexio_putreg(struct imx9_pwmtimer_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * Name: flexio_mux + * + * Description: + * Mux the flex-io output pins to pads. The macros FLEXIOn_PWMx_MUX + * need to be defined in the board.h file + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void flexio_mux(void) +{ +#ifdef CONFIG_IMX9_FLEXIO1_PWM + +# ifdef FLEXIO1_PWM0_MUX + imx9_iomux_configure(FLEXIO1_PWM0_MUX); +# endif + +# ifdef FLEXIO1_PWM1_MUX + imx9_iomux_configure(FLEXIO1_PWM1_MUX); +# endif + +# ifdef FLEXIO1_PWM2_MUX + imx9_iomux_configure(FLEXIO1_PWM2_MUX); +# endif + +# ifdef FLEXIO1_PWM3_MUX + imx9_iomux_configure(FLEXIO1_PWM3_MUX); +# endif + +# ifdef FLEXIO1_PWM4_MUX + imx9_iomux_configure(FLEXIO1_PWM4_MUX); +# endif + +# ifdef FLEXIO1_PWM5_MUX + imx9_iomux_configure(FLEXIO1_PWM5_MUX); +# endif + +# ifdef FLEXIO1_PWM6_MUX + imx9_iomux_configure(FLEXIO1_PWM6_MUX); +# endif + +# ifdef FLEXIO1_PWM7_MUX + imx9_iomux_configure(FLEXIO1_PWM7_MUX); +# endif + +#endif + +#ifdef CONFIG_IMX9_FLEXIO2_PWM + +# ifdef FLEXIO2_PWM0_MUX + imx9_iomux_configure(FLEXIO2_PWM0_MUX); +# endif + +# ifdef FLEXIO2_PWM1_MUX + imx9_iomux_configure(FLEXIO2_PWM1_MUX); +# endif + +# ifdef FLEXIO2_PWM2_MUX + imx9_iomux_configure(FLEXIO2_PWM2_MUX); +# endif + +# ifdef FLEXIO2_PWM3_MUX + imx9_iomux_configure(FLEXIO2_PWM3_MUX); +# endif + +# ifdef FLEXIO2_PWM4_MUX + imx9_iomux_configure(FLEXIO2_PWM4_MUX); +# endif + +# ifdef FLEXIO2_PWM5_MUX + imx9_iomux_configure(FLEXIO2_PWM5_MUX); +# endif + +# ifdef FLEXIO2_PWM6_MUX + imx9_iomux_configure(FLEXIO2_PWM6_MUX); +# endif + +# ifdef FLEXIO2_PWM7_MUX + imx9_iomux_configure(FLEXIO2_PWM7_MUX); +# endif + +#endif +} + +/**************************************************************************** + * Name: pwm_init_trigger_timer + * + * Description: + * Initialize the timer trigger, generating the PWM frequency + * + * Input Parameters: + * priv - A reference to the lower half PWM driver state structure + * + * Returned Value: + * OK on success, ERROR if the timer initialization fails + * + ****************************************************************************/ + +static int pwm_init_trigger_timer(struct imx9_pwmtimer_s *priv) +{ + uint32_t reg; + int num_timers; + + /* For now, use the last available flexio timer to produce internal + * trigger. This can be later expanded to use external trigger from + * LPIT timer, if one more PWM channel is required + */ + + /* Get parameter register and number of supported timers */ + + reg = flexio_getreg(priv, IMX9_FLEXIO_PARAM_OFFSET); + num_timers = (reg & FLEXIO_PARAM_TIMER_MASK) >> FLEXIO_PARAM_TIMER_SHIFT; + + num_timers--; + if (num_timers < priv->nchannels) + { + pwmerr("PWM%d max channels %d\n", priv->id, num_timers); + return ERROR; + } + + priv->trigger_ch = num_timers; + + return OK; +} + +/**************************************************************************** + * Name: pwm_select_func_clock + * + * Description: + * Select best suitable functional clock for the flexio + * + * Input Parameters: + * priv - A reference to the lower half PWM driver state structure + * freq - The requested PWM frequency for this flexio block + * + * Returned Value: + * Zero on success, negated error value on failure + * + ****************************************************************************/ + +static int pwm_select_func_clock(struct imx9_pwmtimer_s *priv, int freq) +{ + const int max_div = 24000000 / 65536 + 1; /* for 1 Hz */ + int div; + uint32_t period; + + if (freq == 0) + { + priv->period = 0; + return 0; + } + + /* Use the 24MHz OSC clock, and find the best divider to get as much + * resolution as possible using 16 bit timer + */ + + for (div = 1; div < max_div; div++) + { + period = 24000000 / div / freq; + if (period < 65536) + { + priv->period = period; + break; + } + } + + imx9_ccm_configure_root_clock(CCM_CR_FLEXIO1 + priv->id, OSC_24M, div); + + /* Enable peripheral clock */ + + imx9_ccm_gate_on(CCM_LPCG_FLEXIO1 + priv->id , true); + + return 0; +} + +/**************************************************************************** + * Name: pwm_update_frequency + * + * Description: + * Initialize the timer trigger, generating the PWM freuency + * + * Input Parameters: + * priv - A reference to the lower half PWM driver state structure + * freq - The requested PWM frequency for this flexio block + * + * Returned Value: + * Zero on success, negated error value on failure + * + ****************************************************************************/ + +static int pwm_update_frequency(struct imx9_pwmtimer_s *priv, int freq) +{ + int ret = pwm_select_func_clock(priv, freq); + if (ret < 0) + { + return ret; + } + + /* Configure the timer to produce internal trigger. The following + * setting produces 50/50 pulse where duty cycle is defined by + * TIMCMP: + * + * TIMCFG: + * TIMOUT = 0 Timer output is logic one when enabled and not + * affected by timer reset + * TIMDEC = 0 Decrement counter on FLEXIO clock + * TIMRST = 0x0 Timer never reset + * TIMDIS = 0x0 Timer never disabled + * TIMENA = 0x0 Timer always enabled + * TIMCTL: + * TIMOD = 0x3 Single 16-bit counter + * PINCFG = 0x0 Output pin disabled + * TIMCMP: frequency / 2 + */ + + flexio_putreg(priv, IMX9_FLEXIO_TIMCMP_OFFSET(priv->trigger_ch), + priv->period / 2); + + /* Enable / disable timer */ + + flexio_putreg(priv, IMX9_FLEXIO_TIMCTL_OFFSET(priv->trigger_ch), + freq > 0 ? FLEXIO_TIMCTL_TIMOD(0x3) : + FLEXIO_TIMCTL_TIMOD(0x0)); + + return ret; +} + +/**************************************************************************** + * Name: pwm_update_duty + * + * Description: + * Change the channel duty cycle. + * + * Input Parameters: + * priv - A reference to the lower half PWM driver state structure + * channel - Channel to by updated + * duty - New duty cycle as fraction of 65536 + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_update_duty(struct imx9_pwmtimer_s *priv, int pwm_ch, + ub16_t duty16) +{ + uint32_t edge = ub16toi(duty16 * priv->period + b16HALF); + int timer = pwm_ch - 1; /* map pwm ch 1 to timer 0 etc.. */ + uint32_t regval; + + if (pwm_ch == 0 || pwm_ch > priv->nchannels) + { + pwmerr("ERROR: PWM%d has no such channel: %u\n", priv->id, pwm_ch); + return -EINVAL; + } + + /* Now configure the flexio timers in 16-bit counter mode */ + + /* Timers 0-6: + * TIMCFG: + * TIMOUT = 0 Timer output is 1 when enabled and not affected by reset + * TIMDEC = 0 Decrement counter on FLEXIO clock + * TIMRST = 0x0 Timer never reset + * TIMDIS = 0x2 Timer disabled on counter 0 + * TIMENA = 0x6 Timer enabled on Trigger rising edge + * TIMCTL: + * TIMOD = 0x3 single 16-bit counter + * TRGSEL = 4 * trg_ch + 3 timer "trg_ch" trigger output + * TRGSRC = 1 internal trigger + * PINCFG = 0x3 Timer pin output + * PINSEL = timer number + mux conf + * TIMCMP: duty cycle + */ + + /* If this is the first time configuring the PWMs, configure the + * timer fully, otherwise just update the duty cycle + */ + + flexio_putreg(priv, IMX9_FLEXIO_TIMCMP_OFFSET(timer), edge); + + if (priv->frequency == 0) + { + flexio_putreg(priv, IMX9_FLEXIO_TIMCFG_OFFSET(timer), + FLEXIO_TIMCFG_TIMDIS(0x2) | + FLEXIO_TIMCFG_TIMENA(0x6)); + + /* When initially configuring PINCFG=11b, FLEXIO may briefly drive the + * pin low. To avoid this, configure PINCFG=10b along with the rest of + * the control register and then perform a subsequent write to set + * PINCFG=11b + */ + + regval = (FLEXIO_TIMCTL_TIMOD(0x3) | + FLEXIO_TIMCTL_TRGSEL(4 * priv->trigger_ch + 3) | + FLEXIO_TIMCTL_TRGSRC(priv->int_trigger) | + FLEXIO_TIMCTL_PINSEL(PIN_FOR_TIMER(priv, timer))); + + flexio_putreg(priv, IMX9_FLEXIO_TIMCTL_OFFSET(timer), + regval | FLEXIO_TIMCTL_PINCFG(0x2)); + + flexio_putreg(priv, IMX9_FLEXIO_TIMCTL_OFFSET(timer), + regval | FLEXIO_TIMCTL_PINCFG(0x3)); + } + + pwminfo("PWM%d channel %d, p: %d e: %" PRIu32 "\n", priv->id, pwm_ch, + priv->period, edge); + + return 0; +} + +/**************************************************************************** + * Name: pwm_setup + * + * Description: + * This method is called when the driver is opened. The lower half driver + * should configure and initialize the device so that it is ready for use. + * It should not, however, output pulses until the start method is called. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * + ****************************************************************************/ + +static int pwm_setup(struct pwm_lowerhalf_s *dev) +{ + return OK; +} + +/**************************************************************************** + * Name: pwm_shutdown + * + * Description: + * This method is called when the driver is closed. The lower half driver + * stop pulsed output, free any resources, disable the timer hardware, and + * put the system into the lowest possible power usage state + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_shutdown(struct pwm_lowerhalf_s *dev) +{ + /* Make sure that the output has been stopped */ + + pwm_stop(dev); + + return OK; +} + +/**************************************************************************** + * Name: pwm_start + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_start(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info) +{ + struct imx9_pwmtimer_s *priv = (struct imx9_pwmtimer_s *)dev; + int ret = OK; + int i; + + if (priv == NULL || info == NULL || info->frequency == 0) + { + return -EINVAL; + } + + /* Set the frequency if not changed */ + + if (info->frequency != priv->frequency) + { + ret = pwm_update_frequency(priv, info->frequency); + } + + /* Handle channel specific setup */ + + for (i = 0; i < CONFIG_PWM_NCHANNELS; i++) + { + if (ret != OK || info->channels[i].channel == -1) + { + break; + } + + ret = pwm_update_duty(priv, info->channels[i].channel, + info->channels[i].duty); + } + + if (ret == OK) + { + priv->frequency = info->frequency; + } + + return ret; +} + +/**************************************************************************** + * Name: pwm_stop + * + * Description: + * Stop the pulsed output and reset the timer resources + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * This function is called to stop the pulsed output at anytime. + * + ****************************************************************************/ + +static int pwm_stop(struct pwm_lowerhalf_s *dev) +{ + struct imx9_pwmtimer_s *priv = (struct imx9_pwmtimer_s *)dev; + int i; + + pwminfo("PWM%d stop\n", priv->id); + + /* Check that timer is valid */ + + if (priv == NULL) + { + return -EINVAL; + } + + /* Disable all the channels */ + + for (i = 0; i < priv->nchannels; i++) + { + flexio_putreg(priv, IMX9_FLEXIO_TIMCTL_OFFSET(i), + FLEXIO_TIMCTL_PINCFG(0x2)); + flexio_putreg(priv, IMX9_FLEXIO_TIMCTL_OFFSET(i), 0); + } + + /* Setting frequency to zero disables trigger clock */ + + return pwm_update_frequency(priv, 0); +} + +/**************************************************************************** + * Name: pwm_ioctl + * + * Description: + * Lower-half logic may support platform-specific ioctl commands + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_flexio_pwm_init + * + * Description: + * Initialize flexio blocks to generate EPWM. + * + * Input Parameters: + * pwmid - A number identifying the pwm block. The number of valid + * IDs varies depending on the configuration. + * + * Returned Value: + * On success, a pointer to the lower half PWM driver is + * returned. NULL is returned on any failure. + * + ****************************************************************************/ + +struct pwm_lowerhalf_s *imx9_flexio_pwm_init(flexio_pwm_id_t pwmid) +{ + struct imx9_pwmtimer_s *lower = NULL; + int i; + + for (i = 0; i < sizeof(g_pwmdev) / sizeof(struct imx9_pwmtimer_s); i++) + { + if (pwmid == g_pwmdev[i].id) + { + lower = &g_pwmdev[i]; + break; + } + } + + if (lower) + { + /* IO mux */ + + flexio_mux(); + + /* Reset FlexIO */ + + flexio_putreg(lower, IMX9_FLEXIO_CTRL_OFFSET, FLEXIO_CTRL_SWRST(1)); + + /* Enable FlexIO and de-assert reset */ + + flexio_putreg(lower, IMX9_FLEXIO_CTRL_OFFSET, FLEXIO_CTRL_FLEXEN(1)); + + /* Make sure that FlexIO is enabled and reset is cleared */ + + while (flexio_getreg(lower, IMX9_FLEXIO_CTRL_OFFSET) != + FLEXIO_CTRL_FLEXEN_MASK); + + /* Initialize the trigger timer used for PWM period generation */ + + if (pwm_init_trigger_timer(lower) != OK) + { + /* Disable FlexIO */ + + flexio_putreg(lower, IMX9_FLEXIO_CTRL_OFFSET, 0); + + return NULL; + } + + pwminfo("PWM%d at 0x%" PRIxPTR " configured\n", pwmid, lower->base); + } + else + { + pwmerr("ERROR: No such timer configured %d\n", pwmid); + } + + return (struct pwm_lowerhalf_s *)lower; +} + +#endif diff --git a/arch/arm64/src/imx9/imx9_flexio_pwm.h b/arch/arm64/src/imx9/imx9_flexio_pwm.h new file mode 100644 index 0000000000000..a4b3f8d97d529 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_flexio_pwm.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_flexio_pwm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_FLEXIO_PWM_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_FLEXIO_PWM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Check if PWM support for any channel is enabled. */ + +#ifdef CONFIG_IMX9_FLEXIO_PWM + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/imx9_flexio.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef enum +{ + PWM_FLEXIO1 = 0, + PWM_FLEXIO2 = 1, +} flexio_pwm_id_t; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_flexio_pwm_init + * + * Description: + * Initialize a FLEXIO block for EPWM usage. + * + * Input Parameters: + * pwmid - A number identifying the pwm block. + * + * Returned Value: + * On success, a pointer to the lower half of the PWM driver is + * returned. NULL is returned on any failure. + * + ****************************************************************************/ + +struct pwm_lowerhalf_s *imx9_flexio_pwm_init(flexio_pwm_id_t pwmid); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_IMX9_FLEXIO_PWM */ +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_FLEXIO_PWM_H */ diff --git a/arch/arm64/src/imx9/imx9_gpio.c b/arch/arm64/src/imx9/imx9_gpio.c new file mode 100644 index 0000000000000..54db67a1469b5 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_gpio.c @@ -0,0 +1,278 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_gpio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "chip.h" +#include "arm64_internal.h" +#include "imx9_iomuxc.h" +#include "imx9_gpio.h" + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_gpio_dirout + ****************************************************************************/ + +static inline void imx9_gpio_dirout(uint32_t port, uint32_t pin) +{ + uint32_t regval = getreg32(IMX9_GPIO_PDDR(port)); + regval |= GPIO_PIN(pin); + putreg32(regval, IMX9_GPIO_PDDR(port)); +} + +/**************************************************************************** + * Name: imx9_gpio_dirin + ****************************************************************************/ + +static inline void imx9_gpio_dirin(uint32_t port, uint32_t pin) +{ + uint32_t regval = getreg32(IMX9_GPIO_PDDR(port)); + regval &= ~GPIO_PIN(pin); + putreg32(regval, IMX9_GPIO_PDDR(port)); +} + +/**************************************************************************** + * Name: imx9_gpio_setoutput + ****************************************************************************/ + +static void imx9_gpio_setoutput(uint32_t port, uint32_t pin, bool value) +{ + uintptr_t regaddr = IMX9_GPIO_PDOR(port); + uint32_t regval; + + regval = getreg32(regaddr); + if (value) + { + regval |= GPIO_PIN(pin); + } + else + { + regval &= ~GPIO_PIN(pin); + } + + putreg32(regval, regaddr); +} + +/**************************************************************************** + * Name: imx9_gpio_getpin_status + ****************************************************************************/ + +static inline bool imx9_gpio_get_pinstatus(uint32_t port, uint32_t pin) +{ + uintptr_t regaddr = IMX9_GPIO_PSOR(port); + uint32_t regval; + + regval = getreg32(regaddr); + return ((regval & GPIO_PIN(pin)) != 0); +} + +/**************************************************************************** + * Name: imx9_gpio_getinput + ****************************************************************************/ + +static inline bool imx9_gpio_getinput(uint32_t port, uint32_t pin) +{ + uintptr_t regaddr = IMX9_GPIO_PDIR(port); + uint32_t regval; + + regval = getreg32(regaddr); + return ((regval & GPIO_PIN(pin)) != 0); +} + +/**************************************************************************** + * Name: imx9_gpio_configinput + ****************************************************************************/ + +static int imx9_gpio_configinput(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + DEBUGASSERT((unsigned int)port < IMX9_GPIO_NPORTS); + + /* Configure pin as in input */ + + imx9_gpio_dirin(port, pin); + + return OK; +} + +/**************************************************************************** + * Name: imx9_gpio_configoutput + ****************************************************************************/ + +static inline int imx9_gpio_configoutput(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + bool value = ((pinset & GPIO_OUTPUT_ONE) != 0); + + DEBUGASSERT((unsigned int)port < IMX9_GPIO_NPORTS); + + /* Set the output value */ + + imx9_gpio_setoutput(port, pin, value); + + /* Convert the configured input GPIO to an output */ + + imx9_gpio_dirout(port, pin); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_config_gpio + * + * Description: + * Configure a GPIO pin based on pin-encoded description of the pin. + * + ****************************************************************************/ + +int imx9_config_gpio(gpio_pinset_t pinset) +{ + irqstate_t flags; + int ret; + + /* Configure the pin as an input initially to avoid any spurious outputs */ + + flags = enter_critical_section(); + + /* Configure based upon the pin mode */ + + switch (pinset & GPIO_MODE_MASK) + { + case GPIO_INPUT: + { + /* Configure the pin as a GPIO input */ + + ret = imx9_gpio_configinput(pinset); + } + break; + + case GPIO_OUTPUT: + { + /* First configure the pin as a GPIO input to avoid output + * glitches. + */ + + ret = imx9_gpio_configinput(pinset); + if (ret >= 0) + { + /* Convert the input to an output */ + + ret = imx9_gpio_configoutput(pinset); + } + } + break; + +#ifdef CONFIG_IMX9_GPIO_IRQ + case GPIO_INTERRUPT: + { + /* Configure the pin as a GPIO input */ + + ret = imx9_gpio_configinput(pinset); + if (ret == OK) + { + ret = imx9_gpioirq_configure(pinset); + } + } + break; +#endif + + default: + ret = -EINVAL; + break; + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: imx9_gpio_write + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void imx9_gpio_write(gpio_pinset_t pinset, bool value) +{ + irqstate_t flags; + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + DEBUGASSERT((unsigned int)port < IMX9_GPIO_NPORTS); + + flags = enter_critical_section(); + imx9_gpio_setoutput(port, pin, value); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: imx9_gpio_read + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool imx9_gpio_read(gpio_pinset_t pinset) +{ + irqstate_t flags; + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + bool value; + + DEBUGASSERT((unsigned int)port < IMX9_GPIO_NPORTS); + + flags = enter_critical_section(); + if ((pinset & (GPIO_OUTPUT)) == (GPIO_OUTPUT)) + { + value = imx9_gpio_get_pinstatus(port, pin); + } + else + { + value = imx9_gpio_getinput(port, pin); + } + + leave_critical_section(flags); + return value; +} diff --git a/arch/arm64/src/imx9/imx9_gpio.h b/arch/arm64/src/imx9/imx9_gpio.h new file mode 100644 index 0000000000000..1c7f44a53f6fe --- /dev/null +++ b/arch/arm64/src/imx9/imx9_gpio.h @@ -0,0 +1,337 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_gpio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_GPIO_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_GPIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "chip.h" +#include "hardware/imx9_gpio.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* GPIO pinset is a 16-bit word used to configure the GPIO settings. The + * encoding is as follows... + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * ENCODING MMVX BEEG GGGP PPPP + * GPIO INPUT 00.. BEEG GGGP PPPP + * INT INPUT 11.. BEEG GGGP PPPP + * GPIO OUTPUT 01V. ...G GGGP PPPP + */ + +/* Input/Output Selection: + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * ENCODING MM.. .... .... .... + */ + +#define GPIO_MODE_SHIFT (14) /* Bits 14-15: Pin mode */ +#define GPIO_MODE_MASK (0x3 << GPIO_MODE_SHIFT) +# define GPIO_INPUT (0 << GPIO_MODE_SHIFT) /* GPIO input */ +# define GPIO_OUTPUT (1 << GPIO_MODE_SHIFT) /* GPIO output */ +# define GPIO_INTERRUPT (2 << GPIO_MODE_SHIFT) /* Interrupt input */ + +/* Initial Output Value: + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * GPIO OUTPUT 01V. .... .... .... + */ + +#define GPIO_OUTPUT_SHIFT (13) /* Bit 13: Initial output */ +#define GPIO_OUTPUT_MASK (0x1 << GPIO_OUTPUT_SHIFT) +# define GPIO_OUTPUT_ZERO (0 << GPIO_OUTPUT_SHIFT) /* Bit 29: 0=Initial output is low */ +# define GPIO_OUTPUT_ONE (1 << GPIO_OUTPUT_SHIFT) /* Bit 29: 1=Initial output is high */ + +/* Interrupt on both edges configuration + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * INT INPUT 11.. B... .... .... + */ + +#define GPIO_INTBOTHCFG_SHIFT (11) /* Bit 11: Interrupt both edges configuration */ +#define GPIO_INTBOTHCFG_MASK (1 << GPIO_INTBOTHCFG_SHIFT) +# define GPIO_INTBOTH_EDGES (1 << GPIO_INTBOTHCFG_SHIFT) + +/* Interrupt edge/level configuration + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * INT INPUT 11.. .EE. .... .... + */ + +#define GPIO_INTCFG_SHIFT (9) /* Bits 9-10: Interrupt edge/level configuration */ +#define GPIO_INTCFG_MASK (0x3 << GPIO_INTCFG_SHIFT) +# define GPIO_INT_LOWLEVEL (0 << GPIO_INTCFG_SHIFT) +# define GPIO_INT_HIGHLEVEL (1 << GPIO_INTCFG_SHIFT) +# define GPIO_INT_RISINGEDGE (2 << GPIO_INTCFG_SHIFT) +# define GPIO_INT_FALLINGEDGE (3 << GPIO_INTCFG_SHIFT) + +/* GPIO Port Number + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * GPIO IN/OUT .... ...G GGG. .... + */ + +#define GPIO_PORT_SHIFT (5) /* Bits 5-8: GPIO port index */ +#define GPIO_PORT_MASK (0xf << GPIO_PORT_SHIFT) +# define GPIO_PORT1 (GPIO1 << GPIO_PORT_SHIFT) /* GPIO1 */ +# define GPIO_PORT2 (GPIO2 << GPIO_PORT_SHIFT) /* GPIO2 */ +# define GPIO_PORT3 (GPIO3 << GPIO_PORT_SHIFT) /* GPIO3 */ +# define GPIO_PORT4 (GPIO4 << GPIO_PORT_SHIFT) /* GPIO4 */ +# define GPIO_PORT5 (GPIO5 << GPIO_PORT_SHIFT) /* GPIO5 */ +# define GPIO_PORT6 (GPIO6 << GPIO_PORT_SHIFT) /* GPIO6 */ +# define GPIO_PORT7 (GPIO7 << GPIO_PORT_SHIFT) /* GPIO7 */ +# define GPIO_PORT8 (GPIO8 << GPIO_PORT_SHIFT) /* GPIO8 */ +# define GPIO_PORT9 (GPIO9 << GPIO_PORT_SHIFT) /* GPIO9 */ +# define GPIO_PORT10 (GPIO10 << GPIO_PORT_SHIFT) /* GPIO10 */ +# define GPIO_PORT11 (GPIO11 << GPIO_PORT_SHIFT) /* GPIO11 */ +# define GPIO_PORT12 (GPIO12 << GPIO_PORT_SHIFT) /* GPIO12 */ +# define GPIO_PORT13 (GPIO13 << GPIO_PORT_SHIFT) /* GPIO13 */ + +/* GPIO Pin Number: + * + * 1111 1100 0000 0000 + * 5432 1098 7654 3210 + * GPIO IN/OUT .... .... ...P PPPP + */ + +#define GPIO_PIN_SHIFT (0) /* Bits 0-4: GPIO pin number */ +#define GPIO_PIN_MASK (0x1f << GPIO_PIN_SHIFT) +# define GPIO_PIN0 (0 << GPIO_PIN_SHIFT) /* Pin 0 */ +# define GPIO_PIN1 (1 << GPIO_PIN_SHIFT) /* Pin 1 */ +# define GPIO_PIN2 (2 << GPIO_PIN_SHIFT) /* Pin 2 */ +# define GPIO_PIN3 (3 << GPIO_PIN_SHIFT) /* Pin 3 */ +# define GPIO_PIN4 (4 << GPIO_PIN_SHIFT) /* Pin 4 */ +# define GPIO_PIN5 (5 << GPIO_PIN_SHIFT) /* Pin 5 */ +# define GPIO_PIN6 (6 << GPIO_PIN_SHIFT) /* Pin 6 */ +# define GPIO_PIN7 (7 << GPIO_PIN_SHIFT) /* Pin 7 */ +# define GPIO_PIN8 (8 << GPIO_PIN_SHIFT) /* Pin 8 */ +# define GPIO_PIN9 (9 << GPIO_PIN_SHIFT) /* Pin 9 */ +# define GPIO_PIN10 (10 << GPIO_PIN_SHIFT) /* Pin 10 */ +# define GPIO_PIN11 (11 << GPIO_PIN_SHIFT) /* Pin 11 */ +# define GPIO_PIN12 (12 << GPIO_PIN_SHIFT) /* Pin 12 */ +# define GPIO_PIN13 (13 << GPIO_PIN_SHIFT) /* Pin 13 */ +# define GPIO_PIN14 (14 << GPIO_PIN_SHIFT) /* Pin 14 */ +# define GPIO_PIN15 (15 << GPIO_PIN_SHIFT) /* Pin 15 */ +# define GPIO_PIN16 (16 << GPIO_PIN_SHIFT) /* Pin 16 */ +# define GPIO_PIN17 (17 << GPIO_PIN_SHIFT) /* Pin 17 */ +# define GPIO_PIN18 (18 << GPIO_PIN_SHIFT) /* Pin 18 */ +# define GPIO_PIN19 (19 << GPIO_PIN_SHIFT) /* Pin 19 */ +# define GPIO_PIN20 (20 << GPIO_PIN_SHIFT) /* Pin 20 */ +# define GPIO_PIN21 (21 << GPIO_PIN_SHIFT) /* Pin 21 */ +# define GPIO_PIN22 (22 << GPIO_PIN_SHIFT) /* Pin 22 */ +# define GPIO_PIN23 (23 << GPIO_PIN_SHIFT) /* Pin 23 */ +# define GPIO_PIN24 (24 << GPIO_PIN_SHIFT) /* Pin 24 */ +# define GPIO_PIN25 (25 << GPIO_PIN_SHIFT) /* Pin 25 */ +# define GPIO_PIN26 (26 << GPIO_PIN_SHIFT) /* Pin 26 */ +# define GPIO_PIN27 (27 << GPIO_PIN_SHIFT) /* Pin 27 */ +# define GPIO_PIN28 (28 << GPIO_PIN_SHIFT) /* Pin 28 */ +# define GPIO_PIN29 (29 << GPIO_PIN_SHIFT) /* Pin 29 */ +# define GPIO_PIN30 (30 << GPIO_PIN_SHIFT) /* Pin 30 */ +# define GPIO_PIN31 (31 << GPIO_PIN_SHIFT) /* Pin 31 */ + +/* Port access via global LUT */ + +#define IMX9_GPIO_BASE(n) g_gpio_base[n] /* Use GPIO1..GPIOn macros as indices */ + +#define IMX9_GPIO_VERID(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_VERID_OFFSET) +#define IMX9_GPIO_PARAM(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PARAM_OFFSET) +#define IMX9_GPIO_LOCK(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_LOCK_OFFSET) +#define IMX9_GPIO_PCNS(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PCNS_OFFSET) +#define IMX9_GPIO_ICNS(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_ICNS_OFFSET) +#define IMX9_GPIO_PCNP(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PCNP_OFFSET) +#define IMX9_GPIO_ICNP(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_ICNP_OFFSET) +#define IMX9_GPIO_PDOR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PDOR_OFFSET) +#define IMX9_GPIO_PSOR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PSOR_OFFSET) +#define IMX9_GPIO_PCOR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PCOR_OFFSET) +#define IMX9_GPIO_PTOR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PTOR_OFFSET) +#define IMX9_GPIO_PDIR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PDIR_OFFSET) +#define IMX9_GPIO_PDDR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PDDR_OFFSET) +#define IMX9_GPIO_PIDR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_PIDR_OFFSET) +#define IMX9_GPIO_GICLR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_GICLR_OFFSET) +#define IMX9_GPIO_GICHR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_GICHR_OFFSET) + +/* Interrupt status flags, these have two channels. Channel is selected by + * setting / clearing ICRN.IRQS bit. + */ + +#define IMX9_GPIO_ISFR0(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_ISFR0_OFFSET) +#define IMX9_GPIO_ISFR1(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_ISFR1_OFFSET) + +/* GPIO PIN[0...31] and ICR[0...31] */ + +#define IMX9_GPIO_P0DR(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_P0DR_OFFSET) +#define IMX9_GPIO_PNDR(n, p) (IMX9_GPIO_P0DR(n) + ((p) * 0x4)) +#define IMX9_GPIO_ICR0(n) (IMX9_GPIO_BASE(n) + IMX9_GPIO_ICR0_OFFSET) +#define IMX9_GPIO_ICRN(n, p) (IMX9_GPIO_ICR0(n) + ((p) * 0x4)) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* The smallest integer type that can hold the GPIO encoding */ + +typedef uint16_t gpio_pinset_t; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/* Look-up table that maps GPIO1..GPIOn indexes into GPIO register base + * addresses + */ + +EXTERN const uintptr_t g_gpio_base[]; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_gpioirq_initialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * GPIO pins. + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_GPIO_IRQ +void imx9_gpioirq_initialize(void); +#else +# define imx9_gpioirq_initialize() +#endif + +/**************************************************************************** + * Name: imx9_config_gpio + * + * Description: + * Configure a GPIO pin based on bit-encoded description of the pin. + * + ****************************************************************************/ + +int imx9_config_gpio(gpio_pinset_t pinset); + +/**************************************************************************** + * Name: imx9_gpio_write + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void imx9_gpio_write(gpio_pinset_t pinset, bool value); + +/**************************************************************************** + * Name: imx9_gpio_read + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool imx9_gpio_read(gpio_pinset_t pinset); + +/**************************************************************************** + * Name: imx9_gpioirq_attach + * + * Description: + * Attach a pin interrupt handler. + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_GPIO_IRQ +int imx9_gpioirq_attach(gpio_pinset_t pinset, xcpt_t isr, void *arg); +#else +#define imx9_gpioirq_attach(pinset, isr, arg) 0 +#endif + +/**************************************************************************** + * Name: imx9_gpioirq_configure + * + * Description: + * Configure an interrupt for the specified GPIO pin. + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_GPIO_IRQ +int imx9_gpioirq_configure(gpio_pinset_t pinset); +#else +# define imx9_gpioirq_configure(pinset) 0 +#endif + +/**************************************************************************** + * Name: imx9_gpioirq_enable + * + * Description: + * Enable the interrupt for specified GPIO IRQ + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_GPIO_IRQ +int imx9_gpioirq_enable(gpio_pinset_t pinset); +#else +# define imx9_gpioirq_enable(pinset) 0 +#endif + +/**************************************************************************** + * Name: imx9_gpioirq_disable + * + * Description: + * Disable the interrupt for specified GPIO IRQ + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_GPIO_IRQ +int imx9_gpioirq_disable(gpio_pinset_t pinset); +#else +# define imx9_gpioirq_disable(pinset) 0 +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_GPIO_H */ diff --git a/arch/arm64/src/imx9/imx9_gpiobase.c b/arch/arm64/src/imx9/imx9_gpiobase.c new file mode 100644 index 0000000000000..cf5e1f0ddb117 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_gpiobase.c @@ -0,0 +1,49 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_gpiobase.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "imx9_gpio.h" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#if defined(CONFIG_ARCH_CHIP_IMX93) +/* Base address for the GPIO memory mapped registers */ + +const uintptr_t g_gpio_base[] = +{ + IMX9_GPIO1_BASE, + IMX9_GPIO2_BASE, + IMX9_GPIO3_BASE, + IMX9_GPIO4_BASE, +}; +#else +# error Unrecognized i.MX9 architecture +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ diff --git a/arch/arm64/src/imx9/imx9_gpioirq.c b/arch/arm64/src/imx9/imx9_gpioirq.c new file mode 100644 index 0000000000000..7290ff6852e24 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_gpioirq.c @@ -0,0 +1,300 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_gpioirq.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "arm64_internal.h" +#include "imx9_gpio.h" + +#ifdef CONFIG_IMX9_GPIO_IRQ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct imx9_portisr_s +{ + struct + { + xcpt_t isr; /* The interrupt service routine */ + void *arg; /* Argument passed to it */ + } + pins[IMX9_GPIO_NPINS]; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct imx9_portisr_s g_isrtab[IMX9_GPIO_NPORTS]; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_gpio_interrupt + * + * Description: + * GPIO interrupt handlers. iMX9 has two interrupt sources for each pin, + * the NuttX driver uses source 0. + * + ****************************************************************************/ + +static int imx9_gpio_interrupt(int irq, void *context, void *arg) +{ + uint32_t port = (uint32_t)((uintptr_t)arg) >> GPIO_PORT_SHIFT; + uint32_t status; + uint32_t pin; + uint32_t regaddr; + + /* Get the pending interrupt indications */ + + regaddr = IMX9_GPIO_ISFR0(port); + status = getreg32(regaddr); + + /* Decode the pending interrupts */ + + for (pin = 0; pin < 32 && status != 0; pin++) + { + /* Is the IRQ associated with this pin pending? */ + + uint32_t mask = (1 << pin); + if ((status & mask) != 0) + { + struct imx9_portisr_s *isrtab; + + /* Yes, clear the status bit and dispatch the interrupt */ + + putreg32(mask, regaddr); + status &= ~mask; + + /* Get the interrupt table for this port */ + + isrtab = &g_isrtab[port]; + if (isrtab->pins[pin].isr != NULL) + { + /* Run the user handler with the user's argument */ + + isrtab->pins[pin].isr(irq, context, isrtab->pins[pin].arg); + } + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_gpioirq_initialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * GPIO pins. + * + ****************************************************************************/ + +void imx9_gpioirq_initialize(void) +{ + uint32_t port; + uint32_t pin; + + /* Disable all GPIO interrupts at the source */ + + for (port = 0; port < IMX9_GPIO_NPORTS; port++) + { + for (pin = 0; pin < IMX9_GPIO_NPINS; pin++) + { + /* Reset the interrupt configuration, disabling the interrupt */ + + putreg32(0, IMX9_GPIO_ICRN(port, pin)); + } + } + + /* Disable all GPIO interrupts */ + + up_disable_irq(IMX9_IRQ_GPIO1_0); + up_disable_irq(IMX9_IRQ_GPIO1_1); + + up_disable_irq(IMX9_IRQ_GPIO2_0); + up_disable_irq(IMX9_IRQ_GPIO2_1); + + up_disable_irq(IMX9_IRQ_GPIO3_0); + up_disable_irq(IMX9_IRQ_GPIO3_1); + + up_disable_irq(IMX9_IRQ_GPIO4_0); + up_disable_irq(IMX9_IRQ_GPIO4_1); + + /* Attach the common GPIO interrupt handler and enable the interrupt */ + + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO1_0, + imx9_gpio_interrupt, (void *)GPIO_PORT1)); + up_enable_irq(IMX9_IRQ_GPIO1_0); + + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO2_0, + imx9_gpio_interrupt, (void *)GPIO_PORT2)); + up_enable_irq(IMX9_IRQ_GPIO2_0); + + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO3_0, + imx9_gpio_interrupt, (void *)GPIO_PORT3)); + up_enable_irq(IMX9_IRQ_GPIO3_0); + + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO4_0, + imx9_gpio_interrupt, (void *)GPIO_PORT4)); + up_enable_irq(IMX9_IRQ_GPIO4_0); +} + +/**************************************************************************** + * Name: imx9_gpioirq_attach + * + * Description: + * Attach a pin interrupt handler. + * + ****************************************************************************/ + +int imx9_gpioirq_attach(gpio_pinset_t pinset, xcpt_t isr, void *arg) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + /* Atomically change the handler */ + + irqstate_t flags = enter_critical_section(); + + g_isrtab[port].pins[pin].isr = isr; + g_isrtab[port].pins[pin].arg = arg; + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: imx9_gpioirq_configure + * + * Description: + * Configure an interrupt for the specified GPIO pin. + * + ****************************************************************************/ + +int imx9_gpioirq_configure(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + + /* Nothing much to do here, just reset the IRQ config */ + + putreg32(0, IMX9_GPIO_ICRN(port, pin)); + + return OK; +} + +/**************************************************************************** + * Name: imx9_gpioirq_enable + * + * Description: + * Enable the interrupt for specified GPIO IRQ + * + ****************************************************************************/ + +int imx9_gpioirq_enable(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + uint32_t both = (pinset & GPIO_INTBOTHCFG_MASK) >> GPIO_INTBOTHCFG_SHIFT; + uint32_t icr = (pinset & GPIO_INTCFG_MASK); + uint32_t regval; + uintptr_t regaddr; + + /* Perform RMW to the specific pin */ + + regaddr = IMX9_GPIO_ICRN(port, pin); + regval = getreg32(regaddr); + regval &= ~IMX9_GPIO_ICRN_MASK; + + if (both) + { + regval |= IMX9_GPIO_ICRN_BOTH; + } + else if (icr == GPIO_INT_LOWLEVEL) + { + regval |= IMX9_GPIO_ICRN_ZERO; + } + else if (icr == GPIO_INT_HIGHLEVEL) + { + regval |= IMX9_GPIO_ICRN_ONE; + } + else if (icr == GPIO_INT_RISINGEDGE) + { + regval |= IMX9_GPIO_ICRN_RISING; + } + else /* GPIO_INT_FALLINGEDGE */ + { + regval |= IMX9_GPIO_ICRN_FALLING; + } + + putreg32(regval, regaddr); + return OK; +} + +/**************************************************************************** + * Name: imx9_gpioirq_disable + * + * Description: + * Disable the interrupt for specified GPIO IRQ + * + ****************************************************************************/ + +int imx9_gpioirq_disable(gpio_pinset_t pinset) +{ + uint32_t port = (pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + uint32_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + uint32_t regval; + uintptr_t regaddr; + + /* Perform RMW to the specific pin */ + + regaddr = IMX9_GPIO_ICRN(port, pin); + regval = getreg32(regaddr); + regval &= ~IMX9_GPIO_ICRN_MASK; + + putreg32(regval, regaddr); + return OK; +} + +#endif /* CONFIG_IMX9_GPIO_IRQ */ diff --git a/arch/arm64/src/imx9/imx9_iomuxc.c b/arch/arm64/src/imx9/imx9_iomuxc.c new file mode 100644 index 0000000000000..b5f8b657cf996 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_iomuxc.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_iomuxc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "arm64_internal.h" +#include "imx9_iomuxc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_iomux_configure + * + * Description: + * This function writes the encoded pad configuration to the Pad Control + * register. + * + * Input Parameters: + * cfg - The IOMUX configuration + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int imx9_iomux_configure(iomux_cfg_t cfg) +{ + if (!cfg.padcfg.ctlreg) + { + return -EINVAL; + } + + putreg32(cfg.padcfg.mode | cfg.mux, cfg.padcfg.ctlreg); + + if (cfg.padcfg.dsyreg) + { + putreg32(cfg.padcfg.dsy, cfg.padcfg.dsyreg); + } + + if (cfg.padcfg.padreg) + { + putreg32(cfg.pad, cfg.padcfg.padreg); + } + + return OK; +} + +/**************************************************************************** + * Name: imx9_iomux_configure + * + * Description: + * This can be used to forcibly set a pad to GPIO mode. This overrides and + * disconnects any peripheral using the pin. + * + * Input Parameters: + * cfg - The IOMUX configuration. + * sion - if true; sets SION, otherwise clears it. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int imx9_iomux_gpio(iomux_cfg_t cfg, bool sion) +{ + uint32_t reg_sion; + + if (!cfg.padcfg.ctlreg) + { + return -EINVAL; + } + + /* Set sion if requested to do so */ + + reg_sion = sion ? IOMUXC_MUX_SION_ON : 0; + + /* Based on pad number, either ALT0/ALT5 sets the pad as GPIO */ + + if ((cfg.padcfg.ctlreg >= IOMUXC_MUX_CTL_GPIO_IO00_OFFSET) && + (cfg.padcfg.ctlreg <= IOMUXC_MUX_CTL_GPIO_IO29_OFFSET)) + { + putreg32(IOMUXC_MUX_MODE_ALT0 | reg_sion, cfg.padcfg.ctlreg); + } + else + { + putreg32(IOMUXC_MUX_MODE_ALT5 | reg_sion, cfg.padcfg.ctlreg); + } + + return OK; +} diff --git a/arch/arm64/src/imx9/imx9_iomuxc.h b/arch/arm64/src/imx9/imx9_iomuxc.h new file mode 100644 index 0000000000000..6b9c8617b3051 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_iomuxc.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_iomuxc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_IOMUXC_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_IOMUXC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "hardware/imx9_iomuxc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IOMUX_PADCFG(_ctlreg, _mode, _dsyreg, _dsy, _padreg) \ + { \ + .ctlreg = (_ctlreg), \ + .padreg = (_padreg), \ + .dsyreg = (_dsyreg), \ + .mode = (_mode), \ + .dsy = (_dsy), \ + } + +#define IOMUX_CFG(_padcfg, _pad, _mux) \ + (iomux_cfg_t) \ + { \ + .padcfg = _padcfg, \ + .pad = (_pad), \ + .mux = (_mux), \ + } + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Information for the pad alternate function */ + +struct iomux_padcfg_s +{ + /* Register offsets for PAD */ + + uintptr_t ctlreg; + uintptr_t padreg; + uintptr_t dsyreg; + + /* ALT and input daisy configuration for pad */ + + uint32_t mode; + uint32_t dsy; +}; + +struct iomux_cfg_s +{ + struct iomux_padcfg_s padcfg; + + /* Register values */ + + uint32_t pad; + uint32_t mux; +}; +typedef struct iomux_cfg_s iomux_cfg_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: imx9_iomux_configure + * + * Description: + * This function writes the encoded pad configuration to the Pad Control + * register. + * + * Input Parameters: + * cfg - The IOMUX configuration + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int imx9_iomux_configure(iomux_cfg_t cfg); + +/**************************************************************************** + * Name: imx9_iomux_configure + * + * Description: + * This can be used to forcibly set a pad to GPIO mode. This overrides and + * disconnects any peripheral using the pin. + * + * Input Parameters: + * cfg - The IOMUX configuration. + * sion - if true; sets SION, otherwise clears it. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int imx9_iomux_gpio(iomux_cfg_t cfg, bool sion); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_IOMUXC_H */ diff --git a/arch/arm64/src/imx9/imx9_lowputc.c b/arch/arm64/src/imx9/imx9_lowputc.c new file mode 100644 index 0000000000000..c41f6f43eed12 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lowputc.c @@ -0,0 +1,532 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_lowputc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include "hardware/imx9_pinmux.h" +#include "hardware/imx9_lpuart.h" + +#include "arm64_internal.h" + +#include "imx9_lowputc.h" +#include "imx9_ccm.h" +#include "imx9_iomuxc.h" +#include "hardware/imx9_ccm.h" +#include "hardware/imx9_pinmux.h" + +#include /* Include last: has dependencies */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#if defined(CONFIG_LPUART1_SERIAL_CONSOLE) +# define IMX9_CONSOLE_DEVOFF 0 +# define IMX9_CONSOLE_BASE IMX9_LPUART1_BASE +# define IMX9_CONSOLE_BAUD CONFIG_LPUART1_BAUD +# define IMX9_CONSOLE_BITS CONFIG_LPUART1_BITS +# define IMX9_CONSOLE_PARITY CONFIG_LPUART1_PARITY +# define IMX9_CONSOLE_2STOP CONFIG_LPUART1_2STOP +#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) +# define IMX9_CONSOLE_DEVNUM 1 +# define IMX9_CONSOLE_BASE IMX9_LPUART2_BASE +# define IMX9_CONSOLE_BAUD CONFIG_LPUART2_BAUD +# define IMX9_CONSOLE_BITS CONFIG_LPUART2_BITS +# define IMX9_CONSOLE_PARITY CONFIG_LPUART2_PARITY +# define IMX9_CONSOLE_2STOP CONFIG_LPUART2_2STOP +#elif defined(CONFIG_LPUART3_SERIAL_CONSOLE) +# define IMX9_CONSOLE_DEVNUM 2 +# define IMX9_CONSOLE_BASE IMX9_LPUART3_BASE +# define IMX9_CONSOLE_BAUD CONFIG_LPUART3_BAUD +# define IMX9_CONSOLE_BITS CONFIG_LPUART3_BITS +# define IMX9_CONSOLE_PARITY CONFIG_LPUART3_PARITY +# define IMX9_CONSOLE_2STOP CONFIG_LPUART3_2STOP +#elif defined(CONFIG_LPUART4_SERIAL_CONSOLE) +# define IMX9_CONSOLE_DEVNUM 3 +# define IMX9_CONSOLE_BASE IMX9_LPUART4_BASE +# define IMX9_CONSOLE_BAUD CONFIG_LPUART4_BAUD +# define IMX9_CONSOLE_BITS CONFIG_LPUART4_BITS +# define IMX9_CONSOLE_PARITY CONFIG_LPUART4_PARITY +# define IMX9_CONSOLE_2STOP CONFIG_LPUART4_2STOP +#elif defined(CONFIG_LPUART5_SERIAL_CONSOLE) +# define IMX9_CONSOLE_DEVNUM 4 +# define IMX9_CONSOLE_BASE IMX9_LPUART5_BASE +# define IMX9_CONSOLE_BAUD CONFIG_LPUART5_BAUD +# define IMX9_CONSOLE_BITS CONFIG_LPUART5_BITS +# define IMX9_CONSOLE_PARITY CONFIG_LPUART5_PARITY +# define IMX9_CONSOLE_2STOP CONFIG_LPUART5_2STOP +#elif defined(CONFIG_LPUART6_SERIAL_CONSOLE) +# define IMX9_CONSOLE_DEVNUM 5 +# define IMX9_CONSOLE_BASE IMX9_LPUART6_BASE +# define IMX9_CONSOLE_BAUD CONFIG_LPUART6_BAUD +# define IMX9_CONSOLE_BITS CONFIG_LPUART6_BITS +# define IMX9_CONSOLE_PARITY CONFIG_LPUART6_PARITY +# define IMX9_CONSOLE_2STOP CONFIG_LPUART6_2STOP +#elif defined(CONFIG_LPUART7_SERIAL_CONSOLE) +# define IMX9_CONSOLE_DEVNUM 6 +# define IMX9_CONSOLE_BASE IMX9_LPUART7_BASE +# define IMX9_CONSOLE_BAUD CONFIG_LPUART7_BAUD +# define IMX9_CONSOLE_BITS CONFIG_LPUART7_BITS +# define IMX9_CONSOLE_PARITY CONFIG_LPUART7_PARITY +# define IMX9_CONSOLE_2STOP CONFIG_LPUART7_2STOP +#elif defined(CONFIG_LPUART8_SERIAL_CONSOLE) +# define IMX9_CONSOLE_DEVNUM 7 +# define IMX9_CONSOLE_BASE IMX9_LPUART8_BASE +# define IMX9_CONSOLE_BAUD CONFIG_LPUART8_BAUD +# define IMX9_CONSOLE_BITS CONFIG_LPUART8_BITS +# define IMX9_CONSOLE_PARITY CONFIG_LPUART8_PARITY +# define IMX9_CONSOLE_2STOP CONFIG_LPUART8_2STOP +#endif + +#define ABS(n) (((n) < 0) ? -(n) : (n)) + +/* Clocking *****************************************************************/ + +/* Functional clocking is provided via the PCC. The PCC clocking must + * be configured by board-specific logic prior to using the LPUART. + */ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef IMX9_CONSOLE_BASE +static const struct uart_config_s g_console_config = +{ + .baud = IMX9_CONSOLE_BAUD, /* Configured baud */ + .parity = IMX9_CONSOLE_PARITY, /* 0=none, 1=odd, 2=even */ + .bits = IMX9_CONSOLE_BITS, /* Number of bits (5-9) */ + .stopbits2 = IMX9_CONSOLE_2STOP, /* true: Configure with 2 stop bits instead of 1 */ +}; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_lowsetup + * + * Description: + * Called at the very beginning of _start. Performs low level + * initialization including setup of the console UART. This UART done + * early so that the serial console is available for debugging very early + * in the boot sequence. + * + ****************************************************************************/ + +void imx9_lowsetup(void) +{ +#ifndef CONFIG_SUPPRESS_LPUART_CONFIG + +#ifdef CONFIG_IMX9_LPUART1 + /* Configure LPUART1 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + imx9_iomux_configure(MUX_LPUART1_RX); + imx9_iomux_configure(MUX_LPUART1_TX); +#ifdef CONFIG_LPUART1_OFLOWCONTROL + imx9_iomux_configure(MUX_LPUART1_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) + imx9_iomux_configure(MUX_LPUART1_RTS); +#endif +#endif + +#ifdef CONFIG_IMX9_LPUART2 + + /* Configure LPUART2 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + imx9_iomux_configure(MUX_LPUART2_RX); + imx9_iomux_configure(MUX_LPUART2_TX); +#ifdef CONFIG_LPUART2_OFLOWCONTROL + imx9_iomux_configure(MUX_LPUART2_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL))) + imx9_iomux_configure(MUX_LPUART2_RTS); +#endif +#endif + +#ifdef CONFIG_IMX9_LPUART3 + + /* Configure LPUART3 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + imx9_iomux_configure(MUX_LPUART3_RX); + imx9_iomux_configure(MUX_LPUART3_TX); +#ifdef CONFIG_LPUART3_OFLOWCONTROL + imx9_iomux_configure(MUX_LPUART3_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL))) + imx9_iomux_configure(MUX_LPUART3_RTS); +#endif +#endif + +#ifdef CONFIG_IMX9_LPUART4 + + /* Configure LPUART4 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + imx9_iomux_configure(LPUART4_RX); + imx9_iomux_configure(LPUART4_TX); +#ifdef CONFIG_LPUART4_OFLOWCONTROL + imx9_iomux_configure(LPUART4_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL))) + imx9_iomux_configure(LPUART4_RTS); +#endif +#endif + +#ifdef CONFIG_IMX9_LPUART5 + + /* Configure LPUART5 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + imx9_iomux_configure(MUX_LPUART5_RX); + imx9_iomux_configure(MUX_LPUART5_TX); +#ifdef CONFIG_LPUART5_OFLOWCONTROL + imx9_iomux_configure(MUX_LPUART5_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL))) + imx9_iomux_configure(MUX_LPUART5_RTS); +#endif +#endif + +#ifdef CONFIG_IMX9_LPUART6 + + /* Configure LPUART6 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + imx9_iomux_configure(MUX_LPUART6_RX); + imx9_iomux_configure(MUX_LPUART6_TX); +#ifdef CONFIG_LPUART6_OFLOWCONTROL + imx9_iomux_configure(MUX_LPUART6_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL))) + imx9_iomux_configure(MUX_LPUART6_RTS); +#endif +#endif + +#ifdef CONFIG_IMX9_LPUART7 + + /* Configure LPUART7 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + imx9_iomux_configure(MUX_LPUART7_RX); + imx9_iomux_configure(MUX_LPUART7_TX); +#ifdef CONFIG_LPUART7_OFLOWCONTROL + imx9_iomux_configure(MUX_LPUART7_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL))) + imx9_iomux_configure(MUX_LPUART7_RTS); +#endif +#endif + +#ifdef CONFIG_IMX9_LPUART8 + + /* Configure LPUART8 pins: RXD and TXD. Also configure RTS and CTS if flow + * control is enabled. + */ + + imx9_iomux_configure(MUX_LPUART8_RX); + imx9_iomux_configure(MUX_LPUART8_TX); +#ifdef CONFIG_LPUART0_OFLOWCONTROL + imx9_iomux_configure(MUX_LPUART8_CTS); +#endif +#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL))) + imx9_iomux_configure(MUX_LPUART8_RTS); +#endif +#endif + +#ifdef IMX9_CONSOLE_BASE + /* Configure the serial console for initial, non-interrupt driver mode */ + + imx9_lpuart_configure(IMX9_CONSOLE_BASE, IMX9_CONSOLE_DEVOFF, + &g_console_config); +#endif + +#endif /* CONFIG_SUPPRESS_LPUART_CONFIG */ +} + +/**************************************************************************** + * Name: imx9_lpuart_configure + * + * Description: + * Configure a UART for non-interrupt driven operation + * + ****************************************************************************/ + +int imx9_lpuart_configure(uint32_t base, int uartnum, + const struct uart_config_s *config) +{ + int lpuart_freq = 24000000; + uint16_t sbr; + uint16_t temp_sbr; + uint32_t osr; + uint32_t temp_osr; + int temp_diff; + int calculated_baud; + int baud_diff; + uint32_t regval; + + /* Configure root clock to 24MHz OSC */ + + imx9_ccm_configure_root_clock(CCM_CR_LPUART1 + uartnum - 1, OSC_24M, 1); + + /* Enable peripheral clock */ + + imx9_ccm_gate_on(CCM_LPCG_LPUART1 + uartnum - 1, true); + + /* This LPUART instantiation uses a slightly different baud rate + * calculation. The idea is to use the best OSR (over-sampling rate) + * possible. + * + * NOTE: OSR is typically hard-set to 16 in other LPUART instantiations + * loop to find the best OSR value possible, one that generates minimum + * baud_diff iterate through the rest of the supported values of OSR + */ + + baud_diff = config->baud; + osr = 0; + sbr = 0; + + for (temp_osr = 4; temp_osr <= 32; temp_osr++) + { + /* Calculate the temporary sbr value */ + + temp_sbr = (lpuart_freq / (config->baud * temp_osr)); + + /* Set temp_sbr to 1 if the sourceClockInHz can not satisfy the + * desired baud rate. + */ + + if (temp_sbr == 0) + { + temp_sbr = 1; + } + + /* Calculate the baud rate based on the temporary OSR and SBR values */ + + calculated_baud = (lpuart_freq / (temp_osr * temp_sbr)); + temp_diff = ABS(calculated_baud - config->baud); + + /* Select the better value between srb and (sbr + 1) */ + + calculated_baud = (lpuart_freq / (temp_osr * (temp_sbr + 1))); + if (temp_diff > + ABS(calculated_baud - config->baud)) + { + temp_diff = ABS(calculated_baud - config->baud); + temp_sbr++; + } + + if (temp_diff <= baud_diff) + { + baud_diff = temp_diff; + osr = temp_osr; + sbr = temp_sbr; + } + } + + if (baud_diff > ((config->baud * 3) / 100)) + { + /* Unacceptable baud rate difference of more than 3% */ + + return ERROR; + } + + /* Reset all internal logic and registers, except the Global Register */ + + regval = getreg32(base + IMX9_LPUART_GLOBAL_OFFSET); + regval |= LPUART_GLOBAL_RST; + putreg32(regval, base + IMX9_LPUART_GLOBAL_OFFSET); + + regval &= ~LPUART_GLOBAL_RST; + putreg32(regval, base + IMX9_LPUART_GLOBAL_OFFSET); + + /* Construct MODIR register */ + + regval = 0; + + if (config->userts) + { + regval |= LPUART_MODIR_RXRTSE; + } + else if (config->users485) + { + /* Both TX and RX side can't control RTS, so this gives + * the RX side precedence. This should have been filtered + * in layers above anyway, but it's just a precaution. + */ + + regval |= LPUART_MODIR_TXRTSE; + } + + if (config->usects) + { + regval |= LPUART_MODIR_TXCTSE; + } + + if (config->invrts) + { + regval |= LPUART_MODIR_TXRTSPOL; + } + + putreg32(regval, base + IMX9_LPUART_MODIR_OFFSET); + + regval = 0; + + if ((osr > 3) && (osr < 8)) + { + regval |= LPUART_BAUD_BOTHEDGE; + } + + if (config->stopbits2) + { + regval |= LPUART_BAUD_SBNS; + } + + regval |= LPUART_BAUD_OSR(osr) | LPUART_BAUD_SBR(sbr); + putreg32(regval, base + IMX9_LPUART_BAUD_OFFSET); + + regval = 0; + if (config->parity == 1) + { + regval |= LPUART_CTRL_PE | LPUART_CTRL_PT_ODD; + } + else if (config->parity == 2) + { + regval |= LPUART_CTRL_PE | LPUART_CTRL_PT_EVEN; + } + + if (config->bits == 9 || (config->bits == 8 && config->parity != 0)) + { + regval |= LPUART_CTRL_M; + } + else if ((config->bits == 8)) + { + regval &= ~LPUART_CTRL_M; + } + else + { + /* REVISIT: Here should be added support of other bit modes. */ + + return -ENOSYS; + } + + regval |= LPUART_CTRL_RE | LPUART_CTRL_TE; + putreg32(regval, base + IMX9_LPUART_CTRL_OFFSET); + + return OK; +} + +/**************************************************************************** + * Name: arm64_earlyprintinit + * + * Description: + * Configure LPUART1 for non-interrupt driven operation + * + ****************************************************************************/ + +void arm64_earlyprintinit(char ch) +{ + /* Assume bootloader has already set up the LPUART1 */ +} + +/**************************************************************************** + * Name: arm64_lowputc + * + * Description: + * Output a byte with as few system dependencies as possible. This will + * even work BEFORE the console is initialized if we are booting from U- + * Boot (and the same UART is used for the console, of course.) + * + ****************************************************************************/ + +void arm64_lowputc(char ch) +{ +#ifdef IMX9_CONSOLE_BASE + while ((getreg32(IMX9_CONSOLE_BASE + IMX9_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } + + /* If the character to output is a newline, + * then pre-pend a carriage return + */ + + if (ch == '\n') + { + /* Send the carriage return by writing it into the UART_TXD register. */ + + putreg32((uint32_t)'\r', + IMX9_CONSOLE_BASE + IMX9_LPUART_DATA_OFFSET); + + /* Wait for the transmit register to be emptied. When the TXFE bit is + * non-zero, the TX Buffer FIFO is empty. + */ + + while ((getreg32(IMX9_CONSOLE_BASE + IMX9_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } + } + + /* Send the character by writing it into the UART_TXD register. */ + + putreg32((uint32_t)ch, IMX9_CONSOLE_BASE + IMX9_LPUART_DATA_OFFSET); + + /* Wait for the transmit register to be emptied. When the TXFE bit is + * non-zero, the TX Buffer FIFO is empty. + */ + + while ((getreg32(IMX9_CONSOLE_BASE + IMX9_LPUART_STAT_OFFSET) & + LPUART_STAT_TDRE) == 0) + { + } +#endif +} diff --git a/arch/arm64/src/imx9/imx9_lowputc.h b/arch/arm64/src/imx9/imx9_lowputc.h new file mode 100644 index 0000000000000..30aceed681c28 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lowputc.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_lowputc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H +#define __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include + +#include "arm64_internal.h" + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This structure describes the configuration of an UART */ + +struct uart_config_s +{ + uint32_t baud; /* Configured baud */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (5-9) */ + bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ + bool userts; /* True: Assert RTS when there are data to be sent */ + bool invrts; /* True: Invert sense of RTS pin (true=active high) */ + bool usects; /* True: Condition transmission on CTS asserted */ + bool users485; /* True: Assert RTS while transmission progresses */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_lowsetup + * + * Description: + * Called at the very beginning of _start. Performs low level + * initialization including setup of the console UART. This UART done + * early so that the serial console is available for debugging very early + * in the boot sequence. + * + ****************************************************************************/ + +void imx9_lowsetup(void); + +/**************************************************************************** + * Name: imx9_lpuart_configure + * + * Description: + * Configure a UART for non-interrupt driven operation + * + ****************************************************************************/ + +int imx9_lpuart_configure(uint32_t base, + int uartnum, + const struct uart_config_s *config); + +#endif /* __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H */ diff --git a/arch/arm64/src/imx9/imx9_lpi2c.c b/arch/arm64/src/imx9/imx9_lpi2c.c new file mode 100644 index 0000000000000..c1122b1ddcb7e --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lpi2c.c @@ -0,0 +1,2579 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_lpi2c.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "arm64_internal.h" +#include "imx9_ccm.h" +#include "imx9_clockconfig.h" +#include "imx9_gpio.h" +#include "imx9_iomuxc.h" +#include "imx9_lpi2c.h" + +#include "hardware/imx9_ccm.h" +#include "hardware/imx9_pinmux.h" +#include "hardware/imx9_lpi2c.h" + +#ifdef CONFIG_IMX9_LPI2C_DMA +# include "chip.h" +# include "imx9_edma.h" +# include "hardware/imx9_dmamux.h" +#endif + +/* At least one I2C peripheral must be enabled */ + +#ifdef CONFIG_IMX9_LPI2C + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* CONFIG_I2C_POLLED may be set so that I2C interrupts will not be used. + * Instead, CPU-intensive polling will be used. + */ + +/* Interrupt wait timeout in seconds and milliseconds */ + +#if !defined(CONFIG_IMX9_LPI2C_TIMEOSEC) && \ + !defined(CONFIG_IMX9_LPI2C_TIMEOMS) +# define CONFIG_IMX9_LPI2C_TIMEOSEC 0 +# define CONFIG_IMX9_LPI2C_TIMEOMS 500 /* Default is 500 milliseconds */ +#elif !defined(CONFIG_IMX9_LPI2C_TIMEOSEC) +# define CONFIG_IMX9_LPI2C_TIMEOSEC 0 /* User provided milliseconds */ +#elif !defined(CONFIG_IMX9_LPI2C_TIMEOMS) +# define CONFIG_IMX9_LPI2C_TIMEOMS 0 /* User provided seconds */ +#endif + +/* Interrupt wait time timeout in system timer ticks */ + +#ifndef CONFIG_IMX9_LPI2C_TIMEOTICKS +# define CONFIG_IMX9_LPI2C_TIMEOTICKS \ + (SEC2TICK(CONFIG_IMX9_LPI2C_TIMEOSEC) + \ + MSEC2TICK(CONFIG_IMX9_LPI2C_TIMEOMS)) +#endif + +#ifndef CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP +# define CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP \ + TICK2USEC(CONFIG_IMX9_LPI2C_TIMEOTICKS) +#endif + +/* Debug ********************************************************************/ + +/* I2C event trace logic. NOTE: trace uses the internal, non-standard, + * low-level debug interface syslog() but does not require that any other + * debug is enabled. + */ + +#ifndef CONFIG_I2C_TRACE +# define imx9_lpi2c_tracereset(p) +# define imx9_lpi2c_tracenew(p,s) +# define imx9_lpi2c_traceevent(p,e,a) +# define imx9_lpi2c_tracedump(p) +#endif + +#ifndef CONFIG_I2C_NTRACE +# define CONFIG_I2C_NTRACE 32 +#endif + +#ifdef CONFIG_I2C_SLAVE +# error I2C slave logic is not supported yet for IMX9 +#endif + +#define LPI2C_MASTER 1 +#define LPI2C_SLAVE 2 + +#define LPI2C_MSR_LIMITED_ERROR_MASK (LPI2C_MSR_ERROR_MASK & ~(LPI2C_MSR_FEF)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* Interrupt state */ + +enum imx9_intstate_e +{ + INTSTATE_IDLE = 0, /* No I2C activity */ + INTSTATE_WAITING, /* Waiting for completion of interrupt activity */ + INTSTATE_DONE, /* Interrupt activity complete */ +}; + +/* Trace events */ + +enum imx9_trace_e +{ + I2CEVENT_NONE = 0, /* No events have occurred with this status */ + I2CEVENT_SENDADDR, /* Start/Master bit set and address sent, param = msgc */ + I2CEVENT_SENDBYTE, /* Send byte, param = dcnt */ + I2CEVENT_RCVBYTE, /* Read more dta, param = dcnt */ + I2CEVENT_NOSTART, /* BTF on last byte with no restart, param = msgc */ + I2CEVENT_STARTRESTART, /* Last byte sent, re-starting, param = msgc */ + I2CEVENT_STOP, /* Last byte sten, send stop, param = 0 */ + I2CEVENT_ERROR /* Error occurred, param = 0 */ +}; + +/* Trace data */ + +struct imx9_trace_s +{ + uint32_t status; /* I2C 32-bit SR2|SR1 status */ + uint32_t count; /* Interrupt count when status change */ + enum imx9_intstate_e event; /* Last event that occurred with this status */ + uint32_t parm; /* Parameter associated with the event */ + clock_t time; /* First of event or first status */ +}; + +/* I2C Device hardware configuration */ + +struct imx9_lpi2c_config_s +{ + uint32_t base; /* LPI2C base address */ + uint8_t clk_root; /* LPI2C clock root */ + uint8_t clk_gate; /* LPI2C clock gate */ + uint16_t busy_idle; /* LPI2C Bus Idle Timeout */ + uint8_t filtscl; /* Glitch Filter for SCL pin */ + uint8_t filtsda; /* Glitch Filter for SDA pin */ + iomux_cfg_t scl_pin; /* Peripheral configuration for SCL as SCL */ + iomux_cfg_t sda_pin; /* Peripheral configuration for SDA as SDA */ +#if defined(CONFIG_I2C_RESET) + gpio_pinset_t reset_scl_pin; /* GPIO configuration for SCL as GPIO */ + gpio_pinset_t reset_sda_pin; /* GPIO configuration for SDA as GPIO */ +#endif + uint8_t mode; /* Master or Slave mode */ +#ifndef CONFIG_I2C_POLLED + uint32_t irq; /* Event IRQ */ +#endif +#ifdef CONFIG_IMX9_LPI2C_DMA + uint32_t dma_rxreqsrc; /* DMA mux rx source */ + uint32_t dma_txreqsrc; /* DMA mux tx source */ +#endif +}; + +/* I2C Device Private Data */ + +struct imx9_lpi2c_priv_s +{ + /* Standard I2C operations */ + + const struct i2c_ops_s *ops; + + /* Port configuration */ + + const struct imx9_lpi2c_config_s *config; + + int refs; /* Reference count */ + mutex_t lock; /* Mutual exclusion mutex */ +#ifndef CONFIG_I2C_POLLED + sem_t sem_isr; /* Interrupt wait semaphore */ +#endif + volatile uint8_t intstate; /* Interrupt handshake (see enum imx9_intstate_e) */ + + uint8_t msgc; /* Message count */ + struct i2c_msg_s *msgv; /* Message list */ + uint8_t *ptr; /* Current message buffer */ + uint32_t frequency; /* Current I2C frequency */ + int dcnt; /* Current message length */ + uint16_t flags; /* Current message flags */ + + /* I2C trace support */ + +#ifdef CONFIG_I2C_TRACE + int tndx; /* Trace array index */ + clock_t start_time; /* Time when the trace was started */ + + /* The actual trace data */ + + struct imx9_trace_s trace[CONFIG_I2C_NTRACE]; +#endif + + uint32_t status; /* End of transfer SR2|SR1 status */ + +#ifdef CONFIG_IMX9_LPI2C_DMA + DMACH_HANDLE rxdma; /* rx DMA handle */ + DMACH_HANDLE txdma; /* tx DMA handle */ + uint16_t cmnds[CONFIG_IMX9_LPI2C_DMA_MAXMSG]; /* Commands */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline uint32_t +imx9_lpi2c_getreg(struct imx9_lpi2c_priv_s *priv, uint16_t offset); +static inline void imx9_lpi2c_putreg(struct imx9_lpi2c_priv_s *priv, + uint16_t offset, uint32_t value); +static inline void imx9_lpi2c_modifyreg(struct imx9_lpi2c_priv_s *priv, + uint16_t offset, uint32_t clearbits, + uint32_t setbits); + +#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO +static uint32_t imx9_lpi2c_toticks(int msgc, struct i2c_msg_s *msgs); +#endif /* CONFIG_IMX9_LPI2C_DYNTIMEO */ + +static inline int +imx9_lpi2c_sem_waitdone(struct imx9_lpi2c_priv_s *priv); + +#ifdef CONFIG_I2C_TRACE +static void imx9_lpi2c_tracereset(struct imx9_lpi2c_priv_s *priv); +static void imx9_lpi2c_tracenew(struct imx9_lpi2c_priv_s *priv, + uint32_t status); +static void imx9_lpi2c_traceevent(struct imx9_lpi2c_priv_s *priv, + enum imx9_trace_e event, uint32_t parm); +static void imx9_lpi2c_tracedump(struct imx9_lpi2c_priv_s *priv); +#endif /* CONFIG_I2C_TRACE */ + +static void imx9_lpi2c_setclock(struct imx9_lpi2c_priv_s *priv, + uint32_t frequency); +static inline void imx9_lpi2c_sendstart(struct imx9_lpi2c_priv_s *priv, + uint8_t address); +static inline void imx9_lpi2c_sendstop(struct imx9_lpi2c_priv_s *priv); +static inline uint32_t +imx9_lpi2c_getstatus(struct imx9_lpi2c_priv_s *priv); + +static int imx9_lpi2c_isr_process(struct imx9_lpi2c_priv_s *priv); + +#ifndef CONFIG_I2C_POLLED +static int imx9_lpi2c_isr(int irq, void *context, void *arg); +#endif /* !CONFIG_I2C_POLLED */ + +static void imx9_lpi2c_clock_enable(struct imx9_lpi2c_priv_s *priv); +static void imx9_lpi2c_clock_disable(struct imx9_lpi2c_priv_s *priv); +static int imx9_lpi2c_init(struct imx9_lpi2c_priv_s *priv); +static int imx9_lpi2c_deinit(struct imx9_lpi2c_priv_s *priv); +static int imx9_lpi2c_transfer(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count); +#ifdef CONFIG_I2C_RESET +static int imx9_lpi2c_reset(struct i2c_master_s *dev); +#endif + +#ifdef CONFIG_IMX9_LPI2C_DMA +static void imx9_rxdma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result); +static void imx9_txdma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Trace events strings */ + +#ifdef CONFIG_I2C_TRACE +static const char *g_trace_names[] = +{ + "NONE ", + "SENDADDR ", + "SENDBYTE ", + "RCVBYTE ", + "NOSTART ", + "START/RESTART ", + "STOP ", + "ERROR " +}; +#endif + +/* I2C interface */ + +static const struct i2c_ops_s imx9_lpi2c_ops = +{ + .transfer = imx9_lpi2c_transfer, +#ifdef CONFIG_I2C_RESET + .reset = imx9_lpi2c_reset, +#endif +}; + +/* I2C device structures */ + +#ifdef CONFIG_IMX9_LPI2C1 +static const struct imx9_lpi2c_config_s imx9_lpi2c1_config = +{ + .base = IMX9_LPI2C1_BASE, + .clk_root = CCM_CR_LPI2C1, + .clk_gate = CCM_LPCG_LPI2C1, + .busy_idle = CONFIG_IMX9_LPI2C1_BUSYIDLE, + .filtscl = CONFIG_IMX9_LPI2C1_FILTSCL, + .filtsda = CONFIG_IMX9_LPI2C1_FILTSDA, + .scl_pin = MUX_LPI2C1_SCL, + .sda_pin = MUX_LPI2C1_SDA, +#if defined(CONFIG_I2C_RESET) + .reset_scl_pin = GPIO_LPI2C1_SCL_RESET, + .reset_sda_pin = GPIO_LPI2C1_SDA_RESET, +#endif +#ifndef CONFIG_I2C_SLAVE + .mode = LPI2C_MASTER, +#else + .mode = LPI2C_SLAVE, +#endif +#ifndef CONFIG_I2C_POLLED + .irq = IMX9_IRQ_LPI2C1, +#endif +#ifdef CONFIG_IMX9_LPI2C1_DMA + .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C1RX, + .dma_txreqsrc = DMA_REQUEST_MUXLPI2C1TX, +#endif +}; + +static struct imx9_lpi2c_priv_s imx9_lpi2c1_priv = +{ + .ops = &imx9_lpi2c_ops, + .config = &imx9_lpi2c1_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .dcnt = 0, + .flags = 0, + .status = 0 +}; +#endif + +#ifdef CONFIG_IMX9_LPI2C2 +static const struct imx9_lpi2c_config_s imx9_lpi2c2_config = +{ + .base = IMX9_LPI2C2_BASE, + .clk_root = CCM_CR_LPI2C2, + .clk_gate = CCM_LPCG_LPI2C2, + .busy_idle = CONFIG_IMX9_LPI2C2_BUSYIDLE, + .filtscl = CONFIG_IMX9_LPI2C2_FILTSCL, + .filtsda = CONFIG_IMX9_LPI2C2_FILTSDA, + .scl_pin = MUX_LPI2C2_SCL, + .sda_pin = MUX_LPI2C2_SDA, +#if defined(CONFIG_I2C_RESET) + .reset_scl_pin = GPIO_LPI2C2_SCL_RESET, + .reset_sda_pin = GPIO_LPI2C2_SDA_RESET, +#endif +#ifndef CONFIG_I2C_SLAVE + .mode = LPI2C_MASTER, +#else + .mode = LPI2C_SLAVE, +#endif +#ifndef CONFIG_I2C_POLLED + .irq = IMX9_IRQ_LPI2C2, +#endif +#ifdef CONFIG_IMX9_LPI2C2_DMA + .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C2RX, + .dma_txreqsrc = DMA_REQUEST_MUXLPI2C2TX, +#endif +}; + +static struct imx9_lpi2c_priv_s imx9_lpi2c2_priv = +{ + .ops = &imx9_lpi2c_ops, + .config = &imx9_lpi2c2_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .dcnt = 0, + .flags = 0, + .status = 0 +}; +#endif + +#ifdef CONFIG_IMX9_LPI2C3 +static const struct imx9_lpi2c_config_s imx9_lpi2c3_config = +{ + .base = IMX9_LPI2C3_BASE, + .clk_root = CCM_CR_LPI2C3, + .clk_gate = CCM_LPCG_LPI2C3, + .busy_idle = CONFIG_IMX9_LPI2C3_BUSYIDLE, + .filtscl = CONFIG_IMX9_LPI2C3_FILTSCL, + .filtsda = CONFIG_IMX9_LPI2C3_FILTSDA, + .scl_pin = MUX_LPI2C3_SCL, + .sda_pin = MUX_LPI2C3_SDA, +#if defined(CONFIG_I2C_RESET) + .reset_scl_pin = GPIO_LPI2C3_SCL_RESET, + .reset_sda_pin = GPIO_LPI2C3_SDA_RESET, +#endif +#ifndef CONFIG_I2C_SLAVE + .mode = LPI2C_MASTER, +#else + .mode = LPI2C_SLAVE, +#endif +#ifndef CONFIG_I2C_POLLED + .irq = IMX9_IRQ_LPI2C3, +#endif +#ifdef CONFIG_IMX9_LPI2C3_DMA + .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C3RX, + .dma_txreqsrc = DMA_REQUEST_MUXLPI2C3TX, +#endif +}; + +static struct imx9_lpi2c_priv_s imx9_lpi2c3_priv = +{ + .ops = &imx9_lpi2c_ops, + .config = &imx9_lpi2c3_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .dcnt = 0, + .flags = 0, + .status = 0 +}; +#endif + +#ifdef CONFIG_IMX9_LPI2C4 +static const struct imx9_lpi2c_config_s imx9_lpi2c4_config = +{ + .base = IMX9_LPI2C4_BASE, + .clk_root = CCM_CR_LPI2C4, + .clk_gate = CCM_LPCG_LPI2C4, + .busy_idle = CONFIG_IMX9_LPI2C4_BUSYIDLE, + .filtscl = CONFIG_IMX9_LPI2C4_FILTSCL, + .filtsda = CONFIG_IMX9_LPI2C4_FILTSDA, + .scl_pin = MUX_LPI2C4_SCL, + .sda_pin = MUX_LPI2C4_SDA, +#if defined(CONFIG_I2C_RESET) + .reset_scl_pin = GPIO_LPI2C4_SCL_RESET, + .reset_sda_pin = GPIO_LPI2C4_SDA_RESET, +#endif +#ifndef CONFIG_I2C_SLAVE + .mode = LPI2C_MASTER, +#else + .mode = LPI2C_SLAVE, +#endif +#ifndef CONFIG_I2C_POLLED + .irq = IMX9_IRQ_LPI2C4, +#endif +#ifdef CONFIG_IMX9_LPI2C4_DMA + .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C4RX, + .dma_txreqsrc = DMA_REQUEST_MUXLPI2C4TX, +#endif +}; + +static struct imx9_lpi2c_priv_s imx9_lpi2c4_priv = +{ + .ops = &imx9_lpi2c_ops, + .config = &imx9_lpi2c4_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .dcnt = 0, + .flags = 0, + .status = 0 +}; +#endif + +#ifdef CONFIG_IMX9_LPI2C5 +static const struct imx9_lpi2c_config_s imx9_lpi2c5_config = +{ + .base = IMX9_LPI2C5_BASE, + .clk_root = CCM_CR_LPI2C5, + .clk_gate = CCM_LPCG_LPI2C5, + .busy_idle = CONFIG_IMX9_LPI2C5_BUSYIDLE, + .filtscl = CONFIG_IMX9_LPI2C5_FILTSCL, + .filtsda = CONFIG_IMX9_LPI2C5_FILTSDA, + .scl_pin = MUX_LPI2C5_SCL, + .sda_pin = MUX_LPI2C5_SDA, +#if defined(CONFIG_I2C_RESET) + .reset_scl_pin = GPIO_LPI2C5_SCL_RESET, + .reset_sda_pin = GPIO_LPI2C5_SDA_RESET, +#endif +#ifndef CONFIG_I2C_SLAVE + .mode = LPI2C_MASTER, +#else + .mode = LPI2C_SLAVE, +#endif +#ifndef CONFIG_I2C_POLLED + .irq = IMX9_IRQ_LPI2C5, +#endif +#ifdef CONFIG_IMX9_LPI2C5_DMA + .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C5RX, + .dma_txreqsrc = DMA_REQUEST_MUXLPI2C5TX, +#endif +}; + +static struct imx9_lpi2c_priv_s imx9_lpi2c5_priv = +{ + .ops = &imx9_lpi2c_ops, + .config = &imx9_lpi2c5_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .dcnt = 0, + .flags = 0, + .status = 0 +}; +#endif + +#ifdef CONFIG_IMX9_LPI2C6 +static const struct imx9_lpi2c_config_s imx9_lpi2c6_config = +{ + .base = IMX9_LPI2C6_BASE, + .clk_root = CCM_CR_LPI2C6, + .clk_gate = CCM_LPCG_LPI2C6, + .busy_idle = CONFIG_IMX9_LPI2C6_BUSYIDLE, + .filtscl = CONFIG_IMX9_LPI2C6_FILTSCL, + .filtsda = CONFIG_IMX9_LPI2C6_FILTSDA, + .scl_pin = MUX_LPI2C6_SCL, + .sda_pin = MUX_LPI2C6_SDA, +#if defined(CONFIG_I2C_RESET) + .reset_scl_pin = GPIO_LPI2C6_SCL_RESET, + .reset_sda_pin = GPIO_LPI2C6_SDA_RESET, +#endif +#ifndef CONFIG_I2C_SLAVE + .mode = LPI2C_MASTER, +#else + .mode = LPI2C_SLAVE, +#endif +#ifndef CONFIG_I2C_POLLED + .irq = IMX9_IRQ_LPI2C6, +#endif +#ifdef CONFIG_IMX9_LPI2C6_DMA + .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C6RX, + .dma_txreqsrc = DMA_REQUEST_MUXLPI2C6TX, +#endif +}; + +static struct imx9_lpi2c_priv_s imx9_lpi2c6_priv = +{ + .ops = &imx9_lpi2c_ops, + .config = &imx9_lpi2c6_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .dcnt = 0, + .flags = 0, + .status = 0 +}; +#endif + +#ifdef CONFIG_IMX9_LPI2C7 +static const struct imx9_lpi2c_config_s imx9_lpi2c7_config = +{ + .base = IMX9_LPI2C7_BASE, + .clk_root = CCM_CR_LPI2C7, + .clk_gate = CCM_LPCG_LPI2C7, + .busy_idle = CONFIG_IMX9_LPI2C7_BUSYIDLE, + .filtscl = CONFIG_IMX9_LPI2C7_FILTSCL, + .filtsda = CONFIG_IMX9_LPI2C7_FILTSDA, + .scl_pin = MUX_LPI2C7_SCL, + .sda_pin = MUX_LPI2C7_SDA, +#if defined(CONFIG_I2C_RESET) + .reset_scl_pin = GPIO_LPI2C7_SCL_RESET, + .reset_sda_pin = GPIO_LPI2C7_SDA_RESET, +#endif +#ifndef CONFIG_I2C_SLAVE + .mode = LPI2C_MASTER, +#else + .mode = LPI2C_SLAVE, +#endif +#ifndef CONFIG_I2C_POLLED + .irq = IMX9_IRQ_LPI2C7, +#endif +#ifdef CONFIG_IMX9_LPI2C7_DMA + .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C7RX, + .dma_txreqsrc = DMA_REQUEST_MUXLPI2C7TX, +#endif +}; + +static struct imx9_lpi2c_priv_s imx9_lpi2c7_priv = +{ + .ops = &imx9_lpi2c_ops, + .config = &imx9_lpi2c7_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .dcnt = 0, + .flags = 0, + .status = 0 +}; +#endif + +#ifdef CONFIG_IMX9_LPI2C8 +static const struct imx9_lpi2c_config_s imx9_lpi2c8_config = +{ + .base = IMX9_LPI2C8_BASE, + .clk_root = CCM_CR_LPI2C8, + .clk_gate = CCM_LPCG_LPI2C8, + .busy_idle = CONFIG_IMX9_LPI2C8_BUSYIDLE, + .filtscl = CONFIG_IMX9_LPI2C8_FILTSCL, + .filtsda = CONFIG_IMX9_LPI2C8_FILTSDA, + .scl_pin = MUX_LPI2C8_SCL, + .sda_pin = MUX_LPI2C8_SDA, +#if defined(CONFIG_I2C_RESET) + .reset_scl_pin = GPIO_LPI2C8_SCL_RESET, + .reset_sda_pin = GPIO_LPI2C8_SDA_RESET, +#endif +#ifndef CONFIG_I2C_SLAVE + .mode = LPI2C_MASTER, +#else + .mode = LPI2C_SLAVE, +#endif +#ifndef CONFIG_I2C_POLLED + .irq = IMX9_IRQ_LPI2C8, +#endif +#ifdef CONFIG_IMX9_LPI2C8_DMA + .dma_rxreqsrc = DMA_REQUEST_MUXLPI2C8RX, + .dma_txreqsrc = DMA_REQUEST_MUXLPI2C8TX, +#endif +}; + +static struct imx9_lpi2c_priv_s imx9_lpi2c8_priv = +{ + .ops = &imx9_lpi2c_ops, + .config = &imx9_lpi2c8_config, + .refs = 0, + .lock = NXMUTEX_INITIALIZER, +#ifndef CONFIG_I2C_POLLED + .sem_isr = SEM_INITIALIZER(0), +#endif + .intstate = INTSTATE_IDLE, + .msgc = 0, + .msgv = NULL, + .ptr = NULL, + .dcnt = 0, + .flags = 0, + .status = 0 +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_lpi2c_getreg + * + * Description: + * Get a 32-bit register value by offset + * + ****************************************************************************/ + +static inline uint32_t +imx9_lpi2c_getreg(struct imx9_lpi2c_priv_s *priv, uint16_t offset) +{ + return getreg32(priv->config->base + offset); +} + +/**************************************************************************** + * Name: imx9_lpi2c_putreg + * + * Description: + * Put a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void imx9_lpi2c_putreg(struct imx9_lpi2c_priv_s *priv, + uint16_t offset, uint32_t value) +{ + putreg32(value, priv->config->base + offset); +} + +/**************************************************************************** + * Name: imx9_lpi2c_modifyreg + * + * Description: + * Modify a 32-bit register value by offset + * + ****************************************************************************/ + +static inline void imx9_lpi2c_modifyreg(struct imx9_lpi2c_priv_s *priv, + uint16_t offset, uint32_t clearbits, + uint32_t setbits) +{ + modifyreg32(priv->config->base + offset, clearbits, setbits); +} + +/**************************************************************************** + * Name: imx9_lpi2c_toticks + * + * Description: + * Return a micro-second delay based on the number of bytes left to be + * processed. + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO +static uint32_t imx9_lpi2c_toticks(int msgc, struct i2c_msg_s *msgs) +{ + int i; + size_t bytecount = 0; + uint32_t tick = 0; + + /* Count the number of bytes left to process */ + + for (i = 0; i < msgc; i++) + { + bytecount += msgs[i].length; + } + + /* Then return a number of microseconds based on a user provided scaling + * factor. + */ + + tick = USEC2TICK(CONFIG_IMX9_LPI2C_DYNTIMEO_USECPERBYTE * bytecount); + if (tick == 0) + { + tick = 1; + } + + return tick; +} +#endif + +/**************************************************************************** + * Name: imx9_lpi2c_sem_waitdone + * + * Description: + * Wait for a transfer to complete + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static inline int +imx9_lpi2c_sem_waitdone(struct imx9_lpi2c_priv_s *priv) +{ + irqstate_t flags; + uint32_t regval; + int ret; + + flags = enter_critical_section(); + +#ifdef CONFIG_IMX9_LPI2C_DMA + if (priv->rxdma == NULL && priv->txdma == NULL) + { +#endif + /* Clear the TX and RX FIFOs */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, 0, + LPI2C_MCR_RTF | LPI2C_MCR_RRF); + + /* Enable Interrupts when master mode */ + + if (priv->config->mode == LPI2C_MASTER) + { + if ((priv->flags & I2C_M_READ) != 0) + { + regval = LPI2C_MIER_TDIE | LPI2C_MIER_RDIE | + LPI2C_MIER_NDIE | LPI2C_MIER_ALIE | + LPI2C_MIER_SDIE; + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, regval); + } + else + { + regval = LPI2C_MIER_TDIE | LPI2C_MIER_NDIE | + LPI2C_MIER_ALIE | LPI2C_MIER_SDIE; + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, regval); + } + } + +#ifdef CONFIG_I2C_SLAVE + /* Enable Interrupts when slave mode */ + + else + { + /* REVISIT: Slave mode has not been implemented */ + } +#endif + +#ifdef CONFIG_IMX9_LPI2C_DMA + } +#endif + + do + { + /* Wait until either the transfer is complete or the timeout expires */ + +#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO + ret = nxsem_tickwait_uninterruptible(&priv->sem_isr, + imx9_lpi2c_toticks(priv->msgc, priv->msgv)); +#else + ret = nxsem_tickwait_uninterruptible(&priv->sem_isr, + CONFIG_IMX9_LPI2C_TIMEOTICKS); +#endif + if (ret < 0) + { + /* Break out of the loop on irrecoverable errors. This would + * include timeouts and mystery errors reported by + * nxsem_tickwait_uninterruptible. + */ + + break; + } + } + + /* Loop until the interrupt level transfer is complete. */ + + while (priv->intstate != INTSTATE_DONE); + + /* Set the interrupt state back to IDLE */ + + priv->intstate = INTSTATE_IDLE; + + /* Disable I2C interrupts */ + + if (priv->config->mode == LPI2C_MASTER) + { + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, 0); + } + else + { + imx9_lpi2c_putreg(priv, IMX9_LPI2C_SIER_OFFSET, 0); + } + + leave_critical_section(flags); + return ret; +} +#else +static inline int +imx9_lpi2c_sem_waitdone(struct imx9_lpi2c_priv_s *priv) +{ + clock_t timeout; + clock_t start; + clock_t elapsed; + int ret; + + /* Get the timeout value */ + +#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO + timeout = imx9_lpi2c_toticks(priv->msgc, priv->msgv); +#else + timeout = CONFIG_IMX9_LPI2C_TIMEOTICKS; +#endif + start = clock_systime_ticks(); + + do + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + + /* Poll by simply calling the timer interrupt handler until it + * reports that it is done. + */ + + imx9_lpi2c_isr_process(priv); + } + + /* Loop until the transfer is complete. */ + + while (priv->intstate != INTSTATE_DONE && elapsed < timeout); + + i2cinfo("intstate: %d elapsed: %ld threshold: %ld status: %08x\n", + priv->intstate, (long)elapsed, (long)timeout, priv->status); + + /* Set the interrupt state back to IDLE */ + + ret = priv->intstate == INTSTATE_DONE ? OK : -ETIMEDOUT; + priv->intstate = INTSTATE_IDLE; + return ret; +} +#endif + +/**************************************************************************** + * Name: imx9_lpi2c_sem_waitstop + * + * Description: + * Wait for a STOP to complete + * + ****************************************************************************/ + +static inline void +imx9_lpi2c_sem_waitstop(struct imx9_lpi2c_priv_s *priv) +{ + clock_t start; + clock_t elapsed; + clock_t timeout; + uint32_t regval; + + /* Select a timeout */ + +#ifdef CONFIG_IMX9_LPI2C_DYNTIMEO + timeout = USEC2TICK(CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP); +#else + timeout = CONFIG_IMX9_LPI2C_TIMEOTICKS; +#endif + + /* Wait as stop might still be in progress; but stop might also + * be set because of a timeout error: "The [STOP] bit is set and + * cleared by software, cleared by hardware when a Stop condition is + * detected, set by hardware when a timeout error is detected." + */ + + start = clock_systime_ticks(); + do + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + + /* Check for STOP condition */ + + if (priv->config->mode == LPI2C_MASTER) + { + regval = imx9_lpi2c_getreg(priv, IMX9_LPI2C_MSR_OFFSET); + if ((regval & LPI2C_MSR_SDF) == LPI2C_MSR_SDF) + { + return; + } + } + + /* Enable Interrupts when slave mode */ + + else + { + regval = imx9_lpi2c_getreg(priv, IMX9_LPI2C_SSR_OFFSET); + if ((regval & LPI2C_SSR_SDF) == LPI2C_SSR_SDF) + { + return; + } + } + + /* Check for NACK error */ + + if (priv->config->mode == LPI2C_MASTER) + { + regval = imx9_lpi2c_getreg(priv, IMX9_LPI2C_MSR_OFFSET); + if ((regval & LPI2C_MSR_NDF) == LPI2C_MSR_NDF) + { + return; + } + } + +#ifdef CONFIG_I2C_SLAVE + /* Enable Interrupts when slave mode */ + + else + { + /* REVISIT: Slave mode has not been implemented */ + } +#endif + } + + /* Loop until the stop is complete or a timeout occurs. */ + + while (elapsed < timeout); + + /* If we get here then a timeout occurred with the STOP condition + * still pending. + */ + + i2cinfo("Timeout with Status Register: %" PRIx32 "\n", regval); +} + +/**************************************************************************** + * Name: imx9_rxdma_callback + * + * Description: + * This function performs the next I2C operation + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPI2C_DMA +static void imx9_rxdma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)arg; + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MIER_OFFSET, 0, + LPI2C_MIER_SDIE); + + if (result == OK) + { + if ((priv->flags & I2C_M_NOSTOP) == 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + imx9_lpi2c_sendstop(priv); + } + } + else + { + uint32_t status = imx9_lpi2c_getstatus(priv); + + if ((status & LPI2C_MSR_ERROR_MASK) != 0) + { + i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", status); + + imx9_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + } + } +} +#endif + +/**************************************************************************** + * Name: imx9_txdma_callback + * + * Description: + * This function performs the next I2C operation + * + ****************************************************************************/ +#ifdef CONFIG_IMX9_LPI2C_DMA +static void imx9_txdma_callback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)arg; + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MIER_OFFSET, 0, + LPI2C_MIER_SDIE); + + if (result == OK) + { + if ((priv->flags & I2C_M_NOSTOP) == 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + imx9_lpi2c_sendstop(priv); + } + } + else + { + uint32_t status = imx9_lpi2c_getstatus(priv); + + if ((status & LPI2C_MSR_ERROR_MASK) != 0) + { + i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", status); + + imx9_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + } + } +} +#endif + +/**************************************************************************** + * Name: imx9_lpi2c_trace* + * + * Description: + * I2C trace instrumentation + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_TRACE +static void imx9_lpi2c_traceclear(struct imx9_lpi2c_priv_s *priv) +{ + struct imx9_trace_s *trace = &priv->trace[priv->tndx]; + + trace->status = 0; /* I2C 32-bit SR2|SR1 status */ + trace->count = 0; /* Interrupt count when status change */ + trace->event = I2CEVENT_NONE; /* Last event that occurred with this status */ + trace->parm = 0; /* Parameter associated with the event */ + trace->time = 0; /* Time of first status or event */ +} + +static void imx9_lpi2c_tracereset(struct imx9_lpi2c_priv_s *priv) +{ + /* Reset the trace info for a new data collection */ + + priv->tndx = 0; + priv->start_time = clock_systime_ticks(); + imx9_lpi2c_traceclear(priv); +} + +static void imx9_lpi2c_tracenew(struct imx9_lpi2c_priv_s *priv, + uint32_t status) +{ + struct imx9_trace_s *trace = &priv->trace[priv->tndx]; + + /* Is the current entry uninitialized? Has the status changed? */ + + if (trace->count == 0 || status != trace->status) + { + /* Yes.. Was it the status changed? */ + + if (trace->count != 0) + { + /* Yes.. bump up the trace index (unless out of trace entries) */ + + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) + { + i2cerr("ERROR: Trace table overflow\n"); + return; + } + + priv->tndx++; + trace = &priv->trace[priv->tndx]; + } + + /* Initialize the new trace entry */ + + imx9_lpi2c_traceclear(priv); + trace->status = status; + trace->count = 1; + trace->time = clock_systime_ticks(); + } + else + { + /* Just increment the count of times that we have seen this status */ + + trace->count++; + } +} + +static void imx9_lpi2c_traceevent(struct imx9_lpi2c_priv_s *priv, + enum imx9_trace_e event, uint32_t parm) +{ + struct imx9_trace_s *trace; + + if (event != I2CEVENT_NONE) + { + trace = &priv->trace[priv->tndx]; + + /* Initialize the new trace entry */ + + trace->event = event; + trace->parm = parm; + + /* Bump up the trace index (unless we are out of trace entries) */ + + if (priv->tndx >= (CONFIG_I2C_NTRACE - 1)) + { + i2cerr("ERROR: Trace table overflow\n"); + return; + } + + priv->tndx++; + imx9_lpi2c_traceclear(priv); + } +} + +static void imx9_lpi2c_tracedump(struct imx9_lpi2c_priv_s *priv) +{ + struct imx9_trace_s *trace; + int i; + + syslog(LOG_DEBUG, "Elapsed time: %ld\n", + (long)(clock_systime_ticks() - priv->start_time)); + + for (i = 0; i < priv->tndx; i++) + { + trace = &priv->trace[i]; + syslog(LOG_DEBUG, + "%2d. STATUS: %08x COUNT: %3d EVENT: %s(%2d) PARM: %08x " + "TIME: %d\n", + i + 1, trace->status, trace->count, + g_trace_names[trace->event], + trace->event, trace->parm, trace->time - priv->start_time); + } +} +#endif /* CONFIG_I2C_TRACE */ + +/**************************************************************************** + * Name: imx9_lpi2c_setclock + * + * Description: + * Set the I2C clock + * + ****************************************************************************/ + +static void imx9_lpi2c_setclock(struct imx9_lpi2c_priv_s *priv, + uint32_t frequency) +{ + uint32_t src_freq = 0; + uint32_t regval; + uint32_t men; + uint32_t prescale = 0; + uint32_t best_prescale = 0; + uint32_t best_clk_hi = 0; + uint32_t abs_error = 0; + uint32_t best_error = 0xffffffff; + uint32_t clk_hi_cycle; + uint32_t computed_rate; + uint32_t count; + + /* Has the I2C bus frequency changed? */ + + if (priv->config->mode == LPI2C_MASTER) + { + if (frequency != priv->frequency) + { + /* Disable the selected LPI2C peripheral to configure the new + * clock if it is enabled. + */ + + men = imx9_lpi2c_getreg(priv, IMX9_LPI2C_MCR_OFFSET) & + LPI2C_MCR_MEN; + if (men) + { + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, + LPI2C_MCR_MEN, 0); + } + + /* Get the LPI2C clock source frequency */ + + imx9_get_rootclock(priv->config->clk_root, &src_freq); + + /* LPI2C output frequency = (Source Clock (Hz)/ 2^prescale) / + * (CLKLO + 1 + CLKHI + 1 + ROUNDDOWN((2 + FILTSCL) / 2^prescale) + * + * Assume CLKLO = 2 * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI / 2 + */ + + for (prescale = 1; + (prescale <= 128) && (best_error != 0); + prescale *= 2) + { + for (clk_hi_cycle = 1; clk_hi_cycle < 32; clk_hi_cycle++) + { + if (clk_hi_cycle == 1) + { + computed_rate = (src_freq / prescale) / + (6 + (2 / prescale)); + } + else + { + computed_rate = (src_freq / prescale) / + ((3 * clk_hi_cycle + 2) + + (2 / prescale)); + } + + if (frequency > computed_rate) + { + abs_error = frequency - computed_rate; + } + else + { + abs_error = computed_rate - frequency; + } + + if (abs_error < best_error) + { + best_prescale = prescale; + best_clk_hi = clk_hi_cycle; + best_error = abs_error; + + if (abs_error == 0) + { + break; + } + } + } + } + + regval = LPI2C_MCCR0_CLKHI(best_clk_hi); + + if (best_clk_hi < 2) + { + regval |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) | + LPI2C_MCCR0_DATAVD(1); + } + else + { + regval |= LPI2C_MCCR0_CLKLO(2 * best_clk_hi) | + LPI2C_MCCR0_SETHOLD(best_clk_hi) | + LPI2C_MCCR0_DATAVD(best_clk_hi / 2); + } + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCCR0_OFFSET, regval); + + for (count = 0; count < 8; count++) + { + if (best_prescale == (1 << count)) + { + best_prescale = count; + break; + } + } + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR1_OFFSET, + LPI2C_MCFGR1_PRESCALE_MASK, + LPI2C_MCFGR1_PRESCALE(best_prescale)); + + /* Re-enable LPI2C if it was enabled previously */ + + if (men) + { + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, 0, + LPI2C_MCR_MEN); + } + + /* Save the new LPI2C frequency */ + + priv->frequency = frequency; + } + } +} + +/**************************************************************************** + * Name: imx9_lpi2c_sendstart + * + * Description: + * Send the START conditions/force Master mode + * + ****************************************************************************/ + +static inline void imx9_lpi2c_sendstart(struct imx9_lpi2c_priv_s *priv, + uint8_t address) +{ + uint32_t txcount = 0; + uint32_t status = 0; + uint8_t addr; + + /* Generate START condition and send the address */ + + /* Disable AUTOSTOP and turn NAK Ignore off */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR1_OFFSET, + LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP, 0); + + do + { + txcount = (imx9_lpi2c_getreg(priv, IMX9_LPI2C_MFSR_OFFSET) & + LPI2C_MFSR_TXCOUNT_MASK) >> LPI2C_MFSR_TXCOUNT_SHIFT; + txcount = 4 - txcount; + + status = imx9_lpi2c_getreg(priv, IMX9_LPI2C_MSR_OFFSET); + + if (status & LPI2C_MSR_ERROR_MASK) + { + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, + status & LPI2C_MSR_ERROR_MASK); + } + } + while (txcount == 0); + + if ((priv->flags & I2C_M_READ) != 0) + { + addr = I2C_READADDR8(address); + } + else + { + addr = I2C_WRITEADDR8(address); + } + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET, + (LPI2C_MTDR_CMD_START | LPI2C_MTDR_DATA(addr))); +} + +/**************************************************************************** + * Name: imx9_lpi2c_sendstop + * + * Description: + * Send the STOP conditions + * + ****************************************************************************/ + +static inline void imx9_lpi2c_sendstop(struct imx9_lpi2c_priv_s *priv) +{ + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET, LPI2C_MTDR_CMD_STOP); +} + +/**************************************************************************** + * Name: imx9_lpi2c_getstatus + * + * Description: + * Get 32-bit status + * + ****************************************************************************/ + +static inline uint32_t +imx9_lpi2c_getstatus(struct imx9_lpi2c_priv_s *priv) +{ + return imx9_lpi2c_getreg(priv, IMX9_LPI2C_MSR_OFFSET); +} + +/**************************************************************************** + * Name: imx9_lpi2c_getenabledints + * + * Description: + * Get 32-bit status + * + ****************************************************************************/ + +static inline uint32_t +imx9_lpi2c_getenabledints(struct imx9_lpi2c_priv_s *priv) +{ + return imx9_lpi2c_getreg(priv, IMX9_LPI2C_MIER_OFFSET); +} + +/**************************************************************************** + * Name: imx9_lpi2c_isr_process + * + * Description: + * Common Interrupt Service Routine + * + ****************************************************************************/ + +static int imx9_lpi2c_isr_process(struct imx9_lpi2c_priv_s *priv) +{ + uint32_t status = imx9_lpi2c_getstatus(priv); + +#ifdef CONFIG_IMX9_LPI2C_DMA + uint32_t current_status = status; + + if (priv->rxdma != NULL || priv->txdma != NULL) + { + /* Condition the status with only the enabled interrupts */ + + status &= imx9_lpi2c_getenabledints(priv); + + /* Is there an Error condition */ + + if (current_status & LPI2C_MSR_LIMITED_ERROR_MASK) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + + /* Return the full error status */ + + priv->status = current_status; + } + + /* End of packet or Stop */ + + if ((status & (LPI2C_MSR_SDF | LPI2C_MSR_EPF)) != 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + + /* Acknowledge End of packet or Stop */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, status & + (LPI2C_MSR_SDF | + LPI2C_MSR_EPF)); + + /* Mark that this transaction stopped */ + + priv->msgv = NULL; + priv->msgc = 0; + priv->dcnt = -1; + + if (priv->intstate == INTSTATE_WAITING) + { + /* inform the thread that transfer is complete + * and wake it up + */ + + imx9_dmach_stop(priv->txdma); + imx9_dmach_stop(priv->rxdma); + + priv->intstate = INTSTATE_DONE; + nxsem_post(&priv->sem_isr); + } + } + + /* Clear the error */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, + (current_status & (LPI2C_MSR_NDF | + LPI2C_MSR_ALF | + LPI2C_MSR_FEF))); + return OK; + } + +#endif + /* Check for new trace setup */ + + imx9_lpi2c_tracenew(priv, status); + + if ((status & LPI2C_MSR_LIMITED_ERROR_MASK) == 0) + { + /* Check if there is more bytes to send */ + + if (((priv->flags & I2C_M_READ) == 0) && + (status & LPI2C_MSR_TDF) != 0) + { + if (priv->dcnt > 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_SENDBYTE, priv->dcnt); + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET, + LPI2C_MTDR_CMD_TXD | + LPI2C_MTDR_DATA(*priv->ptr++)); + priv->dcnt--; + + /* Last byte of last message? */ + + if ((priv->msgc <= 0) && (priv->dcnt == 0)) + { + if ((priv->flags & I2C_M_NOSTOP) == 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + + /* Do this once */ + + priv->flags |= I2C_M_NOSTOP; + imx9_lpi2c_sendstop(priv); + } + } + } + } + + /* Check if there is more bytes to read */ + + else if (((priv->flags & I2C_M_READ) != 0) && + (status & LPI2C_MSR_RDF) != 0) + { + /* Read a byte, if dcnt goes < 0, read dummy bytes to ack ISRs */ + + if (priv->dcnt > 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_RCVBYTE, priv->dcnt); + + /* No interrupts or context switches should occur in the + * following sequence. Otherwise, additional bytes may be + * sent by the device. + */ + + #ifdef CONFIG_I2C_POLLED + irqstate_t flags = enter_critical_section(); + #endif + + /* Receive a byte */ + + *priv->ptr++ = imx9_lpi2c_getreg(priv, + IMX9_LPI2C_MRDR_OFFSET) & + LPI2C_MRDR_DATA_MASK; + priv->dcnt--; + + #ifdef CONFIG_I2C_POLLED + leave_critical_section(flags); + #endif + /* Last byte of last message? */ + + if ((priv->msgc <= 0) && (priv->dcnt == 0)) + { + if ((priv->flags & I2C_M_NOSTOP) == 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + + /* Do this once */ + + priv->flags |= I2C_M_NOSTOP; + imx9_lpi2c_sendstop(priv); + } + } + } + else + { + /* Read and discard data */ + + imx9_lpi2c_getreg(priv, IMX9_LPI2C_MRDR_OFFSET); + } + } + + /* Start the first or next message */ + + if (priv->dcnt <= 0 && (status & (LPI2C_MSR_EPF | LPI2C_MSR_SDF)) == 0) + { + if (priv->msgc > 0 && priv->msgv != NULL) + { + priv->ptr = priv->msgv->buffer; + priv->dcnt = priv->msgv->length; + priv->flags = priv->msgv->flags; + + if ((priv->flags & I2C_M_NOSTART) == 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_STARTRESTART, + priv->msgc); + + /* Do this once */ + + priv->flags |= I2C_M_NOSTART; + + imx9_lpi2c_sendstart(priv, priv->msgv->addr); + } + else + { + imx9_lpi2c_traceevent(priv, I2CEVENT_NOSTART, priv->msgc); + } + + priv->msgv++; + priv->msgc--; + + if ((priv->flags & I2C_M_READ) != 0) + { +#ifndef CONFIG_I2C_POLLED + /* Stop TX interrupt */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MIER_OFFSET, + LPI2C_MIER_TDIE, LPI2C_MIER_RDIE); +#endif + /* Set LPI2C in read mode */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET, + LPI2C_MTDR_CMD_RXD | + LPI2C_MTDR_DATA((priv->dcnt - 1))); + } + else + { + /* Send the first byte from tx buffer */ + + imx9_lpi2c_traceevent(priv, I2CEVENT_SENDBYTE, + priv->dcnt); + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MTDR_OFFSET, + LPI2C_MTDR_CMD_TXD | + LPI2C_MTDR_DATA(*priv->ptr++)); + priv->dcnt--; + + /* Last byte of last message? */ + + if ((priv->msgc <= 0) && (priv->dcnt == 0)) + { + if ((priv->flags & I2C_M_NOSTOP) == 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + + /* Do this once */ + + priv->flags |= I2C_M_NOSTOP; + imx9_lpi2c_sendstop(priv); + } + } + } + } + } + } + else + { + imx9_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0); + + priv->status = status; + + if ((priv->flags & I2C_M_NOSTOP) == 0) + { + imx9_lpi2c_traceevent(priv, I2CEVENT_STOP, 0); + + /* Do this once */ + + priv->flags |= I2C_M_NOSTOP; + imx9_lpi2c_sendstop(priv); + } + + /* Clear the error */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, + (status & (LPI2C_MSR_NDF | LPI2C_MSR_ALF | + LPI2C_MSR_FEF | LPI2C_MSR_EPF))); + } + + /* Check for endof packet or Stop */ + + if ((status & (LPI2C_MSR_EPF | LPI2C_MSR_SDF)) != 0) + { + /* Reset either or both */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, status & + (LPI2C_MSR_EPF | LPI2C_MSR_SDF)); + + /* Was it both End of packet and Stop */ + + if ((status & (LPI2C_MSR_EPF | LPI2C_MSR_SDF)) == + (LPI2C_MSR_EPF | LPI2C_MSR_SDF)) + { +#ifndef CONFIG_I2C_POLLED + if (priv->intstate == INTSTATE_WAITING) + { + /* inform the thread that transfer is complete + * and wake it up + */ + + priv->intstate = INTSTATE_DONE; + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MIER_OFFSET, + LPI2C_MIER_TDIE | LPI2C_MIER_RDIE | + LPI2C_MIER_NDIE | LPI2C_MIER_ALIE | + LPI2C_MIER_SDIE | LPI2C_MIER_EPIE, 0); + nxsem_post(&priv->sem_isr); + } +#else + priv->intstate = INTSTATE_DONE; +#endif + } + } + + return OK; +} + +/**************************************************************************** + * Name: imx9_lpi2c_isr + * + * Description: + * Common I2C interrupt service routine + * + ****************************************************************************/ + +#ifndef CONFIG_I2C_POLLED +static int imx9_lpi2c_isr(int irq, void *context, void *arg) +{ + struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)arg; + + DEBUGASSERT(priv != NULL); + return imx9_lpi2c_isr_process(priv); +} +#endif + +/**************************************************************************** + * Name: imx9_lpi2c_clock_enable + * + * Description: + * Ungate LPI2C clock + * + ****************************************************************************/ + +static void imx9_lpi2c_clock_enable(struct imx9_lpi2c_priv_s *priv) +{ + imx9_ccm_gate_on(priv->config->clk_gate, true); +} + +/**************************************************************************** + * Name: imx9_lpi2c_clock_disable + * + * Description: + * Gate LPI2C clock + * + ****************************************************************************/ + +void imx9_lpi2c_clock_disable(struct imx9_lpi2c_priv_s *priv) +{ + imx9_ccm_gate_on(priv->config->clk_gate, false); +} + +/**************************************************************************** + * Name: imx9_lpi2c_init + * + * Description: + * Setup the I2C hardware, ready for operation with defaults + * + ****************************************************************************/ + +static int imx9_lpi2c_init(struct imx9_lpi2c_priv_s *priv) +{ + /* Power-up and configure GPIOs */ + + /* Configure pins */ + + imx9_iomux_configure(priv->config->scl_pin); + imx9_iomux_configure(priv->config->sda_pin); + + /* Enable power and reset the peripheral */ + + imx9_lpi2c_clock_enable(priv); + + /* Reset LPI2C before configuring it */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, LPI2C_MCR_RST); + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, 0); + + /* Disable doze mode (Set DOZEN bit in 1 to disable) */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, LPI2C_MCR_DOZEN); + + /* Disable host request */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR0_OFFSET, + LPI2C_MCFG0_HREN | LPI2C_MCFG0_HRSEL, + LPI2C_MCFG0_HRPOL); + + /* Disable AUTOSTOP and turn NAK Ignore off */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR1_OFFSET, + LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP, 0); + + /* Set tx and rx watermarks */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MFCR_OFFSET, + LPI2C_MFCR_TXWATER(0) | LPI2C_MFCR_RXWATER(0)); + + /* Force a frequency update */ + + priv->frequency = 0; + imx9_lpi2c_setclock(priv, 100000); + + /* Set scl, sda glitch filters and busy idle */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCFGR2_OFFSET, + LPI2C_MCFG2_BUSIDLE(priv->config->busy_idle) | + LPI2C_MCFG2_FILTSCL_CYCLES(priv->config->filtscl) | + LPI2C_MCFG2_FILTSDA_CYCLES(priv->config->filtsda)); + + /* Set pin low cycles to 0 (disable) */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCFGR3_OFFSET, + LPI2C_MCFG3_PINLOW_CYCLES(0)); + + /* Attach ISRs */ + +#ifndef CONFIG_I2C_POLLED + irq_attach(priv->config->irq, imx9_lpi2c_isr, priv); + up_enable_irq(priv->config->irq); +#endif + + /* Enable I2C */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, 0, LPI2C_MCR_MEN); + return OK; +} + +/**************************************************************************** + * Name: imx9_lpi2c_deinit + * + * Description: + * Shutdown the I2C hardware + * + ****************************************************************************/ + +static int imx9_lpi2c_deinit(struct imx9_lpi2c_priv_s *priv) +{ + /* Disable I2C */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, LPI2C_MCR_MEN, 0); + + /* Reset LPI2C */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, LPI2C_MCR_RST); + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MCR_OFFSET, 0); + + /* Disable and detach interrupts */ + +#ifndef CONFIG_I2C_POLLED + up_disable_irq(priv->config->irq); + irq_detach(priv->config->irq); +#endif + + /* Disable clocking */ + + imx9_lpi2c_clock_disable(priv); + + return OK; +} + +/**************************************************************************** + * Device Driver Operations + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_lpi2c_dma_command_configure + * + * Description: + * Create a command TCD + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPI2C_DMA +static int imx9_lpi2c_dma_command_configure(struct imx9_lpi2c_priv_s *priv, + uint16_t *ccmd, uint32_t ncmd) +{ + struct imx9_edma_xfrconfig_s config; + memset(&config, 0, sizeof(config)); + + config.saddr = (uintptr_t) ccmd; + config.daddr = priv->config->base + IMX9_LPI2C_MTDR_OFFSET; + config.soff = sizeof(uint16_t); + config.doff = 0; + config.iter = 1; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_16BIT; + config.dsize = EDMA_16BIT; + config.nbytes = sizeof(uint16_t) * ncmd; + + up_clean_dcache((uintptr_t)config.saddr, + (uintptr_t)config.saddr + config.nbytes); + + return imx9_dmach_xfrsetup(priv->txdma, &config); +} +#endif + +/**************************************************************************** + * Name: imx9_lpi2c_dma_data_configure + * + * Description: + * Create a data TCD + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPI2C_DMA +static int imx9_lpi2c_dma_data_configure(struct imx9_lpi2c_priv_s *priv, + struct i2c_msg_s *msg) +{ + DMACH_HANDLE dma; + struct imx9_edma_xfrconfig_s config; + memset(&config, 0, sizeof(config)); + + config.iter = msg->length; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = sizeof(msg->buffer[0]); + + if (msg->flags & I2C_M_READ) + { + dma = priv->rxdma; + config.saddr = priv->config->base + IMX9_LPI2C_MRDR_OFFSET; + config.daddr = (uintptr_t) msg->buffer; + config.soff = 0; + config.doff = sizeof(msg->buffer[0]); + up_invalidate_dcache((uintptr_t)msg->buffer, + (uintptr_t)msg->buffer + msg->length); + } + else + { + dma = priv->txdma; + config.saddr = (uintptr_t) msg->buffer; + config.daddr = priv->config->base + IMX9_LPI2C_MTDR_OFFSET; + config.soff = sizeof(msg->buffer[0]); + config.doff = 0; + up_clean_dcache((uintptr_t)msg->buffer, + (uintptr_t)msg->buffer + msg->length); + } + + return imx9_dmach_xfrsetup(dma, &config) ? 0 : msg->length; +} +#endif + +/**************************************************************************** + * Name: imx9_lpi2c_form_command_list + * + * Description: + * Form the DMA command list + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPI2C_DMA +static int imx9_lpi2c_form_command_list(struct imx9_lpi2c_priv_s *priv, + struct i2c_msg_s *msg, int ncmds) +{ + ssize_t length = 0; + + if (priv->flags & I2C_M_NOSTART) + { + if (priv->flags & I2C_M_READ) + { + /* No start read operation */ + + priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD | + LPI2C_MTDR_DATA(msg->length - 1); + } + } + else + { + /* A start based read or write operation */ + + /* Create bus address with R/W */ + + uint16_t badd = (priv->flags & I2C_M_READ) ? I2C_READADDR8(msg->addr) : + I2C_WRITEADDR8(msg->addr); + + priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_START | LPI2C_MTDR_DATA(badd); + + if (badd & I2C_READBIT) + { + length = msg->length; + while (length) + { + if (length > 256u) + { + priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD | + LPI2C_MTDR_DATA(256u - 1); + length -= 256u; + } + else + { + priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD | + LPI2C_MTDR_DATA(length - 1); + length = 0; + } + } + } + } + + return ncmds; +} +#endif + +/**************************************************************************** + * Name: imx9_lpi2c_dma_transfer + * + * Description: + * DMA based I2C transfer function + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPI2C_DMA +static int imx9_lpi2c_dma_transfer(struct imx9_lpi2c_priv_s *priv) +{ + int m; + int ntotcmds = 0; + int ncmds = 0; + uint16_t *ccmnd = NULL; + + /* Disable Interrupts */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, 0); + + /* Disable DMA */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MDER_OFFSET, LPI2C_MDER_TDDE | + LPI2C_MDER_RDDE, 0); + + /* Enable AUTOSTOP and NAK Ignore */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCFGR1_OFFSET, 0, + LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP); + + /* Form chains of TCDs to process the messages */ + + for (m = 0; m < priv->msgc; m++) + { + ncmds = 0; + priv->flags = priv->msgv[m].flags; + + /* Form a command list */ + + ccmnd = &priv->cmnds[ntotcmds]; + + ncmds = imx9_lpi2c_form_command_list(priv, &priv->msgv[m], ntotcmds); + + /* Have commands for this message ? */ + + if (ncmds != 0) + { + /* Build up a TCD with the command from this message */ + + imx9_lpi2c_dma_command_configure(priv, ccmnd, ncmds - ntotcmds); + + ntotcmds += ncmds; + + DEBUGASSERT(ntotcmds < CONFIG_IMX9_LPI2C_DMA_MAXMSG); + + imx9_lpi2c_dma_data_configure(priv, &priv->msgv[m]); + } + } + + /* Clear the TX and RX FIFOs */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MCR_OFFSET, 0, + LPI2C_MCR_RTF | LPI2C_MCR_RRF); + + /* Reset the Error bits */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, LPI2C_MSR_NDF | + LPI2C_MSR_ALF | + LPI2C_MSR_FEF); + + /* Enable the Iterrupts */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MIER_OFFSET, + LPI2C_MIER_NDIE | LPI2C_MIER_ALIE | + LPI2C_MIER_PLTIE); + + /* Start The DMA */ + + imx9_dmach_start(priv->rxdma, imx9_rxdma_callback, (void *)priv); + imx9_dmach_start(priv->txdma, imx9_txdma_callback, (void *)priv); + + /* Enable the DMA Request */ + + imx9_lpi2c_modifyreg(priv, IMX9_LPI2C_MDER_OFFSET, 0, + LPI2C_MDER_TDDE | LPI2C_MDER_RDDE); + return OK; +} +#endif + +/**************************************************************************** + * Name: imx9_lpi2c_transfer + * + * Description: + * Generic I2C transfer function + * + ****************************************************************************/ + +static int imx9_lpi2c_transfer(struct i2c_master_s *dev, + struct i2c_msg_s *msgs, int count) +{ + struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)dev; + int ret; +#ifdef CONFIG_IMX9_LPI2C_DMA + int m; +#endif + + DEBUGASSERT(count > 0); + + /* Ensure that address or flags don't change meanwhile */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + /* Clear any pending error interrupts */ + + imx9_lpi2c_putreg(priv, IMX9_LPI2C_MSR_OFFSET, 0xffffffff); + + /* Old transfers are done */ + + /* Reset ptr and dcnt to ensure an unexpected data interrupt doesn't + * overwrite stale data. + */ + + priv->dcnt = 0; + priv->ptr = NULL; + + priv->msgv = msgs; + priv->msgc = count; + priv->flags = msgs->flags; + + i2cinfo("Flags %x, len %ld\n", msgs->flags, msgs->length); + + /* Reset I2C trace logic */ + + imx9_lpi2c_tracereset(priv); + + /* Set I2C clock frequency */ + + imx9_lpi2c_setclock(priv, msgs->frequency); + + priv->status = 0; + + /* Signal the interrupt handler that we are waiting. NOTE: Interrupts + * are currently disabled but will be temporarily re-enabled below when + * nxsem_tickwait_uninterruptible() sleeps. + */ + + priv->intstate = INTSTATE_WAITING; + + /* Wait for an ISR, if there was a timeout, fetch latest status to get + * the BUSY flag. + */ + +#ifdef CONFIG_IMX9_LPI2C_DMA + if (priv->rxdma || priv->txdma) + { + imx9_lpi2c_dma_transfer(priv); + } +#endif + + if (imx9_lpi2c_sem_waitdone(priv) < 0) + { +#ifdef CONFIG_IMX9_LPI2C_DMA + if (priv->rxdma != NULL) + { + imx9_dmach_stop(priv->rxdma); + } + + if (priv->txdma != NULL) + { + imx9_dmach_stop(priv->txdma); + } + +#endif + ret = -ETIMEDOUT; + i2cerr("ERROR: Timed out: MSR: status: 0x0%" PRIx32 "\n", + priv->status); + } + + /* Check for error status conditions */ + + else if ((priv->status & LPI2C_MSR_ERROR_MASK) != 0) + { + /* I2C_SR1_ERRORMASK is the 'OR' of the following individual bits: */ + + if (priv->status & LPI2C_MSR_ALF) + { + /* Arbitration Lost (master mode) */ + + i2cerr("Arbitration lost\n"); + ret = -EAGAIN; + } + else if (priv->status & LPI2C_MSR_NDF) + { + /* Acknowledge Failure */ + + i2cerr("Ack failure\n"); + ret = -ENXIO; + } + else + { + /* FIFO Error */ + + i2cerr("Transfer without start condition\n"); + ret = -EINVAL; + } + } + + /* Dump the trace result */ + + imx9_lpi2c_tracedump(priv); + + /* Ensure that any ISR happening after we finish can't overwrite any user + * data. + */ + + priv->dcnt = 0; + priv->ptr = NULL; + +#ifdef CONFIG_IMX9_LPI2C_DMA + if (priv->rxdma) + { + for (m = 0; m < count; m++) + { + if (msgs[m].flags & I2C_M_READ) + { + up_invalidate_dcache((uintptr_t)msgs[m].buffer, + (uintptr_t)msgs[m].buffer + + msgs[m].length); + } + } + } +#endif + + nxmutex_unlock(&priv->lock); + return ret; +} + +/**************************************************************************** + * Name: imx9_lpi2c_reset + * + * Description: + * Perform an I2C bus reset in an attempt to break loose stuck I2C devices. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_I2C_RESET +static int imx9_lpi2c_reset(struct i2c_master_s *dev) +{ + struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)dev; + unsigned int clock_count; + unsigned int stretch_count; + uint32_t scl_gpio; + uint32_t sda_gpio; + uint32_t frequency; + int ret; + + DEBUGASSERT(dev); + + /* Our caller must own a ref */ + + DEBUGASSERT(priv->refs > 0); + + /* Lock out other clients */ + + ret = nxmutex_lock(&priv->lock); + if (ret < 0) + { + return ret; + } + + ret = -EIO; + + /* Save the current frequency */ + + frequency = priv->frequency; + + /* De-init the port */ + + imx9_lpi2c_deinit(priv); + + /* Use GPIO configuration to un-wedge the bus */ + + imx9_iomux_gpio(priv->config->scl_pin, true); + imx9_iomux_gpio(priv->config->sda_pin, true); + + scl_gpio = priv->config->reset_scl_pin; + sda_gpio = priv->config->reset_sda_pin; + + imx9_config_gpio(scl_gpio); + imx9_config_gpio(sda_gpio); + + /* Let SDA go high */ + + imx9_gpio_write(sda_gpio, 1); + + /* Clock the bus until any slaves currently driving it let it go. */ + + clock_count = 0; + while (!imx9_gpio_read(sda_gpio)) + { + /* Give up if we have tried too hard */ + + if (clock_count++ > 10) + { + goto out; + } + + /* Sniff to make sure that clock stretching has finished. + * + * If the bus never relaxes, the reset has failed. + */ + + stretch_count = 0; + while (!imx9_gpio_read(scl_gpio)) + { + /* Give up if we have tried too hard */ + + if (stretch_count++ > 10) + { + goto out; + } + + up_udelay(10); + } + + /* Drive SCL low */ + + imx9_gpio_write(scl_gpio, 0); + up_udelay(10); + + /* Drive SCL high again */ + + imx9_gpio_write(scl_gpio, 1); + up_udelay(10); + } + + /* Generate a start followed by a stop to reset slave + * state machines. + */ + + imx9_gpio_write(sda_gpio, 0); + up_udelay(10); + imx9_gpio_write(scl_gpio, 0); + up_udelay(10); + imx9_gpio_write(scl_gpio, 1); + up_udelay(10); + imx9_gpio_write(sda_gpio, 1); + up_udelay(10); + + /* Re-init the port */ + + imx9_lpi2c_init(priv); + + /* Restore the frequency */ + + imx9_lpi2c_setclock(priv, frequency); + ret = OK; + +out: + + /* Release the port for re-use by other clients */ + + nxmutex_unlock(&priv->lock); + return ret; +} +#endif /* CONFIG_I2C_RESET */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_i2cbus_initialize + * + * Description: + * Initialize one I2C bus + * + ****************************************************************************/ + +struct i2c_master_s *imx9_i2cbus_initialize(int port) +{ + struct imx9_lpi2c_priv_s * priv = NULL; + irqstate_t flags; + + /* Get I2C private structure */ + + switch (port) + { +#ifdef CONFIG_IMX9_LPI2C1 + case 1: + priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c1_priv; + break; +#endif +#ifdef CONFIG_IMX9_LPI2C2 + case 2: + priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c2_priv; + break; +#endif +#ifdef CONFIG_IMX9_LPI2C3 + case 3: + priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c3_priv; + break; +#endif +#ifdef CONFIG_IMX9_LPI2C4 + case 4: + priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c4_priv; + break; +#endif +#ifdef CONFIG_IMX9_LPI2C5 + case 5: + priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c5_priv; + break; +#endif +#ifdef CONFIG_IMX9_LPI2C6 + case 6: + priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c6_priv; + break; +#endif +#ifdef CONFIG_IMX9_LPI2C7 + case 7: + priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c7_priv; + break; +#endif +#ifdef CONFIG_IMX9_LPI2C8 + case 8: + priv = (struct imx9_lpi2c_priv_s *)&imx9_lpi2c8_priv; + break; +#endif + default: + return NULL; + } + + /* Initialize private data for the first time, increment reference count, + * power-up hardware and configure GPIOs. + */ + + flags = enter_critical_section(); + + if ((volatile int)priv->refs++ == 0) + { + imx9_lpi2c_init(priv); + +#ifdef CONFIG_IMX9_LPI2C_DMA + if (priv->config->dma_txreqsrc != 0) + { + priv->txdma = imx9_dmach_alloc(priv->config->dma_txreqsrc, 0); + DEBUGASSERT(priv->txdma != NULL); + } + + if (priv->config->dma_rxreqsrc != 0) + { + priv->rxdma = imx9_dmach_alloc(priv->config->dma_rxreqsrc, 0); + DEBUGASSERT(priv->rxdma != NULL); + } +#endif + } + + leave_critical_section(flags); + + return (struct i2c_master_s *)priv; +} + +/**************************************************************************** + * Name: imx9_i2cbus_uninitialize + * + * Description: + * Uninitialize an I2C bus + * + ****************************************************************************/ + +int imx9_i2cbus_uninitialize(struct i2c_master_s *dev) +{ + struct imx9_lpi2c_priv_s *priv = (struct imx9_lpi2c_priv_s *)dev; + irqstate_t flags; + + DEBUGASSERT(dev); + + /* Decrement reference count and check for underflow */ + + if (priv->refs == 0) + { + return ERROR; + } + + flags = enter_critical_section(); + + if (--priv->refs > 0) + { + leave_critical_section(flags); + return OK; + } + + leave_critical_section(flags); + + /* Disable power and other HW resource (GPIO's) */ + +#ifdef CONFIG_IMX9_LPI2C_DMA + if (priv->rxdma != NULL) + { + imx9_dmach_stop(priv->rxdma); + imx9_dmach_free(priv->rxdma); + priv->rxdma = NULL; + } + + if (priv->txdma != NULL) + { + imx9_dmach_stop(priv->txdma); + imx9_dmach_free(priv->txdma); + priv->txdma = NULL; + } +#endif + + imx9_lpi2c_deinit(priv); + + return OK; +} + +#endif /* CONFIG_IMX9_LPI2C */ diff --git a/arch/arm64/src/imx9/imx9_lpi2c.h b/arch/arm64/src/imx9/imx9_lpi2c.h new file mode 100644 index 0000000000000..d323871fa3183 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lpi2c.h @@ -0,0 +1,71 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_lpi2c.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_LPI2C_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_LPI2C_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_i2cbus_initialize + * + * Description: + * Initialize the selected I2C port. And return a unique instance of struct + * struct i2c_master_s. This function may be called to obtain multiple + * instances of the interface, each of which may be set up with a + * different frequency and slave address. + * + * Input Parameters: + * Port number (for hardware that has multiple I2C interfaces) + * + * Returned Value: + * Valid I2C device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct i2c_master_s *imx9_i2cbus_initialize(int port); + +/**************************************************************************** + * Name: imx9_i2cbus_uninitialize + * + * Description: + * De-initialize the selected I2C port, and power down the device. + * + * Input Parameters: + * Device structure as returned by the imx9_i2cbus_initialize() + * + * Returned Value: + * OK on success, ERROR when internal reference count mismatch or dev + * points to invalid hardware device. + * + ****************************************************************************/ + +int imx9_i2cbus_uninitialize(struct i2c_master_s *dev); + +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_LPI2C_H */ diff --git a/arch/arm64/src/imx9/imx9_lpspi.c b/arch/arm64/src/imx9/imx9_lpspi.c new file mode 100644 index 0000000000000..b373b04c8f213 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lpspi.c @@ -0,0 +1,2096 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_lpspi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * The external functions, imx9_lpspi1/2/3/4select and + * imx9_lpspi1/2/3/4status must be provided by board-specific logic. + * They are implementations of the select and status methods of the SPI + * interface defined by struct imx9_lpspi_ops_s (see + * include/nuttx/spi/spi.h). All other methods (including + * imx9_lpspibus_initialize()) are provided by common IMX9 logic. + * To use this common SPI logic on your board: + * + * 1. Provide logic in imx9_boardinitialize() to configure SPI chip + * select pins. + * 2. Provide imx9_lpspi1/2/3/4select() and imx9_lpspi1/2/3/4status() + * functions in your board-specific logic. These functions will + * perform chip selection and status operations using GPIOs in the way + * your board is configured. + * 3. Add a calls to imx9_lpspibus_initialize() in your low level + * application initialization logic + * 4. The handle returned by imx9_lpspibus_initialize() may then be + * used to bind the SPI driver to higher level logic (e.g., calling + * mmcsd_lpspislotinitialize(), for example, will bind the SPI + * driver to the SPI MMC/SD driver). + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "arm64_internal.h" +#include "imx9_ccm.h" +#include "imx9_clockconfig.h" +#include "imx9_dma_alloc.h" +#include "imx9_gpio.h" +#include "imx9_iomuxc.h" +#include "imx9_lpspi.h" + +#include "hardware/imx9_ccm.h" +#include "hardware/imx9_lpspi.h" +#include "hardware/imx9_pinmux.h" + +#ifdef CONFIG_IMX9_LPSPI_DMA +# include "chip.h" +# include "imx9_edma.h" +# include "hardware/imx9_dmamux.h" +#endif + +#ifdef CONFIG_IMX9_LPSPI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* SPI interrupts */ + +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS +# error "Interrupt driven SPI not yet supported" +#endif + +/* Can't have both interrupt driven SPI and SPI DMA */ + +#if defined(CONFIG_IMX9_LPSPI_INTERRUPTS) && defined(CONFIG_IMX9_LPSPI_DMA) +# error "Cannot enable both interrupt mode and DMA mode for SPI" +#endif + +#define SPI_SR_CLEAR (LPSPI_SR_WCF | LPSPI_SR_FCF | LPSPI_SR_TCF | \ + LPSPI_SR_TEF | LPSPI_SR_REF | LPSPI_SR_DMF) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct imx9_lpspidev_s +{ + struct spi_dev_s spidev; /* Externally visible part of the SPI interface */ + uint32_t spibase; /* SPIn base address */ + uint8_t clk_root; /* SPIn clock root */ + uint8_t clk_gate; /* SPIn clock gate */ +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + uint8_t spiirq; /* SPI IRQ number */ +#endif + mutex_t lock; /* Held while chip is selected for mutual exclusion */ + uint32_t frequency; /* Requested clock frequency */ + uint32_t actual; /* Actual clock frequency */ + int8_t nbits; /* Width of word in bits */ + uint8_t mode; /* Mode 0,1,2,3 */ +#ifdef CONFIG_IMX9_LPSPI_DMA + volatile uint32_t rxresult; /* Result of the RX DMA */ + volatile uint32_t txresult; /* Result of the TX DMA */ + const uint16_t rxch; /* The RX DMA channel number */ + const uint16_t txch; /* The TX DMA channel number */ + DMACH_HANDLE rxdma; /* DMA channel handle for RX transfers */ + DMACH_HANDLE txdma; /* DMA channel handle for TX transfers */ + sem_t rxsem; /* Wait for RX DMA to complete */ + sem_t txsem; /* Wait for TX DMA to complete */ + void *txbuf; /* Driver DMA safe buffer for TX */ + void *rxbuf; /* Driver DMA safe buffer for RX */ +#endif +}; + +enum imx9_delay_e +{ + LPSPI_PCS_TO_SCK = 1, /* PCS-to-SCK delay. */ + LPSPI_LAST_SCK_TO_PCS, /* Last SCK edge to PCS delay. */ + LPSPI_BETWEEN_TRANSFER /* Delay between transfers. */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Helpers */ + +static inline uint32_t +imx9_lpspi_getreg32(struct imx9_lpspidev_s *priv, uint8_t offset); +static inline void imx9_lpspi_putreg32(struct imx9_lpspidev_s *priv, + uint8_t offset, uint32_t value); +static inline uint32_t imx9_lpspi_readword( + struct imx9_lpspidev_s *priv); +static inline void imx9_lpspi_writeword(struct imx9_lpspidev_s *priv, + uint16_t byte); +static inline bool imx9_lpspi_9to16bitmode( + struct imx9_lpspidev_s *priv); +static inline void imx9_lpspi_master_set_delays(struct imx9_lpspidev_s + *priv, uint32_t delay_ns, + enum imx9_delay_e type); +static inline void imx9_lpspi_master_set_delay_scaler( + struct imx9_lpspidev_s *priv, + uint32_t scaler, + enum imx9_delay_e type); + +/* DMA support */ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static int spi_dmarxwait(struct imx9_lpspidev_s *priv); +static int spi_dmatxwait(struct imx9_lpspidev_s *priv); +static inline void spi_dmarxwakeup(struct imx9_lpspidev_s *priv); +static inline void spi_dmatxwakeup(struct imx9_lpspidev_s *priv); +static void spi_dmarxcallback(DMACH_HANDLE handle, void *arg, + bool done, int result); +static void spi_dmatxcallback(DMACH_HANDLE handle, void *arg, + bool done, int result); +static inline void spi_dmarxstart(struct imx9_lpspidev_s *priv); +static inline void spi_dmatxstart(struct imx9_lpspidev_s *priv); +#endif + +/* SPI methods */ + +static int imx9_lpspi_lock(struct spi_dev_s *dev, bool lock); +static uint32_t imx9_lpspi_setfrequency(struct spi_dev_s *dev, + uint32_t frequency); +static void imx9_lpspi_setmode(struct spi_dev_s *dev, + enum spi_mode_e mode); +static void imx9_lpspi_setbits(struct spi_dev_s *dev, int nbits); +#ifdef CONFIG_SPI_HWFEATURES +static int imx9_lpspi_hwfeatures(struct spi_dev_s *dev, + imx9_lpspi_hwfeatures_t features); +#endif +static uint32_t imx9_lpspi_send(struct spi_dev_s *dev, uint32_t wd); +static void imx9_lpspi_exchange(struct spi_dev_s *dev, + const void *txbuffer, + void *rxbuffer, + size_t nwords); +#ifndef CONFIG_SPI_EXCHANGE +static void imx9_lpspi_sndblock(struct spi_dev_s *dev, + const void *txbuffer, size_t nwords); +static void imx9_lpspi_recvblock(struct spi_dev_s *dev, + void *rxbuffer, + size_t nwords); +#endif + +/* Initialization */ + +static void imx9_lpspi_bus_initialize(struct imx9_lpspidev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct spi_ops_s g_spiops = +{ + .lock = imx9_lpspi_lock, + .select = imx9_lpspi_select, + .setfrequency = imx9_lpspi_setfrequency, + .setmode = imx9_lpspi_setmode, + .setbits = imx9_lpspi_setbits, +#ifdef CONFIG_SPI_HWFEATURES + .hwfeatures = imx9_lpspi_hwfeatures, +#endif + .status = imx9_lpspi_status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = imx9_lpspi_cmddata, +#endif + .send = imx9_lpspi_send, +#ifdef CONFIG_SPI_EXCHANGE + .exchange = imx9_lpspi_exchange, +#else + .sndblock = imx9_lpspi_sndblock, + .recvblock = imx9_lpspi_recvblock, +#endif +#ifdef CONFIG_SPI_CALLBACK + .registercallback = imx9_lpspi_register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif +}; + +#ifdef CONFIG_IMX9_LPSPI1 +static struct imx9_lpspidev_s g_lpspi1dev = +{ + .spidev = + { + .ops = &g_spiops, + }, + .spibase = IMX9_LPSPI1_BASE, + .clk_root = CCM_CR_LPSPI1, + .clk_gate = CCM_LPCG_LPSPI1, +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + .spiirq = IMX9_IRQ_LPSPI1, +#endif + .lock = NXMUTEX_INITIALIZER, +#ifdef CONFIG_IMX9_LPSPI1_DMA + .rxch = DMA_REQUEST_MUXLPSPI1RX, + .txch = DMA_REQUEST_MUXLPSPI1TX, + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif +}; +#endif + +#ifdef CONFIG_IMX9_LPSPI2 +static struct imx9_lpspidev_s g_lpspi2dev = +{ + .spidev = + { + .ops = &g_spi2ops, + }, + .spibase = IMX9_LPSPI2_BASE, + .clk_root = CCM_CR_LPSPI2, + .clk_gate = CCM_LPCG_LPSPI2, +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + .spiirq = IMX9_IRQ_LPSPI2, +#endif + .lock = NXMUTEX_INITIALIZER, +#ifdef CONFIG_IMX9_LPSPI2_DMA + .rxch = DMA_REQUEST_MUXLPSPI2RX, + .txch = DMA_REQUEST_MUXLPSPI2TX, + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif +}; +#endif + +#ifdef CONFIG_IMX9_LPSPI3 +static struct imx9_lpspidev_s g_lpspi3dev = +{ + .spidev = + { + .ops = &g_spi3ops, + }, + .spibase = IMX9_LPSPI3_BASE, + .clk_root = CCM_CR_LPSPI3, + .clk_gate = CCM_LPCG_LPSPI3, +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + .spiirq = IMX9_IRQ_LPSPI3, +#endif + .lock = NXMUTEX_INITIALIZER, +#ifdef CONFIG_IMX9_LPSPI3_DMA + .rxch = DMA_REQUEST_MUXLPSPI3RX, + .txch = DMA_REQUEST_MUXLPSPI3TX, + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif +}; +#endif + +#ifdef CONFIG_IMX9_LPSPI4 +static struct imx9_lpspidev_s g_lpspi4dev = +{ + .spidev = + { + .ops = &g_spiops, + }, + .spibase = IMX9_LPSPI4_BASE, + .clk_root = CCM_CR_LPSPI4, + .clk_gate = CCM_LPCG_LPSPI4, +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + .spiirq = IMX9_IRQ_LPSPI4, +#endif + .lock = NXMUTEX_INITIALIZER, +#ifdef CONFIG_IMX9_LPSPI4_DMA + .rxch = DMA_REQUEST_MUXLPSPI4RX, + .txch = DMA_REQUEST_MUXLPSPI4TX, + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif +}; +#endif + +#ifdef CONFIG_IMX9_LPSPI5 +static struct imx9_lpspidev_s g_lpspi5dev = +{ + .spidev = + { + &g_spiops + }, + .spibase = IMX9_LPSPI5_BASE, + .clk_root = CCM_CR_LPSPI5, + .clk_gate = CCM_LPCG_LPSPI5, +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + .spiirq = IMX9_IRQ_LPSPI5, +#endif + .lock = NXMUTEX_INITIALIZER, +#ifdef CONFIG_IMX9_LPSPI5_DMA + .rxch = DMA_REQUEST_MUXLPSPI5RX, + .txch = DMA_REQUEST_MUXLPSPI5TX, + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif +}; +#endif + +#ifdef CONFIG_IMX9_LPSPI6 +static struct imx9_lpspidev_s g_lpspi6dev = +{ + .spidev = + { + &g_spiops + }, + .spibase = IMX9_LPSPI6_BASE, + .clk_root = CCM_CR_LPSPI6, + .clk_gate = CCM_LPCG_LPSPI6, +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + .spiirq = IMX9_IRQ_LPSPI6, +#endif + .lock = NXMUTEX_INITIALIZER, +#ifdef CONFIG_IMX9_LPSPI6_DMA + .rxch = DMA_REQUEST_MUXLPSPI6RX, + .txch = DMA_REQUEST_MUXLPSPI6TX, + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif +}; +#endif + +#ifdef CONFIG_IMX9_LPSPI7 +static struct imx9_lpspidev_s g_lpspi7dev = +{ + .spidev = + { + &g_spiops + }, + .spibase = IMX9_LPSPI7_BASE, + .clk_root = CCM_CR_LPSPI7, + .clk_gate = CCM_LPCG_LPSPI7, +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + .spiirq = IMX9_IRQ_LPSPI7, +#endif + .lock = NXMUTEX_INITIALIZER, +#ifdef CONFIG_IMX9_LPSPI7_DMA + .rxch = DMA_REQUEST_MUXLPSPI7RX, + .txch = DMA_REQUEST_MUXLPSPI7TX, + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif +}; +#endif + +#ifdef CONFIG_IMX9_LPSPI8 +static struct imx9_lpspidev_s g_lpspi8dev = +{ + .spidev = + { + &g_spiops + }, + .spibase = IMX9_LPSPI8_BASE, + .clk_root = CCM_CR_LPSPI8, + .clk_gate = CCM_LPCG_LPSPI8, +#ifdef CONFIG_IMX9_LPSPI_INTERRUPTS + .spiirq = IMX9_IRQ_LPSPI8, +#endif + .lock = NXMUTEX_INITIALIZER, +#ifdef CONFIG_IMX9_LPSPI6_DMA + .rxch = DMA_REQUEST_MUXLPSPI8RX, + .txch = DMA_REQUEST_MUXLPSPI8TX, + .rxsem = SEM_INITIALIZER(0), + .txsem = SEM_INITIALIZER(0), +#endif +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_lpspi_getreg + * + * Description: + * Get the contents of the SPI register at offset + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * + * Returned Value: + * The contents of the 32-bit register + * + ****************************************************************************/ + +static inline uint32_t +imx9_lpspi_getreg32(struct imx9_lpspidev_s *priv, uint8_t offset) +{ + return getreg32(priv->spibase + offset); +} + +/**************************************************************************** + * Name: imx9_lpspi_putreg + * + * Description: + * Write a 16-bit value to the SPI register at offset + * + * Input Parameters: + * priv - private SPI device structure + * offset - offset to the register of interest + * value - the 32-bit value to be written + * + * Returned Value: + * The contents of the 32-bit register + * + ****************************************************************************/ + +static inline void imx9_lpspi_putreg32(struct imx9_lpspidev_s *priv, + uint8_t offset, uint32_t value) +{ + putreg32(value, priv->spibase + offset); +} + +/**************************************************************************** + * Name: imx9_lpspi_readword + * + * Description: + * Read one word from SPI + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * word as read + * + ****************************************************************************/ + +static inline uint32_t +imx9_lpspi_readword(struct imx9_lpspidev_s *priv) +{ + /* Wait until the receive buffer is not empty */ + + while ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_SR_OFFSET) + & LPSPI_SR_RDF) == 0); + + /* Then return the received byte */ + + return imx9_lpspi_getreg32(priv, IMX9_LPSPI_RDR_OFFSET); +} + +/**************************************************************************** + * Name: imx9_lpspi_writeword + * + * Description: + * Write one word to SPI + * + * Input Parameters: + * priv - Device-specific state data + * word - word to send + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void imx9_lpspi_writeword(struct imx9_lpspidev_s *priv, + uint16_t word) +{ + /* Wait until the transmit buffer is empty */ + + while ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_SR_OFFSET) + & LPSPI_SR_TDF) == 0); + + /* Then send the word */ + + imx9_lpspi_putreg32(priv, IMX9_LPSPI_TDR_OFFSET, word); +} + +/**************************************************************************** + * Name: imx9_lpspi_9to16bitmode + * + * Description: + * Check if the SPI is operating in more then 8 bit mode + * + * Input Parameters: + * priv - Device-specific state data + * + * Returned Value: + * true: >8 bit mode-bit mode, false: <= 8-bit mode + * + ****************************************************************************/ + +static inline bool +imx9_lpspi_9to16bitmode(struct imx9_lpspidev_s *priv) +{ + bool ret; + + if (((imx9_lpspi_getreg32(priv, IMX9_LPSPI_TCR_OFFSET) & + LPSPI_TCR_FRAMESZ_MASK) + 1) < 9) + { + ret = false; + } + else + { + ret = true; + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_lpspi_modifyreg32 + * + * Description: + * Clear and set bits in register + * + * Input Parameters: + * priv - Device-specific state data + * offset - Register offset + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_lpspi_modifyreg32(struct imx9_lpspidev_s *priv, + uint8_t offset, uint32_t clrbits, + uint32_t setbits) +{ + modifyreg32(priv->spibase + offset, clrbits, setbits); +} + +/**************************************************************************** + * Name: imx9_lpspi_modifyreg32 + * + * Description: + * Clear and set bits TCR register. Need a safe wrapper as TCR expects + * LPSPI is _enabled_ when writing. + * + * Input Parameters: + * priv - Device-specific state data + * offset - Register offset + * clrbits - The bits to clear + * setbits - The bits to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_lpspi_modifytcr(struct imx9_lpspidev_s *priv, + uint32_t clrbits, uint32_t setbits) +{ + uint32_t men; + + /* Enable LPSPI if it was disabled previously */ + + men = imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) & LPSPI_CR_MEN; + if (!men) + { + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, 0, + LPSPI_CR_MEN); + } + + /* Update the register */ + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_TCR_OFFSET, clrbits, setbits); + + /* Disable LPSPI if it was disabled */ + + if (!men) + { + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, + LPSPI_CR_MEN, 0); + } +} + +/**************************************************************************** + * Name: imx9_lpspi_master_set_delays + * + * Description: + * SET LPSPI Delay times + * + * Input Parameters: + * priv - Device-specific state data + * scaler - scaler value + * type - delay time type + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void imx9_lpspi_master_set_delay_scaler( + struct imx9_lpspidev_s *priv, + uint32_t scaler, + enum imx9_delay_e type) +{ + uint32_t ccr1; + uint32_t dbt; + uint32_t sckdiv; + + /* Read from SCKDIV and DTB will always return 0. In order to preserve the + * old values we must calculate them here locally from CCR1 values. + */ + + ccr1 = imx9_lpspi_getreg32(priv, IMX9_LPSPI_CCR1_OFFSET); + dbt = (ccr1 & LPSPI_CCR1_SCKSCK_MASK) >> LPSPI_CCR1_SCKSCK_SHIFT; + sckdiv = (ccr1 & LPSPI_CCR1_SCKHLD_MASK) >> LPSPI_CCR1_SCKHLD_SHIFT; + sckdiv += (ccr1 & LPSPI_CCR1_SCKSET_MASK) >> LPSPI_CCR1_SCKSET_SHIFT; + + switch (type) + { + case LPSPI_PCS_TO_SCK: + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CCR_OFFSET, + LPSPI_CCR_PCSSCK_MASK, 0); + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CCR_OFFSET, 0, + LPSPI_CCR_DBT(dbt) | + LPSPI_CCR_PCSSCK(scaler) | + LPSPI_CCR_SCKDIV(sckdiv)); + break; + + case LPSPI_LAST_SCK_TO_PCS: + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CCR_OFFSET, + LPSPI_CCR_SCKPCS_MASK, 0); + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CCR_OFFSET, 0, + LPSPI_CCR_DBT(dbt) | + LPSPI_CCR_PCSSCK(scaler) | + LPSPI_CCR_SCKDIV(sckdiv)); + break; + + case LPSPI_BETWEEN_TRANSFER: + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CCR_OFFSET, + LPSPI_CCR_DBT_MASK, 0); + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CCR_OFFSET, 0, + LPSPI_CCR_DBT(dbt) | + LPSPI_CCR_PCSSCK(scaler) | + LPSPI_CCR_SCKDIV(sckdiv)); + break; + } +} + +/**************************************************************************** + * Name: imx9_lpspi_master_set_delays + * + * Description: + * SET LPSPI Delay times + * + * Input Parameters: + * priv - Device-specific state data + * delay_ns - delay time in nano seconds + * type - delay time type + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void imx9_lpspi_master_set_delays( + struct imx9_lpspidev_s *priv, + uint32_t delay_ns, + enum imx9_delay_e type) +{ + uint32_t src_freq; + uint64_t real_delay; + uint32_t scaler; + uint32_t best_scaler; + uint32_t diff; + uint32_t min_diff; + uint64_t initial_delay_ns; + uint32_t clock_div_prescaler; + uint32_t additional_scaler; + + imx9_get_rootclock(priv->clk_root, &src_freq); + + clock_div_prescaler = src_freq / + (1 << ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_TCR_OFFSET) & + LPSPI_TCR_PRESCALE_MASK) >> LPSPI_TCR_PRESCALE_SHIFT)); + + min_diff = 0xffffffff; + + /* Initialize scaler to max value to generate the max delay */ + + best_scaler = 0xff; + + if (type == LPSPI_BETWEEN_TRANSFER) + { + /* First calculate the initial, default delay, note min delay is 2 + * clock cycles. Due to large size of * calculated values (uint64_t), + * we need to break up the calculation into several steps to ensure + * accurate calculated results + */ + + initial_delay_ns = 1000000000U; + initial_delay_ns *= 2; + initial_delay_ns /= clock_div_prescaler; + + additional_scaler = 1U; + } + else + { + /* First calculate the initial, default delay, min delay is 1 clock + * cycle. Due to large size of calculated values (uint64_t), we need to + * break up the calculation into several steps to ensure accurate + * calculated * results. + */ + + initial_delay_ns = 1000000000U; + initial_delay_ns /= clock_div_prescaler; + + additional_scaler = 0; + } + + /* If the initial, default delay is already greater than the desired delay, + * then * set the delay to their initial value (0) and return the delay. In + * other words, * there is no way to decrease the delay value further. + */ + + if (initial_delay_ns >= delay_ns) + { + imx9_lpspi_master_set_delay_scaler(priv, 0, type); + } + else + { + /* If min_diff = 0, the exit for loop */ + + for (scaler = 0; (scaler < 256) && min_diff; scaler++) + { + /* Calculate the real delay value as we cycle through the scaler + * values. Due to large size of calculated values (uint64_t), + * we need to break up the calculation into several steps to + * ensure accurate calculated results + */ + + real_delay = 1000000000U; + real_delay *= (scaler + 1 + additional_scaler); + real_delay /= clock_div_prescaler; + + /* calculate the delay difference based on the conditional + * statement that states that the calculated delay must not be + * less then the desired delay + */ + + if (real_delay >= delay_ns) + { + diff = real_delay - delay_ns; + if (min_diff > diff) + { + /* A better match found */ + + min_diff = diff; + best_scaler = scaler; + } + } + } + + imx9_lpspi_master_set_delay_scaler(priv, best_scaler, type); + } +} + +/**************************************************************************** + * Name: imx9_lpspi_lock + * + * Description: + * On SPI buses where there are multiple devices, it will be necessary to + * lock SPI to have exclusive access to the buses for a sequence of + * transfers. The bus should be locked before the chip is selected. After + * locking the SPI bus, the caller should then also call the setfrequency, + * setbits, and setmode methods to make sure that the SPI is properly + * configured for the device. If the SPI bus is being shared, then it + * may have been left in an incompatible state. + * + * Input Parameters: + * dev - Device-specific state data + * lock - true: Lock spi bus, false: unlock SPI bus + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int imx9_lpspi_lock(struct spi_dev_s *dev, bool lock) +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + int ret; + + if (lock) + { + ret = nxmutex_lock(&priv->lock); + } + else + { + ret = nxmutex_unlock(&priv->lock); + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_lpspi_setfrequency + * + * Description: + * Set the SPI frequency. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The SPI frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static uint32_t imx9_lpspi_setfrequency(struct spi_dev_s *dev, + uint32_t frequency) +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + + uint32_t men; + uint32_t src_freq = 0; + uint32_t prescaler; + uint32_t best_prescaler; + uint32_t scaler; + uint32_t best_scaler; + uint32_t real_frequency; + uint32_t best_frequency; + uint32_t diff; + uint32_t min_diff; + + /* Has the LPSPI bus frequency changed? */ + + if (frequency != priv->frequency) + { + /* Disable LPSPI if it is enabled */ + + men = imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) & LPSPI_CR_MEN; + if (men) + { + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, + LPSPI_CR_MEN, 0); + } + + imx9_get_rootclock(priv->clk_root, &src_freq); + + min_diff = 0xffffffff; + best_prescaler = 7; + best_scaler = 255; + best_frequency = 0; + + for (prescaler = 0; (prescaler < 8) && min_diff; prescaler++) + { + for (scaler = 0; (scaler < 256) && min_diff; scaler++) + { + real_frequency = src_freq / ((1 << prescaler) * (scaler + 2)); + + /* Calculate the frequency difference based on conditional + * statement that states that the calculated frequency must not + * exceed desired frequency. + */ + + if (frequency >= real_frequency) + { + diff = frequency - real_frequency; + if (min_diff > diff) + { + /* A better match found */ + + min_diff = diff; + best_prescaler = prescaler; + best_scaler = scaler; + best_frequency = real_frequency; + } + } + } + } + + /* Write the best values in the CCR register */ + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CCR_OFFSET, + LPSPI_CCR_SCKDIV_MASK, + LPSPI_CCR_SCKDIV(best_scaler)); + + /* Update TCR */ + + imx9_lpspi_modifytcr(priv, LPSPI_TCR_PRESCALE_MASK, + LPSPI_TCR_PRESCALE(best_prescaler)); + + priv->frequency = frequency; + priv->actual = best_frequency; + imx9_lpspi_master_set_delays(priv, 1000000000 / best_frequency, + LPSPI_PCS_TO_SCK); + imx9_lpspi_master_set_delays(priv, 1000000000 / best_frequency, + LPSPI_LAST_SCK_TO_PCS); + imx9_lpspi_master_set_delays(priv, 1000000000 / best_frequency, + LPSPI_BETWEEN_TRANSFER); + + /* Re-enable LPSPI if it was enabled previously */ + + if (men) + { + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, 0, + LPSPI_CR_MEN); + } + } + + return priv->actual; +} + +/**************************************************************************** + * Name: imx9_lpspi_setmode + * + * Description: + * Set the SPI mode. see enum spi_mode_e mode for mode definitions + * + * Input Parameters: + * dev - Device-specific state data + * mode - The SPI mode requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static void imx9_lpspi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode) +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + uint32_t setbits; + uint32_t clrbits; + + spiinfo("mode=%d\n", mode); + + /* Has the mode changed? */ + + if (mode != priv->mode) + { + /* Disable LPSPI if it is enabled */ + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */ + setbits = 0; + clrbits = LPSPI_TCR_CPOL | LPSPI_TCR_CPHA; + break; + + case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */ + setbits = LPSPI_TCR_CPHA; + clrbits = LPSPI_TCR_CPOL; + break; + + case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */ + setbits = LPSPI_TCR_CPOL; + clrbits = LPSPI_TCR_CPHA; + break; + + case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */ + setbits = LPSPI_TCR_CPOL | LPSPI_TCR_CPHA; + clrbits = 0; + break; + + default: + return; + } + + /* Update TCR register */ + + imx9_lpspi_modifytcr(priv, clrbits, setbits); + + while ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_RSR_OFFSET) & + LPSPI_RSR_RXEMPTY) != LPSPI_RSR_RXEMPTY) + { + /* Flush SPI read FIFO */ + + imx9_lpspi_getreg32(priv, IMX9_LPSPI_RSR_OFFSET); + } + + /* Save the mode so that subsequent re-configurations will be faster */ + + priv->mode = mode; + } +} + +/**************************************************************************** + * Name: imx9_lpspi_setbits + * + * Description: + * Set the number of bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requested + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_lpspi_setbits(struct spi_dev_s *dev, int nbits) +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + + spiinfo("nbits=%d\n", nbits); + + /* Has the number of bits changed? */ + + if (nbits != priv->nbits) + { + if (nbits < 2 || nbits > 4096) + { + return; + } + + /* Update TCR */ + + imx9_lpspi_modifytcr(priv, LPSPI_TCR_FRAMESZ_MASK, + LPSPI_TCR_FRAMESZ(nbits - 1)); + + /* Save the selection so the subsequent re-configurations + * will be faster. + */ + + priv->nbits = nbits; + } +} + +/**************************************************************************** + * Name: imx9_lpspi_hwfeatures + * + * Description: + * Set hardware-specific feature flags. + * + * Input Parameters: + * dev - Device-specific state data + * features - H/W feature flags + * + * Returned Value: + * Zero (OK) if the selected H/W features are enabled; A negated errno + * value if any H/W feature is not supportable. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_HWFEATURES +static int imx9_lpspi_hwfeatures(struct spi_dev_s *dev, + imx9_lpspi_hwfeatures_t features) +{ +#ifdef CONFIG_SPI_BITORDER + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + uint32_t setbits; + uint32_t clrbits; + + spiinfo("features=%08x\n", features); + + /* Transfer data LSB first? */ + + if ((features & HWFEAT_LSBFIRST) != 0) + { + setbits = LPSPI_TCR_LSBF; + clrbits = 0; + } + else + { + setbits = 0; + clrbits = LPSPI_TCR_LSBF; + } + + imx9_lpspi_modifytcr(priv, clrbits, setbits); + + /* Other H/W features are not supported */ + + return ((features & ~HWFEAT_LSBFIRST) == 0) ? OK : -ENOSYS; +#else + return -ENOSYS; +#endif +} +#endif + +/**************************************************************************** + * Name: imx9_lpspi_send + * + * Description: + * Exchange one word on SPI + * + * Input Parameters: + * dev - Device-specific state data + * wd - The word to send. the size of the data is determined by the + * number of bits selected for the SPI interface. + * + * Returned Value: + * response + * + ****************************************************************************/ + +static uint32_t imx9_lpspi_send(struct spi_dev_s *dev, uint32_t wd) +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + uint32_t regval; + uint32_t ret; + + DEBUGASSERT(priv && priv->spibase); + + imx9_lpspi_writeword(priv, wd); + + while ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_SR_OFFSET) & + LPSPI_SR_RDF) != LPSPI_SR_RDF); + + ret = imx9_lpspi_readword(priv); + + /* Check and clear any error flags (Reading from the SR clears the error + * flags). + */ + + regval = imx9_lpspi_getreg32(priv, IMX9_LPSPI_SR_OFFSET); + + spiinfo( + "Sent: %04" PRIx32 " Return: %04" PRIx32 " Status: %02" PRIx32 "\n", + wd, ret, regval); + + UNUSED(regval); + return ret; +} + +/**************************************************************************** + * Name: imx9_lpspi_exchange (no DMA). aka imx9_lpspi_exchange_nodma + * + * Description: + * Exchange a block of data on SPI without using DMA + * + * Input Parameters: + * dev - Device-specific state data + * txbuffer - A pointer to the buffer of data to be sent + * rxbuffer - A pointer to a buffer in which to receive data + * nwords - the length of data to be exchanged in units of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed + * into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if !defined(CONFIG_IMX9_LPSPI_DMA) +static void imx9_lpspi_exchange(struct spi_dev_s *dev, + const void *txbuffer, + void *rxbuffer, + size_t nwords) +#else +static void imx9_lpspi_exchange_nodma(struct spi_dev_s *dev, + const void *txbuffer, + void *rxbuffer, size_t nwords) +#endif +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + DEBUGASSERT(priv && priv->spibase); + + spiinfo("txbuffer=%p rxbuffer=%p nwords=%lu\n", txbuffer, rxbuffer, + nwords); + + /* 8- or 16-bit mode? */ + + if (imx9_lpspi_9to16bitmode(priv)) + { + /* 16-bit mode */ + + const uint16_t *src = txbuffer; + uint16_t *dest = rxbuffer; + uint16_t word; + + while (nwords-- > 0) + { + /* Get the next word to write. Is there a source buffer? */ + + if (src) + { + word = *src++; + } + else + { + word = 0xffff; + } + + /* Exchange one word */ + + word = (uint16_t) imx9_lpspi_send(dev, (uint32_t) word); + + /* Is there a buffer to receive the return value? */ + + if (dest) + { + *dest++ = word; + } + } + } + else + { + /* 8-bit mode */ + + const uint8_t *src = txbuffer; + uint8_t *dest = rxbuffer; + uint8_t word; + + while (nwords-- > 0) + { + /* Get the next word to write. Is there a source buffer? */ + + if (src) + { + word = *src++; + } + else + { + word = 0xff; + } + + /* Exchange one word */ + + word = (uint8_t)imx9_lpspi_send(dev, word); + + /* Is there a buffer to receive the return value? */ + + if (dest) + { + *dest++ = word; + } + } + } +} + +/**************************************************************************** + * Name: spi_exchange (with DMA capability) + * + * Description: + * Exchange a block of data on SPI using DMA + * + * Input Parameters: + * dev - Device-specific state data + * txbuffer - A pointer to the buffer of data to be sent + * rxbuffer - A pointer to a buffer in which to receive data + * nwords - the length of data to be exchanged in units of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits > 8, the data is packed into + * uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static void imx9_lpspi_exchange(struct spi_dev_s *dev, + const void *txbuffer, + void *rxbuffer, size_t nwords) +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + int ret; + size_t adjust; + ssize_t nbytes; + static uint8_t rxdummy[4] aligned_data(4); + static const uint16_t txdummy = 0xffff; + uint32_t regval; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv && priv->spibase); + spiinfo("txbuffer=%p rxbuffer=%p nwords=%lu\n", txbuffer, rxbuffer, + nwords); + + /* Convert the number of word to a number of bytes */ + + nbytes = (priv->nbits > 8) ? nwords << 2 : nwords; + + /* Invalid DMA channels fall back to non-DMA method. */ + + if (priv->rxdma == NULL || priv->txdma == NULL +#ifdef CONFIG_IMX9_LPSPI_DMATHRESHOLD + /* If this is a small SPI transfer, then let + * imx9_lpspi_exchange_nodma() do the work. + */ + + || nbytes <= CONFIG_IMX9_LPSPI_DMATHRESHOLD +#endif + ) + { + imx9_lpspi_exchange_nodma(dev, txbuffer, rxbuffer, nwords); + return; + } + + /* Check if the transfer is too long */ + + if (nbytes > CONFIG_IMX9_LPSPI_DMA_BUFFER_SIZE) + { + /* Transfer is too long, revert to slow non-DMA method */ + + spiwarn("frame %lu too long, fall back to no DMA transfer\n", nbytes); + imx9_lpspi_exchange_nodma(dev, txbuffer, rxbuffer, nwords); + return; + } + + /* Disable SPI when we are configuring it */ + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, LPSPI_CR_MEN, 0); + + /* ERR050456 workaround: Reset FIFOs using CR[RST] bit */ + + regval = imx9_lpspi_getreg32(priv, IMX9_LPSPI_CFGR1_OFFSET); + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, + LPSPI_CR_RTF | LPSPI_CR_RRF, + LPSPI_CR_RTF | LPSPI_CR_RRF); + + imx9_lpspi_putreg32(priv, IMX9_LPSPI_CFGR1_OFFSET, regval); + + /* Clear all status bits */ + + imx9_lpspi_putreg32(priv, IMX9_LPSPI_SR_OFFSET, SPI_SR_CLEAR); + + /* disable DMA */ + + imx9_lpspi_putreg32(priv, IMX9_LPSPI_DER_OFFSET, 0); + + if (txbuffer) + { + /* Move the user data to device internal buffer */ + + memcpy(priv->txbuf, txbuffer, nbytes); + + /* And flush it to RAM */ + + up_clean_dcache((uintptr_t)priv->txbuf, + (uintptr_t)priv->txbuf + nbytes); + } + + if (rxbuffer) + { + /* Prepare the RX buffer for DMA */ + + up_invalidate_dcache((uintptr_t)priv->rxbuf, + (uintptr_t)priv->rxbuf + nbytes); + } + + /* Set up the DMA */ + + adjust = (priv->nbits > 8) ? 2 : 1; + + struct imx9_edma_xfrconfig_s config; + + config.saddr = priv->spibase + IMX9_LPSPI_RDR_OFFSET; + config.daddr = (uintptr_t) (rxbuffer ? priv->rxbuf : rxdummy); + config.soff = 0; + config.doff = rxbuffer ? adjust : 0; + config.iter = nbytes; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = adjust == 1 ? EDMA_8BIT : EDMA_16BIT; + config.dsize = adjust == 1 ? EDMA_8BIT : EDMA_16BIT; + config.nbytes = adjust; +#ifdef CONFIG_IMX9_EDMA_ELINK + config.linkch = NULL; +#endif + imx9_dmach_xfrsetup(priv->rxdma, &config); + + config.saddr = (uintptr_t) (txbuffer ? priv->txbuf : &txdummy); + config.daddr = priv->spibase + IMX9_LPSPI_TDR_OFFSET; + config.soff = txbuffer ? adjust : 0; + config.doff = 0; + config.iter = nbytes; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = adjust == 1 ? EDMA_8BIT : EDMA_16BIT; + config.dsize = adjust == 1 ? EDMA_8BIT : EDMA_16BIT; + config.nbytes = adjust; +#ifdef CONFIG_IMX9_EDMA_ELINK + config.linkch = NULL; +#endif + imx9_dmach_xfrsetup(priv->txdma, &config); + + /* Start the DMAs */ + + spi_dmarxstart(priv); + spi_dmatxstart(priv); + + /* Enable SPI again */ + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, 0, LPSPI_CR_MEN); + + /* Invoke SPI DMA */ + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_DER_OFFSET, + 0, LPSPI_DER_TDDE | LPSPI_DER_RDDE); + + /* Then wait for each to complete */ + + ret = spi_dmarxwait(priv); + + if (ret < 0) + { + ret = spi_dmatxwait(priv); + } + + /* Reset any status */ + + imx9_lpspi_putreg32(priv, IMX9_LPSPI_SR_OFFSET, SPI_SR_CLEAR); + + /* Disable DMA */ + + imx9_lpspi_putreg32(priv, IMX9_LPSPI_DER_OFFSET, 0); + + if (rxbuffer && ret >= 0) + { + /* Flush the RX data to ram */ + + up_invalidate_dcache((uintptr_t)priv->rxbuf, + (uintptr_t)priv->rxbuf + nbytes); + + /* Copy data to user buffer */ + + memcpy(rxbuffer, priv->rxbuf, nbytes); + } +} + +#endif /* CONFIG_IMX9_SPI_DMA */ + +/**************************************************************************** + * Name: imx9_lpspi_sndblock + * + * Description: + * Send a block of data on SPI + * + * Input Parameters: + * dev - Device-specific state data + * txbuffer - A pointer to the buffer of data to be sent + * nwords - the length of data to send from the buffer in number of + * words. The wordsize is determined by the number of + * bits-per-word selected for the SPI interface. If nbits <= 8, + * the data is packed into uint8_t's; if nbits >8, the data is + * packed into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void imx9_lpspi_sndblock(struct spi_dev_s *dev, + const void *txbuffer, size_t nwords) +{ + spiinfo("txbuffer=%p nwords=%lu\n", txbuffer, nwords); + return imx9_lpspi_exchange(dev, txbuffer, NULL, nwords); +} +#endif + +/**************************************************************************** + * Name: imx9_lpspi_recvblock + * + * Description: + * Receive a block of data from SPI + * + * Input Parameters: + * dev - Device-specific state data + * rxbuffer - A pointer to the buffer in which to receive data + * nwords - the length of data that can be received in the buffer in + * number of words. The wordsize is determined by the number of + * bits-per-word selected for the SPI interface. If nbits <= 8, + * the data is packed into uint8_t's; if nbits >8, the data is + * packed into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_EXCHANGE +static void imx9_lpspi_recvblock(struct spi_dev_s *dev, + void *rxbuffer, size_t nwords) +{ + spiinfo("rxbuffer=%p nwords=%lu\n", rxbuffer, nwords); + return imx9_lpspi_exchange(dev, NULL, rxbuffer, nwords); +} +#endif + +/**************************************************************************** + * Name: imx9_lpspi_clock_enable + * + * Description: + * Ungate LPSPI clock + * + ****************************************************************************/ + +static void imx9_lpspi_clock_enable(struct imx9_lpspidev_s *priv) +{ + imx9_ccm_gate_on(priv->clk_gate, true); +} + +/**************************************************************************** + * Name: imx9_lpspi_bus_initialize + * + * Description: + * Initialize the selected SPI bus in its default state + * (Master, 8-bit, mode 0, etc.) + * + * Input Parameters: + * priv - private SPI device structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_lpspi_bus_initialize(struct imx9_lpspidev_s *priv) +{ + uint32_t reg = 0; + + /* Enable power and reset the peripheral */ + + imx9_lpspi_clock_enable(priv); + + /* Reset to known status */ + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, 0, LPSPI_CR_RST); + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, 0, + LPSPI_CR_RTF | LPSPI_CR_RRF); + imx9_lpspi_putreg32(priv, IMX9_LPSPI_CR_OFFSET, 0x00); + + /* Set LPSPI to master */ + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CFGR1_OFFSET, 0, + LPSPI_CFGR1_MASTER); + + /* Set specific PCS to active high or low + * TODO: Not needed for now + */ + + /* Set Configuration Register 1 related setting. */ + + reg = imx9_lpspi_getreg32(priv, IMX9_LPSPI_CFGR1_OFFSET); + reg &= ~(LPSPI_CFGR1_OUTCFG | LPSPI_CFGR1_PINCFG_MASK | + LPSPI_CFGR1_NOSTALL); + reg |= LPSPI_CFGR1_OUTCFG_RETAIN | LPSPI_CFGR1_PINCFG_SIN_SOUT; + imx9_lpspi_putreg32(priv, IMX9_LPSPI_CFGR1_OFFSET, reg); + + /* Set frequency and delay times */ + + imx9_lpspi_setfrequency((struct spi_dev_s *)priv, 400000); + + /* Set default watermarks */ + + imx9_lpspi_putreg32(priv, IMX9_LPSPI_FCR_OFFSET, + LPSPI_FCR_TXWATER(0) | LPSPI_FCR_RXWATER(0)); + + /* Set Transmit Command Register */ + + imx9_lpspi_setbits((struct spi_dev_s *)priv, 8); + + imx9_lpspi_setmode((struct spi_dev_s *)priv, SPIDEV_MODE0); + + /* Enable LPSPI */ + + imx9_lpspi_modifyreg32(priv, IMX9_LPSPI_CR_OFFSET, 0, LPSPI_CR_MEN); +} + +/**************************************************************************** + * Name: spi_dmarxwait + * + * Description: + * Wait for DMA to complete. + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static int spi_dmarxwait(struct imx9_lpspidev_s *priv) +{ + int ret; + + /* Take the semaphore (perhaps waiting). If the result is zero, then the + * DMA must not really have completed. + */ + + do + { + ret = nxsem_wait_uninterruptible(&priv->rxsem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(ret == OK || ret == -ECANCELED); + } + while (priv->rxresult == 0 && ret == OK); + + return ret; +} +#endif + +/**************************************************************************** + * Name: spi_dmatxwait + * + * Description: + * Wait for DMA to complete. + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static int spi_dmatxwait(struct imx9_lpspidev_s *priv) +{ + int ret; + + /* Take the semaphore (perhaps waiting). If the result is zero, then the + * DMA must not really have completed. + */ + + do + { + ret = nxsem_wait_uninterruptible(&priv->txsem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(ret == OK || ret == -ECANCELED); + } + while (priv->txresult == 0 && ret == OK); + + return ret; +} +#endif + +/**************************************************************************** + * Name: spi_dmarxwakeup + * + * Description: + * Signal that DMA is complete + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static inline void spi_dmarxwakeup(struct imx9_lpspidev_s *priv) +{ + nxsem_post(&priv->rxsem); +} +#endif + +/**************************************************************************** + * Name: spi_dmatxwakeup + * + * Description: + * Signal that DMA is complete + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static inline void spi_dmatxwakeup(struct imx9_lpspidev_s *priv) +{ + nxsem_post(&priv->txsem); +} +#endif + +/**************************************************************************** + * Name: spi_dmarxcallback + * + * Description: + * Called when the RX DMA completes + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static void spi_dmarxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)arg; + + priv->rxresult = result | 0x80000000; /* assure non-zero */ + spi_dmarxwakeup(priv); +} +#endif + +/**************************************************************************** + * Name: spi_dmatxcallback + * + * Description: + * Called when the RX DMA completes + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static void spi_dmatxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)arg; + + /* Wake-up the SPI driver */ + + priv->txresult = result | 0x80000000; /* assure non-zero */ + spi_dmatxwakeup(priv); +} +#endif + +/**************************************************************************** + * Name: spi_dmarxstart + * + * Description: + * Start RX DMA + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static inline void spi_dmarxstart(struct imx9_lpspidev_s *priv) +{ + priv->rxresult = 0; + imx9_dmach_start(priv->rxdma, spi_dmarxcallback, priv); +} +#endif + +/**************************************************************************** + * Name: spi_dmatxstart + * + * Description: + * Start TX DMA + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI_DMA +static inline void spi_dmatxstart(struct imx9_lpspidev_s *priv) +{ + priv->txresult = 0; + imx9_dmach_start(priv->txdma, spi_dmatxcallback, priv); +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_lpspibus_initialize + * + * Description: + * Initialize the selected SPI bus + * + * Input Parameters: + * Port number (for hardware that has multiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct spi_dev_s *imx9_lpspibus_initialize(int bus) +{ + struct imx9_lpspidev_s *priv = NULL; + + irqstate_t flags = enter_critical_section(); + +#ifdef CONFIG_IMX9_LPSPI1 + if (bus == 1) + { + /* Select SPI1 */ + + priv = &g_lpspi1dev; + + /* Only configure if the bus is not already configured */ + + if ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) + & LPSPI_CR_MEN) == 0) + { + /* Configure SPI1 pins: SCK, MISO, and MOSI */ + + imx9_iomux_configure(MUX_LPSPI1_SCK); + imx9_iomux_configure(MUX_LPSPI1_MISO); + imx9_iomux_configure(MUX_LPSPI1_MOSI); +#if defined(MUX_LPSPI1_CS) && defined(GPIO_LPSPI1_CS) + imx9_iomux_configure(MUX_LPSPI1_CS); + imx9_config_gpio(GPIO_LPSPI1_CS); +#endif +#if defined(GPIO_LPSPI1_DC) && defined(CONFIG_SPI_CMDDATA) + imx9_iomux_configure(GPIO_LPSPI1_DC); +#endif + + /* Set up default configuration: Master, 8-bit, etc. */ + + imx9_lpspi_bus_initialize(priv); + } + } + else +#endif +#ifdef CONFIG_IMX9_LPSPI2 + if (bus == 2) + { + /* Select SPI2 */ + + priv = &g_lpspi2dev; + + /* Only configure if the bus is not already configured */ + + if ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) + & LPSPI_CR_MEN) == 0) + { + /* Configure SPI2 pins: SCK, MISO, and MOSI */ + + imx9_iomux_configure(MUX_LPSPI2_SCK); + imx9_iomux_configure(MUX_LPSPI2_MISO); + imx9_iomux_configure(MUX_LPSPI2_MOSI); +#if defined(MUX_LPSPI2_CS) && defined(GPIO_LPSPI2_CS) + imx9_iomux_configure(MUX_LPSPI2_CS); + imx9_config_gpio(GPIO_LPSPI2_CS); +#endif +#if defined(GPIO_LPSPI2_DC) && defined(CONFIG_SPI_CMDDATA) + imx9_iomux_configure(GPIO_LPSPI2_DC); +#endif + + /* Set up default configuration: Master, 8-bit, etc. */ + + imx9_lpspi_bus_initialize(priv); + } + } + else +#endif +#ifdef CONFIG_IMX9_LPSPI3 + if (bus == 3) + { + /* Select SPI3 */ + + priv = &g_lpspi3dev; + + /* Only configure if the bus is not already configured */ + + if ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) + & LPSPI_CR_MEN) == 0) + { + /* Configure SPI3 pins: SCK, MISO, and MOSI */ + + imx9_iomux_configure(MUX_LPSPI3_SCK); + imx9_iomux_configure(MUX_LPSPI3_MISO); + imx9_iomux_configure(MUX_LPSPI3_MOSI); +#if defined(MUX_LPSPI3_CS) && defined(GPIO_LPSPI3_CS) + imx9_iomux_configure(MUX_LPSPI3_CS); + imx9_config_gpio(GPIO_LPSPI3_CS); +#endif +#if defined(GPIO_LPSPI3_DC) && defined(CONFIG_SPI_CMDDATA) + imx9_iomux_configure(GPIO_LPSPI3_DC); +#endif + + /* Set up default configuration: Master, 8-bit, etc. */ + + imx9_lpspi_bus_initialize(priv); + } + } + else +#endif +#ifdef CONFIG_IMX9_LPSPI4 + if (bus == 4) + { + /* Select SPI4 */ + + priv = &g_lpspi4dev; + + /* Only configure if the bus is not already configured */ + + if ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) + & LPSPI_CR_MEN) == 0) + { + /* Configure SPI4 pins: SCK, MISO, and MOSI */ + + imx9_iomux_configure(MUX_LPSPI4_SCK); + imx9_iomux_configure(MUX_LPSPI4_MISO); + imx9_iomux_configure(MUX_LPSPI4_MOSI); +#if defined(MUX_LPSPI4_CS) && defined(GPIO_LPSPI4_CS) + imx9_iomux_configure(MUX_LPSPI4_CS); + imx9_config_gpio(GPIO_LPSPI4_CS); +#endif +#if defined(GPIO_LPSPI4_DC) && defined(CONFIG_SPI_CMDDATA) + imx9_iomux_configure(GPIO_LPSPI4_DC); +#endif + + /* Set up default configuration: Master, 8-bit, etc. */ + + imx9_lpspi_bus_initialize(priv); + } + } + else +#endif +#ifdef CONFIG_IMX9_LPSPI5 + if (bus == 5) + { + /* Select SPI5 */ + + priv = &g_lpspi5dev; + + /* Only configure if the bus is not already configured */ + + if ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) + & LPSPI_CR_MEN) == 0) + { + /* Configure SPI5 pins: SCK, MISO, and MOSI */ + + imx9_iomux_configure(MUX_LPSPI5_SCK); + imx9_iomux_configure(MUX_LPSPI5_MISO); + imx9_iomux_configure(MUX_LPSPI5_MOSI); +#if defined(MUX_LPSPI5_CS) && defined(GPIO_LPSPI5_CS) + imx9_iomux_configure(MUX_LPSPI5_CS); + imx9_config_gpio(GPIO_LPSPI5_CS); +#endif +#if defined(GPIO_LPSPI5_DC) && defined(CONFIG_SPI_CMDDATA) + imx9_iomux_configure(GPIO_LPSPI5_DC); +#endif + + /* Set up default configuration: Master, 8-bit, etc. */ + + imx9_lpspi_bus_initialize(priv); + } + } + else +#endif +#ifdef CONFIG_IMX9_LPSPI6 + if (bus == 6) + { + /* Select SPI6 */ + + priv = &g_lpspi6dev; + + /* Only configure if the bus is not already configured */ + + if ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) + & LPSPI_CR_MEN) == 0) + { + /* Configure SPI6 pins: SCK, MISO, and MOSI */ + + imx9_iomux_configure(MUX_LPSPI6_SCK); + imx9_iomux_configure(MUX_LPSPI6_MISO); + imx9_iomux_configure(MUX_LPSPI6_MOSI); +#if defined(MUX_LPSPI6_CS) && defined(GPIO_LPSPI6_CS) + imx9_iomux_configure(MUX_LPSPI6_CS); + imx9_config_gpio(GPIO_LPSPI6_CS); +#endif +#if defined(GPIO_LPSPI6_DC) && defined(CONFIG_SPI_CMDDATA) + imx9_iomux_configure(GPIO_LPSPI6_DC); +#endif + + /* Set up default configuration: Master, 8-bit, etc. */ + + imx9_lpspi_bus_initialize(priv); + } + } + else +#endif +#ifdef CONFIG_IMX9_LPSPI7 + if (bus == 7) + { + /* Select SPI7 */ + + priv = &g_lpspi7dev; + + /* Only configure if the bus is not already configured */ + + if ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) + & LPSPI_CR_MEN) == 0) + { + /* Configure SPI7 pins: SCK, MISO, and MOSI */ + + imx9_iomux_configure(MUX_LPSPI7_SCK); + imx9_iomux_configure(MUX_LPSPI7_MISO); + imx9_iomux_configure(MUX_LPSPI7_MOSI); +#if defined(MUX_LPSPI7_CS) && defined(GPIO_LPSPI7_CS) + imx9_iomux_configure(MUX_LPSPI7_CS); + imx9_config_gpio(GPIO_LPSPI7_CS); +#endif +#if defined(GPIO_LPSPI7_DC) && defined(CONFIG_SPI_CMDDATA) + imx9_iomux_configure(GPIO_LPSPI7_DC); +#endif + + /* Set up default configuration: Master, 8-bit, etc. */ + + imx9_lpspi_bus_initialize(priv); + } + } + else +#endif +#ifdef CONFIG_IMX9_LPSPI8 + if (bus == 8) + { + /* Select SPI8 */ + + priv = &g_lpspi8dev; + + /* Only configure if the bus is not already configured */ + + if ((imx9_lpspi_getreg32(priv, IMX9_LPSPI_CR_OFFSET) + & LPSPI_CR_MEN) == 0) + { + /* Configure SPI6 pins: SCK, MISO, and MOSI */ + + imx9_iomux_configure(MUX_LPSPI8_SCK); + imx9_iomux_configure(MUX_LPSPI8_MISO); + imx9_iomux_configure(MUX_LPSPI8_MOSI); +#if defined(MUX_LPSPI8_CS) && defined(GPIO_LPSPI8_CS) + imx9_iomux_configure(MUX_LPSPI8_CS); + imx9_config_gpio(GPIO_LPSPI8_CS); +#endif +#if defined(GPIO_LPSPI8_DC) && defined(CONFIG_SPI_CMDDATA) + imx9_iomux_configure(GPIO_LPSPI8_DC); +#endif + + /* Set up default configuration: Master, 8-bit, etc. */ + + imx9_lpspi_bus_initialize(priv); + } + } + else +#endif + { + spierr("ERROR: Unsupported SPI bus: %d\n", bus); + } + +#ifdef CONFIG_IMX9_LPSPI_DMA + if (priv->rxch && priv->txch) + { + if (priv->txdma == NULL && priv->rxdma == NULL) + { + priv->txdma = imx9_dmach_alloc(priv->txch, 0); + priv->rxdma = imx9_dmach_alloc(priv->rxch, 0); + DEBUGASSERT(priv->rxdma && priv->txdma); + } + + if (priv->txbuf == NULL && priv->rxbuf == NULL) + { + priv->txbuf = imx9_dma_alloc(CONFIG_IMX9_LPSPI_DMA_BUFFER_SIZE); + priv->rxbuf = imx9_dma_alloc(CONFIG_IMX9_LPSPI_DMA_BUFFER_SIZE); + DEBUGASSERT(priv->txbuf && priv->rxbuf); + } + } + else + { + priv->rxdma = NULL; + priv->txdma = NULL; + } +#endif + + leave_critical_section(flags); + + return (struct spi_dev_s *)priv; +} + +#endif /* CONFIG_IMX9_LPSPI */ diff --git a/arch/arm64/src/imx9/imx9_lpspi.h b/arch/arm64/src/imx9/imx9_lpspi.h new file mode 100644 index 0000000000000..00907320698d5 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lpspi.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_lpspi.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_LPSPI_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_LPSPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +#include "chip.h" +#include "hardware/imx9_lpspi.h" + +/**************************************************************************** + * Public Functions Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +struct spi_dev_s; /* Forward reference */ + +/**************************************************************************** + * Name: imx9_lpspibus_initialize + * + * Description: + * Initialize the selected SPI bus + * + * Input Parameters: + * bus number (for hardware that has multiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on success; a NULL on failure + * + ****************************************************************************/ + +struct spi_dev_s *imx9_lpspibus_initialize(int bus); + +/**************************************************************************** + * Name: imx9_lpspi1/2/...select and imx9_lpspi1/2/...status + * + * Description: + * The external functions, imx9_lpspi1/2/...select, + * imx9_lpspi1/2/...status, and imx9_lpspi1/2/...cmddata must be + * provided by board-specific logic. These are implementations of the + * select, status, and cmddata methods of the SPI interface defined by + * struct spi_ops_s (see include/nuttx/spi/spi.h). All other methods + * (including imx9_lpspibus_initialize()) are provided by common IMX9 + * logic. To use this common SPI logic on your board: + * + * 1. Provide logic in imx9_boardinitialize() to configure SPI chip select + * pins. + * 2. Provide imx9_lpspi1/2/...select() and imx9_lpspi1/2/...status() + * functions in your board-specific logic. These functions will perform + * chip selection and status operations using GPIOs in the way your + * board is configured. + * 3. If CONFIG_SPI_CMDDATA is defined in your NuttX configuration file, + * then provide imx9_lpspi1/2/...cmddata() functions in your + * board-specific logic. These functions will perform cmd/data selection + * operations using GPIOs in the way your board is configured. + * 4. Add a calls to imx9_lpspibus_initialize() in your low level + * application initialization logic + * 5. The handle returned by imx9_lpspibus_initialize() may then be used + * to bind the SPI driver to higher level logic (e.g., calling + * mmcsd_spislotinitialize(), for example, will bind the SPI driver to + * the SPI MMC/SD driver). + * + ****************************************************************************/ + +void imx9_lpspi_select(struct spi_dev_s *dev, + uint32_t devid, bool selected); +uint8_t imx9_lpspi_status(struct spi_dev_s *dev, uint32_t devid); +int imx9_lpspi_cmddata(struct spi_dev_s *dev, + uint32_t devid, bool cmd); + +/**************************************************************************** + * Name: imx9_lpspi1/2/...register + * + * Description: + * If the board supports a card detect callback to inform the SPI-based + * MMC/SD driver when an SD card is inserted or removed, then + * CONFIG_SPI_CALLBACK should be defined and the following function(s) + * must be implemented. These functions implements the registercallback + * method of the SPI interface (see include/nuttx/spi/spi.h for details) + * + * Input Parameters: + * dev - Device-specific state data + * callback - The function to call on the media change + * arg - A caller provided value to return with the callback + * + * Returned Value: + * 0 on success; negated errno on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_CALLBACK +int imx9_lpspi_register(struct spi_dev_s *dev, + spi_mediachange_t callback, + void *arg); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_LPSPI_H */ diff --git a/arch/arm64/src/imx9/imx9_lpuart.c b/arch/arm64/src/imx9/imx9_lpuart.c new file mode 100644 index 0000000000000..601770b01f840 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lpuart.c @@ -0,0 +1,2821 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_lpuart.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SERIAL_TERMIOS +# include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "arm64_internal.h" +#include "hardware/imx9_lpuart.h" +#include "hardware/imx9_pinmux.h" +#include "imx9_lowputc.h" +#include "imx9_serial.h" + +#if defined(SERIAL_HAVE_TXDMA) || defined(SERIAL_HAVE_RXDMA) +# include "chip.h" +# include "imx9_edma.h" +# include "hardware/imx9_dmamux.h" +#endif + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The DMA buffer size when using RX DMA to emulate a FIFO. + * + * When streaming data, the generic serial layer will be called every time + * the FIFO receives half this number of bytes. + * + * This buffer size should be an even multiple of the Cortex-A55 D-Cache line + * size, ARMV8A_DCACHE_LINESIZE, so that it can be individually invalidated. + */ + +# if !defined(ARMV8A_DCACHE_LINESIZE) || ARMV8A_DCACHE_LINESIZE == 0 +# undef ARMV8A_DCACHE_LINESIZE +# define ARMV8A_DCACHE_LINESIZE 64 +# endif + +# if !defined(CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE) || \ + (CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE < ARMV8A_DCACHE_LINESIZE) +# undef CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE +# define CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE ARMV8A_DCACHE_LINESIZE +# endif + +# define RXDMA_BUFFER_MASK (ARMV8A_DCACHE_LINESIZE - 1) +# define RXDMA_BUFFER_SIZE ((CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE \ + + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK) + +/* The DMA buffer size when using TX DMA. + * + * This TX buffer size should be an even multiple of the Cortex-A55 D-Cache + * line size, ARMV8A_DCACHE_LINESIZE, so that it can be individually + * invalidated. + */ + +#define TXDMA_BUFFER_MASK (ARMV8A_DCACHE_LINESIZE - 1) +#define TXDMA_BUFFER_SIZE ((CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE \ + + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK) + +/* Buffers need to be aligned and multiples of ARMV8A_DCACHE_LINESIZE */ + +#if defined(CONFIG_ARM64_DCACHE_DISABLE) +# define TXDMA_BUF_SIZE(b) (b) +# define TXDMA_BUF_ALIGN +#else +# define TXDMA_BUF_SIZE(b) (((b) + TXDMA_BUFFER_MASK) & ~TXDMA_BUFFER_MASK) +# define TXDMA_BUF_ALIGN aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +#if !defined(CONFIG_LPUART1_TXDMA) +# define LPUART1_TXBUFSIZE_ADJUSTED CONFIG_LPUART1_TXBUFSIZE +# define LPUART1_TXBUFSIZE_ALGN +#else +# define LPUART1_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART1_TXBUFSIZE) +# define LPUART1_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART2_TXDMA) +# define LPUART2_TXBUFSIZE_ADJUSTED CONFIG_LPUART2_TXBUFSIZE +# define LPUART2_TXBUFSIZE_ALGN +#else +# define LPUART2_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART2_TXBUFSIZE) +# define LPUART2_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART3_TXDMA) +# define LPUART3_TXBUFSIZE_ADJUSTED CONFIG_LPUART3_TXBUFSIZE +# define LPUART3_TXBUFSIZE_ALGN +#else +# define LPUART3_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART3_TXBUFSIZE) +# define LPUART3_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART4_TXDMA) +# define LPUART4_TXBUFSIZE_ADJUSTED CONFIG_LPUART4_TXBUFSIZE +# define LPUART4_TXBUFSIZE_ALGN +#else +# define LPUART4_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART4_TXBUFSIZE) +# define LPUART4_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART5_TXDMA) +# define LPUART5_TXBUFSIZE_ADJUSTED CONFIG_LPUART5_TXBUFSIZE +# define LPUART5_TXBUFSIZE_ALGN +#else +# define LPUART5_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART5_TXBUFSIZE) +# define LPUART5_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART6_TXDMA) +# define LPUART6_TXBUFSIZE_ADJUSTED CONFIG_LPUART6_TXBUFSIZE +# define LPUART6_TXBUFSIZE_ALGN +#else +# define LPUART6_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART6_TXBUFSIZE) +# define LPUART6_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART7_TXDMA) +# define LPUART7_TXBUFSIZE_ADJUSTED CONFIG_LPUART7_TXBUFSIZE +# define LPUART7_TXBUFSIZE_ALGN +#else +# define LPUART7_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART7_TXBUFSIZE) +# define LPUART7_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_LPUART8_TXDMA) +# define LPUART8_TXBUFSIZE_ADJUSTED CONFIG_LPUART8_TXBUFSIZE +# define LPUART8_TXBUFSIZE_ALGN +#else +# define LPUART8_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART8_TXBUFSIZE) +# define LPUART8_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +/* Which LPUART with be console? */ + +#if defined(CONFIG_LPUART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart1priv /* LPUART1 is console */ +# if defined(CONFIG_LPUART1_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART1_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart2priv /* LPUART2 is console */ +# if defined(CONFIG_LPUART2_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART2_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART3_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart3priv /* LPUART3 is console */ +# if defined(CONFIG_LPUART3_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART3_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART4_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart4priv /* LPUART4 is console */ +# if defined(CONFIG_LPUART4_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART4_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART5_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart5priv /* LPUART5 is console */ +# if defined(CONFIG_LPUART5_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART5_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART6_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart6priv /* LPUART6 is console */ +# if defined(CONFIG_LPUART6_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART6_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART7_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart7priv /* LPUART7 is console */ +# if defined(CONFIG_LPUART7_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART7_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#elif defined(CONFIG_LPUART8_SERIAL_CONSOLE) +# define CONSOLE_DEV g_lpuart8priv /* LPUART8 is console */ +# if defined(CONFIG_LPUART8_RXDMA) +# define SERIAL_HAVE_CONSOLE_RXDMA 1 +# endif +# if defined(CONFIG_LPUART8_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +# endif +#endif + +#if defined(SERIAL_HAVE_CONSOLE_RXDMA) || defined(SERIAL_HAVE_CONSOLE_TXDMA) +# define SERIAL_HAVE_CONSOLE_DMA +#endif + +#ifdef CONFIG_IMX9_LPUART1 +#define TTYS0_DEV g_lpuart1priv /* LPUART1 is ttyS0 */ +#endif + +#ifdef CONFIG_IMX9_LPUART2 +#define TTYS1_DEV g_lpuart2priv /* LPUART2 is ttyS1 */ +#endif + +#ifdef CONFIG_IMX9_LPUART3 +#define TTYS2_DEV g_lpuart3priv /* LPUART3 is ttyS2 */ +#endif + +#ifdef CONFIG_IMX9_LPUART4 +#define TTYS3_DEV g_lpuart4priv /* LPUART4 is ttyS3 */ +#endif + +#ifdef CONFIG_IMX9_LPUART5 +#define TTYS4_DEV g_lpuart5priv /* LPUART5 is ttyS4 */ +#endif + +#ifdef CONFIG_IMX9_LPUART6 +#define TTYS5_DEV g_lpuart6priv /* LPUART6 is ttyS5 */ +#endif + +#ifdef CONFIG_IMX9_LPUART7 +#define TTYS6_DEV g_lpuart7priv /* LPUART7 is ttyS6 */ +#endif + +#ifdef CONFIG_IMX9_LPUART8 +#define TTYS7_DEV g_lpuart8priv /* LPUART8 is ttyS7 */ +#endif + +/* Power management definitions */ + +#if defined(CONFIG_PM) && !defined(CONFIG_IMX9_PM_SERIAL_ACTIVITY) +# define CONFIG_IMX9_PM_SERIAL_ACTIVITY 10 +#endif + +#if defined(CONFIG_PM) +# define PM_IDLE_DOMAIN 0 /* Revisit */ +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct imx9_uart_s +{ + struct uart_dev_s dev; /* Generic UART device */ + const uint32_t uartbase; /* Base address of UART registers */ + const int uartnum; /* LPUART number 1-8 */ + uint32_t baud; /* Configured baud */ + uint32_t ie; /* Saved enabled interrupts */ + uint8_t irq; /* IRQ associated with this UART */ + uint8_t parity; /* 0=none, 1=odd, 2=even */ + uint8_t bits; /* Number of bits (7 or 8) */ +#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL) + uint8_t inviflow:1; /* Invert RTS sense */ + const uint32_t rts_gpio; /* LPUART RTS GPIO pin configuration */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + const uint32_t cts_gpio; /* LPUART CTS GPIO pin configuration */ +#endif + uint8_t stopbits2:1; /* 1: Configure with 2 stop bits vs 1 */ +#ifdef CONFIG_SERIAL_IFLOWCONTROL + uint8_t iflow:1; /* input flow control (RTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_OFLOWCONTROL + uint8_t oflow:1; /* output flow control (CTS) enabled */ +#endif +#ifdef CONFIG_SERIAL_RS485CONTROL + uint8_t rs485mode:1; /* We are in RS485 (RTS on TX) mode */ +#endif + /* TX DMA state */ + +#ifdef SERIAL_HAVE_TXDMA + const unsigned int txch; /* DMAMUX source of TX DMA request */ + DMACH_HANDLE txdma; /* currently-open transmit DMA stream */ +#endif + + /* RX DMA state */ + +#ifdef SERIAL_HAVE_RXDMA + const unsigned int rxch; /* DMAMUX source of RX DMA request */ + DMACH_HANDLE rxdma; /* currently-open receive DMA stream */ + bool rxenable; /* DMA-based reception en/disable */ + uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */ +#ifndef CONFIG_ARM64_DCACHE_DISABLE + uint32_t rxdmaavail; /* Number of bytes available without need to + * to invalidate the data cache */ +#endif + char *const rxfifo; /* Receive DMA buffer */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline uint32_t imx9_serialin(struct imx9_uart_s *priv, + uint32_t offset); +static inline void imx9_serialout(struct imx9_uart_s *priv, + uint32_t offset, uint32_t value); +static inline void imx9_disableuartint(struct imx9_uart_s *priv, + uint32_t *ie); +static inline void imx9_restoreuartint(struct imx9_uart_s *priv, + uint32_t ie); + +static int imx9_setup(struct uart_dev_s *dev); +static void imx9_shutdown(struct uart_dev_s *dev); +static int imx9_attach(struct uart_dev_s *dev); +static void imx9_detach(struct uart_dev_s *dev); +static int imx9_interrupt(int irq, void *context, void *arg); +static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg); +#if !defined(SERIAL_HAVE_ONLY_RXDMA) +static int imx9_receive(struct uart_dev_s *dev, unsigned int *status); +static void imx9_rxint(struct uart_dev_s *dev, bool enable); +static bool imx9_rxavailable(struct uart_dev_s *dev); +#endif +#if !defined(SERIAL_HAVE_ONLY_TXDMA) +static void imx9_txint(struct uart_dev_s *dev, bool enable); +#endif + +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool imx9_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper); +#endif +static void imx9_send(struct uart_dev_s *dev, int ch); + +static bool imx9_txready(struct uart_dev_s *dev); + +#ifdef SERIAL_HAVE_TXDMA +static void imx9_dma_send(struct uart_dev_s *dev); +static void imx9_dma_txint(struct uart_dev_s *dev, bool enable); +static void imx9_dma_txavailable(struct uart_dev_s *dev); +static void imx9_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int imx9_dma_setup(struct uart_dev_s *dev); +static void imx9_dma_shutdown(struct uart_dev_s *dev); +#endif + +#ifdef SERIAL_HAVE_RXDMA +static int imx9_dma_receive(struct uart_dev_s *dev, + unsigned int *status); +#ifdef CONFIG_PM +static void imx9_dma_reenable(struct imx9_uart_s *priv); +#endif +static void imx9_dma_rxint(struct uart_dev_s *dev, bool enable); +static bool imx9_dma_rxavailable(struct uart_dev_s *dev); + +static void imx9_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result); +#endif + +static bool imx9_txempty(struct uart_dev_s *dev); + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int dowmin, + enum pm_state_e pmstate); +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Serial driver UART operations */ + +#if !defined(SERIAL_HAVE_ONLY_TXDMA) && !defined(SERIAL_HAVE_ONLY_RXDMA) +static const struct uart_ops_s g_lpuart_ops = +{ + .setup = imx9_setup, + .shutdown = imx9_shutdown, + .attach = imx9_attach, + .detach = imx9_detach, + .ioctl = imx9_ioctl, + .receive = imx9_receive, + .rxint = imx9_rxint, + .rxavailable = imx9_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = imx9_rxflowcontrol, +#endif + .send = imx9_send, + .txint = imx9_txint, + .txready = imx9_txready, + .txempty = imx9_txempty, +}; +#endif + +#if defined(SERIAL_HAVE_RXDMA) && defined(SERIAL_HAVE_TXDMA) +static const struct uart_ops_s g_lpuart_rxtxdma_ops = +{ + .setup = imx9_dma_setup, + .shutdown = imx9_dma_shutdown, + .attach = imx9_attach, + .detach = imx9_detach, + .ioctl = imx9_ioctl, + .receive = imx9_dma_receive, + .rxint = imx9_dma_rxint, + .rxavailable = imx9_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = imx9_rxflowcontrol, +#endif + .send = imx9_send, + .txint = imx9_dma_txint, + .txready = imx9_txready, + .txempty = imx9_txempty, + .dmatxavail = imx9_dma_txavailable, + .dmasend = imx9_dma_send, +}; +#endif + +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA) +static const struct uart_ops_s g_lpuart_rxdma_ops = +{ + .setup = imx9_dma_setup, + .shutdown = imx9_dma_shutdown, + .attach = imx9_attach, + .detach = imx9_detach, + .ioctl = imx9_ioctl, + .receive = imx9_dma_receive, + .rxint = imx9_dma_rxint, + .rxavailable = imx9_dma_rxavailable, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = imx9_rxflowcontrol, +#endif + .send = imx9_send, + .txint = imx9_txint, + .txready = imx9_txready, + .txempty = imx9_txempty, +}; +#endif + +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA) +static const struct uart_ops_s g_lpuart_txdma_ops = +{ + .setup = imx9_dma_setup, + .shutdown = imx9_dma_shutdown, + .attach = imx9_attach, + .detach = imx9_detach, + .ioctl = imx9_ioctl, + .receive = imx9_receive, + .rxint = imx9_rxint, + .rxavailable = imx9_rxavailable, + #ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = imx9_rxflowcontrol, + #endif + .send = imx9_send, + .txint = imx9_dma_txint, + .txready = imx9_txready, + .txempty = imx9_txempty, + .dmatxavail = imx9_dma_txavailable, + .dmasend = imx9_dma_send, +}; +#endif + +/* Avoid unused warning */ +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA) +const struct uart_ops_s *g_o0 = &g_lpuart_rxdma_ops; +#endif +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA) +const struct uart_ops_s *g_o1 = &g_lpuart_txdma_ops; +#endif + +/* I/O buffers */ + +#ifdef CONFIG_LPUART1_RXDMA +static char g_lpuart1rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +# ifdef CONFIG_LPUART2_RXDMA +static char g_lpuart2rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART3_RXDMA +static char g_lpuart3rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART4_RXDMA +static char g_lpuart4rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART5_RXDMA +static char g_lpuart5rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART6_RXDMA +static char g_lpuart6rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART7_RXDMA +static char g_lpuart7rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART8_RXDMA +static char g_lpuart8rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8A_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_IMX9_LPUART1 +static char g_lpuart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE]; +static char g_lpuart1txbuffer[LPUART1_TXBUFSIZE_ADJUSTED] + LPUART1_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_IMX9_LPUART2 +static char g_lpuart2rxbuffer[CONFIG_LPUART2_RXBUFSIZE]; +static char g_lpuart2txbuffer[LPUART2_TXBUFSIZE_ADJUSTED] + LPUART2_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_IMX9_LPUART3 +static char g_lpuart3rxbuffer[CONFIG_LPUART3_RXBUFSIZE]; +static char g_lpuart3txbuffer[LPUART3_TXBUFSIZE_ADJUSTED] + LPUART3_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_IMX9_LPUART4 +static char g_lpuart4rxbuffer[CONFIG_LPUART4_RXBUFSIZE]; +static char g_lpuart4txbuffer[LPUART4_TXBUFSIZE_ADJUSTED] + LPUART4_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_IMX9_LPUART5 +static char g_lpuart5rxbuffer[CONFIG_LPUART5_RXBUFSIZE]; +static char g_lpuart5txbuffer[LPUART5_TXBUFSIZE_ADJUSTED] + LPUART5_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_IMX9_LPUART6 +static char g_lpuart6rxbuffer[CONFIG_LPUART6_RXBUFSIZE]; +static char g_lpuart6txbuffer[LPUART6_TXBUFSIZE_ADJUSTED] + LPUART6_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_IMX9_LPUART7 +static char g_lpuart7rxbuffer[CONFIG_LPUART7_RXBUFSIZE]; +static char g_lpuart7txbuffer[LPUART7_TXBUFSIZE_ADJUSTED] + LPUART7_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_IMX9_LPUART8 +static char g_lpuart8rxbuffer[CONFIG_LPUART8_RXBUFSIZE]; +static char g_lpuart8txbuffer[LPUART8_TXBUFSIZE_ADJUSTED] \ + LPUART8_TXBUFSIZE_ALGN; +#endif + +#ifdef CONFIG_IMX9_LPUART1 +static struct imx9_uart_s g_lpuart1priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART1_RXBUFSIZE, + .buffer = g_lpuart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART1_TXBUFSIZE, + .buffer = g_lpuart1txbuffer, + }, +# if defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART1_RXDMA) && !defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = IMX9_LPUART1_BASE, + .uartnum = 1, + .baud = CONFIG_LPUART1_BAUD, + .irq = IMX9_IRQ_LPUART1, + .parity = CONFIG_LPUART1_PARITY, + .bits = CONFIG_LPUART1_BITS, + .stopbits2 = CONFIG_LPUART1_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART1_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART1_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL) + .iflow = 1, +# endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART1_RTS, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART1_INVERTIFLOWCONTROL) + .inviflow = 1, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL) + .rs485mode = 1, +# endif + +# ifdef CONFIG_LPUART1_TXDMA + .txch = DMA_REQUEST_MUXLPUART1TX, +# endif +# ifdef CONFIG_LPUART1_RXDMA + .rxch = DMA_REQUEST_MUXLPUART1RX, + .rxfifo = g_lpuart1rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_IMX9_LPUART2 +static struct imx9_uart_s g_lpuart2priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART2_RXBUFSIZE, + .buffer = g_lpuart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART2_TXBUFSIZE, + .buffer = g_lpuart2txbuffer, + }, +# if defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART2_RXDMA) && !defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = IMX9_LPUART2_BASE, + .uartnum = 2, + .baud = CONFIG_LPUART2_BAUD, + .irq = IMX9_IRQ_LPUART2, + .parity = CONFIG_LPUART2_PARITY, + .bits = CONFIG_LPUART2_BITS, + .stopbits2 = CONFIG_LPUART2_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART2_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART2_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL) + .iflow = 1, +# endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART2_RTS, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART2_INVERTIFLOWCONTROL) + .inviflow = 1, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL) + .rs485mode = 1, +# endif + +# ifdef CONFIG_LPUART2_TXDMA + .txch = DMA_REQUEST_MUXLPUART2TX, +# endif +# ifdef CONFIG_LPUART2_RXDMA + .rxch = DMA_REQUEST_MUXLPUART2RX, + .rxfifo = g_lpuart2rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_IMX9_LPUART3 +static struct imx9_uart_s g_lpuart3priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART3_RXBUFSIZE, + .buffer = g_lpuart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART3_TXBUFSIZE, + .buffer = g_lpuart3txbuffer, + }, +# if defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART3_RXDMA) && !defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = IMX9_LPUART3_BASE, + .uartnum = 3, + .baud = CONFIG_LPUART3_BAUD, + .irq = IMX9_IRQ_LPUART3, + .parity = CONFIG_LPUART3_PARITY, + .bits = CONFIG_LPUART3_BITS, + .stopbits2 = CONFIG_LPUART3_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART3_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART3_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL) + .iflow = 1, +# endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART3_RTS, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART3_INVERTIFLOWCONTROL) + .inviflow = 1, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL) + .rs485mode = 1, +# endif + +# ifdef CONFIG_LPUART3_TXDMA + .txch = DMA_REQUEST_MUXLPUART3TX, +# endif +# ifdef CONFIG_LPUART3_RXDMA + .rxch = DMA_REQUEST_MUXLPUART3RX, + .rxfifo = g_lpuart3rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_IMX9_LPUART4 +static struct imx9_uart_s g_lpuart4priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART4_RXBUFSIZE, + .buffer = g_lpuart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART4_TXBUFSIZE, + .buffer = g_lpuart4txbuffer, + }, +# if defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART4_RXDMA) && !defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = IMX9_LPUART4_BASE, + .uartnum = 4, + .baud = CONFIG_LPUART4_BAUD, + .irq = IMX9_IRQ_LPUART4, + .parity = CONFIG_LPUART4_PARITY, + .bits = CONFIG_LPUART4_BITS, + .stopbits2 = CONFIG_LPUART4_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART4_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART4_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL) + .iflow = 1, +# endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART4_RTS, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART4_INVERTIFLOWCONTROL) + .inviflow = 1, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL) + .rs485mode = 1, +# endif + +# ifdef CONFIG_LPUART4_TXDMA + .txch = DMA_REQUEST_MUXLPUART4TX, +# endif +# ifdef CONFIG_LPUART4_RXDMA + .rxch = DMA_REQUEST_MUXLPUART4RX, + .rxfifo = g_lpuart4rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_IMX9_LPUART5 +static struct imx9_uart_s g_lpuart5priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART5_RXBUFSIZE, + .buffer = g_lpuart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART5_TXBUFSIZE, + .buffer = g_lpuart5txbuffer, + }, +# if defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART5_RXDMA) && !defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = IMX9_LPUART5_BASE, + .uartnum = 5, + .baud = CONFIG_LPUART5_BAUD, + .irq = IMX9_IRQ_LPUART5, + .parity = CONFIG_LPUART5_PARITY, + .bits = CONFIG_LPUART5_BITS, + .stopbits2 = CONFIG_LPUART5_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART5_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART5_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL) + .iflow = 1, +# endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART5_RTS, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART5_INVERTIFLOWCONTROL) + .inviflow = 1, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL) + .rs485mode = 1, +# endif + +# ifdef CONFIG_LPUART5_TXDMA + .txch = DMA_REQUEST_MUXLPUART5TX, +# endif +# ifdef CONFIG_LPUART5_RXDMA + .rxch = DMA_REQUEST_MUXLPUART5RX, + .rxfifo = g_lpuart5rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_IMX9_LPUART6 +static struct imx9_uart_s g_lpuart6priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART6_RXBUFSIZE, + .buffer = g_lpuart6rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART6_TXBUFSIZE, + .buffer = g_lpuart6txbuffer, + }, +# if defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART6_RXDMA) && !defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = IMX9_LPUART6_BASE, + .uartnum = 6, + .baud = CONFIG_LPUART6_BAUD, + .irq = IMX9_IRQ_LPUART6, + .parity = CONFIG_LPUART6_PARITY, + .bits = CONFIG_LPUART6_BITS, + .stopbits2 = CONFIG_LPUART6_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART6_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART6_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL) + .iflow = 1, +# endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART6_RTS, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART6_INVERTIFLOWCONTROL) + .inviflow = 1, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL) + .rs485mode = 1, +# endif + +# ifdef CONFIG_LPUART6_TXDMA + .txch = DMA_REQUEST_MUXLPUART6TX, +# endif +# ifdef CONFIG_LPUART6_RXDMA + .rxch = DMA_REQUEST_MUXLPUART6RX, + .rxfifo = g_lpuart6rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_IMX9_LPUART7 +static struct imx9_uart_s g_lpuart7priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART7_RXBUFSIZE, + .buffer = g_lpuart7rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART7_TXBUFSIZE, + .buffer = g_lpuart7txbuffer, + }, +# if defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, +# elif defined(CONFIG_LPUART7_RXDMA) && !defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_rxdma_ops, +# elif !defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_TXDMA) + .ops = &g_lpuart_txdma_ops, +# else + .ops = &g_lpuart_ops, +# endif + }, + + .uartbase = IMX9_LPUART7_BASE, + .uartnum = 7, + .baud = CONFIG_LPUART7_BAUD, + .irq = IMX9_IRQ_LPUART7, + .parity = CONFIG_LPUART7_PARITY, + .bits = CONFIG_LPUART7_BITS, + .stopbits2 = CONFIG_LPUART7_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART7_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART7_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL) + .iflow = 1, +# endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART7_RTS, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART7_INVERTIFLOWCONTROL) + .inviflow = 1, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL) + .rs485mode = 1, +# endif + +# ifdef CONFIG_LPUART7_TXDMA + .txch = DMA_REQUEST_MUXLPUART7TX, +# endif +# ifdef CONFIG_LPUART7_RXDMA + .rxch = DMA_REQUEST_MUXLPUART7RX, + .rxfifo = g_lpuart7rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_IMX9_LPUART8 +static struct imx9_uart_s g_lpuart8priv = +{ + .dev = + { + .recv = + { + .size = CONFIG_LPUART8_RXBUFSIZE, + .buffer = g_lpuart8rxbuffer, + }, + .xmit = + { + .size = CONFIG_LPUART8_TXBUFSIZE, + .buffer = g_lpuart8txbuffer, + }, + #if defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_TXDMA) + .ops = &g_lpuart_rxtxdma_ops, + #elif defined(CONFIG_LPUART8_RXDMA) && !defined(CONFIG_LPUART8_TXDMA) + .ops = &g_lpuart_rxdma_ops, + #elif !defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_TXDMA) + .ops = &g_lpuart_txdma_ops, + #else + .ops = &g_lpuart_ops, + #endif + }, + + .uartbase = IMX9_LPUART8_BASE, + .uartnum = 8, + .baud = CONFIG_LPUART8_BAUD, + .irq = IMX9_IRQ_LPUART8, + .parity = CONFIG_LPUART8_PARITY, + .bits = CONFIG_LPUART8_BITS, + .stopbits2 = CONFIG_LPUART8_2STOP, +# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART8_OFLOWCONTROL) + .oflow = 1, + .cts_gpio = GPIO_LPUART8_CTS, +# endif +# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL) + .iflow = 1, +# endif +# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)) || \ + (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL))) + .rts_gpio = GPIO_LPUART8_RTS, +# endif + +# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \ + defined(CONFIG_LPUART8_INVERTIFLOWCONTROL) + .inviflow = 1, +# endif + +# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL) + .rs485mode = 1, +# endif + +# ifdef CONFIG_LPUART8_TXDMA + .txch = DMA_REQUEST_MUXLPUART8TX, +# endif +# ifdef CONFIG_LPUART8_RXDMA + .rxch = DMA_REQUEST_MUXLPUART8RX, + .rxfifo = g_lpuart8rxfifo, +# endif +}; +#endif + +#ifdef CONFIG_PM +static struct pm_callback_s g_serial_pmcb = +{ + .notify = up_pm_notify, + .prepare = up_pm_prepare, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_serialin + ****************************************************************************/ + +static inline uint32_t imx9_serialin(struct imx9_uart_s *priv, + uint32_t offset) +{ + return getreg32(priv->uartbase + offset); +} + +/**************************************************************************** + * Name: imx9_serialout + ****************************************************************************/ + +static inline void imx9_serialout(struct imx9_uart_s *priv, + uint32_t offset, uint32_t value) +{ + putreg32(value, priv->uartbase + offset); +} + +/**************************************************************************** + * Name: imx9_dma_nextrx + * + * Description: + * Returns the index into the RX FIFO where the DMA will place the next + * byte that it receives. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int imx9_dma_nextrx(struct imx9_uart_s *priv) +{ + int dmaresidual = imx9_dmach_getcount(priv->rxdma); + DEBUGASSERT(dmaresidual <= RXDMA_BUFFER_SIZE); + + return (RXDMA_BUFFER_SIZE - dmaresidual) % RXDMA_BUFFER_SIZE; +} +#endif + +/**************************************************************************** + * Name: imx9_disableuartint + ****************************************************************************/ + +static inline void imx9_disableuartint(struct imx9_uart_s *priv, + uint32_t *ie) +{ + irqstate_t flags; + uint32_t regval; + + flags = spin_lock_irqsave(NULL); + regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET); + + /* Return the current Rx and Tx interrupt state */ + + if (ie != NULL) + { + *ie = regval & LPUART_ALL_INTS; + } + + regval &= ~LPUART_ALL_INTS; + imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: imx9_restoreuartint + ****************************************************************************/ + +static inline void imx9_restoreuartint(struct imx9_uart_s *priv, + uint32_t ie) +{ + irqstate_t flags; + uint32_t regval; + + /* Enable/disable any interrupts that are currently disabled but should be + * enabled/disabled. + */ + + flags = spin_lock_irqsave(NULL); + regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= ie; + imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: imx9_dma_setup + * + * Description: + * Configure the LPUART baud, bits, parity, etc. This method is called the + * first time that the serial port is opened. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static int imx9_dma_setup(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; +#if defined(SERIAL_HAVE_RXDMA) + struct imx9_edma_xfrconfig_s config; +#endif + int result; + + /* Do the basic UART setup first, unless we are the console */ + + if (!dev->isconsole) + { + result = imx9_setup(dev); + if (result != OK) + { + return result; + } + } + +#if defined(SERIAL_HAVE_TXDMA) + /* Acquire the Tx DMA channel. This should always succeed. */ + + if (priv->txch != 0) + { + if (priv->txdma == NULL) + { + priv->txdma = imx9_dmach_alloc(priv->txch, 0); + if (priv->txdma == NULL) + { + return -EBUSY; + } + } + + /* Enable Tx DMA for the UART */ + + modifyreg32(priv->uartbase + IMX9_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_TDMAE); + } +#endif + +#if defined(SERIAL_HAVE_RXDMA) + /* Acquire the Rx DMA channel. This should always succeed. */ + + if (priv->rxch != 0) + { + if (priv->rxdma == NULL) + { + priv->rxdma = imx9_dmach_alloc(priv->rxch, 0); + + if (priv->rxdma == NULL) + { + return -EBUSY; + } + } + else + { + imx9_dmach_stop(priv->rxdma); + } + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + IMX9_LPUART_DATA_OFFSET; + config.daddr = (uintptr_t)priv->rxfifo; + config.soff = 0; + config.doff = 1; + config.iter = RXDMA_BUFFER_SIZE; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE | + EDMA_CONFIG_LOOPDEST | + EDMA_CONFIG_INTHALF | + EDMA_CONFIG_INTMAJOR; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; +#ifdef CONFIG_IMX9_EDMA_ELINK + config.linkch = 0; +#endif + + imx9_dmach_xfrsetup(priv->rxdma , &config); + + /* Reset our DMA shadow pointer and Rx data availability count to + * match the address just programmed above. + */ + + priv->rxdmanext = 0; + +#ifndef CONFIG_ARM64_DCACHE_DISABLE + + /* Make sure the rx buffer area is all invalid or clean */ + + up_invalidate_dcache((uintptr_t)priv->rxfifo, + (uintptr_t)priv->rxfifo + RXDMA_BUFFER_SIZE); + priv->rxdmaavail = 0; +#endif + + /* Enable receive Rx DMA for the UART */ + + modifyreg32(priv->uartbase + IMX9_LPUART_BAUD_OFFSET, + 0, LPUART_BAUD_RDMAE); + + /* Enable interrupt on idle and erros */ + + modifyreg32(priv->uartbase + IMX9_LPUART_CTRL_OFFSET, 0, + LPUART_CTRL_PEIE | + LPUART_CTRL_FEIE | + LPUART_CTRL_NEIE | + LPUART_CTRL_ILIE); + + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + imx9_dmach_start(priv->rxdma, imx9_dma_rxcallback, (void *)priv); + } +#endif + + return OK; +} +#endif + +/**************************************************************************** + * Name: imx9_setup + * + * Description: + * Configure the UART baud, bits, parity, fifos, etc. This + * method is called the first time that the serial priv is + * opened. + * + ****************************************************************************/ + +static int imx9_setup(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; +#ifndef CONFIG_SUPPRESS_LPUART_CONFIG + struct uart_config_s config = + { + 0 + }; + + int ret; + + /* Configure the UART */ + + config.baud = priv->baud; /* Configured baud */ + config.parity = priv->parity; /* 0=none, 1=odd, 2=even */ + config.bits = priv->bits; /* Number of bits (5-9) */ + config.stopbits2 = priv->stopbits2; /* true: Configure with 2 stop bits instead of 1 */ +#ifdef CONFIG_SERIAL_OFLOWCONTROL + config.usects = priv->oflow; /* Flow control on outbound side */ +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + /* Flow control on outbound side if not GPIO based */ + + if (priv->rts_gpio == 0) + { + config.userts = priv->iflow; + } + +#endif +#ifdef CONFIG_SERIAL_RS485CONTROL + config.users485 = priv->rs485mode; /* Switch into RS485 mode */ +#endif +#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL) + config.invrts = priv->inviflow; /* Inversion of outbound flow control */ +#endif + + ret = imx9_lpuart_configure(priv->uartbase, priv->uartnum, &config); + + priv->ie = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET) & \ + LPUART_ALL_INTS; + return ret; + +#else + priv->ie = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET) & \ + LPUART_ALL_INTS; + return OK; +#endif +} + +/**************************************************************************** + * Name: imx9_shutdown + * + * Description: + * Disable the UART. This method is called when the serial + * priv is closed + * + ****************************************************************************/ + +static void imx9_shutdown(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + /* Disable the UART */ + + imx9_serialout(priv, IMX9_LPUART_GLOBAL_OFFSET, LPUART_GLOBAL_RST); +} + +/**************************************************************************** + * Name: imx9_dma_shutdown + * + * Description: + * Disable the LPUART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) +static void imx9_dma_shutdown(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + /* Perform the normal UART shutdown */ + + imx9_shutdown(dev); + +#if defined(SERIAL_HAVE_RXDMA) + /* Stop the RX DMA channel */ + + if (priv->rxch != 0) + { + imx9_dmach_stop(priv->rxdma); + + /* Release the RX DMA channel */ + + imx9_dmach_free(priv->rxdma); + priv->rxdma = NULL; + } +#endif + +#if defined(SERIAL_HAVE_TXDMA) + /* Stop the TX DMA channel */ + + if (priv->txch != 0) + { + imx9_dmach_stop(priv->txdma); + + /* Release the TX DMA channel */ + + imx9_dmach_free(priv->txdma); + priv->txdma = NULL; + } +#endif +} +#endif + +/**************************************************************************** + * Name: imx9_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method + * is called when the serial priv is opened. Normally, this is just after + * the setup() method is called, however, the serial console may operate + * in a non-interrupt driven mode during the boot phase. + * + * RX and TX interrupts are not enabled when by the attach method (unless + * the hardware supprivs multiple levels of interrupt enabling). The RX + * and TX interrupts are not enabled until the txint() and rxint() methods + * are called. + * + ****************************************************************************/ + +static int imx9_attach(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + int ret; + + /* Attach and enable the IRQ */ + + ret = irq_attach(priv->irq, imx9_interrupt, dev); + if (ret == OK) + { + /* Enable the interrupt (RX and TX interrupts are still disabled + * in the UART + */ + + up_enable_irq(priv->irq); + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial priv is + * closed normally just before the shutdown method is called. The + * exception is the serial console which is never shutdown. + * + ****************************************************************************/ + +static void imx9_detach(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + up_disable_irq(priv->irq); + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: imx9_interrupt (and front-ends) + * + * Description: + * This is the common UART interrupt handler. It will be invoked when an + * interrupt is received on the 'irq'. It should call uart_xmitchars or + * uart_recvchars to perform the appropriate data transfers. The + * interrupt handling logic must be able to map the 'arg' to the + * appropriate uart_dev_s structure in order to call these functions. + * + ****************************************************************************/ + +static int imx9_interrupt(int irq, void *context, void *arg) +{ + struct uart_dev_s *dev = (struct uart_dev_s *)arg; + struct imx9_uart_s *priv; + uint32_t usr; + uint32_t lsr; + int passes = 0; + bool handled; + + DEBUGASSERT(dev != NULL && dev != NULL); + priv = (struct imx9_uart_s *)dev; + +#if defined(CONFIG_PM) && CONFIG_IMX9_PM_SERIAL_ACTIVITY > 0 + /* Repriv serial activity to the power management logic */ + + pm_activity(PM_IDLE_DOMAIN, CONFIG_IMX9_PM_SERIAL_ACTIVITY); +#endif + + /* Loop until there are no characters to be transferred or, + * until we have been looping for a long time. + */ + + handled = true; + for (passes = 0; passes < 256 && handled; passes++) + { + handled = false; + + /* Get the current UART status and check for loop + * termination conditions + */ + + usr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + + /* Removed all W1C from the last sr */ + + lsr = usr & ~(LPUART_STAT_LBKDIF | LPUART_STAT_RXEDGIF | + LPUART_STAT_IDLE | LPUART_STAT_OR | + LPUART_STAT_NF | LPUART_STAT_FE | + LPUART_STAT_PF | LPUART_STAT_MA1F | + LPUART_STAT_MA2F); + + /* Keep what we will service */ + + usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR | + LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_PF | + LPUART_STAT_IDLE); + + /* Clear serial overrun, parity and framing errors */ + + if ((usr & LPUART_STAT_OR) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_OR | lsr); + } + + if ((usr & LPUART_STAT_NF) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_NF | lsr); + } + + if ((usr & LPUART_STAT_PF) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_PF | lsr); + } + + if ((usr & LPUART_STAT_FE) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_FE | lsr); + } + + if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0) + { + /* Discard data */ + + imx9_serialin(priv, IMX9_LPUART_DATA_OFFSET); + } + +#ifdef SERIAL_HAVE_RXDMA + /* The line going to idle, deliver any fractions of RX data */ + + if ((usr & LPUART_STAT_IDLE) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + LPUART_STAT_IDLE | lsr); + imx9_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE); + } +#endif + + /* Handle incoming, receive bytes */ + + if ((usr & LPUART_STAT_RDRF) != 0 && + (priv->ie & LPUART_CTRL_RIE) != 0) + { + uart_recvchars(dev); + handled = true; + } + + /* Handle outgoing, transmit bytes */ + + if ((usr & LPUART_STAT_TDRE) != 0 && + (priv->ie & LPUART_CTRL_TIE) != 0) + { + uart_xmitchars(dev); + handled = true; + } + } + + return OK; +} + +/**************************************************************************** + * Name: imx9_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + ****************************************************************************/ + +static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg) +{ +#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS) + struct inode *inode = filep->f_inode; + struct uart_dev_s *dev = inode->i_private; + irqstate_t flags; +#endif + int ret = OK; + + switch (cmd) + { +#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT + case TIOCSERGSTRUCT: + { + struct imx9_uart_s *user = (struct imx9_uart_s *)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct imx9_uart_s)); + } + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + if (!termiosp) + { + ret = -EINVAL; + break; + } + + /* Return parity */ + + termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) | + ((priv->parity == 1) ? PARODD : 0); + + /* Return stop bits */ + + termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0; + + /* Return flow control */ + +#ifdef CONFIG_SERIAL_OFLOWCONTROL + termiosp->c_cflag |= ((priv->oflow) ? CCTS_OFLOW : 0); +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + termiosp->c_cflag |= ((priv->iflow) ? CRTS_IFLOW : 0); +#endif + /* Return baud */ + + cfsetispeed(termiosp, priv->baud); + + /* Return number of bits */ + + switch (priv->bits) + { + case 5: + termiosp->c_cflag |= CS5; + break; + + case 6: + termiosp->c_cflag |= CS6; + break; + + case 7: + termiosp->c_cflag |= CS7; + break; + + default: + case 8: + termiosp->c_cflag |= CS8; + break; + +#if defined(CS9) + case 9: + termiosp->c_cflag |= CS9; + break; +#endif + } + } + break; + + case TCSETS: + { + struct termios *termiosp = (struct termios *)arg; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t baud; + uint32_t ie; + uint8_t parity; + uint8_t nbits; + bool stop2; + + if ((!termiosp) +#ifdef CONFIG_SERIAL_OFLOWCONTROL + || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0)) +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0)) +#endif + ) + { + ret = -EINVAL; + break; + } + + /* Decode baud. */ + + ret = OK; + baud = cfgetispeed(termiosp); + + /* Decode number of bits */ + + switch (termiosp->c_cflag & CSIZE) + { + case CS5: + nbits = 5; + break; + + case CS6: + nbits = 6; + break; + + case CS7: + nbits = 7; + break; + + case CS8: + nbits = 8; + break; + +#if defined(CS9) + case CS9: + nbits = 9; + break; +#endif + default: + ret = -EINVAL; + break; + } + + /* Decode parity */ + + if ((termiosp->c_cflag & PARENB) != 0) + { + parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + parity = 0; + } + + /* Decode stop bits */ + + stop2 = (termiosp->c_cflag & CSTOPB) != 0; + + /* Verify that all settings are valid before committing */ + + if (ret == OK) + { + /* Commit */ + + priv->baud = baud; + priv->parity = parity; + priv->bits = nbits; + priv->stopbits2 = stop2; +#ifdef CONFIG_SERIAL_OFLOWCONTROL + priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; +#endif +#ifdef CONFIG_SERIAL_IFLOWCONTROL + priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; +#endif + /* effect the changes immediately - note that we do not + * implement TCSADRAIN / TCSAFLUSH + */ + + flags = spin_lock_irqsave(NULL); + imx9_disableuartint(priv, &ie); + ret = dev->ops->setup(dev); + + /* Restore the interrupt state */ + + imx9_restoreuartint(priv, ie); + priv->ie = ie; + spin_unlock_irqrestore(NULL, flags); + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + +#ifdef CONFIG_IMX9_LPUART_SINGLEWIRE + case TIOCSSINGLEWIRE: + { + uint32_t regval; + irqstate_t flags; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + flags = spin_lock_irqsave(NULL); + regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET); + + if ((arg & SER_SINGLEWIRE_ENABLED) != 0) + { + regval |= LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC; + } + else + { + regval &= ~(LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC); + } + + imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval); + + spin_unlock_irqrestore(NULL, flags); + } + break; +#endif + +#ifdef CONFIG_IMX9_LPUART_INVERT + case TIOCSINVERT: + { + uint32_t ctrl; + uint32_t stat; + uint32_t regval; + irqstate_t flags; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + flags = spin_lock_irqsave(NULL); + ctrl = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET); + stat = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + regval = ctrl; + + /* {R|T}XINV bit field can only be written when the receiver is + * disabled (RE=0). + */ + + regval &= ~LPUART_CTRL_RE; + + imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval); + + /* Enable/disable signal inversion. */ + + if (arg & SER_INVERT_ENABLED_RX) + { + stat |= LPUART_STAT_RXINV; + } + else + { + stat &= ~LPUART_STAT_RXINV; + } + + /* Do not invert TX when in TIOCSSINGLEWIRE */ + + if ((arg & SER_INVERT_ENABLED_TX) && + ((ctrl & LPUART_CTRL_LOOPS) != LPUART_CTRL_LOOPS)) + { + ctrl |= LPUART_CTRL_TXINV; + } + else + { + ctrl &= ~LPUART_CTRL_TXINV; + } + + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, stat); + imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, ctrl); + + spin_unlock_irqrestore(NULL, flags); + } + break; +#endif + + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the UART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_RXDMA +static int imx9_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t rxd; + + rxd = imx9_serialin(priv, IMX9_LPUART_DATA_OFFSET); + *status = rxd >> LPUART_DATA_STATUS_SHIFT; + return (rxd & LPUART_DATA_MASK) >> LPUART_DATA_SHIFT; +} +#endif + +/**************************************************************************** + * Name: imx9_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_RXDMA +static void imx9_rxint(struct uart_dev_s *dev, bool enable) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + irqstate_t flags; + uint32_t regval; + + /* Enable interrupts for data available at Rx */ + + flags = spin_lock_irqsave(NULL); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE; +#endif + } + else + { + priv->ie &= ~(LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE); + } + + regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= priv->ie; + imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(NULL, flags); +} +#endif + +/**************************************************************************** + * Name: imx9_rxavailable + * + * Description: + * Return true if the receive fifo is not empty + * + ****************************************************************************/ + +#ifndef SERIAL_HAVE_ONLY_RXDMA +static bool imx9_rxavailable(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t regval; + + /* Return true is data is ready in the Rx FIFO */ + + regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_RDRF) != 0); +} +#endif + +/**************************************************************************** + * Name: imx9_rxflowcontrol + * + * Description: + * Called when Rx buffer is full (or exceeds configured watermark levels + * if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined). + * Return true if UART activated RX flow control to block more incoming + * data + * + * Input Parameters: + * dev - UART device instance + * nbuffered - the number of characters currently buffered + * (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is + * not defined the value will be 0 for an empty buffer or the + * defined buffer size for a full buffer) + * upper - true indicates the upper watermark was crossed where + * false indicates the lower watermark has been crossed + * + * Returned Value: + * true if RX flow control activated. + * + ****************************************************************************/ + +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool imx9_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + if (priv->iflow && (priv->rts_gpio != 0)) + { + /* Assert/de-assert nRTS set it high resume/stop sending */ + + imx9_gpiowrite(priv->rts_gpio, upper); + + if (upper) + { + /* With heavy Rx traffic, RXNE might be set and data pending. + * Returning 'true' in such case would cause RXNE left unhandled + * and causing interrupt storm. Sending end might be also be slow + * to react on nRTS, and returning 'true' here would prevent + * processing that data. + * + * Therefore, return 'false' so input data is still being processed + * until sending end reacts on nRTS signal and stops sending more. + */ + + return false; + } + + return upper; + } + else + { + /* Is the RX buffer full? */ + + if (upper) + { + /* Disable Rx interrupt to prevent more data being from + * peripheral. When hardware RTS is enabled, this will + * prevent more data from coming in. + * + * This function is only called when UART recv buffer is full, + * that is: "dev->recv.head + 1 == dev->recv.tail". + * + * Logic in "uart_read" will automatically toggle Rx interrupts + * when buffer is read empty and thus we do not have to re- + * enable Rx interrupts. + */ + + uart_disablerxint(dev); + return true; + } + + /* No.. The RX buffer is empty */ + + else + { + /* We might leave Rx interrupt disabled if full recv buffer was + * read empty. Enable Rx interrupt to make sure that more input is + * received. + */ + + uart_enablerxint(dev); + } + } + + return false; +} +#endif + +/**************************************************************************** + * Name: imx9_dma_receive + * + * Description: + * Called (usually) from the interrupt level to receive one + * character from the LPUART. Error bits associated with the + * receipt are provided in the return 'status'. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static int imx9_dma_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t nextrx = imx9_dma_nextrx(priv); + int c = 0; + + /* Check if more data is available */ + + if (nextrx != priv->rxdmanext) + { +#ifndef CONFIG_ARM64_DCACHE_DISABLE + /* If the data cache is enabled, then we will also need to manage + * cache coherency. Are any bytes available in the currently coherent + * region of the data cache? + */ + + if (priv->rxdmaavail == 0) + { + uint32_t rxdmaavail; + uintptr_t addr; + + /* No.. then we will have to invalidate additional space in the Rx + * DMA buffer. + */ + + if (nextrx > priv->rxdmanext) + { + /* Number of available bytes */ + + rxdmaavail = nextrx - priv->rxdmanext; + } + else + { + /* Number of available bytes up to the end of RXDMA buffer */ + + rxdmaavail = RXDMA_BUFFER_SIZE - priv->rxdmanext; + } + + /* Invalidate the DMA buffer range */ + + addr = (uintptr_t)&priv->rxfifo[priv->rxdmanext]; + up_invalidate_dcache(addr, addr + rxdmaavail); + + /* We don't need to invalidate the data cache for the next + * rxdmaavail number of next bytes. + */ + + priv->rxdmaavail = rxdmaavail; + } + + priv->rxdmaavail--; +#endif + + /* Now read from the DMA buffer */ + + c = priv->rxfifo[priv->rxdmanext]; + + priv->rxdmanext++; + + if (priv->rxdmanext == RXDMA_BUFFER_SIZE) + { + priv->rxdmanext = 0; + } + } + + /* NOTE: If no data is available, then we would return NULL which is, + * of course, valid binary data. The protocol is that the upper half + * driver must call imx9_dma_rxavailable prior to calling this + * function to assure that this never happens. + */ + + return c; +} +#endif + +/**************************************************************************** + * Name: imx9_dma_reenable + * + * Description: + * Call to re-enable RX DMA. + * + ****************************************************************************/ + +#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM) +static void imx9_dma_reenable(struct imx9_uart_s *priv) +{ + struct imx9_edma_xfrconfig_s config; + + /* Stop an reset the RX DMA */ + + imx9_dmach_stop(priv->rxdma); + + /* Configure for circular DMA reception into the RX FIFO */ + + config.saddr = priv->uartbase + IMX9_LPUART_DATA_OFFSET; + config.daddr = (uint32_t) priv->rxfifo; + config.soff = 0; + config.doff = 1; + config.iter = RXDMA_BUFFER_SIZE; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE | + EDMA_CONFIG_LOOPDEST | + EDMA_CONFIG_INTHALF | + EDMA_CONFIG_INTMAJOR; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; +#ifdef CONFIG_IMX9_EDMA_ELINK + config.linkch = 0; +#endif + + imx9_dmach_xfrsetup(priv->rxdma, &config); + + /* Reset our DMA shadow pointer and Rx data availability count to match + * the address just programmed above. + */ + + priv->rxdmanext = 0; +#ifndef CONFIG_ARM64_DCACHE_DISABLE + priv->rxdmaavail = 0; +#endif + + /* Start the DMA channel, and arrange for callbacks at the half and + * full points in the FIFO. This ensures that we have half a FIFO + * worth of time to claim bytes before they are overwritten. + */ + + imx9_dmach_start(priv->rxdma, imx9_dma_rxcallback, (void *)priv); + + /* Clear DMA suspended flag. */ + + priv->rxdmasusp = false; +} +#endif + +/**************************************************************************** + * Name: imx9_dma_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void imx9_dma_rxint(struct uart_dev_s *dev, bool enable) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + /* Enable/disable DMA reception. + * + * Note that it is not safe to check for available bytes and immediately + * pass them to uart_recvchars as that could potentially recurse back + * to us again. Instead, bytes must wait until the next up_dma_poll or + * DMA event. + */ + + priv->rxenable = enable; +} +#endif + +/**************************************************************************** + * Name: imx9_dma_rxavailable + * + * Description: + * Return true if the receive register is not empty + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static bool imx9_dma_rxavailable(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + /* Compare our receive pointer to the current DMA pointer, if they + * do not match, then there are bytes to be received. + */ + + return (imx9_dma_nextrx(priv) != priv->rxdmanext); +} +#endif + +/**************************************************************************** + * Name: imx9_dma_txcallback + * + * Description: + * This function clears dma buffer at complete of DMA transfer and wakes up + * threads waiting for space in buffer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void imx9_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)arg; + + /* Update 'nbytes' indicating number of bytes actually transferred by DMA. + * This is important to free TX buffer space by 'uart_xmitchars_done'. + */ + + priv->dev.dmatx.nbytes = priv->dev.dmatx.length; +#if CONFIG_IMX9_EDMA_NTCD > 1 + priv->dev.dmatx.nbytes += priv->dev.dmatx.nlength; +#endif + + /* Adjust the pointers */ + + uart_xmitchars_done(&priv->dev); + + /* Send more data if available */ + + imx9_dma_txavailable(&priv->dev); +} +#endif + +/**************************************************************************** + * Name: imx9_dma_txavailable + * + * Description: + * Informs DMA that Tx data is available and is ready for transfer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void imx9_dma_txavailable(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + + /* Only send when the DMA is idle */ + + if (imx9_dmach_idle(priv->txdma) == 0) + { + uart_xmitchars_dma(dev); + } +} +#endif + +/**************************************************************************** + * Name: imx9_dma_send + * + * Description: + * Called (usually) from the interrupt level to start DMA transfer. + * (Re-)Configures DMA Stream updating buffer and buffer length. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void imx9_dma_send(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + struct imx9_edma_xfrconfig_s config; + + /* We need to stop DMA before reconfiguration */ + + imx9_dmach_stop(priv->txdma); + + /* Reset the number sent */ + + dev->dmatx.nbytes = 0; + + /* Make use of setup function to update buffer and its length for next + * transfer + */ + + config.iter = dev->dmatx.length; + config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE; + config.ssize = EDMA_8BIT; + config.dsize = EDMA_8BIT; + config.nbytes = 1; + config.saddr = (uintptr_t)dev->dmatx.buffer; + config.daddr = priv->uartbase + IMX9_LPUART_DATA_OFFSET; + config.soff = 1; + config.doff = 0; +#ifdef CONFIG_IMX9_EDMA_ELINK + config.linkch = 0; +#endif + + /* Flush the contents of the TX buffer into physical memory */ + + up_clean_dcache((uintptr_t)dev->dmatx.buffer, + (uintptr_t)dev->dmatx.buffer + dev->dmatx.length); + + /* Setup first half */ + + imx9_dmach_xfrsetup(priv->txdma, &config); + +#if CONFIG_IMX9_EDMA_NTCD > 1 + /* Is this a split transfer? */ + + if (dev->dmatx.nbuffer) + { + config.iter = priv->dev.dmatx.nlength; + config.saddr = (uintptr_t)priv->dev.dmatx.nbuffer; + + /* Flush the contents of the next TX buffer into physical memory */ + + up_clean_dcache((uintptr_t)dev->dmatx.nbuffer, + (uintptr_t)dev->dmatx.nbuffer + dev->dmatx.nlength); + + imx9_dmach_xfrsetup(priv->txdma, &config); + } +#endif + + /* Start transmission with the callback on DMA completion */ + + imx9_dmach_start(priv->txdma, imx9_dma_txcallback, (void *)priv); +} +#endif + +/**************************************************************************** + * Name: imx9_send + * + * Description: + * This method will send one byte on the UART + * + ****************************************************************************/ + +static void imx9_send(struct uart_dev_s *dev, int ch) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + +#ifdef CONSOLE_DEV + if (dev == &CONSOLE_DEV.dev && !dev->isconsole) + { + return; + } +#endif + + imx9_serialout(priv, IMX9_LPUART_DATA_OFFSET, (uint32_t)ch); +} + +/**************************************************************************** + * Name: imx9_dma_txint + * + * Description: + * Call to enable or disable TX interrupts from the UART. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void imx9_dma_txint(struct uart_dev_s *dev, bool enable) +{ + /* Nothing to do. */ + + /* In case of DMA transfer we do not want to make use of UART interrupts. + * Instead, we use DMA interrupts that are activated once during boot + * sequence. Furthermore we can use imx9_dma_txcallback() to handle + * stuff at half DMA transfer or after transfer completion (depending + * on the configuration). + */ +} +#endif + +/**************************************************************************** + * Name: imx9_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +#if !defined(SERIAL_HAVE_ONLY_TXDMA) +static void imx9_txint(struct uart_dev_s *dev, bool enable) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + irqstate_t flags; + uint32_t regval; + + /* Enable interrupt for TX complete */ + + flags = spin_lock_irqsave(NULL); + if (enable) + { +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_TIE; +#endif + } + else + { + priv->ie &= ~LPUART_CTRL_TIE; + } + + regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET); + regval &= ~LPUART_ALL_INTS; + regval |= priv->ie; + imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval); + spin_unlock_irqrestore(NULL, flags); +} +#endif + +/**************************************************************************** + * Name: imx9_txready + * + * Description: + * Return true if the transmit register is available to be written to + * + ****************************************************************************/ + +static bool imx9_txready(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t regval; + + regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_TDRE) != 0); +} + +/**************************************************************************** + * Name: imx9_txempty + * + * Description: + * Return true if the transmit reg is empty + * + ****************************************************************************/ + +static bool imx9_txempty(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t regval; + + regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_TDRE) != 0); +} + +/**************************************************************************** + * Name: imx9_dma_rxcallback + * + * Description: + * This function checks the current DMA state and calls the generic + * serial stack when bytes appear to be available. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_RXDMA +static void imx9_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done, + int result) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)arg; + uint32_t sr; + + if (priv->rxenable && imx9_dma_rxavailable(&priv->dev)) + { + uart_recvchars(&priv->dev); + } + + /* Get the masked LPUART status word to check and clear error flags. + * + * When wake-up from low power mode was not fast enough, UART is resumed + * too late and sometimes exactly when character was coming over UART, + * resulting to frame error. + * If error flag is not cleared, Rx DMA will be stuck. Clearing errors + * will release Rx DMA. + */ + + sr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + + if ((sr & (LPUART_STAT_OR | LPUART_STAT_NF | LPUART_STAT_FE)) != 0) + { + imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, + sr & (LPUART_STAT_OR | + LPUART_STAT_NF | + LPUART_STAT_FE)); + } +} +#endif + +/**************************************************************************** + * Name: up_pm_notify + * + * Description: + * Notify the driver of new power state. This callback is called after + * all drivers have had the opprivunity to prepare for the new power state. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * None - The driver already agreed to transition to the low power + * consumption state when when it returned OK to the prepare() call. + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static void up_pm_notify(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + switch (pmstate) + { + case(PM_NORMAL): + { + /* Logic for PM_NORMAL goes here */ + } + break; + + case(PM_IDLE): + { + /* Logic for PM_IDLE goes here */ + } + break; + + case(PM_STANDBY): + { + /* Logic for PM_STANDBY goes here */ + } + break; + + case(PM_SLEEP): + { + /* Logic for PM_SLEEP goes here */ + } + break; + + default: + + /* Should not get here */ + + break; + } +} +#endif + +/**************************************************************************** + * Name: up_pm_prepare + * + * Description: + * Request the driver to prepare for a new power state. This is a warning + * that the system is about to enter into a new power state. The driver + * should begin whatever operations that may be required to enter power + * state. The driver may abort the state change mode by returning a + * non-zero value from the callback function. + * + * Input Parameters: + * + * cb - Returned to the driver. The driver version of the callback + * structure may include additional, driver-specific state data at + * the end of the structure. + * + * pmstate - Identifies the new PM state + * + * Returned Value: + * Zero - (OK) means the event was successfully processed and that the + * driver is prepared for the PM state change. + * + * Non-zero - means that the driver is not prepared to perform the tasks + * needed achieve this power setting and will cause the state + * change to be aborted. NOTE: The prepare() method will also + * be called when reverting from lower back to higher power + * consumption modes (say because another driver refused a + * lower power state change). Drivers are not permitted to + * return non-zero values when reverting back to higher power + * consumption modes! + * + * + ****************************************************************************/ + +#ifdef CONFIG_PM +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) +{ + /* Logic to prepare for a reduced power state goes here. */ + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm64_earlyserialinit + * + * Description: + * Performs the low level UART initialization early in debug so that the + * serial console will be available during bootup. This must be called + * before arm64_serialinit. + * + ****************************************************************************/ + +void arm64_earlyserialinit(void) +{ + /* NOTE: This function assumes that low level hardware configuration + * -- including all clocking and pin configuration -- was performed by the + * function imx9_lowsetup() earlier in the boot sequence. + */ + + /* Enable the console UART. The other UARTs will be initialized if and + * when they are first opened. + */ + +#ifdef CONSOLE_DEV + CONSOLE_DEV.dev.isconsole = true; + imx9_setup(&CONSOLE_DEV.dev); +#endif +} + +/**************************************************************************** + * Name: arm64_serialinit + * + * Description: + * Register serial console and serial privs. This assumes + * that imx9_earlyserialinit was called previously. + * + ****************************************************************************/ + +void arm64_serialinit(void) +{ +#ifdef CONFIG_PM + int ret; + + /* Register to receive power management callbacks */ + + ret = pm_register(&g_serial_pmcb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif + +#ifdef CONSOLE_DEV + uart_register("/dev/console", &CONSOLE_DEV.dev); +#if defined(SERIAL_HAVE_CONSOLE_DMA) + imx9_dma_setup(&CONSOLE_DEV.dev); +#endif +#endif + + /* Register all UARTs */ + +#ifdef TTYS0_DEV + uart_register("/dev/ttyS0", &TTYS0_DEV.dev); +#endif +#ifdef TTYS1_DEV + uart_register("/dev/ttyS1", &TTYS1_DEV.dev); +#endif +#ifdef TTYS2_DEV + uart_register("/dev/ttyS2", &TTYS2_DEV.dev); +#endif +#ifdef TTYS3_DEV + uart_register("/dev/ttyS3", &TTYS3_DEV.dev); +#endif +#ifdef TTYS4_DEV + uart_register("/dev/ttyS4", &TTYS4_DEV.dev); +#endif +#ifdef TTYS5_DEV + uart_register("/dev/ttyS5", &TTYS5_DEV.dev); +#endif +#ifdef TTYS6_DEV + uart_register("/dev/ttyS6", &TTYS6_DEV.dev); +#endif +#ifdef TTYS7_DEV + uart_register("/dev/ttyS7", &TTYS7_DEV.dev); +#endif +} + +#endif /* USE_SERIALDRIVER */ + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to suppriv OS debug writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ +#ifdef CONSOLE_DEV + struct imx9_uart_s *priv = (struct imx9_uart_s *)&CONSOLE_DEV; + uint32_t ie; + + if (!CONSOLE_DEV.dev.isconsole) + { + return ch; + } + + imx9_disableuartint(priv, &ie); +#endif + + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + arm64_lowputc('\r'); + } + + arm64_lowputc(ch); +#ifdef CONSOLE_DEV + imx9_restoreuartint(priv, ie); +#endif + return ch; +} diff --git a/arch/arm64/src/imx9/imx9_serial.h b/arch/arm64/src/imx9/imx9_serial.h new file mode 100644 index 0000000000000..e9c175a8ce14d --- /dev/null +++ b/arch/arm64/src/imx9/imx9_serial.h @@ -0,0 +1,242 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_serial.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_SERIAL_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_SERIAL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if defined(CONFIG_IMX9_LPUART1) || defined(CONFIG_IMX9_LPUART2) || \ + defined(CONFIG_IMX9_LPUART3) || defined(CONFIG_IMX9_LPUART4) || \ + defined(CONFIG_IMX9_LPUART5) || defined(CONFIG_IMX9_LPUART6) || \ + defined(CONFIG_IMX9_LPUART7) || defined(CONFIG_IMX9_LPUART8) +# define HAVE_UART 1 +#endif + +/* Assume DMA is not used on the console UART */ + +#undef SERIAL_HAVE_CONSOLE_RXDMA +#undef SERIAL_HAVE_CONSOLE_TXDMA + +#if !defined(HAVE_UART) || !defined(CONFIG_ARCH_DMA) +# undef CONFIG_LPUART1_RXDMA +# undef CONFIG_LPUART1_TXDMA +# undef CONFIG_LPUART2_RXDMA +# undef CONFIG_LPUART2_TXDMA +# undef CONFIG_LPUART3_RXDMA +# undef CONFIG_LPUART3_TXDMA +# undef CONFIG_LPUART4_RXDMA +# undef CONFIG_LPUART4_TXDMA +# undef CONFIG_LPUART5_RXDMA +# undef CONFIG_LPUART5_TXDMA +# undef CONFIG_LPUART6_RXDMA +# undef CONFIG_LPUART6_TXDMA +# undef CONFIG_LPUART7_RXDMA +# undef CONFIG_LPUART7_TXDMA +# undef CONFIG_LPUART8_RXDMA +# undef CONFIG_LPUART8_TXDMA +#endif + +/* Disable the DMA configuration on all unused LPUARTs */ + +#ifndef CONFIG_IMX9_LPUART1 +# undef CONFIG_LPUART1_RXDMA +# undef CONFIG_LPUART1_TXDMA +#endif + +#ifndef CONFIG_IMX9_LPUART2 +# undef CONFIG_LPUART2_RXDMA +# undef CONFIG_LPUART2_TXDMA +#endif + +#ifndef CONFIG_IMX9_LPUART3 +# undef CONFIG_LPUART3_RXDMA +# undef CONFIG_LPUART3_TXDMA +#endif + +#ifndef CONFIG_IMX9_LPUART4 +# undef CONFIG_LPUART4_RXDMA +# undef CONFIG_LPUART4_TXDMA +#endif + +#ifndef CONFIG_IMX9_LPUART5 +# undef CONFIG_LPUART5_RXDMA +# undef CONFIG_LPUART5_TXDMA +#endif + +#ifndef CONFIG_IMX9_LPUART6 +# undef CONFIG_LPUART6_RXDMA +# undef CONFIG_LPUART6_TXDMA +#endif + +#ifndef CONFIG_IMX9_LPUART8 +# undef CONFIG_LPUART7_RXDMA +# undef CONFIG_LPUART7_TXDMA +#endif + +/* Is RX DMA available on any (enabled) LPUART? */ + +#undef SERIAL_HAVE_RXDMA +#if defined(CONFIG_LPUART1_RXDMA) || defined(CONFIG_LPUART2_RXDMA) || \ + defined(CONFIG_LPUART3_RXDMA) || defined(CONFIG_LPUART4_RXDMA) || \ + defined(CONFIG_LPUART5_RXDMA) || defined(CONFIG_LPUART6_RXDMA) || \ + defined(CONFIG_LPUART7_RXDMA) || defined(CONFIG_LPUART8_RXDMA) +# define SERIAL_HAVE_RXDMA 1 +#endif + +/* Is TX DMA available on any (enabled) LPUART? */ +#undef SERIAL_HAVE_TXDMA +#if defined(CONFIG_LPUART1_TXDMA) || defined(CONFIG_LPUART2_TXDMA) || \ + defined(CONFIG_LPUART3_TXDMA) || defined(CONFIG_LPUART4_TXDMA) || \ + defined(CONFIG_LPUART5_TXDMA) || defined(CONFIG_LPUART6_TXDMA) || \ + defined(CONFIG_LPUART7_TXDMA) || defined(CONFIG_LPUART8_TXDMA) +# define SERIAL_HAVE_TXDMA 1 +#endif + +/* Is RX DMA used on all (enabled) LPUARTs */ + +#define SERIAL_HAVE_ONLY_RXDMA 1 +#if defined(CONFIG_IMX9_LPUART1) && !defined(CONFIG_LPUART1_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMX9_LPUART2) && !defined(CONFIG_LPUART2_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMX9_LPUART3) && !defined(CONFIG_LPUART3_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMX9_LPUART4) && !defined(CONFIG_LPUART4_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMX9_LPUART5) && !defined(CONFIG_LPUART5_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMX9_LPUART6) && !defined(CONFIG_LPUART6_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMX9_LPUART7) && !defined(CONFIG_LPUART7_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#elif defined(CONFIG_IMX9_LPUART8) && !defined(CONFIG_LPUART8_RXDMA) +# undef SERIAL_HAVE_ONLY_RXDMA +#endif + +/* Is TX DMA used on all (enabled) LPUARTs */ + +#define SERIAL_HAVE_ONLY_TXDMA 1 +#if defined(CONFIG_IMX9_LPUART1) && !defined(CONFIG_LPUART1_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMX9_LPUART2) && !defined(CONFIG_LPUART2_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMX9_LPUART3) && !defined(CONFIG_LPUART3_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMX9_LPUART4) && !defined(CONFIG_LPUART4_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMX9_LPUART5) && !defined(CONFIG_LPUART5_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMX9_LPUART6) && !defined(CONFIG_LPUART6_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMX9_LPUART7) && !defined(CONFIG_LPUART7_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_IMX9_LPUART8) && !defined(CONFIG_LPUART8_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#endif + +#undef SERIAL_HAVE_ONLY_DMA +#if defined(SERIAL_HAVE_ONLY_RXDMA) && defined(SERIAL_HAVE_ONLY_TXDMA) +#define SERIAL_HAVE_ONLY_DMA +#endif + +/* Verify that DMA has been enabled and the DMA channel has been defined. + */ + +#if defined(SERIAL_HAVE_TXDMA) || defined(SERIAL_HAVE_RXDMA) +# ifndef CONFIG_IMX9_EDMA +# error IMXRT LPUART receive or transmit DMA requires CONFIG_IMX9_EDMA +# endif +#endif + +#if defined(SERIAL_HAVE_RXDMA) +/* Currently RS-485 support cannot be enabled when RXDMA is in use due to + * lack of testing. + */ + +# if (defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_RS485)) || \ + (defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_RS485)) || \ + (defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_RS485)) || \ + (defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_RS485)) || \ + (defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_RS485)) || \ + (defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_RS485)) || \ + (defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_RS485)) || \ + (defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_RS485)) +# error "RXDMA and RS-485 cannot be enabled at the same time for the same LPUART" +# endif +#endif /* SERIAL_HAVE_RXDMA */ + +/* Currently RS-485 support cannot be enabled when TXDMA is in use due to + * lack of testing. + */ + +# if (defined(CONFIG_LPUART1_TXDMA) && defined(CONFIG_LPUART1_RS485)) || \ + (defined(CONFIG_LPUART2_TXDMA) && defined(CONFIG_LPUART2_RS485)) || \ + (defined(CONFIG_LPUART3_TXDMA) && defined(CONFIG_LPUART3_RS485)) || \ + (defined(CONFIG_LPUART4_TXDMA) && defined(CONFIG_LPUART4_RS485)) || \ + (defined(CONFIG_LPUART5_TXDMA) && defined(CONFIG_LPUART5_RS485)) || \ + (defined(CONFIG_LPUART6_TXDMA) && defined(CONFIG_LPUART6_RS485)) || \ + (defined(CONFIG_LPUART7_TXDMA) && defined(CONFIG_LPUART7_RS485)) || \ + (defined(CONFIG_LPUART8_TXDMA) && defined(CONFIG_LPUART8_RS485)) +# error "TXDMA and RS-485 cannot be enabled at the same time for the same LPUART" +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_SERIAL_H */ diff --git a/arch/arm64/src/imx9/imx9_tpm_pwm.c b/arch/arm64/src/imx9/imx9_tpm_pwm.c new file mode 100644 index 0000000000000..8194ac6ea11bd --- /dev/null +++ b/arch/arm64/src/imx9/imx9_tpm_pwm.c @@ -0,0 +1,693 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_tpm_pwm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "arm64_arch.h" +#include "imx9_tpm_pwm.h" +#include "imx9_iomuxc.h" +#include "imx9_ccm.h" + +#include "hardware/imx9_iomuxc.h" +#include "hardware/imx9_pinmux.h" +#include "hardware/imx9_ccm.h" + +#ifdef CONFIG_IMX9_TPM_PWM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CHMUX(priv, x) ((((priv)->chmux) >> (x)) & 0xff) + +/* This is a temporary shortcut to configure TPM1 and TPM3 + * frequencies correctly; they don't have an own root clock + * + * TODO: Determine the frequencies in a more proper way + */ + +#define AON_CLK_FREQ 133333333 +#define WAKEUP_CLK_FREQ 133333333 +#define OSC_24_CLK_FREQ 24000000 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure represents the state of one PWM timer */ + +struct imx9_pwmtimer_s +{ + const struct pwm_ops_s *ops; /* PWM operations */ + const tpm_pwm_id_t id; /* PWM_TPM1...PWM_TPM6 */ + const uintptr_t base; /* The base address of the TPM */ + const int n_channels; /* Number of channels used for TPM block */ + const uint32_t chmux; /* Additional muxing of TPM outputs */ + const int clk; /* Input clock frequency for the TPM */ + uint32_t period; + unsigned frequency; /* Current frequency setting */ +}; + +/**************************************************************************** + * Static Function Prototypes + ****************************************************************************/ + +/* PWM driver methods */ + +static int pwm_setup(struct pwm_lowerhalf_s *dev); +static int pwm_shutdown(struct pwm_lowerhalf_s *dev); + +static int pwm_start(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info); + +static int pwm_stop(struct pwm_lowerhalf_s *dev); +static int pwm_ioctl(struct pwm_lowerhalf_s *dev, + int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* This is the list of lower half PWM driver methods used by the upper half + * driver + */ + +static const struct pwm_ops_s g_pwmops = +{ + .setup = pwm_setup, + .shutdown = pwm_shutdown, + .start = pwm_start, + .stop = pwm_stop, + .ioctl = pwm_ioctl, +}; + +static struct imx9_pwmtimer_s g_pwmdev[] = +{ +#ifdef CONFIG_IMX9_TPM1_PWM + { + .ops = &g_pwmops, + .id = PWM_TPM1, + .base = IMX9_TPM1_BASE, + .n_channels = CONFIG_IMX9_TPM1_PWM_NCHANNELS, + .chmux = CONFIG_IMX9_TPM1_PWM_CHMUX, + .clk = AON_CLK_FREQ, + }, +#endif + +#ifdef CONFIG_IMX9_TPM2_PWM + { + .ops = &g_pwmops, + .id = PWM_TPM2, + .base = IMX9_TPM2_BASE, + .n_channels = CONFIG_IMX9_TPM2_PWM_NCHANNELS, + .chmux = CONFIG_IMX9_TPM2_PWM_CHMUX, + .clk = OSC_24_CLK_FREQ, + }, +#endif + +#ifdef CONFIG_IMX9_TPM3_PWM + { + .ops = &g_pwmops, + .id = PWM_TPM3, + .base = IMX9_TPM3_BASE, + .n_channels = CONFIG_IMX9_TPM3_PWM_NCHANNELS, + .chmux = CONFIG_IMX9_TPM3_PWM_CHMUX, + .clk = WAKEUP_CLK_FREQ, + }, +#endif + +#ifdef CONFIG_IMX9_TPM4_PWM + { + .ops = &g_pwmops, + .id = PWM_TPM4, + .base = IMX9_TPM4_BASE, + .n_channels = CONFIG_IMX9_TPM4_PWM_NCHANNELS, + .chmux = CONFIG_IMX9_TPM4_PWM_CHMUX, + .clk = OSC_24_CLK_FREQ, + }, +#endif + +#ifdef CONFIG_IMX9_TPM5_PWM + { + .ops = &g_pwmops, + .id = PWM_TPM5, + .base = IMX9_TPM5_BASE, + .n_channels = CONFIG_IMX9_TPM5_PWM_NCHANNELS, + .chmux = CONFIG_IMX9_TPM5_PWM_CHMUX, + .clk = OSC_24_CLK_FREQ, + }, +#endif + +#ifdef CONFIG_IMX9_TPM6_PWM + { + .ops = &g_pwmops, + .id = PWM_TPM6, + .base = IMX9_TPM6_BASE, + .n_channels = CONFIG_IMX9_TPM6_PWM_NCHANNELS, + .chmux = CONFIG_IMX9_TPM6_PWM_CHMUX, + .clk = OSC_24_CLK_FREQ, + }, +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pwm_getreg + * + * Description: + * Read the value of an PWM timer register. + * + * Input Parameters: + * priv - A reference to the PWM block status + * offset - The offset to the register to read + * + * Returned Value: + * The current contents of the specified register + * + ****************************************************************************/ + +static inline uint32_t pwm_getreg(struct imx9_pwmtimer_s *priv, int offset) +{ + return getreg32(priv->base + offset); +} + +/**************************************************************************** + * Name: pwm_putreg + * + * Description: + * Read the value of an PWM timer register. + * + * Input Parameters: + * priv - A reference to the PWM block status + * offset - The offset to the register to read + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void pwm_putreg(struct imx9_pwmtimer_s *priv, int offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} + +/**************************************************************************** + * Name: tpm_mux + * + * Description: + * Mux the tpm output pins to pads. The macros TPMn_PWMx_MUX + * need to be defined in the board.h file + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void tpm_mux(void) +{ +#ifdef CONFIG_IMX9_TPM1_PWM +# ifdef TPM1_PWM0_MUX + imx9_iomux_configure(TPM1_PWM0_MUX); +# endif + +# ifdef TPM1_PWM1_MUX + imx9_iomux_configure(TPM1_PWM1_MUX); +# endif + +# ifdef TPM1_PWM2_MUX + imx9_iomux_configure(TPM1_PWM2_MUX); +# endif + +# ifdef TPM1_PWM3_MUX + imx9_iomux_configure(TPM1_PWM3_MUX); +# endif +#endif + +#ifdef CONFIG_IMX9_TPM2_PWM +# ifdef TPM2_PWM0_MUX + imx9_iomux_configure(TPM2_PWM0_MUX); +# endif + +# ifdef TPM2_PWM1_MUX + imx9_iomux_configure(TPM2_PWM1_MUX); +# endif + +# ifdef TPM2_PWM2_MUX + imx9_iomux_configure(TPM2_PWM2_MUX); +# endif + +# ifdef TPM2_PWM3_MUX + imx9_iomux_configure(TPM2_PWM3_MUX); +# endif +#endif + +#ifdef CONFIG_IMX9_TPM3_PWM +# ifdef TPM3_PWM0_MUX + imx9_iomux_configure(TPM3_PWM0_MUX); +# endif + +# ifdef TPM3_PWM1_MUX + imx9_iomux_configure(TPM3_PWM1_MUX); +# endif + +# ifdef TPM3_PWM2_MUX + imx9_iomux_configure(TPM3_PWM2_MUX); +# endif + +# ifdef TPM3_PWM3_MUX + imx9_iomux_configure(TPM3_PWM3_MUX); +# endif +#endif + +#ifdef CONFIG_IMX9_TPM4_PWM +# ifdef TPM4_PWM0_MUX + imx9_iomux_configure(TPM4_PWM0_MUX); +# endif + +# ifdef TPM4_PWM1_MUX + imx9_iomux_configure(TPM4_PWM1_MUX); +# endif + +# ifdef TPM4_PWM2_MUX + imx9_iomux_configure(TPM4_PWM2_MUX); +# endif + +# ifdef TPM4_PWM3_MUX + imx9_iomux_configure(TPM4_PWM3_MUX); +# endif +#endif + +#ifdef CONFIG_IMX9_TPM5_PWM +# ifdef TPM5_PWM0_MUX + imx9_iomux_configure(TPM5_PWM0_MUX); +# endif + +# ifdef TPM5_PWM1_MUX + imx9_iomux_configure(TPM5_PWM1_MUX); +# endif + +# ifdef TPM5_PWM2_MUX + imx9_iomux_configure(TPM5_PWM2_MUX); +# endif + +# ifdef TPM5_PWM3_MUX + imx9_iomux_configure(TPM5_PWM3_MUX); +# endif +#endif + +#ifdef CONFIG_IMX9_TPM6_PWM +# ifdef TPM6_PWM0_MUX + imx9_iomux_configure(TPM6_PWM0_MUX); +# endif + +# ifdef TPM6_PWM1_MUX + imx9_iomux_configure(TPM6_PWM1_MUX); +# endif + +# ifdef TPM6_PWM2_MUX + imx9_iomux_configure(TPM6_PWM2_MUX); +# endif + +# ifdef TPM6_PWM3_MUX + imx9_iomux_configure(TPM6_PWM3_MUX); +# endif +#endif +} + +/**************************************************************************** + * Name: pwm_update_frequency + * + * Description: + * Initialize the timer trigger, generating the PWM freuency + * + * Input Parameters: + * priv - A reference to the lower half PWM driver state structure + * freq - The requested PWM frequency for this flexio block + * + * Returned Value: + * Zero on success, negated error value on failure + * + ****************************************************************************/ + +static int pwm_update_frequency(struct imx9_pwmtimer_s *priv, int freq) +{ + int i; + + if (freq != priv->frequency) + { + /* Start PWM on all channels if it was previously stopped */ + + if (freq > 0 && priv->frequency == 0) + { + /* Set the EPWM mode for all the configured channels: + * + * High-true pulses (clear output on counter match, set output + * on counter reload, clear output when counter first enabled + * or paused) + * SC[CPWMS] = 0, MSnB:MSnA = 1:0 ELSnB:ELSnA = 0 + */ + + for (i = 0; i < priv->n_channels; i++) + { + pwm_putreg(priv, IMX9_TPM_CXSC_OFFSET(CHMUX(priv, i)), + TPM_CXSC_MSB_MASK); + } + } + + priv->period = freq > 0 ? priv->clk / freq : 0; + + pwminfo("PWM%d frequency: %" PRIu32" period: %" PRIu32 "\n", priv->id, + freq, priv->period); + + /* Set the period */ + + pwm_putreg(priv, IMX9_TPM_MOD_OFFSET, priv->period); + + priv->frequency = freq; + } + + return OK; +} + +/**************************************************************************** + * Name: pwm_update_duty + * + * Description: + * Change the channel duty cycle. + * + * Input Parameters: + * priv - A reference to the lower half PWM driver state structure + * period - PWM pulse width in timer ticks + * channel - Channel to by updated + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_update_duty(struct imx9_pwmtimer_s *priv, int pwm_ch, + ub16_t duty16) +{ + uint64_t duty = duty16 & 0xffffffff; + uint32_t edge = (duty * priv->period + 0x8000) >> 16; + int timer = pwm_ch - 1; + + if (pwm_ch == 0 || timer > priv->n_channels) + { + pwmerr("ERROR: PWM%d has no such channel: %d\n", priv->id, timer); + return -EINVAL; + } + + pwminfo("PWM%d channel %d, p: %d e: %" PRIu32 "\n", priv->id, + CHMUX(priv, timer), priv->period, edge); + + pwm_putreg(priv, IMX9_TPM_CXV_OFFSET(CHMUX(priv, timer)), edge); + + return OK; +} + +/**************************************************************************** + * Name: pwm_setup + * + * Description: + * This method is called when the driver is opened. The lower half driver + * should configure and initialize the device so that it is ready for use. + * It should not, however, output pulses until the start method is called. + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * + ****************************************************************************/ + +static int pwm_setup(struct pwm_lowerhalf_s *dev) +{ + return OK; +} + +/**************************************************************************** + * Name: pwm_shutdown + * + * Description: + * This method is called when the driver is closed. The lower half driver + * stop pulsed output, free any resources, disable the timer hardware, and + * put the system into the lowest possible power usage state + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_shutdown(struct pwm_lowerhalf_s *dev) +{ + /* Make sure that the output has been stopped */ + + pwm_stop(dev); + + return OK; +} + +/**************************************************************************** + * Name: pwm_start + * + * Description: + * (Re-)initialize the timer resources and start the pulsed output + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * info - A reference to the characteristics of the pulsed output + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_start(struct pwm_lowerhalf_s *dev, + const struct pwm_info_s *info) +{ + struct imx9_pwmtimer_s *priv = (struct imx9_pwmtimer_s *)dev; + int ret = OK; + int i; + + if (priv == NULL || info == NULL || info->frequency == 0) + { + return -EINVAL; + } + + /* Set the frequency if not changed */ + + if (pwm_update_frequency(priv, info->frequency) == OK) + { + /* Handle channel specific setup */ + + for (i = 0; i < CONFIG_PWM_NCHANNELS; i++) + { + if (ret != OK || info->channels[i].channel == -1) + { + break; + } + + pwm_update_duty(priv, info->channels[i].channel, + info->channels[i].duty); + } + } + + return ret; +} + +/**************************************************************************** + * Name: pwm_stop + * + * Description: + * Stop the pulsed output and reset the timer resources + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + * Assumptions: + * This function is called to stop the pulsed output at anytime. + * + ****************************************************************************/ + +static int pwm_stop(struct pwm_lowerhalf_s *dev) +{ + struct imx9_pwmtimer_s *priv = (struct imx9_pwmtimer_s *)dev; + int i; + + pwminfo("PWM%d stop\n", priv->id); + + /* Check that timer is valid */ + + if (priv == NULL) + { + return -EINVAL; + } + + /* Disable the channels */ + + for (i = 0; i < priv->n_channels; i++) + { + pwm_putreg(priv, IMX9_TPM_CXSC_OFFSET(CHMUX(priv, i)), 0); + } + + /* Set frequency to 0 */ + + pwm_update_frequency(priv, 0); + + return OK; +} + +/**************************************************************************** + * Name: pwm_ioctl + * + * Description: + * Lower-half logic may support platform-specific ioctl commands + * + * Input Parameters: + * dev - A reference to the lower half PWM driver state structure + * cmd - The ioctl command + * arg - The argument accompanying the ioctl command + * + * Returned Value: + * Zero on success; a negated errno value on failure + * + ****************************************************************************/ + +static int pwm_ioctl(struct pwm_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ + return -ENOTTY; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_tpm_pwm_init + * + * Description: + * Initialize tpm blocks to generate EPWM. + * + * Input Parameters: + * pwmid - A number identifying the pwm block. The number of valid + * IDs varies depending on the configuration. + * + * Returned Value: + * On success, a pointer to the lower half PWM driver is + * returned. NULL is returned on any failure. + * + ****************************************************************************/ + +struct pwm_lowerhalf_s *imx9_tpm_pwm_init(tpm_pwm_id_t pwmid) +{ + struct imx9_pwmtimer_s *lower = NULL; + int i; + + for (i = 0; i < sizeof(g_pwmdev) / sizeof(g_pwmdev[0]); i++) + { + if (pwmid == g_pwmdev[i].id) + { + lower = &g_pwmdev[i]; + break; + } + } + + if (lower) + { + /* IO mux */ + + tpm_mux(); + + /* Reset TPM */ + + pwm_putreg(lower, IMX9_TPM_GLOBAL_OFFSET, TPM_GLOBAL_RST_MASK); + pwm_putreg(lower, IMX9_TPM_GLOBAL_OFFSET, 0); + while (pwm_getreg(lower, IMX9_TPM_GLOBAL_OFFSET) != 0); + + /* TPM 1 is always clocked by AON bus and TPM3 by WAKEUP bus */ + + if (pwmid != PWM_TPM1 && pwmid != PWM_TPM3) + { + /* 24 MHz source clock */ + + imx9_ccm_configure_root_clock(CCM_CR_TPM1 + pwmid, OSC_24M, 1); + + /* Enable peripheral clock */ + + imx9_ccm_gate_on(CCM_LPCG_TPM1 + pwmid, true); + } + + /* Set status and control: + * CMOD = 1 (increment on every clock) + * PS = 0 (clock divider 1) + */ + + pwm_putreg(lower, IMX9_TPM_SC_OFFSET, 1 << TPM_SC_CMOD_SHIFT); + + pwminfo("PWM%d at %" PRIxPTR " configured\n", pwmid, lower->base); + } + else + { + pwmerr("ERROR: No such timer configured %d\n", pwmid); + } + + return (struct pwm_lowerhalf_s *)lower; +} + +#endif diff --git a/arch/arm64/src/imx9/imx9_tpm_pwm.h b/arch/arm64/src/imx9/imx9_tpm_pwm.h new file mode 100644 index 0000000000000..f6bdfde28e701 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_tpm_pwm.h @@ -0,0 +1,97 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_tpm_pwm.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_TPM_PWM_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_TPM_PWM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "hardware/imx9_tpm.h" + +/* Check if PWM support for any channel is enabled. */ + +#ifdef CONFIG_IMX9_TPM_PWM + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef enum +{ + PWM_TPM1 = 0, + PWM_TPM2 = 1, + PWM_TPM3 = 2, + PWM_TPM4 = 3, + PWM_TPM5 = 4, + PWM_TPM6 = 5, +} tpm_pwm_id_t; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_tpm_pwm_init + * + * Description: + * Initialize a TPM block for EPWM usage. + * + * Input Parameters: + * pwmid - A number identifying the pwm block. + * + * Returned Value: + * On success, a pointer to the lower half of the PWM driver is + * returned. NULL is returned on any failure. + * + ****************************************************************************/ + +struct pwm_lowerhalf_s *imx9_tpm_pwm_init(tpm_pwm_id_t pwmid); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_IMX9_TPM_PWM */ +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_TPM_PWM_H */ diff --git a/arch/arm64/src/imx9/imx9_usbdev.c b/arch/arm64/src/imx9/imx9_usbdev.c new file mode 100644 index 0000000000000..d34f6919c7fc8 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_usbdev.c @@ -0,0 +1,3141 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_usbdev.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include "chip.h" +#include "arm64_internal.h" +#include "imx9_ccm.h" +#include "hardware/imx9_memorymap.h" +#include "hardware/imx9_usbotg.h" +#include "hardware/imx9_ccm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(ARMV8A_DCACHE_LINESIZE) || ARMV8A_DCACHE_LINESIZE == 0 +# undef ARMV8A_DCACHE_LINESIZE +# define ARMV8A_DCACHE_LINESIZE 64 +#endif + +#define DCACHE_LINEMASK (ARMV8A_DCACHE_LINESIZE - 1) + +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) +# define cache_aligned_alloc(s) kmm_memalign(ARMV8A_DCACHE_LINESIZE,(s)) +# define CACHE_ALIGNED_DATA aligned_data(ARMV8A_DCACHE_LINESIZE) +#else +# define cache_aligned_alloc kmm_malloc +# define CACHE_ALIGNED_DATA +#endif + +/* Configuration ************************************************************/ + +#ifndef CONFIG_USBDEV_EP0_MAXSIZE +# define CONFIG_USBDEV_EP0_MAXSIZE 64 +#endif + +#ifndef CONFIG_USBDEV_MAXPOWER +# define CONFIG_USBDEV_MAXPOWER 100 /* mA */ +#endif + +/* Enable reading SOF from interrupt handler vs. simply reading on demand. + * Probably a bad idea... Unless there is some issue with sampling the SOF + * from hardware asynchronously. + */ + +#ifdef CONFIG_IMX9_USB_FRAME_INTERRUPT +# define USB_FRAME_INT USBDEV_USBINTR_SRE +#else +# define USB_FRAME_INT 0 +#endif + +#ifdef CONFIG_DEBUG_FEATURES +# define USB_ERROR_INT USBDEV_USBINTR_UEE +#else +# define USB_ERROR_INT 0 +#endif + +/* Debug ********************************************************************/ + +/* Trace error codes */ + +#define IMX9_TRACEERR_ALLOCFAIL 0x0001 +#define IMX9_TRACEERR_BADCLEARFEATURE 0x0002 +#define IMX9_TRACEERR_BADDEVGETSTATUS 0x0003 +#define IMX9_TRACEERR_BADEPNO 0x0004 +#define IMX9_TRACEERR_BADEPGETSTATUS 0x0005 +#define IMX9_TRACEERR_BADEPTYPE 0x0006 +#define IMX9_TRACEERR_BADGETCONFIG 0x0007 +#define IMX9_TRACEERR_BADGETSETDESC 0x0008 +#define IMX9_TRACEERR_BADGETSTATUS 0x0009 +#define IMX9_TRACEERR_BADSETADDRESS 0x000a +#define IMX9_TRACEERR_BADSETCONFIG 0x000b +#define IMX9_TRACEERR_BADSETFEATURE 0x000c +#define IMX9_TRACEERR_BINDFAILED 0x000d +#define IMX9_TRACEERR_DISPATCHSTALL 0x000e +#define IMX9_TRACEERR_DRIVER 0x000f +#define IMX9_TRACEERR_DRIVERREGISTERED 0x0010 +#define IMX9_TRACEERR_EP0SETUPSTALLED 0x0011 +#define IMX9_TRACEERR_EPINNULLPACKET 0x0012 +#define IMX9_TRACEERR_EPOUTNULLPACKET 0x0013 +#define IMX9_TRACEERR_INVALIDCTRLREQ 0x0014 +#define IMX9_TRACEERR_INVALIDPARMS 0x0015 +#define IMX9_TRACEERR_IRQREGISTRATION 0x0016 +#define IMX9_TRACEERR_NOEP 0x0017 +#define IMX9_TRACEERR_NOTCONFIGURED 0x0018 +#define IMX9_TRACEERR_REQABORTED 0x0019 + +/* Trace interrupt codes */ + +#define IMX9_TRACEINTID_USB 0x0001 +#define IMX9_TRACEINTID_CLEARFEATURE 0x0002 +#define IMX9_TRACEINTID_DEVGETSTATUS 0x0003 +#define IMX9_TRACEINTID_DEVRESET 0x0004 +#define IMX9_TRACEINTID_DISPATCH 0x0005 +#define IMX9_TRACEINTID_EP0COMPLETE 0x0006 +#define IMX9_TRACEINTID_EP0NAK 0x0007 +#define IMX9_TRACEINTID_EP0SETUP 0x0008 +#define IMX9_TRACEINTID_EPGETSTATUS 0x0009 +#define IMX9_TRACEINTID_EPIN 0x000a +#define IMX9_TRACEINTID_EPINQEMPTY 0x000b +#define IMX9_TRACEINTID_EP0INSETADDRESS 0x000c +#define IMX9_TRACEINTID_EPOUT 0x000d +#define IMX9_TRACEINTID_EPOUTQEMPTY 0x000e +#define IMX9_TRACEINTID_EP0SETUPSETADDRESS 0x000f +#define IMX9_TRACEINTID_FRAME 0x0010 +#define IMX9_TRACEINTID_GETCONFIG 0x0011 +#define IMX9_TRACEINTID_GETSETDESC 0x0012 +#define IMX9_TRACEINTID_GETSETIF 0x0013 +#define IMX9_TRACEINTID_GETSTATUS 0x0014 +#define IMX9_TRACEINTID_IFGETSTATUS 0x0015 +#define IMX9_TRACEINTID_SETCONFIG 0x0016 +#define IMX9_TRACEINTID_SETFEATURE 0x0017 +#define IMX9_TRACEINTID_SUSPENDED 0x0018 +#define IMX9_TRACEINTID_RESUMED 0x0019 +#define IMX9_TRACEINTID_SYNCHFRAME 0x001a + +#ifdef CONFIG_USBDEV_TRACE_STRINGS +const struct trace_msg_t g_usb_trace_strings_deverror[] = +{ + TRACE_STR(IMX9_TRACEERR_ALLOCFAIL), + TRACE_STR(IMX9_TRACEERR_BADCLEARFEATURE), + TRACE_STR(IMX9_TRACEERR_BADDEVGETSTATUS), + TRACE_STR(IMX9_TRACEERR_BADEPNO), + TRACE_STR(IMX9_TRACEERR_BADEPGETSTATUS), + TRACE_STR(IMX9_TRACEERR_BADEPTYPE), + TRACE_STR(IMX9_TRACEERR_BADGETCONFIG), + TRACE_STR(IMX9_TRACEERR_BADGETSETDESC), + TRACE_STR(IMX9_TRACEERR_BADGETSTATUS), + TRACE_STR(IMX9_TRACEERR_BADSETADDRESS), + TRACE_STR(IMX9_TRACEERR_BADSETCONFIG), + TRACE_STR(IMX9_TRACEERR_BADSETFEATURE), + TRACE_STR(IMX9_TRACEERR_BINDFAILED), + TRACE_STR(IMX9_TRACEERR_DISPATCHSTALL), + TRACE_STR(IMX9_TRACEERR_DRIVER), + TRACE_STR(IMX9_TRACEERR_DRIVERREGISTERED), + TRACE_STR(IMX9_TRACEERR_EP0SETUPSTALLED), + TRACE_STR(IMX9_TRACEERR_EPINNULLPACKET), + TRACE_STR(IMX9_TRACEERR_EPOUTNULLPACKET), + TRACE_STR(IMX9_TRACEERR_INVALIDCTRLREQ), + TRACE_STR(IMX9_TRACEERR_INVALIDPARMS), + TRACE_STR(IMX9_TRACEERR_IRQREGISTRATION), + TRACE_STR(IMX9_TRACEERR_NOEP), + TRACE_STR(IMX9_TRACEERR_NOTCONFIGURED), + TRACE_STR(IMX9_TRACEERR_REQABORTED), + TRACE_STR_END +}; + +const struct trace_msg_t g_usb_trace_strings_intdecode[] = +{ + TRACE_STR(IMX9_TRACEINTID_USB), + TRACE_STR(IMX9_TRACEINTID_CLEARFEATURE), + TRACE_STR(IMX9_TRACEINTID_DEVGETSTATUS), + TRACE_STR(IMX9_TRACEINTID_DEVRESET), + TRACE_STR(IMX9_TRACEINTID_DISPATCH), + TRACE_STR(IMX9_TRACEINTID_EP0COMPLETE), + TRACE_STR(IMX9_TRACEINTID_EP0NAK), + TRACE_STR(IMX9_TRACEINTID_EP0SETUP), + TRACE_STR(IMX9_TRACEINTID_EPGETSTATUS), + TRACE_STR(IMX9_TRACEINTID_EPIN), + TRACE_STR(IMX9_TRACEINTID_EPINQEMPTY), + TRACE_STR(IMX9_TRACEINTID_EP0INSETADDRESS), + TRACE_STR(IMX9_TRACEINTID_EPOUT), + TRACE_STR(IMX9_TRACEINTID_EPOUTQEMPTY), + TRACE_STR(IMX9_TRACEINTID_EP0SETUPSETADDRESS), + TRACE_STR(IMX9_TRACEINTID_FRAME), + TRACE_STR(IMX9_TRACEINTID_GETCONFIG), + TRACE_STR(IMX9_TRACEINTID_GETSETDESC), + TRACE_STR(IMX9_TRACEINTID_GETSETIF), + TRACE_STR(IMX9_TRACEINTID_GETSTATUS), + TRACE_STR(IMX9_TRACEINTID_IFGETSTATUS), + TRACE_STR(IMX9_TRACEINTID_SETCONFIG), + TRACE_STR(IMX9_TRACEINTID_SETFEATURE), + TRACE_STR(IMX9_TRACEINTID_SUSPENDED), + TRACE_STR(IMX9_TRACEINTID_RESUMED), + TRACE_STR(IMX9_TRACEINTID_SYNCHFRAME), + TRACE_STR_END +}; +#endif + +/* Hardware interface *******************************************************/ + +/* This represents a Endpoint Transfer Descriptor dQH overlay (32 bytes) */ + +#define IMX9_DTD_S \ + volatile uint32_t nextdesc; /* Address of the next DMA descripto in RAM */ \ + volatile uint32_t config; /* Misc. bit encoded configuration information */ \ + uint32_t buffer0; /* Buffer start address */ \ + uint32_t buffer1; /* Buffer start address */ \ + uint32_t buffer2; /* Buffer start address */ \ + uint32_t buffer3; /* Buffer start address */ \ + uint32_t buffer4; /* Buffer start address */ \ + uint32_t xfer_len; /* Software only - transfer len that was queued */ \ + +struct imx9_dtd_ovl_s +{ + IMX9_DTD_S +}; + +/* This represents a Endpoint Transfer Descriptor - cache line aligned */ + +struct imx9_dtd_s +{ + IMX9_DTD_S +} CACHE_ALIGNED_DATA; + +/* DTD nextdesc field */ + +#define DTD_NEXTDESC_INVALID (1 << 0) /* Bit 0 : Next Descriptor Invalid. The "Terminate" bit. */ + +/* DTD config field */ + +#define DTD_CONFIG_LENGTH(n) ((n) << 16) /* Bits 16-31 : Total bytes to transfer */ +#define DTD_CONFIG_IOC (1 << 15) /* Bit 15 : Interrupt on Completion */ +#define DTD_CONFIG_MULT_VARIABLE (0 << 10) /* Bits 10-11 : Number of packets executed per transacation descriptor (override) */ +#define DTD_CONFIG_MULT_NUM(n) ((n) << 10) +#define DTD_CONFIG_ACTIVE (1 << 7) /* Bit 7 : Status Active */ +#define DTD_CONFIG_HALTED (1 << 6) /* Bit 6 : Status Halted */ +#define DTD_CONFIG_BUFFER_ERROR (1 << 5) /* Bit 6 : Status Buffer Error */ +#define DTD_CONFIG_TRANSACTION_ERROR (1 << 3) /* Bit 3 : Status Transaction Error */ + +/* This represents a queue head */ + +struct imx9_dqh_s +{ + uint32_t capability; /* Endpoint capability */ + uint32_t currdesc; /* Current dTD pointer */ + struct imx9_dtd_ovl_s overlay; /* DTD overlay */ + volatile uint32_t setup[2]; /* Set-up buffer */ +} CACHE_ALIGNED_DATA; + +/* DQH capability field */ + +#define DQH_CAPABILITY_MULT_VARIABLE (0 << 30) /* Bits 30-31 : Number of packets executed per transaction descriptor */ +#define DQH_CAPABILITY_MULT_NUM(n) ((n) << 30) +#define DQH_CAPABILITY_ZLT (1 << 29) /* Bit 29 : Zero Length Termination Select */ +#define DQH_CAPABILITY_MAX_PACKET(n) ((n) << 16) /* Bits 16-29 : Maximum packet size of associated endpoint (<1024) */ +#define DQH_CAPABILITY_IOS (1 << 15) /* Bit 15 : Interrupt on Setup */ + +/* Endpoints ****************************************************************/ + +/* Number of endpoints */ + +#define IMX9_NLOGENDPOINTS (8) /* ep0-7 */ +#define IMX9_NPHYSENDPOINTS (16) /* x2 for IN and OUT */ + +/* Odd physical endpoint numbers are IN; even are OUT */ + +#define IMX9_EPPHYIN(epphy) (((epphy) & 1) != 0) +#define IMX9_EPPHYOUT(epphy) (((epphy) & 1) == 0) + +#define IMX9_EPPHYIN2LOG(epphy) (((uint8_t)(epphy) >> 1) |USB_DIR_IN) +#define IMX9_EPPHYOUT2LOG(epphy) (((uint8_t)(epphy) >> 1) | USB_DIR_OUT) + +/* Endpoint 0 is special... */ + +#define IMX9_EP0_OUT (0) +#define IMX9_EP0_IN (1) + +/* Each endpoint has somewhat different characteristics */ + +#define IMX9_EPALLSET (0xffff) /* All endpoints */ +#define IMX9_EPOUTSET (0x5555) /* Even phy endpoint numbers are OUT EPs */ +#define IMX9_EPINSET (0xaaaa) /* Odd endpoint numbers are IN EPs */ +#define IMX9_EPCTRLSET (0x0003) /* EP0 IN/OUT are control endpoints */ +#define IMX9_EPINTRSET (0x000c) /* Interrupt endpoints */ +#define IMX9_EPBULKSET (0x0ff0) /* Bulk endpoints */ +#define IMX9_EPISOCSET (0xf000) /* Isochronous endpoints */ + +/* Maximum packet sizes for endpoints */ + +#define IMX9_EP0MAXPACKET (64) /* EP0 max packet size (1-64) */ +#define IMX9_BULKMAXPACKET (512) /* Bulk endpoint max packet (8/16/32/64/512) */ +#define IMX9_INTRMAXPACKET (1024) /* Interrupt endpoint max packet (1 to 1024) */ +#define IMX9_ISOCMAXPACKET (512) /* Acutally 1..1023 */ + +/* Endpoint bit position in SETUPSTAT, PRIME, FLUSH, STAT, COMPLETE + * registers + */ + +#define IMX9_ENDPTSHIFT(epphy) (IMX9_EPPHYIN(epphy) ? (16 + ((epphy) >> 1)) : ((epphy) >> 1)) +#define IMX9_ENDPTMASK(epphy) (1 << IMX9_ENDPTSHIFT(epphy)) +#define IMX9_ENDPTMASK_ALL 0x00ff00ff + +/* Request queue operations *************************************************/ + +#define imx9_rqempty(ep) ((ep)->head == NULL) +#define imx9_rqpeek(ep) ((ep)->head) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* A container for a request so that the request may be retained in a list */ + +struct imx9_req_s +{ + struct usbdev_req_s req; /* Standard USB request */ + struct imx9_req_s *flink; /* Supports a singly linked list */ +}; + +/* This is the internal representation of an endpoint */ + +struct imx9_ep_s +{ + /* Common endpoint fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbdev_ep_s + * to struct imx9_ep_s. + */ + + struct usbdev_ep_s ep; /* Standard endpoint structure */ + + /* IMX9XX-specific fields */ + + struct imx9_usb_s *dev; /* Reference to private driver data */ + struct imx9_req_s *head; /* Request list for this endpoint */ + struct imx9_req_s *tail; + uint8_t epphy; /* Physical EP address */ + uint8_t stalled:1; /* 1: Endpoint is stalled */ +}; + +/* Structure for ep0 short transfers */ + +struct imx9_ep0_s +{ + uint8_t * const buf; /* buffer for EP0 short transfers */ + uint16_t buf_len; /* buffer length */ + struct usb_ctrlreq_s ctrl; /* structure for EP0 short transfers */ + uint8_t state; /* state of certain EP0 operations */ +}; + +/* This structure retains the state of the USB device controller */ + +struct imx9_usb_s +{ + /* Common device fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbdev_s + * to struct imx9_usb_s. + */ + + struct usbdev_s usbdev; + + /* The bound device class driver */ + + struct usbdevclass_driver_s *driver; + + const int id; /* Id of the usb controller */ + const uintptr_t base; /* Base address of the controller */ + uint8_t paddr; /* Address assigned by SETADDRESS */ + uint8_t stalled:1; /* 1: Protocol stalled */ + uint8_t selfpowered:1; /* 1: Device is self powered */ + uint8_t paddrset:1; /* 1: Peripheral addr has been set */ + uint8_t attached:1; /* 1: Host attached */ + uint8_t suspended:1; /* 1: Suspended */ + uint32_t softprio; /* Bitset of high priority interrupts */ + uint32_t epavail; /* Bitset of available endpoints */ +#ifdef CONFIG_IMX9_USB_FRAME_INTERRUPT + uint32_t sof; /* Last start-of-frame */ +#endif + + struct imx9_ep0_s ep0; /* ep0 */ + + /* The endpoint list */ + + struct imx9_ep_s eplist[IMX9_NPHYSENDPOINTS]; + struct imx9_dqh_s * const qh; + struct imx9_dtd_s * const td; +}; + +#define EP0STATE_IDLE 0 /* Idle State, leave on receiving a setup packet or epsubmit */ +#define EP0STATE_SETUP_OUT 1 /* Setup Packet received - SET/CLEAR */ +#define EP0STATE_SETUP_IN 2 /* Setup Packet received - GET */ +#define EP0STATE_SHORTREAD 3 /* Short read without a usb_request */ +#define EP0STATE_SHORTWRITE 4 /* Short write without a usb_request */ +#define EP0STATE_WAIT_NAK_OUT 5 /* Waiting for Host to illicit status phase (GET) */ +#define EP0STATE_WAIT_NAK_IN 6 /* Waiting for Host to illicit status phase (SET/CLEAR) */ +#define EP0STATE_WAIT_STATUS_OUT 7 /* Wait for status phase to complete */ +#define EP0STATE_WAIT_STATUS_IN 8 /* Wait for status phase to complete */ +#define EP0STATE_DATA_IN 9 +#define EP0STATE_DATA_OUT 10 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations ******************************************************/ + +#ifdef CONFIG_IMX9_USB_REGDEBUG +static uint32_t imx9_getreg(struct imx9_usb_s *priv, off_t offset); +static void imx9_putreg(struct imx9_usb_s *priv, off_t offset, uint32_t val); +#else +# define imx9_getreg(priv, offset) getreg32(priv->base + offset) +# define imx9_putreg(priv, offset, val) putreg32(val,priv->base + offset) +#endif + +static inline void imx9_modifyreg(struct imx9_usb_s *priv, + off_t offset, + uint32_t clear, + uint32_t set); + +/* Request queue operations *************************************************/ + +static struct imx9_req_s *imx9_rqdequeue( + struct imx9_ep_s *privep); +static bool imx9_rqenqueue(struct imx9_ep_s *privep, + struct imx9_req_s *req); + +/* Low level data transfers and request operations **************************/ + +static inline void imx9_writedtd(struct imx9_dtd_s *dtd, + const uint8_t *data, + uint32_t nbytes); +static inline void imx9_queuedtd(struct imx9_usb_s *priv, uint8_t epphy, + struct imx9_dtd_s *dtd); +static inline void imx9_ep0xfer(struct imx9_usb_s *priv, uint8_t epphy, + uint8_t *data, + uint32_t nbytes); +static void imx9_readsetup(struct imx9_usb_s *priv, uint8_t epphy, + struct usb_ctrlreq_s *ctrl); +static inline void imx9_set_address(struct imx9_usb_s *priv, + uint16_t address); + +static void imx9_flushep(struct imx9_ep_s *privep); + +static int imx9_progressep(struct imx9_ep_s *privep); +static void imx9_reqcomplete(struct imx9_ep_s *privep, + struct imx9_req_s *privreq, int16_t result); + +static void imx9_cancelrequests(struct imx9_ep_s *privep, + int16_t status); + +/* Interrupt handling *******************************************************/ + +static struct imx9_ep_s *imx9_epfindbyaddr(struct imx9_usb_s *priv, + uint16_t eplog); +static void imx9_dispatchrequest(struct imx9_usb_s *priv, + const struct usb_ctrlreq_s *ctrl); +static void imx9_ep0configure(struct imx9_usb_s *priv); +static void imx9_usbreset(struct imx9_usb_s *priv); +static inline void imx9_ep0state(struct imx9_usb_s *priv, + uint16_t state); +static void imx9_ep0setup(struct imx9_usb_s *priv); +static void imx9_ep0complete(struct imx9_usb_s *priv, + uint8_t epphy); +static void imx9_ep0nak(struct imx9_usb_s *priv, uint8_t epphy); +static bool imx9_epcomplete(struct imx9_usb_s *priv, + uint8_t epphy); +static int imx9_usbinterrupt(int irq, void *context, + void *arg); + +/* Endpoint operations ******************************************************/ + +/* USB device controller operations *****************************************/ + +static int imx9_epconfigure(struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, bool last); +static int imx9_epdisable(struct usbdev_ep_s *ep); +static struct usbdev_req_s *imx9_epallocreq(struct usbdev_ep_s *ep); +static void imx9_epfreereq(struct usbdev_ep_s *ep, + struct usbdev_req_s *); +#ifdef CONFIG_USBDEV_DMA +static void *imx9_epallocbuffer(struct usbdev_ep_s *ep, + uint16_t bytes); +static void imx9_epfreebuffer(struct usbdev_ep_s *ep, + void *buf); +#endif +static int imx9_epsubmit(struct usbdev_ep_s *ep, + struct usbdev_req_s *req); +static int imx9_epcancel(struct usbdev_ep_s *ep, + struct usbdev_req_s *req); +static int imx9_epstall(struct usbdev_ep_s *ep, bool resume); + +static struct usbdev_ep_s *imx9_allocep(struct usbdev_s *dev, + uint8_t epno, bool in, uint8_t eptype); +static void imx9_freeep(struct usbdev_s *dev, + struct usbdev_ep_s *ep); +static int imx9_getframe(struct usbdev_s *dev); +static int imx9_wakeup(struct usbdev_s *dev); +static int imx9_selfpowered(struct usbdev_s *dev, bool selfpowered); +static int imx9_pullup(struct usbdev_s *dev, bool enable); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Note: dqh lists must be aligned to a 2048 byte + * boundary, since ENDPTLISTADDR register last 10 bits are tied to 0 + */ + +#ifdef CONFIG_IMX9_USBDEV_USBC1 +static uint8_t g_usb0_ep0buf[64] CACHE_ALIGNED_DATA; +static struct imx9_dqh_s g_usb0_qh[IMX9_NPHYSENDPOINTS] aligned_data(2048); +static struct imx9_dtd_s g_usb0_td[IMX9_NPHYSENDPOINTS]; +#endif + +#ifdef CONFIG_IMX9_USBDEV_USBC2 +static uint8_t g_usb1_ep0buf[64] CACHE_ALIGNED_DATA; +static struct imx9_dqh_s g_usb1_qh[IMX9_NPHYSENDPOINTS] aligned_data(2048); +static struct imx9_dtd_s g_usb1_td[IMX9_NPHYSENDPOINTS]; +#endif + +static struct imx9_usb_s g_usbdev[] = +{ +#ifdef CONFIG_IMX9_USBDEV_USBC1 + { + .id = 0, + .base = IMX9_USB_OTG1_BASE, + .ep0.buf = g_usb0_ep0buf, + .qh = g_usb0_qh, + .td = g_usb0_td, + }, +#endif + +#ifdef CONFIG_IMX9_USBDEV_USBC2 + { + .id = 1, + .base = IMX9_USB_OTG2_BASE, + .ep0.buf = g_usb1_ep0buf, + .qh = g_usb1_qh, + .td = g_usb1_td, + }, +#endif +}; + +static const int n_usbdevs = sizeof(g_usbdev) / sizeof(g_usbdev[0]); + +static const struct usbdev_epops_s g_epops = +{ + .configure = imx9_epconfigure, + .disable = imx9_epdisable, + .allocreq = imx9_epallocreq, + .freereq = imx9_epfreereq, +#ifdef CONFIG_USBDEV_DMA + .allocbuffer = imx9_epallocbuffer, + .freebuffer = imx9_epfreebuffer, +#endif + .submit = imx9_epsubmit, + .cancel = imx9_epcancel, + .stall = imx9_epstall, +}; + +static const struct usbdev_ops_s g_devops = +{ + .allocep = imx9_allocep, + .freeep = imx9_freeep, + .getframe = imx9_getframe, + .wakeup = imx9_wakeup, + .selfpowered = imx9_selfpowered, + .pullup = imx9_pullup, +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_getreg + * + * Description: + * Get the contents of an IMX93x register + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_USB_REGDEBUG +static uint32_t imx9_getreg(struct imx9_usb_s *priv, off_t offset) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Read the value from the register */ + + uint32_t val = getreg32(priv->base + offset); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && val == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + uinfo("...\n"); + } + + return val; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + uinfo("[repeats %d more times]\n", count - 3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = val; + count = 1; + } + + /* Show the register value read */ + + uinfo("%08x->%08x\n", priv->base + offset, val); + return val; +} +#endif + +/**************************************************************************** + * Name: imx9_putreg + * + * Description: + * Set the contents of an IMX93x register to a value + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_USB_REGDEBUG +static void imx9_putreg(struct imx9_usb_s *priv, off_t offset, uint32_t val) +{ + /* Show the register value being written */ + + uinfo("%08x<-%08x\n", priv->base + offset, val); + + /* Write the value */ + + putreg32(val, priv->base + offset); +} +#endif + +/**************************************************************************** + * Name: imx9_modifyreg + * + * Description: + * Change bits in a register + * + ****************************************************************************/ + +static inline void imx9_modifyreg(struct imx9_usb_s *priv, off_t offset, + uint32_t clear, uint32_t set) +{ + uint32_t reg = imx9_getreg(priv, offset); + reg &= ~clear; + reg |= set; + imx9_putreg(priv, offset, reg); +} + +/**************************************************************************** + * Name: imx9_rqdequeue + * + * Description: + * Remove a request from an endpoint request queue + * + ****************************************************************************/ + +static struct imx9_req_s *imx9_rqdequeue(struct imx9_ep_s *privep) +{ + struct imx9_req_s *ret = privep->head; + + if (ret) + { + privep->head = ret->flink; + if (!privep->head) + { + privep->tail = NULL; + } + + ret->flink = NULL; + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_rqenqueue + * + * Description: + * Add a request from an endpoint request queue + * + ****************************************************************************/ + +static bool imx9_rqenqueue(struct imx9_ep_s *privep, + struct imx9_req_s *req) +{ + bool is_empty = !privep->head; + + req->flink = NULL; + if (is_empty) + { + privep->head = req; + privep->tail = req; + } + else + { + privep->tail->flink = req; + privep->tail = req; + } + + return is_empty; +} + +/**************************************************************************** + * Name: imx9_writedtd + * + * Description: + * Initialise a DTD to transfer the data + * + ****************************************************************************/ + +static inline void imx9_writedtd(struct imx9_dtd_s *dtd, + const uint8_t *data, + uint32_t nbytes) +{ + dtd->nextdesc = DTD_NEXTDESC_INVALID; + dtd->config = DTD_CONFIG_LENGTH(nbytes) | DTD_CONFIG_IOC | + DTD_CONFIG_ACTIVE; + dtd->buffer0 = (uint32_t)((uintptr_t) data); + dtd->buffer1 = (uint32_t)(((uintptr_t) data) + 0x1000) & 0xfffff000; + dtd->buffer2 = (uint32_t)(((uintptr_t) data) + 0x2000) & 0xfffff000; + dtd->buffer3 = (uint32_t)(((uintptr_t) data) + 0x3000) & 0xfffff000; + dtd->buffer4 = (uint32_t)(((uintptr_t) data) + 0x4000) & 0xfffff000; + dtd->xfer_len = nbytes; + + up_clean_dcache((uintptr_t)dtd, + (uintptr_t)dtd + sizeof(struct imx9_dtd_s)); + up_clean_dcache((uintptr_t)data, + (uintptr_t)data + nbytes); +} + +/**************************************************************************** + * Name: imx9_queuedtd + * + * Description: + * Add the DTD to the device list + * + * Assumptions: + * DTD is already flushed to RAM. + * + ****************************************************************************/ + +static void imx9_queuedtd(struct imx9_usb_s *priv, uint8_t epphy, + struct imx9_dtd_s *dtd) +{ + struct imx9_dqh_s *dqh = &priv->qh[epphy]; + + /* Queue the DTD onto the Endpoint + * NOTE - this only works when no DTD is currently queued + */ + + dqh->overlay.nextdesc = (uint32_t)(uintptr_t)dtd; + dqh->overlay.config &= ~(DTD_CONFIG_ACTIVE | DTD_CONFIG_HALTED); + + up_flush_dcache((uintptr_t)dqh, + (uintptr_t)dqh + sizeof(struct imx9_dqh_s)); + + uint32_t bit = IMX9_ENDPTMASK(epphy); + + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTPRIME_OFFSET, 0, bit); + + while (imx9_getreg(priv, IMX9_USBDEV_ENDPTPRIME_OFFSET) & bit); +} + +/**************************************************************************** + * Name: imx9_ep0xfer + * + * Description: + * Schedule a short transfer for Endpoint 0 (IN or OUT) + * + ****************************************************************************/ + +static inline void imx9_ep0xfer(struct imx9_usb_s *priv, uint8_t epphy, + uint8_t *buf, uint32_t nbytes) +{ + struct imx9_dtd_s *dtd = &priv->td[epphy]; + + imx9_writedtd(dtd, buf, nbytes); + + imx9_queuedtd(priv, epphy, dtd); +} + +/**************************************************************************** + * Name: imx9_readsetup + * + * Description: + * Read a Setup packet from the DTD. + * + ****************************************************************************/ + +static void imx9_readsetup(struct imx9_usb_s *priv, uint8_t epphy, + struct usb_ctrlreq_s *ctrl) +{ + struct imx9_dqh_s *dqh = &priv->qh[epphy]; + int i; + + do + { + /* Set the trip wire */ + + imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, 0, USBDEV_USBCMD_SUTW); + + up_invalidate_dcache((uintptr_t)dqh, + (uintptr_t)dqh + sizeof(struct imx9_dqh_s)); + + /* Copy the request... */ + + for (i = 0; i < 8; i++) + { + ((uint8_t *) ctrl)[i] = ((uint8_t *) dqh->setup)[i]; + } + } + + while (!(imx9_getreg(priv, + IMX9_USBDEV_USBCMD_OFFSET) & USBDEV_USBCMD_SUTW)); + + /* Clear the trip wire */ + + imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, USBDEV_USBCMD_SUTW, 0); + + up_clean_dcache((uintptr_t)dqh, + (uintptr_t)dqh + sizeof(struct imx9_dqh_s)); + + /* Clear the Setup Interrupt */ + + imx9_putreg(priv, IMX9_USBDEV_ENDPTSETUPSTAT_OFFSET, + IMX9_ENDPTMASK(IMX9_EP0_OUT)); +} + +/**************************************************************************** + * Name: imx9_set_address + * + * Description: + * Set the devices USB address + * + ****************************************************************************/ + +static inline void imx9_set_address(struct imx9_usb_s *priv, + uint16_t address) +{ + priv->paddr = address; + priv->paddrset = address != 0; + + imx9_modifyreg(priv, IMX9_USBDEV_DEVICEADDR_OFFSET, USBDEV_DEVICEADDR_MASK, + priv->paddr << USBDEV_DEVICEADDR_SHIFT); +} + +/**************************************************************************** + * Name: imx9_flushep + * + * Description: + * Flush any primed descriptors from this ep + * + ****************************************************************************/ + +static void imx9_flushep(struct imx9_ep_s *privep) +{ + uint32_t mask = IMX9_ENDPTMASK(privep->epphy); + struct imx9_usb_s *priv = privep->dev; + + do + { + imx9_putreg(priv, IMX9_USBDEV_ENDPTFLUSH_OFFSET, mask); + while ((imx9_getreg(priv, IMX9_USBDEV_ENDPTFLUSH_OFFSET) & mask) != 0); + } + while ((imx9_getreg(priv, IMX9_USBDEV_ENDPTSTATUS_OFFSET) & mask) != 0); +} + +/**************************************************************************** + * Name: imx9_progressep + * + * Description: + * Progress the Endpoint by priming the first request into the queue head + * + ****************************************************************************/ + +static int imx9_progressep(struct imx9_ep_s *privep) +{ + struct imx9_usb_s *priv = privep->dev; + struct imx9_dtd_s *dtd = &priv->td[privep->epphy]; + struct imx9_req_s *privreq; + + /* Check the request from the head of the endpoint request queue */ + + privreq = imx9_rqpeek(privep); + if (!privreq) + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EPINQEMPTY), 0); + return OK; + } + + /* Ignore any attempt to send a zero length packet */ + + if (privreq->req.len == 0) + { + /* If the class driver is responding to a setup packet, then wait for + * the host to illicit the response + */ + + if (privep->epphy == IMX9_EP0_IN && + privep->dev->ep0.state == EP0STATE_SETUP_OUT) + { + imx9_ep0state(priv, EP0STATE_WAIT_NAK_IN); + } + else + { + if (IMX9_EPPHYIN(privep->epphy)) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_EPINNULLPACKET), 0); + } + else + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_EPOUTNULLPACKET), 0); + } + } + + imx9_reqcomplete(privep, imx9_rqdequeue(privep), OK); + return OK; + } + + if (privep->epphy == IMX9_EP0_IN) + { + imx9_ep0state(priv, EP0STATE_DATA_IN); + } + else if (privep->epphy == IMX9_EP0_OUT) + { + imx9_ep0state(priv, EP0STATE_DATA_OUT); + } + + int bytesleft = privreq->req.len - privreq->req.xfrd; + + if (IMX9_EPPHYIN(privep->epphy)) + { + usbtrace(TRACE_WRITE(privep->epphy), privreq->req.xfrd); + } + else + { + usbtrace(TRACE_READ(privep->epphy), privreq->req.xfrd); + } + + /* Initialise the DTD to transfer the next chunk */ + + imx9_writedtd(dtd, privreq->req.buf + privreq->req.xfrd, bytesleft); + + /* Then queue onto the DQH */ + + imx9_queuedtd(priv, privep->epphy, dtd); + + return OK; +} + +/**************************************************************************** + * Name: imx9_reqcomplete + * + * Description: + * Handle termination of the request at the head of the endpoint request + * queue. + * + ****************************************************************************/ + +static void imx9_reqcomplete(struct imx9_ep_s *privep, + struct imx9_req_s *privreq, int16_t result) +{ + /* If endpoint 0, temporarily reflect the state of protocol stalled + * in the callback. + */ + + bool stalled = privep->stalled; + if (privep->epphy == IMX9_EP0_IN) + privep->stalled = privep->dev->stalled; + + /* Save the result in the request structure */ + + privreq->req.result = result; + + /* Callback to the request completion handler */ + + privreq->req.callback(&privep->ep, &privreq->req); + + /* Restore the stalled indication */ + + privep->stalled = stalled; +} + +/**************************************************************************** + * Name: imx9_cancelrequests + * + * Description: + * Cancel all pending requests for an endpoint + * + ****************************************************************************/ + +static void imx9_cancelrequests(struct imx9_ep_s *privep, int16_t status) +{ + if (!imx9_rqempty(privep)) + imx9_flushep(privep); + + while (!imx9_rqempty(privep)) + { + /* FIXME: the entry at the head should be sync'd with the DTD + * FIXME: only report the error status if the transfer hasn't completed + */ + + usbtrace(TRACE_COMPLETE(privep->epphy), + (imx9_rqpeek(privep))->req.xfrd); + imx9_reqcomplete(privep, imx9_rqdequeue(privep), status); + } +} + +/**************************************************************************** + * Name: imx9_epfindbyaddr + * + * Description: + * Find the physical endpoint structure corresponding to a logic endpoint + * address + * + ****************************************************************************/ + +static struct imx9_ep_s *imx9_epfindbyaddr(struct imx9_usb_s *priv, + uint16_t eplog) +{ + struct imx9_ep_s *privep; + int i; + + /* Endpoint zero is a special case */ + + if (USB_EPNO(eplog) == 0) + { + return &priv->eplist[0]; + } + + /* Handle the remaining */ + + for (i = 1; i < IMX9_NPHYSENDPOINTS; i++) + { + privep = &priv->eplist[i]; + + /* Same logical endpoint number? (includes direction bit) */ + + if (eplog == privep->ep.eplog) + { + /* Return endpoint found */ + + return privep; + } + } + + /* Return endpoint not found */ + + return NULL; +} + +/**************************************************************************** + * Name: imx9_dispatchrequest + * + * Description: + * Provide unhandled setup actions to the class driver. This is logically + * part of the USB interrupt handler. + * + ****************************************************************************/ + +static void imx9_dispatchrequest(struct imx9_usb_s *priv, + const struct usb_ctrlreq_s *ctrl) +{ + int ret = -EIO; + + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_DISPATCH), 0); + if (priv->driver) + { + /* Invalidate buffer data cache */ + + up_invalidate_dcache((uintptr_t)priv->ep0.buf, + (uintptr_t)priv->ep0.buf + sizeof(priv->ep0.buf)); + + /* Forward to the control request to the class driver implementation */ + + ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl, priv->ep0.buf, + priv->ep0.buf_len); + } + + if (ret < 0) + { + /* Stall on failure */ + + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_DISPATCHSTALL), 0); + priv->stalled = true; + } +} + +/**************************************************************************** + * Name: imx9_ep0configure + * + * Description: + * Reset Usb engine + * + ****************************************************************************/ + +static void imx9_ep0configure(struct imx9_usb_s *priv) +{ + /* Enable ep0 IN and ep0 OUT */ + + priv->qh[IMX9_EP0_OUT].capability = + (DQH_CAPABILITY_MAX_PACKET(CONFIG_USBDEV_EP0_MAXSIZE) | + DQH_CAPABILITY_IOS | DQH_CAPABILITY_ZLT); + + priv->qh[IMX9_EP0_IN].capability = + (DQH_CAPABILITY_MAX_PACKET(CONFIG_USBDEV_EP0_MAXSIZE) | + DQH_CAPABILITY_IOS | DQH_CAPABILITY_ZLT); + + priv->qh[IMX9_EP0_OUT].currdesc = DTD_NEXTDESC_INVALID; + priv->qh[IMX9_EP0_IN].currdesc = DTD_NEXTDESC_INVALID; + + up_clean_dcache((uintptr_t)priv->qh, + (uintptr_t)priv->qh + (sizeof(struct imx9_dqh_s) * 2)); + + /* Enable EP0 */ + + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL0_OFFSET, 0, + USBDEV_ENDPTCTRL0_RXE | USBDEV_ENDPTCTRL0_TXE); +} + +/**************************************************************************** + * Name: imx9_usbreset + * + * Description: + * Reset Usb engine + * + ****************************************************************************/ + +static void imx9_usbreset(struct imx9_usb_s *priv) +{ + int epphy; + + /* Disable all endpoints. Control endpoint 0 is always enabled */ + + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL1_OFFSET, + USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, 0); + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL2_OFFSET, + USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, 0); + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL3_OFFSET, + USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, 0); + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL4_OFFSET, + USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, 0); + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL5_OFFSET, + USBDEV_ENDPTCTRL_RXE | USBDEV_ENDPTCTRL_TXE, 0); + + /* Clear all pending interrupts */ + + imx9_putreg(priv, IMX9_USBDEV_ENDPTNAK_OFFSET, + imx9_getreg(priv, IMX9_USBDEV_ENDPTNAK_OFFSET)); + + imx9_putreg(priv, IMX9_USBDEV_ENDPTSETUPSTAT_OFFSET, + imx9_getreg(priv, IMX9_USBDEV_ENDPTSETUPSTAT_OFFSET)); + + imx9_putreg(priv, IMX9_USBDEV_ENDPTCOMPLETE_OFFSET, + imx9_getreg(priv, IMX9_USBDEV_ENDPTCOMPLETE_OFFSET)); + + /* Wait for all prime operations to have completed and then flush all + * DTDs + */ + + while (imx9_getreg(priv, IMX9_USBDEV_ENDPTPRIME_OFFSET) != 0); + + imx9_putreg(priv, IMX9_USBDEV_ENDPTFLUSH_OFFSET, IMX9_ENDPTMASK_ALL); + + while (imx9_getreg(priv, IMX9_USBDEV_ENDPTFLUSH_OFFSET)); + + /* Reset endpoints */ + + for (epphy = 0; epphy < IMX9_NPHYSENDPOINTS; epphy++) + { + struct imx9_ep_s *privep = &priv->eplist[epphy]; + + imx9_cancelrequests(privep, -ESHUTDOWN); + + /* Reset endpoint status */ + + privep->stalled = false; + } + + /* Tell the class driver that we are disconnected. The class + * driver should then accept any new configurations. + */ + + if (priv->driver) + { + CLASS_DISCONNECT(priv->driver, &priv->usbdev); + } + + /* Set the interrupt Threshold control interval to 0 */ + + imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, USBDEV_USBCMD_ITC_MASK, + USBDEV_USBCMD_ITCIMME); + + /* Zero out the Endpoint queue heads */ + + memset ((void *)priv->qh, 0, sizeof(priv->qh)); + memset ((void *)priv->td, 0, sizeof(priv->td)); + + up_clean_dcache((uintptr_t)priv->qh, + (uintptr_t)priv->qh + sizeof(priv->qh)); + up_clean_dcache((uintptr_t)priv->td, + (uintptr_t)priv->td + sizeof(priv->td)); + + /* Set USB address to 0 */ + + imx9_set_address(priv, 0); + + /* Initialise the Enpoint List Address */ + + imx9_putreg(priv, IMX9_USBDEV_ENDPOINTLIST_OFFSET, + (uint32_t)(uintptr_t)priv->qh); + + /* EndPoint 0 initialization */ + + imx9_ep0configure(priv); + + /* Enable Device interrupts */ + + imx9_putreg(priv, IMX9_USBDEV_USBINTR_OFFSET, + USB_FRAME_INT | USB_ERROR_INT | USBDEV_USBINTR_NAKE | + USBDEV_USBINTR_SLE | USBDEV_USBINTR_URE | USBDEV_USBINTR_PCE | + USBDEV_USBINTR_UE); +} + +/**************************************************************************** + * Name: imx9_setstate + * + * Description: + * Sets the EP0 state and manages the NAK interrupts + * + ****************************************************************************/ + +static inline void imx9_ep0state(struct imx9_usb_s *priv, + uint16_t state) +{ + priv->ep0.state = state; + + switch (state) + { + case EP0STATE_WAIT_NAK_IN: + imx9_putreg(priv, IMX9_USBDEV_ENDPTNAKEN_OFFSET, + IMX9_ENDPTMASK(IMX9_EP0_IN)); + break; + + case EP0STATE_WAIT_NAK_OUT: + imx9_putreg(priv, IMX9_USBDEV_ENDPTNAKEN_OFFSET, + IMX9_ENDPTMASK(IMX9_EP0_OUT)); + break; + + default: + imx9_putreg(priv, IMX9_USBDEV_ENDPTNAKEN_OFFSET, 0); + break; + } +} + +/**************************************************************************** + * Name: imx9_ep0setup + * + * Description: + * USB Ctrl EP Setup Event. This is logically part of the USB interrupt + * handler. This event occurs when a setup packet is receive on EP0 OUT. + * + ****************************************************************************/ + +static inline void imx9_ep0setup(struct imx9_usb_s *priv) +{ + struct imx9_ep_s *privep; + struct usb_ctrlreq_s *ctrl; + uint16_t value; + uint16_t index; + uint16_t len; + + ctrl = &priv->ep0.ctrl; + + /* Terminate any pending requests - since all DTDs will have been retired + * because of the setup packet. + */ + + imx9_cancelrequests(&priv->eplist[IMX9_EP0_OUT], -EPROTO); + imx9_cancelrequests(&priv->eplist[IMX9_EP0_IN], -EPROTO); + + /* Assume NOT stalled */ + + priv->eplist[IMX9_EP0_OUT].stalled = false; + priv->eplist[IMX9_EP0_IN].stalled = false; + priv->stalled = false; + + /* Read EP0 setup data */ + + imx9_readsetup(priv, IMX9_EP0_OUT, ctrl); + + /* And extract the little-endian 16-bit values to host order */ + + value = GETUINT16(ctrl->value); + index = GETUINT16(ctrl->index); + len = GETUINT16(ctrl->len); + + priv->ep0.buf_len = len; + + uinfo("type=%02x req=%02x value=%04x index=%04x len=%04x\n", + ctrl->type, ctrl->req, value, index, len); + + /* Starting a control request - update state */ + + if (ctrl->type & USB_REQ_DIR_IN) + { + imx9_ep0state(priv, EP0STATE_SETUP_IN); + } + else + { + imx9_ep0state(priv, EP0STATE_SETUP_OUT); + + if (len > 0) + { + imx9_ep0state(priv, EP0STATE_SHORTREAD); + imx9_ep0xfer(priv, IMX9_EP0_OUT, priv->ep0.buf, len); + return; + } + } + + /* Dispatch any non-standard requests */ + + if ((ctrl->type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) + { + imx9_dispatchrequest(priv, ctrl); + } + else + { + /* Handle standard request. Pick off the things of interest to the USB + * device controller driver; pass what is left to the class driver. + */ + + switch (ctrl->req) + { + case USB_REQ_GETSTATUS: + { + /* type: device-to-host; recipient = device, interface, endpoint + * value: 0 + * index: zero interface endpoint + * len: 2; data = status + */ + + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_GETSTATUS), 0); + if (!priv->paddrset || len != 2 || + (ctrl->type & USB_REQ_DIR_IN) == 0 || value != 0) + { + priv->stalled = true; + } + else + { + switch (ctrl->type & USB_REQ_RECIPIENT_MASK) + { + case USB_REQ_RECIPIENT_ENDPOINT: + { + usbtrace( + TRACE_INTDECODE(IMX9_TRACEINTID_EPGETSTATUS), 0); + privep = imx9_epfindbyaddr(priv, index); + if (!privep) + { + usbtrace( + TRACE_DEVERROR(IMX9_TRACEERR_BADEPGETSTATUS), + 0); + priv->stalled = true; + } + else + { + if (privep->stalled) + { + priv->ep0.buf[0] = 1; /* Stalled */ + } + else + { + priv->ep0.buf[0] = 0; /* Not stalled */ + } + + priv->ep0.buf[1] = 0; + + imx9_ep0xfer(priv, IMX9_EP0_IN, priv->ep0.buf, 2); + imx9_ep0state(priv, EP0STATE_SHORTWRITE); + } + } + break; + + case USB_REQ_RECIPIENT_DEVICE: + { + if (index == 0) + { + usbtrace( + TRACE_INTDECODE(IMX9_TRACEINTID_DEVGETSTATUS), + 0); + + /* Features: Remote Wakeup=YES; selfpowered=? */ + + priv->ep0.buf[0] = + (priv->selfpowered << USB_FEATURE_SELFPOWERED) | + (1 << USB_FEATURE_REMOTEWAKEUP); + priv->ep0.buf[1] = 0; + + imx9_ep0xfer(priv, IMX9_EP0_IN, priv->ep0.buf, 2); + imx9_ep0state(priv, EP0STATE_SHORTWRITE); + } + else + { + usbtrace( + TRACE_DEVERROR(IMX9_TRACEERR_BADDEVGETSTATUS), + 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_RECIPIENT_INTERFACE: + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_IFGETSTATUS), + 0); + priv->ep0.buf[0] = 0; + priv->ep0.buf[1] = 0; + + imx9_ep0xfer(priv, IMX9_EP0_IN, priv->ep0.buf, 2); + imx9_ep0state(priv, EP0STATE_SHORTWRITE); + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADGETSTATUS), + 0); + priv->stalled = true; + } + break; + } + } + } + break; + + case USB_REQ_CLEARFEATURE: + { + /* type: host-to-device; recipient = device, interface or endpoint + * value: feature selector + * index: zero interface endpoint; + * len: zero, data = none + */ + + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_CLEARFEATURE), 0); + if ((ctrl->type & USB_REQ_RECIPIENT_MASK) != + USB_REQ_RECIPIENT_ENDPOINT) + { + imx9_dispatchrequest(priv, ctrl); + } + else if (priv->paddrset != 0 && + value == USB_FEATURE_ENDPOINTHALT && + len == 0 && (privep = imx9_epfindbyaddr(priv, index)) != NULL) + { + imx9_epstall(&privep->ep, true); + imx9_ep0state(priv, EP0STATE_WAIT_NAK_IN); + } + else + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADCLEARFEATURE), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETFEATURE: + { + /* type: host-to-device; recipient = device, interface, endpoint + * value: feature selector + * index: zero interface endpoint; + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_SETFEATURE), 0); + if (((ctrl->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE) && value == USB_FEATURE_TESTMODE) + { + uinfo("test mode: %d\n", index); + } + else if ((ctrl->type & USB_REQ_RECIPIENT_MASK) != + USB_REQ_RECIPIENT_ENDPOINT) + { + imx9_dispatchrequest(priv, ctrl); + } + else if (priv->paddrset != 0 && + value == USB_FEATURE_ENDPOINTHALT && + len == 0 && (privep = imx9_epfindbyaddr(priv, index)) != NULL) + { + imx9_epstall(&privep->ep, false); + imx9_ep0state(priv, EP0STATE_WAIT_NAK_IN); + } + else + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADSETFEATURE), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETADDRESS: + { + /* type: host-to-device; recipient = device + * value: device address + * index: 0 + * len: 0; data = none + */ + + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EP0SETUPSETADDRESS), + value); + if (((ctrl->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE) && + index == 0 && len == 0 && value < 128) + { + /* Save the address. We cannot actually change to the next + * address until the completion of the status phase. + */ + + priv->paddr = ctrl->value[0]; + priv->paddrset = false; + imx9_ep0state(priv, EP0STATE_WAIT_NAK_IN); + } + else + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADSETADDRESS), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETDESCRIPTOR: + /* type: device-to-host; recipient = device + * value: descriptor type and index + * index: 0 or language ID; + * len: descriptor len; data = descriptor + */ + + case USB_REQ_SETDESCRIPTOR: + /* type: host-to-device; recipient = device + * value: descriptor type and index + * index: 0 or language ID; + * len: descriptor len; data = descriptor + */ + + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_GETSETDESC), 0); + if ((ctrl->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE) + { + imx9_dispatchrequest(priv, ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADGETSETDESC), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETCONFIGURATION: + /* type: device-to-host; recipient = device + * value: 0; + * index: 0; + * len: 1; data = configuration value + */ + + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_GETCONFIG), 0); + if (priv->paddrset && + ((ctrl->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE) && + value == 0 && index == 0 && len == 1) + { + imx9_dispatchrequest(priv, ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADGETCONFIG), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_SETCONFIGURATION: + /* type: host-to-device; recipient = device + * value: configuration value + * index: 0; + * len: 0; data = none + */ + + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_SETCONFIG), 0); + if (((ctrl->type & USB_REQ_RECIPIENT_MASK) == + USB_REQ_RECIPIENT_DEVICE) && index == 0 && len == 0) + { + imx9_dispatchrequest(priv, ctrl); + } + else + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADSETCONFIG), 0); + priv->stalled = true; + } + } + break; + + case USB_REQ_GETINTERFACE: + /* type: device-to-host; recipient = interface + * value: 0 + * index: interface; + * len: 1; data = alt interface + */ + + case USB_REQ_SETINTERFACE: + /* type: host-to-device; recipient = interface + * value: alternate setting + * index: interface; + * len: 0; data = none + */ + + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_GETSETIF), 0); + imx9_dispatchrequest(priv, ctrl); + } + break; + + case USB_REQ_SYNCHFRAME: + /* type: device-to-host; recipient = endpoint + * value: 0 + * index: endpoint; + * len: 2; data = frame number + */ + + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_SYNCHFRAME), 0); + } + break; + + default: + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_INVALIDCTRLREQ), 0); + priv->stalled = true; + } + break; + } + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_EP0SETUPSTALLED), + priv->ep0.state); + imx9_epstall(&priv->eplist[IMX9_EP0_IN].ep, false); + imx9_epstall(&priv->eplist[IMX9_EP0_OUT].ep, false); + } +} + +/**************************************************************************** + * Name: imx9_ep0complete + * + * Description: + * Transfer complete handler for Endpoint 0 + * + ****************************************************************************/ + +static void imx9_ep0complete(struct imx9_usb_s *priv, uint8_t epphy) +{ + struct imx9_ep_s *privep = &priv->eplist[epphy]; + + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EP0COMPLETE), + (uint16_t)priv->ep0.state); + + switch (priv->ep0.state) + { + case EP0STATE_DATA_IN: + if (imx9_rqempty(privep)) + { + return; + } + + if (imx9_epcomplete(priv, epphy)) + { + imx9_ep0state(priv, EP0STATE_WAIT_NAK_OUT); + } + break; + + case EP0STATE_DATA_OUT: + if (imx9_rqempty(privep)) + { + return; + } + + if (imx9_epcomplete(priv, epphy)) + { + imx9_ep0state(priv, EP0STATE_WAIT_NAK_IN); + } + break; + + case EP0STATE_SHORTREAD: + imx9_dispatchrequest(priv, &priv->ep0.ctrl); + imx9_ep0state(priv, EP0STATE_WAIT_NAK_IN); + break; + + case EP0STATE_SHORTWRITE: + imx9_ep0state(priv, EP0STATE_WAIT_NAK_OUT); + break; + + case EP0STATE_WAIT_STATUS_IN: + imx9_ep0state(priv, EP0STATE_IDLE); + + /* If we've received a SETADDRESS packet, then we set the address + * now that the status phase has completed + */ + + if (!priv->paddrset && priv->paddr != 0) + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EP0INSETADDRESS), + (uint16_t)priv->paddr); + imx9_set_address(priv, priv->paddr); + } + + break; + + case EP0STATE_WAIT_STATUS_OUT: + imx9_ep0state(priv, EP0STATE_IDLE); + break; + + default: +#ifdef CONFIG_DEBUG_FEATURES + DEBUGASSERT(priv->ep0.state != EP0STATE_DATA_IN && + priv->ep0.state != EP0STATE_DATA_OUT && + priv->ep0.state != EP0STATE_SHORTWRITE && + priv->ep0.state != EP0STATE_WAIT_STATUS_IN && + priv->ep0.state != EP0STATE_WAIT_STATUS_OUT); +#endif + priv->stalled = true; + break; + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_EP0SETUPSTALLED), + priv->ep0.state); + imx9_epstall(&priv->eplist[IMX9_EP0_IN].ep, false); + imx9_epstall(&priv->eplist[IMX9_EP0_OUT].ep, false); + } +} + +/**************************************************************************** + * Name: imx9_ep0nak + * + * Description: + * Handle a NAK interrupt on EP0 + * + ****************************************************************************/ + +static void imx9_ep0nak(struct imx9_usb_s *priv, uint8_t epphy) +{ + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EP0NAK), + (uint16_t)priv->ep0.state); + + switch (priv->ep0.state) + { + case EP0STATE_WAIT_NAK_IN: + imx9_ep0xfer(priv, IMX9_EP0_IN, NULL, 0); + imx9_ep0state(priv, EP0STATE_WAIT_STATUS_IN); + break; + + case EP0STATE_WAIT_NAK_OUT: + imx9_ep0xfer(priv, IMX9_EP0_OUT, NULL, 0); + imx9_ep0state(priv, EP0STATE_WAIT_STATUS_OUT); + break; + + default: +#ifdef CONFIG_DEBUG_FEATURES + DEBUGASSERT(priv->ep0.state != EP0STATE_WAIT_NAK_IN && + priv->ep0.state != EP0STATE_WAIT_NAK_OUT); +#endif + priv->stalled = true; + break; + } + + if (priv->stalled) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_EP0SETUPSTALLED), + priv->ep0.state); + imx9_epstall(&priv->eplist[IMX9_EP0_IN].ep, false); + imx9_epstall(&priv->eplist[IMX9_EP0_OUT].ep, false); + } +} + +/**************************************************************************** + * Name: imx9_epcomplete + * + * Description: + * Transfer complete handler for Endpoints other than 0 + * returns whether the request at the head has completed + * + ****************************************************************************/ + +bool imx9_epcomplete(struct imx9_usb_s *priv, uint8_t epphy) +{ + struct imx9_ep_s *privep = &priv->eplist[epphy]; + struct imx9_req_s *privreq = privep->head; + struct imx9_dtd_s *dtd = &priv->td[epphy]; + + if (privreq == NULL) /* This shouldn't really happen */ + { + if (IMX9_EPPHYOUT(privep->epphy)) + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EPINQEMPTY), 0); + } + else + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EPOUTQEMPTY), 0); + } + + return true; + } + + /* Make sure we have updated data after the DMA transfer. */ + + up_invalidate_dcache((uintptr_t)dtd, + (uintptr_t)dtd + sizeof(struct imx9_dtd_s)); + up_invalidate_dcache((uintptr_t)dtd->buffer0, + (uintptr_t)dtd->buffer0 + dtd->xfer_len); + + int xfrd = dtd->xfer_len - (dtd->config >> 16); + + privreq->req.xfrd += xfrd; + + bool complete = true; + if (IMX9_EPPHYOUT(privep->epphy)) + { + /* read(OUT) completes when request filled, or a short transfer is + * received + */ + + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EPIN), complete); + } + else + { + /* write(IN) completes when request finished, unless we need to + * terminate with a ZLP + */ + + bool need_zlp = (xfrd == privep->ep.maxpacket) && + ((privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0); + + complete = (privreq->req.xfrd >= privreq->req.len && !need_zlp); + + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EPOUT), complete); + } + + /* If the transfer is complete, then dequeue and progress any further + * queued requests + */ + + if (complete) + { + privreq = imx9_rqdequeue(privep); + } + + if (!imx9_rqempty(privep)) + { + imx9_progressep(privep); + } + + /* Now it's safe to call the completion callback as it may well submit a + * new request + */ + + if (complete) + { + usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd); + imx9_reqcomplete(privep, privreq, OK); + } + + return complete; +} + +/**************************************************************************** + * Name: imx9_usbinterrupt + * + * Description: + * USB interrupt handler + * + ****************************************************************************/ + +static int imx9_usbinterrupt(int irq, void *context, void *arg) +{ + struct imx9_usb_s *priv = (struct imx9_usb_s *)arg; + uint32_t disr; + uint32_t portsc1; + uint32_t n; + + usbtrace(TRACE_INTENTRY(IMX9_TRACEINTID_USB), 0); + + /* Read the interrupts and then clear them */ + + disr = imx9_getreg(priv, IMX9_USBDEV_USBSTS_OFFSET); + imx9_putreg(priv, IMX9_USBDEV_USBSTS_OFFSET, disr); + + if (disr & USBDEV_USBSTS_URI) + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_DEVRESET), 0); + + imx9_usbreset(priv); + + usbtrace(TRACE_INTEXIT(IMX9_TRACEINTID_USB), 0); + return OK; + } + + /* When the device controller enters a suspend state from an active state, + * the SLI bit will be set to a one. + */ + + if (!priv->suspended && (disr & USBDEV_USBSTS_SLI) != 0) + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_SUSPENDED), 0); + + /* Inform the Class driver of the suspend event */ + + priv->suspended = 1; + if (priv->driver) + { + CLASS_SUSPEND(priv->driver, &priv->usbdev); + } + + /* TODO: Perform power management operations here. */ + } + + /* The device controller clears the SLI bit upon exiting from a suspend + * state. This bit can also be cleared by software writing a one to it. + */ + + else if (priv->suspended && (disr & USBDEV_USBSTS_SLI) == 0) + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_RESUMED), 0); + + /* Inform the Class driver of the resume event */ + + priv->suspended = 0; + if (priv->driver) + { + CLASS_RESUME(priv->driver, &priv->usbdev); + } + + /* TODO: Perform power management operations here. */ + } + + if (disr & USBDEV_USBSTS_PCI) + { + portsc1 = imx9_getreg(priv, IMX9_USBDEV_PORTSC1_OFFSET); + + if (portsc1 & USBDEV_PRTSC1_HSP) + priv->usbdev.speed = USB_SPEED_HIGH; + else + priv->usbdev.speed = USB_SPEED_FULL; + + if (portsc1 & USBDEV_PRTSC1_FPR) + { + /* FIXME: this occurs because of a J-to-K transition detected + * while the port is in SUSPEND state - presumambly this + * is where the host is resuming the device? + * + * - but do we need to "ack" the interrupt + */ + } + } + +#ifdef CONFIG_IMX9_USB_FRAME_INTERRUPT + if (disr & USBDEV_USBSTS_SRI) + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_FRAME), 0); + + uint32_t frindex = imx9_getreg(IMX9_USB_FRINDEX); + uint16_t frame_num = + (frindex & USBDEV_FRINDEX_LFN_MASK) >> USBDEV_FRINDEX_LFN_SHIFT; + + priv->sof = frame_num; + } +#endif + + if (disr & USBDEV_USBSTS_UEI) + { + /* FIXME: these occur when a transfer results in an error condition + * it is set alongside USBINT if the DTD also had its IOC + * bit set. + */ + } + + if (disr & USBDEV_USBSTS_UI) + { + /* Handle completion interrupts */ + + uint32_t mask = imx9_getreg(priv, IMX9_USBDEV_ENDPTCOMPLETE_OFFSET); + + if (mask) + { + /* Clear any NAK interrupt and completion interrupts */ + + imx9_putreg(priv, IMX9_USBDEV_ENDPTNAK_OFFSET, mask); + imx9_putreg(priv, IMX9_USBDEV_ENDPTCOMPLETE_OFFSET, mask); + + if (mask & IMX9_ENDPTMASK(0)) + { + imx9_ep0complete(priv, 0); + } + + if (mask & IMX9_ENDPTMASK(1)) + { + imx9_ep0complete(priv, 1); + } + + for (n = 1; n < IMX9_NLOGENDPOINTS; n++) + { + if (mask & IMX9_ENDPTMASK((n << 1))) + { + imx9_epcomplete(priv, (n << 1)); + } + + if (mask & IMX9_ENDPTMASK((n << 1)+1)) + { + imx9_epcomplete(priv, (n << 1)+1); + } + } + } + + /* Handle setup interrupts */ + + uint32_t setupstat = imx9_getreg(priv, + IMX9_USBDEV_ENDPTSETUPSTAT_OFFSET); + if (setupstat) + { + /* Clear the endpoint complete CTRL OUT and IN when a Setup is + * received + */ + + imx9_putreg(priv, IMX9_USBDEV_ENDPTCOMPLETE_OFFSET, + IMX9_ENDPTMASK(IMX9_EP0_IN) | + IMX9_ENDPTMASK(IMX9_EP0_OUT)); + + if (setupstat & IMX9_ENDPTMASK(IMX9_EP0_OUT)) + { + usbtrace(TRACE_INTDECODE(IMX9_TRACEINTID_EP0SETUP), + setupstat); + imx9_ep0setup(priv); + } + } + } + + if (disr & USBDEV_USBSTS_NAKI) + { + uint32_t pending = imx9_getreg(priv, IMX9_USBDEV_ENDPTNAK_OFFSET) & + imx9_getreg(priv, IMX9_USBDEV_ENDPTNAKEN_OFFSET); + + if (pending) + { + /* We shouldn't see NAK interrupts except on Endpoint 0 */ + + if (pending & IMX9_ENDPTMASK(0)) + { + imx9_ep0nak(priv, 0); + } + + if (pending & IMX9_ENDPTMASK(1)) + { + imx9_ep0nak(priv, 1); + } + } + + /* Clear the interrupts */ + + imx9_putreg(priv, IMX9_USBDEV_ENDPTNAK_OFFSET, pending); + } + + usbtrace(TRACE_INTEXIT(IMX9_TRACEINTID_USB), 0); + return OK; +} + +/**************************************************************************** + * Endpoint operations + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_epconfigure + * + * Description: + * Configure endpoint, making it usable + * + * Input Parameters: + * ep - the struct usbdev_ep_s instance obtained from allocep() + * desc - A struct usb_epdesc_s instance describing the endpoint + * last - true if this is the last endpoint to be configured. Some + * hardware needs to take special action when all of the endpoints + * have been configured. + * + ****************************************************************************/ + +static int imx9_epconfigure(struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, + bool last) +{ + struct imx9_ep_s *privep = (struct imx9_ep_s *)ep; + struct imx9_usb_s *priv = privep->dev; + struct imx9_dqh_s *dqh = &priv->qh[privep->epphy]; + + usbtrace(TRACE_EPCONFIGURE, privep->epphy); + DEBUGASSERT(desc->addr == ep->eplog); + + /* Initialise EP capabilities */ + + uint16_t maxsize = GETUINT16(desc->mxpacketsize); + if ((desc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_ISOC) + { + dqh->capability = (DQH_CAPABILITY_MAX_PACKET(maxsize) | + DQH_CAPABILITY_IOS | + DQH_CAPABILITY_ZLT); + } + else + { + dqh->capability = (DQH_CAPABILITY_MAX_PACKET(maxsize) | + DQH_CAPABILITY_ZLT); + } + + up_clean_dcache((uintptr_t)dqh, + (uintptr_t)dqh + sizeof(struct imx9_dqh_s)); + + /* Setup Endpoint Control Register */ + + if (IMX9_EPPHYIN(privep->epphy)) + { + /* Reset the data toggles */ + + uint32_t cfg = USBDEV_ENDPTCTRL_TXR; + + /* Set the endpoint type */ + + switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK) + { + case USB_EP_ATTR_XFER_CONTROL: + cfg |= USBDEV_ENDPTCTRL_TXT_CTRL; break; + case USB_EP_ATTR_XFER_ISOC: + cfg |= USBDEV_ENDPTCTRL_TXT_ISOC; break; + case USB_EP_ATTR_XFER_BULK: + cfg |= USBDEV_ENDPTCTRL_TXT_BULK; break; + case USB_EP_ATTR_XFER_INT: + cfg |= USBDEV_ENDPTCTRL_TXT_INTR; break; + } + + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL_OFFSET(privep->epphy >> 1), + 0xffff0000, cfg); + } + else + { + /* Reset the data toggles */ + + uint32_t cfg = USBDEV_ENDPTCTRL_RXR; + + /* Set the endpoint type */ + + switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK) + { + case USB_EP_ATTR_XFER_CONTROL: + cfg |= USBDEV_ENDPTCTRL_RXT_CTRL; break; + case USB_EP_ATTR_XFER_ISOC: + cfg |= USBDEV_ENDPTCTRL_RXT_ISOC; break; + case USB_EP_ATTR_XFER_BULK: + cfg |= USBDEV_ENDPTCTRL_RXT_BULK; break; + case USB_EP_ATTR_XFER_INT: + cfg |= USBDEV_ENDPTCTRL_RXT_INTR; break; + } + + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL_OFFSET(privep->epphy >> 1), + 0xffff0000, cfg); + } + + /* Reset endpoint status */ + + privep->stalled = false; + + /* Enable the endpoint */ + + if (IMX9_EPPHYIN(privep->epphy)) + { + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL_OFFSET(privep->epphy >> 1), + 0, USBDEV_ENDPTCTRL_TXE); + } + else + { + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL_OFFSET(privep->epphy >> 1), + 0, USBDEV_ENDPTCTRL_RXE); + } + + return OK; +} + +/**************************************************************************** + * Name: imx9_epdisable + * + * Description: + * The endpoint will no longer be used + * + ****************************************************************************/ + +static int imx9_epdisable(struct usbdev_ep_s *ep) +{ + struct imx9_ep_s *privep = (struct imx9_ep_s *)ep; + struct imx9_usb_s *priv = privep->dev; + irqstate_t flags; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPDISABLE, privep->epphy); + + flags = enter_critical_section(); + + /* Disable Endpoint */ + + if (IMX9_EPPHYIN(privep->epphy)) + { + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL_OFFSET(privep->epphy >> 1), + USBDEV_ENDPTCTRL_TXE, 0); + } + else + { + imx9_modifyreg(priv, IMX9_USBDEV_ENDPTCTRL_OFFSET(privep->epphy >> 1), + USBDEV_ENDPTCTRL_RXE, 0); + } + + privep->stalled = true; + + /* Cancel any ongoing activity */ + + imx9_cancelrequests(privep, -ESHUTDOWN); + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: imx9_epallocreq + * + * Description: + * Allocate an I/O request + * + ****************************************************************************/ + +static struct usbdev_req_s *imx9_epallocreq(struct usbdev_ep_s *ep) +{ + struct imx9_req_s *privreq; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_INVALIDPARMS), 0); + return NULL; + } +#endif + + usbtrace(TRACE_EPALLOCREQ, ((struct imx9_ep_s *)ep)->epphy); + + privreq = kmm_malloc(sizeof(struct imx9_req_s)); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_ALLOCFAIL), 0); + return NULL; + } + + memset(privreq, 0, sizeof(struct imx9_req_s)); + return &privreq->req; +} + +/**************************************************************************** + * Name: imx9_epfreereq + * + * Description: + * Free an I/O request + * + ****************************************************************************/ + +static void imx9_epfreereq(struct usbdev_ep_s *ep, + struct usbdev_req_s *req) +{ + struct imx9_req_s *privreq = (struct imx9_req_s *)req; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_INVALIDPARMS), 0); + return; + } +#endif + + usbtrace(TRACE_EPFREEREQ, ((struct imx9_ep_s *)ep)->epphy); + kmm_free(privreq); +} + +/**************************************************************************** + * Name: imx9_epallocbuffer + * + * Description: + * Allocate an I/O buffer + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_DMA +static void *imx9_epallocbuffer(struct usbdev_ep_s *ep, uint16_t bytes) +{ + /* The USB peripheral DMA is very forgiving, as the dTD allows the buffer + * to start at any address. Hence, no need for alignment. + */ + + struct imx9_ep_s *privep = (struct imx9_ep_s *)ep; + UNUSED(privep); + + usbtrace(TRACE_EPALLOCBUFFER, privep->epphy); +#ifdef CONFIG_USBDEV_DMAMEMORY + return usbdev_dma_alloc(bytes); +#else + return cache_aligned_alloc(bytes); +#endif +} +#endif + +/**************************************************************************** + * Name: imx9_epfreebuffer + * + * Description: + * Free an I/O buffer + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_DMA +static void imx9_epfreebuffer(struct usbdev_ep_s *ep, void *buf) +{ + struct imx9_ep_s *privep = (struct imx9_ep_s *)ep; + UNUSED(privep); + + usbtrace(TRACE_EPFREEBUFFER, privep->epphy); + +#ifdef CONFIG_USBDEV_DMAMEMORY + usbdev_dma_free(buf); +#else + kmm_free(buf); +#endif +} +#endif + +/**************************************************************************** + * Name: imx9_epsubmit + * + * Description: + * Submit an I/O request to the endpoint + * + ****************************************************************************/ + +static int imx9_epsubmit(struct usbdev_ep_s *ep, + struct usbdev_req_s *req) +{ + struct imx9_req_s *privreq = (struct imx9_req_s *)req; + struct imx9_ep_s *privep = (struct imx9_ep_s *)ep; + struct imx9_usb_s *priv; + irqstate_t flags; + int ret = OK; + +#ifdef CONFIG_DEBUG_FEATURES + if (!req || !req->callback || !req->buf || !ep) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_INVALIDPARMS), 0); + uinfo("req=%p callback=%p buf=%p ep=%p\n", req, + req->callback, req->buf, ep); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPSUBMIT, privep->epphy); + priv = privep->dev; + + if (!priv->driver || priv->usbdev.speed == USB_SPEED_UNKNOWN) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_NOTCONFIGURED), + priv->usbdev.speed); + return -ESHUTDOWN; + } + + /* Handle the request from the class driver */ + + req->result = -EINPROGRESS; + req->xfrd = 0; + + /* Disable Interrupts */ + + flags = enter_critical_section(); + + /* If we are stalled, then drop all requests on the floor */ + + if (privep->stalled) + { + ret = -EBUSY; + } + else + { + /* Add the new request to the request queue for the endpoint */ + + if (IMX9_EPPHYIN(privep->epphy)) + { + usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len); + } + else + { + usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len); + } + + if (imx9_rqenqueue(privep, privreq)) + { + imx9_progressep(privep); + } + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: imx9_epcancel + * + * Description: + * Cancel an I/O request previously sent to an endpoint + * + ****************************************************************************/ + +static int imx9_epcancel(struct usbdev_ep_s *ep, + struct usbdev_req_s *req) +{ + struct imx9_ep_s *privep = (struct imx9_ep_s *)ep; + irqstate_t flags; + +#ifdef CONFIG_DEBUG_FEATURES + if (!ep || !req) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } +#endif + + usbtrace(TRACE_EPCANCEL, privep->epphy); + + flags = enter_critical_section(); + + /* FIXME: if the request is the first, then we need to flush the EP + * otherwise just remove it from the list + * + * but ... all other implementations cancel all requests ... + */ + + imx9_cancelrequests(privep, -ESHUTDOWN); + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: imx9_epstall + * + * Description: + * Stall or resume and endpoint + * + ****************************************************************************/ + +static int imx9_epstall(struct usbdev_ep_s *ep, bool resume) +{ + struct imx9_ep_s *privep = (struct imx9_ep_s *)ep; + struct imx9_usb_s *priv = privep->dev; + irqstate_t flags; + + /* STALL or RESUME the endpoint */ + + flags = enter_critical_section(); + usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, privep->epphy); + + uint32_t offs = IMX9_USBDEV_ENDPTCTRL_OFFSET(privep->epphy >> 1); + uint32_t ctrl_xs = IMX9_EPPHYIN(privep->epphy) ? + USBDEV_ENDPTCTRL_TXS : USBDEV_ENDPTCTRL_RXS; + uint32_t ctrl_xr = IMX9_EPPHYIN(privep->epphy) ? + USBDEV_ENDPTCTRL_TXR : USBDEV_ENDPTCTRL_RXR; + + if (resume) + { + privep->stalled = false; + + /* Clear stall and reset the data toggle */ + + imx9_modifyreg(priv, offs, ctrl_xs | ctrl_xr, ctrl_xr); + } + else + { + privep->stalled = true; + + imx9_modifyreg(priv, offs, 0, ctrl_xs); + } + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Device operations + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_allocep + * + * Description: + * Allocate an endpoint matching the parameters. + * + * Input Parameters: + * eplog - 7-bit logical endpoint number (direction bit ignored). Zero + * means that any endpoint matching the other requirements will + * suffice. The assigned endpoint can be found in the eplog field. + * in - true: IN (device-to-host) endpoint requested + * eptype - Endpoint type. One of {USB_EP_ATTR_XFER_ISOC, + * USB_EP_ATTR_XFER_BULK, USB_EP_ATTR_XFER_INT} + * + ****************************************************************************/ + +static struct usbdev_ep_s *imx9_allocep(struct usbdev_s *dev, + uint8_t eplog, + bool in, uint8_t eptype) +{ + struct imx9_usb_s *priv = (struct imx9_usb_s *)dev; + uint32_t epset = IMX9_EPALLSET & ~IMX9_EPCTRLSET; + irqstate_t flags; + int epndx = 0; + + usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog); + + /* Ignore any direction bits in the logical address */ + + eplog = USB_EPNO(eplog); + + /* A logical address of 0 means that any endpoint will do */ + + if (eplog > 0) + { + /* Otherwise, we will return the endpoint structure only for the + * requested 'logical' endpoint. All of the other checks will still be + * performed. + * + * First, verify that the logical endpoint is in the range supported by + * by the hardware. + */ + + if (eplog >= IMX9_NLOGENDPOINTS) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADEPNO), (uint16_t)eplog); + return NULL; + } + + /* Convert the logical address to a physical OUT endpoint address and + * remove all of the candidate endpoints from the bitset except for the + * the IN/OUT pair for this logical address. + */ + + epset &= 3 << (eplog << 1); + } + + /* Get the subset matching the requested direction */ + + if (in) + { + epset &= IMX9_EPINSET; + } + else + { + epset &= IMX9_EPOUTSET; + } + + /* Get the subset matching the requested type */ + + switch (eptype) + { + case USB_EP_ATTR_XFER_INT: /* Interrupt endpoint */ + epset &= IMX9_EPINTRSET; + break; + + case USB_EP_ATTR_XFER_BULK: /* Bulk endpoint */ + epset &= IMX9_EPBULKSET; + break; + + case USB_EP_ATTR_XFER_ISOC: /* Isochronous endpoint */ + epset &= IMX9_EPISOCSET; + break; + + case USB_EP_ATTR_XFER_CONTROL: /* Control endpoint -- not a valid choice */ + default: + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BADEPTYPE), (uint16_t)eptype); + return NULL; + } + + /* Is the resulting endpoint supported by the IMX9? */ + + if (epset) + { + /* Yes.. now see if any of the request endpoints are available */ + + flags = enter_critical_section(); + epset &= priv->epavail; + if (epset) + { + /* Select the lowest bit in the set of matching, available + * endpoints + */ + + for (epndx = 2; epndx < IMX9_NPHYSENDPOINTS; epndx++) + { + uint32_t bit = 1 << epndx; + if ((epset & bit) != 0) + { + /* Mark endpoint no longer available */ + + priv->epavail &= ~bit; + leave_critical_section(flags); + + /* And return the pointer to the standard endpoint + * structure + */ + + return &priv->eplist[epndx].ep; + } + } + + /* Shouldn't get here */ + } + + leave_critical_section(flags); + } + + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_NOEP), (uint16_t)eplog); + return NULL; +} + +/**************************************************************************** + * Name: imx9_freeep + * + * Description: + * Free the previously allocated endpoint + * + ****************************************************************************/ + +static void imx9_freeep(struct usbdev_s *dev, + struct usbdev_ep_s *ep) +{ + struct imx9_usb_s *priv = (struct imx9_usb_s *)dev; + struct imx9_ep_s *privep = (struct imx9_ep_s *)ep; + irqstate_t flags; + + usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy); + + if (priv && privep) + { + /* Mark the endpoint as available */ + + flags = enter_critical_section(); + priv->epavail |= (1 << privep->epphy); + leave_critical_section(flags); + } +} + +/**************************************************************************** + * Name: imx9_getframe + * + * Description: + * Returns the current frame number + * + ****************************************************************************/ + +static int imx9_getframe(struct usbdev_s *dev) +{ + struct imx9_usb_s *priv = (struct imx9_usb_s *)dev; + +#ifdef CONFIG_IMX9_USB_FRAME_INTERRUPT + /* Return last valid value of SOF read by the interrupt handler */ + + usbtrace(TRACE_DEVGETFRAME, (uint16_t)priv->sof); + return priv->sof; +#else + uint32_t frindex = imx9_getreg(priv, IMX9_USBDEV_FRINDEX_OFFSET); + uint16_t frame_num = + (frindex & USBDEV_FRINDEX_LFN_MASK) >> USBDEV_FRINDEX_LFN_SHIFT; + + /* Return the last frame number detected by the hardware */ + + usbtrace(TRACE_DEVGETFRAME, frame_num); + + return (int)(frame_num); +#endif +} + +/**************************************************************************** + * Name: imx9_wakeup + * + * Description: + * Tries to wake up the host connected to this device + * + ****************************************************************************/ + +static int imx9_wakeup(struct usbdev_s *dev) +{ + irqstate_t flags; + struct imx9_usb_s *priv = (struct imx9_usb_s *)dev; + + usbtrace(TRACE_DEVWAKEUP, 0); + + flags = enter_critical_section(); + imx9_modifyreg(priv, IMX9_USBDEV_PORTSC1_OFFSET, 0, USBDEV_PRTSC1_FPR); + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: imx9_selfpowered + * + * Description: + * Sets/clears the device selfpowered feature + * + ****************************************************************************/ + +static int imx9_selfpowered(struct usbdev_s *dev, bool selfpowered) +{ + struct imx9_usb_s *priv = (struct imx9_usb_s *)dev; + + usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered); + +#ifdef CONFIG_DEBUG_FEATURES + if (!dev) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_INVALIDPARMS), 0); + return -ENODEV; + } +#endif + + priv->selfpowered = selfpowered; + return OK; +} + +/**************************************************************************** + * Name: imx9_pullup + * + * Description: + * Software-controlled connect to/disconnect from USB host + * + ****************************************************************************/ + +static int imx9_pullup(struct usbdev_s *dev, bool enable) +{ + struct imx9_usb_s *priv = (struct imx9_usb_s *)dev; + + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + irqstate_t flags = enter_critical_section(); + if (enable) + { + imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, 0, USBDEV_USBCMD_RS); + +#ifdef CONFIG_IMX9_USB0DEV_NOVBUS + /* Create a 'false' power event on the USB port so the MAC connects */ + + imx9_modifyreg(priv, IMX9_USBOTG_OTGSC_OFFSET, USBOTG_OTGSC_VD, 0); + imx9_modifyreg(priv, IMX9_USBOTG_OTGSC_OFFSET, 0, USBOTG_OTGSC_VC); +#endif + } + else + { + imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, USBDEV_USBCMD_RS, 0); + } + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_vbus_detect + * + * Description: + * Read the VBUS state from the USB OTG controller. This can be used + * to poll the VBUS state + * + * Input Parameters: + * id: IMX9_USBC1 or IMX9_USBC2 + * + * Returned Value: + * true if VBUS is valid; false otherwise + * + ****************************************************************************/ + +bool imx9_vbus_detect(imx9_usb_id_t id) +{ + int i; + struct imx9_usb_s *priv; + uint32_t otgsc = 0; + + /* Find the correct device to which the driver is bound to */ + + for (i = 0; i < n_usbdevs; i++) + { + if (id == g_usbdev[i].id) + { + break; + } + } + + if (i < n_usbdevs) + { + priv = &g_usbdev[i]; + otgsc = imx9_getreg(priv, IMX9_USBOTG_OTGSC_OFFSET); + } + + return (otgsc & USBOTG_OTGSC_AVV) != 0; +} + +/**************************************************************************** + * Name: arm64_usbinitialize + * + * Description: + * Initialize USB hardware. + * + * Assumptions: + * - This function is called very early in the initialization sequence + * + ****************************************************************************/ + +void arm64_usbinitialize(void) +{ + /* For now, this driver supports just one usb device, either + * USBC1 or USBC2. The configured one is in g_usbdev[0]. + */ + + struct imx9_usb_s *priv = &g_usbdev[0]; + int i; + irqstate_t flags; + + flags = enter_critical_section(); + + /* Initialize the device state structure */ + + priv->usbdev.ops = &g_devops; + priv->usbdev.ep0 = &priv->eplist[IMX9_EP0_IN].ep; + priv->epavail = IMX9_EPALLSET & ~IMX9_EPCTRLSET; + + /* Initialize the endpoint list */ + + for (i = 0; i < IMX9_NPHYSENDPOINTS; i++) + { + uint32_t bit = 1 << i; + + /* Set endpoint operations, reference to driver structure and + * the physical endpoint number (which is just the index to the + * endpoint). + */ + + priv->eplist[i].ep.ops = &g_epops; + priv->eplist[i].dev = priv; + + /* The index, i, is the physical endpoint address; Map this + * to a logical endpoint address usable by the class driver. + */ + + priv->eplist[i].epphy = i; + if (IMX9_EPPHYIN(i)) + { + priv->eplist[i].ep.eplog = IMX9_EPPHYIN2LOG(i); + } + else + { + priv->eplist[i].ep.eplog = IMX9_EPPHYOUT2LOG(i); + } + + /* The maximum packet size may depend on the type of endpoint */ + + if ((IMX9_EPCTRLSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = IMX9_EP0MAXPACKET; + } + else if ((IMX9_EPINTRSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = IMX9_INTRMAXPACKET; + } + else if ((IMX9_EPBULKSET & bit) != 0) + { + priv->eplist[i].ep.maxpacket = IMX9_BULKMAXPACKET; + } + else /* if ((IMX9_EPISOCSET & bit) != 0) */ + { + priv->eplist[i].ep.maxpacket = IMX9_ISOCMAXPACKET; + } + } + + /* Clock gate on */ + + imx9_ccm_gate_on(CCM_LPCG_USB_CONTROLLER, true); + + /* Disable USB interrupts */ + + imx9_putreg(priv, IMX9_USBDEV_USBINTR_OFFSET, 0); + + /* Soft reset PHY and enable clock - not needed for on-chip USB2 phy */ + + /* Disconnect device */ + + imx9_pullup(&priv->usbdev, false); + + /* Reset the controller */ + + imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, 0, USBDEV_USBCMD_RST); + while (imx9_getreg(priv, IMX9_USBDEV_USBCMD_OFFSET) & USBDEV_USBCMD_RST); + + /* Power up the PHY - not needed for on-chip USB2 phy */ + + /* Program the controller to be the USB device controller */ + + imx9_putreg(priv, IMX9_USBDEV_USBMODE_OFFSET, + USBDEV_USBMODE_SDIS | USBDEV_USBMODE_SLOM | + USBDEV_USBMODE_CM_DEVICE); + + /* Attach USB controller interrupt handler */ + + irq_attach(IMX9_IRQ_USB1 + priv->id, imx9_usbinterrupt, priv); + up_enable_irq(IMX9_IRQ_USB1 + priv->id); + + leave_critical_section(flags); + + /* Reset/Re-initialize the USB hardware */ + + imx9_usbreset(priv); +} + +/**************************************************************************** + * Name: arm_usbuninitialize + ****************************************************************************/ + +void arm64_usbuninitialize(void) +{ + struct imx9_usb_s *priv = &g_usbdev[0]; + irqstate_t flags; + + usbtrace(TRACE_DEVUNINIT, 0); + + if (priv->driver) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_DRIVERREGISTERED), 0); + usbdev_unregister(priv->driver); + } + + flags = enter_critical_section(); + + /* Disconnect device */ + + imx9_pullup(&priv->usbdev, false); + priv->usbdev.speed = USB_SPEED_UNKNOWN; + + /* Disable and detach IRQs */ + + up_disable_irq(IMX9_IRQ_USB1 + priv->id); + irq_detach(IMX9_IRQ_USB1 + priv->id); + + /* Reset the controller */ + + imx9_modifyreg(priv, IMX9_USBDEV_USBCMD_OFFSET, 0, USBDEV_USBCMD_RST); + while (imx9_getreg(priv, IMX9_USBDEV_USBCMD_OFFSET) & USBDEV_USBCMD_RST); + + /* Turn off USB power and clocking */ + + /* Power down the PHY */ + + /* Clock gate off - NOTE: this turns off the clock from both controllers. + * Add reference counting if expanding this to support several ones. + */ + + imx9_ccm_gate_on(CCM_LPCG_USB_CONTROLLER, false); + + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: usbdev_register + * + * Description: + * Register a USB device class driver. The class driver's bind() method + * will be called to bind it to a USB device driver. + * + ****************************************************************************/ + +int usbdev_register(struct usbdevclass_driver_s *driver) +{ + int ret; + + usbtrace(TRACE_DEVREGISTER, 0); + +#ifdef CONFIG_DEBUG_FEATURES + if (!driver || !driver->ops->bind || !driver->ops->unbind || + !driver->ops->disconnect || !driver->ops->setup) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_INVALIDPARMS), 0); + return -EINVAL; + } + + if (g_usbdev[0].driver) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_DRIVER), 0); + return -EBUSY; + } +#endif + + /* First hook up the driver */ + + g_usbdev[0].driver = driver; + + /* Then bind the class driver */ + + ret = CLASS_BIND(driver, &g_usbdev[0].usbdev); + if (ret) + { + usbtrace(TRACE_DEVERROR(IMX9_TRACEERR_BINDFAILED), (uint16_t)-ret); + g_usbdev[0].driver = NULL; + } + else + { + /* Enable USB controller interrupts */ + + up_enable_irq(IMX9_IRQ_USB1 + g_usbdev[0].id); + } + + return ret; +} + +/**************************************************************************** + * Name: usbdev_unregister + * + * Description: + * Un-register usbdev class driver.If the USB device is connected to a USB + * host, it will first disconnect(). The driver is also requested to + * unbind() and clean up any device state, before this procedure finally + * returns. + * + ****************************************************************************/ + +int usbdev_unregister(struct usbdevclass_driver_s *driver) +{ + int i; + + usbtrace(TRACE_DEVUNREGISTER, 0); + + /* Find the correct device to which the driver is bound to */ + + for (i = 0; i < n_usbdevs; i++) + { + if (driver == g_usbdev[i].driver) + { + break; + } + } + + if (i == n_usbdevs) + { + return -EINVAL; + } + + /* Unbind the class driver */ + + CLASS_UNBIND(driver, &g_usbdev[i].usbdev); + + /* Disable USB controller interrupts */ + + up_disable_irq(IMX9_IRQ_USB1 + g_usbdev[i].id); + + /* Unhook the driver */ + + g_usbdev[i].driver = NULL; + + return OK; +} + diff --git a/arch/arm64/src/imx9/imx9_usbdev.h b/arch/arm64/src/imx9/imx9_usbdev.h new file mode 100644 index 0000000000000..b18008c3545b5 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_usbdev.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_usbdev.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_USBDEV_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_USBDEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef enum +{ + IMX9_USBC1 = 0, + IMX9_USBC2 = 1, +} imx9_usb_id_t; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_vbus_detect + * + * Description: + * Read the VBUS state from the USB OTG controller. This can be used + * to poll the VBUS state + * + * Input Parameters: + * id: IMX9_USBC1 or IMX9_USBC2 + * + * Returned Value: + * true if VBUS is valid; false otherwise + * + ****************************************************************************/ + +bool imx9_vbus_detect(imx9_usb_id_t id); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_USBDEV_H */ diff --git a/arch/arm64/src/imx9/imx9_usdhc.c b/arch/arm64/src/imx9/imx9_usdhc.c new file mode 100644 index 0000000000000..29f0501c7be66 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_usdhc.c @@ -0,0 +1,3430 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_usdhc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "chip.h" +#include "arm64_internal.h" +#include "imx9_gpio.h" +#include "hardware/imx9_pinmux.h" +#include "hardware/imx9_ccm.h" +#include "imx9_iomuxc.h" +#include "imx9_ccm.h" +#include "imx9_clockconfig.h" +#include "imx9_usdhc.h" + +#ifdef CONFIG_IMX9_USDHC + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if !defined(ARMV8A_DCACHE_LINESIZE) || ARMV8A_DCACHE_LINESIZE == 0 +# undef ARMV8A_DCACHE_LINESIZE +# define ARMV8A_DCACHE_LINESIZE 64 +#endif + +#define DCACHE_LINEMASK (ARMV8A_DCACHE_LINESIZE - 1) + +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) +# define cache_aligned_alloc(s) kmm_memalign(ARMV8A_DCACHE_LINESIZE,(s)) +# define CACHE_ALIGNED_DATA aligned_data(ARMV8A_DCACHE_LINESIZE) +#else +# define cache_aligned_alloc kmm_malloc +# define CACHE_ALIGNED_DATA +#endif + +/* Configuration ************************************************************/ + +#if ((defined(CONFIG_IMX9_USDHC1) && !defined(CONFIG_IMX9_USDHC2)) || \ + (defined(CONFIG_IMX9_USDHC2) && !defined(CONFIG_IMX9_USDHC1))) +# define IMX9_MAX_SDHC_DEV_SLOTS 1 +#elif (defined(CONFIG_IMX9_USDHC1) && defined(CONFIG_IMX9_USDHC2)) +# define IMX9_MAX_SDHC_DEV_SLOTS 2 +#else +#error Unrecognised number of SDHC slots +#endif + +#if !defined(CONFIG_IMX9_USDHC_DMA) +# warning "Large Non-DMA transfer may result in RX overrun failures" +#elif !defined(CONFIG_SDIO_DMA) +# warning CONFIG_SDIO_DMA should be defined with CONFIG_IMX9_USDHC_DMA +#endif + +#if !defined(CONFIG_SCHED_WORKQUEUE) || !defined(CONFIG_SCHED_HPWORK) +# error "Callback support requires CONFIG_SCHED_WORKQUEUE and CONFIG_SCHED_HPWORK" +#endif + +#if !defined(CONFIG_SDIO_BLOCKSETUP) +# error "CONFIG_SDIO_BLOCKSETUP is mandatory for this driver" +#endif + +#ifndef CONFIG_DEBUG_MEMCARD_INFO +# undef CONFIG_SDIO_XFRDEBUG +#endif + +/* Timing in ms for commands wait response */ + +#define USDHC_CMDTIMEOUT MSEC2TICK(100) +#define USDHC_LONGTIMEOUT MSEC2TICK(500) + +/* Big DTOCV setting. + * 1101 - SDCLK x 2 29, + * recommend to use for supported speed modes + * except HS200, HS400, SDR104 mode + * + * 1110 - SDCLK x 2 30, recommend to use for HS200 and SDR104 mode + */ + +#define USDHC_DTOCV_MAXTIMEOUT (13) + +/* Maximum watermark value */ + +#define USDHC_MAX_WATERMARK 128 + +/* Block size for multi-block transfers */ + +#define SDMMC_MAX_BLOCK_SIZE (512) + +/* Data transfer / Event waiting interrupt mask bits */ + +#define USDHC_RESPERR_INTS (USDHC_INT_CCE | USDHC_INT_CTOE | \ + USDHC_INT_CEBE | USDHC_INT_CIE) +#define USDHC_RESPDONE_INTS (USDHC_RESPERR_INTS | USDHC_INT_CC) + +#define USDHC_XFRERR_INTS (USDHC_INT_DCE | USDHC_INT_DTOE | \ + USDHC_INT_DEBE) +#define USDHC_RCVDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BRR | \ + USDHC_INT_TC) +#define USDHC_SNDDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BWR | \ + USDHC_INT_TC) +#define USDHC_XFRDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BRR | \ + USDHC_INT_BWR | USDHC_INT_TC) + +/* CD Detect Types */ + +/* For DMA operations DINT is not interesting TC will indicate completions */ + +#define USDHC_DMAERR_INTS (USDHC_XFRERR_INTS | USDHC_INT_DMAE) +#define USDHC_DMADONE_INTS (USDHC_DMAERR_INTS | USDHC_INT_TC) + +#define USDHC_WAITALL_INTS (USDHC_RESPDONE_INTS | \ + USDHC_XFRDONE_INTS | \ + USDHC_DMADONE_INTS) + +/* Register logging support */ + +#ifdef CONFIG_SDIO_XFRDEBUG +# if defined(CONFIG_IMX9_USDHC1) +# define DBG_BASE_ADDR IMX9_USDHC1_BASE +# else +# define DBG_BASE_ADDR IMX9_USDHC2_BASE +# endif +# define SAMPLENDX_BEFORE_SETUP 0 +# define SAMPLENDX_AFTER_SETUP 1 +# define SAMPLENDX_END_TRANSFER 2 +# define DEBUG_NSAMPLES 3 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure defines the state of the Imx9 SDIO interface */ + +struct imx9_dev_s +{ + struct sdio_dev_s dev; /* Standard, base SDIO interface */ + + /* Imx9-specific extensions */ + + /* Event support */ + + sem_t waitsem; /* Implements event waiting */ + sdio_eventset_t waitevents; /* Set of events to be waited for */ + uint32_t waitints; /* Interrupt enables for event waiting */ + volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */ + struct wdog_s waitwdog; /* Watchdog that handles event timeouts */ + + /* Callback support */ + + sdio_statset_t cdstatus; /* Card status */ + sdio_eventset_t cbevents; /* Set of events to be cause callbacks */ + worker_t callback; /* Registered callback function */ + void *cbarg; /* Registered callback argument */ + struct work_s cbwork; /* Callback work queue structure */ + + /* Interrupt mode data transfer support */ + + uint32_t *buffer; /* Address of current R/W buffer */ + size_t remaining; /* Number of bytes remaining in the + * transfer */ + uint32_t xfrints; /* Interrupt enables for data transfer */ + +#ifdef CONFIG_IMX9_USDHC_DMA + /* DMA data transfer support */ + + volatile uint8_t xfrflags; /* Used to synchronize SDIO and DMA + * completion */ + /* DMA buffer for unaligned transfers */ +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) + uint32_t blocksize; /* Current block size */ + uint8_t rxbuffer[SDMMC_MAX_BLOCK_SIZE] + __attribute__((aligned(ARMV8A_DCACHE_LINESIZE))); + bool unaligned_rx; /* buffer is not cache-line aligned */ +#endif +#endif + + /* Card interrupt support for SDIO */ + + uint32_t cintints; /* Interrupt enables for card ints */ + int (*do_sdio_card)(void *); /* SDIO card ISR */ + void *do_sdio_arg; /* arg for SDIO card ISR */ + + uint32_t addr; /* Base address of this instances */ + uint32_t sw_cd_gpio; /* If a non USDHCx CD pin is used, + * this is its GPIO */ + uint32_t cd_invert; /* If true invert the CD pin */ +}; + +/* Register logging support */ + +#ifdef CONFIG_SDIO_XFRDEBUG +struct imx9_sdhcregs_s +{ + /* All read-able USDHC registers */ + + uint32_t dsaddr; /* DMA System Address Register */ + uint32_t blkattr; /* Block Attributes Register */ + uint32_t cmdarg; /* Command Argument Register */ + uint32_t xferty; /* Transfer Type Register */ + uint32_t cmdrsp0; /* Command Response 0 */ + uint32_t cmdrsp1; /* Command Response 1 */ + uint32_t cmdrsp2; /* Command Response 2 */ + uint32_t cmdrsp3; /* Command Response 3 */ + uint32_t dbap; /* Data buffer access port */ + uint32_t prsstat; /* Present State Register */ + uint32_t proctl; /* Protocol Control Register */ + uint32_t sysctl; /* System Control Register */ + uint32_t irqstat; /* Interrupt Status Register */ + uint32_t irqstaten; /* Interrupt Status Enable Register */ + uint32_t irqsigen; /* Interrupt Signal Enable Register */ + uint32_t ac12err; /* Auto CMD12 Error Status Register */ + uint32_t htcapblt; /* Host Controller Capabilities */ + uint32_t wml; /* Watermark Level Register */ + uint32_t mixctrl; /* Mixer Control */ + uint32_t fevent; /* Force Event */ + uint32_t admaes; /* ADMA Error Status Register */ + uint32_t adsaddr; /* ADMA System Address Register */ + uint32_t dllctrl; /* Delay line control */ + uint32_t dllstat; /* Delay line status */ + uint32_t clktune; /* Clock tune and control */ + uint32_t vendor; /* Vendor Specific Register */ + uint32_t mmcboot; /* MMC Boot Register */ + uint32_t vendor2; /* Vendor Specific Register 2 */ + uint32_t tuningctrl; /* Tuning Control */ +}; +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Low-level helpers ********************************************************/ + +static void imx9_configwaitints(struct imx9_dev_s *priv, uint32_t waitints, + sdio_eventset_t waitevents, sdio_eventset_t wkupevents); +static void imx9_configxfrints(struct imx9_dev_s *priv, uint32_t xfrints); + +/* DMA Helpers **************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void imx9_sampleinit(void); +static void imx9_sdhcsample(struct imx9_sdhcregs_s *regs); +static void imx9_sample(struct imx9_dev_s *priv, int index); +static void imx9_dumpsample(struct imx9_dev_s *priv, + struct imx9_sdhcregs_s *regs, const char *msg); +static void imx9_dumpsamples(struct imx9_dev_s *priv); +static void imx9_showregs(struct imx9_dev_s *priv, const char *msg); + +#else +# define imx9_sampleinit() +# define imx9_sample(priv, index) +# define imx9_dumpsamples(priv) +# define imx9_showregs(priv, msg) +#endif + +/* Data Transfer Helpers ****************************************************/ + +static void imx9_dataconfig(struct imx9_dev_s *priv, bool bwrite, + unsigned int datalen, unsigned int timeout); + +#ifndef CONFIG_IMX9_USDHC_DMA +static void imx9_transmit(struct imx9_dev_s *priv); +static void imx9_receive(struct imx9_dev_s *priv); +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) +static void imx9_recvdma(struct imx9_dev_s *priv); +#endif +#endif + +static void imx9_eventtimeout(wdparm_t arg); +static void imx9_endwait(struct imx9_dev_s *priv, + sdio_eventset_t wkupevent); +static void imx9_endtransfer(struct imx9_dev_s *priv, + sdio_eventset_t wkupevent); + +/* Interrupt Handling *******************************************************/ + +static int imx9_interrupt(int irq, void *context, void *arg); + +/* SDIO interface methods ***************************************************/ + +/* Mutual exclusion */ + +#ifdef CONFIG_SDIO_MUXBUS +static int imx9_lock(struct sdio_dev_s *dev, bool lock); +#endif + +/* Initialization/setup */ + +static void imx9_reset(struct sdio_dev_s *dev); +static sdio_capset_t imx9_capabilities(struct sdio_dev_s *dev); +static sdio_statset_t imx9_status(struct sdio_dev_s *dev); +static void imx9_widebus(struct sdio_dev_s *dev, bool enable); + +#ifdef CONFIG_IMX9_USDHC_ABSFREQ +static void imx9_frequency(struct sdio_dev_s *dev, uint32_t frequency); +#endif + +static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate); +static int imx9_attach(struct sdio_dev_s *dev); + +/* Command/Status/Data Transfer */ + +static int imx9_sendcmd(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t arg); + +#ifdef CONFIG_SDIO_BLOCKSETUP +static void imx9_blocksetup(struct sdio_dev_s *dev, + unsigned int blocklen, unsigned int nblocks); +#endif + +#ifndef CONFIG_IMX9_USDHC_DMA +static int imx9_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer, + size_t nbytes); +static int imx9_sendsetup(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t nbytes); +#endif + +static int imx9_cancel(struct sdio_dev_s *dev); +static int imx9_waitresponse(struct sdio_dev_s *dev, uint32_t cmd); +static int imx9_recvshortcrc(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rshort); +static int imx9_recvlong(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t rlong[4]); +static int imx9_recvshort(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rshort); + +/* EVENT handler */ + +static void imx9_waitenable(struct sdio_dev_s *dev, + sdio_eventset_t eventset, uint32_t timeout); +static sdio_eventset_t imx9_eventwait(struct sdio_dev_s *dev); +static void imx9_callbackenable(struct sdio_dev_s *dev, + sdio_eventset_t eventset); +static int imx9_registercallback(struct sdio_dev_s *dev, + worker_t callback, void *arg); + +/* DMA */ + +#ifdef CONFIG_IMX9_USDHC_DMA +# if defined(CONFIG_ARCH_HAVE_SDIO_PREFLIGHT) +static int imx9_dmapreflight(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t buflen); +# endif +static int imx9_dmarecvsetup(struct sdio_dev_s *dev, + uint8_t *buffer, size_t buflen); +static int imx9_dmasendsetup(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t buflen); +#endif + +/* Initialization/uninitialization/reset ************************************/ + +static void imx9_callback(void *arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct imx9_dev_s g_sdhcdev[IMX9_MAX_SDHC_DEV_SLOTS] = +{ +#ifdef CONFIG_IMX9_USDHC1 + { + .addr = IMX9_USDHC1_BASE, +#if defined(PIN_USDHC1_CD_GPIO) + .sw_cd_gpio = PIN_USDHC1_CD_GPIO, +#endif +#if defined(CONFIG_IMX9_USDHC1_INVERT_CD) + .cd_invert = true, +#endif + .dev = + { +#ifdef CONFIG_SDIO_MUXBUS + .lock = imx9_lock, +#endif + .reset = imx9_reset, + .capabilities = imx9_capabilities, + .status = imx9_status, + .widebus = imx9_widebus, + .clock = imx9_clock, + .attach = imx9_attach, + .sendcmd = imx9_sendcmd, +#ifdef CONFIG_SDIO_BLOCKSETUP + .blocksetup = imx9_blocksetup, +#endif + +#ifndef CONFIG_IMX9_USDHC_DMA + .recvsetup = imx9_recvsetup, + .sendsetup = imx9_sendsetup, +#else + .recvsetup = imx9_dmarecvsetup, + .sendsetup = imx9_dmasendsetup, +#endif + .cancel = imx9_cancel, + .waitresponse = imx9_waitresponse, + .recv_r1 = imx9_recvshortcrc, + .recv_r2 = imx9_recvlong, + .recv_r3 = imx9_recvshort, + .recv_r4 = imx9_recvshort, + .recv_r5 = imx9_recvshortcrc, + .recv_r6 = imx9_recvshortcrc, + .recv_r7 = imx9_recvshort, + .waitenable = imx9_waitenable, + .eventwait = imx9_eventwait, + .callbackenable = imx9_callbackenable, + .registercallback = imx9_registercallback, +#ifdef CONFIG_SDIO_DMA +#ifdef CONFIG_IMX9_USDHC_DMA +# if defined(CONFIG_ARCH_HAVE_SDIO_PREFLIGHT) + .dmapreflight = imx9_dmapreflight, +# endif + .dmarecvsetup = imx9_dmarecvsetup, + .dmasendsetup = imx9_dmasendsetup, +#else + .dmarecvsetup = imx9_recvsetup, + .dmasendsetup = imx9_sendsetup, +#endif +#endif + }, + .waitsem = SEM_INITIALIZER(0), + }, +#endif + +#ifdef CONFIG_IMX9_USDHC2 + { + .addr = IMX9_USDHC2_BASE, +#if defined(PIN_USDHC2_CD_GPIO) + .sw_cd_gpio = PIN_USDHC2_CD_GPIO, +#endif +#if defined(CONFIG_IMX9_USDHC2_INVERT_CD) + .cd_invert = true, +#endif + .dev = + { +#ifdef CONFIG_SDIO_MUXBUS + .lock = imx9_lock, +#endif + .reset = imx9_reset, + .capabilities = imx9_capabilities, + .status = imx9_status, + .widebus = imx9_widebus, + .clock = imx9_clock, + .attach = imx9_attach, + .sendcmd = imx9_sendcmd, +#ifdef CONFIG_SDIO_BLOCKSETUP + .blocksetup = imx9_blocksetup, +#endif + +#ifndef CONFIG_IMX9_USDHC_DMA + .recvsetup = imx9_recvsetup, + .sendsetup = imx9_sendsetup, +#else + .recvsetup = imx9_dmarecvsetup, + .sendsetup = imx9_dmasendsetup, +#endif + .cancel = imx9_cancel, + .waitresponse = imx9_waitresponse, + .recv_r1 = imx9_recvshortcrc, + .recv_r2 = imx9_recvlong, + .recv_r3 = imx9_recvshort, + .recv_r4 = imx9_recvshort, + .recv_r5 = imx9_recvshortcrc, + .recv_r6 = imx9_recvshortcrc, + .recv_r7 = imx9_recvshort, + .waitenable = imx9_waitenable, + .eventwait = imx9_eventwait, + .callbackenable = imx9_callbackenable, + .registercallback = imx9_registercallback, +#ifdef CONFIG_SDIO_DMA +#ifdef CONFIG_IMX9_USDHC_DMA +# if defined(CONFIG_ARCH_HAVE_SDIO_PREFLIGHT) + .dmapreflight = imx9_dmapreflight, +# endif + .dmarecvsetup = imx9_dmarecvsetup, + .dmasendsetup = imx9_dmasendsetup, +#else + .dmarecvsetup = imx9_recvsetup, + .dmasendsetup = imx9_sendsetup, +#endif +#endif + }, + .waitsem = SEM_INITIALIZER(0), + } +#endif +}; + +#ifdef CONFIG_SDIO_XFRDEBUG +/* Register logging support */ + +static struct imx9_sdhcregs_s g_sampleregs[DEBUG_NSAMPLES]; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_configwaitints + * + * Description: + * Enable/disable SDIO interrupts needed to support the wait function + * + * Input Parameters: + * priv - A reference to the SDIO device state structure + * waitints - The set of bits in the SDIO MASK register to set + * waitevents - Waited for events + * wkupevent - Wake-up events + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_configwaitints(struct imx9_dev_s *priv, uint32_t waitints, + sdio_eventset_t waitevents, + sdio_eventset_t wkupevent) +{ + irqstate_t flags; + + /* Save all of the data and set the new interrupt mask in one, atomic + * operation. + */ + + flags = enter_critical_section(); + priv->waitevents = waitevents; + priv->wkupevent = wkupevent; + priv->waitints = waitints; + +#ifdef CONFIG_IMX9_USDHC_DMA + priv->xfrflags = 0; +#endif + putreg32(priv->xfrints | priv->waitints | priv->cintints, + priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: imx9_configxfrints + * + * Description: + * Enable SDIO interrupts needed to support the data transfer event + * + * Input Parameters: + * priv - A reference to the SDIO device state structure + * xfrints - The set of bits in the SDIO MASK register to set + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_configxfrints(struct imx9_dev_s *priv, uint32_t xfrints) +{ + irqstate_t flags; + + flags = enter_critical_section(); + priv->xfrints = xfrints; + putreg32(priv->xfrints | priv->waitints | priv->cintints, + priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: imx9_sampleinit + * + * Description: + * Setup prior to collecting DMA samples + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void imx9_sampleinit(void) +{ + memset(g_sampleregs, 0xff, + DEBUG_NSAMPLES * sizeof(struct imx9_sdhcregs_s)); +} +#endif + +/**************************************************************************** + * Name: imx9_sdhcsample + * + * Description: + * Sample SDIO registers + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void imx9_sdhcsample(struct imx9_sdhcregs_s *regs) +{ + regs->dsaddr = getreg32(DBG_BASE_ADDR + IMX9_USDHC_DSADDR_OFFSET); + regs->blkattr = getreg32(DBG_BASE_ADDR + IMX9_USDHC_BLKATTR_OFFSET); + regs->cmdarg = getreg32(DBG_BASE_ADDR + IMX9_USDHC_CMDARG_OFFSET); + regs->xferty = getreg32(DBG_BASE_ADDR + IMX9_USDHC_XFERTYP_OFFSET); + regs->cmdrsp0 = getreg32(DBG_BASE_ADDR + IMX9_USDHC_CMDRSP0_OFFSET); + regs->cmdrsp1 = getreg32(DBG_BASE_ADDR + IMX9_USDHC_CMDRSP1_OFFSET); + regs->cmdrsp2 = getreg32(DBG_BASE_ADDR + IMX9_USDHC_CMDRSP2_OFFSET); + regs->cmdrsp3 = getreg32(DBG_BASE_ADDR + IMX9_USDHC_CMDRSP3_OFFSET); + regs->prsstat = getreg32(DBG_BASE_ADDR + IMX9_USDHC_PRSSTAT_OFFSET); + regs->proctl = getreg32(DBG_BASE_ADDR + IMX9_USDHC_PROCTL_OFFSET); + regs->sysctl = getreg32(DBG_BASE_ADDR + IMX9_USDHC_SYSCTL_OFFSET); + regs->irqstat = getreg32(DBG_BASE_ADDR + IMX9_USDHC_IRQSTAT_OFFSET); + regs->irqstaten = getreg32(DBG_BASE_ADDR + IMX9_USDHC_IRQSTATEN_OFFSET); + regs->irqsigen = getreg32(DBG_BASE_ADDR + IMX9_USDHC_IRQSIGEN_OFFSET); + regs->ac12err = getreg32(DBG_BASE_ADDR + IMX9_USDHC_AC12ERR_OFFSET); + regs->htcapblt = getreg32(DBG_BASE_ADDR + IMX9_USDHC_HTCAPBLT_OFFSET); + regs->wml = getreg32(DBG_BASE_ADDR + IMX9_USDHC_WML_OFFSET); + regs->admaes = getreg32(DBG_BASE_ADDR + IMX9_USDHC_ADMAES_OFFSET); + regs->adsaddr = getreg32(DBG_BASE_ADDR + IMX9_USDHC_ADSADDR_OFFSET); + regs->vendor = getreg32(DBG_BASE_ADDR + IMX9_USDHC_VENDOR_OFFSET); + regs->vendor2 = getreg32(DBG_BASE_ADDR + IMX9_USDHC_VENDOR2_OFFSET); + regs->mmcboot = getreg32(DBG_BASE_ADDR + IMX9_USDHC_MMCBOOT_OFFSET); + regs->mixctrl = getreg32(DBG_BASE_ADDR + IMX9_USDHC_MIX_OFFSET); +} +#endif + +/**************************************************************************** + * Name: imx9_sample + * + * Description: + * Sample SDIO/DMA registers + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void imx9_sample(struct imx9_dev_s *priv, int index) +{ + if (priv->addr == DBG_BASE_ADDR) + { + imx9_sdhcsample(&g_sampleregs[index]); + } +} +#endif + +/**************************************************************************** + * Name: imx9_dumpsample + * + * Description: + * Dump one register sample + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void imx9_dumpsample(struct imx9_dev_s *priv, + struct imx9_sdhcregs_s *regs, const char *msg) +{ + mcinfo("USDHC Registers: %s\n", msg); + mcinfo(" DSADDR[%08x]: %08x\n", + IMX9_USDHC_DSADDR_OFFSET, regs->dsaddr); + mcinfo(" BLKATTR[%08x]: %08x\n", + IMX9_USDHC_BLKATTR_OFFSET, regs->blkattr); + mcinfo(" CMDARG[%08x]: %08x\n", + IMX9_USDHC_CMDARG_OFFSET, regs->cmdarg); + mcinfo(" XFERTY[%08x]: %08x\n", + IMX9_USDHC_XFERTYP_OFFSET, regs->xferty); + mcinfo(" CMDRSP0[%08x]: %08x\n", + IMX9_USDHC_CMDRSP0_OFFSET, regs->cmdrsp0); + mcinfo(" CMDRSP1[%08x]: %08x\n", + IMX9_USDHC_CMDRSP1_OFFSET, regs->cmdrsp1); + mcinfo(" CMDRSP2[%08x]: %08x\n", + IMX9_USDHC_CMDRSP2_OFFSET, regs->cmdrsp2); + mcinfo(" CMDRSP3[%08x]: %08x\n", + IMX9_USDHC_CMDRSP3_OFFSET, regs->cmdrsp3); + mcinfo(" PRSSTAT[%08x]: %08x\n", + IMX9_USDHC_PRSSTAT_OFFSET, regs->prsstat); + mcinfo(" PROCTL[%08x]: %08x\n", + IMX9_USDHC_PROCTL_OFFSET, regs->proctl); + mcinfo(" SYSCTL[%08x]: %08x\n", + IMX9_USDHC_SYSCTL_OFFSET, regs->sysctl); + mcinfo(" IRQSTAT[%08x]: %08x\n", + IMX9_USDHC_IRQSTAT_OFFSET, regs->irqstat); + mcinfo("IRQSTATEN[%08x]: %08x\n", + IMX9_USDHC_IRQSTATEN_OFFSET, regs->irqstaten); + mcinfo(" IRQSIGEN[%08x]: %08x\n", + IMX9_USDHC_IRQSIGEN_OFFSET, regs->irqsigen); + mcinfo(" AC12ERR[%08x]: %08x\n", + IMX9_USDHC_AC12ERR_OFFSET, regs->ac12err); + mcinfo(" HTCAPBLT[%08x]: %08x\n", + IMX9_USDHC_HTCAPBLT_OFFSET, regs->htcapblt); + mcinfo(" WML[%08x]: %08x\n", + IMX9_USDHC_WML_OFFSET, regs->wml); + mcinfo(" MIX[%08x]: %08x\n", + IMX9_USDHC_MIX_OFFSET, regs->mixctrl); + mcinfo(" ADMAES[%08x]: %08x\n", + IMX9_USDHC_ADMAES_OFFSET, regs->admaes); + mcinfo(" ADSADDR[%08x]: %08x\n", + IMX9_USDHC_ADSADDR_OFFSET, regs->adsaddr); + mcinfo(" VENDOR[%08x]: %08x\n", + IMX9_USDHC_VENDOR_OFFSET, regs->vendor); + mcinfo(" VENDOR2[%08x]: %08x\n", + IMX9_USDHC_VENDOR2_OFFSET, regs->vendor2); + mcinfo(" MMCBOOT[%08x]: %08x\n", + IMX9_USDHC_MMCBOOT_OFFSET, regs->mmcboot); +} +#endif + +/**************************************************************************** + * Name: imx9_dumpsamples + * + * Description: + * Dump all sampled register data + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void imx9_dumpsamples(struct imx9_dev_s *priv) +{ + imx9_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP], + "Before setup"); + imx9_dumpsample(priv, &g_sampleregs[SAMPLENDX_AFTER_SETUP], + "After setup"); + imx9_dumpsample(priv, &g_sampleregs[SAMPLENDX_END_TRANSFER], + "End of transfer"); +} +#endif + +/**************************************************************************** + * Name: imx9_showregs + * + * Description: + * Dump the current state of all registers + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_XFRDEBUG +static void imx9_showregs(struct imx9_dev_s *priv, const char *msg) +{ + struct imx9_sdhcregs_s regs; + + imx9_sdhcsample(®s); + imx9_dumpsample(priv, ®s, msg); +} +#endif + +/**************************************************************************** + * Data Transfer Helpers + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_dataconfig + * + * Description: + * Configure the SDIO data path for the next data transfer + * + ****************************************************************************/ + +static void imx9_dataconfig(struct imx9_dev_s *priv, bool bwrite, + unsigned int datalen, unsigned int timeout) +{ + unsigned int watermark; + uint32_t regval = 0; + + /* Set the data timeout value in the USDHC_SYSCTL field to the selected + * value. + */ + + regval = getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET); + regval &= ~USDHC_SYSCTL_DTOCV_MASK; + regval |= timeout << USDHC_SYSCTL_DTOCV_SHIFT; + putreg32(regval, priv->addr + IMX9_USDHC_SYSCTL_OFFSET); + +#if defined(CONFIG_IMX9_USDHC_DMA) && !defined(CONFIG_ARM64_DCACHE_DISABLE) + /* If cache is enabled, and this is an unaligned receive, + * receive one block at a time to the internal buffer + */ + + if (!bwrite && priv->unaligned_rx) + { + DEBUGASSERT(priv->blocksize <= sizeof(priv->rxbuffer)); + datalen = priv->blocksize; + } +#endif + + /* Set the watermark level */ + + /* Set the Read Watermark Level to the datalen to be read (limited to half + * of the maximum watermark value). BRR will be set when the number of + * queued words is greater than or equal to this value. + */ + + watermark = (datalen + 3) >> 2; + if (watermark > (USDHC_MAX_WATERMARK / 2)) + { + watermark = (USDHC_MAX_WATERMARK / 2); + } + + /* When the watermark level requirement is met in data transfer, and the + * internal DMA is enabled, the data buffer block sends a DMA request to + * the crossbar switch interface. + */ + + if (bwrite) + { + /* The USDHC will not start data transmission until the number of + * words set in the WML register can be held in the buffer. If the + * buffer is empty and the host system does not write data in time, + * the USDHC will stop the SD_CLK to avoid the data buffer under-run + * situation. + */ + + putreg32(watermark << USDHC_WML_WR_SHIFT, + priv->addr + IMX9_USDHC_WML_OFFSET); + } + else + { + /* The USDHC will not start data transmission until the number of words + * set in the WML register are in the buffer. If the buffer is full and + * the Host System does not read data in time, the USDHC will stop the + * USDHC_DCLK to avoid the data buffer over-run situation. + */ + + putreg32(watermark << USDHC_WML_RD_SHIFT, + priv->addr + IMX9_USDHC_WML_OFFSET); + } +} + +/**************************************************************************** + * Name: imx9_transmit + * + * Description: + * Send SDIO data in interrupt mode + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_IMX9_USDHC_DMA +static void imx9_transmit(struct imx9_dev_s *priv) +{ + union + { + uint32_t w; + uint8_t b[4]; + } data; + + /* Loop while there is more data to be sent, while buffer write enable + * (PRSSTAT.BWEN) + */ + + mcinfo("Entry: remaining: %lu IRQSTAT: %08x\n", priv->remaining, + getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET)); + + while (priv->remaining > 0 && + (getreg32(priv->addr + IMX9_USDHC_PRSSTAT_OFFSET) & + USDHC_PRSSTAT_BWEN) != 0) + { + /* Is there a full word remaining in the user buffer? */ + + if (priv->remaining >= sizeof(uint32_t)) + { + /* Yes, transfer the word to the TX FIFO */ + + data.w = *priv->buffer++; + priv->remaining -= sizeof(uint32_t); + } + else + { + /* No.. transfer just the bytes remaining in the user buffer, + * padding with zero as necessary to extend to a full word. + */ + + uint8_t *ptr = (uint8_t *)priv->remaining; + int i; + + data.w = 0; + for (i = 0; i < priv->remaining; i++) + { + data.b[i] = *ptr++; + } + + /* Now the transfer is finished */ + + priv->remaining = 0; + } + + /* Put the word in the FIFO */ + + putreg32(data.w, priv->addr + IMX9_USDHC_DATAPORT_OFFSET); + } + + /* Clear BWR. If there is more data in the buffer, writing to the buffer + * should reset BWR. + */ + + putreg32(USDHC_INT_BWR, priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + + mcinfo("Exit: remaining: %lu IRQSTAT: %08x\n", priv->remaining, + getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: imx9_receive + * + * Description: + * Receive SDIO data in interrupt mode + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_IMX9_USDHC_DMA +static void imx9_receive(struct imx9_dev_s *priv) +{ + unsigned int watermark; + union + { + uint32_t w; + uint8_t b[4]; + } data; + + /* Set the Read Watermark Level to 1: BRR will be set when the number of + * queued words is greater than or equal to 1. + */ + + putreg32(1 << USDHC_WML_RD_SHIFT, priv->addr + IMX9_USDHC_WML_OFFSET); + + /* Loop while there is space to store the data, waiting for buffer + * read ready (BRR) + */ + + mcinfo("Entry: remaining: %lu IRQSTAT: %08x\n", priv->remaining, + getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET)); + + while (priv->remaining > 0 && + (getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET) & + USDHC_INT_BRR) != 0) + { + /* Clear BRR. If there is more data in the buffer, reading from the + * buffer should reset BRR. + */ + + putreg32(USDHC_INT_BRR, priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + + /* Read the next word from the RX buffer */ + + data.w = getreg32(priv->addr + IMX9_USDHC_DATAPORT_OFFSET); + if (priv->remaining >= sizeof(uint32_t)) + { + /* Transfer the whole word to the user buffer */ + + *priv->buffer++ = data.w; + priv->remaining -= sizeof(uint32_t); + } + else + { + /* Transfer any trailing fractional word */ + + uint8_t *ptr = (uint8_t *)priv->buffer; + int i; + + for (i = 0; i < priv->remaining; i++) + { + *ptr++ = data.b[i]; + } + + /* Now the transfer is finished */ + + priv->remaining = 0; + } + } + + /* Set the Read Watermark Level either the number of remaining words to be + * read (limited to half of the maximum watermark value) + */ + + watermark = ((priv->remaining + 3) >> 2); + if (watermark > (USDHC_MAX_WATERMARK / 2)) + { + watermark = (USDHC_MAX_WATERMARK / 2); + } + + putreg32(watermark << USDHC_WML_RD_SHIFT, + priv->addr + IMX9_USDHC_WML_OFFSET); + + mcinfo("Exit: remaining: %lu IRQSTAT: %08x WML: %08x\n", priv->remaining, + getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET), + getreg32(priv->addr + IMX9_USDHC_WML_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: imx9_recvdma + * + * Description: + * Receive SDIO data in dma mode + * + * Input Parameters: + * priv - Instance of the SDMMC private state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +#if defined(CONFIG_IMX9_USDHC_DMA) && !defined(CONFIG_ARM64_DCACHE_DISABLE) +static void imx9_recvdma(struct imx9_dev_s *priv) +{ + unsigned int watermark; + + if (priv->unaligned_rx) + { + /* If we are receiving multiple blocks to an unaligned buffers, + * we receive them one-by-one + */ + + /* Invalidate the cache before receiving next block */ + + up_invalidate_dcache((uintptr_t)priv->rxbuffer, + (uintptr_t)priv->rxbuffer + priv->blocksize); + + /* Copy the received data to client buffer */ + + memcpy(priv->buffer, priv->rxbuffer, priv->blocksize); + + /* Update how much there is left to receive */ + + priv->remaining -= priv->blocksize; + } + else + { + /* In an aligned case, we have always received all blocks */ + + priv->remaining = 0; + } + + if (priv->remaining == 0) + { + /* no data remaining, end the transfer */ + + imx9_endtransfer(priv, SDIOWAIT_TRANSFERDONE); + } + else + { + /* We end up here only in unaligned rx-buffers case, and are receiving + * the data one block at a time + */ + + /* Update where to receive the following block */ + + priv->buffer = (uint32_t *)((uintptr_t)priv->buffer + priv->blocksize); + + watermark = (priv->blocksize + 3) >> 2; + if (watermark > (USDHC_MAX_WATERMARK / 2)) + { + watermark = (USDHC_MAX_WATERMARK / 2); + } + + /* Re-enable datapath and wait for next block */ + + putreg32(watermark << USDHC_WML_RD_SHIFT, + priv->addr + IMX9_USDHC_WML_OFFSET); + } +} + +#endif +/**************************************************************************** + * Name: imx9_eventtimeout + * + * Description: + * The watchdog timeout setup when the event wait start has expired without + * any other waited-for event occurring. + * + * Input Parameters: + * arg - The argument + * + * Returned Value: + * None + * + * Assumptions: + * Always called from the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +static void imx9_eventtimeout(wdparm_t arg) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)arg; + + DEBUGASSERT(priv != NULL); + DEBUGASSERT((priv->waitevents & SDIOWAIT_TIMEOUT) != 0); + + /* Is a data transfer complete event expected? */ + + if ((priv->waitevents & SDIOWAIT_TIMEOUT) != 0) + { + /* Yes.. Sample registers at the time of the timeout */ + + imx9_sample(priv, SAMPLENDX_END_TRANSFER); + + /* Wake up any waiting threads */ + + imx9_endwait(priv, SDIOWAIT_TIMEOUT); + mcerr("ERROR: Timeout: remaining: %lu\n", priv->remaining); + } +} + +/**************************************************************************** + * Name: imx9_endwait + * + * Description: + * Wake up a waiting thread if the waited-for event has occurred. + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * wkupevent - The event that caused the wait to end + * + * Returned Value: + * None + * + * Assumptions: + * Always called from the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +static void imx9_endwait(struct imx9_dev_s *priv, + sdio_eventset_t wkupevent) +{ + /* Cancel the watchdog timeout */ + + wd_cancel(&priv->waitwdog); + + /* Disable event-related interrupts */ + + imx9_configwaitints(priv, 0, 0, wkupevent); + + /* Wake up the waiting thread */ + + nxsem_post(&priv->waitsem); +} + +/**************************************************************************** + * Name: imx9_endtransfer + * + * Description: + * Terminate a transfer with the provided status. This function is called + * only from the SDIO interrupt handler when end-of-transfer conditions + * are detected. + * + * Input Parameters: + * priv - An instance of the SDIO device interface + * wkupevent - The event that caused the transfer to end + * + * Returned Value: + * None + * + * Assumptions: + * Always called from the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +static void imx9_endtransfer(struct imx9_dev_s *priv, + sdio_eventset_t wkupevent) +{ + /* Disable all transfer related interrupts */ + + imx9_configxfrints(priv, 0); + + /* Clearing pending interrupt status on all transfer related interrupts */ + + putreg32(USDHC_XFRDONE_INTS | USDHC_DMADONE_INTS, + priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + + /* Mark the transfer finished */ + + priv->remaining = 0; + + /* Debug instrumentation */ + + imx9_sample(priv, SAMPLENDX_END_TRANSFER); + + /* Is a thread wait for these data transfer complete events? */ + + if ((priv->waitevents & wkupevent) != 0) + { + /* Yes.. wake up any waiting threads */ + + imx9_endwait(priv, wkupevent); + } +} + +/**************************************************************************** + * Name: imx9_interrupt + * + * Description: + * SDIO interrupt handler + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int imx9_interrupt(int irq, void *context, void *arg) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)arg; + uint32_t enabled; + uint32_t pending; + uint32_t regval; + + /* Check the USDHC IRQSTAT register. Mask out all bits that don't + * correspond to enabled interrupts. (This depends on the fact that bits + * are ordered the same in both the IRQSTAT and IRQSIGEN registers). + * If there are non-zero bits remaining, then we have work to do here. + */ + + regval = getreg32(priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + enabled = getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET) & regval; + + mcinfo("IRQSTAT: %08" PRIx32 " IRQSIGEN %08" PRIx32 + " enabled: %08" PRIx32 "\n", + getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET), regval, enabled); + + /* Clear all pending interrupts */ + + putreg32(enabled, priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + + /* Handle in progress, interrupt driven data transfers ********************/ + + pending = enabled & priv->xfrints; + if (pending != 0) + { +#ifndef CONFIG_IMX9_USDHC_DMA + /* Is the RX buffer read ready? Is so then we must be processing a + * non-DMA receive transaction. + */ + + if ((pending & USDHC_INT_BRR) != 0) + { + /* Receive data from the RX buffer */ + + imx9_receive(priv); + } + + /* Otherwise, Is the TX buffer write ready? If so we must be processing + * non-DMA send transaction. NOTE: We can't be processing both! + */ + + else if ((pending & USDHC_INT_BWR) != 0) + { + /* Send data via the TX FIFO */ + + imx9_transmit(priv); + } +#endif + + /* ... transfer complete events */ + + if ((pending & USDHC_INT_TC) != 0) + { + /* Terminate the transfer */ +#if defined(CONFIG_IMX9_USDHC_DMA) && !defined(CONFIG_ARM64_DCACHE_DISABLE) + imx9_recvdma(priv); +#else + imx9_endtransfer(priv, SDIOWAIT_TRANSFERDONE); +#endif + } + + /* ... data block send/receive CRC failure */ + + else if ((pending & USDHC_INT_DCE) != 0) + { + /* Terminate the transfer with an error */ + + mcerr("ERROR: Data block CRC failure, remaining: %lu\n", + priv->remaining); + imx9_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); + } + + /* ... data timeout error */ + + else if ((pending & USDHC_INT_DTOE) != 0) + { + /* Terminate the transfer with an error */ + + mcerr("ERROR: Data timeout, remaining: %lu\n", priv->remaining); + imx9_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_TIMEOUT); + } + } + + /* Handle Card interrupt events *******************************************/ + + pending = enabled & priv->cintints; + if ((pending & USDHC_INT_CINT) != 0) + { + if (priv->do_sdio_card) + { + (priv->do_sdio_card)(priv->do_sdio_arg); + } + + /* We don't want any more ints now, so switch it off */ + + regval &= ~USDHC_INT_CINT; + priv->cintints = regval; + putreg32(regval, priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + } + + if ((pending & USDHC_INT_CINS) != 0 || (pending & USDHC_INT_CRM) != 0) + { + if (up_interrupt_context()) + { + /* Yes.. queue it */ + + mcinfo("Queuing callback to %p(%p)\n", + priv->callback, priv->cbarg); + + work_queue(HPWORK, &priv->cbwork, priv->callback, + priv->cbarg, 0); + } + else + { + /* No.. then just call the callback here */ + + mcinfo("Callback to %p(%p)\n", priv->callback, priv->cbarg); + + priv->callback(priv->cbarg); + } + } + + /* Handle wait events *****************************************************/ + + pending = enabled & priv->waitints; + if (pending != 0) + { + /* Is this a response completion event? */ + + if ((pending & USDHC_RESPDONE_INTS) != 0) + { + /* Yes.. Is there a thread waiting for response done? */ + + if ((priv->waitevents & + (SDIOWAIT_CMDDONE | SDIOWAIT_RESPONSEDONE)) != 0) + { + /* Yes.. mask further interrupts and wake the thread up */ + + regval = getreg32(priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + regval &= ~USDHC_RESPDONE_INTS; + putreg32(regval, priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + + imx9_endwait(priv, SDIOWAIT_RESPONSEDONE); + } + } + } + + return OK; +} + +/**************************************************************************** + * SDIO Interface Methods + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_lock + * + * Description: + * Locks the bus. Function calls low-level multiplexed bus routines to + * resolve bus requests and acknowledgment issues. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * lock - TRUE to lock, FALSE to unlock. + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_MUXBUS +static int imx9_lock(struct sdio_dev_s *dev, bool lock) +{ + /* The multiplex bus is part of board support package. */ + + /* FIXME: Implement the below function to support bus share: + * + * imx9_muxbus_sdio_lock((dev - g_sdhcdev) / + * sizeof(struct imx9_dev_s), lock); + */ + + return OK; +} +#endif + +/**************************************************************************** + * Name: imx9_reset + * + * Description: + * Reset the SDIO controller. Undo all setup and initialization. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_reset(struct sdio_dev_s *dev) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + + /* Disable all interrupts so that nothing interferes with the following. */ + + putreg32(0, priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + + /* Reset the USDHC block, putting registers in their default, reset state. + * Initiate the reset by setting the RSTA bit in the SYSCTL register. + * USDHC_VS2_BUSRESET has not been documented in i.MX93 ref manual. + */ + + modifyreg32(priv->addr + IMX9_USDHC_VENDOR2_OFFSET, 0, USDHC_VS2_BUSRESET); + modifyreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET, 0, USDHC_SYSCTL_RSTA); + modifyreg32(priv->addr + IMX9_USDHC_VENDOR2_OFFSET, + USDHC_VS2_BUSRESET | USDHC_VS2_ACMD23ARGU2, 0); + + /* The USDHC will reset the RSTA bit to 0 when the capabilities registers + * are valid and the host driver can read them. + */ + + while ((getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET) & + USDHC_SYSCTL_RSTA) != 0) + { + } + + mcinfo("Reset complete\n"); + + /* Make sure that all clocking is disabled */ + + imx9_clock(dev, CLOCK_SDIO_DISABLED); + + /* Enable all status bits (these could not all be potential sources of + * interrupts. + */ + + putreg32(USDHC_INT_ALL, priv->addr + IMX9_USDHC_IRQSTATEN_OFFSET); + + mcinfo("SYSCTL: %08" PRIx32 " PRSSTAT: %08" PRIx32 + " IRQSTATEN: %08" PRIx32 "\n", + getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET), + getreg32(priv->addr + IMX9_USDHC_PRSSTAT_OFFSET), + getreg32(priv->addr + IMX9_USDHC_IRQSTATEN_OFFSET)); + + /* The next phase of the hardware reset would be to set the SYSCTRL INITA + * bit to send 80 clock ticks for card to power up and then reset the card + * with CMD0. This is done elsewhere. + */ + + /* Reset state data */ + + priv->waitevents = 0; /* Set of events to be waited for */ + priv->waitints = 0; /* Interrupt enables for event waiting */ + priv->wkupevent = 0; /* The event that caused the wakeup */ +#ifdef CONFIG_IMX9_USDHC_DMA + priv->xfrflags = 0; /* Used to synchronize SDIO and DMA completion */ +#endif + + wd_cancel(&priv->waitwdog); /* Cancel any timeouts */ + + /* Interrupt mode data transfer support */ + + priv->buffer = 0; /* Address of current R/W buffer */ + priv->remaining = 0; /* Number of bytes remaining in the transfer */ + priv->xfrints = 0; /* Interrupt enables for data transfer */ +} + +/**************************************************************************** + * Name: imx9_capabilities + * + * Description: + * Get capabilities (and limitations) of the SDIO driver (optional) + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Returns a bitset of status values (see SDIO_CAPS_* defines) + * + ****************************************************************************/ + +static sdio_capset_t imx9_capabilities(struct sdio_dev_s *dev) +{ + sdio_capset_t caps = 0; + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + + switch (priv->addr) + { + case IMX9_USDHC1_BASE: +#ifdef CONFIG_IMX9_USDHC1_WIDTH_D1_ONLY + caps |= SDIO_CAPS_1BIT_ONLY; +#endif +#ifdef CONFIG_IMX9_USDHC1_WIDTH_D1_D4 + caps |= SDIO_CAPS_4BIT; +#endif +#ifdef CONFIG_IMX9_USDHC1_WIDTH_D1_D8 + caps |= SDIO_CAPS_8BIT; +#endif + break; + + case IMX9_USDHC2_BASE: +#ifdef CONFIG_IMX9_USDHC2_WIDTH_D1_ONLY + caps |= SDIO_CAPS_1BIT_ONLY; +#endif +#ifdef CONFIG_IMX9_USDHC2_WIDTH_D1_D4 + caps |= SDIO_CAPS_4BIT; +#endif + break; + + default: + break; + } + +#ifdef CONFIG_IMX9_USDHC_DMA + caps |= SDIO_CAPS_DMASUPPORTED; +#endif + caps |= SDIO_CAPS_DMABEFOREWRITE; + + return caps; +} + +/**************************************************************************** + * Name: imx9_status + * + * Description: + * Get SDIO status. + * + * Input Parameters: + * dev - Device-specific state data + * + * Returned Value: + * Returns a bitset of status values (see imx9_status_* defines) + * + ****************************************************************************/ + +static sdio_statset_t imx9_status(struct sdio_dev_s *dev) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + bool present = false; + + /* Board did not use one of the GPIO_USDHCn_CD pins + * but instead a GPIO was used and defined in board.h + * as PIN_USDHCx_CD_GPIO + */ + + if (priv->sw_cd_gpio != 0) + { + present = priv->cd_invert ^ !imx9_gpio_read(priv->sw_cd_gpio); + } + else + { + /* This register reflects the state of CD no matter if it's a separate pin + * or DAT3 + */ + + present = ((getreg32(priv->addr + IMX9_USDHC_PRSSTAT_OFFSET) & + USDHC_PRSSTAT_CINS) != 0) ^ priv->cd_invert; + } + + if (present) + { + priv->cdstatus |= SDIO_STATUS_PRESENT; + } + else + { + priv->cdstatus &= ~SDIO_STATUS_PRESENT; + } + + mcinfo("cdstatus=%02x\n", priv->cdstatus); + + return priv->cdstatus; +} + +/**************************************************************************** + * Name: imx9_widebus + * + * Description: + * Called after change in Bus width has been selected (via ACMD6). Most + * controllers will need to perform some special operations to work + * correctly in the new bus mode. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * wide - true: wide bus (4-bit) bus mode enabled + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_widebus(struct sdio_dev_s *dev, bool wide) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + uint32_t regval; + + /* Set the Data Transfer Width (DTW) field in the PROCTL register. */ + + regval = getreg32(priv->addr + IMX9_USDHC_PROCTL_OFFSET); + regval &= ~USDHC_PROCTL_DTW_MASK; + if (wide) + { + regval |= USDHC_PROCTL_DTW_4BIT; + } + else + { + regval |= USDHC_PROCTL_DTW_1BIT; + } + + putreg32(regval, priv->addr + IMX9_USDHC_PROCTL_OFFSET); +} + +/**************************************************************************** + * Name: imx9_frequency + * + * Description: + * Set the SD clock frequency + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * frequency - The frequency to use + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_USDHC_ABSFREQ +static void imx9_frequency(struct sdio_dev_s *dev, uint32_t frequency) +{ + uint32_t sdclkfs; + uint32_t prescaled; + uint32_t regval; + unsigned int prescaler; + unsigned int divisor; + + /* The SDCLK frequency is determined by + * (1) the frequency of the base clock that was selected as the + * input clock, and + * (2) by a prescaler and a divisor that are selected here: + * + * SDCLK frequency = (base clock) / (prescaler * divisor) + * + * The prescaler is available only for the values: 2, 4, 8, 16, 32, + * 64, 128, and 256. Pick the smallest value of SDCLKFS that would + * result in an in-range frequency. For example, if the base clock + * frequency is 96 MHz, and the target frequency is 25 MHz, the + * following logic will select prescaler: + * + * NOTE: USDHC_SYSCTL_SDCLKFS_DIVs are for Single Data Rate mode. + * See Reference manual for further details. + * + * 96MHz / 2 <= 25MHz <= 96MHz / 2 /16 -- YES, prescaler == 2 + * + * If the target frequency is 400 kHz, the following logic will + * select prescaler: + * + * 96MHz / 2 <= 400KHz <= 96MHz / 2 / 16 -- NO + * 96MHz / 4 <= 400KHz <= 96MHz / 4 / 16 -- NO + * 96MHz / 8 <= 400KHz <= 96MHz / 8 / 16 -- NO + * 96MHz / 16 <=400KHz <= 96MHz / 16 / 16 -- YES, prescaler == 16 + */ + + if (/* frequency >= (BOARD_CORECLK_FREQ / 2) && */ + frequency <= (BOARD_CORECLK_FREQ / 2 / 16)) + { + sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV2; + prescaler = 2; + } + else if (frequency >= (BOARD_CORECLK_FREQ / 4) && + frequency <= (BOARD_CORECLK_FREQ / 4 / 16)) + { + sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV4; + prescaler = 4; + } + else if (frequency >= (BOARD_CORECLK_FREQ / 8) && + frequency <= (BOARD_CORECLK_FREQ / 8 / 16)) + { + sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV8; + prescaler = 8; + } + else if (frequency >= (BOARD_CORECLK_FREQ / 16) && + frequency <= (BOARD_CORECLK_FREQ / 16 / 16)) + { + sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV16; + prescaler = 16; + } + else if (frequency >= (BOARD_CORECLK_FREQ / 32) && + frequency <= (BOARD_CORECLK_FREQ / 32 / 16)) + { + sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV32; + prescaler = 32; + } + else if (frequency >= (BOARD_CORECLK_FREQ / 64) && + frequency <= (BOARD_CORECLK_FREQ / 64 / 16)) + { + sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV64; + prescaler = 64; + } + else if (frequency >= (BOARD_CORECLK_FREQ / 128) && + frequency <= (BOARD_CORECLK_FREQ / 128 / 16)) + { + sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV128; + prescaler = 128; + } + else + { + sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV256; + prescaler = 256; + } + + /* The optimal divider can than be calculated. For example, if the base + * clock frequency is 96 MHz, the target frequency is 25 MHz, and the + * selected prescaler value is 2, then + * + * prescaled = 96MHz / 2 = 48MHz + * divisor = (48MHz + 12.5HMz/ 25MHz = 2 + * + * And the resulting frequency will be 24MHz. Or, for example, if the + * target frequency is 400 kHz and the selected prescaler is 16, the + * following logic will select prescaler: + * + * prescaled = 96MHz / 16 = 6MHz + * divisor = (6MHz + 200KHz) / 400KHz = 15 + * + * And the resulting frequency will be exactly 400KHz. + */ + + prescaled = frequency / prescaler; + divisor = (prescaled + (frequency >> 1)) / frequency; + + /* Set the new divisor information and enable all clocks in the SYSCTRL + * register. TODO: Investigate using the automatically gated clocks to + * reduce power consumption. + */ + + regval = getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET); + regval &= ~(USDHC_SYSCTL_SDCLKFS_MASK | USDHC_SYSCTL_DVS_MASK); + regval |= (sdclkfs | USDHC_SYSCTL_DVS_DIV(divisor)); + regval |= (USDHC_SYSCTL_SDCLKEN | USDHC_SYSCTL_PEREN | + USDHC_SYSCTL_HCKEN | USDHC_SYSCTL_IPGEN); + + putreg32(regval, priv->addr + IMX9_USDHC_SYSCTL_OFFSET); + + mcinfo("SYSCTRL: %08x\n", + getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET)); +} +#endif + +/**************************************************************************** + * Name: imx9_clock + * + * Description: + * Enable/disable SDIO clocking + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * rate - Specifies the clocking to use (see enum sdio_clock_e) + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + uint32_t regval; + + /* Clear the old prescaler and divisor values so that new ones can be + * ORed in. + */ + + regval = getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET); + regval &= ~(USDHC_SYSCTL_SDCLKFS_MASK | USDHC_SYSCTL_DVS_MASK); + + /* Select the new prescaler and divisor values based on the requested + * mode and the settings from the board.h file. Clocks are automatically + * gated by the driver when not needed. + */ + + switch (rate) + { + default: + case CLOCK_SDIO_DISABLED: /* Clock is disabled */ + { + /* Clear the prescaler and divisor settings */ + + putreg32(regval, priv->addr + IMX9_USDHC_SYSCTL_OFFSET); + mcinfo("DISABLED, SYSCTRL: %08" PRIx32 "\n", + getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET)); return; + } + break; + + case CLOCK_IDMODE: + { + /* Initial ID mode clocking (<400KHz) */ + + mcinfo("IDMODE\n"); + + /* Put out an additional 80 clocks in case this is a power-up + * sequence. + */ + + regval |= (BOARD_USDHC_IDMODE_PRESCALER | + BOARD_USDHC_IDMODE_DIVISOR | + USDHC_SYSCTL_INITA); + } + break; + + case CLOCK_MMC_TRANSFER: + { + /* MMC normal operation clocking */ + + mcinfo("MMCTRANSFER\n"); + regval |= (BOARD_USDHC_MMCMODE_PRESCALER | + BOARD_USDHC_MMCMODE_DIVISOR); + } + break; + + case CLOCK_SD_TRANSFER_1BIT: + { + /* SD normal operation clocking (narrow 1-bit mode) */ + + mcinfo("1BITTRANSFER\n"); + regval |= (BOARD_USDHC_SD1MODE_PRESCALER | + BOARD_USDHC_SD1MODE_DIVISOR); + } + break; + + case CLOCK_SD_TRANSFER_4BIT: + { + /* SD normal operation clocking (wide 4-bit mode) */ + + mcinfo("4BITTRANSFER\n"); + regval |= (BOARD_USDHC_SD4MODE_PRESCALER | + BOARD_USDHC_SD4MODE_DIVISOR); + } + break; + } + + putreg32(regval, priv->addr + IMX9_USDHC_SYSCTL_OFFSET); + + /* Wait for clock to become stable */ + + while ((getreg32(priv->addr + IMX9_USDHC_PRSSTAT_OFFSET) & + USDHC_PRSSTAT_SDSTB) == 0) + { + } + + mcinfo("SYSCTRL: %08" PRIx32 "\n", + getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET)); +} + +/**************************************************************************** + * Name: imx9_attach + * + * Description: + * Attach and prepare interrupts + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * OK on success; A negated errno on failure. + * + ****************************************************************************/ + +static int imx9_attach(struct sdio_dev_s *dev) +{ + int ret; + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + int usdhc2_dev = (IMX9_MAX_SDHC_DEV_SLOTS > 1) ? 1 : 0; + + /* Attach the SDIO interrupt handler */ + + if (priv->addr == IMX9_USDHC1_BASE) + { + ret = irq_attach(IMX9_IRQ_USDHC1, imx9_interrupt, &g_sdhcdev[0]); + } + else + { + if (priv->addr == IMX9_USDHC2_BASE) + { + ret = irq_attach(IMX9_IRQ_USDHC2, imx9_interrupt, + &g_sdhcdev[usdhc2_dev]); + } + else + { + PANIC(); + } + } + + if (ret == OK) + { + /* Disable all interrupts at the SDIO controller and clear all pending + * interrupts. + */ + + putreg32(0, priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + putreg32(USDHC_INT_ALL, priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + + /* Enable SDIO interrupts at the NVIC. They can now be enabled at the + * SDIO controller as needed. + */ + + if (priv->addr == IMX9_USDHC1_BASE) + { + up_enable_irq(IMX9_IRQ_USDHC1); + } + else if (priv->addr == IMX9_USDHC2_BASE) + { + up_enable_irq(IMX9_IRQ_USDHC2); + } + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_sendcmd + * + * Description: + * Send the SDIO command + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * cmd - The command to send (32-bits, encoded) + * arg - 32-bit argument required with some commands + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int imx9_sendcmd(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t arg) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + clock_t timeout; + clock_t start; + clock_t elapsed; + uint32_t regval; + uint32_t mcrregval; + uint32_t cmdidx; + + /* Initialize the command index */ + + cmdidx = (cmd & MMCSD_CMDIDX_MASK) >> MMCSD_CMDIDX_SHIFT; + regval = cmdidx << USDHC_XFERTYP_CMDINX_SHIFT; + mcrregval = USDHC_MC_DEFAULTVAL; + + mcinfo("cmdidx: %d\n", cmdidx); + + if (cmdidx == SD_ACMDIDX53) + { + /* Dynamically set parameters for ACMD53 because it can accommodate + * different transmission characteristics (single and multi-block, + * rx & tx). + */ + + if (arg & (1 << 31)) + { + /* Transmit mode */ + + cmd |= MMCSD_WRDATAXFR; + } + else + { + /* Receive mode */ + + cmd |= MMCSD_RDDATAXFR; + } + + if (arg & (1 << 27)) + { + /* In block mode */ + + cmd |= SDIO_MULTIBLOCK; + } + } + + /* Check if a data transfer accompanies the command */ + + switch (cmd & MMCSD_DATAXFR_MASK) + { + default: + case MMCSD_NODATAXFR: + { + /* No.. no data transfer */ + } + break; + + /* The following two cases are probably missing some setup logic */ + + case MMCSD_RDSTREAM: + { + /* Yes.. streaming read data transfer */ + + regval |= USDHC_XFERTYP_DPSEL; + mcrregval |= USDHC_MC_DTDSEL; + } + break; + + case MMCSD_WRSTREAM: + { + /* Yes.. streaming write data transfer */ + + regval |= USDHC_XFERTYP_DPSEL; + } + break; + + case MMCSD_RDDATAXFR: + { + /* Yes.. normal read data transfer */ + + regval |= USDHC_XFERTYP_DPSEL; + mcrregval |= USDHC_MC_DTDSEL; + } + break; + + case MMCSD_WRDATAXFR: + { + /* Yes.. normal write data transfer */ + + regval |= USDHC_XFERTYP_DPSEL; + } + break; + } + + /* Is it a multi-block transfer? */ + + if ((cmd & (MMCSD_MULTIBLOCK | SDIO_MULTIBLOCK)) != 0) + { + mcrregval |= USDHC_MC_MSBSEL; + + /* Yes.. should the transfer be stopped with ACMD12? */ + + if (((cmd & MMCSD_MULTIBLOCK) != 0) && + ((cmd & MMCSD_STOPXFR) != 0)) + { + /* Yes.. Indefinite block transfer (not SDIO) */ + + mcrregval |= USDHC_MC_AC12EN; + } + else + { + /* No.. Fixed block transfer */ + + mcrregval |= USDHC_MC_BCEN; + } + } + + /* Configure response type bits */ + + switch (cmd & MMCSD_RESPONSE_MASK) + { + case MMCSD_NO_RESPONSE: + { + /* No response */ + + regval |= USDHC_XFERTYP_RSPTYP_NONE; + } + break; + + case MMCSD_R1B_RESPONSE: + { + /* Response length 48, check busy & cmdindex */ + + regval |= + (USDHC_XFERTYP_RSPTYP_LEN48BSY | USDHC_XFERTYP_CICEN | + USDHC_XFERTYP_CCCEN); + } + break; + + case MMCSD_R1_RESPONSE: /* Response length 48, check cmdindex */ + case MMCSD_R5_RESPONSE: + case MMCSD_R6_RESPONSE: + { + regval |= + (USDHC_XFERTYP_RSPTYP_LEN48 | USDHC_XFERTYP_CICEN | + USDHC_XFERTYP_CCCEN); + } + break; + + case MMCSD_R2_RESPONSE: + { + /* Response length 136, check CRC */ + + regval |= (USDHC_XFERTYP_RSPTYP_LEN136 | USDHC_XFERTYP_CCCEN); + } + break; + + case MMCSD_R3_RESPONSE: /* Response length 48 */ + case MMCSD_R4_RESPONSE: + case MMCSD_R7_RESPONSE: + { + regval |= USDHC_XFERTYP_RSPTYP_LEN48; + } + break; + } + +#ifdef CONFIG_IMX9_USDHC_DMA + /* Enable DMA */ + + /* Internal DMA is used */ + + mcrregval |= USDHC_MC_DMAEN; +#endif + + /* Check for abort. TODO: Check Suspend/Resume bits too in + * XFR_TYP::CMDTYP. + */ + + if (cmd & MMCSD_STOPXFR) + { + regval |= USDHC_XFERTYP_CMDTYP_ABORT; + } + + mcinfo("cmd: %08" PRIx32 " arg: %08" PRIx32 + " regval: %08" PRIx32 " mcrval: %08" PRIx32 "\n", cmd, arg, + regval, mcrregval); + + /* If there has been a response error then perform a reset and wait for it + * to complete. + */ + + if ((getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET) & + USDHC_RESPERR_INTS) != 0) + { + modifyreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET, 0, + USDHC_SYSCTL_RSTC); + while ((getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET) & + USDHC_SYSCTL_RSTC) != 0) + { + } + } + + /* The Command Inhibit (CIHB) bit is set in the PRSSTAT bit immediately + * after the transfer type register is written. This bit is cleared + * when the command response is received. If this status bit is 0, it + * indicates that the CMD line is not in use and the USDHC can issue a + * SD/MMC Command using the CMD line. CIHB should always be clear before + * this function is called, but this check is performed here to provide + * overlap and maximum performance. + */ + + timeout = USDHC_CMDTIMEOUT; + start = clock_systime_ticks(); + while ((getreg32(priv->addr + IMX9_USDHC_PRSSTAT_OFFSET) & + USDHC_PRSSTAT_CIHB) != 0) + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + if (elapsed >= timeout) + { + mcerr("ERROR: Timeout (waiting CIHB) cmd: %08" PRIx32 + " PRSSTAT: %08" PRIx32 "\n", + cmd, getreg32(priv->addr + IMX9_USDHC_PRSSTAT_OFFSET)); + return -EBUSY; + } + } + + /* Set the USDHC Argument value */ + + putreg32(arg, priv->addr + IMX9_USDHC_CMDARG_OFFSET); + + /* Clear interrupt status and write the USDHC CMD */ + + putreg32(USDHC_RESPDONE_INTS, priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + putreg32(mcrregval, priv->addr + IMX9_USDHC_MIX_OFFSET); + putreg32(regval, priv->addr + IMX9_USDHC_XFERTYP_OFFSET); + + return OK; +} + +/**************************************************************************** + * Name: imx9_blocksetup + * + * Description: + * Configure block size and the number of blocks for next transfer + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * blocklen - The selected block size. + * nblocklen - The number of blocks to transfer + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SDIO_BLOCKSETUP +static void imx9_blocksetup(struct sdio_dev_s *dev, + unsigned int blocklen, + unsigned int nblocks) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + + mcinfo("blocklen=%d, total transfer=%d (%d blocks)\n", blocklen, + blocklen * nblocks, nblocks); + + /* Configure block size for next transfer */ + +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) + priv->blocksize = blocklen; +#endif + + putreg32(USDHC_BLKATTR_SIZE(blocklen) | USDHC_BLKATTR_CNT(nblocks), + priv->addr + IMX9_USDHC_BLKATTR_OFFSET); +} +#endif + +/**************************************************************************** + * Name: imx9_recvsetup + * + * Description: + * Setup hardware in preparation for data transfer from the card in non- + * DMA (interrupt driven mode). This method will do whatever controller + * setup is necessary. This would be called for SD memory just BEFORE + * sending CMD13 (SEND_STATUS), CMD17 (READ_SINGLE_BLOCK), CMD18 + * (READ_MULTIPLE_BLOCKS), ACMD51 (SEND_SCR), etc. Normally, + * SDIO_WAITEVENT will be called to receive the indication that the + * transfer is complete. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - Address of the buffer in which to receive the data + * nbytes - The number of bytes in the transfer + * + * Returned Value: + * Number of bytes sent on success; a negated errno on failure + * + ****************************************************************************/ + +#ifndef CONFIG_IMX9_USDHC_DMA +static int imx9_recvsetup(struct sdio_dev_s *dev, uint8_t *buffer, + size_t nbytes) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0); + DEBUGASSERT(((uint64_t) buffer & 3) == 0); + + /* Reset the DPSM configuration */ + + imx9_sampleinit(); + imx9_sample(priv, SAMPLENDX_BEFORE_SETUP); + + /* Save the destination buffer information for use by the interrupt + * handler and DMA memory invalidation. + */ + + priv->buffer = (uint32_t *)buffer; + priv->remaining = nbytes; + + /* Then set up the SDIO data path */ + + imx9_dataconfig(priv, false, nbytes, USDHC_DTOCV_MAXTIMEOUT); + + /* And enable interrupts */ + + imx9_configxfrints(priv, USDHC_RCVDONE_INTS); + imx9_sample(priv, SAMPLENDX_AFTER_SETUP); return OK; +} +#endif + +/**************************************************************************** + * Name: imx9_sendsetup + * + * Description: + * Setup hardware in preparation for data transfer from the card. This + * method will do whatever controller setup is necessary. This would be + * called for SD memory just AFTER sending CMD24 (WRITE_BLOCK), CMD25 + * (WRITE_MULTIPLE_BLOCK), ... and before SDIO_SENDDATA is called. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - Address of the buffer containing the data to send + * nbytes - The number of bytes in the transfer + * + * Returned Value: + * Number of bytes sent on success; a negated errno on failure + * + ****************************************************************************/ + +#ifndef CONFIG_IMX9_USDHC_DMA +static int imx9_sendsetup(struct sdio_dev_s *dev, + const uint8_t *buffer, + size_t nbytes) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0); + DEBUGASSERT(((uint64_t) buffer & 3) == 0); + + /* Reset the DPSM configuration */ + + imx9_sampleinit(); + imx9_sample(priv, SAMPLENDX_BEFORE_SETUP); + + /* Save the source buffer information for use by the interrupt handler */ + + priv->buffer = (uint32_t *)buffer; + priv->remaining = nbytes; + + /* Then set up the SDIO data path */ + + imx9_dataconfig(priv, true, nbytes, USDHC_DTOCV_MAXTIMEOUT); + + /* Enable TX interrupts */ + + imx9_configxfrints(priv, USDHC_SNDDONE_INTS); + imx9_sample(priv, SAMPLENDX_AFTER_SETUP); return OK; +} +#endif + +/**************************************************************************** + * Name: imx9_cancel + * + * Description: + * Cancel the data transfer setup of SDIO_RECVSETUP, SDIO_SENDSETUP, + * SDIO_DMARECVSETUP or SDIO_DMASENDSETUP. This must be called to cancel + * the data transfer setup if, for some reason, you cannot perform the + * transfer. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * OK is success; a negated errno on failure + * + ****************************************************************************/ + +static int imx9_cancel(struct sdio_dev_s *dev) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + +#ifdef CONFIG_IMX9_USDHC_DMA + uint32_t regval; +#endif + + /* Disable all transfer- and event- related interrupts */ + + imx9_configxfrints(priv, 0); imx9_configwaitints(priv, 0, 0, 0); + + /* Clearing pending interrupt status on all transfer- and event- related + * interrupts + */ + + putreg32(USDHC_WAITALL_INTS, priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + + /* Cancel any watchdog timeout */ + + wd_cancel(&priv->waitwdog); + + /* If this was a DMA transfer, make sure that DMA is stopped */ + +#ifdef CONFIG_IMX9_USDHC_DMA + + /* Stop the DMA by resetting the data path */ + + regval = getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET); + regval |= USDHC_SYSCTL_RSTD; + putreg32(regval, priv->addr + IMX9_USDHC_SYSCTL_OFFSET); +#endif + + /* Mark no transfer in progress */ + + priv->remaining = 0; + + return OK; +} + +/**************************************************************************** + * Name: imx9_waitresponse + * + * Description: + * Poll-wait for the response to the last command to be ready. This + * function should be called even after sending commands that have no + * response (such as CMD0) to make sure that the hardware is ready to + * receive the next command. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * cmd - The command that was sent. See 32-bit command definitions above. + * + * Returned Value: + * OK is success; a negated errno on failure + * + ****************************************************************************/ + +static int imx9_waitresponse(struct sdio_dev_s *dev, uint32_t cmd) +{ + clock_t timeout; + clock_t start; + clock_t elapsed; + uint32_t errors; + uint32_t enerrors; + + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + int ret = OK; + + switch (cmd & MMCSD_RESPONSE_MASK) + { + case MMCSD_NO_RESPONSE: + timeout = USDHC_CMDTIMEOUT; + errors = 0; + break; + + case MMCSD_R1_RESPONSE: + case MMCSD_R1B_RESPONSE: + case MMCSD_R2_RESPONSE: + case MMCSD_R4_RESPONSE: + case MMCSD_R5_RESPONSE: + case MMCSD_R6_RESPONSE: + { + timeout = USDHC_LONGTIMEOUT; + errors = USDHC_RESPERR_INTS; + } + break; + + case MMCSD_R3_RESPONSE: + case MMCSD_R7_RESPONSE: + { + timeout = USDHC_CMDTIMEOUT; + errors = USDHC_RESPERR_INTS; + } + break; + + default: + return -EINVAL; + } + + /* Then wait for the Command Complete (CC) indication (or timeout). The + * CC bit is set when the end bit of the command response is received + * (except Auto CMD12). + */ + + start = clock_systime_ticks(); + while ((getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET) & + USDHC_INT_CC) == 0) + { + /* Calculate the elapsed time */ + + elapsed = clock_systime_ticks() - start; + if (elapsed >= timeout) + { + mcerr("ERROR: Timeout cmd: %08" PRIx32 + " IRQSTAT: %08" PRIx32 "\n", cmd, + getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET)); + ret = -ETIMEDOUT; + break; + } + } + + /* Check for hardware detected errors */ + + enerrors = getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET) & errors; + if (enerrors != 0) + { + mcerr("ERROR: cmd: %08" PRIx32 " errors: %08" PRIx32 ", " + "fired %08" PRIx32 " IRQSTAT: %08" PRIx32 "\n", + cmd, errors, enerrors, + getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET)); + + ret = -EIO; + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_recv* + * + * Description: + * Receive response to SDIO command. Only the critical payload is + * returned -- that is 32 bits for 48 bit status and 128 bits for 136 bit + * status. The driver implementation should verify the correctness of + * the remaining, non-returned bits (CRCs, CMD index, etc.). + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * Rx - Buffer in which to receive the response + * + * Returned Value: + * Number of bytes sent on success; a negated errno on failure. Here a + * failure means only a failure to obtain the requested response (due to + * transport problem -- timeout, CRC, etc.). The implementation only + * assures that the response is returned intact and does not check errors + * within the response itself. + * + ****************************************************************************/ + +static int imx9_recvshortcrc(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rshort) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + uint32_t regval; + int ret = OK; + + /* R1 Command response (48-bit) + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Command index (0-63) + * 39:8 bit31- bit0 32-bit card status + * 7:1 bit6 - bit0 CRC7 + * 0 1 End bit + * + * R1b Identical to R1 with the additional busy signalling via the data + * line. + * R6 Published RCA Response (48-bit, SD card only) + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Command index (0-63) + * 39:8 bit31 - bit0 32-bit Argument Field, consisting of: + * [31:16] New published RCA of card + * [15:0] Card status bits + * {23,22,19,12:0} + * 7:1 bit6 - bit0 CRC7 + * 0 1 End bit + */ + +#ifdef CONFIG_DEBUG_FEATURES + if (!rshort) + { + mcerr("ERROR: rshort=NULL\n"); + ret = -EINVAL; + } + + /* Check that this is the correct response to this command */ + + else if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1B_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R5_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R6_RESPONSE) + { + mcerr("ERROR: Wrong response CMD=%08" PRIx32 "\n", cmd); + ret = -EINVAL; + } + else +#endif + { + /* Check if a timeout or CRC error occurred */ + + regval = getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + if ((regval & USDHC_INT_CTOE) != 0) + { + mcerr("ERROR: Command timeout: %08" PRIx32 "\n", regval); + ret = -ETIMEDOUT; + } + else if ((regval & USDHC_INT_CCE) != 0) + { + mcerr("ERROR: CRC failure: %08" PRIx32 "\n", regval); ret = -EIO; + } + } + + /* Return the R1/R1b/R6 response. These responses are returned in + * CDMRSP0. NOTE: This is not true for R1b (Auto CMD12 response) which is + * returned in CMDRSP3. + */ + + *rshort = getreg32(priv->addr + IMX9_USDHC_CMDRSP0_OFFSET); + return ret; +} + +static int imx9_recvlong(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t rlong[4]) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + uint32_t regval; + int ret = OK; + + /* R2 CID, CSD register (136-bit) + * 135 0 Start bit + * 134 0 Transmission bit (0=from card) + * 133:128 bit5 - bit0 Reserved + * 127:1 bit127 - bit1 127-bit CID or CSD register (including int. CRC) + * 0 1 End bit + */ + +#ifdef CONFIG_DEBUG_FEATURES + /* Check that R1 is the correct response to this command */ + + if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R2_RESPONSE) + { + mcerr("ERROR: Wrong response CMD=%08" PRIx32 "\n", cmd); + ret = -EINVAL; + } + else +#endif + { + /* Check if a timeout or CRC error occurred */ + + regval = getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + if (regval & USDHC_INT_CTOE) + { + mcerr("ERROR: Timeout IRQSTAT: %08" PRIx32 "\n", regval); + ret = -ETIMEDOUT; + } + else if (regval & USDHC_INT_CCE) + { + mcerr("ERROR: CRC fail IRQSTAT: %08" PRIx32 "\n", regval); + ret = -EIO; + } + } + + /* Return the long response in CMDRSP3..0 */ + + if (rlong) + { + uint32_t rsp3 = getreg32(priv->addr + IMX9_USDHC_CMDRSP3_OFFSET); + uint32_t rsp2 = getreg32(priv->addr + IMX9_USDHC_CMDRSP2_OFFSET); + uint32_t rsp1 = getreg32(priv->addr + IMX9_USDHC_CMDRSP1_OFFSET); + uint32_t rsp0 = getreg32(priv->addr + IMX9_USDHC_CMDRSP0_OFFSET); + + rlong[0] = rsp3 << 8 | rsp2 >> 24; + rlong[1] = rsp2 << 8 | rsp1 >> 24; + rlong[2] = rsp1 << 8 | rsp0 >> 24; rlong[3] = rsp0 << 8; + } + + return ret; +} + +static int imx9_recvshort(struct sdio_dev_s *dev, uint32_t cmd, + uint32_t *rshort) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + uint32_t regval; + int ret = OK; + + /* R3 OCR (48-bit) + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Reserved + * 39:8 bit31- bit0 32-bit OCR register + * 7:1 bit6 - bit0 Reserved + * 0 1 End bit + */ + + /* Check that this is the correct response to this command */ + +#ifdef CONFIG_DEBUG_FEATURES + if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R3_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R4_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R7_RESPONSE) + { + mcerr("ERROR: Wrong response CMD=%08" PRIx32 "\n", cmd); + ret = -EINVAL; + } + else +#endif + { + /* Check if a timeout occurred (Apparently a CRC error can terminate a + * good response) + */ + + regval = getreg32(priv->addr + IMX9_USDHC_IRQSTAT_OFFSET); + if (regval & USDHC_INT_CTOE) + { + mcerr("ERROR: Timeout IRQSTAT: %08" PRIx32 "\n", regval); + ret = -ETIMEDOUT; + } + } + + /* Return the short response in CMDRSP0 */ + + if (rshort) + { + *rshort = getreg32(priv->addr + IMX9_USDHC_CMDRSP0_OFFSET); + } + + return ret; +} + +/**************************************************************************** + * Name: imx9_waitenable + * + * Description: + * Enable/disable of a set of SDIO wait events. This is part of the + * the SDIO_WAITEVENT sequence. The set of to-be-waited-for events is + * configured before calling imx9_eventwait. This is done in this way + * to help the driver to eliminate race conditions between the command + * setup and the subsequent events. + * + * The enabled events persist until either (1) SDIO_WAITENABLE is called + * again specifying a different set of wait events, or (2) SDIO_EVENTWAIT + * returns. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * eventset - A bitset of events to enable or disable (see SDIOWAIT_* + * definitions). 0=disable; 1=enable. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_waitenable(struct sdio_dev_s *dev, + sdio_eventset_t eventset, uint32_t timeout) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + uint32_t waitints; + + DEBUGASSERT(priv != NULL); + + /* Disable event-related interrupts */ + + imx9_configwaitints(priv, 0, 0, 0); + + /* Select the interrupt mask that will give us the appropriate wakeup + * interrupts. + */ + + waitints = 0; + if ((eventset & (SDIOWAIT_CMDDONE | SDIOWAIT_RESPONSEDONE)) != 0) + { + waitints |= USDHC_RESPDONE_INTS; + } + + if ((eventset & SDIOWAIT_TRANSFERDONE) != 0) + { +#ifdef CONFIG_IMX9_USDHC_DMA + waitints |= USDHC_DMADONE_INTS; +#else + waitints |= USDHC_XFRDONE_INTS; +#endif + } + + /* Enable event-related interrupts */ + + imx9_configwaitints(priv, waitints, eventset, 0); + + /* Check if the timeout event is specified in the event set */ + + if ((priv->waitevents & SDIOWAIT_TIMEOUT) != 0) + { + int delay; + int ret; + + /* Yes.. Handle a corner case */ + + if (!timeout) + { + priv->wkupevent = SDIOWAIT_TIMEOUT; + return; + } + + /* Start the watchdog timer */ + + delay = MSEC2TICK(timeout); + ret = wd_start(&priv->waitwdog, delay, + imx9_eventtimeout, (wdparm_t)priv); + + if (ret < 0) + { + mcerr("ERROR: wd_start failed: %d\n", ret); + } + } +} + +/**************************************************************************** + * Name: imx9_eventwait + * + * Description: + * Wait for one of the enabled events to occur (or a timeout). Note that + * all events enabled by SDIO_WAITEVENTS are disabled when imx9_eventwait + * returns. SDIO_WAITEVENTS must be called again before imx9_eventwait + * can be used again. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * timeout - Maximum time in milliseconds to wait. Zero means immediate + * timeout with no wait. The timeout value is ignored if + * SDIOWAIT_TIMEOUT is not included in the waited-for eventset. + * + * Returned Value: + * Event set containing the event(s) that ended the wait. Should always + * be non-zero. All events are disabled after the wait concludes. + * + ****************************************************************************/ + +static sdio_eventset_t imx9_eventwait(struct sdio_dev_s *dev) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + sdio_eventset_t wkupevent = 0; int ret; + + /* There is a race condition here... the event may have completed before + * we get here. In this case waitevents will be zero, but wkupevents + * will be non-zero (and, hopefully, the semaphore count will also be + * non-zero. + */ + + DEBUGASSERT((priv->waitevents != 0 && priv->wkupevent == 0) || + (priv->waitevents == 0 && priv->wkupevent != 0)); + + /* Loop until the event (or the timeout occurs). Race conditions are + * avoided by calling imx9_waitenable prior to triggering the logic + * that will cause the wait to terminate. Under certain race + * conditions, the waited-for may have already occurred before this + * function was called! + */ + + for (; ; ) + { + /* Wait for an event in event set to occur. If this the event has + * already occurred, then the semaphore will already have been + * incremented and there will be no wait. + */ + + ret = nxsem_wait_uninterruptible(&priv->waitsem); + if (ret < 0) + { + /* Task canceled. Cancel the wdog (assuming it was started) and + * return an SDIO error. + */ + + wd_cancel(&priv->waitwdog); + return SDIOWAIT_ERROR; + } + + wkupevent = priv->wkupevent; + + /* Check if the event has occurred. When the event has occurred, then + * evenset will be set to 0 and wkupevent will be set to a non-zero + * value. + */ + + if (wkupevent != 0) + { + /* Yes... break out of the loop with wkupevent non-zero */ + + break; + } + } + + /* Disable event-related interrupts */ + + imx9_configwaitints(priv, 0, 0, 0); +#ifdef CONFIG_IMX9_USDHC_DMA + priv->xfrflags = 0; +#endif + imx9_dumpsamples(priv); + return wkupevent; +} + +/**************************************************************************** + * Name: imx9_callbackenable + * + * Description: + * Enable/disable of a set of SDIO callback events. This is part of the + * the SDIO callback sequence. The set of events is configured to enabled + * callbacks to the function provided in imx9_registercallback. + * + * Events are automatically disabled once the callback is performed and no + * further callback events will occur until they are again enabled by + * calling this method. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * eventset - A bitset of events to enable or disable (see SDIOMEDIA_* + * definitions). 0=disable; 1=enable. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void imx9_callbackenable(struct sdio_dev_s *dev, + sdio_eventset_t eventset) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + + mcinfo("eventset: %02x\n", eventset); + DEBUGASSERT(priv != NULL); + + priv->cbevents = eventset; + imx9_callback(priv); +} + +/**************************************************************************** + * Name: imx9_registercallback + * + * Description: + * Register a callback that that will be invoked on any media status + * change. Callbacks should not be made from interrupt handlers, rather + * interrupt level events should be handled by calling back on the work + * thread. + * + * When this method is called, all callbacks should be disabled until they + * are enabled via a call to SDIO_CALLBACKENABLE + * + * Input Parameters: + * dev - Device-specific state data + * callback - The function to call on the media change + * arg - A caller provided value to return with the callback + * + * Returned Value: + * 0 on success; negated errno on failure. + * + ****************************************************************************/ + +static int imx9_registercallback(struct sdio_dev_s *dev, + worker_t callback, void *arg) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + + /* Disable callbacks and register this callback and is argument */ + + mcinfo("Register %p(%p)\n", callback, arg); + + DEBUGASSERT(priv != NULL); + priv->cbevents = 0; + priv->cbarg = arg; + priv->callback = callback; + return OK; +} + +/**************************************************************************** + * Name: imx9_dmapreflight + * + * Description: + * Preflight an SDIO DMA operation. If the buffer is not well-formed for + * SDIO DMA transfer (alignment, size, etc.) returns an error. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - The memory to DMA to/from + * buflen - The size of the DMA transfer in bytes + * + * Returned Value: + * OK on success; a negated errno on failure + ****************************************************************************/ + +#if defined(CONFIG_IMX9_USDHC_DMA) && defined(CONFIG_ARCH_HAVE_SDIO_PREFLIGHT) +static int imx9_dmapreflight(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t buflen) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + DEBUGASSERT(priv != NULL && buflen > 0); + + /* DMA must be possible to the buffer and it must be word (4 bytes) aligned + */ + + if (buffer != priv->rxbuffer && ((uintptr_t)buffer & 3) != 0) + { + mcerr("non word aligned buffer:%p\n", buffer); + return -EFAULT; + } + +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) + /* buffer alignment is required for DMA transfers with dcache in buffered + * mode (not write-through) because a) arch_invalidate_dcache could lose + * buffered writes and b) arch_flush_dcache could corrupt adjacent memory + * if the maddr and the mend+1, the next next address are not on + * ARMV8A_DCACHE_LINESIZE boundaries. + */ + + if (buffer != priv->rxbuffer && + (((uintptr_t)buffer & (ARMV8A_DCACHE_LINESIZE - 1)) != 0 || + ((uintptr_t)(buffer + buflen) & (ARMV8A_DCACHE_LINESIZE - 1)) != 0)) + { + mcerr("dcache unaligned buffer:%p end:%p\n", + buffer, buffer + buflen - 1); + return -EFAULT; + } +#endif + + return 0; +} +#endif + +/**************************************************************************** + * Name: imx9_dmarecvsetup + * + * Description: + * Setup to perform a read DMA. If the processor supports a data cache, + * then this method will also make sure that the contents of the DMA memory + * and the data cache are coherent. For read transfers this may mean + * invalidating the data cache. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - The memory to DMA from + * buflen - The size of the DMA transfer in bytes + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_USDHC_DMA +static int imx9_dmarecvsetup(struct sdio_dev_s *dev, + uint8_t *buffer, size_t buflen) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); + +#if defined(CONFIG_ARCH_HAVE_SDIO_PREFLIGHT) + /* Normaly imx9_dmapreflight is called prior to imx9_dmarecvsetup + * except for the case where the CSR read is done at initalization + * + * With a total read size of less then priv->rxbuffer we can + * handle the unaligned case herein, using the rxbuffer. + * + * Any other case is a fault. + */ + + DEBUGASSERT(buflen <= sizeof(priv->rxbuffer) || + imx9_dmapreflight(dev, buffer, buflen) == 0); +#endif + + /* Begin sampling register values */ + + imx9_sampleinit(); + imx9_sample(priv, SAMPLENDX_BEFORE_SETUP); + +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) + if (((uintptr_t)buffer & (ARMV8A_DCACHE_LINESIZE - 1)) != 0 || + (buflen & (ARMV8A_DCACHE_LINESIZE - 1)) != 0) + { + /* The read buffer is not cache-line aligned, but will fit in + * the rxbuffer. So read to an internal buffer instead. + */ + + up_invalidate_dcache((uintptr_t)priv->rxbuffer, + (uintptr_t)priv->rxbuffer + priv->blocksize); + + priv->unaligned_rx = true; + } + else + { + up_invalidate_dcache((uintptr_t)buffer, + (uintptr_t)buffer + buflen); + + priv->unaligned_rx = false; + } +#endif + + /* Save the destination buffer information for use by the interrupt + * handler + */ + + priv->buffer = (uint32_t *)buffer; + priv->remaining = buflen; + + /* Then set up the SDIO data path */ + + imx9_dataconfig(priv, false, buflen, USDHC_DTOCV_MAXTIMEOUT); + + /* Configure the RX DMA */ + + imx9_configxfrints(priv, USDHC_DMADONE_INTS); +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) + if (priv->unaligned_rx) + { + putreg32((uint64_t) priv->rxbuffer, + priv->addr + IMX9_USDHC_DSADDR_OFFSET); + } + else +#endif + { + putreg32((uint64_t) priv->buffer, + priv->addr + IMX9_USDHC_DSADDR_OFFSET); + } + + /* Sample the register state */ + + imx9_sample(priv, SAMPLENDX_AFTER_SETUP); + return OK; +} +#endif + +/**************************************************************************** + * Name: imx9_dmasendsetup + * + * Description: + * Setup to perform a write DMA. If the processor supports a data cache, + * then this method will also make sure that the contents of the DMA memory + * and the data cache are coherent. For write transfers, this may mean + * flushing the data cache. + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * buffer - The memory to DMA into + * buflen - The size of the DMA transfer in bytes + * + * Returned Value: + * OK on success; a negated errno on failure + * + ****************************************************************************/ + +#ifdef CONFIG_IMX9_USDHC_DMA +static int imx9_dmasendsetup(struct sdio_dev_s *dev, + const uint8_t *buffer, size_t buflen) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); + DEBUGASSERT(((uint64_t) buffer & 3) == 0); + + /* Begin sampling register values */ + + imx9_sampleinit(); + imx9_sample(priv, SAMPLENDX_BEFORE_SETUP); + + /* Save the source buffer information for use by the interrupt handler */ + +#if !defined(CONFIG_ARM64_DCACHE_DISABLE) + priv->unaligned_rx = false; + + /* Flush cache to physical memory when not in DTCM memory */ + + up_clean_dcache((uintptr_t)buffer, (uintptr_t)buffer + buflen); + +#endif + priv->buffer = (uint32_t *)buffer; + priv->remaining = buflen; + + /* Then set up the SDIO data path */ + + imx9_dataconfig(priv, true, buflen, USDHC_DTOCV_MAXTIMEOUT); + + /* Configure the TX DMA */ + + putreg32((uint64_t) buffer, priv->addr + IMX9_USDHC_DSADDR_OFFSET); + + /* Sample the register state */ + + imx9_sample(priv, SAMPLENDX_AFTER_SETUP); + + /* Enable TX interrupts */ + + imx9_configxfrints(priv, USDHC_DMADONE_INTS); + return OK; +} +#endif + +/**************************************************************************** + * Name: imx9_callback + * + * Description: + * Perform callback. + * + * Assumptions: + * This function does not execute in the context of an interrupt handler. + * It may be invoked on any user thread or scheduled on the work thread + * from an interrupt handler. + * + ****************************************************************************/ + +static void imx9_callback(void *arg) +{ + struct imx9_dev_s *priv = (struct imx9_dev_s *)arg; + + /* Is a callback registered? */ + + DEBUGASSERT(priv != NULL); + mcinfo("Callback %p(%p) cbevents: %02x cdstatus: %02x\n", priv->callback, + priv->cbarg, priv->cbevents, priv->cdstatus); + + if (priv->callback) + { + /* Yes.. Check for enabled callback events */ + + if ((priv->cdstatus & SDIO_STATUS_PRESENT) != 0) + { + /* Media is present. Is the media inserted event enabled? */ + + if ((priv->cbevents & SDIOMEDIA_INSERTED) == 0) + { + /* No... return without performing the callback */ + + return; + } + } + else + { + /* Media is not present. Is the media eject event enabled? */ + + if ((priv->cbevents & SDIOMEDIA_EJECTED) == 0) + { + /* No... return without performing the callback */ + + return; + } + } + + /* Perform the callback, disabling further callbacks. Of course, the + * the callback can (and probably should) re-enable callbacks. + */ + + priv->cbevents = 0; + + /* Callbacks cannot be performed in the context of an interrupt + * handler. If we are in an interrupt handler, then queue the + * callback to be performed later on the work thread. + */ + + if (up_interrupt_context()) + { + /* Yes.. queue it */ + + mcinfo("Queuing callback to %p(%p)\n", + priv->callback, priv->cbarg); + + work_queue(HPWORK, &priv->cbwork, priv->callback, + priv->cbarg, 0); + } + else + { + /* No.. then just call the callback here */ + + mcinfo("Callback to %p(%p)\n", + priv->callback, priv->cbarg); + + priv->callback(priv->cbarg); + } + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_usdhc_set_sdio_card_isr + * + * Description: + * SDIO card generates interrupt via SDIO_DATA_1 pin. + * Called by board-specific logic to register an ISR for SDIO card. + * + * Input Parameters: + * func - callback function. + * arg - arg to be passed to the function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imx9_usdhc_set_sdio_card_isr(struct sdio_dev_s *dev, + int (*func)(void *), void *arg) +{ + irqstate_t flags; + uint32_t regval; + struct imx9_dev_s *priv = (struct imx9_dev_s *)dev; + + priv->do_sdio_card = func; + priv->do_sdio_arg = arg; + + if (priv->do_sdio_card != NULL) + { + priv->cintints = USDHC_INT_CINT; + } + else + { + priv->cintints = 0; + } + +#if defined(CONFIG_MMCSD_HAVE_CARDDETECT) + if (priv->sw_cd_gpio == 0) + { + priv->cintints |= USDHC_INT_CINS | USDHC_INT_CRM; + } +#endif + + flags = enter_critical_section(); + regval = getreg32(priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + regval = (regval & ~USDHC_INT_CINT) | priv->cintints; + putreg32(regval, priv->addr + IMX9_USDHC_IRQSIGEN_OFFSET); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: imx9_sdhc_initialize + * + * Description: + * Initialize SDIO for operation. + * + * Input Parameters: + * slotno - Slot to be used + * + * Returned Value: + * A reference to an SDIO interface structure. + * NULL is returned on failures. + * + ****************************************************************************/ + +struct sdio_dev_s *imx9_usdhc_initialize(int slotno) +{ + DEBUGASSERT(slotno < IMX9_MAX_SDHC_DEV_SLOTS); + struct imx9_dev_s *priv = &g_sdhcdev[slotno]; + + /* Initialize the USDHC slot structure data structure */ + + switch (priv->addr) + { +#if defined(CONFIG_IMX9_USDHC1) + case IMX9_USDHC1_BASE: + +# if defined(CONFIG_IMX9_USDHC1_WIDTH_D1_D4) || defined(CONFIG_IMX9_USDHC1_WIDTH_D1_D8) + imx9_iomux_configure(PIN_USDHC1_D1_MUX); + imx9_iomux_configure(PIN_USDHC1_D2_MUX); + imx9_iomux_configure(PIN_USDHC1_D3_MUX); +# endif + +# if defined(CONFIG_IMX9_USDHC1_WIDTH_D1_D8) + imx9_iomux_configure(PIN_USDHC1_D4_MUX); + imx9_iomux_configure(PIN_USDHC1_D5_MUX); + imx9_iomux_configure(PIN_USDHC1_D6_MUX); + imx9_iomux_configure(PIN_USDHC1_D7_MUX); +# endif + + /* Clocking and CMD pins (all data widths) */ + + imx9_iomux_configure(PIN_USDHC1_D0_MUX); + imx9_iomux_configure(PIN_USDHC1_DCLK_MUX); + imx9_iomux_configure(PIN_USDHC1_CMD_MUX); + +# if defined(CONFIG_MMCSD_HAVE_CARDDETECT) +# if defined(PIN_USDHC1_CD) + imx9_iomux_configure(PIN_USDHC1_CD_MUX); +# elif defined (PIN_USDHC2_CD_GPIO) + if (priv->sw_cd_gpio != 0) + { + imx9_config_gpio(priv->sw_cd_gpio); + imx9_iomux_configure(PIN_USDHC1_CD_GPIO_MUX); + } +# endif +# endif + + /* Enable clocks */ + + imx9_ccm_configure_root_clock(CCM_CR_USDHC2, SYS_PLL1PFD1, 4); + + imx9_ccm_gate_on(CCM_LPCG_USDHC1, true); + + break; +#endif + +#if defined(CONFIG_IMX9_USDHC2) + case IMX9_USDHC2_BASE: +# if defined(CONFIG_IMX9_USDHC2_WIDTH_D1_D4) + imx9_iomux_configure(PIN_USDHC2_D1_MUX); + imx9_iomux_configure(PIN_USDHC2_D2_MUX); + imx9_iomux_configure(PIN_USDHC2_D3_MUX); +# endif + + imx9_iomux_configure(PIN_USDHC2_D0_MUX); + imx9_iomux_configure(PIN_USDHC2_DCLK_MUX); + imx9_iomux_configure(PIN_USDHC2_CMD_MUX); + +# if defined(CONFIG_MMCSD_HAVE_CARDDETECT) +# if defined(PIN_USDHC2_CD) + imx9_iomux_configure(PIN_USDHC2_CD_MUX); +# elif defined (PIN_USDHC2_CD_GPIO) + if (priv->sw_cd_gpio != 0) + { + imx9_config_gpio(priv->sw_cd_gpio); + imx9_iomux_configure(PIN_USDHC2_CD_GPIO_MUX); + } +# endif +# endif + + imx9_iomux_configure(PIN_USDHC2_VSELECT_MUX); + + /* Enable clocks */ + + imx9_ccm_configure_root_clock(CCM_CR_USDHC2, SYS_PLL1PFD1, 4); + + imx9_ccm_gate_on(CCM_LPCG_USDHC2, true); + + mcinfo("Enabled clocks\n"); + + break; +#endif + default: + return NULL; + } + + imx9_reset(&priv->dev); + imx9_showregs(priv, "After reset"); + + return &g_sdhcdev[slotno].dev; +} + +#endif /* CONFIG_IMX9_USDHC */ diff --git a/arch/arm64/src/imx9/imx9_usdhc.h b/arch/arm64/src/imx9/imx9_usdhc.h new file mode 100644 index 0000000000000..0b830914e2805 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_usdhc.h @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx9_usdhc.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_USDHC_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_USDHC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "chip.h" +#include "hardware/imx9_usdhc.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_usdhc_set_sdio_card_isr + * + * Description: + * SDIO card generates interrupt via SDIO_DATA_1 pin. + * Called by board-specific logic to register an ISR for SDIO card. + * + * Input Parameters: + * func - callback function. + * arg - arg to be passed to the function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imx9_usdhc_set_sdio_card_isr(struct sdio_dev_s *dev, + int (*func)(void *), void *arg); + +/**************************************************************************** + * Name: imx9_usdhc_initialize + * + * Description: + * Initialize USDHC for operation. + * + * Input Parameters: + * slotno - Not used. + * + * Returned Value: + * A reference to an USDIO interface structure. NULL is returned on + * failures. + * + ****************************************************************************/ + +struct sdio_dev_s *imx9_usdhc_initialize(int slotno); + +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_USDHC_H */ diff --git a/arch/risc-v/include/irq.h b/arch/risc-v/include/irq.h index 9d587b6d3d980..cb8266ff42722 100644 --- a/arch/risc-v/include/irq.h +++ b/arch/risc-v/include/irq.h @@ -96,14 +96,6 @@ /* Configuration ************************************************************/ -/* If this is a kernel build, how many nested system calls should we - * support? - */ - -#ifndef CONFIG_SYS_NNEST -# define CONFIG_SYS_NNEST 2 -#endif - /* Processor PC */ #define REG_EPC_NDX 0 @@ -500,18 +492,6 @@ #ifndef __ASSEMBLY__ -/* This structure represents the return state from a system call */ - -#ifdef CONFIG_LIB_SYSCALL -struct xcpt_syscall_s -{ - uintptr_t sysreturn; /* The return PC */ -#ifndef CONFIG_BUILD_FLAT - uintptr_t int_ctx; /* Interrupt context (i.e. m-/sstatus) */ -#endif -}; -#endif - /* The following structure is included in the TCB and defines the complete * state of the thread. */ @@ -543,16 +523,6 @@ struct xcptcontext uintptr_t sigreturn; #endif -#ifdef CONFIG_LIB_SYSCALL - /* The following array holds information needed to return from each nested - * system call. - */ - - uint8_t nsyscalls; - struct xcpt_syscall_s syscall[CONFIG_SYS_NNEST]; - -#endif - #ifdef CONFIG_ARCH_ADDRENV #ifdef CONFIG_ARCH_KERNEL_STACK /* In this configuration, all syscalls execute from an internal kernel diff --git a/arch/risc-v/include/syscall.h b/arch/risc-v/include/syscall.h index c7d5375a44eeb..9d22006760810 100644 --- a/arch/risc-v/include/syscall.h +++ b/arch/risc-v/include/syscall.h @@ -77,15 +77,6 @@ #define SYS_switch_context (2) -#ifdef CONFIG_LIB_SYSCALL -/* SYS call 3: - * - * void riscv_syscall_return(void); - */ - -#define SYS_syscall_return (3) -#endif /* CONFIG_LIB_SYSCALL */ - #ifndef CONFIG_BUILD_FLAT /* SYS call 4: * diff --git a/arch/risc-v/src/common/riscv_addrenv.c b/arch/risc-v/src/common/riscv_addrenv.c index f26a5d11c2869..42417788c576a 100644 --- a/arch/risc-v/src/common/riscv_addrenv.c +++ b/arch/risc-v/src/common/riscv_addrenv.c @@ -65,6 +65,7 @@ #include #include #include +#include #include @@ -421,6 +422,12 @@ int up_addrenv_create(size_t textsize, size_t datasize, size_t heapsize, heapsize = heapsize + MM_PGALIGNUP(CONFIG_DEFAULT_TASK_STACKSIZE); +#ifdef CONFIG_TLS_ALIGNED + /* Need more stack for TLS alignment */ + + heapsize += MM_PGALIGNUP(2 * TLS_MAXSTACK); +#endif + /* Map the reserved area */ ret = create_region(addrenv, resvbase, resvsize, MMU_UDATA_FLAGS); diff --git a/arch/risc-v/src/common/riscv_addrenv_pgmap.c b/arch/risc-v/src/common/riscv_addrenv_pgmap.c index da9e250e7652f..08335387a0295 100644 --- a/arch/risc-v/src/common/riscv_addrenv_pgmap.c +++ b/arch/risc-v/src/common/riscv_addrenv_pgmap.c @@ -147,6 +147,26 @@ bool up_addrenv_user_vaddr(uintptr_t vaddr) return riscv_uservaddr(vaddr); } +/**************************************************************************** + * Name: up_addrenv_page_wipe + * + * Description: + * Wipe a page of physical memory, first mapping it into kernel virtual + * memory. + * + * Input Parameters: + * page - The page physical address. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +void up_addrenv_page_wipe(uintptr_t page) +{ + riscv_pgwipe(page); +} + #ifdef CONFIG_MM_KMAP /**************************************************************************** @@ -178,7 +198,7 @@ int up_addrenv_kmap_init(void) next = g_kernel_pgt_pbase; vaddr = CONFIG_ARCH_KMAP_VBASE; - for (i = 0; i < (ARCH_SPGTS - 1); i++) + for (i = 0; i < ARCH_SPGTS; i++) { /* Connect the static page tables */ @@ -191,6 +211,10 @@ int up_addrenv_kmap_init(void) addrenv->satp = mmu_satp_reg(g_kernel_pgt_pbase, 0); + /* When all is set and done, flush the data caches */ + + __DMB(); + return OK; } diff --git a/arch/risc-v/src/common/riscv_exception.c b/arch/risc-v/src/common/riscv_exception.c index f560a60b0a0be..bb81e6066da44 100644 --- a/arch/risc-v/src/common/riscv_exception.c +++ b/arch/risc-v/src/common/riscv_exception.c @@ -31,6 +31,7 @@ #include #include +#include "sched/sched.h" #include "riscv_internal.h" #include "chip.h" @@ -72,6 +73,9 @@ static const char *g_reasons_str[RISCV_MAX_EXCEPTION + 1] = int riscv_exception(int mcause, void *regs, void *args) { +#ifdef CONFIG_ARCH_KERNEL_STACK + FAR struct tcb_s *tcb = this_task(); +#endif uintptr_t cause = mcause & RISCV_IRQ_MASK; _alert("EXCEPTION: %s. MCAUSE: %" PRIxREG ", EPC: %" PRIxREG @@ -79,10 +83,33 @@ int riscv_exception(int mcause, void *regs, void *args) mcause > RISCV_MAX_EXCEPTION ? "Unknown" : g_reasons_str[cause], cause, READ_CSR(CSR_EPC), READ_CSR(CSR_TVAL)); - _alert("PANIC!!! Exception = %" PRIxREG "\n", cause); - up_irq_save(); - CURRENT_REGS = regs; - PANIC_WITH_REGS("panic", regs); +#ifdef CONFIG_ARCH_KERNEL_STACK + if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) + { + _alert("Segmentation fault in PID %d: %s\n", tcb->pid, tcb->name); + + tcb->flags |= TCB_FLAG_FORCED_CANCEL; + + /* Return to _exit function in privileged mode with argument SIGSEGV */ + + CURRENT_REGS[REG_EPC] = (uintptr_t)_exit; + CURRENT_REGS[REG_A0] = SIGSEGV; + CURRENT_REGS[REG_INT_CTX] |= STATUS_PPP; + + /* Continue with kernel stack in use. The frame(s) in kernel stack + * are no longer needed, so just set it to top + */ + + CURRENT_REGS[REG_SP] = (uintptr_t)tcb->xcp.ktopstk; + } + else +#endif + { + _alert("PANIC!!! Exception = %" PRIxREG "\n", cause); + up_irq_save(); + CURRENT_REGS = regs; + PANIC_WITH_REGS("panic", regs); + } return 0; } diff --git a/arch/risc-v/src/common/riscv_exception_common.S b/arch/risc-v/src/common/riscv_exception_common.S index 9d78b65c09673..c058bdac49aa8 100644 --- a/arch/risc-v/src/common/riscv_exception_common.S +++ b/arch/risc-v/src/common/riscv_exception_common.S @@ -30,6 +30,10 @@ #include +#ifdef CONFIG_LIB_SYSCALL +# include +#endif + #include "chip.h" #include "riscv_percpu.h" @@ -72,6 +76,8 @@ .section EXCEPTION_SECTION .global exception_common + .global return_from_exception + .global return_from_syscall .align 8 exception_common: @@ -98,24 +104,69 @@ exception_common: addi sp, sp, -XCPTCONTEXT_SIZE save_ctx sp - csrr s0, CSR_STATUS - REGSTORE s0, REG_INT_CTX(sp) /* status */ + csrr s0, CSR_STATUS /* s0=status */ + csrr s1, CSR_EPC /* s1=exception PC */ + csrr s2, CSR_CAUSE /* s2=cause */ #ifdef CONFIG_ARCH_KERNEL_STACK - csrr s0, CSR_SCRATCH - REGLOAD s0, RISCV_PERCPU_USP(s0) + csrr s3, CSR_SCRATCH + REGLOAD s3, RISCV_PERCPU_USP(s3) #else - addi s0, sp, XCPTCONTEXT_SIZE + addi s3, sp, XCPTCONTEXT_SIZE #endif - REGSTORE s0, REG_X2(sp) /* original SP */ + REGSTORE s0, REG_INT_CTX(sp) + REGSTORE s1, REG_EPC(sp) + REGSTORE s3, REG_SP(sp) + +#ifdef CONFIG_LIB_SYSCALL + /* Check whether it is an exception or interrupt */ + + blt s2, x0, handle_irq /* If cause < 0 it is interrupt */ + + /* Is it a system call ? */ + + li s3, RISCV_IRQ_ECALLU /* Is it a system call ? */ + bne s2, s3, handle_irq + + /* Is it one of the reserved system calls ? */ + + li s3, CONFIG_SYS_RESERVED + blt a0, s3, handle_irq /* If a0 < CONFIG_SYS_RESERVED */ + + /* It is a system call, re-enable interrupts if they were enabled */ + + andi s3, s0, STATUS_PIE + beqz s3, 1f + csrs CSR_STATUS, STATUS_IE + +1: + addi s1, s1, 0x4 /* Must move EPC forward by +4 */ + REGSTORE s1, REG_EPC(sp) /* Updated EPC to user context */ - csrr s0, CSR_EPC - REGSTORE s0, REG_EPC(sp) /* exception PC */ + csrr tp, CSR_SCRATCH /* Load kernel TP */ + REGLOAD tp, RISCV_PERCPU_TCB(tp) + + call x1, dispatch_syscall /* Dispatch the system call */ + +return_from_syscall: + + /* System call is done, disable interrupts */ + + csrc CSR_STATUS, STATUS_IE + + /* Clean up after system call */ + + REGSTORE a0, REG_A0(sp) /* Syscall return value to user context */ + mv a0, sp /* Return to same context */ + tail return_from_exception + +handle_irq: +#endif /* Setup arg0(exception cause), arg1(context) */ - csrr a0, CSR_CAUSE /* exception cause */ + mv a0, s2 /* exception cause */ mv a1, sp /* context = sp */ #if CONFIG_ARCH_INTERRUPTSTACK > 15 @@ -142,6 +193,8 @@ exception_common: addi sp, sp, XCPTCONTEXT_SIZE #endif +return_from_exception: + /* If context switch is needed, return a new sp */ mv sp, a0 @@ -149,9 +202,17 @@ exception_common: REGLOAD s0, REG_EPC(sp) /* restore sepc */ csrw CSR_EPC, s0 - REGLOAD s0, REG_INT_CTX(sp) /* restore sstatus */ + REGLOAD s0, REG_INT_CTX(sp) /* restore status */ csrw CSR_STATUS, s0 +#ifdef CONFIG_LIB_SYSCALL + /* Store tcb to scratch register */ + + call x1, nxsched_self + csrr s1, CSR_SCRATCH + REGSTORE a0, RISCV_PERCPU_TCB(s1) +#endif + #ifdef CONFIG_ARCH_KERNEL_STACK /* Returning to userspace ? */ diff --git a/arch/risc-v/src/common/riscv_fork.c b/arch/risc-v/src/common/riscv_fork.c index 0dd41aecdc1eb..0c19f9f19c254 100644 --- a/arch/risc-v/src/common/riscv_fork.c +++ b/arch/risc-v/src/common/riscv_fork.c @@ -246,29 +246,6 @@ pid_t riscv_fork(const struct fork_s *context) fregs[REG_FS11] = context->fs11; /* Saved register fs11 */ #endif -#ifdef CONFIG_LIB_SYSCALL - /* If we got here via a syscall, then we are going to have to setup some - * syscall return information as well. - */ - - if (parent->xcp.nsyscalls > 0) - { - int index; - for (index = 0; index < parent->xcp.nsyscalls; index++) - { - child->cmn.xcp.syscall[index].sysreturn = - parent->xcp.syscall[index].sysreturn; - -#ifndef CONFIG_BUILD_FLAT - child->cmn.xcp.syscall[index].int_ctx = - parent->xcp.syscall[index].int_ctx; -#endif - } - - child->cmn.xcp.nsyscalls = parent->xcp.nsyscalls; - } -#endif /* CONFIG_LIB_SYSCALL */ - /* And, finally, start the child task. On a failure, nxtask_start_fork() * will discard the TCB by calling nxtask_abort_fork(). */ diff --git a/arch/risc-v/src/common/riscv_internal.h b/arch/risc-v/src/common/riscv_internal.h index ac16c0bd87f93..ff1ef5aebb88a 100644 --- a/arch/risc-v/src/common/riscv_internal.h +++ b/arch/risc-v/src/common/riscv_internal.h @@ -363,16 +363,6 @@ void *riscv_perform_syscall(uintptr_t *regs); #define riscv_switchcontext(prev, next) \ sys_call2(SYS_switch_context, (uintptr_t)prev, (uintptr_t)next) -#ifdef CONFIG_BUILD_KERNEL -/* SYS call 3: - * - * void riscv_syscall_return(void); - */ - -#define riscv_syscall_return() sys_call0(SYS_syscall_return) - -#endif /* CONFIG_BUILD_KERNEL */ - #undef EXTERN #ifdef __cplusplus } diff --git a/arch/risc-v/src/common/riscv_percpu.c b/arch/risc-v/src/common/riscv_percpu.c index 458682746ac9a..52e855b85ddc5 100644 --- a/arch/risc-v/src/common/riscv_percpu.c +++ b/arch/risc-v/src/common/riscv_percpu.c @@ -43,10 +43,16 @@ #define HART_CNT (CONFIG_SMP_NCPUS) #define STACK_SIZE (STACK_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK)) +static_assert(RISCV_PERCPU_TCB == offsetof(riscv_percpu_t, tcb), + "RISCV_PERCPU_TCB offset is wrong"); static_assert(RISCV_PERCPU_HARTID == offsetof(riscv_percpu_t, hartid), "RISCV_PERCPU_HARTID offset is wrong"); static_assert(RISCV_PERCPU_IRQSTACK == offsetof(riscv_percpu_t, irq_stack), "RISCV_PERCPU_IRQSTACK offset is wrong"); +static_assert(RISCV_PERCPU_USP == offsetof(riscv_percpu_t, usp), + "RISCV_PERCPU_USP offset is wrong"); +static_assert(RISCV_PERCPU_KSP == offsetof(riscv_percpu_t, ksp), + "RISCV_PERCPU_KSP offset is wrong"); /**************************************************************************** * Private Data @@ -224,3 +230,35 @@ void riscv_percpu_set_kstack(uintptr_t ksp) ((riscv_percpu_t *)scratch)->ksp = ksp; leave_critical_section(flags); } + +/**************************************************************************** + * Name: riscv_percpu_set_thread + * + * Description: + * Set current thread (tcb), so it can be found quickly when a trap is + * taken. + * + * Input Parameters: + * tcb - Pointer to the current thread's tcb + * + * Returned Value: + * None + * + ****************************************************************************/ + +void riscv_percpu_set_thread(struct tcb_s *tcb) +{ + irqstate_t flags; + uintptr_t scratch; + + /* This must be done with interrupts disabled */ + + flags = enter_critical_section(); + scratch = READ_CSR(CSR_SCRATCH); + + DEBUGASSERT(scratch >= (uintptr_t) &g_percpu && + scratch < (uintptr_t) &g_percpu + sizeof(g_percpu)); + + ((riscv_percpu_t *)scratch)->tcb = tcb; + leave_critical_section(flags); +} diff --git a/arch/risc-v/src/common/riscv_percpu.h b/arch/risc-v/src/common/riscv_percpu.h index cc09fe0b24070..147e6c143d72f 100644 --- a/arch/risc-v/src/common/riscv_percpu.h +++ b/arch/risc-v/src/common/riscv_percpu.h @@ -47,7 +47,7 @@ * 2: REGLOAD a0, RISCV_PERCPU_HARTID(a0) */ -#define RISCV_PERCPU_LIST (0 * INT_REG_SIZE) +#define RISCV_PERCPU_TCB (0 * INT_REG_SIZE) #define RISCV_PERCPU_HARTID (1 * INT_REG_SIZE) #define RISCV_PERCPU_IRQSTACK (2 * INT_REG_SIZE) #define RISCV_PERCPU_USP (3 * INT_REG_SIZE) @@ -65,16 +65,20 @@ * will set up [m/s]scratch to point to the CPUs own area */ -struct riscv_percpu_s +union riscv_percpu_s { - struct riscv_percpu_s *next; /* For sl list linkage */ - uintptr_t hartid; /* Hart ID */ - uintptr_t irq_stack; /* Interrupt stack */ - uintptr_t usp; /* Area to store user sp */ - uintptr_t ksp; /* Area to load kernel sp */ + union riscv_percpu_s *next; /* For sl list linkage */ + struct + { + struct tcb_s *tcb; /* Current thread TCB */ + uintptr_t hartid; /* Hart ID */ + uintptr_t irq_stack; /* Interrupt stack */ + uintptr_t usp; /* Area to store user sp */ + uintptr_t ksp; /* Area to load kernel sp */ + }; }; -typedef struct riscv_percpu_s riscv_percpu_t; +typedef union riscv_percpu_s riscv_percpu_t; /**************************************************************************** * Public Function Prototypes @@ -137,5 +141,22 @@ uintptr_t riscv_percpu_get_irqstack(void); void riscv_percpu_set_kstack(uintptr_t ksp); +/**************************************************************************** + * Name: riscv_percpu_set_thread + * + * Description: + * Set current thread (tcb), so it can be found quickly when a trap is + * taken. + * + * Input Parameters: + * tcb - Pointer to the current thread's tcb + * + * Returned Value: + * None + * + ****************************************************************************/ + +void riscv_percpu_set_thread(struct tcb_s *tcb); + #endif /* __ASSEMBLY__ */ #endif /* __ARCH_RISC_V_SRC_COMMON_RISCV_PERCPU_H */ diff --git a/arch/risc-v/src/common/riscv_pmp.c b/arch/risc-v/src/common/riscv_pmp.c index e6074b5154b02..1114390d5eb18 100644 --- a/arch/risc-v/src/common/riscv_pmp.c +++ b/arch/risc-v/src/common/riscv_pmp.c @@ -134,9 +134,9 @@ static bool pmp_check_region_attrs(uintptr_t base, uintptr_t size, case PMPCFG_A_NAPOT: { - /* For NAPOT, both base and size must be properly aligned */ + /* For NAPOT, Naturally aligned power-of-two region, >= 8 bytes */ - if ((base & 0x07) != 0 || size < 8) + if ((base & 0x07) != 0 || size < 8 || (size & (size - 1)) != 0) { return false; } diff --git a/arch/risc-v/src/common/riscv_swint.c b/arch/risc-v/src/common/riscv_swint.c index 0a262fe700328..5177cec5bd4eb 100644 --- a/arch/risc-v/src/common/riscv_swint.c +++ b/arch/risc-v/src/common/riscv_swint.c @@ -48,10 +48,16 @@ * Pre-processor Definitions ****************************************************************************/ +#ifdef CONFIG_LIB_SYSCALL +# define TCB_FLAGS_OFFSET offsetof(struct tcb_s, flags) +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ +#ifdef CONFIG_LIB_SYSCALL + /**************************************************************************** * Name: dispatch_syscall * @@ -69,14 +75,38 @@ * ****************************************************************************/ -#ifdef CONFIG_LIB_SYSCALL -static void dispatch_syscall(void) naked_function; -static void dispatch_syscall(void) +uintptr_t dispatch_syscall(unsigned int nbr, uintptr_t parm1, + uintptr_t parm2, uintptr_t parm3, + uintptr_t parm4, uintptr_t parm5, + uintptr_t parm6) { + register long a0 asm("a0") = (long)(nbr); + register long a1 asm("a1") = (long)(parm1); + register long a2 asm("a2") = (long)(parm2); + register long a3 asm("a3") = (long)(parm3); + register long a4 asm("a4") = (long)(parm4); + register long a5 asm("a5") = (long)(parm5); + register long a6 asm("a6") = (long)(parm6); + + uintptr_t ret; + + /* Valid system call ? */ + + if (a0 > SYS_maxsyscall) + { + /* Nope, get out */ + + return -ENOSYS; + } + + /* ra gets clobbered below, but it does not matter */ + asm volatile ( - "addi sp, sp, -" STACK_FRAME_SIZE "\n" /* Create a stack frame to hold ra */ - REGSTORE " ra, 0(sp)\n" /* Save ra in the stack frame */ + REGLOAD " t0, %1(tp)\n" /* Load tcb->flags */ + "ori t0, t0, %2\n" /* tcb->flags |= TCB_FLAG_SYSCALL */ + REGSTORE " t0, %1(tp)\n" + "addi a0, a0, -%3\n" /* Offset a0 to account for the reserved syscalls */ "la t0, g_stublookup\n" /* t0=The base of the stub lookup table */ #ifdef CONFIG_ARCH_RV32 "slli a0, a0, 2\n" /* a0=Offset for the stub lookup table */ @@ -86,16 +116,26 @@ static void dispatch_syscall(void) "add t0, t0, a0\n" /* t0=The address in the table */ REGLOAD " t0, 0(t0)\n" /* t0=The address of the stub for this syscall */ "jalr ra, t0\n" /* Call the stub (modifies ra) */ - REGLOAD " ra, 0(sp)\n" /* Restore ra */ - "addi sp, sp, " STACK_FRAME_SIZE "\n" /* Destroy the stack frame */ - "mv a2, a0\n" /* a2=Save return value in a0 */ - "li a0, 3\n" /* a0=SYS_syscall_return (3) */ -#ifdef CONFIG_ARCH_USE_S_MODE - "j sys_call2" /* Return from the syscall */ -#else - "ecall" /* Return from the syscall */ -#endif + REGLOAD " t0, %1(tp)\n" /* Load tcb->flags */ + "andi t0, t0, ~%2\n" /* tcb->flags &= ~TCB_FLAG_SYSCALL */ + REGSTORE " t0, %1(tp)\n" + : "+r"(a0) + : "i"(TCB_FLAGS_OFFSET), + "i"(TCB_FLAG_SYSCALL), + "i"(CONFIG_SYS_RESERVED), + "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6) + : "t0", "memory" ); + + /* a0 gets clobbered below, save it locally here */ + + ret = a0; + + /* Unmask any pending signals now */ + + nxsig_unmask_pendingsignal(); + + return ret; } #endif @@ -185,70 +225,6 @@ int riscv_swint(int irq, void *context, void *arg) } break; - /* A0=SYS_syscall_return: This is a SYSCALL return command: - * - * void up_sycall_return(void); - * - * At this point, the following values are saved in context: - * - * A0 = SYS_syscall_return - * - * We need to restore the saved return address and return in - * unprivileged thread mode. - */ - -#ifdef CONFIG_LIB_SYSCALL - case SYS_syscall_return: - { - struct tcb_s *rtcb = nxsched_self(); - int index = (int)rtcb->xcp.nsyscalls - 1; - - /* Make sure that there is a saved syscall return address. */ - - DEBUGASSERT(index >= 0); - - /* Setup to return to the saved syscall return address in - * the original mode. - */ - - regs[REG_EPC] = rtcb->xcp.syscall[index].sysreturn; -#ifndef CONFIG_BUILD_FLAT - regs[REG_INT_CTX] = rtcb->xcp.syscall[index].int_ctx; -#endif - - /* The return value must be in A0-A1. - * dispatch_syscall() temporarily moved the value for R0 into A2. - */ - - regs[REG_A0] = regs[REG_A2]; - -#ifdef CONFIG_ARCH_KERNEL_STACK - /* If this is the outermost SYSCALL and if there is a saved user - * stack pointer, then restore the user stack pointer on this - * final return to user code. - */ - - if (index == 0 && rtcb->xcp.ustkptr != NULL) - { - regs[REG_SP] = (uintptr_t)rtcb->xcp.ustkptr; - rtcb->xcp.ustkptr = NULL; - } -#endif - - /* Save the new SYSCALL nesting level */ - - rtcb->xcp.nsyscalls = index; - - /* Handle any signal actions that were deferred while processing - * the system call. - */ - - rtcb->flags &= ~TCB_FLAG_SYSCALL; - nxsig_unmask_pendingsignal(); - } - break; -#endif - /* R0=SYS_task_start: This a user task start * * void up_task_start(main_t taskentry, int argc, @@ -391,6 +367,7 @@ int riscv_swint(int irq, void *context, void *arg) if (rtcb->xcp.kstack != NULL) { uintptr_t usp; + uintptr_t *usr_regs; /* Store the current kernel stack pointer so it is not lost */ @@ -398,7 +375,9 @@ int riscv_swint(int irq, void *context, void *arg) /* Copy "info" into user stack */ - usp = rtcb->xcp.saved_regs[REG_SP]; + usr_regs = (uintptr_t *)((uintptr_t)rtcb->xcp.ktopstk - + XCPTCONTEXT_SIZE); + usp = usr_regs[REG_SP]; /* Create a frame for info and copy the kernel info */ @@ -454,66 +433,9 @@ int riscv_swint(int irq, void *context, void *arg) break; #endif - /* This is not an architecture-specify system call. If NuttX is built - * as a standalone kernel with a system call interface, then all of the - * additional system calls must be handled as in the default case. - */ - default: - { -#ifdef CONFIG_LIB_SYSCALL - struct tcb_s *rtcb = nxsched_self(); - int index = rtcb->xcp.nsyscalls; - - /* Verify that the SYS call number is within range */ - - DEBUGASSERT(CURRENT_REGS[REG_A0] < SYS_maxsyscall); - - /* Make sure that we got here that there is a no saved syscall - * return address. We cannot yet handle nested system calls. - */ - - DEBUGASSERT(index < CONFIG_SYS_NNEST); - - /* Setup to return to dispatch_syscall in privileged mode. */ - rtcb->xcp.syscall[index].sysreturn = regs[REG_EPC]; -#ifndef CONFIG_BUILD_FLAT - rtcb->xcp.syscall[index].int_ctx = regs[REG_INT_CTX]; -#endif - - rtcb->xcp.nsyscalls = index + 1; - - regs[REG_EPC] = (uintptr_t)dispatch_syscall; - -#ifndef CONFIG_BUILD_FLAT - regs[REG_INT_CTX] |= STATUS_PPP; /* Privileged mode */ -#endif - - /* Offset A0 to account for the reserved values */ - - regs[REG_A0] -= CONFIG_SYS_RESERVED; - - /* Indicate that we are in a syscall handler. */ - - rtcb->flags |= TCB_FLAG_SYSCALL; -#else - svcerr("ERROR: Bad SYS call: %" PRIdPTR "\n", regs[REG_A0]); -#endif - -#ifdef CONFIG_ARCH_KERNEL_STACK - /* If this is the first level system call, we must store the user - * stack pointer so it doesn't get lost. - */ - - if (index == 0 && rtcb->xcp.kstack != NULL) - { - DEBUGASSERT(rtcb->xcp.ustkptr == NULL); - rtcb->xcp.ustkptr = (uintptr_t *)regs[REG_SP]; - regs[REG_SP] = (uintptr_t)regs; - } -#endif - } + DEBUGPANIC(); break; } diff --git a/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c b/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c index 88d8be77ee2e3..d1bf8503b4c0e 100644 --- a/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c +++ b/arch/risc-v/src/common/supervisor/riscv_perform_syscall.c @@ -28,6 +28,7 @@ #include +#include "sched/sched.h" #include "riscv_internal.h" /**************************************************************************** @@ -59,6 +60,12 @@ void *riscv_perform_syscall(uintptr_t *regs) if (regs != CURRENT_REGS) { + /* Record the new "running" task. g_running_tasks[] is only used by + * assertion logic for reporting crashes. + */ + + g_running_tasks[this_cpu()] = this_task(); + /* Restore the cpu lock */ restore_critical_section(); diff --git a/arch/risc-v/src/common/supervisor/riscv_syscall.S b/arch/risc-v/src/common/supervisor/riscv_syscall.S index 3e4515fea7736..bda64d3de2cfb 100644 --- a/arch/risc-v/src/common/supervisor/riscv_syscall.S +++ b/arch/risc-v/src/common/supervisor/riscv_syscall.S @@ -119,52 +119,8 @@ sys_call6: /* Run the handler */ - jal x1, riscv_perform_syscall - - /* Restore (potentially new) context */ - - mv sp, a0 /* use sp, as a0 gets wiped */ - - REGLOAD s0, REG_EPC(sp) /* restore epc */ - csrw CSR_EPC, s0 - - /* Restore status register, but don't enable interrupts yet */ - - REGLOAD s0, REG_INT_CTX(sp) /* restore status */ - li s1, STATUS_IE /* move IE -> PIE */ - and s1, s0, s1 /* if (STATUS & IE) */ - beqz s1, 1f - li s1, ~STATUS_IE /* clear IE */ - and s0, s0, s1 - li s1, STATUS_PIE /* set PIE */ - or s0, s0, s1 - -1: - csrw CSR_STATUS, s0 - -#ifdef CONFIG_ARCH_KERNEL_STACK - /* Returning to userspace ? */ - - li s1, STATUS_PPP - and s0, s0, s1 - bnez s0, 1f - - /* Set the next task's kernel stack to the scratch area */ - - jal x1, riscv_current_ksp - csrr s0, CSR_SCRATCH - REGSTORE a0, RISCV_PERCPU_KSP(s0) - -1: -#endif - - load_ctx sp - - REGLOAD sp, REG_SP(sp) /* restore original sp */ - - /* return from exception, which updates the status register */ - - ERET + la x1, return_from_exception + tail riscv_perform_syscall .size sys_call0, .-sys_call0 .size sys_call1, .-sys_call1 diff --git a/arch/risc-v/src/mpfs/.gitignore b/arch/risc-v/src/mpfs/.gitignore new file mode 100644 index 0000000000000..b099a95f78380 --- /dev/null +++ b/arch/risc-v/src/mpfs/.gitignore @@ -0,0 +1 @@ +/crypto diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 9ba677b2acf52..532e9f7f720a2 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -52,7 +52,8 @@ config MPFS_BOARD_PMP default n ---help--- If true, the board must provide "mpfs_board_pmp_setup" for PMP - configuration. If false, set ALL memory accessible for every + configuration and "mpfs_board_pmp_error" for PMP error handling. + If false, set ALL memory accessible for every configured HART. Only the bootloader should do this. config MPFS_OPENSBI @@ -252,15 +253,48 @@ config MPFS_HAVE_UART4 select UART4_SERIALDRIVER select ARCH_HAVE_SERIAL_TERMIOS +config MPFS_HAVE_UART5 + bool + depends on MPFS_FPGA_UART + default n + select UART5_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + +config MPFS_HAVE_UART6 + bool + depends on MPFS_FPGA_UART + default n + select UART6_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + +config MPFS_HAVE_UART7 + bool + depends on MPFS_FPGA_UART + default n + select UART7_SERIALDRIVER + select ARCH_HAVE_SERIAL_TERMIOS + # These are the peripheral selections proper +config MPFS_SPI + bool + default n + config MPFS_SPI0 bool "SPI 0" default n + select MPFS_SPI config MPFS_SPI1 bool "SPI 1" default n + select MPFS_SPI + +config MPFS_FPGA_UART + bool "FPGA uarts" + default n + ---help--- + Use FPGA UARTs instead of MSS UARTS. config MPFS_UART0 bool "UART 0" @@ -297,6 +331,30 @@ config MPFS_UART4 select ARCH_HAVE_SERIAL_TERMIOS select MPFS_HAVE_UART4 +config MPFS_UART5 + bool "UART 5" + depends on MPFS_FPGA_UART + default n + select ARCH_HAVE_UART5 + select ARCH_HAVE_SERIAL_TERMIOS + select MPFS_HAVE_UART5 + +config MPFS_UART6 + bool "UART 6" + depends on MPFS_FPGA_UART + default n + select ARCH_HAVE_UART6 + select ARCH_HAVE_SERIAL_TERMIOS + select MPFS_HAVE_UART6 + +config MPFS_UART7 + bool "UART 7" + depends on MPFS_FPGA_UART + default n + select ARCH_HAVE_UART7 + select ARCH_HAVE_SERIAL_TERMIOS + select MPFS_HAVE_UART7 + config MPFS_I2C0 bool "I2C 0" select ARCH_HAVE_I2CRESET @@ -369,6 +427,12 @@ config MPFS_COREMMC_IRQNUM range 0 63 depends on MPFS_COREMMC +config MPFS_TAMPER + bool "Tamper detection" + default n + ---help--- + Enable tamper detection mechanisms. + config MPFS_IHC_CLIENT bool "IHC slave" depends on RPTUN && !MPFS_BOOTLOADER @@ -410,7 +474,7 @@ config MPFS_IHC_LINUX_ON_HART3 config MPFS_IHC_LINUX_ON_HART4 int "Linux on hart4" depends on MPFS_IHC_CLIENT || MPFS_IHC_SBI - default 1 + default 0 range 0 1 ---help--- Set this to 1 if U-boot / Linux is running on hart4 @@ -577,12 +641,6 @@ config MPFS_COREPWM0_BASE default 0x44000000 depends on MPFS_COREPWM0 -config MPFS_COREPWM0_PWMCLK - int "Clock frequency of the CorePWM0 block (Hz)" - default 25000000 - range 1000000 100000000 - depends on MPFS_COREPWM0 - config MPFS_COREPWM0_REGWIDTH int "Width of the PWM register (8, 16 or 32 bits)" default 32 @@ -606,12 +664,6 @@ config MPFS_COREPWM1_BASE default 0x45000000 depends on MPFS_COREPWM1 -config MPFS_COREPWM1_PWMCLK - int "Clock frequency of the CorePWM1 block (Hz)" - default 25000000 - range 1000000 100000000 - depends on MPFS_COREPWM1 - config MPFS_COREPWM1_REGWIDTH int "Width of the PWM register (8, 16 or 32 bits)" default 32 @@ -624,6 +676,56 @@ config MPFS_COREPWM1_NCHANNELS range 1 16 depends on MPFS_COREPWM1 +comment "CAN-FD Options" + +config MPFS_HAVE_CANFD + bool "CAN FD" + select ARCH_HAVE_CAN_ERRORS + select NET_CAN_HAVE_CANFD + select NET_CAN_EXTID + select NET_CAN_HAVE_TX_DEADLINE + default n + +config MPFS_CANFD0 + bool "MPFS FPGA CANFD0 IP block configured" + default n + depends on MPFS_HAVE_CANFD + +config MPFS_CANFD_BASE0 + hex "Base address for the CANFD0 instance" + default 0x46000000 + depends on MPFS_CANFD0 + +config MPFS_CANFD_ARBI_BITRATE0 + int "CANFD0 Arbitration phase bitrate" + default 1000000 + depends on MPFS_CANFD0 + +config MPFS_CANFD_DATA_BITRATE0 + int "CANFD0 Data phase bitrate" + default 4000000 + depends on MPFS_CANFD0 + +config MPFS_CANFD1 + bool "MPFS FPGA CANFD1 IP block configured" + default n + depends on MPFS_HAVE_CANFD + +config MPFS_CANFD_BASE1 + hex "Base address for the CANFD1 instance" + default 0x47000000 + depends on MPFS_CANFD1 + +config MPFS_CANFD_ARBI_BITRATE1 + int "CANFD1 Arbitration phase bitrate" + default 1000000 + depends on MPFS_CANFD1 + +config MPFS_CANFD_DATA_BITRATE1 + int "CANFD1 Data phase bitrate" + default 4000000 + depends on MPFS_CANFD1 + endmenu config MPFS_DMA @@ -751,6 +853,20 @@ endchoice # GMAC speed endif # !MPFS_MAC_AUTONEG +config MPFS_ETHMAC_HPWORK + bool "Use HP workqueue" + default n + depends on MPFS_ETHMAC + ---help--- + Select HPWORK workqueue for eth ISR work + +config MPFS_ETHMAC_LPWORK + bool "Use LP workqueue" + default n + depends on MPFS_ETHMAC + ---help--- + Select LPWORK workqueue for eth ISR work + config MPFS_ETHMAC_MDC_CLOCK_SOURCE_HZ int "MDC Clock Source (Hz)" default 125000000 @@ -791,6 +907,12 @@ config MPFS_ETHMAC_REGDEBUG endmenu +config MPFS_MPUCFG + bool "Enable MPUCFG driver" + default n + ---help--- + Enable driver to set MPUCFG entries. + config MPFS_HAVE_CORERMII bool "CoreRMII FPGA IP block configured" default n @@ -799,3 +921,13 @@ config MPFS_CORERMII_ADDRESS int "CoreRMII Phy address" default 1 depends on MPFS_HAVE_CORERMII + +config MPFS_CRYPTO + bool "Enable MPFS HW crypto" + default n + +if MPFS_CRYPTO +config MPFS_CRYPTO_DMA + bool "Enable MPFS HW crypto DMA" + default y +endif diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index 6e060cef60e07..027277a5d0960 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -50,7 +50,7 @@ ifeq ($(CONFIG_MM_PGALLOC),y) CHIP_CSRCS += mpfs_pgalloc.c endif -ifeq ($(CONFIG_SPI),y) +ifeq ($(CONFIG_MPFS_SPI),y) CHIP_CSRCS += mpfs_spi.c endif @@ -58,6 +58,10 @@ ifeq ($(CONFIG_I2C),y) CHIP_CSRCS += mpfs_i2c.c endif +ifneq ($(filter y,$(CONFIG_MPFS_EMMCSD) $(CONFIG_MPFS_COREMMC)),) +CHIP_CSRCS += mpfs_sdio.c +endif + ifeq ($(CONFIG_MPFS_EMMCSD),y) CHIP_CSRCS += mpfs_emmcsd.c endif @@ -78,6 +82,10 @@ ifeq (${CONFIG_MPFS_HAVE_COREPWM},y) CHIP_CSRCS += mpfs_corepwm.c endif +ifeq (${CONFIG_MPFS_HAVE_CANFD}, y) +CHIP_CSRCS += mpfs_fpga_canfd.c +endif + ifeq (${CONFIG_MPFS_DDR_INIT},y) CHIP_CSRCS += mpfs_ddr.c endif @@ -108,3 +116,14 @@ ifeq ($(CONFIG_MPFS_CORESPI),y) CHIP_CSRCS += mpfs_corespi.c endif +ifeq ($(CONFIG_MPFS_TAMPER),y) +CHIP_CSRCS += mpfs_tamper.c +endif + +ifeq ($(CONFIG_MPFS_CRYPTO),y) +include mpfs/crypto.defs +endif + +ifeq ($(CONFIG_MPFS_MPUCFG),y) +CHIP_CSRCS += mpfs_mpu.c +endif diff --git a/arch/risc-v/src/mpfs/crypto.defs b/arch/risc-v/src/mpfs/crypto.defs new file mode 100644 index 0000000000000..98f5c330e65c1 --- /dev/null +++ b/arch/risc-v/src/mpfs/crypto.defs @@ -0,0 +1,14 @@ +MPFS_CRYPTO = mpfs/crypto/.git +$(MPFS_CRYPTO): + $(Q) echo "Symlink PolarFire crypto driver submodule" + $(Q) $(DIRLINK) $(CURDIR)/../../../../extern/pf_crypto mpfs/crypto + +context::$(MPFS_CRYPTO) + +distclean:: + $(Q) rm -rf mpfs/crypto + +CHIP_CSRCS += mpfs_crypto.c mpfs_systemservice.c + +DEPPATH += --dep-path mpfs/crypto +VPATH += :mpfs/crypto diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_clint.h b/arch/risc-v/src/mpfs/hardware/mpfs_clint.h index a15d849267902..d398cca8dbd71 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_clint.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_clint.h @@ -21,6 +21,12 @@ #ifndef __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_CLINT_H #define __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_CLINT_H +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include "mpfs_memorymap.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h new file mode 100644 index 0000000000000..16587add2d226 --- /dev/null +++ b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h @@ -0,0 +1,472 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_CANFD_H +#define __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_CANFD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/mpfs_memorymap.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register Offsets *********************************************************/ + +#define MPFS_CANFD_DEVICE_ID_OFFSET (0x00) +#define MPFS_CANFD_VERSION_OFFSET (0x02) + +#define MPFS_CANFD_MODE_OFFSET (0x04) +#define MPFS_CANFD_SETTINGS_OFFSET (0x06) + +#define MPFS_CANFD_STATUS_OFFSET (0x08) + +#define MPFS_CANFD_COMMAND_OFFSET (0x0c) + +#define MPFS_CANFD_INT_STAT_OFFSET (0x10) + +#define MPFS_CANFD_INT_ENA_SET_OFFSET (0x14) + +#define MPFS_CANFD_INT_ENA_CLR_OFFSET (0x18) + +#define MPFS_CANFD_INT_MASK_SET_OFFSET (0x1c) + +#define MPFS_CANFD_INT_MASK_CLR_OFFSET (0x20) + +#define MPFS_CANFD_BTR_OFFSET (0x24) + +#define MPFS_CANFD_BTR_FD_OFFSET (0x28) + +#define MPFS_CANFD_EWL_OFFSET (0x2c) +#define MPFS_CANFD_ERP_OFFSET (0x2d) +#define MPFS_CANFD_FAULT_STATE_OFFSET (0x2e) + +#define MPFS_CANFD_REC_OFFSET (0x30) +#define MPFS_CANFD_TEC_OFFSET (0x32) + +#define MPFS_CANFD_ERR_NORM_OFFSET (0x34) +#define MPFS_CANFD_ERR_FD_OFFSET (0x36) + +#define MPFS_CANFD_CTR_PRES_OFFSET (0x38) + +#define MPFS_CANFD_FILTER_A_MASK_OFFSET (0x3c) + +#define MPFS_CANFD_FILTER_A_VAL_OFFSET (0x40) + +#define MPFS_CANFD_FILTER_B_MASK_OFFSET (0x44) + +#define MPFS_CANFD_FILTER_B_VAL_OFFSET (0x48) + +#define MPFS_CANFD_FILTER_C_MASK_OFFSET (0x4c) + +#define MPFS_CANFD_FILTER_C_VAL_OFFSET (0x50) + +#define MPFS_CANFD_FILTER_RAN_LOW_OFFSET (0x54) + +#define MPFS_CANFD_FILTER_RAN_HIGH_OFFSET (0x58) + +#define MPFS_CANFD_FILTER_CONTROL_OFFSET (0x5c) +#define MPFS_CANFD_FILTER_STATUS_OFFSET (0x5e) + +/* RX registers */ +#define MPFS_CANFD_RX_MEM_INFO_OFFSET (0x60) + +#define MPFS_CANFD_RX_POINTERS_OFFSET (0x64) + +#define MPFS_CANFD_RX_STATUS_OFFSET (0x68) +#define MPFS_CANFD_RX_SETTINGS_OFFSET (0x6a) + +#define MPFS_CANFD_RX_DATA_OFFSET (0x6c) + +/* TX registers */ +#define MPFS_CANFD_TX_STATUS_OFFSET (0x70) + +#define MPFS_CANFD_TX_COMMAND_OFFSET (0x74) +#define MPFS_CANFD_TXTB_INFO_OFFSET (0x76) + +#define MPFS_CANFD_TX_PRIORITY_OFFSET (0x78) + +#define MPFS_CANFD_ERR_CAPT_OFFSET (0x7c) +#define MPFS_CANFD_RETR_CTR_OFFSET (0x7d) +#define MPFS_CANFD_ALC_OFFSET (0x7e) + +#define MPFS_CANFD_TRV_DELAY_OFFSET (0x80) +#define MPFS_CANFD_SSP_CFG_OFFSET (0x82) + +#define MPFS_CANFD_RX_FR_CTR_OFFSET (0x84) + +#define MPFS_CANFD_TX_FR_CTR_OFFSET (0x88) + +#define MPFS_CANFD_DEBUG_REGISTER_OFFSET (0x8c) + +#define MPFS_CANFD_YOLO_OFFSET (0x90) + +#define MPFS_CANFD_TIMESTAMP_LOW_OFFSET (0x94) + +#define MPFS_CANFD_TIMESTAMP_HIGH_OFFSET (0x98) + +# define MPFS_CANFD_CTUCANFD_TXTB1_DATA_1 (0x100) +# define MPFS_CANFD_CTUCANFD_TXTB1_DATA_2 (0x104) +# define MPFS_CANFD_CTUCANFD_TXTB1_DATA_20 (0x14c) + +# define MPFS_CANFD_CTUCANFD_TXTB2_DATA_1 (0x200) +# define MPFS_CANFD_CTUCANFD_TXTB2_DATA_2 (0x204) +# define MPFS_CANFD_CTUCANFD_TXTB2_DATA_20 (0x24c) + +# define MPFS_CANFD_CTUCANFD_TXTB3_DATA_1 (0x300) +# define MPFS_CANFD_CTUCANFD_TXTB3_DATA_2 (0x304) +# define MPFS_CANFD_CTUCANFD_TXTB3_DATA_20 (0x34c) + +# define MPFS_CANFD_CTUCANFD_TXTB4_DATA_1 (0x400) +# define MPFS_CANFD_CTUCANFD_TXTB4_DATA_2 (0x404) +# define MPFS_CANFD_CTUCANFD_TXTB4_DATA_20 (0x44c) + +# define MPFS_CANFD_CTUCANFD_TXTB5_DATA_1 (0x500) +# define MPFS_CANFD_CTUCANFD_TXTB5_DATA_2 (0x504) +# define MPFS_CANFD_CTUCANFD_TXTB5_DATA_20 (0x54c) + +# define MPFS_CANFD_CTUCANFD_TXTB6_DATA_1 (0x600) +# define MPFS_CANFD_CTUCANFD_TXTB6_DATA_2 (0x604) +# define MPFS_CANFD_CTUCANFD_TXTB6_DATA_20 (0x64c) + +# define MPFS_CANFD_CTUCANFD_TXTB7_DATA_1 (0x700) +# define MPFS_CANFD_CTUCANFD_TXTB7_DATA_2 (0x704) +# define MPFS_CANFD_CTUCANFD_TXTB7_DATA_20 (0x74c) + +# define MPFS_CANFD_CTUCANFD_TXTB8_DATA_1 (0x800) +# define MPFS_CANFD_CTUCANFD_TXTB8_DATA_2 (0x804) +# define MPFS_CANFD_CTUCANFD_TXTB8_DATA_20 (0x84c) + +# define MPFS_CANFD_CTUCANFD_TST_CONTROL (0x900) +# define MPFS_CANFD_CTUCANFD_TST_DEST (0x904) +# define MPFS_CANFD_CTUCANFD_TST_WDATA (0x908) +# define MPFS_CANFD_CTUCANFD_TST_RDATA (0x90c) + +/* Control_registers memory region ******************************************/ + +/* DEVICE ID / VERSION registers */ +#define MPFS_CANFD_DEVICE_ID_DEVICE_ID_SHIFT (0) +#define MPFS_CANFD_DEVICE_ID_DEVICE_ID (0xffff << MPFS_CANFD_DEVICE_ID_DEVICE_ID_SHIFT) +#define MPFS_CANFD_DEVICE_ID_VER_MINOR_SHIFT (16) +#define MPFS_CANFD_DEVICE_ID_VER_MINOR (0xff << MPFS_CANFD_DEVICE_ID_VER_MINOR_SHIFT) +#define MPFS_CANFD_DEVICE_ID_VER_MAJOR_SHIFT (24) +#define MPFS_CANFD_DEVICE_ID_VER_MAJOR (0xff << MPFS_CANFD_DEVICE_ID_VER_MAJOR_SHIFT) + +/* MODE / SETTINGS registers */ +#define MPFS_CANFD_MODE_RST (1 << 0) +#define MPFS_CANFD_MODE_BMM (1 << 1) +#define MPFS_CANFD_MODE_STM (1 << 2) +#define MPFS_CANFD_MODE_AFM (1 << 3) +#define MPFS_CANFD_MODE_FDE (1 << 4) +#define MPFS_CANFD_MODE_TTTM (1 << 5) +#define MPFS_CANFD_MODE_ROM (1 << 6) +#define MPFS_CANFD_MODE_ACF (1 << 7) +#define MPFS_CANFD_MODE_TSTM (1 << 8) +#define MPFS_CANFD_MODE_RXBAM (1 << 9) +#define MPFS_CANFD_MODE_RTRLE (1 << 16) +#define MPFS_CANFD_MODE_RTRTH_SHIFT (17) +#define MPFS_CANFD_MODE_RTRTH (0x0f << MPFS_CANFD_MODE_RTRTH_SHIFT) +#define MPFS_CANFD_MODE_ILBP (1 << 21) +#define MPFS_CANFD_MODE_ENA (1 << 22) +#define MPFS_CANFD_MODE_NISOFD (1 << 23) +#define MPFS_CANFD_MODE_PEX (1 << 24) +#define MPFS_CANFD_MODE_TBFBO (1 << 25) +#define MPFS_CANFD_MODE_FDRF (1 << 26) + +/* STATUS registers */ +#define MPFS_CANFD_STATUS_RXNE (1 << 0) +#define MPFS_CANFD_STATUS_DOR (1 << 1) +#define MPFS_CANFD_STATUS_TXNF (1 << 2) +#define MPFS_CANFD_STATUS_EFT (1 << 3) +#define MPFS_CANFD_STATUS_RXS (1 << 4) +#define MPFS_CANFD_STATUS_TXS (1 << 5) +#define MPFS_CANFD_STATUS_EWL (1 << 6) +#define MPFS_CANFD_STATUS_IDLE (1 << 7) +#define MPFS_CANFD_STATUS_PEXS (1 << 8) +#define MPFS_CANFD_STATUS_STCNT (1 << 16) +#define MPFS_CANFD_STATUS_STRGS (1 << 17) + +/* COMMAND registers */ +#define MPFS_CANFD_COMMAND_RXRPMV (1 << 1) +#define MPFS_CANFD_COMMAND_RRB (1 << 2) +#define MPFS_CANFD_COMMAND_CDO (1 << 3) +#define MPFS_CANFD_COMMAND_ERCRST (1 << 4) +#define MPFS_CANFD_COMMAND_RXFCRST (1 << 5) +#define MPFS_CANFD_COMMAND_TXFCRST (1 << 6) +#define MPFS_CANFD_COMMAND_CPEXS (1 << 7) + +/* INT_STAT registers */ +#define MPFS_CANFD_INT_STAT_RXI (1 << 0) +#define MPFS_CANFD_INT_STAT_TXI (1 << 1) +#define MPFS_CANFD_INT_STAT_EWLI (1 << 2) +#define MPFS_CANFD_INT_STAT_DOI (1 << 3) +#define MPFS_CANFD_INT_STAT_FCSI (1 << 4) +#define MPFS_CANFD_INT_STAT_ALI (1 << 5) +#define MPFS_CANFD_INT_STAT_BEI (1 << 6) +#define MPFS_CANFD_INT_STAT_OFI (1 << 7) +#define MPFS_CANFD_INT_STAT_RXFI (1 << 8) +#define MPFS_CANFD_INT_STAT_BSI (1 << 9) +#define MPFS_CANFD_INT_STAT_RBNEI (1 << 10) +#define MPFS_CANFD_INT_STAT_TXBHCI (1 << 11) + +/* INT_ENA_SET registers */ +#define MPFS_CANFD_INT_ENA_SET_INT_ENA_SET (0x0fff << 0) + +/* INT_ENA_CLR registers */ +#define MPFS_CANFD_INT_ENA_CLR_INT_ENA_CLR (0x0fff << 0) + +/* INT_MASK_SET registers */ +#define MPFS_CANFD_INT_MASK_SET_INT_MASK_SET (0x0fff << 0) + +/* INT_MASK_CLR registers */ +#define MPFS_CANFD_INT_MASK_CLR_INT_MASK_CLR (0x0fff << 0) + +/* BTR registers */ +#define MPFS_CANFD_BTR_PROP_SHIFT (0) +#define MPFS_CANFD_BTR_PROP (0x7f << MPFS_CANFD_BTR_PROP_SHIFT) +#define MPFS_CANFD_BTR_PH1_SHIFT (7) +#define MPFS_CANFD_BTR_PH1 (0x3f << MPFS_CANFD_BTR_PH1_SHIFT) +#define MPFS_CANFD_BTR_PH2_SHIFT (13) +#define MPFS_CANFD_BTR_PH2 (0x3f << MPFS_CANFD_BTR_PH2_SHIFT) +#define MPFS_CANFD_BTR_BRP_SHIFT (19) +#define MPFS_CANFD_BTR_BRP (0xff << MPFS_CANFD_BTR_BRP_SHIFT) +#define MPFS_CANFD_BTR_SJW_SHIFT (27) +#define MPFS_CANFD_BTR_SJW (0x1f << MPFS_CANFD_BTR_SJW_SHIFT) + +/* BTR_FD registers */ +#define MPFS_CANFD_BTR_FD_PROP_FD_SHIFT (0) +#define MPFS_CANFD_BTR_FD_PROP_FD (0x3f << MPFS_CANFD_BTR_FD_PROP_FD_SHIFT) +#define MPFS_CANFD_BTR_FD_PH1_FD_SHIFT (7) +#define MPFS_CANFD_BTR_FD_PH1_FD (0x1f << MPFS_CANFD_BTR_FD_PH1_FD_SHIFT) +#define MPFS_CANFD_BTR_FD_PH2_FD_SHIFT (13) +#define MPFS_CANFD_BTR_FD_PH2_FD (0x1f << MPFS_CANFD_BTR_FD_PH2_FD_SHIFT) +#define MPFS_CANFD_BTR_FD_BRP_FD_SHIFT (19) +#define MPFS_CANFD_BTR_FD_BRP_FD (0xff << MPFS_CANFD_BTR_FD_BRP_FD_SHIFT) +#define MPFS_CANFD_BTR_FD_SJW_FD_SHIFT (27) +#define MPFS_CANFD_BTR_FD_SJW_FD (0x1f << MPFS_CANFD_BTR_FD_SJW_FD_SHIFT) + +/* EWL / ERP / FAULT_STATE registers */ +#define MPFS_CANFD_EWL_EW_LIMIT_SHIFT (0) +#define MPFS_CANFD_EWL_EW_LIMIT (0xff << MPFS_CANFD_EWL_EW_LIMIT_SHIFT) +#define MPFS_CANFD_EWL_ERP_LIMIT_SHIFT (8) +#define MPFS_CANFD_EWL_ERP_LIMIT (0xff << MPFS_CANFD_EWL_ERP_LIMIT_SHIFT) +#define MPFS_CANFD_EWL_ERA (1 << 16) +#define MPFS_CANFD_EWL_ERP (1 << 17) +#define MPFS_CANFD_EWL_BOF (1 << 18) + +/* REC / TEC registers */ +#define MPFS_CANFD_REC_REC_VAL_SHIFT (0) +#define MPFS_CANFD_REC_REC_VAL (0x01ff << MPFS_CANFD_REC_REC_VAL_SHIFT) +#define MPFS_CANFD_REC_TEC_VAL_SHIFT (16) +#define MPFS_CANFD_REC_TEC_VAL (0x01ff << MPFS_CANFD_REC_TEC_VAL_SHIFT) + +/* ERR_NORM ERR_FD registers */ +#define MPFS_CANFD_ERR_NORM_ERR_NORM_VAL_SHIFT (0) +#define MPFS_CANFD_ERR_NORM_ERR_NORM_VAL (0xffff << MPFS_CANFD_ERR_NORM_ERR_NORM_VAL_SHIFT) +#define MPFS_CANFD_ERR_NORM_ERR_FD_VAL_SHIFT (16) +#define MPFS_CANFD_ERR_NORM_ERR_FD_VAL (0xffff << MPFS_CANFD_ERR_NORM_ERR_FD_VAL_SHIFT) + +/* CTR_PRES registers */ +#define MPFS_CANFD_CTR_PRES_CTPV_SHIFT (0) +#define MPFS_CANFD_CTR_PRES_CTPV (0x01ff << MPFS_CANFD_CTR_PRES_CTPV_SHIFT) +#define MPFS_CANFD_CTR_PRES_PTX (1 << 9) +#define MPFS_CANFD_CTR_PRES_PRX (1 << 10) +#define MPFS_CANFD_CTR_PRES_ENORM (1 << 11) +#define MPFS_CANFD_CTR_PRES_EFD (1 << 12) + +/* FILTER_A_MASK registers */ +#define MPFS_CANFD_FILTER_A_MASK_BIT_MASK_A_VAL (0x1fffffff << 0) + +/* FILTER_A_VAL registers */ +#define MPFS_CANFD_FILTER_A_VAL_BIT_VAL_A_VAL (0x1fffffff << 0) + +/* FILTER_B_MASK registers */ +#define MPFS_CANFD_FILTER_B_MASK_BIT_MASK_B_VAL (0x1fffffff << 0) + +/* FILTER_B_VAL registers */ +#define MPFS_CANFD_FILTER_B_VAL_BIT_VAL_B_VAL (0x1fffffff << 0) + +/* FILTER_C_MASK registers */ +#define MPFS_CANFD_FILTER_C_MASK_BIT_MASK_C_VAL (0x1fffffff << 0) + +/* FILTER_C_VAL registers */ +#define MPFS_CANFD_FILTER_C_VAL_BIT_VAL_C_VAL (0x1fffffff << 0) + +/* FILTER_RAN_LOW registers */ +#define MPFS_CANFD_FILTER_RAN_LOW_BIT_RAN_LOW_VAL (0x1fffffff << 0) + +/* FILTER_RAN_HIGH registers */ +#define MPFS_CANFD_FILTER_RAN_HIGH_BIT_RAN_HIGH_VAL (0x1fffffff << 0) + +/* FILTER_CONTROL / FILTER_STATUS registers */ +#define MPFS_CANFD_FILTER_CONTROL_FANB (1 << 0) +#define MPFS_CANFD_FILTER_CONTROL_FANE (1 << 1) +#define MPFS_CANFD_FILTER_CONTROL_FAFB (1 << 2) +#define MPFS_CANFD_FILTER_CONTROL_FAFE (1 << 3) +#define MPFS_CANFD_FILTER_CONTROL_FBNB (1 << 4) +#define MPFS_CANFD_FILTER_CONTROL_FBNE (1 << 5) +#define MPFS_CANFD_FILTER_CONTROL_FBFB (1 << 6) +#define MPFS_CANFD_FILTER_CONTROL_FBFE (1 << 7) +#define MPFS_CANFD_FILTER_CONTROL_FCNB (1 << 8) +#define MPFS_CANFD_FILTER_CONTROL_FCNE (1 << 9) +#define MPFS_CANFD_FILTER_CONTROL_FCFB (1 << 10) +#define MPFS_CANFD_FILTER_CONTROL_FCFE (1 << 11) +#define MPFS_CANFD_FILTER_CONTROL_FRNB (1 << 12) +#define MPFS_CANFD_FILTER_CONTROL_FRNE (1 << 13) +#define MPFS_CANFD_FILTER_CONTROL_FRFB (1 << 14) +#define MPFS_CANFD_FILTER_CONTROL_FRFE (1 << 15) +#define MPFS_CANFD_FILTER_CONTROL_SFA (1 << 16) +#define MPFS_CANFD_FILTER_CONTROL_SFB (1 << 17) +#define MPFS_CANFD_FILTER_CONTROL_SFC (1 << 18) +#define MPFS_CANFD_FILTER_CONTROL_SFR (1 << 19) + +/* RX_MEM_INFO registers */ +#define MPFS_CANFD_RX_MEM_INFO_RX_BUFF_SIZE_SHIFT (0) +#define MPFS_CANFD_RX_MEM_INFO_RX_BUFF_SIZE (0x1fff << MPFS_CANFD_RX_MEM_INFO_RX_BUFF_SIZE_SHIFT) +#define MPFS_CANFD_RX_MEM_INFO_RX_MEM_FREE_SHIFT (16) +#define MPFS_CANFD_RX_MEM_INFO_RX_MEM_FREE (0x1fff << MPFS_CANFD_RX_MEM_INFO_RX_MEM_FREE_SHIFT) + +/* RX_POINTERS registers */ +#define MPFS_CANFD_RX_POINTERS_RX_WPP_SHIFT (0) +#define MPFS_CANFD_RX_POINTERS_RX_WPP (0x0fff << MPFS_CANFD_RX_POINTERS_RX_WPP_SHIFT) +#define MPFS_CANFD_RX_POINTERS_RX_RPP_SHIFT (16) +#define MPFS_CANFD_RX_POINTERS_RX_RPP (0x0fff << MPFS_CANFD_RX_POINTERS_RX_RPP_SHIFT) + +/* RX_STATUS / RX_SETTINGS registers */ +#define MPFS_CANFD_RX_STATUS_RXE (1 << 0) +#define MPFS_CANFD_RX_STATUS_RXF (1 << 1) +#define MPFS_CANFD_RX_STATUS_RXMOF (1 << 2) +#define MPFS_CANFD_RX_STATUS_RXFRC_SHIFT (4) +#define MPFS_CANFD_RX_STATUS_RXFRC (0x07ff << MPFS_CANFD_RX_STATUS_RXFRC_SHIFT) +#define MPFS_CANFD_RX_STATUS_RTSOP (1 << 16) + +/* RX_DATA registers */ +#define MPFS_CANFD_RX_DATA_RX_DATA (0xffffffff << 0) + +/* TX_STATUS registers */ +#define MPFS_CANFD_TX_STATUS_TX1S_SHIFT (0) +#define MPFS_CANFD_TX_STATUS_TX1S (0x0f << MPFS_CANFD_TX_STATUS_TX1S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX2S_SHIFT (4) +#define MPFS_CANFD_TX_STATUS_TX2S (0x0f << MPFS_CANFD_TX_STATUS_TX2S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX3S_SHIFT (8) +#define MPFS_CANFD_TX_STATUS_TX3S (0x0f << MPFS_CANFD_TX_STATUS_TX3S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX4S_SHIFT (12) +#define MPFS_CANFD_TX_STATUS_TX4S (0x0f << MPFS_CANFD_TX_STATUS_TX4S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX5S_SHIFT (16) +#define MPFS_CANFD_TX_STATUS_TX5S (0x0f << MPFS_CANFD_TX_STATUS_TX5S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX6S_SHIFT (20) +#define MPFS_CANFD_TX_STATUS_TX6S (0x0f << MPFS_CANFD_TX_STATUS_TX6S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX7S_SHIFT (24) +#define MPFS_CANFD_TX_STATUS_TX7S (0x0f << MPFS_CANFD_TX_STATUS_TX7S_SHIFT) +#define MPFS_CANFD_TX_STATUS_TX8S_SHIFT (28) +#define MPFS_CANFD_TX_STATUS_TX8S (0x0f << MPFS_CANFD_TX_STATUS_TX8S_SHIFT) + +/* TX_COMMAND TXTB_INFO registers */ +#define MPFS_CANFD_TX_COMMAND_TXCE (1 << 0) +#define MPFS_CANFD_TX_COMMAND_TXCR (1 << 1) +#define MPFS_CANFD_TX_COMMAND_TXCA (1 << 2) +#define MPFS_CANFD_TX_COMMAND_TXB1 (1 << 8) +#define MPFS_CANFD_TX_COMMAND_TXB2 (1 << 9) +#define MPFS_CANFD_TX_COMMAND_TXB3 (1 << 10) +#define MPFS_CANFD_TX_COMMAND_TXB4 (1 << 11) +#define MPFS_CANFD_TX_COMMAND_TXB5 (1 << 12) +#define MPFS_CANFD_TX_COMMAND_TXB6 (1 << 13) +#define MPFS_CANFD_TX_COMMAND_TXB7 (1 << 14) +#define MPFS_CANFD_TX_COMMAND_TXB8 (1 << 15) +#define MPFS_CANFD_TX_COMMAND_TXT_BUFFER_COUNT_SHIFT (16) +#define MPFS_CANFD_TX_COMMAND_TXT_BUFFER_COUNT (0x0f << MPFS_CANFD_TX_COMMAND_TXT_BUFFER_COUNT_SHIFT) + +/* TX_PRIORITY registers */ +#define MPFS_CANFD_TX_PRIORITY_TXT1P_SHIFT (0) +#define MPFS_CANFD_TX_PRIORITY_TXT1P (0x07 << )MPFS_CANFD_TX_PRIORITY_TXT1P_SHIFT +#define MPFS_CANFD_TX_PRIORITY_TXT2P_SHIFT (4) +#define MPFS_CANFD_TX_PRIORITY_TXT2P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT2P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT3P_SHIFT (8) +#define MPFS_CANFD_TX_PRIORITY_TXT3P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT3P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT4P_SHIFT (12) +#define MPFS_CANFD_TX_PRIORITY_TXT4P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT4P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT5P_SHIFT (16) +#define MPFS_CANFD_TX_PRIORITY_TXT5P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT5P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT6P_SHIFT (20) +#define MPFS_CANFD_TX_PRIORITY_TXT6P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT6P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT7P_SHIFT (24) +#define MPFS_CANFD_TX_PRIORITY_TXT7P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT7P_SHIFT) +#define MPFS_CANFD_TX_PRIORITY_TXT8P_SHIFT (28) +#define MPFS_CANFD_TX_PRIORITY_TXT8P (0x07 << MPFS_CANFD_TX_PRIORITY_TXT8P_SHIFT) + +/* ERR_CAPT RETR_CTR ALC registers */ +#define MPFS_CANFD_ERR_CAPT_ERR_POS_SHIFT (0) +#define MPFS_CANFD_ERR_CAPT_ERR_POS (0x1f << MPFS_CANFD_ERR_CAPT_ERR_POS_SHIFT) +#define MPFS_CANFD_ERR_CAPT_ERR_TYPE_SHIFT (5) +#define MPFS_CANFD_ERR_CAPT_ERR_TYPE (0x07 << MPFS_CANFD_ERR_CAPT_ERR_TYPE_SHIFT) +#define MPFS_CANFD_ERR_CAPT_RETR_CTR_VAL_SHIFT (8) +#define MPFS_CANFD_ERR_CAPT_RETR_CTR_VAL (0x0f << MPFS_CANFD_ERR_CAPT_RETR_CTR_VAL_SHIFT) +#define MPFS_CANFD_ERR_CAPT_ALC_BIT_SHIFT (16) +#define MPFS_CANFD_ERR_CAPT_ALC_BIT (0x1f << MPFS_CANFD_ERR_CAPT_ALC_BIT_SHIFT) +#define MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD_SHIFT (21) +#define MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD (0x07 << MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD_SHIFT) + +/* TRV_DELAY SSP_CFG registers */ +#define MPFS_CANFD_TRV_DELAY_TRV_DELAY_VALUE_SHIFT (0) +#define MPFS_CANFD_TRV_DELAY_TRV_DELAY_VALUE (0x7f << MPFS_CANFD_TRV_DELAY_TRV_DELAY_VALUE_SHIFT) +#define MPFS_CANFD_TRV_DELAY_SSP_OFFSET_SHIFT (16) +#define MPFS_CANFD_TRV_DELAY_SSP_OFFSET (0xff << MPFS_CANFD_TRV_DELAY_SSP_OFFSET_SHIFT) +#define MPFS_CANFD_TRV_DELAY_SSP_SRC_SHIFT (24) +#define MPFS_CANFD_TRV_DELAY_SSP_SRC (0x03 << MPFS_CANFD_TRV_DELAY_SSP_SRC_SHIFT) + +/* RX_FR_CTR registers */ +#define MPFS_CANFD_RX_FR_CTR_RX_FR_CTR_VAL (0xffffffff << 0) + +/* TX_FR_CTR registers */ +#define MPFS_CANFD_TX_FR_CTR_TX_FR_CTR_VAL (0xffffffff << 0) + +/* DEBUG_REGISTER registers */ +#define MPFS_CANFD_DEBUG_REGISTER_STUFF_COUNT_SHIFT (0) +#define MPFS_CANFD_DEBUG_REGISTER_STUFF_COUNT (0x07 << MPFS_CANFD_DEBUG_REGISTER_STUFF_COUNT_SHIFT) +#define MPFS_CANFD_DEBUG_REGISTER_DESTUFF_COUNT_SHIFT (3) +#define MPFS_CANFD_DEBUG_REGISTER_DESTUFF_COUNT (0x07 << MPFS_CANFD_DEBUG_REGISTER_DESTUFF_COUNT_SHIFT) +#define MPFS_CANFD_DEBUG_REGISTER_PC_ARB (1 << 6) +#define MPFS_CANFD_DEBUG_REGISTER_PC_CON (1 << 7) +#define MPFS_CANFD_DEBUG_REGISTER_PC_DAT (1 << 8) +#define MPFS_CANFD_DEBUG_REGISTER_PC_STC (1 << 9) +#define MPFS_CANFD_DEBUG_REGISTER_PC_CRC (1 << 10) +#define MPFS_CANFD_DEBUG_REGISTER_PC_CRCD (1 << 11) +#define MPFS_CANFD_DEBUG_REGISTER_PC_ACK (1 << 12) +#define MPFS_CANFD_DEBUG_REGISTER_PC_ACKD (1 << 13) +#define MPFS_CANFD_DEBUG_REGISTER_PC_EOF (1 << 14) +#define MPFS_CANFD_DEBUG_REGISTER_PC_INT (1 << 15) +#define MPFS_CANFD_DEBUG_REGISTER_PC_SUSP (1 << 16) +#define MPFS_CANFD_DEBUG_REGISTER_PC_OVR (1 << 17) +#define MPFS_CANFD_DEBUG_REGISTER_PC_SOF (1 << 18) + +/* YOLO_REG registers */ +#define MPFS_CANFD_YOLO_REG_YOLO_VAL (0xffffffff << 0) + +/* TIMESTAMP_LOW registers */ +#define MPFS_CANFD_TIMESTAMP_LOW_TIMESTAMP_LOW (0xffffffff << 0) + +/* TIMESTAMP_HIGH registers */ +#define MPFS_CANFD_TIMESTAMP_HIGH_TIMESTAMP_HIGH (0xffffffff << 0) + +#endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_FPGA_CANFD_H */ \ No newline at end of file diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h index 5d93013734d19..54d9fda0c2d2c 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h @@ -130,4 +130,15 @@ #define MPFS_UART3_BASE MPFS_UART3_LO_BASE #define MPFS_UART4_BASE MPFS_UART4_LO_BASE +/* FPGA UART defines */ + +#define MPFS_FPGA_UART0_BASE 0x4c000000UL +#define MPFS_FPGA_UART1_BASE 0x4c001000UL +#define MPFS_FPGA_UART2_BASE 0x4c002000UL +#define MPFS_FPGA_UART3_BASE 0x4c003000UL +#define MPFS_FPGA_UART4_BASE 0x4c004000UL +#define MPFS_FPGA_UART5_BASE 0x4c005000UL +#define MPFS_FPGA_UART6_BASE 0x4c006000UL +#define MPFS_FPGA_UART7_BASE 0x4c007000UL + #endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_MEMORYMAP_H */ diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_mpucfg.h b/arch/risc-v/src/mpfs/hardware/mpfs_mpucfg.h index e7aaecdf798d7..6047dd8dbbba5 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_mpucfg.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_mpucfg.h @@ -21,6 +21,25 @@ #ifndef __ARCH_RISC_V_SRC_MPFS_HARDWARE_MPFS_MPUCFG_H #define __ARCH_RISC_V_SRC_MPFS_HARDWARE_MPFS_MPUCFG_H +/* FIC0 (FPGA) PMP configurations - for fabric memory transfers */ + +#define MPFS_PMPCFG_FIC0_0 (MPFS_MPUCFG_BASE + 0x00) +#define MPFS_PMPCFG_FIC0_1 (MPFS_MPUCFG_BASE + 0x08) +#define MPFS_PMPCFG_FIC0_2 (MPFS_MPUCFG_BASE + 0x10) +#define MPFS_PMPCFG_FIC0_3 (MPFS_MPUCFG_BASE + 0x18) +#define MPFS_PMPCFG_FIC0_4 (MPFS_MPUCFG_BASE + 0x20) +#define MPFS_PMPCFG_FIC0_5 (MPFS_MPUCFG_BASE + 0x28) +#define MPFS_PMPCFG_FIC0_6 (MPFS_MPUCFG_BASE + 0x30) +#define MPFS_PMPCFG_FIC0_7 (MPFS_MPUCFG_BASE + 0x38) +#define MPFS_PMPCFG_FIC0_8 (MPFS_MPUCFG_BASE + 0x40) +#define MPFS_PMPCFG_FIC0_9 (MPFS_MPUCFG_BASE + 0x48) +#define MPFS_PMPCFG_FIC0_10 (MPFS_MPUCFG_BASE + 0x50) +#define MPFS_PMPCFG_FIC0_11 (MPFS_MPUCFG_BASE + 0x58) +#define MPFS_PMPCFG_FIC0_12 (MPFS_MPUCFG_BASE + 0x60) +#define MPFS_PMPCFG_FIC0_13 (MPFS_MPUCFG_BASE + 0x68) +#define MPFS_PMPCFG_FIC0_14 (MPFS_MPUCFG_BASE + 0x70) +#define MPFS_PMPCFG_FIC0_15 (MPFS_MPUCFG_BASE + 0x78) + /* FIC1 (FPGA) PMP configurations - for fabric memory transfers */ #define MPFS_PMPCFG_FIC1_0 (MPFS_MPUCFG_BASE + 0x100) @@ -40,6 +59,17 @@ #define MPFS_PMPCFG_FIC1_14 (MPFS_MPUCFG_BASE + 0x170) #define MPFS_PMPCFG_FIC1_15 (MPFS_MPUCFG_BASE + 0x178) +/* FIC2 (FPGA) PMP configurations - for fabric memory transfers */ + +#define MPFS_PMPCFG_FIC2_0 (MPFS_MPUCFG_BASE + 0x200) +#define MPFS_PMPCFG_FIC2_1 (MPFS_MPUCFG_BASE + 0x208) +#define MPFS_PMPCFG_FIC2_2 (MPFS_MPUCFG_BASE + 0x210) +#define MPFS_PMPCFG_FIC2_3 (MPFS_MPUCFG_BASE + 0x218) +#define MPFS_PMPCFG_FIC2_4 (MPFS_MPUCFG_BASE + 0x220) +#define MPFS_PMPCFG_FIC2_5 (MPFS_MPUCFG_BASE + 0x228) +#define MPFS_PMPCFG_FIC2_6 (MPFS_MPUCFG_BASE + 0x230) +#define MPFS_PMPCFG_FIC2_7 (MPFS_MPUCFG_BASE + 0x238) + /* Crpyto PMP configurations - for DMA transfers */ #define MPFS_PMPCFG_CRYPTO_0 (MPFS_MPUCFG_BASE + 0x300) @@ -53,10 +83,18 @@ #define MPFS_PMPCFG_ETH0_1 (MPFS_MPUCFG_BASE + 0x408) #define MPFS_PMPCFG_ETH0_2 (MPFS_MPUCFG_BASE + 0x410) #define MPFS_PMPCFG_ETH0_3 (MPFS_MPUCFG_BASE + 0x418) +#define MPFS_PMPCFG_ETH0_4 (MPFS_MPUCFG_BASE + 0x420) +#define MPFS_PMPCFG_ETH0_5 (MPFS_MPUCFG_BASE + 0x428) +#define MPFS_PMPCFG_ETH0_6 (MPFS_MPUCFG_BASE + 0x430) +#define MPFS_PMPCFG_ETH0_7 (MPFS_MPUCFG_BASE + 0x438) #define MPFS_PMPCFG_ETH1_0 (MPFS_MPUCFG_BASE + 0x500) #define MPFS_PMPCFG_ETH1_1 (MPFS_MPUCFG_BASE + 0x508) #define MPFS_PMPCFG_ETH1_2 (MPFS_MPUCFG_BASE + 0x510) #define MPFS_PMPCFG_ETH1_3 (MPFS_MPUCFG_BASE + 0x518) +#define MPFS_PMPCFG_ETH1_4 (MPFS_MPUCFG_BASE + 0x520) +#define MPFS_PMPCFG_ETH1_5 (MPFS_MPUCFG_BASE + 0x528) +#define MPFS_PMPCFG_ETH1_6 (MPFS_MPUCFG_BASE + 0x530) +#define MPFS_PMPCFG_ETH1_7 (MPFS_MPUCFG_BASE + 0x528) /* USB PMP configurations - for DMA transfers */ @@ -72,6 +110,22 @@ #define MPFS_PMPCFG_MMC_2 (MPFS_MPUCFG_BASE + 0x710) #define MPFS_PMPCFG_MMC_3 (MPFS_MPUCFG_BASE + 0x718) +/* SCB PMP configurations - for DMA transfers */ + +#define MPFS_PMPCFG_SCB_0 (MPFS_MPUCFG_BASE + 0x800) +#define MPFS_PMPCFG_SCB_1 (MPFS_MPUCFG_BASE + 0x808) +#define MPFS_PMPCFG_SCB_2 (MPFS_MPUCFG_BASE + 0x810) +#define MPFS_PMPCFG_SCB_3 (MPFS_MPUCFG_BASE + 0x818) +#define MPFS_PMPCFG_SCB_4 (MPFS_MPUCFG_BASE + 0x820) +#define MPFS_PMPCFG_SCB_5 (MPFS_MPUCFG_BASE + 0x828) +#define MPFS_PMPCFG_SCB_6 (MPFS_MPUCFG_BASE + 0x830) +#define MPFS_PMPCFG_SCB_7 (MPFS_MPUCFG_BASE + 0x838) + +/* TRACE PMP configurations - for DMA transfers */ + +#define MPFS_PMPCFG_TRACE_0 (MPFS_MPUCFG_BASE + 0x900) +#define MPFS_PMPCFG_TRACE_1 (MPFS_MPUCFG_BASE + 0x908) + /* DDR segments - set up by mpfs_ddr.c */ #define MPFS_MPUCFG_SEG0_REG0 (MPFS_MPUCFG_BASE + 0xd00) diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_usb.h b/arch/risc-v/src/mpfs/hardware/mpfs_usb.h index 863044d8ddd9a..00f15dbedaf79 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_usb.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_usb.h @@ -142,6 +142,8 @@ #define MPFS_USB_C_T_HHSRTN_OFFSET 0x346 #define MPFS_USB_C_T_HSBT_OFFSET 0x348 +#define MPFS_USB_DMA_ADDR_UPPER_REG_OFFSET 0x3FC + #define MPFS_USB_POWER (MPFS_USB_BASE + MPFS_USB_POWER_OFFSET) #define MPFS_USB_POWER_ENABLE_SUSPENDM (1 << 0) #define MPFS_USB_POWER_SUSPEND_MODE (1 << 1) @@ -175,6 +177,12 @@ #define MPFS_USB_RX_DPBUF_DIS (MPFS_USB_BASE + MPFS_USB_RX_DPBUF_DIS_OFFSET) #define MPFS_USB_TX_DPBUF_DIS (MPFS_USB_BASE + MPFS_USB_TX_DPBUF_DIS_OFFSET) +/* MPFS_USB_DMA_ADDR_UPPER_REG is used to set the upper 6-bits of + * the Address bus for USB DMA operations. + */ + +#define MPFS_USB_DMA_ADDR_UPPER_REG (MPFS_USB_BASE + MPFS_USB_DMA_ADDR_UPPER_REG_OFFSET) + #define MPFS_USB_DMA_CHANNEL(n) (MPFS_USB_BASE + MPFS_USB_DMA_CHANNEL_OFFSET + MPFS_USB_DMA_CHANNEL_SIZE * n) /**************************************************************************** @@ -419,6 +427,7 @@ struct mpfs_ep_s struct mpfs_rqhead_s reqq; /* Read/write request queue */ struct mpfs_rqhead_s pendq; /* Write requests pending stall sent */ struct usbdev_epdesc_s *descb[2]; /* Pointers to this endpoint descriptors */ + uint32_t linkdead; /* Remote end has closed the connection */ volatile uint8_t epstate; /* State of the endpoint (see enum mpfs_epstate_e) */ uint8_t stalled:1; /* true: Endpoint is stalled */ uint8_t pending:1; /* true: IN Endpoint stall is pending */ diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_wdog.h b/arch/risc-v/src/mpfs/hardware/mpfs_wdog.h new file mode 100644 index 0000000000000..a2059e1f41958 --- /dev/null +++ b/arch/risc-v/src/mpfs/hardware/mpfs_wdog.h @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/hardware/mpfs_wdog.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_WDOG_H +#define __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_WDOG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Magic value for REFRESH register to reload watchdog countdown counter */ + +#define WDOG_REFRESH_RELOAD (0xdeadc0de) + +/* Magic value for FORCE register to perform immediate system reset */ + +#define WDOG_FORCE_IMMEDIATE_RESET (0x0c) + +/**************************************************************************** + * Register Offsets + ****************************************************************************/ + +#define MPFS_WDOG_REFRESH_OFFSET 0x000 /* Write value 0xdeadc0de to reset wdog. Read to get current count value */ +#define MPFS_WDOG_CONTROL_OFFSET 0x004 /* WDOG counter register */ +#define MPFS_WDOG_STATUS_OFFSET 0x008 /* WDOG status register */ +#define MPFS_WDOG_TIME_OFFSET 0x00C /* Set WDOG time value */ +#define MPFS_WDOG_MSVP_OFFSET 0x010 /* Set MSVP int level */ +#define MPFS_WDOG_TRIGGER_OFFSET 0x014 /* Set NMI int level */ +#define MPFS_WDOG_FORCE_OFFSET 0x018 /* Force trigger WDOG NMI seq. Writing 0xc triggers immediate reset */ + +/**************************************************************************** + * Control register masks + ****************************************************************************/ + +#define WDOG_CONTROL_INTEN_MSVP_MASK (1 << 0) /* Bit 0: Enable MVRP interrupt when MVRP level is passed */ +#define WDOG_CONTROL_INTEN_TRIG_MASK (1 << 1) /* Bit 1: Enable NMI interrupt. This bit is permanenty set */ +#define WDOG_CONTROL_INTEN_SLEEP_MASK (1 << 2) /* Bit 2: Enable MVRP interrupt when MVRP level is passed and M3 is sleeping */ +#define WDOG_CONTROL_ACTIVE_SLEEP_MASK (1 << 3) /* Bit 3: Set WDOG operational during CPU sleep */ +#define WDOG_CONTROL_ENABLE_FORBITTEN_MASK (1 << 4) /* Bit 4: Enable trigger wdog from write during forbitten window */ + +/**************************************************************************** + * Status register masks + ****************************************************************************/ + +#define WDOG_STATUS_MVRP_TRIPPED_MASK (1 << 0) /* Bit 0: MVRP level has passed. Write to clear interrupt */ +#define WDOG_STATUS_WDOG_TRIPPED_MASK (1 << 1) /* Bit 1: TRIGGER level has passed and NMI is asserted. Write to clear interrupt */ +#define WDOG_STATUS_FORBITTEN_MASK (1 << 2) /* Bit 2: Watchdog in forbitten window */ +#define WDOG_STATUS_TRIGGERED_MASK (1 << 3) /* Bit 3: Watchdog has triggered */ +#define WDOG_STATUS_LOCKED_MASK (1 << 4) /* Bit 4: Following registers are locked and cannot be changed */ +#define WDOG_STATUS_DEVRST_MASK (1 << 5) /* Bit 5: DEVRST caused NMI */ + +#endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_WDOG_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_clockconfig.c b/arch/risc-v/src/mpfs/mpfs_clockconfig.c index 320021a27805f..7802560cfa838 100644 --- a/arch/risc-v/src/mpfs/mpfs_clockconfig.c +++ b/arch/risc-v/src/mpfs/mpfs_clockconfig.c @@ -143,6 +143,8 @@ enum part_type_e static uint64_t g_cpu_clock = MPFS_MSS_EXT_SGMII_REF_CLK; +#ifdef CONFIG_MPFS_BOOTLOADER + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -630,6 +632,8 @@ void mpfs_clockconfig(void) mpfs_pll_config(); } +#endif + /**************************************************************************** * Name: mpfs_get_cpuclk ****************************************************************************/ diff --git a/arch/risc-v/src/mpfs/mpfs_config.h b/arch/risc-v/src/mpfs/mpfs_config.h index ce2007d599822..896036b5c6ac9 100644 --- a/arch/risc-v/src/mpfs/mpfs_config.h +++ b/arch/risc-v/src/mpfs/mpfs_config.h @@ -37,7 +37,8 @@ #undef HAVE_UART_DEVICE #if defined(CONFIG_MPFS_UART0) || defined(CONFIG_MPFS_UART1) || \ defined(CONFIG_MPFS_UART2) || defined(CONFIG_MPFS_UART3) || \ - defined(CONFIG_MPFS_UART4) + defined(CONFIG_MPFS_UART4) || defined(CONFIG_MPFS_UART5) || \ + defined(CONFIG_MPFS_UART6) || defined(CONFIG_MPFS_UART7) # define HAVE_UART_DEVICE 1 #endif @@ -46,30 +47,72 @@ # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #elif defined(CONFIG_UART1_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART1) # undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #elif defined(CONFIG_UART2_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART2) # undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART1_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #elif defined(CONFIG_UART3_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART3) # undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART1_SERIAL_CONSOLE # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART4) # undef CONFIG_UART0_SERIAL_CONSOLE # undef CONFIG_UART1_SERIAL_CONSOLE # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# define HAVE_SERIAL_CONSOLE 1 +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART5) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# define HAVE_SERIAL_CONSOLE 1 +#elif defined(CONFIG_UART6_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART6) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE +# define HAVE_SERIAL_CONSOLE 1 +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_MPFS_UART7) +# undef CONFIG_UART0_SERIAL_CONSOLE +# undef CONFIG_UART1_SERIAL_CONSOLE +# undef CONFIG_UART2_SERIAL_CONSOLE +# undef CONFIG_UART3_SERIAL_CONSOLE +# undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE # define HAVE_SERIAL_CONSOLE 1 #else # undef CONFIG_UART0_SERIAL_CONSOLE diff --git a/arch/risc-v/src/mpfs/mpfs_coremmc.c b/arch/risc-v/src/mpfs/mpfs_coremmc.c index 02d8bd7499ad6..b725f1556cef6 100644 --- a/arch/risc-v/src/mpfs/mpfs_coremmc.c +++ b/arch/risc-v/src/mpfs/mpfs_coremmc.c @@ -45,10 +45,12 @@ #include -#include "mpfs_emmcsd.h" +#include "mpfs_coremmc.h" #include "riscv_internal.h" #include "hardware/mpfs_coremmc.h" +#include "mpfs_sdio_dev.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -158,54 +160,6 @@ * Private Types ****************************************************************************/ -/* This structure defines the state of the MPFS eMMCSD interface */ - -struct mpfs_dev_s -{ - struct sdio_dev_s dev; /* Standard, base SDIO interface */ - - const uintptr_t hw_base; /* Base address */ - const int plic_irq; /* PLIC interrupt */ - bool clk_enabled; /* Clk state */ - - /* Event support */ - - sem_t waitsem; /* Implements event waiting */ - sdio_eventset_t waitevents; /* Set of events to be waited for */ - uint32_t waitmask; /* Interrupt enables for event waiting */ - volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */ - struct wdog_s waitwdog; /* Watchdog that handles event timeouts */ - - /* Callback support */ - - sdio_statset_t cdstatus; /* Card status */ - sdio_eventset_t cbevents; /* Set of events to be cause callbacks */ - worker_t callback; /* Registered callback function */ - void *cbarg; /* Registered callback argument */ - struct work_s cbwork; /* Callback work queue structure */ - - /* Interrupt mode data transfer support */ - - uint32_t *buffer; /* Address of current R/W buffer */ - size_t remaining; /* Number of bytes remaining in the transfer */ - size_t receivecnt; /* Real count to receive */ - uint32_t xfrmask; /* Interrupt enables for data transfer */ - uint32_t xfr_blkmask; /* Interrupt enables for SB/MB data transfer */ - - bool widebus; /* Required for DMA support */ - bool onebit; /* true: Only 1-bit transfers are supported */ - - /* Data transfer support */ - - bool polltransfer; /* Indicate a poll transfer, no DMA */ - bool multiblock; /* Indicate a multi-block transfer */ - - /* Misc */ - - uint32_t blocksize; /* Current block size */ - uint32_t fifo_depth; /* Fifo size, read from the register */ -}; - union { uint32_t w; @@ -2277,7 +2231,7 @@ static void mpfs_callback(void *arg) ****************************************************************************/ /**************************************************************************** - * Name: sdio_initialize + * Name: mpfs_coremmc_sdio_initialize * * Description: * Initialize SDIO for operation. @@ -2291,7 +2245,7 @@ static void mpfs_callback(void *arg) * ****************************************************************************/ -struct sdio_dev_s *sdio_initialize(int slotno) +struct sdio_dev_s *mpfs_coremmc_sdio_initialize(int slotno) { struct mpfs_dev_s *priv = &g_coremmc_dev; @@ -2308,7 +2262,7 @@ struct sdio_dev_s *sdio_initialize(int slotno) } /**************************************************************************** - * Name: sdio_mediachange + * Name: mpfs_coremmc_sdio_mediachange * * Description: * Called by board-specific logic -- possible from an interrupt handler -- @@ -2326,7 +2280,7 @@ struct sdio_dev_s *sdio_initialize(int slotno) * ****************************************************************************/ -void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) +void mpfs_coremmc_sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) { struct mpfs_dev_s *priv = (struct mpfs_dev_s *)dev; sdio_statset_t cdstatus; @@ -2359,7 +2313,7 @@ void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) } /**************************************************************************** - * Name: sdio_wrprotect + * Name: mpfs_coremmc_sdio_wrprotect * * Description: * Called by board-specific logic to report if the card in the slot is @@ -2374,7 +2328,7 @@ void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) * ****************************************************************************/ -void sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect) +void mpfs_coremmc_sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect) { struct mpfs_dev_s *priv = (struct mpfs_dev_s *)dev; irqstate_t flags; diff --git a/arch/risc-v/src/mpfs/mpfs_coremmc.h b/arch/risc-v/src/mpfs/mpfs_coremmc.h index 86cc90dca2ff3..95bf79b4d3b9b 100644 --- a/arch/risc-v/src/mpfs/mpfs_coremmc.h +++ b/arch/risc-v/src/mpfs/mpfs_coremmc.h @@ -48,7 +48,7 @@ extern "C" #endif /**************************************************************************** - * Name: sdio_initialize + * Name: mpfs_coremmc_sdio_initialize * * Description: * Initialize SDIO for operation. @@ -63,10 +63,10 @@ extern "C" ****************************************************************************/ struct sdio_dev_s; /* See include/nuttx/sdio.h */ -struct sdio_dev_s *sdio_initialize(int slotno); +struct sdio_dev_s *mpfs_coremmc_sdio_initialize(int slotno); /**************************************************************************** - * Name: sdio_mediachange + * Name: mpfs_coremmc_sdio_mediachange * * Description: * Called by board-specific logic -- possibly from an interrupt handler -- @@ -84,10 +84,10 @@ struct sdio_dev_s *sdio_initialize(int slotno); * ****************************************************************************/ -void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot); +void mpfs_coremmc_sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot); /**************************************************************************** - * Name: sdio_wrprotect + * Name: mpfs_coremmc_sdio_wrprotect * * Description: * Called by board-specific logic to report if the card in the slot is @@ -102,7 +102,7 @@ void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot); * ****************************************************************************/ -void sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect); +void mpfs_coremmc_sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect); #undef EXTERN #if defined(__cplusplus) diff --git a/arch/risc-v/src/mpfs/mpfs_corepwm.c b/arch/risc-v/src/mpfs/mpfs_corepwm.c index e291bc6ab5a1d..b59d3250b6172 100644 --- a/arch/risc-v/src/mpfs/mpfs_corepwm.c +++ b/arch/risc-v/src/mpfs/mpfs_corepwm.c @@ -76,7 +76,6 @@ struct mpfs_pwmtimer_s struct mpfs_pwmchan_s channels[MPFS_MAX_PWM_CHANNELS]; uint32_t frequency; /* Current frequency setting */ uintptr_t base; /* The base address of the pwm block */ - uint32_t pwmclk; /* The frequency of the pwm clock */ }; /**************************************************************************** @@ -187,7 +186,6 @@ static struct mpfs_pwmtimer_s g_pwm0dev = } }, .base = CONFIG_MPFS_COREPWM0_BASE, - .pwmclk = CONFIG_MPFS_COREPWM0_PWMCLK, }; #endif @@ -249,7 +247,6 @@ static struct mpfs_pwmtimer_s g_pwm1dev = } }, .base = CONFIG_MPFS_COREPWM1_BASE, - .pwmclk = CONFIG_MPFS_COREPWM1_PWMCLK, }; #endif @@ -404,12 +401,12 @@ static int pwm_timer(struct mpfs_pwmtimer_s *priv, * PERIOD = pwmclk / frequency = 25,000,000 / 50 = 500,000 */ - pwminfo("PWM%u frequency: %u PWMCLK: %u prescaler: %u\n", - priv->pwmid, info->frequency, priv->pwmclk, prescaler); + pwminfo("PWM%u frequency: %u PWMCLK: %lu prescaler: %u\n", + priv->pwmid, info->frequency, MPFS_FPGA_PERIPHERAL_CLK, prescaler); /* Set the reload and prescaler values */ - period = priv->pwmclk / info->frequency; + period = MPFS_FPGA_PERIPHERAL_CLK / info->frequency; pwm_putreg(priv, MPFS_COREPWM_PERIOD_OFFSET, period); pwm_putreg(priv, MPFS_COREPWM_PRESCALE_OFFSET, prescaler); diff --git a/arch/risc-v/src/mpfs/mpfs_corespi.c b/arch/risc-v/src/mpfs/mpfs_corespi.c index f92ed0123c8e1..b7636c953bcb3 100644 --- a/arch/risc-v/src/mpfs/mpfs_corespi.c +++ b/arch/risc-v/src/mpfs/mpfs_corespi.c @@ -929,6 +929,18 @@ static void mpfs_spi_irq_exchange(struct mpfs_spi_priv_s *priv, MPFS_SPI_INTTXDONE, 0); + /* TX_DONE interrupt can be received after a semaphore timeout, but before + * interrupts are disabled. This will leave the semaphore to the signaled + * state. + * After a timeout the semaphore is always reset to non-signaled state + * to fix this race condition. + */ + + if (priv->error == -ETIMEDOUT) + { + nxsem_reset(&priv->sem_isr, 0); + } + putreg32(MPFS_SPI_TXCHUNDRUN | MPFS_SPI_RXCHOVRFLW | MPFS_SPI_DATA_RX | @@ -1435,6 +1447,22 @@ static void mpfs_spi_init(struct spi_dev_s *dev) mpfs_spi_set_master_mode(priv, 1); mpfs_spi_enable(priv, 1); + /* Disable all interrupt sources */ + + modifyreg32(MPFS_SPI_CONTROL, MPFS_SPI_INTTXTURUN | + MPFS_SPI_INTRXOVRFLOW | + MPFS_SPI_INTTXDONE, + 0); + + /* Clear all interrupt sources */ + + putreg32(MPFS_SPI_TXCHUNDRUN | + MPFS_SPI_RXCHOVRFLW | + MPFS_SPI_DATA_RX | + MPFS_SPI_TXDONE, MPFS_SPI_INT_CLEAR); + + /* Then enable the interrupt */ + up_enable_irq(priv->plic_irq); } diff --git a/arch/risc-v/src/mpfs/mpfs_ddr.c b/arch/risc-v/src/mpfs/mpfs_ddr.c index 3819fba3a91f5..565770dc1fed7 100644 --- a/arch/risc-v/src/mpfs/mpfs_ddr.c +++ b/arch/risc-v/src/mpfs/mpfs_ddr.c @@ -100,8 +100,6 @@ /* Retraining limits */ -#define ABNORMAL_RETRAIN_CA_DECREASE_COUNT 2 -#define ABNORMAL_RETRAIN_CA_DLY_DECREASE_COUNT 2 #define DQ_DQS_NUM_TAPS 5 /* PLL convenience bits */ @@ -719,6 +717,8 @@ static int mpfs_ddr_pll_lock_scb(void) #define INIT_SETTING_SEG1_6 0x00000000 #define INIT_SETTING_SEG1_7 0x00000000 +#define SEG_LOCKED (1 << 31) + /**************************************************************************** * Name: mpfs_setup_ddr_segments * @@ -758,11 +758,18 @@ void mpfs_setup_ddr_segments(enum seg_setup_e option) } else { + /* This is the final configuration that cannot be changed after being + * locked. + */ + /* Segment 0 */ val_l = LIBERO_SETTING_SEG0_0 & 0x7fff; val_h = LIBERO_SETTING_SEG0_1 & 0x7fff; + val_l |= SEG_LOCKED; + val_h |= SEG_LOCKED; + putreg64((((uint64_t)val_h) << 32) | val_l, MPFS_MPUCFG_SEG0_REG0); /* Segment 1 */ @@ -770,18 +777,24 @@ void mpfs_setup_ddr_segments(enum seg_setup_e option) val_l = LIBERO_SETTING_SEG1_2 & 0x7fff; val_h = LIBERO_SETTING_SEG1_3 & 0x7fff; + val_l |= SEG_LOCKED; + val_h |= SEG_LOCKED; + putreg64((((uint64_t)val_h) << 32) | val_l, MPFS_MPUCFG_SEG1_REG1); val_l = LIBERO_SETTING_SEG1_4 & 0x7fff; val_h = LIBERO_SETTING_SEG1_5 & 0x7fff; + val_l |= SEG_LOCKED; + val_h |= SEG_LOCKED; + putreg64((((uint64_t)val_h) << 32) | val_l, MPFS_MPUCFG_SEG1_REG2); } /* Disable ddr blocker: cleared at reset. When written to '1' disables * the blocker function allowing the L2 cache controller to access the * DDRC. Once written to '1' the register cannot be written to 0, only - * an devie reset will clear the register. + * an device reset will clear the register. */ putreg64((((uint64_t)0x01) << 32) , MPFS_MPUCFG_SEG0_REG3); @@ -3407,15 +3420,15 @@ static int mpfs_training_addcmd(void) static int mpfs_training_verify(void) { - uint32_t low_ca_dly_count; - uint32_t decrease_count; uint32_t addcmd_status0; uint32_t addcmd_status1; uint32_t retries = MPFS_DEFAULT_RETRIES; uint32_t t_status = 0; uint32_t lane_sel; - uint32_t last; uint32_t i; + uint32_t off_taps; + uint32_t width_taps; + uint32_t gt_clk_sel; while (!(getreg32(MPFS_DDR_CSR_APB_STAT_DFI_TRAINING_COMPLETE) & 0x01) && --retries); @@ -3426,19 +3439,15 @@ static int mpfs_training_verify(void) return -ETIMEDOUT; } - for (lane_sel = 0; lane_sel < LIBERO_SETTING_DATA_LANES_USED; lane_sel++) - { - mpfs_wait_cycles(10); - - putreg32(lane_sel, MPFS_CFG_DDR_SGMII_PHY_LANE_SELECT); - mpfs_wait_cycles(10); - - /* Verify cmd address results, rejects if not acceptable */ + /* Verify cmd address results, rejects if not acceptable */ - addcmd_status0 = getreg32(MPFS_CFG_DDR_SGMII_PHY_ADDCMD_STATUS0); - addcmd_status1 = getreg32(MPFS_CFG_DDR_SGMII_PHY_ADDCMD_STATUS1); + addcmd_status0 = getreg32(MPFS_CFG_DDR_SGMII_PHY_ADDCMD_STATUS0); + addcmd_status1 = getreg32(MPFS_CFG_DDR_SGMII_PHY_ADDCMD_STATUS1); - uint32_t ca_status[8] = + if ((LIBERO_SETTING_TRAINING_SKIP_SETTING & ADDCMD_BIT) != ADDCMD_BIT) + { + unsigned low_ca_dly_count = 0; + uint8_t ca_status[8] = { ((addcmd_status0) & 0xff), ((addcmd_status0 >> 8) & 0xff), @@ -3450,46 +3459,40 @@ static int mpfs_training_verify(void) ((addcmd_status1 >> 24) & 0xff) }; - low_ca_dly_count = 0; - last = 0; - decrease_count = 0; + uint8_t last = ca_status[7]; + + /* Retrain if abnormal CA training result detected + * Expected result is increasing numbers, starting at index n and + * wrapping around. For example: + * [0x35, 0x3b, 0x4, 0x14, 0x1b, 0x21, 0x28, 0x2f]. + * + * Also they need to be separated by at least 5 + */ for (i = 0; i < 8; i++) { - if (ca_status[i] < 5) + if (ca_status[i] < last + 5) { low_ca_dly_count++; } - if (ca_status[i] <= last) - { - decrease_count++; - } - last = ca_status[i]; } - if (ca_status[0] <= ca_status[7]) - { - decrease_count++; - } - - if ((LIBERO_SETTING_TRAINING_SKIP_SETTING & ADDCMD_BIT) != ADDCMD_BIT) + if (low_ca_dly_count > 1) { - /* Retrain if abnormal CA training result detected */ + /* Retrain via reset */ - if (low_ca_dly_count > ABNORMAL_RETRAIN_CA_DLY_DECREASE_COUNT) - { - t_status |= 0x01; - } + return -EIO; + } + } - /* Retrain if abnormal CA training result detected */ + for (lane_sel = 0; lane_sel < LIBERO_SETTING_DATA_LANES_USED; lane_sel++) + { + mpfs_wait_cycles(10); - if (decrease_count > ABNORMAL_RETRAIN_CA_DECREASE_COUNT) - { - t_status |= 0x01; - } - } + putreg32(lane_sel, MPFS_CFG_DDR_SGMII_PHY_LANE_SELECT); + mpfs_wait_cycles(10); /* Check that gate training passed without error */ @@ -3503,56 +3506,27 @@ static int mpfs_training_verify(void) t_status |= 0x01; } - /* Check that DQ/DQS calculated window is above 5 taps. */ + /* Check that DQ/DQS calculated window is above 5 taps + * and centered with margin + */ + + off_taps = getreg32(MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS1); + width_taps = getreg32(MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS2); - if (getreg32(MPFS_CFG_DDR_SGMII_PHY_DQDQS_STATUS2) < DQ_DQS_NUM_TAPS) + if (width_taps < DQ_DQS_NUM_TAPS || + width_taps + off_taps <= 16 + DQ_DQS_NUM_TAPS / 2) { t_status |= 0x01; } /* Extra checks */ - uint32_t temp = 0; - uint32_t gt_clk_sel = getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_CLK_SEL) & - 0x03; - - if ((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) & 0xff) == 0) - { - temp++; - if (gt_clk_sel == 0) - { - t_status |= 0x01; - } - } - - if (((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) >> 8) & 0xff) == 0) - { - temp++; - if (gt_clk_sel == 1) - { - t_status |= 0x01; - } - } - - if (((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) >> 16) & 0xff) == 0) - { - temp++; - if (gt_clk_sel == 2) - { - t_status |= 0x01; - } - } + /* Check the GT_TXDLY result for the selected clock */ - if (((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) >> 24) & 0xff) == 0) - { - temp++; - if (gt_clk_sel == 3) - { - t_status |= 0x01; - } - } + gt_clk_sel = getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_CLK_SEL) & 0x03; - if (temp > 1) + if (((getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_TXDLY) >> (gt_clk_sel * 8)) & + 0xff) == 0) { t_status |= 0x01; } diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index 267894dc81c1e..37b1cc8075115 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -50,6 +50,8 @@ #include "hardware/mpfs_emmcsd.h" #include "hardware/mpfs_mpucfg.h" +#include "mpfs_sdio_dev.h" + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -152,7 +154,7 @@ /* Provide default SD-card 4bit clk if unset at board.h */ #ifndef MPFS_SD_CLOCK_4BIT -# define MPFS_SD_CLOCK_4BIT MPFS_MMC_CLOCK_25MHZ +# define MPFS_SD_CLOCK_4BIT MPFS_MMC_CLOCK_50MHZ #endif /* Define the Hardware FIFO size */ @@ -291,58 +293,6 @@ * Private Types ****************************************************************************/ -/* This structure defines the state of the MPFS eMMCSD interface */ - -struct mpfs_dev_s -{ - struct sdio_dev_s dev; /* Standard, base SDIO interface */ - - const uintptr_t hw_base; /* Base address */ - const int plic_irq; /* PLIC interrupt */ - bool clk_enabled; /* Clk state */ - - /* eMMC / SD and HW parameters */ - - const bool emmc; /* eMMC or SD */ - int bus_voltage; /* Bus voltage */ - int bus_mode; /* eMMC Bus mode */ - bool jumpers_3v3; /* Jumper settings: 1v8 or 3v3 */ - - /* Event support */ - - sem_t waitsem; /* Implements event waiting */ - sdio_eventset_t waitevents; /* Set of events to be waited for */ - uint32_t waitmask; /* Interrupt enables for event waiting */ - volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */ - struct wdog_s waitwdog; /* Watchdog that handles event timeouts */ - - /* Callback support */ - - sdio_statset_t cdstatus; /* Card status */ - sdio_eventset_t cbevents; /* Set of events to be cause callbacks */ - worker_t callback; /* Registered callback function */ - void *cbarg; /* Registered callback argument */ - struct work_s cbwork; /* Callback work queue structure */ - - /* Interrupt mode data transfer support */ - - uint32_t *buffer; /* Address of current R/W buffer */ - size_t remaining; /* Number of bytes remaining in the transfer */ - size_t receivecnt; /* Real count to receive */ - uint32_t xfrmask; /* Interrupt enables for data transfer */ - - bool widebus; /* Required for DMA support */ - bool onebit; /* true: Only 1-bit transfers are supported */ - - /* DMA data transfer support */ - - bool polltransfer; /* Indicate a poll transfer, no DMA */ - - /* Misc */ - - uint32_t blocksize; /* Current block size */ -}; - /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -779,12 +729,22 @@ static void mpfs_sendfifo(struct mpfs_dev_s *priv) * come back when we're good to write again. */ - if (priv->remaining && (!(getreg32(MPFS_EMMCSD_SRS09) & - MPFS_EMMCSD_SRS09_BWE))) + if (priv->remaining) { - modifyreg32(MPFS_EMMCSD_SRS14, 0, MPFS_EMMCSD_SRS14_BWR_IE); + /* Enable BWR before checking BWE bit */ + putreg32(MPFS_EMMCSD_SRS12_BWR, MPFS_EMMCSD_SRS12); - return; + modifyreg32(MPFS_EMMCSD_SRS14, 0, MPFS_EMMCSD_SRS14_BWR_IE); + if (!(getreg32(MPFS_EMMCSD_SRS09) & MPFS_EMMCSD_SRS09_BWE)) + { + return; + } + + /* There is still room for writing to buffer, + * disable BWR and continue. + */ + + modifyreg32(MPFS_EMMCSD_SRS14, MPFS_EMMCSD_SRS14_BWR_IE, 0); } } @@ -1135,14 +1095,14 @@ static int mpfs_emmcsd_interrupt(int irq, void *context, void *arg) { mcinfo("Card inserted!\n"); - sdio_mediachange((struct sdio_dev_s *)priv, true); + mpfs_emmcsd_sdio_mediachange((struct sdio_dev_s *)priv, true); putreg32(MPFS_EMMCSD_SRS12_CIN, MPFS_EMMCSD_SRS12); } else if (status & MPFS_EMMCSD_SRS12_CR) { mcinfo("Card removed!\n"); - sdio_mediachange((struct sdio_dev_s *)priv, false); + mpfs_emmcsd_sdio_mediachange((struct sdio_dev_s *)priv, false); putreg32(MPFS_EMMCSD_SRS12_CR, MPFS_EMMCSD_SRS12); } else @@ -1802,6 +1762,84 @@ static void mpfs_widebus(struct sdio_dev_s *dev, bool wide) } } +/**************************************************************************** + * Name: mpfs_clock + * + ****************************************************************************/ + +static void mpfs_set_hs_8bit(struct sdio_dev_s *dev) +{ + struct mpfs_dev_s *priv = (struct mpfs_dev_s *)dev; + int ret; + uint32_t r1; + uint32_t rr; + + /* mpfs to DDR mode */ + + modifyreg32(MPFS_EMMCSD_HRS06, 0x7, MPFS_EMMCSD_MODE_DDR); + + /* eMMC to HS mode */ + + if ((ret = mpfs_sendcmd(dev, MMCSD_CMD6, 0x03b90100u)) == OK) + { + if ((ret == mpfs_waitresponse(dev, MMCSD_CMD6)) == OK) + { + ret = mpfs_recvshortcrc(dev, MMCSD_CMD6, &r1); + } + } + + if (ret < 0) + { + mcerr("Failed to set high speed mode\n"); + goto err; + } + + /* While busy */ + + do + { + rr = getreg32(MPFS_EMMCSD_SRS09); + } + while ((rr & (1 << 20)) == 0); + + /* mpfs to 8-bit mode */ + + modifyreg32(MPFS_EMMCSD_SRS10, 0, MPFS_EMMCSD_SRS10_EDTW); + + /* eMMC to 8-bit DDR mode */ + + if ((ret = mpfs_sendcmd(dev, MMCSD_CMD6, 0x03b70600u)) == OK) + { + if ((ret == mpfs_waitresponse(dev, MMCSD_CMD6)) == OK) + { + ret = mpfs_recvshortcrc(dev, MMCSD_CMD6, &r1); + } + } + + if (ret < 0) + { + mcerr("Failed to set 8-bit mode\n"); + goto err; + } + + /* While busy */ + + do + { + rr = getreg32(MPFS_EMMCSD_SRS09); + } + while ((rr & (1 << 20)) == 0); + + return; + +err: + + /* Reset to 1-bit legacy mode */ + + modifyreg32(MPFS_EMMCSD_HRS06, 0, MPFS_EMMCSD_MODE_LEGACY); + modifyreg32(MPFS_EMMCSD_SRS10, MPFS_EMMCSD_SRS10_EDTW, 0); +} + /**************************************************************************** * Name: mpfs_clock * @@ -1845,7 +1883,8 @@ static void mpfs_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) { clckr = MPFS_MMC_CLOCK_200MHZ; } - else if (priv->bus_mode == MPFS_EMMCSD_MODE_SDR) + else if (priv->bus_mode == MPFS_EMMCSD_MODE_SDR || + priv->bus_mode == MPFS_EMMCSD_MODE_DDR) { clckr = MPFS_MMC_CLOCK_50MHZ; } @@ -1866,10 +1905,17 @@ static void mpfs_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) /* SD normal operation clocking (narrow 1-bit mode) */ case CLOCK_SD_TRANSFER_1BIT: - clckr = MPFS_MMC_CLOCK_25MHZ; + clckr = MPFS_MMC_CLOCK_50MHZ; break; } + if (rate == CLOCK_MMC_TRANSFER) + { + /* eMMC: Set 8-bit data bus and correct bus mode */ + + mpfs_set_hs_8bit(dev); + } + /* Set the new clock frequency */ mpfs_setclkrate(priv, clckr); @@ -2205,7 +2251,11 @@ static int mpfs_dmarecvsetup(struct sdio_dev_s *dev, mcinfo("Receive: %zu bytes\n", buflen); DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); - DEBUGASSERT(((uintptr_t)buffer & 3) == 0); + if (((uintptr_t)buffer & 3) != 0) + { + mcerr("Unaligned buffer: %p\n", buffer); + return -EFAULT; + } priv->buffer = (uint32_t *)buffer; priv->remaining = buflen; @@ -2265,15 +2315,10 @@ static int mpfs_dmasendsetup(struct sdio_dev_s *dev, mcinfo("Send: %zu bytes\n", buflen); DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); - DEBUGASSERT(((uintptr_t)buffer & 3) == 0); - - /* DMA send doesn't work in 0x08xxxxxxx address range. Default to IRQ mode - * in this special case. - */ - - if (((uintptr_t)buffer & 0xff000000) == 0x08000000) + if (((uintptr_t)buffer & 3) != 0) { - return mpfs_sendsetup(dev, buffer, buflen); + mcerr("Unaligned buffer: %p\n", buffer); + return -EFAULT; } /* Save the source buffer information for use by the interrupt handler */ @@ -2948,7 +2993,7 @@ static void mpfs_callback(void *arg) ****************************************************************************/ /**************************************************************************** - * Name: sdio_initialize + * Name: mpfs_emmcsd_sdio_initialize * * Description: * Initialize SDIO for operation. @@ -2962,7 +3007,7 @@ static void mpfs_callback(void *arg) * ****************************************************************************/ -struct sdio_dev_s *sdio_initialize(int slotno) +struct sdio_dev_s *mpfs_emmcsd_sdio_initialize(int slotno) { struct mpfs_dev_s *priv = NULL; priv = &g_emmcsd_dev; @@ -2973,14 +3018,14 @@ struct sdio_dev_s *sdio_initialize(int slotno) if (!mpfs_device_reset(&priv->dev)) { - return NULL; + return (struct sdio_dev_s *)NULL; } - return &priv->dev; + return (struct sdio_dev_s *) &priv->dev; } /**************************************************************************** - * Name: sdio_mediachange + * Name: mpfs_emmcsd_sdio_mediachange * * Description: * Called by board-specific logic -- possible from an interrupt handler -- @@ -2998,7 +3043,7 @@ struct sdio_dev_s *sdio_initialize(int slotno) * ****************************************************************************/ -void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) +void mpfs_emmcsd_sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) { struct mpfs_dev_s *priv = (struct mpfs_dev_s *)dev; sdio_statset_t cdstatus; @@ -3031,7 +3076,7 @@ void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) } /**************************************************************************** - * Name: sdio_wrprotect + * Name: mpfs_emmcsd_sdio_wrprotect * * Description: * Called by board-specific logic to report if the card in the slot is @@ -3046,7 +3091,7 @@ void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) * ****************************************************************************/ -void sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect) +void mpfs_emmcsd_sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect) { struct mpfs_dev_s *priv = (struct mpfs_dev_s *)dev; irqstate_t flags; diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.h b/arch/risc-v/src/mpfs/mpfs_emmcsd.h index 3f1e0f562453d..40e90a91dccd9 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.h +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.h @@ -48,7 +48,7 @@ extern "C" #endif /**************************************************************************** - * Name: sdio_initialize + * Name: mpfs_emmcsd_sdio_initialize * * Description: * Initialize SDIO for operation. @@ -63,10 +63,10 @@ extern "C" ****************************************************************************/ struct sdio_dev_s; /* See include/nuttx/sdio.h */ -struct sdio_dev_s *sdio_initialize(int slotno); +struct sdio_dev_s *mpfs_emmcsd_sdio_initialize(int slotno); /**************************************************************************** - * Name: sdio_mediachange + * Name: mpfs_emmcsd_sdio_mediachange * * Description: * Called by board-specific logic -- possibly from an interrupt handler -- @@ -84,10 +84,10 @@ struct sdio_dev_s *sdio_initialize(int slotno); * ****************************************************************************/ -void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot); +void mpfs_emmcsd_sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot); /**************************************************************************** - * Name: sdio_wrprotect + * Name: mpfs_emmcsd_sdio_wrprotect * * Description: * Called by board-specific logic to report if the card in the slot is @@ -102,7 +102,7 @@ void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot); * ****************************************************************************/ -void sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect); +void mpfs_emmcsd_sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect); #undef EXTERN #if defined(__cplusplus) diff --git a/arch/risc-v/src/mpfs/mpfs_entrypoints.c b/arch/risc-v/src/mpfs/mpfs_entrypoints.c index 2480253f783e6..71c659220cbc1 100644 --- a/arch/risc-v/src/mpfs/mpfs_entrypoints.c +++ b/arch/risc-v/src/mpfs/mpfs_entrypoints.c @@ -107,6 +107,7 @@ void mpfs_jump_to_app(void) "la sp, g_mpfs_boot_stacks\n" /* Stack area base */ "add sp, sp, t0\n" /* Set stack pointer */ "call mpfs_board_pmp_setup\n" /* Run PMP configuration */ + "bne a0, x0, mpfs_board_pmp_error\n" /* If ret != 0, jump to errhan */ "csrr a0, mhartid\n" /* Restore hartid */ #else "li t0, -1\n" /* Open the whole SoC */ @@ -221,4 +222,28 @@ int mpfs_set_use_sbi(uint64_t hartid, bool use_sbi) return ERROR; } +/**************************************************************************** + * Name: mpfs_get_use_sbi + * + * Description: + * Get if hart boots via SBI. + * + * Input Parameters: + * hartid - hart id to check + * + * Returned value: + * true if SBI is used, false otherwise + * + ****************************************************************************/ + +bool mpfs_get_use_sbi(uint64_t hartid) +{ + if (hartid < ENTRYPT_CNT) + { + return (g_hart_use_sbi & (1 << hartid)) != 0; + } + + return false; +} + #endif /* CONFIG_MPFS_BOOTLOADER */ diff --git a/arch/risc-v/src/mpfs/mpfs_entrypoints.h b/arch/risc-v/src/mpfs/mpfs_entrypoints.h index 949972db74f2c..794b01974a691 100644 --- a/arch/risc-v/src/mpfs/mpfs_entrypoints.h +++ b/arch/risc-v/src/mpfs/mpfs_entrypoints.h @@ -86,6 +86,22 @@ int mpfs_set_entrypt(uint64_t hartid, uintptr_t entry); int mpfs_set_use_sbi(uint64_t hartid, bool use_sbi); +/**************************************************************************** + * Name: mpfs_get_use_sbi + * + * Description: + * Get if hart boots via SBI. + * + * Input Parameters: + * hartid - hart id to check + * + * Returned value: + * true if SBI is used, false otherwise + * + ****************************************************************************/ + +bool mpfs_get_use_sbi(uint64_t hartid); + #if defined(__cplusplus) } #endif diff --git a/arch/risc-v/src/mpfs/mpfs_ethernet.c b/arch/risc-v/src/mpfs/mpfs_ethernet.c index 382477fa9e60e..b11226afd88e3 100644 --- a/arch/risc-v/src/mpfs/mpfs_ethernet.c +++ b/arch/risc-v/src/mpfs/mpfs_ethernet.c @@ -61,6 +61,8 @@ #include "hardware/mpfs_ethernet.h" #include "hardware/mpfs_mpucfg.h" +#define SIZE_ALIGNED_64(m) (((m) + (0x3f)) & ~0x3f) + #if defined(CONFIG_MPFS_ETH0_PHY_KSZ9477) ||\ defined(CONFIG_MPFS_ETH1_PHY_KSZ9477) # if !defined(CONFIG_MPFS_MAC_SGMII) @@ -101,7 +103,7 @@ # elif defined(CONFIG_MPFS_ETHMAC_LPWORK) # define ETHWORK LPWORK # else -# define ETHWORK LPWORK +# define ETHWORK HPWORK # endif #endif @@ -129,14 +131,6 @@ # define CONFIG_MPFS_ETHMAC_NTXBUFFERS (8) #endif -/* GMAC buffer sizes - * REVISIT: do we want to make GMAC_RX_UNITSIZE configurable? - * issue when using the MTU size receive block - */ - -#define GMAC_RX_UNITSIZE (512) /* Fixed size for RX buffer */ -#define GMAC_TX_UNITSIZE CONFIG_NET_ETH_PKTSIZE /* MAX size for Ethernet packet */ - /* The MAC can support frame lengths up to 1536 bytes */ #define GMAC_MAX_FRAMELEN (1536) @@ -144,6 +138,11 @@ # error CONFIG_NET_ETH_PKTSIZE is too large #endif +/* Max size of RX and TX buffers */ + +#define GMAC_RX_UNITSIZE SIZE_ALIGNED_64(GMAC_MAX_FRAMELEN) +#define GMAC_TX_UNITSIZE SIZE_ALIGNED_64(CONFIG_NET_ETH_PKTSIZE) + /* for DMA dma_rxbuf_size */ #define MPFS_MAC_RX_BUF_VALUE ((GMAC_RX_UNITSIZE + 63) / 64) @@ -171,6 +170,10 @@ #define MPFS_TXTIMEOUT (60 * CLK_TCK) +/* RX timeout = 30s */ + +#define MPFS_RXTIMEOUT (30 * CLK_TCK) + /* PHY reset tim in loop counts */ #define PHY_RESET_WAIT_COUNT (10) @@ -268,6 +271,7 @@ struct mpfs_ethmac_s uint8_t phyaddr; /* PHY address */ #endif struct wdog_s txtimeout; /* TX timeout timer */ + struct wdog_s rxtimeout; /* RX timeout timer */ struct work_s irqwork; /* For deferring interrupt work to the work queue */ struct work_s pollwork; /* For deferring poll work to the work queue */ @@ -389,6 +393,7 @@ static int mpfs_ethconfig(struct mpfs_ethmac_s *priv); static void mpfs_ethreset(struct mpfs_ethmac_s *priv); static void mpfs_interrupt_work(void *arg); +static void mpfs_txtimeout_expiry(wdparm_t arg); /**************************************************************************** * Private Functions @@ -470,6 +475,14 @@ static int mpfs_interrupt_0(int irq, void *context, void *arg) wd_cancel(&priv->txtimeout); } + if ((isr & GEM_INT_RECEIVE_COMPLETE) != 0) + { + /* If a RX transfer just completed, restart the timeout */ + + wd_start(&priv->rxtimeout, MPFS_RXTIMEOUT, + mpfs_txtimeout_expiry, (wdparm_t)priv); + } + /* Schedule to perform the interrupt processing on the worker thread. */ work_queue(ETHWORK, &priv->irqwork, mpfs_interrupt_work, priv, 0); @@ -1558,6 +1571,13 @@ static int mpfs_ifup(struct net_driver_s *dev) up_enable_irq(priv->mac_q_int[2]); up_enable_irq(priv->mac_q_int[3]); + /* Set up the RX timeout. If we don't receive anything in time, try + * to re-initialize + */ + + wd_start(&priv->rxtimeout, MPFS_RXTIMEOUT, + mpfs_txtimeout_expiry, (wdparm_t)priv); + return OK; } @@ -1601,6 +1621,10 @@ static int mpfs_ifdown(struct net_driver_s *dev) wd_cancel(&priv->txtimeout); + /* Cancel the RX timeout timers */ + + wd_cancel(&priv->rxtimeout); + /* Put the MAC in its reset, non-operational state. This should be * a known configuration that will guarantee the mpfs_ifup() always * successfully brings the interface back up. diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c new file mode 100644 index 0000000000000..fd76bc5187ea1 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -0,0 +1,3081 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_fpga_canfd.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mpfs_fpga_canfd.h" +#include "riscv_internal.h" +#include "mpfs_memorymap.h" + +#include "hardware/mpfs_fpga_canfd.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef OK +# define OK 0 +#endif + +/* This module only compiles if the CANFD IP core instance + * is configured to the FPGA + */ + +#ifndef CONFIG_MPFS_HAVE_CANFD +# error This should not be compiled as CANFD FPGA block is not defined +#endif + +/* This module only compiles if Nuttx socketCAN interface supports CANFD */ + +#ifndef CONFIG_NET_CAN_CANFD +# error This should not be compiled as CANFD driver relies on socket CAN +#endif + +/* Clock reset and enabling */ + +#define MPFS_SYSREG_SOFT_RESET_CR (MPFS_SYSREG_BASE + \ + MPFS_SYSREG_SOFT_RESET_CR_OFFSET) +#define MPFS_SYSREG_SUBBLK_CLOCK_CR (MPFS_SYSREG_BASE + \ + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET) + +#define CANWORK HPWORK + +#define MPFS_CANFD_ID 0xCAFD + +/* For allocating the tx and rx CANFD frame buffer */ + +#define POOL_SIZE 1 +#define TIMESTAMP_SIZE sizeof(struct timeval) /* To support + * timestamping frame */ + +/* For bit timing calculation */ + +#define BT_COMPUTE_MAX_ERROR 50 /* 1/10th of % */ +#define BT_COMPUTE_SYNC_SEG 1 + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +/* CAN hw filter support */ + +#define HW_FILTER_A 0 +#define HW_FILTER_B 1 +#define HW_FILTER_C 2 +#define HW_FILTER_RANGE 3 + +#define CAN_STD_ID 0 +#define CAN_EXT_ID 1 +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + +/* Special address description flags for the CAN_ID */ + +#define CAN_EFF_FLAG 0x80000000 /* EFF/SFF is set in the MSB */ +#define CAN_RTR_FLAG 0x40000000 /* remote transmission request */ +#define CAN_ERR_FLAG 0x20000000 /* error message frame */ + +/* Valid bits in CAN ID for frame formats */ + +#define CAN_SFF_MASK 0x000007FF /* standard frame format (SFF) */ +#define CAN_EFF_MASK 0x1FFFFFFF /* extended frame format (EFF) */ +#define CAN_ERR_MASK 0x1FFFFFFF /* omit EFF, RTR, ERR flags */ + +/* CAN control mode */ + +#define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */ +#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */ +#define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */ +#define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ +#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ +#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ +#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ +#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ +#define CAN_CTRLMODE_CC_LEN8_DLC 0x100 /* Classic CAN DLC option */ +#define CAN_CTRLMODE_TDC_AUTO 0x200 /* CAN transiver automatically + * calculates TDCV */ +#define CAN_CTRLMODE_TDC_MANUAL 0x400 /* TDCV is manually set up by user */ + +/* TXT buffer */ + +enum mpfs_can_txb_status +{ + TXT_NOT_EXIST = 0x0, + TXT_RDY = 0x1, + TXT_TRAN = 0x2, + TXT_ABTP = 0x3, + TXT_TOK = 0x4, + TXT_ERR = 0x6, + TXT_ABT = 0x7, + TXT_ETY = 0x8, +}; + +enum mpfs_can_txb_command +{ + TXT_CMD_SET_EMPTY = 0x01, + TXT_CMD_SET_READY = 0x02, + TXT_CMD_SET_ABORT = 0x04 +}; + +/**************************************************************************** + * Utility definitions + ****************************************************************************/ + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define clamp(val, lo, hi) min(max(val, lo), hi) + +#define MPFS_CAN_FD_TXNF(priv) \ + (getreg32(priv->base + MPFS_CANFD_STATUS_OFFSET) & MPFS_CANFD_STATUS_TXNF) +#define MPFS_CAN_FD_ENABLED(priv) \ + (getreg32(priv->base + MPFS_CANFD_MODE_OFFSET) & MPFS_CANFD_MODE_ENA) + +#if __GNUC__ >= 3 +# define expect(expr,value) __builtin_expect((expr),(value)) +#else +# define expect(expr,value) (expr) +#endif + +#define expect_false(expr) expect((expr) != 0, 0) +#define expect_true(expr) expect((expr) != 0, 1) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* CAN operational and error states */ + +/* CAN bit timing parameters */ + +struct mpfs_can_bittiming_s +{ + uint32_t bitrate; /* Bit-rate in bits/second */ + uint32_t sample_point; /* Sample point in one-tenth of a percent */ + uint32_t tq; /* Time quanta (TQ) in nanoseconds */ + uint32_t prop_seg; /* Propagation segment in TQs */ + uint32_t phase_seg1; /* Phase buffer segment 1 in TQs */ + uint32_t phase_seg2; /* Phase buffer segment 2 in TQs */ + uint32_t sjw; /* Synchronisation jump width in TQs */ + uint32_t brp; /* Bitrate prescaler */ +}; + +/* CAN harware dependent bit timing constants + * Used for calculating and checking bit timing parameters + */ + +struct mpfs_can_bittiming_const_s +{ + uint32_t tseg_min; + uint32_t tseg_max; + uint32_t brp_min; + uint32_t brp_max; +}; + +static const struct mpfs_can_bittiming_const_s mpfs_can_bit_timing_range = +{ + .tseg_min = 3, + .tseg_max = 253, + .brp_min = 1, + .brp_max = 8, +}; + +static const struct mpfs_can_bittiming_const_s + mpfs_can_bit_timing_data_range = +{ + .tseg_min = 3, + .tseg_max = 125, + .brp_min = 1, + .brp_max = 2, +}; + +struct mpfs_can_clock_s +{ + uint32_t freq; /* CAN system clock frequency in Hz */ +}; + +enum mpfs_can_state_e +{ + CAN_STATE_ERROR_ACTIVE = 0, /* RX/TX error count < 96 */ + CAN_STATE_ERROR_WARNING, /* RX/TX error count < 128 */ + CAN_STATE_ERROR_PASSIVE, /* RX/TX error count < 256 */ + CAN_STATE_BUS_OFF, /* RX/TX error count >= 256 */ + CAN_STATE_STOPPED, /* Device is stopped */ + CAN_STATE_SLEEPING, /* Device is sleeping */ + CAN_STATE_MAX +}; + +struct mpfs_can_ctrlmode_s +{ + uint32_t mask; + uint32_t flags; +}; + +struct mpfs_can_berr_counter_s +{ + uint16_t txerr; + uint16_t rxerr; +}; + +struct mpfs_can_device_stats_s +{ + uint32_t bus_error; /* Bus errors */ + uint32_t error_warning; /* Changes to error warning state */ + uint32_t error_passive; /* Changes to error passive state */ + uint32_t bus_off; /* Changes to bus off state */ + uint32_t arbitration_lost; /* Arbitration lost errors */ + uint32_t restarts; /* CAN controller re-starts */ +}; + +/* CAN common private data */ + +struct mpfs_can_priv_s +{ + struct mpfs_can_device_stats_s can_stats; + struct mpfs_can_bittiming_s bittiming; + struct mpfs_can_bittiming_s data_bittiming; + const struct mpfs_can_bittiming_const_s *bittiming_const; + const struct mpfs_can_bittiming_const_s *data_bittiming_const; + struct mpfs_can_clock_s clock; + + enum mpfs_can_state_e state; + uint32_t ctrlmode; +}; + +/**************************************************************************** + * CANFD Frame Format + ****************************************************************************/ + +/* CAN frame format memory map */ + +enum mpfs_canfd_can_frame_format +{ + MPFS_CANFD_FRAME_FORMAT_W_OFFSET = 0x0, + MPFS_CANFD_IDENTIFIER_W_OFFSET = 0x4, + MPFS_CANFD_TIMESTAMP_L_W_OFFSET = 0x8, + MPFS_CANFD_TIMESTAMP_U_W_OFFSET = 0xc, + MPFS_CANFD_DATA_1_4_W_OFFSET = 0x10, + MPFS_CANFD_DATA_5_8_W_OFFSET = 0x14, + MPFS_CANFD_DATA_61_64_W_OFFSET = 0x4c, +}; + +/* CANFD_Frame_format memory region */ + +/* FRAME_FORMAT_W registers */ + +#define MPFS_CANFD_FRAME_FORMAT_W_DLC_SHIFT (0) +#define MPFS_CANFD_FRAME_FORMAT_W_DLC (0x0F << \ + MPFS_CANFD_FRAME_FORMAT_W_DLC_SHIFT) +#define MPFS_CANFD_FRAME_FORMAT_W_RTR (1 << 5) +#define MPFS_CANFD_FRAME_FORMAT_W_IDE (1 << 6) +#define MPFS_CANFD_FRAME_FORMAT_W_FDF (1 << 7) +#define MPFS_CANFD_FRAME_FORMAT_W_BRS (1 << 9) +#define MPFS_CANFD_FRAME_FORMAT_W_ESI_RSV (1 << 10) +#define MPFS_CANFD_FRAME_FORMAT_W_RWCNT_SHIFT (11) +#define MPFS_CANFD_FRAME_FORMAT_W_RWCNT (0x1F << \ + MPFS_CANFD_FRAME_FORMAT_W_RWCNT_SHIFT) + +/* IDENTIFIER_W registers */ + +#define MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT_SHIFT (0) +#define MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT (0x03FFFF << \ + MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT_SHIFT) +#define MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT (18) +#define MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE (0x07FF << \ + MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT) + +/**************************************************************************** + * CAN controller hardware configuration + ****************************************************************************/ + +struct mpfs_config_s +{ + uint32_t canfd_fpga_irq; /* the only CANFD FPGA IRQ */ +}; + +#ifdef CONFIG_MPFS_CANFD0 +static const struct mpfs_config_s mpfs_fpga_canfd_config0 = +{ + .canfd_fpga_irq = MPFS_IRQ_FABRIC_F2H_0, +}; +#endif +#ifdef CONFIG_MPFS_CANFD1 +static const struct mpfs_config_s mpfs_fpga_canfd_config1 = +{ + .canfd_fpga_irq = MPFS_IRQ_FABRIC_F2H_9, +}; +#endif + +/**************************************************************************** + * The mpfs_driver_s encapsulates all state information for a single + * hw interface + ****************************************************************************/ + +struct mpfs_driver_s +{ + struct mpfs_can_priv_s can; + + const struct mpfs_config_s *config; + + uintptr_t base; /* CANFD FPGA base address */ + bool bifup; /* true:ifup false:ifdown */ + + struct work_s rxwork; /* for deferring rx interrupt work to the wq */ + struct work_s txdwork; /* For deferring tx done interrupt work to the + * wq */ + struct work_s pollwork; /* For deferring poll work to the wq */ + + struct canfd_frame *txdesc; /* A pointer to the list of TX descriptor */ + struct canfd_frame *rxdesc; /* A pointer to the list of RX descriptors */ + + /* rx */ + + uint32_t drv_flags; /* driver flag */ + uint32_t rxfrm_first_word; /* rx frame first word (usually a FFW) */ + + /* tx */ + + unsigned int txb_sent; + unsigned int txb_processed; + uint32_t txb_prio; + unsigned int ntxbufs; + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + /* hw filter */ + + uint8_t used_bit_filter_number; + bool used_range_filter; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + /* This holds the information visible to the NuttX network */ + + struct net_driver_s dev; /* Interface understood by the network */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_MPFS_CANFD0 +static struct mpfs_driver_s g_canfd0; + +static uint8_t g_tx_pool0[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +static uint8_t g_rx_pool0[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +#endif + +#ifdef CONFIG_MPFS_CANFD1 +static struct mpfs_driver_s g_canfd1; + +static uint8_t g_tx_pool1[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +static uint8_t g_rx_pool1[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +#endif + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* (from interrupt) RX related functions */ + +static bool mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, + struct canfd_frame *cf, + uint32_t ffw); +static void mpfs_receive_work(void *arg); + +/* (from interrupt) TX related functions */ + +static void mpfs_can_update_txb_prio(struct mpfs_driver_s *priv); +static void mpfs_can_send_txb_cmd(struct mpfs_driver_s *priv, + enum mpfs_can_txb_command cmd, + uint8_t buf); +static bool mpfs_txdone(struct mpfs_driver_s *priv); +static void mpfs_txdone_work(void *arg); + +/* (from interrupt) Error handling related functions */ + +static enum mpfs_can_state_e + mpfs_can_get_err_state(struct mpfs_driver_s *priv); +static void mpfs_can_get_err_count(struct mpfs_driver_s *priv, + struct mpfs_can_berr_counter_s *bec); +static void mpfs_err_interrupt(struct mpfs_driver_s *priv, uint32_t isr); + +/* Interrupt service routine */ + +static int mpfs_interrupt(int irq, void *context, void *arg); + +/* (Nuttx network driver interface callback when TX packet available) Tx + * related functions + */ + +static enum mpfs_can_txb_status + mpfs_can_get_txb_status(struct mpfs_driver_s *priv, + uint8_t buf); +static bool mpfs_can_is_txb_writable(struct mpfs_driver_s *priv, + uint8_t buf); +static bool mpfs_can_write_txb(struct mpfs_driver_s *priv, + const struct canfd_frame *cf, + uint8_t buf, + bool is_ccf); +static int mpfs_transmit(struct mpfs_driver_s *priv); +static int mpfs_txpoll(struct net_driver_s *dev); +static void mpfs_txavail_work(void *arg); +static int mpfs_txavail(struct net_driver_s *dev); + +/* Bit timing related functions */ + +static int + mpfs_can_btr_compute(struct mpfs_driver_s *priv, + struct mpfs_can_bittiming_s *bt, + const struct mpfs_can_bittiming_const_s *btc); + +static int mpfs_can_config_bit_timing(struct mpfs_driver_s *priv, + struct mpfs_can_bittiming_s *bt, + bool arbi); +static int mpfs_can_config_arbi_bit_timing(struct mpfs_driver_s *priv); +static int mpfs_can_config_data_bit_timing(struct mpfs_driver_s *priv); + +/* Miscellaneous CAN controller interface functions */ + +static int mpfs_can_config_ssp(struct mpfs_driver_s *priv); +static void + mpfs_can_config_controller_mode(struct mpfs_driver_s *priv, + const struct mpfs_can_ctrlmode_s *mode); + +/* HW filter related functions */ + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, + uint8_t filter_type, + uint8_t can_id_type, + uint8_t can_type, + uint32_t fid1, + uint32_t fid2); +static void mpfs_can_reset_hw_filter(struct mpfs_driver_s *priv); +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + +/* CAN controller life cycle routines */ + +static int mpfs_can_controller_start(struct mpfs_driver_s *priv); +static void mpfs_can_controller_stop(struct mpfs_driver_s *priv); +static int mpfs_reset(struct mpfs_driver_s *priv); + +/* Driver interface to Nuttx network callbacks */ + +static int mpfs_ifup(struct net_driver_s *dev); +static int mpfs_ifdown(struct net_driver_s *dev); +#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL +static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); +#endif + +/**************************************************************************** + * Private Function + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_can_read_frame_data + * + * Description: + * Retrieve 4 bytes of CAN/CANFD frame data from RX Buffer + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * data - Pointer to data to be written + * + * Returned Value: + * true if data was read successfulle + * false if buffer is empty or next data would be the frame format word + * + ****************************************************************************/ + +static bool mpfs_can_read_frame_data(struct mpfs_driver_s *priv, + uint32_t *data) +{ + uint32_t rx_status = getreg32(priv->base + MPFS_CANFD_RX_STATUS_OFFSET); + if ((rx_status & MPFS_CANFD_RX_STATUS_RXMOF) == 0 || + (rx_status & MPFS_CANFD_RX_STATUS_RXE) != 0) + { + /* Reached the beginning of the next frame or buffer is empty */ + + return false; + } + + *data = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + return true; +} + +/**************************************************************************** + * Name: mpfs_can_retrieve_rx_frame + * + * Description: + * Retrieve CAN/CANFD frame from RX Buffer + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * cf - Pointer to CANFD frame structure + * ffw - Previously read frame format word + * + * Returned Value: + * true if frame was read successfully, false otherwise + * + * Assumptions: + * Frame format word is already parsed in advance and provided as 'ffw' arg + * + ****************************************************************************/ + +static bool mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, + struct canfd_frame *cf, + uint32_t ffw) +{ + uint32_t idw; + uint32_t tmp; + unsigned int i; + unsigned int data_wc; /* data word count */ + unsigned int data_bc; /* data byte count */ + unsigned int dlc; + unsigned int len; + + /* CAN ID */ + + if (!mpfs_can_read_frame_data(priv, &idw)) + { + return false; + } + + if (MPFS_CANFD_FRAME_FORMAT_W_IDE & ffw) + { + cf->can_id = (idw & CAN_EFF_MASK) | CAN_EFF_FLAG; + } + else + { + cf->can_id = + (idw >> MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT) & + CAN_SFF_MASK; + } + + /* BRS, ESI, RTR Flags */ + + cf->flags = 0; + if (MPFS_CANFD_FRAME_FORMAT_W_FDF & ffw) + { + /* Enable bitrate switch by default if frame is CANFD */ + + cf->flags |= CANFD_BRS; + + if (MPFS_CANFD_FRAME_FORMAT_W_ESI_RSV & ffw) + { + cf->flags |= CANFD_ESI; + } + } + else if (MPFS_CANFD_FRAME_FORMAT_W_RTR & ffw) + { + cf->can_id |= CAN_RTR_FLAG; + } + + /* RWCNT : RX Count of Words without FRAME_FORMAT WORD. Minus the 3 words + * for 1 IDW, 2 timestamp words + */ + + data_wc = ((MPFS_CANFD_FRAME_FORMAT_W_RWCNT & ffw) >> + MPFS_CANFD_FRAME_FORMAT_W_RWCNT_SHIFT) - 3; + data_bc = data_wc * 4; + + /* DLC */ + + dlc = (MPFS_CANFD_FRAME_FORMAT_W_DLC & ffw) >> + MPFS_CANFD_FRAME_FORMAT_W_DLC_SHIFT; + if (dlc <= 8) + { + len = dlc; + } + else + { + if (MPFS_CANFD_FRAME_FORMAT_W_FDF & ffw) + { + len = data_wc << 2; + } + else + { + len = 8; + } + } + cf->len = len; + if (expect_false(len > data_bc)) + { + len = data_bc; + } + + /* Timestamp - Read and throw away */ + + if (!mpfs_can_read_frame_data(priv, &tmp) || + !mpfs_can_read_frame_data(priv, &tmp)) + { + return false; + } + + /* Data */ + + for (i = 0; i < len; i += 4) + { + uint32_t data; + if (!mpfs_can_read_frame_data(priv, &data)) + { + return false; + } + + *(uint32_t *)(cf->data + i) = data; + } + + return true; +} + +/**************************************************************************** + * Name: mpfs_receive_work + * + * Description: + * An interrupt was received indicating the availability of a new RX packet + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by interrupt handling logic. + * + ****************************************************************************/ + +static void mpfs_receive_work(void *arg) +{ + struct mpfs_driver_s *priv = (struct mpfs_driver_s *)arg; + + uint32_t status; + uint32_t frame_count; + uint32_t tmp; + bool is_classical_can_frame = false; + + frame_count = (getreg32(priv->base + MPFS_CANFD_RX_STATUS_OFFSET) & + MPFS_CANFD_RX_STATUS_RXFRC) >> MPFS_CANFD_RX_STATUS_RXFRC_SHIFT; + while (frame_count) + { + struct canfd_frame *cf = (struct canfd_frame *)priv->rxdesc; + uint32_t ffw; + + /* Error recovery: if for any reason the RX buffer pointer points to + * a middle of a frame, read until the start of the first frame is + * found. This may happen after bus errors or rx overflow. + */ + + while (mpfs_can_read_frame_data(priv, &tmp)); + + ffw = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + + if (!(MPFS_CANFD_FRAME_FORMAT_W_RWCNT & ffw)) + { + break; + } + + if (!(MPFS_CANFD_FRAME_FORMAT_W_FDF & ffw)) + { + if (MPFS_CANFD_FRAME_FORMAT_W_RTR & ffw) + { + caninfo("Remote Frame received\n"); + } + else + { + caninfo("Classical CAN Frame received\n"); + } + + is_classical_can_frame = true; + } + else + { + caninfo("CANFD Frame received\n"); + } + + /* Retrieve the classical or CANFD or remote frame */ + + if (!mpfs_can_retrieve_rx_frame(priv, cf, ffw)) + { + /* Didn't receive full frame, bail out */ + + goto out; + } + + /* Lock the network; we have to protect the dev.d_len, dev.d_buf + * and dev.d_iob from the devif_poll path + */ + + net_lock(); + + /* Copy the buffer pointer to priv->dev.. Set amount of data + * in priv->dev.d_len + */ + + priv->dev.d_len = is_classical_can_frame ? + sizeof(struct can_frame) : sizeof(struct canfd_frame); + priv->dev.d_buf = (uint8_t *)cf; + + /* Send to socket interface */ + + NETDEV_RXPACKETS(&priv->dev); + can_input(&priv->dev); + + net_unlock(); + + /* Point the packet buffer back to the next Tx buffer that will be + * used during the next write. If the write queue is full, then + * this will point at an active buffer, which must not be written + * to. This is OK because devif_poll won't be called unless the + * queue is not full. + */ + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + frame_count = (getreg32(priv->base + MPFS_CANFD_RX_STATUS_OFFSET) & + MPFS_CANFD_RX_STATUS_RXFRC) >> MPFS_CANFD_RX_STATUS_RXFRC_SHIFT; + } + +out: + + /* Check for RX FIFO Overflow */ + + status = getreg32(priv->base + MPFS_CANFD_STATUS_OFFSET); + if (MPFS_CANFD_STATUS_DOR & status) + { + /* Clear and re-enable Data Overrun interrupt */ + + putreg32(MPFS_CANFD_COMMAND_CDO, + priv->base + MPFS_CANFD_COMMAND_OFFSET); + putreg32(MPFS_CANFD_INT_STAT_DOI, + priv->base + MPFS_CANFD_INT_MASK_CLR_OFFSET); + } + + /* Clear and re-enable RBNEI */ + + putreg32(MPFS_CANFD_INT_STAT_RBNEI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + putreg32(MPFS_CANFD_INT_STAT_RBNEI, + priv->base + MPFS_CANFD_INT_MASK_CLR_OFFSET); +} + +/**************************************************************************** + * Name: mpfs_can_update_txb_prio + * + * Description: + * Rotates priorities of TXT buffers + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void mpfs_can_update_txb_prio(struct mpfs_driver_s *priv) +{ + uint32_t prio = priv->txb_prio; + + /* Rotate TX_PRIORITY register states one step left */ + + prio = (prio << 4) | ((prio >> ((priv->ntxbufs - 1) * 4)) & 0xf); + priv->txb_prio = prio; + putreg32(prio, priv->base + MPFS_CANFD_TX_PRIORITY_OFFSET); +} + +/**************************************************************************** + * Name: mpfs_can_send_txb_cmd + * + * Description: + * Execute a TXT buffer command + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * cmd - Cmd to give + * buf - The TXT buffer index (0-based) + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void mpfs_can_send_txb_cmd(struct mpfs_driver_s *priv, + enum mpfs_can_txb_command cmd, + uint8_t buf) +{ + uint32_t txb_cmd = cmd; + + txb_cmd |= 1 << (buf + 8); + putreg32(txb_cmd, priv->base + MPFS_CANFD_TX_COMMAND_OFFSET); +} + +/**************************************************************************** + * Name: mpfs_txdone + * + * Description: + * Tx done interrupt service rountine + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * true on success, false on any error + * + * Assumptions: + * None + * + ****************************************************************************/ + +static bool mpfs_txdone(struct mpfs_driver_s *priv) +{ + bool first_buffer = true; + bool buffer_processed; + enum mpfs_can_txb_status txb_status; + uint8_t txb_id; + + do + { + buffer_processed = false; + while ((int)(priv->txb_sent - priv->txb_processed) > 0) + { + txb_id = priv->txb_processed % priv->ntxbufs; + txb_status = mpfs_can_get_txb_status(priv, txb_id); + bool other_status = false; + + switch (txb_status) + { + case TXT_TOK: + break; + case TXT_ERR: + canwarn("TXB in Error state\n"); + break; + case TXT_ABT: + canwarn("TXB in Aborted state\n"); + break; + default: + other_status = true; + + if (first_buffer) + { + canerr("TXB#%u not in a finished state (0x%x)!\n", + txb_id, txb_status); + + priv->txb_processed++; + + /* Rotate TXT buffer priority */ + + mpfs_can_update_txb_prio(priv); + + /* Mark current unfinished state TXT buffer as empty */ + + mpfs_can_send_txb_cmd(priv, TXT_CMD_SET_EMPTY, txb_id); + + /* Something is fishy, bail out */ + + return false; + } + break; + } + + if (other_status) + { + break; + } + else + { + priv->txb_processed++; + first_buffer = false; + buffer_processed = true; + + /* Rotate TXT buffer priority */ + + mpfs_can_update_txb_prio(priv); + + /* Mark current finished state TXT buffer as empty */ + + mpfs_can_send_txb_cmd(priv, TXT_CMD_SET_EMPTY, txb_id); + } + } + } + while (buffer_processed); + + return true; +} + +/**************************************************************************** + * Name: mpfs_txdone_work + * + * Description: + * An interrupt was received indicating that the last TX packet(s) is done + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * We are not in an interrupt context so that we can lock the network. + * + ****************************************************************************/ + +static void mpfs_txdone_work(void *arg) +{ + struct mpfs_driver_s *priv = (struct mpfs_driver_s *)arg; + + /* There should be space for a new TX in any event. Poll the network for + * new XMIT data + */ + + net_lock(); + devif_poll(&priv->dev, mpfs_txpoll); + net_unlock(); +} + +/**************************************************************************** + * Name: mpfs_can_get_err_state + * + * Description: + * Reads CAN fault confinement state + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Fault confinement state of controller + * + ****************************************************************************/ + +static enum mpfs_can_state_e + mpfs_can_get_err_state(struct mpfs_driver_s *priv) +{ + u_int32_t ewl_erp_fs_reg, rec_tec_reg, ew_limit, rec_val, tec_val; + + ewl_erp_fs_reg = getreg32(priv->base + MPFS_CANFD_EWL_OFFSET); + rec_tec_reg = getreg32(priv->base + MPFS_CANFD_REC_OFFSET); + + ew_limit = ((ewl_erp_fs_reg & MPFS_CANFD_EWL_EW_LIMIT) >> + MPFS_CANFD_EWL_EW_LIMIT_SHIFT); + rec_val = ((rec_tec_reg & MPFS_CANFD_REC_REC_VAL) >> + MPFS_CANFD_REC_REC_VAL_SHIFT); + tec_val = ((rec_tec_reg & MPFS_CANFD_REC_TEC_VAL) >> + MPFS_CANFD_REC_TEC_VAL_SHIFT); + + if (ewl_erp_fs_reg & MPFS_CANFD_EWL_ERA) + { + if (rec_val < ew_limit && tec_val < ew_limit) + { + return CAN_STATE_ERROR_ACTIVE; + } + else + { + return CAN_STATE_ERROR_WARNING; + } + } + else if (ewl_erp_fs_reg & MPFS_CANFD_EWL_ERP) + { + return CAN_STATE_ERROR_PASSIVE; + } + else if (ewl_erp_fs_reg & MPFS_CANFD_EWL_BOF) + { + return CAN_STATE_BUS_OFF; + } + + canwarn("Invalid FPGA CANFD error state\n"); + return CAN_STATE_ERROR_PASSIVE; +} + +/**************************************************************************** + * Name: mpfs_can_get_err_count + * + * Description: + * Reads CAN RX/TX error counter + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * bec - Pointer to Error counter structure + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mpfs_can_get_err_count(struct mpfs_driver_s *priv, + struct mpfs_can_berr_counter_s *bec) +{ + uint32_t rec_tec_reg = getreg32(priv->base + MPFS_CANFD_REC_OFFSET); + + bec->rxerr = ((rec_tec_reg & MPFS_CANFD_REC_REC_VAL) >> + MPFS_CANFD_REC_REC_VAL_SHIFT); + bec->txerr = ((rec_tec_reg & MPFS_CANFD_REC_TEC_VAL) >> + MPFS_CANFD_REC_TEC_VAL_SHIFT); +} + +/**************************************************************************** + * Name: mpfs_err_interrupt + * + * Description: + * Error frame ISR + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * isr - Interrupt status register value + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void mpfs_err_interrupt(struct mpfs_driver_s *priv, uint32_t isr) +{ + enum mpfs_can_state_e state; + struct mpfs_can_berr_counter_s bec; + uint32_t err_capt_retr_ctr_alc_reg; + uint32_t err_type; + uint32_t err_pos; + uint32_t alc_id_field; + uint32_t alc_bit; + + mpfs_can_get_err_count(priv, &bec); + state = mpfs_can_get_err_state(priv); + err_capt_retr_ctr_alc_reg = + getreg32(priv->base + MPFS_CANFD_ERR_CAPT_OFFSET); + + err_type = ((err_capt_retr_ctr_alc_reg & MPFS_CANFD_ERR_CAPT_ERR_TYPE) >> + MPFS_CANFD_ERR_CAPT_ERR_TYPE_SHIFT); + err_pos = ((err_capt_retr_ctr_alc_reg & MPFS_CANFD_ERR_CAPT_ERR_POS) >> + MPFS_CANFD_ERR_CAPT_ERR_POS_SHIFT); + alc_id_field = + ((err_capt_retr_ctr_alc_reg & MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD) >> + MPFS_CANFD_ERR_CAPT_ALC_ID_FIELD_SHIFT); + alc_bit = ((err_capt_retr_ctr_alc_reg & MPFS_CANFD_ERR_CAPT_ALC_BIT) >> + MPFS_CANFD_ERR_CAPT_ALC_BIT_SHIFT); + + caninfo("ISR = 0x%08x, rxerr %d, txerr %d, error type %u, pos %u, ALC " + "id_field %u, bit %u\n", isr, bec.rxerr, bec.txerr, err_type, + err_pos, alc_id_field, alc_bit); + + /* Check for error warning limit and fault confinement state change */ + + if (MPFS_CANFD_INT_STAT_FCSI & isr || MPFS_CANFD_INT_STAT_EWLI & isr) + { + if (priv->can.state == state) + { + canwarn("No state change! Missed interrupt?\n"); + } + + priv->can.state = state; + + switch (state) + { + case CAN_STATE_BUS_OFF: + priv->can.can_stats.bus_off++; + canwarn("Change to BUS_OFF error state\n"); + break; + case CAN_STATE_ERROR_PASSIVE: + priv->can.can_stats.error_passive++; + canwarn("Change to ERROR_PASSIVE error state\n"); + + /* Mask BERR interrupts */ + + putreg32(MPFS_CANFD_INT_STAT_ALI | MPFS_CANFD_INT_STAT_BEI, + priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + break; + case CAN_STATE_ERROR_WARNING: + priv->can.can_stats.error_warning++; + canwarn("Change to ERROR_WARNING error state\n"); + break; + case CAN_STATE_ERROR_ACTIVE: + caninfo("Change to ERROR_ACTIVE error state\n"); + + /* Unmask BERR interrupts */ + + putreg32(MPFS_CANFD_INT_STAT_ALI | MPFS_CANFD_INT_STAT_BEI, + priv->base + MPFS_CANFD_INT_MASK_CLR_OFFSET); + return; + default: + canwarn("Unhandled error state %d\n", state); + break; + } + } + + if (MPFS_CANFD_INT_STAT_ALI & isr) + { + canerr("Arbitration lost\n"); + priv->can.can_stats.arbitration_lost++; + } + + if (MPFS_CANFD_INT_STAT_BEI & isr) + { + canerr("Bus error\n"); + priv->can.can_stats.bus_error++; + } + + if (MPFS_CANFD_INT_STAT_DOI & isr) + { + canerr("DOI interrupt\n"); + + /* Mask the interrupt until it is handled in worker */ + + putreg32(MPFS_CANFD_INT_STAT_DOI, + priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + + /* Notify to socket interface */ + + NETDEV_RXERRORS(&priv->dev); + } + + /* Notify to socket interface. */ + + NETDEV_ERRORS(&priv->dev); +} + +/**************************************************************************** + * Name: mpfs_interrupt + * + * Description: + * Three interrupt sources will vector to this function: + * 1. CAN frame transmit interrupt + * 2. CAN frame receive interrupt + * 3. Error interrupt + * + * Input Parameters: + * irq - Number of the IRQ that generated the interrupt + * context - Interrupt register state save info (architecture-specific) + * + * Returned Value: + * OK on success + * + ****************************************************************************/ + +static int mpfs_interrupt(int irq, void *context, void *arg) +{ + struct mpfs_driver_s *priv = (struct mpfs_driver_s *)arg; + + uint32_t isr; + uint32_t icr; + + /* Get the interrupt status */ + + isr = getreg32(priv->base + MPFS_CANFD_INT_STAT_OFFSET); + + /* Receive Buffer Not Empty Interrupt */ + + if (isr & MPFS_CANFD_INT_STAT_RBNEI) + { + /* Mask RBNEI until receive is handled be the worker */ + + icr = MPFS_CANFD_INT_STAT_RBNEI; + putreg32(icr, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + + work_queue(CANWORK, &priv->rxwork, mpfs_receive_work, priv, 0); + } + + /* TXT Buffer HW Command Interrupt */ + + if (isr & MPFS_CANFD_INT_STAT_TXBHCI) + { + /* Handle TX interrupt */ + + if (!mpfs_txdone(priv)) + { + canerr("TXBHCI error\n"); + +#ifdef CONFIG_DEBUG_CAN_INFO + caninfo("txb_sent=0x%08x txb_processed=0x%08x\n", priv->txb_sent, + priv->txb_processed); + for (int i = 0; i < priv->ntxbufs; i++) + { + uint32_t status = mpfs_can_get_txb_status(priv, i); + caninfo("txb[%d] txb status=0x%08x\n", i, status); + } +#endif + /* Notify to socket interface */ + + NETDEV_TXERRORS(&priv->dev); + } + + /* Schedule work to poll for next available tx frame from the + * network. + */ + + work_queue(CANWORK, &priv->txdwork, mpfs_txdone_work, priv, 0); + } + + /* Error Interrupts */ + + if ((isr & (MPFS_CANFD_INT_STAT_EWLI | MPFS_CANFD_INT_STAT_FCSI | + MPFS_CANFD_INT_STAT_ALI | MPFS_CANFD_INT_STAT_BEI | + MPFS_CANFD_INT_STAT_DOI)) != 0) + { + canerr("Some error interrupts: 0x%08x\n", isr); + mpfs_err_interrupt(priv, isr); + } + + /* All interrupts are now handled, clear them */ + + putreg32(isr, priv->base + MPFS_CANFD_INT_STAT_OFFSET); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_get_tx_state + * + * Description: + * Get status of txt buffer + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * buf - txt buffer index to get status of (0-based) + * + * Returned Value: + * Status of txt buffer + * + * Assumptions: + * None + * + ****************************************************************************/ + +static enum mpfs_can_txb_status + mpfs_can_get_txb_status(struct mpfs_driver_s *priv, uint8_t buf) +{ + uint32_t tx_status = getreg32(priv->base + MPFS_CANFD_TX_STATUS_OFFSET); + enum mpfs_can_txb_status status = (tx_status >> (buf * 4)) & 0xf; + + return status; +} + +/**************************************************************************** + * Name: mpfs_can_is_txb_writable + * + * Description: + * Precheck txb state if a new frame can be written + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * buf - txt buffer index to get status of (0-based) + * + * Returned Value: + * True - Frame can be inserted to txt buffer + * False - If attempted, frame will not be inserted to txt buffer + * + * Assumptions: + * None + * + ****************************************************************************/ + +static bool mpfs_can_is_txb_writable(struct mpfs_driver_s *priv, + uint8_t buf) +{ + enum mpfs_can_txb_status buf_status; + + buf_status = mpfs_can_get_txb_status(priv, buf); + if (buf_status == TXT_RDY || buf_status == TXT_TRAN || + buf_status == TXT_ABTP) + { + canwarn("TXT buffer status %d\n", buf_status); + return false; + } + + return true; +} + +/**************************************************************************** + * Name: mpfs_can_write_txb + * + * Description: + * Load CAN frame onto txt buffer on the CAN controller + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * cf - Pointer to the CANFD frame to be inserted + * buf - txt buffer index to which the cf frame is inserted (0-based) + * is_ccf- is classical can frame (bool) + * + * Returned Value: + * True - TXT buffer written successfully + * False - Frame was not written to TXT buffer due to: + * 1. TXT buffer is not writable + * 2. Invalid TXT buffer index + * 3. Invalid frame length + * + * Assumptions: + * None + * + ****************************************************************************/ + +static bool mpfs_can_write_txb(struct mpfs_driver_s *priv, + const struct canfd_frame *cf, + uint8_t buf, + bool is_ccf) +{ + uint32_t buf_base; + uint32_t ffw = 0; + uint32_t idw = 0; + unsigned int i; + + /* Check for invalid txt buffer index */ + + if (buf >= priv->ntxbufs) + { + canerr("Invalid txt buffer index...\n"); + return false; + } + + /* Check if it is possible to insert frame to txt buffer */ + + if (!mpfs_can_is_txb_writable(priv, buf)) + { + canwarn("Not possible to insert frame to txt buffer...\n"); + return false; + } + + /* Check for invalid classical CAN / CANFD frame length */ + + if (cf->len > CANFD_MAX_DLEN || (cf->len > CAN_MAX_DLEN && is_ccf)) + { + canerr("Invalid classical / CANFD CAN frame length...\n"); + return false; + } + + /* Populate frame format word */ + + if (cf->can_id & CAN_RTR_FLAG) /* remote transmission request */ + { + ffw |= MPFS_CANFD_FRAME_FORMAT_W_RTR; + } + + if (cf->can_id & CAN_EFF_FLAG) /* extended frame format (29 bit long id) */ + { + ffw |= MPFS_CANFD_FRAME_FORMAT_W_IDE; + } + + if (!is_ccf) + { + ffw |= MPFS_CANFD_FRAME_FORMAT_W_FDF; /* FD Frame */ + if (cf->flags & CANFD_BRS) + { + ffw |= MPFS_CANFD_FRAME_FORMAT_W_BRS; /* Bit rate switch */ + } + } + + ffw |= MPFS_CANFD_FRAME_FORMAT_W_DLC & (len_to_can_dlc[cf->len] << + MPFS_CANFD_FRAME_FORMAT_W_DLC_SHIFT); + + /* Populate CAN frame id word */ + + if (cf->can_id & CAN_EFF_FLAG) + { + idw = cf->can_id & CAN_EFF_MASK; + } + else + { + idw = MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE & + ((cf->can_id & CAN_SFF_MASK) << + MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT); + } + + /* Write frame id and frame format word */ + + buf_base = (buf + 1) * 0x100; + putreg32(ffw, priv->base + buf_base + MPFS_CANFD_FRAME_FORMAT_W_OFFSET); + putreg32(idw, priv->base + buf_base + MPFS_CANFD_IDENTIFIER_W_OFFSET); + + /* Write CAN data payload */ + + if (!(cf->can_id & CAN_RTR_FLAG)) + { + for (i = 0; i < cf->len; i += 4) + { + uint32_t data = *(uint32_t *)(cf->data + i); + putreg32(data, + priv->base + buf_base + MPFS_CANFD_DATA_1_4_W_OFFSET + i); + } + } + + return true; +} + +/**************************************************************************** + * Name: mpfs_transmit + * + * Description: + * Start hardware transmission. Called either from the txdone interrupt + * handling or from watchdog based polling. + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int mpfs_transmit(struct mpfs_driver_s *priv) +{ + uint32_t txb_id; + bool ok; + bool is_classical_can_frame; + + /* Retrieve the classical CAN / CANFD frame from network device buffer */ + + is_classical_can_frame = + priv->dev.d_len <= sizeof(struct can_frame) ? true : false; + struct canfd_frame *cf = (struct canfd_frame *)priv->dev.d_buf; + + /* Get the current txt buffer ID */ + + txb_id = priv->txb_sent % priv->ntxbufs; + + /* Insert classical CAN/CANFD frame into controller txt bf at txb_id */ + + ok = mpfs_can_write_txb(priv, cf, txb_id, is_classical_can_frame); + if (!ok) + { + canwarn("TXNF set but cannot insert frame into TXT buffer!\n"); + NETDEV_TXERRORS(&priv->dev); + return OK; + } + + /* Now, write to txt buffer seems ok, use txt command to set buffer state + * to READY for xmit. + */ + + mpfs_can_send_txb_cmd(priv, TXT_CMD_SET_READY, txb_id); + priv->txb_sent++; + + /* Increment statistics */ + + NETDEV_TXPACKETS(&priv->dev); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_txpoll + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + * Assumptions: + * May or may not be called from an interrupt handler. In either case, + * global interrupts are disabled, either explicitly or indirectly through + * interrupt handling logic. + * + ****************************************************************************/ + +static int mpfs_txpoll(struct net_driver_s *dev) +{ + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; + + /* If the polling resulted in data that should be sent out on the network, + * the field d_len is set to a value > 0. + */ + + if (priv->dev.d_len > 0) + { + /* Send the packet */ + + mpfs_transmit(priv); + + /* Check if there is room in the device to hold another packet. If + * not, return a non-zero value to terminate the poll. + */ + + if (!MPFS_CAN_FD_TXNF(priv)) + { + return -EBUSY; + } + } + + /* If zero is returned, the polling will continue until all connections + * have been examined. + */ + + return OK; +} + +/**************************************************************************** + * Name: mpfs_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void mpfs_txavail_work(void *arg) +{ + struct mpfs_driver_s *priv = (struct mpfs_driver_s *)arg; + + /* Ignore the notification if the interface is not yet up */ + + if (priv->bifup) + { + /* Check if there is room in the controller to hold another outgoing + * packet. + */ + + if (MPFS_CAN_FD_TXNF(priv)) + { + /* Yes, there is, poll the network for new TXT transmit */ + + net_lock(); + devif_poll(&priv->dev, mpfs_txpoll); + net_unlock(); + } + } +} + +/**************************************************************************** + * Name: mpfs_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * 0 - OK + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int mpfs_txavail(struct net_driver_s *dev) +{ + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; + + if (work_available(&priv->pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + mpfs_txavail_work(priv); + } + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_btr_compute + * + * Description: + * Calculate bit timing values to be written to bit timing register + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * bt - Pointer to the bit timing structure to be set + * btc - Pointer to the constant bit timing structure to be used to set + * the bit timing params + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + * Assumptions: + * Bit timing constants needed to be set in advance on which calculation + * in this function is based + * + ****************************************************************************/ + +static int + mpfs_can_btr_compute(struct mpfs_driver_s *priv, + struct mpfs_can_bittiming_s *bt, + const struct mpfs_can_bittiming_const_s *btc) +{ + /* All measured in number of time quanta (Tq = brp / fsys) + * brp : baud rate prescaler as number of system clock periods + * prop_seg : propagation segment (1..8 Tq) + * phase_seg1 : phase segment 1 (1..8 Tq) + * phase_seg2 : phase segment 2 (1..8 Tq) + * + * tseg1 = prop_seg + phase_seg1 + * tseg2 = phase_seg2 + * tseg = tseg1 + tseg2 + * tsegall = BT_COMPUTE_SYNC_SEG + tseg / 2 + * + * sample point = (BT_COMPUTE_SYNC_SEG + tseg1) / + * (BT_COMPUTE_SYNC_SEG + tseg1 + tseg2) * 1000 + * + * CAN bitrate = 1 / (number_of_Tq * Tq) + */ + + unsigned int calc_br; /* current calculated bitrate */ + unsigned int br_err = 0; /* diff between user set bitrate + * and calculated bitrate */ + unsigned int best_br_err = UINT_MAX; /* best bitrate error */ + + unsigned int nominal_sp; /* nominal sample point either set + * by user or inferred from bitrate + * (CiA recommendation) */ + unsigned int calc_sp; /* calculated sample point */ + unsigned int sp_err; /* diff between and nominal sample + * point and currently calculated + * sample point */ + unsigned int best_sp_err = UINT_MAX; /* best sample point error */ + + unsigned int calc_brp; /* currently calculated bitrate + * prescaler */ + unsigned int best_brp = 0; /* currently calculated bitrate + * prescaler */ + unsigned int tseg_double; + unsigned int tseg_sync; + unsigned int tseg1 = 0; + unsigned int tseg2 = 0; + + /* Get sample point nominal */ + + if (bt->sample_point) + { + nominal_sp = bt->sample_point; + } + else + { + if (bt->bitrate <= 500000) + { + nominal_sp = 875; + } + else if (bt->bitrate <= 800000) + { + nominal_sp = 800; + } + else + { + nominal_sp = 750; + } + } + calc_sp = nominal_sp; + + /* Iterate tseg in possible range to find best bit timing values */ + + for (tseg_double = btc->tseg_max * 2 + 1; + tseg_double >= btc->tseg_min * 2; tseg_double--) + { + tseg_sync = tseg_double / 2 + BT_COMPUTE_SYNC_SEG; + + /* Recalculate bitrate prescaler */ + + calc_brp = priv->can.clock.freq / (tseg_sync * bt->bitrate) + + tseg_double % 2; + + if (calc_brp < btc->brp_min || calc_brp > btc->brp_max) + { + continue; + } + + /* Recalculate bitrate and bitrate error */ + + calc_br = priv->can.clock.freq / (calc_brp * tseg_sync); + + br_err = bt->bitrate - calc_br; + if (br_err > best_br_err) + { + continue; + } + else + { + best_sp_err = UINT_MAX; + } + + /* Now, it seems that we have a better bitrate, recalculate sample + * point, tseg1, tseg2 and sample point error + */ + + tseg2 = clamp(tseg_sync - nominal_sp * tseg_sync / 1000, 1, + btc->tseg_max * 249 / 1000); + tseg1 = tseg_double / 2 - tseg2; + calc_sp = 1000 * (tseg_sync - tseg2) / tseg_sync; + + sp_err = nominal_sp - calc_sp; + if (calc_sp > nominal_sp || sp_err > best_sp_err) + { + continue; + } + + /* Update best values and end condition check */ + + best_brp = calc_brp; + best_br_err = br_err; + best_sp_err = sp_err; + + if (best_br_err == 0 && best_sp_err == 0) + { + break; + } + } + + /* Check bitrate error against limit */ + + if ((uint32_t)best_br_err * 1000 > BT_COMPUTE_MAX_ERROR * bt->bitrate) + { + canerr("Bitrate error %d.%d%% is too high\n", br_err / 10, + br_err % 10); + return -EDOM; + } + + /* Retrieve the best calculated sample point */ + + bt->sample_point = calc_sp; + + /* Retrieve bit timing register components */ + + bt->brp = best_brp; + bt->prop_seg = tseg1 / 2; + bt->phase_seg1 = tseg1 - bt->prop_seg; + bt->phase_seg2 = tseg2; + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_config_bit_timing + * + * Description: + * Set CAN controller arbitration or data bitrate bit timing + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * bt - Pointer to Bit timing structure + * arbi - True - Arbitration bit timing, False - Data bit timing + * + * Returned Value: + * Zero (OK) on success, -EPERM if CAN controller is not disabled + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_config_bit_timing(struct mpfs_driver_s *priv, + struct mpfs_can_bittiming_s *bt, + bool arbi) +{ + int max_ph1_len = 31; + uint32_t btr = 0; + + if (MPFS_CAN_FD_ENABLED(priv)) + { + canerr("CAN controller should be disabled to set bit timing\n"); + return -EPERM; + } + + if (arbi) + { + max_ph1_len = 63; + } + + if (bt->phase_seg1 > max_ph1_len) + { + bt->prop_seg += bt->phase_seg1 - max_ph1_len; + bt->phase_seg1 = max_ph1_len; + } + + if (arbi) + { + btr = bt->prop_seg << MPFS_CANFD_BTR_PROP_SHIFT; + btr |= bt->phase_seg1 << MPFS_CANFD_BTR_PH1_SHIFT; + btr |= bt->phase_seg2 << MPFS_CANFD_BTR_PH2_SHIFT; + btr |= bt->brp << MPFS_CANFD_BTR_BRP_SHIFT; + btr |= bt->sjw << MPFS_CANFD_BTR_SJW_SHIFT; + caninfo("Arbitration bitrate: %u, Prop_seg: %u, phase_seg1: %u, " + "phase_seg2: %u, brp: %u, sjw: %u \n", bt->bitrate, + bt->prop_seg, bt->phase_seg1, bt->phase_seg2, bt->brp, + bt->sjw); + putreg32(btr, priv->base + MPFS_CANFD_BTR_OFFSET); + } + else + { + btr = bt->prop_seg << MPFS_CANFD_BTR_FD_PROP_FD_SHIFT; + btr |= bt->phase_seg1 << MPFS_CANFD_BTR_FD_PH1_FD_SHIFT; + btr |= bt->phase_seg2 << MPFS_CANFD_BTR_FD_PH2_FD_SHIFT; + btr |= bt->brp << MPFS_CANFD_BTR_FD_BRP_FD_SHIFT; + btr |= bt->sjw << MPFS_CANFD_BTR_FD_SJW_FD_SHIFT; + caninfo("Data bitrate: %u, Prop_seg: %u, phase_seg1: %u, " + "phase_seg2: %u, brp: %u, sjw: %u \n", bt->bitrate, + bt->prop_seg, bt->phase_seg1, bt->phase_seg2, bt->brp, + bt->sjw); + putreg32(btr, priv->base + MPFS_CANFD_BTR_FD_OFFSET); + } + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_config_arbi_bit_timing + * + * Description: + * Set CAN controller arbitration bit timing + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success, -%EPERM if controller is enabled + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_config_arbi_bit_timing(struct mpfs_driver_s *priv) +{ + struct mpfs_can_bittiming_s *arbi_bt = &priv->can.bittiming; + + /* Set bit timing for arbitration bit rate */ + + return mpfs_can_config_bit_timing(priv, arbi_bt, true); +} + +/**************************************************************************** + * Name: mpfs_can_config_data_bit_timing + * + * Description: + * Set CAN controller data bit timing + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success, -%EPERM if controller is enabled + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_config_data_bit_timing(struct mpfs_driver_s *priv) +{ + struct mpfs_can_bittiming_s *data_bt = &priv->can.data_bittiming; + + /* Set bit timing for data bit rate */ + + return mpfs_can_config_bit_timing(priv, data_bt, false); +} + +/**************************************************************************** + * Name: mpfs_can_config_ssp + * + * Description: + * Set CAN controller secondary sample point. + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success, -EPERM if CAN controller is not disabled + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_config_ssp(struct mpfs_driver_s *priv) +{ + struct mpfs_can_bittiming_s *dbt = &(priv->can.data_bittiming); + int ssp_offset = 0; + uint32_t ssp_cfg = 0; + + if (MPFS_CAN_FD_ENABLED(priv)) + { + canerr("CAN controller should be disabled to set secondary sample " + "point\n"); + return -EPERM; + } + + /* secondary sample point is only used for bitrates > 1 Mbits/s */ + + if (dbt->bitrate > 1000000) + { + ssp_offset = (priv->can.clock.freq / 1000) * + dbt->sample_point / dbt->bitrate; + + if (ssp_offset > 127) + { + canwarn("Secondary sample point offset exceeds 127\n"); + ssp_offset = 127; + } + + ssp_cfg = ssp_offset << MPFS_CANFD_TRV_DELAY_SSP_OFFSET_SHIFT; + ssp_cfg |= 0x1 << MPFS_CANFD_TRV_DELAY_SSP_SRC_SHIFT; + } + + putreg32(ssp_cfg, priv->base + MPFS_CANFD_TRV_DELAY_OFFSET); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_config_controller_mode + * + * Description: + * Configure CAN controller mode + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * mode - Pointer to controller modes to be set + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void + mpfs_can_config_controller_mode(struct mpfs_driver_s *priv, + const struct mpfs_can_ctrlmode_s *mode) +{ + uint32_t mode_reg = getreg32(priv->base + MPFS_CANFD_MODE_OFFSET); + + mode_reg = (mode->flags & CAN_CTRLMODE_LOOPBACK) ? + (mode_reg | MPFS_CANFD_MODE_ILBP) : + (mode_reg & ~MPFS_CANFD_MODE_ILBP); + + mode_reg = (mode->flags & CAN_CTRLMODE_LISTENONLY) ? + (mode_reg | MPFS_CANFD_MODE_BMM) : + (mode_reg & ~MPFS_CANFD_MODE_BMM); + + mode_reg = (mode->flags & CAN_CTRLMODE_FD) ? + (mode_reg | MPFS_CANFD_MODE_FDE) : + (mode_reg & ~MPFS_CANFD_MODE_FDE); + + mode_reg = (mode->flags & CAN_CTRLMODE_PRESUME_ACK) ? + (mode_reg | MPFS_CANFD_MODE_ACF) : + (mode_reg & ~MPFS_CANFD_MODE_ACF); + + mode_reg = (mode->flags & CAN_CTRLMODE_FD_NON_ISO) ? + (mode_reg | MPFS_CANFD_MODE_NISOFD) : + (mode_reg & ~MPFS_CANFD_MODE_NISOFD); + + mode_reg &= ~MPFS_CANFD_MODE_RTRTH; + mode_reg = (mode->flags & CAN_CTRLMODE_ONE_SHOT) ? + (mode_reg | MPFS_CANFD_MODE_RTRLE) : + (mode_reg & ~MPFS_CANFD_MODE_RTRLE); + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + mode_reg |= MPFS_CANFD_MODE_AFM; +#endif + + /* Disable test mode */ + + mode_reg &= ~MPFS_CANFD_MODE_TSTM; + + putreg32(mode_reg, priv->base + MPFS_CANFD_MODE_OFFSET); +} + +/**************************************************************************** + * Name: mpfs_can_add_hw_filter + * + * Description: + * Add new hw filter to CAN Controller + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * filter_type - Filter A, B, C or Range + * can_id_type - std CAN ID / ext CAN ID + * can_type - classical CAN / CANFD + * filter_id1 - filter id 1 (can be filter value for bit filter or range + * low for range filter) + * filter_id2 - filter id 2 (can be filter mask for bit filter or range + * high for range filter) + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, + uint8_t filter_type, + uint8_t can_id_type, + uint8_t can_type, + uint32_t fid1, + uint32_t fid2) +{ + uint32_t fc_reg; + + fc_reg = getreg32(priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Clean up filter control reg */ + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FAFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FAFB; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FANE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FANB; + + /* Transform fid1, fid2 */ + + uint32_t fid1_trans = (can_id_type == CAN_EXT_ID) ? + (MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT & + (fid1 << MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT_SHIFT)) : + (MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE & + (fid1 << MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT)); + + uint32_t fid2_trans = (can_id_type == CAN_EXT_ID) ? + (MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT & + (fid2 << MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_EXT_SHIFT)) : + (MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE & + (fid2 << MPFS_CANFD_IDENTIFIER_W_IDENTIFIER_BASE_SHIFT)); + + switch (filter_type) + { + case HW_FILTER_A: + + /* Set filter control reg for filter A */ + + if (can_type == CAN_MSGPRIO_LOW) + { + /* Classical CAN frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FANE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FANB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FAFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FAFB; + } + else if (can_type == CAN_MSGPRIO_HIGH) + { + /* CANFD frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FAFE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FAFB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FANE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FANB; + } + putreg32(fc_reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Set bit filter value / mask */ + + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_A_VAL_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_A_MASK_OFFSET); + break; + + case HW_FILTER_B: + + /* Set filter control reg for filter B */ + + if (can_type == CAN_MSGPRIO_LOW) + { + /* Classical CAN frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FBNE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FBNB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FBFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FBFB; + } + else if (can_type == CAN_MSGPRIO_HIGH) + { + /* CANFD frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FBFE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FBFB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FBNE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FBNB; + } + putreg32(fc_reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Set bit filter value / mask */ + + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_B_VAL_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_B_MASK_OFFSET); + break; + + case HW_FILTER_C: + + /* Set filter control reg for filter C */ + + if (can_type == CAN_MSGPRIO_LOW) + { + /* Classical CAN frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FCNE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FCNB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FCFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FCFB; + } + else if (can_type == CAN_MSGPRIO_HIGH) + { + /* CANFD frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FCFE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FCFB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FCNE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FCNB; + } + putreg32(fc_reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Set bit filter value / mask */ + + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_C_VAL_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_C_MASK_OFFSET); + break; + + case HW_FILTER_RANGE: + + /* Set filter control reg for filter range */ + + if (can_type == CAN_MSGPRIO_LOW) + { + /* Classical CAN frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FRNE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FRNB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FRFE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FRFB; + } + else if (can_type == CAN_MSGPRIO_HIGH) + { + /* CANFD frame filter */ + + fc_reg = (can_id_type == CAN_EXT_ID) ? + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FRFE) : + (fc_reg | MPFS_CANFD_FILTER_CONTROL_FRFB); + + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FRNE; + fc_reg &= ~MPFS_CANFD_FILTER_CONTROL_FRNB; + } + putreg32(fc_reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Set range filter low / high */ + + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_RAN_LOW_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_RAN_HIGH_OFFSET); + break; + + default: + + /* Unsupported filter type */ + + break; + } +} +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + +/**************************************************************************** + * Name: mpfs_can_reset_hw_filter + * + * Description: + * Reset all hw filters (both bit and range filter) to default settings + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL +static void mpfs_can_reset_hw_filter(struct mpfs_driver_s *priv) +{ + uint32_t reg; + + /* Reset filter control */ + + reg = 0; + reg |= MPFS_CANFD_FILTER_CONTROL_FANB; + reg |= MPFS_CANFD_FILTER_CONTROL_FANE; + reg |= MPFS_CANFD_FILTER_CONTROL_FAFB; + reg |= MPFS_CANFD_FILTER_CONTROL_FAFE; + putreg32(reg, priv->base + MPFS_CANFD_FILTER_CONTROL_OFFSET); + + /* Reset bit filter A */ + + putreg32(0, priv->base + MPFS_CANFD_FILTER_A_VAL_OFFSET); + putreg32(0, priv->base + MPFS_CANFD_FILTER_A_MASK_OFFSET); + + /* Reset bit filter B */ + + putreg32(0, priv->base + MPFS_CANFD_FILTER_B_VAL_OFFSET); + putreg32(0, priv->base + MPFS_CANFD_FILTER_B_MASK_OFFSET); + + /* Reset bit filter C */ + + putreg32(0, priv->base + MPFS_CANFD_FILTER_C_VAL_OFFSET); + putreg32(0, priv->base + MPFS_CANFD_FILTER_C_MASK_OFFSET); + + /* Reset range filter */ + + putreg32(0, priv->base + MPFS_CANFD_FILTER_RAN_LOW_OFFSET); + putreg32(0, priv->base + MPFS_CANFD_FILTER_RAN_HIGH_OFFSET); + + priv->used_bit_filter_number = 0; + priv->used_range_filter = false; +} +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + +/**************************************************************************** + * Name: mpfs_can_controller_start + * + * Description: + * This routine starts the driver. Routine expects that controller is in + * reset state. It setups initial Tx buffers for FIFO priorities, sets + * bittiming, enables interrupts, switches core to operational mode and + * changes controller state to %CAN_STATE_STOPPED. + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * Zero (OK) on success and failure value on error + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_can_controller_start(struct mpfs_driver_s *priv) +{ + uint32_t int_ena; + uint32_t int_msk; + uint32_t mode_reg; + int err; + struct mpfs_can_ctrlmode_s mode; + + /* Initialize TXT buffer sent / processed counter values */ + + priv->txb_sent = 0; + priv->txb_processed = 0; + + /* Configure TXT buffers priority */ + + priv->txb_prio = 0x01234567; + putreg32(priv->base, priv->base + MPFS_CANFD_TX_PRIORITY_OFFSET); + + /* Configure bit-rates and ssp */ + + err = mpfs_can_config_arbi_bit_timing(priv); + if (err < 0) + { + return err; + } + + err = mpfs_can_config_data_bit_timing(priv); + if (err < 0) + { + return err; + } + + err = mpfs_can_config_ssp(priv); + if (err < 0) + { + return err; + } + + /* Configure modes */ + + mode.flags = priv->can.ctrlmode; + mode.mask = 0xffffffff; + mpfs_can_config_controller_mode(priv, &mode); + + /* Configure interrupts */ + + int_ena = MPFS_CANFD_INT_STAT_RBNEI | + MPFS_CANFD_INT_STAT_TXBHCI | + MPFS_CANFD_INT_STAT_EWLI | + MPFS_CANFD_INT_STAT_FCSI | + MPFS_CANFD_INT_STAT_DOI; + + int_msk = ~int_ena; /* Initially allow all but errors */ + + /* Bus error reporting -> Allow Error/Arb.lost interrupts */ + + if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) + { + int_ena |= MPFS_CANFD_INT_STAT_ALI | MPFS_CANFD_INT_STAT_BEI; + } + + uint32_t mask = 0xffffffff; + putreg32(mask, priv->base + MPFS_CANFD_INT_MASK_CLR_OFFSET); + putreg32(int_msk, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + putreg32(int_ena, priv->base + MPFS_CANFD_INT_ENA_SET_OFFSET); + + /* Put CAN driver to STOPPED state first, CAN controller will enters + * ERROR_ACTIVE on initial FCSI + */ + + priv->can.state = CAN_STATE_STOPPED; + + /* Enable the CAN controller */ + + mode_reg = getreg32(priv->base + MPFS_CANFD_MODE_OFFSET); + mode_reg |= MPFS_CANFD_MODE_ENA; + putreg32(mode_reg, priv->base + MPFS_CANFD_MODE_OFFSET); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_can_controller_stop + * + * Description: + * This routine stops the driver. This is the drivers stop routine. It will + * disable the interrupts and disable the CAN controller + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void mpfs_can_controller_stop(struct mpfs_driver_s *priv) +{ + uint32_t mask = 0xffffffff; + uint32_t mode; + + /* Disable interrupts */ + + putreg32(mask, priv->base + MPFS_CANFD_INT_ENA_CLR_OFFSET); + putreg32(mask, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + + /* Disable the CAN controller */ + + mode = getreg32(priv->base + MPFS_CANFD_MODE_OFFSET); + mode &= ~MPFS_CANFD_MODE_ENA; + putreg32(mode, priv->base + MPFS_CANFD_MODE_OFFSET); + + /* Set CAN driver state to STOPPED */ + + priv->can.state = CAN_STATE_STOPPED; +} + +/**************************************************************************** + * Name: mpfs_reset + * + * Description: + * Put the EMAC in the non-operational, reset state + * + * Input Parameters: + * priv - Pointer to the private CAN driver state structure + * + * Returned Value: + * OK for success and -ETIMEDOUT for failure + * + * Assumptions: + * + ****************************************************************************/ + +static int mpfs_reset(struct mpfs_driver_s *priv) +{ + uint32_t i = 100; + uint32_t device_id; + + /* Reset FPGA and FIC3, enable clock for FIC3 before RD WR */ + + modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, + SYSREG_SOFT_RESET_CR_FPGA | SYSREG_SOFT_RESET_CR_FIC3, + 0); + modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, SYSREG_SUBBLK_CLOCK_CR_FIC3); + + /* Reset CAN controller */ + + putreg32(MPFS_CANFD_MODE_RST, priv->base + MPFS_CANFD_MODE_OFFSET); + + /* Check if the device is up again */ + + do + { + device_id = (getreg32(priv->base + MPFS_CANFD_DEVICE_ID_OFFSET) & + MPFS_CANFD_DEVICE_ID_DEVICE_ID) >> + MPFS_CANFD_DEVICE_ID_DEVICE_ID_SHIFT; + + if (device_id == MPFS_CANFD_ID) + { + return OK; + } + + if (!i--) + { + canwarn("Device did not leave reset\n"); + return -ETIMEDOUT; + } + + nxsig_usleep(200); + } + while (1); + + priv->can.can_stats.restarts++; +} + +/**************************************************************************** + * Name: mpfs_ifup + * + * Description: + * NuttX Callback: Start the CAN interface + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure + * + * Assumptions: + * + ****************************************************************************/ + +static int mpfs_ifup(struct net_driver_s *dev) +{ + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; + + if (mpfs_can_controller_start(priv) < 0) + { + canerr("CAN controller start failed\n"); + return -1; + } + + priv->bifup = true; + + priv->dev.d_buf = (uint8_t *)priv->txdesc; + + /* Set interrupts */ + + up_enable_irq(priv->config->canfd_fpga_irq); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_ifdown + * + * Description: + * NuttX Callback: Stop the CAN interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure + * + * Assumptions: + * None + * + ****************************************************************************/ + +static int mpfs_ifdown(struct net_driver_s *dev) +{ + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; + + mpfs_can_controller_stop(priv); + + priv->bifup = false; + return OK; +} + +/**************************************************************************** + * Name: mpfs_ioctl + * + * Description: + * PHY ioctl command handler + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * cmd - ioctl command + * arg - Argument accompanying the command + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + * Assumptions: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_NETDEV_IOCTL +static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg) +{ +#if defined(CONFIG_NETDEV_CAN_BITRATE_IOCTL) || \ +defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) + struct mpfs_driver_s *priv = + (struct mpfs_driver_s *)dev->d_private; +#endif + int ret; + + switch (cmd) + { +#ifdef CONFIG_NETDEV_CAN_BITRATE_IOCTL + case SIOCGCANBITRATE: + + /* Get bitrate from the CAN controller */ + + { + struct can_ioctl_data_s *req = + (struct can_ioctl_data_s *)((uintptr_t)arg); + req->arbi_bitrate = priv->can.bittiming.bitrate / 1000; /* kbit/s */ + req->arbi_samplep = priv->can.bittiming.sample_point / 10; + req->data_bitrate = priv->can.data_bittiming.bitrate / 1000; /* kbit/s */ + req->data_samplep = priv->can.data_bittiming.sample_point / 10; + ret = OK; + } + break; + + case SIOCSCANBITRATE: + + /* Set bitrate of the CAN controller */ + + { + struct can_ioctl_data_s *req = + (struct can_ioctl_data_s *)((uintptr_t)arg); + + if (req->arbi_bitrate > 1000) + { + canerr("Arbitration bitrate > 1Mbps is not supported."); + ret = -EINVAL; + break; + } + priv->can.bittiming.bitrate = req->arbi_bitrate * 1000; /* bit/s */ + + if (req->arbi_samplep > 100 || req->arbi_samplep < 0) + { + canerr("Invalid arbitration sample point. " + "Range should be [0,100]%%."); + ret = -EINVAL; + break; + } + priv->can.bittiming.sample_point = + req->arbi_samplep * 10; /* In one-tenth of a percent */ + + if (req->data_bitrate > 4000 || + req->data_bitrate < req->arbi_bitrate) + { + canerr("Data bitrate higher than 4Mbps is yet to be supported. " + "Data br cannot be smaller than arbitration br."); + ret = -EINVAL; + break; + } + priv->can.data_bittiming.bitrate = req->data_bitrate * 1000; /* bit/s */ + + if (req->data_samplep > 100 || req->data_samplep < 0) + { + canerr("Invalid data sample point. Range should be [0,100]%%."); + ret = -EINVAL; + break; + } + priv->can.data_bittiming.sample_point = + req->data_samplep * 10; /* In one-tenth of a percent */ + + /* Calculate arbitration and data bit timing */ + + mpfs_can_btr_compute(priv, + &priv->can.bittiming, + priv->can.bittiming_const); + mpfs_can_btr_compute(priv, + &priv->can.data_bittiming, + priv->can.data_bittiming_const); + + /* CAN controller reset to write bit timing register */ + + mpfs_can_controller_stop(priv); + if (mpfs_can_controller_start(priv) < 0) + { + canerr("CAN controller start failed."); + ret = -1; + break; + } + + ret = OK; + } + break; +#endif /* CONFIG_NETDEV_CAN_BITRATE_IOCTL */ + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + case SIOCACANSTDFILTER: + + { + uint8_t filter; + struct can_ioctl_filter_s *req = + (struct can_ioctl_filter_s *)((uintptr_t)arg); + + if (req->ftype == CAN_FILTER_MASK) + { + if (priv->used_bit_filter_number == 0) + { + /* Use bit filter A */ + + filter = HW_FILTER_A; + } + else if (priv->used_bit_filter_number == 1) + { + /* Use bit filter B */ + + filter = HW_FILTER_B; + } + else if (priv->used_bit_filter_number == 2) + { + /* Use bit filter C */ + + filter = HW_FILTER_C; + } + else + { + /* All bit filters used. Return with error */ + + canerr("All bit filters used. Cannot add more. Delete all and " + "add again."); + ret = -1; + break; + } + priv->used_bit_filter_number++; + } + else if (req->ftype == CAN_FILTER_RANGE) + { + /* Use range filter */ + + filter = HW_FILTER_RANGE; + priv->used_range_filter = true; + } + else + { + /* Dual address and other filter types not yet support */ + + canerr("Dual address and other filter types not yet support"); + ret = -1; + break; + } + + /* Add hw filter */ + + mpfs_can_add_hw_filter(priv, + filter, + CAN_STD_ID, + req->fprio, /* LOW for CAN, HIGH for FDCAN */ + req->fid1, + req->fid2); + + ret = OK; + } + break; + + case SIOCACANEXTFILTER: + + /* Add CAN EXTENDED ID HW FILTER */ + + { + uint8_t filter; + struct can_ioctl_filter_s *req = + (struct can_ioctl_filter_s *)((uintptr_t)arg); + + if (req->ftype == CAN_FILTER_MASK) + { + if (priv->used_bit_filter_number == 0) + { + /* Use bit filter A */ + + filter = HW_FILTER_A; + } + else if (priv->used_bit_filter_number == 1) + { + /* Use bit filter B */ + + filter = HW_FILTER_B; + } + else if (priv->used_bit_filter_number == 2) + { + /* Use bit filter C */ + + filter = HW_FILTER_C; + } + else + { + /* All bit filters used. Return with error */ + + canerr("All bit filters used. Cannot add more. Delete all and " + "add again."); + ret = -1; + break; + } + priv->used_bit_filter_number++; + } + else if (req->ftype == CAN_FILTER_RANGE) + { + /* Use range filter */ + + if (priv->used_range_filter) + { + /* The range filter is already used. Return with error */ + + canerr("Range filter used. Cannot add more. Delete all and " + "add again."); + ret = -1; + break; + } + filter = HW_FILTER_RANGE; + priv->used_range_filter = true; + } + else + { + /* Dual address and other filter types not yet support */ + + canerr("Dual address and other filter types not yet support"); + ret = -1; + break; + } + + /* Add hw filter */ + + mpfs_can_add_hw_filter(priv, + filter, + CAN_EXT_ID, + req->fprio, /* CAN Type: LOW for CAN, HIGH for FDCAN */ + req->fid1, + req->fid2); + + ret = OK; + } + break; + + case SIOCDCANSTDFILTER: + case SIOCDCANEXTFILTER: + + /* Reset all HW FILTERs */ + + { + mpfs_can_reset_hw_filter(priv); + ret = OK; + } + break; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + default: + ret = -ENOTTY; + break; + } + + return ret; +} +#endif /* CONFIG_NETDEV_IOCTL */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_fpga_canfd_init + * + * Description: + * Initialize the CAN controller and driver + * + * Returned Value: + * On success, a pointer to the MPFS CANFD driver is + * returned. NULL is returned on any failure. + * + * Assumptions: + * None + * + ****************************************************************************/ + +int mpfs_fpga_canfd_init(void) +{ +#ifdef CONFIG_MPFS_CANFD0 + caninfo("Initialize CANFD0 driver...\n"); + struct mpfs_driver_s *priv0; + priv0 = &g_canfd0; + memset(priv0, 0, sizeof(struct mpfs_driver_s)); + + priv0->base = CONFIG_MPFS_CANFD_BASE0; + priv0->config = &mpfs_fpga_canfd_config0; + + /* Initialize the CAN common private data structure */ + + priv0->can.state = CAN_STATE_ERROR_ACTIVE; + priv0->ntxbufs = 2; + priv0->can.bittiming_const = &mpfs_can_bit_timing_range; + priv0->can.data_bittiming_const = &mpfs_can_bit_timing_data_range; + + priv0->can.can_stats.arbitration_lost = 0; + priv0->can.can_stats.bus_error = 0; + priv0->can.can_stats.bus_off = 0; + priv0->can.can_stats.error_warning = 0; + priv0->can.can_stats.error_passive = 0; + priv0->can.can_stats.restarts = 0; + + /* Get the can_clk info */ + + priv0->can.clock.freq = MPFS_FPGA_PERIPHERAL_CLK; + + /* Needed for timing adjustment to be performed as soon as possible */ + + priv0->can.bittiming.bitrate = CONFIG_MPFS_CANFD_ARBI_BITRATE0; + priv0->can.data_bittiming.bitrate = CONFIG_MPFS_CANFD_DATA_BITRATE0; + priv0->can.bittiming.sjw = 5; + priv0->can.data_bittiming.sjw = 5; + + /* Calculate nominal and data bit timing */ + + mpfs_can_btr_compute(priv0, + &priv0->can.bittiming, + priv0->can.bittiming_const); + mpfs_can_btr_compute(priv0, + &priv0->can.data_bittiming, + priv0->can.data_bittiming_const); + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + /* Init hw filter runtime var */ + + priv0->used_bit_filter_number = 0; + priv0->used_range_filter = false; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + /* Set CAN control modes */ + + priv0->can.ctrlmode = CAN_CTRLMODE_FD + | CAN_CTRLMODE_BERR_REPORTING; + + /* Attach the interrupt handler */ + + if (irq_attach(priv0->config->canfd_fpga_irq, mpfs_interrupt, priv0)) + { + /* We could not attach the ISR to the interrupt */ + + canerr("ERROR: Failed to attach to CAN0 IRQ\n"); + return -EAGAIN; + } + + /* Initialize TX/RX descriptor structure */ + + priv0->txdesc = (struct canfd_frame *)&g_tx_pool0; + priv0->rxdesc = (struct canfd_frame *)&g_rx_pool0; + + /* Initialize the driver network device structure */ + + priv0->dev.d_ifup = mpfs_ifup; /* I/F up (new IP address) callback */ + priv0->dev.d_ifdown = mpfs_ifdown; /* I/F down callback */ + priv0->dev.d_txavail = mpfs_txavail; /* New TX data callback */ +#ifdef CONFIG_NETDEV_IOCTL + priv0->dev.d_ioctl = mpfs_ioctl; /* Support CAN ioctl() calls */ +#endif + priv0->dev.d_private = priv0; /* Used to recover private state from dev */ + + /* Reset controller */ + + if (mpfs_reset(priv0) < 0) + { + return -1; + } + + caninfo("CANFD0 driver init done\n"); + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling mpfs_ifdown(). + */ + + mpfs_ifdown(&priv0->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + netdev_register(&priv0->dev, NET_LL_CAN); +#endif /* CONFIG_MPFS_CANFD0 */ + +#ifdef CONFIG_MPFS_CANFD1 + caninfo("Initialize CANFD1 driver...\n"); + struct mpfs_driver_s *priv1; + priv1 = &g_canfd1; + memset(priv1, 0, sizeof(struct mpfs_driver_s)); + + priv1->base = CONFIG_MPFS_CANFD_BASE1; + priv1->config = &mpfs_fpga_canfd_config1; + + /* Initialize the CAN common private data structure */ + + priv1->can.state = CAN_STATE_ERROR_ACTIVE; + priv1->ntxbufs = 2; + priv1->can.bittiming_const = &mpfs_can_bit_timing_range; + priv1->can.data_bittiming_const = &mpfs_can_bit_timing_data_range; + + priv1->can.can_stats.arbitration_lost = 0; + priv1->can.can_stats.bus_error = 0; + priv1->can.can_stats.bus_off = 0; + priv1->can.can_stats.error_warning = 0; + priv1->can.can_stats.error_passive = 0; + priv1->can.can_stats.restarts = 0; + + /* Get the can_clk info */ + + priv1->can.clock.freq = MPFS_FPGA_PERIPHERAL_CLK; + + /* Needed for timing adjustment to be performed as soon as possible */ + + priv1->can.bittiming.bitrate = CONFIG_MPFS_CANFD_ARBI_BITRATE1; + priv1->can.data_bittiming.bitrate = CONFIG_MPFS_CANFD_DATA_BITRATE1; + priv1->can.bittiming.sjw = 5; + priv1->can.data_bittiming.sjw = 5; + + /* Calculate nominal and data bit timing */ + + mpfs_can_btr_compute(priv1, + &priv1->can.bittiming, + priv1->can.bittiming_const); + mpfs_can_btr_compute(priv1, + &priv1->can.data_bittiming, + priv1->can.data_bittiming_const); + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + /* Init hw filter runtime var */ + + priv1->used_bit_filter_number = 0; + priv1->used_range_filter = false; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + /* Set CAN control modes */ + + priv1->can.ctrlmode = CAN_CTRLMODE_FD + | CAN_CTRLMODE_BERR_REPORTING; + + /* Attach the interrupt handler */ + + if (irq_attach(priv1->config->canfd_fpga_irq, mpfs_interrupt, priv1)) + { + /* We could not attach the ISR to the interrupt */ + + canerr("ERROR: Failed to attach to CAN1 IRQ\n"); + return -EAGAIN; + } + + /* Initialize TX/RX descriptor structure */ + + priv1->txdesc = (struct canfd_frame *)&g_tx_pool1; + priv1->rxdesc = (struct canfd_frame *)&g_rx_pool1; + + /* Initialize the driver network device structure */ + + priv1->dev.d_ifup = mpfs_ifup; /* I/F up (new IP address) callback */ + priv1->dev.d_ifdown = mpfs_ifdown; /* I/F down callback */ + priv1->dev.d_txavail = mpfs_txavail; /* New TX data callback */ +#ifdef CONFIG_NETDEV_IOCTL + priv1->dev.d_ioctl = mpfs_ioctl; /* Support CAN ioctl() calls */ +#endif + priv1->dev.d_private = priv1; /* Used to recover private state from dev */ + + /* Reset controller */ + + if (mpfs_reset(priv1) < 0) + { + return -1; + } + + caninfo("CANFD1 driver init done\n"); + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling mpfs_ifdown(). + */ + + mpfs_ifdown(&priv1->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + netdev_register(&priv1->dev, NET_LL_CAN); +#endif /* CONFIG_MPFS_CANFD1 */ + + return OK; +} diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h new file mode 100644 index 0000000000000..9bc78552b3eb7 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h @@ -0,0 +1,87 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_fpga_canfd.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_MPFS_MPFS_FPGA_CANFD_H +#define __ARCH_RISCV_SRC_MPFS_MPFS_FPGA_CANFD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* Check if CAN-FD support is enabled. */ + +#ifdef CONFIG_MPFS_HAVE_CANFD + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_fpga_canfd_init + * + * Description: + * Initialize a CANFD block. + * + * Returned Value: + * OK on success, Negated errno on failure + * + ****************************************************************************/ + +int mpfs_fpga_canfd_init(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_MPFS_HAVE_CANFD */ +#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_FPGA_CANFD_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 26fa4408eb14e..ab67839ea5b96 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -83,7 +83,10 @@ typedef enum mpfs_i2c_status MPFS_I2C_SUCCESS = 0u, MPFS_I2C_IN_PROGRESS, MPFS_I2C_FAILED, - MPFS_I2C_TIMED_OUT + MPFS_I2C_FAILED_SLAW_NACK, + MPFS_I2C_FAILED_SLAR_NACK, + MPFS_I2C_FAILED_TX_DATA_NACK, + MPFS_I2C_FAILED_BUS_ERROR, } mpfs_i2c_status_t; typedef enum mpfs_i2c_clock_divider @@ -123,6 +126,8 @@ static const uint32_t mpfs_i2c_freqs_fpga[MPFS_I2C_NUMBER_OF_DIVIDERS] = MPFS_FPGA_BCLK / 8 }; +static int mpfs_i2c_irq(int cpuint, void *context, void *arg); + static int mpfs_i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgs, int count); @@ -298,8 +303,67 @@ static uint32_t mpfs_i2c_timeout(int msgc, struct i2c_msg_s *msgv); static int mpfs_i2c_init(struct mpfs_i2c_priv_s *priv) { + int ret = OK; + uint32_t ctrl; + uint32_t status; + if (!priv->initialized) { + /* In case of warm boot, or after reset, check that the IP block is + * not already active and try to recover from any pending data + * transfer if it is. + */ + + ctrl = getreg32(MPFS_I2C_CTRL); + if (ctrl != 0) + { + /* Check if the IP is enabled */ + + status = getreg32(MPFS_I2C_STATUS); + if (ctrl & MPFS_I2C_CTRL_ENS1_MASK) + { + if (status == MPFS_I2C_ST_RX_DATA_ACK) + { + /* In case the machine was in the middle of data RX, try to + * receive one byte and nack it + */ + + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_AA_MASK, 0); + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + usleep(100); + status = getreg32(MPFS_I2C_STATUS); + } + + if (status != MPFS_I2C_ST_IDLE) + { + /* If the bus is not idle, send STOP */ + + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK); + usleep(100); + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + status = getreg32(MPFS_I2C_STATUS); + } + } + + if (status != MPFS_I2C_ST_IDLE) + { + i2cerr("Bus not idle before init\n"); + } + + /* Disable IP and continue initialization */ + + putreg32(0, MPFS_I2C_CTRL); + } + + /* Attach interrupt */ + + ret = irq_attach(priv->plic_irq, mpfs_i2c_irq, priv); + if (ret != OK) + { + return ret; + } + if (priv->fpga) { /* FIC3 is used by many, don't reset it here, or many @@ -358,10 +422,11 @@ static int mpfs_i2c_init(struct mpfs_i2c_priv_s *priv) putreg32(priv->ser_address, MPFS_I2C_ADDR); - /* Enable i2c bus */ + /* Enable i2c bus, clear all other bits */ + + putreg32(MPFS_I2C_CTRL_ENS1_MASK, MPFS_I2C_CTRL); - modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_ENS1_MASK, - MPFS_I2C_CTRL_ENS1_MASK); + nxsem_reset(&priv->sem_isr, 0); priv->initialized = true; } @@ -385,8 +450,7 @@ static void mpfs_i2c_deinit(struct mpfs_i2c_priv_s *priv) up_disable_irq(priv->plic_irq); irq_detach(priv->plic_irq); - modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_ENS1_MASK, - ~MPFS_I2C_CTRL_ENS1_MASK); + putreg32(0, MPFS_I2C_CTRL); priv->initialized = false; } @@ -408,8 +472,27 @@ static void mpfs_i2c_deinit(struct mpfs_i2c_priv_s *priv) static int mpfs_i2c_sem_waitdone(struct mpfs_i2c_priv_s *priv) { + int res = 0; uint32_t timeout = mpfs_i2c_timeout(priv->msgc, priv->msgv); - return nxsem_tickwait_uninterruptible(&priv->sem_isr, USEC2TICK(timeout)); + + res = nxsem_tickwait_uninterruptible(&priv->sem_isr, USEC2TICK(timeout)); + + /* -> race condition <- */ + + priv->inflight = false; + + /* Handle a race condition above in which interrupt MPFS_I2C_ST_STOP_SENT + * was received right after semaphore timeout. In that case semaphore is + * signalled and has the incorrect state when the next transfer starts. + */ + + if (res < 0) + { + res = nxsem_tickwait_uninterruptible(&priv->sem_isr, + USEC2TICK(timeout)); + } + + return res; } /**************************************************************************** @@ -437,8 +520,6 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) volatile uint32_t status; uint8_t clear_irq = 1u; - DEBUGASSERT(msg != NULL); - status = getreg32(MPFS_I2C_STATUS); switch (status) @@ -472,14 +553,23 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) case MPFS_I2C_ST_SLAW_NACK: modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK); - priv->status = MPFS_I2C_FAILED; + priv->status = MPFS_I2C_FAILED_SLAW_NACK; break; case MPFS_I2C_ST_SLAW_ACK: case MPFS_I2C_ST_TX_DATA_ACK: if (priv->tx_idx < priv->tx_size) { - DEBUGASSERT(priv->tx_buffer != NULL); + if (priv->tx_buffer == NULL) + { + i2cerr("ERROR: tx_buffer is NULL!\n"); + + /* Clear the serial interrupt flag and exit */ + + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + return 0; + } + putreg32(priv->tx_buffer[priv->tx_idx], MPFS_I2C_DATA); priv->tx_idx++; } @@ -493,7 +583,10 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) /* Jump to the next message */ - priv->msgid++; + if (priv->msgid < (priv->msgc - 1)) + { + priv->msgid++; + } } else { @@ -512,7 +605,10 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) /* Jump to the next message */ - priv->msgid++; + if (priv->msgid < (priv->msgc - 1)) + { + priv->msgid++; + } } else { @@ -525,7 +621,7 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) case MPFS_I2C_ST_TX_DATA_NACK: modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK); - priv->status = MPFS_I2C_FAILED; + priv->status = MPFS_I2C_FAILED_TX_DATA_NACK; break; case MPFS_I2C_ST_SLAR_ACK: /* SLA+R tx'ed. */ @@ -547,14 +643,22 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) case MPFS_I2C_ST_SLAR_NACK: /* SLA+R tx'ed; send a stop condition */ modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK); - priv->status = MPFS_I2C_FAILED; + priv->status = MPFS_I2C_FAILED_SLAR_NACK; break; case MPFS_I2C_ST_RX_DATA_ACK: + if (priv->rx_buffer == NULL) + { + i2cerr("ERROR: rx_buffer is NULL!\n"); + + /* Clear the serial interrupt flag and exit */ + + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + return 0; + } /* Data byte received, ACK returned */ - DEBUGASSERT(priv->rx_buffer != NULL); priv->rx_buffer[priv->rx_idx] = (uint8_t)getreg32(MPFS_I2C_DATA); priv->rx_idx++; @@ -566,13 +670,31 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) case MPFS_I2C_ST_RX_DATA_NACK: + /* Some sanity checks */ + + if (priv->rx_buffer == NULL) + { + i2cerr("ERROR: rx_buffer is NULL!\n"); + + /* Clear the serial interrupt flag and exit */ + + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + return 0; + } + else if (priv->rx_idx >= priv->rx_size) + { + i2cerr("ERROR: rx_idx is out of bounds!\n"); + + /* Clear the serial interrupt flag and exit */ + + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + return 0; + } + /* Data byte received, NACK returned */ - DEBUGASSERT(priv->rx_buffer != NULL); - DEBUGASSERT(priv->rx_idx < priv->rx_size); priv->rx_buffer[priv->rx_idx] = (uint8_t)getreg32(MPFS_I2C_DATA); priv->rx_idx++; - priv->status = MPFS_I2C_SUCCESS; modifyreg32(MPFS_I2C_CTRL, 0, MPFS_I2C_CTRL_STO_MASK); break; @@ -613,7 +735,7 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) if (priv->status == MPFS_I2C_IN_PROGRESS) { - priv->status = MPFS_I2C_FAILED; + priv->status = MPFS_I2C_FAILED_BUS_ERROR; } break; @@ -665,9 +787,17 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, { struct mpfs_i2c_priv_s *priv = (struct mpfs_i2c_priv_s *)dev; int ret = OK; +#ifdef CONFIG_DEBUG_I2C_ERROR + int sval; + uint32_t status; +#endif i2cinfo("Starting transfer request of %d message(s):\n", count); - DEBUGASSERT(count > 0); + + if (count <= 0) + { + return -EINVAL; + } ret = nxmutex_lock(&priv->lock); if (ret < 0) @@ -675,6 +805,24 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, return ret; } +#ifdef CONFIG_DEBUG_I2C_ERROR + /* We should never start at transfer with semaphore already signalled */ + + sem_getvalue(&priv->sem_isr, &sval); + if (sval != 0) + { + i2cerr("Already signalled at start? %d\n", sval); + } + + /* We should always be idle before transfer */ + + status = getreg32(MPFS_I2C_STATUS); + if (status != MPFS_I2C_ST_IDLE) + { + i2cerr("I2C bus not idle before transfer! Status: 0x%x\n", status); + } +#endif + priv->msgv = msgs; priv->msgc = count; @@ -709,9 +857,17 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, if (msgs[i].flags & I2C_M_NOSTOP) { - /* Support only write + read combinations */ + /* Support only write + read combinations. No write + write, + * nor read + write without stop condition between supported + * yet. + */ - DEBUGASSERT(!(msgs[i].flags & I2C_M_READ)); + if (msgs[i].flags & I2C_M_READ) + { + i2cerr("No read before write supported!\n"); + nxmutex_unlock(&priv->lock); + return -EINVAL; + } /* Combine write + read transaction into one */ @@ -738,7 +894,6 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, if (mpfs_i2c_sem_waitdone(priv) < 0) { i2cinfo("Message %" PRIu8 " timed out.\n", priv->msgid); - priv->inflight = false; ret = -ETIMEDOUT; break; } @@ -759,6 +914,20 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, i2cinfo("Message %" PRIu8 " transfer complete.\n", priv->msgid); } +#ifdef CONFIG_DEBUG_I2C_ERROR + /* We should always be idle after the transfers */ + + status = getreg32(MPFS_I2C_STATUS); + if (status != MPFS_I2C_ST_IDLE) + { + i2cerr("I2C bus not idle after transfer! Status: 0x%x\n", status); + } +#endif + + /* Irq was enabled at mpfs_i2c_sendstart() */ + + up_disable_irq(priv->plic_irq); + nxmutex_unlock(&priv->lock); return ret; } @@ -782,26 +951,17 @@ static int mpfs_i2c_reset(struct i2c_master_s *dev) { struct mpfs_i2c_priv_s *priv = (struct mpfs_i2c_priv_s *)dev; int ret; - irqstate_t flags; - - DEBUGASSERT(priv != NULL); - flags = enter_critical_section(); - - /* Disabling I2C interrupts. - * NOTE: up_enable_irq() will be called at mpfs_i2c_sendstart() - */ + nxmutex_lock(&priv->lock); - up_disable_irq(priv->plic_irq); + i2cerr("i2c bus %d reset\n", priv->id); - priv->inflight = false; - priv->status = MPFS_I2C_SUCCESS; - priv->initialized = false; + mpfs_i2c_deinit(priv); ret = mpfs_i2c_init(priv); if (ret != OK) { - leave_critical_section(flags); + nxmutex_unlock(&priv->lock); return ret; } @@ -809,8 +969,10 @@ static int mpfs_i2c_reset(struct i2c_master_s *dev) priv->tx_idx = 0; priv->rx_size = 0; priv->rx_idx = 0; + priv->inflight = false; + priv->status = MPFS_I2C_SUCCESS; - leave_critical_section(flags); + nxmutex_unlock(&priv->lock); return OK; } @@ -1004,14 +1166,6 @@ struct i2c_master_s *mpfs_i2cbus_initialize(int port) priv->fpga = true; #endif - ret = irq_attach(priv->plic_irq, mpfs_i2c_irq, priv); - if (ret != OK) - { - priv->refs--; - nxmutex_unlock(&priv->lock); - return NULL; - } - ret = mpfs_i2c_init(priv); if (ret != OK) { diff --git a/arch/risc-v/src/mpfs/mpfs_irq.c b/arch/risc-v/src/mpfs/mpfs_irq.c index a7550c5d7317d..5ee1a744ed8b6 100644 --- a/arch/risc-v/src/mpfs/mpfs_irq.c +++ b/arch/risc-v/src/mpfs/mpfs_irq.c @@ -50,6 +50,18 @@ void up_irqinitialize(void) up_irq_save(); + /* Complete possibly claimed IRQs in PLIC (for current hart) in case + * of warm reboot, e.g. after a crash in the middle of IRQ handler. + * This has no effect on non-claimed or disabled interrupts. + */ + + uintptr_t claim_address = mpfs_plic_get_claimbase(); + + for (int irq = MPFS_IRQ_EXT_START; irq < NR_IRQS; irq++) + { + putreg32(irq - MPFS_IRQ_EXT_START, claim_address); + } + /* Disable all global interrupts for current hart */ uintptr_t iebase = mpfs_plic_get_iebase(); @@ -61,12 +73,6 @@ void up_irqinitialize(void) putreg32(0x0, iebase + 16); putreg32(0x0, iebase + 20); - /* Clear pendings in PLIC (for current hart) */ - - uintptr_t claim_address = mpfs_plic_get_claimbase(); - uint32_t val = getreg32(claim_address); - putreg32(val, claim_address); - /* Colorize the interrupt stack for debug purposes */ #if defined(CONFIG_STACK_COLORATION) && CONFIG_ARCH_INTERRUPTSTACK > 15 @@ -76,9 +82,7 @@ void up_irqinitialize(void) /* Set priority for all global interrupts to 1 (lowest) */ - int id; - - for (id = 1; id <= NR_IRQS; id++) + for (int id = 1; id <= NR_IRQS; id++) { putreg32(1, (uintptr_t)(MPFS_PLIC_PRIORITY + (4 * id))); } diff --git a/arch/risc-v/src/mpfs/mpfs_lowputc.c b/arch/risc-v/src/mpfs/mpfs_lowputc.c index 93dede2fd4ad0..8daa7d6b82f3c 100644 --- a/arch/risc-v/src/mpfs/mpfs_lowputc.c +++ b/arch/risc-v/src/mpfs/mpfs_lowputc.c @@ -40,6 +40,8 @@ ****************************************************************************/ /* Select UART parameters for the selected console */ + +#ifndef CONFIG_MPFS_FPGA_UART #if defined(CONFIG_UART0_SERIAL_CONSOLE) # define MPFS_CONSOLE_BASE MPFS_UART0_BASE # define MPFS_CONSOLE_BAUD CONFIG_UART0_BAUD @@ -89,6 +91,93 @@ # error "No CONFIG_UARTn_SERIAL_CONSOLE Setting" # endif +#else /* CONFIG_MPFS_FPGA_UART */ + +#if defined(CONFIG_UART0_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART0_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART0_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART0_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART0_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART0_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART1_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART1_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART1_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART1_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART1_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART2_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART2_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART2_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART2_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART2_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART2_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +# elif defined(CONFIG_UART3_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART3_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART3_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART3_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART3_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART3_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART4_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART4_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART4_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART4_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART4_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART5_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART5_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART5_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART5_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART5_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART6_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART6_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART6_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART6_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART6_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART6_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) +# define MPFS_CONSOLE_BASE MPFS_FPGA_UART7_BASE +# define MPFS_CONSOLE_BAUD CONFIG_UART7_BAUD +# define MPFS_CONSOLE_BITS CONFIG_UART7_BITS +# define MPFS_CONSOLE_PARITY CONFIG_UART7_PARITY +# define MPFS_CONSOLE_2STOP CONFIG_UART7_2STOP +# define MPFS_CONSOLE_CLOCKBIT SYSREG_SUBBLK_CLOCK_CR_FIC3 +# define MPFS_CONSOLE_RESETBIT SYSREG_SOFT_RESET_CR_FIC3 | \ + SYSREG_SOFT_RESET_CR_FPGA +# define HAVE_UART +#elif defined(HAVE_UART) +# error "No CONFIG_UARTn_SERIAL_CONSOLE Setting" +#endif +#endif /* CONFIG_MPFS_FPGA_UART */ + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -111,7 +200,16 @@ static void config_baud_divisors(void) uint32_t fractional_baud_value; uint64_t pclk_freq; - pclk_freq = MPFS_MSS_APB_AHB_CLK; + if (MPFS_CONSOLE_CLOCKBIT == SYSREG_SUBBLK_CLOCK_CR_FIC3) + { + /* This is an FPGA UART */ + + pclk_freq = MPFS_FPGA_PERIPHERAL_CLK; + } + else + { + pclk_freq = MPFS_MSS_APB_AHB_CLK; + } /* Compute baud value based on requested baud rate and PCLK frequency. * The baud value is computed using the following equation: @@ -189,20 +287,23 @@ void mpfs_lowsetup(void) #if defined(HAVE_SERIAL_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG) uint32_t lcr = 0; - /* reset on */ + /* reset on - only for non-FPGA uarts */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, - 0, MPFS_CONSOLE_RESETBIT); + if (SYSREG_SUBBLK_CLOCK_CR_FIC3 != MPFS_CONSOLE_CLOCKBIT) + { + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, 0, + MPFS_CONSOLE_RESETBIT); + } /* reset off */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, - 0, MPFS_CONSOLE_CLOCKBIT); + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, + MPFS_CONSOLE_RESETBIT, 0); /* clock on */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, - MPFS_CONSOLE_RESETBIT, 0); + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, + 0, MPFS_CONSOLE_CLOCKBIT); switch (MPFS_CONSOLE_BITS) { diff --git a/arch/risc-v/src/mpfs/mpfs_mm_init.c b/arch/risc-v/src/mpfs/mpfs_mm_init.c index 90f69b33fe440..6c5bdd394dacc 100644 --- a/arch/risc-v/src/mpfs/mpfs_mm_init.c +++ b/arch/risc-v/src/mpfs/mpfs_mm_init.c @@ -54,9 +54,9 @@ #define PGT_L2_VBASE PGT_L2_PBASE #define PGT_L3_VBASE PGT_L3_PBASE -#define PGT_L1_SIZE (512) /* Enough to map 512 GiB */ -#define PGT_L2_SIZE (512) /* Enough to map 1 GiB */ -#define PGT_L3_SIZE (1024) /* Enough to map 4 MiB */ +#define PGT_L1_SIZE (512) /* Enough to map 512 GiB */ +#define PGT_L2_SIZE (512) /* Enough to map 1 GiB */ +#define PGT_L3_SIZE (40 * 1024) /* Enough to map 40 MiB */ /* Calculate the minimum size for the L3 table */ @@ -251,4 +251,9 @@ void mpfs_kernel_mappings(void) mmu_ln_map_region(2, PGT_L2_VBASE, PGPOOL_START, PGPOOL_START, PGPOOL_SIZE, MMU_KDATA_FLAGS); + + /* Map the MTIME counter to the start of USR IO region */ + + map_region(MPFS_CLINT_MTIME & (~RV_MMU_PAGE_MASK), USRIO_START, + RV_MMU_PAGE_SIZE, PTE_R | PTE_U | PTE_G); } diff --git a/arch/risc-v/src/mpfs/mpfs_mpu.c b/arch/risc-v/src/mpfs/mpfs_mpu.c new file mode 100644 index 0000000000000..2adaf3d911c58 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_mpu.c @@ -0,0 +1,285 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_mpu.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include + +#include "riscv_internal.h" +#include "mpfs_memorymap.h" + +#include "hardware/mpfs_mpucfg.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* MPUCFG entry is 64-bits */ + +#define MPFS_MPUCFG_WIDTH 64 + +/* Mode bits [63:56] */ + +#define MPFS_MPUCFG_MODE_SHIFT 56 +#define MPFS_MPUCFG_MODE_WIDTH 8 +#define MPFS_MPUCFG_MODE_MASK \ + (((1ul << MPFS_MPUCFG_MODE_WIDTH) - 1) << MPFS_MPUCFG_MODE_SHIFT) + +/* PMP entry bits [35:0] */ + +#define MPFS_MPUCFG_PMP_SHIFT 0 +#define MPFS_MPUCFG_PMP_WIDTH 36 +#define MPFS_MPUCFG_PMP_MASK \ + (((1ul << MPFS_MPUCFG_PMP_WIDTH) - 1) << MPFS_MPUCFG_PMP_SHIFT) + +/* Encode the MPUCFG register value */ + +#define MPFS_MPUCFG_ENCODE(mode, napot) \ + ((((mode) << MPFS_MPUCFG_MODE_SHIFT) & MPFS_MPUCFG_MODE_MASK) | \ + (((napot) << MPFS_MPUCFG_PMP_SHIFT) & MPFS_MPUCFG_PMP_MASK)) + +/* Decode the MPUCFG register value */ + +#define MPFS_MPUCFG_DECODE(reg, mode, napot) \ + do \ + { \ + uintptr_t val = getreg64(reg); \ + *(mode) = (val & MPFS_MPUCFG_MODE_MASK) >> MPFS_MPUCFG_MODE_SHIFT; \ + *(napot) = (val & MPFS_MPUCFG_PMP_MASK) >> MPFS_MPUCFG_PMP_SHIFT; \ + } \ + while(0) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: napot_decode + * + * Description: + * Decode base and size from NAPOT value + * + * Input Parameters: + * val - Value to decode. + * size - Size out. + * + * Returned Value: + * Base address. + * + ****************************************************************************/ + +static void napot_decode(uintptr_t val, uintptr_t *base, uintptr_t *size) +{ + uintptr_t mask = (uintptr_t)(-1) >> 1; + uintptr_t pot = MPFS_MPUCFG_WIDTH + 2; + + while (mask) + { + if ((val & mask) == mask) + { + break; + } + + pot--; + mask >>= 1; + } + + *size = UINT64_C(1) << pot; + *base = (val & ~mask) << 2; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_mpu_set + * + * Description: + * Set value to MPFS MPUCFG register. + * + * Input Parameters: + * reg - The MPUCFG register to write. + * perm - The region permissions. + * base - The base address of the region. + * size - The length of the region. + * + * Note: + * Only NAPOT encoded regions are supported, thus the base address and + * size must align with each other. + * + * Returned Value: + * 0 on success; negated error on failure. + * + ****************************************************************************/ + +int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, + uintptr_t size) +{ + uintptr_t mode; + uintptr_t napot; + + /* Read the the permission and napot fields */ + + MPFS_MPUCFG_DECODE(reg, &mode, &napot); + + /* First, check that the register is not already configured */ + + if ((mode & PMPCFG_L) != 0) + { + /* The entry is locked, get out */ + + return -EACCES; + } + + /* Base must be word aligned, + * minimum size is 4K and it has to be power-of-two + */ + + if ((base & 0x07) != 0 || size < 0x1000 || (size & (size - 1)) != 0) + { + return -EINVAL; + } + + /* Make sure the base + size are NAPOT encodable */ + + if ((base & ((UINT64_C(1) << log2ceil(size)) - 1)) != 0) + { + /* The start address is not properly aligned with size */ + + return -EINVAL; + } + + /* Sanity check the register */ + + if (reg < MPFS_MPUCFG_BASE || reg >= MPFS_MPUCFG_END) + { + return -EINVAL; + } + + /* Calculate mode (RWX), only NAPOT encoding is supported */ + + mode = (perm & (PMPCFG_RWX_MASK | PMPCFG_L)) | PMPCFG_A_NAPOT; + + /* Do the NAPOT encoding */ + + napot = (base >> 2) | ((size - 1) >> 3); + + /* Then set the value */ + + putreg64(MPFS_MPUCFG_ENCODE(mode, napot), reg); + + return OK; +} + +/**************************************************************************** + * Name: mpfs_mpu_access_ok + * + * Description: + * Check if MPFS MPUCFG access is OK for register. + * + * Input Parameters: + * reg - The MPUCFG register to check. + * perm - The region permissions. + * base - The base address of the region. + * size - The length of the region. + * + * Returned Value: + * true if access OK; false if not. + * + ****************************************************************************/ + +bool mpfs_mpu_access_ok(uintptr_t reg, uintptr_t perm, uintptr_t base, + uintptr_t size) +{ + uintptr_t mode; + uintptr_t napot; + uintptr_t reg_base; + uintptr_t reg_size; + + /* Read the the permission and napot fields */ + + MPFS_MPUCFG_DECODE(reg, &mode, &napot); + + /* Check for permission match */ + + if ((mode & PMPCFG_RWX_MASK) != perm) + { + return false; + } + + /* Decode the napot field */ + + napot_decode(napot, ®_base, ®_size); + + /* Then check if the area fits */ + + return (base >= reg_base && (base + size) <= (reg_base + reg_size)); +} + +/**************************************************************************** + * Name: mpfs_mpu_lock + * + * Description: + * Lock an MPUCFG register from further modifications. + * + * Input Parameters: + * reg - The MPUCFG register to lock. + * + * Returned Value: + * 0 on success; negated error on failure. + * + ****************************************************************************/ + +int mpfs_mpu_lock(uintptr_t reg) +{ + uintptr_t mode; + uintptr_t napot; + + /* Sanity check the register */ + + if (reg < MPFS_MPUCFG_BASE || reg >= MPFS_MPUCFG_END) + { + return -EINVAL; + } + + MPFS_MPUCFG_DECODE(reg, &mode, &napot); + + /* If the entry is already locked, everything is fine */ + + if ((mode & PMPCFG_L) == 0) + { + /* Set the lock bit and write the value back */ + + putreg64(MPFS_MPUCFG_ENCODE(mode | PMPCFG_L, napot), reg); + } + + return OK; +} diff --git a/arch/risc-v/src/mpfs/mpfs_mpu.h b/arch/risc-v/src/mpfs/mpfs_mpu.h new file mode 100644 index 0000000000000..d934cd64044ef --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_mpu.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_mpu.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H +#define __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_mpu_set + * + * Description: + * Set value to MPFS MPUCFG register. + * + * Input Parameters: + * reg - The MPUCFG register to write. + * perm - The region permissions. + * base - The base address of the region. + * size - The length of the region. + * + * Note: + * Only NAPOT encoded regions are supported, thus the base address and + * size must align with each other. + * + * Returned Value: + * 0 on success; negated error on failure. + * + ****************************************************************************/ + +int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, + uintptr_t size); + +/**************************************************************************** + * Name: mpfs_mpu_access_ok + * + * Description: + * Check if MPFS MPUCFG access is OK for register. + * + * Input Parameters: + * reg - The MPUCFG register to check. + * perm - The region permissions. + * base - The base address of the region. + * size - The length of the region. + * + * Returned Value: + * true if access OK; false if not. + * + ****************************************************************************/ + +bool mpfs_mpu_access_ok(uintptr_t reg, uintptr_t perm, uintptr_t base, + uintptr_t size); + +/**************************************************************************** + * Name: mpfs_mpu_lock + * + * Description: + * Lock an MPUCFG register from further modifications. + * + * Input Parameters: + * reg - The MPUCFG register to lock. + * + * Returned Value: + * 0 on success; negated error on failure. + * + ****************************************************************************/ + +int mpfs_mpu_lock(uintptr_t reg); + +#endif /* __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi.c b/arch/risc-v/src/mpfs/mpfs_opensbi.c index ad9e835c346c5..3c7a1e9e2badd 100644 --- a/arch/risc-v/src/mpfs/mpfs_opensbi.c +++ b/arch/risc-v/src/mpfs/mpfs_opensbi.c @@ -28,8 +28,31 @@ #include #ifdef CONFIG_MPFS_IHC_SBI #include +#include +#endif +#include "mpfs_entrypoints.h" + +/* Make sure that anything that intefraces with the SBI uses the same data + * types as the SBI code (e.g. same "bool") + */ + +#ifdef bool +#undef bool +#endif + +#ifdef true +#undef true +#endif + +#ifdef false +#undef false #endif +#ifdef NULL +#undef NULL +#endif + +#include #include #include #include @@ -41,10 +64,6 @@ #include #include -#ifdef CONFIG_MPFS_IHC_SBI -#include -#endif - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -84,8 +103,8 @@ typedef struct sbi_scratch_holder_s sbi_scratch_holder_t; extern const uint8_t __mpfs_nuttx_start[]; extern const uint8_t __mpfs_nuttx_end[]; -extern const uint8_t _ssbi_ddr[]; -extern const uint8_t _esbi_ddr[]; +extern const uint8_t _ssbi_ram[]; +extern const uint8_t _esbi_ram[]; /**************************************************************************** * Private Function Prototypes @@ -184,30 +203,7 @@ static struct aclint_mswi_data mpfs_mswi = * Unused hart is marked with -1. Mpfs will always have the hart0 unused. */ -static const u32 mpfs_hart_index2id[MPFS_HART_COUNT] = -{ - [0] = -1, -#ifdef CONFIG_MPFS_HART1_SBI - [1] = 1, -#else - [1] = -1, -#endif -#ifdef CONFIG_MPFS_HART2_SBI - [2] = 2, -#else - [2] = -1, -#endif -#ifdef CONFIG_MPFS_HART3_SBI - [3] = 3, -#else - [3] = -1, -#endif -#ifdef CONFIG_MPFS_HART4_SBI - [4] = 4, -#else - [4] = -1, -#endif -}; +static u32 mpfs_hart_index2id[MPFS_HART_COUNT]; static const struct sbi_platform platform = { @@ -479,9 +475,9 @@ static void mpfs_opensbi_scratch_setup(uint32_t hartid) * them so that OpenSBI has no chance override then. */ - g_scratches[hartid].scratch.fw_start = (unsigned long)_ssbi_ddr; - g_scratches[hartid].scratch.fw_size = (unsigned long)_esbi_ddr - - (unsigned long)_ssbi_ddr; + g_scratches[hartid].scratch.fw_start = (unsigned long)_ssbi_ram; + g_scratches[hartid].scratch.fw_size = (unsigned long)_esbi_ram - + (unsigned long)_ssbi_ram; g_scratches[hartid].scratch.fw_rw_offset = (unsigned long)g_scratches[hartid].scratch.fw_size; @@ -602,6 +598,13 @@ static int mpfs_opensbi_ecall_handler(long funcid, void __attribute__((noreturn)) mpfs_opensbi_setup(void) { uint32_t hartid = current_hartid(); + size_t i; + + for (i = 0; i < sizeof(mpfs_hart_index2id) / sizeof(mpfs_hart_index2id[0]); + i++) + { + mpfs_hart_index2id[i] = mpfs_get_use_sbi(i) ? i : -1; + } sbi_console_set_device(&mpfs_console); mpfs_opensbi_scratch_setup(hartid); diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi_trap.S b/arch/risc-v/src/mpfs/mpfs_opensbi_trap.S index 517cc20dc9814..eab2ecb06280c 100644 --- a/arch/risc-v/src/mpfs/mpfs_opensbi_trap.S +++ b/arch/risc-v/src/mpfs/mpfs_opensbi_trap.S @@ -167,8 +167,10 @@ mpfs_global_pointer: /* Restore GP */ - la a0, mpfs_global_pointer - ld gp, 0(a0) + .option push + .option norelax + la gp, __global_pointer$ + .option pop /* Call C routine */ diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S b/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S index db8f8fff7f738..ac81ace844c65 100644 --- a/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S +++ b/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S @@ -39,6 +39,22 @@ ****************************************************************************/ .global mpfs_opensbi_prepare_hart + .global mpfs_opensbi_relocate_from_envm + + /* Add some weak default values to make this compile without */ + + .weak _sbi_ram_loadaddr + .weak _ssbi_ram + .weak _esbi_ram + + /* These are the weak pointless variables, only to get this PR compile */ + +_sbi_ram_loadaddr: + .dword 0x0a006000 +_ssbi_ram: + .dword _stext +_esbi_ram: + .dword _stext /**************************************************************************** * Private Data @@ -68,21 +84,43 @@ mpfs_global_pointer: * ****************************************************************************/ + .align 3 +mpfs_opensbi_relocate_from_envm: + + /* Relocate the code from eNVM into L2 zero device */ + + la a0, _sbi_ram_loadaddr + la a1, _ssbi_ram + la a2, _esbi_ram +.check_if_opensbi_copy_done: + bge a1, a2, .opensbi_copy_done + ld a3, 0(a0) + sd a3, 0(a1) + addi a0, a0, 8 + addi a1, a1, 8 + j .check_if_opensbi_copy_done +.opensbi_copy_done: + + /* To make a store to instruction memory visible to all RISC-V harts, the + * writing hart has to execute a data FENCE before requesting that all + * remote RISC-V harts execute a FENCE.I. This is hart0 only. + */ + + fence + ret + .align 3 mpfs_opensbi_prepare_hart: + /* These are harts other than 0. Thus, fence.i */ + + fence.i + /* Setup OpenSBI exception handler */ la t0, mpfs_exception_opensbi csrw mtvec, t0 - /* la gp, __global_pointer$ will not work. We want to have the gp as seen - * in the .map file exactly. We need to restore gp in the trap handler. - */ - - la t0, mpfs_global_pointer - ld gp, 0(t0) - /* Setup stacks per hart, the stack top is the end of the hart's scratch */ csrr a0, mhartid diff --git a/arch/risc-v/src/mpfs/mpfs_sdio.c b/arch/risc-v/src/mpfs/mpfs_sdio.c new file mode 100644 index 0000000000000..530ae37e659ab --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_sdio.c @@ -0,0 +1,177 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_sdio.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "mpfs_coremmc.h" +#include "mpfs_emmcsd.h" +#include "mpfs_sdio_dev.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sdio_initialize + * + * Description: + * Initialize SDIO for operation. + * + * Input Parameters: + * slotno - Not used. + * + * Returned Values: + * A reference to an SDIO interface structure. NULL is returned on + * failures. + * + ****************************************************************************/ + +struct sdio_dev_s *sdio_initialize(int slotno) +{ + switch (slotno) + { + case 0: +#ifdef CONFIG_MPFS_EMMCSD + return mpfs_emmcsd_sdio_initialize(slotno); +#endif + + case 1: +#ifdef CONFIG_MPFS_COREMMC + return mpfs_coremmc_sdio_initialize(slotno); +#endif + + default: + break; + } + + mcerr("sdio slot number %d not supported!\n", slotno); + return NULL; +} + +/**************************************************************************** + * Name: sdio_mediachange + * + * Description: + * Called by board-specific logic -- possible from an interrupt handler -- + * in order to signal to the driver that a card has been inserted or + * removed from the slot + * + * Input Parameters: + * dev - An instance of the SDIO driver device state structure. + * cardinslot - true is a card has been detected in the slot; false if a + * card has been removed from the slot. Only transitions + * (inserted->removed or removed->inserted should be reported) + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot) +{ + struct mpfs_dev_s *priv = (struct mpfs_dev_s *)dev; + + if (!dev) + { + mcerr("sdio device not found\n"); + return; + } + + switch (priv->hw_base) + { +#ifdef CONFIG_MPFS_EMMCSD + case MPFS_EMMC_SD_BASE: + mpfs_emmcsd_sdio_mediachange(dev, cardinslot); + return; +#endif + +#ifdef CONFIG_MPFS_COREMMC + case CONFIG_MPFS_COREMMC_BASE: + mpfs_coremmc_sdio_mediachange(dev, cardinslot); + return; +#endif + + default: + break; + } + + mcerr("Invalid sdio base address\n"); +} + +/**************************************************************************** + * Name: sdio_wrprotect + * + * Description: + * Called by board-specific logic to report if the card in the slot is + * mechanically write protected. + * + * Input Parameters: + * dev - An instance of the SDIO driver device state structure. + * wrprotect - true is a card is writeprotected. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect) +{ + struct mpfs_dev_s *priv = (struct mpfs_dev_s *)dev; + + if (!dev) + { + mcerr("sdio device not found\n"); + return; + } + + switch (priv->hw_base) + { +#ifdef CONFIG_MPFS_EMMCSD + case MPFS_EMMC_SD_BASE: + mpfs_emmcsd_sdio_wrprotect(dev, wrprotect); + return; +#endif + +#ifdef CONFIG_MPFS_COREMMC + case CONFIG_MPFS_COREMMC_BASE: + mpfs_coremmc_sdio_wrprotect(dev, wrprotect); + return; +#endif + + default: + break; + } + + mcerr("Invalid sdio base address\n"); +} diff --git a/arch/risc-v/src/mpfs/mpfs_sdio.h b/arch/risc-v/src/mpfs/mpfs_sdio.h new file mode 100644 index 0000000000000..ec63db76e7c3c --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_sdio.h @@ -0,0 +1,112 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_sdio.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_MPFS_MPFS_SDIO_H +#define __ARCH_RISCV_SRC_MPFS_MPFS_SDIO_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include "chip.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: sdio_initialize + * + * Description: + * Initialize SDIO for operation. + * + * Input Parameters: + * slotno - Not used. + * + * Returned Values: + * A reference to an SDIO interface structure. NULL is returned on + * failures. + * + ****************************************************************************/ + +struct sdio_dev_s; /* See include/nuttx/sdio.h */ +struct sdio_dev_s *sdio_initialize(int slotno); + +/**************************************************************************** + * Name: sdio_mediachange + * + * Description: + * Called by board-specific logic -- possibly from an interrupt handler -- + * in order to signal to the driver that a card has been inserted or + * removed from the slot. + * + * Input Parameters: + * dev - An instance of the SDIO driver device state structure. + * cardinslot - true is a card has been detected in the slot; false if a + * card has been removed from the slot. Only transitions + * (inserted->removed or removed->inserted should be reported) + * + * Returned Values: + * None + * + ****************************************************************************/ + +void sdio_mediachange(struct sdio_dev_s *dev, bool cardinslot); + +/**************************************************************************** + * Name: sdio_wrprotect + * + * Description: + * Called by board-specific logic to report if the card in the slot is + * mechanically write protected. + * + * Input Parameters: + * dev - An instance of the SDIO driver device state structure. + * wrprotect - true is a card is writeprotected. + * + * Returned Values: + * None + * + ****************************************************************************/ + +void sdio_wrprotect(struct sdio_dev_s *dev, bool wrprotect); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_SDIO_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_sdio_dev.h b/arch/risc-v/src/mpfs/mpfs_sdio_dev.h new file mode 100644 index 0000000000000..688a6c462756d --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_sdio_dev.h @@ -0,0 +1,92 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_sdio_dev.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_MPFS_MPFS_SDIO_DEV_H +#define __ARCH_RISCV_SRC_MPFS_MPFS_SDIO_DEV_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This structure defines the state of the MPFS eMMCSD interface */ + +struct mpfs_dev_s +{ + struct sdio_dev_s dev; /* Standard, base SDIO interface */ + + const uintptr_t hw_base; /* Base address */ + const int plic_irq; /* PLIC interrupt */ + bool clk_enabled; /* Clk state */ + + /* eMMC / SD and HW parameters */ + + const bool emmc; /* eMMC or SD */ + int bus_voltage; /* Bus voltage */ + int bus_mode; /* eMMC Bus mode */ + bool jumpers_3v3; /* Jumper settings: 1v8 or 3v3 */ + + /* Event support */ + + sem_t waitsem; /* Implements event waiting */ + sdio_eventset_t waitevents; /* Set of events to be waited for */ + uint32_t waitmask; /* Interrupt enables for event waiting */ + volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */ + struct wdog_s waitwdog; /* Watchdog that handles event timeouts */ + + /* Callback support */ + + sdio_statset_t cdstatus; /* Card status */ + sdio_eventset_t cbevents; /* Set of events to be cause callbacks */ + worker_t callback; /* Registered callback function */ + void *cbarg; /* Registered callback argument */ + struct work_s cbwork; /* Callback work queue structure */ + + /* Interrupt mode data transfer support */ + + uint32_t *buffer; /* Address of current R/W buffer */ + size_t remaining; /* Number of bytes remaining in the transfer */ + size_t receivecnt; /* Real count to receive */ + uint32_t xfrmask; /* Interrupt enables for data transfer */ + uint32_t xfr_blkmask; /* Interrupt enables for SB/MB data transfer */ + + bool widebus; /* Required for DMA support */ + bool onebit; /* true: Only 1-bit transfers are supported */ + + /* DMA data transfer support */ + + bool polltransfer; /* Indicate a poll transfer, no DMA */ + bool multiblock; /* Indicate a multi-block transfer */ + + /* Misc */ + + uint32_t blocksize; /* Current block size */ + uint32_t fifo_depth; /* Fifo size, read from the register */ +}; + +#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_SDIO_DEV_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_serial.c b/arch/risc-v/src/mpfs/mpfs_serial.c index ec9ab908cf712..9064a1f060c4d 100644 --- a/arch/risc-v/src/mpfs/mpfs_serial.c +++ b/arch/risc-v/src/mpfs/mpfs_serial.c @@ -80,6 +80,15 @@ # elif defined(CONFIG_UART4_SERIAL_CONSOLE) # define CONSOLE_DEV g_uart4port /* UART4 is console */ # define SERIAL_CONSOLE 5 +# elif defined(CONFIG_UART5_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart5port /* UART5 is console */ +# define SERIAL_CONSOLE 6 +# elif defined(CONFIG_UART6_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart6port /* UART6 is console */ +# define SERIAL_CONSOLE 7 +# elif defined(CONFIG_UART7_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart7port /* UART7 is console */ +# define SERIAL_CONSOLE 8 # else # error "I'm confused... Do we have a serial console or not?" # endif @@ -90,6 +99,9 @@ # undef CONFIG_UART2_SERIAL_CONSOLE # undef CONFIG_UART3_SERIAL_CONSOLE # undef CONFIG_UART4_SERIAL_CONSOLE +# undef CONFIG_UART5_SERIAL_CONSOLE +# undef CONFIG_UART6_SERIAL_CONSOLE +# undef CONFIG_UART7_SERIAL_CONSOLE # if defined(CONFIG_MPFS_UART0) # define SERIAL_CONSOLE 1 # elif defined(CONFIG_MPFS_UART1) @@ -100,6 +112,12 @@ # define SERIAL_CONSOLE 4 # elif defined(CONFIG_MPFS_UART4) # define SERIAL_CONSOLE 5 +# elif defined(CONFIG_MPFS_UART5) +# define SERIAL_CONSOLE 6 +# elif defined(CONFIG_MPFS_UART6) +# define SERIAL_CONSOLE 7 +# elif defined(CONFIG_MPFS_UART7) +# define SERIAL_CONSOLE 8 # else # undef TTYS0_DEV # undef TTYS1_DEV @@ -127,6 +145,7 @@ struct up_dev_s uint8_t parity; /* 0=none, 1=odd, 2=even */ uint8_t bits; /* Number of bits (7 or 8) */ bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */ + bool fpga; /* true: this is an FPGA based driver */ }; /**************************************************************************** @@ -197,6 +216,22 @@ static char g_uart4rxbuffer[CONFIG_UART4_RXBUFSIZE]; static char g_uart4txbuffer[CONFIG_UART4_TXBUFSIZE]; #endif +#ifdef CONFIG_MPFS_UART5 +static char g_uart5rxbuffer[CONFIG_UART5_RXBUFSIZE]; +static char g_uart5txbuffer[CONFIG_UART5_TXBUFSIZE]; +#endif + +#ifdef CONFIG_MPFS_UART6 +static char g_uart6rxbuffer[CONFIG_UART6_RXBUFSIZE]; +static char g_uart6txbuffer[CONFIG_UART6_TXBUFSIZE]; +#endif + +#ifdef CONFIG_MPFS_UART7 +static char g_uart7rxbuffer[CONFIG_UART7_RXBUFSIZE]; +static char g_uart7txbuffer[CONFIG_UART7_TXBUFSIZE]; +#endif + +#ifndef CONFIG_MPFS_FPGA_UART #ifdef CONFIG_MPFS_UART0 static struct up_dev_s g_uart0priv = { @@ -206,6 +241,7 @@ static struct up_dev_s g_uart0priv = .parity = CONFIG_UART0_PARITY, .bits = CONFIG_UART0_BITS, .stopbits2 = CONFIG_UART0_2STOP, + .fpga = false, }; static uart_dev_t g_uart0port = @@ -237,6 +273,7 @@ static struct up_dev_s g_uart1priv = .parity = CONFIG_UART1_PARITY, .bits = CONFIG_UART1_BITS, .stopbits2 = CONFIG_UART1_2STOP, + .fpga = false, }; static uart_dev_t g_uart1port = @@ -268,6 +305,7 @@ static struct up_dev_s g_uart2priv = .parity = CONFIG_UART2_PARITY, .bits = CONFIG_UART2_BITS, .stopbits2 = CONFIG_UART2_2STOP, + .fpga = false, }; static uart_dev_t g_uart2port = @@ -299,6 +337,7 @@ static struct up_dev_s g_uart3priv = .parity = CONFIG_UART3_PARITY, .bits = CONFIG_UART3_BITS, .stopbits2 = CONFIG_UART3_2STOP, + .fpga = false, }; static uart_dev_t g_uart3port = @@ -330,6 +369,7 @@ static struct up_dev_s g_uart4priv = .parity = CONFIG_UART4_PARITY, .bits = CONFIG_UART4_BITS, .stopbits2 = CONFIG_UART4_2STOP, + .fpga = false, }; static uart_dev_t g_uart4port = @@ -352,6 +392,266 @@ static uart_dev_t g_uart4port = }; #endif +#else /* CONFIG_MPFS_FPGA_UART */ + +#ifdef CONFIG_MPFS_UART0 +static struct up_dev_s g_uart0priv = +{ + .uartbase = MPFS_FPGA_UART0_BASE, + .baud = CONFIG_UART0_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_12, + .parity = CONFIG_UART0_PARITY, + .bits = CONFIG_UART0_BITS, + .stopbits2 = CONFIG_UART0_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart0port = +{ +#if SERIAL_CONSOLE == 1 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART0_RXBUFSIZE, + .buffer = g_uart0rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART0_TXBUFSIZE, + .buffer = g_uart0txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart0priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART1 +static struct up_dev_s g_uart1priv = +{ + .uartbase = MPFS_FPGA_UART1_BASE, + .baud = CONFIG_UART1_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_13, + .parity = CONFIG_UART1_PARITY, + .bits = CONFIG_UART1_BITS, + .stopbits2 = CONFIG_UART1_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart1port = +{ +#if SERIAL_CONSOLE == 2 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART2 +static struct up_dev_s g_uart2priv = +{ + .uartbase = MPFS_FPGA_UART2_BASE, + .baud = CONFIG_UART2_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_14, + .parity = CONFIG_UART2_PARITY, + .bits = CONFIG_UART2_BITS, + .stopbits2 = CONFIG_UART2_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart2port = +{ +#if SERIAL_CONSOLE == 3 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART2_RXBUFSIZE, + .buffer = g_uart2rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART2_TXBUFSIZE, + .buffer = g_uart2txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart2priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART3 +static struct up_dev_s g_uart3priv = +{ + .uartbase = MPFS_FPGA_UART3_BASE, + .baud = CONFIG_UART3_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_15, + .parity = CONFIG_UART3_PARITY, + .bits = CONFIG_UART3_BITS, + .stopbits2 = CONFIG_UART3_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart3port = +{ +#if SERIAL_CONSOLE == 4 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART3_RXBUFSIZE, + .buffer = g_uart3rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART3_TXBUFSIZE, + .buffer = g_uart3txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart3priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART4 +static struct up_dev_s g_uart4priv = +{ + .uartbase = MPFS_FPGA_UART4_BASE, + .baud = CONFIG_UART4_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_16, + .parity = CONFIG_UART4_PARITY, + .bits = CONFIG_UART4_BITS, + .stopbits2 = CONFIG_UART4_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart4port = +{ +#if SERIAL_CONSOLE == 5 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART4_RXBUFSIZE, + .buffer = g_uart4rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART4_TXBUFSIZE, + .buffer = g_uart4txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart4priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART5 +static struct up_dev_s g_uart5priv = +{ + .uartbase = MPFS_FPGA_UART5_BASE, + .baud = CONFIG_UART5_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_17, + .parity = CONFIG_UART5_PARITY, + .bits = CONFIG_UART5_BITS, + .stopbits2 = CONFIG_UART5_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart5port = +{ +#if SERIAL_CONSOLE == 6 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART5_RXBUFSIZE, + .buffer = g_uart5rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART5_TXBUFSIZE, + .buffer = g_uart5txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart5priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART6 +static struct up_dev_s g_uart6priv = +{ + .uartbase = MPFS_FPGA_UART6_BASE, + .baud = CONFIG_UART6_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_18, + .parity = CONFIG_UART6_PARITY, + .bits = CONFIG_UART6_BITS, + .stopbits2 = CONFIG_UART6_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart6port = +{ +#if SERIAL_CONSOLE == 7 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART6_RXBUFSIZE, + .buffer = g_uart6rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART6_TXBUFSIZE, + .buffer = g_uart6txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart6priv, +}; +#endif + +#ifdef CONFIG_MPFS_UART7 +static struct up_dev_s g_uart7priv = +{ + .uartbase = MPFS_FPGA_UART7_BASE, + .baud = CONFIG_UART7_BAUD, + .irq = MPFS_IRQ_FABRIC_F2H_19, + .parity = CONFIG_UART7_PARITY, + .bits = CONFIG_UART7_BITS, + .stopbits2 = CONFIG_UART7_2STOP, + .fpga = true, +}; + +static uart_dev_t g_uart7port = +{ +#if SERIAL_CONSOLE == 7 + .isconsole = 1, +#endif + .recv = + { + .size = CONFIG_UART7_RXBUFSIZE, + .buffer = g_uart7rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART7_TXBUFSIZE, + .buffer = g_uart7txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart7priv, +}; +#endif + +#endif /* CONFIG_MPFS_FPGA_UART */ + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -447,34 +747,55 @@ static void up_enable_uart(struct up_dev_s *priv, bool enable) clock_bit = SYSREG_SUBBLK_CLOCK_CR_MMUART4; reset_bit = SYSREG_SOFT_RESET_CR_MMUART4; break; + case MPFS_FPGA_UART0_BASE: + case MPFS_FPGA_UART1_BASE: + case MPFS_FPGA_UART2_BASE: + case MPFS_FPGA_UART3_BASE: + case MPFS_FPGA_UART4_BASE: + case MPFS_FPGA_UART5_BASE: + case MPFS_FPGA_UART6_BASE: + case MPFS_FPGA_UART7_BASE: + clock_bit = SYSREG_SUBBLK_CLOCK_CR_FIC3; + reset_bit = SYSREG_SOFT_RESET_CR_FIC3 | SYSREG_SOFT_RESET_CR_FPGA; + break; default: return; } - /* reset on */ + /* reset on for non-fpga */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, - 0, reset_bit); + if (!priv->fpga) + { + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, + 0, reset_bit); + } if (enable) { /* reset off */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, - 0, reset_bit); + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, + reset_bit, 0); /* clock on */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SOFT_RESET_CR_OFFSET, - clock_bit, 0); + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, + 0, clock_bit); } else { - /* clock off */ + /* clock off for non-fpga */ - modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, - clock_bit, 0); + if (!priv->fpga) + { + /* Turning off FPGA clk would disable it for all other FPGA + * peripherals as well. Don't touch it without refcnt mechanism. + */ + + modifyreg32(MPFS_SYSREG_BASE + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET, + clock_bit, 0); + } } } @@ -494,7 +815,14 @@ static void up_config_baud_divisors(struct up_dev_s *priv, uint32_t baudrate) uint32_t fractional_baud_value; uint64_t pclk_freq; - pclk_freq = MPFS_MSS_APB_AHB_CLK; + if (!priv->fpga) + { + pclk_freq = MPFS_MSS_APB_AHB_CLK; + } + else + { + pclk_freq = MPFS_FPGA_PERIPHERAL_CLK; + } /* Compute baud value based on requested baud rate and PCLK frequency. * The baud value is computed using the following equation: @@ -1027,6 +1355,13 @@ static void up_send(struct uart_dev_s *dev, int ch) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; +#ifdef HAVE_SERIAL_CONSOLE + if (dev == &CONSOLE_DEV && !dev->isconsole) + { + return; + } +#endif + while ((up_serialin(priv, MPFS_UART_LSR_OFFSET) & UART_LSR_THRE) == 0); @@ -1140,6 +1475,18 @@ void riscv_earlyserialinit(void) up_disableuartint(g_uart4port.priv, NULL); #endif +#ifdef CONFIG_MPFS_UART5 + up_disableuartint(g_uart5port.priv, NULL); +#endif + +#ifdef CONFIG_MPFS_UART6 + up_disableuartint(g_uart6port.priv, NULL); +#endif + +#ifdef CONFIG_MPFS_UART7 + up_disableuartint(g_uart7port.priv, NULL); +#endif + /* Configuration whichever one is the console */ #ifdef HAVE_SERIAL_CONSOLE @@ -1183,6 +1530,15 @@ void riscv_serialinit(void) #ifdef CONFIG_MPFS_UART4 uart_register("/dev/ttyS4", &g_uart4port); #endif +#ifdef CONFIG_MPFS_UART5 + uart_register("/dev/ttyS5", &g_uart5port); +#endif +#ifdef CONFIG_MPFS_UART6 + uart_register("/dev/ttyS6", &g_uart6port); +#endif +#ifdef CONFIG_MPFS_UART7 + uart_register("/dev/ttyS7", &g_uart7port); +#endif } /**************************************************************************** @@ -1198,6 +1554,12 @@ int up_putc(int ch) #ifdef HAVE_SERIAL_CONSOLE struct up_dev_s *priv = (struct up_dev_s *)CONSOLE_DEV.priv; uint32_t ier; + + if (!CONSOLE_DEV.isconsole) + { + return ch; + } + up_disableuartint(priv, &ier); #endif diff --git a/arch/risc-v/src/mpfs/mpfs_tamper.c b/arch/risc-v/src/mpfs/mpfs_tamper.c new file mode 100644 index 0000000000000..4729854ac0283 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_tamper.c @@ -0,0 +1,396 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_tamper.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Register base-addresses */ + +#define MPFS_TAMPER_CTRL_BASE 0x4b00c000 +#define MPFS_TAMPER_TVS_BASE 0x4b00d000 + +/* CTRL Register offsets */ + +#define MPFS_SELECTED_EVENTS_OFFSET 0x00 +#define MPFS_STATUS_EVENTS_OFFSET 0x04 +#define MPFS_CLEAR_EVENTS_OFFSET 0x08 +#define MPFS_ENABLE_EVENTS_OFFSET 0x0c +#define MPFS_ENABLE_TVS_OFFSET 0x10 +#define MPFS_RESET_REASON_OFFSET 0x14 +#define MPFS_TAMPER_RESPONSE_OFFSET 0x18 + +/* Selected eventlist */ + +#define MPFS_SELECTED_EVENTS (MPFS_TAMPER_CTRL_BASE + \ + MPFS_SELECTED_EVENTS_OFFSET) + +#define FLAG_JTAG_ACTIVE (1 << 0) +#define FLAG_MESH_ERROR (1 << 1) +#define FLAG_CLOCK_MONITOR_GLITCH (1 << 2) +#define FLAG_CLOCK_MONITOR_FREQ (1 << 3) +#define FLAG_SECDED (1 << 4) +#define FLAG_SCB_BUS_ERROR (1 << 5) +#define FLAG_SC_WATCHDOG (1 << 6) +#define FLAG_LOCK_ERROR (1 << 7) +#define FLAG_DIGEST (1 << 8) +#define FLAG_INST_PASSCODE_FAIL (1 << 9) +#define FLAG_INST_KEY_VALIDATION_FAIL (1 << 10) +#define FLAG_INST_UNUSED (1 << 11) +#define FLAG_BITSTREAM_AUTHENTICATION_FAIL (1 << 12) +#define FLAG_DETECT_LOW_1P0 (1 << 13) +#define FLAG_DETECT_LOW_1P8 (1 << 14) +#define FLAG_DETECT_LOW_2P5 (1 << 15) +#define FLAG_DETECT_HIGH_1P0 (1 << 16) +#define FLAG_DETECT_HIGH_1P8 (1 << 17) +#define FLAG_DETECT_HIGH_2P5 (1 << 18) +#define FLAG_DETECT_TEMPERATURE_LOW (1 << 19) +#define FLAG_DETECT_TEMPERATURE_HIGH (1 << 20) + +#define FLAGS_ALL 0x1fffff +#define FLAG_BITS 21 + +/* Status eventlist */ + +#define MPFS_STATUS_EVENTS (MPFS_TAMPER_CTRL_BASE + \ + MPFS_STATUS_EVENTS_OFFSET) + +/* Clear eventlist */ + +#define MPFS_CLEAR_EVENTS (MPFS_TAMPER_CTRL_BASE + \ + MPFS_CLEAR_EVENTS_OFFSET) + +/* Enable eventlist */ + +#define MPFS_ENABLE_EVENTS (MPFS_TAMPER_CTRL_BASE + \ + MPFS_ENABLE_EVENTS_OFFSET) + +/* Enable TVS */ + +#define MPFS_ENABLE_TVS (MPFS_TAMPER_CTRL_BASE +\ + MPFS_ENABLE_TVS_OFFSET) + +#define MPFS_ENABLE_TVS_MONITORING (1 << 0) +#define MPFS_ENABLE_VOLTAGE_MONITORING (1 << 1) + +/* Reset reason */ + +#define MPFS_RESET_REASON (MPFS_TAMPER_CTRL_BASE + \ + MPFS_RESET_REASON_OFFSET) + +/* Clock and reset */ + +#define MPFS_SYSREG_SOFT_RESET_CR (MPFS_SYSREG_BASE + \ + MPFS_SYSREG_SOFT_RESET_CR_OFFSET) +#define MPFS_SYSREG_SUBBLK_CLOCK_CR (MPFS_SYSREG_BASE + \ + MPFS_SYSREG_SUBBLK_CLOCK_CR_OFFSET) + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +/* Mesh system defines */ + +#define MPFS_MESH_CR 0x200020b0 +#define MPFS_MESH_START (1 << 0) + +/* Debug output defines, info promoted to _err for visibility */ + +#ifdef CONFIG_DEBUG_ERROR +# define tinfo _err +#else +# define tinfo _none +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_tamper_event_string + * + * Description: + * Tamper event to string function + * + * Input Parameters: + * List of events + * + * Returned Value: + * Readable string + * + ****************************************************************************/ + +static const char *mpfs_tamper_event_string(uint32_t eventlist) +{ + int i; + + static const char *const names[] = + { + "JTAG ACTIVE", + "MESH ERROR", + "CLOCK MONITOR GLITCH", + "CLOCK MONITOR FREQ", + "SECDED", + "SCB BUS ERROR", + "SC WATCHDOG", + "LOCK ERROR", + "DIGEST", + "PASSCODE FAIL", + "KEY VALIDATION FAIL", + "INST UNUSED", + "BITSTREAM AUTH FAIL", + "LOW 1P0", + "LOW 1P8", + "LOW 2P5", + "HIGH 1P0", + "HIGH 1P8", + "HIGH 2P5", + "TEMPERATURE LOW", + "TEMPERATURE HIGH", + }; + + for (i = 0; i < ARRAY_SIZE(names); i++) + { + if ((1 << i) & eventlist) + { + break; + } + } + + if (i >= ARRAY_SIZE(names)) + { + return "UNDEFINED"; + } + + return names[i]; +} + +/**************************************************************************** + * Name: mpfs_tamper_interrupt + * + * Description: + * Tamper intinfoupt handler + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +static int mpfs_tamper_interrupt(int irq, void *context, void *arg) +{ + uint32_t eventlist; + uint32_t sel; + uint32_t status; + uint32_t clr; + uint32_t enabled; + uint32_t entvs; + int i; + + sel = getreg32(MPFS_SELECTED_EVENTS); + status = getreg32(MPFS_STATUS_EVENTS); + clr = getreg32(MPFS_CLEAR_EVENTS); + enabled = getreg32(MPFS_ENABLE_EVENTS); + entvs = getreg32(MPFS_ENABLE_TVS); + + eventlist = sel; + + if (eventlist) + { + tinfo("**********************************************************\n"); + tinfo("Tamper detection has caught out the following event(s):\n"); + for (i = 0; i < FLAG_BITS; i++) + { + if ((1 << i) & eventlist) + { + tinfo(" <%s>\n", mpfs_tamper_event_string(eventlist)); + eventlist &= ~(1 << i); + } + } + + tinfo("Regs: 0x00: 0x%x, 0x04: 0x%x, 0x08: 0x%x, 0x0c: 0x%x," + " 0x10: 0x%x\n", + sel, status, clr, enabled, entvs); + tinfo("**********************************************************\n"); + } + + putreg32(sel, MPFS_CLEAR_EVENTS); + + return 0; +} + +/**************************************************************************** + * Name: mpfs_tamper_tests + * + * Description: + * Various tamper tests for testing + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef TAMPER_TESTS +extern int mpfs_systemservice_init(); +extern int mpfs_sys_get_serial_number(uint8_t *out_sn, uint16_t mb_offset); +extern int mpfs_sys_query_security(uint8_t *out_security_resp, + uint16_t mb_offset); +extern int mpfs_sys_query_design_information(uint8_t *out_security_resp, + uint16_t mb_offset); +extern int mpfs_sys_query_device_certificate(uint8_t *out_security_resp, + uint16_t mb_offset); +extern uint16_t mpfs_sys_unlock_debug_passcode(uint8_t *cmd_data, + uint16_t mb_offset, + uint16_t resp_offset); +extern void test_ecdsa(void); + +static void mpfs_tamper_tests(void) +{ + uint8_t buf[1024 + 4]; + + mpfs_systemservice_init(); + + /* Some of the functions do not exist */ + + mpfs_sys_get_serial_number(buf, 0); + mpfs_sys_query_security(buf, 0); + mpfs_sys_query_design_information(buf, 0); + mpfs_sys_query_device_certificate(buf, 0); + mpfs_sys_unlock_debug_passcode(buf, 0, 0); + test_ecdsa(); + mpfs_sys_authenticate_iap_image(0); +} +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_tamper_enable + * + * Description: + * Enables the tamper service + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_tamper_enable(void) +{ + int ret; + + modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, + SYSREG_SOFT_RESET_CR_FPGA | SYSREG_SOFT_RESET_CR_FIC3, + 0); + + modifyreg32(MPFS_SYSREG_SUBBLK_CLOCK_CR, 0, + SYSREG_SUBBLK_CLOCK_CR_FIC3); + + tinfo("Enabling Tamper detection - if no FPGA support, will hang here\n"); + tinfo("Tamper reset reason 0x%x\n", getreg32(MPFS_RESET_REASON)); + + /* Enable events */ + + putreg32(FLAGS_ALL, MPFS_ENABLE_EVENTS); + putreg32(MPFS_ENABLE_TVS_MONITORING | MPFS_ENABLE_VOLTAGE_MONITORING, + MPFS_ENABLE_TVS); + + /* Start the mesh system */ + + modifyreg32(MPFS_MESH_CR, 0, MPFS_MESH_START); + + ret = irq_attach(MPFS_IRQ_FABRIC_F2H_10, mpfs_tamper_interrupt, NULL); + + if (ret == 0) + { + up_enable_irq(MPFS_IRQ_FABRIC_F2H_10); + } + else + { + tinfo("Tamper IRQ attach failed"); + } + +#ifdef TAMPER_TESTS + mpfs_tamper_tests(); +#endif +} + +/**************************************************************************** + * Name: mpfs_tamper_disable + * + * Description: + * Disables tamper service + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_tamper_disable(void) +{ + modifyreg32(MPFS_MESH_CR, MPFS_MESH_START, 0); + + up_disable_irq(MPFS_IRQ_FABRIC_F2H_10); + irq_detach(MPFS_IRQ_FABRIC_F2H_10); + + putreg32(0x00, MPFS_ENABLE_EVENTS); + putreg32(0, MPFS_ENABLE_TVS); +} diff --git a/arch/risc-v/src/mpfs/mpfs_tamper.h b/arch/risc-v/src/mpfs/mpfs_tamper.h new file mode 100644 index 0000000000000..800c4471d956a --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_tamper.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * arch/risc-v/src/mpfs/mpfs_tamper.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __ARCH_RISCV_SRC_MPFS_MPFS_TAMPER_H +#define __ARCH_RISCV_SRC_MPFS_MPFS_TAMPER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip.h" + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: mpfs_tamper_enable + * + * Description: + * Enables the tamper service + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_tamper_enable(void); + +/**************************************************************************** + * Name: mpfs_tamper_disable + * + * Description: + * Disables tamper service + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void mpfs_tamper_disable(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_TAMPER_H */ diff --git a/arch/risc-v/src/mpfs/mpfs_timerisr.c b/arch/risc-v/src/mpfs/mpfs_timerisr.c index 3a43fa278f18e..b8c635811fef9 100644 --- a/arch/risc-v/src/mpfs/mpfs_timerisr.c +++ b/arch/risc-v/src/mpfs/mpfs_timerisr.c @@ -24,7 +24,6 @@ #include -#include #include #include #include @@ -32,11 +31,8 @@ #include #include #include -#include -#include "hardware/mpfs_clint.h" #include "riscv_internal.h" -#include "riscv_mtimer.h" #include "mpfs.h" #include "mpfs_clockconfig.h" @@ -45,7 +41,81 @@ * Pre-processor Definitions ****************************************************************************/ -#define MTIMER_FREQ MPFS_MSS_RTC_TOGGLE_CLK +#define TICK_COUNT (MPFS_MSS_RTC_TOGGLE_CLK / TICK_PER_SEC) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifndef CONFIG_BUILD_KERNEL +static bool _b_tick_started; +static uint64_t *_mtime_cmp; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint64_t get_current(void) +{ +#ifndef CONFIG_BUILD_KERNEL + if (!_b_tick_started) + { + _b_tick_started = true; + return getreg64(MPFS_CLINT_MTIME); + } + else + { + return getreg64(_mtime_cmp); + } +#else + return riscv_sbi_get_time(); +#endif +} + +static void set_next(uint64_t next) +{ +#ifndef CONFIG_BUILD_KERNEL + putreg64(next, _mtime_cmp); +#else + riscv_sbi_set_timer(next); +#endif +} + +/**************************************************************************** + * Name: mpfs_reload_mtimecmp + ****************************************************************************/ + +static void mpfs_reload_mtimecmp(void) +{ + irqstate_t flags = spin_lock_irqsave(NULL); + + uint64_t current; + uint64_t next; + + current = get_current(); + uint64_t tick = TICK_COUNT; + next = current + tick; + + set_next(next); + + spin_unlock_irqrestore(NULL, flags); +} + +/**************************************************************************** + * Name: mpfs_timerisr + ****************************************************************************/ + +static int mpfs_timerisr(int irq, void *context, void *arg) +{ + mpfs_reload_mtimecmp(); + + /* Process timer interrupt */ + + nxsched_process_timer(); + + return 0; +} /**************************************************************************** * Public Functions @@ -62,15 +132,22 @@ void up_timer_initialize(void) { +#ifndef CONFIG_BUILD_KERNEL /* what is our timecmp address for this hart */ uintptr_t hart_id = riscv_mhartid(); + _mtime_cmp = (uint64_t *)MPFS_CLINT_MTIMECMP0 + hart_id; +#endif + + /* Attach timer interrupt handler */ + + irq_attach(RISCV_IRQ_TIMER, mpfs_timerisr, NULL); + + /* Reload CLINT mtimecmp */ - struct oneshot_lowerhalf_s *lower = riscv_mtimer_initialize( - MPFS_CLINT_MTIME, MPFS_CLINT_MTIMECMP0 + hart_id * sizeof(uintptr_t), - RISCV_IRQ_TIMER, MTIMER_FREQ); + mpfs_reload_mtimecmp(); - DEBUGASSERT(lower); + /* And enable the timer interrupt */ - up_alarm_set_lowerhalf(lower); + up_enable_irq(RISCV_IRQ_TIMER); } diff --git a/arch/risc-v/src/mpfs/mpfs_usb.c b/arch/risc-v/src/mpfs/mpfs_usb.c index fec9deb8fd823..3c6be8ade298f 100644 --- a/arch/risc-v/src/mpfs/mpfs_usb.c +++ b/arch/risc-v/src/mpfs/mpfs_usb.c @@ -124,10 +124,16 @@ # define MSB 1 #endif +#ifndef MPFS_USB_DMA_ADDR_UPPER_OFFSET +# define MPFS_USB_DMA_ADDR_UPPER_OFFSET 0x14u +#endif + #define MPFS_NUM_USB_PKT 1 #define MPFS_MIN_EP_FIFO_SIZE 8 #define MPFS_USB_REG_MAX 0x2000 +#define LINKDEAD_THRESHOLD 20 + /* Request queue operations *************************************************/ #define mpfs_rqempty(q) ((q)->head == NULL) @@ -224,6 +230,7 @@ static void mpfs_epset_reset(struct mpfs_usbdev_s *priv, uint16_t epset); static struct mpfs_usbdev_s g_usbd; static uint8_t g_clkrefs; +static bool g_linkdead; static const struct usbdev_epops_s g_epops = { @@ -767,11 +774,26 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv, if (nbytes > packetsize) { - ret = mpfs_write_tx_fifo(buf, packetsize, epno); - if (ret != OK) + if (privep->linkdead < LINKDEAD_THRESHOLD) { - privep->epstate = USB_EPSTATE_IDLE; - return ret; + ret = mpfs_write_tx_fifo(buf, packetsize, epno); + if (ret != OK) + { + privep->linkdead++; + privep->epstate = USB_EPSTATE_IDLE; + return ret; + } + else + { + privep->linkdead = 0; + } + } + else + { + /* We're in trouble, remote has likely closed */ + + g_linkdead = true; + return -EIO; } if (epno == EP0) @@ -792,11 +814,26 @@ static int mpfs_req_wrsetup(struct mpfs_usbdev_s *priv, } else { - ret = mpfs_write_tx_fifo(buf, nbytes, epno); - if (ret != OK) + if (privep->linkdead < LINKDEAD_THRESHOLD) { - privep->epstate = USB_EPSTATE_IDLE; - return ret; + ret = mpfs_write_tx_fifo(buf, nbytes, epno); + if (ret != OK) + { + privep->linkdead++; + privep->epstate = USB_EPSTATE_IDLE; + return ret; + } + else + { + privep->linkdead = 0; + } + } + else + { + /* We're in trouble, remote has likely closed */ + + g_linkdead = true; + return -EIO; } } @@ -2439,6 +2476,8 @@ static void mpfs_reset(struct mpfs_usbdev_s *priv) mpfs_req_cancel(privep, -ESHUTDOWN); + privep->linkdead = 0; + /* Reset endpoint status */ privep->stalled = false; @@ -3438,7 +3477,7 @@ static int mpfs_usb_interrupt(int irq, void *context, void *arg) if (pending_tx_ep != 0) { - for (i = 1; i < MPFS_USB_NENDPOINTS; i++) + for (i = 1; i < (MPFS_USB_NENDPOINTS / 2 + 1); i++) { if ((pending_tx_ep & (1 << i)) != 0) { @@ -3449,13 +3488,37 @@ static int mpfs_usb_interrupt(int irq, void *context, void *arg) if (pending_rx_ep != 0) { - for (i = 0; i < MPFS_USB_NENDPOINTS; i++) + for (i = 1; i < (MPFS_USB_NENDPOINTS / 2 + 1); i++) { + /* Check if dead connections are back in business */ + + if (g_linkdead) + { + /* This releases all tx counterparts with linkdead flag + * set, which is a problem if only some endpoints are + * closed on the remote; whereas some are functioning; + * for example ACM and mass storage; now the functioning + * one likely marks the closed ones as no longer dead. + * Please note that tx counterparts have MPFS_EPIN_START + * offset on top of the rx eps. + * + * For clarity, the eplist[] is as follows: + * eplist: 0: ep0, + * 1-4: ep1rx, ep2rx, ep3rx, ep4rx, + * 5-8: ep1tx, ep2tx, ep3tx, ep4tx + */ + + struct mpfs_ep_s *privep = &priv->eplist[i + MPFS_EPIN_START]; + privep->linkdead = 0; + } + if ((pending_rx_ep & (1 << i)) != 0) { mpfs_ep_rx_interrupt(priv, i); } } + + g_linkdead = false; } if ((isr & SUSPEND_IRQ_MASK) != 0) @@ -3613,7 +3676,7 @@ static void mpfs_usb_iomux(void) #ifdef CONFIG_USBDEV_DMA /* DMA operations need to open the USB PMP registers for proper - * operation. If not configured, apply default settings. + * operation. */ uint64_t pmpcfg_usb_x; @@ -3622,28 +3685,24 @@ static void mpfs_usb_iomux(void) if ((pmpcfg_usb_x & 0x1ffffff000000000llu) != 0x1f00000000000000llu) { uerr("Please check the MPFS_PMPCFG_USB_0 register.\n"); - putreg64(0x1f00000fffffffffllu, MPFS_PMPCFG_USB_0); } pmpcfg_usb_x = getreg64(MPFS_PMPCFG_USB_1); if ((pmpcfg_usb_x & 0x1ffffff000000000llu) != 0x1f00000000000000llu) { uerr("Please check the MPFS_PMPCFG_USB_1 register.\n"); - putreg64(0x1f00000fffffffffllu, MPFS_PMPCFG_USB_1); } pmpcfg_usb_x = getreg64(MPFS_PMPCFG_USB_2); if ((pmpcfg_usb_x & 0x1ffffff000000000llu) != 0x1f00000000000000llu) { uerr("Please check the MPFS_PMPCFG_USB_2 register.\n"); - putreg64(0x1f00000fffffffffllu, MPFS_PMPCFG_USB_2); } pmpcfg_usb_x = getreg64(MPFS_PMPCFG_USB_3); if ((pmpcfg_usb_x & 0x1ffffff000000000llu) != 0x1f00000000000000llu) { uerr("Please check the MPFS_PMPCFG_USB_3 register.\n"); - putreg64(0x1f00000fffffffffllu, MPFS_PMPCFG_USB_3); } #endif } @@ -3680,6 +3739,10 @@ static void mpfs_hw_setup(struct mpfs_usbdev_s *priv) modifyreg32(MPFS_SYSREG_SOFT_RESET_CR, SYSREG_SOFT_RESET_CR_USB | SYSREG_SOFT_RESET_CR_FPGA, 0); + /* Set USB upper address offset to enable USB DMA support for himen */ + + mpfs_putreg32(MPFS_USB_DMA_ADDR_UPPER_OFFSET, MPFS_USB_DMA_ADDR_UPPER_REG); + /* Reset the controller */ mpfs_putreg8(SOFT_RESET_REG_MASK, MPFS_USB_SOFT_RST); diff --git a/arch/risc-v/src/mpfs/mpfs_userspace.c b/arch/risc-v/src/mpfs/mpfs_userspace.c index a4409e2dcb088..7c13fd6a41ac3 100644 --- a/arch/risc-v/src/mpfs/mpfs_userspace.c +++ b/arch/risc-v/src/mpfs/mpfs_userspace.c @@ -31,6 +31,7 @@ #include #include +#include "hardware/mpfs_clint.h" #include "mpfs_userspace.h" #include "riscv_internal.h" @@ -53,7 +54,7 @@ #define PGT_L1_SIZE (512) /* Enough to map 512 GiB */ #define PGT_L2_SIZE (512) /* Enough to map 1 GiB */ -#define PGT_L3_SIZE (1024) /* Enough to map 4 MiB */ +#define PGT_L3_SIZE (2048) /* Enough to map 8 MiB */ #define SLAB_COUNT (sizeof(m_l3_pgtable) / RV_MMU_PAGE_SIZE) @@ -248,6 +249,11 @@ static void configure_mmu(void) map_region(UFLASH_START, UFLASH_START, UFLASH_SIZE, MMU_UTEXT_FLAGS); map_region(USRAM_START, USRAM_START, USRAM_SIZE, MMU_UDATA_FLAGS); + /* Map the MTIME counter to the start of USR IO region */ + + map_region(MPFS_CLINT_MTIME & (~RV_MMU_PAGE_MASK), USRIO_START, + RV_MMU_PAGE_SIZE, PTE_R | PTE_U | PTE_G); + /* Connect the L1 and L2 page tables */ mmu_ln_setentry(1, PGT_L1_VBASE, PGT_L2_PBASE, UFLASH_START, PTE_G); diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs index 4b0f37d1116be..c893e17a0a28f 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -44,9 +44,9 @@ SBI_DIR := opensbi OPENSBI_UNPACK = opensbi-3rdparty OPENSBI_COMMIT = fbaaafe808f3da7745760d757c436ef1b293d3ed -OPENSBI_URL = https://github.com/riscv-software-src/opensbi/tarball +OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = riscv-software-src-opensbi-fbaaafe +OPENSBI_DIR = tiiuae-opensbi-fbaaafe $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) diff --git a/boards/Kconfig b/boards/Kconfig index 720b6120678f7..7be086a526961 100644 --- a/boards/Kconfig +++ b/boards/Kconfig @@ -2115,6 +2115,14 @@ config ARCH_BOARD_IMX8QM_MEK This options selects support for NuttX on the NXP i.MX8 QuadMax CPUs MEK configure board with ARM Cortex-A53. +config ARCH_BOARD_IMX93_EVK + bool "NXP i.MX93 CPUs EVK board" + depends on ARCH_CHIP_IMX93 + select ARCH_HAVE_IRQBUTTONS + ---help--- + This options selects support for NuttX on the NXP i.MX93 CPUs EVK + board with ARM Cortex-A55. + config ARCH_BOARD_SAMA5D2_XULT bool "Atmel SAMA5D2 Xplained Ultra development board" depends on ARCH_CHIP_ATSAMA5D27 @@ -3284,6 +3292,7 @@ config ARCH_BOARD default "fvp-armv8r" if ARCH_BOARD_FVP_ARMV8R default "fvp-armv8r-aarch32" if ARCH_BOARD_FVP_ARMV8R_AARCH32 default "imx8qm-mek" if ARCH_BOARD_IMX8QM_MEK + default "imx93-evk" if ARCH_BOARD_IMX93_EVK default "sama5d2-xult" if ARCH_BOARD_SAMA5D2_XULT default "giant-board" if ARCH_BOARD_GIANT_BOARD default "jupiter-nano" if ARCH_BOARD_JUPITER_NANO @@ -3497,6 +3506,9 @@ endif if ARCH_BOARD_IMX8QM_MEK source "boards/arm64/imx8/imx8qm-mek/Kconfig" endif +if ARCH_BOARD_IMX93_EVK +source "boards/arm64/imx9/imx93-evk/Kconfig" +endif if ARCH_BOARD_IMXRT1020_EVK source "boards/arm/imxrt/imxrt1020-evk/Kconfig" endif diff --git a/boards/arm64/a64/pinephone/scripts/dramboot.ld b/boards/arm64/a64/pinephone/scripts/dramboot.ld index 15c82c9d32304..f5f515d4b819a 100644 --- a/boards/arm64/a64/pinephone/scripts/dramboot.ld +++ b/boards/arm64/a64/pinephone/scripts/dramboot.ld @@ -33,6 +33,7 @@ SECTIONS _start = .; .text : { _stext = .; /* Text section */ + *(.start .start.*) /* Place __start here */ *(.text) *(.text.cold) *(.text.unlikely) diff --git a/boards/arm64/fvp-v8r/fvp-armv8r/scripts/dramboot.ld b/boards/arm64/fvp-v8r/fvp-armv8r/scripts/dramboot.ld index ec2d6956c52ad..50d5ba78d41cd 100644 --- a/boards/arm64/fvp-v8r/fvp-armv8r/scripts/dramboot.ld +++ b/boards/arm64/fvp-v8r/fvp-armv8r/scripts/dramboot.ld @@ -33,6 +33,7 @@ SECTIONS _start = .; .text : { _stext = .; /* Text section */ + *(.start .start.*) /* Place __start here */ *(.text) *(.text.cold) *(.text.unlikely) diff --git a/boards/arm64/imx8/imx8qm-mek/scripts/dramboot.ld b/boards/arm64/imx8/imx8qm-mek/scripts/dramboot.ld index 160a5f8f86db7..24e385d9948b5 100644 --- a/boards/arm64/imx8/imx8qm-mek/scripts/dramboot.ld +++ b/boards/arm64/imx8/imx8qm-mek/scripts/dramboot.ld @@ -33,6 +33,7 @@ SECTIONS _start = .; .text : { _stext = .; /* Text section */ + *(.start .start.*) /* Place __start here */ *(.text) *(.text.cold) *(.text.unlikely) diff --git a/boards/arm64/imx9/imx93-evk/Kconfig b/boards/arm64/imx9/imx93-evk/Kconfig new file mode 100644 index 0000000000000..7a671a3a358df --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/Kconfig @@ -0,0 +1,7 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +if ARCH_BOARD_IMX9QM_MEK +endif diff --git a/boards/arm64/imx9/imx93-evk/configs/bootloader/defconfig b/boards/arm64/imx9/imx93-evk/configs/bootloader/defconfig new file mode 100644 index 0000000000000..95ff53b67c8c2 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/configs/bootloader/defconfig @@ -0,0 +1,64 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_STANDARD_SERIAL is not set +CONFIG_ARCH="arm64" +CONFIG_ARCH_ARM64=y +CONFIG_ARCH_ARM64_EXCEPTION_LEVEL=3 +CONFIG_ARCH_BOARD="imx93-evk" +CONFIG_ARCH_BOARD_IMX93_EVK=y +CONFIG_ARCH_CHIP="imx9" +CONFIG_ARCH_CHIP_IMX93=y +CONFIG_ARCH_CHIP_IMX9=y +CONFIG_ARCH_INTERRUPTSTACK=4096 +CONFIG_ARM64_DCACHE_DISABLE=y +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_TASK_STACKSIZE=8192 +CONFIG_DEV_ZERO=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_IDLETHREAD_STACKSIZE=8192 +CONFIG_IMX9_BOOTLOADER=y +CONFIG_IMX9_GPIO_IRQ=y +CONFIG_IMX9_LPUART1=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_LPUART1_SERIAL_CONSOLE=y +CONFIG_MM_FILL_ALLOCATIONS=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAMLOG=y +CONFIG_RAM_SIZE=548864 +CONFIG_RAM_START=0x2049a000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=192 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPWORKPRIORITY=50 +CONFIG_SPINLOCK=y +CONFIG_STACK_COLORATION=y +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2022 +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_SYSTEM=y +CONFIG_SYSTEM_TIME64=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y diff --git a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig new file mode 100644 index 0000000000000..e2810cc58124b --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig @@ -0,0 +1,112 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_MMCSD_HAVE_WRITEPROTECT is not set +# CONFIG_MMCSD_IOCSUPPORT is not set +# CONFIG_MMCSD_MMCSUPPORT is not set +# CONFIG_MMCSD_SPI is not set +CONFIG_ARCH="arm64" +CONFIG_ARCH_ARM64=y +CONFIG_ARCH_BOARD="imx93-evk" +CONFIG_ARCH_BOARD_IMX93_EVK=y +CONFIG_ARCH_CHIP="imx9" +CONFIG_ARCH_CHIP_IMX93=y +CONFIG_ARCH_CHIP_IMX9=y +CONFIG_ARCH_EARLY_PRINT=y +CONFIG_ARCH_INTERRUPTSTACK=4096 +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEFAULT_TASK_STACKSIZE=8192 +CONFIG_DEV_ZERO=y +CONFIG_ETH0_PHY_MULTI=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_TCPBLASTER=y +CONFIG_EXAMPLES_UDPBLASTER=y +CONFIG_EXPERIMENTAL=y +CONFIG_FAT_DMAMEMORY=y +CONFIG_FS_FAT=y +CONFIG_FS_FATTIME=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_GRAN=y +CONFIG_HAVE_CXX=y +CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_I2C=y +CONFIG_I2C_RESET=y +CONFIG_IDLETHREAD_STACKSIZE=8192 +CONFIG_IMX9_DMA_ALLOC=y +CONFIG_IMX9_DMA_ALLOC_POOL_SIZE=81920 +CONFIG_IMX9_EDMA=y +CONFIG_IMX9_ENET1_RGMII=y +CONFIG_IMX9_ENET=y +CONFIG_IMX9_ENET_USE_OTP_MAC=y +CONFIG_IMX9_FLEXIO1_PWM=y +CONFIG_IMX9_GPIO_IRQ=y +CONFIG_IMX9_LPI2C1=y +CONFIG_IMX9_LPI2C1_DMA=y +CONFIG_IMX9_LPI2C_DMA=y +CONFIG_IMX9_LPI2C_DYNTIMEO=y +CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP=10 +CONFIG_IMX9_LPSPI6=y +CONFIG_IMX9_LPSPI6_DMA=y +CONFIG_IMX9_LPSPI_DMA=y +CONFIG_IMX9_LPUART1=y +CONFIG_IMX9_TPM3_PWM=y +CONFIG_IMX9_TPM3_PWM_CHMUX=0x00000003 +CONFIG_IMX9_USBDEV_USBC1=y +CONFIG_IMX9_USDHC2=y +CONFIG_IMX9_USDHC2_INVERT_CD=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=y +CONFIG_LPUART1_SERIAL_CONSOLE=y +CONFIG_MMCSD=y +CONFIG_MMCSD_SDIO=y +CONFIG_NDEBUG=y +CONFIG_NET=y +CONFIG_NETDB_DNSCLIENT=y +CONFIG_NETDEV_PHY_IOCTL=y +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_TCP=y +CONFIG_NET_UDP=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FILEIOSIZE=512 +CONFIG_NSH_READLINE=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_PWM=y +CONFIG_PWM_NCHANNELS=4 +CONFIG_RAMLOG=y +CONFIG_RAM_SIZE=134217728 +CONFIG_RAM_START=0x80000000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_HPWORKPRIORITY=192 +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_LPWORKPRIORITY=50 +CONFIG_SDIO_BLOCKSETUP=y +CONFIG_SPI=y +CONFIG_SPINLOCK=y +CONFIG_STACK_COLORATION=y +CONFIG_START_MONTH=3 +CONFIG_START_YEAR=2022 +CONFIG_SYMTAB_ORDEREDBYNAME=y +CONFIG_SYSTEM_CDCACM=y +CONFIG_SYSTEM_I2CTOOL=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_PING=y +CONFIG_SYSTEM_SPITOOL=y +CONFIG_SYSTEM_SYSTEM=y +CONFIG_SYSTEM_TIME64=y +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y diff --git a/boards/arm64/imx9/imx93-evk/include/board.h b/boards/arm64/imx9/imx93-evk/include/board.h new file mode 100644 index 0000000000000..1d93aef9c7f2e --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/include/board.h @@ -0,0 +1,261 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/include/board.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM64_IMX9_IMX93_EVK_INCLUDE_BOARD_H +#define __BOARDS_ARM64_IMX9_IMX93_EVK_INCLUDE_BOARD_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Default PAD configurations */ + +#define IOMUX_LPI2C_DEFAULT (IOMUXC_PAD_OD_ENABLE | IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6) +#define IOMUX_LPSPI_DEFAULT (IOMUXC_PAD_PU_ON | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6) +#define IOMUX_GPIO_DEFAULT (IOMUXC_PAD_FSEL_SLOW | IOMUXC_PAD_DSE_X6) + +/* UART pin muxings */ + +#define MUX_LPUART1_RX IOMUX_CFG(IOMUXC_PAD_UART1_RXD_LPUART1_RX, 0, IOMUXC_MUX_SION_ON) +#define MUX_LPUART1_TX IOMUX_CFG(IOMUXC_PAD_UART1_TXD_LPUART1_TX, IOMUXC_PAD_FSEL_SLOW | IOMUXC_PAD_DSE_X4, 0) + +/* FLEXIO to PWM pin muxings */ + +/* EVK signals + * GPIO_IO04 -> FLEXIO1_04 + * GPIO_IO05 -> FLEXIO1_05 + * GPIO_IO06 -> FLEXIO1_06 + * GPIO_IO07 -> FLEXIO1_07 + */ + +#define FLEXIO1_PWM0_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO04_FLEXIO1_FLEXIO04, IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0) +#define FLEXIO1_PWM1_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO05_FLEXIO1_FLEXIO05, IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0) +#define FLEXIO1_PWM2_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO06_FLEXIO1_FLEXIO06, IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0) +#define FLEXIO1_PWM3_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO07_FLEXIO1_FLEXIO07, IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0) + +/* LPI2Cs */ + +/* TPM3 ch3 to PWM pin GPIO_IO24 muxing */ + +#define TPM3_PWM3_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO24_TPM3_CH3, IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0) + +/* LPI2Cs */ + +#define MUX_LPI2C1_SCL IOMUX_CFG(IOMUXC_PAD_I2C1_SCL_LPI2C1_SCL, IOMUX_LPI2C_DEFAULT, IOMUXC_MUX_SION_ON) +#define MUX_LPI2C1_SDA IOMUX_CFG(IOMUXC_PAD_I2C1_SDA_LPI2C1_SDA, IOMUX_LPI2C_DEFAULT, IOMUXC_MUX_SION_ON) + +/* I2C reset functionality */ + +#define GPIO_LPI2C1_SCL_RESET (GPIO_PORT1 | GPIO_PIN0 | GPIO_OUTPUT | GPIO_OUTPUT_ONE) +#define GPIO_LPI2C1_SDA_RESET (GPIO_PORT1 | GPIO_PIN1 | GPIO_OUTPUT | GPIO_OUTPUT_ONE) + +/* LPSPIs */ + +#define MUX_LPSPI3_SCK IOMUX_CFG(IOMUXC_PAD_GPIO_IO11_LPSPI3_SCK, IOMUX_LPSPI_DEFAULT, IOMUXC_MUX_SION_ON) +#define MUX_LPSPI3_MOSI IOMUX_CFG(IOMUXC_PAD_GPIO_IO10_LPSPI3_SOUT, IOMUX_LPSPI_DEFAULT, IOMUXC_MUX_SION_ON) +#define MUX_LPSPI3_MISO IOMUX_CFG(IOMUXC_PAD_GPIO_IO09_LPSPI3_SIN, IOMUX_LPSPI_DEFAULT, IOMUXC_MUX_SION_ON) +#define MUX_LPSPI6_SCK IOMUX_CFG(IOMUXC_PAD_GPIO_IO03_LPSPI6_SCK, IOMUX_LPSPI_DEFAULT, IOMUXC_MUX_SION_ON) +#define MUX_LPSPI6_MOSI IOMUX_CFG(IOMUXC_PAD_GPIO_IO02_LPSPI6_SOUT, IOMUX_LPSPI_DEFAULT, IOMUXC_MUX_SION_ON) +#define MUX_LPSPI6_MISO IOMUX_CFG(IOMUXC_PAD_GPIO_IO01_LPSPI6_SIN, IOMUX_LPSPI_DEFAULT, IOMUXC_MUX_SION_ON) + +/* SPI CS */ + +#define MUX_LPSPI3_CS IOMUX_CFG(IOMUXC_PAD_GPIO_IO08_GPIO2_IO08, IOMUX_GPIO_DEFAULT, IOMUXC_MUX_SION_ON) +#define GPIO_LPSPI3_CS (GPIO_PORT2 | GPIO_PIN8 | GPIO_OUTPUT | GPIO_OUTPUT_ONE) +#define MUX_LPSPI6_CS IOMUX_CFG(IOMUXC_PAD_GPIO_IO00_GPIO2_IO00, IOMUX_GPIO_DEFAULT, IOMUXC_MUX_SION_ON) +#define GPIO_LPSPI6_CS (GPIO_PORT2 | GPIO_PIN0 | GPIO_OUTPUT | GPIO_OUTPUT_ONE) + +/* USDHC */ + +/* Note: Need to set the SION for cmd and data pads (ERR052021) */ + +#define PIN_USDHC2_D0_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA0_USDHC2_DATA0, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON) +#define PIN_USDHC2_D1_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA1_USDHC2_DATA1, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON) +#define PIN_USDHC2_D2_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA2_USDHC2_DATA2, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON) +#define PIN_USDHC2_D3_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA3_USDHC2_DATA3, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON) +#define PIN_USDHC2_DCLK_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA1_USDHC2_DATA1, IOMUXC_PAD_DSE_X6 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PD_ON | IOMUXC_PAD_HYS_ST_ON, 0) +#define PIN_USDHC2_CMD_MUX IOMUX_CFG(IOMUXC_PAD_SD2_CMD_USDHC2_CMD, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON) +#define PIN_USDHC2_CD_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA3_USDHC2_DATA3, IOMUXC_PAD_DSE_X4 | IOMUXC_PAD_FSEL_FAST, 0) +#define PIN_USDHC2_VSELECT_MUX IOMUX_CFG(IOMUXC_PAD_SD2_VSELECT_USDHC2_VSELECT, IOMUXC_PAD_DSE_X5 | IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_PD_ON, 0) + +/* 390 KHz for initial inquiry stuff */ + +#define BOARD_USDHC_IDMODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV256 +#define BOARD_USDHC_IDMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(2) + +/* 25MHz for 1-bit wide bus */ + +#define BOARD_USDHC_MMCMODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8 +#define BOARD_USDHC_MMCMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1) + +#define BOARD_USDHC_SD1MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8 +#define BOARD_USDHC_SD1MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1) + +/* 50MHz for 4-bit wide bus */ + +#define BOARD_USDHC_SD4MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV4 +#define BOARD_USDHC_SD4MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1) + +/* Set the PLL clocks as follows: + * + * - OSC24M : 24 MHz + * - ARMPLL_OUT : 1692 MHz + * - DRAMPLL : 933 MHz + * - SYSPLL1 : 4000 MHz + * - SYSPLL_PFD0 : 1000 MHz + * - SYSPLL_PFD1 : 800 MHz + * - SYSPLL_PFD2 : 625 MHz + * - AUDIOPLL_OUT : OFF + * - VIDEOPLL_OUT : OFF + * + * After reset all clock sources (OSCPLL) and root clocks (CLOCK_ROOT) are + * running, but gated (LPCG). + * + * By default, all peripheral root clocks are set to the 24 MHz oscillator. + */ + +#define ARMPLL_CFG PLL_CFG(IMX9_ARMPLL_BASE, false, PLL_PARMS(1, 2, 141, 0, 0)) +#define DRAMPLL_CFG PLL_CFG(IMX9_DRAMPLL_BASE, true, PLL_PARMS(1, 2, 155, 1, 2)) + +#define PLL_CFGS \ + { \ + PLL_CFG(IMX9_SYSPLL_BASE, true, PLL_PARMS(1, 4, 166, 2, 3)), \ + } + +#define PFD_CFGS \ + { \ + PFD_CFG(IMX9_SYSPLL_BASE, 0, PFD_PARMS(4, 0, true)), \ + PFD_CFG(IMX9_SYSPLL_BASE, 1, PFD_PARMS(5, 0, true)), \ + PFD_CFG(IMX9_SYSPLL_BASE, 2, PFD_PARMS(6, 2, true)), \ + } + +/* Ethernet configuration */ + +#define BOARD_ENET1_PHY_LIST \ +{ \ + { \ + .name = GMII_RTL8211F_NAME, \ + .id1 = GMII_PHYID1_RTL8211F, \ + .id2 = GMII_PHYID2_RTL8211F, \ + .status = GMII_RTL8211F_PHYSR_A43, \ + .address_lo = 2, \ + .address_high = 0xffff, \ + .mbps10 = GMII_RTL8211F_PHYSR_10MBPS, \ + .mbps100 = GMII_RTL8211F_PHYSR_100MBPS, \ + .duplex = GMII_RTL8211F_PHYSR_DUPLEX, \ + .clause = 22, \ + .mbps1000 = GMII_RTL8211F_PHYSR_1000MBPS, \ + .speed_mask = GMII_RTL8211F_PHYSR_SPEED_MASK, \ + }, \ +} + +#endif /* CONFIG_IMX9_ENET1 */ + +#ifdef CONFIG_IMX9_ENET1 + +#define MUX_ENET1_MDIO IOMUX_CFG(IOMUXC_PAD_ENET2_MDIO_ENET1_MDIO, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, IOMUXC_MUX_SION_ON) +#define MUX_ENET1_MDC IOMUX_CFG(IOMUXC_PAD_ENET2_MDC_ENET1_MDC, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, 0) + +#define MUX_ENET1_RX_DATA00 IOMUX_CFG(IOMUXC_PAD_ENET2_RD0_ENET1_RGMII_RD0, 0, 0) +#define MUX_ENET1_RX_DATA01 IOMUX_CFG(IOMUXC_PAD_ENET2_RD1_ENET1_RGMII_RD1, 0, 0) + +#define MUX_ENET1_TX_DATA00 IOMUX_CFG(IOMUXC_PAD_ENET2_TD0_ENET1_RGMII_TD0, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, 0) +#define MUX_ENET1_TX_DATA01 IOMUX_CFG(IOMUXC_PAD_ENET2_TD1_ENET1_RGMII_TD1, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, 0) + +#if defined(CONFIG_IMX9_ENET1_RGMII) + +# define MUX_ENET1_RX_DATA02 IOMUX_CFG(IOMUXC_PAD_ENET2_RD2_ENET1_RGMII_RD2, 0, 0) +# define MUX_ENET1_RX_DATA03 IOMUX_CFG(IOMUXC_PAD_ENET2_RD3_ENET1_RGMII_RD3, 0, 0) +# define MUX_ENET1_TX_DATA02 IOMUX_CFG(IOMUXC_PAD_ENET2_TD2_ENET1_RGMII_TD2, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, 0) +# define MUX_ENET1_TX_DATA03 IOMUX_CFG(IOMUXC_PAD_ENET2_TD3_ENET1_RGMII_TD3, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, 0) +# define MUX_ENET1_RXC IOMUX_CFG(IOMUXC_PAD_ENET2_RXC_ENET1_RGMII_RXC, 0, 0) +# define MUX_ENET1_TX_CTL IOMUX_CFG(IOMUXC_PAD_ENET2_TX_CTL_ENET1_RGMII_TX_CTL, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, 0) +# define MUX_ENET1_RX_CTL IOMUX_CFG(IOMUXC_PAD_ENET2_RX_CTL_ENET1_RGMII_RX_CTL, 0, 0) + +#elif defined(CONFIG_IMX9_ENET1_RMII) + +/* Same pin as TX_CTL for RGMII */ + +# define MUX_ENET1_TX_EN IOMUX_CFG(IOMUXC_PAD_ENET2_TX_CTL_ENET1_RGMII_TX_CTL, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, 0) + +/* Same pin as TX_DATA02 for RGMII */ + +# define MUX_ENET1_REF_CLK IOMUX_CFG(IOMUXC_PAD_ENET2_TD2_ENET1_RGMII_TD2, IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_DSE_X6, 0) + +/* Same pin as RX_CTL for RGMII */ + +# define MUX_ENET1_CRS_DV IOMUX_CFG(IOMUXC_PAD_ENET2_RX_CTL_ENET1_RGMII_RX_CTL, 0, 0) + +#else +#error ENET1 supports only RMII and RGMII +#endif + +#define BOARD_ENET1_PHY_LIST \ +{ \ + { \ + GMII_RTL8211F_NAME, \ + GMII_PHYID1_RTL8211F, \ + GMII_PHYID2_RTL8211F, \ + GMII_RTL8211F_PHYSR_A43, \ + 2, \ + 0xffff, \ + GMII_RTL8211F_PHYSR_10MBPS, \ + GMII_RTL8211F_PHYSR_100MBPS, \ + GMII_RTL8211F_PHYSR_DUPLEX, \ + 22, \ + GMII_RTL8211F_PHYSR_1000MBPS, \ + GMII_RTL8211F_PHYSR_SPEED_MASK, \ + }, \ +} + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM64_IMX9_IMX93_EVK_INCLUDE_BOARD_H */ diff --git a/boards/arm64/imx9/imx93-evk/include/board_memorymap.h b/boards/arm64/imx9/imx93-evk/include/board_memorymap.h new file mode 100644 index 0000000000000..07649afbc5df5 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/include/board_memorymap.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/include/board_memorymap.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM64_IMX9_IMX93_EVK_INCLUDE_BOARD_MEMORYMAP_H +#define __BOARDS_ARM64_IMX9_IMX93_EVK_INCLUDE_BOARD_MEMORYMAP_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM64_IMX9_IMX93_EVK_INCLUDE_BOARD_MEMORYMAP_H */ diff --git a/boards/arm64/imx9/imx93-evk/scripts/Make.defs b/boards/arm64/imx9/imx93-evk/scripts/Make.defs new file mode 100644 index 0000000000000..670686a3eb831 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/scripts/Make.defs @@ -0,0 +1,53 @@ +############################################################################ +# boards/arm64/imx9/imx93-evk/scripts/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/.config +include $(TOPDIR)/tools/Config.mk +include $(TOPDIR)/tools/imx9/Config.mk +include $(TOPDIR)/arch/arm64/src/Toolchain.defs + +ifeq ($(CONFIG_IMX9_BOOTLOADER),y) + LDSCRIPT = ocramboot.ld +else + LDSCRIPT = dramboot.ld +endif + +ARCHSCRIPT += $(BOARD_DIR)$(DELIM)scripts$(DELIM)$(LDSCRIPT) + +CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe +CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) +CXXFLAGS := $(ARCHCXXFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) $(ARCHXXINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) -pipe +CXXPICFLAGS = $(ARCHPICFLAGS) $(CXXFLAGS) +CPPFLAGS := $(ARCHINCLUDES) $(ARCHDEFINES) $(EXTRAFLAGS) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ + +# NXFLAT module definitions + +NXFLATLDFLAGS1 = -r -d -warn-common +NXFLATLDFLAGS2 = $(NXFLATLDFLAGS1) -T$(TOPDIR)$(DELIM)binfmt$(DELIM)libnxflat$(DELIM)gnu-nxflat-pcrel.ld -no-check-sections +LDNXFLATFLAGS = -e main -s 2048 + +# ELF module definitions + +CELFFLAGS = $(CFLAGS) -mlong-calls # --target1-abs +CXXELFFLAGS = $(CXXFLAGS) -mlong-calls # --target1-abs + +LDELFFLAGS = -r -e main +LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)/binfmt/libelf/gnu-elf.ld) diff --git a/boards/arm64/imx9/imx93-evk/scripts/dramboot.ld b/boards/arm64/imx9/imx93-evk/scripts/dramboot.ld new file mode 100644 index 0000000000000..f437d8d13745a --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/scripts/dramboot.ld @@ -0,0 +1,157 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/scripts/dramboot.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +OUTPUT_ARCH(aarch64) + +ENTRY(__start) +EXTERN(__start) + +/* Memory is organized as follows: + * - Uboot reserved area is 0x00000000 - 0x00a00000 + * - NuttX is loaded to 0x80000000, u-boot expects us here + * - NuttX ROM and RAM are one continuous region, starting from 0x80000000 + with a size of 128MB + * - Heap memory is allocated from dram end to idlestack top + */ + +MEMORY +{ + dram (rwx) : ORIGIN = 0x80000000, LENGTH = 128M +} + +PHDRS +{ + /* R = 100, W = 010, X = 001 */ + + text PT_LOAD FLAGS(5); /* RX */ + rodata PT_LOAD FLAGS(4); /* R */ + data PT_LOAD FLAGS(6); /* RW */ +} + +SECTIONS +{ + .text : + { + _stext = ABSOLUTE(.); /* Text section */ + *(.start .start.*) /* Place __start here */ + *(.text .text.*) + *(.text.cold) + *(.text.unlikely) + *(.fixup) + *(.gnu.warning) + } > dram :text + + .init_section : + { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array .ctors)) + _einit = ABSOLUTE(.); + } > dram :text + + /* Vector table must be page aligned */ + + .vector : ALIGN(4096) + { + _vector_start = ABSOLUTE(.); + KEEP(*(.exc_vector_table)) + KEEP(*(".exc_vector_table.*")) + KEEP(*(.vectors)) + _vector_end = ABSOLUTE(.); + } > dram :text + + /* End of text data must be aligned to page boundary */ + + . = ALIGN(4096); + _etext = .; + _sztext = _etext - _stext; + + /* Start of RO data must be page aligned (mapped as read only) */ + + .rodata : ALIGN(4096) + { + _srodata = ABSOLUTE(.); /* Read-only data */ + *(.rodata .rodata.*) + *(.data.rel.ro) + *(.data.rel.ro.*) + } > dram :rodata + + /* End of RO data must be page aligned */ + + . = ALIGN(4096); + + _erodata = .; /* End of read-only data */ + _szrodata = _erodata - _srodata; + _eronly = .; /* End of read-only data */ + + .data : ALIGN(4096) + { + _sdata = ABSOLUTE(.); + *(.data.page_aligned) + *(.data .data.*) + . = ALIGN(8); + *(.data.rel) + *(.data.rel.*) + CONSTRUCTORS + . = ALIGN(8); + _edata = ABSOLUTE(.); + } > dram :data + + .bss : + { + . = ALIGN(8); + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + . = ALIGN(8); + _ebss = ABSOLUTE(.); + } > dram :data + + _szbss = _ebss - _sbss; + + .initstack : + { + _s_initstack = ABSOLUTE(.); + *(.initstack) + } > dram :data + + /* End of data must be page aligned */ + . = ALIGN(4096); + + g_idle_topstack = .; + _e_initstack = .; + _szdata = _e_initstack - _sdata; + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + *(.eh_frame) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff --git a/boards/arm64/imx9/imx93-evk/scripts/imx93_ca55.JLinkScript b/boards/arm64/imx9/imx93-evk/scripts/imx93_ca55.JLinkScript new file mode 100644 index 0000000000000..483fc7005f202 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/scripts/imx93_ca55.JLinkScript @@ -0,0 +1,58 @@ +/* Adds custom i.MX93 logic to replace default procedures from JLink */ + +int ResetTarget(void) { + + JLINK_SYS_Report("-- Resetting target device..."); + + JLINK_TIF_ActivateTargetReset(); + JLINK_Delay_us(50000); // _Delay_us: Keep reset active for some time so possible glitch filters on target do not filter out reset pulse + JLINK_TIF_ReleaseTargetReset(); + + // + // This device requires a special reset as default reset does not work for this device. + // + JLINK_TARGET_Halt(); // Make sure that the CPU is halted when reset is called + + return 0; +} + +void ConfigTargetSettings(void) { + // JLINK_SYS_Report("J-Link script: Manually configuring JTAG chain"); + + // AP[0]: AHB-AP (IDR: 0x74770001) + // AP[1]: APB-AP (IDR: 0x44770002) + + JLINK_ExecCommand("CORESIGHT_AddAP Index=0 Type=AHB-AP"); // Connects to System Bus + JLINK_ExecCommand("CORESIGHT_AddAP Index=1 Type=APB-AP"); // Connects to CoreSight/A-core Platform (see APBIC) + JLINK_ExecCommand("CORESIGHT_AddAP Index=3 Type=DAP-AP"); // Connects to a Cortex-M33 + JLINK_ExecCommand("CORESIGHT_AddAP Index=4 Type=DAP-AP"); // Connects to a EdgeLock (Risc-V) + JLINK_ExecCommand("CORESIGHT_AddAP Index=6 Type=MDM-AP"); // Connects to a MDM + + // A55_0 + JLINK_ExecCommand("CORESIGHT_SetCoreBaseAddr = 0x40810000"); // Location in AP address space where debug registers of core are located + JLINK_ExecCommand("CORESIGHT_SetCSCTICoreBaseAddr = 0x40820000"); // Location in AP address space where CTI that connects to the core is located + + // A55_1 + //JLINK_ExecCommand("CORESIGHT_SetCoreBaseAddr = 0x40910000"); // Location in AP address space where debug registers of core are located + //JLINK_ExecCommand("CORESIGHT_SetCSCTICoreBaseAddr = 0x40920000"); // Location in AP address space where CTI that connects to the core is located + + // There is also a debug core at SetCoreBaseAddr = 0x40840000, but don't know what it is + + JTAG_AllowTAPReset = 1; // J-Link is allowed to use a TAP reset for JTAG-chain auto-detection + + JLINK_JTAG_IRPre = 0; // Sum of IRLen of all JTAG TAPs preceding the one we want to communicate with + JLINK_JTAG_DRPre = 0; // Number of JTAG TAPs preceding the one we want to communicate with + JLINK_JTAG_IRPost = 0; // Sum of IRLen of all JTAG TAPs following the one we want to communicate with + JLINK_JTAG_DRPost = 0; // Number of JTAG TAPs following the one we want to communicate with + JLINK_JTAG_IRLen = 4; // IRLen of device we want to communicate with + + JLINK_JTAG_SetDeviceId(0, 0x6BA00477); + + // For Cortex-A55: + JLINK_ExecCommand("CORESIGHT_SetIndexAPBAPToUse = 1"); + // For Cortex-M33: + // JLINK_ExecCommand("CORESIGHT_SetIndexAPBAPToUse = 3"); + + return 0; +} + diff --git a/boards/arm64/imx9/imx93-evk/scripts/ocramboot.ld b/boards/arm64/imx9/imx93-evk/scripts/ocramboot.ld new file mode 100644 index 0000000000000..6dd6c38684be2 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/scripts/ocramboot.ld @@ -0,0 +1,150 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/scripts/ocramboot.ld + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +OUTPUT_ARCH(aarch64) + +ENTRY(__start) +EXTERN(__start) + +/* Memory is organized as follows: + * - ahab reserves memory from 2048k to 0x2049a000 + * - NuttX is compiled into 0x2049a000, ahab expects NuttX here + * - Heap memory is allocated from ocram end to idlestack top + */ + +MEMORY +{ + ocram (rx) : ORIGIN = 0x2049a000, LENGTH = 0x37ff0 + ocram_data (rw) : ORIGIN = 0x204e0000, LENGTH = 0x2000 + ocram_noload (rw) : ORIGIN = 0x204f0000, LENGTH = 0x30000 +} + +PHDRS +{ + /* R = 100, W = 010, X = 001 */ + + text PT_LOAD FLAGS(5); /* RX */ + rodata PT_LOAD FLAGS(4); /* R */ + data PT_LOAD FLAGS(6); /* RW */ +} + +SECTIONS +{ + .text : + { + _stext = ABSOLUTE(.); /* Text section */ + *(.start .start.*) /* Place __start here */ + *(.text .text.*) + *(.text.cold) + *(.text.unlikely) + *(.fixup) + *(.gnu.warning) + } > ocram :text + + .init_section : + { + _sinit = ABSOLUTE(.); + KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP(*(.init_array .ctors)) + _einit = ABSOLUTE(.); + } > ocram :text + + /* Vector table must be page aligned */ + + .vector : ALIGN(4096) + { + _vector_start = ABSOLUTE(.); + KEEP(*(.exc_vector_table)) + KEEP(*(".exc_vector_table.*")) + KEEP(*(.vectors)) + _vector_end = ABSOLUTE(.); + } > ocram :text + + _etext = .; + + .rodata : ALIGN(4096) + { + _srodata = ABSOLUTE(.); /* Read-only data */ + *(.rodata .rodata.*) + *(.data.rel.ro) + *(.data.rel.ro.*) + } > ocram :rodata + + _erodata = .; /* End of read-only data */ + _eronly = .; /* End of read-only data */ + + .data : ALIGN(4096) + { + _sdata = ABSOLUTE(.); + *(.data.page_aligned) + *(.data .data.*) + . = ALIGN(8); + *(.data.rel) + *(.data.rel.*) + CONSTRUCTORS + . = ALIGN(8); + _edata = ABSOLUTE(.); + } > ocram_data :data + + .bss (NOLOAD) : + { + . = ALIGN(8); + _sbss = ABSOLUTE(.); + *(.bss .bss.*) + . = ALIGN(8); + _ebss = ABSOLUTE(.); + } > ocram_noload :data + + .initstack : + { + _s_initstack = ABSOLUTE(.); + *(.initstack) + } > ocram_noload :data + + /* End of data must be page aligned */ + + . = ALIGN(4096); + + g_idle_topstack = .; + _e_initstack = .; + + _sztext = _srodata - _stext; /* _erodata is aligned, after _etext */ + _szrodata = _sdata - _srodata; /* _sdata is aligned, after _erodata */ + + /* Sections to be discarded */ + /DISCARD/ : { + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + *(.eh_frame) + } + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} + +_heapend = ORIGIN(ocram_noload) + LENGTH(ocram_noload); +_szdata = _heapend - _sdata; diff --git a/boards/arm64/imx9/imx93-evk/src/Makefile b/boards/arm64/imx9/imx93-evk/src/Makefile new file mode 100644 index 0000000000000..6a9b3eebfa594 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/Makefile @@ -0,0 +1,45 @@ +############################################################################ +# boards/arm64/imx9/imx93-evk/src/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(TOPDIR)/Make.defs + +CSRCS = imx9_boardinit.c imx9_bringup.c + +ifeq ($(CONFIG_BOARDCTL),y) +CSRCS += imx9_appinit.c +endif + +ifeq ($(CONFIG_PWM),y) +CSRCS += imx9_pwm.c +endif + +ifeq ($(CONFIG_IMX9_LPI2C),y) +CSRCS += imx9_i2c.c +endif + +ifeq ($(CONFIG_IMX9_LPSPI),y) +CSRCS += imx9_spi.c +endif + +ifeq ($(CONFIG_IMX9_USDHC),y) +CSRCS += imx9_usdhc.c +endif + +include $(TOPDIR)/boards/Board.mk diff --git a/boards/arm64/imx9/imx93-evk/src/imx93-evk.h b/boards/arm64/imx9/imx93-evk/src/imx93-evk.h new file mode 100644 index 0000000000000..f8125289f4571 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx93-evk.h @@ -0,0 +1,125 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/src/imx93-evk.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H +#define __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Checking needed by MMC/SDCard */ + +#ifdef CONFIG_NSH_MMCSDSLOTNO +# define SDIO_SLOTNO CONFIG_NSH_MMCSDSLOTNO +#else +# define SDIO_SLOTNO 0 +#endif + +#ifdef CONFIG_NSH_MMCSDMINOR +# define SDIO_MINOR CONFIG_NSH_MMCSDMINOR +#else +# define SDIO_MINOR 0 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Functions Definitions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_bringup + * + * Description: + * Bring up board features + * + ****************************************************************************/ + +#if defined(CONFIG_BOARDCTL) || defined(CONFIG_BOARD_LATE_INITIALIZE) +int imx9_bringup(void); +#endif + +/**************************************************************************** + * Name: imx9_pwm_setup + * + * Description: + * Initialize PWM outputs + * + ****************************************************************************/ + +#if defined(CONFIG_PWM) +int imx9_pwm_setup(void); +#endif + +/**************************************************************************** + * Name: imx9_i2c_setup + * + * Description: + * Initialize I2C devices and driver + * + ****************************************************************************/ + +#if defined(CONFIG_I2C_DRIVER) +int imx9_i2c_initialize(void); +#endif + +/**************************************************************************** + * Name: imx9_spi_setup + * + * Description: + * Initialize SPI devices and driver + * + ****************************************************************************/ + +#if defined(CONFIG_SPI_DRIVER) +int imx9_spi_initialize(void); +#endif + +/**************************************************************************** + * Name: imx9_usdhc_init + * + * Description: + * Initialize uSDHC driver + * + ****************************************************************************/ + +#if defined(CONFIG_MMCSD) +int imx9_usdhc_init(void); +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H */ diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_appinit.c b/boards/arm64/imx9/imx93-evk/src/imx9_appinit.c new file mode 100644 index 0000000000000..289395145ce57 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_appinit.c @@ -0,0 +1,76 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/src/imx9_appinit.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +#include "imx93-evk.h" + +#ifdef CONFIG_BOARDCTL + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_app_initialize + * + * Description: + * Perform application specific initialization. This function is never + * called directly from application code, but only indirectly via the + * (non-standard) boardctl() interface using the command BOARDIOC_INIT. + * + * Input Parameters: + * arg - The boardctl() argument is passed to the board_app_initialize() + * implementation without modification. The argument has no + * meaning to NuttX; the meaning of the argument is a contract + * between the board-specific initialization logic and the + * matching application logic. The value could be such things as a + * mode enumeration value, a set of DIP switch switch settings, a + * pointer to configuration data read from a file or serial FLASH, + * or whatever you would like to do with it. Every implementation + * should accept zero/NULL as a default configuration. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure to indicate the nature of the failure. + * + ****************************************************************************/ + +int board_app_initialize(uintptr_t arg) +{ + UNUSED(arg); +#ifndef CONFIG_BOARD_LATE_INITIALIZE + /* Perform board initialization */ + + return imx9_bringup(); +#else + return OK; +#endif +} + +#endif /* CONFIG_BOARDCTL */ diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c b/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c new file mode 100644 index 0000000000000..876b9014de6f0 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include + +#include "imx93-evk.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_memory_initialize + * + * Description: + * All i.MX8 architectures must provide the following entry point. This + * entry point is called early in the initialization before memory has + * been configured. This board-specific function is responsible for + * configuring any on-board memories. + * + * Logic in imx9_memory_initialize must be careful to avoid using any + * global variables because those will be uninitialized at the time this + * function is called. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imx9_memory_initialize(void) +{ + /* SDRAM was initialized by a bootloader in the supported configurations. */ +} + +/**************************************************************************** + * Name: imx9_board_initialize + * + * Description: + * All i.MX8 architectures must provide the following entry point. This + * entry point is called in the initialization phase -- after + * imx_memory_initialize and after all memory has been configured and + * mapped but before any devices have been initialized. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imx9_board_initialize(void) +{ +#ifdef CONFIG_ARCH_LEDS + /* Configure on-board LEDs if LED support has been selected. */ + +#endif +} + +/**************************************************************************** + * Name: board_late_initialize + * + * Description: + * If CONFIG_BOARD_LATE_INITIALIZE is selected, then an additional + * initialization call will be performed in the boot-up sequence to a + * function called board_late_initialize(). board_late_initialize() will be + * called immediately after up_intitialize() is called and just before the + * initial application is started. This additional initialization phase + * may be used, for example, to initialize board-specific device drivers. + * + ****************************************************************************/ + +#ifdef CONFIG_BOARD_LATE_INITIALIZE +void board_late_initialize(void) +{ + /* Perform board initialization */ + + imx9_bringup(); +} +#endif /* CONFIG_BOARD_LATE_INITIALIZE */ diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c new file mode 100644 index 0000000000000..57d2887c98cab --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c @@ -0,0 +1,113 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/src/imx9_bringup.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#include "imx9_dma_alloc.h" + +#include "imx93-evk.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx_bringup + * + * Description: + * Bring up board features + * + ****************************************************************************/ + +int imx9_bringup(void) +{ + int ret; + +#ifdef CONFIG_FS_PROCFS + /* Mount the procfs file system */ + + ret = nx_mount(NULL, "/proc", "procfs", 0, NULL); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed to mount procfs at /proc: %d\n", ret); + } +#endif + +#ifdef CONFIG_IMX9_DMA_ALLOC + /* Initialize the DMA memory allocator */ + + ret = imx9_dma_alloc_init(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed initialize DMA allocator: %d\n", ret); + } +#endif + +#ifdef CONFIG_PWM + /* Configure PWM outputs */ + + ret = imx9_pwm_setup(); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: Failed initialize PWM outputs: %d\n", ret); + } +#endif + +#if defined(CONFIG_I2C_DRIVER) + /* Configure I2C peripheral interfaces */ + + ret = imx9_i2c_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize I2C driver: %d\n", ret); + } +#endif + +#if defined(CONFIG_SPI_DRIVER) + /* Configure SPI peripheral interfaces */ + + ret = imx9_spi_initialize(); + if (ret < 0) + { + syslog(LOG_ERR, "Failed to initialize SPI driver: %d\n", ret); + } +#endif + +#ifdef CONFIG_MMCSD + ret = imx9_usdhc_init(); + + if (ret < 0) + { + syslog(LOG_ERR, "Failed to init MMCSD driver: %d\n", ret); + } +#endif + + UNUSED(ret); + return OK; +} diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_i2c.c b/boards/arm64/imx9/imx93-evk/src/imx9_i2c.c new file mode 100644 index 0000000000000..ac30b5da2d0fc --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_i2c.c @@ -0,0 +1,77 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/src/imx9_i2c.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include + +#include "imx9_lpi2c.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_i2c_init + * + * Description: + * Configure the I2C driver. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int imx9_i2c_initialize(void) +{ + int ret = OK; + +#ifdef CONFIG_IMX9_LPI2C1 + struct i2c_master_s *i2c; + + i2c = imx9_i2cbus_initialize(1); + if (i2c == NULL) + { + i2cerr("ERROR: Failed to init I2C0 interface\n"); + return -ENODEV; + } +#endif + +#ifdef CONFIG_I2C_DRIVER + ret = i2c_register(i2c, 0); + if (ret < 0) + { + i2cerr("ERROR: Failed to register I2C0 driver: %d\n", ret); + imx9_i2cbus_uninitialize(i2c); + return ret; + } +#endif + + return OK; +} diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c b/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c new file mode 100644 index 0000000000000..494331617ad81 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/src/imx9_pwm.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include + +#include "imx9_flexio_pwm.h" +#include "imx9_tpm_pwm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_pwm_setup + * + * Description: + * + * Initialize PWM and register PWM devices + * + * Input Parameters: + * None + * + * Returned Value: + * 0 on success, negated error value on error + * + ****************************************************************************/ + +int imx9_pwm_setup(void) +{ + struct pwm_lowerhalf_s *lower_half = NULL; + int ret = 0; + +#ifdef CONFIG_IMX9_FLEXIO1_PWM + lower_half = imx9_flexio_pwm_init(PWM_FLEXIO1); + + if (lower_half) + { + ret = pwm_register("/dev/pwm0", lower_half); + } + else + { + ret = -ENODEV; + } + + if (ret < 0) + { + return ret; + } +#endif + +#ifdef CONFIG_IMX9_FLEXIO2_PWM + lower_half = imx9_flexio_pwm_init(PWM_FLEXIO2); + + if (lower_half) + { + ret = pwm_register("/dev/pwm1", lower_half); + } + else + { + ret = -ENODEV; + } + + if (ret < 0) + { + return ret; + } +#endif + +#ifdef CONFIG_IMX9_TPM3_PWM + lower_half = imx9_tpm_pwm_init(PWM_TPM3); + + if (lower_half) + { + ret = pwm_register("/dev/pwm2", lower_half); + } + else + { + ret = -ENODEV; + } +#endif + + return ret; +} diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_spi.c b/boards/arm64/imx9/imx93-evk/src/imx9_spi.c new file mode 100644 index 0000000000000..826cc73dbbe6b --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_spi.c @@ -0,0 +1,162 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/src/imx9_spi.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +#include "imx9_gpio.h" +#include "imx9_lpspi.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI6 +static struct spi_dev_s *g_spi6; +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef CONFIG_IMX9_LPSPI + +/**************************************************************************** + * Name: imx9_lpspix_select + * + * Description: + * Enable/disable the SPI chip select. The implementation of this method + * must include handshaking: If a device is selected, it must hold off + * all other attempts to select the device until the device is deselected. + * Required. + * + * Input Parameters: + * dev - Device-specific state data + * devid - Identifies the device to select + * selected - true: slave selected, false: slave de-selected + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imx9_lpspi_select(struct spi_dev_s *dev, uint32_t devid, bool selected) +{ +#ifdef CONFIG_IMX9_LPSPI6 + if (dev == g_spi6) + { + imx9_gpio_write(GPIO_LPSPI6_CS, !selected); + } +#endif +} + +/**************************************************************************** + * Name: imx9_lpspix_status + * + * Description: + * Get SPI/MMC status. Optional. + * + * Input Parameters: + * dev - Device-specific state data + * devid - Identifies the device to report status on + * + * Returned Value: + * Returns a bitset of status values (see SPI_STATUS_* defines) + * + ****************************************************************************/ + +uint8_t imx9_lpspi_status(struct spi_dev_s *dev, uint32_t devid) +{ + return 0; +} + +/**************************************************************************** + * Name: imx9_lpspixcmddata + * + * Description: + * Some devices require an additional out-of-band bit to specify if the + * next word sent to the device is a command or data. This is typical, for + * example, in "9-bit" displays where the 9th bit is the CMD/DATA bit. + * This function provides selection of command or data. + * + * This "latches" the CMD/DATA state. It does not have to be called before + * every word is transferred; only when the CMD/DATA state changes. This + * method is required if CONFIG_SPI_CMDDATA is selected in the NuttX + * configuration + * + * Input Parameters: + * dev - Device-specific state data + * cmd - TRUE: The following word is a command; FALSE: the following words + * are data. + * + * Returned Value: + * OK unless an error occurs. Then a negated errno value is returned + * + ****************************************************************************/ + +int imx9_lpspi_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd) +{ + return -ENODEV; +} +#endif + +/**************************************************************************** + * Name: board_spi_initialize + * + * Description: + * Initialize and register SPI driver for the defined SPI ports. + * + ****************************************************************************/ + +int imx9_spi_initialize(void) +{ + int ret = OK; + +#if defined(CONFIG_IMX9_LPSPI) + /* Initialize SPI device */ + + g_spi6 = imx9_lpspibus_initialize(6); + if (g_spi6 == NULL) + { + spierr("Failed to initialize SPI6\n"); + return -ENODEV; + } +#endif /* CONFIG_MPFS_SPI0 */ + +#ifdef CONFIG_SPI_DRIVER + ret = spi_register(g_spi6, 0); + if (ret < 0) + { + spierr("Failed to register /dev/spi0: %d\n", ret); + } +#endif /* CONFIG_SPI_DRIVER */ + + return OK; +} diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_usdhc.c b/boards/arm64/imx9/imx93-evk/src/imx9_usdhc.c new file mode 100644 index 0000000000000..54116fa795d54 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_usdhc.c @@ -0,0 +1,84 @@ +/**************************************************************************** + * boards/arm64/imx9/imx93-evk/src/imx9_usdhc.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "imx9_usdhc.h" +#include "imx93-evk.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct sdio_dev_s *g_sdio_dev; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: imx9_usdhc_init + * + * Description: + * Configure the uSDHC driver. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int imx9_usdhc_init(void) +{ + int ret; + + /* First, get an instance of the SDIO interface */ + + finfo("Initializing SDIO slot %d\n", SDIO_SLOTNO); + + g_sdio_dev = imx9_usdhc_initialize(SDIO_SLOTNO); + if (!g_sdio_dev) + { + ferr("ERROR: Failed to initialize SDIO slot %d\n", SDIO_SLOTNO); + return -ENODEV; + } + + /* Now bind the SDIO interface to the MMC/SD driver */ + + finfo("Bind SDIO to the MMC/SD driver, minor=%d\n", SDIO_MINOR); + + ret = mmcsd_slotinitialize(SDIO_MINOR, g_sdio_dev); + if (ret != OK) + { + ferr("ERROR: Failed to bind SDIO to the MMC/SD driver: %d\n", ret); + return ret; + } + + return OK; +} + diff --git a/boards/arm64/qemu/qemu-armv8a/scripts/dramboot.ld b/boards/arm64/qemu/qemu-armv8a/scripts/dramboot.ld index c8857860ea1cd..c4cbc49957987 100644 --- a/boards/arm64/qemu/qemu-armv8a/scripts/dramboot.ld +++ b/boards/arm64/qemu/qemu-armv8a/scripts/dramboot.ld @@ -33,6 +33,7 @@ SECTIONS _start = .; .text : { _stext = .; /* Text section */ + *(.start .start.*) /* Place __start here */ *(.text) *(.text.cold) *(.text.unlikely) diff --git a/boards/arm64/rk3399/nanopi_m4/scripts/dramboot.ld b/boards/arm64/rk3399/nanopi_m4/scripts/dramboot.ld index bebe73fff0013..d202807ea601c 100644 --- a/boards/arm64/rk3399/nanopi_m4/scripts/dramboot.ld +++ b/boards/arm64/rk3399/nanopi_m4/scripts/dramboot.ld @@ -43,6 +43,7 @@ SECTIONS _start = .; .text : { _stext = .; /* Text section */ + *(.start .start.*) /* Place __start here */ *(.text) *(.text.cold) *(.text.unlikely) diff --git a/boards/arm64/rk3399/pinephonepro/scripts/dramboot.ld b/boards/arm64/rk3399/pinephonepro/scripts/dramboot.ld index e50ea0b0ea1c3..f3a47b2719846 100644 --- a/boards/arm64/rk3399/pinephonepro/scripts/dramboot.ld +++ b/boards/arm64/rk3399/pinephonepro/scripts/dramboot.ld @@ -34,6 +34,7 @@ SECTIONS _start = .; .text : { _stext = .; /* Text section */ + *(.start .start.*) /* Place __start here */ *(.text) *(.text.cold) *(.text.unlikely) diff --git a/boards/risc-v/mpfs/common/src/mpfs_composite.c b/boards/risc-v/mpfs/common/src/mpfs_composite.c index a8530f284923e..ef24c9c58893b 100644 --- a/boards/risc-v/mpfs/common/src/mpfs_composite.c +++ b/boards/risc-v/mpfs/common/src/mpfs_composite.c @@ -34,7 +34,7 @@ #include "mpfs.h" -#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) +#if defined(CONFIG_USBDEV_COMPOSITE) /**************************************************************************** * Private Data @@ -174,6 +174,28 @@ int board_composite_initialize(int port) } #endif +/**************************************************************************** + * Name: board_composite_uninitialize + * + * Description: + * Perform architecture specific initialization of a composite USB device. + * + * Input Parameters: + * port - port number, unused + * + * Returned Value: + * OK always + * + ****************************************************************************/ + +#ifdef CONFIG_USBMSC_COMPOSITE +int board_composite_uninitialize(int port) +{ + board_mscuninitialize(NULL); + return OK; +} +#endif + /**************************************************************************** * Name: board_usbmsc_initialize * @@ -218,91 +240,95 @@ void *board_composite_connect(int port, int configid) * The standard is to use one CDC/ACM and one USB mass storage device. */ - if (configid == 0) - { -#ifdef CONFIG_USBMSC_COMPOSITE - struct composite_devdesc_s dev[2]; - int ifnobase = 0; - int strbase = COMPOSITE_NSTRIDS; + struct composite_devdesc_s dev[2]; + int devs = 0; + int ifnobase = 0; + int strbase = COMPOSITE_NSTRIDS; + if (configid == 0 || configid == 1) + { +#ifdef CONFIG_CDCACM_COMPOSITE /* Configure the CDC/ACM device */ /* Ask the cdcacm driver to fill in the constants we didn't * know here. */ - cdcacm_get_composite_devdesc(&dev[0]); + cdcacm_get_composite_devdesc(&dev[devs]); /* Overwrite and correct some values... */ /* The callback functions for the CDC/ACM class */ - dev[0].classobject = cdcacm_classobject; - dev[0].uninitialize = cdcacm_uninitialize; + dev[devs].classobject = cdcacm_classobject; + dev[devs].uninitialize = cdcacm_uninitialize; /* Interfaces */ - dev[0].devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ - dev[0].minor = 0; /* The minor interface number */ + dev[devs].devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[devs].minor = 0; /* The minor interface number */ /* Strings */ - dev[0].devinfo.strbase = strbase; /* Offset to String Numbers */ + dev[devs].devinfo.strbase = strbase; /* Offset to String Numbers */ /* Endpoints */ - dev[0].devinfo.epno[CDCACM_EP_BULKIN_IDX] = 3; - dev[0].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 3; - dev[0].devinfo.epno[CDCACM_EP_INTIN_IDX] = 4; + dev[devs].devinfo.epno[CDCACM_EP_BULKIN_IDX] = 3; + dev[devs].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 3; + dev[devs].devinfo.epno[CDCACM_EP_INTIN_IDX] = 4; /* Count up the base numbers */ - ifnobase += dev[0].devinfo.ninterfaces; - strbase += dev[0].devinfo.nstrings; + ifnobase += dev[devs].devinfo.ninterfaces; + strbase += dev[devs].devinfo.nstrings; + devs++; +#endif + } + + if (configid == 1) + { +#ifdef CONFIG_USBMSC_COMPOSITE /* Configure the mass storage device device */ /* Ask the usbmsc driver to fill in the constants we didn't * know here. */ - usbmsc_get_composite_devdesc(&dev[1]); + usbmsc_get_composite_devdesc(&dev[devs]); /* Overwrite and correct some values... */ /* The callback functions for the USBMSC class */ - dev[1].classobject = board_mscclassobject; - dev[1].uninitialize = board_mscuninitialize; + dev[devs].classobject = board_mscclassobject; + dev[devs].uninitialize = board_mscuninitialize; /* Interfaces */ - dev[1].devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ - dev[1].minor = 0; /* The minor interface number */ + dev[devs].devinfo.ifnobase = ifnobase; /* Offset to Interface-IDs */ + dev[devs].minor = 0; /* The minor interface number */ /* Strings */ - dev[1].devinfo.strbase = strbase; /* Offset to String Numbers */ + dev[devs].devinfo.strbase = strbase; /* Offset to String Numbers */ /* Endpoints */ - dev[1].devinfo.epno[USBMSC_EP_BULKIN_IDX] = 1; - dev[1].devinfo.epno[USBMSC_EP_BULKOUT_IDX] = 2; + dev[devs].devinfo.epno[USBMSC_EP_BULKIN_IDX] = 1; + dev[devs].devinfo.epno[USBMSC_EP_BULKOUT_IDX] = 2; /* Count up the base numbers */ - ifnobase += dev[1].devinfo.ninterfaces; - strbase += dev[1].devinfo.nstrings; + ifnobase += dev[devs].devinfo.ninterfaces; + strbase += dev[devs].devinfo.nstrings; - return composite_initialize(composite_getdevdescs(), dev, 2); -#else - return NULL; + devs++; #endif } - else - { - return NULL; - } + + return composite_initialize(composite_getdevdescs(), dev, devs); } -#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ +#endif /* CONFIG_USBDEV_COMPOSITE */ diff --git a/boards/risc-v/mpfs/common/src/mpfs_emmcsd.c b/boards/risc-v/mpfs/common/src/mpfs_emmcsd.c index 25a0ed09d6638..400f68f4c8584 100644 --- a/boards/risc-v/mpfs/common/src/mpfs_emmcsd.c +++ b/boards/risc-v/mpfs/common/src/mpfs_emmcsd.c @@ -27,8 +27,9 @@ #include #include #include +#include -#include "mpfs_emmcsd.h" +#include "mpfs_sdio.h" #include "board_config.h" /**************************************************************************** @@ -37,10 +38,44 @@ static struct sdio_dev_s *g_sdio_dev; +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void partition_handler(FAR struct partition_s *part, FAR void *arg) +{ + unsigned partition = *(int *)arg; + char devname[] = "/dev/mmcsd0p0"; + + if (partition < 10 && part->index == partition) + { + devname[sizeof(devname) - 2] = partition + 48; + register_blockpartition(devname, 0, "/dev/mmcsd0", part->firstblock, + part->nblocks); + } +} + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: mpfs_board_register_partition + * + * Description: + * Register partitions found in mmcsd0 + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned + * to indicate the nature of any failure. + * + ****************************************************************************/ + +int mpfs_board_register_partition(unsigned partition) +{ + return parse_block_partition("/dev/mmcsd0", partition_handler, &partition); +} + /**************************************************************************** * Name: board_emmcsd_init * diff --git a/boards/risc-v/mpfs/common/src/mpfs_usb.c b/boards/risc-v/mpfs/common/src/mpfs_usb.c index 627a5d71c951c..0c198aeb81bae 100644 --- a/boards/risc-v/mpfs/common/src/mpfs_usb.c +++ b/boards/risc-v/mpfs/common/src/mpfs_usb.c @@ -75,7 +75,7 @@ int mpfs_board_usb_init(void) return ret; } - if (board_composite_connect(0, 0) == NULL) + if (board_composite_connect(0, 1) == NULL) { syslog(LOG_ERR, "Failed to connect composite: %d\n", ret); return ret; diff --git a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig new file mode 100644 index 0000000000000..b4c5cf0acff04 --- /dev/null +++ b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig @@ -0,0 +1,83 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_DISABLE_OS_API is not set +# CONFIG_NET_ETHERNET is not set +# CONFIG_NET_IPv4 is not set +# CONFIG_NSH_DISABLE_LOSMART is not set +CONFIG_ALLOW_BSD_COMPONENTS=y +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="icicle" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ICICLE_MPFS=y +CONFIG_ARCH_CHIP="mpfs" +CONFIG_ARCH_CHIP_MPFS250T_FCVG484=y +CONFIG_ARCH_CHIP_MPFS=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=54000 +CONFIG_BUILTIN=y +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_NET=y +CONFIG_DEBUG_NET_ERROR=y +CONFIG_DEBUG_NET_INFO=y +CONFIG_DEBUG_NET_WARN=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEV_ZERO=y +CONFIG_EXPERIMENTAL=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_HOSTNAME="icicle" +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_MEMSET_64BIT=y +CONFIG_MEMSET_OPTSPEED=y +CONFIG_MPFS_CANFD0=y +CONFIG_MPFS_CANFD1=y +CONFIG_MPFS_ENABLE_DPFPU=y +CONFIG_MPFS_HAVE_CANFD=y +CONFIG_MPFS_UART1=y +CONFIG_NET=y +CONFIG_NETDEV_IFINDEX=y +CONFIG_NETDEV_LATEINIT=y +CONFIG_NET_CAN=y +CONFIG_NET_CAN_SOCK_OPTS=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_DISABLE_UMOUNT=y +CONFIG_NSH_LINELEN=160 +CONFIG_NSH_STRERROR=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=1048576 +CONFIG_RAM_START=0x80200000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_RR_INTERVAL=200 +CONFIG_SCHED_HPWORK=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SERIAL_NPOLLWAITERS=2 +CONFIG_STACK_COLORATION=y +CONFIG_START_MONTH=4 +CONFIG_START_YEAR=2021 +CONFIG_SYSLOG_COLOR_OUTPUT=y +CONFIG_SYSTEM_CLE_CMD_HISTORY=y +CONFIG_SYSTEM_COLOR_CLE=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TIME64=y +CONFIG_TASK_NAME_SIZE=20 +CONFIG_TESTING_GETPRIME=y +CONFIG_TESTING_OSTEST=y +CONFIG_UART1_SERIAL_CONSOLE=y diff --git a/boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig b/boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig index b7ee1caff5550..3d3911d46f140 100644 --- a/boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig @@ -47,7 +47,6 @@ CONFIG_MEMSET_64BIT=y CONFIG_MEMSET_OPTSPEED=y CONFIG_MM_IOB=y CONFIG_MPFS_IHC_CLIENT=y -CONFIG_MPFS_IHC_LINUX_ON_HART4=0 CONFIG_MPFS_IHC_NUTTX_ON_HART1=1 CONFIG_MPFS_IHC_NUTTX_ON_HART2=0 CONFIG_MPFS_UART1=y diff --git a/boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig b/boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig index 961ad494f19d7..53b56e22b689a 100644 --- a/boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig @@ -48,6 +48,7 @@ CONFIG_MEMSET_OPTSPEED=y CONFIG_MM_IOB=y CONFIG_MPFS_IHC_CLIENT=y CONFIG_MPFS_IHC_LINUX_ON_HART3=0 +CONFIG_MPFS_IHC_LINUX_ON_HART4=1 CONFIG_MPFS_IHC_RPMSG_CH2=y CONFIG_MPFS_UART2=y CONFIG_NSH_ARCHINIT=y diff --git a/boards/risc-v/mpfs/icicle/configs/standalone/defconfig b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig new file mode 100644 index 0000000000000..532550067b6ce --- /dev/null +++ b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig @@ -0,0 +1,61 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +CONFIG_ARCH="risc-v" +CONFIG_ARCH_BOARD="icicle" +CONFIG_ARCH_BOARD_COMMON=y +CONFIG_ARCH_BOARD_ICICLE_MPFS=y +CONFIG_ARCH_CHIP="mpfs" +CONFIG_ARCH_CHIP_MPFS250T_FCVG484=y +CONFIG_ARCH_CHIP_MPFS=y +CONFIG_ARCH_INTERRUPTSTACK=2048 +CONFIG_ARCH_RISCV=y +CONFIG_ARCH_STACKDUMP=y +CONFIG_BOARD_LOOPSPERMSEC=54000 +CONFIG_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_FS_ERROR=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_IDLETHREAD_STACKSIZE=2048 +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INIT_STACKSIZE=3072 +CONFIG_INTELHEX_BINARY=y +CONFIG_LIBC_HOSTNAME="icicle" +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_MEMSET_64BIT=y +CONFIG_MEMSET_OPTSPEED=y +CONFIG_MPFS_BOOTLOADER=y +CONFIG_MPFS_BOOT_HART=1 +CONFIG_MPFS_DDR_INIT=y +CONFIG_MPFS_ENABLE_DPFPU=y +CONFIG_MPFS_UART0=y +CONFIG_MPFS_UART1=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_DISABLE_IFUPDOWN=y +CONFIG_NSH_DISABLE_MKDIR=y +CONFIG_NSH_DISABLE_RM=y +CONFIG_NSH_DISABLE_RMDIR=y +CONFIG_NSH_DISABLE_UMOUNT=y +CONFIG_NSH_LINELEN=160 +CONFIG_NSH_STRERROR=y +CONFIG_PREALLOC_TIMERS=4 +CONFIG_RAM_SIZE=1048576 +CONFIG_RAM_START=0x08000000 +CONFIG_RAW_BINARY=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_SCHED_HPWORK=y +CONFIG_START_MONTH=4 +CONFIG_START_YEAR=2021 +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_TIME64=y +CONFIG_TASK_NAME_SIZE=20 +CONFIG_UART0_SERIAL_CONSOLE=y +CONFIG_UART1_BAUD=2000000 +CONFIG_USEC_PER_TICK=1000 diff --git a/boards/risc-v/mpfs/icicle/include/board.h b/boards/risc-v/mpfs/icicle/include/board.h index 85834a553bc5e..9ccabcd94bc03 100644 --- a/boards/risc-v/mpfs/icicle/include/board.h +++ b/boards/risc-v/mpfs/icicle/include/board.h @@ -43,6 +43,8 @@ # define MPFS_SD_CLOCK_4BIT MPFS_MMC_CLOCK_25MHZ #endif +#define MPFS_USB_DMA_ADDR_UPPER_OFFSET 0x14u + /* Clocking TODO: */ #define MPFS_MSS_EXT_SGMII_REF_CLK (125000000UL) diff --git a/boards/risc-v/mpfs/icicle/include/board_memorymap.h b/boards/risc-v/mpfs/icicle/include/board_memorymap.h index 47cac1185796c..353112aa86d6d 100644 --- a/boards/risc-v/mpfs/icicle/include/board_memorymap.h +++ b/boards/risc-v/mpfs/icicle/include/board_memorymap.h @@ -65,6 +65,11 @@ #define USRAM_START (uintptr_t)__usram_start #define USRAM_SIZE (uintptr_t)__usram_size +/* User IO */ + +#define USRIO_START (uintptr_t)__usrio_start +#define USRIO_SIZE (uintptr_t)__usrio_size + /**************************************************************************** * Public Data ****************************************************************************/ @@ -95,4 +100,9 @@ extern uint8_t __uflash_size[]; extern uint8_t __usram_start[]; extern uint8_t __usram_size[]; +/* User IO (R) */ + +extern uint8_t __usrio_start[]; +extern uint8_t __usrio_size[]; + #endif /* __BOARDS_RISC_V_MPFS_ICICLE_INCLUDE_BOARD_MEMORYMAP_H */ diff --git a/boards/risc-v/mpfs/icicle/scripts/kernel-space.ld b/boards/risc-v/mpfs/icicle/scripts/kernel-space.ld index 071d7fd8e9072..087e8ac490b96 100644 --- a/boards/risc-v/mpfs/icicle/scripts/kernel-space.ld +++ b/boards/risc-v/mpfs/icicle/scripts/kernel-space.ld @@ -30,6 +30,8 @@ __uflash_start = ORIGIN(uflash); __uflash_size = LENGTH(uflash); __usram_start = ORIGIN(usram); __usram_size = LENGTH(usram); +__usrio_start = ORIGIN(usrio); +__usrio_size = LENGTH(usrio); /* Provide the kernel boundaries as well */ diff --git a/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script b/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script index 265db0c5ef158..419d441b776f6 100644 --- a/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script +++ b/boards/risc-v/mpfs/icicle/scripts/ld-envm-opensbi.script @@ -36,12 +36,12 @@ SECTIONS PROVIDE(__l2lim_end = ORIGIN(l2lim) + LENGTH(l2lim)); .text.sbi : { - _ssbi_ddr = ABSOLUTE(.); + _ssbi_ram = ABSOLUTE(.); sbi* riscv_atomic* riscv_locks* riscv_asm* - _esbi_ddr = ABSOLUTE(.); + _esbi_ram = ABSOLUTE(.); . = ALIGN(0x2000); . += 16k; /* OpenSBI heap, aligned, at least 16k */ } > ddr diff --git a/boards/risc-v/mpfs/icicle/scripts/ld-kernel.script b/boards/risc-v/mpfs/icicle/scripts/ld-kernel.script index f5586f08f3aa6..2806601d90bbd 100644 --- a/boards/risc-v/mpfs/icicle/scripts/ld-kernel.script +++ b/boards/risc-v/mpfs/icicle/scripts/ld-kernel.script @@ -28,6 +28,7 @@ MEMORY kflash (rx) : ORIGIN = 0x80000000, LENGTH = 2048K /* w/ cache */ ksram (rwx) : ORIGIN = 0x80200000, LENGTH = 2048K /* w/ cache */ pgram (rwx) : ORIGIN = 0x80400000, LENGTH = 4096K /* w/ cache */ + usrio (r) : ORIGIN = 0x80800000, LENGTH = 32K /* w/ cache */ } OUTPUT_ARCH("riscv") @@ -45,6 +46,11 @@ __ksram_end = ORIGIN(ksram) + LENGTH(ksram); __pgheap_start = ORIGIN(pgram); __pgheap_size = LENGTH(pgram); +/* User I/O */ + +__usrio_start = ORIGIN(usrio); +__usrio_size = LENGTH(usrio); + ENTRY(_stext) EXTERN(__start) SECTIONS diff --git a/boards/risc-v/mpfs/icicle/scripts/memory.ld b/boards/risc-v/mpfs/icicle/scripts/memory.ld index 890ba735baf8c..f31a88d4eaacc 100644 --- a/boards/risc-v/mpfs/icicle/scripts/memory.ld +++ b/boards/risc-v/mpfs/icicle/scripts/memory.ld @@ -25,4 +25,6 @@ MEMORY ksram (rwx) : ORIGIN = 0x80080000, LENGTH = 256K /* w/ cache */ usram (rwx) : ORIGIN = 0x800C0000, LENGTH = 256K /* w/ cache */ + + usrio (r) : ORIGIN = 0x80100000, LENGTH = 32K } diff --git a/drivers/mmcsd/mmcsd_sdio.c b/drivers/mmcsd/mmcsd_sdio.c index 68ee8ff5d26a2..a4073fa263d7d 100644 --- a/drivers/mmcsd/mmcsd_sdio.c +++ b/drivers/mmcsd/mmcsd_sdio.c @@ -3395,7 +3395,7 @@ static int mmcsd_sdinitialize(FAR struct mmcsd_state_s *priv) mmcsd_decode_scr(priv, scr); - if ((priv->caps & SDIO_CAPS_4BIT_ONLY) != 0) + if ((priv->caps & SDIO_CAPS_4BIT) != 0) { /* Select width (4-bit) bus operation (if the card supports it) */ diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index be6130891b885..84b4f357201e8 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -549,6 +549,13 @@ choice config ETH0_PHY_NONE bool "No PHY support" +config ETH0_PHY_MULTI + bool "Multiple PHYs are supported" + ---help--- + The Board will provide a list of PHYs to probe for. + The first one found on the bpard will be used. + This setting is not supported by all Ethernet drivers. + config ETH0_PHY_AM79C874 bool "AMD Am79C874 PHY" @@ -603,6 +610,9 @@ config ETH0_PHY_LAN8740A config ETH0_PHY_LAN8742A bool "SMSC LAN8742A PHY" +config ETH0_PHY_RTL8211F + bool "Realtek RTL8211F PHY" + config ETH0_PHY_DM9161 bool "Davicom DM9161 PHY" @@ -656,6 +666,9 @@ config ETH1_PHY_TJA1101 config ETH1_PHY_LAN8720 bool "SMSC LAN8720 PHY" +config ETH1_PHY_RTL8211F + bool "Realtek RTL8211F PHY" + config ETH1_PHY_DM9161 bool "Davicom DM9161 PHY" diff --git a/drivers/net/rpmsgdrv.c b/drivers/net/rpmsgdrv.c index 3f55c31584b21..00b8303be0693 100644 --- a/drivers/net/rpmsgdrv.c +++ b/drivers/net/rpmsgdrv.c @@ -591,6 +591,13 @@ static int net_rpmsg_drv_ept_cb(FAR struct rpmsg_endpoint *ept, void *data, FAR struct net_rpmsg_header_s *header = data; uint32_t command = header->command; +#ifdef CONFIG_MPFS_IHC_CLIENT + if (command != NET_RPMSG_TRANSFER) + { + return -EINVAL; + } +#endif + if (command < sizeof(g_net_rpmsg_drv_handler) / sizeof(g_net_rpmsg_drv_handler[0])) { @@ -609,6 +616,13 @@ static int net_rpmsg_drv_send_recv(FAR struct net_driver_s *dev, FAR struct net_rpmsg_drv_cookie_s cookie; int ret; + /* TODO: Only TRANSFER command is implemeted on Linux side */ + + if (command != NET_RPMSG_TRANSFER) + { + return 0; + } + nxsem_init(&cookie.sem, 0, 0); cookie.header = header; diff --git a/fs/shm/CMakeLists.txt b/fs/shm/CMakeLists.txt index d76fb17e3bcdd..d6770ea4f13c1 100644 --- a/fs/shm/CMakeLists.txt +++ b/fs/shm/CMakeLists.txt @@ -20,6 +20,6 @@ # Include POSIX message queue support -if(CONFIG_FS_SHM) +if(CONFIG_FS_SHMFS) target_sources(fs PRIVATE shm_open.c shm_unlink.c shmfs.c shmfs_alloc.c) endif() diff --git a/fs/shm/Kconfig b/fs/shm/Kconfig index 7ec28209a0bdb..77bdbe5a320f4 100644 --- a/fs/shm/Kconfig +++ b/fs/shm/Kconfig @@ -19,4 +19,4 @@ config FS_SHMFS_VFS_PATH The path to where shared memory objects will exist in the VFS namespace. -endif # FS_SHM +endif # FS_SHMFS diff --git a/fs/shm/shmfs.c b/fs/shm/shmfs.c index fef22222efd11..b7095907e7cf7 100644 --- a/fs/shm/shmfs.c +++ b/fs/shm/shmfs.c @@ -238,8 +238,13 @@ static int shmfs_truncate(FAR struct file *filep, off_t length) filep->f_inode->i_private = shmfs_alloc_object(length); if (!filep->f_inode->i_private) { + filep->f_inode->i_size = 0; ret = -EFAULT; } + else + { + filep->f_inode->i_size = length; + } } else if (object->length != length) { diff --git a/fs/shm/shmfs_alloc.c b/fs/shm/shmfs_alloc.c index 979fd4c3f4648..65fb74ca3efd4 100644 --- a/fs/shm/shmfs_alloc.c +++ b/fs/shm/shmfs_alloc.c @@ -22,7 +22,11 @@ * Included Files ****************************************************************************/ +#include + #include + +#include #include #include @@ -87,6 +91,12 @@ FAR struct shmfs_object_s *shmfs_alloc_object(size_t length) { break; } + else + { + /* Clear the page memory (requirement for truncate) */ + + up_addrenv_page_wipe((uintptr_t)pages[i]); + } } } diff --git a/fs/vfs/fs_stat.c b/fs/vfs/fs_stat.c index e6acc398580b6..200e629dcf7c1 100644 --- a/fs/vfs/fs_stat.c +++ b/fs/vfs/fs_stat.c @@ -278,12 +278,13 @@ int inode_stat(FAR struct inode *inode, FAR struct stat *buf, int resolve) } else #endif -#if defined(CONFIG_FS_SHM) +#if defined(CONFIG_FS_SHMFS) /* Check for shared memory */ if (INODE_IS_SHM(inode)) { buf->st_mode = S_IFSHM; + buf->st_size = inode->i_size; } else #endif diff --git a/include/cxx/cstdlib b/include/cxx/cstdlib index 34483cdf9c06e..8517f164231bb 100644 --- a/include/cxx/cstdlib +++ b/include/cxx/cstdlib @@ -28,6 +28,28 @@ #include #include +#include + +//*************************************************************************** +// Pre-processor Definitions +//*************************************************************************** + +#if !defined(CONFIG_BUILD_FLAT) && defined(__KERNEL__) +#undef malloc +#undef free +#undef realloc +#undef memalign +#undef zalloc +#undef calloc + +#define malloc kmm_malloc +#define free kmm_free +#define realloc kmm_realloc +#define memalign kmm_memalign +#define zalloc kmm_zalloc +#define calloc kmm_calloc +#endif + //*************************************************************************** // Namespace //*************************************************************************** diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index 2aee23fc8c7cb..785b113b94fe7 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -1378,7 +1378,7 @@ uintptr_t up_addrenv_page_vaddr(uintptr_t page); * vaddr - The virtual address. * * Returned Value: - * True if it is; false if it's not + * True if it is; false if it's not. * ****************************************************************************/ @@ -1386,6 +1386,25 @@ uintptr_t up_addrenv_page_vaddr(uintptr_t page); bool up_addrenv_user_vaddr(uintptr_t vaddr); #endif +/**************************************************************************** + * Name: up_addrenv_page_wipe + * + * Description: + * Wipe a page of physical memory, first mapping it into kernel virtual + * memory. + * + * Input Parameters: + * page - The page physical address. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_ADDRENV +void up_addrenv_page_wipe(uintptr_t page); +#endif + /**************************************************************************** * Name: up_addrenv_kmap_init * diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h index f17a04f5eb0d3..3d2ccec42baf4 100644 --- a/include/nuttx/fs/fs.h +++ b/include/nuttx/fs/fs.h @@ -412,7 +412,7 @@ struct inode uint16_t i_flags; /* Flags for inode */ union inode_ops_u u; /* Inode operations */ ino_t i_ino; /* Inode serial number */ -#ifdef CONFIG_PSEUDOFS_FILE +#if defined(CONFIG_PSEUDOFS_FILE) || defined(CONFIG_FS_SHMFS) size_t i_size; /* The size of per inode driver */ #endif #ifdef CONFIG_PSEUDOFS_ATTRIBUTES diff --git a/include/nuttx/net/gmii.h b/include/nuttx/net/gmii.h index e4ab94edad527..ed8511461e7e3 100644 --- a/include/nuttx/net/gmii.h +++ b/include/nuttx/net/gmii.h @@ -80,6 +80,21 @@ #define GMII_KSZ90X1_RRDPSR 261 /* RGMII RX data pad skew */ #define GMII_KSZ90x1_ATR 263 /* Analog test register */ +/* Realtek RTL8211 PHY Extended Registers */ + +#define GMII_RTL8211F_NAME "RTL8211F" +#define GMII_RTL8211F_INER_A42 18 /* Interrupt Enable Register */ +#define GMII_RTL8211F_PHYCR1_A43 24 /* PHY Specific Control Register 1 */ +#define GMII_RTL8211F_PHYCR2_A43 25 /* PHY Specific Control Register 2 */ +#define GMII_RTL8211F_PHYSR_A43 26 /* PHY Specific Status Register */ +#define GMII_RTL8211F_INSR_A43 29 /* Interrupt Status Register */ +#define GMII_RTL8211F_PAGSR 31 /* Page Select Register */ +#define GMII_RTL8211F_PHYSCR_A46 20 /* PHY Special Cofig Register */ +#define GMII_RTL8211F_LCR_D04 16 /* LED Control Register */ +#define GMII_RTL8211F_EEELCR_D04 17 /* EEE LED Control Register */ +#define GMII_RTL8211F_MIICR_D08 21 /* MII Control Register */ +#define GMII_RTL8211F_INTBCR_D40 22 /* INTB Pin Control Register */ + /* MII register bit settings ************************************************/ /* MII Control register bit definitions */ @@ -280,6 +295,18 @@ #define GMII_KSZ90x1_INT_RF (1 << 1) /* Remote fault interrupt */ #define GMII_KSZ90x1_INT_LU (1 << 0) /* Link up interrupt */ +/* RTL8211 register bit settings ********************************************/ + +/* RTL8211F MII ID1/2 register bits */ + +#define GMII_PHYID1_RTL8211F 0x001c /* ID1 value for Realtek RTL8211F */ +#define GMII_PHYID2_RTL8211F 0xc878 /* ID2 value for Realtek RTL8211F */ +#define GMII_RTL8211F_PHYSR_SPEED_MASK 0x30 +#define GMII_RTL8211F_PHYSR_10MBPS 0x00 +#define GMII_RTL8211F_PHYSR_100MBPS 0x10 +#define GMII_RTL8211F_PHYSR_1000MBPS 0x20 +#define GMII_RTL8211F_PHYSR_DUPLEX 0x8 + /**************************************************************************** * Type Definitions ****************************************************************************/ diff --git a/include/nuttx/net/mii.h b/include/nuttx/net/mii.h index 623610cc26bd1..b9eeefc15ac85 100644 --- a/include/nuttx/net/mii.h +++ b/include/nuttx/net/mii.h @@ -21,11 +21,14 @@ #ifndef __INCLUDE_NUTTX_NET_MII_H #define __INCLUDE_NUTTX_NET_MII_H +#ifndef __ASSEMBLY__ + /**************************************************************************** * Included Files ****************************************************************************/ #include +#include /**************************************************************************** * Pre-processor Definitions @@ -62,12 +65,14 @@ /* AR8031: */ +#define MII_AR8031_NAME "AR8031" #define MII_AR8031_PSSR 0x11 /* Phy-Specific Status Register */ /* National Semiconductor DP83840: 0x07-0x11, 0x14, 0x1a, 0x1d-0x1f * reserved */ +#define MII_DP83840_NAME "DP83840" #define MII_DP83840_COUNTER 0x12 /* Disconnect counter */ #define MII_DP83840_FCSCOUNTER 0x13 /* False carrier sense counter */ #define MII_DP83840_NWAYTEST 0x14 /* N-way auto-neg test reg */ @@ -80,6 +85,7 @@ /* Am79c874: 0x08-0x0f, 0x14, 0x16, 0x19-0x1f reserved */ +#define MII_AM79C874_NAME "AM79C874" #define MII_AM79C874_NPADVERTISE 0x07 /* Auto-negotiation next page advertisement */ #define MII_AM79C874_MISCFEATURES 0x10 /* Miscellaneous features reg */ #define MII_AM79C874_INTCS 0x11 /* Interrupt control/status */ @@ -91,6 +97,7 @@ /* Luminary LM3S6918 built-in PHY: 0x07-0x0f, 0x14-0x16, 0x19-0x1f reserved */ +#define MII_LM3S6918_NAME "LM3S6918" #define MII_LM_VSPECIFIC 0x10 /* Vendor-Specific */ #define MII_LM_INTCS 0x11 /* Interrupt control/status */ #define MII_LM_DIAGNOSTIC 0x12 /* Diagnostic */ @@ -100,12 +107,14 @@ /* Micrel KS8721: 0x15, 0x1b, and 0x1f */ +#define MII_KS8721_NAME "KS8721" #define MII_KS8721_RXERCOUNTER 0x15 /* RXER counter */ #define MII_KS8721_INTCS 0x1b /* Interrupt control/status register */ #define MII_KS8721_10BTCR 0x1f /* 10BASE-TX PHY control register */ /* Micrel KSZ8041: 0x15, 0x1b, 0x1e-0x1f */ +#define MII_KSZ8041_NAME "KSZ8041" #define MII_KSZ8041_RXERR 0x15 /* RXERR Counter */ #define MII_KSZ8041_INT 0x1b /* Interrupt Control/Status */ #define MII_KSZ8041_PHYCTRL1 0x1e /* PHY Control 1 */ @@ -113,6 +122,7 @@ /* Micrel KSZ8051: 0x11, 0x15-0x18, 0x1b, 0x1d-0x1f */ +#define MII_KSZ8051_NAME "KSZ8051" #define MII_KSZ8051_AFEC1 0x11 /* AFE Control 1 */ #define MII_KSZ8051_RXERR 0x15 /* RXERR Counter */ #define MII_KSZ8051_OMSO 0x16 /* Operation Mode Strap Override */ @@ -124,6 +134,8 @@ #define MII_KSZ8051_PHYCTRL2 0x1f /* PHY Control 2 */ /* Micrel KSZ8061: 0x10-0x18, 0x1b, 0x1c-0x1f */ + +#define MII_KSZ8061_NAME "KSZ8061" #define MII_KSZ8061_DIG_CTRL 0x10 /* Digital Control */ #define MII_KSZ8061_AFE_CTRL_0 0x11 /* AFE Control 0 */ #define MII_KSZ8061_AFE_CTRL_1 0x12 /* AFE Control 1 */ @@ -141,6 +153,7 @@ /* Micrel KSZ8081: 0x10-0x11, 0x15-0x18, 0x1b, 0x1d-0x1f */ +#define MII_KSZ8081_NAME "KSZ8081" #define MII_KSZ8081_DRCTRL 0x10 /* Digital Reserve Control */ #define MII_KSZ8081_AFEC1 0x11 /* AFE Control 1 */ #define MII_KSZ8081_RXERR 0x15 /* RXERR Counter */ @@ -156,6 +169,7 @@ * 0x8-0x15, 0x13, 0x1c reserved */ +#define MII_DP83848C_NAME "DP83848C" #define MII_DP83848C_STS 0x10 /* RO PHY Status Register */ #define MII_DP83848C_MICR 0x11 /* RW MII Interrupt Control Register */ #define MII_DP83848C_MISR 0x12 /* RO MII Interrupt Status Register */ @@ -171,6 +185,7 @@ /* Texas Instruments DP83825I PHY Extended Registers. */ +#define MII_DP83825I_NAME "DP83825I" #define MII_DP83825I_PHYSTS 0x10 /* RO PHY Status Register */ #define MII_DP83825I_PHYSCR 0x11 /* RW PHY Specific Control Register */ #define MII_DP83825I_MISR1 0x12 /* RO MII Interrupt Status Register 1 */ @@ -189,6 +204,7 @@ /* SMSC LAN8720 PHY Extended Registers */ +#define MII_LAN8720_NAME "LAN8720" #define MII_LAN8720_REV 0x10 /* Silicon Revision Register */ #define MII_LAN8720_MCSR 0x11 /* Mode Control/Status Register */ #define MII_LAN8720_MODES 0x12 /* Special modes */ @@ -201,6 +217,8 @@ /* SMSC LAN8740/LAN8742A PHY Extended Registers */ +#define MII_LAN8740_NAME "LAN8740" +#define MII_LAN8742A_NAME "LAN8742A" #define MII_LAN8740_CONFIG 0x10 /* EDPD NDL/Crossover Timer/EEE Configuration */ #define MII_LAN8740_MCSR 0x11 /* Mode Control/Status Register */ #define MII_LAN8740_MODES 0x12 /* Special modes */ @@ -215,6 +233,7 @@ /* Motorcomm YT8512C/YT8512H Extended Registers */ +#define MII_YT8512_NAME "YT8512" #define MII_YT8512_PHYSFC 0x10 /* PHY Function conrtol Register */ #define MII_YT8512_PHYSTS 0x11 /* PHY Status Register */ #define MII_YT8512_IMR 0x12 /* Interrupt Mask Register */ @@ -728,12 +747,15 @@ /* TJA110X MII ID1/2 register bits */ +#define MII_TJA1100_NAME "TJA1100" #define MII_PHYID1_TJA1100 0x0180 /* ID1 value for NXP TJA1100 */ #define MII_PHYID2_TJA1100 0xdc40 /* ID2 value for NXP TJA1100 */ +#define MII_TJA1101_NAME "TJA1101" #define MII_PHYID1_TJA1101 0x0180 /* ID1 value for NXP TJA1101 */ #define MII_PHYID2_TJA1101 0xdd00 /* ID2 value for NXP TJA1101 */ +#define MII_TJA1103_NAME "TJA1103" #define MII_PHYID1_TJA1103 0x01b /* ID1 value for NXP TJA1103 */ #define MII_PHYID2_TJA1103 0xB013 /* ID2 value for NXP TJA1103 */ @@ -915,6 +937,24 @@ * Type Definitions ****************************************************************************/ +struct phy_desc_s +{ + char name[16]; /* The name of the PHY */ + uint16_t id1; /* The MII_PHYID1 registers value */ + uint16_t id2; /* The MII_PHYID2 registers value */ + uint16_t status; /* The Phys status register or 0xffff */ + uint16_t address_lo; /* The lowest address to check for the PHY */ + uint16_t address_high; /* The highest address to check for the PHY or + * 0xffff uses only the address_lo (one address) + */ + uint16_t mbps10; /* The bit mask for 10MBP if status is not 0xffff */ + uint16_t mbps100; /* The bit mask for 100MBP if status is not 0xffff */ + uint16_t duplex; /* The bit mask for DUPLEX if status is not 0xffff */ + uint16_t clause; /* The PHY clause supported. 22 or 45 */ + uint16_t mbps1000; /* The bit mask for 1000MBP if status is not 0xffff */ + uint16_t speed_mask; /* The bit mask for mbps10, 100, 1000 */ +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -932,4 +972,5 @@ extern "C" } #endif +#endif /* __ASSEMBLY__ */ #endif /* __INCLUDE_NUTTX_NET_MII_H */ diff --git a/include/nuttx/tls.h b/include/nuttx/tls.h index 8b685a456c892..1e8e4724a8e28 100644 --- a/include/nuttx/tls.h +++ b/include/nuttx/tls.h @@ -48,7 +48,6 @@ #endif #ifndef CONFIG_TLS_NELEM -# warning CONFIG_TLS_NELEM is not defined # define CONFIG_TLS_NELEM 0 #endif diff --git a/libs/libc/machine/risc-v/arch_elf.c b/libs/libc/machine/risc-v/arch_elf.c index 1fe174d307eb1..c64e2c8548e48 100644 --- a/libs/libc/machine/risc-v/arch_elf.c +++ b/libs/libc/machine/risc-v/arch_elf.c @@ -154,25 +154,24 @@ static void _add_val(uint16_t *addr, uint32_t val) static void _calc_imm(long offset, long *imm_hi, long *imm_lo) { - long lo; - long hi = offset / 4096; - long r = offset % 4096; + long hi = offset / 0x1000; + long lo = offset - hi * 0x1000; - if (2047 < r) + if (0x7ff < lo) { hi++; + lo -= 0x1000; } - else if (r < -2048) + else if (lo < -0x800) { hi--; + lo += 0x1000; } - lo = offset - (hi * 4096); - binfo("offset=%ld: hi=%ld lo=%ld\n", offset, hi, lo); - ASSERT(-2048 <= lo && lo <= 2047); + ASSERT(-0x800 <= lo && lo <= 0x7ff); *imm_lo = lo; *imm_hi = hi; diff --git a/net/can/can_callback.c b/net/can/can_callback.c index d8ebfc65506ef..2804b67d1ba67 100644 --- a/net/can/can_callback.c +++ b/net/can/can_callback.c @@ -65,6 +65,10 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn, uint16_t recvlen; uint16_t ret; +#ifdef CONFIG_NET_TIMESTAMP + buflen -= sizeof(struct timeval); +#endif + ret = (flags & ~CAN_NEWDATA); /* Save as the packet data as in the read-ahead buffer. NOTE that @@ -214,11 +218,16 @@ uint16_t can_datahandler(FAR struct net_driver_s *dev, can_readahead_signal(conn); #endif ret = iob->io_pktlen; - } - /* Device buffer must be enqueue or freed, clear the handle */ + /* Device buffer has been enqueued, clear the handle */ - netdev_iob_clear(dev); + netdev_iob_clear(dev); + } + else + { + nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret); + netdev_iob_release(dev); + } return ret; } diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index f7dc4e459eb3a..4ce63b69ee751 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -233,7 +233,7 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) pstate->pr_recvlen = -1; - if ((iob = iob_peek_queue(&conn->readahead)) != NULL && + if ((iob = iob_remove_queue(&conn->readahead)) != NULL && pstate->pr_buflen > 0) { DEBUGASSERT(iob->io_pktlen > 0); @@ -246,17 +246,7 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) if (can_recv_filter(conn, can_id) == 0) { - FAR struct iob_s *tmp; - - /* Remove the I/O buffer chain from the head of the read-ahead - * buffer queue. - */ - - tmp = iob_remove_queue(&conn->readahead); - DEBUGASSERT(tmp == iob); - UNUSED(tmp); - - /* And free the I/O buffer chain */ + /* Free the I/O buffer chain */ iob_free_chain(iob); return 0; @@ -277,37 +267,16 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) recvlen = iob_copyout(pstate->pr_buffer, iob, pstate->pr_buflen, 0); - /* If we took all of the data from the I/O buffer chain is empty, then - * release it. If there is still data available in the I/O buffer - * chain, then just trim the data that we have taken from the - * beginning of the I/O buffer chain. + /* We should have taken all of the data from the I/O buffer chain, + * so release it. There is no trimming needed, since One CAN/CANFD + * frame can always fit in one IOB. */ - if (recvlen >= iob->io_pktlen) - { - FAR struct iob_s *tmp; - - /* Remove the I/O buffer chain from the head of the read-ahead - * buffer queue. - */ - - tmp = iob_remove_queue(&conn->readahead); - DEBUGASSERT(tmp == iob); - UNUSED(tmp); + static_assert(sizeof(struct can_frame) <= CONFIG_IOB_BUFSIZE); - /* And free the I/O buffer chain */ + /* Free the I/O buffer chain */ - iob_free_chain(iob); - } - else - { - /* The bytes that we have received from the head of the I/O - * buffer chain (probably changing the head of the I/O - * buffer queue). - */ - - iob_trimhead_queue(&conn->readahead, recvlen); - } + iob_free_chain(iob); /* do not pass frames with DLC > 8 to a legacy socket */ #if defined(CONFIG_NET_CANPROTO_OPTIONS) && defined(CONFIG_NET_CAN_CANFD) diff --git a/net/devif/devif_send.c b/net/devif/devif_send.c index 943b737bbdba4..15ec735f7cfbf 100644 --- a/net/devif/devif_send.c +++ b/net/devif/devif_send.c @@ -102,7 +102,12 @@ int devif_send(FAR struct net_driver_s *dev, FAR const void *buf, /* Prepare device buffer before poll callback */ - iob_update_pktlen(dev->d_iob, offset, false); + /* if pktlen is 0, no need to update */ + + if (offset != 0) + { + iob_update_pktlen(dev->d_iob, offset, false); + } ret = iob_trycopyin(dev->d_iob, buf, len, offset, false); if (ret != len) diff --git a/openamp/0003-libmetal-nuttx-io.c-Fix-void-pointer-arithmetic-in-a.patch b/openamp/0003-libmetal-nuttx-io.c-Fix-void-pointer-arithmetic-in-a.patch new file mode 100644 index 0000000000000..88ce403c93f8c --- /dev/null +++ b/openamp/0003-libmetal-nuttx-io.c-Fix-void-pointer-arithmetic-in-a.patch @@ -0,0 +1,36 @@ +From 59e2764f9d0598ad0135286d4a0ee1ac95893bba Mon Sep 17 00:00:00 2001 +From: Jukka Laitinen +Date: Mon, 12 Feb 2024 13:27:13 +0200 +Subject: [PATCH] libmetal/nuttx/io.c: Fix void pointer arithmetic in access + alignment + +Signed-off-by: Jukka Laitinen +--- + libmetal/lib/system/nuttx/io.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/lib/system/nuttx/io.c libmetal/lib/system/nuttx/io.c +index 3ce9cbe..ab9bc6a 100644 +--- a/lib/system/nuttx/io.c ++++ libmetal/lib/system/nuttx/io.c +@@ -45,7 +45,7 @@ static int metal_io_block_read_(struct metal_io_region *io, + *(uint32_t *)dst = *(uint32_t *)va; + else if (len == 8) { + *(uint32_t *)dst = *(uint32_t *)va; +- *(uint32_t *)(dst + 4) = *(uint32_t *)(va + 4); ++ *((uint32_t *)dst + 1) = *((uint32_t *)va + 1); + } else + memcpy(dst, va, len); + +@@ -68,7 +68,7 @@ static int metal_io_block_write_(struct metal_io_region *io, + *(uint32_t *)va = *(uint32_t *)src; + else if (len == 8) { + *(uint32_t *)va = *(uint32_t *)src; +- *(uint32_t *)(va + 4) = *(uint32_t *)(src + 4); ++ *((uint32_t *)va + 1) = *((uint32_t *)src + 1); + } else + memcpy(va, src, len); + +-- +2.34.1 + diff --git a/openamp/libmetal.defs b/openamp/libmetal.defs index b3369496abe8c..90e8a690bee8c 100644 --- a/openamp/libmetal.defs +++ b/openamp/libmetal.defs @@ -79,6 +79,7 @@ libmetal.zip: $(Q) mv libmetal-$(VERSION) libmetal $(Q) patch -p0 < 0001-libmetal-add-metal_list_for_each_safe-support.patch $(Q) patch -p0 < 0002-libmetal-nuttx-io.c-align-access-when-read-write-siz.patch + $(Q) patch -p0 < 0003-libmetal-nuttx-io.c-Fix-void-pointer-arithmetic-in-a.patch .libmetal_headers: libmetal.zip else diff --git a/sched/group/group_killchildren.c b/sched/group/group_killchildren.c index bafe734071979..331ae3dddb0d9 100644 --- a/sched/group/group_killchildren.c +++ b/sched/group/group_killchildren.c @@ -181,29 +181,33 @@ int group_kill_children(FAR struct tcb_s *tcb) #if defined(CONFIG_GROUP_KILL_CHILDREN_TIMEOUT_MS) && \ CONFIG_GROUP_KILL_CHILDREN_TIMEOUT_MS != 0 - /* Send SIGTERM for each first */ - group_foreachchild(tcb->group, group_kill_children_handler, - (FAR void *)((uintptr_t)tcb->pid)); + if ((tcb->flags & TCB_FLAG_FORCED_CANCEL) == 0) + { + /* Send SIGTERM for each first */ - /* Wait a bit for child exit */ + group_foreachchild(tcb->group, group_kill_children_handler, + (FAR void *)((uintptr_t)tcb->pid)); - ret = CONFIG_GROUP_KILL_CHILDREN_TIMEOUT_MS; - while (1) - { - if (tcb->group->tg_nmembers <= 1) + /* Wait a bit for child exit */ + + ret = CONFIG_GROUP_KILL_CHILDREN_TIMEOUT_MS; + while (1) { - break; - } + if (tcb->group->tg_nmembers <= 1) + { + break; + } - nxsig_usleep(USEC_PER_MSEC); + nxsig_usleep(USEC_PER_MSEC); # if CONFIG_GROUP_KILL_CHILDREN_TIMEOUT_MS > 0 - if (--ret < 0) - { - break; - } + if (--ret < 0) + { + break; + } # endif + } } #endif diff --git a/tools/ci/cibuild.sh b/tools/ci/cibuild.sh index c2120f6dcb574..980628c1ca7f5 100755 --- a/tools/ci/cibuild.sh +++ b/tools/ci/cibuild.sh @@ -116,7 +116,7 @@ function avr-gcc-toolchain { brew install avr-gcc ;; Linux) - apt-get install -y avr-libc gcc-avr + sudo apt-get install -y avr-libc gcc-avr ;; esac fi @@ -187,7 +187,7 @@ function clang-tidy { if ! type clang-tidy &> /dev/null; then case ${os} in Linux) - apt-get install -y clang clang-tidy + sudo apt-get install -y clang clang-tidy ;; esac fi @@ -215,7 +215,7 @@ function util-linux { brew install flock ;; Linux) - apt-get install -y util-linux + sudo apt-get install -y util-linux ;; esac fi @@ -231,7 +231,7 @@ function gen-romfs { brew install genromfs ;; Linux) - apt-get install -y genromfs + sudo apt-get install -y genromfs ;; esac fi @@ -467,7 +467,7 @@ function u-boot-tools { brew install u-boot-tools ;; Linux) - apt-get install -y u-boot-tools + sudo apt-get install -y u-boot-tools ;; esac fi @@ -588,7 +588,7 @@ case ${os} in rm -f /usr/local/bin/openssl || : ;; Linux) - install="arm-clang-toolchain arm-gcc-toolchain arm64-gcc-toolchain avr-gcc-toolchain binutils bloaty clang-tidy gen-romfs gperf kconfig-frontends mips-gcc-toolchain python-tools riscv-gcc-toolchain rust rx-gcc-toolchain sparc-gcc-toolchain xtensa-esp32-gcc-toolchain u-boot-tools util-linux wasi-sdk c-cache" + install="arm-gcc-toolchain binutils gen-romfs gperf kconfig-frontends python-tools riscv-gcc-toolchain c-cache" ;; esac diff --git a/tools/ci/testlist/ssrc-arm.dat b/tools/ci/testlist/ssrc-arm.dat new file mode 100644 index 0000000000000..215a99582a7ca --- /dev/null +++ b/tools/ci/testlist/ssrc-arm.dat @@ -0,0 +1,2 @@ +/arm/stm32f7,CONFIG_ARM_TOOLCHAIN_GNU_EABI + diff --git a/tools/ci/testlist/ssrc-riscv.dat b/tools/ci/testlist/ssrc-riscv.dat new file mode 100644 index 0000000000000..d8becf48b6e83 --- /dev/null +++ b/tools/ci/testlist/ssrc-riscv.dat @@ -0,0 +1,2 @@ +/risc-v/mpfs + diff --git a/tools/imx9/Config.mk b/tools/imx9/Config.mk new file mode 100644 index 0000000000000..af7f0ee010009 --- /dev/null +++ b/tools/imx9/Config.mk @@ -0,0 +1,33 @@ +############################################################################ +# tools/imx9/Config.mk +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +# These are the macros that will be used in the NuttX make system to compile +# and assembly source files and to insert the resulting object files into an +# archive. These replace the default definitions at tools/Config.mk + +# POSTBUILD -- Perform post build operations + +ifeq ($(CONFIG_IMX9_BOOTLOADER),y) +define POSTBUILD + $(Q) echo "Removing sections" + $(Q) $(OBJCOPY) -O binary -R .bss -R .initstack $(BIN) nuttx.bin + $(Q) ([ $$? -eq 0 ] && echo "Done.") +endef +endif