void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn) { 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)); /* Make sure that port registers are updated before returning */ mb(); }
void msm_hw_set_port(struct msm_slim_ctrl *dev, u8 pn) { 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)); mb(); }
int msm_slim_connect_pipe_port(struct msm_slim_ctrl *dev, u8 pn) { struct msm_slim_endp *endpoint = &dev->pipes[pn]; struct sps_connect *cfg = &endpoint->config; u32 stat; int ret; if (pn >= dev->port_nums) return -ENODEV; endpoint = &dev->pipes[pn]; ret = sps_get_config(dev->pipes[pn].sps, cfg); if (ret) { dev_err(dev->dev, "sps pipe-port get config error%x\n", ret); return ret; } cfg->options = SPS_O_DESC_DONE | SPS_O_ERROR | SPS_O_ACK_TRANSFERS | SPS_O_AUTO_ENABLE; if (dev->pipes[pn].connected && dev->ctrl.ports[pn].state == SLIM_P_CFG) { return -EISCONN; } else if (dev->pipes[pn].connected) { writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn, (endpoint->port_b), dev->ver)); /* Make sure port disabling goes through */ mb(); /* Is pipe already connected in desired direction */ if ((dev->ctrl.ports[pn].flow == SLIM_SRC && 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); return 0; } msm_slim_disconn_pipe_port(dev, pn); } stat = readl_relaxed(PGD_PORT(PGD_PORT_STATn, endpoint->port_b, dev->ver)); if (dev->ctrl.ports[pn].flow == SLIM_SRC) { cfg->destination = dev->bam.hdl; cfg->source = SPS_DEV_HANDLE_MEM; cfg->dest_pipe_index = ((stat & (0xFF << 4)) >> 4); cfg->src_pipe_index = 0; dev_dbg(dev->dev, "flow src:pipe num:%d", cfg->dest_pipe_index); cfg->mode = SPS_MODE_DEST; } else {
irqreturn_t msm_slim_port_irq_handler(struct msm_slim_ctrl *dev, u32 pstat) { int i; u32 int_en = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver)); if ((pstat & int_en) == 0) return IRQ_HANDLED; for (i = dev->port_b; i < MSM_SLIM_NPORTS; i++) { if (pstat & (1 << i)) { u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn, i, dev->ver)); if (val & MSM_PORT_OVERFLOW) { dev->ctrl.ports[i-dev->port_b].err = SLIM_P_OVERFLOW; } else if (val & MSM_PORT_UNDERFLOW) { dev->ctrl.ports[i-dev->port_b].err = SLIM_P_UNDERFLOW; } } } writel_relaxed((int_en & (~pstat)), PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver)); writel_relaxed(pstat, PGD_THIS_EE(PGD_PORT_INT_CL_EEn, dev->ver)); SLIM_INFO(dev, "disabled overflow/underflow for port 0x%x", pstat); mb(); return IRQ_HANDLED; }
static void msm_slim_disconn_pipe_port(struct msm_slim_ctrl *dev, u8 pn) { struct msm_slim_endp *endpoint = &dev->pipes[pn]; struct sps_register_event sps_event; writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn, (pn + dev->port_b), dev->ver)); mb(); memset(&sps_event, 0, sizeof(sps_event)); sps_register_event(endpoint->sps, &sps_event); sps_disconnect(endpoint->sps); dev->pipes[pn].connected = false; }
irqreturn_t msm_slim_port_irq_handler(struct msm_slim_ctrl *dev, u32 pstat) { int i; u32 int_en = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver)); /* * different port-interrupt than what we enabled, ignore. * This may happen if overflow/underflow is reported, but * was disabled due to unavailability of buffers provided by * client. */ if ((pstat & int_en) == 0) return IRQ_HANDLED; for (i = 0; i < dev->port_nums; i++) { struct msm_slim_endp *endpoint = &dev->pipes[i]; if (pstat & (1 << endpoint->port_b)) { u32 val = readl_relaxed(PGD_PORT(PGD_PORT_STATn, endpoint->port_b, dev->ver)); if (val & MSM_PORT_OVERFLOW) { dev->ctrl.ports[i].err = SLIM_P_OVERFLOW; } else if (val & MSM_PORT_UNDERFLOW) { dev->ctrl.ports[i].err = SLIM_P_UNDERFLOW; } } } /* * Disable port interrupt here. Re-enable when more * buffers are provided for this port. */ writel_relaxed((int_en & (~pstat)), PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver)); /* clear port interrupts */ writel_relaxed(pstat, PGD_THIS_EE(PGD_PORT_INT_CL_EEn, dev->ver)); SLIM_INFO(dev, "disabled overflow/underflow for port 0x%x", pstat); /* * Guarantee that port interrupt bit(s) clearing writes go * through before exiting ISR */ mb(); return IRQ_HANDLED; }
static void msm_slim_disconn_pipe_port(struct msm_slim_ctrl *dev, u8 pn) { struct msm_slim_endp *endpoint = &dev->pipes[pn]; struct sps_register_event sps_event; u32 int_port = readl_relaxed(PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver)); writel_relaxed(0, PGD_PORT(PGD_PORT_CFGn, (endpoint->port_b), dev->ver)); writel_relaxed((int_port & ~(1 << endpoint->port_b)), PGD_THIS_EE(PGD_PORT_INT_EN_EEn, dev->ver)); /* Make sure port register is updated */ mb(); memset(&sps_event, 0, sizeof(sps_event)); sps_register_event(endpoint->sps, &sps_event); sps_disconnect(endpoint->sps); dev->pipes[pn].connected = false; }