| /* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ | |
| /* Copyright(c) 2015-17 Intel Corporation. */ | |
| #ifndef __SDW_INTEL_LOCAL_H | |
| #define __SDW_INTEL_LOCAL_H | |
| struct hdac_bus; | |
| /** | |
| * struct sdw_intel_link_res - Soundwire Intel link resource structure, | |
| * typically populated by the controller driver. | |
| * @hw_ops: platform-specific ops | |
| * @mmio_base: mmio base of SoundWire registers | |
| * @registers: Link IO registers base | |
| * @ip_offset: offset for MCP_IP registers | |
| * @shim: Audio shim pointer | |
| * @shim_vs: Audio vendor-specific shim pointer | |
| * @alh: ALH (Audio Link Hub) pointer | |
| * @irq: Interrupt line | |
| * @ops: Shim callback ops | |
| * @dev: device implementing hw_params and free callbacks | |
| * @shim_lock: mutex to handle access to shared SHIM registers | |
| * @shim_mask: global pointer to check SHIM register initialization | |
| * @clock_stop_quirks: mask defining requested behavior on pm_suspend | |
| * @mic_privacy: ACE version supports microphone privacy | |
| * @link_mask: global mask needed for power-up/down sequences | |
| * @cdns: Cadence master descriptor | |
| * @list: used to walk-through all masters exposed by the same controller | |
| * @hbus: hdac_bus pointer, needed for power management | |
| */ | |
| struct sdw_intel_link_res { | |
| const struct sdw_intel_hw_ops *hw_ops; | |
| void __iomem *mmio_base; /* not strictly needed, useful for debug */ | |
| void __iomem *registers; | |
| u32 ip_offset; | |
| void __iomem *shim; | |
| void __iomem *shim_vs; | |
| void __iomem *alh; | |
| int irq; | |
| const struct sdw_intel_ops *ops; | |
| struct device *dev; | |
| struct mutex *shim_lock; /* protect shared registers */ | |
| u32 *shim_mask; | |
| u32 clock_stop_quirks; | |
| bool mic_privacy; | |
| u32 link_mask; | |
| struct sdw_cdns *cdns; | |
| struct list_head list; | |
| struct hdac_bus *hbus; | |
| }; | |
| /** | |
| * struct sdw_intel_bpt - SoundWire Intel BPT context | |
| * @bpt_tx_stream: BPT TX stream | |
| * @dmab_tx_bdl: BPT TX buffer descriptor list | |
| * @bpt_rx_stream: BPT RX stream | |
| * @dmab_rx_bdl: BPT RX buffer descriptor list | |
| * @pdi0_buffer_size: PDI0 buffer size | |
| * @pdi1_buffer_size: PDI1 buffer size | |
| * @num_frames: number of frames | |
| * @data_per_frame: data per frame | |
| */ | |
| struct sdw_intel_bpt { | |
| struct hdac_ext_stream *bpt_tx_stream; | |
| struct snd_dma_buffer dmab_tx_bdl; | |
| struct hdac_ext_stream *bpt_rx_stream; | |
| struct snd_dma_buffer dmab_rx_bdl; | |
| unsigned int pdi0_buffer_size; | |
| unsigned int pdi1_buffer_size; | |
| unsigned int num_frames; | |
| unsigned int data_per_frame; | |
| }; | |
| struct sdw_intel { | |
| struct sdw_cdns cdns; | |
| int instance; | |
| struct sdw_intel_link_res *link_res; | |
| bool startup_done; | |
| struct sdw_intel_bpt bpt_ctx; | |
| #ifdef CONFIG_DEBUG_FS | |
| struct dentry *debugfs; | |
| #endif | |
| }; | |
| struct sdw_intel_prop { | |
| u16 clde; | |
| u16 doaise2; | |
| u16 dodse2; | |
| u16 clds; | |
| u16 clss; | |
| u16 doaise; | |
| u16 doais; | |
| u16 dodse; | |
| u16 dods; | |
| }; | |
| enum intel_pdi_type { | |
| INTEL_PDI_IN = 0, | |
| INTEL_PDI_OUT = 1, | |
| INTEL_PDI_BD = 2, | |
| }; | |
| /* | |
| * Read, write helpers for HW registers | |
| */ | |
| static inline int intel_readl(void __iomem *base, int offset) | |
| { | |
| return readl(base + offset); | |
| } | |
| static inline void intel_writel(void __iomem *base, int offset, int value) | |
| { | |
| writel(value, base + offset); | |
| } | |
| static inline u16 intel_readw(void __iomem *base, int offset) | |
| { | |
| return readw(base + offset); | |
| } | |
| static inline void intel_writew(void __iomem *base, int offset, u16 value) | |
| { | |
| writew(value, base + offset); | |
| } | |
| #define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns) | |
| #define INTEL_MASTER_RESET_ITERATIONS 10 | |
| #define SDW_INTEL_DELAYED_ENUMERATION_MS 100 | |
| #define SDW_INTEL_CHECK_OPS(sdw, cb) ((sdw) && (sdw)->link_res && (sdw)->link_res->hw_ops && \ | |
| (sdw)->link_res->hw_ops->cb) | |
| #define SDW_INTEL_OPS(sdw, cb) ((sdw)->link_res->hw_ops->cb) | |
| #ifdef CONFIG_DEBUG_FS | |
| void intel_ace2x_debugfs_init(struct sdw_intel *sdw); | |
| void intel_ace2x_debugfs_exit(struct sdw_intel *sdw); | |
| #else | |
| static inline void intel_ace2x_debugfs_init(struct sdw_intel *sdw) {} | |
| static inline void intel_ace2x_debugfs_exit(struct sdw_intel *sdw) {} | |
| #endif | |
| static inline void sdw_intel_debugfs_init(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, debugfs_init)) | |
| SDW_INTEL_OPS(sdw, debugfs_init)(sdw); | |
| } | |
| static inline void sdw_intel_debugfs_exit(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, debugfs_exit)) | |
| SDW_INTEL_OPS(sdw, debugfs_exit)(sdw); | |
| } | |
| static inline int sdw_intel_register_dai(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, register_dai)) | |
| return SDW_INTEL_OPS(sdw, register_dai)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline void sdw_intel_check_clock_stop(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, check_clock_stop)) | |
| SDW_INTEL_OPS(sdw, check_clock_stop)(sdw); | |
| } | |
| static inline int sdw_intel_start_bus(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, start_bus)) | |
| return SDW_INTEL_OPS(sdw, start_bus)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline int sdw_intel_start_bus_after_reset(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, start_bus_after_reset)) | |
| return SDW_INTEL_OPS(sdw, start_bus_after_reset)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline int sdw_intel_start_bus_after_clock_stop(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, start_bus_after_clock_stop)) | |
| return SDW_INTEL_OPS(sdw, start_bus_after_clock_stop)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline int sdw_intel_stop_bus(struct sdw_intel *sdw, bool clock_stop) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, stop_bus)) | |
| return SDW_INTEL_OPS(sdw, stop_bus)(sdw, clock_stop); | |
| return -ENOTSUPP; | |
| } | |
| static inline int sdw_intel_link_power_up(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, link_power_up)) | |
| return SDW_INTEL_OPS(sdw, link_power_up)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline int sdw_intel_link_power_down(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, link_power_down)) | |
| return SDW_INTEL_OPS(sdw, link_power_down)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline int sdw_intel_shim_check_wake(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, shim_check_wake)) | |
| return SDW_INTEL_OPS(sdw, shim_check_wake)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline void sdw_intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, shim_wake)) | |
| SDW_INTEL_OPS(sdw, shim_wake)(sdw, wake_enable); | |
| } | |
| static inline void sdw_intel_sync_arm(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, sync_arm)) | |
| SDW_INTEL_OPS(sdw, sync_arm)(sdw); | |
| } | |
| static inline int sdw_intel_sync_go_unlocked(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, sync_go_unlocked)) | |
| return SDW_INTEL_OPS(sdw, sync_go_unlocked)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline int sdw_intel_sync_go(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, sync_go)) | |
| return SDW_INTEL_OPS(sdw, sync_go)(sdw); | |
| return -ENOTSUPP; | |
| } | |
| static inline bool sdw_intel_sync_check_cmdsync_unlocked(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, sync_check_cmdsync_unlocked)) | |
| return SDW_INTEL_OPS(sdw, sync_check_cmdsync_unlocked)(sdw); | |
| return false; | |
| } | |
| static inline int sdw_intel_get_link_count(struct sdw_intel *sdw) | |
| { | |
| if (SDW_INTEL_CHECK_OPS(sdw, get_link_count)) | |
| return SDW_INTEL_OPS(sdw, get_link_count)(sdw); | |
| return 4; /* default on older generations */ | |
| } | |
| /* common bus management */ | |
| int intel_start_bus(struct sdw_intel *sdw); | |
| int intel_start_bus_after_reset(struct sdw_intel *sdw); | |
| void intel_check_clock_stop(struct sdw_intel *sdw); | |
| int intel_start_bus_after_clock_stop(struct sdw_intel *sdw); | |
| int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop); | |
| /* common bank switch routines */ | |
| int intel_pre_bank_switch(struct sdw_intel *sdw); | |
| int intel_post_bank_switch(struct sdw_intel *sdw); | |
| #endif /* __SDW_INTEL_LOCAL_H */ |