// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2016 Nexell Co., Ltd. * * Author: junghyun, kim */ #include #include #include "s5pxx18_soc_disptop.h" #include "s5pxx18_soc_mipi.h" static struct nx_mipi_register_set *__g_pregister[NUMBER_OF_MIPI_MODULE]; int nx_mipi_smoke_test(u32 module_index) { register struct nx_mipi_register_set *pregister; pregister = __g_pregister[module_index]; if (pregister->csis_config_ch0 != 0x000000FC) return false; if (pregister->dsim_intmsk != 0xB337FFFF) return false; writel(0xDEADC0DE, &pregister->csis_dphyctrl); writel(0xFFFFFFFF, &pregister->csis_ctrl2); writel(0xDEADC0DE, &pregister->dsim_msync); if (pregister->csis_dphyctrl != 0xDE80001E) return false; if ((pregister->csis_ctrl2 & (~1)) != 0xEEE00010) return false; if (pregister->dsim_msync != 0xDE80C0DE) return false; return true; } void nx_mipi_set_base_address(u32 module_index, void *base_address) { __g_pregister[module_index] = (struct nx_mipi_register_set *)base_address; } void *nx_mipi_get_base_address(u32 module_index) { return (void *)__g_pregister[module_index]; } u32 nx_mipi_get_physical_address(u32 module_index) { const u32 physical_addr[] = PHY_BASEADDR_MIPI_LIST; return physical_addr[module_index]; } #define __nx_mipi_valid_dsi_intmask__ \ (~((1 << 26) | (1 << 23) | (1 << 22) | (1 << 19))) void nx_mipi_set_interrupt_enable(u32 module_index, u32 int_num, int enable) { register struct nx_mipi_register_set *pregister; register u32 regvalue; pregister = __g_pregister[module_index]; if (int_num < 32) { regvalue = pregister->csis_intmsk; regvalue &= ~(1ul << int_num); regvalue |= (u32)enable << int_num; writel(regvalue, &pregister->csis_intmsk); } else { regvalue = pregister->dsim_intmsk; regvalue &= ~(1ul << (int_num - 32)); regvalue |= (u32)enable << (int_num - 32); writel(regvalue, &pregister->dsim_intmsk); } } int nx_mipi_get_interrupt_enable(u32 module_index, u32 int_num) { if (int_num < 32) return (int)((__g_pregister[module_index]->csis_intmsk >> int_num) & 0x01); else return (int)((__g_pregister[module_index]->dsim_intmsk >> (int_num - 32)) & 0x01); } int nx_mipi_get_interrupt_pending(u32 module_index, u32 int_num) { register struct nx_mipi_register_set *pregister; register u32 regvalue; int ret; pregister = __g_pregister[module_index]; if (int_num < 32) { regvalue = pregister->csis_intmsk; regvalue &= pregister->csis_intsrc; ret = (int)((regvalue >> int_num) & 0x01); } else { regvalue = pregister->dsim_intmsk; regvalue &= pregister->dsim_intsrc; ret = (int)((regvalue >> (int_num - 32)) & 0x01); } return ret; } void nx_mipi_clear_interrupt_pending(u32 module_index, u32 int_num) { register struct nx_mipi_register_set *pregister; pregister = __g_pregister[module_index]; if (int_num < 32) writel(1ul << int_num, &pregister->csis_intsrc); else writel(1ul << (int_num - 32), &pregister->dsim_intsrc); } void nx_mipi_set_interrupt_enable_all(u32 module_index, int enable) { register struct nx_mipi_register_set *pregister; pregister = __g_pregister[module_index]; if (enable) writel(__nx_mipi_valid_dsi_intmask__, &pregister->dsim_intmsk); else writel(0, &pregister->dsim_intmsk); } int nx_mipi_get_interrupt_enable_all(u32 module_index) { if (__g_pregister[module_index]->csis_intmsk) return true; if (__g_pregister[module_index]->dsim_intmsk) return true; return false; } int nx_mipi_get_interrupt_pending_all(u32 module_index) { register struct nx_mipi_register_set *pregister; register u32 regvalue; pregister = __g_pregister[module_index]; regvalue = pregister->csis_intmsk; regvalue &= pregister->csis_intsrc; if (regvalue) return true; regvalue = pregister->dsim_intmsk; regvalue &= pregister->dsim_intsrc; if (regvalue) return true; return false; } void nx_mipi_clear_interrupt_pending_all(u32 module_index) { register struct nx_mipi_register_set *pregister; pregister = __g_pregister[module_index]; writel(__nx_mipi_valid_dsi_intmask__, &pregister->dsim_intsrc); } int32_t nx_mipi_get_interrupt_pending_number(u32 module_index) { register struct nx_mipi_register_set *pregister; register u32 regvalue; int i; pregister = __g_pregister[module_index]; regvalue = pregister->csis_intmsk; regvalue &= pregister->csis_intsrc; if (regvalue != 0) { for (i = 0; i < 32; i++) { if (regvalue & 1ul) return i; regvalue >>= 1; } } regvalue = pregister->dsim_intmsk; regvalue &= pregister->dsim_intsrc; if (regvalue != 0) { for (i = 0; i < 32; i++) { if (regvalue & 1ul) return i + 32; regvalue >>= 1; } } return -1; } #define writereg(regname, mask, value) \ regvalue = pregister->(regname); \ regvalue = (regvalue & (~(mask))) | (value); \ writel(regvalue, &pregister->(regname)) void nx_mipi_dsi_get_status(u32 module_index, u32 *pulps, u32 *pstop, u32 *pispllstable, u32 *pisinreset, u32 *pisbackward, u32 *pishsclockready) { register struct nx_mipi_register_set *pregister; register u32 regvalue; pregister = __g_pregister[module_index]; regvalue = pregister->dsim_status; if (pulps) { *pulps = 0; if (regvalue & (1 << 4)) *pulps |= (1 << 0); if (regvalue & (1 << 5)) *pulps |= (1 << 1); if (regvalue & (1 << 6)) *pulps |= (1 << 2); if (regvalue & (1 << 7)) *pulps |= (1 << 3); if (regvalue & (1 << 9)) *pulps |= (1 << 4); } if (pstop) { *pstop = 0; if (regvalue & (1 << 0)) *pstop |= (1 << 0); if (regvalue & (1 << 1)) *pstop |= (1 << 1); if (regvalue & (1 << 2)) *pstop |= (1 << 2); if (regvalue & (1 << 3)) *pstop |= (1 << 3); if (regvalue & (1 << 8)) *pstop |= (1 << 4); } if (pispllstable) *pispllstable = (regvalue >> 31) & 1; if (pisinreset) *pisinreset = ((regvalue >> 20) & 1) ? 0 : 1; if (pisbackward) *pisbackward = (regvalue >> 16) & 1; if (pishsclockready) *pishsclockready = (regvalue >> 10) & 1; } void nx_mipi_dsi_software_reset(u32 module_index) { register struct nx_mipi_register_set *pregister; pregister = __g_pregister[module_index]; writel(0x00010001, &pregister->dsim_swrst); while (0 != (readl(&pregister->dsim_status) & (1 << 20))) ; writel(0x00000000, &pregister->dsim_swrst); } void nx_mipi_dsi_set_clock(u32 module_index, int enable_txhsclock, int use_external_clock, int enable_byte_clock, int enable_escclock_clock_lane, int enable_escclock_data_lane0, int enable_escclock_data_lane1, int enable_escclock_data_lane2, int enable_escclock_data_lane3, int enable_escprescaler, u32 escprescalervalue) { register struct nx_mipi_register_set *pregister; register u32 regvalue; pregister = __g_pregister[module_index]; regvalue = 0; regvalue |= (enable_txhsclock << 31); regvalue |= (use_external_clock << 27); regvalue |= (enable_byte_clock << 24); regvalue |= (enable_escclock_clock_lane << 19); regvalue |= (enable_escclock_data_lane0 << 20); regvalue |= (enable_escclock_data_lane1 << 21); regvalue |= (enable_escclock_data_lane2 << 22); regvalue |= (enable_escclock_data_lane3 << 23); regvalue |= (enable_escprescaler << 28); regvalue |= escprescalervalue; writel(regvalue, &pregister->dsim_clkctrl); } void nx_mipi_dsi_set_timeout(u32 module_index, u32 bta_tout, u32 lpdrtout) { register struct nx_mipi_register_set *pregister; register u32 regvalue; pregister = __g_pregister[module_index]; regvalue = 0; regvalue |= (bta_tout << 16); regvalue |= (lpdrtout << 0); writel(regvalue, &pregister->dsim_timeout); } void nx_mipi_dsi_set_config_video_mode(u32 module_index, int enable_auto_flush_main_display_fifo, int enable_auto_vertical_count, int enable_burst, enum nx_mipi_dsi_syncmode sync_mode, int enable_eo_tpacket, int enable_hsync_end_packet, int enable_hfp, int enable_hbp, int enable_hsa, u32 number_of_virtual_channel, enum nx_mipi_dsi_format format, u32 number_of_words_in_hfp, u32 number_of_words_in_hbp, u32 number_of_words_in_hsync, u32 number_of_lines_in_vfp, u32 number_of_lines_in_vbp, u32 number_of_lines_in_vsync, u32 number_of_lines_in_command_allow) { register struct nx_mipi_register_set *pregister; register u32 regvalue; u32 newvalue; pregister = __g_pregister[module_index]; newvalue = (1 << 25); newvalue |= ((1 - enable_auto_flush_main_display_fifo) << 29); newvalue |= (enable_auto_vertical_count << 24); newvalue |= (enable_burst << 26); newvalue |= (sync_mode << 27); newvalue |= ((1 - enable_eo_tpacket) << 28); newvalue |= (enable_hsync_end_packet << 23); newvalue |= ((1 - enable_hfp) << 22); newvalue |= ((1 - enable_hbp) << 21); newvalue |= ((1 - enable_hsa) << 20); newvalue |= (number_of_virtual_channel << 18); newvalue |= (format << 12); writereg(dsim_config, 0xFFFFFF00, newvalue); newvalue = (number_of_lines_in_command_allow << 28); newvalue |= (number_of_lines_in_vfp << 16); newvalue |= (number_of_lines_in_vbp << 0); writel(newvalue, &pregister->dsim_mvporch); newvalue = (number_of_words_in_hfp << 16); newvalue |= (number_of_words_in_hbp << 0); writel(newvalue, &pregister->dsim_mhporch); newvalue = (number_of_words_in_hsync << 0); newvalue |= (number_of_lines_in_vsync << 22); writel(newvalue, &pregister->dsim_msync); } void nx_mipi_dsi_set_config_command_mode(u32 module_index, int enable_auto_flush_main_display_fifo, int enable_eo_tpacket, u32 number_of_virtual_channel, enum nx_mipi_dsi_format format) { register struct nx_mipi_register_set *pregister; register u32 regvalue; u32 newvalue; pregister = __g_pregister[module_index]; newvalue = (0 << 25); newvalue |= (enable_auto_flush_main_display_fifo << 29); newvalue |= (enable_eo_tpacket << 28); newvalue |= (number_of_virtual_channel << 18); newvalue |= (format << 12); writereg(dsim_config, 0xFFFFFF00, newvalue); } void nx_mipi_dsi_set_escape_mode(u32 module_index, u32 stop_state_count, int force_stop_state, int force_bta, enum nx_mipi_dsi_lpmode cmdin_lp, enum nx_mipi_dsi_lpmode txinlp) { register struct nx_mipi_register_set *pregister; register u32 regvalue; u32 newvalue; pregister = __g_pregister[module_index]; newvalue = (stop_state_count << 21); newvalue |= (force_stop_state << 20); newvalue |= (force_bta << 16); newvalue |= (cmdin_lp << 7); newvalue |= (txinlp << 6); writereg(dsim_escmode, 0xFFFFFFC0, newvalue); } void nx_mipi_dsi_set_escape_lp(u32 module_index, enum nx_mipi_dsi_lpmode cmdin_lp, enum nx_mipi_dsi_lpmode txinlp) { register struct nx_mipi_register_set *pregister; register u32 regvalue; u32 newvalue = 0; pregister = __g_pregister[module_index]; newvalue |= (cmdin_lp << 7); newvalue |= (txinlp << 6); writereg(dsim_escmode, 0xC0, newvalue); } void nx_mipi_dsi_remote_reset_trigger(u32 module_index) { register struct nx_mipi_register_set *pregister; register u32 regvalue; u32 newvalue; pregister = __g_pregister[module_index]; newvalue = (1 << 4); writereg(dsim_escmode, (1 << 4), newvalue); while (readl(&pregister->dsim_escmode) & (1 << 4)) ; } void nx_mipi_dsi_set_ulps(u32 module_index, int ulpsclocklane, int ulpsdatalane) { register struct nx_mipi_register_set *pregister; register u32 regvalue; pregister = __g_pregister[module_index]; regvalue = pregister->dsim_escmode; if (ulpsclocklane) { regvalue &= ~(1 << 0); regvalue |= (1 << 1); } else { regvalue |= (1 << 0); } if (ulpsdatalane) { regvalue &= ~(1 << 2); regvalue |= (1 << 3); } else { regvalue |= (1 << 2); } writel(regvalue, &pregister->dsim_escmode); if (ulpsclocklane) while ((1 << 9) == (readl(&pregister->dsim_status) & (1 << 9))) ; else while (0 != (readl(&pregister->dsim_status) & (1 << 9))) ; if (ulpsdatalane) while ((15 << 4) == (readl(&pregister->dsim_status) & (15 << 4))) ; else while (0 != (readl(&pregister->dsim_status) & (15 << 4))) ; if (!ulpsclocklane) regvalue &= (3 << 0); if (!ulpsdatalane) regvalue |= (3 << 2); writel(regvalue, &pregister->dsim_escmode); } void nx_mipi_dsi_set_size(u32 module_index, u32 width, u32 height) { register struct nx_mipi_register_set *pregister; register u32 regvalue; u32 newvalue; pregister = __g_pregister[module_index]; newvalue = (height << 16); newvalue |= (width << 0); writereg(dsim_mdresol, 0x0FFFFFFF, newvalue); } void nx_mipi_dsi_set_enable(u32 module_index, int enable) { register struct nx_mipi_register_set *pregister; register u32 regvalue; pregister = __g_pregister[module_index]; writereg(dsim_mdresol, (1 << 31), (enable << 31)); } void nx_mipi_dsi_set_phy(u32 module_index, u32 number_of_data_lanes, int enable_clock_lane, int enable_data_lane0, int enable_data_lane1, int enable_data_lane2, int enable_data_lane3, int swap_clock_lane, int swap_data_lane) { register struct nx_mipi_register_set *pregister; register u32 regvalue; u32 newvalue; pregister = __g_pregister[module_index]; newvalue = (number_of_data_lanes << 5); newvalue |= (enable_clock_lane << 0); newvalue |= (enable_data_lane0 << 1); newvalue |= (enable_data_lane1 << 2); newvalue |= (enable_data_lane2 << 3); newvalue |= (enable_data_lane3 << 4); writereg(dsim_config, 0xFF, newvalue); newvalue = (swap_clock_lane << 1); newvalue |= (swap_data_lane << 0); writereg(dsim_phyacchr1, 0x3, newvalue); } void nx_mipi_dsi_set_pll(u32 module_index, int enable, u32 pllstabletimer, u32 m_pllpms, u32 m_bandctl, u32 m_dphyctl, u32 b_dphyctl) { register struct nx_mipi_register_set *pregister; register u32 regvalue; u32 newvalue; pregister = __g_pregister[module_index]; if (!enable) { newvalue = (enable << 23); newvalue |= (m_pllpms << 1); newvalue |= (m_bandctl << 24); writereg(dsim_pllctrl, 0x0FFFFFFF, newvalue); } writel(m_dphyctl, &pregister->dsim_phyacchr); writel(pllstabletimer, &pregister->dsim_plltmr); writel((b_dphyctl << 9), &pregister->dsim_phyacchr1); if (enable) { newvalue = (enable << 23); newvalue |= (m_pllpms << 1); newvalue |= (m_bandctl << 24); writereg(dsim_pllctrl, 0x0FFFFFFF, newvalue); } } void nx_mipi_dsi_write_pkheader(u32 module_index, u32 data) { register struct nx_mipi_register_set *pregister; pregister = __g_pregister[module_index]; writel(data, &pregister->dsim_pkthdr); } void nx_mipi_dsi_write_payload(u32 module_index, u32 data) { register struct nx_mipi_register_set *pregister; pregister = __g_pregister[module_index]; writel(data, &pregister->dsim_payload); } u32 nx_mipi_dsi_read_fifo_status(u32 module_index) { register struct nx_mipi_register_set *pregister; pregister = __g_pregister[module_index]; return readl(&pregister->dsim_fifoctrl); }