slim-msm: Configure push pull protocol on MSM Controller

Configures push pull protocol parameters on
MSM controller. It makes sure to program the
push pull protocol per channel in the framework.
Irresepective of client request, configure to
ISO protocol if channel frequency is multiple
of super frame frequency.

Change-Id: I7f9fc4d7af682d27f617d0220bab2d9b79ade6c8
Signed-off-by: Dilip Kota <dkota@codeaurora.org>
This commit is contained in:
Dilip Kota 2015-02-03 19:21:31 +05:30 committed by Dilip Kota
parent 99312a09ac
commit 9d1a97fab0
3 changed files with 92 additions and 14 deletions

View File

@ -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,35 @@ 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 port_b, u8 pn)
{
struct slim_controller *ctrl;
struct slim_ch *chan;
struct msm_slim_pshpull_parm *parm;
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));
if (!dev) {
pr_err("%s:Dev node is null\n", __func__);
return;
}
if (pn >= dev->port_nums) {
pr_err("%s:Invalid port\n", __func__);
return;
}
ctrl = &dev->ctrl;
chan = ctrl->ports[pn].ch;
parm = &dev->pipes[pn].psh_pull;
writel_relaxed(set_cfg, PGD_PORT(PGD_PORT_CFGn, port_b, dev->ver));
writel_relaxed(DEF_BLKSZ, PGD_PORT(PGD_PORT_BLKn, port_b, dev->ver));
writel_relaxed(DEF_TRANSZ, PGD_PORT(PGD_PORT_TRANn, port_b, 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,
port_b, dev->ver));
}
/* Make sure that port registers are updated before returning */
mb();
}
@ -212,15 +236,50 @@ 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;
return;
}
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);
@ -231,6 +290,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;
@ -244,7 +306,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);
@ -279,7 +341,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;
}

View File

@ -194,6 +194,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;
@ -201,6 +211,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 {
@ -368,7 +379,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 pn, u8 port_no);
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);

View File

@ -1317,6 +1317,7 @@ static int disconnect_port_ch(struct slim_controller *ctrl, u32 ph)
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;
}
@ -1341,6 +1342,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)
@ -1349,7 +1351,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;
@ -1370,7 +1371,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)
@ -1429,8 +1430,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]);
@ -1623,8 +1626,10 @@ 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;