linux/drivers/soundwire/intel.h

237 lines
6.3 KiB
C
Raw Normal View History

/* 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;
/**
soundwire: intel: update interfaces between ASoC and SoundWire The current interfaces between ASoC and SoundWire are limited by the platform_device infrastructure to an init() and exit() (mapped to the platform driver.probe and .remove) To help with the platform detection, machine driver selection and management of power dependencies between DSP and SoundWire IP, the ASoC side requires: a) an ACPI scan helper, to report if any devices are exposed in the DSDT tables, and if any links are disabled by the BIOS. b) a probe helper that allocates the resources without actually starting the bus. c) a startup helper which does start the bus when all power dependencies are settled. d) an exit helper to free all resources e) an interrupt_enable/disable helper, typically invoked after the startup helper but also used in suspend routines. This patch moves all required interfaces to sdw_intel.h, mainly to allow SoundWire and ASoC parts to be merged separately once the header files are shared between trees. To avoid compilation issues, the conflicts in intel_init.c are blindly removed. This would in theory prevent the code from working, but since there are no users of the Intel Soundwire driver this has no impact. Functionality will be restored when the removal of platform devices is complete. Support for SoundWire + SOF builds will only be provided once all the required pieces are upstream. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20191212014507.28050-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:45:01 +00:00
* struct sdw_intel_link_res - Soundwire Intel link resource structure,
* typically populated by the controller driver.
* @hw_ops: platform-specific ops
soundwire: intel: update interfaces between ASoC and SoundWire The current interfaces between ASoC and SoundWire are limited by the platform_device infrastructure to an init() and exit() (mapped to the platform driver.probe and .remove) To help with the platform detection, machine driver selection and management of power dependencies between DSP and SoundWire IP, the ASoC side requires: a) an ACPI scan helper, to report if any devices are exposed in the DSDT tables, and if any links are disabled by the BIOS. b) a probe helper that allocates the resources without actually starting the bus. c) a startup helper which does start the bus when all power dependencies are settled. d) an exit helper to free all resources e) an interrupt_enable/disable helper, typically invoked after the startup helper but also used in suspend routines. This patch moves all required interfaces to sdw_intel.h, mainly to allow SoundWire and ASoC parts to be merged separately once the header files are shared between trees. To avoid compilation issues, the conflicts in intel_init.c are blindly removed. This would in theory prevent the code from working, but since there are no users of the Intel Soundwire driver this has no impact. Functionality will be restored when the removal of platform devices is complete. Support for SoundWire + SOF builds will only be provided once all the required pieces are upstream. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20191212014507.28050-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:45:01 +00:00
* @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
* @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;
soundwire: intel: update interfaces between ASoC and SoundWire The current interfaces between ASoC and SoundWire are limited by the platform_device infrastructure to an init() and exit() (mapped to the platform driver.probe and .remove) To help with the platform detection, machine driver selection and management of power dependencies between DSP and SoundWire IP, the ASoC side requires: a) an ACPI scan helper, to report if any devices are exposed in the DSDT tables, and if any links are disabled by the BIOS. b) a probe helper that allocates the resources without actually starting the bus. c) a startup helper which does start the bus when all power dependencies are settled. d) an exit helper to free all resources e) an interrupt_enable/disable helper, typically invoked after the startup helper but also used in suspend routines. This patch moves all required interfaces to sdw_intel.h, mainly to allow SoundWire and ASoC parts to be merged separately once the header files are shared between trees. To avoid compilation issues, the conflicts in intel_init.c are blindly removed. This would in theory prevent the code from working, but since there are no users of the Intel Soundwire driver this has no impact. Functionality will be restored when the removal of platform devices is complete. Support for SoundWire + SOF builds will only be provided once all the required pieces are upstream. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20191212014507.28050-6-pierre-louis.bossart@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
2019-12-12 01:45:01 +00:00
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;
u32 link_mask;
struct sdw_cdns *cdns;
struct list_head list;
struct hdac_bus *hbus;
};
struct sdw_intel {
struct sdw_cdns cdns;
int instance;
struct sdw_intel_link_res *link_res;
soundwire: intel: skip suspend/resume/wake when link was not started The SoundWire Linux devices are created purely based on information provided by platform firmware (e.g. ACPI DSDT table). When the kernel finds a matching driver for the device address (_ADR), the probe will initialize required data structures and initialize pm ops. When the SoundWire link is started at a later point, the physical devices will synchronize on the SoundWire frames and report their attachment status, thereby triggering the enumeration and initialization of device registers. This two-step solution was a conscious design decision to allow e.g. a driver to use sideband mechanisms to turn power rails on. This can also allow OEMs to describe multiple platforms with the same DSDT table, the devices that are not physically present in hardware. The drawback of this approach is a bit of confusion, with more devices than are actually present in hardware. This results in 'ghost' devices, for which the driver successfully probes, but that will not generate any traffic on the bus. suspend-resume transitions are handled by drivers, and skipped when the devices are not physically present. This patch provides a work-around for a second-level of confusion in platform firmware: some platforms only use HDaudio links, but nevertheless expose SoundWire 'ghost' devices. This results in error messages in the Intel driver while trying to suspend/resume these links. The simplest solution is to add a boolean status flag to skip all suspend/resume/wake sequences if the link was never started. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://lore.kernel.org/r/20210818024954.16873-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
2021-08-18 02:49:53 +00:00
bool startup_done;
#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_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;
}
/* 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 */