Commit Graph

81 Commits

Author SHA1 Message Date
Guennadi Liakhovetski
4de0c9abc0 SoC: Intel: ADSP: ACE30: add .imrdata to MMU definitions
On ACE30 platforms adding a section to the linker script isn't
enough, it should also be added to the xtensa_soc_mmu_ranges[] array.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2025-06-10 12:52:38 -04:00
Tomasz Leman
c26b0767f2 soc: intel_adsp: Update comment style and fix typos
This patch makes cosmetic changes to ace/power.c by updating comments to
Doxygen style, fixing typos, and removing an extraneous character for
improved readability and consistency.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2025-06-06 08:43:15 +02:00
Tomasz Leman
fbafada9b6 soc: intel_adsp: Manage power gating based on core activity
This patch enhances the power management capabilities of the Intel ADSP
by ensuring that power gating states are appropriately managed based on
core activity. It prevents the primary core from entering power gating
if secondary cores are active and re-enables power gating when all
secondary cores are off, using pm_policy_state_lock_get and
pm_policy_state_lock_put functions.

The Sound Open Firmware (SOF) project currently uses a custom power
management policy to achieve these effects. With this patch, the default
power management policy can be utilized, allowing the option to disable
the custom policy while maintaining system reliability and performance
across different core states.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2025-06-06 08:43:15 +02:00
Adrian Bonislawski
7918839ddd intel_adsp: ace30: Bring up ACE 3.0 (WCL)
This commit adds definition of ACE 3.0 Wildcat Lake board

Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
2025-05-15 22:14:44 +02:00
Daniel Leung
92ebb2eb69 kernel: remove kernel/internal/smp.h
There is no need for kernel/internal/smp.h as SOF does not call
z_sched_ipi(). Actually... git log over there has no mention of
z_sched_ipi() anywhere, just arch_sched_ipi().

And include <ksched.h> for source using z_sched_ipi() since
they are using scheduling functions, and would be the correct
file to include.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2025-04-29 02:42:09 +02:00
Daniel Leung
d08981527d soc: intel_adsp/ace: use custom arch_spin_relax()
Intel Audio DSP ACE needs to use arch_spin_relax() to give
the bus more time to propagate the RCW transactions among
CPUs, and to avoid sending too many requests to the bus
after failing to lock spinlocks. However, the number of
NOPs results in a very big arch_spin_relax() that spans
multiple instruction cache lines, and requires evicting
them just for NOPs.  With 5 CPUs, it can span 6 cache
lines (if using nop.n instead of nop). That's a waste of
space and cache. So instead, we do a tight loop instead.
Since the SoC supports zero-overhead loops, this should
have minimal performance impact.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2025-04-21 07:45:23 +02:00
Daniel Leung
58b035b85f soc: intel_adsp/ace: linker: align cpuhold_* variables
For some weird unknown reasons, the simulator really do not
like the cpuhold_* variables to be tightly packed together.
This results in cpuhold_spawned not being updated, and we
will be stuck in the while loop for it to be set.
Workaround this by explicitly aligning these variables on
16 byte boundary. This seems to work for now.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2025-04-21 07:45:23 +02:00
Daniel Leung
e5685cab4a soc: intel_adsp/ace: link xtensa_swap_update_page_tables...
...earlier. Similar to xtensa_do_syscall, we want to group
some functions together.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2025-04-21 07:45:23 +02:00
Adrian Bonislawski
e64cce9053 soc: intel_adsp: ace30: set MMU permissions for rom_ext sections
This patch will set MMU permissions for rom_ext sections
It is possible to call the rom_ext code located in IMR

Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
2025-04-04 09:35:29 +02:00
Adrian Bonislawski
368f6cfee4 soc: intel_adsp: ace30: extend hwreg1 MMU mapping
This patch will extend MMU mapping range for hwreg1 entry
because it is required to access lower register addresses

Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
2025-04-04 09:35:29 +02:00
Adrian Bonislawski
e7f2e1412d soc: intel_adsp: set MMU permissions for .cold* sections
This patch will set MMU permissions for .cold* sections
Fixes cold section execution if MMU is enabled

Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
2025-03-15 00:35:13 +01:00
Adrian Bonislawski
72f820cda3 dts: xtensa: intel_adsp_ace30: enable Mic privacy driver
Enable Microphone Privacy driver for Intel ACE 3.0 platform

Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
2025-02-13 01:13:31 +01:00
Benjamin Cabé
248d3d02c4 soc: intel: ace: Fix power down compilation issue
CONFIG_ADSP_POWER_DOWN_HPSRAM may not be defined (when it's "n") so
update the code accordingly so that power_down() is called with
correct parameters.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2025-02-06 10:42:25 +01:00
Guennadi Liakhovetski
6d0c23be31 soc: intel_adsp: add support for .cold* sections
Add support for .cold and .coldrodata sections, used to implement
a cold module. Assigning code and read-only data to those sections
makes them suitable for use in a cold module, stored and executed in
slow memory.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-12-29 05:50:25 +01:00
Tomasz Leman
c0a01d33e3 Revert "soc: intel_adsp/ace30: do not map 0x0"
This reverts commit 3d3ffa2c05.

The original commit aimed to prevent NULL pointer accesses by moving the
MMU mapping starting point one page later. However, this change has
caused a regression on PTL. Our DSP has registers with addresses lower
than 0x1000, and the firmware uses addresses starting from 0xC40. For
instance, the HDAMLDMICL register is located at 0xCC0, which is now
inaccessible due to the change.

Reverting this commit restores access to these critical registers and
resolves the regression issue.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-11-29 19:27:53 -05:00
Daniel Leung
22de29e768 soc: intel_adsp/ace: put syscall helpers in vector code section
This puts the syscall helpers into the vector code section, and
is a tiny TLB optimization. Before this, worst case scenario is
that there would 2 instruction TLB misses when both the syscall
helpers and the vector code pages are not in TLB cache. With
this change, there would be at most 1 instruction TLB miss as
now the syscall helper and the vector code (which includes
exception handling code and xtensa_do_syscall()) are now in
the same page, and the same TLB entry.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2024-11-26 00:12:18 +01:00
Daniel Leung
3d3ffa2c05 soc: intel_adsp/ace30: do not map 0x0
The MMU mapping in SoC covers 0x0 which prevents catching NULL
pointer accesses. Since there are no hardware registers at
the very first page of memory, we move the starting point one
page later.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
2024-11-25 08:30:57 +01:00
Tomasz Leman
5cf2cb6a37 soc: intel_adsp: ace: Use DT macros instead of hardcoded values
Replace hardcoded register addresses and values in
asm_memory_management.h with Devicetree (DT) macros for LPSRAM
power-down operations. This change ensures that register addresses and
bank counts are dynamically obtained from the Devicetree, improving code
portability and reducing the risk of errors due to manual updates.

- Removed hardcoded LSPGCTL address definitions.
- Updated m_ace_lpsram_power_down_entire macro to use DT_NODELABEL to
  fetch LPSRAM bank count and control register address
- Adjusted bit field extraction logic to align with the updated register
  information from the Devicetree.

This commit aligns with the ongoing effort to utilize Devicetree for
hardware abstraction and to facilitate easier maintenance and updates to
the codebase.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-11-16 14:03:50 -05:00
Tomasz Leman
946aeaa7e8 soc: intel_adsp: ace: Remove obsolete HPSRAM power change macro
Remove the m_ace_hpsram_power_change macro from asm_memory_management.h
as it is no longer used after refactoring the power_down function to
utilize the new m_ace_hpsram_power_down_entire macro. This cleanup helps
to reduce code complexity and maintainability.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-11-16 14:03:50 -05:00
Tomasz Leman
2d997082fc soc: intel_adsp: ace: Update power_down to use new HPSRAM power-down macro
Refactor the power_down function to utilize the newly introduced
m_ace_hpsram_power_down_entire macro for shutting down the entire
HPSRAM. This change simplifies the power-down process by replacing the
previous segment-based power gating mask approach with a single boolean
flag that indicates whether the entire HPSRAM should be disabled.

The function signature of power_down has been updated to accept the new
boolean flag, and the corresponding call sites have been modified to
pass the flag based on the CONFIG_ADSP_POWER_DOWN_HPSRAM Kconfig option.

Additionally, the assembly code has been cleaned up to remove the
now-obsolete hpsram_mask array and related logic.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-11-16 14:03:50 -05:00
Tomasz Leman
f447d10b0a soc: intel_adsp: ace: Add macro to power down entire HPSRAM
Introduce a new assembly macro, m_ace_hpsram_power_down_entire, which
utilizes Zephyr Devicetree macros to power down the entire HPSRAM on
Intel ADSP ACE platforms.

This macro dynamically retrieves the HPSRAM bank count and control
register address from the Devicetree, streamlining the power-down
process. The macro is designed to iterate over all HPSRAM banks and
issue a power down command to each, ensuring a complete shutdown of the
HPSRAM when required by the system's power management policy.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-11-16 14:03:50 -05:00
Tomasz Leman
e0977dccd8 dts: xtensa: intel: Add hsbcap register node for ADSP ACE platforms
This commit introduces the L2 Memory Capabilities (hsbcap) register node
to the Devicetree specifications for Intel ADSP ACE platforms. The
hsbcap register provides information on the general capabilities
associated with the L2 memory, which is critical for system
configuration and resource management. The hsbcap node has been added to
the Devicetree source files for ACE 1.5 (MTPM), ACE 2.0 (LNL), and ACE
3.0 (PTL) platforms.

In addition, the DFL2MM_REG macro in adsp_memory.h has been updated to
use the Devicetree node label for hsbcap, ensuring a consistent and
maintainable approach to accessing this register across the codebase.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-11-16 14:03:50 -05:00
Tomasz Leman
f810b5d292 soc: intel_adsp: ace: Clean up macro indentation in power_down.S
This commit improves the readability of the power_down.S assembly file
by standardizing the indentation of the preprocessor definitions.

No functional changes have been made; this is purely a cosmetic update
to the code formatting.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-11-16 14:03:50 -05:00
Tomasz Leman
095bc56a57 soc: intel_adsp: ace: Ensure TLB entry for HW registers during power-down
This commit addresses an issue on platforms with an MMU where a
LoadStoreTLBMissCause exception occurs when accessing hardware registers
during the power-down process. The exception arises when attempting to
access the IPC register after HPSRAM has been powered down, leading to a
double exception: LoadStoreTLBMissCause followed by
InstrPIFDataErrorCause.

To resolve this, we preload the IPC register before shutting down
LPSRAM. This change prevents the double exception by ensuring that the
page table entries are correctly managed in the TLB before HPSRAM is
powered down and allowing the power-down sequence to complete
successfully.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-11-16 14:03:50 -05:00
Anas Nashif
cb02d090bf soc: intel_adsp: rename missing file during compilation
Fix renaming of file during refactoring of SoC.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2024-09-24 09:20:01 -04:00
Grzegorz Bernat
a654bfbdfa soc: intel: renamed soc from ace30_ptl to ace30
Renamed soc from ace30_ptl to ace30.
We were previously using the wrong soc name.
The correct name is ace30.

There is only one ptl platform, but there can be several ace30 platforms.

Signed-off-by: Grzegorz Bernat <grzegorzx.bernat@intel.com>
2024-09-24 10:10:37 +02:00
Grzegorz Bernat
966abb2f57 soc: intel: Fix problems with the formatter
No functional changes were made in this update.
Only code formatting issues were corrected.

This commit is necessary to preserve Git history
continuity for future changes involving the switch from ace30_ptl to ace30.

Signed-off-by: Grzegorz Bernat <grzegorzx.bernat@intel.com>
2024-09-24 10:10:37 +02:00
Anas Nashif
810f978bed Revert parts of "soc: intel: move init code from SYS_INIT to hooks"
This reverts parts of commit c344771d8b
related to intel_adsp soc.

There is a dependency on device initialization that was missed.

Reverting until we have a proper way for migrating to hooks.

Fixes #78880

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2024-09-23 18:13:17 -04:00
Anas Nashif
c344771d8b soc: intel: move init code from SYS_INIT to hooks
Replace SYS_INIT with SoC hooks and adapt SoC init code

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2024-09-20 13:15:31 +02:00
Guennadi Liakhovetski
1dde70637d Intel: ACE: move hpsram_mask to a data section
On platforms with enforced memory access modes, .text is read-only.
Move hpsram_mask to a cached data section to fix PTL.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-16 10:03:26 +02:00
Tomasz Leman
4f5f4c0389 fix: power: ace: Move HST domain suspend before IMR context save
This patch addresses an issue in the ACE platform power management code
where the HST domain suspend operation was performed after the IMR
context save. This resulted in the power management context being
restored with outdated values upon wake-up from D3 state, leading to a
failure to resume the HST domain correctly.

By moving the `pm_device_runtime_put(INTEL_ADSP_HST_DOMAIN_DEV)` call
before the IMR context save, we ensure that the HST domain is suspended
with the current context, and upon resume, the power management context
has the correct information to restore the HST domain state.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-09-12 10:03:11 +02:00
Pisit Sawangvonganan
8e4c072991 style: soc: comply with MISRA C:2012 Rule 15.6
Add missing braces to comply with MISRA C:2012 Rule 15.6 and
also following Zephyr's style guideline.

Signed-off-by: Pisit Sawangvonganan <pisit@ndrsolution.com>
2024-09-11 07:40:35 -04:00
Guennadi Liakhovetski
be041b14fe Intel: ADSP: move HPSRAM mask into assembly
Assembly in power_down() in power_down.S already defines data and
code to be locked in cache when powering down SRAM. Instead of adding
another such location in power.c, move the hpsram_mask[] array into
power_down.S.  This fixes hard to debug failures when shutting down
the ADSP.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-09 13:53:56 -04:00
Tomasz Leman
d389c95935 soc: intel_adsp: ace: Configurable SRAM retention mode and cleanup
This commit introduces a new Kconfig option `CONFIG_SRAM_RETENTION_MODE`
that allows the configuration of SRAM retention mode during the
initialization phase of the firmware boot-up process. By default, the
retention mode is enabled to maintain the existing behavior. However,
this option provides the flexibility to disable the retention mode if
needed, without modifying the Zephyr codebase.

The SRAM initialization functions `hp_sram_init` and `lp_sram_init` in
`sram.c` have been updated to conditionally set the retention mode based
on the value of this Kconfig option.

Additionally, an unused macro `DELAY_COUNT` has been removed from
`sram.c` to clean up the code.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-09-05 16:56:56 -04:00
Flavio Ceolin
874e4e2e19 intel_adsp: Add board definitions for adsp simulator
Add board definition for Intel ADSP (ACE family) simulators.

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
2024-08-28 16:35:55 -04:00
Flavio Ceolin
32cf0e0f9f intel_adsp: ace: Fix undefined reference
/zephyr/soc/intel/intel_adsp/ace/power.c:46:9: warning: implicit
declaration of function 'cache_data_flush_range'; did you mean
'sys_cache_data_flush_range'? [-Wimplicit-function-declaration]
   46 |         cache_data_flush_range((__sparse_force void *)
      |         ^~~~~~~~~~~~~~~~~~~~~~
      |         sys_cache_data_flush_range

Signed-off-by: Flavio Ceolin <flavio.ceolin@intel.com>
2024-08-20 19:43:37 -04:00
Pisit Sawangvonganan
daae40811e style: soc: comply with MISRA C:2012 Rule 15.6
Add missing braces to comply with MISRA C:2012 Rule 15.6 and
also following Zephyr's style guideline.

Signed-off-by: Pisit Sawangvonganan <pisit@ndrsolution.com>
2024-08-20 10:33:51 +02:00
Peter Ujfalusi
85758444f7 intel_adsp: clk: Configure correct cardinal clock divider for PTL
The Audio integration PLL is faster on PTL compared to earlier ACE
platforms: 442.368 MHz instead 393.216 MHz, however the default
divider remained 16, which will result incorrect cardinal clock speed.

Change the divider to 18 in order to get correct 24.576 MHz cardinal
clock.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
2024-08-20 10:33:04 +02:00
Adrian Bonislawski
784bc06e7e soc: intel_adsp: ace: set xtensa ccount per platform
XTENSA_CCOUNT_HZ is no longer common to ACE soc series
This will fix Hz value for ACE30 platform

Signed-off-by: Adrian Bonislawski <adrian.bonislawski@intel.com>
2024-08-14 15:51:55 -05:00
Anas Nashif
a91c6e56c8 arch: use same syntax for custom arch calls
Use same Kconfig syntax for those  custom arch call.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2024-08-12 12:43:36 +02:00
Kai Vehmanen
2fcdbba534 intel_adsp/ace: power: pad the hpsram_mask passed to power_down
The power_down() function will lock dcache for the hpsram_mask
array. On some platforms, the dcache lock will fail if the array
is on cache line that can be used for window register context
saves.

Work around this by aligning and padding the hpsram_mask to cacheline
size.

Link: https://github.com/thesofproject/sof/issues/9268
Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
2024-08-08 15:38:58 +02:00
Anas Nashif
d590c18672 intel_adsp: ace: call soc_num_cpus_init early
Restore order of execution. Code that was run in EARLY init level is now
too late.

Signed-off-by: Anas Nashif <anas.nashif@intel.com>
2024-08-07 13:50:53 +02:00
Guennadi Liakhovetski
1497f77cc8 intel: adsp: make SRAM power-off configurable
Currently the code suggests, that setting the SRAM disabling mask to
0 skips powering off SRAM, whereas in fact it's the address of the
mask variable that's checked for NULL. Make this consistent and let
platforms select whether SRAM power down should be selected.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-07-27 10:44:02 +03:00
Guennadi Liakhovetski
293fa118df intel: adsp: fix firmware image in IMR overwriting
The IMR is used by the firmware to hold its own copy for hot-booting
and for an "L3 heap," used for slow large allocations like loadable
libraries. The beginning of the L3 heap is currently hard-coded and
now the firmware has grown too large to fit into the dedicated area
so that it gets overwritten by heap allocations. This is a critical
bug that needs an urgent solution, for which we increase the offset,
but a real fix must calculate the L3 heap offset automatically.

BugLink: https://github.com/thesofproject/sof/issues/9308
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-07-27 10:42:27 +03:00
Guennadi Liakhovetski
46b356a6b0 intel-adsp: fix ACE power-off assembly
A recent commit fb53d2ef8d ("ace: power: replace pseudo-assembly
movi") contained a bug: the Xtensa "movi" assembly instruction must
be written with the immediate argument already shifted left by 8, the
compiler doesn't do that automatically. This still somehow worked on
MTL but failed on LNL. Fix both occurrences.

Fixes: #75700
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-07-12 05:48:20 -04:00
Guennadi Liakhovetski
fb53d2ef8d ace: power: replace pseudo-assembly movi
When switching off memory banks we cannot use movi with arbitrary
immediate arguments, they will be converted by the compiler to memory
accesses. Only constants within the allowed range should be used.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-07-04 18:01:02 -04:00
Guennadi Liakhovetski
32d05d360b intel_adsp/ace: power: fix firmware panic on MTL
The power_down() function attempts to lock the hpsram_mask on-stack
variable in data cache, which causes an exception. Moving it to .bss
by making it static fixes it.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-07-03 15:31:12 +02:00
Tomasz Leman
a3835041bd intel_adsp/ace: power: Use MMU reinit API on core context restore
Replace the MMU initialization call with the new MMU re-initialization
API during the core context restore process in the ACE power management
code.

The previous code was directly calling `xtensa_mmu_init()` upon
restoring the core context, which is not appropriate when the MMU
context may have been preserved during low-power states. The new
`xtensa_mmu_reinit()` API is designed to re-establish the MMU context
without overwriting the existing page table, ensuring that any runtime
changes to the MMU configuration are retained.

Changes made in this patch:
- Removed the call to `xtensa_mmu_init()` from the
  `_restore_core_context()` function.
- Added a call to `xtensa_mmu_reinit()` after restoring the
  miscellaneous registers.

This update aligns the ACE power management code with the correct MMU
handling procedures when recovering from low-power states, as per the
recent changes in the Xtensa MMU support.

Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-06-25 14:15:27 -04:00
Ievgen Ganakov
d1b5d7092e intel_adsp: ace30: Correct power control register bitfield definitions
This patch updates the power control and status register bitfield
definitions in the ACE30 PTL ADSP power management header to match the
documented hardware specifications. The previous definitions contained
discrepancies that did not align with the actual hardware layout,
potentially leading to incorrect assumptions and usage within the
firmware.

Changes made in this patch:
- Renamed 'rsvd0' to 'rsvd4' to accurately represent the reserved bits
  starting at bit position 4.
- Removed the 'rsvd6' field, which was incorrectly defined and is not
  present in the hardware register layout.
- Adjusted the bit widths for 'ioxpgs' and 'mlpgs' to correctly reflect
  the number of bits these fields occupy in the hardware.
- Introduced a new 'rsvd15' field in both 'ace_pwrctl2' and
  'ace_pwrsts2' structures to account for the remaining reserved bits,
  ensuring the structure sizes accurately represent the full register
  width.

By correcting these bitfield definitions, the firmware's power
management code will now be consistent with the actual hardware design,
improving reliability and maintainability of the codebase.

Signed-off-by: Ievgen Ganakov <ievgen.ganakov@intel.com>
Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
2024-06-25 14:15:27 -04:00
Jordan Yates
07870934e3 everywhere: replace double words
Treewide search and replace on a range of double word combinations:
    * `the the`
    * `to to`
    * `if if`
    * `that that`
    * `on on`
    * `is is`
    * `from from`

Signed-off-by: Jordan Yates <jordan@embeint.com>
2024-06-22 05:40:22 -04:00