mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-24 12:03:39 +00:00
6390378408
Low level functions for MLC (Multi Layer Control) and MIPI (Mobile Industry Processor Interface). Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
580 lines
15 KiB
C
580 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);
|
|
}
|