GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2000-2007
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
|
||||
obj-$(CONFIG_EXYNOS_DP) += exynos_dp.o exynos_dp_lowlevel.o
|
||||
obj-$(CONFIG_EXYNOS_FB) += exynos_fb.o
|
||||
obj-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
|
||||
exynos_mipi_dsi_lowlevel.o
|
||||
obj-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_EDP_LOWLEVEL_H
|
||||
#define _EXYNOS_EDP_LOWLEVEL_H
|
||||
|
||||
void exynos_dp_enable_video_bist(struct exynos_dp *dp_regs,
|
||||
unsigned int enable);
|
||||
void exynos_dp_enable_video_mute(struct exynos_dp *dp_regs,
|
||||
unsigned int enable);
|
||||
void exynos_dp_reset(struct exynos_dp *dp_regs);
|
||||
void exynos_dp_enable_sw_func(struct exynos_dp *dp_regs, unsigned int enable);
|
||||
unsigned int exynos_dp_set_analog_power_down(struct exynos_dp *dp_regs,
|
||||
unsigned int block, u32 enable);
|
||||
unsigned int exynos_dp_get_pll_lock_status(struct exynos_dp *dp_regs);
|
||||
int exynos_dp_init_analog_func(struct exynos_dp *dp_regs);
|
||||
void exynos_dp_init_hpd(struct exynos_dp *dp_regs);
|
||||
void exynos_dp_init_aux(struct exynos_dp *dp_regs);
|
||||
void exynos_dp_config_interrupt(struct exynos_dp *dp_regs);
|
||||
unsigned int exynos_dp_get_plug_in_status(struct exynos_dp *dp_regs);
|
||||
unsigned int exynos_dp_detect_hpd(struct exynos_dp *dp_regs);
|
||||
unsigned int exynos_dp_start_aux_transaction(struct exynos_dp *dp_regs);
|
||||
unsigned int exynos_dp_write_byte_to_dpcd(struct exynos_dp *dp_regs,
|
||||
unsigned int reg_addr,
|
||||
unsigned char data);
|
||||
unsigned int exynos_dp_read_byte_from_dpcd(struct exynos_dp *dp_regs,
|
||||
unsigned int reg_addr,
|
||||
unsigned char *data);
|
||||
unsigned int exynos_dp_write_bytes_to_dpcd(struct exynos_dp *dp_regs,
|
||||
unsigned int reg_addr,
|
||||
unsigned int count,
|
||||
unsigned char data[]);
|
||||
unsigned int exynos_dp_read_bytes_from_dpcd(struct exynos_dp *dp_regs,
|
||||
unsigned int reg_addr,
|
||||
unsigned int count,
|
||||
unsigned char data[]);
|
||||
int exynos_dp_select_i2c_device(struct exynos_dp *dp_regs,
|
||||
unsigned int device_addr,
|
||||
unsigned int reg_addr);
|
||||
int exynos_dp_read_byte_from_i2c(struct exynos_dp *dp_regs,
|
||||
unsigned int device_addr,
|
||||
unsigned int reg_addr, unsigned int *data);
|
||||
int exynos_dp_read_bytes_from_i2c(struct exynos_dp *dp_regs,
|
||||
unsigned int device_addr,
|
||||
unsigned int reg_addr, unsigned int count,
|
||||
unsigned char edid[]);
|
||||
void exynos_dp_reset_macro(struct exynos_dp *dp_regs);
|
||||
void exynos_dp_set_link_bandwidth(struct exynos_dp *dp_regs,
|
||||
unsigned char bwtype);
|
||||
unsigned char exynos_dp_get_link_bandwidth(struct exynos_dp *dp_regs);
|
||||
void exynos_dp_set_lane_count(struct exynos_dp *dp_regs, unsigned char count);
|
||||
unsigned int exynos_dp_get_lane_count(struct exynos_dp *dp_regs);
|
||||
unsigned char exynos_dp_get_lanex_pre_emphasis(struct exynos_dp *dp_regs,
|
||||
unsigned char lanecnt);
|
||||
void exynos_dp_set_lane_pre_emphasis(struct exynos_dp *dp_regs,
|
||||
unsigned int level, unsigned char lanecnt);
|
||||
void exynos_dp_set_lanex_pre_emphasis(struct exynos_dp *dp_regs,
|
||||
unsigned char request_val,
|
||||
unsigned char lanecnt);
|
||||
void exynos_dp_set_training_pattern(struct exynos_dp *dp_regs,
|
||||
unsigned int pattern);
|
||||
void exynos_dp_enable_enhanced_mode(struct exynos_dp *dp_regs,
|
||||
unsigned char enable);
|
||||
void exynos_dp_enable_scrambling(struct exynos_dp *dp_regs,
|
||||
unsigned int enable);
|
||||
int exynos_dp_init_video(struct exynos_dp *dp_regs);
|
||||
void exynos_dp_config_video_slave_mode(struct exynos_dp *dp_regs,
|
||||
struct edp_video_info *video_info);
|
||||
void exynos_dp_set_video_color_format(struct exynos_dp *dp_regs,
|
||||
struct edp_video_info *video_info);
|
||||
int exynos_dp_config_video_bist(struct exynos_dp *dp_regs,
|
||||
struct exynos_dp_priv *priv);
|
||||
unsigned int exynos_dp_is_slave_video_stream_clock_on(
|
||||
struct exynos_dp *dp_regs);
|
||||
void exynos_dp_set_video_cr_mn(struct exynos_dp *dp_regs, unsigned int type,
|
||||
unsigned int m_value, unsigned int n_value);
|
||||
void exynos_dp_set_video_timing_mode(struct exynos_dp *dp_regs,
|
||||
unsigned int type);
|
||||
void exynos_dp_enable_video_master(struct exynos_dp *dp_regs,
|
||||
unsigned int enable);
|
||||
void exynos_dp_start_video(struct exynos_dp *dp_regs);
|
||||
unsigned int exynos_dp_is_video_stream_on(struct exynos_dp *dp_regs);
|
||||
|
||||
#endif /* _EXYNOS_DP_LOWLEVEL_H */
|
||||
@@ -0,0 +1,719 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <display.h>
|
||||
#include <div64.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <panel.h>
|
||||
#include <video.h>
|
||||
#include <video_bridge.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
#include <asm/arch/dp_info.h>
|
||||
#include <asm/arch/fb.h>
|
||||
#include <asm/arch/pinmux.h>
|
||||
#include <asm/arch/system.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
enum {
|
||||
FIMD_RGB_INTERFACE = 1,
|
||||
FIMD_CPU_INTERFACE = 2,
|
||||
};
|
||||
|
||||
enum exynos_fb_rgb_mode_t {
|
||||
MODE_RGB_P = 0,
|
||||
MODE_BGR_P = 1,
|
||||
MODE_RGB_S = 2,
|
||||
MODE_BGR_S = 3,
|
||||
};
|
||||
|
||||
struct exynos_fb_priv {
|
||||
ushort vl_col; /* Number of columns (i.e. 640) */
|
||||
ushort vl_row; /* Number of rows (i.e. 480) */
|
||||
ushort vl_rot; /* Rotation of Display (0, 1, 2, 3) */
|
||||
ushort vl_width; /* Width of display area in millimeters */
|
||||
ushort vl_height; /* Height of display area in millimeters */
|
||||
|
||||
/* LCD configuration register */
|
||||
u_char vl_freq; /* Frequency */
|
||||
u_char vl_clkp; /* Clock polarity */
|
||||
u_char vl_oep; /* Output Enable polarity */
|
||||
u_char vl_hsp; /* Horizontal Sync polarity */
|
||||
u_char vl_vsp; /* Vertical Sync polarity */
|
||||
u_char vl_dp; /* Data polarity */
|
||||
u_char vl_bpix; /* Bits per pixel */
|
||||
|
||||
/* Horizontal control register. Timing from data sheet */
|
||||
u_char vl_hspw; /* Horz sync pulse width */
|
||||
u_char vl_hfpd; /* Wait before of line */
|
||||
u_char vl_hbpd; /* Wait end of line */
|
||||
|
||||
/* Vertical control register. */
|
||||
u_char vl_vspw; /* Vertical sync pulse width */
|
||||
u_char vl_vfpd; /* Wait before of frame */
|
||||
u_char vl_vbpd; /* Wait end of frame */
|
||||
u_char vl_cmd_allow_len; /* Wait end of frame */
|
||||
|
||||
unsigned int win_id;
|
||||
unsigned int init_delay;
|
||||
unsigned int power_on_delay;
|
||||
unsigned int reset_delay;
|
||||
unsigned int interface_mode;
|
||||
unsigned int mipi_enabled;
|
||||
unsigned int dp_enabled;
|
||||
unsigned int cs_setup;
|
||||
unsigned int wr_setup;
|
||||
unsigned int wr_act;
|
||||
unsigned int wr_hold;
|
||||
unsigned int logo_on;
|
||||
unsigned int logo_width;
|
||||
unsigned int logo_height;
|
||||
int logo_x_offset;
|
||||
int logo_y_offset;
|
||||
unsigned long logo_addr;
|
||||
unsigned int rgb_mode;
|
||||
unsigned int resolution;
|
||||
|
||||
/* parent clock name(MPLL, EPLL or VPLL) */
|
||||
unsigned int pclk_name;
|
||||
/* ratio value for source clock from parent clock. */
|
||||
unsigned int sclk_div;
|
||||
|
||||
unsigned int dual_lcd_enabled;
|
||||
struct exynos_fb *reg;
|
||||
struct exynos_platform_mipi_dsim *dsim_platform_data_dt;
|
||||
};
|
||||
|
||||
static void exynos_fimd_set_dualrgb(struct exynos_fb_priv *priv, bool enabled)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
|
||||
if (enabled) {
|
||||
cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT |
|
||||
EXYNOS_DUALRGB_VDEN_EN_ENABLE;
|
||||
|
||||
/* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
|
||||
cfg |= EXYNOS_DUALRGB_SUB_CNT(priv->vl_col / 2) |
|
||||
EXYNOS_DUALRGB_MAIN_CNT(0);
|
||||
}
|
||||
|
||||
writel(cfg, ®->dualrgb);
|
||||
}
|
||||
|
||||
static void exynos_fimd_set_dp_clkcon(struct exynos_fb_priv *priv,
|
||||
unsigned int enabled)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
|
||||
if (enabled)
|
||||
cfg = EXYNOS_DP_CLK_ENABLE;
|
||||
|
||||
writel(cfg, ®->dp_mie_clkcon);
|
||||
}
|
||||
|
||||
static void exynos_fimd_set_par(struct exynos_fb_priv *priv,
|
||||
unsigned int win_id)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
|
||||
/* set window control */
|
||||
cfg = readl((unsigned int)®->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
|
||||
cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE |
|
||||
EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE |
|
||||
EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK |
|
||||
EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK);
|
||||
|
||||
/* DATAPATH is DMA */
|
||||
cfg |= EXYNOS_WINCON_DATAPATH_DMA;
|
||||
|
||||
cfg |= EXYNOS_WINCON_HAWSWP_ENABLE;
|
||||
|
||||
/* dma burst is 16 */
|
||||
cfg |= EXYNOS_WINCON_BURSTLEN_16WORD;
|
||||
|
||||
switch (priv->vl_bpix) {
|
||||
case 4:
|
||||
cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565;
|
||||
break;
|
||||
default:
|
||||
cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888;
|
||||
break;
|
||||
}
|
||||
|
||||
writel(cfg, (unsigned int)®->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
|
||||
/* set window position to x=0, y=0*/
|
||||
cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
|
||||
writel(cfg, (unsigned int)®->vidosd0a +
|
||||
EXYNOS_VIDOSD(win_id));
|
||||
|
||||
cfg = EXYNOS_VIDOSD_RIGHT_X(priv->vl_col - 1) |
|
||||
EXYNOS_VIDOSD_BOTTOM_Y(priv->vl_row - 1) |
|
||||
EXYNOS_VIDOSD_RIGHT_X_E(1) |
|
||||
EXYNOS_VIDOSD_BOTTOM_Y_E(0);
|
||||
|
||||
writel(cfg, (unsigned int)®->vidosd0b +
|
||||
EXYNOS_VIDOSD(win_id));
|
||||
|
||||
/* set window size for window0*/
|
||||
cfg = EXYNOS_VIDOSD_SIZE(priv->vl_col * priv->vl_row);
|
||||
writel(cfg, (unsigned int)®->vidosd0c +
|
||||
EXYNOS_VIDOSD(win_id));
|
||||
}
|
||||
|
||||
static void exynos_fimd_set_buffer_address(struct exynos_fb_priv *priv,
|
||||
unsigned int win_id,
|
||||
ulong lcd_base_addr)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned long start_addr, end_addr;
|
||||
|
||||
start_addr = lcd_base_addr;
|
||||
end_addr = start_addr + ((priv->vl_col * (VNBITS(priv->vl_bpix) / 8)) *
|
||||
priv->vl_row);
|
||||
|
||||
writel(start_addr, (unsigned int)®->vidw00add0b0 +
|
||||
EXYNOS_BUFFER_OFFSET(win_id));
|
||||
writel(end_addr, (unsigned int)®->vidw00add1b0 +
|
||||
EXYNOS_BUFFER_OFFSET(win_id));
|
||||
}
|
||||
|
||||
static void exynos_fimd_set_clock(struct exynos_fb_priv *priv)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0, div = 0, remainder, remainder_div;
|
||||
unsigned long pixel_clock;
|
||||
unsigned long long src_clock;
|
||||
|
||||
if (priv->dual_lcd_enabled) {
|
||||
pixel_clock = priv->vl_freq *
|
||||
(priv->vl_hspw + priv->vl_hfpd +
|
||||
priv->vl_hbpd + priv->vl_col / 2) *
|
||||
(priv->vl_vspw + priv->vl_vfpd +
|
||||
priv->vl_vbpd + priv->vl_row);
|
||||
} else if (priv->interface_mode == FIMD_CPU_INTERFACE) {
|
||||
pixel_clock = priv->vl_freq *
|
||||
priv->vl_width * priv->vl_height *
|
||||
(priv->cs_setup + priv->wr_setup +
|
||||
priv->wr_act + priv->wr_hold + 1);
|
||||
} else {
|
||||
pixel_clock = priv->vl_freq *
|
||||
(priv->vl_hspw + priv->vl_hfpd +
|
||||
priv->vl_hbpd + priv->vl_col) *
|
||||
(priv->vl_vspw + priv->vl_vfpd +
|
||||
priv->vl_vbpd + priv->vl_row);
|
||||
}
|
||||
|
||||
cfg = readl(®->vidcon0);
|
||||
cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK |
|
||||
EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK |
|
||||
EXYNOS_VIDCON0_CLKDIR_MASK);
|
||||
cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS |
|
||||
EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED);
|
||||
|
||||
src_clock = (unsigned long long) get_lcd_clk();
|
||||
|
||||
/* get quotient and remainder. */
|
||||
remainder = do_div(src_clock, pixel_clock);
|
||||
div = src_clock;
|
||||
|
||||
remainder *= 10;
|
||||
remainder_div = remainder / pixel_clock;
|
||||
|
||||
/* round about one places of decimals. */
|
||||
if (remainder_div >= 5)
|
||||
div++;
|
||||
|
||||
/* in case of dual lcd mode. */
|
||||
if (priv->dual_lcd_enabled)
|
||||
div--;
|
||||
|
||||
cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1);
|
||||
writel(cfg, ®->vidcon0);
|
||||
}
|
||||
|
||||
void exynos_set_trigger(struct exynos_fb_priv *priv)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
|
||||
cfg = readl(®->trigcon);
|
||||
|
||||
cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG);
|
||||
|
||||
writel(cfg, ®->trigcon);
|
||||
}
|
||||
|
||||
int exynos_is_i80_frame_done(struct exynos_fb_priv *priv)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
int status;
|
||||
|
||||
cfg = readl(®->trigcon);
|
||||
|
||||
/* frame done func is valid only when TRIMODE[0] is set to 1. */
|
||||
status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) ==
|
||||
EXYNOS_I80STATUS_TRIG_DONE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void exynos_fimd_lcd_on(struct exynos_fb_priv *priv)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
|
||||
/* display on */
|
||||
cfg = readl(®->vidcon0);
|
||||
cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE);
|
||||
writel(cfg, ®->vidcon0);
|
||||
}
|
||||
|
||||
static void exynos_fimd_window_on(struct exynos_fb_priv *priv,
|
||||
unsigned int win_id)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
|
||||
/* enable window */
|
||||
cfg = readl((unsigned int)®->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
cfg |= EXYNOS_WINCON_ENWIN_ENABLE;
|
||||
writel(cfg, (unsigned int)®->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
|
||||
cfg = readl(®->winshmap);
|
||||
cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id);
|
||||
writel(cfg, ®->winshmap);
|
||||
}
|
||||
|
||||
void exynos_fimd_lcd_off(struct exynos_fb_priv *priv)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
|
||||
cfg = readl(®->vidcon0);
|
||||
cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE);
|
||||
writel(cfg, ®->vidcon0);
|
||||
}
|
||||
|
||||
void exynos_fimd_window_off(struct exynos_fb_priv *priv, unsigned int win_id)
|
||||
{
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0;
|
||||
|
||||
cfg = readl((unsigned int)®->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
cfg &= EXYNOS_WINCON_ENWIN_DISABLE;
|
||||
writel(cfg, (unsigned int)®->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
|
||||
cfg = readl(®->winshmap);
|
||||
cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id);
|
||||
writel(cfg, ®->winshmap);
|
||||
}
|
||||
|
||||
/*
|
||||
* The reset value for FIMD SYSMMU register MMU_CTRL is 3
|
||||
* on Exynos5420 and newer versions.
|
||||
* This means FIMD SYSMMU is on by default on Exynos5420
|
||||
* and newer versions.
|
||||
* Since in u-boot we don't use SYSMMU, we should disable
|
||||
* those FIMD SYSMMU.
|
||||
* Note that there are 2 SYSMMU for FIMD: m0 and m1.
|
||||
* m0 handles windows 0 and 4, and m1 handles windows 1, 2 and 3.
|
||||
* We disable both of them here.
|
||||
*/
|
||||
void exynos_fimd_disable_sysmmu(void)
|
||||
{
|
||||
u32 *sysmmufimd;
|
||||
unsigned int node;
|
||||
int node_list[2];
|
||||
int count;
|
||||
int i;
|
||||
|
||||
count = fdtdec_find_aliases_for_id(gd->fdt_blob, "fimd",
|
||||
COMPAT_SAMSUNG_EXYNOS_SYSMMU, node_list, 2);
|
||||
for (i = 0; i < count; i++) {
|
||||
node = node_list[i];
|
||||
if (node <= 0) {
|
||||
debug("Can't get device node for fimd sysmmu\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sysmmufimd = (u32 *)fdtdec_get_addr(gd->fdt_blob, node, "reg");
|
||||
if (!sysmmufimd) {
|
||||
debug("Can't get base address for sysmmu fimdm0");
|
||||
return;
|
||||
}
|
||||
|
||||
writel(0x0, sysmmufimd);
|
||||
}
|
||||
}
|
||||
|
||||
void exynos_fimd_lcd_init(struct udevice *dev)
|
||||
{
|
||||
struct exynos_fb_priv *priv = dev_get_priv(dev);
|
||||
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
|
||||
struct exynos_fb *reg = priv->reg;
|
||||
unsigned int cfg = 0, rgb_mode;
|
||||
unsigned int offset;
|
||||
unsigned int node;
|
||||
|
||||
node = dev_of_offset(dev);
|
||||
if (fdtdec_get_bool(gd->fdt_blob, node, "samsung,disable-sysmmu"))
|
||||
exynos_fimd_disable_sysmmu();
|
||||
|
||||
offset = exynos_fimd_get_base_offset();
|
||||
|
||||
rgb_mode = priv->rgb_mode;
|
||||
|
||||
if (priv->interface_mode == FIMD_RGB_INTERFACE) {
|
||||
cfg |= EXYNOS_VIDCON0_VIDOUT_RGB;
|
||||
writel(cfg, ®->vidcon0);
|
||||
|
||||
cfg = readl(®->vidcon2);
|
||||
cfg &= ~(EXYNOS_VIDCON2_WB_MASK |
|
||||
EXYNOS_VIDCON2_TVFORMATSEL_MASK |
|
||||
EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK);
|
||||
cfg |= EXYNOS_VIDCON2_WB_DISABLE;
|
||||
writel(cfg, ®->vidcon2);
|
||||
|
||||
/* set polarity */
|
||||
cfg = 0;
|
||||
if (!priv->vl_clkp)
|
||||
cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE;
|
||||
if (!priv->vl_hsp)
|
||||
cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT;
|
||||
if (!priv->vl_vsp)
|
||||
cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT;
|
||||
if (!priv->vl_dp)
|
||||
cfg |= EXYNOS_VIDCON1_IVDEN_INVERT;
|
||||
|
||||
writel(cfg, (unsigned int)®->vidcon1 + offset);
|
||||
|
||||
/* set timing */
|
||||
cfg = EXYNOS_VIDTCON0_VFPD(priv->vl_vfpd - 1);
|
||||
cfg |= EXYNOS_VIDTCON0_VBPD(priv->vl_vbpd - 1);
|
||||
cfg |= EXYNOS_VIDTCON0_VSPW(priv->vl_vspw - 1);
|
||||
writel(cfg, (unsigned int)®->vidtcon0 + offset);
|
||||
|
||||
cfg = EXYNOS_VIDTCON1_HFPD(priv->vl_hfpd - 1);
|
||||
cfg |= EXYNOS_VIDTCON1_HBPD(priv->vl_hbpd - 1);
|
||||
cfg |= EXYNOS_VIDTCON1_HSPW(priv->vl_hspw - 1);
|
||||
|
||||
writel(cfg, (unsigned int)®->vidtcon1 + offset);
|
||||
|
||||
/* set lcd size */
|
||||
cfg = EXYNOS_VIDTCON2_HOZVAL(priv->vl_col - 1) |
|
||||
EXYNOS_VIDTCON2_LINEVAL(priv->vl_row - 1) |
|
||||
EXYNOS_VIDTCON2_HOZVAL_E(priv->vl_col - 1) |
|
||||
EXYNOS_VIDTCON2_LINEVAL_E(priv->vl_row - 1);
|
||||
|
||||
writel(cfg, (unsigned int)®->vidtcon2 + offset);
|
||||
}
|
||||
|
||||
/* set display mode */
|
||||
cfg = readl(®->vidcon0);
|
||||
cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK;
|
||||
cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT);
|
||||
writel(cfg, ®->vidcon0);
|
||||
|
||||
/* set par */
|
||||
exynos_fimd_set_par(priv, priv->win_id);
|
||||
|
||||
/* set memory address */
|
||||
exynos_fimd_set_buffer_address(priv, priv->win_id, plat->base);
|
||||
|
||||
/* set buffer size */
|
||||
cfg = EXYNOS_VIDADDR_PAGEWIDTH(priv->vl_col *
|
||||
VNBITS(priv->vl_bpix) / 8) |
|
||||
EXYNOS_VIDADDR_PAGEWIDTH_E(priv->vl_col *
|
||||
VNBITS(priv->vl_bpix) / 8) |
|
||||
EXYNOS_VIDADDR_OFFSIZE(0) |
|
||||
EXYNOS_VIDADDR_OFFSIZE_E(0);
|
||||
|
||||
writel(cfg, (unsigned int)®->vidw00add2 +
|
||||
EXYNOS_BUFFER_SIZE(priv->win_id));
|
||||
|
||||
/* set clock */
|
||||
exynos_fimd_set_clock(priv);
|
||||
|
||||
/* set rgb mode to dual lcd. */
|
||||
exynos_fimd_set_dualrgb(priv, priv->dual_lcd_enabled);
|
||||
|
||||
/* display on */
|
||||
exynos_fimd_lcd_on(priv);
|
||||
|
||||
/* window on */
|
||||
exynos_fimd_window_on(priv, priv->win_id);
|
||||
|
||||
exynos_fimd_set_dp_clkcon(priv, priv->dp_enabled);
|
||||
}
|
||||
|
||||
unsigned long exynos_fimd_calc_fbsize(struct exynos_fb_priv *priv)
|
||||
{
|
||||
return priv->vl_col * priv->vl_row * (VNBITS(priv->vl_bpix) / 8);
|
||||
}
|
||||
|
||||
int exynos_fb_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct exynos_fb_priv *priv = dev_get_priv(dev);
|
||||
unsigned int node = dev_of_offset(dev);
|
||||
const void *blob = gd->fdt_blob;
|
||||
fdt_addr_t addr;
|
||||
|
||||
addr = devfdt_get_addr(dev);
|
||||
if (addr == FDT_ADDR_T_NONE) {
|
||||
debug("Can't get the FIMD base address\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
priv->reg = (struct exynos_fb *)addr;
|
||||
|
||||
priv->vl_col = fdtdec_get_int(blob, node, "samsung,vl-col", 0);
|
||||
if (priv->vl_col == 0) {
|
||||
debug("Can't get XRES\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_row = fdtdec_get_int(blob, node, "samsung,vl-row", 0);
|
||||
if (priv->vl_row == 0) {
|
||||
debug("Can't get YRES\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_width = fdtdec_get_int(blob, node,
|
||||
"samsung,vl-width", 0);
|
||||
|
||||
priv->vl_height = fdtdec_get_int(blob, node,
|
||||
"samsung,vl-height", 0);
|
||||
|
||||
priv->vl_freq = fdtdec_get_int(blob, node, "samsung,vl-freq", 0);
|
||||
if (priv->vl_freq == 0) {
|
||||
debug("Can't get refresh rate\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (fdtdec_get_bool(blob, node, "samsung,vl-clkp"))
|
||||
priv->vl_clkp = VIDEO_ACTIVE_LOW;
|
||||
|
||||
if (fdtdec_get_bool(blob, node, "samsung,vl-oep"))
|
||||
priv->vl_oep = VIDEO_ACTIVE_LOW;
|
||||
|
||||
if (fdtdec_get_bool(blob, node, "samsung,vl-hsp"))
|
||||
priv->vl_hsp = VIDEO_ACTIVE_LOW;
|
||||
|
||||
if (fdtdec_get_bool(blob, node, "samsung,vl-vsp"))
|
||||
priv->vl_vsp = VIDEO_ACTIVE_LOW;
|
||||
|
||||
if (fdtdec_get_bool(blob, node, "samsung,vl-dp"))
|
||||
priv->vl_dp = VIDEO_ACTIVE_LOW;
|
||||
|
||||
priv->vl_bpix = fdtdec_get_int(blob, node, "samsung,vl-bpix", 0);
|
||||
if (priv->vl_bpix == 0) {
|
||||
debug("Can't get bits per pixel\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_hspw = fdtdec_get_int(blob, node, "samsung,vl-hspw", 0);
|
||||
if (priv->vl_hspw == 0) {
|
||||
debug("Can't get hsync width\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_hfpd = fdtdec_get_int(blob, node, "samsung,vl-hfpd", 0);
|
||||
if (priv->vl_hfpd == 0) {
|
||||
debug("Can't get right margin\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_hbpd = (u_char)fdtdec_get_int(blob, node,
|
||||
"samsung,vl-hbpd", 0);
|
||||
if (priv->vl_hbpd == 0) {
|
||||
debug("Can't get left margin\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_vspw = (u_char)fdtdec_get_int(blob, node,
|
||||
"samsung,vl-vspw", 0);
|
||||
if (priv->vl_vspw == 0) {
|
||||
debug("Can't get vsync width\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_vfpd = fdtdec_get_int(blob, node,
|
||||
"samsung,vl-vfpd", 0);
|
||||
if (priv->vl_vfpd == 0) {
|
||||
debug("Can't get lower margin\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_vbpd = fdtdec_get_int(blob, node, "samsung,vl-vbpd", 0);
|
||||
if (priv->vl_vbpd == 0) {
|
||||
debug("Can't get upper margin\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
priv->vl_cmd_allow_len = fdtdec_get_int(blob, node,
|
||||
"samsung,vl-cmd-allow-len", 0);
|
||||
|
||||
priv->win_id = fdtdec_get_int(blob, node, "samsung,winid", 0);
|
||||
priv->init_delay = fdtdec_get_int(blob, node,
|
||||
"samsung,init-delay", 0);
|
||||
priv->power_on_delay = fdtdec_get_int(blob, node,
|
||||
"samsung,power-on-delay", 0);
|
||||
priv->reset_delay = fdtdec_get_int(blob, node,
|
||||
"samsung,reset-delay", 0);
|
||||
priv->interface_mode = fdtdec_get_int(blob, node,
|
||||
"samsung,interface-mode", 0);
|
||||
priv->mipi_enabled = fdtdec_get_int(blob, node,
|
||||
"samsung,mipi-enabled", 0);
|
||||
priv->dp_enabled = fdtdec_get_int(blob, node,
|
||||
"samsung,dp-enabled", 0);
|
||||
priv->cs_setup = fdtdec_get_int(blob, node,
|
||||
"samsung,cs-setup", 0);
|
||||
priv->wr_setup = fdtdec_get_int(blob, node,
|
||||
"samsung,wr-setup", 0);
|
||||
priv->wr_act = fdtdec_get_int(blob, node, "samsung,wr-act", 0);
|
||||
priv->wr_hold = fdtdec_get_int(blob, node, "samsung,wr-hold", 0);
|
||||
|
||||
priv->logo_on = fdtdec_get_int(blob, node, "samsung,logo-on", 0);
|
||||
if (priv->logo_on) {
|
||||
priv->logo_width = fdtdec_get_int(blob, node,
|
||||
"samsung,logo-width", 0);
|
||||
priv->logo_height = fdtdec_get_int(blob, node,
|
||||
"samsung,logo-height", 0);
|
||||
priv->logo_addr = fdtdec_get_int(blob, node,
|
||||
"samsung,logo-addr", 0);
|
||||
}
|
||||
|
||||
priv->rgb_mode = fdtdec_get_int(blob, node,
|
||||
"samsung,rgb-mode", 0);
|
||||
priv->pclk_name = fdtdec_get_int(blob, node,
|
||||
"samsung,pclk-name", 0);
|
||||
priv->sclk_div = fdtdec_get_int(blob, node,
|
||||
"samsung,sclk-div", 0);
|
||||
priv->dual_lcd_enabled = fdtdec_get_int(blob, node,
|
||||
"samsung,dual-lcd-enabled", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_fb_probe(struct udevice *dev)
|
||||
{
|
||||
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct exynos_fb_priv *priv = dev_get_priv(dev);
|
||||
struct udevice *panel, *bridge;
|
||||
struct udevice *dp;
|
||||
int ret;
|
||||
|
||||
debug("%s: start\n", __func__);
|
||||
set_system_display_ctrl();
|
||||
set_lcd_clk();
|
||||
|
||||
#ifdef CONFIG_EXYNOS_MIPI_DSIM
|
||||
exynos_init_dsim_platform_data(&panel_info);
|
||||
#endif
|
||||
exynos_fimd_lcd_init(dev);
|
||||
|
||||
ret = uclass_first_device(UCLASS_PANEL, &panel);
|
||||
if (ret) {
|
||||
printf("LCD panel failed to probe\n");
|
||||
return ret;
|
||||
}
|
||||
if (!panel) {
|
||||
printf("LCD panel not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = uclass_first_device(UCLASS_DISPLAY, &dp);
|
||||
if (ret) {
|
||||
debug("%s: Display device error %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
if (!dev) {
|
||||
debug("%s: Display device missing\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = display_enable(dp, 18, NULL);
|
||||
if (ret) {
|
||||
debug("%s: Display enable error %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* backlight / pwm */
|
||||
ret = panel_enable_backlight(panel);
|
||||
if (ret) {
|
||||
debug("%s: backlight error: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge);
|
||||
if (!ret)
|
||||
ret = video_bridge_set_backlight(bridge, 80);
|
||||
if (ret) {
|
||||
debug("%s: No video bridge, or no backlight on bridge\n",
|
||||
__func__);
|
||||
exynos_pinmux_config(PERIPH_ID_PWM0, 0);
|
||||
}
|
||||
|
||||
uc_priv->xsize = priv->vl_col;
|
||||
uc_priv->ysize = priv->vl_row;
|
||||
uc_priv->bpix = priv->vl_bpix;
|
||||
|
||||
/* Enable flushing after LCD writes if requested */
|
||||
video_set_flush_dcache(dev, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_fb_bind(struct udevice *dev)
|
||||
{
|
||||
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
|
||||
|
||||
/* This is the maximum panel size we expect to see */
|
||||
plat->size = 1920 * 1080 * 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct video_ops exynos_fb_ops = {
|
||||
};
|
||||
|
||||
static const struct udevice_id exynos_fb_ids[] = {
|
||||
{ .compatible = "samsung,exynos-fimd" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(exynos_fb) = {
|
||||
.name = "exynos_fb",
|
||||
.id = UCLASS_VIDEO,
|
||||
.of_match = exynos_fb_ids,
|
||||
.ops = &exynos_fb_ops,
|
||||
.bind = exynos_fb_bind,
|
||||
.probe = exynos_fb_probe,
|
||||
.ofdata_to_platdata = exynos_fb_ofdata_to_platdata,
|
||||
.priv_auto_alloc_size = sizeof(struct exynos_fb_priv),
|
||||
};
|
||||
@@ -0,0 +1,323 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <malloc.h>
|
||||
#include <fdtdec.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/arch/dsim.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clk.h>
|
||||
|
||||
#include "exynos_mipi_dsi_lowlevel.h"
|
||||
#include "exynos_mipi_dsi_common.h"
|
||||
|
||||
#define master_to_driver(a) (a->dsim_lcd_drv)
|
||||
#define master_to_device(a) (a->dsim_lcd_dev)
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct mipi_dsim_ddi {
|
||||
int bus_id;
|
||||
struct list_head list;
|
||||
struct mipi_dsim_lcd_device *dsim_lcd_dev;
|
||||
struct mipi_dsim_lcd_driver *dsim_lcd_drv;
|
||||
};
|
||||
|
||||
static LIST_HEAD(dsim_ddi_list);
|
||||
static LIST_HEAD(dsim_lcd_dev_list);
|
||||
|
||||
int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
|
||||
{
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
|
||||
if (!lcd_dev) {
|
||||
debug("mipi_dsim_lcd_device is NULL.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!lcd_dev->name) {
|
||||
debug("dsim_lcd_device name is NULL.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
|
||||
if (!dsim_ddi) {
|
||||
debug("failed to allocate dsim_ddi object.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim_ddi->dsim_lcd_dev = lcd_dev;
|
||||
|
||||
list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mipi_dsim_ddi
|
||||
*exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
|
||||
{
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
struct mipi_dsim_lcd_device *lcd_dev;
|
||||
|
||||
list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
|
||||
lcd_dev = dsim_ddi->dsim_lcd_dev;
|
||||
if (!lcd_dev)
|
||||
continue;
|
||||
|
||||
if (lcd_drv->id >= 0) {
|
||||
if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 &&
|
||||
lcd_drv->id == lcd_dev->id) {
|
||||
/**
|
||||
* bus_id would be used to identify
|
||||
* connected bus.
|
||||
*/
|
||||
dsim_ddi->bus_id = lcd_dev->bus_id;
|
||||
|
||||
return dsim_ddi;
|
||||
}
|
||||
} else {
|
||||
if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
|
||||
/**
|
||||
* bus_id would be used to identify
|
||||
* connected bus.
|
||||
*/
|
||||
dsim_ddi->bus_id = lcd_dev->bus_id;
|
||||
|
||||
return dsim_ddi;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(dsim_ddi);
|
||||
list_del(&dsim_ddi_list);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
|
||||
{
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
|
||||
if (!lcd_drv) {
|
||||
debug("mipi_dsim_lcd_driver is NULL.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!lcd_drv->name) {
|
||||
debug("dsim_lcd_driver name is NULL.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
|
||||
if (!dsim_ddi) {
|
||||
debug("mipi_dsim_ddi object not found.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim_ddi->dsim_lcd_drv = lcd_drv;
|
||||
|
||||
debug("registered panel driver(%s) to mipi-dsi driver.\n",
|
||||
lcd_drv->name);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
struct mipi_dsim_ddi
|
||||
*exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
|
||||
const char *name)
|
||||
{
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
struct mipi_dsim_lcd_driver *lcd_drv;
|
||||
struct mipi_dsim_lcd_device *lcd_dev;
|
||||
|
||||
list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
|
||||
lcd_drv = dsim_ddi->dsim_lcd_drv;
|
||||
lcd_dev = dsim_ddi->dsim_lcd_dev;
|
||||
if (!lcd_drv || !lcd_dev)
|
||||
continue;
|
||||
|
||||
debug("lcd_drv->id = %d, lcd_dev->id = %d\n",
|
||||
lcd_drv->id, lcd_dev->id);
|
||||
|
||||
if ((strcmp(lcd_drv->name, name) == 0)) {
|
||||
lcd_dev->master = dsim;
|
||||
|
||||
dsim->dsim_lcd_dev = lcd_dev;
|
||||
dsim->dsim_lcd_drv = lcd_drv;
|
||||
|
||||
return dsim_ddi;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* define MIPI-DSI Master operations. */
|
||||
static struct mipi_dsim_master_ops master_ops = {
|
||||
.cmd_write = exynos_mipi_dsi_wr_data,
|
||||
.get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status,
|
||||
.clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done,
|
||||
};
|
||||
|
||||
int exynos_mipi_dsi_init(struct exynos_platform_mipi_dsim *dsim_pd)
|
||||
{
|
||||
struct mipi_dsim_device *dsim;
|
||||
struct mipi_dsim_config *dsim_config;
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
|
||||
dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
|
||||
if (!dsim) {
|
||||
debug("failed to allocate dsim object.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* get mipi_dsim_config. */
|
||||
dsim_config = dsim_pd->dsim_config;
|
||||
if (dsim_config == NULL) {
|
||||
debug("failed to get dsim config data.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim->pd = dsim_pd;
|
||||
dsim->dsim_config = dsim_config;
|
||||
dsim->master_ops = &master_ops;
|
||||
|
||||
/* bind lcd ddi matched with panel name. */
|
||||
dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
|
||||
if (!dsim_ddi) {
|
||||
debug("mipi_dsim_ddi object not found.\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
if (dsim_pd->lcd_power)
|
||||
dsim_pd->lcd_power();
|
||||
|
||||
if (dsim_pd->mipi_power)
|
||||
dsim_pd->mipi_power();
|
||||
|
||||
/* phy_enable(unsigned int dev_index, unsigned int enable) */
|
||||
if (dsim_pd->phy_enable)
|
||||
dsim_pd->phy_enable(0, 1);
|
||||
|
||||
set_mipi_clk();
|
||||
|
||||
exynos_mipi_dsi_init_dsim(dsim);
|
||||
exynos_mipi_dsi_init_link(dsim);
|
||||
exynos_mipi_dsi_set_hs_enable(dsim);
|
||||
|
||||
/* set display timing. */
|
||||
exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
|
||||
|
||||
/* initialize mipi-dsi client(lcd panel). */
|
||||
if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) {
|
||||
dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim);
|
||||
dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim);
|
||||
}
|
||||
|
||||
debug("mipi-dsi driver(%s mode) has been probed.\n",
|
||||
(dsim_config->e_interface == DSIM_COMMAND) ?
|
||||
"CPU" : "RGB");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt,
|
||||
struct mipi_dsim_lcd_device *lcd_dt)
|
||||
{
|
||||
int node;
|
||||
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_MIPI_DSI);
|
||||
if (node <= 0) {
|
||||
printf("exynos_mipi_dsi: Can't get device node for mipi dsi\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dt->e_interface = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-e-interface", 0);
|
||||
|
||||
dt->e_virtual_ch = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-e-virtual-ch", 0);
|
||||
|
||||
dt->e_pixel_format = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-e-pixel-format", 0);
|
||||
|
||||
dt->e_burst_mode = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-e-burst-mode", 0);
|
||||
|
||||
dt->e_no_data_lane = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-e-no-data-lane", 0);
|
||||
|
||||
dt->e_byte_clk = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-e-byte-clk", 0);
|
||||
|
||||
dt->hfp = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-hfp", 0);
|
||||
|
||||
dt->p = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-p", 0);
|
||||
dt->m = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-m", 0);
|
||||
dt->s = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-s", 0);
|
||||
|
||||
dt->pll_stable_time = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-pll-stable-time", 0);
|
||||
|
||||
dt->esc_clk = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-esc-clk", 0);
|
||||
|
||||
dt->stop_holding_cnt = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-stop-holding-cnt", 0);
|
||||
|
||||
dt->bta_timeout = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-bta-timeout", 0);
|
||||
|
||||
dt->rx_timeout = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-config-rx-timeout", 0);
|
||||
|
||||
lcd_dt->name = fdtdec_get_config_string(blob,
|
||||
"samsung,dsim-device-name");
|
||||
|
||||
lcd_dt->id = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-device-id", 0);
|
||||
|
||||
lcd_dt->bus_id = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-device-bus_id", 0);
|
||||
|
||||
lcd_dt->reverse_panel = fdtdec_get_int(blob, node,
|
||||
"samsung,dsim-device-reverse-panel", 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exynos_init_dsim_platform_data(vidinfo_t *vid)
|
||||
{
|
||||
static struct mipi_dsim_config dsim_config_dt;
|
||||
static struct exynos_platform_mipi_dsim dsim_platform_data_dt;
|
||||
static struct mipi_dsim_lcd_device mipi_lcd_device_dt;
|
||||
|
||||
if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt,
|
||||
&mipi_lcd_device_dt))
|
||||
debug("Can't get proper dsim config.\n");
|
||||
|
||||
strcpy(dsim_platform_data_dt.lcd_panel_name, mipi_lcd_device_dt.name);
|
||||
dsim_platform_data_dt.dsim_config = &dsim_config_dt;
|
||||
dsim_platform_data_dt.mipi_power = mipi_power;
|
||||
dsim_platform_data_dt.phy_enable = set_mipi_phy_ctrl;
|
||||
dsim_platform_data_dt.lcd_panel_info = (void *)vid;
|
||||
|
||||
mipi_lcd_device_dt.platform_data = (void *)&dsim_platform_data_dt;
|
||||
exynos_mipi_dsi_register_lcd_device(&mipi_lcd_device_dt);
|
||||
|
||||
vid->dsim_platform_data_dt = &dsim_platform_data_dt;
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <lcd.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/arch/dsim.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
|
||||
#include "exynos_mipi_dsi_lowlevel.h"
|
||||
|
||||
#define MHZ (1000 * 1000)
|
||||
#define FIN_HZ (24 * MHZ)
|
||||
|
||||
#define DFIN_PLL_MIN_HZ (6 * MHZ)
|
||||
#define DFIN_PLL_MAX_HZ (12 * MHZ)
|
||||
|
||||
#define DFVCO_MIN_HZ (500 * MHZ)
|
||||
#define DFVCO_MAX_HZ (1000 * MHZ)
|
||||
|
||||
#define TRY_GET_FIFO_TIMEOUT (5000 * 2)
|
||||
|
||||
/* MIPI-DSIM status types. */
|
||||
enum {
|
||||
DSIM_STATE_INIT, /* should be initialized. */
|
||||
DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */
|
||||
DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
|
||||
DSIM_STATE_ULPS
|
||||
};
|
||||
|
||||
/* define DSI lane types. */
|
||||
enum {
|
||||
DSIM_LANE_CLOCK = (1 << 0),
|
||||
DSIM_LANE_DATA0 = (1 << 1),
|
||||
DSIM_LANE_DATA1 = (1 << 2),
|
||||
DSIM_LANE_DATA2 = (1 << 3),
|
||||
DSIM_LANE_DATA3 = (1 << 4)
|
||||
};
|
||||
|
||||
static unsigned int dpll_table[15] = {
|
||||
100, 120, 170, 220, 270,
|
||||
320, 390, 450, 510, 560,
|
||||
640, 690, 770, 870, 950
|
||||
};
|
||||
|
||||
static void exynos_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
|
||||
const unsigned char *data0, unsigned int data1)
|
||||
{
|
||||
unsigned int data_cnt = 0, payload = 0;
|
||||
|
||||
/* in case that data count is more then 4 */
|
||||
for (data_cnt = 0; data_cnt < data1; data_cnt += 4) {
|
||||
/*
|
||||
* after sending 4bytes per one time,
|
||||
* send remainder data less then 4.
|
||||
*/
|
||||
if ((data1 - data_cnt) < 4) {
|
||||
if ((data1 - data_cnt) == 3) {
|
||||
payload = data0[data_cnt] |
|
||||
data0[data_cnt + 1] << 8 |
|
||||
data0[data_cnt + 2] << 16;
|
||||
debug("count = 3 payload = %x, %x %x %x\n",
|
||||
payload, data0[data_cnt],
|
||||
data0[data_cnt + 1],
|
||||
data0[data_cnt + 2]);
|
||||
} else if ((data1 - data_cnt) == 2) {
|
||||
payload = data0[data_cnt] |
|
||||
data0[data_cnt + 1] << 8;
|
||||
debug("count = 2 payload = %x, %x %x\n", payload,
|
||||
data0[data_cnt], data0[data_cnt + 1]);
|
||||
} else if ((data1 - data_cnt) == 1) {
|
||||
payload = data0[data_cnt];
|
||||
}
|
||||
} else {
|
||||
/* send 4bytes per one time. */
|
||||
payload = data0[data_cnt] |
|
||||
data0[data_cnt + 1] << 8 |
|
||||
data0[data_cnt + 2] << 16 |
|
||||
data0[data_cnt + 3] << 24;
|
||||
|
||||
debug("count = 4 payload = %x, %x %x %x %x\n",
|
||||
payload, *(u8 *)(data0 + data_cnt),
|
||||
data0[data_cnt + 1],
|
||||
data0[data_cnt + 2],
|
||||
data0[data_cnt + 3]);
|
||||
}
|
||||
exynos_mipi_dsi_wr_tx_data(dsim, payload);
|
||||
}
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
|
||||
const unsigned char *data0, unsigned int data1)
|
||||
{
|
||||
unsigned int timeout = TRY_GET_FIFO_TIMEOUT;
|
||||
unsigned long delay_val, delay;
|
||||
unsigned int check_rx_ack = 0;
|
||||
|
||||
if (dsim->state == DSIM_STATE_ULPS) {
|
||||
debug("state is ULPS.\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
delay_val = MHZ / dsim->dsim_config->esc_clk;
|
||||
delay = 10 * delay_val;
|
||||
|
||||
mdelay(delay);
|
||||
|
||||
/* only if transfer mode is LPDT, wait SFR becomes empty. */
|
||||
if (dsim->state == DSIM_STATE_STOP) {
|
||||
while (!(exynos_mipi_dsi_get_fifo_state(dsim) &
|
||||
SFR_HEADER_EMPTY)) {
|
||||
if ((timeout--) > 0)
|
||||
mdelay(1);
|
||||
else {
|
||||
debug("SRF header fifo is not empty.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (data_id) {
|
||||
/* short packet types of packet types for command. */
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
|
||||
case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
|
||||
debug("data0 = %x data1 = %x\n",
|
||||
data0[0], data0[1]);
|
||||
exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
|
||||
if (check_rx_ack) {
|
||||
/* process response func should be implemented */
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* general command */
|
||||
case MIPI_DSI_COLOR_MODE_OFF:
|
||||
case MIPI_DSI_COLOR_MODE_ON:
|
||||
case MIPI_DSI_SHUTDOWN_PERIPHERAL:
|
||||
case MIPI_DSI_TURN_ON_PERIPHERAL:
|
||||
exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
|
||||
if (check_rx_ack) {
|
||||
/* process response func should be implemented. */
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* packet types for video data */
|
||||
case MIPI_DSI_V_SYNC_START:
|
||||
case MIPI_DSI_V_SYNC_END:
|
||||
case MIPI_DSI_H_SYNC_START:
|
||||
case MIPI_DSI_H_SYNC_END:
|
||||
case MIPI_DSI_END_OF_TRANSMISSION:
|
||||
return 0;
|
||||
|
||||
/* short and response packet types for command */
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
|
||||
case MIPI_DSI_DCS_READ:
|
||||
exynos_mipi_dsi_clear_all_interrupt(dsim);
|
||||
exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0[0], data0[1]);
|
||||
/* process response func should be implemented. */
|
||||
return 0;
|
||||
|
||||
/* long packet type and null packet */
|
||||
case MIPI_DSI_NULL_PACKET:
|
||||
case MIPI_DSI_BLANKING_PACKET:
|
||||
return 0;
|
||||
case MIPI_DSI_GENERIC_LONG_WRITE:
|
||||
case MIPI_DSI_DCS_LONG_WRITE:
|
||||
{
|
||||
unsigned int payload = 0;
|
||||
|
||||
/* if data count is less then 4, then send 3bytes data. */
|
||||
if (data1 < 4) {
|
||||
payload = data0[0] |
|
||||
data0[1] << 8 |
|
||||
data0[2] << 16;
|
||||
|
||||
exynos_mipi_dsi_wr_tx_data(dsim, payload);
|
||||
|
||||
debug("count = %d payload = %x,%x %x %x\n",
|
||||
data1, payload, data0[0],
|
||||
data0[1], data0[2]);
|
||||
} else {
|
||||
/* in case that data count is more then 4 */
|
||||
exynos_mipi_dsi_long_data_wr(dsim, data0, data1);
|
||||
}
|
||||
|
||||
/* put data into header fifo */
|
||||
exynos_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff,
|
||||
(data1 & 0xff00) >> 8);
|
||||
|
||||
}
|
||||
if (check_rx_ack)
|
||||
/* process response func should be implemented. */
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
/* packet typo for video data */
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_16:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_18:
|
||||
case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_24:
|
||||
if (check_rx_ack) {
|
||||
/* process response func should be implemented. */
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
debug("data id %x is not supported current DSI spec.\n",
|
||||
data_id);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable)
|
||||
{
|
||||
int sw_timeout;
|
||||
|
||||
if (enable) {
|
||||
sw_timeout = 1000;
|
||||
|
||||
exynos_mipi_dsi_clear_interrupt(dsim);
|
||||
exynos_mipi_dsi_enable_pll(dsim, 1);
|
||||
while (1) {
|
||||
sw_timeout--;
|
||||
if (exynos_mipi_dsi_is_pll_stable(dsim))
|
||||
return 0;
|
||||
if (sw_timeout == 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
} else
|
||||
exynos_mipi_dsi_enable_pll(dsim, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
|
||||
unsigned int pre_divider, unsigned int main_divider,
|
||||
unsigned int scaler)
|
||||
{
|
||||
unsigned long dfin_pll, dfvco, dpll_out;
|
||||
unsigned int i, freq_band = 0xf;
|
||||
|
||||
dfin_pll = (FIN_HZ / pre_divider);
|
||||
|
||||
/******************************************************
|
||||
* Serial Clock(=ByteClk X 8) FreqBand[3:0] *
|
||||
******************************************************
|
||||
* ~ 99.99 MHz 0000
|
||||
* 100 ~ 119.99 MHz 0001
|
||||
* 120 ~ 159.99 MHz 0010
|
||||
* 160 ~ 199.99 MHz 0011
|
||||
* 200 ~ 239.99 MHz 0100
|
||||
* 140 ~ 319.99 MHz 0101
|
||||
* 320 ~ 389.99 MHz 0110
|
||||
* 390 ~ 449.99 MHz 0111
|
||||
* 450 ~ 509.99 MHz 1000
|
||||
* 510 ~ 559.99 MHz 1001
|
||||
* 560 ~ 639.99 MHz 1010
|
||||
* 640 ~ 689.99 MHz 1011
|
||||
* 690 ~ 769.99 MHz 1100
|
||||
* 770 ~ 869.99 MHz 1101
|
||||
* 870 ~ 949.99 MHz 1110
|
||||
* 950 ~ 1000 MHz 1111
|
||||
******************************************************/
|
||||
if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
|
||||
debug("fin_pll range should be 6MHz ~ 12MHz\n");
|
||||
exynos_mipi_dsi_enable_afc(dsim, 0, 0);
|
||||
} else {
|
||||
if (dfin_pll < 7 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x1);
|
||||
else if (dfin_pll < 8 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x0);
|
||||
else if (dfin_pll < 9 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x3);
|
||||
else if (dfin_pll < 10 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x2);
|
||||
else if (dfin_pll < 11 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x5);
|
||||
else
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x4);
|
||||
}
|
||||
|
||||
dfvco = dfin_pll * main_divider;
|
||||
debug("dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
|
||||
dfvco, dfin_pll, main_divider);
|
||||
if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
|
||||
debug("fvco range should be 500MHz ~ 1000MHz\n");
|
||||
|
||||
dpll_out = dfvco / (1 << scaler);
|
||||
debug("dpll_out = %lu, dfvco = %lu, scaler = %d\n",
|
||||
dpll_out, dfvco, scaler);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
|
||||
if (dpll_out < dpll_table[i] * MHZ) {
|
||||
freq_band = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug("freq_band = %d\n", freq_band);
|
||||
|
||||
exynos_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
|
||||
|
||||
exynos_mipi_dsi_hs_zero_ctrl(dsim, 0);
|
||||
exynos_mipi_dsi_prep_ctrl(dsim, 0);
|
||||
|
||||
/* Freq Band */
|
||||
exynos_mipi_dsi_pll_freq_band(dsim, freq_band);
|
||||
|
||||
/* Stable time */
|
||||
exynos_mipi_dsi_pll_stable_time(dsim,
|
||||
dsim->dsim_config->pll_stable_time);
|
||||
|
||||
/* Enable PLL */
|
||||
debug("FOUT of mipi dphy pll is %luMHz\n",
|
||||
(dpll_out / MHZ));
|
||||
|
||||
return dpll_out;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int byte_clk_sel, unsigned int enable)
|
||||
{
|
||||
unsigned int esc_div;
|
||||
unsigned long esc_clk_error_rate;
|
||||
unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0;
|
||||
|
||||
if (enable) {
|
||||
dsim->e_clk_src = byte_clk_sel;
|
||||
|
||||
/* Escape mode clock and byte clock source */
|
||||
exynos_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
|
||||
|
||||
/* DPHY, DSIM Link : D-PHY clock out */
|
||||
if (byte_clk_sel == DSIM_PLL_OUT_DIV8) {
|
||||
hs_clk = exynos_mipi_dsi_change_pll(dsim,
|
||||
dsim->dsim_config->p, dsim->dsim_config->m,
|
||||
dsim->dsim_config->s);
|
||||
if (hs_clk == 0) {
|
||||
debug("failed to get hs clock.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
byte_clk = hs_clk / 8;
|
||||
exynos_mipi_dsi_enable_pll_bypass(dsim, 0);
|
||||
exynos_mipi_dsi_pll_on(dsim, 1);
|
||||
/* DPHY : D-PHY clock out, DSIM link : external clock out */
|
||||
} else if (byte_clk_sel == DSIM_EXT_CLK_DIV8)
|
||||
debug("not support EXT CLK source for MIPI DSIM\n");
|
||||
else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS)
|
||||
debug("not support EXT CLK source for MIPI DSIM\n");
|
||||
|
||||
/* escape clock divider */
|
||||
esc_div = byte_clk / (dsim->dsim_config->esc_clk);
|
||||
debug("esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
|
||||
esc_div, byte_clk, dsim->dsim_config->esc_clk);
|
||||
if ((byte_clk / esc_div) >= (20 * MHZ) ||
|
||||
(byte_clk / esc_div) > dsim->dsim_config->esc_clk)
|
||||
esc_div += 1;
|
||||
|
||||
escape_clk = byte_clk / esc_div;
|
||||
debug("escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
|
||||
escape_clk, byte_clk, esc_div);
|
||||
|
||||
/* enable escape clock. */
|
||||
exynos_mipi_dsi_enable_byte_clock(dsim, 1);
|
||||
|
||||
/* enable byte clk and escape clock */
|
||||
exynos_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
|
||||
/* escape clock on lane */
|
||||
exynos_mipi_dsi_enable_esc_clk_on_lane(dsim,
|
||||
(DSIM_LANE_CLOCK | dsim->data_lane), 1);
|
||||
|
||||
debug("byte clock is %luMHz\n",
|
||||
(byte_clk / MHZ));
|
||||
debug("escape clock that user's need is %lu\n",
|
||||
(dsim->dsim_config->esc_clk / MHZ));
|
||||
debug("escape clock divider is %x\n", esc_div);
|
||||
debug("escape clock is %luMHz\n",
|
||||
((byte_clk / esc_div) / MHZ));
|
||||
|
||||
if ((byte_clk / esc_div) > escape_clk) {
|
||||
esc_clk_error_rate = escape_clk /
|
||||
(byte_clk / esc_div);
|
||||
debug("error rate is %lu over.\n",
|
||||
(esc_clk_error_rate / 100));
|
||||
} else if ((byte_clk / esc_div) < (escape_clk)) {
|
||||
esc_clk_error_rate = (byte_clk / esc_div) /
|
||||
escape_clk;
|
||||
debug("error rate is %lu under.\n",
|
||||
(esc_clk_error_rate / 100));
|
||||
}
|
||||
} else {
|
||||
exynos_mipi_dsi_enable_esc_clk_on_lane(dsim,
|
||||
(DSIM_LANE_CLOCK | dsim->data_lane), 0);
|
||||
exynos_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
|
||||
|
||||
/* disable escape clock. */
|
||||
exynos_mipi_dsi_enable_byte_clock(dsim, 0);
|
||||
|
||||
if (byte_clk_sel == DSIM_PLL_OUT_DIV8)
|
||||
exynos_mipi_dsi_pll_on(dsim, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
dsim->state = DSIM_STATE_INIT;
|
||||
|
||||
switch (dsim->dsim_config->e_no_data_lane) {
|
||||
case DSIM_DATA_LANE_1:
|
||||
dsim->data_lane = DSIM_LANE_DATA0;
|
||||
break;
|
||||
case DSIM_DATA_LANE_2:
|
||||
dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
|
||||
break;
|
||||
case DSIM_DATA_LANE_3:
|
||||
dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
|
||||
DSIM_LANE_DATA2;
|
||||
break;
|
||||
case DSIM_DATA_LANE_4:
|
||||
dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
|
||||
DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
|
||||
break;
|
||||
default:
|
||||
debug("data lane is invalid.\n");
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
exynos_mipi_dsi_sw_reset(dsim);
|
||||
exynos_mipi_dsi_dp_dn_swap(dsim, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
/* enable only frame done interrupt */
|
||||
exynos_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void convert_to_fb_videomode(struct fb_videomode *mode1,
|
||||
struct vidinfo *mode2)
|
||||
{
|
||||
mode1->xres = mode2->vl_width;
|
||||
mode1->yres = mode2->vl_height;
|
||||
mode1->upper_margin = mode2->vl_vfpd;
|
||||
mode1->lower_margin = mode2->vl_vbpd;
|
||||
mode1->left_margin = mode2->vl_hfpd;
|
||||
mode1->right_margin = mode2->vl_hbpd;
|
||||
mode1->vsync_len = mode2->vl_vspw;
|
||||
mode1->hsync_len = mode2->vl_hspw;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
|
||||
struct mipi_dsim_config *dsim_config)
|
||||
{
|
||||
struct exynos_platform_mipi_dsim *dsim_pd;
|
||||
struct fb_videomode lcd_video;
|
||||
struct vidinfo *vid;
|
||||
|
||||
dsim_pd = (struct exynos_platform_mipi_dsim *)dsim->pd;
|
||||
vid = (struct vidinfo *)dsim_pd->lcd_panel_info;
|
||||
|
||||
convert_to_fb_videomode(&lcd_video, vid);
|
||||
|
||||
/* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
|
||||
if (dsim->dsim_config->e_interface == (u32) DSIM_VIDEO) {
|
||||
if (dsim->dsim_config->auto_vertical_cnt == 0) {
|
||||
exynos_mipi_dsi_set_main_disp_vporch(dsim,
|
||||
vid->vl_cmd_allow_len,
|
||||
lcd_video.upper_margin,
|
||||
lcd_video.lower_margin);
|
||||
exynos_mipi_dsi_set_main_disp_hporch(dsim,
|
||||
lcd_video.left_margin,
|
||||
lcd_video.right_margin);
|
||||
exynos_mipi_dsi_set_main_disp_sync_area(dsim,
|
||||
lcd_video.vsync_len,
|
||||
lcd_video.hsync_len);
|
||||
}
|
||||
}
|
||||
|
||||
exynos_mipi_dsi_set_main_disp_resol(dsim, lcd_video.xres,
|
||||
lcd_video.yres);
|
||||
|
||||
exynos_mipi_dsi_display_config(dsim, dsim->dsim_config);
|
||||
|
||||
debug("lcd panel ==> width = %d, height = %d\n",
|
||||
lcd_video.xres, lcd_video.yres);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
unsigned int time_out = 100;
|
||||
|
||||
switch (dsim->state) {
|
||||
case DSIM_STATE_INIT:
|
||||
exynos_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
|
||||
|
||||
/* dsi configuration */
|
||||
exynos_mipi_dsi_init_config(dsim);
|
||||
exynos_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
|
||||
exynos_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
|
||||
|
||||
/* set clock configuration */
|
||||
exynos_mipi_dsi_set_clock(dsim,
|
||||
dsim->dsim_config->e_byte_clk, 1);
|
||||
|
||||
/* check clock and data lane state are stop state */
|
||||
while (!(exynos_mipi_dsi_is_lane_state(dsim))) {
|
||||
time_out--;
|
||||
if (time_out == 0) {
|
||||
debug("DSI Master is not stop state.\n");
|
||||
debug("Check initialization process\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
dsim->state = DSIM_STATE_STOP;
|
||||
|
||||
/* BTA sequence counters */
|
||||
exynos_mipi_dsi_set_stop_state_counter(dsim,
|
||||
dsim->dsim_config->stop_holding_cnt);
|
||||
exynos_mipi_dsi_set_bta_timeout(dsim,
|
||||
dsim->dsim_config->bta_timeout);
|
||||
exynos_mipi_dsi_set_lpdr_timeout(dsim,
|
||||
dsim->dsim_config->rx_timeout);
|
||||
|
||||
return 0;
|
||||
default:
|
||||
debug("DSI Master is already init.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
if (dsim->state == DSIM_STATE_STOP) {
|
||||
if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) {
|
||||
dsim->state = DSIM_STATE_HSCLKEN;
|
||||
|
||||
/* set LCDC and CPU transfer mode to HS. */
|
||||
exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
|
||||
exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
|
||||
|
||||
exynos_mipi_dsi_enable_hs_clock(dsim, 1);
|
||||
|
||||
return 0;
|
||||
} else
|
||||
debug("clock source is external bypass.\n");
|
||||
} else
|
||||
debug("DSIM is not stop state.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int mode)
|
||||
{
|
||||
if (mode) {
|
||||
if (dsim->state != DSIM_STATE_HSCLKEN) {
|
||||
debug("HS Clock lane is not enabled.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
|
||||
} else {
|
||||
if (dsim->state == DSIM_STATE_INIT || dsim->state ==
|
||||
DSIM_STATE_ULPS) {
|
||||
debug("DSI Master is not STOP or HSDT state.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
return _exynos_mipi_dsi_get_frame_done_status(dsim);
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
_exynos_mipi_dsi_clear_frame_done(dsim);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*/
|
||||
|
||||
#include <linux/fb.h>
|
||||
|
||||
#ifndef _EXYNOS_MIPI_DSI_COMMON_H
|
||||
#define _EXYNOS_MIPI_DSI_COMMON_H
|
||||
|
||||
int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
|
||||
const unsigned char *data0, unsigned int data1);
|
||||
int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable);
|
||||
unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
|
||||
unsigned int pre_divider, unsigned int main_divider,
|
||||
unsigned int scaler);
|
||||
int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int byte_clk_sel, unsigned int enable);
|
||||
int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
|
||||
int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
|
||||
struct mipi_dsim_config *dsim_info);
|
||||
int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
|
||||
int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
|
||||
int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int mode);
|
||||
int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
|
||||
int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
|
||||
|
||||
#endif /* _EXYNOS_MIPI_DSI_COMMON_H */
|
||||
@@ -0,0 +1,638 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/dsim.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
|
||||
#include "exynos_mipi_dsi_lowlevel.h"
|
||||
#include "exynos_mipi_dsi_common.h"
|
||||
|
||||
void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->swrst);
|
||||
|
||||
reg |= DSIM_FUNCRST;
|
||||
|
||||
writel(reg, &mipi_dsim->swrst);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
unsigned int reg = 0;
|
||||
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->swrst);
|
||||
|
||||
reg |= DSIM_SWRST;
|
||||
reg |= DSIM_FUNCRST;
|
||||
|
||||
writel(reg, &mipi_dsim->swrst);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_sw_release(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intsrc);
|
||||
|
||||
reg |= INTSRC_SWRST_RELEASE;
|
||||
|
||||
writel(reg, &mipi_dsim->intsrc);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
|
||||
unsigned int mode, unsigned int mask)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intmsk);
|
||||
|
||||
if (mask)
|
||||
reg |= mode;
|
||||
else
|
||||
reg &= ~mode;
|
||||
|
||||
writel(reg, &mipi_dsim->intmsk);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
|
||||
unsigned int cfg)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->fifoctrl);
|
||||
|
||||
writel(reg & ~(cfg), &mipi_dsim->fifoctrl);
|
||||
udelay(10 * 1000);
|
||||
reg |= cfg;
|
||||
|
||||
writel(reg, &mipi_dsim->fifoctrl);
|
||||
}
|
||||
|
||||
/*
|
||||
* this function set PLL P, M and S value in D-PHY
|
||||
*/
|
||||
void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
|
||||
unsigned int value)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
writel(DSIM_AFC_CTL(value), &mipi_dsim->phyacchr);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
|
||||
unsigned int width_resol, unsigned int height_resol)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
/* standby should be set after configuration so set to not ready*/
|
||||
reg = (readl(&mipi_dsim->mdresol)) & ~(DSIM_MAIN_STAND_BY);
|
||||
writel(reg, &mipi_dsim->mdresol);
|
||||
|
||||
/* reset resolution */
|
||||
reg &= ~(DSIM_MAIN_VRESOL(0x7ff) | DSIM_MAIN_HRESOL(0x7ff));
|
||||
reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol);
|
||||
|
||||
reg |= DSIM_MAIN_STAND_BY;
|
||||
writel(reg, &mipi_dsim->mdresol);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
|
||||
unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = (readl(&mipi_dsim->mvporch)) &
|
||||
~((DSIM_CMD_ALLOW_MASK) | (DSIM_STABLE_VFP_MASK) |
|
||||
(DSIM_MAIN_VBP_MASK));
|
||||
|
||||
reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) |
|
||||
((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) |
|
||||
((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->mvporch);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
|
||||
unsigned int front, unsigned int back)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = (readl(&mipi_dsim->mhporch)) &
|
||||
~((DSIM_MAIN_HFP_MASK) | (DSIM_MAIN_HBP_MASK));
|
||||
|
||||
reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->mhporch);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
|
||||
unsigned int vert, unsigned int hori)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = (readl(&mipi_dsim->msync)) &
|
||||
~((DSIM_MAIN_VSA_MASK) | (DSIM_MAIN_HSA_MASK));
|
||||
|
||||
reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) |
|
||||
(hori << DSIM_MAIN_HSA_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->msync);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
|
||||
unsigned int vert, unsigned int hori)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = (readl(&mipi_dsim->sdresol)) &
|
||||
~(DSIM_SUB_STANDY_MASK);
|
||||
|
||||
writel(reg, &mipi_dsim->sdresol);
|
||||
|
||||
reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
|
||||
reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) |
|
||||
((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT);
|
||||
writel(reg, &mipi_dsim->sdresol);
|
||||
|
||||
/* DSIM STANDBY */
|
||||
reg |= (1 << DSIM_SUB_STANDY_SHIFT);
|
||||
writel(reg, &mipi_dsim->sdresol);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct mipi_dsim_config *dsim_config = dsim->dsim_config;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int cfg = (readl(&mipi_dsim->config)) &
|
||||
~((1 << DSIM_EOT_PACKET_SHIFT) |
|
||||
(0x1f << DSIM_HSA_MODE_SHIFT) |
|
||||
(0x3 << DSIM_NUM_OF_DATALANE_SHIFT));
|
||||
|
||||
cfg |= (dsim_config->auto_flush << DSIM_AUTO_FLUSH_SHIFT) |
|
||||
(dsim_config->eot_disable << DSIM_EOT_PACKET_SHIFT) |
|
||||
(dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) |
|
||||
(dsim_config->hse << DSIM_HSE_MODE_SHIFT) |
|
||||
(dsim_config->hfp << DSIM_HFP_MODE_SHIFT) |
|
||||
(dsim_config->hbp << DSIM_HBP_MODE_SHIFT) |
|
||||
(dsim_config->hsa << DSIM_HSA_MODE_SHIFT) |
|
||||
(dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT);
|
||||
|
||||
writel(cfg, &mipi_dsim->config);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
|
||||
struct mipi_dsim_config *dsim_config)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
u32 reg = (readl(&mipi_dsim->config)) &
|
||||
~((0x3 << DSIM_BURST_MODE_SHIFT) | (1 << DSIM_VIDEO_MODE_SHIFT)
|
||||
| (0x3 << DSIM_MAINVC_SHIFT) | (0x7 << DSIM_MAINPIX_SHIFT)
|
||||
| (0x3 << DSIM_SUBVC_SHIFT) | (0x7 << DSIM_SUBPIX_SHIFT));
|
||||
|
||||
if (dsim_config->e_interface == DSIM_VIDEO)
|
||||
reg |= (1 << DSIM_VIDEO_MODE_SHIFT);
|
||||
else if (dsim_config->e_interface == DSIM_COMMAND)
|
||||
reg &= ~(1 << DSIM_VIDEO_MODE_SHIFT);
|
||||
else {
|
||||
printf("unknown lcd type.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* main lcd */
|
||||
reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << DSIM_BURST_MODE_SHIFT
|
||||
| ((u8) (dsim_config->e_virtual_ch) & 0x3) << DSIM_MAINVC_SHIFT
|
||||
| ((u8) (dsim_config->e_pixel_format) & 0x7) << DSIM_MAINPIX_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->config);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim,
|
||||
unsigned int lane, unsigned int enable)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->config);
|
||||
|
||||
if (enable)
|
||||
reg |= DSIM_LANE_ENx(lane);
|
||||
else
|
||||
reg &= ~DSIM_LANE_ENx(lane);
|
||||
|
||||
writel(reg, &mipi_dsim->config);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
|
||||
unsigned int count)
|
||||
{
|
||||
unsigned int cfg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
/* get the data lane number. */
|
||||
cfg = DSIM_NUM_OF_DATA_LANE(count);
|
||||
|
||||
writel(cfg, &mipi_dsim->config);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable, unsigned int afc_code)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->phyacchr);
|
||||
|
||||
reg = 0;
|
||||
|
||||
if (enable) {
|
||||
reg |= DSIM_AFC_EN;
|
||||
reg &= ~(0x7 << DSIM_AFC_CTL_SHIFT);
|
||||
reg |= DSIM_AFC_CTL(afc_code);
|
||||
} else
|
||||
reg &= ~DSIM_AFC_EN;
|
||||
|
||||
writel(reg, &mipi_dsim->phyacchr);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~(DSIM_PLL_BYPASS_EXTERNAL);
|
||||
|
||||
reg |= enable << DSIM_PLL_BYPASS_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
|
||||
unsigned int freq_band)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0x1f << DSIM_FREQ_BAND_SHIFT);
|
||||
|
||||
reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
|
||||
unsigned int pre_divider, unsigned int main_divider,
|
||||
unsigned int scaler)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0x7ffff << 1);
|
||||
|
||||
reg |= ((pre_divider & 0x3f) << DSIM_PREDIV_SHIFT) |
|
||||
((main_divider & 0x1ff) << DSIM_MAIN_SHIFT) |
|
||||
((scaler & 0x7) << DSIM_SCALER_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
|
||||
unsigned int lock_time)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
writel(lock_time, &mipi_dsim->plltmr);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0x1 << DSIM_PLL_EN_SHIFT);
|
||||
|
||||
reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
|
||||
unsigned int src)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT);
|
||||
|
||||
reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~(1 << DSIM_BYTE_CLKEN_SHIFT);
|
||||
|
||||
reg |= enable << DSIM_BYTE_CLKEN_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable, unsigned int prs_val)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~((1 << DSIM_ESC_CLKEN_SHIFT) | (0xffff));
|
||||
|
||||
reg |= enable << DSIM_ESC_CLKEN_SHIFT;
|
||||
if (enable)
|
||||
reg |= prs_val;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
|
||||
unsigned int lane_sel, unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->clkctrl);
|
||||
|
||||
if (enable)
|
||||
reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
|
||||
else
|
||||
reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->escmode)) &
|
||||
~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT);
|
||||
|
||||
reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->escmode);
|
||||
}
|
||||
|
||||
unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->status);
|
||||
|
||||
/**
|
||||
* check clock and data lane states.
|
||||
* if MIPI-DSI controller was enabled at bootloader then
|
||||
* TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
|
||||
* so it should be checked for two case.
|
||||
*/
|
||||
if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
|
||||
((reg & DSIM_STOP_STATE_CLK) ||
|
||||
(reg & DSIM_TX_READY_HS_CLK)))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
|
||||
unsigned int cnt_val)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->escmode)) &
|
||||
~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT);
|
||||
|
||||
reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->escmode);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
|
||||
unsigned int timeout)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->timeout)) &
|
||||
~(0xff << DSIM_BTA_TOUT_SHIFT);
|
||||
|
||||
reg |= (timeout << DSIM_BTA_TOUT_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->timeout);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
|
||||
unsigned int timeout)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->timeout)) &
|
||||
~(0xffff << DSIM_LPDR_TOUT_SHIFT);
|
||||
|
||||
reg |= (timeout << DSIM_LPDR_TOUT_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->timeout);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int lp)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->escmode);
|
||||
|
||||
reg &= ~DSIM_CMD_LPDT_LP;
|
||||
|
||||
if (lp)
|
||||
reg |= DSIM_CMD_LPDT_LP;
|
||||
|
||||
writel(reg, &mipi_dsim->escmode);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int lp)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->escmode);
|
||||
|
||||
reg &= ~DSIM_TX_LPDT_LP;
|
||||
|
||||
if (lp)
|
||||
reg |= DSIM_TX_LPDT_LP;
|
||||
|
||||
writel(reg, &mipi_dsim->escmode);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT);
|
||||
|
||||
reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
|
||||
unsigned int swap_en)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->phyacchr1);
|
||||
|
||||
reg &= ~(0x3 << DSIM_DPDN_SWAP_DATA_SHIFT);
|
||||
reg |= (swap_en & 0x3) << DSIM_DPDN_SWAP_DATA_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->phyacchr1);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
|
||||
unsigned int hs_zero)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0xf << DSIM_ZEROCTRL_SHIFT);
|
||||
|
||||
reg |= ((hs_zero & 0xf) << DSIM_ZEROCTRL_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0x7 << DSIM_PRECTRL_SHIFT);
|
||||
|
||||
reg |= ((prep & 0x7) << DSIM_PRECTRL_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intsrc);
|
||||
|
||||
reg |= INTSRC_PLL_STABLE;
|
||||
|
||||
writel(reg, &mipi_dsim->intsrc);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
writel(0xffffffff, &mipi_dsim->intsrc);
|
||||
}
|
||||
|
||||
unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->status);
|
||||
|
||||
return reg & DSIM_PLL_STABLE ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
return readl(&mipi_dsim->fifoctrl) & ~(0x1f);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
|
||||
unsigned int di, const unsigned char data0, const unsigned char data1)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (DSIM_PKTHDR_DAT1(data1) | DSIM_PKTHDR_DAT0(data0) |
|
||||
DSIM_PKTHDR_DI(di));
|
||||
|
||||
writel(reg, &mipi_dsim->pkthdr);
|
||||
}
|
||||
|
||||
unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device
|
||||
*dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intsrc);
|
||||
|
||||
return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
|
||||
}
|
||||
|
||||
void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intsrc);
|
||||
|
||||
writel(reg | INTSRC_FRAME_DONE, &mipi_dsim->intsrc);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
|
||||
unsigned int tx_data)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
writel(tx_data, &mipi_dsim->payload);
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_MIPI_DSI_LOWLEVEL_H
|
||||
#define _EXYNOS_MIPI_DSI_LOWLEVEL_H
|
||||
|
||||
void exynos_mipi_dsi_register(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_sw_release(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
|
||||
unsigned int mode, unsigned int mask);
|
||||
void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
|
||||
unsigned int count);
|
||||
void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
|
||||
unsigned int cfg);
|
||||
void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
|
||||
unsigned int value);
|
||||
void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
|
||||
unsigned int value);
|
||||
void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
|
||||
unsigned int width_resol, unsigned int height_resol);
|
||||
void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
|
||||
unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
|
||||
void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
|
||||
unsigned int front, unsigned int back);
|
||||
void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
|
||||
unsigned int vert, unsigned int hori);
|
||||
void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
|
||||
unsigned int vert, unsigned int hori);
|
||||
void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
|
||||
struct mipi_dsim_config *dsim_config);
|
||||
void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
|
||||
unsigned int count);
|
||||
void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim,
|
||||
unsigned int lane, unsigned int enable);
|
||||
void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable, unsigned int afc_code);
|
||||
void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
|
||||
unsigned int freq_band);
|
||||
void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
|
||||
unsigned int pre_divider, unsigned int main_divider,
|
||||
unsigned int scaler);
|
||||
void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
|
||||
unsigned int lock_time);
|
||||
void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
|
||||
unsigned int src);
|
||||
void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable, unsigned int prs_val);
|
||||
void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
|
||||
unsigned int lane_sel, unsigned int enable);
|
||||
void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
|
||||
unsigned int cnt_val);
|
||||
void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
|
||||
unsigned int timeout);
|
||||
void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
|
||||
unsigned int timeout);
|
||||
void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int lp);
|
||||
void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int lp);
|
||||
void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
|
||||
unsigned int swap_en);
|
||||
void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
|
||||
unsigned int hs_zero);
|
||||
void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim,
|
||||
unsigned int prep);
|
||||
void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim);
|
||||
unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
|
||||
unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
|
||||
unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device
|
||||
*dsim);
|
||||
void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
|
||||
unsigned int di, const unsigned char data0, const unsigned char data1);
|
||||
void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
|
||||
unsigned int tx_data);
|
||||
|
||||
#endif /* _EXYNOS_MIPI_DSI_LOWLEVEL_H */
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* PWM BACKLIGHT driver for Board based on EXYNOS.
|
||||
*
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.com>
|
||||
*
|
||||
* Derived from linux/drivers/video/backlight/pwm_backlight.c
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <pwm.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/pwm.h>
|
||||
#include <asm/arch/pwm_backlight.h>
|
||||
|
||||
static struct pwm_backlight_data *pwm;
|
||||
|
||||
static int exynos_pwm_backlight_update_status(void)
|
||||
{
|
||||
int brightness = pwm->brightness;
|
||||
int max = pwm->max_brightness;
|
||||
|
||||
if (brightness == 0) {
|
||||
pwm_config(pwm->pwm_id, 0, pwm->period);
|
||||
pwm_disable(pwm->pwm_id);
|
||||
} else {
|
||||
pwm_config(pwm->pwm_id,
|
||||
brightness * pwm->period / max, pwm->period);
|
||||
pwm_enable(pwm->pwm_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_pwm_backlight_init(struct pwm_backlight_data *pd)
|
||||
{
|
||||
pwm = pd;
|
||||
|
||||
exynos_pwm_backlight_update_status();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user