Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e5bd104 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "slim-msm: Add support to set port config and options"

parents 3ad22dac e4c519a7
Loading
Loading
Loading
Loading
+90 −11
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/slimbus/slimbus.h>
#include <linux/msm-sps.h>
#include <linux/gcd.h>
#include "slim-msm.h"

int msm_slim_rx_enqueue(struct msm_slim_ctrl *dev, u32 *buf, u8 len)
@@ -188,12 +189,54 @@ msm_slim_sps_mem_free(struct msm_slim_ctrl *dev, struct sps_mem_buffer *mem)
	mem->phys_base = 0;
}

void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn)
void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pipenum, u8 portnum)
{
	u32 set_cfg = DEF_WATERMARK | DEF_ALIGN | DEF_PACK | ENABLE_PORT;
	writel_relaxed(set_cfg, PGD_PORT(PGD_PORT_CFGn, pn, dev->ver));
	writel_relaxed(DEF_BLKSZ, PGD_PORT(PGD_PORT_BLKn, pn, dev->ver));
	writel_relaxed(DEF_TRANSZ, PGD_PORT(PGD_PORT_TRANn, pn, dev->ver));
	struct slim_controller *ctrl;
	struct slim_ch *chan;
	struct msm_slim_pshpull_parm *parm;
	u32 set_cfg = 0;
	struct slim_port_cfg cfg = dev->ctrl.ports[portnum].cfg;

	if (!dev) {
		pr_err("%s:Dev node is null\n", __func__);
		return;
	}
	if (portnum >= dev->port_nums) {
		pr_err("%s:Invalid port\n", __func__);
		return;
	}
	ctrl = &dev->ctrl;
	chan = ctrl->ports[portnum].ch;
	parm = &dev->pipes[portnum].psh_pull;

	if (cfg.watermark)
		set_cfg = (cfg.watermark << 1);
	else
		set_cfg = DEF_WATERMARK;

	if (cfg.port_opts & SLIM_OPT_NO_PACK)
		set_cfg |= DEF_NO_PACK;
	else
		set_cfg |= DEF_PACK;

	if (cfg.port_opts & SLIM_OPT_ALIGN_MSB)
		set_cfg |= DEF_ALIGN_MSB;
	else
		set_cfg |= DEF_ALIGN_LSB;

	set_cfg |= ENABLE_PORT;

	writel_relaxed(set_cfg, PGD_PORT(PGD_PORT_CFGn, pipenum, dev->ver));
	writel_relaxed(DEF_BLKSZ, PGD_PORT(PGD_PORT_BLKn, pipenum, dev->ver));
	writel_relaxed(DEF_TRANSZ, PGD_PORT(PGD_PORT_TRANn, pipenum, dev->ver));

	if (chan->prot == SLIM_PUSH || chan->prot == SLIM_PULL) {
		set_cfg = 0;
		set_cfg |= ((0xFFFF & parm->num_samples)<<16);
		set_cfg |= (0xFFFF & parm->rpt_period);
		writel_relaxed(set_cfg, PGD_PORT(PGD_PORT_PSHPLLn,
							pipenum, dev->ver));
	}
	/* Make sure that port registers are updated before returning */
	mb();
}
@@ -216,15 +259,49 @@ static void msm_slim_disconn_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
	dev->pipes[pn].connected = false;
}

int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
static void msm_slim_calc_pshpull_parm(struct msm_slim_ctrl *dev,
					u8 pn, struct slim_ch *prop)
{
	struct msm_slim_endp *endpoint = &dev->pipes[pn];
	struct sps_connect *cfg = &endpoint->config;
	struct msm_slim_pshpull_parm *parm = &endpoint->psh_pull;
	int	chan_freq, round_off, divisor, super_freq;

	super_freq = dev->ctrl.a_framer->superfreq;

	if (prop->baser == SLIM_RATE_4000HZ)
		chan_freq = 4000 * prop->ratem;
	else if (prop->baser == SLIM_RATE_11025HZ)
		chan_freq = 11025 * prop->ratem;
	else
		chan_freq = prop->baser * prop->ratem;

	/*
	 * If channel frequency is multiple of super frame frequency
	 * ISO protocol is suggested
	 */
	if (!(chan_freq % super_freq)) {
		prop->prot = SLIM_HARD_ISO;
		return;
	}
	round_off = DIV_ROUND_UP(chan_freq, super_freq);
	divisor = gcd(round_off * super_freq, chan_freq);
	parm->num_samples = chan_freq/divisor;
	parm->rpt_period = (round_off * super_freq)/divisor;
}

int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
{
	struct msm_slim_endp *endpoint;
	struct sps_connect *cfg;
	struct slim_ch *prop;
	u32 stat;
	int ret;

	if (pn >= dev->port_nums)
	if (!dev || pn >= dev->port_nums)
		return -ENODEV;
	endpoint = &dev->pipes[pn];
	cfg = &endpoint->config;
	prop = dev->ctrl.ports[pn].ch;

	endpoint = &dev->pipes[pn];
	ret = sps_get_config(dev->pipes[pn].sps, cfg);
@@ -235,6 +312,9 @@ int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
	cfg->options = SPS_O_DESC_DONE | SPS_O_ERROR |
				SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE;

	if (prop->prot == SLIM_PUSH || prop->prot ==  SLIM_PULL)
		msm_slim_calc_pshpull_parm(dev, pn, prop);

	if (dev->pipes[pn].connected &&
			dev->ctrl.ports[pn].state == SLIM_P_CFG) {
		return -EISCONN;
@@ -248,7 +328,7 @@ int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn)
			cfg->mode == SPS_MODE_DEST) ||
			(dev->ctrl.ports[pn].flow == SLIM_SINK &&
			 cfg->mode == SPS_MODE_SRC)) {
			msm_hw_set_port(dev, endpoint->port_b);
			msm_hw_set_port(dev, endpoint->port_b, pn);
			return 0;
		}
		msm_slim_disconn_pipe_port(dev, pn);
@@ -283,7 +363,7 @@ int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn)

	if (!ret) {
		dev->pipes[pn].connected = true;
		msm_hw_set_port(dev, endpoint->port_b);
		msm_hw_set_port(dev, endpoint->port_b, pn);
	}
	return ret;
}
@@ -1093,7 +1173,6 @@ void msm_slim_deinit_ep(struct msm_slim_ctrl *dev,
static void msm_slim_sps_unreg_event(struct sps_pipe *sps)
{
	struct sps_register_event sps_event;

	memset(&sps_event, 0x00, sizeof(sps_event));
	/* Disable interrupt and signal notification for Rx/Tx pipe */
	sps_register_event(sps, &sps_event);
+16 −2
Original line number Diff line number Diff line
@@ -71,9 +71,12 @@
#define DEF_RETRY_MS	10
#define MSM_CONCUR_MSG	8
#define SAT_CONCUR_MSG	8

#define DEF_WATERMARK	(8 << 1)
#define DEF_ALIGN	0
#define DEF_ALIGN_LSB	0
#define DEF_ALIGN_MSB	(1 << 7)
#define DEF_PACK	(1 << 6)
#define DEF_NO_PACK	0
#define ENABLE_PORT	1

#define DEF_BLKSZ	0
@@ -197,6 +200,16 @@ struct msm_slim_sps_bam {
	int			irq;
};

/*
 * struct slim_pshpull_parm: Structure to store push pull protocol parameters
 * @num_samples: Number of samples in a period
 * @rpt_period: Repeat period value
 */
struct msm_slim_pshpull_parm {
	int		num_samples;
	int		rpt_period;
};

struct msm_slim_endp {
	struct sps_pipe			*sps;
	struct sps_connect		config;
@@ -204,6 +217,7 @@ struct msm_slim_endp {
	struct sps_mem_buffer		buf;
	bool				connected;
	int				port_b;
	struct msm_slim_pshpull_parm	psh_pull;
};

struct msm_slim_qmi {
@@ -385,7 +399,7 @@ void msm_slim_put_ctrl(struct msm_slim_ctrl *dev);
irqreturn_t msm_slim_port_irq_handler(struct msm_slim_ctrl *dev, u32 pstat);
int msm_slim_init_endpoint(struct msm_slim_ctrl *dev, struct msm_slim_endp *ep);
void msm_slim_free_endpoint(struct msm_slim_endp *ep);
void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn);
void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pipenum, u8 portnum);
int msm_alloc_port(struct slim_controller *ctrl, u8 pn);
void msm_dealloc_port(struct slim_controller *ctrl, u8 pn);
int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn);
+53 −7
Original line number Diff line number Diff line
@@ -1278,6 +1278,39 @@ int slim_dealloc_mgrports(struct slim_device *sb, u32 *hdl, int nports)
}
EXPORT_SYMBOL_GPL(slim_dealloc_mgrports);

/*
 * slim_config_mgrports: Configure manager side ports
 * @sb: device/client handle.
 * @ph: array of port handles for which this configuration is valid
 * @nports: Number of ports in ph
 * @cfg: configuration requested for port(s)
 * Configure port settings if they are different than the default ones.
 * Returns success if the config could be applied. Returns -EISCONN if the
 * port is in use
 */
int slim_config_mgrports(struct slim_device *sb, u32 *ph, int nports,
				struct slim_port_cfg *cfg)
{
	int i;
	struct slim_controller *ctrl;

	if (!sb || !ph || !nports || !sb->ctrl || !cfg)
		return -EINVAL;

	ctrl = sb->ctrl;
	mutex_lock(&ctrl->sched.m_reconf);
	for (i = 0; i < nports; i++) {
		u8 pn = SLIM_HDL_TO_PORT(ph[i]);

		if (ctrl->ports[pn].state == SLIM_P_CFG)
			return -EISCONN;
		ctrl->ports[pn].cfg = *cfg;
	}
	mutex_unlock(&ctrl->sched.m_reconf);
	return 0;
}
EXPORT_SYMBOL(slim_config_mgrports);

/*
 * slim_get_slaveport: Get slave port handle
 * @la: slave device logical address.
@@ -1331,8 +1364,12 @@ static int disconnect_port_ch(struct slim_controller *ctrl, u32 ph)
	ret = slim_processtxn(ctrl, &txn, false);
	if (ret)
		return ret;
	if (la == SLIM_LA_MANAGER)
	if (la == SLIM_LA_MANAGER) {
		ctrl->ports[pn].state = SLIM_P_UNCFG;
		ctrl->ports[pn].cfg.watermark = 0;
		ctrl->ports[pn].cfg.port_opts = 0;
		ctrl->ports[pn].ch = NULL;
	}
	return 0;
}

@@ -1356,6 +1393,7 @@ int slim_connect_src(struct slim_device *sb, u32 srch, u16 chanh)
	struct slim_ich *slc = &ctrl->chans[chan];
	enum slim_port_flow flow = SLIM_HDL_TO_FLOW(srch);
	u8 la = SLIM_HDL_TO_LA(srch);
	u8 pn = SLIM_HDL_TO_PORT(srch);

	/* manager ports don't have direction when they are allocated */
	if (la != SLIM_LA_MANAGER && flow != SLIM_SRC)
@@ -1364,7 +1402,6 @@ int slim_connect_src(struct slim_device *sb, u32 srch, u16 chanh)
	mutex_lock(&ctrl->sched.m_reconf);

	if (la == SLIM_LA_MANAGER) {
		u8 pn = SLIM_HDL_TO_PORT(srch);
		if (pn >= ctrl->nports ||
			ctrl->ports[pn].state != SLIM_P_UNCFG) {
			ret = -EINVAL;
@@ -1385,7 +1422,7 @@ int slim_connect_src(struct slim_device *sb, u32 srch, u16 chanh)
		ret = -EALREADY;
		goto connect_src_err;
	}

	ctrl->ports[pn].ch = &slc->prop;
	ret = connect_port_ch(ctrl, chan, srch, SLIM_SRC);

	if (!ret)
@@ -1444,8 +1481,10 @@ int slim_connect_sink(struct slim_device *sb, u32 *sinkh, int nsink, u16 chanh)
				(pn >= ctrl->nports ||
				ctrl->ports[pn].state != SLIM_P_UNCFG))
				ret = -EINVAL;
		else
		else {
			ctrl->ports[pn].ch = &slc->prop;
			ret = connect_port_ch(ctrl, chan, sinkh[j], SLIM_SINK);
		}
		if (ret) {
			for (j = j - 1; j >= 0; j--)
				disconnect_port_ch(ctrl, sinkh[j]);
@@ -1638,14 +1677,21 @@ static int slim_remove_ch(struct slim_controller *ctrl, struct slim_ich *slc)
		 * disconnect. It is client's responsibility to call disconnect
		 * on ports owned by the slave device
		 */
		if (la == SLIM_LA_MANAGER)
		if (la == SLIM_LA_MANAGER) {
			ctrl->ports[SLIM_HDL_TO_PORT(ph)].state = SLIM_P_UNCFG;
			ctrl->ports[SLIM_HDL_TO_PORT(ph)].ch = NULL;
		}
	}

	ph = slc->srch;
	la = SLIM_HDL_TO_LA(ph);
	if (la == SLIM_LA_MANAGER)
		ctrl->ports[SLIM_HDL_TO_PORT(ph)].state = SLIM_P_UNCFG;
	if (la == SLIM_LA_MANAGER) {
		u8 pn = SLIM_HDL_TO_PORT(ph);

		ctrl->ports[pn].state = SLIM_P_UNCFG;
		ctrl->ports[pn].cfg.watermark = 0;
		ctrl->ports[pn].cfg.port_opts = 0;
	}

	kfree(slc->sinkh);
	slc->sinkh = NULL;
+30 −7
Original line number Diff line number Diff line
@@ -226,13 +226,13 @@ enum slim_port_req {
};

/*
 * enum slim_port_cfg: Port configuration parameters requested.
 * User can request no configuration, packed data, or MSB aligned data port
 * enum slim_port_opts: Port options requested.
 * User can request no configuration, packed data, and/or MSB aligned data port
 */
enum slim_port_cfg {
	SLIM_CFG_NONE,
	SLIM_CFG_PACKED,
	SLIM_CFG_ALIGN_MSB,
enum slim_port_opts {
	SLIM_OPT_NONE = 0,
	SLIM_OPT_NO_PACK = 1U,
	SLIM_OPT_ALIGN_MSB = 1U << 1,
};

/* enum slim_port_flow: Port flow type (inbound/outbound). */
@@ -250,6 +250,16 @@ enum slim_port_err {
	SLIM_P_NOT_OWNED,
};

/*
 * struct slim_port_cfg: Port config for the manager port
 * port_opts: port options (bit-map) for this port
 * watermark: watermark level set for this port
 */
struct slim_port_cfg {
	u32 port_opts;
	u32 watermark;
};

/*
 * struct slim_port: Internal structure used by framework to manage ports
 * @err: Port error if any for this port. Refer to enum above.
@@ -267,7 +277,7 @@ struct slim_port {
	enum slim_port_err	err;
	enum slim_port_state	state;
	enum slim_port_req	req;
	enum slim_port_cfg	cfg;
	struct slim_port_cfg	cfg;
	enum slim_port_flow	flow;
	struct slim_ch		*ch;
	struct completion	*xcomp;
@@ -834,6 +844,19 @@ extern int slim_alloc_mgrports(struct slim_device *sb, enum slim_port_req req,
/* Deallocate the port(s) allocated using the API above */
extern int slim_dealloc_mgrports(struct slim_device *sb, u32 *hdl, int hsz);

/*
 * slim_config_mgrports: Configure manager side ports
 * @sb: device/client handle.
 * @ph: array of port handles for which this configuration is valid
 * @nports: Number of ports in ph
 * @cfg: configuration requested for port(s)
 * Configure port settings if they are different than the default ones.
 * Returns success if the config could be applied. Returns -EISCONN if the
 * port is in use
 */
extern int slim_config_mgrports(struct slim_device *sb, u32 *ph, int nports,
				struct slim_port_cfg *cfg);

/*
 * slim_port_xfer: Schedule buffer to be transferred/received using port-handle.
 * @sb: client handle