u-boot-brain/drivers/video/nexell/soc/s5pxx18_soc_mipi.c
Stefan Bosch 6390378408 video: add nexell video driver (soc: mlc, mipi)
Low level functions for MLC (Multi Layer Control) and MIPI (Mobile
Industry Processor Interface).

Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
2020-07-29 08:43:40 -04:00

581 lines
15 KiB
C

// 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);
}