/* spi_dw.h - Designware SPI driver private definitions */ /* * Copyright (c) 2015 Intel Corporation. * Copyright (c) 2023 Synopsys, Inc. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_DRIVERS_SPI_SPI_DW_H_ #define ZEPHYR_DRIVERS_SPI_SPI_DW_H_ #include #include #include #include "spi_context.h" #ifdef __cplusplus extern "C" { #endif typedef void (*spi_dw_config_t)(void); typedef uint32_t (*spi_dw_read_t)(uint8_t size, mm_reg_t addr, uint32_t off); typedef void (*spi_dw_write_t)(uint8_t size, uint32_t data, mm_reg_t addr, uint32_t off); typedef void (*spi_dw_set_bit_t)(uint8_t bit, mm_reg_t addr, uint32_t off); typedef void (*spi_dw_clear_bit_t)(uint8_t bit, mm_reg_t addr, uint32_t off); typedef int (*spi_dw_test_bit_t)(uint8_t bit, mm_reg_t addr, uint32_t off); /* Private structures */ struct spi_dw_config { DEVICE_MMIO_ROM; uint32_t clock_frequency; spi_dw_config_t config_func; bool serial_target; uint8_t fifo_depth; uint8_t max_xfer_size; #ifdef CONFIG_PINCTRL const struct pinctrl_dev_config *pcfg; #endif spi_dw_read_t read_func; spi_dw_write_t write_func; spi_dw_set_bit_t set_bit_func; spi_dw_clear_bit_t clear_bit_func; spi_dw_test_bit_t test_bit_func; }; struct spi_dw_data { DEVICE_MMIO_RAM; struct spi_context ctx; uint8_t dfs; /* dfs in bytes: 1,2 or 4 */ uint8_t fifo_diff; /* cannot be bigger than FIFO depth */ }; /* Register operation functions */ #define DT_INST_NODE_PROP_NOT_OR(inst, prop) \ !DT_INST_PROP(inst, prop) || #define DT_ANY_INST_NOT_PROP_STATUS_OKAY(prop) \ (DT_INST_FOREACH_STATUS_OKAY_VARGS(DT_INST_NODE_PROP_NOT_OR, prop) 0) #define DT_INST_NODE_PROP_AND_OR(inst, prop) \ DT_INST_PROP(inst, prop) || #define DT_ANY_INST_PROP_STATUS_OKAY(prop) \ (DT_INST_FOREACH_STATUS_OKAY_VARGS(DT_INST_NODE_PROP_AND_OR, prop) 0) #if DT_ANY_INST_PROP_STATUS_OKAY(aux_reg) static uint32_t aux_reg_read(uint8_t size, mm_reg_t addr, uint32_t off) { ARG_UNUSED(size); return sys_in32(addr + off/4); } static void aux_reg_write(uint8_t size, uint32_t data, mm_reg_t addr, uint32_t off) { ARG_UNUSED(size); sys_out32(data, addr + off/4); } static void aux_reg_set_bit(uint8_t bit, mm_reg_t addr, uint32_t off) { sys_io_set_bit(addr + off/4, bit); } static void aux_reg_clear_bit(uint8_t bit, mm_reg_t addr, uint32_t off) { sys_io_clear_bit(addr + off/4, bit); } static int aux_reg_test_bit(uint8_t bit, mm_reg_t addr, uint32_t off) { return sys_io_test_bit(addr + off/4, bit); } #endif #if DT_ANY_INST_NOT_PROP_STATUS_OKAY(aux_reg) static uint32_t reg_read(uint8_t size, mm_reg_t addr, uint32_t off) { switch (size) { case 8: return sys_read8(addr + off); case 16: return sys_read16(addr + off); case 32: return sys_read32(addr + off); default: return -EINVAL; } } static void reg_write(uint8_t size, uint32_t data, mm_reg_t addr, uint32_t off) { switch (size) { case 8: sys_write8(data, addr + off); break; case 16: sys_write16(data, addr + off); break; case 32: sys_write32(data, addr + off); break; default: break; } } static void reg_set_bit(uint8_t bit, mm_reg_t addr, uint32_t off) { sys_set_bit(addr + off, bit); } static void reg_clear_bit(uint8_t bit, mm_reg_t addr, uint32_t off) { sys_clear_bit(addr + off, bit); } static int reg_test_bit(uint8_t bit, mm_reg_t addr, uint32_t off) { return sys_test_bit(addr + off, bit); } #endif /* Helper macros */ #define SPI_DW_CLK_DIVIDER(clock_freq, ssi_clk_hz) \ ((clock_freq / ssi_clk_hz) & 0xFFFF) #define DEFINE_MM_REG_READ(__reg, __off, __sz) \ static inline uint32_t read_##__reg(const struct device *dev) \ { \ const struct spi_dw_config *info = dev->config; \ return info->read_func(__sz, (mm_reg_t)DEVICE_MMIO_GET(dev), __off); \ } #define DEFINE_MM_REG_WRITE(__reg, __off, __sz) \ static inline void write_##__reg(const struct device *dev, uint32_t data)\ { \ const struct spi_dw_config *info = dev->config; \ info->write_func(__sz, data, (mm_reg_t)DEVICE_MMIO_GET(dev), __off); \ } #define DEFINE_SET_BIT_OP(__reg_bit, __reg_off, __bit) \ static inline void set_bit_##__reg_bit(const struct device *dev) \ { \ const struct spi_dw_config *info = dev->config; \ info->set_bit_func(__bit, (mm_reg_t)DEVICE_MMIO_GET(dev), __reg_off); \ } #define DEFINE_CLEAR_BIT_OP(__reg_bit, __reg_off, __bit) \ static inline void clear_bit_##__reg_bit(const struct device *dev)\ { \ const struct spi_dw_config *info = dev->config; \ info->clear_bit_func(__bit, (mm_reg_t)DEVICE_MMIO_GET(dev), __reg_off); \ } #define DEFINE_TEST_BIT_OP(__reg_bit, __reg_off, __bit) \ static inline int test_bit_##__reg_bit(const struct device *dev)\ { \ const struct spi_dw_config *info = dev->config; \ return info->test_bit_func(__bit, (mm_reg_t)DEVICE_MMIO_GET(dev), __reg_off); \ } /* Common registers settings, bits etc... */ /* CTRLR0 settings */ #if !defined(CONFIG_SPI_DW_HSSI) #define DW_SPI_CTRLR0_SCPH_BIT (6) #define DW_SPI_CTRLR0_SCPOL_BIT (7) #define DW_SPI_CTRLR0_TMOD_SHIFT (8) #define DW_SPI_CTRLR0_SLV_OE_BIT (10) #define DW_SPI_CTRLR0_SRL_BIT (11) #else /* The register layout is different in the HSSI variant */ #define DW_SPI_CTRLR0_SCPH_BIT (8) #define DW_SPI_CTRLR0_SCPOL_BIT (9) #define DW_SPI_CTRLR0_TMOD_SHIFT (10) #define DW_SPI_CTRLR0_SLV_OE_BIT (12) #define DW_SPI_CTRLR0_SRL_BIT (13) #endif #define DW_SPI_CTRLR0_SCPH BIT(DW_SPI_CTRLR0_SCPH_BIT) #define DW_SPI_CTRLR0_SCPOL BIT(DW_SPI_CTRLR0_SCPOL_BIT) #define DW_SPI_CTRLR0_SRL BIT(DW_SPI_CTRLR0_SRL_BIT) #define DW_SPI_CTRLR0_SLV_OE BIT(DW_SPI_CTRLR0_SLV_OE_BIT) #define DW_SPI_CTRLR0_TMOD_TX_RX (0) #define DW_SPI_CTRLR0_TMOD_TX (1 << DW_SPI_CTRLR0_TMOD_SHIFT) #define DW_SPI_CTRLR0_TMOD_RX (2 << DW_SPI_CTRLR0_TMOD_SHIFT) #define DW_SPI_CTRLR0_TMOD_EEPROM (3 << DW_SPI_CTRLR0_TMOD_SHIFT) #define DW_SPI_CTRLR0_TMOD_RESET (3 << DW_SPI_CTRLR0_TMOD_SHIFT) #define DW_SPI_CTRLR0_DFS_16(__bpw) ((__bpw) - 1) #define DW_SPI_CTRLR0_DFS_32(__bpw) (((__bpw) - 1) << 16) /* 0x38 represents the bits 8, 16 and 32. Knowing that 24 is bits 8 and 16 * These are the bits were when you divide by 8, you keep the result as it is. * For all the other ones, 4 to 7, 9 to 15, etc... you need a +1, * since on such division it takes only the result above 0 */ #define SPI_WS_TO_DFS(__bpw) (((__bpw) & ~0x38) ? \ (((__bpw) / 8) + 1) : \ ((__bpw) / 8)) /* SSIENR bits */ #define DW_SPI_SSIENR_SSIEN_BIT (0) /* CLK_ENA bits */ #define DW_SPI_CLK_ENA_BIT (0) /* SR bits and values */ #define DW_SPI_SR_BUSY_BIT (0) #define DW_SPI_SR_TFNF_BIT (1) #define DW_SPI_SR_RFNE_BIT (3) /* IMR bits (ISR valid as well) */ #define DW_SPI_IMR_TXEIM_BIT (0) #define DW_SPI_IMR_TXOIM_BIT (1) #define DW_SPI_IMR_RXUIM_BIT (2) #define DW_SPI_IMR_RXOIM_BIT (3) #define DW_SPI_IMR_RXFIM_BIT (4) #define DW_SPI_IMR_MSTIM_BIT (5) /* IMR values */ #define DW_SPI_IMR_TXEIM BIT(DW_SPI_IMR_TXEIM_BIT) #define DW_SPI_IMR_TXOIM BIT(DW_SPI_IMR_TXOIM_BIT) #define DW_SPI_IMR_RXUIM BIT(DW_SPI_IMR_RXUIM_BIT) #define DW_SPI_IMR_RXOIM BIT(DW_SPI_IMR_RXOIM_BIT) #define DW_SPI_IMR_RXFIM BIT(DW_SPI_IMR_RXFIM_BIT) #define DW_SPI_IMR_MSTIM BIT(DW_SPI_IMR_MSTIM_BIT) /* ISR values (same as IMR) */ #define DW_SPI_ISR_TXEIS DW_SPI_IMR_TXEIM #define DW_SPI_ISR_TXOIS DW_SPI_IMR_TXOIM #define DW_SPI_ISR_RXUIS DW_SPI_IMR_RXUIM #define DW_SPI_ISR_RXOIS DW_SPI_IMR_RXOIM #define DW_SPI_ISR_RXFIS DW_SPI_IMR_RXFIM #define DW_SPI_ISR_MSTIS DW_SPI_IMR_MSTIM /* Error interrupt */ #define DW_SPI_ISR_ERRORS_MASK (DW_SPI_ISR_TXOIS | \ DW_SPI_ISR_RXUIS | \ DW_SPI_ISR_RXOIS | \ DW_SPI_ISR_MSTIS) /* ICR Bit */ #define DW_SPI_SR_ICR_BIT (0) /* Interrupt mask (IMR) */ #define DW_SPI_IMR_MASK (0x0) #define DW_SPI_IMR_UNMASK (DW_SPI_IMR_TXEIM | \ DW_SPI_IMR_TXOIM | \ DW_SPI_IMR_RXUIM | \ DW_SPI_IMR_RXOIM | \ DW_SPI_IMR_RXFIM) #define DW_SPI_IMR_MASK_TX (~(DW_SPI_IMR_TXEIM | \ DW_SPI_IMR_TXOIM)) #define DW_SPI_IMR_MASK_RX (~(DW_SPI_IMR_RXUIM | \ DW_SPI_IMR_RXOIM | \ DW_SPI_IMR_RXFIM)) /* * Including the right register definition file * SoC SPECIFIC! * * The file included next uses the DEFINE_MM_REG macros above to * declare functions. In this situation we'll leave the containing * extern "C" active in C++ compilations. */ #include "spi_dw_regs.h" #define z_extra_clock_on(...) #define z_extra_clock_off(...) /* Based on those macros above, here are common helpers for some registers */ DEFINE_MM_REG_READ(txflr, DW_SPI_REG_TXFLR, 32) DEFINE_MM_REG_READ(rxflr, DW_SPI_REG_RXFLR, 32) #ifdef CONFIG_SPI_DW_ACCESS_WORD_ONLY DEFINE_MM_REG_WRITE(baudr, DW_SPI_REG_BAUDR, 32) DEFINE_MM_REG_WRITE(imr, DW_SPI_REG_IMR, 32) DEFINE_MM_REG_READ(imr, DW_SPI_REG_IMR, 32) DEFINE_MM_REG_READ(isr, DW_SPI_REG_ISR, 32) #else DEFINE_MM_REG_WRITE(baudr, DW_SPI_REG_BAUDR, 16) DEFINE_MM_REG_WRITE(imr, DW_SPI_REG_IMR, 8) DEFINE_MM_REG_READ(imr, DW_SPI_REG_IMR, 8) DEFINE_MM_REG_READ(isr, DW_SPI_REG_ISR, 8) #endif DEFINE_SET_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT) DEFINE_CLEAR_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT) DEFINE_TEST_BIT_OP(ssienr, DW_SPI_REG_SSIENR, DW_SPI_SSIENR_SSIEN_BIT) DEFINE_TEST_BIT_OP(sr_busy, DW_SPI_REG_SR, DW_SPI_SR_BUSY_BIT) #ifdef __cplusplus } #endif #endif /* ZEPHYR_DRIVERS_SPI_SPI_DW_H_ */