static int mdp3_dmap_histo_get(struct mdp3_dma *dma, struct mdp3_dma_histogram_data *data) { int i; u32 addr, extra; addr = MDP3_REG_DMA_P_HIST_R_DATA; for (i = 0; i < 32; i++) { data->r_data[i] = MDP3_REG_READ(addr); addr += 4; } addr = MDP3_REG_DMA_P_HIST_G_DATA; for (i = 0; i < 32; i++) { data->g_data[i] = MDP3_REG_READ(addr); addr += 4; } addr = MDP3_REG_DMA_P_HIST_B_DATA; for (i = 0; i < 32; i++) { data->b_data[i] = MDP3_REG_READ(addr); addr += 4; } extra = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_0); data->r_min_value = (extra & 0x1F0000) >> 16; data->r_max_value = (extra & 0x1F000000) >> 24; extra = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_1); data->g_min_value = extra & 0x1F; data->g_max_value = (extra & 0x1F00) >> 8; data->b_min_value = (extra & 0x1F0000) >> 16; data->b_max_value = (extra & 0x1F000000) >> 24; return 0; }
static void mdp3_hist_done_intr_handler(int type, void *arg) { struct mdp3_dma *dma = (struct mdp3_dma *)arg; u32 isr, mask; isr = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_STATUS); mask = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_ENABLE); MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_CLEAR, isr); isr &= mask; if (isr == 0) return; if (isr & MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT) { spin_lock(&dma->histo_lock); dma->histo_state = MDP3_DMA_HISTO_STATE_READY; complete(&dma->histo_comp); spin_unlock(&dma->histo_lock); } if (isr & MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT) { spin_lock(&dma->histo_lock); dma->histo_state = MDP3_DMA_HISTO_STATE_IDLE; complete(&dma->histo_comp); spin_unlock(&dma->histo_lock); } }
void mdp3_dump_dma(void *data) { struct mdp3_dma *dma = (struct mdp3_dma *)data; u32 isr, mask; mdp3_clk_prepare(); mdp3_clk_enable(1, 0); isr = MDP3_REG_READ(MDP3_REG_INTR_STATUS); mask = MDP3_REG_READ(MDP3_REG_INTR_ENABLE); MDSS_TIMEOUT_LOG("-------- MDP3 INTERRUPT DATA ---------\n"); MDSS_TIMEOUT_LOG("MDP3_REG_INTR_STATUS: 0x%08X\n", isr); MDSS_TIMEOUT_LOG("MDP3_REG_INTR_ENABLE: 0x%08X\n", mask); MDSS_TIMEOUT_LOG("global irqs disabled: %d\n", irqs_disabled()); MDSS_TIMEOUT_LOG("------ MDP3 INTERRUPT DATA DONE ------\n"); if (dma) { MDSS_TIMEOUT_LOG("-------- MDP3 DMA DATA ---------\n"); MDSS_TIMEOUT_LOG("vsync_cnt=%u\n", dma->vsync_cnt); MDSS_TIMEOUT_LOG("------ MDP3 DMA DATA DONE ------\n"); } mdp3_clk_enable(0, 0); mdp3_clk_unprepare(); }
static int mdp3_dmap_lut_config(struct mdp3_dma *dma, struct mdp3_dma_lut_config *config, struct mdp3_dma_lut *lut) { u32 cc_config, addr, color; int i; if (config->lut_enable && lut) { addr = MDP3_REG_DMA_P_CSC_LUT1; if (config->lut_sel) addr = MDP3_REG_DMA_P_CSC_LUT2; for (i = 0; i < MDP_LUT_SIZE; i++) { color = lut->color0_lut[i] & 0xff; color |= (lut->color1_lut[i] & 0xff) << 8; color |= (lut->color2_lut[i] & 0xff) << 16; MDP3_REG_WRITE(addr, color); addr += 4; } } cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG); cc_config &= DMA_LUT_CONFIG_MASK; cc_config |= config->lut_enable; cc_config |= config->lut_position << 4; cc_config |= config->lut_sel << 10; MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config); wmb(); dma->lut_config = *config; return 0; }
static void mdp3_dma_clk_auto_gating(struct mdp3_dma *dma, int enable) { u32 cgc; int clock_bit = 10; clock_bit += dma->dma_sel; if (enable) { cgc = MDP3_REG_READ(MDP3_REG_CGC_EN); cgc |= BIT(clock_bit); MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc); } else { cgc = MDP3_REG_READ(MDP3_REG_CGC_EN); cgc &= ~BIT(clock_bit); MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc); } }
static int mdp3_dmap_update(struct mdp3_dma *dma, void *buf, struct mdp3_intf *intf) { unsigned long flag; int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC; int rc = 0; pr_debug("mdp3_dmap_update\n"); if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE; if (intf->active) { rc = wait_for_completion_timeout(&dma->dma_comp, KOFF_TIMEOUT); if (rc <= 0) { WARN(1, "cmd kickoff timed out (%d)\n", rc); rc = -1; } } } if (dma->update_src_cfg) { if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO && intf->active) pr_err("configuring dma source while dma is active\n"); dma->dma_config_source(dma); dma->update_src_cfg = false; } spin_lock_irqsave(&dma->dma_lock, flag); MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_ADDR, (u32)buf); dma->source_config.buf = buf; if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) { mdp3_ccs_update(dma); MDP3_REG_WRITE(MDP3_REG_DMA_P_START, 1); } if (!intf->active) { pr_debug("mdp3_dmap_update start interface\n"); intf->start(intf); } mb(); dma->vsync_status = MDP3_REG_READ(MDP3_REG_INTR_STATUS) & (1 << MDP3_INTR_LCDC_START_OF_FRAME); init_completion(&dma->vsync_comp); spin_unlock_irqrestore(&dma->dma_lock, flag); mdp3_dma_callback_enable(dma, cb_type); pr_debug("mdp3_dmap_update wait for vsync_comp in\n"); if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO) { rc = wait_for_completion_timeout(&dma->vsync_comp, KOFF_TIMEOUT); if (rc <= 0) rc = -1; } pr_debug("mdp3_dmap_update wait for vsync_comp out\n"); return rc; }
static void mdp3_dmas_config_source(struct mdp3_dma *dma) { struct mdp3_dma_source *source_config = &dma->source_config; u32 dma_s_cfg_reg, dma_s_size; dma_s_cfg_reg = MDP3_REG_READ(MDP3_REG_DMA_S_CONFIG); dma_s_cfg_reg &= ~MDP3_DMA_IBUF_FORMAT_MASK; dma_s_cfg_reg |= source_config->format << 25; dma_s_size = source_config->width | (source_config->height << 16); MDP3_REG_WRITE(MDP3_REG_DMA_S_CONFIG, dma_s_cfg_reg); MDP3_REG_WRITE(MDP3_REG_DMA_S_SIZE, dma_s_size); MDP3_REG_WRITE(MDP3_REG_DMA_S_IBUF_Y_STRIDE, source_config->stride); }
static void mdp3_dmap_config_source(struct mdp3_dma *dma) { struct mdp3_dma_source *source_config = &dma->source_config; u32 dma_p_cfg_reg, dma_p_size; dma_p_cfg_reg = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG); dma_p_cfg_reg &= ~MDP3_DMA_IBUF_FORMAT_MASK; dma_p_cfg_reg |= source_config->format << 25; dma_p_cfg_reg &= ~MDP3_DMA_PACK_PATTERN_MASK; dma_p_cfg_reg |= dma->output_config.pack_pattern << 8; dma_p_size = source_config->width | (source_config->height << 16); MDP3_REG_WRITE(MDP3_REG_DMA_P_CONFIG, dma_p_cfg_reg); MDP3_REG_WRITE(MDP3_REG_DMA_P_SIZE, dma_p_size); MDP3_REG_WRITE(MDP3_REG_DMA_P_IBUF_Y_STRIDE, source_config->stride); }
static int mdp3_dmap_histo_reset(struct mdp3_dma *dma) { unsigned long flag; int ret; u32 cgc; if (dma->histo_state == MDP3_DMA_HISTO_STATE_START) return -EINVAL; spin_lock_irqsave(&dma->histo_lock, flag); init_completion(&dma->histo_comp); cgc = MDP3_REG_READ(MDP3_REG_CGC_EN); cgc &= ~BIT(10); MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc); MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_INTR_ENABLE, BIT(0)|BIT(1)); MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_RESET_SEQ_START, 1); wmb(); dma->histo_state = MDP3_DMA_HISTO_STATE_RESET; spin_unlock_irqrestore(&dma->histo_lock, flag); mdp3_dma_callback_enable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE); ret = wait_for_completion_killable_timeout(&dma->histo_comp, msecs_to_jiffies(DMA_HISTO_RESET_TIMEOUT_MS)); if (ret == 0) { pr_err("mdp3_dmap_histo_reset time out\n"); ret = -ETIMEDOUT; } else if (ret < 0) { pr_err("mdp3_dmap_histo_reset interrupted\n"); } else { ret = 0; } mdp3_dma_callback_disable(dma, MDP3_DMA_CALLBACK_TYPE_HIST_RESET_DONE); cgc |= BIT(10); MDP3_REG_WRITE(MDP3_REG_CGC_EN, cgc); return ret; }
static void mdp3_ccs_update(struct mdp3_dma *dma) { u32 cc_config; int updated = 0; cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG); if (dma->ccs_config.ccs_dirty) { cc_config &= DMA_CCS_CONFIG_MASK; if (dma->ccs_config.ccs_enable) cc_config |= BIT(3); else cc_config &= ~BIT(3); cc_config |= dma->ccs_config.ccs_sel << 5; cc_config |= dma->ccs_config.pre_bias_sel << 6; cc_config |= dma->ccs_config.post_bias_sel << 7; cc_config |= dma->ccs_config.pre_limit_sel << 8; cc_config |= dma->ccs_config.post_limit_sel << 9; dma->ccs_config.ccs_dirty = false; updated = 1; } if (dma->lut_config.lut_dirty) { cc_config &= DMA_LUT_CONFIG_MASK; cc_config |= dma->lut_config.lut_enable; cc_config |= dma->lut_config.lut_position << 4; cc_config |= dma->lut_config.lut_sel << 10; dma->lut_config.lut_dirty = false; updated = 1; } if (updated) { MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config); /* Make sure ccs configuration update is done before continuing with the DMA transfer */ wmb(); } }
static int mdp3_dmap_histo_intr_status(struct mdp3_dma *dma, int *status) { *status = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_INTR_STATUS); return 0; }
static int mdp3_dmap_histo_get(struct mdp3_dma *dma) { int i, state, timeout, ret; u32 addr; unsigned long flag; spin_lock_irqsave(&dma->histo_lock, flag); state = dma->histo_state; spin_unlock_irqrestore(&dma->histo_lock, flag); if (state != MDP3_DMA_HISTO_STATE_START && state != MDP3_DMA_HISTO_STATE_READY) { pr_err("mdp3_dmap_histo_get invalid state %d\n", state); return -EINVAL; } timeout = HIST_WAIT_TIMEOUT(dma->histogram_config.frame_count); ret = wait_for_completion_killable_timeout(&dma->histo_comp, timeout); if (ret == 0) { pr_debug("mdp3_dmap_histo_get time out\n"); ret = -ETIMEDOUT; } else if (ret < 0) { pr_err("mdp3_dmap_histo_get interrupted\n"); } if (ret < 0) return ret; if (dma->histo_state != MDP3_DMA_HISTO_STATE_READY) { pr_debug("mdp3_dmap_histo_get after dma shut down\n"); return -EPERM; } addr = MDP3_REG_DMA_P_HIST_R_DATA; for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) { dma->histo_data.r_data[i] = MDP3_REG_READ(addr); addr += 4; } addr = MDP3_REG_DMA_P_HIST_G_DATA; for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) { dma->histo_data.g_data[i] = MDP3_REG_READ(addr); addr += 4; } addr = MDP3_REG_DMA_P_HIST_B_DATA; for (i = 0; i < MDP_HISTOGRAM_BIN_NUM; i++) { dma->histo_data.b_data[i] = MDP3_REG_READ(addr); addr += 4; } dma->histo_data.extra[0] = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_0); dma->histo_data.extra[1] = MDP3_REG_READ(MDP3_REG_DMA_P_HIST_EXTRA_INFO_1); spin_lock_irqsave(&dma->histo_lock, flag); init_completion(&dma->histo_comp); MDP3_REG_WRITE(MDP3_REG_DMA_P_HIST_START, 1); wmb(); dma->histo_state = MDP3_DMA_HISTO_STATE_START; spin_unlock_irqrestore(&dma->histo_lock, flag); return 0; }
static int mdp3_dmap_ccs_config(struct mdp3_dma *dma, struct mdp3_dma_color_correct_config *config, struct mdp3_dma_ccs *ccs) { int i; u32 cc_config, addr; cc_config = MDP3_REG_READ(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG); cc_config &= DMA_CCS_CONFIG_MASK; cc_config |= BIT(3); cc_config |= config->ccs_sel << 5; cc_config |= config->pre_bias_sel << 6; cc_config |= config->post_bias_sel << 7; cc_config |= config->pre_limit_sel << 8; cc_config |= config->post_limit_sel << 9; MDP3_REG_WRITE(MDP3_REG_DMA_P_COLOR_CORRECT_CONFIG, cc_config); if (config->ccs_enable && ccs) { if (ccs->mv1) { addr = MDP3_REG_DMA_P_CSC_MV1; for (i = 0; i < 9; i++) { MDP3_REG_WRITE(addr, ccs->mv1[i]); addr += 4; } } if (ccs->mv2) { addr = MDP3_REG_DMA_P_CSC_MV2; for (i = 0; i < 9; i++) { MDP3_REG_WRITE(addr, ccs->mv2[i]); addr += 4; } } if (ccs->pre_bv1) { addr = MDP3_REG_DMA_P_CSC_PRE_BV1; for (i = 0; i < 3; i++) { MDP3_REG_WRITE(addr, ccs->pre_bv1[i]); addr += 4; } } if (ccs->pre_bv2) { addr = MDP3_REG_DMA_P_CSC_PRE_BV2; for (i = 0; i < 3; i++) { MDP3_REG_WRITE(addr, ccs->pre_bv2[i]); addr += 4; } } if (ccs->post_bv1) { addr = MDP3_REG_DMA_P_CSC_POST_BV1; for (i = 0; i < 3; i++) { MDP3_REG_WRITE(addr, ccs->post_bv1[i]); addr += 4; } } if (ccs->post_bv2) { addr = MDP3_REG_DMA_P_CSC_POST_BV2; for (i = 0; i < 3; i++) { MDP3_REG_WRITE(addr, ccs->post_bv2[i]); addr += 4; } } if (ccs->pre_lv1) { addr = MDP3_REG_DMA_P_CSC_PRE_LV1; for (i = 0; i < 6; i++) { MDP3_REG_WRITE(addr, ccs->pre_lv1[i]); addr += 4; } } if (ccs->pre_lv2) { addr = MDP3_REG_DMA_P_CSC_PRE_LV2; for (i = 0; i < 6; i++) { MDP3_REG_WRITE(addr, ccs->pre_lv2[i]); addr += 4; } } if (ccs->post_lv1) { addr = MDP3_REG_DMA_P_CSC_POST_LV1; for (i = 0; i < 6; i++) { MDP3_REG_WRITE(addr, ccs->post_lv1[i]); addr += 4; } } if (ccs->post_lv2) { addr = MDP3_REG_DMA_P_CSC_POST_LV2; for (i = 0; i < 6; i++) { MDP3_REG_WRITE(addr, ccs->post_lv2[i]); addr += 4; } } } dma->ccs_config = *config; return 0; }