static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { int rc; struct mdss_dsi_ctrl_pdata *mctrl = NULL; if (&ctrl->mmss_misc_io == NULL) { pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__); return -EINVAL; } if (mdss_dsi_is_slave_ctrl(ctrl)) { mctrl = mdss_dsi_get_master_ctrl(); if (!mctrl) { pr_err("%s: Unable to get master control\n", __func__); return -EINVAL; } } if (mctrl) { pr_debug("%s: configuring ulps (%s) for master ctrl%d\n", __func__, (enable ? "on" : "off"), ctrl->ndx); rc = mdss_dsi_ulps_config_sub(mctrl, enable, 0); if (rc) return rc; } pr_debug("%s: configuring ulps (%s) for ctrl%d\n", __func__, (enable ? "on" : "off"), ctrl->ndx); return mdss_dsi_ulps_config_sub(ctrl, enable, 0); }
/* * mdss_dsi_cmds_tx: * thread context only */ int mdss_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int cnt) { int ret = 0; bool ctrl_restore = false, mctrl_restore = false; struct mdss_dsi_ctrl_pdata *mctrl = NULL; /* * In broadcast mode, the configuration for master controller * would be done when the slave controller is configured */ if (mdss_dsi_is_master_ctrl(ctrl)) { pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n", __func__, ctrl->ndx); return 0; } /* * Turn on cmd mode in order to transmit the commands. * For video mode, do not send cmds more than one pixel line, * since it only transmit it during BLLP. * Ensure that for slave controller, master is also configured */ if (mdss_dsi_is_slave_ctrl(ctrl)) { mctrl = mdss_dsi_get_master_ctrl(); if (!mctrl) pr_warn("%s: Unable to get master control\n", __func__); else mctrl_restore = __mdss_dsi_cmd_mode_config(mctrl, 1); } ctrl_restore = __mdss_dsi_cmd_mode_config(ctrl, 1); ret = mdss_dsi_cmds2buf_tx(ctrl, cmds, cnt); if (IS_ERR_VALUE(ret)) { pr_err("%s: failed to call\n", __func__); cnt = -EINVAL; } if (mctrl_restore) __mdss_dsi_cmd_mode_config(mctrl, 0); if (ctrl_restore) __mdss_dsi_cmd_mode_config(ctrl, 0); return cnt; }
void mdss_dsi_op_mode_config(int mode, struct mdss_panel_data *pdata) { u32 dsi_ctrl, intr_ctrl; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_dsi_ctrl_pdata *mctrl = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); /* * In broadcast mode, the configuration for master controller * would be done when the slave controller is configured */ if (mdss_dsi_is_master_ctrl(ctrl_pdata)) { pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n", __func__, ctrl_pdata->ndx); return; } dsi_ctrl = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0004); /*If Video enabled, Keep Video and Cmd mode ON */ if (dsi_ctrl & 0x02) dsi_ctrl &= ~0x05; else dsi_ctrl &= ~0x07; if (mode == DSI_VIDEO_MODE) { dsi_ctrl |= 0x03; intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_BTA_DONE_MASK; } else { /* command mode */ dsi_ctrl |= 0x05; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) dsi_ctrl |= 0x02; intr_ctrl = DSI_INTR_CMD_DMA_DONE_MASK | DSI_INTR_ERROR_MASK | DSI_INTR_CMD_MDP_DONE_MASK | DSI_INTR_BTA_DONE_MASK; } /* Ensure that for slave controller, master is also configured */ if (mdss_dsi_is_slave_ctrl(ctrl_pdata)) { mctrl = mdss_dsi_get_master_ctrl(); if (mctrl) { pr_debug("%s: configuring ctrl%d\n", __func__, mctrl->ndx); MIPI_OUTP(mctrl->ctrl_base + 0x0110, intr_ctrl); MIPI_OUTP(mctrl->ctrl_base + 0x0004, dsi_ctrl); } else { pr_warn("%s: Unable to get master control\n", __func__); } } pr_debug("%s: configuring ctrl%d\n", __func__, ctrl_pdata->ndx); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0110, intr_ctrl); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0004, dsi_ctrl); wmb(); }
/* * mdss_dsi_cmds_rx() - dcs read from panel * @ctrl: dsi controller * @cmds: read command descriptor * @len: number of bytes to read back * * controller have 4 registers can hold 16 bytes of rxed data * dcs packet: 4 bytes header + payload + 2 bytes crc * 2 padding bytes add to payload to have payload length is mutipled by 4 * 1st read: 4 bytes header + 8 bytes payload + 2 padding + 2 crc * 2nd read: 12 bytes payload + 2 padding + 2 crc * 3rd read: 12 bytes payload + 2 padding + 2 crc * */ int mdss_dsi_cmds_rx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_cmd_desc *cmds, int rlen) { int data_byte, rx_byte, dlen, end; int short_response, diff, pkt_size, ret = 0; struct dsi_buf *tp, *rp; char cmd; bool ctrl_restore = false, mctrl_restore = false; struct mdss_dsi_ctrl_pdata *mctrl = NULL; /* * In broadcast mode, the configuration for master controller * would be done when the slave controller is configured */ if (mdss_dsi_is_master_ctrl(ctrl)) { pr_debug("%s: Broadcast mode enabled. skipping config for ctrl%d\n", __func__, ctrl->ndx); return 0; } /* * Turn on cmd mode in order to transmit the commands. * For video mode, do not send cmds more than one pixel line, * since it only transmit it during BLLP. * Ensure that for slave controller, master is also configured */ if (mdss_dsi_is_slave_ctrl(ctrl)) { mctrl = mdss_dsi_get_master_ctrl(); if (!mctrl) pr_warn("%s: Unable to get master control\n", __func__); else mctrl_restore = __mdss_dsi_cmd_mode_config(mctrl, 1); } ctrl_restore = __mdss_dsi_cmd_mode_config(ctrl, 1); if (rlen <= 2) { short_response = 1; rx_byte = 4; } else { short_response = 0; data_byte = 8; /* first read */ /* * add extra 2 padding bytes to have overall * packet size is multipe by 4. This also make * sure 4 bytes dcs headerlocates within a * 32 bits register after shift in. */ pkt_size = data_byte + 2; rx_byte = data_byte + 8; /* 4 header + 2 crc + 2 padding*/ } tp = &ctrl->tx_buf; rp = &ctrl->rx_buf; end = 0; mdss_dsi_buf_init(rp); while (!end) { pr_debug("%s: rlen=%d pkt_size=%d rx_byte=%d\n", __func__, rlen, pkt_size, rx_byte); if (!short_response) { max_pktsize[0] = pkt_size; mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, &pkt_size_cmd); if (!ret) { pr_err("%s: failed to add max_pkt_size\n", __func__); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx max_pkt_size\n", __func__); rp->len = 0; goto end; } pr_debug("%s: max_pkt_size=%d sent\n", __func__, pkt_size); } mdss_dsi_buf_init(tp); ret = mdss_dsi_cmd_dma_add(tp, cmds); if (!ret) { pr_err("%s: failed to add cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } mdss_dsi_wait4video_eng_busy(ctrl); /* video mode only */ mdss_dsi_enable_irq(ctrl, DSI_CMD_TERM); /* transmit read comamnd to client */ ret = mdss_dsi_cmd_dma_tx(ctrl, tp); if (IS_ERR_VALUE(ret)) { mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); pr_err("%s: failed to tx cmd = 0x%x\n", __func__, cmds->payload[0]); rp->len = 0; goto end; } /* * once cmd_dma_done interrupt received, * return data from client is ready and stored * at RDBK_DATA register already * since rx fifo is 16 bytes, dcs header is kept at first loop, * after that dcs header lost during shift into registers */ dlen = mdss_dsi_cmd_dma_rx(ctrl, rp, rx_byte); if (short_response) break; if (rlen <= data_byte) { diff = data_byte - rlen; end = 1; } else { diff = 0; rlen -= data_byte; } dlen -= 2; /* 2 padding bytes */ dlen -= 2; /* 2 crc */ dlen -= diff; rp->data += dlen; /* next start position */ rp->len += dlen; data_byte = 12; /* NOT first read */ pkt_size += data_byte; pr_debug("%s: rp data=%x len=%d dlen=%d diff=%d\n", __func__, (int) (unsigned long) rp->data, rp->len, dlen, diff); } rp->data = rp->start; /* move back to start position */ cmd = rp->data[0]; switch (cmd) { case DTYPE_ACK_ERR_RESP: pr_debug("%s: rx ACK_ERR_PACLAGE\n", __func__); rp->len = 0; case DTYPE_GEN_READ1_RESP: case DTYPE_DCS_READ1_RESP: mdss_dsi_short_read1_resp(rp); break; case DTYPE_GEN_READ2_RESP: case DTYPE_DCS_READ2_RESP: mdss_dsi_short_read2_resp(rp); break; case DTYPE_GEN_LREAD_RESP: case DTYPE_DCS_LREAD_RESP: mdss_dsi_long_read_resp(rp); break; default: pr_warning("%s:Invalid response cmd\n", __func__); rp->len = 0; } end: if (mctrl_restore) __mdss_dsi_cmd_mode_config(mctrl, 0); if (ctrl_restore) __mdss_dsi_cmd_mode_config(ctrl, 0); return rp->len; }
irqreturn_t mdss_dsi_isr(int irq, void *ptr) { u32 isr; struct mdss_dsi_ctrl_pdata *ctrl = (struct mdss_dsi_ctrl_pdata *)ptr; struct mdss_dsi_ctrl_pdata *mctrl = NULL; if (!ctrl->ctrl_base) { pr_err("%s:%d DSI base adr no Initialized", __func__, __LINE__); return IRQ_HANDLED; } isr = MIPI_INP(ctrl->ctrl_base + 0x0110);/* DSI_INTR_CTRL */ MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr); if (mdss_dsi_is_slave_ctrl(ctrl)) { mctrl = mdss_dsi_get_master_ctrl(); if (mctrl) { u32 isr0; isr0 = MIPI_INP(mctrl->ctrl_base + 0x0110); if (isr0 & DSI_INTR_CMD_DMA_DONE) MIPI_OUTP(mctrl->ctrl_base + 0x0110, DSI_INTR_CMD_DMA_DONE); } else { pr_warn("%s: Unable to get master control\n", __func__); } } pr_debug("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr); if (isr & DSI_INTR_ERROR) { MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x97); pr_err("%s: ndx=%d isr=%x\n", __func__, ctrl->ndx, isr); mdss_dsi_error(ctrl); } if (isr & DSI_INTR_VIDEO_DONE) { spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM); complete(&ctrl->video_comp); spin_unlock(&ctrl->mdp_lock); } if (isr & DSI_INTR_CMD_DMA_DONE) { MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x98); spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM); complete(&ctrl->dma_comp); spin_unlock(&ctrl->mdp_lock); } if (isr & DSI_INTR_CMD_MDP_DONE) { MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x99); spin_lock(&ctrl->mdp_lock); ctrl->mdp_busy = false; mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); complete(&ctrl->mdp_comp); spin_unlock(&ctrl->mdp_lock); } if (isr & DSI_INTR_BTA_DONE) { spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_BTA_TERM); complete(&ctrl->bta_comp); spin_unlock(&ctrl->mdp_lock); } return IRQ_HANDLED; }
static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, struct dsi_buf *tp) { int len, ret = 0; int domain = MDSS_IOMMU_DOMAIN_UNSECURE; char *bp; unsigned long size; dma_addr_t addr; struct mdss_dsi_ctrl_pdata *mctrl = NULL; #ifdef DEBUG_CMD int i; bp = tp->data; pr_info("%s: ", __func__); for (i = 0; i < tp->len; i++) printk("%x ", *bp++); pr_info("\n"); #endif bp = tp->data; len = ALIGN(tp->len, 4); size = ALIGN(tp->len, SZ_4K); if (is_mdss_iommu_attached()) { ret = msm_iommu_map_contig_buffer(tp->dmap, mdss_get_iommu_domain(domain), 0, size, SZ_4K, 0, &(addr)); if (IS_ERR_VALUE(ret)) { pr_err("unable to map dma memory to iommu(%d)\n", ret); return -ENOMEM; } } else { addr = tp->dmap; } INIT_COMPLETION(ctrl->dma_comp); /* Ensure that for slave controller, master is also configured */ if (mdss_dsi_is_slave_ctrl(ctrl)) { mctrl = mdss_dsi_get_master_ctrl(); if (mctrl) { MIPI_OUTP(mctrl->ctrl_base + 0x048, addr); MIPI_OUTP(mctrl->ctrl_base + 0x04c, len); } else { pr_warn("%s: Unable to get master control\n", __func__); } } MIPI_OUTP((ctrl->ctrl_base) + 0x048, addr); MIPI_OUTP((ctrl->ctrl_base) + 0x04c, len); wmb(); /* Trigger on master controller as well */ if (mctrl) MIPI_OUTP(mctrl->ctrl_base + 0x090, 0x01); MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01); wmb(); ret = wait_for_completion_timeout(&ctrl->dma_comp, msecs_to_jiffies(DMA_TX_TIMEOUT)); if (ret == 0) ret = -ETIMEDOUT; else ret = tp->len; if (is_mdss_iommu_attached()) msm_iommu_unmap_contig_buffer(addr, mdss_get_iommu_domain(domain), 0, size); return ret; }
int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type, int enable) { int rc = 0; int link_changed = 0, bus_changed = 0; int m_link_changed = 0, m_bus_changed = 0; struct mdss_dsi_ctrl_pdata *mctrl = NULL; if (!ctrl) { pr_err("%s: Invalid arg\n", __func__); return -EINVAL; } /* * In broadcast mode, we need to enable clocks for the * master controller as well when enabling clocks for the * slave controller */ if (mdss_dsi_is_slave_ctrl(ctrl)) { mctrl = mdss_dsi_get_master_ctrl(); if (!mctrl) pr_warn("%s: Unable to get master control\n", __func__); } pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d\n", __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt, ctrl->link_clk_cnt); pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, enable=%d\n", __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1, mctrl ? mctrl->link_clk_cnt : -1, enable); mutex_lock(&dsi_clk_lock); if (clk_type & DSI_BUS_CLKS) { bus_changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable); if (bus_changed && mctrl) m_bus_changed = __mdss_dsi_update_clk_cnt( &mctrl->bus_clk_cnt, enable); } if (clk_type & DSI_LINK_CLKS) { link_changed = __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable); if (link_changed && mctrl) m_link_changed = __mdss_dsi_update_clk_cnt( &mctrl->link_clk_cnt, enable); } if (!link_changed && !bus_changed) goto no_error; /* clk cnts updated, nothing else needed */ /* * If updating link clock, need to make sure that the bus * clocks are enabled */ if (link_changed && (!bus_changed && !ctrl->bus_clk_cnt)) { pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d", __func__, mctrl->ndx); goto error_mctrl_start; } if (m_link_changed && (!m_bus_changed && !mctrl->bus_clk_cnt)) { pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d", __func__, ctrl->ndx); goto error_mctrl_start; } if (enable && (m_bus_changed || m_link_changed)) { rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable); if (rc) { pr_err("Failed to start mctrl clocks. rc=%d\n", rc); goto error_mctrl_start; } } if (!enable && (m_bus_changed || m_link_changed)) { rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable); if (rc) { pr_err("Failed to stop mctrl clocks. rc=%d\n", rc); goto error_mctrl_stop; } } rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable); if (rc) { pr_err("Failed to %s ctrl clocks. rc=%d\n", (enable ? "start" : "stop"), rc); goto error_ctrl; } goto no_error; error_mctrl_stop: mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1); error_ctrl: if (enable && (m_bus_changed || m_link_changed)) mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0); error_mctrl_start: if (clk_type & DSI_BUS_CLKS) { if (mctrl) __mdss_dsi_update_clk_cnt(&mctrl->bus_clk_cnt, enable ? 0 : 1); __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable ? 0 : 1); } if (clk_type & DSI_LINK_CLKS) { if (mctrl) __mdss_dsi_update_clk_cnt(&mctrl->link_clk_cnt, enable ? 0 : 1); __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable ? 0 : 1); } no_error: mutex_unlock(&dsi_clk_lock); pr_debug("%s--: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d\n", __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt, ctrl->link_clk_cnt, link_changed && bus_changed); pr_debug("%s--: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, m_changed=%d, enable=%d\n", __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1, mctrl ? mctrl->link_clk_cnt : -1, m_link_changed && m_bus_changed, enable); return rc; }
int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type, int enable) { int rc = 0; int changed = 0, m_changed = 0; struct mdss_dsi_ctrl_pdata *mctrl = NULL; if (!ctrl) { pr_err("%s: Invalid arg\n", __func__); return -EINVAL; } /* * In broadcast mode, we need to enable clocks for the * master controller as well when enabling clocks for the * slave controller */ if (mdss_dsi_is_slave_ctrl(ctrl)) { mctrl = mdss_dsi_get_master_ctrl(); if (!mctrl) pr_warn("%s: Unable to get master control\n", __func__); } pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d", __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt, ctrl->link_clk_cnt); pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, enable=%d\n", __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1, mctrl ? mctrl->link_clk_cnt : -1, enable); mutex_lock(&dsi_clk_lock); if (clk_type & DSI_BUS_CLKS) { changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable); if (changed && mctrl) m_changed = __mdss_dsi_update_clk_cnt( &mctrl->bus_clk_cnt, enable); } if (clk_type & DSI_LINK_CLKS) { changed += __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable); if (changed && mctrl) m_changed += __mdss_dsi_update_clk_cnt( &mctrl->link_clk_cnt, enable); } #if defined (CONFIG_FB_MSM_MDSS_DSI_DBG) xlog(__func__,ctrl->ndx, enable,changed,m_changed,ctrl->bus_clk_cnt,mctrl?mctrl->bus_clk_cnt:0xbbb); #endif if (changed) { if (enable && m_changed) { rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable); if (rc) { pr_err("Failed to start mctrl clocks. rc=%d\n", rc); goto error_mctrl_start; } } rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable); if (rc) { pr_err("Failed to %s ctrl clocks. rc=%d\n", (enable ? "start" : "stop"), rc); goto error_ctrl; } if (!enable && m_changed) { rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable); if (rc) { pr_err("Failed to stop mctrl clocks. rc=%d\n", rc); goto error_mctrl_stop; } } } goto no_error; error_mctrl_stop: mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1); error_ctrl: if (enable && m_changed) mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0); error_mctrl_start: if (clk_type & DSI_BUS_CLKS) { if (mctrl) __mdss_dsi_update_clk_cnt(&mctrl->bus_clk_cnt, enable ? 0 : 1); __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable ? 0 : 1); } if (clk_type & DSI_LINK_CLKS) { if (mctrl) __mdss_dsi_update_clk_cnt(&mctrl->link_clk_cnt, enable ? 0 : 1); __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable ? 0 : 1); } no_error: mutex_unlock(&dsi_clk_lock); pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d", __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt, ctrl->link_clk_cnt, changed); pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, m_changed=%d, enable=%d\n", __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1, mctrl ? mctrl->link_clk_cnt : -1, m_changed, enable); return rc; }