summaryrefslogtreecommitdiff
path: root/drivers/soundwire/intel.h
blob: 511932c55216c77da4f34d54fcd40501b0b1e282 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/* 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
 * @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;
	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;
	bool startup_done;
#ifdef CONFIG_DEBUG_FS
	struct dentry *debugfs;
#endif
};

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 */