From 96c2707737391642ac1d3ade84fb03f4c1fa51e4 Mon Sep 17 00:00:00 2001 From: Alin Jerpelea Date: Tue, 9 Jan 2024 14:27:59 +0100 Subject: [PATCH 001/147] Documentation: add NuttX-12.4.0 release notes Add release notes for 12.4.0 release Signed-off-by: Alin Jerpelea --- Documentation/ReleaseNotes/NuttX-12.4.0 | 519 ++++++++++++++++++++++++ 1 file changed, 519 insertions(+) create mode 100644 Documentation/ReleaseNotes/NuttX-12.4.0 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 From 2a73509f26b4cb56d369b7b1600c6116472f8766 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Mon, 22 Nov 2021 14:58:29 +0200 Subject: [PATCH 002/147] boards/riscv/mpfs/icicle/configs/standalone: Add a standalone target - boots from eNVM - uses lim memory for RAM - has console on uart 0 - has procfs enabled - has most of nsh commands enabled Signed-off-by: Jukka Laitinen --- .../mpfs/icicle/configs/standalone/defconfig | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 boards/risc-v/mpfs/icicle/configs/standalone/defconfig 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..7958978dacb46 --- /dev/null +++ b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig @@ -0,0 +1,63 @@ +# +# 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_ERROR=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_FLOATINGPOINT=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 From 003e785d375d803a5d522163f0877763a54745bd Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 24 Nov 2021 10:13:55 +0200 Subject: [PATCH 003/147] Fix the check workflow for tiiuae repo - Change git repository urls to point to our tiiuae repos for nuttx & nuttx apps - Remove most of the the build steps, leave just arm-12 and riscv; arm-12 has a build for stm32f7, and riscv for mpfs Signed-off-by: Jukka Laitinen --- .github/workflows/build.yml | 10 +++++----- .github/workflows/check.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2ce3afa911471..b630ce2bd34a7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -67,13 +67,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" @@ -91,7 +91,7 @@ jobs: - name: Checkout nuttx repo uses: actions/checkout@v4 with: - repository: apache/nuttx + repository: tiiuae/nuttx ref: ${{ steps.gittargets.outputs.os_ref }} path: sources/nuttx fetch-depth: 1 @@ -101,7 +101,7 @@ jobs: - name: Checkout apps repo uses: actions/checkout@v4 with: - repository: apache/nuttx-apps + repository: tiiuae/incubator-nuttx-apps ref: ${{ steps.gittargets.outputs.apps_ref }} path: sources/apps fetch-depth: 1 @@ -123,7 +123,7 @@ jobs: 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] + boards: [arm-12, risc-v] steps: - name: Download Source Artifact 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 From cd75eb6c761f7131dd4fa2af7172c4e9cb4f7601 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 21 Jul 2022 14:14:53 +0400 Subject: [PATCH 004/147] arch/risc-v/src/opensbi/Make.defs: Switch opensbi to the nuttx/size optimized version in tiiuae repo Signed-off-by: Jukka Laitinen --- arch/risc-v/src/opensbi/Make.defs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs index 4b0f37d1116be..5f56cf3353fdf 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -43,10 +43,10 @@ INCLUDES += ${INCDIR_PREFIX}$(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdpar SBI_DIR := opensbi OPENSBI_UNPACK = opensbi-3rdparty -OPENSBI_COMMIT = fbaaafe808f3da7745760d757c436ef1b293d3ed -OPENSBI_URL = https://github.com/riscv-software-src/opensbi/tarball +OPENSBI_COMMIT = 19b05a2fd4fd04329d26f73a73e179631d7ae44c +OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = riscv-software-src-opensbi-fbaaafe +OPENSBI_DIR = tiiuae-opensbi-19b05a2 $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) From 45351424d24e0e9e2edd63e2d682def4341fb9f2 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 17 Aug 2022 15:43:38 +0400 Subject: [PATCH 005/147] [REVERTME] arch/risc-v/src/mpfs/mpfs_ethernet.c: Hack the ethernet driver to re-initialize on rx timeout If the interface is UP, and no packets are received in 30s, re-initialize the interface by calling the already implemented mpfs_txtimeout_expiry. This is a temporary workaround for a bug where IF might be UP and working but packets can only be transmitted. Receive side just doesn't work at all. The original bug can be re-produced easily by disconnecting and reconnecting the ethernet cable while the IF is up. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_ethernet.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/risc-v/src/mpfs/mpfs_ethernet.c b/arch/risc-v/src/mpfs/mpfs_ethernet.c index 382477fa9e60e..467e46a173538 100644 --- a/arch/risc-v/src/mpfs/mpfs_ethernet.c +++ b/arch/risc-v/src/mpfs/mpfs_ethernet.c @@ -171,6 +171,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 +272,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 +394,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 +476,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 +1572,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 +1622,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. From e67bbe11cdf0e69526a309c2e0c3cb3b61b4fc93 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 14 Sep 2022 12:50:22 +0400 Subject: [PATCH 006/147] [HACK] Set SD-card speed to 50MHz SD-card clock speed is just forced to 50MHz. Note that to be correct, one should first set the SD-card into high-speed mode, but currently NuttX doesn't support this. With our cards, just setting the interface to 50MHz seems to work fine, and it removes the issue with 25MHZ clock causing disturbance on GPS bands. Typically cards which support high-speed mode just work with 50MHz interface clock. This patch should be reverted when the NuttX supports high-speed mode, and we can properly set it. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_emmcsd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index 267894dc81c1e..d141dfb0f2c8a 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -152,7 +152,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 */ @@ -1866,7 +1866,7 @@ 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; } From 1870a5c95d489b32b072f98573b172cfe04abc01 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 20 Sep 2022 14:56:42 +0300 Subject: [PATCH 007/147] opensbi: Take SBI version that removes console into use --- arch/risc-v/src/opensbi/Make.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs index 5f56cf3353fdf..cae6f7f674958 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -43,10 +43,10 @@ INCLUDES += ${INCDIR_PREFIX}$(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdpar SBI_DIR := opensbi OPENSBI_UNPACK = opensbi-3rdparty -OPENSBI_COMMIT = 19b05a2fd4fd04329d26f73a73e179631d7ae44c +OPENSBI_COMMIT = b18bb7ce78d4e5504a9cbd8df7b57d795f489a0a OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = tiiuae-opensbi-19b05a2 +OPENSBI_DIR = tiiuae-opensbi-b18bb7c $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) From da031e55febcb5cb568457f60c1f092f77d6c03f Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 28 Sep 2022 10:56:19 +0400 Subject: [PATCH 008/147] Fix standalone defconfig for CI Signed-off-by: Jukka Laitinen --- boards/risc-v/mpfs/icicle/configs/standalone/defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/boards/risc-v/mpfs/icicle/configs/standalone/defconfig b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig index 7958978dacb46..78d417dfdee52 100644 --- a/boards/risc-v/mpfs/icicle/configs/standalone/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig @@ -27,7 +27,6 @@ CONFIG_IDLETHREAD_STACKSIZE=2048 CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INIT_STACKSIZE=3072 CONFIG_INTELHEX_BINARY=y -CONFIG_LIBC_FLOATINGPOINT=y CONFIG_LIBC_HOSTNAME="icicle" CONFIG_LIBC_PERROR_STDOUT=y CONFIG_LIBC_STRERROR=y From 9c49561cfb117977337b87fffd102dfc5e258006 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 28 Sep 2022 11:42:00 +0400 Subject: [PATCH 009/147] arch/risc-v/src/mpfs/mpfs_clockconfig.c: Flag out code only used in bootloader This removes the need to have all the DDR/clock configuration related "LIBERODEFS" flags defined, when not building a standalone/coldboot configuration All of this code is unused when not building with CONFIG_MPFS_BOOTLOADER Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_clockconfig.c | 4 ++++ 1 file changed, 4 insertions(+) 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 ****************************************************************************/ From 3943af68f53fa85adb66ca88960579b06c79c13a Mon Sep 17 00:00:00 2001 From: haitomatic Date: Thu, 26 May 2022 16:07:53 +0300 Subject: [PATCH 010/147] arch/risc-v/src/mpfs: Add mpfs canfd socket can driver --- arch/risc-v/src/mpfs/Kconfig | 31 + arch/risc-v/src/mpfs/Make.defs | 4 + .../src/mpfs/hardware/mpfs_fpga_canfd.h | 465 +++ arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 2915 +++++++++++++++++ arch/risc-v/src/mpfs/mpfs_fpga_canfd.h | 94 + 5 files changed, 3509 insertions(+) create mode 100644 arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h create mode 100644 arch/risc-v/src/mpfs/mpfs_fpga_canfd.c create mode 100644 arch/risc-v/src/mpfs/mpfs_fpga_canfd.h diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 9ba677b2acf52..a70d9b36c0647 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -624,6 +624,37 @@ config MPFS_COREPWM1_NCHANNELS range 1 16 depends on MPFS_COREPWM1 +comment "CAN-FD Options" + +config MPFS_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_CANFD_BASE + hex "Base address for the instance" + default 0x46000000 + depends on MPFS_CANFD + +config MPFS_CANFD_CLK + int "Clock frequency of the CANFD block (Hz)" + default 62500000 + range 1000000 100000000 + depends on MPFS_CANFD + +config MPFS_CANFD_ARBI_BITRATE + int "CAN FD Arbitration phase bitrate" + default 1000000 + depends on MPFS_CANFD + +config MPFS_CANFD_DATA_BITRATE + int "CAN Arbitration phase bitrate" + default 4000000 + depends on MPFS_CANFD + endmenu config MPFS_DMA diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index 6e060cef60e07..7bd6d0ac2cf57 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -78,6 +78,10 @@ ifeq (${CONFIG_MPFS_HAVE_COREPWM},y) CHIP_CSRCS += mpfs_corepwm.c endif +ifeq (${CONFIG_MPFS_CANFD}, y) +CHIP_CSRCS += mpfs_fpga_canfd.c +endif + ifeq (${CONFIG_MPFS_DDR_INIT},y) CHIP_CSRCS += mpfs_ddr.c endif 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..e883ccef22011 --- /dev/null +++ b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h @@ -0,0 +1,465 @@ +/**************************************************************************** + * 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 + +/**************************************************************************** + * 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/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c new file mode 100644 index 0000000000000..fc9d0ec202be5 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -0,0 +1,2915 @@ +/**************************************************************************** + * 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 "hardware/mpfs_fpga_canfd.h" +#include "riscv_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef OK +# define OK 0 +#endif + +/* This module only compiles if the CAN-FD IP core instance + * is configured to the FPGA + */ + +#ifndef CONFIG_MPFS_CANFD +# error This should not be compiled as CAN-FD 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 CAN-FD 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 CAN-FD 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 CAN-FD FPGA IRQ */ +}; + +static const struct mpfs_config_s mpfs_fpga_canfd_config = +{ + .canfd_fpga_irq = MPFS_IRQ_FABRIC_F2H_0, +}; + +/**************************************************************************** + * 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 + ****************************************************************************/ + +static struct mpfs_driver_s g_canfd; + +static uint8_t g_tx_pool[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; +static uint8_t g_rx_pool[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * + POOL_SIZE]; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* (from interrupt) RX related functions */ + +static void 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 void 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_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: + * None + * + * Assumptions: + * Frame format word is already parsed in advance and provided as 'ffw' arg + * + ****************************************************************************/ + +static void mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, + struct canfd_frame *cf, + uint32_t ffw) +{ + uint32_t idw; + 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 */ + + idw = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + 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 */ + + getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + + /* Data */ + + for (i = 0; i < len; i += 4) + { + uint32_t data = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + + *(uint32_t *)(cf->data + i) = data; + } + + /* Read and discard exceeding data that does not fit any frame. read + * pointer is automatically increased if RX buffer is not empty. + */ + + while (expect_false(i < data_bc)) + { + getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + i += 4; + } +} + +/**************************************************************************** + * 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; + 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; + + 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 */ + + mpfs_can_retrieve_rx_frame(priv, cf, ffw); + + /* 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); + + /* 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; + } + + /* Check for RX FIFO Overflow */ + + status = getreg32(priv->base + MPFS_CANFD_STATUS_OFFSET); + if (MPFS_CANFD_STATUS_DOR & status) + { + /* Notify to socket interface */ + + NETDEV_RXERRORS(&priv->dev); + + /* Clear Data Overrun */ + + putreg32(MPFS_CANFD_COMMAND_CDO, + priv->base + MPFS_CANFD_COMMAND_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: + * None + * + * Assumptions: + * None + * + ****************************************************************************/ + +static void 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. CLear txb status change interrupt */ + + putreg32(MPFS_CANFD_INT_STAT_TXBHCI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + + return; + } + 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); + } + } + + if (buffer_processed) + { + /* Since there are some buffers processed and the number of TXT + * used now matched the number of processed buffer, we can clear + * the interrupt in order to avoid any erroneous interrupt after + * the last true TXT buffer interrupt is processed. + */ + + putreg32(MPFS_CANFD_INT_STAT_TXBHCI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + } + } + while (buffer_processed); +} + +/**************************************************************************** + * 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 CAN-FD 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: + 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"); + 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"); + 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++; + } + + /* 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; + uint32_t imask; + int irq_loops; + + for (irq_loops = 0; irq_loops < 10000; irq_loops++) + { + /* Get the interrupt status */ + + isr = getreg32(priv->base + MPFS_CANFD_INT_STAT_OFFSET); + + /* Check and exit interrupt service routine if there is no int flag in + * INT_STAT reg. + */ + + if (!isr) + { + return irq_loops ? OK : -1; + } + + /* Receive Buffer Not Empty Interrupt */ + + if (isr & MPFS_CANFD_INT_STAT_RBNEI) + { + /* Mask RBNEI first, then clear interrupt. Even if + * another IRQ fires, RBNEI will always be 0 (masked). + */ + + icr = MPFS_CANFD_INT_STAT_RBNEI; + putreg32(icr, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); + putreg32(icr, priv->base + MPFS_CANFD_INT_STAT_OFFSET); + + /* Schedule work to process RX frame from CAN controller */ + + work_queue(CANWORK, &priv->rxwork, mpfs_receive_work, priv, 0); + } + + /* TXT Buffer HW Command Interrupt */ + + if (isr & MPFS_CANFD_INT_STAT_TXBHCI) + { + /* Clear TX interrupt flags */ + + mpfs_txdone(priv); + + /* 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 || + isr & MPFS_CANFD_INT_STAT_FCSI || + isr & MPFS_CANFD_INT_STAT_ALI || + isr & MPFS_CANFD_INT_STAT_BEI) + { + icr = isr & (MPFS_CANFD_INT_STAT_EWLI | + MPFS_CANFD_INT_STAT_FCSI | + MPFS_CANFD_INT_STAT_ALI | + MPFS_CANFD_INT_STAT_BEI); + canerr("Some error interrupts. Clearing 0x%08x\n", icr); + putreg32(icr, priv->base + MPFS_CANFD_INT_STAT_OFFSET); + mpfs_err_interrupt(priv, isr); + } + } + + /* Now, it seems that there are still some interrupt flags that remain + * stuck in INT_STAT reg. + */ + + canerr("Stuck interrupt (isr=%08x)\n", isr); + + /* Check if any of the stuck one belongs to txb status. */ + + if (isr & MPFS_CANFD_INT_STAT_TXBHCI) + { +#if 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); + + /* Clear txb status change interrupt */ + + putreg32(MPFS_CANFD_INT_STAT_TXBHCI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + } + + /* Check if any of the stuck one belongs to RX buffer data overrun */ + + if (isr & MPFS_CANFD_INT_STAT_DOI) + { + /* Notify to socket interface */ + + NETDEV_RXERRORS(&priv->dev); + + /* Clear Data Overrun interrupt */ + + putreg32(MPFS_CANFD_INT_STAT_DOI, + priv->base + MPFS_CANFD_INT_STAT_OFFSET); + } + + /* Clear and reset all interrupt. */ + + canwarn("Reset all interrupts...\n"); + imask = 0xffffffff; + putreg32(imask, priv->base + MPFS_CANFD_INT_ENA_CLR_OFFSET); + putreg32(imask, priv->base + MPFS_CANFD_INT_ENA_SET_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) + { + if (!devif_loopback(&priv->dev)) + { + /* 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); + + 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, priv->base + MPFS_CANFD_FILTER_A_VAL_OFFSET); + putreg32(fid2, 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, priv->base + MPFS_CANFD_FILTER_B_VAL_OFFSET); + putreg32(fid2, 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, priv->base + MPFS_CANFD_FILTER_C_VAL_OFFSET); + putreg32(fid2, 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, priv->base + MPFS_CANFD_FILTER_RAN_LOW_OFFSET); + putreg32(fid2, 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; + + /* 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; + } + + int_msk = ~int_ena; /* Mask all disabled interrupts */ + + /* It's after reset, so there is no need to clear anything */ + + 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); +} + +/**************************************************************************** + * 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->txdesc = (struct canfd_frame *)&g_tx_pool; + priv->rxdesc = (struct canfd_frame *)&g_rx_pool; + + 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 CAN-FD driver is + * returned. NULL is returned on any failure. + * + * Assumptions: + * None + * + ****************************************************************************/ + +int mpfs_fpga_canfd_init(void) +{ + caninfo("Initialize CAN-FD driver...\n"); + struct mpfs_driver_s *priv; + priv = &g_canfd; + memset(priv, 0, sizeof(struct mpfs_driver_s)); + + priv->base = CONFIG_MPFS_CANFD_BASE; + priv->config = &mpfs_fpga_canfd_config; + + /* Initialize the CAN common private data structure */ + + priv->can.state = CAN_STATE_ERROR_ACTIVE; + priv->ntxbufs = 2; + priv->can.bittiming_const = &mpfs_can_bit_timing_range; + priv->can.data_bittiming_const = &mpfs_can_bit_timing_data_range; + + /* Get the can_clk info */ + + priv->can.clock.freq = CONFIG_MPFS_CANFD_CLK; + + /* Needed for timing adjustment to be performed as soon as possible */ + + priv->can.bittiming.bitrate = CONFIG_MPFS_CANFD_ARBI_BITRATE; + priv->can.data_bittiming.bitrate = CONFIG_MPFS_CANFD_DATA_BITRATE; + priv->can.bittiming.sjw = 5; + priv->can.data_bittiming.sjw = 5; + + /* Calculate nominal 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); + +#ifdef CONFIG_NETDEV_CAN_FILTER_IOCTL + /* Init hw filter runtime var */ + + priv->used_bit_filter_number = 0; + priv->used_range_filter = false; +#endif /* CONFIG_NETDEV_CAN_FILTER_IOCTL */ + + /* Set CAN control modes */ + + priv->can.ctrlmode = CAN_CTRLMODE_FD + | CAN_CTRLMODE_BERR_REPORTING; + + /* Attach the interrupt handler */ + + if (irq_attach(priv->config->canfd_fpga_irq, mpfs_interrupt, priv)) + { + /* We could not attach the ISR to the interrupt */ + + canerr("ERROR: Failed to attach to CAN IRQ\n"); + return -EAGAIN; + } + + /* Initialize the driver structure */ + + priv->dev.d_ifup = mpfs_ifup; /* I/F up (new IP address) callback */ + priv->dev.d_ifdown = mpfs_ifdown; /* I/F down callback */ + priv->dev.d_txavail = mpfs_txavail; /* New TX data callback */ +#ifdef CONFIG_NETDEV_IOCTL + priv->dev.d_ioctl = mpfs_ioctl; /* Support CAN ioctl() calls */ +#endif + priv->dev.d_private = priv; /* Used to recover private state from dev */ + + /* Reset controller */ + + if (mpfs_reset(priv) < 0) + { + return -1; + } + + caninfo("CAN-FD 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(&priv->dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + netdev_register(&priv->dev, NET_LL_CAN); + + 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..4d925560b7d9f --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h @@ -0,0 +1,94 @@ +/**************************************************************************** + * 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_CANFD + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "hardware/mpfs_fpga_canfd.h" + +/**************************************************************************** + * 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_CANFD */ +#endif /* __ARCH_RISCV_SRC_MPFS_MPFS_FPGA_CANFD_H */ From 38a301513883a224625d2b7127415ef1027beb50 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Wed, 15 Jun 2022 09:30:29 +0000 Subject: [PATCH 011/147] boards/risc-v/mpfs/icicle: add new target for testing mpfs canfd driver --- .../mpfs/icicle/configs/canfd/defconfig | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 boards/risc-v/mpfs/icicle/configs/canfd/defconfig 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..94ce3f360e6d1 --- /dev/null +++ b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig @@ -0,0 +1,125 @@ +# +# 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_NSH_DISABLE_LOSMART is not set +# CONFIG_SPI_CALLBACK 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_ERROR=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_WARN=y +CONFIG_DEBUG_CUSTOM_INFO=y +CONFIG_DEBUG_NET=y +CONFIG_DEBUG_NET_INFO=y +CONFIG_DEBUG_NET_WARN=y +CONFIG_DEBUG_NET_ERROR=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_FLOATINGPOINT=y +CONFIG_LIBC_HOSTNAME="icicle" +CONFIG_LIBC_PERROR_STDOUT=y +CONFIG_LIBC_STRERROR=y +CONFIG_MEMSET_64BIT=y +CONFIG_MEMSET_OPTSPEED=y +CONFIG_MPFS_ENABLE_DPFPU=y +CONFIG_MPFS_UART1=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y + +# nsh commands enable +CONFIG_NSH_DISABLE_IFUPDOWN=n +CONFIG_NSH_DISABLE_ENV=n +CONFIG_NSH_DISABLE_MKDIR=n +CONFIG_NSH_DISABLE_RM=n +CONFIG_NSH_DISABLE_RMDIR=n +CONFIG_NSH_DISABLE_UMOUNT=y +CONFIG_NSH_DISABLE_UNSET=n +CONFIG_NSH_DISABLE_SET=n +CONFIG_NSH_DISABLE_SOURCE=n +CONFIG_NSH_DISABLE_UNAME=n +CONFIG_NSH_DISABLE_PWD=n +CONFIG_NSH_DISABLE_PS=n +CONFIG_NSH_DISABLE_MV=n +CONFIG_NSH_DISABLE_IFCONFIG=n +CONFIG_NSH_DISABLE_DMESG=n +CONFIG_NSH_DISABLE_DF=n + +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 + +# Net +CONFIG_NET=y +CONFIG_NET_ETHERNET=n +CONFIG_NET_IPv4=n +# CONFIG_NET_ETHERNET=y +# CONFIG_NET_IPv4=y +CONFIG_NET_READAHEAD=y +CONFIG_NETDEV_LATEINIT=y + +# Net socket +CONFIG_NSOCKET_DESCRIPTORS=8 +CONFIG_NET_NACTIVESOCKETS=16 +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_TIMESTAMP=n +CONFIG_NETDEV_IFINDEX=y +CONFIG_NSH_NETINIT=y # or where network is init? + +# socketCAN +CONFIG_NET_CANPROTO_OPTIONS=y +CONFIG_NET_CAN=y +CONFIG_NET_CAN_CANFD=y +CONFIG_CAN_CONNS=4 +CONFIG_NET_CAN_SOCK_OPTS=y +CONFIG_NET_CAN_RAW_FILTER_MAX=32 + +# MPFS FGPA CANFD +CONFIG_MPFS_CANFD=y From 34b693557ced61dfd70dc35ebc850aebb12c1102 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 30 Nov 2022 11:57:34 +0200 Subject: [PATCH 012/147] mpfs/emmcsd: Set same base clock for SDR/DDR modes --- arch/risc-v/src/mpfs/mpfs_emmcsd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index d141dfb0f2c8a..dafc1f468d6e0 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -1845,7 +1845,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; } From b913e85cc17afbc575d21b86e65eb5eb6fd6cb70 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 30 Nov 2022 11:58:17 +0200 Subject: [PATCH 013/147] mpfs/emmcsd: [HACK] Set 8-bit data width and DDR HS mode for eMMC This is not the correct way to do this, but it gives a nice perf. boost --- arch/risc-v/src/mpfs/mpfs_emmcsd.c | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index dafc1f468d6e0..2bea993a9f054 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -1802,6 +1802,57 @@ 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) +{ + int ret; + uint32_t r1; + + if ((ret = mpfs_sendcmd(dev, MMCSD_CMD6, 0x03b70000u | (6 << 8))) == 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; + } + + modifyreg32(MPFS_EMMCSD_HRS06, 0, priv->bus_mode); + + if ((ret = mpfs_sendcmd(dev, MMCSD_CMD6, 0x03b70000u | (2 << 8))) == 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; + } + + modifyreg32(MPFS_EMMCSD_SRS10, 0, MPFS_EMMCSD_SRS10_EDTW); + 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 * @@ -1874,6 +1925,15 @@ static void mpfs_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) /* Set the new clock frequency */ mpfs_setclkrate(priv, clckr); + + /* REVISIT: This should really be a separate configuration procedure */ + + if (rate == CLOCK_MMC_TRANSFER) + { + /* eMMC: Set 8-bit data bus and correct bus mode */ + + mpfs_set_hs_8bit(dev); + } } /**************************************************************************** From f6694fb80f771f0a4eb0697cbb8840e8b4745b7e Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 30 Nov 2022 13:40:08 +0200 Subject: [PATCH 014/147] mpfs/emmcsd: Fix build issue with 8-bit HS mode --- arch/risc-v/src/mpfs/mpfs_emmcsd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index 2bea993a9f054..618c8b5aba6ab 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -1809,6 +1809,7 @@ static void mpfs_widebus(struct sdio_dev_s *dev, bool wide) 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; From 4f2ee91b97f60124c6dada99c33c999d31ed744e Mon Sep 17 00:00:00 2001 From: Jani Paalijarvi Date: Mon, 12 Dec 2022 17:25:45 +0200 Subject: [PATCH 015/147] Fix build.yml Disable macOS builds for now. --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b630ce2bd34a7..83e20bbcc7cc0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -173,6 +173,7 @@ jobs: continue-on-error: true macOS: + if: ${{ false }} # disable for now permissions: contents: none runs-on: macos-13 From 542c1fe6f5172c120abc40efef2f42f44a00dcd6 Mon Sep 17 00:00:00 2001 From: Jani Paalijarvi Date: Tue, 13 Dec 2022 09:22:25 +0200 Subject: [PATCH 016/147] drivers/net/rpmsgdrv.c: Support only TRANSFER commands All other commands are disabled in send_recv(). Signed-off-by: Jani Paalijarvi --- drivers/net/rpmsgdrv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/rpmsgdrv.c b/drivers/net/rpmsgdrv.c index 3f55c31584b21..3280399cde872 100644 --- a/drivers/net/rpmsgdrv.c +++ b/drivers/net/rpmsgdrv.c @@ -609,6 +609,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; From bd903b89f963dd73241ba029843ca2ed31c15c9b Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 19 Jan 2023 12:06:33 +0400 Subject: [PATCH 017/147] arch/risc-v/src/mpfs/mpfs_fpga_canfd.c: Fix CONFIG_DEBUG_CAN_INFO ifdef and forward declare devif_loopback Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index fc9d0ec202be5..0fb3ea06eebec 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -50,6 +50,12 @@ #include "hardware/mpfs_fpga_canfd.h" #include "riscv_internal.h" +/**************************************************************************** + * Forward Declarations + ****************************************************************************/ + +extern int devif_loopback(FAR struct net_driver_s *dev); + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -1196,7 +1202,7 @@ static int mpfs_interrupt(int irq, void *context, void *arg) if (isr & MPFS_CANFD_INT_STAT_TXBHCI) { -#if CONFIG_DEBUG_CAN_INFO +#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++) From 1ddb55e025ba87615aa1a4c40855cf0f6380f292 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 19 Jan 2023 15:05:36 +0400 Subject: [PATCH 018/147] boards/risc-v/mpfs/icicle/configs/canfd/defconfig: Normalize Signed-off-by: Jukka Laitinen --- .../mpfs/icicle/configs/canfd/defconfig | 63 ++++--------------- 1 file changed, 11 insertions(+), 52 deletions(-) diff --git a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig index 94ce3f360e6d1..32507993c60e8 100644 --- a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig @@ -6,8 +6,9 @@ # 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_SPI_CALLBACK is not set CONFIG_ALLOW_BSD_COMPONENTS=y CONFIG_ARCH="risc-v" CONFIG_ARCH_BOARD="icicle" @@ -26,13 +27,12 @@ CONFIG_DEBUG_ERROR=y CONFIG_DEBUG_FEATURES=y CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_SYMBOLS=y -CONFIG_DEBUG_WARN=y -CONFIG_DEBUG_CUSTOM_INFO=y CONFIG_DEBUG_NET=y +CONFIG_DEBUG_NET_ERROR=y CONFIG_DEBUG_NET_INFO=y CONFIG_DEBUG_NET_WARN=y -CONFIG_DEBUG_NET_ERROR=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEBUG_WARN=y CONFIG_DEV_ZERO=y CONFIG_EXPERIMENTAL=y CONFIG_FS_PROCFS=y @@ -41,35 +41,22 @@ CONFIG_IDLETHREAD_STACKSIZE=2048 CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INIT_STACKSIZE=3072 CONFIG_INTELHEX_BINARY=y -CONFIG_LIBC_FLOATINGPOINT=y CONFIG_LIBC_HOSTNAME="icicle" CONFIG_LIBC_PERROR_STDOUT=y CONFIG_LIBC_STRERROR=y CONFIG_MEMSET_64BIT=y CONFIG_MEMSET_OPTSPEED=y +CONFIG_MPFS_CANFD=y CONFIG_MPFS_ENABLE_DPFPU=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 - -# nsh commands enable -CONFIG_NSH_DISABLE_IFUPDOWN=n -CONFIG_NSH_DISABLE_ENV=n -CONFIG_NSH_DISABLE_MKDIR=n -CONFIG_NSH_DISABLE_RM=n -CONFIG_NSH_DISABLE_RMDIR=n CONFIG_NSH_DISABLE_UMOUNT=y -CONFIG_NSH_DISABLE_UNSET=n -CONFIG_NSH_DISABLE_SET=n -CONFIG_NSH_DISABLE_SOURCE=n -CONFIG_NSH_DISABLE_UNAME=n -CONFIG_NSH_DISABLE_PWD=n -CONFIG_NSH_DISABLE_PS=n -CONFIG_NSH_DISABLE_MV=n -CONFIG_NSH_DISABLE_IFCONFIG=n -CONFIG_NSH_DISABLE_DMESG=n -CONFIG_NSH_DISABLE_DF=n - CONFIG_NSH_LINELEN=160 CONFIG_NSH_STRERROR=y CONFIG_PREALLOC_TIMERS=4 @@ -95,31 +82,3 @@ CONFIG_TASK_NAME_SIZE=20 CONFIG_TESTING_GETPRIME=y CONFIG_TESTING_OSTEST=y CONFIG_UART1_SERIAL_CONSOLE=y - -# Net -CONFIG_NET=y -CONFIG_NET_ETHERNET=n -CONFIG_NET_IPv4=n -# CONFIG_NET_ETHERNET=y -# CONFIG_NET_IPv4=y -CONFIG_NET_READAHEAD=y -CONFIG_NETDEV_LATEINIT=y - -# Net socket -CONFIG_NSOCKET_DESCRIPTORS=8 -CONFIG_NET_NACTIVESOCKETS=16 -CONFIG_NET_SOCKOPTS=y -CONFIG_NET_TIMESTAMP=n -CONFIG_NETDEV_IFINDEX=y -CONFIG_NSH_NETINIT=y # or where network is init? - -# socketCAN -CONFIG_NET_CANPROTO_OPTIONS=y -CONFIG_NET_CAN=y -CONFIG_NET_CAN_CANFD=y -CONFIG_CAN_CONNS=4 -CONFIG_NET_CAN_SOCK_OPTS=y -CONFIG_NET_CAN_RAW_FILTER_MAX=32 - -# MPFS FGPA CANFD -CONFIG_MPFS_CANFD=y From d0ef7aed75967aca17e3dc822a54f21cfa39ba65 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Thu, 19 Jan 2023 19:59:44 +0000 Subject: [PATCH 019/147] remove devif_loopback in canfd driver since it is now devif_poll func that takes care of the need for loopback --- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index 0fb3ea06eebec..7fa4996cfe697 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -50,12 +50,6 @@ #include "hardware/mpfs_fpga_canfd.h" #include "riscv_internal.h" -/**************************************************************************** - * Forward Declarations - ****************************************************************************/ - -extern int devif_loopback(FAR struct net_driver_s *dev); - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -1517,20 +1511,17 @@ static int mpfs_txpoll(struct net_driver_s *dev) if (priv->dev.d_len > 0) { - if (!devif_loopback(&priv->dev)) - { - /* Send the packet */ + /* Send the packet */ - mpfs_transmit(priv); + 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. - */ + /* 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 (!MPFS_CAN_FD_TXNF(priv)) + { + return -EBUSY; } } From aaca09023b586ddfd7d1c3fe1987d3073416b2ab Mon Sep 17 00:00:00 2001 From: Jani Paalijarvi Date: Fri, 27 Jan 2023 10:57:21 +0200 Subject: [PATCH 020/147] Remove MPFS_IHC_LINUX_ON_HART4 from default configurations Enable LINUX_ON_HART4 in rpmsg-ch2 defconfig of ICICLE board. Remove LINUX_ON_HART4 config from rpmsg-ch1 defconfig of ICICLE board. --- arch/risc-v/src/mpfs/Kconfig | 2 +- boards/risc-v/mpfs/icicle/configs/rpmsg-ch1/defconfig | 1 - boards/risc-v/mpfs/icicle/configs/rpmsg-ch2/defconfig | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index a70d9b36c0647..1d16c0fd9a872 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -410,7 +410,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 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 From 979fdab1208fe54585de321c5d9b723def58bff9 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 3 Feb 2023 17:17:15 +0400 Subject: [PATCH 021/147] arch/arm/src/stm32f7/stm32_ethernet.c: Fix "unused variable" warning Fix build warning when CONFIG_STM32F7_AUTONEG is not set Signed-off-by: Jukka Laitinen --- arch/arm/src/stm32f7/stm32_ethernet.c | 2 ++ 1 file changed, 2 insertions(+) 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; From fb79ce45c77e363c8f4ddd4fa8757bfa48544934 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 9 Feb 2023 20:53:42 +0400 Subject: [PATCH 022/147] arch/risc-v/src/mpfs/mpfs_userspace.c: Map MTIME into userspace reserved IO area in protected build Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/hardware/mpfs_clint.h | 6 ++++++ arch/risc-v/src/mpfs/mpfs_userspace.c | 5 +++++ 2 files changed, 11 insertions(+) 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/mpfs_userspace.c b/arch/risc-v/src/mpfs/mpfs_userspace.c index a4409e2dcb088..3b8f9ef5d5093 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" @@ -248,6 +249,10 @@ 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); From 966dd7145b5f7243bc2004bc9920ee1507ddc536 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 10 Feb 2023 15:48:33 +0400 Subject: [PATCH 023/147] boards/risc-v/mpfs/icicle: Add USRIO area for userspace IO mappings Signed-off-by: Jukka Laitinen --- boards/risc-v/mpfs/icicle/include/board_memorymap.h | 10 ++++++++++ boards/risc-v/mpfs/icicle/scripts/kernel-space.ld | 2 ++ boards/risc-v/mpfs/icicle/scripts/memory.ld | 2 ++ 3 files changed, 14 insertions(+) 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/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 } From 730618395ae475c383105dab1a8b1c53287c4ba0 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Mon, 13 Feb 2023 17:36:12 +0400 Subject: [PATCH 024/147] Add mpfs crypto driver into nuttx build Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/.gitignore | 1 + arch/risc-v/src/mpfs/Kconfig | 8 ++++++++ arch/risc-v/src/mpfs/Make.defs | 3 +++ arch/risc-v/src/mpfs/crypto.defs | 14 ++++++++++++++ 4 files changed, 26 insertions(+) create mode 100644 arch/risc-v/src/mpfs/.gitignore create mode 100644 arch/risc-v/src/mpfs/crypto.defs 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 1d16c0fd9a872..9603578946d3d 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -830,3 +830,11 @@ 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 +source crypto/Kconfig +#endif diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index 7bd6d0ac2cf57..6d883c80a3428 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -112,3 +112,6 @@ ifeq ($(CONFIG_MPFS_CORESPI),y) CHIP_CSRCS += mpfs_corespi.c endif +ifeq ($(CONFIG_MPFS_CRYPTO),y) +include mpfs/crypto.defs +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..44e6a4633968c --- /dev/null +++ b/arch/risc-v/src/mpfs/crypto.defs @@ -0,0 +1,14 @@ +MPFS_CRYPTO = mpfs/crypto/.git +$(MPFS_CRYPTO): + $(Q) echo "Cloning PolarFire crypto driver" + $(Q) git clone git@github.com:tiiuae/pf_crypto mpfs/crypto + +context::$(MPFS_CRYPTO) + +distclean:: + $(Q) rm -rf mpfs/crypto + +CHIP_CSRCS += mpfs_crypto.c + +DEPPATH += --dep-path crypto --dep-path mpfs/crypto +VPATH += :crypto:mpfs/crypto From a28d303cbe62301dfb3371ddaf8437efad77ffc2 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 14 Feb 2023 12:51:04 +0200 Subject: [PATCH 025/147] mpfs/Kconfig: fix typo on config file --- arch/risc-v/src/mpfs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 9603578946d3d..85816e4f15f2c 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -832,7 +832,7 @@ config MPFS_CORERMII_ADDRESS depends on MPFS_HAVE_CORERMII config MPFS_CRYPTO - bool "Enable MPFS HW crypto + bool "Enable MPFS HW crypto" default n #if MPFS_CRYPTO From dda0d9e84667ee0c6b9bb331bbc9e844e12da7de Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 14 Feb 2023 13:56:55 +0200 Subject: [PATCH 026/147] mpfs/mpfs_mm_init: Add the MTIME user mapping for kernel mode as well Just a temporary patch, need to implement some kind of scalable solution for this. It might be a good idea to map something else for the user to avoid using ecall to enter the kernel for simple reads ? Also, increase the L3 table size --- arch/risc-v/src/mpfs/mpfs_mm_init.c | 11 ++++++++--- arch/risc-v/src/mpfs/mpfs_userspace.c | 3 ++- boards/risc-v/mpfs/icicle/scripts/ld-kernel.script | 6 ++++++ 3 files changed, 16 insertions(+), 4 deletions(-) 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_userspace.c b/arch/risc-v/src/mpfs/mpfs_userspace.c index 3b8f9ef5d5093..f457a26f6b949 100644 --- a/arch/risc-v/src/mpfs/mpfs_userspace.c +++ b/arch/risc-v/src/mpfs/mpfs_userspace.c @@ -251,7 +251,8 @@ static void configure_mmu(void) /* 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); + 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 */ 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 From 4d7eb9800c60cc6a556b83e449347ebb0c408a40 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 23 Feb 2023 11:46:02 +0400 Subject: [PATCH 027/147] arch/risc-v/src/mpfs/Kconfig: Don't source crypto/Kconfig There is no make step executed for this directory before the Kconfigure, so all Kconfig's just need to be in-tree Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/Kconfig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 85816e4f15f2c..b18ca274b8ff2 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -835,6 +835,8 @@ config MPFS_CRYPTO bool "Enable MPFS HW crypto" default n -#if MPFS_CRYPTO -source crypto/Kconfig -#endif +if MPFS_CRYPTO +config MPFS_CRYPTO_DMA + bool "Enable MPFS HW crypto DMA" + default y +endif From 53374fd27fb633dfddd5c72fa077c0f8f013421d Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Mon, 6 Mar 2023 10:42:50 +0200 Subject: [PATCH 028/147] arch/risc-v/src/mpfs: symlink pf_crypto submodule --- arch/risc-v/src/mpfs/crypto.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/mpfs/crypto.defs b/arch/risc-v/src/mpfs/crypto.defs index 44e6a4633968c..caf2403be34ab 100644 --- a/arch/risc-v/src/mpfs/crypto.defs +++ b/arch/risc-v/src/mpfs/crypto.defs @@ -1,7 +1,7 @@ MPFS_CRYPTO = mpfs/crypto/.git $(MPFS_CRYPTO): - $(Q) echo "Cloning PolarFire crypto driver" - $(Q) git clone git@github.com:tiiuae/pf_crypto mpfs/crypto + $(Q) echo "Symlink PolarFire crypto driver submodule" + $(Q) $(DIRLINK) $(CURDIR)/../../../../extern/pf_crypto mpfs/crypto context::$(MPFS_CRYPTO) From d0125e459138d5e29bfddf0f0edaf88b3f7f2b9f Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 16 Mar 2023 13:00:35 +0200 Subject: [PATCH 029/147] arch/risc-v/src/mpfs/crypto.defs: Update to include mpfs_systemservice.c Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/crypto.defs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/risc-v/src/mpfs/crypto.defs b/arch/risc-v/src/mpfs/crypto.defs index caf2403be34ab..98f5c330e65c1 100644 --- a/arch/risc-v/src/mpfs/crypto.defs +++ b/arch/risc-v/src/mpfs/crypto.defs @@ -8,7 +8,7 @@ context::$(MPFS_CRYPTO) distclean:: $(Q) rm -rf mpfs/crypto -CHIP_CSRCS += mpfs_crypto.c +CHIP_CSRCS += mpfs_crypto.c mpfs_systemservice.c -DEPPATH += --dep-path crypto --dep-path mpfs/crypto -VPATH += :crypto:mpfs/crypto +DEPPATH += --dep-path mpfs/crypto +VPATH += :mpfs/crypto From 35424159a9bf1b6f574ebd8f5b13161930e5e256 Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Fri, 14 Apr 2023 10:51:57 +0300 Subject: [PATCH 030/147] emmc interrupt blackout issue fix sendfifo() function need enable BWR_IE before checking if BWE is enabled to avoid BWE to be activated between the BWE check and BWR interrupt enabling, which causes the interrupt to be missed and Data Timeout error. --- arch/risc-v/src/mpfs/mpfs_emmcsd.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index 618c8b5aba6ab..f5f8939109a86 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -779,12 +779,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); } } From 70d1883de01db97666cfae5f14b0b7a38e905c29 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 18 Apr 2023 15:18:54 +0300 Subject: [PATCH 031/147] mpfs/mpfs_userspace: Increase user space size to 8MB The user i/o area goes over 4MB, so need more page tables --- arch/risc-v/src/mpfs/mpfs_userspace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/mpfs_userspace.c b/arch/risc-v/src/mpfs/mpfs_userspace.c index f457a26f6b949..7c13fd6a41ac3 100644 --- a/arch/risc-v/src/mpfs/mpfs_userspace.c +++ b/arch/risc-v/src/mpfs/mpfs_userspace.c @@ -54,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) From c772b195b8066cd115f24d720d40da4588e73ac3 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Thu, 27 Apr 2023 12:22:25 +0000 Subject: [PATCH 032/147] canfd: fix hw filter --- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 37 ++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index 7fa4996cfe697..efe6f2f094e54 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -2049,6 +2049,27 @@ static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, 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: @@ -2081,8 +2102,8 @@ static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, /* Set bit filter value / mask */ - putreg32(fid1, priv->base + MPFS_CANFD_FILTER_A_VAL_OFFSET); - putreg32(fid2, priv->base + MPFS_CANFD_FILTER_A_MASK_OFFSET); + 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: @@ -2115,8 +2136,8 @@ static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, /* Set bit filter value / mask */ - putreg32(fid1, priv->base + MPFS_CANFD_FILTER_B_VAL_OFFSET); - putreg32(fid2, priv->base + MPFS_CANFD_FILTER_B_MASK_OFFSET); + 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: @@ -2149,8 +2170,8 @@ static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, /* Set bit filter value / mask */ - putreg32(fid1, priv->base + MPFS_CANFD_FILTER_C_VAL_OFFSET); - putreg32(fid2, priv->base + MPFS_CANFD_FILTER_C_MASK_OFFSET); + 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: @@ -2183,8 +2204,8 @@ static void mpfs_can_add_hw_filter(struct mpfs_driver_s *priv, /* Set range filter low / high */ - putreg32(fid1, priv->base + MPFS_CANFD_FILTER_RAN_LOW_OFFSET); - putreg32(fid2, priv->base + MPFS_CANFD_FILTER_RAN_HIGH_OFFSET); + putreg32(fid1_trans, priv->base + MPFS_CANFD_FILTER_RAN_LOW_OFFSET); + putreg32(fid2_trans, priv->base + MPFS_CANFD_FILTER_RAN_HIGH_OFFSET); break; default: From d5b1e839d3ccc77b0c4215c440a719941ac1d305 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Tue, 9 May 2023 16:35:12 +0300 Subject: [PATCH 033/147] risc-v/mpfs: serial: add fpga uarts Add FPGA serial support, including console capabilities. FPGA has UARTs from 0-7, so all UARTs starting from 5 depend on FPGA. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/Kconfig | 51 +++ .../risc-v/src/mpfs/hardware/mpfs_memorymap.h | 11 + arch/risc-v/src/mpfs/mpfs_config.h | 45 ++- arch/risc-v/src/mpfs/mpfs_lowputc.c | 117 +++++- arch/risc-v/src/mpfs/mpfs_serial.c | 355 +++++++++++++++++- 5 files changed, 562 insertions(+), 17 deletions(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index b18ca274b8ff2..d85913b020889 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -252,6 +252,27 @@ 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_SPI0 @@ -262,6 +283,12 @@ config MPFS_SPI1 bool "SPI 1" default n +config MPFS_FPGA_UART + bool "FPGA uarts" + default n + ---help--- + Use FPGA UARTs instead of MSS UARTS. + config MPFS_UART0 bool "UART 0" default n @@ -297,6 +324,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 diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h index 5d93013734d19..cbc55d9f18011 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 0x4c000100UL +#define MPFS_FPGA_UART2_BASE 0x4c000200UL +#define MPFS_FPGA_UART3_BASE 0x4c000300UL +#define MPFS_FPGA_UART4_BASE 0x4c000400UL +#define MPFS_FPGA_UART5_BASE 0x4c000500UL +#define MPFS_FPGA_UART6_BASE 0x4c000600UL +#define MPFS_FPGA_UART7_BASE 0x4c000700UL + #endif /* __ARCH_RISCV_SRC_MPFS_HARDWARE_MPFS_MEMORYMAP_H */ 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_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_serial.c b/arch/risc-v/src/mpfs/mpfs_serial.c index ec9ab908cf712..64dcfee59620c 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 @@ -100,6 +109,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 +142,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 +213,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 +238,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 +270,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 +302,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 +334,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 +366,169 @@ 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 = +{ +#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 + +#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 = @@ -352,6 +551,104 @@ static uart_dev_t g_uart4port = }; #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,27 +744,41 @@ 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 { @@ -494,7 +805,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: @@ -1140,6 +1458,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 +1513,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 } /**************************************************************************** From 18b27f170b83be3892803b0ae3742d222897afc2 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 12 May 2023 10:22:00 +0300 Subject: [PATCH 034/147] Add CONFIG_MPFS_SPI flag to define using SOC hard-ip SPI block Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/Kconfig | 6 ++++++ arch/risc-v/src/mpfs/Make.defs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index d85913b020889..5c1b81c19ddf1 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -275,13 +275,19 @@ config MPFS_HAVE_UART7 # 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" diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index 6d883c80a3428..dea41b5216ec9 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 From cebd840b05a7298489c7ae1d441e174eb1d2c072 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 12 May 2023 10:23:31 +0300 Subject: [PATCH 035/147] arch/risc-v/src/mpfs: Remove CONFIG_MPFS_COREPWMx_PWMCLK configs These are always the same as FPGA peripheral clock, so use that directly Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/Kconfig | 12 ------------ arch/risc-v/src/mpfs/mpfs_corepwm.c | 9 +++------ 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 5c1b81c19ddf1..7dd96c67eb095 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -634,12 +634,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 @@ -663,12 +657,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 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); From 791c121cecc7258483cdd3346e4a9b2b84116f4f Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Fri, 12 May 2023 15:26:15 +0300 Subject: [PATCH 036/147] risc-v/mpfs: serial: fix uart closing Don't turn off FIC3 clk which would terminate all other peripherals depending on it. Also add a few missing undefs. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/mpfs_serial.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_serial.c b/arch/risc-v/src/mpfs/mpfs_serial.c index 64dcfee59620c..8fb857274a557 100644 --- a/arch/risc-v/src/mpfs/mpfs_serial.c +++ b/arch/risc-v/src/mpfs/mpfs_serial.c @@ -99,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) @@ -782,10 +785,17 @@ static void up_enable_uart(struct up_dev_s *priv, bool enable) } 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); + } } } From 1b397a07809e051b7b099434222641513f138407 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Mon, 15 May 2023 16:14:06 +0300 Subject: [PATCH 037/147] Change MPFS_FPGA_UARTx_BASE addresses to 4k aligned as per new FPGA image Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h index cbc55d9f18011..54d9fda0c2d2c 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_memorymap.h @@ -133,12 +133,12 @@ /* FPGA UART defines */ #define MPFS_FPGA_UART0_BASE 0x4c000000UL -#define MPFS_FPGA_UART1_BASE 0x4c000100UL -#define MPFS_FPGA_UART2_BASE 0x4c000200UL -#define MPFS_FPGA_UART3_BASE 0x4c000300UL -#define MPFS_FPGA_UART4_BASE 0x4c000400UL -#define MPFS_FPGA_UART5_BASE 0x4c000500UL -#define MPFS_FPGA_UART6_BASE 0x4c000600UL -#define MPFS_FPGA_UART7_BASE 0x4c000700UL +#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 */ From ee839e4f38785a4ac357a2a4c47519b395ed9ece Mon Sep 17 00:00:00 2001 From: haitomatic Date: Wed, 10 May 2023 10:04:52 +0000 Subject: [PATCH 038/147] Add support for 2xCAN --- arch/risc-v/src/mpfs/Kconfig | 57 ++++- arch/risc-v/src/mpfs/Make.defs | 2 +- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 239 ++++++++++++++---- arch/risc-v/src/mpfs/mpfs_fpga_canfd.h | 4 +- .../mpfs/icicle/configs/canfd/defconfig | 2 +- 5 files changed, 236 insertions(+), 68 deletions(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 7dd96c67eb095..b058adaed4cc5 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -671,7 +671,7 @@ config MPFS_COREPWM1_NCHANNELS comment "CAN-FD Options" -config MPFS_CANFD +config MPFS_HAVE_CANFD bool "CAN FD" select ARCH_HAVE_CAN_ERRORS select NET_CAN_HAVE_CANFD @@ -679,26 +679,57 @@ config MPFS_CANFD select NET_CAN_HAVE_TX_DEADLINE default n -config MPFS_CANFD_BASE - hex "Base address for the instance" +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_CANFD + depends on MPFS_CANFD0 + +config MPFS_CANFD_CLK0 + int "Clock frequency of the CANFD0 block (Hz)" + default 62500000 + range 1000000 100000000 + 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_CLK - int "Clock frequency of the CANFD block (Hz)" +config MPFS_CANFD_CLK1 + int "Clock frequency of the CANFD1 block (Hz)" default 62500000 range 1000000 100000000 - depends on MPFS_CANFD + depends on MPFS_CANFD1 -config MPFS_CANFD_ARBI_BITRATE - int "CAN FD Arbitration phase bitrate" +config MPFS_CANFD_ARBI_BITRATE1 + int "CANFD1 Arbitration phase bitrate" default 1000000 - depends on MPFS_CANFD + depends on MPFS_CANFD1 -config MPFS_CANFD_DATA_BITRATE - int "CAN Arbitration phase bitrate" +config MPFS_CANFD_DATA_BITRATE1 + int "CANFD1 Data phase bitrate" default 4000000 - depends on MPFS_CANFD + depends on MPFS_CANFD1 endmenu diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index dea41b5216ec9..925e4467619a8 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -78,7 +78,7 @@ ifeq (${CONFIG_MPFS_HAVE_COREPWM},y) CHIP_CSRCS += mpfs_corepwm.c endif -ifeq (${CONFIG_MPFS_CANFD}, y) +ifeq (${CONFIG_MPFS_HAVE_CANFD}, y) CHIP_CSRCS += mpfs_fpga_canfd.c endif diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index efe6f2f094e54..6262fa0869dd4 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -58,18 +58,18 @@ # define OK 0 #endif -/* This module only compiles if the CAN-FD IP core instance +/* This module only compiles if the CANFD IP core instance * is configured to the FPGA */ -#ifndef CONFIG_MPFS_CANFD -# error This should not be compiled as CAN-FD FPGA block is not defined +#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 CAN-FD driver relies on socket CAN +# error This should not be compiled as CANFD driver relies on socket CAN #endif /* Clock reset and enabling */ @@ -83,7 +83,7 @@ #define MPFS_CANFD_ID 0xCAFD -/* For allocating the tx and rx CAN-FD frame buffer */ +/* For allocating the tx and rx CANFD frame buffer */ #define POOL_SIZE 1 #define TIMESTAMP_SIZE sizeof(struct timeval) /* To support @@ -332,13 +332,21 @@ enum mpfs_canfd_can_frame_format struct mpfs_config_s { - uint32_t canfd_fpga_irq; /* the only CAN-FD FPGA IRQ */ + uint32_t canfd_fpga_irq; /* the only CANFD FPGA IRQ */ }; -static const struct mpfs_config_s mpfs_fpga_canfd_config = +#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 @@ -390,12 +398,23 @@ struct mpfs_driver_s * Private Data ****************************************************************************/ -static struct mpfs_driver_s g_canfd; +#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_pool[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * +static uint8_t g_tx_pool1[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * POOL_SIZE]; -static uint8_t g_rx_pool[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * +static uint8_t g_rx_pool1[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * POOL_SIZE]; +#endif /**************************************************************************** * Private Function Prototypes @@ -971,7 +990,7 @@ static enum mpfs_can_state_e return CAN_STATE_BUS_OFF; } - canwarn("Invalid FPGA CAN-FD error state\n"); + canwarn("Invalid FPGA CANFD error state\n"); return CAN_STATE_ERROR_PASSIVE; } @@ -1059,6 +1078,7 @@ static void mpfs_err_interrupt(struct mpfs_driver_s *priv, uint32_t isr) 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: @@ -1196,6 +1216,8 @@ static int mpfs_interrupt(int irq, void *context, void *arg) if (isr & MPFS_CANFD_INT_STAT_TXBHCI) { + canerr("TXBHCI interrupt\n"); + #ifdef CONFIG_DEBUG_CAN_INFO caninfo("txb_sent=0x%08x txb_processed=0x%08x\n", priv->txb_sent, priv->txb_processed); @@ -1219,6 +1241,8 @@ static int mpfs_interrupt(int irq, void *context, void *arg) if (isr & MPFS_CANFD_INT_STAT_DOI) { + canerr("DOI interrupt\n"); + /* Notify to socket interface */ NETDEV_RXERRORS(&priv->dev); @@ -2468,6 +2492,8 @@ static int mpfs_reset(struct mpfs_driver_s *priv) nxsig_usleep(200); } while (1); + + priv->can.can_stats.restarts++; } /**************************************************************************** @@ -2499,9 +2525,6 @@ static int mpfs_ifup(struct net_driver_s *dev) priv->bifup = true; - priv->txdesc = (struct canfd_frame *)&g_tx_pool; - priv->rxdesc = (struct canfd_frame *)&g_rx_pool; - priv->dev.d_buf = (uint8_t *)priv->txdesc; /* Set interrupts */ @@ -2833,7 +2856,7 @@ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) * Initialize the CAN controller and driver * * Returned Value: - * On success, a pointer to the MPFS CAN-FD driver is + * On success, a pointer to the MPFS CANFD driver is * returned. NULL is returned on any failure. * * Assumptions: @@ -2843,91 +2866,205 @@ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) int mpfs_fpga_canfd_init(void) { - caninfo("Initialize CAN-FD driver...\n"); - struct mpfs_driver_s *priv; - priv = &g_canfd; - memset(priv, 0, sizeof(struct mpfs_driver_s)); +#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)); - priv->base = CONFIG_MPFS_CANFD_BASE; - priv->config = &mpfs_fpga_canfd_config; + priv0->base = CONFIG_MPFS_CANFD_BASE0; + priv0->config = &mpfs_fpga_canfd_config0; /* Initialize the CAN common private data structure */ - priv->can.state = CAN_STATE_ERROR_ACTIVE; - priv->ntxbufs = 2; - priv->can.bittiming_const = &mpfs_can_bit_timing_range; - priv->can.data_bittiming_const = &mpfs_can_bit_timing_data_range; + 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 */ - priv->can.clock.freq = CONFIG_MPFS_CANFD_CLK; + priv0->can.clock.freq = CONFIG_MPFS_CANFD_CLK0; /* Needed for timing adjustment to be performed as soon as possible */ - priv->can.bittiming.bitrate = CONFIG_MPFS_CANFD_ARBI_BITRATE; - priv->can.data_bittiming.bitrate = CONFIG_MPFS_CANFD_DATA_BITRATE; - priv->can.bittiming.sjw = 5; - priv->can.data_bittiming.sjw = 5; + 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(priv, - &priv->can.bittiming, - priv->can.bittiming_const); - mpfs_can_btr_compute(priv, - &priv->can.data_bittiming, - priv->can.data_bittiming_const); + 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 */ - priv->used_bit_filter_number = 0; - priv->used_range_filter = false; + 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 = CONFIG_MPFS_CANFD_CLK1; + + /* 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 */ - priv->can.ctrlmode = CAN_CTRLMODE_FD + priv1->can.ctrlmode = CAN_CTRLMODE_FD | CAN_CTRLMODE_BERR_REPORTING; /* Attach the interrupt handler */ - if (irq_attach(priv->config->canfd_fpga_irq, mpfs_interrupt, priv)) + 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 CAN IRQ\n"); + canerr("ERROR: Failed to attach to CAN1 IRQ\n"); return -EAGAIN; } - /* Initialize the driver structure */ + /* 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 */ - priv->dev.d_ifup = mpfs_ifup; /* I/F up (new IP address) callback */ - priv->dev.d_ifdown = mpfs_ifdown; /* I/F down callback */ - priv->dev.d_txavail = mpfs_txavail; /* New TX data callback */ + 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 - priv->dev.d_ioctl = mpfs_ioctl; /* Support CAN ioctl() calls */ + priv1->dev.d_ioctl = mpfs_ioctl; /* Support CAN ioctl() calls */ #endif - priv->dev.d_private = priv; /* Used to recover private state from dev */ + priv1->dev.d_private = priv1; /* Used to recover private state from dev */ /* Reset controller */ - if (mpfs_reset(priv) < 0) + if (mpfs_reset(priv1) < 0) { return -1; } - caninfo("CAN-FD driver init done\n"); + 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(&priv->dev); + mpfs_ifdown(&priv1->dev); /* Register the device with the OS so that socket IOCTLs can be performed */ - netdev_register(&priv->dev, NET_LL_CAN); + 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 index 4d925560b7d9f..d7dc98098bba0 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h @@ -35,7 +35,7 @@ /* Check if CAN-FD support is enabled. */ -#ifdef CONFIG_MPFS_CANFD +#ifdef CONFIG_MPFS_HAVE_CANFD /**************************************************************************** * Included Files @@ -90,5 +90,5 @@ int mpfs_fpga_canfd_init(void); #endif #endif /* __ASSEMBLY__ */ -#endif /* CONFIG_MPFS_CANFD */ +#endif /* CONFIG_MPFS_HAVE_CANFD */ #endif /* __ARCH_RISCV_SRC_MPFS_MPFS_FPGA_CANFD_H */ diff --git a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig index 32507993c60e8..0c1101b582987 100644 --- a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig @@ -46,7 +46,7 @@ CONFIG_LIBC_PERROR_STDOUT=y CONFIG_LIBC_STRERROR=y CONFIG_MEMSET_64BIT=y CONFIG_MEMSET_OPTSPEED=y -CONFIG_MPFS_CANFD=y +CONFIG_MPFS_HAVE_CANFD=y CONFIG_MPFS_ENABLE_DPFPU=y CONFIG_MPFS_UART1=y CONFIG_NET=y From 93056e66a7ea2aac6212122fadd83af4d4ef0612 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Tue, 16 May 2023 10:00:40 +0000 Subject: [PATCH 039/147] canfd : add missing configs for 2xCAN support --- boards/risc-v/mpfs/icicle/configs/canfd/defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig index 0c1101b582987..97d0ac1545c59 100644 --- a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig @@ -47,6 +47,8 @@ CONFIG_LIBC_STRERROR=y CONFIG_MEMSET_64BIT=y CONFIG_MEMSET_OPTSPEED=y CONFIG_MPFS_HAVE_CANFD=y +CONFIG_MPFS_CANFD0=y +CONFIG_MPFS_CANFD1=y CONFIG_MPFS_ENABLE_DPFPU=y CONFIG_MPFS_UART1=y CONFIG_NET=y From 2ba70653a8168156a6219f6c0caba4689146d177 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Tue, 16 May 2023 10:29:48 +0000 Subject: [PATCH 040/147] canfd : use board peripheral clock --- arch/risc-v/src/mpfs/Kconfig | 12 ------------ arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 4 ++-- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index b058adaed4cc5..43b901798c34a 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -689,12 +689,6 @@ config MPFS_CANFD_BASE0 default 0x46000000 depends on MPFS_CANFD0 -config MPFS_CANFD_CLK0 - int "Clock frequency of the CANFD0 block (Hz)" - default 62500000 - range 1000000 100000000 - depends on MPFS_CANFD0 - config MPFS_CANFD_ARBI_BITRATE0 int "CANFD0 Arbitration phase bitrate" default 1000000 @@ -715,12 +709,6 @@ config MPFS_CANFD_BASE1 default 0x47000000 depends on MPFS_CANFD1 -config MPFS_CANFD_CLK1 - int "Clock frequency of the CANFD1 block (Hz)" - default 62500000 - range 1000000 100000000 - depends on MPFS_CANFD1 - config MPFS_CANFD_ARBI_BITRATE1 int "CANFD1 Arbitration phase bitrate" default 1000000 diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index 6262fa0869dd4..64910be0287eb 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -2891,7 +2891,7 @@ int mpfs_fpga_canfd_init(void) /* Get the can_clk info */ - priv0->can.clock.freq = CONFIG_MPFS_CANFD_CLK0; + priv0->can.clock.freq = MPFS_FPGA_PERIPHERAL_CLK; /* Needed for timing adjustment to be performed as soon as possible */ @@ -2991,7 +2991,7 @@ int mpfs_fpga_canfd_init(void) /* Get the can_clk info */ - priv1->can.clock.freq = CONFIG_MPFS_CANFD_CLK1; + priv1->can.clock.freq = MPFS_FPGA_PERIPHERAL_CLK; /* Needed for timing adjustment to be performed as soon as possible */ From d954bd6c2a2912ec04e57ad023d40e6bd5db803b Mon Sep 17 00:00:00 2001 From: haitomatic Date: Wed, 17 May 2023 10:59:20 +0000 Subject: [PATCH 041/147] canfd : normalize defconfig --- boards/risc-v/mpfs/icicle/configs/canfd/defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig index 97d0ac1545c59..7bcc1380138d6 100644 --- a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig @@ -46,10 +46,10 @@ CONFIG_LIBC_PERROR_STDOUT=y CONFIG_LIBC_STRERROR=y CONFIG_MEMSET_64BIT=y CONFIG_MEMSET_OPTSPEED=y -CONFIG_MPFS_HAVE_CANFD=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 From 361a44dffc43c947eae1740bf2d646ee69073632 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 19 May 2023 15:36:14 +0300 Subject: [PATCH 042/147] arch/risc-v/src/mpfs/mpfs_timerisr.c: Partially revert common mtime driver change Revert: commit 19758788356f8623bac5f439419e231ff81cac14 Author: Huang Qi Date: Mon Apr 11 18:42:24 2022 +0800 arch/risc-v: Apply common mtime driver to mtime based chps Signed-off-by: Huang Qi As this breaks the systick Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_timerisr.c | 76 ++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_timerisr.c b/arch/risc-v/src/mpfs/mpfs_timerisr.c index 3a43fa278f18e..b9db1e760d23c 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,62 @@ * Pre-processor Definitions ****************************************************************************/ -#define MTIMER_FREQ MPFS_MSS_RTC_TOGGLE_CLK +#define TICK_COUNT (MPFS_MSS_RTC_TOGGLE_CLK / TICK_PER_SEC) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static bool _b_tick_started; +static uint64_t *_mtime_cmp; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mpfs_reload_mtimecmp + ****************************************************************************/ + +static void mpfs_reload_mtimecmp(void) +{ + irqstate_t flags = spin_lock_irqsave(NULL); + + uint64_t current; + uint64_t next; + + if (!_b_tick_started) + { + _b_tick_started = true; + current = getreg64(MPFS_CLINT_MTIME); + } + else + { + current = getreg64(_mtime_cmp); + } + + uint64_t tick = TICK_COUNT; + next = current + tick; + + putreg64(next, _mtime_cmp); + + 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 @@ -65,12 +116,17 @@ void up_timer_initialize(void) /* what is our timecmp address for this hart */ uintptr_t hart_id = riscv_mhartid(); + _mtime_cmp = (uint64_t *)MPFS_CLINT_MTIMECMP0 + hart_id; + + /* Attach timer interrupt handler */ + + irq_attach(RISCV_IRQ_MTIMER, 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_MTIMER); } From 0397e5b62201af79d3dd956cee4609903d0d7444 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 24 May 2023 07:09:52 +0300 Subject: [PATCH 043/147] arch/risc-v/src/mpfs: Make mpfs_hart_index2id table modifiable by bootloader This is actually the same table as entrypoints, so just use the same data, which can be set before booting any of the harts Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_entrypoints.c | 24 +++++++++++++++++++ arch/risc-v/src/mpfs/mpfs_entrypoints.h | 16 +++++++++++++ arch/risc-v/src/mpfs/mpfs_opensbi.c | 32 +++++++------------------ 3 files changed, 48 insertions(+), 24 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_entrypoints.c b/arch/risc-v/src/mpfs/mpfs_entrypoints.c index 2480253f783e6..fdcbc1a3b4d56 100644 --- a/arch/risc-v/src/mpfs/mpfs_entrypoints.c +++ b/arch/risc-v/src/mpfs/mpfs_entrypoints.c @@ -221,4 +221,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_opensbi.c b/arch/risc-v/src/mpfs/mpfs_opensbi.c index ad9e835c346c5..76af1f59366fa 100644 --- a/arch/risc-v/src/mpfs/mpfs_opensbi.c +++ b/arch/risc-v/src/mpfs/mpfs_opensbi.c @@ -184,30 +184,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 = { @@ -602,6 +579,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); From 461ab29754c5d397d73a131cda7410cbbb572812 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 24 May 2023 12:55:54 +0300 Subject: [PATCH 044/147] mpfs_timerisr: Add patch to make the code work in CONFIG_BUILD_KERNEL --- arch/risc-v/src/mpfs/mpfs_timerisr.c | 47 ++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_timerisr.c b/arch/risc-v/src/mpfs/mpfs_timerisr.c index b9db1e760d23c..b8c635811fef9 100644 --- a/arch/risc-v/src/mpfs/mpfs_timerisr.c +++ b/arch/risc-v/src/mpfs/mpfs_timerisr.c @@ -47,13 +47,41 @@ * 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 ****************************************************************************/ @@ -65,20 +93,11 @@ static void mpfs_reload_mtimecmp(void) uint64_t current; uint64_t next; - if (!_b_tick_started) - { - _b_tick_started = true; - current = getreg64(MPFS_CLINT_MTIME); - } - else - { - current = getreg64(_mtime_cmp); - } - + current = get_current(); uint64_t tick = TICK_COUNT; next = current + tick; - putreg64(next, _mtime_cmp); + set_next(next); spin_unlock_irqrestore(NULL, flags); } @@ -113,14 +132,16 @@ static int mpfs_timerisr(int irq, void *context, void *arg) 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_MTIMER, mpfs_timerisr, NULL); + irq_attach(RISCV_IRQ_TIMER, mpfs_timerisr, NULL); /* Reload CLINT mtimecmp */ @@ -128,5 +149,5 @@ void up_timer_initialize(void) /* And enable the timer interrupt */ - up_enable_irq(RISCV_IRQ_MTIMER); + up_enable_irq(RISCV_IRQ_TIMER); } From 9ba0690f2fbc4837f4737f9e9038f237b96f0b51 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 25 May 2023 10:19:50 +0300 Subject: [PATCH 045/147] arch/risc-v/src/mpfs/mpfs_opensbi.c: Fix conflicting datatypes defined by NuttX vs. opensbi Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_opensbi.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi.c b/arch/risc-v/src/mpfs/mpfs_opensbi.c index 76af1f59366fa..77f14d127e189 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 ****************************************************************************/ From ac2c32133bec14425fba2f903f26a35c7ff9518a Mon Sep 17 00:00:00 2001 From: haitomatic Date: Mon, 22 May 2023 13:11:36 +0000 Subject: [PATCH 046/147] net/can, net/devif: fix CAN RX/TX iob free semcount runaway issue --- net/can/can_callback.c | 16 +++++++++++++++ net/can/can_recvmsg.c | 45 +++++++++++++++++++++++------------------- net/devif/devif_send.c | 7 ++++++- 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/net/can/can_callback.c b/net/can/can_callback.c index d8ebfc65506ef..ac5de920937f5 100644 --- a/net/can/can_callback.c +++ b/net/can/can_callback.c @@ -62,6 +62,9 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn, uint16_t flags) { int buflen = dev->d_len; +#ifdef CONFIG_NET_TIMESTAMP + buflen -= sizeof(struct timeval); +#endif uint16_t recvlen; uint16_t ret; @@ -133,6 +136,19 @@ uint16_t can_callback(FAR struct net_driver_s *dev, if ((flags & CAN_NEWDATA) != 0) { + if (dev->d_iob->io_flink != NULL || + dev->d_iob->io_pktlen == 0 || + dev->d_iob->io_offset <= 0) + { + if (dev->d_iob->io_flink == NULL) + { + iob_free(dev->d_iob); + } + + netdev_iob_clear(dev); + return flags; + } + #ifdef CONFIG_NET_TIMESTAMP /* TIMESTAMP sockopt is activated, * create timestamp and copy to iob diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index f7dc4e459eb3a..b6a486b28463d 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -236,6 +236,19 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) if ((iob = iob_peek_queue(&conn->readahead)) != NULL && pstate->pr_buflen > 0) { + if (iob->io_flink != NULL || + iob->io_pktlen == 0 || + iob->io_offset <= 0) + { + if (iob->io_pktlen == 0 || iob->io_offset <= 0) + { + iob_free(iob); + } + + iob_remove_queue(&conn->readahead); + return 0; + } + DEBUGASSERT(iob->io_pktlen > 0); #ifdef CONFIG_NET_CANPROTO_OPTIONS @@ -283,31 +296,23 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) * beginning of the I/O buffer chain. */ - if (recvlen >= iob->io_pktlen) - { - FAR struct iob_s *tmp; + /* No trimming needed since one CAN/CANFD frame can perfectly + * fit in one iob + */ - /* Remove the I/O buffer chain from the head of the read-ahead - * buffer queue. - */ + FAR struct iob_s *tmp; - tmp = iob_remove_queue(&conn->readahead); - DEBUGASSERT(tmp == iob); - UNUSED(tmp); + /* Remove the I/O buffer chain from the head of the read-ahead + * buffer queue. + */ - /* And free the I/O buffer chain */ + tmp = iob_remove_queue(&conn->readahead); + DEBUGASSERT(tmp == iob); + UNUSED(tmp); - 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). - */ + /* And free the I/O buffer chain */ - 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) From ef38f6da49a219c291afc4bb800c8e3a2da6b19b Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 22 Jun 2023 15:45:44 +0300 Subject: [PATCH 047/147] mpfs_opensbi_utils.S: relocate OpenSBI into l2zerodevice This loads the OpenSBI from eNVM into the zerodevice. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/mpfs_opensbi_utils.S | 45 +++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S b/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S index db8f8fff7f738..9f43b5bb16621 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_zerodev_loadaddr + .weak _ssbi_zerodev + .weak _esbi_zerodev + + /* These are the weak pointless variables, only to get this PR compile */ + +_sbi_zerodev_loadaddr: + .dword 0x0a006000 +_ssbi_zerodev: + .dword _stext +_esbi_zerodev: + .dword _stext /**************************************************************************** * Private Data @@ -68,9 +84,38 @@ mpfs_global_pointer: * ****************************************************************************/ + .align 3 +mpfs_opensbi_relocate_from_envm: + + /* Relocate the code from eNVM into L2 zero device */ + + la a0, _sbi_zerodev_loadaddr + la a1, _ssbi_zerodev + la a2, _esbi_zerodev +.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 From c87ad9ff9f98598e4682a8edd1821776165b69c8 Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Wed, 28 Jun 2023 14:57:57 +0300 Subject: [PATCH 048/147] opensbi: update to contain shrinked version --- arch/risc-v/src/opensbi/Make.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs index cae6f7f674958..735bd5061f933 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -43,10 +43,10 @@ INCLUDES += ${INCDIR_PREFIX}$(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdpar SBI_DIR := opensbi OPENSBI_UNPACK = opensbi-3rdparty -OPENSBI_COMMIT = b18bb7ce78d4e5504a9cbd8df7b57d795f489a0a +OPENSBI_COMMIT = a082fb83f218a647d2009b565e573dac8f179cb9 OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = tiiuae-opensbi-b18bb7c +OPENSBI_DIR = tiiuae-opensbi-a082fb8 $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) From 400a507ba18e53b6274b804df8f7391e1963ed0b Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Wed, 9 Aug 2023 15:06:39 +0300 Subject: [PATCH 049/147] Disable linker relaxed addressing when loading gp --- arch/risc-v/src/mpfs/mpfs_opensbi_trap.S | 6 ++++-- arch/risc-v/src/mpfs/mpfs_opensbi_utils.S | 7 ------- 2 files changed, 4 insertions(+), 9 deletions(-) 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 9f43b5bb16621..6f623ed560def 100644 --- a/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S +++ b/arch/risc-v/src/mpfs/mpfs_opensbi_utils.S @@ -121,13 +121,6 @@ mpfs_opensbi_prepare_hart: 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 From 0155cfc46abe3937c3dd6aee8483863933d56924 Mon Sep 17 00:00:00 2001 From: Jani Paalijarvi Date: Wed, 30 Aug 2023 15:14:35 +0300 Subject: [PATCH 050/147] arch/risc-v/src/mpfs: Set USB DMA upper addr offset Use a configuration register to set the upper address lines [37:32] for USB DMA engine. Signed-off-by: Jani Paalijarvi --- arch/risc-v/src/mpfs/hardware/mpfs_usb.h | 8 ++++++++ arch/risc-v/src/mpfs/mpfs_usb.c | 8 ++++++++ boards/risc-v/mpfs/icicle/include/board.h | 2 ++ 3 files changed, 18 insertions(+) diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_usb.h b/arch/risc-v/src/mpfs/hardware/mpfs_usb.h index 863044d8ddd9a..bbea409fbdaba 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) /**************************************************************************** diff --git a/arch/risc-v/src/mpfs/mpfs_usb.c b/arch/risc-v/src/mpfs/mpfs_usb.c index fec9deb8fd823..5cf384618442b 100644 --- a/arch/risc-v/src/mpfs/mpfs_usb.c +++ b/arch/risc-v/src/mpfs/mpfs_usb.c @@ -124,6 +124,10 @@ # 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 @@ -3680,6 +3684,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/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) From e9838988468641d0f1748fa648f98be3c0fdccf7 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Tue, 26 Sep 2023 11:59:00 +0300 Subject: [PATCH 051/147] risc-v/mpfs: emmcsd: deny unaligned access Don't allow unaligned access with the DMA requests. Return -EFAULT in case the provided address is unaligned. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/mpfs_emmcsd.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index f5f8939109a86..9e96d895f2be9 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -2277,7 +2277,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; @@ -2337,7 +2341,11 @@ 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); + if (((uintptr_t)buffer & 3) != 0) + { + mcerr("Unaligned buffer: %p\n", buffer); + return -EFAULT; + } /* DMA send doesn't work in 0x08xxxxxxx address range. Default to IRQ mode * in this special case. From 7b9a5a367cd68c2ef904b1e93f3cde5bf9d929d8 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 4 Oct 2023 12:19:16 +0300 Subject: [PATCH 052/147] [REVERTME] riscv_addrenc.c: Add more heap, if TLS_ALIGNED is set The TLS alignment requires more room in the stack, which means more _initial_ heap is required to accomodate the stack. Why 2x TLS_MAXSTACK ? No idea. This is a temporary fix, like the +1 page extra above. --- arch/risc-v/src/common/riscv_addrenv.c | 7 +++++++ 1 file changed, 7 insertions(+) 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); From e4ba1333ae6b12af2543a5d558b7eab09f279208 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 10 Oct 2023 13:29:41 +0300 Subject: [PATCH 053/147] arch/risc-v/src/mpfs/mpfs_ddr.c: Add read dq/dqs eye centering test After read training, check also that the eye is centered properly. Sometimes after the training the width is long enough, but it is not centered. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_ddr.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_ddr.c b/arch/risc-v/src/mpfs/mpfs_ddr.c index 3819fba3a91f5..183284c20e6c1 100644 --- a/arch/risc-v/src/mpfs/mpfs_ddr.c +++ b/arch/risc-v/src/mpfs/mpfs_ddr.c @@ -3416,6 +3416,8 @@ static int mpfs_training_verify(void) uint32_t lane_sel; uint32_t last; uint32_t i; + uint32_t off_taps; + uint32_t width_taps; while (!(getreg32(MPFS_DDR_CSR_APB_STAT_DFI_TRAINING_COMPLETE) & 0x01) && --retries); @@ -3503,9 +3505,15 @@ 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; } From 76f0e45ced27613dca161bf1be17c59d0cec9c45 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 11 Oct 2023 12:59:44 +0300 Subject: [PATCH 054/147] arch/risc-v/src/mpfs/mpfs_ddr.c: Clean up the TXDLY verify step Just verify that the delay for the selected clock != 0 Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_ddr.c | 44 ++++----------------------------- 1 file changed, 5 insertions(+), 39 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_ddr.c b/arch/risc-v/src/mpfs/mpfs_ddr.c index 183284c20e6c1..a4e2393b4f478 100644 --- a/arch/risc-v/src/mpfs/mpfs_ddr.c +++ b/arch/risc-v/src/mpfs/mpfs_ddr.c @@ -3418,6 +3418,7 @@ static int mpfs_training_verify(void) 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); @@ -3520,47 +3521,12 @@ static int mpfs_training_verify(void) /* Extra checks */ - uint32_t temp = 0; - uint32_t gt_clk_sel = getreg32(MPFS_CFG_DDR_SGMII_PHY_GT_CLK_SEL) & - 0x03; + /* Check the GT_TXDLY result for the selected clock */ - 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; - } - } - - 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; } From 5ab5570342807553d4c6b46a2ab3f02b011a07d5 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 11 Oct 2023 12:38:12 +0300 Subject: [PATCH 055/147] arch/risc-v/src/mpfs/mpfs_ddr.c: Fix CA training verify step Corrections to CA training verify step. The original copied from HSS didn't make sense in all aspects: - The check is not per lane, so it should be out of the "for (lane_sel" loop. - The check wasn't proper. The expected outcome is just a vector of increasing numbers separated enough Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_ddr.c | 69 +++++++++++++-------------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_ddr.c b/arch/risc-v/src/mpfs/mpfs_ddr.c index a4e2393b4f478..95621f7364765 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 */ @@ -3407,14 +3405,11 @@ 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; @@ -3429,19 +3424,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), @@ -3453,46 +3444,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]) + if (low_ca_dly_count > 1) { - decrease_count++; - } + /* Retrain via reset */ - if ((LIBERO_SETTING_TRAINING_SKIP_SETTING & ADDCMD_BIT) != ADDCMD_BIT) - { - /* Retrain if abnormal CA training result detected */ - - 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 */ From 5be96e37ee9753702841c4f30523d6f3d213ed9d Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Fri, 3 Nov 2023 14:53:04 +0200 Subject: [PATCH 056/147] arch/risc-v/src/mpfs: Add hardware/mpfs_wdog.h --- arch/risc-v/src/mpfs/hardware/mpfs_wdog.h | 75 +++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 arch/risc-v/src/mpfs/hardware/mpfs_wdog.h 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 */ From 9f7817abd2d72ba634c857a8a279d32c605040d4 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Tue, 28 Nov 2023 13:18:32 +0200 Subject: [PATCH 057/147] risc-v/mpfs: usb: fix fierce cpu polling if remote closes If the remote end just closes an endpoint and no longer handles it, the system is prone to intensive cpu polling via mpfs_write_tx_fifo() especially if the device side doesn't know a thing about what the remote did. Fix this by marking the EP as dead, which will skip all writes causing unnecessary polling. The EP is back in business if the remote end sends some data (rx) or the connection is re-established. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/hardware/mpfs_usb.h | 1 + arch/risc-v/src/mpfs/mpfs_usb.c | 68 +++++++++++++++++++++--- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_usb.h b/arch/risc-v/src/mpfs/hardware/mpfs_usb.h index bbea409fbdaba..00f15dbedaf79 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_usb.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_usb.h @@ -427,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/mpfs_usb.c b/arch/risc-v/src/mpfs/mpfs_usb.c index 5cf384618442b..b996bf419439c 100644 --- a/arch/risc-v/src/mpfs/mpfs_usb.c +++ b/arch/risc-v/src/mpfs/mpfs_usb.c @@ -132,6 +132,8 @@ #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) @@ -228,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 = { @@ -771,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) @@ -796,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; } } @@ -2443,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; @@ -3455,11 +3490,28 @@ static int mpfs_usb_interrupt(int irq, void *context, void *arg) { for (i = 0; i < MPFS_USB_NENDPOINTS; i++) { + /* Check if dead connections are back in business */ + + if (g_linkdead) + { + /* This releases all, 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. + */ + + struct mpfs_ep_s *privep = &priv->eplist[i]; + 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) From 32725d7c1ee8978c7fdde33bfc8f43b9a06ba57d Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 30 Nov 2023 09:38:33 +0200 Subject: [PATCH 058/147] risc-v/mpfs: usb: don't try nonexistent ep int flags Currently the irq handler checks many reserved bits, which is a waste of resources: 1. pending_rx_ep bit 0 is reserved (always 0) 2. pending_rx_ep and pending_tx_ep have only bits 1, 2, 3 and 4 defined, no need to scan MPFS_USB_NENDPOINTS (9) bits as the rest are reserved Fix this by checking only the relevant bits. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/mpfs_usb.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_usb.c b/arch/risc-v/src/mpfs/mpfs_usb.c index b996bf419439c..5ca49b6ee7f88 100644 --- a/arch/risc-v/src/mpfs/mpfs_usb.c +++ b/arch/risc-v/src/mpfs/mpfs_usb.c @@ -3477,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) { @@ -3488,20 +3488,27 @@ 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, 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. + /* 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]; + struct mpfs_ep_s *privep = &priv->eplist[i + MPFS_EPIN_START]; privep->linkdead = 0; } From 20caa0a75dcc4b3f6cb31c8b64ad11e08022c554 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Mon, 4 Dec 2023 13:57:07 +0200 Subject: [PATCH 059/147] net: rpmsgdrv.c: prevent potential danger Provide support for NET_RPMSG_TRANSFER only: "It is recommended to drop all messages with commands other than NET_RPMSG_TRANSFER in function net_rpmsg_drv_ept_cb() of the flight controller." Signed-off-by: Eero Nurkkala --- drivers/net/rpmsgdrv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/rpmsgdrv.c b/drivers/net/rpmsgdrv.c index 3280399cde872..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])) { From 30b7eccb0ddd4de8e9d638e0aac7d6376fff9d1a Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Tue, 12 Dec 2023 10:02:13 +0200 Subject: [PATCH 060/147] fix MPFS_ETHMAC_LP/HPWORK flags Set HPWORK as default workqueue for eth ISR work --- arch/risc-v/src/mpfs/Kconfig | 14 ++++++++++++++ arch/risc-v/src/mpfs/mpfs_ethernet.c | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 43b901798c34a..ee6cd074c9cb7 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -846,6 +846,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 diff --git a/arch/risc-v/src/mpfs/mpfs_ethernet.c b/arch/risc-v/src/mpfs/mpfs_ethernet.c index 467e46a173538..bea93cc80ab65 100644 --- a/arch/risc-v/src/mpfs/mpfs_ethernet.c +++ b/arch/risc-v/src/mpfs/mpfs_ethernet.c @@ -101,7 +101,7 @@ # elif defined(CONFIG_MPFS_ETHMAC_LPWORK) # define ETHWORK LPWORK # else -# define ETHWORK LPWORK +# define ETHWORK HPWORK # endif #endif From cf8d458d01551b16b8576efc6aead43eced2f259 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 13 Apr 2023 14:57:44 +0300 Subject: [PATCH 061/147] risc-v/mpfs: emmcsd: enforce HS DDR mode Previously, address 0x03b70000u was written with shift bits that only changed the bit width, not the mode. HS mode is changed via 0x03B90100, which is required, according to Jedec specs, for DDR mode. HS mode was not applied before. Enforce DDR mode (50 MHz) for now. The real boost, however, comes from removing the DMA limitation at 0x08xxxxxx address space, which now seems unnecessary. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/mpfs_emmcsd.c | 53 +++++++++++++++++++----------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index 9e96d895f2be9..67f2c8e419d45 100644 --- a/arch/risc-v/src/mpfs/mpfs_emmcsd.c +++ b/arch/risc-v/src/mpfs/mpfs_emmcsd.c @@ -1822,8 +1822,15 @@ 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; - if ((ret = mpfs_sendcmd(dev, MMCSD_CMD6, 0x03b70000u | (6 << 8))) == OK) + /* 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) { @@ -1837,9 +1844,21 @@ static void mpfs_set_hs_8bit(struct sdio_dev_s *dev) goto err; } - modifyreg32(MPFS_EMMCSD_HRS06, 0, priv->bus_mode); + /* While busy */ + + do + { + rr = getreg32(MPFS_EMMCSD_SRS09); + } + while ((rr & (1 << 20)) == 0); + + /* mpfs to 8-bit mode */ - if ((ret = mpfs_sendcmd(dev, MMCSD_CMD6, 0x03b70000u | (2 << 8))) == OK) + 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) { @@ -1853,7 +1872,14 @@ static void mpfs_set_hs_8bit(struct sdio_dev_s *dev) goto err; } - modifyreg32(MPFS_EMMCSD_SRS10, 0, MPFS_EMMCSD_SRS10_EDTW); + /* While busy */ + + do + { + rr = getreg32(MPFS_EMMCSD_SRS09); + } + while ((rr & (1 << 20)) == 0); + return; err: @@ -1933,18 +1959,16 @@ static void mpfs_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate) break; } - /* Set the new clock frequency */ - - mpfs_setclkrate(priv, clckr); - - /* REVISIT: This should really be a separate configuration procedure */ - 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); } /**************************************************************************** @@ -2347,15 +2371,6 @@ static int mpfs_dmasendsetup(struct sdio_dev_s *dev, return -EFAULT; } - /* DMA send doesn't work in 0x08xxxxxxx address range. Default to IRQ mode - * in this special case. - */ - - if (((uintptr_t)buffer & 0xff000000) == 0x08000000) - { - return mpfs_sendsetup(dev, buffer, buflen); - } - /* Save the source buffer information for use by the interrupt handler */ priv->buffer = (uint32_t *)buffer; From a01eaafc382d16999000d1a05d837c1c3119760b Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Mon, 18 Dec 2023 08:50:43 +0200 Subject: [PATCH 062/147] risc-v/mpfs: ddr: lock segmentation registers Set the LOCKED bit when the final ddr segmentatition is in place. Otherwise the system is prone to potential security issues if the config is altered later. Once the LOCKED bit is set, the register may no longer be changed. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/mpfs_ddr.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/mpfs/mpfs_ddr.c b/arch/risc-v/src/mpfs/mpfs_ddr.c index 95621f7364765..565770dc1fed7 100644 --- a/arch/risc-v/src/mpfs/mpfs_ddr.c +++ b/arch/risc-v/src/mpfs/mpfs_ddr.c @@ -717,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 * @@ -756,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 */ @@ -768,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); From 9525f10361264b06e85094019bed2fb90d3cce95 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 21 Dec 2023 12:31:21 +0200 Subject: [PATCH 063/147] build.yml: Modify the build config Remove unnecessary junk, just build icicle (we don't care about the rest) --- .github/workflows/build.yml | 110 +++--------------------------------- tools/ci/cibuild.sh | 12 ++-- 2 files changed, 15 insertions(+), 107 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 83e20bbcc7cc0..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 @@ -89,7 +77,7 @@ jobs: echo "app_ref=$APPS_REF" >> $GITHUB_OUTPUT - name: Checkout nuttx repo - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: repository: tiiuae/nuttx ref: ${{ steps.gittargets.outputs.os_ref }} @@ -99,7 +87,7 @@ jobs: run: git -C sources/nuttx fetch --tags - name: Checkout apps repo - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: repository: tiiuae/incubator-nuttx-apps ref: ${{ steps.gittargets.outputs.apps_ref }} @@ -115,72 +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-12, risc-v] - - 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: - if: ${{ false }} # disable for now - 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 @@ -191,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/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 From 164ae43868dad0938caa3506696523cccb1e583c Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 3 Jan 2024 11:51:01 +0200 Subject: [PATCH 064/147] build.yml: Add ssrc board matrix for arm and risc-v Don't use the upstream build targets --- tools/ci/testlist/ssrc-arm.dat | 2 ++ tools/ci/testlist/ssrc-riscv.dat | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 tools/ci/testlist/ssrc-arm.dat create mode 100644 tools/ci/testlist/ssrc-riscv.dat 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 + From dba5de5e30f959e0a19fb002d5f39f5fd8a2b878 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 18 Jan 2024 15:00:53 +0200 Subject: [PATCH 065/147] [HACK] cstdlib: Forward malloc et. al. to kmm_malloc, if __KERNEL__ This is the only way to get the external module "uavcanlib" to work inside the px4 kernel. If an alternate solution, e.g. moving uavcanlib to user space is implemented this hack should be removed. --- include/cxx/cstdlib | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) 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 //*************************************************************************** From a418e48c8d119dfa51ff9d06a1f197378a10f279 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 26 Jan 2024 14:57:00 +0200 Subject: [PATCH 066/147] mpfs_mpucfg.h: Add missing MPUCFG registers Now all registers are defined --- arch/risc-v/src/mpfs/hardware/mpfs_mpucfg.h | 54 +++++++++++++++++++++ 1 file changed, 54 insertions(+) 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) From 6c51e05885af97e8d9c4185221c3547d551e023a Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Thu, 9 Nov 2023 11:14:55 +0200 Subject: [PATCH 067/147] risc-v/mpfs: add tamper detection support This adds support for detecting various tamper events. The interrupt handler makes noise at every detection. Perhaps easiest test is to attach JTAG debugger. TAMPER_TESTS -define has some nonexisting (not in repos) calls, perhaps could remove it alltogether. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/Kconfig | 6 + arch/risc-v/src/mpfs/Make.defs | 4 + arch/risc-v/src/mpfs/mpfs_tamper.c | 396 +++++++++++++++++++++++++++++ arch/risc-v/src/mpfs/mpfs_tamper.h | 86 +++++++ 4 files changed, 492 insertions(+) create mode 100644 arch/risc-v/src/mpfs/mpfs_tamper.c create mode 100644 arch/risc-v/src/mpfs/mpfs_tamper.h diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index ee6cd074c9cb7..169d6069ea9bd 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -426,6 +426,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 diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index 925e4467619a8..e168aa6586171 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -112,6 +112,10 @@ 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 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 */ From 71ec880afbd5ce978ef9eada94128c1acb9f3ca6 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 8 Feb 2024 11:14:21 +0200 Subject: [PATCH 068/147] [REVERTME - useless] libs/libc/machine/risc-v/arch_elf.c: Minor optimization to _calc_imm Signed-off-by: Jukka Laitinen --- libs/libc/machine/risc-v/arch_elf.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) 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; From 5067846b30b5efd9c0b02443af3bb01746d6c811 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 5 Jan 2024 13:14:26 +0200 Subject: [PATCH 069/147] mpfs_mpu: Add driver to set MPUCFG registers MPUCFG registers are used to enforce memory protection for DMA master devices. --- arch/risc-v/src/mpfs/Kconfig | 6 + arch/risc-v/src/mpfs/Make.defs | 4 + arch/risc-v/src/mpfs/mpfs_mpu.c | 243 ++++++++++++++++++++++++++++++++ arch/risc-v/src/mpfs/mpfs_mpu.h | 79 +++++++++++ 4 files changed, 332 insertions(+) create mode 100644 arch/risc-v/src/mpfs/mpfs_mpu.c create mode 100644 arch/risc-v/src/mpfs/mpfs_mpu.h diff --git a/arch/risc-v/src/mpfs/Kconfig b/arch/risc-v/src/mpfs/Kconfig index 169d6069ea9bd..4e9b9194b4e09 100644 --- a/arch/risc-v/src/mpfs/Kconfig +++ b/arch/risc-v/src/mpfs/Kconfig @@ -906,6 +906,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 diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index e168aa6586171..bfcaba84ec486 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -119,3 +119,7 @@ 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/mpfs_mpu.c b/arch/risc-v/src/mpfs/mpfs_mpu.c new file mode 100644 index 0000000000000..58bc30f4e8deb --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_mpu.c @@ -0,0 +1,243 @@ +/**************************************************************************** + * 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 */ + + if ((base & 0x07) != 0 || size < 0x1000) + { + 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_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)); +} 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..6bef8fe5f4c25 --- /dev/null +++ b/arch/risc-v/src/mpfs/mpfs_mpu.h @@ -0,0 +1,79 @@ +/**************************************************************************** + * 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); + +#endif /* __ARCH_RISC_V_SRC_MPFS_MPFS_MPU_H */ From 21aae4670396ebc534bb6fab3a3c9d14f0e44553 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 11 Jan 2024 12:18:24 +0200 Subject: [PATCH 070/147] mpfs_usb.c: Remove PMPCFG configuration from the driver This is not the right place to modify DMA memory protection values. Why not? These are designed to protect other AMP mode instances. Opening the entire SoC's memory for the USB DMA kind of defeats this purpose. Also, the driver cannot know how to configure these registers correctly, only opening up the whole SoC "works". --- arch/risc-v/src/mpfs/mpfs_usb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_usb.c b/arch/risc-v/src/mpfs/mpfs_usb.c index 5ca49b6ee7f88..3c6be8ade298f 100644 --- a/arch/risc-v/src/mpfs/mpfs_usb.c +++ b/arch/risc-v/src/mpfs/mpfs_usb.c @@ -3676,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; @@ -3685,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 } From 7f50b53d8ef77c837bdc8e75e86ac6dba7537e62 Mon Sep 17 00:00:00 2001 From: Jari Nippula Date: Thu, 25 Jan 2024 19:05:16 +0200 Subject: [PATCH 071/147] wrapper to sdio device drivers --- arch/risc-v/src/mpfs/Make.defs | 4 + arch/risc-v/src/mpfs/mpfs_coremmc.c | 64 +------ arch/risc-v/src/mpfs/mpfs_coremmc.h | 12 +- arch/risc-v/src/mpfs/mpfs_emmcsd.c | 74 ++------ arch/risc-v/src/mpfs/mpfs_emmcsd.h | 12 +- arch/risc-v/src/mpfs/mpfs_sdio.c | 177 ++++++++++++++++++++ arch/risc-v/src/mpfs/mpfs_sdio.h | 112 +++++++++++++ arch/risc-v/src/mpfs/mpfs_sdio_dev.h | 92 ++++++++++ boards/risc-v/mpfs/common/src/mpfs_emmcsd.c | 2 +- 9 files changed, 419 insertions(+), 130 deletions(-) create mode 100644 arch/risc-v/src/mpfs/mpfs_sdio.c create mode 100644 arch/risc-v/src/mpfs/mpfs_sdio.h create mode 100644 arch/risc-v/src/mpfs/mpfs_sdio_dev.h diff --git a/arch/risc-v/src/mpfs/Make.defs b/arch/risc-v/src/mpfs/Make.defs index bfcaba84ec486..027277a5d0960 100644 --- a/arch/risc-v/src/mpfs/Make.defs +++ b/arch/risc-v/src/mpfs/Make.defs @@ -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 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_emmcsd.c b/arch/risc-v/src/mpfs/mpfs_emmcsd.c index 67f2c8e419d45..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 ****************************************************************************/ @@ -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 ****************************************************************************/ @@ -1145,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 @@ -3043,7 +2993,7 @@ static void mpfs_callback(void *arg) ****************************************************************************/ /**************************************************************************** - * Name: sdio_initialize + * Name: mpfs_emmcsd_sdio_initialize * * Description: * Initialize SDIO for operation. @@ -3057,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; @@ -3068,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 -- @@ -3093,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; @@ -3126,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 @@ -3141,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_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/boards/risc-v/mpfs/common/src/mpfs_emmcsd.c b/boards/risc-v/mpfs/common/src/mpfs_emmcsd.c index 25a0ed09d6638..217b66920d5b6 100644 --- a/boards/risc-v/mpfs/common/src/mpfs_emmcsd.c +++ b/boards/risc-v/mpfs/common/src/mpfs_emmcsd.c @@ -28,7 +28,7 @@ #include #include -#include "mpfs_emmcsd.h" +#include "mpfs_sdio.h" #include "board_config.h" /**************************************************************************** From b8964954b143c164afe3499adcba05f8d7e5cc18 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 18 Jan 2024 14:54:23 +0200 Subject: [PATCH 072/147] mpfs_corespi: Fix firing of stale interrupt after warm reset After warm reset the interrupt source in the HW block is not explicitly cleared, thus once the interrupt source is enabled the old / stale interrupt fires immediately. This causes a DEBUGASSERT() failure on line 808 mpfs_spi_unload_rx_fifo: DEBUGASSERT(nwords > 0); --- arch/risc-v/src/mpfs/mpfs_corespi.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/risc-v/src/mpfs/mpfs_corespi.c b/arch/risc-v/src/mpfs/mpfs_corespi.c index f92ed0123c8e1..e4931f86f7508 100644 --- a/arch/risc-v/src/mpfs/mpfs_corespi.c +++ b/arch/risc-v/src/mpfs/mpfs_corespi.c @@ -1435,6 +1435,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); } From e6fd583502acb6fef48d5e41f9ba34930e4ae42a Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 31 Oct 2023 11:46:02 +0200 Subject: [PATCH 073/147] arch/risc-v/src/mpfs/mpfs_serial.c: Allow switching uart output to console off By setting "isconsole" to false, mpfs_serial stops outputting to console. This can be used to disable output to debug console in low level. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_serial.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/risc-v/src/mpfs/mpfs_serial.c b/arch/risc-v/src/mpfs/mpfs_serial.c index 8fb857274a557..9064a1f060c4d 100644 --- a/arch/risc-v/src/mpfs/mpfs_serial.c +++ b/arch/risc-v/src/mpfs/mpfs_serial.c @@ -1355,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); @@ -1547,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 From 21d720584aeda2518186089aa6e457388596a21d Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Mon, 6 Nov 2023 17:25:13 +0200 Subject: [PATCH 074/147] risc-v/mpfs: i2c: prevent out of bounds read access priv->msgid may grow past its boundaries, causing struct i2c_msg_s *msg = &priv->msgv[priv->msgid] to read data out of boundaris. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/mpfs_i2c.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 26fa4408eb14e..7748db1f0fde9 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -493,7 +493,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 +515,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 { From 961ccc87adfd9d0d0706be46992a5765a8de8c42 Mon Sep 17 00:00:00 2001 From: Eero Nurkkala Date: Tue, 5 Dec 2023 12:53:39 +0200 Subject: [PATCH 075/147] risc-v/mpfs: i2c: perform sanity checks Replace risky DEBUGASSERT()s with real sanity checks. Also, do a few more checks as the system might occasionally fire an interrupt if the system has been restarted while in middle of an i2c transaction. Yet, modify i2c_transfer() function so that up_disable_irq() is always called at the end to better prevent ill-timed irqs. Signed-off-by: Eero Nurkkala --- arch/risc-v/src/mpfs/mpfs_i2c.c | 68 ++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 9 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 7748db1f0fde9..3a131f68e94a6 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -437,8 +437,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) @@ -479,7 +477,16 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) 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++; } @@ -557,10 +564,18 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) 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++; @@ -572,10 +587,29 @@ 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++; @@ -673,7 +707,11 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, int ret = OK; 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) @@ -715,9 +753,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 */ @@ -765,6 +811,10 @@ static int mpfs_i2c_transfer(struct i2c_master_s *dev, i2cinfo("Message %" PRIu8 " transfer complete.\n", priv->msgid); } + /* Irq was enabled at mpfs_i2c_sendstart() */ + + up_disable_irq(priv->plic_irq); + nxmutex_unlock(&priv->lock); return ret; } From 6488a4b4aa60f82463dbabd22a786876bd6f1af3 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 10 Jan 2024 08:45:25 +0200 Subject: [PATCH 076/147] arch/risc-v/src/mpfs/mpfs_i2c.c: Clear I2C_CTRL bits when initializing/deinitializing bus Ensure that there are no pending state or interrupts in the i2c controller. This removes errors caused by deinitialize/initialize sequences in error cases. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_i2c.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 3a131f68e94a6..020b8237e2f1c 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -358,10 +358,9 @@ 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 */ - modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_ENS1_MASK, - MPFS_I2C_CTRL_ENS1_MASK); + putreg32(MPFS_I2C_CTRL_ENS1_MASK, MPFS_I2C_CTRL); priv->initialized = true; } @@ -385,8 +384,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; } From 98be59119726636db37581cd535961231ae5aea3 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 10 Jan 2024 08:45:25 +0200 Subject: [PATCH 077/147] arch/risc-v/src/mpfs/mpfs_i2c.c: Add more error status codes Add more error status codes to help debugging in the future. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_i2c.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 020b8237e2f1c..0e39e3efc714d 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 @@ -468,7 +471,7 @@ 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: @@ -536,7 +539,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. */ @@ -558,7 +561,7 @@ 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: @@ -610,7 +613,6 @@ static int mpfs_i2c_irq(int cpuint, void *context, void *arg) 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; @@ -651,7 +653,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; From c5cd7fe2891e9da6a12a01fc99f70772b792db0d Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 11 Jan 2024 12:13:35 +0200 Subject: [PATCH 078/147] arch/risc-v/src/mpfs/mpfs_i2c.c: Correct i2c reset / error recovery - Use mpfs_i2c_deinit+mpfs_i2c_init sequence to re-initialize i2c block - Use the i2c mutex to protect the reset; in case there are several devices on the same bus, and one of them resets the bus, reset must not occur in the middle of another device's transfer. - Move irq attach to the i2c_init as the irq detach is in i2c_deinit Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_i2c.c | 45 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 0e39e3efc714d..e9754d4ddde25 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -126,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); @@ -301,8 +303,22 @@ 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; + if (!priv->initialized) { + /* Clear any pending serial interrupt flag */ + + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + + /* 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 @@ -838,26 +854,15 @@ 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() - */ - - up_disable_irq(priv->plic_irq); + nxmutex_lock(&priv->lock); - 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; } @@ -865,8 +870,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; } @@ -1060,14 +1067,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) { From 4d05bcd169b7d6c719653618c606f5398860344e Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 10 Jan 2024 08:45:25 +0200 Subject: [PATCH 079/147] arch/risc-v/src/mpfs/mpfs_i2c.c: Add more i2cerr traces Add sanity checks for debugging possible errors in the driver. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_i2c.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index e9754d4ddde25..495ff7658cfa0 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -721,6 +721,10 @@ 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); @@ -735,6 +739,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; @@ -827,6 +849,16 @@ 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); From bad4a41c123bea006b8e0e4d80053d9b927055a3 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 12 Jan 2024 15:49:27 +0200 Subject: [PATCH 080/147] arch/risc-v/src/mpfs/mpfs_i2c.c: Recover i2c from pending transactions in warm boot Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_i2c.c | 49 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index 495ff7658cfa0..cf0ecd418aa9f 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -304,12 +304,57 @@ 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) { - /* Clear any pending serial interrupt flag */ + /* 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. + */ - modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + 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 */ From a7bbe339ddc285e9e44e8ed60f1b3fe45cc8ef47 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 16 Jan 2024 16:09:38 +0200 Subject: [PATCH 081/147] arch/risc-v/src/mpfs/mpfs_irq.c: Fix up_irqinitialize for warm reboot It is possible that a PLIC IRQ is claimed but not completed at warm reset. This occurs at least if there is a fault in the middle of irq handler execution. To recover from such situation, we can complete all IRQ:s in PLIC; this completes any already claimed IRQ, but has no effect on IRQs which are not claimed or not enabled. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_irq.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) 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))); } From 24f84fda9413e6b4846bdcd3e9180298c2b6fad1 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 11 Jan 2024 12:22:21 +0200 Subject: [PATCH 082/147] mpfs_mpucfg.c: Add mpfs_mpu_lock() Add method to lock an MPUCFG entry. Locking means the value of the register cannot be changed until the SoC is reset. --- arch/risc-v/src/mpfs/mpfs_mpu.c | 54 ++++++++++++++++++++++++++++----- arch/risc-v/src/mpfs/mpfs_mpu.h | 20 ++++++++++-- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_mpu.c b/arch/risc-v/src/mpfs/mpfs_mpu.c index 58bc30f4e8deb..2643c79c0ac7a 100644 --- a/arch/risc-v/src/mpfs/mpfs_mpu.c +++ b/arch/risc-v/src/mpfs/mpfs_mpu.c @@ -61,9 +61,9 @@ /* 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)) +#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 */ @@ -91,7 +91,7 @@ * size - Size out. * * Returned Value: - * Base address + * Base address. * ****************************************************************************/ @@ -136,7 +136,7 @@ static void napot_decode(uintptr_t val, uintptr_t *base, uintptr_t *size) * size must align with each other. * * Returned Value: - * 0 on success; negated error on failure + * 0 on success; negated error on failure. * ****************************************************************************/ @@ -184,7 +184,7 @@ int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, /* Calculate mode (RWX), only NAPOT encoding is supported */ - mode = (perm & PMPCFG_RWX_MASK) | PMPCFG_A_NAPOT; + mode = (perm & (PMPCFG_RWX_MASK | PMPCFG_L)) | PMPCFG_A_NAPOT; /* Do the NAPOT encoding */ @@ -210,7 +210,7 @@ int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, * size - The length of the region. * * Returned Value: - * true if access OK; false if not + * true if access OK; false if not. * ****************************************************************************/ @@ -241,3 +241,43 @@ bool mpfs_mpu_access_ok(uintptr_t reg, uintptr_t perm, uintptr_t base, 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 index 6bef8fe5f4c25..d934cd64044ef 100644 --- a/arch/risc-v/src/mpfs/mpfs_mpu.h +++ b/arch/risc-v/src/mpfs/mpfs_mpu.h @@ -49,7 +49,7 @@ * size must align with each other. * * Returned Value: - * 0 on success; negated error on failure + * 0 on success; negated error on failure. * ****************************************************************************/ @@ -69,11 +69,27 @@ int mpfs_mpu_set(uintptr_t reg, uintptr_t perm, uintptr_t base, * size - The length of the region. * * Returned Value: - * true if access OK; false if not + * 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 */ From 065af556a42e00fb7a626fed449c7b080f42660c Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 31 Jan 2024 15:56:23 +0200 Subject: [PATCH 083/147] fs/shmfs: Fix CONFIG_FS_SHM -> CONFIG_FS_SHMFS The macro was wrong --- fs/shm/CMakeLists.txt | 2 +- fs/shm/Kconfig | 2 +- fs/vfs/fs_stat.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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/vfs/fs_stat.c b/fs/vfs/fs_stat.c index e6acc398580b6..74984fb300d38 100644 --- a/fs/vfs/fs_stat.c +++ b/fs/vfs/fs_stat.c @@ -278,7 +278,7 @@ 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)) From 2a5799db33edd1866e55cd7e937cf6717289f531 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 1 Feb 2024 12:31:46 +0200 Subject: [PATCH 084/147] fs/shmfs: Fix stat() system call for shmfs object Set i_size for shmfs objects --- fs/shm/shmfs.c | 5 +++++ fs/vfs/fs_stat.c | 1 + include/nuttx/fs/fs.h | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) 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/vfs/fs_stat.c b/fs/vfs/fs_stat.c index 74984fb300d38..200e629dcf7c1 100644 --- a/fs/vfs/fs_stat.c +++ b/fs/vfs/fs_stat.c @@ -284,6 +284,7 @@ int inode_stat(FAR struct inode *inode, FAR struct stat *buf, int resolve) if (INODE_IS_SHM(inode)) { buf->st_mode = S_IFSHM; + buf->st_size = inode->i_size; } else #endif 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 From aad6ae0dfb264de8277df4ccd0ee8bed09145ae9 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 1 Feb 2024 14:59:10 +0200 Subject: [PATCH 085/147] arch/addrenv: Add utility function to wipe one page up_addrenv_page_wipe can be used to wipe a single page of memory. --- arch/risc-v/src/common/riscv_addrenv_pgmap.c | 20 +++++++++++++++++++ include/nuttx/arch.h | 21 +++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/arch/risc-v/src/common/riscv_addrenv_pgmap.c b/arch/risc-v/src/common/riscv_addrenv_pgmap.c index da9e250e7652f..0d36c1adeb107 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 /**************************************************************************** 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 * From d27f710413344cda2c3d3dcd72c638c62fc37e7f Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 1 Feb 2024 14:59:35 +0200 Subject: [PATCH 086/147] arch/arm_addrenv_pgmap.c: Add minimal page map implementation for ARM --- arch/arm/src/armv7-a/CMakeLists.txt | 10 +++- arch/arm/src/armv7-a/Make.defs | 1 + arch/arm/src/armv7-a/arm_addrenv_pgmap.c | 75 ++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 arch/arm/src/armv7-a/arm_addrenv_pgmap.c 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); +} From 5368788e1681b391a60dd8d072ac9f2fff90bee7 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 1 Feb 2024 15:23:09 +0200 Subject: [PATCH 087/147] shmfs/shmfs_alloc. Fix POSIX violation for shmfs_truncate When shmfs_truncate is called, it uses shmfs_alloc_object to create the physical backing for the shm file. However, the allocated physical memory returned by mm_pgalloc is not cleared when CONFIG_BUILD_KERNEL is set, which is a clear POSIX violation: https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html "If the file was previously shorter than length, its size is increased, and the extended area appears as if it were zero-filled." For FLAT and PROTECTED modes zalloc is used, so the violation affects KERNEL mode only. --- fs/shm/shmfs_alloc.c | 10 ++++++++++ 1 file changed, 10 insertions(+) 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]); + } } } From 8276b09a738fb9ba192f68459bb91d07bfe30c93 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Mon, 12 Feb 2024 13:30:30 +0200 Subject: [PATCH 088/147] openamp: Fix void pointer arithmetic in openamp to remove compilation warnings Signed-off-by: Jukka Laitinen --- ...o.c-Fix-void-pointer-arithmetic-in-a.patch | 36 +++++++++++++++++++ openamp/libmetal.defs | 1 + 2 files changed, 37 insertions(+) create mode 100644 openamp/0003-libmetal-nuttx-io.c-Fix-void-pointer-arithmetic-in-a.patch 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 From db43707f2b6a5d11f0780ab9ce455cb6d5739eec Mon Sep 17 00:00:00 2001 From: haitomatic Date: Mon, 12 Feb 2024 13:31:41 +0000 Subject: [PATCH 089/147] canfd: accept ioctl assignment of sample point 0 --- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index 64910be0287eb..cf2ee85b6e377 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -2625,10 +2625,10 @@ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) } priv->can.bittiming.bitrate = req->arbi_bitrate * 1000; /* bit/s */ - if (req->arbi_samplep > 100 || req->arbi_samplep <= 0) + if (req->arbi_samplep > 100 || req->arbi_samplep < 0) { canerr("Invalid arbitration sample point. " - "Range should be (0,100]%%."); + "Range should be [0,100]%%."); ret = -EINVAL; break; } @@ -2645,9 +2645,9 @@ defined(CONFIG_NETDEV_CAN_FILTER_IOCTL) } priv->can.data_bittiming.bitrate = req->data_bitrate * 1000; /* bit/s */ - if (req->data_samplep > 100 || req->data_samplep <= 0) + if (req->data_samplep > 100 || req->data_samplep < 0) { - canerr("Invalid data sample point. Range should be (0,100]%%."); + canerr("Invalid data sample point. Range should be [0,100]%%."); ret = -EINVAL; break; } From 7833795e503461a46b609939d2f57b58e4a0f0d6 Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Wed, 3 Jan 2024 12:10:22 -0800 Subject: [PATCH 090/147] [BACKPORT] net:Add support for multi PHY Support runtime phy selection based on a list supplied by board.h For Example: #define BOARD_ETH0_PHY_LIST \ { \ "LAN8742A", \ MII_PHYID1_LAN8742A, \ MII_PHYID2_LAN8742A, \ MII_LAN8740_SCSR, \ 0, \ 0xffff, \ MII_LAN8720_SPSCR_10MBPS, \ MII_LAN8720_SPSCR_100MBPS, \ MII_LAN8720_SPSCR_DUPLEX, \ 22 \ }, \ { \ "TJA1103", \ MII_PHYID1_TJA1103, \ MII_PHYID2_TJA1103, \ 0xffff, \ 18, \ 0xffff, \ 0 , \ MII_LAN8720_SPSCR_100MBPS, \ MII_LAN8720_SPSCR_DUPLEX, \ 45, \ }, \ --- drivers/net/Kconfig | 7 +++++++ include/nuttx/net/mii.h | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index be6130891b885..61469781069c0 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" diff --git a/include/nuttx/net/mii.h b/include/nuttx/net/mii.h index 623610cc26bd1..cbc818a2d07e1 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,22 @@ * 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 */ +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -932,4 +970,5 @@ extern "C" } #endif +#endif /* __ASSEMBLY__ */ #endif /* __INCLUDE_NUTTX_NET_MII_H */ From 45bb791bcf521adea0bb3cea293d03d0df7b1b75 Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Wed, 3 Jan 2024 12:10:48 -0800 Subject: [PATCH 091/147] [BACKPORT] imxrt:ENET Use multi PHY Allow a board to specify a list of PHYs. Then use this list, at run-time, to select and use the PHY populated on the board. --- arch/arm/src/imxrt/imxrt_enet.c | 574 ++++++++++++++++++++++---------- 1 file changed, 406 insertions(+), 168 deletions(-) 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 From 52bca70b81e182318217b5f8434b01c3a0de74f6 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Mon, 12 Feb 2024 14:34:44 +0000 Subject: [PATCH 092/147] canfd driver: add missing hardware header depedency on mpfs_memorymap --- arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h index e883ccef22011..16587add2d226 100644 --- a/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h +++ b/arch/risc-v/src/mpfs/hardware/mpfs_fpga_canfd.h @@ -21,6 +21,13 @@ #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 ****************************************************************************/ From 671839b77933062b6137cb7d3a1d63fac1440165 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Mon, 12 Feb 2024 15:19:12 +0000 Subject: [PATCH 093/147] mpfs canfd driver: add missing memorymap header and reorganize --- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 5 ++++- arch/risc-v/src/mpfs/mpfs_fpga_canfd.h | 7 ------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index cf2ee85b6e377..71c2a0fa8e2c1 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -47,8 +47,11 @@ #include -#include "hardware/mpfs_fpga_canfd.h" +#include "mpfs_fpga_canfd.h" #include "riscv_internal.h" +#include "mpfs_memorymap.h" + +#include "hardware/mpfs_fpga_canfd.h" /**************************************************************************** * Pre-processor Definitions diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h index d7dc98098bba0..9bc78552b3eb7 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.h @@ -37,13 +37,6 @@ #ifdef CONFIG_MPFS_HAVE_CANFD -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include -#include "hardware/mpfs_fpga_canfd.h" - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ From ba97332706c941b64eb37b87d68ed6f108e7f7e3 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 13 Feb 2024 09:52:59 +0200 Subject: [PATCH 094/147] boards/risc-v/mpfs/icicle: Normalize standalone and canfd target defconfigs Signed-off-by: Jukka Laitinen --- boards/risc-v/mpfs/icicle/configs/canfd/defconfig | 3 --- boards/risc-v/mpfs/icicle/configs/standalone/defconfig | 1 - 2 files changed, 4 deletions(-) diff --git a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig index 7bcc1380138d6..b4c5cf0acff04 100644 --- a/boards/risc-v/mpfs/icicle/configs/canfd/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/canfd/defconfig @@ -23,16 +23,13 @@ CONFIG_ARCH_STACKDUMP=y CONFIG_BOARD_LOOPSPERMSEC=54000 CONFIG_BUILTIN=y CONFIG_DEBUG_ASSERTIONS=y -CONFIG_DEBUG_ERROR=y CONFIG_DEBUG_FEATURES=y CONFIG_DEBUG_FULLOPT=y -CONFIG_DEBUG_INFO=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_DEBUG_WARN=y CONFIG_DEV_ZERO=y CONFIG_EXPERIMENTAL=y CONFIG_FS_PROCFS=y diff --git a/boards/risc-v/mpfs/icicle/configs/standalone/defconfig b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig index 78d417dfdee52..532550067b6ce 100644 --- a/boards/risc-v/mpfs/icicle/configs/standalone/defconfig +++ b/boards/risc-v/mpfs/icicle/configs/standalone/defconfig @@ -17,7 +17,6 @@ CONFIG_ARCH_RISCV=y CONFIG_ARCH_STACKDUMP=y CONFIG_BOARD_LOOPSPERMSEC=54000 CONFIG_DEBUG_ASSERTIONS=y -CONFIG_DEBUG_ERROR=y CONFIG_DEBUG_FEATURES=y CONFIG_DEBUG_FS=y CONFIG_DEBUG_FS_ERROR=y From b86f022d9a06110bc9861aa7f69664bfea27acb5 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 13 Feb 2024 12:35:05 +0200 Subject: [PATCH 095/147] Revert "opensbi: update to contain shrinked version" This reverts commit c87ad9ff9f98598e4682a8edd1821776165b69c8. --- arch/risc-v/src/opensbi/Make.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs index 735bd5061f933..cae6f7f674958 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -43,10 +43,10 @@ INCLUDES += ${INCDIR_PREFIX}$(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdpar SBI_DIR := opensbi OPENSBI_UNPACK = opensbi-3rdparty -OPENSBI_COMMIT = a082fb83f218a647d2009b565e573dac8f179cb9 +OPENSBI_COMMIT = b18bb7ce78d4e5504a9cbd8df7b57d795f489a0a OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = tiiuae-opensbi-a082fb8 +OPENSBI_DIR = tiiuae-opensbi-b18bb7c $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) From 3a1620586767371393aec3a97b0910cac7a66f90 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 13 Feb 2024 12:36:49 +0200 Subject: [PATCH 096/147] Revert "opensbi: Take SBI version that removes console into use" This reverts commit 1870a5c95d489b32b072f98573b172cfe04abc01. --- arch/risc-v/src/opensbi/Make.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs index cae6f7f674958..5f56cf3353fdf 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -43,10 +43,10 @@ INCLUDES += ${INCDIR_PREFIX}$(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdpar SBI_DIR := opensbi OPENSBI_UNPACK = opensbi-3rdparty -OPENSBI_COMMIT = b18bb7ce78d4e5504a9cbd8df7b57d795f489a0a +OPENSBI_COMMIT = 19b05a2fd4fd04329d26f73a73e179631d7ae44c OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = tiiuae-opensbi-b18bb7c +OPENSBI_DIR = tiiuae-opensbi-19b05a2 $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) From 996e32034a61c47f4ff4b294025806b8f6b488c8 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 13 Feb 2024 12:36:58 +0200 Subject: [PATCH 097/147] Revert "arch/risc-v/src/opensbi/Make.defs: Switch opensbi to the nuttx/size optimized version in tiiuae repo" This reverts commit cd75eb6c761f7131dd4fa2af7172c4e9cb4f7601. --- arch/risc-v/src/opensbi/Make.defs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/risc-v/src/opensbi/Make.defs b/arch/risc-v/src/opensbi/Make.defs index 5f56cf3353fdf..4b0f37d1116be 100644 --- a/arch/risc-v/src/opensbi/Make.defs +++ b/arch/risc-v/src/opensbi/Make.defs @@ -43,10 +43,10 @@ INCLUDES += ${INCDIR_PREFIX}$(ARCH_SRCDIR)$(DELIM)opensbi$(DELIM)opensbi-3rdpar SBI_DIR := opensbi OPENSBI_UNPACK = opensbi-3rdparty -OPENSBI_COMMIT = 19b05a2fd4fd04329d26f73a73e179631d7ae44c -OPENSBI_URL = https://github.com/tiiuae/opensbi/tarball +OPENSBI_COMMIT = fbaaafe808f3da7745760d757c436ef1b293d3ed +OPENSBI_URL = https://github.com/riscv-software-src/opensbi/tarball OPENSBI_TARBALL = opensbi.tar.gz -OPENSBI_DIR = tiiuae-opensbi-19b05a2 +OPENSBI_DIR = riscv-software-src-opensbi-fbaaafe $(OPENSBI_TARBALL): $(call DOWNLOAD,$(OPENSBI_URL),$(OPENSBI_COMMIT),opensbi/$(OPENSBI_TARBALL)) From 2a9b7926be14f9231a6b0b59350b21bccf88f56a Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 13 Feb 2024 12:39:08 +0200 Subject: [PATCH 098/147] Replace opensbi with tiiuae version Signed-off-by: Jukka Laitinen --- arch/risc-v/src/opensbi/Make.defs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)) From a3b7b2d5df29d88235f555123f03c6d3de346476 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 13 Feb 2024 14:28:42 +0200 Subject: [PATCH 099/147] arch/arm/src/imxrt/imxrt_start.c: Clear CONTROL register at start to make sure we use MSP as the stack pointer When entering the function from an external bootloader, the CPU could be using PSP. But the following code expects MSP to be in use. Signed-off-by: Jukka Laitinen --- arch/arm/src/imxrt/imxrt_start.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 From e926c68a29ddd99dc69971a5dd6eb72bd8bcc7fc Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 8 Mar 2024 14:45:25 +0200 Subject: [PATCH 100/147] Revert "net/can, net/devif: fix CAN RX/TX iob free semcount runaway issue" This reverts commit ac2c32133bec14425fba2f903f26a35c7ff9518a. --- net/can/can_callback.c | 16 --------------- net/can/can_recvmsg.c | 45 +++++++++++++++++++----------------------- net/devif/devif_send.c | 7 +------ 3 files changed, 21 insertions(+), 47 deletions(-) diff --git a/net/can/can_callback.c b/net/can/can_callback.c index ac5de920937f5..d8ebfc65506ef 100644 --- a/net/can/can_callback.c +++ b/net/can/can_callback.c @@ -62,9 +62,6 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn, uint16_t flags) { int buflen = dev->d_len; -#ifdef CONFIG_NET_TIMESTAMP - buflen -= sizeof(struct timeval); -#endif uint16_t recvlen; uint16_t ret; @@ -136,19 +133,6 @@ uint16_t can_callback(FAR struct net_driver_s *dev, if ((flags & CAN_NEWDATA) != 0) { - if (dev->d_iob->io_flink != NULL || - dev->d_iob->io_pktlen == 0 || - dev->d_iob->io_offset <= 0) - { - if (dev->d_iob->io_flink == NULL) - { - iob_free(dev->d_iob); - } - - netdev_iob_clear(dev); - return flags; - } - #ifdef CONFIG_NET_TIMESTAMP /* TIMESTAMP sockopt is activated, * create timestamp and copy to iob diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index b6a486b28463d..f7dc4e459eb3a 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -236,19 +236,6 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) if ((iob = iob_peek_queue(&conn->readahead)) != NULL && pstate->pr_buflen > 0) { - if (iob->io_flink != NULL || - iob->io_pktlen == 0 || - iob->io_offset <= 0) - { - if (iob->io_pktlen == 0 || iob->io_offset <= 0) - { - iob_free(iob); - } - - iob_remove_queue(&conn->readahead); - return 0; - } - DEBUGASSERT(iob->io_pktlen > 0); #ifdef CONFIG_NET_CANPROTO_OPTIONS @@ -296,23 +283,31 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) * beginning of the I/O buffer chain. */ - /* No trimming needed since one CAN/CANFD frame can perfectly - * fit in one iob - */ + if (recvlen >= iob->io_pktlen) + { + FAR struct iob_s *tmp; - FAR struct iob_s *tmp; + /* Remove the I/O buffer chain from the head of the read-ahead + * buffer queue. + */ - /* 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); - tmp = iob_remove_queue(&conn->readahead); - DEBUGASSERT(tmp == iob); - UNUSED(tmp); + /* And free the I/O buffer chain */ - /* And 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_free_chain(iob); + iob_trimhead_queue(&conn->readahead, recvlen); + } /* 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 15ec735f7cfbf..943b737bbdba4 100644 --- a/net/devif/devif_send.c +++ b/net/devif/devif_send.c @@ -102,12 +102,7 @@ int devif_send(FAR struct net_driver_s *dev, FAR const void *buf, /* Prepare device buffer before poll callback */ - /* if pktlen is 0, no need to update */ - - if (offset != 0) - { - iob_update_pktlen(dev->d_iob, offset, false); - } + iob_update_pktlen(dev->d_iob, offset, false); ret = iob_trycopyin(dev->d_iob, buf, len, offset, false); if (ret != len) From 91498d8d8f3f82dbb4cd548fe5822d7e2b9da5fa Mon Sep 17 00:00:00 2001 From: Zhe Weng Date: Wed, 27 Dec 2023 10:43:11 +0800 Subject: [PATCH 101/147] net/can: Release IOB when failed to queue in datahandler If we just clear the IOB when failed to queue, we'll leak it. Signed-off-by: Zhe Weng --- net/can/can_callback.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/net/can/can_callback.c b/net/can/can_callback.c index d8ebfc65506ef..0ca5363406d1c 100644 --- a/net/can/can_callback.c +++ b/net/can/can_callback.c @@ -214,11 +214,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; } From 47b9140bf4bd7f04df5d80c8e805507b8d9d21c4 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Tue, 12 Mar 2024 11:13:19 +0200 Subject: [PATCH 102/147] net/can/can_callback.c: Take the timestamp size into account in "buflen" In case CONFIG_NET_TIMESTAMP is enabled, subtract the timestamp size from the buflen Signed-off-by: Jukka Laitinen --- net/can/can_callback.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/can/can_callback.c b/net/can/can_callback.c index 0ca5363406d1c..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 From cae7c47e35aed056729eb25568628ea9354b9877 Mon Sep 17 00:00:00 2001 From: haitomatic Date: Tue, 12 Mar 2024 12:19:13 +0200 Subject: [PATCH 103/147] net/devif/devif_send.c: Don't update the pktlen to 0 If pktlen is 0, there is no need to update Signed-off-by: Jukka Laitinen --- net/devif/devif_send.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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) From 6f03907818741a2fbd247e37da196751396082dc Mon Sep 17 00:00:00 2001 From: haitomatic Date: Tue, 12 Mar 2024 11:26:37 +0200 Subject: [PATCH 104/147] net/can/can_recvmsg.c: Remove IOB trimming as useless, can frames can always fit in one IOB Signed-off-by: Jukka Laitinen --- net/can/can_recvmsg.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index f7dc4e459eb3a..db05be824c254 100644 --- a/net/can/can_recvmsg.c +++ b/net/can/can_recvmsg.c @@ -277,37 +277,26 @@ 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; + static_assert(sizeof(struct can_frame) <= CONFIG_IOB_BUFSIZE); - /* Remove the I/O buffer chain from the head of the read-ahead - * buffer queue. - */ + FAR struct iob_s *tmp; - tmp = iob_remove_queue(&conn->readahead); - DEBUGASSERT(tmp == iob); - UNUSED(tmp); + /* Remove the I/O buffer chain from the head of the read-ahead + * buffer queue. + */ - /* And free the I/O buffer chain */ + tmp = iob_remove_queue(&conn->readahead); + DEBUGASSERT(tmp == iob); + UNUSED(tmp); - 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). - */ + /* And free the I/O buffer chain */ - 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) From ceaef749df8bb16819e1491d0e808aa2098104a1 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 12 Mar 2024 09:58:21 +0200 Subject: [PATCH 105/147] arch/risc-v/src/mpfs/mpfs_fpga_canfd.c: Fix a race condition with devif_poll Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index 71c2a0fa8e2c1..06009d44c7967 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -701,6 +701,12 @@ static void mpfs_receive_work(void *arg) mpfs_can_retrieve_rx_frame(priv, cf, ffw); + /* 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 */ @@ -714,6 +720,8 @@ static void mpfs_receive_work(void *arg) 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 From 51162be66862503788e14bda1002aae619e98084 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 12 Mar 2024 10:42:51 +0200 Subject: [PATCH 106/147] net/can/can_recvmsg.c: Cleanup can_readahead It is better to just atomically remove the iob from the readahead queue first, and only after that work on the iob. Signed-off-by: Jukka Laitinen --- net/can/can_recvmsg.c | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/net/can/can_recvmsg.c b/net/can/can_recvmsg.c index db05be824c254..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; @@ -284,17 +274,7 @@ static inline int can_readahead(struct can_recvfrom_s *pstate) static_assert(sizeof(struct can_frame) <= CONFIG_IOB_BUFSIZE); - 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); From 2797ee2b9bde5ec79943644eec30f40fd075e723 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 14 Mar 2024 13:14:53 +0200 Subject: [PATCH 107/147] arch/risc-v/src/mpfs/mpfs_fpga_canfd.c: Improve interrupt and error handling - Remove unnecessary looping in the interrupt handling - Recover properly from the rx overflow error - Check the RXMOF bit always to sychrnonize the RX frames to recover from any errors - Clear the interrupts in a single place after the irq handler is finished Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 272 ++++++++++++------------- 1 file changed, 132 insertions(+), 140 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index 06009d44c7967..d848ddeb693a0 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -425,7 +425,7 @@ static uint8_t g_rx_pool1[(sizeof(struct canfd_frame) + TIMESTAMP_SIZE) * /* (from interrupt) RX related functions */ -static void mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, +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); @@ -436,7 +436,7 @@ 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 void mpfs_txdone(struct mpfs_driver_s *priv); +static bool mpfs_txdone(struct mpfs_driver_s *priv); static void mpfs_txdone_work(void *arg); /* (from interrupt) Error handling related functions */ @@ -519,6 +519,38 @@ static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); * 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 * @@ -531,18 +563,19 @@ static int mpfs_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg); * ffw - Previously read frame format word * * Returned Value: - * None + * true if frame was read successfully, false otherwise * * Assumptions: * Frame format word is already parsed in advance and provided as 'ffw' arg * ****************************************************************************/ -static void mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, - struct canfd_frame *cf, - uint32_t ffw) +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 */ @@ -551,7 +584,11 @@ static void mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, /* CAN ID */ - idw = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + 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; @@ -617,27 +654,26 @@ static void mpfs_can_retrieve_rx_frame(struct mpfs_driver_s *priv, /* Timestamp - Read and throw away */ - getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); - getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + 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 = getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); + uint32_t data; + if (!mpfs_can_read_frame_data(priv, &data)) + { + return false; + } *(uint32_t *)(cf->data + i) = data; } - /* Read and discard exceeding data that does not fit any frame. read - * pointer is automatically increased if RX buffer is not empty. - */ - - while (expect_false(i < data_bc)) - { - getreg32(priv->base + MPFS_CANFD_RX_DATA_OFFSET); - i += 4; - } + return true; } /**************************************************************************** @@ -663,6 +699,7 @@ static void mpfs_receive_work(void *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) & @@ -672,6 +709,13 @@ static void mpfs_receive_work(void *arg) 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)) @@ -699,7 +743,12 @@ static void mpfs_receive_work(void *arg) /* Retrieve the classical or CANFD or remote frame */ - mpfs_can_retrieve_rx_frame(priv, cf, ffw); + 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 @@ -735,19 +784,19 @@ static void mpfs_receive_work(void *arg) 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) { - /* Notify to socket interface */ - - NETDEV_RXERRORS(&priv->dev); - - /* Clear Data Overrun */ + /* 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 */ @@ -825,14 +874,14 @@ static void mpfs_can_send_txb_cmd(struct mpfs_driver_s *priv, * priv - Pointer to the private CAN driver state structure * * Returned Value: - * None + * true on success, false on any error * * Assumptions: * None * ****************************************************************************/ -static void mpfs_txdone(struct mpfs_driver_s *priv) +static bool mpfs_txdone(struct mpfs_driver_s *priv) { bool first_buffer = true; bool buffer_processed; @@ -876,12 +925,9 @@ static void mpfs_txdone(struct mpfs_driver_s *priv) mpfs_can_send_txb_cmd(priv, TXT_CMD_SET_EMPTY, txb_id); - /* Something is fishy. CLear txb status change interrupt */ + /* Something is fishy, bail out */ - putreg32(MPFS_CANFD_INT_STAT_TXBHCI, - priv->base + MPFS_CANFD_INT_STAT_OFFSET); - - return; + return false; } break; } @@ -905,20 +951,10 @@ static void mpfs_txdone(struct mpfs_driver_s *priv) mpfs_can_send_txb_cmd(priv, TXT_CMD_SET_EMPTY, txb_id); } } - - if (buffer_processed) - { - /* Since there are some buffers processed and the number of TXT - * used now matched the number of processed buffer, we can clear - * the interrupt in order to avoid any erroneous interrupt after - * the last true TXT buffer interrupt is processed. - */ - - putreg32(MPFS_CANFD_INT_STAT_TXBHCI, - priv->base + MPFS_CANFD_INT_STAT_OFFSET); - } } while (buffer_processed); + + return true; } /**************************************************************************** @@ -1121,6 +1157,20 @@ static void mpfs_err_interrupt(struct mpfs_driver_s *priv, uint32_t isr) 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); @@ -1150,126 +1200,68 @@ static int mpfs_interrupt(int irq, void *context, void *arg) uint32_t isr; uint32_t icr; - uint32_t imask; - int irq_loops; - - for (irq_loops = 0; irq_loops < 10000; irq_loops++) - { - /* Get the interrupt status */ - - isr = getreg32(priv->base + MPFS_CANFD_INT_STAT_OFFSET); - - /* Check and exit interrupt service routine if there is no int flag in - * INT_STAT reg. - */ - - if (!isr) - { - return irq_loops ? OK : -1; - } - - /* Receive Buffer Not Empty Interrupt */ - - if (isr & MPFS_CANFD_INT_STAT_RBNEI) - { - /* Mask RBNEI first, then clear interrupt. Even if - * another IRQ fires, RBNEI will always be 0 (masked). - */ - - icr = MPFS_CANFD_INT_STAT_RBNEI; - putreg32(icr, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); - putreg32(icr, priv->base + MPFS_CANFD_INT_STAT_OFFSET); - - /* Schedule work to process RX frame from CAN controller */ - - work_queue(CANWORK, &priv->rxwork, mpfs_receive_work, priv, 0); - } - - /* TXT Buffer HW Command Interrupt */ - if (isr & MPFS_CANFD_INT_STAT_TXBHCI) - { - /* Clear TX interrupt flags */ + /* Get the interrupt status */ - mpfs_txdone(priv); + isr = getreg32(priv->base + MPFS_CANFD_INT_STAT_OFFSET); - /* Schedule work to poll for next available tx frame from the - * network. - */ + /* Receive Buffer Not Empty Interrupt */ - work_queue(CANWORK, &priv->txdwork, mpfs_txdone_work, priv, 0); - } + if (isr & MPFS_CANFD_INT_STAT_RBNEI) + { + /* Mask RBNEI until receive is handled be the worker */ - /* Error Interrupts */ + icr = MPFS_CANFD_INT_STAT_RBNEI; + putreg32(icr, priv->base + MPFS_CANFD_INT_MASK_SET_OFFSET); - if (isr & MPFS_CANFD_INT_STAT_EWLI || - isr & MPFS_CANFD_INT_STAT_FCSI || - isr & MPFS_CANFD_INT_STAT_ALI || - isr & MPFS_CANFD_INT_STAT_BEI) - { - icr = isr & (MPFS_CANFD_INT_STAT_EWLI | - MPFS_CANFD_INT_STAT_FCSI | - MPFS_CANFD_INT_STAT_ALI | - MPFS_CANFD_INT_STAT_BEI); - canerr("Some error interrupts. Clearing 0x%08x\n", icr); - putreg32(icr, priv->base + MPFS_CANFD_INT_STAT_OFFSET); - mpfs_err_interrupt(priv, isr); - } + work_queue(CANWORK, &priv->rxwork, mpfs_receive_work, priv, 0); } - /* Now, it seems that there are still some interrupt flags that remain - * stuck in INT_STAT reg. - */ - - canerr("Stuck interrupt (isr=%08x)\n", isr); - - /* Check if any of the stuck one belongs to txb status. */ + /* TXT Buffer HW Command Interrupt */ if (isr & MPFS_CANFD_INT_STAT_TXBHCI) { - canerr("TXBHCI interrupt\n"); + /* Handle TX interrupt */ -#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++) + if (!mpfs_txdone(priv)) { - uint32_t status = mpfs_can_get_txb_status(priv, i); - caninfo("txb[%d] txb status=0x%08x\n", i, status); - } + 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 */ + /* Notify to socket interface */ - NETDEV_TXERRORS(&priv->dev); + NETDEV_TXERRORS(&priv->dev); + } - /* Clear txb status change interrupt */ + /* Schedule work to poll for next available tx frame from the + * network. + */ - putreg32(MPFS_CANFD_INT_STAT_TXBHCI, - priv->base + MPFS_CANFD_INT_STAT_OFFSET); + work_queue(CANWORK, &priv->txdwork, mpfs_txdone_work, priv, 0); } - /* Check if any of the stuck one belongs to RX buffer data overrun */ + /* Error Interrupts */ - if (isr & MPFS_CANFD_INT_STAT_DOI) + 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("DOI interrupt\n"); - - /* Notify to socket interface */ - - NETDEV_RXERRORS(&priv->dev); - - /* Clear Data Overrun interrupt */ - - putreg32(MPFS_CANFD_INT_STAT_DOI, - priv->base + MPFS_CANFD_INT_STAT_OFFSET); + canerr("Some error interrupts: 0x%08x\n", isr); + mpfs_err_interrupt(priv, isr); } - /* Clear and reset all interrupt. */ + /* All interrupts are now handled, clear them */ + + putreg32(isr, priv->base + MPFS_CANFD_INT_STAT_OFFSET); - canwarn("Reset all interrupts...\n"); - imask = 0xffffffff; - putreg32(imask, priv->base + MPFS_CANFD_INT_ENA_CLR_OFFSET); - putreg32(imask, priv->base + MPFS_CANFD_INT_ENA_SET_OFFSET); return OK; } From 34fa847fdf1666c48e3c3a8662ac402afce2c49f Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 14 Mar 2024 14:22:46 +0200 Subject: [PATCH 108/147] arch/risc-v/src/mpfs/mpfs_fpga_canfd.c: Enable error interrupts only when in ERROR_ACTIVE state Having error interrupts enabled while in ERROR_PASSIVE will cause interrupt storms, for example bus error would be always asserted if the can is / gets disconnected. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_fpga_canfd.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c index d848ddeb693a0..fd76bc5187ea1 100644 --- a/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c +++ b/arch/risc-v/src/mpfs/mpfs_fpga_canfd.c @@ -1131,6 +1131,11 @@ static void mpfs_err_interrupt(struct mpfs_driver_s *priv, uint32_t isr) 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++; @@ -1138,6 +1143,11 @@ static void mpfs_err_interrupt(struct mpfs_driver_s *priv, uint32_t isr) 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); @@ -2371,6 +2381,8 @@ static int mpfs_can_controller_start(struct mpfs_driver_s *priv) 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) @@ -2378,10 +2390,6 @@ static int mpfs_can_controller_start(struct mpfs_driver_s *priv) int_ena |= MPFS_CANFD_INT_STAT_ALI | MPFS_CANFD_INT_STAT_BEI; } - int_msk = ~int_ena; /* Mask all disabled interrupts */ - - /* It's after reset, so there is no need to clear anything */ - 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); From e4d95ee5bef0b180cd982cd5fab4ccf4cec845d0 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 19 Mar 2024 12:06:34 +0200 Subject: [PATCH 109/147] sched/group/group_killchildren.c: Force-cancel children if parent is force-cancelled There is no point in waiting for children to exit if the parent is force-cancelled Signed-off-by: Jukka Laitinen --- sched/group/group_killchildren.c | 34 ++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 15 deletions(-) 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 From ac70ce4d5c153c462927b9c831bcbdc8f4cfc175 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 19 Mar 2024 11:41:41 +0200 Subject: [PATCH 110/147] arch/risc-v/src/common/riscv_exception.c: Just _exit the user task causing an exception We shouldn't panic the kernel when a user task excepts, we can just kill the user task and it's children. Do this by returning to _exit() in kernel context. Signed-off-by: Jukka Laitinen --- arch/risc-v/src/common/riscv_exception.c | 35 +++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) 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; } From 6c4e6d6fb904accf95b4ee7d800a8975b18ea825 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 21 Mar 2024 09:29:57 +0200 Subject: [PATCH 111/147] arch/risc-v/src/common/supervisor/riscv_perform_syscall.c: Record the currently running task in risc-v syscall If a context switch occurs in syscall, the g_running_task need to be recorded for assert logic. This copies the logic from arm platforms Signed-off-by: Jukka Laitinen --- arch/risc-v/src/common/supervisor/riscv_perform_syscall.c | 7 +++++++ 1 file changed, 7 insertions(+) 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(); From 680592ccbc9a1c252b8b7f569faf2805353cba22 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 12 Mar 2024 16:43:15 +0200 Subject: [PATCH 112/147] arm64_internal.h: Expose prototype for arm64_lowputc Useful procedure in many places. --- arch/arm64/src/common/arm64_internal.h | 4 ++++ 1 file changed, 4 insertions(+) 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 From 0b061bd797b7d466ab5083afe7342b304d660f05 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 13 Feb 2024 17:22:50 +0200 Subject: [PATCH 113/147] arm64/imx9: Add support for imx9 series SoMs, imx93 implemented Adds support for NXP i.MX9-series System-on-Module chips. - Support for i.MX93 is added - CPU is Cortex A55 / ARMv8.2A - The chip also contains a Cortex M33, but no support is provided - Supported drivers include lpuart only for now --- arch/arm64/Kconfig | 25 + arch/arm64/include/imx9/chip.h | 77 ++ arch/arm64/include/imx9/imx93_irq.h | 298 ++++++ arch/arm64/include/imx9/irq.h | 70 ++ arch/arm64/src/imx9/Kconfig | 31 + arch/arm64/src/imx9/Make.defs | 32 + arch/arm64/src/imx9/chip.h | 42 + .../src/imx9/hardware/imx93/imx93_memorymap.h | 174 ++++ arch/arm64/src/imx9/hardware/imx9_lpuart.h | 158 +++ arch/arm64/src/imx9/hardware/imx9_memorymap.h | 36 + arch/arm64/src/imx9/imx93_lowputc.S | 85 ++ arch/arm64/src/imx9/imx9_boot.c | 112 +++ arch/arm64/src/imx9/imx9_boot.h | 79 ++ arch/arm64/src/imx9/imx9_lpuart.c | 950 ++++++++++++++++++ arch/arm64/src/imx9/imx9_serial.h | 96 ++ 15 files changed, 2265 insertions(+) create mode 100644 arch/arm64/include/imx9/chip.h create mode 100644 arch/arm64/include/imx9/imx93_irq.h create mode 100644 arch/arm64/include/imx9/irq.h create mode 100644 arch/arm64/src/imx9/Kconfig create mode 100644 arch/arm64/src/imx9/Make.defs create mode 100644 arch/arm64/src/imx9/chip.h create mode 100644 arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h create mode 100644 arch/arm64/src/imx9/hardware/imx9_lpuart.h create mode 100644 arch/arm64/src/imx9/hardware/imx9_memorymap.h create mode 100644 arch/arm64/src/imx9/imx93_lowputc.S create mode 100644 arch/arm64/src/imx9/imx9_boot.c create mode 100644 arch/arm64/src/imx9/imx9_boot.h create mode 100644 arch/arm64/src/imx9/imx9_lpuart.c create mode 100644 arch/arm64/src/imx9/imx9_serial.h diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index a37e03aa694ba..37b632f9aeb47 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -91,6 +91,14 @@ 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_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 @@ -181,6 +189,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 +249,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 +332,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..b5b46f8ce1032 --- /dev/null +++ b/arch/arm64/include/imx9/chip.h @@ -0,0 +1,77 @@ +/**************************************************************************** + * 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 + ****************************************************************************/ + +/* 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) + +#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..cc3e24d707829 --- /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_15 (IMX9_IRQ_EXT + 10) /* General Purpose Input/Output 1 interrupt 0 */ +#define IMX9_IRQ_GPIO1_16_31 (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_15 (IMX9_IRQ_EXT + 57) /* General Purpose Input/Output 2 interrupt 0 */ +#define IMX9_IRQ_GPIO2_16_31 (IMX9_IRQ_EXT + 58) /* General Purpose Input/Output 2 interrupt 1 */ +#define IMX9_IRQ_GPIO3_0_15 (IMX9_IRQ_EXT + 59) /* General Purpose Input/Output 3 interrupt 0 */ +#define IMX9_IRQ_GPIO3_16_31 (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_RESERVED219 (IMX9_IRQ_EXT + 187) /* USB-1 Wake-up Interrupt */ +#define IMX9_IRQ_RESERVED220 (IMX9_IRQ_EXT + 188) /* USB-2 Wake-up Interrupt */ +#define IMX9_IRQ_GPIO4_0_15 (IMX9_IRQ_EXT + 189) /* General Purpose Input/Output 4 interrupt 0 */ +#define IMX9_IRQ_GPIO4_16_31 (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/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig new file mode 100644 index 0000000000000..e0b72de272a00 --- /dev/null +++ b/arch/arm64/src/imx9/Kconfig @@ -0,0 +1,31 @@ +# +# 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 + +endchoice # i.MX9 Chip Selection + +endmenu # "i.MX9 Chip Selection" + +menu "i.MX9 Peripheral Selection" +config IMX9_UART1 + bool "UART1" + default n + select UART1_SERIALDRIVER +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..0f9a4821c6336 --- /dev/null +++ b/arch/arm64/src/imx9/Make.defs @@ -0,0 +1,32 @@ +############################################################################ +# 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 + +ifeq ($(CONFIG_ARCH_CHIP_IMX93),y) + CHIP_CSRCS += imx9_lpuart.c + ifeq ($(CONFIG_ARCH_EARLY_PRINT),y) + CHIP_ASRCS = imx93_lowputc.S + endif +endif diff --git a/arch/arm64/src/imx9/chip.h b/arch/arm64/src/imx9/chip.h new file mode 100644 index 0000000000000..691f795ed8f28 --- /dev/null +++ b/arch/arm64/src/imx9/chip.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * 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 +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Macro Definitions + ****************************************************************************/ + +#endif /* __ARCH_ARM64_SRC_IMX9_CHIP_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..f3fcbded4e0fc --- /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__TSTMRA_BASE (0x442C0000UL) +#define IMX9_TSTMR2__TSTMRA_BASE (0x42480000UL) +#define IMX9_USB__USB_OTG1_BASE (0x4C100000UL) +#define IMX9_USB__USB_OTG2_BASE (0x4C200000UL) +#define IMX9_USB__USBNC_OTG1_BASE (0x4C100200UL) +#define IMX9_USB__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/imx9_lpuart.h b/arch/arm64/src/imx9/hardware/imx9_lpuart.h new file mode 100644 index 0000000000000..3925c51bc606f --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx9_lpuart.h @@ -0,0 +1,158 @@ +/**************************************************************************** + * 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 + ****************************************************************************/ + +/* 32-bit register definition */ + +#define UARTVERID 0x0000 /* Version ID Register */ +#define UARTPARAM 0x0004 /* Parameter Register */ +#define UARTGLOBAL 0x0008 /* LPUART Global Register */ +#define UARTPINCFG 0x000c /* LPUART Pin Configuration Register */ +#define UARTBAUD 0x0010 /* LPUART Baud Rate Register */ +#define UARTSTAT 0x0014 /* LPUART Status Register */ +#define UARTCTRL 0x0018 /* LPUART Control Register */ +#define UARTDATA 0x001c /* LPUART Data Register */ +#define UARTMATCH 0x0020 /* LPUART Match Address Register */ +#define UARTMODIR 0x0024 /* LPUART Modem IrDA Register */ +#define UARTFIFO 0x0028 /* LPUART FIFO Register */ +#define UARTWATER 0x002c /* LPUART Watermark Register */ + +#define UARTBAUD_MAEN1 0x80000000 +#define UARTBAUD_MAEN2 0x40000000 +#define UARTBAUD_M10 0x20000000 +#define UARTBAUD_TDMAE 0x00800000 +#define UARTBAUD_RDMAE 0x00200000 +#define UARTBAUD_RIDMAE 0x00100000 +#define UARTBAUD_MATCFG 0x00400000 +#define UARTBAUD_BOTHEDGE 0x00020000 +#define UARTBAUD_RESYNCDIS 0x00010000 +#define UARTBAUD_LBKDIE 0x00008000 +#define UARTBAUD_RXEDGIE 0x00004000 +#define UARTBAUD_SBNS 0x00002000 +#define UARTBAUD_SBR 0x00000000 +#define UARTBAUD_SBR_MASK 0x1fff +#define UARTBAUD_OSR_MASK 0x1f +#define UARTBAUD_OSR_SHIFT 24 + +#define UARTSTAT_LBKDIF 0x80000000 +#define UARTSTAT_RXEDGIF 0x40000000 +#define UARTSTAT_MSBF 0x20000000 +#define UARTSTAT_RXINV 0x10000000 +#define UARTSTAT_RWUID 0x08000000 +#define UARTSTAT_BRK13 0x04000000 +#define UARTSTAT_LBKDE 0x02000000 +#define UARTSTAT_RAF 0x01000000 +#define UARTSTAT_TDRE 0x00800000 +#define UARTSTAT_TC 0x00400000 +#define UARTSTAT_RDRF 0x00200000 +#define UARTSTAT_IDLE 0x00100000 +#define UARTSTAT_OR 0x00080000 +#define UARTSTAT_NF 0x00040000 +#define UARTSTAT_FE 0x00020000 +#define UARTSTAT_PE 0x00010000 +#define UARTSTAT_MA1F 0x00008000 +#define UARTSTAT_M21F 0x00004000 + +#define UARTCTRL_R8T9 0x80000000 +#define UARTCTRL_R9T8 0x40000000 +#define UARTCTRL_TXDIR 0x20000000 +#define UARTCTRL_TXINV 0x10000000 +#define UARTCTRL_ORIE 0x08000000 +#define UARTCTRL_NEIE 0x04000000 +#define UARTCTRL_FEIE 0x02000000 +#define UARTCTRL_PEIE 0x01000000 +#define UARTCTRL_TIE 0x00800000 +#define UARTCTRL_TCIE 0x00400000 +#define UARTCTRL_RIE 0x00200000 +#define UARTCTRL_ILIE 0x00100000 +#define UARTCTRL_TE 0x00080000 +#define UARTCTRL_RE 0x00040000 +#define UARTCTRL_RWU 0x00020000 +#define UARTCTRL_SBK 0x00010000 +#define UARTCTRL_MA1IE 0x00008000 +#define UARTCTRL_MA2IE 0x00004000 +#define UARTCTRL_IDLECFG_OFF 0x8 +#define UARTCTRL_LOOPS 0x00000080 +#define UARTCTRL_DOZEEN 0x00000040 +#define UARTCTRL_RSRC 0x00000020 +#define UARTCTRL_M 0x00000010 +#define UARTCTRL_WAKE 0x00000008 +#define UARTCTRL_ILT 0x00000004 +#define UARTCTRL_PE 0x00000002 +#define UARTCTRL_PT 0x00000001 + +#define UARTDATA_NOISY 0x00008000 +#define UARTDATA_PARITYE 0x00004000 +#define UARTDATA_FRETSC 0x00002000 +#define UARTDATA_RXEMPT 0x00001000 +#define UARTDATA_IDLINE 0x00000800 +#define UARTDATA_MASK 0x3ff + +#define UARTMODIR_IREN 0x00020000 +#define UARTMODIR_RTSWATER_S 0x8 +#define UARTMODIR_TXCTSSRC 0x00000020 +#define UARTMODIR_TXCTSC 0x00000010 +#define UARTMODIR_RXRTSE 0x00000008 +#define UARTMODIR_TXRTSPOL 0x00000004 +#define UARTMODIR_TXRTSE 0x00000002 +#define UARTMODIR_TXCTSE 0x00000001 + +#define UARTFIFO_TXEMPT 0x00800000 +#define UARTFIFO_RXEMPT 0x00400000 +#define UARTFIFO_TXOF 0x00020000 +#define UARTFIFO_RXUF 0x00010000 +#define UARTFIFO_TXFLUSH 0x00008000 +#define UARTFIFO_RXFLUSH 0x00004000 +#define UARTFIFO_RXIDEN_MASK 0x7 +#define UARTFIFO_RXIDEN_OFF 10 +#define UARTFIFO_TXOFE 0x00000200 +#define UARTFIFO_RXUFE 0x00000100 +#define UARTFIFO_TXFE 0x00000080 +#define UARTFIFO_FIFOSIZE_MASK 0x7 +#define UARTFIFO_TXSIZE_OFF 4 +#define UARTFIFO_RXFE 0x00000008 +#define UARTFIFO_RXSIZE_OFF 0 +#define UARTFIFO_DEPTH(x) (0x1 << ((x) ? ((x) + 1) : 0)) + +#define UARTWATER_COUNT_MASK 0xff +#define UARTWATER_TXCNT_OFF 8 +#define UARTWATER_RXCNT_OFF 24 +#define UARTWATER_WATER_MASK 0xff +#define UARTWATER_TXWATER_OFF 0 +#define UARTWATER_RXWATER_OFF 16 + +#define UARTGLOBAL_RST 0x2 + +#define UARTFIFO_RXIDEN_RDRF 0x3 +#define UARTCTRL_IDLECFG 0x7 + +#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/imx93_lowputc.S b/arch/arm64/src/imx9/imx93_lowputc.S new file mode 100644 index 0000000000000..f3311810e05dd --- /dev/null +++ b/arch/arm64/src/imx9/imx93_lowputc.S @@ -0,0 +1,85 @@ +/**************************************************************************** + * arch/arm64/src/imx9/imx93_lowputs.S + * + * 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. + * + **************************************************************************** + * + * DESCRIPTION + * Wrapper for early printk + * + ***************************************************************************/ + +#include + +#include "arm64_macro.inc" + +#include "hardware/imx9_lpuart.h" +#include "hardware/imx93/imx93_memorymap.h" + +/**************************************************************************** + * Public Symbols + ****************************************************************************/ + + .file "imx93_lowputc.S" + +/**************************************************************************** + * Assembly Macros + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/* PL011 UART initialization */ + +GTEXT(arm64_earlyprintinit) +SECTION_FUNC(text, arm64_earlyprintinit) + /* TODO: Assumes u-boot has set us up, assumption is fine for now */ + ret + +/* i.MX93 wait LPUART to be ready to transmit + * rb: register which contains the UART base address + * rc: scratch register + */ +.macro early_uart_ready rb, rc +1: + ldr \rc, [\rb, #UARTSTAT] /* <- Flag register */ + tst \rc, #UARTSTAT_TDRE /* Check FIFO EMPTY bit */ + beq 1b /* Wait for the UART to be ready */ +.endm + +/* i.MX93 LPUART transmit character + * rb: register which contains the UART base address + * rt: register which contains the character to transmit */ +.macro early_uart_transmit rb, rt + str \rt, [\rb, #UARTDATA] /* -> Data Register */ +.endm + +/* + * Print a character on the UART - this function is called by C + * w0: character to print + */ +GTEXT(arm64_lowputc) +SECTION_FUNC(text, arm64_lowputc) + ldr x15, =IMX9_LPUART1_BASE + early_uart_ready x15, w2 + early_uart_transmit x15, w0 + ret diff --git a/arch/arm64/src/imx9/imx9_boot.c b/arch/arm64/src/imx9/imx9_boot.c new file mode 100644 index 0000000000000..16f19de2c6b54 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_boot.c @@ -0,0 +1,112 @@ +/**************************************************************************** + * 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_serial.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) +{ +} + +/**************************************************************************** + * 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); + + /* 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_lpuart.c b/arch/arm64/src/imx9/imx9_lpuart.c new file mode 100644 index 0000000000000..2fa4307f4c259 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lpuart.c @@ -0,0 +1,950 @@ +/**************************************************************************** + * 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 "chip.h" +#include "arm64_arch.h" +#include "arm64_internal.h" +#include "arm64_gic.h" + +#include "imx9_serial.h" +#include "imx9_boot.h" + +#include "hardware/imx9_lpuart.h" +#include "hardware/imx9_memorymap.h" + +#ifdef USE_SERIALDRIVER + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Which UART with be tty0/console and which tty1-4? The console will + * always be ttyS0. If there is no console then will use the lowest + * numbered UART. + */ + +/* First pick the console and ttys0. This could be any of UART1-5 */ + +#if defined(CONFIG_UART1_SERIAL_CONSOLE) +# define CONSOLE_DEV g_uart1port /* UART1 is console */ +# define TTYS0_DEV g_uart1port /* UART1 is ttyS0 */ +# define UART1_ASSIGNED 1 +#endif + +/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */ +#define DMA_RX_TIMEOUT (10) +#define UART_AUTOSUSPEND_TIMEOUT 3000 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct imx9_uart_port_s +{ + unsigned long iobase; + unsigned int baud; /* Configured baud */ + unsigned int irq_num; + unsigned int txfifo_size; + unsigned int rxfifo_size; + int is_console; +}; + +static inline uint32_t imx9_read(struct imx9_uart_port_s *port, uint32_t off) +{ + return getreg32(port->iobase + off); +} + +static inline void imx9_write(struct imx9_uart_port_s *port, uint32_t val, + uint32_t off) +{ + putreg32(val, port->iobase + off); +} + +static int imx9_lpuart_stop_tx(struct imx9_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx9_read(sport, UARTCTRL); + temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE); + imx9_write(sport, temp, UARTCTRL); + + return 0; +} + +static int imx9_lpuart_stop_rx(struct imx9_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx9_read(sport, UARTCTRL); + imx9_write(sport, temp & ~UARTCTRL_RE, UARTCTRL); + + return 0; +} + +static int imx9_lpuart_start_tx(struct imx9_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx9_read(sport, UARTCTRL); + imx9_write(sport, temp | UARTCTRL_TIE, UARTCTRL); + + return 0; +} + +static int imx9_lpuart_start_rx(struct imx9_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx9_read(sport, UARTCTRL); + imx9_write(sport, temp | UARTCTRL_RE, UARTCTRL); + + return 0; +} + +/**************************************************************************** + * Name: imx9_rxint + * + * Description: + * Call to enable or disable RX interrupts + * + ****************************************************************************/ + +static void imx9_rxint(struct uart_dev_s *dev, bool enable) +{ + struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + + if (enable) + { + imx9_lpuart_start_rx(sport); + } + else + { + imx9_lpuart_stop_rx(sport); + } +} + +/**************************************************************************** + * Name: imx9_txint + * + * Description: + * Call to enable or disable TX interrupts + * + ****************************************************************************/ + +static void imx9_txint(struct uart_dev_s *dev, bool enable) +{ + struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + + if (enable) + { + imx9_lpuart_start_tx(sport); + } + else + { + imx9_lpuart_stop_tx(sport); + } +} + +/**************************************************************************** + * 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_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + + imx9_write(sport, ch, UARTDATA); +} + +/**************************************************************************** + * 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'. + * + ****************************************************************************/ + +static int imx9_receive(struct uart_dev_s *dev, unsigned int *status) +{ + struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + unsigned int rx; + unsigned int sr; + + /* to clear the FE, OR, NF, FE, PE flags, + * read STAT then read DATA reg + */ + + sr = imx9_read(sport, UARTSTAT); + rx = imx9_read(sport, UARTDATA); + + *status = sr; + + return rx; +} + +/**************************************************************************** + * Name: imx9_rxavailable + * + * Description: + * Return true if the receive fifo is not empty + * + ****************************************************************************/ + +static bool imx9_rxavailable(struct uart_dev_s *dev) +{ + struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + unsigned long sfifo = imx9_read(sport, UARTFIFO); + + if (sfifo & UARTFIFO_RXEMPT) + { + return false; + } + else + { + return true; + } +} + +/**************************************************************************** + * Name: imx9_txready + * + * Description: + * Return true if the tranmsit fifo is not full + * + ****************************************************************************/ + +static bool imx9_txready(struct uart_dev_s *dev) +{ + struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + unsigned long txcnt; + + /* When TXFULL is set, there is no space in the Tx FIFO */ + + txcnt = imx9_read(sport, UARTWATER); + txcnt = txcnt >> UARTWATER_TXCNT_OFF; + txcnt &= UARTWATER_COUNT_MASK; + + if (txcnt < sport->txfifo_size) + { + return true; + } + else + { + return false; + } +} + +/**************************************************************************** + * Name: imx9_txempty + * + * Description: + * Return true if the transmit fifo is empty + * + ****************************************************************************/ + +static bool imx9_txempty(struct uart_dev_s *dev) +{ + struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + unsigned long stat = imx9_read(sport, UARTSTAT); + unsigned long sfifo = imx9_read(sport, UARTFIFO); + + if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) + { + return true; + } + else + { + return false; + } +} + +/**************************************************************************** + * Name: imx9_irq_handler (and front-ends) + * + * Description: + * This is the common UART interrupt handler. It should cal + * uart_transmitchars or uart_receivechar to perform the appropriate data + * transfers. + * + ****************************************************************************/ + +static int imx9_uart_irq_handler(int irq, void *context, void *arg) +{ + struct uart_dev_s *dev = (struct uart_dev_s *)arg; + struct imx9_uart_port_s *sport; + unsigned long sts; + unsigned long rxcount; + + DEBUGASSERT(dev != NULL && dev->priv != NULL); + sport = (struct imx9_uart_port_s *)dev->priv; + + sts = imx9_read(sport, UARTSTAT); + rxcount = imx9_read(sport, UARTWATER); + rxcount = rxcount >> UARTWATER_RXCNT_OFF; + + if (sts & UARTSTAT_RDRF || rxcount > 0) + { + uart_recvchars(dev); + } + + if (sts & UARTSTAT_TDRE) + { + uart_xmitchars(dev); + } + + imx9_write(sport, sts, UARTSTAT); + return OK; +} + +static int imx9_lpuart_hw_reset(struct imx9_uart_port_s *sport) +{ + if (sport->is_console) + { + return 0; + } + + /* Toggle the reset signal to reset and release the peripheral */ + + putreg32(UARTGLOBAL_RST, sport->iobase + UARTGLOBAL); + putreg32(0, sport->iobase + UARTGLOBAL); + + return 0; +} + +static int imx9_setup(struct uart_dev_s *dev) +{ + irqstate_t i_flags; + int ret; + struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + + i_flags = up_irq_save(); + + ret = imx9_lpuart_hw_reset(sport); + if (ret < 0) + { + serr("failed to reset hw: %d\n", ret); + } + + up_irq_restore(i_flags); + + return ret; +} + +/**************************************************************************** + * Name: imx9_shutdown + * + * Description: + * Disable the UART. This method is called when the serial + * port is closed + * + ****************************************************************************/ + +static void imx9_shutdown(struct uart_dev_s *dev) +{ + struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + unsigned long temp; + irqstate_t i_flags; + + i_flags = up_irq_save(); + + /* clear statue */ + + temp = imx9_read(sport, UARTSTAT); + imx9_write(sport, temp, UARTSTAT); + + /* disable Rx/Tx DMA */ + + temp = imx9_read(sport, UARTBAUD); + temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE | UARTBAUD_RIDMAE); + imx9_write(sport, temp, UARTBAUD); + + /* disable Rx/Tx and interrupts */ + + temp = imx9_read(sport, UARTCTRL); + temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_TIE | + UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_ILIE | + UARTCTRL_LOOPS); + imx9_write(sport, temp, UARTCTRL); + imx9_write(sport, 0, UARTMODIR); + + up_irq_restore(i_flags); +} + +static void imx9_setup_watermark(struct imx9_uart_port_s *sport) +{ + unsigned long val; + unsigned long ctrl; + unsigned long ctrl_saved; + unsigned long rxiden_cnt; + + ctrl = imx9_read(sport, UARTCTRL); + ctrl_saved = ctrl; + ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE | + UARTCTRL_RIE | UARTCTRL_RE); + imx9_write(sport, ctrl, UARTCTRL); + + /* enable FIFO mode */ + + val = imx9_read(sport, UARTFIFO); + val |= UARTFIFO_TXFE | UARTFIFO_RXFE; + val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; + val &= ~(UARTFIFO_RXIDEN_MASK << UARTFIFO_RXIDEN_OFF); + rxiden_cnt = 0; + val |= ((rxiden_cnt & UARTFIFO_RXIDEN_MASK) << UARTFIFO_RXIDEN_OFF); + + imx9_write(sport, val, UARTFIFO); + + /* set the watermark + * rx_watermark = 1; + */ + + val = (1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF); + imx9_write(sport, val, UARTWATER); + + /* Restore cr2 */ + + imx9_write(sport, ctrl_saved, UARTCTRL); +} + +static void imx9_setup_watermark_enable(struct imx9_uart_port_s *sport) +{ + uint32_t temp; + + imx9_setup_watermark(sport); + + temp = imx9_read(sport, UARTCTRL); + temp |= UARTCTRL_RE | UARTCTRL_TE; + temp |= UARTCTRL_IDLECFG << UARTCTRL_IDLECFG_OFF; + imx9_write(sport, temp, UARTCTRL); +} + +static void imx9_hw_disable(struct imx9_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx9_read(sport, UARTCTRL); + temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE | + UARTCTRL_TIE | UARTCTRL_TE); + imx9_write(sport, temp, UARTCTRL); +} + +static void imx9_configure(struct imx9_uart_port_s *sport) +{ + unsigned long temp; + + temp = imx9_read(sport, UARTCTRL); + temp |= UARTCTRL_RIE | UARTCTRL_ILIE; + temp |= UARTCTRL_TIE; + imx9_write(sport, temp, UARTCTRL); +} + +static void imx9_hw_setup(struct imx9_uart_port_s *sport) +{ + irqstate_t i_flags; + + i_flags = up_irq_save(); + + imx9_hw_disable(sport); + + imx9_setup_watermark_enable(sport); + imx9_configure(sport); + up_enable_irq(sport->irq_num); + + up_irq_restore(i_flags); +} + +/**************************************************************************** + * Name: imx9_attach + * + * Description: + * Configure the UART to operation in interrupt driven mode. This method + * is called when the serial port 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 supports 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_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + int ret; + unsigned long temp; + + /* determine FIFO size */ + + temp = imx9_read(sport, UARTFIFO); + + sport->txfifo_size = UARTFIFO_DEPTH( + (temp >> UARTFIFO_TXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); + sport->rxfifo_size = UARTFIFO_DEPTH( + (temp >> UARTFIFO_RXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); + + ret = irq_attach(sport->irq_num, imx9_uart_irq_handler, dev); + + if (ret == OK) + { + imx9_hw_setup(sport); + } + else + { + sinfo("error ret=%d\n", ret); + } + + return ret; +} + +/**************************************************************************** + * Name: imx_detach + * + * Description: + * Detach UART interrupts. This method is called when the serial port 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_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + + up_disable_irq(sport->irq_num); + irq_detach(sport->irq_num); +} + +/**************************************************************************** + * Name: imx9_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * for current imx9 configure. + * + ****************************************************************************/ + +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 imx_uart_s *user = (struct imx_uart_s *)arg; + if (!user) + { + ret = -EINVAL; + } + else + { + memcpy(user, dev, sizeof(struct imx_uart_s)); + } + } + break; +#endif + +#ifdef CONFIG_SERIAL_TERMIOS + case TCGETS: + { + struct termios *termiosp = (struct termios *)arg; + struct imx_uart_s *priv = (struct imx_uart_s *)dev->priv; + + 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 imx_uart_s *priv = (struct imx_uart_s *)dev->priv; + 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 = imx9_setup(dev); + + /* Restore the interrupt state */ + + imx_restoreuartint(priv, ie); + priv->ie = ie; + spin_unlock_irqrestore(NULL, flags); + } + } + break; +#endif /* CONFIG_SERIAL_TERMIOS */ + + case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ + case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ + default: + { + ret = -ENOTTY; + break; + } + } + + return ret; +} + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* Serial driver UART operations */ + +static const struct uart_ops_s g_uart_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 = NULL, +#endif + .send = imx9_send, + .txint = imx9_txint, + .txready = imx9_txready, + .txempty = imx9_txempty, +}; + +/* I/O buffers */ + +#ifdef CONFIG_IMX9_UART1 +static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; +static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; + +/* This describes the state of the IMX uart1 port. */ + +static struct imx9_uart_port_s g_uart1priv = +{ + .iobase = IMX9_LPUART1_BASE, + .baud = CONFIG_UART1_BAUD, + .irq_num = IMX9_IRQ_LPUART1, + .is_console = 1, +}; + +static struct uart_dev_s g_uart1port = +{ + .recv = + { + .size = CONFIG_UART1_RXBUFSIZE, + .buffer = g_uart1rxbuffer, + }, + .xmit = + { + .size = CONFIG_UART1_TXBUFSIZE, + .buffer = g_uart1txbuffer, + }, + .ops = &g_uart_ops, + .priv = &g_uart1priv, +}; + +#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.isconsole = true; + imx9_setup(&CONSOLE_DEV); +#endif +} + +/**************************************************************************** + * Name: up_putc + * + * Description: + * Provide priority, low-level access to support OS debug + * writes + * + ****************************************************************************/ + +int up_putc(int ch) +{ + /* Check for LF */ + + if (ch == '\n') + { + /* Add CR */ + + arm64_lowputc('\r'); + } + + arm64_lowputc((uint8_t)ch); + return ch; +} + +/**************************************************************************** + * Name: arm64_serialinit + * + * Description: + * Register serial console and serial ports. This assumes + * that imx_earlyserialinit was called previously. + * + ****************************************************************************/ + +void arm64_serialinit(void) +{ + int ret; + + ret = uart_register("/dev/console", &CONSOLE_DEV); + if (ret < 0) + { + sinfo("error at register dev/console, ret =%d\n", ret); + } + + ret = uart_register("/dev/ttyS0", &TTYS0_DEV); + if (ret < 0) + { + sinfo("error at register dev/ttyS0, ret =%d\n", ret); + } +} + +#endif /* USE_SERIALDRIVER */ diff --git a/arch/arm64/src/imx9/imx9_serial.h b/arch/arm64/src/imx9/imx9_serial.h new file mode 100644 index 0000000000000..854c6367aee77 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_serial.h @@ -0,0 +1,96 @@ +/**************************************************************************** + * 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 + +#include "arm64_internal.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: imx_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 arm_serialinit. + * + ****************************************************************************/ + +#ifdef USE_EARLYSERIALINIT +void imx9_earlyserialinit(void); +#endif + +/**************************************************************************** + * Name: uart_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 arm_serialinit. + * + ****************************************************************************/ + +#if defined(USE_EARLYSERIALINIT) && defined(IMX9_HAVE_UART) +void uart_earlyserialinit(void); +#endif + +/**************************************************************************** + * Name: uart_serialinit + * + * Description: + * Register the UART serial console and serial ports. This assumes that + * uart_earlyserialinit was called previously. + * + ****************************************************************************/ + +#ifdef IMX9_HAVE_UART +void uart_serialinit(void); +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_IMX9_IMX_SERIAL_H */ From 913410dc9ac2b69c3b5b6e5340aa1c528551b7d2 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 14 Feb 2024 13:05:42 +0200 Subject: [PATCH 114/147] arm64/imx9: Add board for imx93-evk Adds board definition for imx93-evk board - Support for the Cortex-A55 core in i.MX93, support for the Cortex-M33 core is _not_ provided - "nsh" profile is provided, this includes a minimalistic feature set which boots the SoM to nsh console - A bootloader is required, u-boot has been tested --- .../arm64/imx9/boards/imx93-evk/README.txt | 145 ++++++++++++++++ .../arm64/imx9/boards/imx93-evk/index.rst | 6 + Documentation/platforms/arm64/imx9/index.rst | 12 ++ boards/Kconfig | 12 ++ boards/arm64/imx9/imx93-evk/Kconfig | 7 + .../imx9/imx93-evk/configs/nsh/defconfig | 61 +++++++ boards/arm64/imx9/imx93-evk/include/board.h | 59 +++++++ .../imx9/imx93-evk/include/board_memorymap.h | 59 +++++++ boards/arm64/imx9/imx93-evk/scripts/Make.defs | 48 ++++++ .../arm64/imx9/imx93-evk/scripts/dramboot.ld | 157 ++++++++++++++++++ boards/arm64/imx9/imx93-evk/src/Makefile | 29 ++++ boards/arm64/imx9/imx93-evk/src/imx93-evk.h | 59 +++++++ .../arm64/imx9/imx93-evk/src/imx9_appinit.c | 76 +++++++++ .../arm64/imx9/imx93-evk/src/imx9_boardinit.c | 113 +++++++++++++ .../arm64/imx9/imx93-evk/src/imx9_bringup.c | 62 +++++++ 15 files changed, 905 insertions(+) create mode 100644 Documentation/platforms/arm64/imx9/boards/imx93-evk/README.txt create mode 100644 Documentation/platforms/arm64/imx9/boards/imx93-evk/index.rst create mode 100644 Documentation/platforms/arm64/imx9/index.rst create mode 100644 boards/arm64/imx9/imx93-evk/Kconfig create mode 100644 boards/arm64/imx9/imx93-evk/configs/nsh/defconfig create mode 100644 boards/arm64/imx9/imx93-evk/include/board.h create mode 100644 boards/arm64/imx9/imx93-evk/include/board_memorymap.h create mode 100644 boards/arm64/imx9/imx93-evk/scripts/Make.defs create mode 100644 boards/arm64/imx9/imx93-evk/scripts/dramboot.ld create mode 100644 boards/arm64/imx9/imx93-evk/src/Makefile create mode 100644 boards/arm64/imx9/imx93-evk/src/imx93-evk.h create mode 100644 boards/arm64/imx9/imx93-evk/src/imx9_appinit.c create mode 100644 boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c create mode 100644 boards/arm64/imx9/imx93-evk/src/imx9_bringup.c 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/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/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/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig new file mode 100644 index 0000000000000..9bf34ecc59718 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/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="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_DEBUG_ASSERTIONS=y +CONFIG_DEBUG_FEATURES=y +CONFIG_DEBUG_FULLOPT=y +CONFIG_DEBUG_SCHED=y +CONFIG_DEBUG_SCHED_ERROR=y +CONFIG_DEBUG_SCHED_INFO=y +CONFIG_DEBUG_SCHED_WARN=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_UART1=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_INTELHEX_BINARY=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=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_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 +CONFIG_UART1_SERIAL_CONSOLE=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..e8fd207609ecc --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/include/board.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * 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 + +/**************************************************************************** + * 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_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..dd8d6fac4b286 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/scripts/Make.defs @@ -0,0 +1,48 @@ +############################################################################ +# 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)/arch/arm64/src/Toolchain.defs + +LDSCRIPT = dramboot.ld + +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..6f3f0afde5457 --- /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 */ + *(.text.__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/src/Makefile b/boards/arm64/imx9/imx93-evk/src/Makefile new file mode 100644 index 0000000000000..d034d21b4b4b7 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/Makefile @@ -0,0 +1,29 @@ +############################################################################ +# boards/arm64/imx9/emx93-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 + +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..5956c51fce815 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx93-evk.h @@ -0,0 +1,59 @@ +/**************************************************************************** + * 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 + +/**************************************************************************** + * 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 + +#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..7443f92ccd263 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c @@ -0,0 +1,113 @@ +/**************************************************************************** + * 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..a267b844503e3 --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c @@ -0,0 +1,62 @@ +/**************************************************************************** + * 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 "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 + + UNUSED(ret); + return OK; +} From ca5230dcaa1f40a37e62074e97d7d826d3efcae5 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 19 Mar 2024 13:14:31 +0200 Subject: [PATCH 115/147] arm64/imx9: Add JLinkScript for imx93-evk This is needed, as it contains the DAP addresses. --- .../imx93-evk/scripts/imx93_ca55.JLinkScript | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 boards/arm64/imx9/imx93-evk/scripts/imx93_ca55.JLinkScript 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; +} + From 4c690c379620fe36f75645930a4b27686d21af90 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 21 Mar 2024 23:21:04 +0200 Subject: [PATCH 116/147] arch/arm64/src/common: Remove void * arithmetic Signed-off-by: Jukka Laitinen --- arch/arm64/src/common/arm64_copystate.c | 4 ++-- arch/arm64/src/common/arm64_fpu.c | 6 ++++-- arch/arm64/src/common/arm64_initialstate.c | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) 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_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_initialstate.c b/arch/arm64/src/common/arm64_initialstate.c index 0dc836e7a4725..b54532ba71cbb 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,7 +67,7 @@ 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); From 8e43b84b54be9c80899ef36d94561c4c470d1522 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 22 Mar 2024 11:59:10 +0200 Subject: [PATCH 117/147] arch/arm64: Add the head obj to libarch.a as well On other platforms libarch.a contains the head object. Some projects depend on this fact so let's provide the head object in the archive here as well. --- arch/arm64/src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From c5b86b5c20d1eab3c7bd4817f0b169f15f269154 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 21 Mar 2024 11:28:14 +0200 Subject: [PATCH 118/147] stm32f7/stm32_foc.c: Set .info_get to foc_lower_ops This fixes build error (Werror): Error: chip/stm32_foc.c:1918:12: error: 'stm32_foc_info_get' defined but not used [-Werror=unused-function] 1918 | static int stm32_foc_info_get(struct foc_dev_s *dev, struct foc_info_s *info) | ^~~~~~~~~~~~~~~~~~ cc1: all warnings being treated as errors --- arch/arm/src/stm32f7/stm32_foc.c | 1 + 1 file changed, 1 insertion(+) 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, From 5d9f63feb0ee7aa63c20592c05c4902b969f1097 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 22 Mar 2024 14:19:00 +0200 Subject: [PATCH 119/147] arm64_head.S: Add explicit input section for __start As __start must be placed at a precise location, a separate, explicit input section is needed to guarantee this. Why is this an issue ? NuttX uses --entry=__start which puts __start in its correct location, but out-of-tree builds won't work, so it more robust to use an explicit section for the startup code and enforce its placement in the linker script. --- arch/arm64/src/common/arm64_head.S | 2 ++ boards/arm64/a64/pinephone/scripts/dramboot.ld | 1 + boards/arm64/fvp-v8r/fvp-armv8r/scripts/dramboot.ld | 1 + boards/arm64/imx8/imx8qm-mek/scripts/dramboot.ld | 1 + boards/arm64/imx9/imx93-evk/scripts/dramboot.ld | 2 +- boards/arm64/qemu/qemu-armv8a/scripts/dramboot.ld | 1 + boards/arm64/rk3399/nanopi_m4/scripts/dramboot.ld | 1 + boards/arm64/rk3399/pinephonepro/scripts/dramboot.ld | 1 + 8 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/src/common/arm64_head.S b/arch/arm64/src/common/arm64_head.S index 18ea5c97ea72f..f10dcd4005b68 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: 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/scripts/dramboot.ld b/boards/arm64/imx9/imx93-evk/scripts/dramboot.ld index 6f3f0afde5457..f437d8d13745a 100644 --- a/boards/arm64/imx9/imx93-evk/scripts/dramboot.ld +++ b/boards/arm64/imx9/imx93-evk/scripts/dramboot.ld @@ -50,7 +50,7 @@ SECTIONS .text : { _stext = ABSOLUTE(.); /* Text section */ - *(.text.__start) /* Place __start here */ + *(.start .start.*) /* Place __start here */ *(.text .text.*) *(.text.cold) *(.text.unlikely) 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) From c908e948b1dc726ea59649c9ab6f9aecf8be3138 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Fri, 23 Feb 2024 15:37:49 +0200 Subject: [PATCH 120/147] arm64/imx9: Add CCM (Clock Controller Module) --- arch/arm64/src/imx9/Kconfig | 4 + arch/arm64/src/imx9/Make.defs | 2 +- .../arm64/src/imx9/hardware/imx93/imx93_ccm.h | 701 ++++++++++++++++++ .../arm64/src/imx9/hardware/imx93/imx93_pll.h | 226 ++++++ arch/arm64/src/imx9/hardware/imx9_ccm.h | 38 + arch/arm64/src/imx9/imx9_ccm.c | 197 +++++ arch/arm64/src/imx9/imx9_ccm.h | 88 +++ arch/arm64/src/imx9/imx9_clockconfig.c | 216 ++++++ arch/arm64/src/imx9/imx9_clockconfig.h | 46 ++ 9 files changed, 1517 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h create mode 100644 arch/arm64/src/imx9/hardware/imx93/imx93_pll.h create mode 100644 arch/arm64/src/imx9/hardware/imx9_ccm.h create mode 100644 arch/arm64/src/imx9/imx9_ccm.c create mode 100644 arch/arm64/src/imx9/imx9_ccm.h create mode 100644 arch/arm64/src/imx9/imx9_clockconfig.c create mode 100644 arch/arm64/src/imx9/imx9_clockconfig.h diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index e0b72de272a00..3c921bbebe7c5 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -28,4 +28,8 @@ config IMX9_UART1 select UART1_SERIALDRIVER endmenu # iMX Peripheral Selection +config IMX9_PLL + bool "PLL setup support (WIP)" + default n + endif # ARCH_CHIP_IMX9 diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 0f9a4821c6336..8e8a8d98623be 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -22,7 +22,7 @@ include common/Make.defs # i.MX9-specific C source files -CHIP_CSRCS = imx9_boot.c +CHIP_CSRCS = imx9_boot.c imx9_ccm.c imx9_clockconfig.c ifeq ($(CONFIG_ARCH_CHIP_IMX93),y) CHIP_CSRCS += imx9_lpuart.c 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..7ac0f77954f98 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h @@ -0,0 +1,701 @@ +/**************************************************************************** + * 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) + +/* 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_EDMA1 21 +#define CCM_LPCG_EDMA2 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 + +/* 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 = 5, /* 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 = 11, /* 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_pll.h b/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h new file mode 100644 index 0000000000000..fa99b92c7f893 --- /dev/null +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_pll.h @@ -0,0 +1,226 @@ +/**************************************************************************** + * 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 (0xe << 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) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct pll_parms +{ + /* 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 +{ + uint32_t mfi; /* PLL integer divider */ + uint32_t mfn; /* PLL fractional divider numerator */ + bool divby2_en; /* Enable the divide-by-2 output */ +}; + +#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/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..bf097f6dcf461 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_clockconfig.c @@ -0,0 +1,216 @@ +/**************************************************************************** + * 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 "barriers.h" + +#include "arm64_internal.h" +#include "imx9_ccm.h" +#include "imx9_clockconfig.h" + +#include "hardware/imx9_ccm.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define mb() \ + do \ + { \ + ARM64_DSB(); \ + ARM64_ISB(); \ + } \ + while (0) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_IMX9_PLL + +# error "Missing logic" + +static int pll_init(uintptr_t reg, bool frac, struct pll_parms *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 *pfdparm) +{ + uintptr_t ctrl; + uintptr_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_ENABLE, PLL_CLR(ctrl)); + + /* Set the divider */ + + val = PLL_DFS_MFI(pfdparm->mfi) | PLL_DFS_MFN(pfdparm->mfn); + putreg32(val, PLL_SET(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))); + + return OK; +} +#endif + +/**************************************************************************** + * 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) +{ + /* REVISIT: Define a clock config and run it. For now we rely on the fact + * that the boot code + bootloader will have set us up. + * + * During boot the ROM code initializes the PLL clocks as follows: + * + * - OSC24M : 24 MHz + * - ARMPLL : 2000 MHz + * - ARMPLL_OUT : 2000 MHz + * - DRAMPLL : 1000 MHz + * - SYSPLL1 : 4000 MHz + * - SYSPLL_PFD0 : 1000 MHz + * - SYSPLL_PFD1 : 800 MHz + * - SYSPLL_PFD2 : 625 MHz + * - AUDIOPLL : OFF + * - AUDIOPLL_OUT : OFF + * - VIDEOPLL : 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. + */ +} diff --git a/arch/arm64/src/imx9/imx9_clockconfig.h b/arch/arm64/src/imx9/imx9_clockconfig.h new file mode 100644 index 0000000000000..b688e450f38ea --- /dev/null +++ b/arch/arm64/src/imx9/imx9_clockconfig.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * 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 + +/**************************************************************************** + * 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); + +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_CLOCKCONFIG_H */ From 2ead78d4bdae5ef1ca891a9a6b4ce9d990f308b7 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 20 Mar 2024 12:17:51 +0200 Subject: [PATCH 121/147] arm64/imx9: Add register definitions for LPIT --- arch/arm64/src/imx9/hardware/imx9_lpit.h | 125 +++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 arch/arm64/src/imx9/hardware/imx9_lpit.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 */ From 72e8c85ae4557efe25de29cc54b00fc122cce260 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 21 Mar 2024 13:49:37 +0200 Subject: [PATCH 122/147] arm64/imx9: Add register definitions for LPTMR --- arch/arm64/src/imx9/hardware/imx9_lptmr.h | 100 ++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 arch/arm64/src/imx9/hardware/imx9_lptmr.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_ */ From a643391b41f17a56782bc70cca1cd8c93eea7e27 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 26 Mar 2024 10:19:43 +0200 Subject: [PATCH 123/147] imx9_clockconfig.c: Add way to query clock frequency The frequency of a clock source is stored in a LUT. Currently the LUT contains the PLL frequencies set by the boot ROM code. --- .../arm64/src/imx9/hardware/imx93/imx93_ccm.h | 4 +- arch/arm64/src/imx9/imx9_clockconfig.c | 104 ++++++++++++++++++ arch/arm64/src/imx9/imx9_clockconfig.h | 44 ++++++++ 3 files changed, 150 insertions(+), 2 deletions(-) diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h b/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h index 7ac0f77954f98..ae46d228ff776 100644 --- a/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_ccm.h @@ -579,13 +579,13 @@ enum ccm_clock_name_e ARM_PLL = 1, /* ARM PLL */ ARM_PLLOUT = 2, /* ARM PLL OUT */ SYS_PLL1_IN = 3, /* SYSTEM PLL1 IN */ - SYS_PLL1PFD0_IN = 5, /* SYSTEM PLL1 PFD0 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 = 11, /* SYSTEM PLL1 PFD2 IN */ + 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 */ diff --git a/arch/arm64/src/imx9/imx9_clockconfig.c b/arch/arm64/src/imx9/imx9_clockconfig.c index bf097f6dcf461..cc4d87a0b032b 100644 --- a/arch/arm64/src/imx9/imx9_clockconfig.c +++ b/arch/arm64/src/imx9/imx9_clockconfig.c @@ -58,6 +58,30 @@ * Private Data ****************************************************************************/ +static uint32_t g_pll_freqs[] = +{ + [OSC_24M] = 24000000U, /* 24MHZ OSCILLATOR. */ + [ARM_PLL] = 2000000000U, /* ARM PLL */ + [ARM_PLLOUT] = 2000000000U, /* ARM PLL OUT */ + [SYS_PLL1_IN] = 4000000000U, /* SYSTEM PLL1 IN */ + [SYS_PLL1PFD0_IN] = 1000000000U, /* SYSTEM PLL1 PFD0 IN */ + [SYS_PLL1PFD0] = 1000000000U, /* SYSTEM PLL1 PFD0 */ + [SYS_PLL1PFD0DIV2] = 500000000U, /* SYSTEM PLL1 PFD0 DIV2 */ + [SYS_PLL1PFD1_IN] = 800000000U, /* SYSTEM PLL1 PFD1 IN */ + [SYS_PLL1PFD1] = 800000000U, /* SYSTEM PLL1 PFD1 */ + [SYS_PLL1PFD1DIV2] = 400000000U, /* SYSTEM PLL1 PFD1 DIV2 */ + [SYS_PLL1PFD2_IN] = 625000000U, /* SYSTEM PLL1 PFD2 IN */ + [SYS_PLL1PFD2] = 625000000U, /* SYSTEM PLL1 PFD2 */ + [SYS_PLL1PFD2DIV2] = 312500000U, /* SYSTEM PLL1 PFD2 DIV2 */ + [AUDIO_PLL1] = 0U, /* AUDIO PLL1 */ + [AUDIO_PLL1OUT] = 0U, /* AUDIO PLL1 OUT */ + [DRAM_PLL] = 1000000000U, /* DRAM PLL */ + [DRAM_PLLOUT] = 1000000000U, /* DRAM PLL OUT */ + [VIDEO_PLL1] = 0U, /* VIDEO PLL1 */ + [VIDEO_PLL1OUT] = 0U, /* VIDEO PLL1 OUT */ + [EXT] = 0U /* EXT */ +}; + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -214,3 +238,83 @@ void imx9_clockconfig(void) * By default, all peripheral root clocks are set to the 24 MHz oscillator. */ } + +/**************************************************************************** + * 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) +{ + if (clkname >= EXT) + { + *frequency = 0; + return -ENODEV; + } + + *frequency = g_pll_freqs[clkname]; + 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 index b688e450f38ea..90301989a9462 100644 --- a/arch/arm64/src/imx9/imx9_clockconfig.h +++ b/arch/arm64/src/imx9/imx9_clockconfig.h @@ -27,6 +27,8 @@ #include +#include + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ @@ -43,4 +45,46 @@ 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 */ From dc8234245f21f89dc06ec99311baf71a8c3c1fd9 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Thu, 22 Feb 2024 16:59:38 +0200 Subject: [PATCH 124/147] arm64/imx9: Add GPIO, IOMUX and external interrupt support This adds memory mapped registers and drivers for digital I/O. --- arch/arm64/include/imx9/chip.h | 2 + arch/arm64/src/imx9/Kconfig | 4 + arch/arm64/src/imx9/Make.defs | 6 +- arch/arm64/src/imx9/chip.h | 2 + .../src/imx9/hardware/imx93/imx93_gpio.h | 59 ++ .../src/imx9/hardware/imx93/imx93_iomux.h | 604 +++++++++++++++++ .../src/imx9/hardware/imx93/imx93_pinmux.h | 634 ++++++++++++++++++ arch/arm64/src/imx9/hardware/imx9_gpio.h | 106 +++ arch/arm64/src/imx9/hardware/imx9_iomuxc.h | 104 +++ arch/arm64/src/imx9/hardware/imx9_pinmux.h | 36 + arch/arm64/src/imx9/imx9_gpio.c | 278 ++++++++ arch/arm64/src/imx9/imx9_gpio.h | 323 +++++++++ arch/arm64/src/imx9/imx9_gpiobase.c | 49 ++ arch/arm64/src/imx9/imx9_gpioirq.c | 356 ++++++++++ arch/arm64/src/imx9/imx9_iomuxc.c | 116 ++++ arch/arm64/src/imx9/imx9_iomuxc.h | 117 ++++ .../imx9/imx93-evk/configs/nsh/defconfig | 1 + 17 files changed, 2796 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/src/imx9/hardware/imx93/imx93_gpio.h create mode 100644 arch/arm64/src/imx9/hardware/imx93/imx93_iomux.h create mode 100644 arch/arm64/src/imx9/hardware/imx93/imx93_pinmux.h create mode 100644 arch/arm64/src/imx9/hardware/imx9_gpio.h create mode 100644 arch/arm64/src/imx9/hardware/imx9_iomuxc.h create mode 100644 arch/arm64/src/imx9/hardware/imx9_pinmux.h create mode 100644 arch/arm64/src/imx9/imx9_gpio.c create mode 100644 arch/arm64/src/imx9/imx9_gpio.h create mode 100644 arch/arm64/src/imx9/imx9_gpiobase.c create mode 100644 arch/arm64/src/imx9/imx9_gpioirq.c create mode 100644 arch/arm64/src/imx9/imx9_iomuxc.c create mode 100644 arch/arm64/src/imx9/imx9_iomuxc.h diff --git a/arch/arm64/include/imx9/chip.h b/arch/arm64/include/imx9/chip.h index b5b46f8ce1032..28553a96e2837 100644 --- a/arch/arm64/include/imx9/chip.h +++ b/arch/arm64/include/imx9/chip.h @@ -59,6 +59,8 @@ #define MPID_TO_CLUSTER_ID(mpid) ((mpid) & ~0xff) +#define IMX9_GPIO_NPORTS 4 + #endif /**************************************************************************** diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 3c921bbebe7c5..64a266865aa84 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -28,6 +28,10 @@ config IMX9_UART1 select UART1_SERIALDRIVER endmenu # iMX Peripheral Selection +config IMX9_GPIO_IRQ + bool "GPIO Interrupt Support" + default n + config IMX9_PLL bool "PLL setup support (WIP)" default n diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 8e8a8d98623be..15128654abaed 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -22,7 +22,7 @@ include common/Make.defs # i.MX9-specific C source files -CHIP_CSRCS = imx9_boot.c imx9_ccm.c imx9_clockconfig.c +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 @@ -30,3 +30,7 @@ ifeq ($(CONFIG_ARCH_CHIP_IMX93),y) CHIP_ASRCS = imx93_lowputc.S endif endif + +ifeq ($(CONFIG_IMX9_GPIO_IRQ),y) + CHIP_CSRCS += imx9_gpioirq.c +endif diff --git a/arch/arm64/src/imx9/chip.h b/arch/arm64/src/imx9/chip.h index 691f795ed8f28..f9792f5518e30 100644 --- a/arch/arm64/src/imx9/chip.h +++ b/arch/arm64/src/imx9/chip.h @@ -29,6 +29,8 @@ #ifndef __ASSEMBLY__ # include +# include +# include #endif /**************************************************************************** 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_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/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_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/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..229d4d635afa0 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_gpio.h @@ -0,0 +1,323 @@ +/**************************************************************************** + * 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_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..e8ba83642c54e --- /dev/null +++ b/arch/arm64/src/imx9/imx9_gpioirq.c @@ -0,0 +1,356 @@ +/**************************************************************************** + * 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_gpioN_A_B_interrupt + * + * Description: + * GPIO interrupt handlers. + * + ****************************************************************************/ + +static int imx9_gpio_0_15_interrupt(int irq, void *context, void *arg) +{ + uint32_t port = *(uint32_t *)arg; + uint32_t status; + uint32_t pin; + uint32_t regaddr; + + /* Get the pending interrupt indications */ + + regaddr = IMX9_GPIO_ISFR0(port); + status = getreg32(regaddr) & 0x0000ffff; + + /* Decode the pending interrupts */ + + for (pin = 0; pin < 16 && status != 0; pin++) + { + /* Is the IRQ associate 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; +} + +static int imx9_gpio_16_31_interrupt(int irq, void *context, void *arg) +{ + uint32_t port = *(uint32_t *)arg; + uint32_t status; + uint32_t pin; + uint32_t regaddr; + + /* Get the pending interrupt indications */ + + regaddr = IMX9_GPIO_ISFR0(port); + status = getreg32(regaddr) & 0xffff0000; + + /* Decode the pending interrupts */ + + for (pin = 16; pin < 32 && status != 0; pin++) + { + /* Is the IRQ associate 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 unconfigured GPIO interrupts at the NVIC */ + + up_disable_irq(IMX9_IRQ_GPIO1_0_15); + up_disable_irq(IMX9_IRQ_GPIO1_16_31); + + up_disable_irq(IMX9_IRQ_GPIO2_0_15); + up_disable_irq(IMX9_IRQ_GPIO2_16_31); + + up_disable_irq(IMX9_IRQ_GPIO3_0_15); + up_disable_irq(IMX9_IRQ_GPIO3_16_31); + + up_disable_irq(IMX9_IRQ_GPIO4_0_15); + up_disable_irq(IMX9_IRQ_GPIO4_16_31); + + /* Attach all configured GPIO interrupts and enable the interrupt at the + * NVIC + */ + + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO1_0_15, + imx9_gpio_0_15_interrupt, (void *)1)); + up_enable_irq(IMX9_IRQ_GPIO1_0_15); + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO1_16_31, + imx9_gpio_16_31_interrupt, (void *)1)); + up_enable_irq(IMX9_IRQ_GPIO1_16_31); + + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO2_0_15, + imx9_gpio_0_15_interrupt, (void *)2)); + up_enable_irq(IMX9_IRQ_GPIO1_0_15); + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO2_16_31, + imx9_gpio_16_31_interrupt, (void *)2)); + up_enable_irq(IMX9_IRQ_GPIO1_16_31); + + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO3_0_15, + imx9_gpio_0_15_interrupt, (void *)3)); + up_enable_irq(IMX9_IRQ_GPIO1_0_15); + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO3_16_31, + imx9_gpio_16_31_interrupt, (void *)3)); + up_enable_irq(IMX9_IRQ_GPIO1_16_31); + + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO4_0_15, + imx9_gpio_0_15_interrupt, (void *)4)); + up_enable_irq(IMX9_IRQ_GPIO1_0_15); + DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO4_16_31, + imx9_gpio_16_31_interrupt, (void *)4)); + up_enable_irq(IMX9_IRQ_GPIO1_16_31); +} + +/**************************************************************************** + * 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 icr = (pinset & GPIO_INTCFG_MASK) >> GPIO_INTCFG_SHIFT; + uint32_t both = (pinset & GPIO_INTBOTHCFG_MASK) >> GPIO_INTBOTHCFG_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; + + 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..80bacc7e5c8d6 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_iomuxc.h @@ -0,0 +1,117 @@ +/**************************************************************************** + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "hardware/imx9_iomuxc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IOMUX_PADCFG(_ctlreg, _mode, _dsyreg, _dsy, _padreg) \ + { \ + .ctlreg = (_ctlreg), \ + .mode = (_mode), \ + .dsyreg = (_dsyreg), \ + .dsy = (_dsy), \ + .padreg = (_padreg), \ + } + +#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; + +/**************************************************************************** + * 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); diff --git a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig index 9bf34ecc59718..90729bcb457ed 100644 --- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig @@ -32,6 +32,7 @@ CONFIG_FS_ROMFS=y CONFIG_HAVE_CXX=y CONFIG_HAVE_CXXINITIALIZE=y CONFIG_IDLETHREAD_STACKSIZE=8192 +CONFIG_IMX9_GPIO_IRQ=y CONFIG_IMX9_UART1=y CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INTELHEX_BINARY=y From fc9595ae9662dda7311f872874ddbcbab639574c Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 27 Mar 2024 10:46:24 +0200 Subject: [PATCH 125/147] arch/arm64/src/imx9: Flex-IO based PWM driver for imx9 This is a high resolution PWM driver, utilizing one 16-bit Flex-IO timer for generating PWM period and the rest of the timers to generate PWM duty cycles. This means that the period has to be the same for every PWM generated from one FLEXIO block, but this way we can get 16-bit resolution for the PWM signals. For a typical IMX9 HW there are 8 timers for each Flex-IO block, which means that by using this driver one can get 7 PWM outputs from one block. This driver can be later extended to have configuration options to use all 8 channels per flex-io by either using 8+8 -bit timer (less resolution) or by using an external trigger from an LPIT. Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/Kconfig | 41 + arch/arm64/src/imx9/Make.defs | 4 + arch/arm64/src/imx9/hardware/imx9_flexio.h | 823 +++++++++++++++++++++ arch/arm64/src/imx9/imx9_flexio_pwm.c | 756 +++++++++++++++++++ arch/arm64/src/imx9/imx9_flexio_pwm.h | 104 +++ 5 files changed, 1728 insertions(+) create mode 100644 arch/arm64/src/imx9/hardware/imx9_flexio.h create mode 100644 arch/arm64/src/imx9/imx9_flexio_pwm.c create mode 100644 arch/arm64/src/imx9/imx9_flexio_pwm.h diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 64a266865aa84..18183cdde58b5 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -16,16 +16,57 @@ config ARCH_CHIP_IMX93 select ARCH_HAVE_MULTICPU select ARMV8A_HAVE_GICv3 select ARCH_CORTEX_A55 + select ARCH_HAVE_PWM_MULTICHAN endchoice # i.MX9 Chip Selection endmenu # "i.MX9 Chip Selection" +config IMX9_FLEXIO_PWM + bool + select PWM_MULTICHAN + default n + menu "i.MX9 Peripheral Selection" config IMX9_UART1 bool "UART1" default n select UART1_SERIALDRIVER + +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 + endmenu # iMX Peripheral Selection config IMX9_GPIO_IRQ diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 15128654abaed..d7f26f8d91fbf 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -34,3 +34,7 @@ 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 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/imx9_flexio_pwm.c b/arch/arm64/src/imx9/imx9_flexio_pwm.c new file mode 100644 index 0000000000000..f213c1e5acab8 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_flexio_pwm.c @@ -0,0 +1,756 @@ +/**************************************************************************** + * 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) +{ + uint64_t duty = ub16toi(duty16); + uint32_t edge = (duty * priv->period + 0x8000) >> 16; + 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), duty); + + 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 */ From 47c725fecc740aebccbe035fd4e3f642c6330300 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 3 Apr 2024 12:05:37 +0300 Subject: [PATCH 126/147] arch/arm64/include/imx9/imx93_irq.h: Define IRQ_USBx interrupt numbers Signed-off-by: Jukka Laitinen --- arch/arm64/include/imx9/imx93_irq.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/imx9/imx93_irq.h b/arch/arm64/include/imx9/imx93_irq.h index cc3e24d707829..5e5de4ba43709 100644 --- a/arch/arm64/include/imx9/imx93_irq.h +++ b/arch/arm64/include/imx9/imx93_irq.h @@ -208,8 +208,8 @@ #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_RESERVED219 (IMX9_IRQ_EXT + 187) /* USB-1 Wake-up Interrupt */ -#define IMX9_IRQ_RESERVED220 (IMX9_IRQ_EXT + 188) /* USB-2 Wake-up 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_15 (IMX9_IRQ_EXT + 189) /* General Purpose Input/Output 4 interrupt 0 */ #define IMX9_IRQ_GPIO4_16_31 (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 */ From 1e907ae9001ee9acbad0e8c7b243744ba52b6e85 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 3 Apr 2024 16:01:59 +0300 Subject: [PATCH 127/147] arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h: Clean up some base address macros Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h b/arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h index f3fcbded4e0fc..050602fc0af0d 100644 --- a/arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h +++ b/arch/arm64/src/imx9/hardware/imx93/imx93_memorymap.h @@ -154,12 +154,12 @@ #define IMX9_TRDC1_BASE (0x44270000UL) #define IMX9_TRDC2_BASE (0x42460000UL) #define IMX9_TRGMUX_BASE (0x44531000UL) -#define IMX9_TSTMR1__TSTMRA_BASE (0x442C0000UL) -#define IMX9_TSTMR2__TSTMRA_BASE (0x42480000UL) -#define IMX9_USB__USB_OTG1_BASE (0x4C100000UL) -#define IMX9_USB__USB_OTG2_BASE (0x4C200000UL) -#define IMX9_USB__USBNC_OTG1_BASE (0x4C100200UL) -#define IMX9_USB__USBNC_OTG2_BASE (0x4C200200UL) +#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) From cac53922e536420ab929a800a6c9706cbdd38aa1 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 3 Apr 2024 12:06:34 +0300 Subject: [PATCH 128/147] arch/arm64/src/imx9: Add imx9 usb device driver This is a modified version from imxrt driver, which has the same controller. Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/Kconfig | 44 + arch/arm64/src/imx9/Make.defs | 4 + arch/arm64/src/imx9/hardware/imx9_usbotg.h | 665 +++++ arch/arm64/src/imx9/imx9_usbdev.c | 3111 ++++++++++++++++++++ arch/arm64/src/imx9/imx9_usbdev.h | 86 + 5 files changed, 3910 insertions(+) create mode 100644 arch/arm64/src/imx9/hardware/imx9_usbotg.h create mode 100644 arch/arm64/src/imx9/imx9_usbdev.c create mode 100644 arch/arm64/src/imx9/imx9_usbdev.h diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 18183cdde58b5..5056abd44f980 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -67,6 +67,50 @@ config IMX9_FLEXIO2_PWM_CHANNEL_PINS hex "FlexIO outputs used for FLEXIO2 timers" default 0x0000000000000000 +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 + endmenu # iMX Peripheral Selection config IMX9_GPIO_IRQ diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index d7f26f8d91fbf..8b74632163550 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -38,3 +38,7 @@ endif ifeq ($(CONFIG_IMX9_FLEXIO_PWM),y) CHIP_CSRCS += imx9_flexio_pwm.c endif + +ifeq ($(CONFIG_IMX9_USBDEV),y) + CHIP_CSRCS += imx9_usbdev.c +endif 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/imx9_usbdev.c b/arch/arm64/src/imx9/imx9_usbdev.c new file mode 100644 index 0000000000000..30f9fef33f785 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_usbdev.c @@ -0,0 +1,3111 @@ +/**************************************************************************** + * 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 + ****************************************************************************/ + +/* 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 + +#if defined(CONFIG_ARMV7M_DCACHE) +# define cache_aligned_alloc(s) kmm_memalign(ARMV7M_DCACHE_LINESIZE,(s)) +# define CACHE_ALIGNED_DATA aligned_data(ARMV7M_DCACHE_LINESIZE) +#else +# define cache_aligned_alloc kmm_malloc +# define CACHE_ALIGNED_DATA +#endif + +/* Hardware interface *******************************************************/ + +/* This represents a Endpoint Transfer Descriptor - note these must be 32 + * byte aligned. + */ + +struct 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 */ +}; + +/* 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 - note these must be aligned to a 2048 byte + * boundary + */ + +struct imx9_dqh_s +{ + uint32_t capability; /* Endpoint capability */ + uint32_t currdesc; /* Current dTD pointer */ + struct imx9_dtd_s overlay; /* DTD overlay */ + volatile uint32_t setup[2]; /* Set-up buffer */ + uint32_t gap[4]; /* align to 64 bytes */ +}; + +/* 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 buf[64] CACHE_ALIGNED_DATA; /* 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 qh[IMX9_NPHYSENDPOINTS] aligned_data(2048); + + struct imx9_dtd_s td[IMX9_NPHYSENDPOINTS] aligned_data(32); +}; + +#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 + ****************************************************************************/ + +static struct imx9_usb_s g_usbdev[] = +{ +#ifdef CONFIG_IMX9_USBDEV_USBC1 + { + .id = 0, + .base = IMX9_USB_OTG1_BASE, + }, +#endif + +#ifdef CONFIG_IMX9_USBDEV_USBC2 + { + .id = 1, + .base = IMX9_USB_OTG2_BASE, + }, +#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_flush_dcache((uintptr_t)dtd, + (uintptr_t)dtd + sizeof(struct imx9_dtd_s)); + up_flush_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); + + /* 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) + { + /* 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: + + /* Make sure we have updated data after the DMA transfer. + * This invalidation matches the flush in writedtd(). + */ + + up_invalidate_dcache((uintptr_t)priv->ep0.buf, + (uintptr_t)priv->ep0.buf + sizeof(priv->ep0.buf)); + + 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. + * This invalidation matches the flush in writedtd(). + */ + + 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 */ From 8288acc71c607ab63de429a929e363cffc600eab Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 26 Mar 2024 14:58:09 +0200 Subject: [PATCH 129/147] arch/arm64/src/imx9: Add TPM based PWM driver for IMX9 Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/Kconfig | 101 ++++ arch/arm64/src/imx9/Make.defs | 4 + arch/arm64/src/imx9/hardware/imx9_tpm.h | 206 +++++++ arch/arm64/src/imx9/imx9_tpm_pwm.c | 693 ++++++++++++++++++++++++ arch/arm64/src/imx9/imx9_tpm_pwm.h | 97 ++++ 5 files changed, 1101 insertions(+) create mode 100644 arch/arm64/src/imx9/hardware/imx9_tpm.h create mode 100644 arch/arm64/src/imx9/imx9_tpm_pwm.c create mode 100644 arch/arm64/src/imx9/imx9_tpm_pwm.h diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 5056abd44f980..9ab957be0133a 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -67,6 +67,107 @@ config IMX9_FLEXIO2_PWM_CHANNEL_PINS 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 diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 8b74632163550..0d7427aec3eb0 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -39,6 +39,10 @@ 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 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/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 */ From 1bd5a0c703b06130ef3e9c683158e69888e03197 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 5 Apr 2024 13:20:20 +0300 Subject: [PATCH 130/147] arch/arm64/src/imx9/imx9_flexio_pwm.c: Fix wrong input scale and pulse width Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/imx9_flexio_pwm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm64/src/imx9/imx9_flexio_pwm.c b/arch/arm64/src/imx9/imx9_flexio_pwm.c index f213c1e5acab8..1e93a1ffdc45c 100644 --- a/arch/arm64/src/imx9/imx9_flexio_pwm.c +++ b/arch/arm64/src/imx9/imx9_flexio_pwm.c @@ -444,8 +444,7 @@ static int pwm_update_frequency(struct imx9_pwmtimer_s *priv, int freq) static int pwm_update_duty(struct imx9_pwmtimer_s *priv, int pwm_ch, ub16_t duty16) { - uint64_t duty = ub16toi(duty16); - uint32_t edge = (duty * priv->period + 0x8000) >> 16; + uint32_t edge = ub16toi(duty16 * priv->period + b16HALF); int timer = pwm_ch - 1; /* map pwm ch 1 to timer 0 etc.. */ uint32_t regval; @@ -477,7 +476,7 @@ static int pwm_update_duty(struct imx9_pwmtimer_s *priv, int pwm_ch, * timer fully, otherwise just update the duty cycle */ - flexio_putreg(priv, IMX9_FLEXIO_TIMCMP_OFFSET(timer), duty); + flexio_putreg(priv, IMX9_FLEXIO_TIMCMP_OFFSET(timer), edge); if (priv->frequency == 0) { From af9f6ef7479496774d868d0f37ba2cdc1a5fecc1 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Wed, 27 Sep 2023 15:09:19 +0300 Subject: [PATCH 131/147] Create codeql.yml Signed-off-by: Jukka Laitinen --- .github/workflows/codeql.yml | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/codeql.yml 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}}" From b1fc6a1517dbd5711e11e6daee9615397813acc2 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Mon, 15 Apr 2024 17:47:35 +0300 Subject: [PATCH 132/147] imx93_gpioirq: Fix the GPIO interrupt source names The original assumption was that the interrupt numbers are divided so that 16 pins from 1 port are handled by a single interrupt source. So source 0 would handle pins 0-15 and source 1 would handle pins 16-31. This assumption is wrong, each pin has two sources, thus there are two interrupt lines for each pin. The driver uses source 0, and leaves source 1 disabled. --- arch/arm64/include/imx9/imx93_irq.h | 16 ++-- arch/arm64/src/imx9/imx9_gpio.h | 14 +++ arch/arm64/src/imx9/imx9_gpioirq.c | 134 ++++++++-------------------- 3 files changed, 61 insertions(+), 103 deletions(-) diff --git a/arch/arm64/include/imx9/imx93_irq.h b/arch/arm64/include/imx9/imx93_irq.h index 5e5de4ba43709..010a1b3e25e20 100644 --- a/arch/arm64/include/imx9/imx93_irq.h +++ b/arch/arm64/include/imx9/imx93_irq.h @@ -31,8 +31,8 @@ #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_15 (IMX9_IRQ_EXT + 10) /* General Purpose Input/Output 1 interrupt 0 */ -#define IMX9_IRQ_GPIO1_16_31 (IMX9_IRQ_EXT + 11) /* General Purpose Input/Output 1 interrupt 1 */ +#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 */ @@ -78,10 +78,10 @@ #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_15 (IMX9_IRQ_EXT + 57) /* General Purpose Input/Output 2 interrupt 0 */ -#define IMX9_IRQ_GPIO2_16_31 (IMX9_IRQ_EXT + 58) /* General Purpose Input/Output 2 interrupt 1 */ -#define IMX9_IRQ_GPIO3_0_15 (IMX9_IRQ_EXT + 59) /* General Purpose Input/Output 3 interrupt 0 */ -#define IMX9_IRQ_GPIO3_16_31 (IMX9_IRQ_EXT + 60) /* General Purpose Input/Output 3 interrupt 1 */ +#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 */ @@ -210,8 +210,8 @@ #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_15 (IMX9_IRQ_EXT + 189) /* General Purpose Input/Output 4 interrupt 0 */ -#define IMX9_IRQ_GPIO4_16_31 (IMX9_IRQ_EXT + 190) /* General Purpose Input/Output 4 interrupt 1 */ +#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 */ diff --git a/arch/arm64/src/imx9/imx9_gpio.h b/arch/arm64/src/imx9/imx9_gpio.h index 229d4d635afa0..1c7f44a53f6fe 100644 --- a/arch/arm64/src/imx9/imx9_gpio.h +++ b/arch/arm64/src/imx9/imx9_gpio.h @@ -274,6 +274,20 @@ void imx9_gpio_write(gpio_pinset_t pinset, bool value); 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 * diff --git a/arch/arm64/src/imx9/imx9_gpioirq.c b/arch/arm64/src/imx9/imx9_gpioirq.c index e8ba83642c54e..3d75e9079834c 100644 --- a/arch/arm64/src/imx9/imx9_gpioirq.c +++ b/arch/arm64/src/imx9/imx9_gpioirq.c @@ -66,16 +66,17 @@ static struct imx9_portisr_s g_isrtab[IMX9_GPIO_NPORTS]; ****************************************************************************/ /**************************************************************************** - * Name: imx9_gpioN_A_B_interrupt + * Name: imx9_gpio_interrupt * * Description: - * GPIO interrupt handlers. + * GPIO interrupt handlers. iMX9 has two interrupt sources for each pin, + * the NuttX driver uses source 0. * ****************************************************************************/ -static int imx9_gpio_0_15_interrupt(int irq, void *context, void *arg) +static int imx9_gpio_interrupt(int irq, void *context, void *arg) { - uint32_t port = *(uint32_t *)arg; + uint32_t port = (uint32_t)((uintptr_t)arg) >> GPIO_PORT_SHIFT; uint32_t status; uint32_t pin; uint32_t regaddr; @@ -83,56 +84,13 @@ static int imx9_gpio_0_15_interrupt(int irq, void *context, void *arg) /* Get the pending interrupt indications */ regaddr = IMX9_GPIO_ISFR0(port); - status = getreg32(regaddr) & 0x0000ffff; + status = getreg32(regaddr); /* Decode the pending interrupts */ - for (pin = 0; pin < 16 && status != 0; pin++) + for (pin = 0; pin < 32 && status != 0; pin++) { - /* Is the IRQ associate 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; -} - -static int imx9_gpio_16_31_interrupt(int irq, void *context, void *arg) -{ - uint32_t port = *(uint32_t *)arg; - uint32_t status; - uint32_t pin; - uint32_t regaddr; - - /* Get the pending interrupt indications */ - - regaddr = IMX9_GPIO_ISFR0(port); - status = getreg32(regaddr) & 0xffff0000; - - /* Decode the pending interrupts */ - - for (pin = 16; pin < 32 && status != 0; pin++) - { - /* Is the IRQ associate with this pin pending? */ + /* Is the IRQ associated with this pin pending? */ uint32_t mask = (1 << pin); if ((status & mask) != 0) @@ -189,51 +147,37 @@ void imx9_gpioirq_initialize(void) } } - /* Disable all unconfigured GPIO interrupts at the NVIC */ - - up_disable_irq(IMX9_IRQ_GPIO1_0_15); - up_disable_irq(IMX9_IRQ_GPIO1_16_31); - - up_disable_irq(IMX9_IRQ_GPIO2_0_15); - up_disable_irq(IMX9_IRQ_GPIO2_16_31); - - up_disable_irq(IMX9_IRQ_GPIO3_0_15); - up_disable_irq(IMX9_IRQ_GPIO3_16_31); - - up_disable_irq(IMX9_IRQ_GPIO4_0_15); - up_disable_irq(IMX9_IRQ_GPIO4_16_31); - - /* Attach all configured GPIO interrupts and enable the interrupt at the - * NVIC - */ - - DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO1_0_15, - imx9_gpio_0_15_interrupt, (void *)1)); - up_enable_irq(IMX9_IRQ_GPIO1_0_15); - DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO1_16_31, - imx9_gpio_16_31_interrupt, (void *)1)); - up_enable_irq(IMX9_IRQ_GPIO1_16_31); - - DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO2_0_15, - imx9_gpio_0_15_interrupt, (void *)2)); - up_enable_irq(IMX9_IRQ_GPIO1_0_15); - DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO2_16_31, - imx9_gpio_16_31_interrupt, (void *)2)); - up_enable_irq(IMX9_IRQ_GPIO1_16_31); - - DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO3_0_15, - imx9_gpio_0_15_interrupt, (void *)3)); - up_enable_irq(IMX9_IRQ_GPIO1_0_15); - DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO3_16_31, - imx9_gpio_16_31_interrupt, (void *)3)); - up_enable_irq(IMX9_IRQ_GPIO1_16_31); - - DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO4_0_15, - imx9_gpio_0_15_interrupt, (void *)4)); - up_enable_irq(IMX9_IRQ_GPIO1_0_15); - DEBUGVERIFY(irq_attach(IMX9_IRQ_GPIO4_16_31, - imx9_gpio_16_31_interrupt, (void *)4)); - up_enable_irq(IMX9_IRQ_GPIO1_16_31); + /* 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); } /**************************************************************************** From f349c37985b2f1f4f7892f90df0e454df976fbe3 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 2 Apr 2024 10:01:41 +0300 Subject: [PATCH 133/147] boards/arm64/imx9/imx93-evk: Add PWM support utilizing flexio-pwm Signed-off-by: Jukka Laitinen --- .../imx9/imx93-evk/configs/nsh/defconfig | 3 + boards/arm64/imx9/imx93-evk/include/board.h | 14 +++ boards/arm64/imx9/imx93-evk/src/Makefile | 4 + boards/arm64/imx9/imx93-evk/src/imx93-evk.h | 12 +++ .../arm64/imx9/imx93-evk/src/imx9_bringup.c | 10 ++ boards/arm64/imx9/imx93-evk/src/imx9_pwm.c | 93 +++++++++++++++++++ 6 files changed, 136 insertions(+) create mode 100644 boards/arm64/imx9/imx93-evk/src/imx9_pwm.c diff --git a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig index 90729bcb457ed..38ae401b21317 100644 --- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig @@ -32,6 +32,7 @@ CONFIG_FS_ROMFS=y CONFIG_HAVE_CXX=y CONFIG_HAVE_CXXINITIALIZE=y CONFIG_IDLETHREAD_STACKSIZE=8192 +CONFIG_IMX9_FLEXIO1_PWM=y CONFIG_IMX9_GPIO_IRQ=y CONFIG_IMX9_UART1=y CONFIG_INIT_ENTRYPOINT="nsh_main" @@ -41,6 +42,8 @@ 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 diff --git a/boards/arm64/imx9/imx93-evk/include/board.h b/boards/arm64/imx9/imx93-evk/include/board.h index e8fd207609ecc..0cfea9b6eafb1 100644 --- a/boards/arm64/imx9/imx93-evk/include/board.h +++ b/boards/arm64/imx9/imx93-evk/include/board.h @@ -31,6 +31,20 @@ * Pre-processor Definitions ****************************************************************************/ +/* 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) + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/boards/arm64/imx9/imx93-evk/src/Makefile b/boards/arm64/imx9/imx93-evk/src/Makefile index d034d21b4b4b7..13b8bf445a96c 100644 --- a/boards/arm64/imx9/imx93-evk/src/Makefile +++ b/boards/arm64/imx9/imx93-evk/src/Makefile @@ -26,4 +26,8 @@ ifeq ($(CONFIG_BOARDCTL),y) CSRCS += imx9_appinit.c endif +ifeq ($(CONFIG_PWM),y) +CSRCS += imx9_pwm.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 index 5956c51fce815..4b9c0f3a464b3 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx93-evk.h +++ b/boards/arm64/imx9/imx93-evk/src/imx93-evk.h @@ -55,5 +55,17 @@ int imx9_bringup(void); #endif +/**************************************************************************** + * Name: imx9_pwm_setup + * + * Description: + * Initialize PWM outputs + * + ****************************************************************************/ + +#if defined(CONFIG_PWM) +int imx9_pwm_setup(void); +#endif + #endif /* __ASSEMBLY__ */ #endif /* __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H */ diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c index a267b844503e3..fc30e67cff102 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c +++ b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c @@ -57,6 +57,16 @@ int imx9_bringup(void) } #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 + UNUSED(ret); 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..152e78da90e4f --- /dev/null +++ b/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c @@ -0,0 +1,93 @@ +/**************************************************************************** + * 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" + +/**************************************************************************** + * 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; + } +#endif + + return ret; +} From 85de98ecdcb8048cb84811056c42bef1da3722f0 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 4 Apr 2024 14:53:26 +0300 Subject: [PATCH 134/147] boards/arm64/imx9/imx93-evk/configs/nsh/defconfig: Enable USB and CDCACM Signed-off-by: Jukka Laitinen --- boards/arm64/imx9/imx93-evk/configs/nsh/defconfig | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig index 38ae401b21317..903e4fb67a46c 100644 --- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig @@ -15,13 +15,10 @@ 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_SCHED=y -CONFIG_DEBUG_SCHED_ERROR=y -CONFIG_DEBUG_SCHED_INFO=y -CONFIG_DEBUG_SCHED_WARN=y CONFIG_DEBUG_SYMBOLS=y CONFIG_DEFAULT_TASK_STACKSIZE=8192 CONFIG_DEV_ZERO=y @@ -35,6 +32,7 @@ CONFIG_IDLETHREAD_STACKSIZE=8192 CONFIG_IMX9_FLEXIO1_PWM=y CONFIG_IMX9_GPIO_IRQ=y CONFIG_IMX9_UART1=y +CONFIG_IMX9_USBDEV_USBC1=y CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INTELHEX_BINARY=y CONFIG_NSH_ARCHINIT=y @@ -52,11 +50,14 @@ 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_CDCACM=y CONFIG_SYSTEM_NSH=y CONFIG_SYSTEM_SYSTEM=y CONFIG_SYSTEM_TIME64=y From 60c612fb30aee3ef87ce4b07e8b224ac4be5cea0 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 4 Apr 2024 19:16:25 +0300 Subject: [PATCH 135/147] boards/arm64/imx9/imx93-evk: Enable PWM from TPM3ch3 on imx93-evk pin GPIO_IO24 Signed-off-by: Jukka Laitinen --- .../imx9/imx93-evk/configs/nsh/defconfig | 2 ++ boards/arm64/imx9/imx93-evk/include/board.h | 4 ++++ boards/arm64/imx9/imx93-evk/src/imx9_pwm.c | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig index 903e4fb67a46c..e1834dc8ed440 100644 --- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig @@ -31,6 +31,8 @@ CONFIG_HAVE_CXXINITIALIZE=y CONFIG_IDLETHREAD_STACKSIZE=8192 CONFIG_IMX9_FLEXIO1_PWM=y CONFIG_IMX9_GPIO_IRQ=y +CONFIG_IMX9_TPM3_PWM=y +CONFIG_IMX9_TPM3_PWM_CHMUX=0x00000003 CONFIG_IMX9_UART1=y CONFIG_IMX9_USBDEV_USBC1=y CONFIG_INIT_ENTRYPOINT="nsh_main" diff --git a/boards/arm64/imx9/imx93-evk/include/board.h b/boards/arm64/imx9/imx93-evk/include/board.h index 0cfea9b6eafb1..bd78f1cf7906e 100644 --- a/boards/arm64/imx9/imx93-evk/include/board.h +++ b/boards/arm64/imx9/imx93-evk/include/board.h @@ -45,6 +45,10 @@ #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) +/* 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) + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c b/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c index 152e78da90e4f..f3989167f892b 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c +++ b/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c @@ -29,6 +29,7 @@ #include #include "imx9_flexio_pwm.h" +#include "imx9_tpm_pwm.h" /**************************************************************************** * Pre-processor Definitions @@ -87,6 +88,24 @@ int imx9_pwm_setup(void) { ret = -ENODEV; } + + if (ret < 0) + { + return ret; + } +#endif + +#ifdef CONFIG_IMX9_TPM3_PWM + lower_half = imx9_flexio_pwm_init(PWM_TPM3); + + if (lower_half) + { + ret = pwm_register("/dev/pwm2", lower_half); + } + else + { + ret = -ENODEV; + } #endif return ret; From ed4511e0de19c46e32b3961110f147bf88c5af40 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 2 Apr 2024 14:12:37 +0300 Subject: [PATCH 136/147] arch/arm64: Add atomic modifyregXX These are needed by drivers --- arch/arm64/src/common/Make.defs | 1 + arch/arm64/src/common/arm64_arch.h | 8 ++++ arch/arm64/src/common/arm64_modifyreg16.c | 57 +++++++++++++++++++++++ arch/arm64/src/common/arm64_modifyreg32.c | 57 +++++++++++++++++++++++ arch/arm64/src/common/arm64_modifyreg8.c | 57 +++++++++++++++++++++++ 5 files changed, 180 insertions(+) create mode 100644 arch/arm64/src/common/arm64_modifyreg16.c create mode 100644 arch/arm64/src/common/arm64_modifyreg32.c create mode 100644 arch/arm64/src/common/arm64_modifyreg8.c 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..63f3f6d7c1293 100644 --- a/arch/arm64/src/common/arm64_arch.h +++ b/arch/arm64/src/common/arm64_arch.h @@ -479,10 +479,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_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); +} From f542f57a27a8b3e378fe846d82f824c14a109351 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 27 Mar 2024 17:13:08 +0200 Subject: [PATCH 137/147] arm64/imx9: Add LPI2C driver --- arch/arm64/Kconfig | 1 + arch/arm64/src/imx9/Kconfig | 249 ++ arch/arm64/src/imx9/Make.defs | 4 + arch/arm64/src/imx9/hardware/imx9_lpi2c.h | 622 ++++ arch/arm64/src/imx9/imx9_lpi2c.c | 2579 +++++++++++++++++ arch/arm64/src/imx9/imx9_lpi2c.h | 71 + .../imx9/imx93-evk/configs/nsh/defconfig | 6 + boards/arm64/imx9/imx93-evk/include/board.h | 12 + boards/arm64/imx9/imx93-evk/src/Makefile | 4 + boards/arm64/imx9/imx93-evk/src/imx93-evk.h | 12 + .../arm64/imx9/imx93-evk/src/imx9_boardinit.c | 3 + .../arm64/imx9/imx93-evk/src/imx9_bringup.c | 10 + boards/arm64/imx9/imx93-evk/src/imx9_i2c.c | 77 + 13 files changed, 3650 insertions(+) create mode 100644 arch/arm64/src/imx9/hardware/imx9_lpi2c.h create mode 100644 arch/arm64/src/imx9/imx9_lpi2c.c create mode 100644 arch/arm64/src/imx9/imx9_lpi2c.h create mode 100644 boards/arm64/imx9/imx93-evk/src/imx9_i2c.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 37b632f9aeb47..b9fc7bdb06348 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -94,6 +94,7 @@ config ARCH_CHIP_IMX8 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--- diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 9ab957be0133a..9368c961c160f 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -218,8 +218,257 @@ config IMX9_GPIO_IRQ bool "GPIO Interrupt Support" default n +config IMX9_LPI2C + bool "LPI2C support" + default n + config IMX9_PLL bool "PLL setup support (WIP)" 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 "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 + endif # ARCH_CHIP_IMX9 diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 0d7427aec3eb0..27a19cb357b97 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -46,3 +46,7 @@ endif ifeq ($(CONFIG_IMX9_USBDEV),y) CHIP_CSRCS += imx9_usbdev.c endif + +ifeq ($(CONFIG_IMX9_LPI2C),y) + CHIP_CSRCS += imx9_lpi2c.c +endif 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/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/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig index e1834dc8ed440..64c7f53357551 100644 --- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig @@ -28,9 +28,14 @@ CONFIG_FS_PROCFS=y CONFIG_FS_ROMFS=y CONFIG_HAVE_CXX=y CONFIG_HAVE_CXXINITIALIZE=y +CONFIG_I2C=y +CONFIG_I2C_RESET=y CONFIG_IDLETHREAD_STACKSIZE=8192 CONFIG_IMX9_FLEXIO1_PWM=y CONFIG_IMX9_GPIO_IRQ=y +CONFIG_IMX9_LPI2C1=y +CONFIG_IMX9_LPI2C_DYNTIMEO=y +CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP=10 CONFIG_IMX9_TPM3_PWM=y CONFIG_IMX9_TPM3_PWM_CHMUX=0x00000003 CONFIG_IMX9_UART1=y @@ -60,6 +65,7 @@ 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_SYSTEM=y CONFIG_SYSTEM_TIME64=y diff --git a/boards/arm64/imx9/imx93-evk/include/board.h b/boards/arm64/imx9/imx93-evk/include/board.h index bd78f1cf7906e..6cd4c26e56143 100644 --- a/boards/arm64/imx9/imx93-evk/include/board.h +++ b/boards/arm64/imx9/imx93-evk/include/board.h @@ -31,6 +31,8 @@ * Pre-processor Definitions ****************************************************************************/ +#define IOMUX_LPI2C_DEFAULT (IOMUXC_PAD_OD_ENABLE | IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6) + /* FLEXIO to PWM pin muxings */ /* EVK signals @@ -49,6 +51,16 @@ #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) + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/boards/arm64/imx9/imx93-evk/src/Makefile b/boards/arm64/imx9/imx93-evk/src/Makefile index 13b8bf445a96c..e8c38027a4bf9 100644 --- a/boards/arm64/imx9/imx93-evk/src/Makefile +++ b/boards/arm64/imx9/imx93-evk/src/Makefile @@ -30,4 +30,8 @@ ifeq ($(CONFIG_PWM),y) CSRCS += imx9_pwm.c endif +ifeq ($(CONFIG_IMX9_LPI2C),y) +CSRCS += imx9_i2c.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 index 4b9c0f3a464b3..1da0b3b88eeac 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx93-evk.h +++ b/boards/arm64/imx9/imx93-evk/src/imx93-evk.h @@ -67,5 +67,17 @@ int imx9_bringup(void); 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 + #endif /* __ASSEMBLY__ */ #endif /* __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H */ diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c b/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c index 7443f92ccd263..876b9014de6f0 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c +++ b/boards/arm64/imx9/imx93-evk/src/imx9_boardinit.c @@ -23,8 +23,11 @@ ****************************************************************************/ #include + #include + #include + #include "imx93-evk.h" /**************************************************************************** diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c index fc30e67cff102..6048509b67980 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c +++ b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c @@ -67,6 +67,16 @@ int imx9_bringup(void) } #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 + 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; +} From 08d4f08f732c1b6502a5c16f3ab55c98e08736b5 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 16 Apr 2024 11:59:06 +0300 Subject: [PATCH 138/147] imx9_iomux.h: Fix issues with the header file - Add missing include guard - Add missing C++ guard - Fix the initialization ordering in IOMUX_PADCFG macro. Why ? Becaused of: imx9_iomuxc.h:54:3: error: designator order for field 'iomux_padcfg_s::dsyreg' does not match declaration order in 'iomux_padcfg_s' 54 | } | --- arch/arm64/src/imx9/imx9_iomuxc.h | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/arch/arm64/src/imx9/imx9_iomuxc.h b/arch/arm64/src/imx9/imx9_iomuxc.h index 80bacc7e5c8d6..6b9c8617b3051 100644 --- a/arch/arm64/src/imx9/imx9_iomuxc.h +++ b/arch/arm64/src/imx9/imx9_iomuxc.h @@ -18,6 +18,9 @@ * ****************************************************************************/ +#ifndef __ARCH_ARM64_SRC_IMX9_IMX9_IOMUXC_H +#define __ARCH_ARM64_SRC_IMX9_IMX9_IOMUXC_H + /**************************************************************************** * Included Files ****************************************************************************/ @@ -36,10 +39,10 @@ #define IOMUX_PADCFG(_ctlreg, _mode, _dsyreg, _dsy, _padreg) \ { \ .ctlreg = (_ctlreg), \ - .mode = (_mode), \ + .padreg = (_padreg), \ .dsyreg = (_dsyreg), \ + .mode = (_mode), \ .dsy = (_dsy), \ - .padreg = (_padreg), \ } #define IOMUX_CFG(_padcfg, _pad, _mux) \ @@ -81,6 +84,19 @@ struct iomux_cfg_s }; 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 * @@ -115,3 +131,9 @@ int imx9_iomux_configure(iomux_cfg_t cfg); ****************************************************************************/ int imx9_iomux_gpio(iomux_cfg_t cfg, bool sion); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_IOMUXC_H */ From 55eeb017948f8c059e8a96fd1ec18818fe6b7d4b Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 16 Apr 2024 15:44:30 +0300 Subject: [PATCH 139/147] arch/arm64/src/imx9: Add a more capable uart driver Add an uart driver supporting LPUART1-8, dma, flow control, tc etc. Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/Kconfig | 85 +- arch/arm64/src/imx9/Make.defs | 5 +- arch/arm64/src/imx9/hardware/imx9_lpuart.h | 403 ++- arch/arm64/src/imx9/imx9_boot.c | 7 + arch/arm64/src/imx9/imx9_lowputc.c | 532 +++ .../imx9/{imx93_lowputc.S => imx9_lowputc.h} | 97 +- arch/arm64/src/imx9/imx9_lpuart.c | 3121 +++++++++++++---- arch/arm64/src/imx9/imx9_serial.h | 228 +- .../imx9/imx93-evk/configs/nsh/defconfig | 4 +- boards/arm64/imx9/imx93-evk/include/board.h | 7 + 10 files changed, 3641 insertions(+), 848 deletions(-) create mode 100644 arch/arm64/src/imx9/imx9_lowputc.c rename arch/arm64/src/imx9/{imx93_lowputc.S => imx9_lowputc.h} (50%) diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 9368c961c160f..7673dc6356259 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -28,10 +28,89 @@ config IMX9_FLEXIO_PWM default n menu "i.MX9 Peripheral Selection" -config IMX9_UART1 - bool "UART1" + +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 UART1_SERIALDRIVER + 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 diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 27a19cb357b97..5e11a38b59c76 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -25,10 +25,7 @@ include common/Make.defs 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 - ifeq ($(CONFIG_ARCH_EARLY_PRINT),y) - CHIP_ASRCS = imx93_lowputc.S - endif + CHIP_CSRCS += imx9_lpuart.c imx9_lowputc.c endif ifeq ($(CONFIG_IMX9_GPIO_IRQ),y) diff --git a/arch/arm64/src/imx9/hardware/imx9_lpuart.h b/arch/arm64/src/imx9/hardware/imx9_lpuart.h index 3925c51bc606f..c688d5966a14e 100644 --- a/arch/arm64/src/imx9/hardware/imx9_lpuart.h +++ b/arch/arm64/src/imx9/hardware/imx9_lpuart.h @@ -25,134 +25,289 @@ * Included Files ****************************************************************************/ -#include +#include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* 32-bit register definition */ - -#define UARTVERID 0x0000 /* Version ID Register */ -#define UARTPARAM 0x0004 /* Parameter Register */ -#define UARTGLOBAL 0x0008 /* LPUART Global Register */ -#define UARTPINCFG 0x000c /* LPUART Pin Configuration Register */ -#define UARTBAUD 0x0010 /* LPUART Baud Rate Register */ -#define UARTSTAT 0x0014 /* LPUART Status Register */ -#define UARTCTRL 0x0018 /* LPUART Control Register */ -#define UARTDATA 0x001c /* LPUART Data Register */ -#define UARTMATCH 0x0020 /* LPUART Match Address Register */ -#define UARTMODIR 0x0024 /* LPUART Modem IrDA Register */ -#define UARTFIFO 0x0028 /* LPUART FIFO Register */ -#define UARTWATER 0x002c /* LPUART Watermark Register */ - -#define UARTBAUD_MAEN1 0x80000000 -#define UARTBAUD_MAEN2 0x40000000 -#define UARTBAUD_M10 0x20000000 -#define UARTBAUD_TDMAE 0x00800000 -#define UARTBAUD_RDMAE 0x00200000 -#define UARTBAUD_RIDMAE 0x00100000 -#define UARTBAUD_MATCFG 0x00400000 -#define UARTBAUD_BOTHEDGE 0x00020000 -#define UARTBAUD_RESYNCDIS 0x00010000 -#define UARTBAUD_LBKDIE 0x00008000 -#define UARTBAUD_RXEDGIE 0x00004000 -#define UARTBAUD_SBNS 0x00002000 -#define UARTBAUD_SBR 0x00000000 -#define UARTBAUD_SBR_MASK 0x1fff -#define UARTBAUD_OSR_MASK 0x1f -#define UARTBAUD_OSR_SHIFT 24 - -#define UARTSTAT_LBKDIF 0x80000000 -#define UARTSTAT_RXEDGIF 0x40000000 -#define UARTSTAT_MSBF 0x20000000 -#define UARTSTAT_RXINV 0x10000000 -#define UARTSTAT_RWUID 0x08000000 -#define UARTSTAT_BRK13 0x04000000 -#define UARTSTAT_LBKDE 0x02000000 -#define UARTSTAT_RAF 0x01000000 -#define UARTSTAT_TDRE 0x00800000 -#define UARTSTAT_TC 0x00400000 -#define UARTSTAT_RDRF 0x00200000 -#define UARTSTAT_IDLE 0x00100000 -#define UARTSTAT_OR 0x00080000 -#define UARTSTAT_NF 0x00040000 -#define UARTSTAT_FE 0x00020000 -#define UARTSTAT_PE 0x00010000 -#define UARTSTAT_MA1F 0x00008000 -#define UARTSTAT_M21F 0x00004000 - -#define UARTCTRL_R8T9 0x80000000 -#define UARTCTRL_R9T8 0x40000000 -#define UARTCTRL_TXDIR 0x20000000 -#define UARTCTRL_TXINV 0x10000000 -#define UARTCTRL_ORIE 0x08000000 -#define UARTCTRL_NEIE 0x04000000 -#define UARTCTRL_FEIE 0x02000000 -#define UARTCTRL_PEIE 0x01000000 -#define UARTCTRL_TIE 0x00800000 -#define UARTCTRL_TCIE 0x00400000 -#define UARTCTRL_RIE 0x00200000 -#define UARTCTRL_ILIE 0x00100000 -#define UARTCTRL_TE 0x00080000 -#define UARTCTRL_RE 0x00040000 -#define UARTCTRL_RWU 0x00020000 -#define UARTCTRL_SBK 0x00010000 -#define UARTCTRL_MA1IE 0x00008000 -#define UARTCTRL_MA2IE 0x00004000 -#define UARTCTRL_IDLECFG_OFF 0x8 -#define UARTCTRL_LOOPS 0x00000080 -#define UARTCTRL_DOZEEN 0x00000040 -#define UARTCTRL_RSRC 0x00000020 -#define UARTCTRL_M 0x00000010 -#define UARTCTRL_WAKE 0x00000008 -#define UARTCTRL_ILT 0x00000004 -#define UARTCTRL_PE 0x00000002 -#define UARTCTRL_PT 0x00000001 - -#define UARTDATA_NOISY 0x00008000 -#define UARTDATA_PARITYE 0x00004000 -#define UARTDATA_FRETSC 0x00002000 -#define UARTDATA_RXEMPT 0x00001000 -#define UARTDATA_IDLINE 0x00000800 -#define UARTDATA_MASK 0x3ff - -#define UARTMODIR_IREN 0x00020000 -#define UARTMODIR_RTSWATER_S 0x8 -#define UARTMODIR_TXCTSSRC 0x00000020 -#define UARTMODIR_TXCTSC 0x00000010 -#define UARTMODIR_RXRTSE 0x00000008 -#define UARTMODIR_TXRTSPOL 0x00000004 -#define UARTMODIR_TXRTSE 0x00000002 -#define UARTMODIR_TXCTSE 0x00000001 - -#define UARTFIFO_TXEMPT 0x00800000 -#define UARTFIFO_RXEMPT 0x00400000 -#define UARTFIFO_TXOF 0x00020000 -#define UARTFIFO_RXUF 0x00010000 -#define UARTFIFO_TXFLUSH 0x00008000 -#define UARTFIFO_RXFLUSH 0x00004000 -#define UARTFIFO_RXIDEN_MASK 0x7 -#define UARTFIFO_RXIDEN_OFF 10 -#define UARTFIFO_TXOFE 0x00000200 -#define UARTFIFO_RXUFE 0x00000100 -#define UARTFIFO_TXFE 0x00000080 -#define UARTFIFO_FIFOSIZE_MASK 0x7 -#define UARTFIFO_TXSIZE_OFF 4 -#define UARTFIFO_RXFE 0x00000008 -#define UARTFIFO_RXSIZE_OFF 0 -#define UARTFIFO_DEPTH(x) (0x1 << ((x) ? ((x) + 1) : 0)) - -#define UARTWATER_COUNT_MASK 0xff -#define UARTWATER_TXCNT_OFF 8 -#define UARTWATER_RXCNT_OFF 24 -#define UARTWATER_WATER_MASK 0xff -#define UARTWATER_TXWATER_OFF 0 -#define UARTWATER_RXWATER_OFF 16 - -#define UARTGLOBAL_RST 0x2 - -#define UARTFIFO_RXIDEN_RDRF 0x3 -#define UARTCTRL_IDLECFG 0x7 +/* 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/imx9_boot.c b/arch/arm64/src/imx9/imx9_boot.c index 16f19de2c6b54..260e67997428f 100644 --- a/arch/arm64/src/imx9/imx9_boot.c +++ b/arch/arm64/src/imx9/imx9_boot.c @@ -39,6 +39,7 @@ #include "arm64_mmu.h" #include "imx9_boot.h" #include "imx9_serial.h" +#include "imx9_lowputc.h" /**************************************************************************** * Private Data @@ -96,6 +97,12 @@ void arm64_chip_boot(void) arm64_mmu_init(true); + /* Do UART early initialization & pin muxing */ + +#ifdef CONFIG_IMX9_LPUART + imx9_lowsetup(); +#endif + /* Perform board-specific device initialization. This would include * configuration of board specific resources such as GPIOs, LEDs, etc. */ 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/imx93_lowputc.S b/arch/arm64/src/imx9/imx9_lowputc.h similarity index 50% rename from arch/arm64/src/imx9/imx93_lowputc.S rename to arch/arm64/src/imx9/imx9_lowputc.h index f3311810e05dd..30aceed681c28 100644 --- a/arch/arm64/src/imx9/imx93_lowputc.S +++ b/arch/arm64/src/imx9/imx9_lowputc.h @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/arm64/src/imx9/imx93_lowputs.S + * 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 @@ -16,70 +16,69 @@ * License for the specific language governing permissions and limitations * under the License. * - **************************************************************************** - * - * DESCRIPTION - * Wrapper for early printk - * - ***************************************************************************/ + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H +#define __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ #include +#include -#include "arm64_macro.inc" +#include +#include +#include -#include "hardware/imx9_lpuart.h" -#include "hardware/imx93/imx93_memorymap.h" +#include "arm64_internal.h" /**************************************************************************** - * Public Symbols + * Public Types ****************************************************************************/ - .file "imx93_lowputc.S" +/* This structure describes the configuration of an UART */ -/**************************************************************************** - * Assembly Macros - ****************************************************************************/ +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 */ +}; /**************************************************************************** - * Private Functions + * Public Function Prototypes ****************************************************************************/ /**************************************************************************** - * 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. + * ****************************************************************************/ -/* PL011 UART initialization */ - -GTEXT(arm64_earlyprintinit) -SECTION_FUNC(text, arm64_earlyprintinit) - /* TODO: Assumes u-boot has set us up, assumption is fine for now */ - ret +void imx9_lowsetup(void); -/* i.MX93 wait LPUART to be ready to transmit - * rb: register which contains the UART base address - * rc: scratch register - */ -.macro early_uart_ready rb, rc -1: - ldr \rc, [\rb, #UARTSTAT] /* <- Flag register */ - tst \rc, #UARTSTAT_TDRE /* Check FIFO EMPTY bit */ - beq 1b /* Wait for the UART to be ready */ -.endm +/**************************************************************************** + * Name: imx9_lpuart_configure + * + * Description: + * Configure a UART for non-interrupt driven operation + * + ****************************************************************************/ -/* i.MX93 LPUART transmit character - * rb: register which contains the UART base address - * rt: register which contains the character to transmit */ -.macro early_uart_transmit rb, rt - str \rt, [\rb, #UARTDATA] /* -> Data Register */ -.endm +int imx9_lpuart_configure(uint32_t base, + int uartnum, + const struct uart_config_s *config); -/* - * Print a character on the UART - this function is called by C - * w0: character to print - */ -GTEXT(arm64_lowputc) -SECTION_FUNC(text, arm64_lowputc) - ldr x15, =IMX9_LPUART1_BASE - early_uart_ready x15, w2 - early_uart_transmit x15, w0 - ret +#endif /* __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H */ diff --git a/arch/arm64/src/imx9/imx9_lpuart.c b/arch/arm64/src/imx9/imx9_lpuart.c index 2fa4307f4c259..6743d32ae3944 100644 --- a/arch/arm64/src/imx9/imx9_lpuart.c +++ b/arch/arm64/src/imx9/imx9_lpuart.c @@ -23,6 +23,7 @@ ****************************************************************************/ #include + #include #include #include @@ -33,838 +34,2663 @@ #include #ifdef CONFIG_SERIAL_TERMIOS -# include -#endif +# 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, ARMV8M_DCACHE_LINESIZE, so that it can be individually invalidated. + */ + +# if !defined(ARMV8M_DCACHE_LINESIZE) || ARMV8M_DCACHE_LINESIZE == 0 +# undef ARMV8M_DCACHE_LINESIZE +# define ARMV8M_DCACHE_LINESIZE 64 +# endif + +# if !defined(CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE) || \ + (CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE < ARMV8M_DCACHE_LINESIZE) +# undef CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE +# define CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE ARMV8M_DCACHE_LINESIZE +# endif + +# define RXDMA_BUFFER_MASK (ARMV8M_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, ARMV8M_DCACHE_LINESIZE, so that it can be individually + * invalidated. + */ + +#define TXDMA_BUFFER_MASK (ARMV8M_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 ARMV8M_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(ARMV8M_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(ARMV8M_DCACHE_LINESIZE); +#endif + +# ifdef CONFIG_LPUART2_RXDMA +static char g_lpuart2rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART3_RXDMA +static char g_lpuart3rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART4_RXDMA +static char g_lpuart4rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART5_RXDMA +static char g_lpuart5rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART6_RXDMA +static char g_lpuart6rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART7_RXDMA +static char g_lpuart7rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8M_DCACHE_LINESIZE); +#endif + +#ifdef CONFIG_LPUART8_RXDMA +static char g_lpuart8rxfifo[RXDMA_BUFFER_SIZE] + aligned_data(ARMV8M_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; -#include -#include -#include -#include -#include -#include -#include + if (!termiosp) + { + ret = -EINVAL; + break; + } -#include "chip.h" -#include "arm64_arch.h" -#include "arm64_internal.h" -#include "arm64_gic.h" + /* Return parity */ -#include "imx9_serial.h" -#include "imx9_boot.h" + termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) | + ((priv->parity == 1) ? PARODD : 0); -#include "hardware/imx9_lpuart.h" -#include "hardware/imx9_memorymap.h" + /* Return stop bits */ -#ifdef USE_SERIALDRIVER + termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0; -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ + /* Return flow control */ -/* Which UART with be tty0/console and which tty1-4? The console will - * always be ttyS0. If there is no console then will use the lowest - * numbered UART. - */ +#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 */ -/* First pick the console and ttys0. This could be any of UART1-5 */ + 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; -#if defined(CONFIG_UART1_SERIAL_CONSOLE) -# define CONSOLE_DEV g_uart1port /* UART1 is console */ -# define TTYS0_DEV g_uart1port /* UART1 is ttyS0 */ -# define UART1_ASSIGNED 1 + 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; + } -/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */ -#define DMA_RX_TIMEOUT (10) -#define UART_AUTOSUSPEND_TIMEOUT 3000 + /* Decode baud. */ -/**************************************************************************** - * Private Types - ****************************************************************************/ + ret = OK; + baud = cfgetispeed(termiosp); -struct imx9_uart_port_s -{ - unsigned long iobase; - unsigned int baud; /* Configured baud */ - unsigned int irq_num; - unsigned int txfifo_size; - unsigned int rxfifo_size; - int is_console; -}; + /* Decode number of bits */ -static inline uint32_t imx9_read(struct imx9_uart_port_s *port, uint32_t off) -{ - return getreg32(port->iobase + off); -} + switch (termiosp->c_cflag & CSIZE) + { + case CS5: + nbits = 5; + break; -static inline void imx9_write(struct imx9_uart_port_s *port, uint32_t val, - uint32_t off) -{ - putreg32(val, port->iobase + off); -} + case CS6: + nbits = 6; + break; -static int imx9_lpuart_stop_tx(struct imx9_uart_port_s *sport) -{ - unsigned long temp; + case CS7: + nbits = 7; + break; - temp = imx9_read(sport, UARTCTRL); - temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE); - imx9_write(sport, temp, UARTCTRL); + case CS8: + nbits = 8; + break; - return 0; -} +#if defined(CS9) + case CS9: + nbits = 9; + break; +#endif + default: + ret = -EINVAL; + break; + } -static int imx9_lpuart_stop_rx(struct imx9_uart_port_s *sport) -{ - unsigned long temp; + /* Decode parity */ - temp = imx9_read(sport, UARTCTRL); - imx9_write(sport, temp & ~UARTCTRL_RE, UARTCTRL); + if ((termiosp->c_cflag & PARENB) != 0) + { + parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + } + else + { + parity = 0; + } - return 0; -} + /* Decode stop bits */ -static int imx9_lpuart_start_tx(struct imx9_uart_port_s *sport) -{ - unsigned long temp; + stop2 = (termiosp->c_cflag & CSTOPB) != 0; - temp = imx9_read(sport, UARTCTRL); - imx9_write(sport, temp | UARTCTRL_TIE, UARTCTRL); + /* Verify that all settings are valid before committing */ - return 0; -} + if (ret == OK) + { + /* Commit */ -static int imx9_lpuart_start_rx(struct imx9_uart_port_s *sport) -{ - unsigned long temp; + 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 */ - temp = imx9_read(sport, UARTCTRL); - imx9_write(sport, temp | UARTCTRL_RE, UARTCTRL); +#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 0; + return ret; } /**************************************************************************** - * Name: imx9_rxint + * Name: imx9_receive * * Description: - * Call to enable or disable RX interrupts + * 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'. * ****************************************************************************/ -static void imx9_rxint(struct uart_dev_s *dev, bool enable) +#ifndef SERIAL_HAVE_ONLY_RXDMA +static int imx9_receive(struct uart_dev_s *dev, unsigned int *status) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t rxd; - if (enable) - { - imx9_lpuart_start_rx(sport); - } - else - { - imx9_lpuart_stop_rx(sport); - } + 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_txint + * Name: imx9_rxint * * Description: - * Call to enable or disable TX interrupts + * Call to enable or disable RX interrupts * ****************************************************************************/ -static void imx9_txint(struct uart_dev_s *dev, bool enable) +#ifndef SERIAL_HAVE_ONLY_RXDMA +static void imx9_rxint(struct uart_dev_s *dev, bool enable) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + 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) { - imx9_lpuart_start_tx(sport); +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE; +#endif } else { - imx9_lpuart_stop_tx(sport); + 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_send + * Name: imx9_rxavailable * * Description: - * This method will send one byte on the UART + * Return true if the receive fifo is not empty * ****************************************************************************/ -static void imx9_send(struct uart_dev_s *dev, int ch) +#ifndef SERIAL_HAVE_ONLY_RXDMA +static bool imx9_rxavailable(struct uart_dev_s *dev) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t regval; - imx9_write(sport, ch, UARTDATA); + /* 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_receive + * Name: imx9_rxflowcontrol * * 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'. + * 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. * ****************************************************************************/ -static int imx9_receive(struct uart_dev_s *dev, unsigned int *status) +#ifdef CONFIG_SERIAL_IFLOWCONTROL +static bool imx9_rxflowcontrol(struct uart_dev_s *dev, + unsigned int nbuffered, bool upper) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; - unsigned int rx; - unsigned int sr; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; - /* to clear the FE, OR, NF, FE, PE flags, - * read STAT then read DATA reg - */ + 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 */ - sr = imx9_read(sport, UARTSTAT); - rx = imx9_read(sport, UARTDATA); + 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. + */ - *status = sr; + uart_enablerxint(dev); + } + } - return rx; + return false; } +#endif /**************************************************************************** - * Name: imx9_rxavailable + * Name: imx9_dma_receive * * Description: - * Return true if the receive fifo is not empty + * 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'. * ****************************************************************************/ -static bool imx9_rxavailable(struct uart_dev_s *dev) +#ifdef SERIAL_HAVE_RXDMA +static int imx9_dma_receive(struct uart_dev_s *dev, unsigned int *status) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; - unsigned long sfifo = imx9_read(sport, UARTFIFO); + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t nextrx = imx9_dma_nextrx(priv); + int c = 0; - if (sfifo & UARTFIFO_RXEMPT) - { - return false; - } - else + /* Check if more data is available */ + + if (nextrx != priv->rxdmanext) { - return true; +#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_txready + * Name: imx9_dma_reenable * * Description: - * Return true if the tranmsit fifo is not full + * Call to re-enable RX DMA. * ****************************************************************************/ -static bool imx9_txready(struct uart_dev_s *dev) +#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM) +static void imx9_dma_reenable(struct imx9_uart_s *priv) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; - unsigned long txcnt; + 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 - /* When TXFULL is set, there is no space in the Tx FIFO */ + imx9_dmach_xfrsetup(priv->rxdma, &config); - txcnt = imx9_read(sport, UARTWATER); - txcnt = txcnt >> UARTWATER_TXCNT_OFF; - txcnt &= UARTWATER_COUNT_MASK; + /* Reset our DMA shadow pointer and Rx data availability count to match + * the address just programmed above. + */ - if (txcnt < sport->txfifo_size) - { - return true; - } - else - { - return false; - } + 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_txempty + * Name: imx9_dma_rxint * * Description: - * Return true if the transmit fifo is empty + * Call to enable or disable RX interrupts * ****************************************************************************/ -static bool imx9_txempty(struct uart_dev_s *dev) +#ifdef SERIAL_HAVE_RXDMA +static void imx9_dma_rxint(struct uart_dev_s *dev, bool enable) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; - unsigned long stat = imx9_read(sport, UARTSTAT); - unsigned long sfifo = imx9_read(sport, UARTFIFO); + 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. + */ - if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) - { - return true; - } - else - { - return false; - } + priv->rxenable = enable; } +#endif /**************************************************************************** - * Name: imx9_irq_handler (and front-ends) + * Name: imx9_dma_rxavailable * * Description: - * This is the common UART interrupt handler. It should cal - * uart_transmitchars or uart_receivechar to perform the appropriate data - * transfers. + * Return true if the receive register is not empty * ****************************************************************************/ -static int imx9_uart_irq_handler(int irq, void *context, void *arg) +#ifdef SERIAL_HAVE_RXDMA +static bool imx9_dma_rxavailable(struct uart_dev_s *dev) { - struct uart_dev_s *dev = (struct uart_dev_s *)arg; - struct imx9_uart_port_s *sport; - unsigned long sts; - unsigned long rxcount; - - DEBUGASSERT(dev != NULL && dev->priv != NULL); - sport = (struct imx9_uart_port_s *)dev->priv; - - sts = imx9_read(sport, UARTSTAT); - rxcount = imx9_read(sport, UARTWATER); - rxcount = rxcount >> UARTWATER_RXCNT_OFF; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; - if (sts & UARTSTAT_RDRF || rxcount > 0) - { - uart_recvchars(dev); - } - - if (sts & UARTSTAT_TDRE) - { - uart_xmitchars(dev); - } + /* Compare our receive pointer to the current DMA pointer, if they + * do not match, then there are bytes to be received. + */ - imx9_write(sport, sts, UARTSTAT); - return OK; + return (imx9_dma_nextrx(priv) != priv->rxdmanext); } +#endif -static int imx9_lpuart_hw_reset(struct imx9_uart_port_s *sport) -{ - if (sport->is_console) - { - return 0; - } - - /* Toggle the reset signal to reset and release the peripheral */ +/**************************************************************************** + * Name: imx9_dma_txcallback + * + * Description: + * This function clears dma buffer at complete of DMA transfer and wakes up + * threads waiting for space in buffer. + * + ****************************************************************************/ - putreg32(UARTGLOBAL_RST, sport->iobase + UARTGLOBAL); - putreg32(0, sport->iobase + UARTGLOBAL); +#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; - return 0; -} + /* Update 'nbytes' indicating number of bytes actually transferred by DMA. + * This is important to free TX buffer space by 'uart_xmitchars_done'. + */ -static int imx9_setup(struct uart_dev_s *dev) -{ - irqstate_t i_flags; - int ret; - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + priv->dev.dmatx.nbytes = priv->dev.dmatx.length; +#if CONFIG_IMX9_EDMA_NTCD > 1 + priv->dev.dmatx.nbytes += priv->dev.dmatx.nlength; +#endif - i_flags = up_irq_save(); + /* Adjust the pointers */ - ret = imx9_lpuart_hw_reset(sport); - if (ret < 0) - { - serr("failed to reset hw: %d\n", ret); - } + uart_xmitchars_done(&priv->dev); - up_irq_restore(i_flags); + /* Send more data if available */ - return ret; + imx9_dma_txavailable(&priv->dev); } +#endif /**************************************************************************** - * Name: imx9_shutdown + * Name: imx9_dma_txavailable * * Description: - * Disable the UART. This method is called when the serial - * port is closed + * Informs DMA that Tx data is available and is ready for transfer. * ****************************************************************************/ -static void imx9_shutdown(struct uart_dev_s *dev) +#ifdef SERIAL_HAVE_TXDMA +static void imx9_dma_txavailable(struct uart_dev_s *dev) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; - unsigned long temp; - irqstate_t i_flags; - - i_flags = up_irq_save(); - - /* clear statue */ - - temp = imx9_read(sport, UARTSTAT); - imx9_write(sport, temp, UARTSTAT); - - /* disable Rx/Tx DMA */ - - temp = imx9_read(sport, UARTBAUD); - temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE | UARTBAUD_RIDMAE); - imx9_write(sport, temp, UARTBAUD); + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; - /* disable Rx/Tx and interrupts */ + /* Only send when the DMA is idle */ - temp = imx9_read(sport, UARTCTRL); - temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_TIE | - UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_ILIE | - UARTCTRL_LOOPS); - imx9_write(sport, temp, UARTCTRL); - imx9_write(sport, 0, UARTMODIR); - - up_irq_restore(i_flags); + 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. + * + ****************************************************************************/ -static void imx9_setup_watermark(struct imx9_uart_port_s *sport) +#ifdef SERIAL_HAVE_TXDMA +static void imx9_dma_send(struct uart_dev_s *dev) { - unsigned long val; - unsigned long ctrl; - unsigned long ctrl_saved; - unsigned long rxiden_cnt; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + struct imx9_edma_xfrconfig_s config; - ctrl = imx9_read(sport, UARTCTRL); - ctrl_saved = ctrl; - ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE | - UARTCTRL_RIE | UARTCTRL_RE); - imx9_write(sport, ctrl, UARTCTRL); + /* We need to stop DMA before reconfiguration */ - /* enable FIFO mode */ + imx9_dmach_stop(priv->txdma); - val = imx9_read(sport, UARTFIFO); - val |= UARTFIFO_TXFE | UARTFIFO_RXFE; - val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; - val &= ~(UARTFIFO_RXIDEN_MASK << UARTFIFO_RXIDEN_OFF); - rxiden_cnt = 0; - val |= ((rxiden_cnt & UARTFIFO_RXIDEN_MASK) << UARTFIFO_RXIDEN_OFF); + /* Reset the number sent */ - imx9_write(sport, val, UARTFIFO); + dev->dmatx.nbytes = 0; - /* set the watermark - * rx_watermark = 1; + /* Make use of setup function to update buffer and its length for next + * transfer */ - val = (1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF); - imx9_write(sport, val, UARTWATER); - - /* Restore cr2 */ - - imx9_write(sport, ctrl_saved, UARTCTRL); -} - -static void imx9_setup_watermark_enable(struct imx9_uart_port_s *sport) -{ - uint32_t temp; + 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 - imx9_setup_watermark(sport); + /* Flush the contents of the TX buffer into physical memory */ - temp = imx9_read(sport, UARTCTRL); - temp |= UARTCTRL_RE | UARTCTRL_TE; - temp |= UARTCTRL_IDLECFG << UARTCTRL_IDLECFG_OFF; - imx9_write(sport, temp, UARTCTRL); -} + up_clean_dcache((uintptr_t)dev->dmatx.buffer, + (uintptr_t)dev->dmatx.buffer + dev->dmatx.length); -static void imx9_hw_disable(struct imx9_uart_port_s *sport) -{ - unsigned long temp; + /* Setup first half */ - temp = imx9_read(sport, UARTCTRL); - temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE | - UARTCTRL_TIE | UARTCTRL_TE); - imx9_write(sport, temp, UARTCTRL); -} + imx9_dmach_xfrsetup(priv->txdma, &config); -static void imx9_configure(struct imx9_uart_port_s *sport) -{ - unsigned long temp; +#if CONFIG_IMX9_EDMA_NTCD > 1 + /* Is this a split transfer? */ - temp = imx9_read(sport, UARTCTRL); - temp |= UARTCTRL_RIE | UARTCTRL_ILIE; - temp |= UARTCTRL_TIE; - imx9_write(sport, temp, UARTCTRL); -} + if (dev->dmatx.nbuffer) + { + config.iter = priv->dev.dmatx.nlength; + config.saddr = (uintptr_t)priv->dev.dmatx.nbuffer; -static void imx9_hw_setup(struct imx9_uart_port_s *sport) -{ - irqstate_t i_flags; + /* Flush the contents of the next TX buffer into physical memory */ - i_flags = up_irq_save(); + up_clean_dcache((uintptr_t)dev->dmatx.nbuffer, + (uintptr_t)dev->dmatx.nbuffer + dev->dmatx.nlength); - imx9_hw_disable(sport); + imx9_dmach_xfrsetup(priv->txdma, &config); + } +#endif - imx9_setup_watermark_enable(sport); - imx9_configure(sport); - up_enable_irq(sport->irq_num); + /* Start transmission with the callback on DMA completion */ - up_irq_restore(i_flags); + imx9_dmach_start(priv->txdma, imx9_dma_txcallback, (void *)priv); } +#endif /**************************************************************************** - * Name: imx9_attach + * Name: imx9_send * * Description: - * Configure the UART to operation in interrupt driven mode. This method - * is called when the serial port 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 supports multiple levels of interrupt enabling). The RX - * and TX interrupts are not enabled until the txint() and rxint() methods - * are called. + * This method will send one byte on the UART * ****************************************************************************/ -static int imx9_attach(struct uart_dev_s *dev) +static void imx9_send(struct uart_dev_s *dev, int ch) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; - int ret; - unsigned long temp; - - /* determine FIFO size */ - - temp = imx9_read(sport, UARTFIFO); - - sport->txfifo_size = UARTFIFO_DEPTH( - (temp >> UARTFIFO_TXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); - sport->rxfifo_size = UARTFIFO_DEPTH( - (temp >> UARTFIFO_RXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK); - - ret = irq_attach(sport->irq_num, imx9_uart_irq_handler, dev); + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; - if (ret == OK) - { - imx9_hw_setup(sport); - } - else +#ifdef CONSOLE_DEV + if (dev == &CONSOLE_DEV.dev && !dev->isconsole) { - sinfo("error ret=%d\n", ret); + return; } +#endif - return ret; + imx9_serialout(priv, IMX9_LPUART_DATA_OFFSET, (uint32_t)ch); } /**************************************************************************** - * Name: imx_detach + * Name: imx9_dma_txint * * Description: - * Detach UART interrupts. This method is called when the serial port is - * closed normally just before the shutdown method is called. The - * exception is the serial console which is never shutdown. + * Call to enable or disable TX interrupts from the UART. * ****************************************************************************/ -static void imx9_detach(struct uart_dev_s *dev) +#ifdef SERIAL_HAVE_TXDMA +static void imx9_dma_txint(struct uart_dev_s *dev, bool enable) { - struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv; + /* Nothing to do. */ - up_disable_irq(sport->irq_num); - irq_detach(sport->irq_num); + /* 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_ioctl + * Name: imx9_txint * * Description: - * All ioctl calls will be routed through this method - * for current imx9 configure. + * Call to enable or disable TX interrupts * ****************************************************************************/ -static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg) +#if !defined(SERIAL_HAVE_ONLY_TXDMA) +static void imx9_txint(struct uart_dev_s *dev, bool enable) { -#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; + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + irqstate_t flags; + uint32_t regval; - switch (cmd) - { -#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT - case TIOCSERGSTRUCT: + /* Enable interrupt for TX complete */ + + flags = spin_lock_irqsave(NULL); + if (enable) { - struct imx_uart_s *user = (struct imx_uart_s *)arg; - if (!user) - { - ret = -EINVAL; - } - else - { - memcpy(user, dev, sizeof(struct imx_uart_s)); - } - } - break; +#ifndef CONFIG_SUPPRESS_SERIAL_INTS + priv->ie |= LPUART_CTRL_TIE; #endif - -#ifdef CONFIG_SERIAL_TERMIOS - case TCGETS: + } + else { - struct termios *termiosp = (struct termios *)arg; - struct imx_uart_s *priv = (struct imx_uart_s *)dev->priv; - - 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 */ + priv->ie &= ~LPUART_CTRL_TIE; + } -#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); + 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 - /* Return baud */ +/**************************************************************************** + * Name: imx9_txready + * + * Description: + * Return true if the transmit register is available to be written to + * + ****************************************************************************/ - cfsetispeed(termiosp, priv->baud); +static bool imx9_txready(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t regval; - /* Return number of bits */ + regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_TDRE) != 0); +} - switch (priv->bits) - { - case 5: - { - termiosp->c_cflag |= CS5; - break; - } +/**************************************************************************** + * Name: imx9_txempty + * + * Description: + * Return true if the transmit reg is empty + * + ****************************************************************************/ - case 6: - { - termiosp->c_cflag |= CS6; - break; - } +static bool imx9_txempty(struct uart_dev_s *dev) +{ + struct imx9_uart_s *priv = (struct imx9_uart_s *)dev; + uint32_t regval; - case 7: - { - termiosp->c_cflag |= CS7; - break; - } + regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); + return ((regval & LPUART_STAT_TDRE) != 0); +} - default: - case 8: - { - termiosp->c_cflag |= CS8; - break; - } +/**************************************************************************** + * Name: imx9_dma_rxcallback + * + * Description: + * This function checks the current DMA state and calls the generic + * serial stack when bytes appear to be available. + * + ****************************************************************************/ -#if defined(CS9) - case 9: - { - termiosp->c_cflag |= CS9; - break; - } -#endif - } - } - break; +#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; - case TCSETS: + if (priv->rxenable && imx9_dma_rxavailable(&priv->dev)) { - struct termios *termiosp = (struct termios *)arg; - struct imx_uart_s *priv = (struct imx_uart_s *)dev->priv; - 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); + uart_recvchars(&priv->dev); + } - /* Decode number of bits */ + /* 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. + */ - switch (termiosp->c_cflag & CSIZE) - { - case CS5: - { - nbits = 5; - break; - } + sr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET); - case CS6: - { - nbits = 6; - break; - } + 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 - case CS7: - { - nbits = 7; - break; - } +/**************************************************************************** + * 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. + * + ****************************************************************************/ - case CS8: +#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): { - nbits = 8; - break; + /* Logic for PM_NORMAL goes here */ } + break; -#if defined(CS9) - case CS9: + case(PM_IDLE): { - nbits = 9; - break; + /* Logic for PM_IDLE goes here */ } + break; -#endif - default: + case(PM_STANDBY): { - ret = -EINVAL; - break; + /* Logic for PM_STANDBY goes here */ } - } - - /* Decode parity */ + break; - if ((termiosp->c_cflag & PARENB) != 0) + case(PM_SLEEP): { - parity = (termiosp->c_cflag & PARODD) ? 1 : 2; + /* Logic for PM_SLEEP goes here */ } - else - { - parity = 0; - } - - /* Decode stop bits */ - - stop2 = (termiosp->c_cflag & CSTOPB) != 0; - - /* Verify that all settings are valid before committing */ - - if (ret == OK) - { - /* Commit */ + break; - 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 = imx9_setup(dev); - - /* Restore the interrupt state */ + default: - imx_restoreuartint(priv, ie); - priv->ie = ie; - spin_unlock_irqrestore(NULL, flags); - } - } - break; -#endif /* CONFIG_SERIAL_TERMIOS */ + /* Should not get here */ - case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ - case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ - default: - { - ret = -ENOTTY; - break; - } + break; } - - return ret; } +#endif /**************************************************************************** - * Private Data + * 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! + * + * ****************************************************************************/ -/* Serial driver UART operations */ - -static const struct uart_ops_s g_uart_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 = NULL, -#endif - .send = imx9_send, - .txint = imx9_txint, - .txready = imx9_txready, - .txempty = imx9_txempty, -}; - -/* I/O buffers */ - -#ifdef CONFIG_IMX9_UART1 -static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; -static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; - -/* This describes the state of the IMX uart1 port. */ - -static struct imx9_uart_port_s g_uart1priv = +#ifdef CONFIG_PM +static int up_pm_prepare(struct pm_callback_s *cb, int domain, + enum pm_state_e pmstate) { - .iobase = IMX9_LPUART1_BASE, - .baud = CONFIG_UART1_BAUD, - .irq_num = IMX9_IRQ_LPUART1, - .is_console = 1, -}; - -static struct uart_dev_s g_uart1port = -{ - .recv = - { - .size = CONFIG_UART1_RXBUFSIZE, - .buffer = g_uart1rxbuffer, - }, - .xmit = - { - .size = CONFIG_UART1_TXBUFSIZE, - .buffer = g_uart1txbuffer, - }, - .ops = &g_uart_ops, - .priv = &g_uart1priv, -}; + /* Logic to prepare for a reduced power state goes here. */ + return OK; +} #endif /**************************************************************************** @@ -875,9 +2701,9 @@ static struct uart_dev_s g_uart1port = * 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. + * 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. * ****************************************************************************/ @@ -891,60 +2717,105 @@ void arm64_earlyserialinit(void) /* Enable the console UART. The other UARTs will be initialized if and * when they are first opened. */ + #ifdef CONSOLE_DEV - CONSOLE_DEV.isconsole = true; - imx9_setup(&CONSOLE_DEV); + CONSOLE_DEV.dev.isconsole = true; + imx9_setup(&CONSOLE_DEV.dev); #endif } /**************************************************************************** - * Name: up_putc + * Name: arm64_serialinit * * Description: - * Provide priority, low-level access to support OS debug - * writes + * Register serial console and serial privs. This assumes + * that imx9_earlyserialinit was called previously. * ****************************************************************************/ -int up_putc(int ch) +void arm64_serialinit(void) { - /* Check for LF */ +#ifdef CONFIG_PM + int ret; - if (ch == '\n') - { - /* Add CR */ + /* Register to receive power management callbacks */ - arm64_lowputc('\r'); - } + ret = pm_register(&g_serial_pmcb); + DEBUGASSERT(ret == OK); + UNUSED(ret); +#endif - arm64_lowputc((uint8_t)ch); - return ch; +#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: arm64_serialinit + * Name: up_putc * * Description: - * Register serial console and serial ports. This assumes - * that imx_earlyserialinit was called previously. + * Provide priority, low-level access to suppriv OS debug writes * ****************************************************************************/ -void arm64_serialinit(void) +int up_putc(int ch) { - int ret; +#ifdef CONSOLE_DEV + struct imx9_uart_s *priv = (struct imx9_uart_s *)&CONSOLE_DEV; + uint32_t ie; - ret = uart_register("/dev/console", &CONSOLE_DEV); - if (ret < 0) + if (!CONSOLE_DEV.dev.isconsole) { - sinfo("error at register dev/console, ret =%d\n", ret); + return ch; } - ret = uart_register("/dev/ttyS0", &TTYS0_DEV); - if (ret < 0) + imx9_disableuartint(priv, &ie); +#endif + + /* Check for LF */ + + if (ch == '\n') { - sinfo("error at register dev/ttyS0, ret =%d\n", ret); + /* Add CR */ + + arm64_lowputc('\r'); } -} -#endif /* USE_SERIALDRIVER */ + 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 index 854c6367aee77..e9c175a8ce14d 100644 --- a/arch/arm64/src/imx9/imx9_serial.h +++ b/arch/arm64/src/imx9/imx9_serial.h @@ -27,70 +27,216 @@ #include -#include "arm64_internal.h" - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/**************************************************************************** - * Public Types - ****************************************************************************/ +#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 -/**************************************************************************** - * Inline Functions - ****************************************************************************/ +/* 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 -#ifndef __ASSEMBLY__ +/* Disable the DMA configuration on all unused LPUARTs */ -/**************************************************************************** - * Public Data - ****************************************************************************/ +#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 Function Prototypes + * Public Types ****************************************************************************/ /**************************************************************************** - * Name: imx_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 arm_serialinit. - * + * Inline Functions ****************************************************************************/ -#ifdef USE_EARLYSERIALINIT -void imx9_earlyserialinit(void); -#endif +#ifndef __ASSEMBLY__ /**************************************************************************** - * Name: uart_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 arm_serialinit. - * + * Public Data ****************************************************************************/ -#if defined(USE_EARLYSERIALINIT) && defined(IMX9_HAVE_UART) -void uart_earlyserialinit(void); +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern #endif /**************************************************************************** - * Name: uart_serialinit - * - * Description: - * Register the UART serial console and serial ports. This assumes that - * uart_earlyserialinit was called previously. - * + * Public Function Prototypes ****************************************************************************/ -#ifdef IMX9_HAVE_UART -void uart_serialinit(void); +#undef EXTERN +#if defined(__cplusplus) +} #endif #endif /* __ASSEMBLY__ */ -#endif /* __ARCH_ARM_SRC_IMX9_IMX_SERIAL_H */ +#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_SERIAL_H */ diff --git a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig index 64c7f53357551..b4ae81e0a023c 100644 --- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig @@ -36,12 +36,13 @@ CONFIG_IMX9_GPIO_IRQ=y CONFIG_IMX9_LPI2C1=y CONFIG_IMX9_LPI2C_DYNTIMEO=y CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP=10 +CONFIG_IMX9_LPUART1=y CONFIG_IMX9_TPM3_PWM=y CONFIG_IMX9_TPM3_PWM_CHMUX=0x00000003 -CONFIG_IMX9_UART1=y CONFIG_IMX9_USBDEV_USBC1=y CONFIG_INIT_ENTRYPOINT="nsh_main" CONFIG_INTELHEX_BINARY=y +CONFIG_LPUART1_SERIAL_CONSOLE=y CONFIG_NSH_ARCHINIT=y CONFIG_NSH_BUILTIN_APPS=y CONFIG_NSH_FILEIOSIZE=512 @@ -71,4 +72,3 @@ CONFIG_SYSTEM_SYSTEM=y CONFIG_SYSTEM_TIME64=y CONFIG_TESTING_GETPRIME=y CONFIG_TESTING_OSTEST=y -CONFIG_UART1_SERIAL_CONSOLE=y diff --git a/boards/arm64/imx9/imx93-evk/include/board.h b/boards/arm64/imx9/imx93-evk/include/board.h index 6cd4c26e56143..37d46536eca7b 100644 --- a/boards/arm64/imx9/imx93-evk/include/board.h +++ b/boards/arm64/imx9/imx93-evk/include/board.h @@ -33,6 +33,11 @@ #define IOMUX_LPI2C_DEFAULT (IOMUXC_PAD_OD_ENABLE | IOMUXC_PAD_FSEL_SFAST | 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 @@ -47,6 +52,8 @@ #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) From fdacfdf2371c0a29c8c6fbcc962a33935702463c Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Tue, 16 Apr 2024 12:50:53 +0300 Subject: [PATCH 140/147] boards/arm64/imx9/imx93-evk/src/imx9_pwm.c: Fix initialization of TPM PWM registration Fix typo causing TPM PWM not initializing on EVK board Signed-off-by: Jukka Laitinen --- boards/arm64/imx9/imx93-evk/src/imx9_pwm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c b/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c index f3989167f892b..494331617ad81 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c +++ b/boards/arm64/imx9/imx93-evk/src/imx9_pwm.c @@ -96,7 +96,7 @@ int imx9_pwm_setup(void) #endif #ifdef CONFIG_IMX9_TPM3_PWM - lower_half = imx9_flexio_pwm_init(PWM_TPM3); + lower_half = imx9_tpm_pwm_init(PWM_TPM3); if (lower_half) { From ccb67403bcf199923565fafbb74d50fa0c1bc16d Mon Sep 17 00:00:00 2001 From: simbit18 <101105604+simbit18@users.noreply.github.com> Date: Tue, 16 Apr 2024 10:07:32 +0200 Subject: [PATCH 141/147] fix nxstyle fix Relative file path does not match actual file. --- boards/arm64/imx9/imx93-evk/src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/arm64/imx9/imx93-evk/src/Makefile b/boards/arm64/imx9/imx93-evk/src/Makefile index e8c38027a4bf9..564a2db926ab2 100644 --- a/boards/arm64/imx9/imx93-evk/src/Makefile +++ b/boards/arm64/imx9/imx93-evk/src/Makefile @@ -1,5 +1,5 @@ ############################################################################ -# boards/arm64/imx9/emx93-evk/src/Makefile +# 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 From 7ff92b057c2e088b8e6c596cff584f6b74522667 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 17 Apr 2024 13:13:30 +0300 Subject: [PATCH 142/147] imx9_boot.c: Add initialization of pin interrupts Initialize the pin interrupt support during boot --- arch/arm64/src/imx9/imx9_boot.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/src/imx9/imx9_boot.c b/arch/arm64/src/imx9/imx9_boot.c index 260e67997428f..aaef4e8606f70 100644 --- a/arch/arm64/src/imx9/imx9_boot.c +++ b/arch/arm64/src/imx9/imx9_boot.c @@ -37,8 +37,10 @@ #include "arm64_arch.h" #include "arm64_internal.h" #include "arm64_mmu.h" + #include "imx9_boot.h" #include "imx9_serial.h" +#include "imx9_gpio.h" #include "imx9_lowputc.h" /**************************************************************************** @@ -103,6 +105,12 @@ void arm64_chip_boot(void) imx9_lowsetup(); #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. */ From 9a83aecaf2dd9b57ee6ef9fc6c8020df08451438 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Wed, 17 Apr 2024 13:16:46 +0300 Subject: [PATCH 143/147] imx9_gpioirq: Fix testing of ICR field from pinset icr is tested below with macros like GPIO_INT_LOWLEVEL et al. Those macros are shifted left by GPIO_INTCFG_SHIFT, so the temporary icr variable should not be shifted right. --- arch/arm64/src/imx9/imx9_gpioirq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/src/imx9/imx9_gpioirq.c b/arch/arm64/src/imx9/imx9_gpioirq.c index 3d75e9079834c..7290ff6852e24 100644 --- a/arch/arm64/src/imx9/imx9_gpioirq.c +++ b/arch/arm64/src/imx9/imx9_gpioirq.c @@ -236,8 +236,8 @@ 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 icr = (pinset & GPIO_INTCFG_MASK) >> GPIO_INTCFG_SHIFT; uint32_t both = (pinset & GPIO_INTBOTHCFG_MASK) >> GPIO_INTBOTHCFG_SHIFT; + uint32_t icr = (pinset & GPIO_INTCFG_MASK); uint32_t regval; uintptr_t regaddr; From 7af04771516ace0f6292f25e636b68654e760d80 Mon Sep 17 00:00:00 2001 From: Ville Juven Date: Tue, 2 Apr 2024 15:30:02 +0300 Subject: [PATCH 144/147] arm64/imx9: Add LPSPI driver Add driver for LPSPI Co-authored-by: Jukka Laitinen --- arch/arm64/src/imx9/Kconfig | 126 + arch/arm64/src/imx9/Make.defs | 4 + arch/arm64/src/imx9/hardware/imx9_lpspi.h | 351 +++ arch/arm64/src/imx9/imx9_lpspi.c | 2060 +++++++++++++++++ arch/arm64/src/imx9/imx9_lpspi.h | 139 ++ .../imx9/imx93-evk/configs/nsh/defconfig | 3 + boards/arm64/imx9/imx93-evk/include/board.h | 20 + boards/arm64/imx9/imx93-evk/src/Makefile | 4 + boards/arm64/imx9/imx93-evk/src/imx93-evk.h | 12 + .../arm64/imx9/imx93-evk/src/imx9_bringup.c | 10 + boards/arm64/imx9/imx93-evk/src/imx9_spi.c | 162 ++ 11 files changed, 2891 insertions(+) create mode 100644 arch/arm64/src/imx9/hardware/imx9_lpspi.h create mode 100644 arch/arm64/src/imx9/imx9_lpspi.c create mode 100644 arch/arm64/src/imx9/imx9_lpspi.h create mode 100644 boards/arm64/imx9/imx93-evk/src/imx9_spi.c diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig index 7673dc6356259..aa27d2fb3fd01 100644 --- a/arch/arm64/src/imx9/Kconfig +++ b/arch/arm64/src/imx9/Kconfig @@ -301,6 +301,10 @@ config IMX9_LPI2C bool "LPI2C support" default n +config IMX9_LPSPI + bool "LPSPI support" + default n + config IMX9_PLL bool "PLL setup support (WIP)" default n @@ -496,6 +500,51 @@ config IMX9_LPI2C8_FILTSDA 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 "LPI2C Configuration" depends on IMX9_LPI2C @@ -550,4 +599,81 @@ config IMX9_LPI2C_TIMEOTICKS 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_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 + endif # ARCH_CHIP_IMX9 diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs index 5e11a38b59c76..c420afd939154 100644 --- a/arch/arm64/src/imx9/Make.defs +++ b/arch/arm64/src/imx9/Make.defs @@ -47,3 +47,7 @@ endif ifeq ($(CONFIG_IMX9_LPI2C),y) CHIP_CSRCS += imx9_lpi2c.c endif + +ifeq ($(CONFIG_IMX9_LPSPI), y) + CHIP_CSRCS += imx9_lpspi.c +endif 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/imx9_lpspi.c b/arch/arm64/src/imx9/imx9_lpspi.c new file mode 100644 index 0000000000000..48d8ccf582a79 --- /dev/null +++ b/arch/arm64/src/imx9/imx9_lpspi.c @@ -0,0 +1,2060 @@ +/**************************************************************************** + * 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_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 */ +#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) +{ + 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; + struct imx9_lpspidev_s *priv = (struct imx9_lpspidev_s *)dev; + + 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; + } + + /* 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) + { + up_clean_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + nbytes); + } + + if (rxbuffer) + { + up_invalidate_dcache((uintptr_t)rxbuffer, + (uintptr_t)rxbuffer + 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 ? rxbuffer : 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 ? txbuffer : &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) + { + up_invalidate_dcache((uintptr_t)rxbuffer, + (uintptr_t)rxbuffer + 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); + } + } + 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/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig index b4ae81e0a023c..206f086215eb3 100644 --- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig +++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig @@ -36,6 +36,7 @@ CONFIG_IMX9_GPIO_IRQ=y CONFIG_IMX9_LPI2C1=y CONFIG_IMX9_LPI2C_DYNTIMEO=y CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP=10 +CONFIG_IMX9_LPSPI6=y CONFIG_IMX9_LPUART1=y CONFIG_IMX9_TPM3_PWM=y CONFIG_IMX9_TPM3_PWM_CHMUX=0x00000003 @@ -60,6 +61,7 @@ CONFIG_SCHED_HPWORK=y CONFIG_SCHED_HPWORKPRIORITY=192 CONFIG_SCHED_LPWORK=y CONFIG_SCHED_LPWORKPRIORITY=50 +CONFIG_SPI=y CONFIG_SPINLOCK=y CONFIG_STACK_COLORATION=y CONFIG_START_MONTH=3 @@ -68,6 +70,7 @@ CONFIG_SYMTAB_ORDEREDBYNAME=y CONFIG_SYSTEM_CDCACM=y CONFIG_SYSTEM_I2CTOOL=y CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_SPITOOL=y CONFIG_SYSTEM_SYSTEM=y CONFIG_SYSTEM_TIME64=y CONFIG_TESTING_GETPRIME=y diff --git a/boards/arm64/imx9/imx93-evk/include/board.h b/boards/arm64/imx9/imx93-evk/include/board.h index 37d46536eca7b..d1a74a7e5aa6c 100644 --- a/boards/arm64/imx9/imx93-evk/include/board.h +++ b/boards/arm64/imx9/imx93-evk/include/board.h @@ -31,7 +31,11 @@ * 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 */ @@ -68,6 +72,22 @@ #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) + /**************************************************************************** * Public Data ****************************************************************************/ diff --git a/boards/arm64/imx9/imx93-evk/src/Makefile b/boards/arm64/imx9/imx93-evk/src/Makefile index 564a2db926ab2..7849be43dc386 100644 --- a/boards/arm64/imx9/imx93-evk/src/Makefile +++ b/boards/arm64/imx9/imx93-evk/src/Makefile @@ -34,4 +34,8 @@ ifeq ($(CONFIG_IMX9_LPI2C),y) CSRCS += imx9_i2c.c endif +ifeq ($(CONFIG_IMX9_LPSPI),y) +CSRCS += imx9_spi.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 index 1da0b3b88eeac..be6bceb339bb5 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx93-evk.h +++ b/boards/arm64/imx9/imx93-evk/src/imx93-evk.h @@ -79,5 +79,17 @@ int imx9_pwm_setup(void); 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 + #endif /* __ASSEMBLY__ */ #endif /* __BOARDS_ARM64_IMX9_IMX93_EVK_SRC_IMX93_EVK_H */ diff --git a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c index 6048509b67980..acd7b309a0afe 100644 --- a/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c +++ b/boards/arm64/imx9/imx93-evk/src/imx9_bringup.c @@ -77,6 +77,16 @@ int imx9_bringup(void) } #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 + UNUSED(ret); return OK; } 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; +} From a1dab0459d85af8b32ff5208c5e663e8dc9dfa12 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Fri, 19 Apr 2024 09:56:11 +0300 Subject: [PATCH 145/147] arch/arm64/src/imx9/imx9_usbdev.c: Fix the descriptor alignments and cache management Align all the dtd and dqh on cache line boundaries and clean up the cache management Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/imx9_usbdev.c | 124 +++++++++++++++++++----------- 1 file changed, 77 insertions(+), 47 deletions(-) diff --git a/arch/arm64/src/imx9/imx9_usbdev.c b/arch/arm64/src/imx9/imx9_usbdev.c index 30f9fef33f785..d34f6919c7fc8 100644 --- a/arch/arm64/src/imx9/imx9_usbdev.c +++ b/arch/arm64/src/imx9/imx9_usbdev.c @@ -54,6 +54,21 @@ * 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 @@ -203,32 +218,32 @@ const struct trace_msg_t g_usb_trace_strings_intdecode[] = }; #endif -#if defined(CONFIG_ARMV7M_DCACHE) -# define cache_aligned_alloc(s) kmm_memalign(ARMV7M_DCACHE_LINESIZE,(s)) -# define CACHE_ALIGNED_DATA aligned_data(ARMV7M_DCACHE_LINESIZE) -#else -# define cache_aligned_alloc kmm_malloc -# define CACHE_ALIGNED_DATA -#endif - /* Hardware interface *******************************************************/ -/* This represents a Endpoint Transfer Descriptor - note these must be 32 - * byte aligned. - */ +/* This represents a Endpoint Transfer Descriptor dQH overlay (32 bytes) */ -struct imx9_dtd_s +#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 { - 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 */ + 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. */ @@ -244,18 +259,15 @@ struct imx9_dtd_s #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 - note these must be aligned to a 2048 byte - * boundary - */ +/* This represents a queue head */ struct imx9_dqh_s { uint32_t capability; /* Endpoint capability */ uint32_t currdesc; /* Current dTD pointer */ - struct imx9_dtd_s overlay; /* DTD overlay */ + struct imx9_dtd_ovl_s overlay; /* DTD overlay */ volatile uint32_t setup[2]; /* Set-up buffer */ - uint32_t gap[4]; /* align to 64 bytes */ -}; +} CACHE_ALIGNED_DATA; /* DQH capability field */ @@ -351,10 +363,10 @@ struct imx9_ep_s struct imx9_ep0_s { - uint8_t buf[64] CACHE_ALIGNED_DATA; /* 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 */ + 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 */ @@ -391,10 +403,8 @@ struct imx9_usb_s /* The endpoint list */ struct imx9_ep_s eplist[IMX9_NPHYSENDPOINTS]; - - struct imx9_dqh_s qh[IMX9_NPHYSENDPOINTS] aligned_data(2048); - - struct imx9_dtd_s td[IMX9_NPHYSENDPOINTS] aligned_data(32); + 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 */ @@ -513,12 +523,31 @@ 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 @@ -526,6 +555,9 @@ static struct imx9_usb_s g_usbdev[] = { .id = 1, .base = IMX9_USB_OTG2_BASE, + .ep0.buf = g_usb1_ep0buf, + .qh = g_usb1_qh, + .td = g_usb1_td, }, #endif }; @@ -742,9 +774,9 @@ static inline void imx9_writedtd(struct imx9_dtd_s *dtd, dtd->buffer4 = (uint32_t)(((uintptr_t) data) + 0x4000) & 0xfffff000; dtd->xfer_len = nbytes; - up_flush_dcache((uintptr_t)dtd, + up_clean_dcache((uintptr_t)dtd, (uintptr_t)dtd + sizeof(struct imx9_dtd_s)); - up_flush_dcache((uintptr_t)data, + up_clean_dcache((uintptr_t)data, (uintptr_t)data + nbytes); } @@ -837,6 +869,9 @@ static void imx9_readsetup(struct imx9_usb_s *priv, uint8_t epphy, 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, @@ -1083,6 +1118,11 @@ static void imx9_dispatchrequest(struct imx9_usb_s *priv, 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, @@ -1705,14 +1745,6 @@ static void imx9_ep0complete(struct imx9_usb_s *priv, uint8_t epphy) break; case EP0STATE_SHORTREAD: - - /* Make sure we have updated data after the DMA transfer. - * This invalidation matches the flush in writedtd(). - */ - - up_invalidate_dcache((uintptr_t)priv->ep0.buf, - (uintptr_t)priv->ep0.buf + sizeof(priv->ep0.buf)); - imx9_dispatchrequest(priv, &priv->ep0.ctrl); imx9_ep0state(priv, EP0STATE_WAIT_NAK_IN); break; @@ -1834,9 +1866,7 @@ bool imx9_epcomplete(struct imx9_usb_s *priv, uint8_t epphy) return true; } - /* Make sure we have updated data after the DMA transfer. - * This invalidation matches the flush in writedtd(). - */ + /* Make sure we have updated data after the DMA transfer. */ up_invalidate_dcache((uintptr_t)dtd, (uintptr_t)dtd + sizeof(struct imx9_dtd_s)); From c5c188b6035acb91a7c6908139ca75b19f3e3950 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Sat, 20 Apr 2024 08:31:05 +0300 Subject: [PATCH 146/147] arch/arm64/src/imx9/imx9_lpuart.c: Change ARMV8M_DCACHE_LINESIZE -> ARMV8A_DCACHE_LINESIZE Signed-off-by: Jukka Laitinen --- arch/arm64/src/imx9/imx9_lpuart.c | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/arm64/src/imx9/imx9_lpuart.c b/arch/arm64/src/imx9/imx9_lpuart.c index 6743d32ae3944..601770b01f840 100644 --- a/arch/arm64/src/imx9/imx9_lpuart.c +++ b/arch/arm64/src/imx9/imx9_lpuart.c @@ -71,43 +71,43 @@ * the FIFO receives half this number of bytes. * * This buffer size should be an even multiple of the Cortex-A55 D-Cache line - * size, ARMV8M_DCACHE_LINESIZE, so that it can be individually invalidated. + * size, ARMV8A_DCACHE_LINESIZE, so that it can be individually invalidated. */ -# if !defined(ARMV8M_DCACHE_LINESIZE) || ARMV8M_DCACHE_LINESIZE == 0 -# undef ARMV8M_DCACHE_LINESIZE -# define ARMV8M_DCACHE_LINESIZE 64 +# 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 < ARMV8M_DCACHE_LINESIZE) + (CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE < ARMV8A_DCACHE_LINESIZE) # undef CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE -# define CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE ARMV8M_DCACHE_LINESIZE +# define CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE ARMV8A_DCACHE_LINESIZE # endif -# define RXDMA_BUFFER_MASK (ARMV8M_DCACHE_LINESIZE - 1) +# 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, ARMV8M_DCACHE_LINESIZE, so that it can be individually + * line size, ARMV8A_DCACHE_LINESIZE, so that it can be individually * invalidated. */ -#define TXDMA_BUFFER_MASK (ARMV8M_DCACHE_LINESIZE - 1) +#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 ARMV8M_DCACHE_LINESIZE */ +/* 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(ARMV8M_DCACHE_LINESIZE); +# define TXDMA_BUF_ALIGN aligned_data(ARMV8A_DCACHE_LINESIZE); #endif #if !defined(CONFIG_LPUART1_TXDMA) @@ -518,42 +518,42 @@ const struct uart_ops_s *g_o1 = &g_lpuart_txdma_ops; #ifdef CONFIG_LPUART1_RXDMA static char g_lpuart1rxfifo[RXDMA_BUFFER_SIZE] - aligned_data(ARMV8M_DCACHE_LINESIZE); + aligned_data(ARMV8A_DCACHE_LINESIZE); #endif # ifdef CONFIG_LPUART2_RXDMA static char g_lpuart2rxfifo[RXDMA_BUFFER_SIZE] - aligned_data(ARMV8M_DCACHE_LINESIZE); + aligned_data(ARMV8A_DCACHE_LINESIZE); #endif #ifdef CONFIG_LPUART3_RXDMA static char g_lpuart3rxfifo[RXDMA_BUFFER_SIZE] - aligned_data(ARMV8M_DCACHE_LINESIZE); + aligned_data(ARMV8A_DCACHE_LINESIZE); #endif #ifdef CONFIG_LPUART4_RXDMA static char g_lpuart4rxfifo[RXDMA_BUFFER_SIZE] - aligned_data(ARMV8M_DCACHE_LINESIZE); + aligned_data(ARMV8A_DCACHE_LINESIZE); #endif #ifdef CONFIG_LPUART5_RXDMA static char g_lpuart5rxfifo[RXDMA_BUFFER_SIZE] - aligned_data(ARMV8M_DCACHE_LINESIZE); + aligned_data(ARMV8A_DCACHE_LINESIZE); #endif #ifdef CONFIG_LPUART6_RXDMA static char g_lpuart6rxfifo[RXDMA_BUFFER_SIZE] - aligned_data(ARMV8M_DCACHE_LINESIZE); + aligned_data(ARMV8A_DCACHE_LINESIZE); #endif #ifdef CONFIG_LPUART7_RXDMA static char g_lpuart7rxfifo[RXDMA_BUFFER_SIZE] - aligned_data(ARMV8M_DCACHE_LINESIZE); + aligned_data(ARMV8A_DCACHE_LINESIZE); #endif #ifdef CONFIG_LPUART8_RXDMA static char g_lpuart8rxfifo[RXDMA_BUFFER_SIZE] - aligned_data(ARMV8M_DCACHE_LINESIZE); + aligned_data(ARMV8A_DCACHE_LINESIZE); #endif #ifdef CONFIG_IMX9_LPUART1 From 9514ce4da77f1a233560fc67bedbcba4269b8b9b Mon Sep 17 00:00:00 2001 From: Timo Sairiala Date: Tue, 23 Apr 2024 09:21:04 +0300 Subject: [PATCH 147/147] DO NOT MERGE: introduce codeQL issue --- libs/libc/stdio/lib_libvsprintf.c | 9 +++++++++ tools/mkdeps.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/libs/libc/stdio/lib_libvsprintf.c b/libs/libc/stdio/lib_libvsprintf.c index de285527d5342..f34404366a09d 100644 --- a/libs/libc/stdio/lib_libvsprintf.c +++ b/libs/libc/stdio/lib_libvsprintf.c @@ -159,6 +159,15 @@ static int vsprintf_internal(FAR struct lib_outstream_s *stream, FAR struct arg_s *arglist, int numargs, FAR const IPTR char *fmt, va_list ap) { + // DO NOT MERGE: + int test_int = 0; + uint8_t test_uint8_t = 0; + + if ( test_int < test_uint8_t ) { + test_uint8_t = test_int; + } + + unsigned char c; /* Holds a char from the format string */ uint16_t flags; int width; diff --git a/tools/mkdeps.c b/tools/mkdeps.c index da9a3f5b8874a..fad451de18224 100644 --- a/tools/mkdeps.c +++ b/tools/mkdeps.c @@ -794,6 +794,8 @@ static void do_dependency(const char *file) cmdlen++; g_command[cmdlen] = '\0'; + ret = system(g_command); + /* Make a copy of g_altpath. We need to do this because at least the * version of strtok_r above does modify it. */