2265 lines · 54.2 KB · C
RawDownload
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)// Copyright(c) 2015-18 Intel Corporation. /* *  stream.c - SoundWire Bus stream operations. */ #include <linux/delay.h>#include <linux/device.h>#include <linux/init.h>#include <linux/iopoll.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/soundwire/sdw_registers.h>#include <linux/soundwire/sdw.h>#include <linux/soundwire/sdw_type.h>#include <linux/string_choices.h>#include <sound/soc.h>#include "bus.h" #define SDW_PORT_PREP_POLL_USEC	1000 /* * Array of supported rows and columns as per MIPI SoundWire Specification 1.1 * * The rows are arranged as per the array index value programmed * in register. The index 15 has dummy value 0 in order to fill hole. */int sdw_rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,			96, 100, 120, 128, 150, 160, 250, 0,			192, 200, 240, 256, 72, 144, 90, 180};EXPORT_SYMBOL(sdw_rows); int sdw_cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};EXPORT_SYMBOL(sdw_cols); int sdw_find_col_index(int col){	int i; 	for (i = 0; i < SDW_FRAME_COLS; i++) {		if (sdw_cols[i] == col)			return i;	} 	pr_warn("Requested column not found, selecting lowest column no: 2\n");	return 0;}EXPORT_SYMBOL(sdw_find_col_index); int sdw_find_row_index(int row){	int i; 	for (i = 0; i < SDW_FRAME_ROWS; i++) {		if (sdw_rows[i] == row)			return i;	} 	pr_warn("Requested row not found, selecting lowest row no: 48\n");	return 0;}EXPORT_SYMBOL(sdw_find_row_index); static int _sdw_program_slave_port_params(struct sdw_bus *bus,					  struct sdw_slave *slave,					  struct sdw_transport_params *t_params,					  enum sdw_dpn_type type){	u32 addr1, addr2, addr3, addr4;	int ret;	u16 wbuf; 	if (bus->params.next_bank) {		addr1 = SDW_DPN_OFFSETCTRL2_B1(t_params->port_num);		addr2 = SDW_DPN_BLOCKCTRL3_B1(t_params->port_num);		addr3 = SDW_DPN_SAMPLECTRL2_B1(t_params->port_num);		addr4 = SDW_DPN_HCTRL_B1(t_params->port_num);	} else {		addr1 = SDW_DPN_OFFSETCTRL2_B0(t_params->port_num);		addr2 = SDW_DPN_BLOCKCTRL3_B0(t_params->port_num);		addr3 = SDW_DPN_SAMPLECTRL2_B0(t_params->port_num);		addr4 = SDW_DPN_HCTRL_B0(t_params->port_num);	} 	/* Program DPN_OffsetCtrl2 registers */	ret = sdw_write_no_pm(slave, addr1, t_params->offset2);	if (ret < 0) {		dev_err(bus->dev, "DPN_OffsetCtrl2 register write failed\n");		return ret;	} 	/* DP0 does not implement BlockCtrl3 */	if (t_params->port_num) {		/* Program DPN_BlockCtrl3 register */		ret = sdw_write_no_pm(slave, addr2, t_params->blk_pkg_mode);		if (ret < 0) {			dev_err(bus->dev, "DPN_BlockCtrl3 register write failed\n");			return ret;		}	} 	/*	 * Data ports are FULL, SIMPLE and REDUCED. This function handles	 * FULL and REDUCED only and beyond this point only FULL is	 * handled, so bail out if we are not FULL data port type	 */	if (type != SDW_DPN_FULL)		return ret; 	/* Program DPN_SampleCtrl2 register */	wbuf = FIELD_GET(SDW_DPN_SAMPLECTRL_HIGH, t_params->sample_interval - 1); 	ret = sdw_write_no_pm(slave, addr3, wbuf);	if (ret < 0) {		dev_err(bus->dev, "DPN_SampleCtrl2 register write failed\n");		return ret;	} 	/* Program DPN_HCtrl register */	wbuf = FIELD_PREP(SDW_DPN_HCTRL_HSTART, t_params->hstart);	wbuf |= FIELD_PREP(SDW_DPN_HCTRL_HSTOP, t_params->hstop); 	ret = sdw_write_no_pm(slave, addr4, wbuf);	if (ret < 0)		dev_err(bus->dev, "DPN_HCtrl register write failed\n"); 	return ret;} static int sdw_program_slave_port_params(struct sdw_bus *bus,					 struct sdw_slave_runtime *s_rt,					 struct sdw_port_runtime *p_rt){	struct sdw_transport_params *t_params = &p_rt->transport_params;	struct sdw_port_params *p_params = &p_rt->port_params;	struct sdw_slave_prop *slave_prop = &s_rt->slave->prop;	u32 addr1, addr2, addr3, addr4, addr5, addr6;	enum sdw_dpn_type port_type;	bool read_only_wordlength;	int ret;	u8 wbuf; 	if (s_rt->slave->is_mockup_device)		return 0; 	if (t_params->port_num) {		struct sdw_dpn_prop *dpn_prop; 		dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, s_rt->direction,						  t_params->port_num);		if (!dpn_prop)			return -EINVAL; 		read_only_wordlength = dpn_prop->read_only_wordlength;		port_type = dpn_prop->type;	} else {		read_only_wordlength = false;		port_type = SDW_DPN_FULL;	} 	addr1 = SDW_DPN_PORTCTRL(t_params->port_num);	addr2 = SDW_DPN_BLOCKCTRL1(t_params->port_num); 	if (bus->params.next_bank) {		addr3 = SDW_DPN_SAMPLECTRL1_B1(t_params->port_num);		addr4 = SDW_DPN_OFFSETCTRL1_B1(t_params->port_num);		addr5 = SDW_DPN_BLOCKCTRL2_B1(t_params->port_num);		addr6 = SDW_DPN_LANECTRL_B1(t_params->port_num); 	} else {		addr3 = SDW_DPN_SAMPLECTRL1_B0(t_params->port_num);		addr4 = SDW_DPN_OFFSETCTRL1_B0(t_params->port_num);		addr5 = SDW_DPN_BLOCKCTRL2_B0(t_params->port_num);		addr6 = SDW_DPN_LANECTRL_B0(t_params->port_num);	} 	/* Program DPN_PortCtrl register */	wbuf = FIELD_PREP(SDW_DPN_PORTCTRL_DATAMODE, p_params->data_mode);	wbuf |= FIELD_PREP(SDW_DPN_PORTCTRL_FLOWMODE, p_params->flow_mode); 	ret = sdw_update_no_pm(s_rt->slave, addr1, 0xF, wbuf);	if (ret < 0) {		dev_err(&s_rt->slave->dev,			"DPN_PortCtrl register write failed for port %d\n",			t_params->port_num);		return ret;	} 	if (!read_only_wordlength) {		/* Program DPN_BlockCtrl1 register */		ret = sdw_write_no_pm(s_rt->slave, addr2, (p_params->bps - 1));		if (ret < 0) {			dev_err(&s_rt->slave->dev,				"DPN_BlockCtrl1 register write failed for port %d\n",				t_params->port_num);			return ret;		}	} 	/* Program DPN_SampleCtrl1 register */	wbuf = (t_params->sample_interval - 1) & SDW_DPN_SAMPLECTRL_LOW;	ret = sdw_write_no_pm(s_rt->slave, addr3, wbuf);	if (ret < 0) {		dev_err(&s_rt->slave->dev,			"DPN_SampleCtrl1 register write failed for port %d\n",			t_params->port_num);		return ret;	} 	/* Program DPN_OffsetCtrl1 registers */	ret = sdw_write_no_pm(s_rt->slave, addr4, t_params->offset1);	if (ret < 0) {		dev_err(&s_rt->slave->dev,			"DPN_OffsetCtrl1 register write failed for port %d\n",			t_params->port_num);		return ret;	} 	/* Program DPN_BlockCtrl2 register*/	if (t_params->blk_grp_ctrl_valid) {		ret = sdw_write_no_pm(s_rt->slave, addr5, t_params->blk_grp_ctrl);		if (ret < 0) {			dev_err(&s_rt->slave->dev,				"DPN_BlockCtrl2 reg write failed for port %d\n",				t_params->port_num);			return ret;		}	} 	/* program DPN_LaneCtrl register */	if (slave_prop->lane_control_support) {		ret = sdw_write_no_pm(s_rt->slave, addr6, t_params->lane_ctrl);		if (ret < 0) {			dev_err(&s_rt->slave->dev,				"DPN_LaneCtrl register write failed for port %d\n",				t_params->port_num);			return ret;		}	} 	if (port_type != SDW_DPN_SIMPLE) {		ret = _sdw_program_slave_port_params(bus, s_rt->slave,						     t_params, port_type);		if (ret < 0)			dev_err(&s_rt->slave->dev,				"Transport reg write failed for port: %d\n",				t_params->port_num);	} 	return ret;} static int sdw_program_master_port_params(struct sdw_bus *bus,					  struct sdw_port_runtime *p_rt){	int ret; 	/*	 * we need to set transport and port parameters for the port.	 * Transport parameters refers to the sample interval, offsets and	 * hstart/stop etc of the data. Port parameters refers to word	 * length, flow mode etc of the port	 */	ret = bus->port_ops->dpn_set_port_transport_params(bus,					&p_rt->transport_params,					bus->params.next_bank);	if (ret < 0)		return ret; 	return bus->port_ops->dpn_set_port_params(bus,						  &p_rt->port_params,						  bus->params.next_bank);} /** * sdw_program_port_params() - Programs transport parameters of Master(s) * and Slave(s) * * @m_rt: Master stream runtime */static int sdw_program_port_params(struct sdw_master_runtime *m_rt){	struct sdw_slave_runtime *s_rt;	struct sdw_bus *bus = m_rt->bus;	struct sdw_port_runtime *p_rt;	int ret = 0; 	/* Program transport & port parameters for Slave(s) */	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {		list_for_each_entry(p_rt, &s_rt->port_list, port_node) {			ret = sdw_program_slave_port_params(bus, s_rt, p_rt);			if (ret < 0)				return ret;		}	} 	/* Program transport & port parameters for Master(s) */	list_for_each_entry(p_rt, &m_rt->port_list, port_node) {		ret = sdw_program_master_port_params(bus, p_rt);		if (ret < 0)			return ret;	} 	return 0;} /** * sdw_enable_disable_slave_ports: Enable/disable slave data port * * @bus: bus instance * @s_rt: slave runtime * @p_rt: port runtime * @en: enable or disable operation * * This function only sets the enable/disable bits in the relevant bank, the * actual enable/disable is done with a bank switch */static int sdw_enable_disable_slave_ports(struct sdw_bus *bus,					  struct sdw_slave_runtime *s_rt,					  struct sdw_port_runtime *p_rt,					  bool en){	struct sdw_transport_params *t_params = &p_rt->transport_params;	u32 addr;	int ret; 	if (bus->params.next_bank)		addr = SDW_DPN_CHANNELEN_B1(p_rt->num);	else		addr = SDW_DPN_CHANNELEN_B0(p_rt->num); 	/*	 * Since bus doesn't support sharing a port across two streams,	 * it is safe to reset this register	 */	if (en)		ret = sdw_write_no_pm(s_rt->slave, addr, p_rt->ch_mask);	else		ret = sdw_write_no_pm(s_rt->slave, addr, 0x0); 	if (ret < 0)		dev_err(&s_rt->slave->dev,			"Slave chn_en reg write failed:%d port:%d\n",			ret, t_params->port_num); 	return ret;} static int sdw_enable_disable_master_ports(struct sdw_master_runtime *m_rt,					   struct sdw_port_runtime *p_rt,					   bool en){	struct sdw_transport_params *t_params = &p_rt->transport_params;	struct sdw_bus *bus = m_rt->bus;	struct sdw_enable_ch enable_ch;	int ret; 	enable_ch.port_num = p_rt->num;	enable_ch.ch_mask = p_rt->ch_mask;	enable_ch.enable = en; 	/* Perform Master port channel(s) enable/disable */	if (bus->port_ops->dpn_port_enable_ch) {		ret = bus->port_ops->dpn_port_enable_ch(bus,							&enable_ch,							bus->params.next_bank);		if (ret < 0) {			dev_err(bus->dev,				"Master chn_en write failed:%d port:%d\n",				ret, t_params->port_num);			return ret;		}	} else {		dev_err(bus->dev,			"dpn_port_enable_ch not supported, %s failed\n",			str_enable_disable(en));		return -EINVAL;	} 	return 0;} /** * sdw_enable_disable_ports() - Enable/disable port(s) for Master and * Slave(s) * * @m_rt: Master stream runtime * @en: mode (enable/disable) */static int sdw_enable_disable_ports(struct sdw_master_runtime *m_rt, bool en){	struct sdw_port_runtime *s_port, *m_port;	struct sdw_slave_runtime *s_rt;	int ret = 0; 	/* Enable/Disable Slave port(s) */	list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {		list_for_each_entry(s_port, &s_rt->port_list, port_node) {			ret = sdw_enable_disable_slave_ports(m_rt->bus, s_rt,							     s_port, en);			if (ret < 0)				return ret;		}	} 	/* Enable/Disable Master port(s) */	list_for_each_entry(m_port, &m_rt->port_list, port_node) {		ret = sdw_enable_disable_master_ports(m_rt, m_port, en);		if (ret < 0)			return ret;	} 	return 0;} static int sdw_do_port_prep(struct sdw_slave_runtime *s_rt,			    struct sdw_prepare_ch prep_ch,			    enum sdw_port_prep_ops cmd){	int ret = 0;	struct sdw_slave *slave = s_rt->slave; 	mutex_lock(&slave->sdw_dev_lock); 	if (slave->probed) {		struct device *dev = &slave->dev;		struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 		if (drv->ops && drv->ops->port_prep) {			ret = drv->ops->port_prep(slave, &prep_ch, cmd);			if (ret < 0)				dev_err(dev, "Slave Port Prep cmd %d failed: %d\n",					cmd, ret);		}	} 	mutex_unlock(&slave->sdw_dev_lock); 	return ret;} static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,				       struct sdw_slave_runtime *s_rt,				       struct sdw_port_runtime *p_rt,				       bool prep){	struct sdw_dpn_prop *dpn_prop;	struct sdw_prepare_ch prep_ch;	u32 imp_def_interrupts;	bool simple_ch_prep_sm;	u32 ch_prep_timeout;	bool intr = false;	int ret = 0, val;	u32 addr; 	prep_ch.num = p_rt->num;	prep_ch.ch_mask = p_rt->ch_mask; 	if (p_rt->num) {		dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, s_rt->direction, prep_ch.num);		if (!dpn_prop) {			dev_err(bus->dev,				"Slave Port:%d properties not found\n", prep_ch.num);			return -EINVAL;		} 		imp_def_interrupts = dpn_prop->imp_def_interrupts;		simple_ch_prep_sm = dpn_prop->simple_ch_prep_sm;		ch_prep_timeout = dpn_prop->ch_prep_timeout;	} else {		struct sdw_dp0_prop *dp0_prop = s_rt->slave->prop.dp0_prop; 		if (!dp0_prop) {			dev_err(bus->dev,				"Slave DP0 properties not found\n");			return -EINVAL;		}		imp_def_interrupts = dp0_prop->imp_def_interrupts;		simple_ch_prep_sm =  dp0_prop->simple_ch_prep_sm;		ch_prep_timeout = dp0_prop->ch_prep_timeout;	} 	prep_ch.prepare = prep; 	prep_ch.bank = bus->params.next_bank; 	if (imp_def_interrupts || !simple_ch_prep_sm ||	    bus->params.s_data_mode != SDW_PORT_DATA_MODE_NORMAL)		intr = true; 	/*	 * Enable interrupt before Port prepare.	 * For Port de-prepare, it is assumed that port	 * was prepared earlier	 */	if (prep && intr) {		ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,					     imp_def_interrupts);		if (ret < 0)

Lines 1–500 of 2265.