summaryrefslogtreecommitdiff
path: root/drivers/video/nexell/soc/s5pxx18_soc_mipi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/nexell/soc/s5pxx18_soc_mipi.c')
-rw-r--r--drivers/video/nexell/soc/s5pxx18_soc_mipi.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/drivers/video/nexell/soc/s5pxx18_soc_mipi.c b/drivers/video/nexell/soc/s5pxx18_soc_mipi.c
new file mode 100644
index 0000000000..1000ddb642
--- /dev/null
+++ b/drivers/video/nexell/soc/s5pxx18_soc_mipi.c
@@ -0,0 +1,580 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+#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);
+}