aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/include/linux/soundwire
diff options
context:
space:
mode:
Diffstat (limited to 'include/linux/soundwire')
-rw-r--r--include/linux/soundwire/sdw.h558
-rw-r--r--include/linux/soundwire/sdw_amd.h173
-rw-r--r--include/linux/soundwire/sdw_intel.h307
-rw-r--r--include/linux/soundwire/sdw_registers.h59
-rw-r--r--include/linux/soundwire/sdw_type.h10
5 files changed, 895 insertions, 212 deletions
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index 41cc1192f9aa..0832776262ac 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -4,8 +4,21 @@
#ifndef __SOUNDWIRE_H
#define __SOUNDWIRE_H
-#include <linux/mod_devicetable.h>
#include <linux/bitfield.h>
+#include <linux/bug.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/lockdep_types.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <sound/sdca.h>
+
+struct dentry;
+struct fwnode_handle;
struct sdw_bus;
struct sdw_slave;
@@ -38,10 +51,13 @@ struct sdw_slave;
#define SDW_FRAME_CTRL_BITS 48
#define SDW_MAX_DEVICES 11
+#define SDW_FW_MAX_DEVICES 16
#define SDW_MAX_PORTS 15
#define SDW_VALID_PORT_RANGE(n) ((n) < SDW_MAX_PORTS && (n) >= 1)
+#define SDW_MAX_LANES 8
+
enum {
SDW_PORT_DIRN_SINK = 0,
SDW_PORT_DIRN_SOURCE,
@@ -125,17 +141,25 @@ enum sdw_dpn_grouping {
SDW_BLK_GRP_CNT_4 = 3,
};
+/* block packing mode enum */
+enum sdw_dpn_pkg_mode {
+ SDW_BLK_PKG_PER_PORT = 0,
+ SDW_BLK_PKG_PER_CHANNEL = 1
+};
+
/**
* enum sdw_stream_type: data stream type
*
* @SDW_STREAM_PCM: PCM data stream
* @SDW_STREAM_PDM: PDM data stream
+ * @SDW_STREAM_BPT: BPT data stream
*
* spec doesn't define this, but is used in implementation
*/
enum sdw_stream_type {
SDW_STREAM_PCM = 0,
SDW_STREAM_PDM = 1,
+ SDW_STREAM_BPT = 2,
};
/**
@@ -216,62 +240,36 @@ enum sdw_clk_stop_mode {
/**
* struct sdw_dp0_prop - DP0 properties
+ * @words: wordlengths supported
* @max_word: Maximum number of bits in a Payload Channel Sample, 1 to 64
* (inclusive)
* @min_word: Minimum number of bits in a Payload Channel Sample, 1 to 64
* (inclusive)
* @num_words: number of wordlengths supported
- * @words: wordlengths supported
+ * @ch_prep_timeout: Port-specific timeout value, in milliseconds
* @BRA_flow_controlled: Slave implementation results in an OK_NotReady
* response
* @simple_ch_prep_sm: If channel prepare sequence is required
* @imp_def_interrupts: If set, each bit corresponds to support for
* implementation-defined interrupts
+ * @num_lanes: array size of @lane_list
+ * @lane_list: indicates which Lanes can be used by DP0
*
* The wordlengths are specified by Spec as max, min AND number of
* discrete values, implementation can define based on the wordlengths they
* support
*/
struct sdw_dp0_prop {
+ u32 *words;
u32 max_word;
u32 min_word;
u32 num_words;
- u32 *words;
+ u32 ch_prep_timeout;
bool BRA_flow_controlled;
bool simple_ch_prep_sm;
bool imp_def_interrupts;
-};
-
-/**
- * struct sdw_dpn_audio_mode - Audio mode properties for DPn
- * @bus_min_freq: Minimum bus frequency, in Hz
- * @bus_max_freq: Maximum bus frequency, in Hz
- * @bus_num_freq: Number of discrete frequencies supported
- * @bus_freq: Discrete bus frequencies, in Hz
- * @min_freq: Minimum sampling frequency, in Hz
- * @max_freq: Maximum sampling bus frequency, in Hz
- * @num_freq: Number of discrete sampling frequency supported
- * @freq: Discrete sampling frequencies, in Hz
- * @prep_ch_behave: Specifies the dependencies between Channel Prepare
- * sequence and bus clock configuration
- * If 0, Channel Prepare can happen at any Bus clock rate
- * If 1, Channel Prepare sequence shall happen only after Bus clock is
- * changed to a frequency supported by this mode or compatible modes
- * described by the next field
- * @glitchless: Bitmap describing possible glitchless transitions from this
- * Audio Mode to other Audio Modes
- */
-struct sdw_dpn_audio_mode {
- u32 bus_min_freq;
- u32 bus_max_freq;
- u32 bus_num_freq;
- u32 *bus_freq;
- u32 max_freq;
- u32 min_freq;
- u32 num_freq;
- u32 *freq;
- u32 prep_ch_behave;
- u32 glitchless;
+ int num_lanes;
+ u32 *lane_list;
};
/**
@@ -286,24 +284,25 @@ struct sdw_dpn_audio_mode {
* @type: Data port type. Full, Simplified or Reduced
* @max_grouping: Maximum number of samples that can be grouped together for
* a full data port
- * @simple_ch_prep_sm: If the port supports simplified channel prepare state
- * machine
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
* @imp_def_interrupts: If set, each bit corresponds to support for
* implementation-defined interrupts
* @max_ch: Maximum channels supported
* @min_ch: Minimum channels supported
* @num_channels: Number of discrete channels supported
- * @channels: Discrete channels supported
* @num_ch_combinations: Number of channel combinations supported
+ * @channels: Discrete channels supported
* @ch_combinations: Channel combinations supported
+ * @lane_list: indicates which Lanes can be used by DPn
+ * @num_lanes: array size of @lane_list
* @modes: SDW mode supported
* @max_async_buffer: Number of samples that this port can buffer in
* asynchronous modes
+ * @port_encoding: Payload Channel Sample encoding schemes supported
* @block_pack_mode: Type of block port mode supported
* @read_only_wordlength: Read Only wordlength field in DPN_BlockCtrl1 register
- * @port_encoding: Payload Channel Sample encoding schemes supported
- * @audio_modes: Audio modes supported
+ * @simple_ch_prep_sm: If the port supports simplified channel prepare state
+ * machine
*/
struct sdw_dpn_prop {
u32 num;
@@ -313,25 +312,29 @@ struct sdw_dpn_prop {
u32 *words;
enum sdw_dpn_type type;
u32 max_grouping;
- bool simple_ch_prep_sm;
u32 ch_prep_timeout;
u32 imp_def_interrupts;
u32 max_ch;
u32 min_ch;
u32 num_channels;
- u32 *channels;
u32 num_ch_combinations;
+ u32 *channels;
u32 *ch_combinations;
+ u32 *lane_list;
+ int num_lanes;
u32 modes;
u32 max_async_buffer;
+ u32 port_encoding;
bool block_pack_mode;
bool read_only_wordlength;
- u32 port_encoding;
- struct sdw_dpn_audio_mode *audio_modes;
+ bool simple_ch_prep_sm;
};
/**
* struct sdw_slave_prop - SoundWire Slave properties
+ * @dp0_prop: Data Port 0 properties
+ * @src_dpn_prop: Source Data Port N properties
+ * @sink_dpn_prop: Sink Data Port N properties
* @mipi_revision: Spec version of the implementation
* @wake_capable: Wake-up events are supported
* @test_mode_capable: If test mode is supported
@@ -348,19 +351,27 @@ struct sdw_dpn_prop {
* SCP_AddrPage2
* @bank_delay_support: Slave implements bank delay/bridge support registers
* SCP_BankDelay and SCP_NextFrame
+ * @lane_control_support: Slave supports lane control
* @p15_behave: Slave behavior when the Master attempts a read to the Port15
* alias
- * @lane_control_support: Slave supports lane control
* @master_count: Number of Masters present on this Slave
* @source_ports: Bitmap identifying source ports
* @sink_ports: Bitmap identifying sink ports
- * @dp0_prop: Data Port 0 properties
- * @src_dpn_prop: Source Data Port N properties
- * @sink_dpn_prop: Sink Data Port N properties
- * @scp_int1_mask: SCP_INT1_MASK desired settings
* @quirks: bitmask identifying deltas from the MIPI specification
+ * @sdca_interrupt_register_list: indicates which sets of SDCA interrupt status
+ * and masks are supported
+ * @commit_register_supported: is PCP_Commit register supported
+ * @scp_int1_mask: SCP_INT1_MASK desired settings
+ * @lane_maps: Lane mapping for the slave, only valid if lane_control_support is set
+ * @clock_reg_supported: the Peripheral implements the clock base and scale
+ * registers introduced with the SoundWire 1.2 specification. SDCA devices
+ * do not need to set this boolean property as the registers are required.
+ * @use_domain_irq: call actual IRQ handler on slave, as well as callback
*/
struct sdw_slave_prop {
+ struct sdw_dp0_prop *dp0_prop;
+ struct sdw_dpn_prop *src_dpn_prop;
+ struct sdw_dpn_prop *sink_dpn_prop;
u32 mipi_revision;
bool wake_capable;
bool test_mode_capable;
@@ -372,29 +383,32 @@ struct sdw_slave_prop {
bool high_PHY_capable;
bool paging_support;
bool bank_delay_support;
- enum sdw_p15_behave p15_behave;
bool lane_control_support;
+ enum sdw_p15_behave p15_behave;
u32 master_count;
u32 source_ports;
u32 sink_ports;
- struct sdw_dp0_prop *dp0_prop;
- struct sdw_dpn_prop *src_dpn_prop;
- struct sdw_dpn_prop *sink_dpn_prop;
- u8 scp_int1_mask;
u32 quirks;
+ u32 sdca_interrupt_register_list;
+ u8 commit_register_supported;
+ u8 scp_int1_mask;
+ u8 lane_maps[SDW_MAX_LANES];
+ bool clock_reg_supported;
+ bool use_domain_irq;
};
#define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0)
/**
* struct sdw_master_prop - Master properties
+ * @clk_gears: Clock gears supported
+ * @clk_freq: Clock frequencies supported, in Hz
+ * @quirks: bitmask identifying optional behavior beyond the scope of the MIPI specification
* @revision: MIPI spec version of the implementation
* @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported
* @max_clk_freq: Maximum Bus clock frequency, in Hz
* @num_clk_gears: Number of clock gears supported
- * @clk_gears: Clock gears supported
* @num_clk_freq: Number of clock frequencies supported, in Hz
- * @clk_freq: Clock frequencies supported, in Hz
* @default_frame_rate: Controller default Frame rate, in Hz
* @default_row: Number of rows
* @default_col: Number of columns
@@ -405,24 +419,46 @@ struct sdw_slave_prop {
* @hw_disabled: if true, the Master is not functional, typically due to pin-mux
*/
struct sdw_master_prop {
+ u32 *clk_gears;
+ u32 *clk_freq;
+ u64 quirks;
u32 revision;
u32 clk_stop_modes;
u32 max_clk_freq;
u32 num_clk_gears;
- u32 *clk_gears;
u32 num_clk_freq;
- u32 *clk_freq;
u32 default_frame_rate;
u32 default_row;
u32 default_col;
- bool dynamic_frame;
u32 err_threshold;
u32 mclk_freq;
+ bool dynamic_frame;
bool hw_disabled;
};
+/* Definitions for Master quirks */
+
+/*
+ * In a number of platforms bus clashes are reported after a hardware
+ * reset but without any explanations or evidence of a real problem.
+ * The following quirk will discard all initial bus clash interrupts
+ * but will leave the detection on should real bus clashes happen
+ */
+#define SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH BIT(0)
+
+/*
+ * Some Slave devices have known issues with incorrect parity errors
+ * reported after a hardware reset. However during integration unexplained
+ * parity errors can be reported by Slave devices, possibly due to electrical
+ * issues at the Master level.
+ * The following quirk will discard all initial parity errors but will leave
+ * the detection on should real parity errors happen.
+ */
+#define SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY BIT(1)
+
int sdw_master_read_prop(struct sdw_bus *bus);
int sdw_slave_read_prop(struct sdw_slave *slave);
+int sdw_slave_read_lane_mapping(struct sdw_slave *slave);
/*
* SDW Slave Structures and APIs
@@ -448,6 +484,11 @@ struct sdw_slave_id {
__u8 sdw_version:4;
};
+struct sdw_peripherals {
+ int num_peripherals;
+ struct sdw_slave *array[];
+};
+
/*
* Helper macros to extract the MIPI-defined IDs
*
@@ -479,10 +520,12 @@ struct sdw_slave_id {
/**
* struct sdw_slave_intr_status - Slave interrupt status
+ * @sdca_cascade: set if the Slave device reports an SDCA interrupt
* @control_port: control port status
* @port: data port status
*/
struct sdw_slave_intr_status {
+ bool sdca_cascade;
u8 control_port;
u8 port[15];
};
@@ -498,21 +541,6 @@ enum sdw_reg_bank {
};
/**
- * struct sdw_bus_conf: Bus configuration
- *
- * @clk_freq: Clock frequency, in Hz
- * @num_rows: Number of rows in frame
- * @num_cols: Number of columns in frame
- * @bank: Next register bank
- */
-struct sdw_bus_conf {
- unsigned int clk_freq;
- unsigned int num_rows;
- unsigned int num_cols;
- unsigned int bank;
-};
-
-/**
* struct sdw_prepare_ch: Prepare/De-prepare Data Port channel
*
* @num: Port number
@@ -534,13 +562,15 @@ struct sdw_prepare_ch {
* enum sdw_port_prep_ops: Prepare operations for Data Port
*
* @SDW_OPS_PORT_PRE_PREP: Pre prepare operation for the Port
- * @SDW_OPS_PORT_PREP: Prepare operation for the Port
+ * @SDW_OPS_PORT_PRE_DEPREP: Pre deprepare operation for the Port
* @SDW_OPS_PORT_POST_PREP: Post prepare operation for the Port
+ * @SDW_OPS_PORT_POST_DEPREP: Post deprepare operation for the Port
*/
enum sdw_port_prep_ops {
SDW_OPS_PORT_PRE_PREP = 0,
- SDW_OPS_PORT_PREP = 1,
- SDW_OPS_PORT_POST_PREP = 2,
+ SDW_OPS_PORT_PRE_DEPREP,
+ SDW_OPS_PORT_POST_PREP,
+ SDW_OPS_PORT_POST_DEPREP,
};
/**
@@ -580,6 +610,7 @@ struct sdw_bus_params {
* @update_status: Update Slave status
* @bus_config: Update the bus config for Slave
* @port_prep: Prepare the port with parameters
+ * @clk_stop: handle imp-def sequences before and after prepare and de-prepare
*/
struct sdw_slave_ops {
int (*read_prop)(struct sdw_slave *sdw);
@@ -592,30 +623,27 @@ struct sdw_slave_ops {
int (*port_prep)(struct sdw_slave *slave,
struct sdw_prepare_ch *prepare_ch,
enum sdw_port_prep_ops pre_ops);
- int (*get_clk_stop_mode)(struct sdw_slave *slave);
int (*clk_stop)(struct sdw_slave *slave,
enum sdw_clk_stop_mode mode,
enum sdw_clk_stop_type type);
-
};
/**
* struct sdw_slave - SoundWire Slave
* @id: MIPI device ID
* @dev: Linux device
+ * @index: internal ID for this slave
+ * @irq: IRQ number
* @status: Status reported by the Slave
* @bus: Bus handle
- * @ops: Slave callback ops
* @prop: Slave properties
* @debugfs: Slave debugfs
* @node: node for bus list
* @port_ready: Port ready completion flag for each Slave port
+ * @m_port_map: static Master port map for each Slave port
* @dev_num: Current Device Number, values can be 0 or dev_num_sticky
* @dev_num_sticky: one-time static Device Number assigned by Bus
* @probed: boolean tracking driver state
- * @probe_complete: completion utility to control potential races
- * on startup between driver probe/initialization and SoundWire
- * Slave state changes/implementation-defined interrupts
* @enumeration_complete: completion utility to control potential races
* on startup between device enumeration and read/write access to the
* Slave device
@@ -628,28 +656,35 @@ struct sdw_slave_ops {
* initialized
* @first_interrupt_done: status flag tracking if the interrupt handling
* for a Slave happens for the first time after enumeration
+ * @is_mockup_device: status flag used to squelch errors in the command/control
+ * protocol for SoundWire mockup devices
+ * @sdw_dev_lock: mutex used to protect callbacks/remove races
+ * @sdca_data: structure containing all device data for SDCA helpers
*/
struct sdw_slave {
struct sdw_slave_id id;
struct device dev;
+ int index;
+ int irq;
enum sdw_slave_status status;
struct sdw_bus *bus;
- const struct sdw_slave_ops *ops;
struct sdw_slave_prop prop;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
#endif
struct list_head node;
struct completion port_ready[SDW_MAX_PORTS];
- enum sdw_clk_stop_mode curr_clk_stop_mode;
+ unsigned int m_port_map[SDW_MAX_PORTS];
u16 dev_num;
u16 dev_num_sticky;
bool probed;
- struct completion probe_complete;
struct completion enumeration_complete;
struct completion initialization_complete;
u32 unattach_request;
bool first_interrupt_done;
+ bool is_mockup_device;
+ struct mutex sdw_dev_lock; /* protect callbacks/remove races */
+ struct sdca_device_data sdca_data;
};
#define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev)
@@ -668,10 +703,7 @@ struct sdw_master_device {
container_of(d, struct sdw_master_device, dev)
struct sdw_driver {
- const char *name;
-
- int (*probe)(struct sdw_slave *sdw,
- const struct sdw_device_id *id);
+ int (*probe)(struct sdw_slave *sdw, const struct sdw_device_id *id);
int (*remove)(struct sdw_slave *sdw);
void (*shutdown)(struct sdw_slave *sdw);
@@ -690,7 +722,7 @@ struct sdw_driver {
SDW_SLAVE_ENTRY_EXT((_mfg_id), (_part_id), 0, 0, (_drv_data))
int sdw_handle_slave_status(struct sdw_bus *bus,
- enum sdw_slave_status status[]);
+ enum sdw_slave_status status[]);
/*
* SDW master structures and APIs
@@ -772,119 +804,85 @@ struct sdw_enable_ch {
*/
struct sdw_master_port_ops {
int (*dpn_set_port_params)(struct sdw_bus *bus,
- struct sdw_port_params *port_params,
- unsigned int bank);
+ struct sdw_port_params *port_params,
+ unsigned int bank);
int (*dpn_set_port_transport_params)(struct sdw_bus *bus,
- struct sdw_transport_params *transport_params,
- enum sdw_reg_bank bank);
- int (*dpn_port_prep)(struct sdw_bus *bus,
- struct sdw_prepare_ch *prepare_ch);
+ struct sdw_transport_params *transport_params,
+ enum sdw_reg_bank bank);
+ int (*dpn_port_prep)(struct sdw_bus *bus, struct sdw_prepare_ch *prepare_ch);
int (*dpn_port_enable_ch)(struct sdw_bus *bus,
- struct sdw_enable_ch *enable_ch, unsigned int bank);
+ struct sdw_enable_ch *enable_ch, unsigned int bank);
};
struct sdw_msg;
/**
- * struct sdw_defer - SDW deffered message
- * @length: message length
+ * struct sdw_defer - SDW deferred message
* @complete: message completion
* @msg: SDW message
+ * @length: message length
*/
struct sdw_defer {
+ struct sdw_msg *msg;
int length;
struct completion complete;
- struct sdw_msg *msg;
};
+/*
+ * Add a practical limit to BPT transfer sizes. BPT is typically used
+ * to transfer firmware, and larger firmware transfers will increase
+ * the cold latency beyond typical OS or user requirements.
+ */
+#define SDW_BPT_MSG_MAX_BYTES (1024 * 1024)
+
+struct sdw_bpt_msg;
+
/**
* struct sdw_master_ops - Master driver ops
* @read_prop: Read Master properties
+ * @override_adr: Override value read from firmware (quirk for buggy firmware)
* @xfer_msg: Transfer message callback
- * @xfer_msg_defer: Defer version of transfer message callback
- * @reset_page_addr: Reset the SCP page address registers
+ * @xfer_msg_defer: Defer version of transfer message callback. The message is handled with the
+ * bus struct @sdw_defer
* @set_bus_conf: Set the bus configuration
* @pre_bank_switch: Callback for pre bank switch
* @post_bank_switch: Callback for post bank switch
+ * @read_ping_status: Read status from PING frames, reported with two bits per Device.
+ * Bits 31:24 are reserved.
+ * @get_device_num: Callback for vendor-specific device_number allocation
+ * @put_device_num: Callback for vendor-specific device_number release
+ * @new_peripheral_assigned: Callback to handle enumeration of new peripheral.
+ * @bpt_send_async: reserve resources for BPT stream and send message
+ * using BTP protocol
+ * @bpt_wait: wait for message completion using BTP protocol
+ * and release resources
*/
struct sdw_master_ops {
int (*read_prop)(struct sdw_bus *bus);
-
- enum sdw_command_response (*xfer_msg)
- (struct sdw_bus *bus, struct sdw_msg *msg);
- enum sdw_command_response (*xfer_msg_defer)
- (struct sdw_bus *bus, struct sdw_msg *msg,
- struct sdw_defer *defer);
- enum sdw_command_response (*reset_page_addr)
- (struct sdw_bus *bus, unsigned int dev_num);
+ u64 (*override_adr)(struct sdw_bus *bus, u64 addr);
+ enum sdw_command_response (*xfer_msg)(struct sdw_bus *bus, struct sdw_msg *msg);
+ enum sdw_command_response (*xfer_msg_defer)(struct sdw_bus *bus);
int (*set_bus_conf)(struct sdw_bus *bus,
- struct sdw_bus_params *params);
+ struct sdw_bus_params *params);
int (*pre_bank_switch)(struct sdw_bus *bus);
int (*post_bank_switch)(struct sdw_bus *bus);
-
-};
-
-/**
- * struct sdw_bus - SoundWire bus
- * @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
- * @md: Master device
- * @link_id: Link id number, can be 0 to N, unique for each Master
- * @id: bus system-wide unique id
- * @slaves: list of Slaves on this bus
- * @assigned: Bitmap for Slave device numbers.
- * Bit set implies used number, bit clear implies unused number.
- * @bus_lock: bus lock
- * @msg_lock: message lock
- * @compute_params: points to Bus resource management implementation
- * @ops: Master callback ops
- * @port_ops: Master port callback ops
- * @params: Current bus parameters
- * @prop: Master properties
- * @m_rt_list: List of Master instance of all stream(s) running on Bus. This
- * is used to compute and program bus bandwidth, clock, frame shape,
- * transport and port parameters
- * @debugfs: Bus debugfs
- * @defer_msg: Defer message
- * @clk_stop_timeout: Clock stop timeout computed
- * @bank_switch_timeout: Bank switch timeout computed
- * @multi_link: Store bus property that indicates if multi links
- * are supported. This flag is populated by drivers after reading
- * appropriate firmware (ACPI/DT).
- * @hw_sync_min_links: Number of links used by a stream above which
- * hardware-based synchronization is required. This value is only
- * meaningful if multi_link is set. If set to 1, hardware-based
- * synchronization will be used even if a stream only uses a single
- * SoundWire segment.
- */
-struct sdw_bus {
- struct device *dev;
- struct sdw_master_device *md;
- unsigned int link_id;
- int id;
- struct list_head slaves;
- DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
- struct mutex bus_lock;
- struct mutex msg_lock;
- int (*compute_params)(struct sdw_bus *bus);
- const struct sdw_master_ops *ops;
- const struct sdw_master_port_ops *port_ops;
- struct sdw_bus_params params;
- struct sdw_master_prop prop;
- struct list_head m_rt_list;
-#ifdef CONFIG_DEBUG_FS
- struct dentry *debugfs;
-#endif
- struct sdw_defer defer_msg;
- unsigned int clk_stop_timeout;
- u32 bank_switch_timeout;
- bool multi_link;
- int hw_sync_min_links;
+ u32 (*read_ping_status)(struct sdw_bus *bus);
+ int (*get_device_num)(struct sdw_bus *bus, struct sdw_slave *slave);
+ void (*put_device_num)(struct sdw_bus *bus, struct sdw_slave *slave);
+ void (*new_peripheral_assigned)(struct sdw_bus *bus,
+ struct sdw_slave *slave,
+ int dev_num);
+ int (*bpt_send_async)(struct sdw_bus *bus, struct sdw_slave *slave,
+ struct sdw_bpt_msg *msg);
+ int (*bpt_wait)(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
};
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
struct fwnode_handle *fwnode);
void sdw_bus_master_delete(struct sdw_bus *bus);
+void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay);
+
/**
* sdw_port_config: Master or Slave Port configuration
*
@@ -903,7 +901,7 @@ struct sdw_port_config {
* @ch_count: Channel count of the stream
* @bps: Number of bits per audio sample
* @direction: Data direction
- * @type: Stream type PCM or PDM
+ * @type: Stream type PCM, PDM or BPT
*/
struct sdw_stream_config {
unsigned int frame_rate;
@@ -953,40 +951,113 @@ struct sdw_stream_params {
* @name: SoundWire stream name
* @params: Stream parameters
* @state: Current state of the stream
- * @type: Stream type PCM or PDM
+ * @type: Stream type PCM, PDM or BPT
+ * @m_rt_count: Count of Master runtime(s) in this stream
* @master_list: List of Master runtime(s) in this stream.
* master_list can contain only one m_rt per Master instance
* for a stream
- * @m_rt_count: Count of Master runtime(s) in this stream
*/
struct sdw_stream_runtime {
const char *name;
struct sdw_stream_params params;
enum sdw_stream_state state;
enum sdw_stream_type type;
- struct list_head master_list;
int m_rt_count;
+ struct list_head master_list;
+};
+
+/**
+ * struct sdw_bus - SoundWire bus
+ * @dev: Shortcut to &bus->md->dev to avoid changing the entire code.
+ * @md: Master device
+ * @bus_lock_key: bus lock key associated to @bus_lock
+ * @bus_lock: bus lock
+ * @slave_ida: IDA for allocating internal slave IDs
+ * @slaves: list of Slaves on this bus
+ * @msg_lock_key: message lock key associated to @msg_lock
+ * @msg_lock: message lock
+ * @m_rt_list: List of Master instance of all stream(s) running on Bus. This
+ * is used to compute and program bus bandwidth, clock, frame shape,
+ * transport and port parameters
+ * @defer_msg: Defer message
+ * @params: Current bus parameters
+ * @stream_refcount: number of streams currently using this bus
+ * @btp_stream_refcount: number of BTP streams currently using this bus (should
+ * be zero or one, multiple streams per link is not supported).
+ * @bpt_stream: pointer stored to handle BTP streams.
+ * @ops: Master callback ops
+ * @port_ops: Master port callback ops
+ * @prop: Master properties
+ * @vendor_specific_prop: pointer to non-standard properties
+ * @hw_sync_min_links: Number of links used by a stream above which
+ * hardware-based synchronization is required. This value is only
+ * meaningful if multi_link is set. If set to 1, hardware-based
+ * synchronization will be used even if a stream only uses a single
+ * SoundWire segment.
+ * @controller_id: system-unique controller ID. If set to -1, the bus @id will be used.
+ * @link_id: Link id number, can be 0 to N, unique for each Controller
+ * @id: bus system-wide unique id
+ * @compute_params: points to Bus resource management implementation
+ * @assigned: Bitmap for Slave device numbers.
+ * Bit set implies used number, bit clear implies unused number.
+ * @clk_stop_timeout: Clock stop timeout computed
+ * @bank_switch_timeout: Bank switch timeout computed
+ * @domain: IRQ domain
+ * @irq_chip: IRQ chip
+ * @debugfs: Bus debugfs (optional)
+ * @multi_link: Store bus property that indicates if multi links
+ * are supported. This flag is populated by drivers after reading
+ * appropriate firmware (ACPI/DT).
+ * @lane_used_bandwidth: how much bandwidth in bits per second is used by each lane
+ */
+struct sdw_bus {
+ struct device *dev;
+ struct sdw_master_device *md;
+ struct lock_class_key bus_lock_key;
+ struct mutex bus_lock;
+ struct ida slave_ida;
+ struct list_head slaves;
+ struct lock_class_key msg_lock_key;
+ struct mutex msg_lock;
+ struct list_head m_rt_list;
+ struct sdw_defer defer_msg;
+ struct sdw_bus_params params;
+ int stream_refcount;
+ int bpt_stream_refcount;
+ struct sdw_stream_runtime *bpt_stream;
+ const struct sdw_master_ops *ops;
+ const struct sdw_master_port_ops *port_ops;
+ struct sdw_master_prop prop;
+ void *vendor_specific_prop;
+ int hw_sync_min_links;
+ int controller_id;
+ unsigned int link_id;
+ int id;
+ int (*compute_params)(struct sdw_bus *bus, struct sdw_stream_runtime *stream);
+ DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
+ unsigned int clk_stop_timeout;
+ u32 bank_switch_timeout;
+ struct irq_chip irq_chip;
+ struct irq_domain *domain;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs;
+#endif
+ bool multi_link;
+ unsigned int lane_used_bandwidth[SDW_MAX_LANES];
};
-struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name);
+struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name, enum sdw_stream_type type);
void sdw_release_stream(struct sdw_stream_runtime *stream);
-int sdw_compute_params(struct sdw_bus *bus);
+int sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream);
int sdw_stream_add_master(struct sdw_bus *bus,
- struct sdw_stream_config *stream_config,
- struct sdw_port_config *port_config,
- unsigned int num_ports,
- struct sdw_stream_runtime *stream);
-int sdw_stream_add_slave(struct sdw_slave *slave,
- struct sdw_stream_config *stream_config,
- struct sdw_port_config *port_config,
- unsigned int num_ports,
- struct sdw_stream_runtime *stream);
+ struct sdw_stream_config *stream_config,
+ const struct sdw_port_config *port_config,
+ unsigned int num_ports,
+ struct sdw_stream_runtime *stream);
int sdw_stream_remove_master(struct sdw_bus *bus,
- struct sdw_stream_runtime *stream);
-int sdw_stream_remove_slave(struct sdw_slave *slave,
- struct sdw_stream_runtime *stream);
+ struct sdw_stream_runtime *stream);
int sdw_startup_stream(void *sdw_substream);
int sdw_prepare_stream(struct sdw_stream_runtime *stream);
int sdw_enable_stream(struct sdw_stream_runtime *stream);
@@ -997,11 +1068,118 @@ int sdw_bus_prep_clk_stop(struct sdw_bus *bus);
int sdw_bus_clk_stop(struct sdw_bus *bus);
int sdw_bus_exit_clk_stop(struct sdw_bus *bus);
-/* messaging and data APIs */
+int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
+void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id);
+bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave);
+int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
+int sdw_bpt_wait(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
+int sdw_bpt_send_sync(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
+
+#if IS_ENABLED(CONFIG_SOUNDWIRE)
+
+int sdw_stream_add_slave(struct sdw_slave *slave,
+ struct sdw_stream_config *stream_config,
+ const struct sdw_port_config *port_config,
+ unsigned int num_ports,
+ struct sdw_stream_runtime *stream);
+int sdw_stream_remove_slave(struct sdw_slave *slave,
+ struct sdw_stream_runtime *stream);
+
+int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base);
+
+/* messaging and data APIs */
int sdw_read(struct sdw_slave *slave, u32 addr);
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
+int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value);
+int sdw_read_no_pm(struct sdw_slave *slave, u32 addr);
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
-int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
+int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
+int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val);
+int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val);
+int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val);
+int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val);
+
+#else
+
+static inline int sdw_stream_add_slave(struct sdw_slave *slave,
+ struct sdw_stream_config *stream_config,
+ const struct sdw_port_config *port_config,
+ unsigned int num_ports,
+ struct sdw_stream_runtime *stream)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_stream_remove_slave(struct sdw_slave *slave,
+ struct sdw_stream_runtime *stream)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+/* messaging and data APIs */
+static inline int sdw_read(struct sdw_slave *slave, u32 addr)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_write(struct sdw_slave *slave, u32 addr, u8 value)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+static inline int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
+{
+ WARN_ONCE(1, "SoundWire API is disabled");
+ return -EINVAL;
+}
+
+#endif /* CONFIG_SOUNDWIRE */
#endif /* __SOUNDWIRE_H */
diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
new file mode 100644
index 000000000000..6b839987f14c
--- /dev/null
+++ b/include/linux/soundwire/sdw_amd.h
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/*
+ * Copyright (C) 2023-24 Advanced Micro Devices, Inc. All rights reserved.
+ */
+
+#ifndef __SDW_AMD_H
+#define __SDW_AMD_H
+
+#include <linux/acpi.h>
+#include <linux/soundwire/sdw.h>
+
+/* AMD pm_runtime quirk definitions */
+
+/*
+ * Force the clock to stop(ClockStopMode0) when suspend callback
+ * is invoked.
+ */
+#define AMD_SDW_CLK_STOP_MODE 1
+
+/*
+ * Stop the bus when runtime suspend/system level suspend callback
+ * is invoked. If set, a complete bus reset and re-enumeration will
+ * be performed when the bus restarts. In-band wake interrupts are
+ * not supported in this mode.
+ */
+#define AMD_SDW_POWER_OFF_MODE 2
+#define ACP_SDW0 0
+#define ACP_SDW1 1
+#define AMD_SDW_MAX_MANAGER_COUNT 2
+#define ACP63_PCI_REV_ID 0x63
+#define ACP70_PCI_REV_ID 0x70
+#define ACP71_PCI_REV_ID 0x71
+
+struct acp_sdw_pdata {
+ u16 instance;
+ u32 acp_rev;
+ /* mutex to protect acp common register access */
+ struct mutex *acp_sdw_lock;
+};
+
+/**
+ * struct sdw_amd_dai_runtime: AMD sdw dai runtime data
+ *
+ * @name: SoundWire stream name
+ * @stream: stream runtime
+ * @bus: Bus handle
+ * @stream_type: Stream type
+ */
+struct sdw_amd_dai_runtime {
+ char *name;
+ struct sdw_stream_runtime *stream;
+ struct sdw_bus *bus;
+ enum sdw_stream_type stream_type;
+};
+
+/**
+ * struct amd_sdw_manager - amd manager driver context
+ * @bus: bus handle
+ * @dev: linux device
+ * @mmio: SoundWire registers mmio base
+ * @acp_mmio: acp registers mmio base
+ * @amd_sdw_irq_thread: SoundWire manager irq workqueue
+ * @amd_sdw_work: peripheral status work queue
+ * @acp_sdw_lock: mutex to protect acp share register access
+ * @status: peripheral devices status array
+ * @num_din_ports: number of input ports
+ * @num_dout_ports: number of output ports
+ * @cols_index: Column index in frame shape
+ * @rows_index: Rows index in frame shape
+ * @instance: SoundWire manager instance
+ * @quirks: SoundWire manager quirks
+ * @wake_en_mask: wake enable mask per SoundWire manager
+ * @acp_rev: acp pci device revision id
+ * @clk_stopped: flag set to true when clock is stopped
+ * @power_mode_mask: flag interprets amd SoundWire manager power mode
+ * @dai_runtime_array: dai runtime array
+ */
+struct amd_sdw_manager {
+ struct sdw_bus bus;
+ struct device *dev;
+
+ void __iomem *mmio;
+ void __iomem *acp_mmio;
+
+ struct work_struct amd_sdw_irq_thread;
+ struct work_struct amd_sdw_work;
+ /* mutex to protect acp common register access */
+ struct mutex *acp_sdw_lock;
+
+ enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
+
+ int num_din_ports;
+ int num_dout_ports;
+
+ int cols_index;
+ int rows_index;
+
+ u32 instance;
+ u32 quirks;
+ u32 wake_en_mask;
+ u32 power_mode_mask;
+ u32 acp_rev;
+ bool clk_stopped;
+
+ struct sdw_amd_dai_runtime **dai_runtime_array;
+};
+
+/**
+ * struct sdw_amd_acpi_info - Soundwire AMD information found in ACPI tables
+ * @handle: ACPI controller handle
+ * @count: maximum no of soundwire manager links supported on AMD platform.
+ * @link_mask: bit-wise mask listing links enabled by BIOS menu
+ */
+struct sdw_amd_acpi_info {
+ acpi_handle handle;
+ int count;
+ u32 link_mask;
+};
+
+/**
+ * struct sdw_amd_ctx - context allocated by the controller driver probe
+ *
+ * @count: link count
+ * @link_mask: bit-wise mask listing SoundWire links reported by the
+ * Controller
+ * @pdev: platform device structure
+ * @peripherals: array representing Peripherals exposed across all enabled links
+ */
+struct sdw_amd_ctx {
+ int count;
+ u32 link_mask;
+ struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT];
+ struct sdw_peripherals *peripherals;
+};
+
+/**
+ * struct sdw_amd_res - Soundwire AMD global resource structure,
+ * typically populated by the DSP driver/Legacy driver
+ *
+ * @acp_rev: acp pci device revision id
+ * @addr: acp pci device resource start address
+ * @reg_range: ACP register range
+ * @link_mask: bit-wise mask listing links selected by the DSP driver/
+ * legacy driver
+ * @count: link count
+ * @mmio_base: mmio base of SoundWire registers
+ * @handle: ACPI parent handle
+ * @parent: parent device
+ * @dev: device implementing hwparams and free callbacks
+ * @acp_lock: mutex protecting acp common registers access
+ */
+struct sdw_amd_res {
+ u32 acp_rev;
+ u32 addr;
+ u32 reg_range;
+ u32 link_mask;
+ int count;
+ void __iomem *mmio_base;
+ acpi_handle handle;
+ struct device *parent;
+ struct device *dev;
+ /* use to protect acp common registers access */
+ struct mutex *acp_lock;
+};
+
+int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **ctx);
+
+void sdw_amd_exit(struct sdw_amd_ctx *ctx);
+
+int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx);
+
+int amd_sdw_scan_controller(struct sdw_amd_acpi_info *info);
+#endif
diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h
index 120ffddc03d2..9c9435009537 100644
--- a/include/linux/soundwire/sdw_intel.h
+++ b/include/linux/soundwire/sdw_intel.h
@@ -4,9 +4,194 @@
#ifndef __SDW_INTEL_H
#define __SDW_INTEL_H
+#include <linux/acpi.h>
#include <linux/irqreturn.h>
#include <linux/soundwire/sdw.h>
+/*********************************************************************
+ * cAVS and ACE1.x definitions
+ *********************************************************************/
+
+#define SDW_SHIM_BASE 0x2C000
+#define SDW_ALH_BASE 0x2C800
+#define SDW_SHIM_BASE_ACE 0x38000
+#define SDW_ALH_BASE_ACE 0x24000
+#define SDW_LINK_BASE 0x30000
+#define SDW_LINK_SIZE 0x10000
+
+/* Intel SHIM Registers Definition */
+/* LCAP */
+#define SDW_SHIM_LCAP 0x0
+#define SDW_SHIM_LCAP_LCOUNT_MASK GENMASK(2, 0)
+#define SDW_SHIM_LCAP_MLCS_MASK BIT(8)
+
+/* LCTL */
+#define SDW_SHIM_LCTL 0x4
+
+#define SDW_SHIM_LCTL_SPA BIT(0)
+#define SDW_SHIM_LCTL_SPA_MASK GENMASK(3, 0)
+#define SDW_SHIM_LCTL_CPA BIT(8)
+#define SDW_SHIM_LCTL_CPA_MASK GENMASK(11, 8)
+#define SDW_SHIM_LCTL_MLCS_MASK GENMASK(29, 27)
+#define SDW_SHIM_MLCS_XTAL_CLK 0x0
+#define SDW_SHIM_MLCS_CARDINAL_CLK 0x1
+#define SDW_SHIM_MLCS_AUDIO_PLL_CLK 0x2
+
+/* SYNC */
+#define SDW_SHIM_SYNC 0xC
+
+#define SDW_SHIM_SYNC_SYNCPRD_VAL_24 (24000 / SDW_CADENCE_GSYNC_KHZ - 1)
+#define SDW_SHIM_SYNC_SYNCPRD_VAL_24_576 (24576 / SDW_CADENCE_GSYNC_KHZ - 1)
+#define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4 (38400 / SDW_CADENCE_GSYNC_KHZ - 1)
+#define SDW_SHIM_SYNC_SYNCPRD_VAL_96 (96000 / SDW_CADENCE_GSYNC_KHZ - 1)
+#define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0)
+#define SDW_SHIM_SYNC_SYNCCPU BIT(15)
+#define SDW_SHIM_SYNC_CMDSYNC_MASK GENMASK(19, 16)
+#define SDW_SHIM_SYNC_CMDSYNC BIT(16)
+#define SDW_SHIM_SYNC_SYNCGO BIT(24)
+
+/* Control stream capabililities and channel mask */
+#define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * (x))
+#define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * (x))
+#define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * (x))
+#define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * (x))
+#define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * (x))
+
+/* PCM Stream capabilities */
+#define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * (x))
+
+#define SDW_SHIM_PCMSCAP_ISS GENMASK(3, 0)
+#define SDW_SHIM_PCMSCAP_OSS GENMASK(7, 4)
+#define SDW_SHIM_PCMSCAP_BSS GENMASK(12, 8)
+
+/* PCM Stream Channel Map */
+#define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * (x)) + (0x2 * (y)))
+
+/* PCM Stream Channel Count */
+#define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * (x)) + (0x2 * (y)))
+
+#define SDW_SHIM_PCMSYCM_LCHN GENMASK(3, 0)
+#define SDW_SHIM_PCMSYCM_HCHN GENMASK(7, 4)
+#define SDW_SHIM_PCMSYCM_STREAM GENMASK(13, 8)
+#define SDW_SHIM_PCMSYCM_DIR BIT(15)
+
+/* IO control */
+#define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * (x))
+
+#define SDW_SHIM_IOCTL_MIF BIT(0)
+#define SDW_SHIM_IOCTL_CO BIT(1)
+#define SDW_SHIM_IOCTL_COE BIT(2)
+#define SDW_SHIM_IOCTL_DO BIT(3)
+#define SDW_SHIM_IOCTL_DOE BIT(4)
+#define SDW_SHIM_IOCTL_BKE BIT(5)
+#define SDW_SHIM_IOCTL_WPDD BIT(6)
+#define SDW_SHIM_IOCTL_CIBD BIT(8)
+#define SDW_SHIM_IOCTL_DIBD BIT(9)
+
+/* Wake Enable*/
+#define SDW_SHIM_WAKEEN 0x190
+
+#define SDW_SHIM_WAKEEN_ENABLE BIT(0)
+
+/* Wake Status */
+#define SDW_SHIM_WAKESTS 0x192
+
+#define SDW_SHIM_WAKESTS_STATUS BIT(0)
+
+/* AC Timing control */
+#define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * (x))
+
+#define SDW_SHIM_CTMCTL_DACTQE BIT(0)
+#define SDW_SHIM_CTMCTL_DODS BIT(1)
+#define SDW_SHIM_CTMCTL_DOAIS GENMASK(4, 3)
+
+/* Intel ALH Register definitions */
+#define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x)))
+#define SDW_ALH_NUM_STREAMS 64
+
+#define SDW_ALH_STRMZCFG_DMAT_VAL 0x3
+#define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0)
+#define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16)
+
+/*********************************************************************
+ * ACE2.x definitions for SHIM registers - only accessible when the
+ * HDAudio extended link LCTL.SPA/CPA = 1.
+ *********************************************************************/
+/* x variable is link index */
+#define SDW_SHIM2_GENERIC_BASE(x) (0x00030000 + 0x8000 * (x))
+#define SDW_IP_BASE(x) (0x00030100 + 0x8000 * (x))
+#define SDW_SHIM2_VS_BASE(x) (0x00036000 + 0x8000 * (x))
+
+/* SHIM2 Generic Registers */
+/* Read-only capabilities */
+#define SDW_SHIM2_LECAP 0x00
+#define SDW_SHIM2_LECAP_HDS BIT(0) /* unset -> Host mode */
+#define SDW_SHIM2_LECAP_MLC GENMASK(3, 1) /* Number of Lanes */
+
+/* PCM Stream capabilities */
+#define SDW_SHIM2_PCMSCAP 0x10
+#define SDW_SHIM2_PCMSCAP_ISS GENMASK(3, 0) /* Input-only streams */
+#define SDW_SHIM2_PCMSCAP_OSS GENMASK(7, 4) /* Output-only streams */
+#define SDW_SHIM2_PCMSCAP_BSS GENMASK(12, 8) /* Bidirectional streams */
+
+/* Read-only PCM Stream Channel Count, y variable is stream */
+#define SDW_SHIM2_PCMSYCHC(y) (0x14 + (0x4 * (y)))
+#define SDW_SHIM2_PCMSYCHC_CS GENMASK(3, 0) /* Channels Supported */
+
+/* PCM Stream Channel Map */
+#define SDW_SHIM2_PCMSYCHM(y) (0x16 + (0x4 * (y)))
+#define SDW_SHIM2_PCMSYCHM_LCHAN GENMASK(3, 0) /* Lowest channel used by the FIFO port */
+#define SDW_SHIM2_PCMSYCHM_HCHAN GENMASK(7, 4) /* Lowest channel used by the FIFO port */
+#define SDW_SHIM2_PCMSYCHM_STRM GENMASK(13, 8) /* HDaudio stream tag */
+#define SDW_SHIM2_PCMSYCHM_DIR BIT(15) /* HDaudio stream direction */
+
+/* SHIM2 vendor-specific registers */
+#define SDW_SHIM2_INTEL_VS_LVSCTL 0x04
+#define SDW_SHIM2_INTEL_VS_LVSCTL_FCG BIT(26)
+#define SDW_SHIM2_INTEL_VS_LVSCTL_MLCS GENMASK(29, 27)
+#define SDW_SHIM2_INTEL_VS_LVSCTL_DCGD BIT(30)
+#define SDW_SHIM2_INTEL_VS_LVSCTL_ICGD BIT(31)
+
+#define SDW_SHIM2_MLCS_XTAL_CLK 0x0
+#define SDW_SHIM2_MLCS_CARDINAL_CLK 0x1
+#define SDW_SHIM2_MLCS_AUDIO_PLL_CLK 0x2
+#define SDW_SHIM2_MLCS_MCLK_INPUT_CLK 0x3
+#define SDW_SHIM2_MLCS_WOV_RING_OSC_CLK 0x4
+
+#define SDW_SHIM2_INTEL_VS_WAKEEN 0x08
+#define SDW_SHIM2_INTEL_VS_WAKEEN_PWE BIT(0)
+
+#define SDW_SHIM2_INTEL_VS_WAKESTS 0x0A
+#define SDW_SHIM2_INTEL_VS_WAKEEN_PWS BIT(0)
+
+#define SDW_SHIM2_INTEL_VS_IOCTL 0x0C
+#define SDW_SHIM2_INTEL_VS_IOCTL_MIF BIT(0)
+#define SDW_SHIM2_INTEL_VS_IOCTL_CO BIT(1)
+#define SDW_SHIM2_INTEL_VS_IOCTL_COE BIT(2)
+#define SDW_SHIM2_INTEL_VS_IOCTL_DO BIT(3)
+#define SDW_SHIM2_INTEL_VS_IOCTL_DOE BIT(4)
+#define SDW_SHIM2_INTEL_VS_IOCTL_BKE BIT(5)
+#define SDW_SHIM2_INTEL_VS_IOCTL_WPDD BIT(6)
+#define SDW_SHIM2_INTEL_VS_IOCTL_ODC BIT(7)
+#define SDW_SHIM2_INTEL_VS_IOCTL_CIBD BIT(8)
+#define SDW_SHIM2_INTEL_VS_IOCTL_DIBD BIT(9)
+#define SDW_SHIM2_INTEL_VS_IOCTL_HAMIFD BIT(10)
+
+#define SDW_SHIM2_INTEL_VS_ACTMCTL 0x0E
+#define SDW_SHIM2_INTEL_VS_ACTMCTL_DACTQE BIT(0)
+#define SDW_SHIM2_INTEL_VS_ACTMCTL_DODS BIT(1)
+#define SDW_SHIM2_INTEL_VS_ACTMCTL_DODSE BIT(2)
+#define SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS GENMASK(4, 3)
+#define SDW_SHIM2_INTEL_VS_ACTMCTL_DOAISE BIT(5)
+#define SDW_SHIM3_INTEL_VS_ACTMCTL_CLSS BIT(6)
+#define SDW_SHIM3_INTEL_VS_ACTMCTL_CLDS GENMASK(11, 7)
+#define SDW_SHIM3_INTEL_VS_ACTMCTL_DODSE2 GENMASK(13, 12)
+#define SDW_SHIM3_INTEL_VS_ACTMCTL_DOAISE2 BIT(14)
+#define SDW_SHIM3_INTEL_VS_ACTMCTL_CLDE BIT(15)
+
+/* ACE3+ Mic privacy control and status register */
+#define SDW_SHIM2_INTEL_VS_PVCCS 0x10
+
/**
* struct sdw_intel_stream_params_data: configuration passed during
* the @params_stream callback, e.g. for interaction with DSP
@@ -40,12 +225,13 @@ struct sdw_intel_ops {
struct sdw_intel_stream_params_data *params_data);
int (*free_stream)(struct device *dev,
struct sdw_intel_stream_free_data *free_data);
+ int (*trigger)(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai);
};
/**
* struct sdw_intel_acpi_info - Soundwire Intel information found in ACPI tables
* @handle: ACPI controller handle
- * @count: link count found with "sdw-master-count" property
+ * @count: link count found with "sdw-master-count" or "sdw-manager-list" property
* @link_mask: bit-wise mask listing links enabled by BIOS menu
*
* this structure could be expanded to e.g. provide all the _ADR
@@ -58,7 +244,7 @@ struct sdw_intel_acpi_info {
u32 link_mask;
};
-struct sdw_intel_link_res;
+struct sdw_intel_link_dev;
/* Intel clock-stop/pm_runtime quirk definitions */
@@ -94,10 +280,7 @@ struct sdw_intel_link_res;
*/
#define SDW_INTEL_CLK_STOP_BUS_RESET BIT(3)
-struct sdw_intel_slave_id {
- int link_id;
- struct sdw_slave_id id;
-};
+struct hdac_bus;
/**
* struct sdw_intel_ctx - context allocated by the controller
@@ -107,33 +290,35 @@ struct sdw_intel_slave_id {
* hardware capabilities after all power dependencies are settled.
* @link_mask: bit-wise mask listing SoundWire links reported by the
* Controller
- * @num_slaves: total number of devices exposed across all enabled links
* @handle: ACPI parent handle
- * @links: information for each link (controller-specific and kept
+ * @ldev: information for each link (controller-specific and kept
* opaque here)
- * @ids: array of slave_id, representing Slaves exposed across all enabled
- * links
* @link_list: list to handle interrupts across all links
* @shim_lock: mutex to handle concurrent rmw access to shared SHIM registers.
* @shim_mask: flags to track initialization of SHIM shared registers
+ * @shim_base: sdw shim base.
+ * @alh_base: sdw alh base.
+ * @peripherals: array representing Peripherals exposed across all enabled links
*/
struct sdw_intel_ctx {
int count;
void __iomem *mmio_base;
u32 link_mask;
- int num_slaves;
acpi_handle handle;
- struct sdw_intel_link_res *links;
- struct sdw_intel_slave_id *ids;
+ struct sdw_intel_link_dev **ldev;
struct list_head link_list;
struct mutex shim_lock; /* lock for access to shared SHIM registers */
u32 shim_mask;
+ u32 shim_base;
+ u32 alh_base;
+ struct sdw_peripherals *peripherals;
};
/**
* struct sdw_intel_res - Soundwire Intel global resource structure,
* typically populated by the DSP driver
*
+ * @hw_ops: abstraction for platform ops
* @count: link count
* @mmio_base: mmio base of SoundWire registers
* @irq: interrupt number
@@ -146,8 +331,16 @@ struct sdw_intel_ctx {
* machine-specific quirks are handled in the DSP driver.
* @clock_stop_quirks: mask array of possible behaviors requested by the
* DSP driver. The quirks are common for all links for now.
+ * @shim_base: sdw shim base.
+ * @alh_base: sdw alh base.
+ * @ext: extended HDaudio link support
+ * @mic_privacy: ACE version supports microphone privacy
+ * @hbus: hdac_bus pointer, needed for power management
+ * @eml_lock: mutex protecting shared registers in the HDaudio multi-link
+ * space
*/
struct sdw_intel_res {
+ const struct sdw_intel_hw_ops *hw_ops;
int count;
void __iomem *mmio_base;
int irq;
@@ -157,6 +350,12 @@ struct sdw_intel_res {
struct device *dev;
u32 link_mask;
u32 clock_stop_quirks;
+ u32 shim_base;
+ u32 alh_base;
+ bool ext;
+ bool mic_privacy;
+ struct hdac_bus *hbus;
+ struct mutex *eml_lock;
};
/*
@@ -171,7 +370,7 @@ struct sdw_intel_res {
* on e.g. which machine driver to select (I2S mode, HDaudio or
* SoundWire).
*/
-int sdw_intel_acpi_scan(acpi_handle *parent_handle,
+int sdw_intel_acpi_scan(acpi_handle parent_handle,
struct sdw_intel_acpi_info *info);
void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx);
@@ -183,8 +382,84 @@ int sdw_intel_startup(struct sdw_intel_ctx *ctx);
void sdw_intel_exit(struct sdw_intel_ctx *ctx);
-void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable);
-
irqreturn_t sdw_intel_thread(int irq, void *dev_id);
+#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1)
+
+struct sdw_intel;
+
+/* struct intel_sdw_hw_ops - SoundWire ops for Intel platforms.
+ * @debugfs_init: initialize all debugfs capabilities
+ * @debugfs_exit: close and cleanup debugfs capabilities
+ * @get_link_count: fetch link count from hardware registers
+ * @register_dai: read all PDI information and register DAIs
+ * @check_clock_stop: throw error message if clock is not stopped.
+ * @start_bus: normal start
+ * @start_bus_after_reset: start after reset
+ * @start_bus_after_clock_stop: start after mode0 clock stop
+ * @stop_bus: stop all bus
+ * @link_power_up: power-up using chip-specific helpers
+ * @link_power_down: power-down with chip-specific helpers
+ * @shim_check_wake: check if a wake was received
+ * @shim_wake: enable/disable in-band wake management
+ * @pre_bank_switch: helper for bus management
+ * @post_bank_switch: helper for bus management
+ * @sync_arm: helper for multi-link synchronization
+ * @sync_go_unlocked: helper for multi-link synchronization -
+ * shim_lock is assumed to be locked at higher level
+ * @sync_go: helper for multi-link synchronization
+ * @sync_check_cmdsync_unlocked: helper for multi-link synchronization
+ * and bank switch - shim_lock is assumed to be locked at higher level
+ * @program_sdi: helper for codec command/control based on dev_num
+ */
+struct sdw_intel_hw_ops {
+ void (*debugfs_init)(struct sdw_intel *sdw);
+ void (*debugfs_exit)(struct sdw_intel *sdw);
+
+ int (*get_link_count)(struct sdw_intel *sdw);
+
+ int (*register_dai)(struct sdw_intel *sdw);
+
+ void (*check_clock_stop)(struct sdw_intel *sdw);
+ int (*start_bus)(struct sdw_intel *sdw);
+ int (*start_bus_after_reset)(struct sdw_intel *sdw);
+ int (*start_bus_after_clock_stop)(struct sdw_intel *sdw);
+ int (*stop_bus)(struct sdw_intel *sdw, bool clock_stop);
+
+ int (*link_power_up)(struct sdw_intel *sdw);
+ int (*link_power_down)(struct sdw_intel *sdw);
+
+ int (*shim_check_wake)(struct sdw_intel *sdw);
+ void (*shim_wake)(struct sdw_intel *sdw, bool wake_enable);
+
+ int (*pre_bank_switch)(struct sdw_intel *sdw);
+ int (*post_bank_switch)(struct sdw_intel *sdw);
+
+ void (*sync_arm)(struct sdw_intel *sdw);
+ int (*sync_go_unlocked)(struct sdw_intel *sdw);
+ int (*sync_go)(struct sdw_intel *sdw);
+ bool (*sync_check_cmdsync_unlocked)(struct sdw_intel *sdw);
+
+ void (*program_sdi)(struct sdw_intel *sdw, int dev_num);
+
+ int (*bpt_send_async)(struct sdw_intel *sdw, struct sdw_slave *slave,
+ struct sdw_bpt_msg *msg);
+ int (*bpt_wait)(struct sdw_intel *sdw, struct sdw_slave *slave, struct sdw_bpt_msg *msg);
+};
+
+extern const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops;
+extern const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops;
+
+/*
+ * IDA min selected to allow for 5 unconstrained devices per link,
+ * and 6 system-unique Device Numbers for wake-capable devices.
+ */
+
+#define SDW_INTEL_DEV_NUM_IDA_MIN 6
+
+/*
+ * Max number of links supported in hardware
+ */
+#define SDW_INTEL_MAX_LINKS 5
+
#endif
diff --git a/include/linux/soundwire/sdw_registers.h b/include/linux/soundwire/sdw_registers.h
index f420e8059779..0a5939285583 100644
--- a/include/linux/soundwire/sdw_registers.h
+++ b/include/linux/soundwire/sdw_registers.h
@@ -4,6 +4,9 @@
#ifndef __SDW_REGISTERS_H
#define __SDW_REGISTERS_H
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+
/*
* SDW registers as defined by MIPI 1.2 Spec
*/
@@ -13,7 +16,7 @@
#define SDW_REG_NO_PAGE 0x00008000
#define SDW_REG_OPTIONAL_PAGE 0x00010000
-#define SDW_REG_MAX 0x80000000
+#define SDW_REG_MAX 0x48000000
#define SDW_DPN_SIZE 0x100
#define SDW_BANK1_OFFSET 0x10
@@ -41,6 +44,12 @@
#define SDW_DP0_INT_IMPDEF1 BIT(5)
#define SDW_DP0_INT_IMPDEF2 BIT(6)
#define SDW_DP0_INT_IMPDEF3 BIT(7)
+#define SDW_DP0_INTERRUPTS (SDW_DP0_INT_TEST_FAIL | \
+ SDW_DP0_INT_PORT_READY | \
+ SDW_DP0_INT_BRA_FAILURE | \
+ SDW_DP0_INT_IMPDEF1 | \
+ SDW_DP0_INT_IMPDEF2 | \
+ SDW_DP0_INT_IMPDEF3)
#define SDW_DP0_PORTCTRL_DATAMODE GENMASK(3, 2)
#define SDW_DP0_PORTCTRL_NXTINVBANK BIT(4)
@@ -241,6 +250,11 @@
#define SDW_DPN_INT_IMPDEF1 BIT(5)
#define SDW_DPN_INT_IMPDEF2 BIT(6)
#define SDW_DPN_INT_IMPDEF3 BIT(7)
+#define SDW_DPN_INTERRUPTS (SDW_DPN_INT_TEST_FAIL | \
+ SDW_DPN_INT_PORT_READY | \
+ SDW_DPN_INT_IMPDEF1 | \
+ SDW_DPN_INT_IMPDEF2 | \
+ SDW_DPN_INT_IMPDEF3)
#define SDW_DPN_PORTCTRL_FLOWMODE GENMASK(1, 0)
#define SDW_DPN_PORTCTRL_DATAMODE GENMASK(3, 2)
@@ -298,4 +312,47 @@
#define SDW_CASC_PORT_MASK_INTSTAT3 1
#define SDW_CASC_PORT_REG_OFFSET_INTSTAT3 2
+/*
+ * v1.2 device - SDCA address mapping
+ *
+ * Spec definition
+ * Bits Contents
+ * 31 0 (required by addressing range)
+ * 30:26 0b10000 (Control Prefix)
+ * 25 0 (Reserved)
+ * 24:22 Function Number [2:0]
+ * 21 Entity[6]
+ * 20:19 Control Selector[5:4]
+ * 18 0 (Reserved)
+ * 17:15 Control Number[5:3]
+ * 14 Next
+ * 13 MBQ
+ * 12:7 Entity[5:0]
+ * 6:3 Control Selector[3:0]
+ * 2:0 Control Number[2:0]
+ */
+
+#define SDW_SDCA_CTL(fun, ent, ctl, ch) (BIT(30) | \
+ (((fun) & GENMASK(2, 0)) << 22) | \
+ (((ent) & BIT(6)) << 15) | \
+ (((ent) & GENMASK(5, 0)) << 7) | \
+ (((ctl) & GENMASK(5, 4)) << 15) | \
+ (((ctl) & GENMASK(3, 0)) << 3) | \
+ (((ch) & GENMASK(5, 3)) << 12) | \
+ ((ch) & GENMASK(2, 0)))
+
+#define SDW_SDCA_CTL_FUNC(reg) FIELD_GET(GENMASK(24, 22), (reg))
+#define SDW_SDCA_CTL_ENT(reg) ((FIELD_GET(BIT(21), (reg)) << 6) | \
+ FIELD_GET(GENMASK(12, 7), (reg)))
+#define SDW_SDCA_CTL_CSEL(reg) ((FIELD_GET(GENMASK(20, 19), (reg)) << 4) | \
+ FIELD_GET(GENMASK(6, 3), (reg)))
+#define SDW_SDCA_CTL_CNUM(reg) ((FIELD_GET(GENMASK(17, 15), (reg)) << 3) | \
+ FIELD_GET(GENMASK(2, 0), (reg)))
+
+#define SDW_SDCA_MBQ_CTL(reg) ((reg) | BIT(13))
+#define SDW_SDCA_NEXT_CTL(reg) ((reg) | BIT(14))
+
+/* Check the reserved and fixed bits in address */
+#define SDW_SDCA_VALID_CTL(reg) (((reg) & (GENMASK(31, 25) | BIT(18) | BIT(13))) == BIT(30))
+
#endif /* __SDW_REGISTERS_H */
diff --git a/include/linux/soundwire/sdw_type.h b/include/linux/soundwire/sdw_type.h
index 52eb66cd11bc..d405935a45fe 100644
--- a/include/linux/soundwire/sdw_type.h
+++ b/include/linux/soundwire/sdw_type.h
@@ -4,16 +4,16 @@
#ifndef __SOUNDWIRE_TYPES_H
#define __SOUNDWIRE_TYPES_H
-extern struct bus_type sdw_bus_type;
-extern struct device_type sdw_slave_type;
-extern struct device_type sdw_master_type;
+extern const struct bus_type sdw_bus_type;
+extern const struct device_type sdw_slave_type;
+extern const struct device_type sdw_master_type;
static inline int is_sdw_slave(const struct device *dev)
{
return dev->type == &sdw_slave_type;
}
-#define drv_to_sdw_driver(_drv) container_of(_drv, struct sdw_driver, driver)
+#define drv_to_sdw_driver(_drv) container_of_const(_drv, struct sdw_driver, driver)
#define sdw_register_driver(drv) \
__sdw_register_driver(drv, THIS_MODULE)
@@ -21,7 +21,7 @@ static inline int is_sdw_slave(const struct device *dev)
int __sdw_register_driver(struct sdw_driver *drv, struct module *owner);
void sdw_unregister_driver(struct sdw_driver *drv);
-int sdw_slave_uevent(struct device *dev, struct kobj_uevent_env *env);
+int sdw_slave_uevent(const struct device *dev, struct kobj_uevent_env *env);
/**
* module_sdw_driver() - Helper macro for registering a Soundwire driver