blob: 4af6d833d109cec34ac3af4234d3a36189ad417e [file] [log] [blame]
#include "asrfb.h"
#include "dsi_drv.h"
//#define DSI_VERSION_14
#define DSI_VERSION_24
//#define DSI_VERSION_4
#if defined(DSI_VERSION_14) || defined(DSI_VERSION_24) || defined(DSI_VERSION_4)
#define DSI_GEN4
#endif
#define dsi_ex_pixel_cnt 0
#define dsi_hex_en 0
#define to_dsi_bcnt(timing, bpp) (((timing) * (bpp)) >> 3)
static unsigned int dsi_lane[5] = { 0, 0x1, 0x3, 0x7, 0xf };
static struct dsi_phy_timing phy = {
.hs_prep_constant = 40, /* Unit: ns. */
.hs_prep_ui = 4,
.hs_zero_constant = 145,
.hs_zero_ui = 10,
.hs_trail_constant = 60,
.hs_trail_ui = 4,
.hs_exit_constant = 100,
.hs_exit_ui = 0,
.ck_zero_constant = 300,
.ck_zero_ui = 0,
.ck_trail_constant = 60,
.ck_trail_ui = 0,
.req_ready = 0x3c,
.wakeup_constant = 1000000,
.wakeup_ui = 0,
/*
* According to the D-PHY spec, Tlpx >= 50 ns
* For the panel otm1281a, it works unstable when Tlpx = 50,
* so increase to 60ns.
*/
.lpx_constant = 60,
.lpx_ui = 0,
};
static void dphy_write(unsigned int reg, unsigned int value)
{
writel(value, reg);
}
static unsigned int dphy_read(unsigned int reg)
{
return readl(reg);
}
static void dsi_write(unsigned int reg, unsigned int value)
{
writel(value, reg);
}
static unsigned int dsi_read(unsigned int reg)
{
return readl(reg);
}
#if 0
static void dsi_set_bits(unsigned int bits, unsigned int reg)
{
dsi_write(reg, dsi_read(reg) | bits);
}
#endif
static void dsi_clear_bits(unsigned int bits, unsigned int reg)
{
dsi_write(reg, dsi_read(reg) & ~bits);
}
static unsigned char dsi_bit(unsigned int index, unsigned char *pdata)
{
unsigned char ret;
unsigned int cindex, bindex;
cindex = index / 8;
bindex = index % 8;
if (pdata[cindex] & (0x1 << bindex)) {
ret = (unsigned char) 0x1;
}
else {
ret = (unsigned char) 0x0;
}
return ret;
}
static unsigned char calculate_ecc(unsigned char *pdata)
{
unsigned char ret;
unsigned char p[8];
p[7] = (unsigned char) 0x0;
p[6] = (unsigned char) 0x0;
p[5] = (unsigned char) (
(
dsi_bit(10, pdata) ^
dsi_bit(11, pdata) ^
dsi_bit(12, pdata) ^
dsi_bit(13, pdata) ^
dsi_bit(14, pdata) ^
dsi_bit(15, pdata) ^
dsi_bit(16, pdata) ^
dsi_bit(17, pdata) ^
dsi_bit(18, pdata) ^
dsi_bit(19, pdata) ^
dsi_bit(21, pdata) ^
dsi_bit(22, pdata) ^
dsi_bit(23, pdata)
)
);
p[4] = (unsigned char) (
dsi_bit(4, pdata) ^
dsi_bit(5, pdata) ^
dsi_bit(6, pdata) ^
dsi_bit(7, pdata) ^
dsi_bit(8, pdata) ^
dsi_bit(9, pdata) ^
dsi_bit(16, pdata) ^
dsi_bit(17, pdata) ^
dsi_bit(18, pdata) ^
dsi_bit(19, pdata) ^
dsi_bit(20, pdata) ^
dsi_bit(22, pdata) ^
dsi_bit(23, pdata)
);
p[3] = (unsigned char) (
(
dsi_bit(1, pdata) ^
dsi_bit(2, pdata) ^
dsi_bit(3, pdata) ^
dsi_bit(7, pdata) ^
dsi_bit(8, pdata) ^
dsi_bit(9, pdata) ^
dsi_bit(13, pdata) ^
dsi_bit(14, pdata) ^
dsi_bit(15, pdata) ^
dsi_bit(19, pdata) ^
dsi_bit(20, pdata) ^
dsi_bit(21, pdata) ^
dsi_bit(23, pdata)
)
);
p[2] = (unsigned char) (
(
dsi_bit(0, pdata) ^
dsi_bit(2, pdata) ^
dsi_bit(3, pdata) ^
dsi_bit(5, pdata) ^
dsi_bit(6, pdata) ^
dsi_bit(9, pdata) ^
dsi_bit(11, pdata) ^
dsi_bit(12, pdata) ^
dsi_bit(15, pdata) ^
dsi_bit(18, pdata) ^
dsi_bit(20, pdata) ^
dsi_bit(21, pdata) ^
dsi_bit(22, pdata)
)
);
p[1] = (unsigned char) (
(
dsi_bit(0, pdata) ^
dsi_bit(1, pdata) ^
dsi_bit(3, pdata) ^
dsi_bit(4, pdata) ^
dsi_bit(6, pdata) ^
dsi_bit(8, pdata) ^
dsi_bit(10, pdata) ^
dsi_bit(12, pdata) ^
dsi_bit(14, pdata) ^
dsi_bit(17, pdata) ^
dsi_bit(20, pdata) ^
dsi_bit(21, pdata) ^
dsi_bit(22, pdata) ^
dsi_bit(23, pdata)
)
);
p[0] = (unsigned char) (
(
dsi_bit(0, pdata) ^
dsi_bit(1, pdata) ^
dsi_bit(2, pdata) ^
dsi_bit(4, pdata) ^
dsi_bit(5, pdata) ^
dsi_bit(7, pdata) ^
dsi_bit(10, pdata) ^
dsi_bit(11, pdata) ^
dsi_bit(13, pdata) ^
dsi_bit(16, pdata) ^
dsi_bit(20, pdata) ^
dsi_bit(21, pdata) ^
dsi_bit(22, pdata) ^
dsi_bit(23, pdata)
)
);
ret = (unsigned char)(
p[0] |
(p[1] << 0x1) |
(p[2] << 0x2) |
(p[3] << 0x3) |
(p[4] << 0x4) |
(p[5] << 0x5)
);
return ret;
}
static unsigned short gs_crc16_generation_code = 0x8408;
static unsigned short calculate_crc16(unsigned char *pdata, unsigned
short count)
{
unsigned short byte_counter;
unsigned char bit_counter;
unsigned char data;
unsigned short crc16_result = 0xFFFF;
if (count > 0) {
for (byte_counter = 0; byte_counter < count;
byte_counter++) {
data = *(pdata + byte_counter);
for (bit_counter = 0; bit_counter < 8; bit_counter++) {
if (((crc16_result & 0x0001) ^ ((0x0001 *
data) & 0x0001)) > 0) {
crc16_result = ((crc16_result >> 1)
& 0x7FFF) ^ gs_crc16_generation_code;
}
else {
crc16_result = (crc16_result >> 1)
& 0x7FFF;
}
data = (data >> 1) & 0x7F;
}
}
}
return crc16_result;
}
static void dsi_set_ctrl0(struct dsi_regs *dsi,
unsigned int mask, unsigned int set)
{
unsigned int tmp;
tmp = dsi_read((unsigned int)&dsi->ctrl0);
tmp &= ~mask;
tmp |= set;
dsi_write((unsigned int)&dsi->ctrl0, tmp);
}
static void dsi_set_dphy_ctrl1(struct dsi_regs *dsi, unsigned int mask, unsigned int set)
{
#ifdef DSI_GEN4
void *phy_ctrl1_reg = (void *)&dsi->phy.phy_ctrl1;
#else
void *phy_ctrl1_reg = &dsi->phy_ctrl1;
#endif
unsigned int tmp;
tmp = dphy_read((unsigned int)phy_ctrl1_reg);
tmp &= ~mask;
tmp |= set;
dphy_write((unsigned int)phy_ctrl1_reg, tmp);
}
static void dsi_lanes_enable(struct dsi_regs *dsi, int en, int lane_num)
{
#ifdef DSI_GEN4
volatile unsigned int phy_ctrl2_reg = (unsigned int)&dsi->phy.phy_ctrl2;
#else
volatile unsigned int phy_ctrl2_reg = (unsigned int)&dsi->phy_ctrl2;
#endif
unsigned int reg1 = dphy_read(phy_ctrl2_reg) &
(~DSI_PHY_CTRL_2_CFG_CSR_LANE_EN_MASK);
unsigned int reg2 = dsi_read((unsigned int)&dsi->cmd1) &
~(0xf << DSI_CPU_CMD_1_CFG_TXLP_LPDT_SHIFT);
if (en) {
reg1 |= (dsi_lane[lane_num] <<
DSI_PHY_CTRL_2_CFG_CSR_LANE_EN_SHIFT);
reg2 |= (dsi_lane[lane_num] <<
DSI_CPU_CMD_1_CFG_TXLP_LPDT_SHIFT);
}
reg1 |= BIT_14;
dphy_write((unsigned int)phy_ctrl2_reg, reg1);
dsi_write((unsigned int)&dsi->cmd1, reg2);
}
static void dsi_set_dphy(struct dsi_regs *dsi, struct mipi_info *mipi_info)
{
unsigned int bitclk;
int ui, lpx_clk, lpx_time, ta_get, ta_go, wakeup, reg;
int hs_prep, hs_zero, hs_trail, hs_exit, ck_zero, ck_trail, ck_exit;
void *phy_timing0_reg, *phy_timing1_reg, *phy_timing2_reg, *phy_timing3_reg;
bitclk = mipi_info->phy_feq / 1000000; /*MHz*/
ui = 1000 / bitclk + 1;
lpx_clk = (phy.lpx_constant + phy.lpx_ui * ui) / DSI_ESC_CLK_T + 1;
lpx_time = lpx_clk * DSI_ESC_CLK_T;
/* Below is for NT35451 */
ta_get = lpx_time * 5 / DSI_ESC_CLK_T - 1;
ta_go = lpx_time * 4 / DSI_ESC_CLK_T - 1;
wakeup = phy.wakeup_constant;
wakeup = wakeup / DSI_ESC_CLK_T + 1;
hs_prep = phy.hs_prep_constant + phy.hs_prep_ui * ui;
#if 0
hs_prep = hs_prep / DSI_ESC_CLK_T + 1;
#else
hs_prep = hs_prep / DSI_ESC_CLK_T;
// if(hs_prep >= 1)
// hs_prep = hs_prep -1;
#endif
/* Our hardware added 3-byte clk automatically.
* 3-byte 3 * 8 * ui.
*/
hs_zero = phy.hs_zero_constant + phy.hs_zero_ui * ui -
(hs_prep + 1) * DSI_ESC_CLK_T;
hs_zero = (hs_zero - (3 * ui << 3)) / DSI_ESC_CLK_T + 4;
if (hs_zero < 0) {
hs_zero = 0;
}
hs_trail = phy.hs_trail_constant + phy.hs_trail_ui * ui;
hs_trail = ((8 * ui) >= hs_trail) ? (8 * ui) : hs_trail;
hs_trail = hs_trail / DSI_ESC_CLK_T + 1;
if (hs_trail > 3) {
hs_trail -= 3;
}
else {
hs_trail = 0;
}
hs_exit = phy.hs_exit_constant + phy.hs_exit_ui * ui;
hs_exit = hs_exit / DSI_ESC_CLK_T + 1;
ck_zero = phy.ck_zero_constant + phy.ck_zero_ui * ui -
(hs_prep + 1) * DSI_ESC_CLK_T;
ck_zero = ck_zero / DSI_ESC_CLK_T + 1;
ck_trail = phy.ck_trail_constant + phy.ck_trail_ui * ui;
ck_trail = ck_trail / DSI_ESC_CLK_T + 1;
ck_exit = hs_exit;
/* bandgap ref enabled by default */
#ifndef DSI_GEN4
// reg = BU_REG_READ(&dsi->phy_rcomp0);
// reg |= DPHY_BG_VREF_EN;
phy_timing0_reg = &dsi->phy_timing0;
phy_timing1_reg = &dsi->phy_timing1;
phy_timing2_reg = &dsi->phy_timing2;
phy_timing3_reg = &dsi->phy_timing3;
// BU_REG_WRITE(&dsi->phy_rcomp0, reg);
#else
// reg = BU_REG_READ(&dsi->phy.phy_rcomp0);
// reg |= DPHY_BG_VREF_EN_DC4;
phy_timing0_reg = (void *)&dsi->phy.phy_timing0;
phy_timing1_reg = (void *)&dsi->phy.phy_timing1;
phy_timing2_reg = (void *)&dsi->phy.phy_timing2;
phy_timing3_reg = (void *)&dsi->phy.phy_timing3;
// BU_REG_WRITE(&dsi->phy.phy_rcomp0, reg);
#endif
/* timing_0 */
reg = (hs_exit << DSI_PHY_TIME_0_CFG_CSR_TIME_HS_EXIT_SHIFT)
| (hs_trail << DSI_PHY_TIME_0_CFG_CSR_TIME_HS_TRAIL_SHIFT)
| (hs_zero << DSI_PHY_TIME_0_CDG_CSR_TIME_HS_ZERO_SHIFT)
| (hs_prep);
dphy_write((unsigned)phy_timing0_reg, reg);
reg = (ta_get << DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GET_SHIFT)
| (ta_go << DSI_PHY_TIME_1_CFG_CSR_TIME_TA_GO_SHIFT)
| wakeup;
dphy_write((unsigned)phy_timing1_reg, reg);
reg = (ck_exit << DSI_PHY_TIME_2_CFG_CSR_TIME_CK_EXIT_SHIFT)
| (ck_trail << DSI_PHY_TIME_2_CFG_CSR_TIME_CK_TRAIL_SHIFT)
| (ck_zero << DSI_PHY_TIME_2_CFG_CSR_TIME_CK_ZERO_SHIFT)
| lpx_clk;
dphy_write((unsigned)phy_timing2_reg, reg);
reg = (lpx_clk << DSI_PHY_TIME_3_CFG_CSR_TIME_LPX_SHIFT)
| phy.req_ready;
dphy_write((unsigned)phy_timing3_reg, reg);
/* calculated timing on brownstone:
* DSI_PHY_TIME_0 0x06080204
* DSI_PHY_TIME_1 0x6d2bfff0
* DSI_PHY_TIME_2 0x603130a
* DSI_PHY_TIME_3 0xa3c
*/
}
static void dphy_config(struct dsi_regs *dsi, struct panel_spec *p_panel)
{
int reg_value;
/*clk src select*/
/*use pll5 clk src*/
reg_value = dphy_read((unsigned int)&dsi->phy.phy_ana_ctrl1);
reg_value &= ~(BIT_23);
reg_value |= BIT_11;
//zhimi add 0227 for cranegt
dphy_write((unsigned int)&dsi->phy.phy_ana_pwr_ctrl, 0x100);
dphy_write((unsigned int)&dsi->phy.phy_ana_pwr_ctrl, 0x101);
mdelay(10);
dphy_write((unsigned int)&dsi->phy.phy_ana_ctrl1, 0x3ea);
/* digital and analog power on */
dsi_set_dphy_ctrl1(dsi, 0x0, DPHY_CFG_VDD_VALID);
/* turn on DSI continuous clock for HS */
dsi_set_dphy_ctrl1(dsi, 0x0, 0x1);
/* set dphy */
dsi_set_dphy(dsi, p_panel->info.mipi);
/* enable data lanes */
dsi_lanes_enable(dsi, 0, p_panel->info.mipi->lan_number);
dsi_lanes_enable(dsi, 1, p_panel->info.mipi->lan_number);
}
static void dsi_reset(struct dsi_regs *dsi, int hold)
{
/* software reset DSI module */
dsi_set_ctrl0(dsi, 0, DSI_CTRL_0_CFG_SOFT_RST);
/* Note: there need some delay after set DSI_CTRL_0_CFG_SOFT_RST */
udelay(1000);
dsi_set_ctrl0(dsi, (unsigned int)DSI_CTRL_0_CFG_LCD1_EN, 0);
if (!hold) {
dsi_set_ctrl0(dsi, DSI_CTRL_0_CFG_SOFT_RST, 0);
udelay(1000);
dsi_set_ctrl0(dsi, DSI_CTRL_0_CFG_SOFT_RST_REG, 0);
}
}
static void dsi_set_video_panel(struct dsi_regs *dsi, struct panel_spec *p_panel)
{
struct dsi_lcd_regs *dsi_lcd = &dsi->lcd1;
unsigned int hsync_b, hbp_b, hact_b, hex_b, hfp_b, httl_b;
unsigned int hsync, hbp, hact, httl, v_total;
unsigned int hsa_wc, hbp_wc, hact_wc, hex_wc, hfp_wc, hlp_wc;
unsigned int bpp, hss_bcnt = 4, hse_bct = 4, lgp_over_head = 6, reg;
unsigned int slot_cnt0, slot_cnt1;
union dsi_lcd_ctrl1 lcd_ctrl1;
struct mipi_info *mipi = p_panel->info.mipi;
struct timing_rgb *timing = mipi->timing;
#ifdef DSI_GEN4
void *phy_ctrl2_reg = (void *)&dsi->phy.phy_ctrl2;
#else
void *phy_ctrl2_reg = &dsi->phy_ctrl2;
#endif
unsigned int width = 0;
if (p_panel->info.mipi->dsi_number == 2) {
width = p_panel->width / 2;
}
else {
width = p_panel->width;
}
bpp = mipi->video_bus_width;
v_total = p_panel->height + timing->vfp + timing->vbp + timing->vsync;
hact_b = to_dsi_bcnt(width, bpp);
hfp_b = to_dsi_bcnt(timing->hfp, bpp);
hbp_b = to_dsi_bcnt(timing->hbp, bpp);
hsync_b = to_dsi_bcnt(timing->hsync, bpp);
hex_b = to_dsi_bcnt(dsi_ex_pixel_cnt, bpp);
httl_b = hact_b + hsync_b + hfp_b + hbp_b + hex_b;
slot_cnt0 = (httl_b - hact_b) / mipi->lan_number + 3;
slot_cnt1 = slot_cnt0;
hact = hact_b / mipi->lan_number;
hbp = hbp_b / mipi->lan_number;
hsync = hsync_b / mipi->lan_number;
httl = (hact_b + hfp_b + hbp_b + hsync_b) / mipi->lan_number;
/* word count in the unit of byte */
hsa_wc = (mipi->burst_mode == DSI_BURST_MODE_SYNC_PULSE) ?
(hsync_b - hss_bcnt - lgp_over_head) : 0;
/* Hse is with backporch */
hbp_wc = (mipi->burst_mode == DSI_BURST_MODE_SYNC_PULSE) ?
(hbp_b - hse_bct - lgp_over_head)
: (hsync_b + hbp_b - hss_bcnt - lgp_over_head);
hfp_wc = ((mipi->burst_mode == DSI_BURST_MODE_BURST) && (dsi_hex_en == 0)) ?
(hfp_b + hex_b - lgp_over_head - lgp_over_head) :
(hfp_b - lgp_over_head - lgp_over_head);
hact_wc = ((width) * bpp) >> 3;
/* disable Hex currently */
hex_wc = 0;
/* There is no hlp with active data segment. */
hlp_wc = (mipi->burst_mode == DSI_BURST_MODE_SYNC_PULSE) ?
(httl_b - hsync_b - hse_bct - lgp_over_head) :
(httl_b - hss_bcnt - lgp_over_head);
/* FIXME - need to double check the (*3) is bytes_per_pixel
* from input data or output to panel
*/
/* dsi_lane_enable - Set according to specified DSI lane count */
dphy_write((unsigned int)phy_ctrl2_reg, dsi_lane[mipi->lan_number] << DSI_PHY_CTRL_2_CFG_CSR_LANE_EN_SHIFT);
dsi_write((unsigned int)&dsi->cmd1, dsi_lane[mipi->lan_number] << DSI_CPU_CMD_1_CFG_TXLP_LPDT_SHIFT);
dsi_write((unsigned int)&dsi_lcd->ctrl0, (0x50 << 16) | 0xc08);
/* SET UP LCD1 TIMING REGISTERS FOR DSI BUS */
/* NOTE: Some register values were obtained by trial and error */
dsi_write((unsigned int)&dsi_lcd->timing0, (hact << 16) | httl);
dsi_write((unsigned int)&dsi_lcd->timing1, (hsync << 16) | hbp);
/*
* For now the active size is set really low (we'll use 10) to allow
* the hardware to attain V Sync. Once the DSI bus is up and running,
* the final value will be put in place for the active size (this is
* done below). In a later stepping of the processor this requirement
* will not be required.
*/
dsi_write((unsigned int)&dsi_lcd->timing2, ((p_panel->height) << 16) | (v_total));
dsi_write((unsigned int)&dsi_lcd->timing3, ((timing->vsync) << 16) | (timing->vbp));
/* SET UP LCD1 WORD COUNT REGISTERS FOR DSI BUS */
/* Set up for word(byte) count register 0 */
dsi_write((unsigned int)&dsi_lcd->wc0, (hbp_wc << 16) | hsa_wc);
dsi_write((unsigned int)&dsi_lcd->wc1, (hfp_wc << 16) | hact_wc);
dsi_write((unsigned int)&dsi_lcd->wc2, (hex_wc << 16) | hlp_wc);
dsi_write((unsigned int)&dsi_lcd->slot_cnt0, (slot_cnt0 << 16) | slot_cnt0);
dsi_write((unsigned int)&dsi_lcd->slot_cnt1, (slot_cnt1 << 16) | slot_cnt1);
/* Configure LCD control register 1 FOR DSI BUS */
lcd_ctrl1.val = dsi_read((unsigned int)&dsi_lcd->ctrl1);
lcd_ctrl1.bit.input_fmt = mipi->rgb_mode;
lcd_ctrl1.bit.burst_mode = mipi->burst_mode;
lcd_ctrl1.bit.lpm_frame_en = mipi->lpm_line_en;
lcd_ctrl1.bit.last_line_turn = mipi->last_line_turn;
lcd_ctrl1.bit.hex_slot_en = 0;
lcd_ctrl1.bit.hsa_pkt_en = mipi->hsa_en;
lcd_ctrl1.bit.hse_pkt_en = mipi->hse_en;
if (mipi->burst_mode == DSI_BURST_MODE_SYNC_PULSE) {
lcd_ctrl1.bit.hse_pkt_en = 1;
}
else {
lcd_ctrl1.bit.hsa_pkt_en = 0;
}
lcd_ctrl1.bit.hbp_pkt_en = mipi->hbp_en;
lcd_ctrl1.bit.hfp_pkt_en = mipi->hfp_en;
lcd_ctrl1.bit.hex_pkt_en = 0;
lcd_ctrl1.bit.hlp_pkt_en = mipi->hlp_en;
lcd_ctrl1.bit.vsync_rst_en = 1; //Jessica: 1
#ifndef DSI_GEN4
/* These bits were removed for DC4 */
lcd_ctrl1.bit.lpm_line_en = mipi->lpm_line_en;
lcd_ctrl1.bit.hact_pkt_en = mipi->hact_en;
lcd_ctrl1.bit.m2k_en = 0;
lcd_ctrl1.bit.all_slot_en = 0;
#else
/*
* FIXME: some extend features in DC4, default enable
* 1. word count auto calculation.
* 2. check timing before request DPHY for TX.
* 3. auto vsync delay count calculation.
*/
lcd_ctrl1.bit.auto_wc_dis = 0;
lcd_ctrl1.bit.hact_wc_en = 0;
lcd_ctrl1.bit.timing_check_dis = 1; //Jessica: 0
lcd_ctrl1.bit.auto_dly_dis = 1;
#endif
dsi_write((unsigned int)&dsi_lcd->ctrl1, lcd_ctrl1.val);
/*Start the transfer of LCD data over the DSI bus*/
/* DSI_CTRL_1 */
reg = dsi_read((unsigned int)&dsi->ctrl1);
#if 0 /*Jessica*/
reg &= ~(DSI_CTRL_1_CFG_LCD2_VCH_NO_MASK
| DSI_CTRL_1_CFG_LCD1_VCH_NO_MASK);
reg |= 0x1 << DSI_CTRL_1_CFG_LCD1_VCH_NO_SHIFT;
#endif
reg &= ~(DSI_CTRL_1_CFG_EOTP);
if (mipi->eotp_en) {
reg |= DSI_CTRL_1_CFG_EOTP; /* EOTP */
}
dsi_write((unsigned int)&dsi->ctrl1, reg);
/* DSI_CTRL_0 */
reg = (mipi->master_mode ? 0 : DSI_CTRL_0_CFG_LCD1_SLV) |
DSI_CTRL_0_CFG_LCD1_TX_EN | DSI_CTRL_0_CFG_LCD1_EN;
dsi_set_ctrl0(dsi, DSI_CTRL_0_CFG_LCD1_SLV, reg);
udelay(100000);
lcd_clear_bits(LCD_SMPN_CTRL, BIT_0);
// lcd_set_bits(LCD_DUMB_CTRL, BIT_0);
lcd_set_bits(LCD_MISC_CNTL, BIT_1); //should be set, otherwise color will be error
}
static void dsi_set_cmd_panel(struct dsi_regs *dsi, struct panel_spec *p_panel)
{
int cfg_cpn_te_en = 0x0;
int cfg_cpn_dma_dis = 0;
int cfg_smt_wr_cycle = 0x0; //pixel write cycle = cfg_smt_wr_cycle +1
int cfg_cpn_addr0_en = 0; //fix to 0
int cfg_cpn_burst_mode; //0x1: new smart panel if
//0x0: old smart panel if
//configure it to 0x1 when cfg_smt_wr_cycle = 0x0, or else configure it to 1.
//int cfg_cpn_2cyc_en = 0;
int cfg_cpn_rgb_type;
//0x0: 888
//0x1: 666 unpack
//0x2: 565: G3B5R5G3??
//0x3:444
//0x4:332
//0x5:111
//0x6: 565: R5G6B5
int dsi_cpn_cmd;
int cfg_cpn_fifo_full_level = 0x302;
int cfg_cpn_pkt_len = p_panel->width * p_panel->info.mipi->video_bus_width / 8 + 1;
int dsi_cpn_ctrl_1 = (cfg_cpn_pkt_len << 16) |
(cfg_cpn_fifo_full_level);
lcd_write_bits(LCD_SMPN_CTRL, 0, MASK4, BIT_20); //cfg_smt_wr_cycle = 0;
cfg_cpn_burst_mode = (cfg_smt_wr_cycle == 0) ? 1 : 0;
switch (p_panel->info.mipi->rgb_mode) {
case DSI_LCD_INPUT_DATA_RGB_MODE_565:
cfg_cpn_rgb_type = 0x6;
break;
case DSI_LCD_INPUT_DATA_RGB_MODE_666UNPACKET:
cfg_cpn_rgb_type = 0x1;
break;
case DSI_LCD_INPUT_DATA_RGB_MODE_888:
cfg_cpn_rgb_type = 0x0;
break;
default:
printf("%s: Invalid mipi format, use DSI_LCD_INPUT_DATA_RGB_MODE_888 as default!\n", __func__);
cfg_cpn_rgb_type = 0x0;
}
dsi_cpn_cmd = (cfg_cpn_te_en << 28) |
(cfg_cpn_rgb_type << 24) |
(cfg_cpn_burst_mode << 3) |
(cfg_cpn_dma_dis << 1) |
(cfg_cpn_addr0_en);
dsi_clear_bits(BIT_6 | BIT_7, (unsigned int)&dsi->ctrl1);
dsi_write((unsigned int)&dsi->smt_cmd, dsi_cpn_cmd);
dsi_write((unsigned int)&dsi->smt_ctrl1, dsi_cpn_ctrl_1);
dsi_write((unsigned int)&dsi->lcd_bdg_ctrl0, 0x0);
dsi_write((unsigned int)&dsi->lcd_bdg_ctrl1, 0x800000);
dsi_set_ctrl0(dsi, 0, DSI_CTRL_0_CFG_SMT_EN | DSI_CTRL_0_CFG_LCD1_TX_EN | DSI_CTRL_0_CFG_LCD1_SLV);
lcd_set_bits(LCD_SMPN_CTRL, BIT_0);
lcd_clear_bits(LCD_DUMB_CTRL, BIT_0);
lcd_set_bits(LCD_MISC_CNTL, BIT_1); //should be set, otherwise color will be error
}
static void dsi_send_cmds(unsigned char *parameter, unsigned char count, unsigned char lp, u32 dsi_base)
{
struct dsi_regs *dsi = (struct dsi_regs *)(dsi_base);
unsigned int send_data = 0, waddr, timeout, tmp, i, turnaround;
unsigned int len;
/* write all packet bytes to packet data buffer */
for (i = 0; i < count; i++) {
send_data |= parameter[i] << ((i % 4) * 8);
if (!((i + 1) % 4)) {
dsi_write((unsigned int)&dsi->dat0, send_data);
waddr = DSI_CFG_CPU_DAT_REQ_MASK |
DSI_CFG_CPU_DAT_RW_MASK |
((i - 3) << DSI_CFG_CPU_DAT_ADDR_SHIFT);
dsi_write((unsigned int)&dsi->cmd3, waddr);
/* wait write operation done */
timeout = 1000;
do {
timeout--;
tmp = dsi_read((unsigned int)&dsi->cmd3);
} while ((tmp & DSI_CFG_CPU_DAT_REQ_MASK) && timeout);
if (!timeout)
printf("%s %d: DSI write data to the packet data buffer not done.\n", __func__, __LINE__);
send_data = 0;
}
}
/* handle last none 4Byte align data */
if (i % 4) {
dsi_write((unsigned int)&dsi->dat0, send_data);
waddr = DSI_CFG_CPU_DAT_REQ_MASK |
DSI_CFG_CPU_DAT_RW_MASK |
((4 * (i / 4)) << DSI_CFG_CPU_DAT_ADDR_SHIFT);
dsi_write((unsigned int)&dsi->cmd3, waddr);
/* wait write operation done */
timeout = 1000;
do {
timeout--;
tmp = dsi_read((unsigned int)&dsi->cmd3);
} while ((tmp & DSI_CFG_CPU_DAT_REQ_MASK) && timeout);
if (!timeout)
printf("%s %d: DSI write data to the packet data buffer not done.\n", __func__, __LINE__);
send_data = 0;
}
if (parameter[0] == DSI_DI_DCS_READ ||
parameter[0] == DSI_DI_GENERIC_READ1) {
turnaround = 0x1;
}
else {
turnaround = 0x0;
}
len = count;
#ifndef DSI_GEN4
if ((parameter[0] == DSI_DI_DCS_LWRITE ||
parameter[0] == DSI_DI_GENERIC_LWRITE) && !lp) {
len = count - 6;
}
#endif
waddr = DSI_CFG_CPU_CMD_REQ_MASK |
((count == 4) ? DSI_CFG_CPU_SP_MASK : 0) |
(turnaround << DSI_CFG_CPU_TURN_SHIFT) |
(lp ? DSI_CFG_CPU_TXLP_MASK : 0) |
(len << DSI_CFG_CPU_WC_SHIFT);
/* send out the packet */
dsi_write((unsigned int)&dsi->cmd0, waddr);
/* wait packet be sent out */
timeout = 1000;
do {
timeout--;
tmp = dsi_read((unsigned int)&dsi->cmd0);
if (0 == timeout % 50)
printf("%s: read cmd0 is 0x%x\n", __func__, tmp);
udelay(50);
} while ((tmp & DSI_CFG_CPU_CMD_REQ_MASK) && timeout);
if (!timeout)
printf("%s: DSI send out packet maybe failed. 0x%x \n", __func__, tmp);
tmp = dsi_read((unsigned int)&dsi->irq_status);
#if 0
printf("%s: DSI irq status: 0x%x \n", __func__, tmp);
#endif
}
void asr_dsi_cmd_array_tx(struct dsi_cmd_desc cmds[], unsigned int count, struct mipi_info *mipi)
{
struct dsi_cmd_desc cmd_line;
unsigned char command, parameter[DSI_MAX_DATA_BYTES], len;
unsigned int crc, loop;
for (loop = 0; loop < count; loop++) {
cmd_line = cmds[loop];
command = cmd_line.data_type;
len = cmd_line.length;
memset(parameter, 0x00, len + 6);
parameter[0] = command & 0xff;
switch (command) {
case DSI_DI_DCS_SWRITE:
case DSI_DI_DCS_SWRITE1:
case DSI_DI_DCS_READ:
case DSI_DI_GENERIC_READ1:
case DSI_DI_SET_MAX_PKT_SIZE:
memcpy(&parameter[1], cmd_line.data, len);
len = 4;
break;
case DSI_DI_GENERIC_LWRITE:
case DSI_DI_DCS_LWRITE:
parameter[1] = len & 0xff;
parameter[2] = 0;
memcpy(&parameter[4], cmd_line.data, len);
crc = calculate_crc16(&parameter[4], len);
parameter[len + 4] = crc & 0xff;
parameter[len + 5] = (crc >> 8) & 0xff;
len += 6;
break;
default:
printf("%s: data type not supported 0x%8x\n",
__func__, command);
break;
}
parameter[3] = calculate_ecc(parameter);
/* support to send lower power mode command on multi lanes */
#if (!defined(DSI_VERSION_24)) && (!defined(DSI_VERSION_14))
unsigned char *temp;
if (cmd_line.lp) {
temp = malloc(sizeof(unsigned char) * DSI_MAX_DATA_BYTES
* mipi->lan_number);
if (temp == NULL) {
return;
}
for (int i = 0; i < len * mipi->lan_number; i += mipi->lan_number) {
for (int j = 0; j < mipi->lan_number; j++) {
temp[i + j] = parameter[i / mipi->lan_number];
}
}
len = mipi->lan_number * len;
memcpy(parameter, temp, len);
free(temp);
}
#endif
(void)mipi;
/* send dsi commands */
dsi_send_cmds(parameter, len, cmd_line.lp, mipi->dsi_base);
if (cmd_line.delay)
udelay(cmd_line.delay * 1000);
}
}
void asr_dsi_cmd_array_rx(struct dsi_buf *dbuf, struct dsi_cmd_desc cmds[],
unsigned int count, struct mipi_info *mipi)
{
struct dsi_regs *dsi = (struct dsi_regs *)(mipi->dsi_base);
unsigned char parameter[DSI_DI_SET_MAX_PKT_SIZE];
unsigned int i, rx_reg, timeout, tmp, packet,
data_pointer, byte_count;
memset(dbuf, 0x0, sizeof(struct dsi_buf));
asr_dsi_cmd_array_tx(cmds, count, mipi);
timeout = 1000;
do {
timeout--;
tmp = dsi_read((unsigned int)&dsi->irq_status);
} while (((tmp & 0x4) == 0) && timeout);
if (!timeout) {
printf("%s: error: dsi didn't receive packet, irq status 0x%x\n",
__func__, dsi_read((unsigned int)&dsi->irq_status));
return;
}
if (tmp & IRQ_RX_TRG2)
printf("%s: ACK received\n", __func__);
if (tmp & IRQ_RX_TRG1)
printf("%s: TE trigger received\n", __func__);
if (tmp & IRQ_RX_ERR) {
printf("%s: error: ACK with error report\n", __func__);
tmp = dsi_read((unsigned int)&dsi->rx0_header);
}
packet = dsi_read((unsigned int)&dsi->rx0_status);
data_pointer = (packet & RX_PKT0_PKT_PTR_MASK) >> RX_PKT0_PKT_PTR_SHIFT;
tmp = dsi_read((unsigned int)&dsi->rx_ctrl1);
byte_count = tmp & RX_PKT_BCNT_MASK;
memset(parameter, 0x00, byte_count);
for (i = data_pointer; i < data_pointer + byte_count; i++) {
rx_reg = dsi_read((unsigned int)&dsi->rx_ctrl);
rx_reg &= ~RX_PKT_RD_PTR_MASK;
rx_reg |= RX_PKT_RD_REQ | (i << RX_PKT_RD_PTR_SHIFT);
dsi_write((unsigned int)&dsi->rx_ctrl, rx_reg);
count = 10000;
do {
count--;
rx_reg = dsi_read((unsigned int)&dsi->rx_ctrl);
} while (rx_reg & RX_PKT_RD_REQ && count);
if (!count) {
printf("%s: error: Rx packet FIFO error\n", __func__);
}
parameter[i - data_pointer] = rx_reg & 0xff;
}
switch (parameter[0]) {
case DSI_DI_ACK_ERR_RESP:
printf("%s: error: Acknowledge with error report\n", __func__);
break;
case DSI_DI_EOTP:
printf("%s: error: End of Transmission packet\n", __func__);
break;
case DSI_DI_GEN_READ1_RESP:
case DSI_DI_DCS_READ1_RESP:
dbuf->data_type = parameter[0];
dbuf->length = 1;
memcpy(dbuf->data, &parameter[1], dbuf->length);
break;
case DSI_DI_GEN_READ2_RESP:
case DSI_DI_DCS_READ2_RESP:
dbuf->data_type = parameter[0];
dbuf->length = 2;
memcpy(dbuf->data, &parameter[1], dbuf->length);
break;
case DSI_DI_GEN_LREAD_RESP:
case DSI_DI_DCS_LREAD_RESP:
dbuf->data_type = parameter[0];
dbuf->length = (parameter[2] << 8) | parameter[1];
memcpy(dbuf->data, &parameter[4], dbuf->length);
printf("%s: read %d data: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", __func__, dbuf->length,
parameter[4], parameter[5], parameter[6], parameter[7], parameter[8]);
break;
}
}
void asr_dsi_init(struct panel_spec *p_panel)
{
struct dsi_regs *dsi = (struct dsi_regs *)(p_panel->info.mipi->dsi_base);
/* reset and de-assert DSI controller */
dsi_reset(dsi, 0);
dphy_config(dsi, p_panel);
}
int asr_dsi_ready(struct panel_spec *p_panel)
{
int reg_value;
struct dsi_regs *dsi = (struct dsi_regs *)(p_panel->info.mipi->dsi_base);
if (p_panel->info.mipi->work_mode == MIPI_MODE_CMD)
dsi_set_cmd_panel(dsi, p_panel);
else
dsi_set_video_panel(dsi, p_panel);
reg_value = dsi_read((unsigned int)&dsi->lcd_bdg_ctrl0);
reg_value = reg_value | BIT_6;
reg_value = reg_value | BIT_1;
dsi_write((unsigned int)&dsi->lcd_bdg_ctrl0, reg_value);
return 0;
}