/** * @file sdrv_dc_drv.c * @brief sdrv dc driver source. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #define DC_NO_UPDATE 0x0000 #define DC_GP_UPDATE 0x0001 #define DC_SP_UPDATE 0x0002 #define DC_DP0_UPDATE 0x0004 #define DC_DP1_UPDATE 0x0004 #define DC_TCON_UPDATE 0x0008 #define DC_MLC_UPDATE 0x0010 #define DC_GAMMA_UPDATE 0x0020 #define DC_DITHER_UPDATE 0x0040 #define DC_CSC_UPDATE 0x0080 #define DC_CRC_UPDATE 0x0800 #define POLYNOMIAL 0x04c11db7L static unsigned int crc_table[256] = {0}; static const unsigned int csc_param[5][15] = { {/*bt601 YCbCr to RGB(0-255)*/ 0x094F, 0x0000, 0x0CC4, 0x094F, 0x3CE0, 0x397F, 0x094F, 0x1024, 0x0000, 0x0000, 0x0000, 0x0000, 0x0040, 0x0200, 0x0200}, {/*basic YUV to RGB*/ 0x0800, 0x0000, 0x091E, 0x0800, 0x7CD8, 0x7B5B, 0x0800, 0x1041, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, {/*bt709 YCbCr to RGB(16-235)*/ 0x0800, 0x0000, 0x0C51, 0x0800, 0x3E8A, 0x3C54, 0x0800, 0x0E87, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0200}, {/*RGB to YCbCr*/ 0x0000}, {/*RGB to YUV*/ 0x0000}}; static unsigned int dc_triggle_type = DC_NO_UPDATE; struct tcon_timing t_timing; static unsigned int get_l_addr(unsigned long addr) { unsigned int addr_l; addr_l = (unsigned int)(addr & 0x00000000FFFFFFFF); return addr_l; } static unsigned int get_h_addr(unsigned long addr) { unsigned int addr_h; addr_h = (unsigned int)(addr & 0xFFFFFFFF00000000); return addr_h; } unsigned int get_csi_dc_ratio_num(int ratio) { unsigned int ret = 0; switch (ratio) { case CSI_DC_1_1: ret = 1; break; case CSI_DC_1_2: ret = 2; break; case CSI_DC_1_3: ret = 3; break; case CSI_DC_1_4: ret = 4; break; default: DISPSS_LOG_INFO("csi_dc ratio param err"); break; } return ret; } static void timing_to_tcon_timing(struct display_timing *timing, struct tcon_timing *t_timing) { DISPSS_LOG_INFO("LCD Timing:"); DISPSS_LOG_INFO("hact: %d, hsync: %d, hfp: %d, hbp: %d", timing->hactive, timing->hsync_len, timing->hfront_porch, timing->hback_porch); DISPSS_LOG_INFO("vact: %d, vsync: %d, vfp: %d, vbp: %d", timing->vactive, timing->vsync_len, timing->vfront_porch, timing->vback_porch); t_timing->hact = timing->hactive; t_timing->hsync = timing->hsync_len; t_timing->hsbp = timing->hsync_len + timing->hback_porch; t_timing->htol = timing->hactive + timing->hfront_porch + timing->hsync_len + timing->hback_porch; t_timing->vact = timing->vactive; t_timing->vsync = timing->vsync_len; t_timing->vsbp = timing->vsync_len + timing->vback_porch; t_timing->vtol = timing->vactive + timing->vfront_porch + timing->vsync_len + timing->vback_porch; DISPSS_LOG_INFO("Tcon Timing:"); DISPSS_LOG_INFO("hact: %d, hsync: %d, hsbp: %d, htol: %d", t_timing->hact, t_timing->hsync, t_timing->hsbp, t_timing->htol); DISPSS_LOG_INFO("vact: %d, vsync: %d, vsbp: %d, vtol: %d", t_timing->vact, t_timing->vsync, t_timing->vsbp, t_timing->vtol); } static void dc_sp_sdw_triggle(struct dc_dev *dev) { unsigned long base = dev->base; disp_write(base, DC_RDF00(0), 1); } static void dc_gp_sdw_triggle(struct dc_dev *dev) { unsigned long base = dev->base; disp_write(base, DC_RCF00, 1); } static void dc_force_update(struct dc_dev *dev) { static bool first_triggle = false; unsigned long base = dev->base; if (!first_triggle) { first_triggle = true; disp_write(base, DC_RA008, 1); } } static void dc_triggle(struct dc_dev *dev) { unsigned val = 0; unsigned long base = dev->base; if (dc_triggle_type & DC_SP_UPDATE) dc_sp_sdw_triggle(dev); if (dc_triggle_type & DC_GP_UPDATE) dc_gp_sdw_triggle(dev); if (dc_triggle_type & (DC_MLC_UPDATE | DC_CSC_UPDATE | DC_GAMMA_UPDATE | DC_DITHER_UPDATE)) val = reg_value(1, val, DC_SHIFT01_RA004, DC_MASK01_RA004); if (dc_triggle_type & DC_CRC_UPDATE) val = reg_value(1, val, DC_SHIFT03_RA004, DC_MASK03_RA004); if (dc_triggle_type & DC_TCON_UPDATE) val = reg_value(1, val, DC_SHIFT02_RA004, DC_MASK02_RA004); disp_write(base, DC_RA004, val); val = reg_value(1, val, DC_SHIFT00_RA004, DC_MASK00_RA004); disp_write(base, DC_RA004, val); dc_triggle_type = DC_NO_UPDATE; dc_force_update(dev); } static unsigned int dc_check_triggle_status(struct dc_dev *dev) { unsigned int val = 0; unsigned long base = dev->base; val = disp_read(base, DC_RA004); return val & 0x1; } static void dc_ms_mode(struct dc_dev *dev) { unsigned long base = dev->base; unsigned int val = 0; val = disp_read(base, DC_RA000); val = reg_value(0, val, DC_SHIFT01_RA000, DC_MASK01_RA000); disp_write(base, DC_RA000, val); } static void dc_irq_disable(struct dc_dev *dev) { unsigned long base = dev->base; disp_write(base, DC_RA020, DC_INIT_DEF_MASK); disp_write(base, DC_RA120, DC_INIT_DEF_MASK); disp_write(base, DC_RJ008, 0); } static void dc_irq_init(struct dc_dev *dev) { unsigned long base = dev->base; unsigned int val = 0; /*enable crc32 error irq*/ val = 0xFF << DC_SHIFT08_RJ004; disp_write(base, DC_RJ008, val); } static void dc_rdma_init(struct dc_dev *dev) { const unsigned short wml_cfg[] = {0x40, 0x10, 0x10, 0x20}; const unsigned short d_depth_cfg[] = {8, 2, 2, 4}; const unsigned short c_depth_cfg[] = {4, 1, 1, 2}; const unsigned char sche_cfg[] = {0x04, 0x01, 0x01, 0x04}; const unsigned char p1_cfg[] = {0x30, 0x20, 0x20, 0x30}; const unsigned char p0_cfg[] = {0x10, 0x08, 0x08, 0x10}; const unsigned char burst_mode_cfg[] = {0x00, 0x00, 0x00, 0x00}; const unsigned char burst_len_cfg[] = {0x04, 0x04, 0x04, 0x04}; const unsigned char wml_req_inv[] = {0xa0, 0xa0, 0xa0, 0xa0}; const unsigned char wml_down[] = {1, 1, 1, 1}; const unsigned char wml_up[] = {6, 6, 6, 6}; unsigned int val; unsigned long base = dev->base; for (int i = 0; i < RDMA_CHN_COUNT; i++) { disp_write(base, DC_RB000(i), wml_cfg[i]); } disp_write(base, DC_RB400(0), wml_cfg[3]); for (int i = 0; i < RDMA_CHN_COUNT; i++) { disp_write(base, DC_RB004(i), d_depth_cfg[i]); } disp_write(base, DC_RB404(0), d_depth_cfg[3]); for (int i = 0; i < RDMA_CHN_COUNT; i++) { disp_write(base, DC_RB008(i), c_depth_cfg[i]); } disp_write(base, DC_RB408(0), c_depth_cfg[3]); for (int i = 0; i < RDMA_CHN_COUNT; i++) { val = reg_value(sche_cfg[i], 0, DC_SHIFT16_RB00C, DC_MASK16_RB00C); val = reg_value(p1_cfg[i], val, DC_SHIFT08_RB00C, DC_MASK08_RB00C); val = reg_value(p0_cfg[i], val, DC_SHIFT00_RB00C, DC_MASK00_RB00C); disp_write(base, DC_RB00C(i), val); disp_write(base, DC_RB40C(i), val); } for (int i = 0; i < RDMA_CHN_COUNT; i++) { val = reg_value(burst_mode_cfg[i], 0, DC_SHIFT03_RB010, DC_MASK03_RB010); val = reg_value(burst_len_cfg[i], val, DC_SHIFT00_RB010, DC_MASK00_RB010); disp_write(base, DC_RB010(i), val); disp_write(base, DC_RB410(i), val); } for (int i = 0; i < RDMA_CHN_COUNT; i++) { val = reg_value(wml_req_inv[i], 0, DC_SHIFT16_RB01C, DC_MASK16_RB01C); val = reg_value(wml_down[i], val, DC_SHIFT04_RB01C, DC_MASK04_RB01C); val = reg_value(wml_up[i], val, DC_SHIFT00_RB01C, DC_MASK00_RB01C); disp_write(base, DC_RB01C(i), val); disp_write(base, DC_RB41C(i), val); } disp_write(base, DC_RB220, RDMA_INT_DEF_MASK); disp_write(base, DC_RB620, RDMA_INT_DEF_MASK); val = reg_value(1, 0, DC_SHIFT01_RB100, DC_MASK01_RB100); val = reg_value(1, val, DC_SHIFT00_RB100, DC_MASK00_RB100); disp_write(base, DC_RB100, val); disp_write(base, DC_RB500, val); } /*NOTE: Timing regs value = real vaule minus 1*/ static void dc_set_tcon_timing(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; unsigned int kick_x, kick_y; timing_to_tcon_timing(dev->panel->timing, &t_timing); /* Horizontal active size && total horizontal size in pixels */ val = reg_value(t_timing.hact - 1, 0, DC_SHIFT16_RG000, DC_MASK16_RG000); val = reg_value(t_timing.htol - 1, val, DC_SHIFT00_RG000, DC_MASK00_RG000); disp_write(base, DC_RG000, val); /*Horizontal back porch size && wdith of hsync pulse in pixels.*/ val = reg_value(t_timing.hsbp - 1, 0, DC_SHIFT16_RG004, DC_MASK16_RG004); val = reg_value(t_timing.hsync - 1, val, DC_SHIFT00_RG004, DC_MASK00_RG004); disp_write(base, DC_RG004, val); /*Vertical active size && total vertical size in lines.*/ val = reg_value(t_timing.vact - 1, 0, DC_SHIFT16_RG008, DC_MASK16_RG008); val = reg_value(t_timing.vtol - 1, val, DC_SHIFT00_RG008, DC_MASK00_RG008); disp_write(base, DC_RG008, val); /*Vertical back porch size && width of vsync pulse in lines.*/ val = reg_value(t_timing.vsbp - 1, 0, DC_SHIFT16_RG00C, DC_MASK16_RG00C); val = reg_value(t_timing.vsync - 1, val, DC_SHIFT00_RG00C, DC_MASK00_RG00C); disp_write(base, DC_RG00C, val); /*TCON TRCL*/ val = reg_value(0, 0, DC_SHIFT06_RG010, DC_MASK06_RG010); val = reg_value(1, val, DC_SHIFT05_RG010, DC_MASK05_RG010); val = reg_value(dev->panel->timing->dsp_clk_pol, val, DC_SHIFT04_RG010, DC_MASK04_RG010); val = reg_value(dev->panel->timing->de_pol, val, DC_SHIFT03_RG010, DC_MASK03_RG010); val = reg_value(dev->panel->timing->vsync_pol, val, DC_SHIFT02_RG010, DC_MASK02_RG010); val = reg_value(dev->panel->timing->hsync_pol, val, DC_SHIFT01_RG010, DC_MASK01_RG010); disp_write(base, DC_RG010, val); for (int i = 0; i < KICK_LAYER_COUNT; i++) { kick_y = t_timing.vact + 1; kick_x = 20 + i * 20; if (kick_x > t_timing.htol - 1) kick_x = t_timing.htol - 1; val = reg_value(kick_y, 0, DC_SHIFT16_RG020, DC_MASK16_RG020); val = reg_value(kick_x, val, DC_SHIFT00_RG020, DC_MASK00_RG020); disp_write(base, DC_RG020(i), val); if (i != 4) disp_write(base, DC_RG024(i), 1); else disp_write(base, DC_RG024(i), 0); } dc_triggle_type |= DC_TCON_UPDATE; } static void dc_tcon_init(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; dc_set_tcon_timing(dev); /*TCON Trigger*/ val = disp_read(base, DC_RA004); val = reg_value(1, val, DC_SHIFT02_RA004, DC_MASK02_RA004); disp_write(base, DC_RA004, val); } static void dc_mlc_init(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; const unsigned char prot_val[] = {0x07, 0x07, 0x07, 0x07}; const unsigned char alpha_bld[] = {0xF, 0xF, 0xF, 0xF, 0xF}; const unsigned char layer_out[] = {0xF, 0xF, 0xF, 0xF, 0xF}; for (int i = 0; i < MLC_LAYER_COUNT; i++) { val = reg_value(prot_val[i], 0, DC_SHIFT08_RE000, DC_MASK08_RE000); val = reg_value(1, val, DC_SHIFT02_RE000, DC_MASK02_RE000); disp_write(base, DC_RE000(i), val); disp_write(base, DC_RF000(i), val); disp_write(base, DC_RE018(i), 0xFF); disp_write(base, DC_RF018(i), 0xFF); } for (int i = 0; i < MLC_PATH_COUNT; i++) { val = reg_value(alpha_bld[i], 0, DC_SHIFT16_RE200, DC_MASK16_RE200); val = reg_value(layer_out[i], val, DC_SHIFT00_RE200, DC_MASK00_RE200); disp_write(base, DC_RE200(i), val); disp_write(base, DC_RF200(i), val); } disp_write(base, DC_RE230, 0x0); disp_write(base, DC_RE234, 0xFFFF); disp_write(base, DC_RF234, 0xFFFF); } static void dc_spipe_init(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; for (int i = 0; i < SP_COUNT; i++) { val = disp_read(base, DC_RD200(i)); val = reg_value(1, val, DC_SHIFT16_RD200, DC_MASK16_RD200); disp_write(base, DC_RD200(i), val); val = disp_read(base, DC_RD204(i)); val = reg_value(1, val, DC_SHIFT16_RD204, DC_MASK16_RD204); disp_write(base, DC_RD204(i), val); val = disp_read(base, DC_RD208(i)); val = reg_value(1, val, DC_SHIFT16_RD208, DC_MASK16_RD208); disp_write(base, DC_RD208(i), val); val = disp_read(base, DC_RD20C(i)); val = reg_value(1, val, DC_SHIFT16_RD20C, DC_MASK16_RD20C); disp_write(base, DC_RD20C(i), val); } } static void dc_gpipe_init(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; val = reg_value(1, 0, DC_SHIFT00_RC044, DC_MASK00_RC044); disp_write(base, DC_RC044, val); val = reg_value(1, 0, DC_SHIFT00_RC200, DC_MASK00_RC200); disp_write(base, DC_RC200, val); val = reg_value(csc_param[0][1], 0, DC_SHIFT16_RC204, DC_MASK16_RC204); val = reg_value(csc_param[0][0], val, DC_SHIFT00_RC204, DC_MASK00_RC204); disp_write(base, DC_RC204, val); val = reg_value(csc_param[0][3], 0, DC_SHIFT16_RC208, DC_MASK16_RC208); val = reg_value(csc_param[0][2], val, DC_SHIFT00_RC208, DC_MASK00_RC208); disp_write(base, DC_RC208, val); val = reg_value(csc_param[0][5], 0, DC_SHIFT16_RC20C, DC_MASK16_RC20C); val = reg_value(csc_param[0][4], val, DC_SHIFT00_RC20C, DC_MASK00_RC204C); disp_write(base, DC_RC20C, val); val = reg_value(csc_param[0][7], 0, DC_SHIFT16_RC210, DC_MASK16_RC210); val = reg_value(csc_param[0][6], val, DC_SHIFT00_RC210, DC_MASK00_RC210); disp_write(base, DC_RC210, val); val = reg_value(csc_param[0][9], 0, DC_SHIFT16_RC214, DC_MASK16_RC214); val = reg_value(csc_param[0][8], val, DC_SHIFT00_RC214, DC_MASK00_RC214); disp_write(base, DC_RC214, val); val = reg_value(csc_param[0][11], 0, DC_SHIFT16_RC218, DC_MASK16_RC218); val = reg_value(csc_param[0][10], val, DC_SHIFT00_RC218, DC_MASK00_RC218); disp_write(base, DC_RC218, val); val = reg_value(csc_param[0][13], 0, DC_SHIFT16_RC21C, DC_MASK16_RC21C); val = reg_value(csc_param[0][12], val, DC_SHIFT00_RC21C, DC_MASK00_RC21C); disp_write(base, DC_RC21C, val); val = reg_value(csc_param[0][14], 0, DC_SHIFT00_RC220, DC_MASK00_RC220); disp_write(base, DC_RC220, val); } static void dc_csc_init(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; val = reg_value(1, 0, DC_SHIFT00_RH000, DC_MASK00_RH000); disp_write(base, DC_RH000, val); val = reg_value(csc_param[0][1], 0, DC_SHIFT16_RH004, DC_MASK16_RH004); val = reg_value(csc_param[0][0], val, DC_SHIFT00_RH004, DC_MASK00_RH004); disp_write(base, DC_RH004, val); val = reg_value(csc_param[0][3], 0, DC_SHIFT16_RH008, DC_MASK16_RH008); val = reg_value(csc_param[0][2], val, DC_SHIFT00_RH008, DC_MASK00_RH008); disp_write(base, DC_RH008, val); val = reg_value(csc_param[0][5], 0, DC_SHIFT16_RH00C, DC_MASK16_RH00C); val = reg_value(csc_param[0][4], val, DC_SHIFT00_RH00C, DC_MASK00_RH00C); disp_write(base, DC_RH00C, val); val = reg_value(csc_param[0][7], 0, DC_SHIFT16_RH010, DC_MASK16_RH010); val = reg_value(csc_param[0][6], val, DC_SHIFT00_RH010, DC_MASK00_RH010); disp_write(base, DC_RH010, val); val = reg_value(csc_param[0][9], 0, DC_SHIFT16_RH014, DC_MASK16_RH014); val = reg_value(csc_param[0][8], val, DC_SHIFT00_RH014, DC_MASK00_RH014); disp_write(base, DC_RH014, val); val = reg_value(csc_param[0][11], 0, DC_SHIFT16_RH018, DC_MASK16_RH018); val = reg_value(csc_param[0][10], val, DC_SHIFT00_RH018, DC_MASK00_RH018); disp_write(base, DC_RH018, val); val = reg_value(csc_param[0][13], 0, DC_SHIFT16_RH01C, DC_MASK16_RH01C); val = reg_value(csc_param[0][12], val, DC_SHIFT00_RH01C, DC_MASK00_RH01C); disp_write(base, DC_RH01C, val); val = reg_value(csc_param[0][14], 0, DC_SHIFT00_RH020, DC_MASK00_RH020); disp_write(base, DC_RH020, val); dc_triggle_type |= DC_CSC_UPDATE; } static void dc_gamma_init(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; val = reg_value(1, 0, DC_SHIFT00_RI000, DC_MASK00_RI000); disp_write(base, DC_RI000, val); dc_triggle_type |= DC_GAMMA_UPDATE; } static void dc_dither_init(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; val = reg_value(1, 0, DC_SHIFT06_RI004, DC_MASK06_RI004); val = reg_value(1, val, DC_SHIFT00_RI004, DC_MASK00_RI004); disp_write(base, DC_RI004, val); dc_triggle_type |= DC_DITHER_UPDATE; } static void dc_crc32_init(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; val = (dev->panel->timing->vsync_pol << DC_SHIFT09_RJ000) | (dev->panel->timing->hsync_pol << DC_SHIFT08_RJ000) | (dev->panel->timing->de_pol << DC_SHIFT07_RJ000) | (1 << DC_SHIFT00_RJ000); disp_write(base, DC_RJ000, val); } static void gen_crc_table(void) { register int i, j; register unsigned int crc_accum; for (i = 0; i < 256; i++) { crc_accum = ((unsigned int)i << 24); for (j = 0; j < 8; j++) { if (crc_accum & 0x80000000L) crc_accum = (crc_accum << 1) ^ POLYNOMIAL; else crc_accum = (crc_accum << 1); } crc_table[i] = crc_accum; } } static unsigned int update_crc(unsigned int crc_accum, void *data_blk_ptr, int data_blk_size) { unsigned char *p; p = (unsigned char *)data_blk_ptr; register int i, j; for (j = 0; j < data_blk_size; j++) { i = ((int)(crc_accum >> 24) ^ *p) & 0xff; crc_accum = (crc_accum << 8) ^ crc_table[i]; p++; } return crc_accum; } unsigned int sdrv_expect_crc32(int mode, struct surface *layer, struct crc32block *crc32block) { unsigned int crc = 0; unsigned int R; unsigned int G; unsigned int B; unsigned int indata; unsigned int *pindata; unsigned int indata_b0; unsigned int indata_b1; unsigned int indata_b2; unsigned int indata_b3; unsigned int indata_MSB; int stride = layer->src_stride[0]; int off; int start_x = crc32block->cfg_start_x - layer->dst.x; int start_y = crc32block->cfg_start_y - layer->dst.y; int end_x = crc32block->cfg_end_x - layer->dst.x; int end_y = crc32block->cfg_end_y - layer->dst.y; char *addr = (char *)layer->addr[0]; gen_crc_table(); for (unsigned int i = start_y; i <= end_y; i++) { for (unsigned int j = start_x; j <= end_x; j++) { switch (layer->fmt) { case COLOR_ARGB8888: off = layer->src.x * 4 + stride * layer->src.y; B = addr[off + i * stride + j * 4]; G = addr[off + i * stride + j * 4 + 1]; R = addr[off + i * stride + j * 4 + 2]; break; case COLOR_BGRA8888: off = layer->src.x * 4 + stride * layer->src.y; R = addr[off + i * stride + j * 4 + 1]; G = addr[off + i * stride + j * 4 + 2]; B = addr[off + i * stride + j * 4 + 3]; break; case COLOR_ABGR8888: off = layer->src.x * 4 + stride * layer->src.y; R = addr[off + i * stride + j * 4]; G = addr[off + i * stride + j * 4 + 1]; B = addr[off + i * stride + j * 4 + 2]; break; case COLOR_RGB888: off = layer->src.x * 3 + stride * layer->src.y; B = addr[off + i * stride + j * 3]; G = addr[off + i * stride + j * 3 + 1]; R = addr[off + i * stride + j * 3 + 2]; break; case COLOR_BGR888: off = layer->src.x * 3 + stride * layer->src.y; R = addr[off + i * stride + j * 3]; G = addr[off + i * stride + j * 3 + 1]; B = addr[off + i * stride + j * 3 + 2]; break; default: return 0; } if (mode == CRC32_MODE_INTERNAL) { B = (B << 2) | (B >> 6); G = (G << 2) | (G >> 6); R = (R << 2) | (R >> 6); } else { B = (B << 2); G = (G << 2); R = (R << 2); } indata = 0x00000000 | (R << 22) | (G << 12) | (B << 2); indata_b0 = (indata & 0x000000FF) << 24; indata_b1 = (indata & 0x0000FF00) << 8; indata_b2 = (indata & 0x00FF0000) >> 8; indata_b3 = (indata & 0xFF000000) >> 24; indata_MSB = indata_b0 | indata_b1 | indata_b2 | indata_b3; pindata = &indata_MSB; crc = update_crc(crc, pindata, 4); } } crc32block->expect_crc = crc; return 1; } static void dc_crc32_set(struct dc_dev *dev) { unsigned int value; unsigned long base = dev->base; struct crc_info *info = dev->crc32; for (int i = 0; i < info->block_num; i++) { if (info->blocks[i].block_use) { value = ((unsigned int)1 << DC_SHIFT31_RJ010) | (info->blocks[i].cfg_start_y << DC_SHIFT16_RJ010) | (info->blocks[i].cfg_start_x << DC_SHIFT00_RJ010); disp_write(base, DC_RJ010(i), value); value = (info->blocks[i].cfg_end_y << DC_SHIFT16_RJ014) | (info->blocks[i].cfg_end_x << DC_SHIFT00_RJ014); disp_write(base, DC_RJ014(i), value); value = info->blocks[i].expect_crc; disp_write(base, DC_RJ018(i), value); } else { disp_write(base, DC_RJ010(i), 0); } } dc_triggle_type |= DC_CRC_UPDATE; } static int crc32_check_and_calc(struct dc_dev *dev, struct post_cfg *post) { struct crc32block *block; struct surface *layer; int start_x, start_y, end_x, end_y; int flag, b_en; for (int i = 0; i < dev->crc32->block_num; i++) { flag = 0; block = &dev->crc32->blocks[i]; if (!block->block_use) continue; for (int k = 0; k < post->num_layers; k++) { layer = &post->layers[i]; if (!layer->en) continue; start_x = layer->dst.x; start_y = layer->dst.y; end_x = layer->dst.x + layer->dst.w; end_y = layer->dst.y + layer->dst.h; if ((start_x <= block->cfg_start_x) && (start_y <= block->cfg_start_y) && (end_x >= block->cfg_end_x) && (end_y >= block->cfg_end_y)) { if (layer->id == PIPE_TYPE_SPIPE) flag |= 1; else flag |= 2; } } switch (flag) { case 1: for (int k = 0; k < post->num_layers; k++) { layer = &post->layers[i]; if (layer->id == PIPE_TYPE_SPIPE) { b_en = sdrv_expect_crc32(dev->crc32->mode, layer, block); if (b_en == 0) block->block_use = 0; } } break; case 2: for (int k = 0; k < post->num_layers; k++) { layer = &post->layers[i]; if (layer->id == PIPE_TYPE_GPIPE) { b_en = sdrv_expect_crc32(dev->crc32->mode, layer, block); if (b_en == 0) block->block_use = 0; } } break; case 3: default: break; } } return 0; } static void set_tcon_ctrl_en(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; static int enable = 0; if (!enable) { enable = 1; val = disp_read(base, DC_RG010); val = reg_value(1, val, DC_SHIFT00_RG010, DC_MASK00_RG010); disp_write(base, DC_RG010, val); } } static int dc_plane_frm_comp_set(struct dc_dev *dev, struct surface *input) { unsigned int compval; unsigned int frmc_val; unsigned char abits, ybits, ubits, vbits; unsigned char swap; unsigned char comp_swap; unsigned char is_yuv; unsigned char is_uvswap; unsigned char uv_mode; unsigned char data_mode; unsigned char buf_fmt; unsigned long base = dev->base; abits = COLOR_GET_A_BITS_NUM(input->fmt); ybits = COLOR_GET_Y_BITS_NUM(input->fmt); ubits = COLOR_GET_U_BITS_NUM(input->fmt); vbits = COLOR_GET_V_BITS_NUM(input->fmt); compval = reg_value(vbits, 0, DC_SHIFT24_RC000, DC_MASK24_RC000); compval = reg_value(ubits, compval, DC_SHIFT16_RC000, DC_MASK16_RC000); compval = reg_value(ybits, compval, DC_SHIFT08_RC000, DC_MASK08_RC000); compval = reg_value(abits, compval, DC_SHIFT00_RC000, DC_MASK00_RC000); swap = COLOR_GET_SWAP(input->fmt); comp_swap = COLOR_GET_COMP_SWAP(input->fmt); is_yuv = COLOR_GET_IS_YUV(input->fmt); is_uvswap = COLOR_GET_IS_UV_SWAP(input->fmt); uv_mode = COLOR_GET_UV_MODE(input->fmt); if (!input->rle.en) data_mode = COLOR_GET_DATA_MODE(input->fmt); else data_mode = RLE_COMPR_MODE; buf_fmt = COLOR_GET_BUF_FMT(input->fmt); frmc_val = reg_value(swap, 0, DC_SHIFT16_RC004, DC_MASK16_RC004); frmc_val = reg_value(comp_swap, frmc_val, DC_SHIFT12_RC004, DC_MASK12_RC004); frmc_val = reg_value(is_yuv, frmc_val, DC_SHIFT07_RC004, DC_MASK07_RC004); frmc_val = reg_value(is_uvswap, frmc_val, DC_SHIFT06_RC004, DC_MASK06_RC004); frmc_val = reg_value(uv_mode, frmc_val, DC_SHIFT04_RC004, DC_MASK04_RC004); frmc_val = reg_value(data_mode, frmc_val, DC_SHIFT02_RC004, DC_MASK02_RC004); frmc_val = reg_value(buf_fmt, frmc_val, DC_SHIFT00_RC004, DC_MASK00_RC004); if (input->id == PIPE_TYPE_SPIPE) { disp_write(base, DC_RD000(0), compval); disp_write(base, DC_RD004(0), frmc_val); } else if (input->id == PIPE_TYPE_GPIPE) { disp_write(base, DC_RC000, compval); disp_write(base, DC_RC004, frmc_val); } else { return -1; } return 0; } static int dc_safety_init(struct dc_dev *dev) { unsigned int val, compval, frmc_val; unsigned char comp_swap, is_yuv, is_uvswap; unsigned char uv_mode, data_mode, buf_fmt; unsigned char abits, ybits, ubits, vbits; unsigned int input_fmt = COLOR_RGB565; unsigned int src_size; unsigned long base = dev->base; struct display_timing *timing = dev->panel->timing; abits = COLOR_GET_A_BITS_NUM(input_fmt); ybits = COLOR_GET_Y_BITS_NUM(input_fmt); ubits = COLOR_GET_U_BITS_NUM(input_fmt); vbits = COLOR_GET_V_BITS_NUM(input_fmt); compval = reg_value(vbits, 0, DC_SHIFT24_RC000, DC_MASK24_RC000); compval = reg_value(ubits, compval, DC_SHIFT16_RC000, DC_MASK16_RC000); compval = reg_value(ybits, compval, DC_SHIFT08_RC000, DC_MASK08_RC000); compval = reg_value(abits, compval, DC_SHIFT00_RC000, DC_MASK00_RC000); comp_swap = COLOR_GET_COMP_SWAP(input_fmt); is_yuv = COLOR_GET_IS_YUV(input_fmt); is_uvswap = COLOR_GET_IS_UV_SWAP(input_fmt); uv_mode = COLOR_GET_UV_MODE(input_fmt); data_mode = COLOR_GET_DATA_MODE(input_fmt); buf_fmt = COLOR_GET_BUF_FMT(input_fmt); frmc_val = reg_value(comp_swap, 0, DC_SHIFT12_RC004, DC_MASK12_RC004); frmc_val = reg_value(is_yuv, frmc_val, DC_SHIFT07_RC004, DC_MASK07_RC004); frmc_val = reg_value(is_uvswap, frmc_val, DC_SHIFT06_RC004, DC_MASK06_RC004); frmc_val = reg_value(uv_mode, frmc_val, DC_SHIFT04_RC004, DC_MASK04_RC004); frmc_val = reg_value(data_mode, frmc_val, DC_SHIFT02_RC004, DC_MASK02_RC004); frmc_val = reg_value(buf_fmt, frmc_val, DC_SHIFT00_RC004, DC_MASK00_RC004); disp_write(base, DC_RD000(1), compval); disp_write(base, DC_RD004(1), frmc_val); /*pipe related*/ src_size = reg_value(warning_image.width - 1, 0, DC_SHIFT00_RC008, DC_MASK00_RC008); src_size = reg_value(warning_image.height - 1, src_size, DC_SHIFT16_RC008, DC_MASK16_RC008); disp_write(base, DC_RD008(1), src_size); disp_write(base, DC_RD00C(1), (unsigned long)warning_image.y); disp_write(base, DC_RD010(1), 0); disp_write(base, DC_RD02C(1), warning_image.width * 2 - 1); disp_write(base, DC_RD040(1), 0); /*S_SP Triggle*/ disp_write(base, DC_RDF00(1), 0x1); /*mlc related*/ disp_write(base, DC_RF230, 0x3ff); disp_write(base, DC_RF004(MLC_LAYER_SP), (timing->hactive - warning_image.width) / 2); disp_write(base, DC_RF008(MLC_LAYER_SP), (timing->vactive - warning_image.height) / 2); disp_write(base, DC_RF00C(MLC_LAYER_SP), src_size); disp_write(base, DC_RF018(MLC_LAYER_SP), 0xFF); val = disp_read(base, DC_RF000(MLC_LAYER_SP)); val = reg_value(1, val, DC_SHIFT02_RE000, DC_MASK02_RE000); val = reg_value(1, val, DC_SHIFT00_RE000, DC_MASK00_RE000); disp_write(base, DC_RF000(MLC_LAYER_SP), val); /*set z-order*/ disp_write(base, DC_RF200(MLC_PATH_SP), 0x10001); /*SF_FLC_CTRL Triggle*/ val = reg_value(1, 0, DC_SHIFT02_RA004, DC_MASK02_RA004); val = reg_value(1, val, DC_SHIFT01_RA004, DC_MASK01_RA004); val = reg_value(1, val, DC_SHIFT00_RA004, DC_MASK00_RA004); disp_write(base, DC_RA100, val); return 0; } static int dc_reset(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; val = disp_read(base, DC_RA000); val = reg_value(1, val, DC_SHIFT31_RA000, DC_MASK31_RA000); disp_write(base, DC_RA000, val); udelay(10); val = reg_value(0, val, DC_SHIFT31_RA000, DC_MASK31_RA000); disp_write(base, DC_RA000, val); return 0; } static int dc_gpipe_reset(struct dc_dev *dev) { unsigned int val; unsigned long base = dev->base; val = disp_read(base, DC_RCE00); val = reg_value(1, val, DC_SHIFT00_RCE00, DC_MASK00_RCE00); disp_write(base, DC_RCE00, val); udelay(10); val = reg_value(0, val, DC_SHIFT00_RCE00, DC_MASK00_RCE00); disp_write(base, DC_RCE00, val); return 0; } static int dc_csi_mask_ratio_set(struct dc_dev *dev, int mask_count, int ratio) { unsigned long base = dev->base; unsigned int val; val = disp_read(base, DC_RG500); val = reg_value(ratio, val, DC_SHIFT04_RG500, DC_MASK04_RG500); val = reg_value(mask_count, val, DC_SHIFT02_RG500, DC_MASK02_RG500); disp_write(base, DC_RG500, val); return 0; } static int dc_csi_timing_dectet_enable(struct dc_dev *dev, bool enable) { unsigned long base = dev->base; if (enable) { disp_write(base, DC_RG504, 1); } else { disp_write(base, DC_RG504, 0); } return 0; } static int dc_init(struct dc_dev *dev) { dc_reset(dev); dc_ms_mode(dev); dc_irq_disable(dev); dc_rdma_init(dev); dc_tcon_init(dev); dc_mlc_init(dev); dc_spipe_init(dev); dc_gpipe_init(dev); dc_csc_init(dev); dc_gamma_init(dev); dc_dither_init(dev); dc_irq_init(dev); dc_crc32_init(dev); dc_safety_init(dev); return 0; } bool fmt_is_spipe_support(unsigned int fmt) { switch (fmt) { case COLOR_RGB565: case COLOR_BGR565: case COLOR_ARGB4444: case COLOR_BGRA4444: case COLOR_ARGB1555: case COLOR_BGRA5551: case COLOR_ABGR1555: case COLOR_RGB666: case COLOR_BGR666: case COLOR_RGB888: case COLOR_BGR888: case COLOR_ARGB8888: case COLOR_BGRA8888: case COLOR_ARGB2101010: case COLOR_BGRA1010102: return true; default: return false; } } static int dc_offset_to_addr(struct surface *input) { unsigned char uv_mode = COLOR_GET_UV_MODE(input->fmt); unsigned char n_planes = COLOR_GET_PLANE_COUNT(input->fmt); if (n_planes == 1) return 0; switch (uv_mode) { case UV_YUV422: if (n_planes == 2) { input->addr[0] += input->start.y * input->src_stride[0] + input->start.x; input->addr[1] += input->start.y * input->src_stride[1] + input->start.x; } if (n_planes == 3) { input->addr[0] += input->start.y * input->src_stride[0] + input->start.x; input->addr[1] += input->start.y * input->src_stride[1] + input->start.x / 2; input->addr[2] += input->start.y * input->src_stride[2] + input->start.x / 2; } break; case UV_YUV420: if (n_planes == 2) { input->addr[0] += input->start.y * input->src_stride[0] + input->start.x; input->addr[1] += input->start.y / 2 * input->src_stride[1] + input->start.x; } if (n_planes == 3) { input->addr[0] += input->start.y * input->src_stride[0] + input->start.x; input->addr[1] += input->start.y / 2 * input->src_stride[1] + input->start.x / 2; input->addr[2] += input->start.y / 2 * input->src_stride[2] + input->start.x / 2; } break; case UV_YUV440: if (n_planes == 2) { input->addr[0] += input->start.y * input->src_stride[0] + input->start.x; input->addr[1] += input->start.y * input->src_stride[1] + input->start.x * 2; } break; default: break; } return 0; } static void dc_clear_layers(struct dc_dev *dev, uint8_t mask, uint8_t z_order) { int val; unsigned long base = dev->base; int zorder = z_order + 1; switch (mask) { case CLEAR_SPIPE_LAYER: /*Disable Layer*/ val = disp_read(base, DC_RE000(MLC_LAYER_SP)); val = reg_value(0, val, DC_SHIFT00_RE000, DC_MASK00_RE000); disp_write(base, DC_RE000(MLC_LAYER_SP), val); /*Disable Path*/ val = disp_read(base, DC_RE200(MLC_PATH_SP)); val = reg_value(0xF, val, DC_SHIFT00_RE200, DC_MASK00_RE200); disp_write(base, DC_RE200(MLC_PATH_SP), val); val = disp_read(base, DC_RE200(zorder)); val = reg_value(0xF, val, DC_SHIFT16_RE200, DC_MASK16_RE200); disp_write(base, DC_RE200(zorder), val); dc_triggle_type |= DC_SP_UPDATE; dc_triggle_type |= DC_MLC_UPDATE; break; case CLEAR_GPIPE_LAYER: /*Disable Layer*/ val = disp_read(base, DC_RE000(MLC_LAYER_GP)); val = reg_value(0, val, DC_SHIFT00_RE000, DC_MASK00_RE000); disp_write(base, DC_RE000(MLC_LAYER_GP), val); /*Disable Path*/ val = disp_read(base, DC_RE200(MLC_PATH_GP)); val = reg_value(0xF, val, DC_SHIFT00_RE200, DC_MASK00_RE200); disp_write(base, DC_RE200(MLC_PATH_GP), val); val = disp_read(base, DC_RE200(zorder)); val = reg_value(0xF, val, DC_SHIFT16_RE200, DC_MASK16_RE200); disp_write(base, DC_RE200(zorder), val); dc_triggle_type |= DC_GP_UPDATE; dc_triggle_type |= DC_MLC_UPDATE; break; case CLEAR_ALL_LAYERS: for (int i = 0; i < MLC_LAYER_NUM; i++) { val = disp_read(base, DC_RE000(i)); val = reg_value(0, val, DC_SHIFT00_RE000, DC_MASK00_RE000); disp_write(base, DC_RE000(i), val); } disp_write(base, DC_RE200(1), 0xF000F); disp_write(base, DC_RE200(2), 0xF000F); dc_triggle_type |= DC_SP_UPDATE; dc_triggle_type |= DC_GP_UPDATE; dc_triggle_type |= DC_MLC_UPDATE; break; default: break; } } static int dc_update_layer(struct dc_dev *dev, struct surface *layer) { unsigned int val; unsigned char nplanes; unsigned int src_size; unsigned int src_offset; unsigned long base = dev->base; unsigned char is_yuv = 0; int zorder; if (!layer) { return -1; } zorder = layer->z_order + 1; nplanes = COLOR_GET_PLANE_COUNT(layer->fmt); dc_plane_frm_comp_set(dev, layer); src_size = reg_value(layer->start.w - 1, 0, DC_SHIFT00_RC008, DC_MASK00_RC008); src_size = reg_value(layer->start.h - 1, src_size, DC_SHIFT16_RC008, DC_MASK16_RC008); if (nplanes == 1) { src_offset = reg_value(layer->start.x, 0, DC_SHIFT00_RC040, DC_MASK00_RC040); src_offset = reg_value(layer->start.y, src_offset, DC_SHIFT16_RC040, DC_MASK16_RC040); } else { src_offset = 0; } dc_offset_to_addr(layer); dev->last_zorder[layer->id] = zorder; if (layer->id == PIPE_TYPE_SPIPE) { /*pipe related*/ disp_write(base, DC_RD008(0), src_size); disp_write(base, DC_RD00C(0), get_l_addr(layer->addr[0])); disp_write(base, DC_RD010(0), get_h_addr(layer->addr[1])); disp_write(base, DC_RD02C(0), layer->src_stride[0] - 1); disp_write(base, DC_RD040(0), src_offset); dc_triggle_type |= DC_SP_UPDATE; /*mlc related*/ disp_write(base, DC_RE004(MLC_LAYER_SP), layer->dst.x); disp_write(base, DC_RE008(MLC_LAYER_SP), layer->dst.y); disp_write(base, DC_RE00C(MLC_LAYER_SP), src_size); if (layer->alpha_en) disp_write(base, DC_RE018(MLC_LAYER_SP), layer->alpha); val = disp_read(base, DC_RE000(MLC_LAYER_SP)); val = reg_value(layer->alpha_en, val, DC_SHIFT02_RE000, DC_MASK02_RE000); val = reg_value(1, val, DC_SHIFT00_RE000, DC_MASK00_RE000); disp_write(base, DC_RE000(MLC_LAYER_SP), val); /*set z-order*/ val = disp_read(base, DC_RE200(MLC_PATH_SP)); val = reg_value(zorder, val, DC_SHIFT00_RE200, DC_MASK00_RE200); disp_write(base, DC_RE200(MLC_PATH_SP), val); val = disp_read(base, DC_RE200(zorder)); val = reg_value(0x1, val, DC_SHIFT16_RE200, DC_MASK16_RE200); disp_write(base, DC_RE200(zorder), val); if (!layer->rle.en) { val = reg_value(0, 0, DC_SHIFT00_RD120, DC_MASK00_RD120); disp_write(base, DC_RD120(0), val); } else { val = reg_value(layer->rle.data_size, 0, DC_SHIFT01_RD120, DC_MASK01_RD120); val = reg_value(layer->rle.en, val, DC_SHIFT00_RD120, DC_MASK00_RD120); disp_write(base, DC_RD120(0), val); disp_write(base, DC_RD100(0), layer->rle.y_len); disp_write(base, DC_RD110(0), layer->rle.y_checksum); } dc_triggle_type |= DC_MLC_UPDATE; } else if (layer->id == PIPE_TYPE_GPIPE) { /*pipe related*/ disp_write(base, DC_RC008, src_size); disp_write(base, DC_RC00C, get_l_addr(layer->addr[0])); disp_write(base, DC_RC010, get_h_addr(layer->addr[0])); disp_write(base, DC_RC02C, layer->src_stride[0] - 1); disp_write(base, DC_RC040, src_offset); if (nplanes > 1) { disp_write(base, DC_RC014, get_l_addr(layer->addr[1])); disp_write(base, DC_RC018, get_h_addr(layer->addr[1])); disp_write(base, DC_RC030, layer->src_stride[1] - 1); } if (nplanes > 2) { disp_write(base, DC_RC01C, get_l_addr(layer->addr[2])); disp_write(base, DC_RC020, get_h_addr(layer->addr[2])); disp_write(base, DC_RC034, layer->src_stride[2] - 1); } is_yuv = COLOR_GET_IS_YUV(layer->fmt); val = disp_read(base, DC_RC044); val = reg_value(is_yuv, val, DC_SHIFT31_RC044, DC_MASK31_RC044); val = reg_value(is_yuv ? 0 : 1, val, DC_SHIFT00_RC044, DC_MASK00_RC044); disp_write(base, DC_RC044, val); val = disp_read(base, DC_RC200); val = reg_value(is_yuv ? 0 : 1, val, DC_SHIFT00_RC200, DC_MASK00_RC200); disp_write(base, DC_RC200, val); dc_triggle_type |= DC_GP_UPDATE; /*mlc related*/ disp_write(base, DC_RE004(MLC_LAYER_GP), layer->dst.x); disp_write(base, DC_RE008(MLC_LAYER_GP), layer->dst.y); disp_write(base, DC_RE00C(MLC_LAYER_GP), src_size); if (layer->alpha_en) disp_write(base, DC_RE018(MLC_LAYER_GP), layer->alpha); val = disp_read(base, DC_RE000(MLC_LAYER_GP)); val = reg_value(layer->alpha_en, val, DC_SHIFT02_RE000, DC_MASK02_RE000); val = reg_value(1, val, DC_SHIFT00_RE000, DC_MASK00_RE000); disp_write(base, DC_RE000(MLC_LAYER_GP), val); /*set z-order*/ val = disp_read(base, DC_RE200(MLC_PATH_GP)); val = reg_value(zorder, val, DC_SHIFT00_RE200, DC_MASK00_RE200); disp_write(base, DC_RE200(MLC_PATH_GP), val); val = disp_read(base, DC_RE200(zorder)); val = reg_value(0x2, val, DC_SHIFT16_RE200, DC_MASK16_RE200); disp_write(base, DC_RE200(zorder), val); dc_triggle_type |= DC_MLC_UPDATE; } else { return -1; } return 0; } static int dc_update(struct dc_dev *dev, struct post_cfg *post) { int ret; if (post->num_layers > PIPE_TYPE_NUM) { return -1; } if (dev->crc32) { crc32_check_and_calc(dev, post); dc_crc32_set(dev); } for (unsigned int i = 0; i < post->num_layers; i++) { if (!post->layers[i].en) { if (post->layers[i].dirty) dc_clear_layers(dev, 1 << post->layers[i].id, dev->last_zorder[post->layers[i].id]); continue; } ret = dc_update_layer(dev, &post->layers[i]); if (ret < 0) { return -1; } } return 0; } static void dc_vsync_enable(struct dc_dev *dev, bool enable) { unsigned int val; unsigned long base = dev->base; val = disp_read(base, DC_RA020); val = reg_value(enable ? 0 : 1, val, DC_SHIFT03_RA02X, DC_MASK03_RA02X); disp_write(base, DC_RA020, val); } void dc_dect_done_enable(struct dc_dev *dev, bool enable) { unsigned int val; unsigned long base = dev->base; val = disp_read(base, DC_RA020); val = reg_value(enable ? 0 : 1, val, DC_SHIFT28_RA02X, DC_MASK28_RA02X); disp_write(base, DC_RA020, val); } void dc_vsync_delay_done_enable(struct dc_dev *dev, bool enable) { unsigned int val; unsigned long base = dev->base; val = disp_read(base, DC_RA020); val = reg_value(enable ? 0 : 1, val, DC_SHIFT29_RA02X, DC_MASK29_RA02X); disp_write(base, DC_RA020, val); } static void tcon_auto_adj_enable(struct dc_dev *dev, bool enable) { unsigned int val; unsigned long base = dev->base; DISPSS_LOG_FUNC(); val = disp_read(base, DC_RG500); val = reg_value(enable ? 1 : 0, val, DC_SHIFT08_RG500, DC_MASK08_RG500); disp_write(base, DC_RG500, val); dc_csi_timing_dectet_enable(dev, enable); } void dc_short_convt(struct dc_dev *dev, int is_up, int delta) { unsigned long base = dev->base; int val, old; int lmax, remainder; lmax = delta / 4; remainder = delta % 4; if (remainder) lmax += 1; for (int i = 0; i < lmax; i++) { while (1) { val = disp_read(base, DC_RA024); disp_write(base, DC_RA024, val); if (val & DC_MASK28_RA02X) break; } val = disp_read(base, DC_RG500); if (is_up && (i == 0)) old = (val >> DC_SHIFT16_RG500) + t_timing.vtol; else old = val >> DC_SHIFT16_RG500; if (i < (lmax - 1)) val = reg_value(old - 4, val, DC_SHIFT16_RG500, DC_MASK16_RG500); else val = reg_value(old - remainder, val, DC_SHIFT16_RG500, DC_MASK16_RG500); disp_write(base, DC_RG500, val); dc_triggle_type |= DC_TCON_UPDATE; dc_triggle(dev); } } static void tcon_csi_delay_set(struct dc_dev *dev) { unsigned long base = dev->base; int t1, t2, t3, t4, dly_pre, dly_cur; int val, htol, vfp; int is_up; DISPSS_LOG_FUNC(); htol = t_timing.htol; vfp = t_timing.vtol - t_timing.vact - t_timing.vsbp; val = disp_read(base, DC_RG518); if (((val + 1) % htol) == 0) t1 = (val + 1) / htol; else t1 = (val + 1) / htol + 1; t3 = dev->app.buf_size_num_lines; dly_pre = disp_read(base, DC_RG500) >> DC_SHIFT16_RG500; t2 = disp_read(base, DC_RG520); t4 = t1 + dev->app.t_delta + t3 + vfp; if (t4 > t2) { dly_cur = (t4 - t2) + dly_pre; val = disp_read(base, DC_RG500); val = reg_value(dly_cur, val, DC_SHIFT16_RG500, DC_MASK16_RG500); disp_write(base, DC_RG500, val); dc_triggle_type |= DC_TCON_UPDATE; dc_triggle(dev); } else { if ((t2 - t4) <= dly_pre) { is_up = 0; } else { is_up = 1; } dc_short_convt(dev, is_up, t2 - t4); } } static int get_dt(struct dc_dev *dev) { unsigned long base = dev->base; int val, htol, vfp; int t1, t2, t3, t4; htol = t_timing.htol; vfp = t_timing.vtol - t_timing.vact - t_timing.vsbp; val = disp_read(base, DC_RG518); if (((val + 1) % htol) == 0) t1 = (val + 1) / htol; else t1 = (val + 1) / htol + 1; t3 = dev->app.buf_size_num_lines; t2 = disp_read(base, DC_RG520); t4 = t1 + dev->app.t_delta + t3 + vfp; return (t2 - t4); } static void tcon_csi_delay_set2(struct dc_dev *dev) { const int pll_lvds_base = 0xF30a0000; const int reg_n = 0x4; int dt, n; DISPSS_LOG_FUNC(); n = disp_read(pll_lvds_base, reg_n); dt = get_dt(dev); while (!((dt < 0) ? (dt > -1) : (dt < 1))) { if (dt < 0) { disp_write(pll_lvds_base, reg_n, n - 1); } else { disp_write(pll_lvds_base, reg_n, n + 1); } udelay(1); dt = get_dt(dev); } disp_write(pll_lvds_base, reg_n, n); } static int dc_irq_handler(uint32_t irq, void *arg) { struct dc_dev *dev = (struct dc_dev *)arg; unsigned long base = dev->base; unsigned int value; value = disp_read(base, DC_RA024); disp_write(base, DC_RA024, value); if (value & DC_MASK04_RA02X) { if (dev->vsync_callback) dev->vsync_callback(); } if (value & DC_MASK05_RA02X) { DISPSS_LOG_INFO("dc tcon underrun"); } return 0; } void dc_set_tcon_after_detect(struct dc_dev *dev, int ratio_num) { unsigned long base = dev->base; int csi_vtol; int val; timing_to_tcon_timing(dev->panel->timing, &t_timing); /* csi_vtol && csi_vysnc unit is dc pixel clock. */ csi_vtol = disp_read(base, DC_RG514) + 1; if ((csi_vtol % t_timing.htol) == 0) { t_timing.vtol = csi_vtol / t_timing.htol; } else { t_timing.vtol = csi_vtol / t_timing.htol + 1; } t_timing.vsbp = (t_timing.vtol - t_timing.vact) / 3 * 2; t_timing.vsync = (t_timing.vtol - t_timing.vact) / 3; /* Vertical active size && total vertical size in lines. */ val = reg_value(t_timing.vact - 1, 0, DC_SHIFT16_RG008, DC_MASK16_RG008); val = reg_value(t_timing.vtol - 1, val, DC_SHIFT00_RG008, DC_MASK00_RG008); disp_write(base, DC_RG008, val); /* Vertical back porch size && width of vsync pulse in lines. */ val = reg_value(t_timing.vsbp - 1, 0, DC_SHIFT16_RG00C, DC_MASK16_RG00C); val = reg_value(t_timing.vsync - 1, val, DC_SHIFT00_RG00C, DC_MASK00_RG00C); disp_write(base, DC_RG00C, val); disp_write(base, DC_RG600, 1); dc_triggle_type |= DC_TCON_UPDATE; } void dc_hsdk_enable(struct dc_dev *dev, int mode, bool enable) { unsigned int val; unsigned long base = dev->base; val = reg_value(mode, 0, DC_SHIFT01_RCD00, DC_MASK01_RCD00); val = reg_value(enable ? 1 : 0, val, DC_SHIFT00_RCD00, DC_MASK00_RCD00); disp_write(base, DC_RCD00, val); dc_triggle_type |= DC_GP_UPDATE; disp_write(base, DC_RG024(4), enable ? 1 : 0); dc_triggle_type |= DC_TCON_UPDATE; } void dc_update_csi_detect(struct dc_dev *dev, struct surface *surface, int mask_count, int ratio, bool enable, bool pll_mode) { unsigned long base = dev->base; int value; int count = 0; dc_gpipe_reset(dev); dc_update_layer(dev, surface); dc_csi_mask_ratio_set(dev, mask_count, ratio); dc_csi_timing_dectet_enable(dev, enable); dc_triggle(dev); set_tcon_ctrl_en(dev); dc_vsync_enable(dev, false); while (1) { value = disp_read(base, DC_RA024); disp_write(base, DC_RA024, value); if (value & DC_MASK29_RA02X) { count++; if ((count == 2) && (!pll_mode)) { tcon_auto_adj_enable(dev, true); } if (count == 3) { if (pll_mode) { tcon_csi_delay_set2(dev); } else { tcon_csi_delay_set(dev); break; } } if ((count == 4) && (pll_mode)) { tcon_auto_adj_enable(dev, true); break; } } } dc_triggle(dev); if (dev->app.work_mode == WORK_MODE_CSI_DC_HS) { dc_hsdk_enable(dev, dev->app.mode, true); dc_triggle(dev); } dc_vsync_enable(dev, true); } void dc_set_bg_color(struct dc_dev *dev, int color) { unsigned long base = dev->base; disp_write(base, DC_RE230, color); } struct dc_operations dc_ops = { .init = dc_init, .reset = dc_reset, .update = dc_update, .update_layer = dc_update_layer, .triggle = dc_triggle, .check_triggle_status = dc_check_triggle_status, .vsync_enable = dc_vsync_enable, .enable = set_tcon_ctrl_en, .irq_handler = dc_irq_handler, .hsdk_enable = dc_hsdk_enable, .csi_mask_ratio_set = dc_csi_mask_ratio_set, .csi_timing_dectet_enable = dc_csi_timing_dectet_enable, .set_tcon_after_detect = dc_set_tcon_after_detect, .tcon_auto_adj_enable = tcon_auto_adj_enable, .tcon_csi_delay_set = tcon_csi_delay_set, .update_csi_detect = dc_update_csi_detect, .set_bg_color = dc_set_bg_color, .clear_layers = dc_clear_layers, };