slimbus.h 16.3 KB
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 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2011-2017, The Linux Foundation
 */

#ifndef _DRIVERS_SLIMBUS_H
#define _DRIVERS_SLIMBUS_H
#include <linux/module.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/slimbus.h>

/* Standard values per SLIMbus spec needed by controllers and devices */
#define SLIM_CL_PER_SUPERFRAME		6144
#define SLIM_CL_PER_SUPERFRAME_DIV8	(SLIM_CL_PER_SUPERFRAME >> 3)

/* SLIMbus message types. Related to interpretation of message code. */
#define SLIM_MSG_MT_CORE			0x0
#define SLIM_MSG_MT_DEST_REFERRED_USER		0x2
#define SLIM_MSG_MT_SRC_REFERRED_USER		0x6

/*
 * SLIM Broadcast header format
 * BYTE 0: MT[7:5] RL[4:0]
 * BYTE 1: RSVD[7] MC[6:0]
 * BYTE 2: RSVD[7:6] DT[5:4] PI[3:0]
 */
#define SLIM_MSG_MT_MASK	GENMASK(2, 0)
#define SLIM_MSG_MT_SHIFT	5
#define SLIM_MSG_RL_MASK	GENMASK(4, 0)
#define SLIM_MSG_RL_SHIFT	0
#define SLIM_MSG_MC_MASK	GENMASK(6, 0)
#define SLIM_MSG_MC_SHIFT	0
#define SLIM_MSG_DT_MASK	GENMASK(1, 0)
#define SLIM_MSG_DT_SHIFT	4

#define SLIM_HEADER_GET_MT(b)	((b >> SLIM_MSG_MT_SHIFT) & SLIM_MSG_MT_MASK)
#define SLIM_HEADER_GET_RL(b)	((b >> SLIM_MSG_RL_SHIFT) & SLIM_MSG_RL_MASK)
#define SLIM_HEADER_GET_MC(b)	((b >> SLIM_MSG_MC_SHIFT) & SLIM_MSG_MC_MASK)
#define SLIM_HEADER_GET_DT(b)	((b >> SLIM_MSG_DT_SHIFT) & SLIM_MSG_DT_MASK)

/* Device management messages used by this framework */
#define SLIM_MSG_MC_REPORT_PRESENT               0x1
#define SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS       0x2
#define SLIM_MSG_MC_REPORT_ABSENT                0xF

/* Data channel management messages */
#define SLIM_MSG_MC_CONNECT_SOURCE		0x10
#define SLIM_MSG_MC_CONNECT_SINK		0x11
#define SLIM_MSG_MC_DISCONNECT_PORT		0x14
#define SLIM_MSG_MC_CHANGE_CONTENT		0x18

/* Clock pause Reconfiguration messages */
#define SLIM_MSG_MC_BEGIN_RECONFIGURATION        0x40
#define SLIM_MSG_MC_NEXT_PAUSE_CLOCK             0x4A
#define SLIM_MSG_MC_NEXT_DEFINE_CHANNEL          0x50
#define SLIM_MSG_MC_NEXT_DEFINE_CONTENT          0x51
#define SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL        0x54
#define SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL      0x55
#define SLIM_MSG_MC_NEXT_REMOVE_CHANNEL          0x58
#define SLIM_MSG_MC_RECONFIGURE_NOW              0x5F

/* Clock pause values per SLIMbus spec */
#define SLIM_CLK_FAST				0
#define SLIM_CLK_CONST_PHASE			1
#define SLIM_CLK_UNSPECIFIED			2

/* Destination type Values */
#define SLIM_MSG_DEST_LOGICALADDR	0
#define SLIM_MSG_DEST_ENUMADDR		1
#define	SLIM_MSG_DEST_BROADCAST		3

/* Standard values per SLIMbus spec needed by controllers and devices */
#define SLIM_MAX_CLK_GEAR		10
#define SLIM_MIN_CLK_GEAR		1
#define SLIM_SLOT_LEN_BITS		4

/* Indicate that the frequency of the flow and the bus frequency are locked */
#define SLIM_CHANNEL_CONTENT_FL		BIT(7)

/* Standard values per SLIMbus spec needed by controllers and devices */
#define SLIM_CL_PER_SUPERFRAME		6144
#define SLIM_SLOTS_PER_SUPERFRAME	(SLIM_CL_PER_SUPERFRAME >> 2)
#define SLIM_SL_PER_SUPERFRAME		(SLIM_CL_PER_SUPERFRAME >> 2)
/* Manager's logical address is set to 0xFF per spec */
#define SLIM_LA_MANAGER 0xFF

#define SLIM_MAX_TIDS			256
/**
 * struct slim_framer - Represents SLIMbus framer.
 * Every controller may have multiple framers. There is 1 active framer device
 * responsible for clocking the bus.
 * Manager is responsible for framer hand-over.
 * @dev: Driver model representation of the device.
 * @e_addr: Enumeration address of the framer.
 * @rootfreq: Root Frequency at which the framer can run. This is maximum
 *	frequency ('clock gear 10') at which the bus can operate.
 * @superfreq: Superframes per root frequency. Every frame is 6144 bits.
 */
struct slim_framer {
	struct device		dev;
	struct slim_eaddr	e_addr;
	int			rootfreq;
	int			superfreq;
};

#define to_slim_framer(d) container_of(d, struct slim_framer, dev)

/**
 * struct slim_msg_txn - Message to be sent by the controller.
 *			This structure has packet header,
 *			payload and buffer to be filled (if any)
 * @rl: Header field. remaining length.
 * @mt: Header field. Message type.
 * @mc: Header field. LSB is message code for type mt.
 * @dt: Header field. Destination type.
 * @ec: Element code. Used for elemental access APIs.
 * @tid: Transaction ID. Used for messages expecting response.
 *	(relevant for message-codes involving read operation)
 * @la: Logical address of the device this message is going to.
 *	(Not used when destination type is broadcast.)
 * @msg: Elemental access message to be read/written
 * @comp: completion if read/write is synchronous, used internally
 *	for tid based transactions.
 */
struct slim_msg_txn {
	u8			rl;
	u8			mt;
	u8			mc;
	u8			dt;
	u16			ec;
	u8			tid;
	u8			la;
	struct slim_val_inf	*msg;
	struct	completion	*comp;
};

/* Frequently used message transaction structures */
#define DEFINE_SLIM_LDEST_TXN(name, mc, rl, la, msg) \
	struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_LOGICALADDR, 0,\
					0, la, msg, }

#define DEFINE_SLIM_BCAST_TXN(name, mc, rl, la, msg) \
	struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_BROADCAST, 0,\
					0, la, msg, }

#define DEFINE_SLIM_EDEST_TXN(name, mc, rl, la, msg) \
	struct slim_msg_txn name = { rl, 0, mc, SLIM_MSG_DEST_ENUMADDR, 0,\
					0, la, msg, }
/**
 * enum slim_clk_state: SLIMbus controller's clock state used internally for
 *	maintaining current clock state.
 * @SLIM_CLK_ACTIVE: SLIMbus clock is active
 * @SLIM_CLK_ENTERING_PAUSE: SLIMbus clock pause sequence is being sent on the
 *	bus. If this succeeds, state changes to SLIM_CLK_PAUSED. If the
 *	transition fails, state changes back to SLIM_CLK_ACTIVE
 * @SLIM_CLK_PAUSED: SLIMbus controller clock has paused.
 */
enum slim_clk_state {
	SLIM_CLK_ACTIVE,
	SLIM_CLK_ENTERING_PAUSE,
	SLIM_CLK_PAUSED,
};

/**
 * struct slim_sched: Framework uses this structure internally for scheduling.
 * @clk_state: Controller's clock state from enum slim_clk_state
 * @pause_comp: Signals completion of clock pause sequence. This is useful when
 *	client tries to call SLIMbus transaction when controller is entering
 *	clock pause.
 * @m_reconf: This mutex is held until current reconfiguration (data channel
 *	scheduling, message bandwidth reservation) is done. Message APIs can
 *	use the bus concurrently when this mutex is held since elemental access
 *	messages can be sent on the bus when reconfiguration is in progress.
 */
struct slim_sched {
	enum slim_clk_state	clk_state;
	struct completion	pause_comp;
	struct mutex		m_reconf;
};

/**
 * enum slim_port_direction: SLIMbus port direction
 *
 * @SLIM_PORT_SINK: SLIMbus port is a sink
 * @SLIM_PORT_SOURCE: SLIMbus port is a source
 */
enum slim_port_direction {
	SLIM_PORT_SINK = 0,
	SLIM_PORT_SOURCE,
};
/**
 * enum slim_port_state: SLIMbus Port/Endpoint state machine
 *	according to SLIMbus Spec 2.0
 * @SLIM_PORT_DISCONNECTED: SLIMbus port is disconnected
 *	entered from Unconfigure/configured state after
 *	DISCONNECT_PORT or REMOVE_CHANNEL core command
 * @SLIM_PORT_UNCONFIGURED: SLIMbus port is in unconfigured state.
 *	entered from disconnect state after CONNECT_SOURCE/SINK core command
 * @SLIM_PORT_CONFIGURED: SLIMbus port is in configured state.
 *	entered from unconfigured state after DEFINE_CHANNEL, DEFINE_CONTENT
 *	and ACTIVATE_CHANNEL core commands. Ready for data transmission.
 */
enum slim_port_state {
	SLIM_PORT_DISCONNECTED = 0,
	SLIM_PORT_UNCONFIGURED,
	SLIM_PORT_CONFIGURED,
};

/**
 * enum slim_channel_state: SLIMbus channel state machine used by core.
 * @SLIM_CH_STATE_DISCONNECTED: SLIMbus channel is disconnected
 * @SLIM_CH_STATE_ALLOCATED: SLIMbus channel is allocated
 * @SLIM_CH_STATE_ASSOCIATED: SLIMbus channel is associated with port
 * @SLIM_CH_STATE_DEFINED: SLIMbus channel parameters are defined
 * @SLIM_CH_STATE_CONTENT_DEFINED: SLIMbus channel content is defined
 * @SLIM_CH_STATE_ACTIVE: SLIMbus channel is active and ready for data
 * @SLIM_CH_STATE_REMOVED: SLIMbus channel is inactive and removed
 */
enum slim_channel_state {
	SLIM_CH_STATE_DISCONNECTED = 0,
	SLIM_CH_STATE_ALLOCATED,
	SLIM_CH_STATE_ASSOCIATED,
	SLIM_CH_STATE_DEFINED,
	SLIM_CH_STATE_CONTENT_DEFINED,
	SLIM_CH_STATE_ACTIVE,
	SLIM_CH_STATE_REMOVED,
};

/**
 * enum slim_ch_data_fmt: SLIMbus channel data Type identifiers according to
 *	Table 60 of SLIMbus Spec 1.01.01
 * @SLIM_CH_DATA_FMT_NOT_DEFINED: Undefined
 * @SLIM_CH_DATA_FMT_LPCM_AUDIO: LPCM audio
 * @SLIM_CH_DATA_FMT_IEC61937_COMP_AUDIO: IEC61937 Compressed audio
 * @SLIM_CH_DATA_FMT_PACKED_PDM_AUDIO: Packed PDM audio
 */
enum slim_ch_data_fmt {
	SLIM_CH_DATA_FMT_NOT_DEFINED = 0,
	SLIM_CH_DATA_FMT_LPCM_AUDIO = 1,
	SLIM_CH_DATA_FMT_IEC61937_COMP_AUDIO = 2,
	SLIM_CH_DATA_FMT_PACKED_PDM_AUDIO = 3,
};

/**
 * enum slim_ch_aux_fmt: SLIMbus channel Aux Field format IDs according to
 *	Table 63 of SLIMbus Spec 2.0
 * @SLIM_CH_AUX_FMT_NOT_APPLICABLE: Undefined
 * @SLIM_CH_AUX_FMT_ZCUV_TUNNEL_IEC60958: ZCUV for tunneling IEC60958
 * @SLIM_CH_AUX_FMT_USER_DEFINED: User defined
 */
enum slim_ch_aux_bit_fmt {
	SLIM_CH_AUX_FMT_NOT_APPLICABLE = 0,
	SLIM_CH_AUX_FMT_ZCUV_TUNNEL_IEC60958 = 1,
	SLIM_CH_AUX_FMT_USER_DEFINED = 0xF,
};

/**
 * struct slim_channel  - SLIMbus channel, used for state machine
 *
 * @id: ID of channel
 * @prrate: Presense rate of channel from Table 66 of SLIMbus 2.0 Specs
 * @seg_dist: segment distribution code from Table 20 of SLIMbus 2.0 Specs
 * @data_fmt: Data format of channel.
 * @aux_fmt: Aux format for this channel.
 * @state: channel state machine
 */
struct slim_channel {
	int id;
	int prrate;
	int seg_dist;
	enum slim_ch_data_fmt data_fmt;
	enum slim_ch_aux_bit_fmt aux_fmt;
	enum slim_channel_state state;
};

/**
 * struct slim_port  - SLIMbus port
 *
 * @id: Port id
 * @direction: Port direction, Source or Sink.
 * @state: state machine of port.
 * @ch: channel associated with this port.
 */
struct slim_port {
	int id;
	enum slim_port_direction direction;
	enum slim_port_state state;
	struct slim_channel ch;
};

/**
 * enum slim_transport_protocol: SLIMbus Transport protocol list from
 *	Table 47 of SLIMbus 2.0 specs.
 * @SLIM_PROTO_ISO: Isochronous Protocol, no flow control as data rate match
 *		channel rate flow control embedded in the data.
 * @SLIM_PROTO_PUSH: Pushed Protocol, includes flow control, Used to carry
 *		data whose rate	is equal to, or lower than the channel rate.
 * @SLIM_PROTO_PULL: Pulled Protocol, similar usage as pushed protocol
 *		but pull is a unicast.
 * @SLIM_PROTO_LOCKED: Locked Protocol
 * @SLIM_PROTO_ASYNC_SMPLX: Asynchronous Protocol-Simplex
 * @SLIM_PROTO_ASYNC_HALF_DUP: Asynchronous Protocol-Half-duplex
 * @SLIM_PROTO_EXT_SMPLX: Extended Asynchronous Protocol-Simplex
 * @SLIM_PROTO_EXT_HALF_DUP: Extended Asynchronous Protocol-Half-duplex
 */
enum slim_transport_protocol {
	SLIM_PROTO_ISO = 0,
	SLIM_PROTO_PUSH,
	SLIM_PROTO_PULL,
	SLIM_PROTO_LOCKED,
	SLIM_PROTO_ASYNC_SMPLX,
	SLIM_PROTO_ASYNC_HALF_DUP,
	SLIM_PROTO_EXT_SMPLX,
	SLIM_PROTO_EXT_HALF_DUP,
};

/**
 * struct slim_stream_runtime  - SLIMbus stream runtime instance
 *
 * @name: Name of the stream
 * @dev: SLIM Device instance associated with this stream
 * @direction: direction of stream
 * @prot: Transport protocol used in this stream
 * @rate: Data rate of samples *
 * @bps: bits per sample
 * @ratem: rate multipler which is super frame rate/data rate
 * @num_ports: number of ports
 * @ports: pointer to instance of ports
 * @node: list head for stream associated with slim device.
 */
struct slim_stream_runtime {
	const char *name;
	struct slim_device *dev;
	int direction;
	enum slim_transport_protocol prot;
	unsigned int rate;
	unsigned int bps;
	unsigned int ratem;
	int num_ports;
	struct slim_port *ports;
	struct list_head node;
};

/**
 * struct slim_controller  - Controls every instance of SLIMbus
 *				(similar to 'master' on SPI)
 * @dev: Device interface to this driver
 * @id: Board-specific number identifier for this controller/bus
 * @name: Name for this controller
 * @min_cg: Minimum clock gear supported by this controller (default value: 1)
 * @max_cg: Maximum clock gear supported by this controller (default value: 10)
 * @clkgear: Current clock gear in which this bus is running
 * @laddr_ida: logical address id allocator
 * @a_framer: Active framer which is clocking the bus managed by this controller
 * @lock: Mutex protecting controller data structures
 * @devices: Slim device list
 * @tid_idr: tid id allocator
 * @txn_lock: Lock to protect table of transactions
 * @sched: scheduler structure used by the controller
 * @xfer_msg: Transfer a message on this controller (this can be a broadcast
 *	control/status message like data channel setup, or a unicast message
 *	like value element read/write.
 * @set_laddr: Setup logical address at laddr for the slave with elemental
 *	address e_addr. Drivers implementing controller will be expected to
 *	send unicast message to this device with its logical address.
 * @get_laddr: It is possible that controller needs to set fixed logical
 *	address table and get_laddr can be used in that case so that controller
 *	can do this assignment. Use case is when the master is on the remote
 *	processor side, who is resposible for allocating laddr.
 * @wakeup: This function pointer implements controller-specific procedure
 *	to wake it up from clock-pause. Framework will call this to bring
 *	the controller out of clock pause.
 * @enable_stream: This function pointer implements controller-specific procedure
 *	to enable a stream.
 * @disable_stream: This function pointer implements controller-specific procedure
 *	to disable stream.
 *
 *	'Manager device' is responsible for  device management, bandwidth
 *	allocation, channel setup, and port associations per channel.
 *	Device management means Logical address assignment/removal based on
 *	enumeration (report-present, report-absent) of a device.
 *	Bandwidth allocation is done dynamically by the manager based on active
 *	channels on the bus, message-bandwidth requests made by SLIMbus devices.
 *	Based on current bandwidth usage, manager chooses a frequency to run
 *	the bus at (in steps of 'clock-gear', 1 through 10, each clock gear
 *	representing twice the frequency than the previous gear).
 *	Manager is also responsible for entering (and exiting) low-power-mode
 *	(known as 'clock pause').
 *	Manager can do handover of framer if there are multiple framers on the
 *	bus and a certain usecase warrants using certain framer to avoid keeping
 *	previous framer being powered-on.
 *
 *	Controller here performs duties of the manager device, and 'interface
 *	device'. Interface device is responsible for monitoring the bus and
 *	reporting information such as loss-of-synchronization, data
 *	slot-collision.
 */
struct slim_controller {
	struct device		*dev;
	unsigned int		id;
	char			name[SLIMBUS_NAME_SIZE];
	int			min_cg;
	int			max_cg;
	int			clkgear;
	struct ida		laddr_ida;
	struct slim_framer	*a_framer;
	struct mutex		lock;
	struct list_head	devices;
	struct idr		tid_idr;
	spinlock_t		txn_lock;
	struct slim_sched	sched;
	int			(*xfer_msg)(struct slim_controller *ctrl,
					    struct slim_msg_txn *tx);
	int			(*set_laddr)(struct slim_controller *ctrl,
					     struct slim_eaddr *ea, u8 laddr);
	int			(*get_laddr)(struct slim_controller *ctrl,
					     struct slim_eaddr *ea, u8 *laddr);
	int		(*enable_stream)(struct slim_stream_runtime *rt);
	int		(*disable_stream)(struct slim_stream_runtime *rt);
	int			(*wakeup)(struct slim_controller *ctrl);
};

int slim_device_report_present(struct slim_controller *ctrl,
			       struct slim_eaddr *e_addr, u8 *laddr);
void slim_report_absent(struct slim_device *sbdev);
int slim_register_controller(struct slim_controller *ctrl);
int slim_unregister_controller(struct slim_controller *ctrl);
void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 l);
int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn);
int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart);
int slim_alloc_txn_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn);
void slim_free_txn_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn);

static inline bool slim_tid_txn(u8 mt, u8 mc)
{
	return (mt == SLIM_MSG_MT_CORE &&
		(mc == SLIM_MSG_MC_REQUEST_INFORMATION ||
		 mc == SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION ||
		 mc == SLIM_MSG_MC_REQUEST_VALUE ||
		 mc == SLIM_MSG_MC_REQUEST_CHANGE_VALUE));
}

static inline bool slim_ec_txn(u8 mt, u8 mc)
{
	return (mt == SLIM_MSG_MT_CORE &&
		((mc >= SLIM_MSG_MC_REQUEST_INFORMATION &&
		  mc <= SLIM_MSG_MC_REPORT_INFORMATION) ||
		 (mc >= SLIM_MSG_MC_REQUEST_VALUE &&
		  mc <= SLIM_MSG_MC_CHANGE_VALUE)));
}
#endif /* _LINUX_SLIMBUS_H */