最近需要调试一个lcd驱动,在原先的驱动上面适配好了,为了分离出来好给后续单个适配,从新添加多一个驱动
君正T40添加一个lcd驱动
步骤:
1.添加驱动源文件
os/kernel/drivers/video/fbdev/ingenic/fb_v12/displays/panel-st7102-xiaomi.c
/*
* Copyright (c) 2012 Ingenic Semiconductor Co., Ltd.
* http://www.ingenic.com/
*
* dorado board lcd setup routines.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/pwm_backlight.h>
#include <linux/lcd.h>
#include <linux/of_gpio.h>
#include <soc/gpio.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/ide.h>
#include <linux/irq.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include "../ingenicfb.h"
#include "../jz_dsim.h"
#include "../jz_mipi_dsi/jz_mipi_dsih_hal.h"
#define ST7102_SUPPORT_LANE_2_FPS_60 0
#define ST7102_SUPPORT_LANE_2_FPS_30 1
#if defined(CONFIG_FB_ESD_CHECK_MODE)
#define ST7102_TE_IRQ_USE 1
#else
#define ST7102_TE_IRQ_USE 0
#endif
#define JZ_LCD_FPS_MAX ST7102_SUPPORT_LANE_2_FPS_60
static struct dsi_cmd_packet st7102_xiaomi_cmd_list[] = {
#if 0
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x13}},
{0x39, 0x02, 0x00, {0xEF,0x08}},
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x10}},
{0x39, 0x03, 0x00, {0xC0,0x63,0x00}},
{0x39, 0x03, 0x00, {0xC1,0x09,0x02}},
{0x39, 0x03, 0x00, {0xC2,0x20,0x02}},
{0x39, 0x02, 0x00, {0xCC,0x18}},
{0x39, 0x11, 0x00, {0xB0,0x40,0x0E,0x51,0x0F,0x11,0x07,0x00,0x09,0x06,0x1E,0x04,0x12,0x11,0x64,0x29,0xDF}},
{0x39, 0x11, 0x00, {0xB1,0x40,0x07,0x4C,0x0A,0x0E,0x04,0x00,0x08,0x09,0x1D,0x01,0x0E,0x0C,0x6A,0x34,0xDF}},
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x11}},
{0x39, 0x02, 0x00, {0xB0,0x30}},
{0x39, 0x02, 0x00, {0xB1,0x48}},
{0x39, 0x02, 0x00, {0xB2,0x80}},
{0x39, 0x02, 0x00, {0xB3,0x80}},
{0x39, 0x02, 0x00, {0xB5,0x4F}},
{0x39, 0x02, 0x00, {0xB7,0x85}},
{0x39, 0x02, 0x00, {0xB8,0x23}},
{0x39, 0x03, 0x00, {0xB9,0x22,0x13}},
{0x39, 0x02, 0x00, {0xBB,0x03}},
{0x39, 0x02, 0x00, {0xBC,0x10}},
{0x39, 0x02, 0x00, {0xC0,0x89}},
{0x39, 0x02, 0x00, {0xC1,0x78}},
{0x39, 0x02, 0x00, {0xC2,0x78}},
{0x39, 0x02, 0x00, {0xD0,0x88}},
{0x39, 0x04, 0x00, {0xE0,0x00,0x00,0x02}},
{0x39, 0x0C, 0x00, {0xE1,0x04,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x00,0x10,0x10}},
{0x39, 0x0E, 0x00, {0xE2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{0x39, 0x05, 0x00, {0xE3,0x00,0x00,0x33,0x00}},
{0x39, 0x03, 0x00, {0xE4,0x22,0x00}},
{0x39, 0x11, 0x00, {0xE5,0x03,0x34,0xAF,0xB3,0x05,0x34,0xAF,0xB3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{0x39, 0x05, 0x00, {0xE6,0x00,0x00,0x33,0x00}},
{0x39, 0x03, 0x00, {0xE7,0x22,0x00}},
{0x39, 0x11, 0x00, {0xE8,0x04,0x34,0xAF,0xB3,0x06,0x34,0xAF,0xB3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
{0x39, 0x08, 0x00, {0xEB,0x02,0x00,0x40,0x40,0x00,0x00,0x00}},
{0x39, 0x03, 0x00, {0xEC,0x00,0x00}},
{0x39, 0x11, 0x00, {0xED,0xFA,0x45,0x0B,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xB0,0x54,0xAF}},
{0x39, 0x07, 0x00, {0xEF,0x08,0x08,0x08,0x45,0x3F,0x54}},
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x13}},
{0x39, 0x03, 0x00, {0xE6,0x16,0x7c}},
{0x39, 0x03, 0x00, {0xe8,0x00,0x0E}},
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x00}},
{0x15, 0x11, 0x00, { 0x00 }}, //Sleep out
{0x99, 120, 0x00, {0x00}},
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x13}},
{0x39, 0x03, 0x00, {0xe8,0x00,0x0C}},
{0x99, 10, 0x00, {0x00}},
{0x39, 0x03, 0x00, {0xe8,0x00,0x00}},
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x00}},
{0x39, 0x02, 0x00, {0x35,0x00}},
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x00}},
{0x15, 0x29, 0x00, { 0x00}}, // Display On
{0x99, 20, 0x00, {0x00}}, //delay 50ms
{0x39, 0x06, 0x00, {0xFF,0x77,0x01,0x00,0x00,0x10}},
{0x39, 0x02, 0x00, {0xE5,0x00}},
#else
//{0x99, 50, 0x00, {0x00}}, //sleep 5ms
{0x05, 0x10, 0x00 },
{0x05, 0x28, 0x00 },
{0x29, 0x04, 0x00, { 0x99, 0x71, 0x02, 0xa2, } },
{0x29, 0x04, 0x00, { 0x99, 0x71, 0x02, 0xa3, } },
{0x29, 0x04, 0x00, { 0x99, 0x71, 0x02, 0xa4, } },
{0x39, 0x02, 0x00, { 0x78, 0x21, } },
{0x39, 0x02, 0x00, { 0x79, 0xCF, } },
//2lane
//{0x39, 0x02, 0x00, { 0xA4, 0x31, } },
{0x39, 0x08, 0x00, { 0xB0, 0x22, 0x57, 0x1E, 0x61, 0x2F, 0x57, 0x61, } },
{0x39, 0x03, 0x00, { 0xB7, 0x64, 0x64, } },
{0x39, 0x03, 0x00, { 0xBF, 0x6e, 0x6e, } },
{0x29, 0x26, 0x00, { 0xC8, 0x00, 0x00, 0x13, 0x23, 0x3E, 0x00, 0x6A, 0x03, 0xB0, 0x06, 0x11, 0x0F, 0x07, 0x85, 0x03, 0x21, 0xD5, 0x01, 0x18, 0x00, 0x22, 0x56, 0x0F, 0x98, 0x0A, 0x32, 0xF8, 0x0D, 0x48, 0x0F, 0xF3, 0x80, 0x0F, 0xAC, 0xC1, 0x03, 0xC4, } },
{0x29, 0x26, 0x00, { 0xC9, 0x00, 0x00, 0x13, 0x23, 0x3E, 0x00, 0x6A, 0x03, 0xB0, 0x06, 0x11, 0x0F, 0x07, 0x85, 0x03, 0x21, 0xD5, 0x01, 0x18, 0x00, 0x22, 0x56, 0x0F, 0x98, 0x0A, 0x32, 0xF8, 0x0D, 0x48, 0x0F, 0xF3, 0x80, 0x0F, 0xAC, 0xC1, 0x03, 0xC4, } },
{0x39, 0x07, 0x00, { 0xD7, 0x10, 0x0C, 0x77, 0x19, 0xE0, 0xE0, } },
{0x39, 0x21, 0x00, { 0xA3, 0x40, 0x03, 0x80, 0xCF, 0x44, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6F, 0x6F, 0x00, 0x1A, 0x00, 0x45, 0x05, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x02, 0x20, 0x52, 0x00, 0x05, 0x00, 0x00, 0xFF, } },
{0x39, 0x2D, 0x00, { 0xA6, 0x02, 0x00, 0x24, 0x55, 0x35, 0x00, 0x38, 0x00, 0x5E, 0x5E, 0x00, 0x24, 0x55,0x36, 0x00, 0x37, 0x00, 0x5E, 0x5E, 0x02, 0xAC, 0x51, 0x3A, 0x00, 0x00, 0x00, 0x5E, 0x5E, 0x00, 0xAC, 0x11, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x5E, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, } },
{0x39, 0x31, 0x00, { 0xA7, 0x19, 0x19, 0x00, 0x64, 0x40, 0x07, 0x16, 0x40, 0x00, 0x04, 0x03, 0x5E, 0x5E, 0x00, 0x64, 0x40, 0x25, 0x34, 0x00, 0x00, 0x02, 0x01, 0x5E, 0x5E, 0x00, 0x64, 0x40, 0x4B, 0x5A, 0x00, 0x00, 0x02, 0x01, 0x5E, 0x5E, 0x00, 0x24, 0x40, 0x69, 0x78, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x5E, 0x00, 0x44, } },
{0x39, 0x26, 0x00, { 0xAC, 0x08, 0x0A, 0x11, 0x00, 0x13, 0x03, 0x1B,0x18, 0x06, 0x1A, 0x19, 0x1B, 0x1B,0x1B, 0x18, 0x1B, 0x09,0x0B, 0x10, 0x02, 0x12, 0x01, 0x1B, 0x18, 0x06, 0x1A, 0x19, 0x1B, 0x1B, 0x1B, 0x18, 0x1B, 0xFF, 0x67, 0xFF, 0x67, 0x00, } },
{0x39, 0x08, 0x00, { 0xAD, 0xCC, 0x40, 0x46, 0x11, 0x04, 0x6F, 0x6F, } },
{0x39, 0x0F, 0x00, { 0xE8, 0x30, 0x07, 0x00, 0x7A, 0x7A, 0x9C, 0x00, 0xE2, 0x04, 0x00, 0x00, 0x00, 0x00, 0xEF, } },
{0x29, 0x03, 0x00, { 0x75, 0x03, 0x04, } },
{0x39, 0x22, 0x00, { 0xE7, 0x8B, 0x3C, 0x00, 0x0C, 0xF0, 0x5D, 0x00, 0x5D, 0x00, 0x5D, 0x00, 0x5D, 0x00, 0xFF, 0x00, 0x08, 0x7B, 0x00, 0x00, 0xC8, 0x6A, 0x5A, 0x08, 0x1A, 0x3C, 0x00, 0x91, 0x01, 0xCC, 0x01, 0x7F, 0xF0, 0x22, } },
{0x39, 0x0A, 0x00, { 0xE9, 0x4C, 0x7F, 0x08, 0x07, 0x1A, 0x7A, 0x22, 0x1A, 0x33, } },
{0x05, 0x11, 0x00 }, //Sleep out
{0x99, 120, 0x00, {0x00}}, //delay 250ms
{0x05, 0x29, 0x00 }, // Display On
{0x29, 0x02, 0x00, { 0x35, 0x00, } },
//{0x39, 0x02, 0x00, { 0xB5, 0x85, } },
#endif
};
struct board_gpio {
short gpio;
short active_level;
};
struct panel_dev {
/* ingenic frame buffer */
struct device *dev;
struct lcd_panel *panel;
/* common lcd framework */
struct lcd_device *lcd;
struct backlight_device *backlight;
int power;
struct regulator *vcc;
struct board_gpio vdd_en;
struct board_gpio bl;
struct board_gpio rst;
struct board_gpio oled;
struct board_gpio lcd_pwm;
struct mipi_dsim_lcd_device *dsim_dev;
};
struct panel_dev *panel;
#define lcd_to_master(a) (a->dsim_dev->master)
#define lcd_to_master_ops(a) ((lcd_to_master(a))->master_ops)
#define DEV_NAME "gpio_irq"
#define GPIO_LCD_TE GPIO_PC(24)
struct gpio_irq_st
{
int gpio;
unsigned int irq_num; //中断号
unsigned char value; //键值
};
// static int te_reset_flag = 0;
static int sg_suspend_flag = 1;
static int sg_init_ignore_cnt = 0;
static volatile unsigned long long lcd_te_irq_ts = 0;
static struct gpio_irq_st gpio_data = {GPIO_LCD_TE, 0, 0};
struct st7102_xiaomi {
struct device *dev;
unsigned int power;
unsigned int id;
struct lcd_device *ld;
struct backlight_device *bd;
struct mipi_dsim_lcd_device *dsim_dev;
};
struct fb_videomode jzfb_st7102_xiaomi_videomode[] = {
//[0] 4lane 60fps
{
.name = "st7102_xiaomi",
.refresh = 30,//现在不支持60fps
.xres = 480,
.yres = 960,
.pixclock = KHZ2PICOS(56000), //60
.left_margin = 40,
.right_margin = 80,
.hsync_len = 2,//2
.upper_margin = 10,
.lower_margin = 215,//215
.vsync_len = 2,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.vmode = FB_VMODE_NONINTERLACED,
.flag = 0
},
{
.name = "st7102_xiaomi",
.refresh = 30,
.xres = 480,
.yres = 960,
.pixclock = KHZ2PICOS(56000), //60//56000
.left_margin = 40,
.right_margin = 80,
.hsync_len = 2,//2
.upper_margin = 10,
.lower_margin = 215,
.vsync_len = 2,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.vmode = FB_VMODE_NONINTERLACED,
.flag = 0
},
};
struct jzdsi_data jzdsi_pdata = {
.modes = &jzfb_st7102_xiaomi_videomode[JZ_LCD_FPS_MAX],
#ifdef CONFIG_MIPI_2LANE
.video_config.no_of_lanes = 2,
#endif
#ifdef CONFIG_MIPI_4LANE
.video_config.no_of_lanes = 4,
#endif
.video_config.virtual_channel = 0,
.video_config.color_coding = COLOR_CODE_24BIT,
#if 0
.video_config.video_mode = VIDEO_NON_BURST_WITH_SYNC_PULSES,
// .video_config.video_mode = VIDEO_NON_BURST_WITH_SYNC_EVENTS,
#else
.video_config.video_mode = VIDEO_BURST_WITH_SYNC_PULSES,
#endif
.video_config.receive_ack_packets = 0, /* enable receiving of ack packets */
/*loosely: R0R1R2R3R4R5__G0G1G2G3G4G5G6__B0B1B2B3B4B5B6,
* not loosely: R0R1R2R3R4R5G0G1G2G3G4G5B0B1B2B3B4B5*/
.video_config.is_18_loosely = 0,
.video_config.data_en_polarity = 1,
.dsi_config.max_lanes = 4,//4
.dsi_config.max_hs_to_lp_cycles = 100,
.dsi_config.max_lp_to_hs_cycles = 40,
.dsi_config.max_bta_cycles = 4095,
.dsi_config.color_mode_polarity = 1,
.dsi_config.shut_down_polarity = 1,
.dsi_config.max_bps = 460,//460
// .max_bps = 650, // 650 Mbps
.bpp_info = 24,
};
struct tft_config st7102_xiaomi_cfg = {
.pix_clk_inv = 0,
.de_dl = 0,
.sync_dl = 0,
.color_even = TFT_LCD_COLOR_EVEN_RGB,
.color_odd = TFT_LCD_COLOR_ODD_RGB,
.mode = TFT_LCD_MODE_PARALLEL_888,
};
struct lcd_panel lcd_panel = {
.num_modes = 1,
.modes = &jzfb_st7102_xiaomi_videomode[JZ_LCD_FPS_MAX],
.dsi_pdata = &jzdsi_pdata,
//.smart_config = &smart_cfg,
.tft_config = &st7102_xiaomi_cfg,
.lcd_type = LCD_TYPE_TFT ,
.width = 480,
.height = 960,
//.bpp = 24,
//.pixclk_falling_edge = 0,
//.data_enable_active_low = 0,
};
/**************************************************************************************************/
#ifdef CONFIG_BACKLIGHT_PWM
static struct platform_pwm_backlight_data backlight_data = {
.pwm_id = 0,
.max_brightness = 255,
.dft_brightness = 100,
.pwm_period_ns = 30000,
};
struct platform_device backlight_device = {
.name = "pwm-backlight",
.dev = {
.platform_data = &backlight_data,
},
};
#endif
#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
static int panel_set_power(struct lcd_device *lcd, int power)
{
return 0;
}
static int panel_get_power(struct lcd_device *lcd)
{
struct panel_dev *panel = lcd_get_data(lcd);
return panel->power;
}
static struct lcd_ops panel_lcd_ops = {
.early_set_power = panel_set_power,
.set_power = panel_set_power,
.get_power = panel_get_power,
};
static unsigned long long get_ms_time(void) {
struct timeval ts;
do_gettimeofday(&ts);
return ((unsigned long long)ts.tv_sec * 1000) + (ts.tv_usec / 1000);
}
//中断回调函数
static irqreturn_t key_handler(int irq, void *dev_id)
{
lcd_te_irq_ts = get_ms_time();
struct gpio_irq_st *dev = (struct gpio_irq_st *)dev_id;
// printk("key%d irq\n",dev->gpio);
return IRQ_RETVAL(IRQ_HANDLED);
}
int lcd_te_irq_init(void)
{
int ret;
ret = gpio_request(gpio_data.gpio, DEV_NAME);
if (ret < 0)
printk("gpio_request %d error!\n", gpio_data.gpio);
gpio_direction_input(gpio_data.gpio);
gpio_data.irq_num = gpio_to_irq(gpio_data.gpio);
if (gpio_data.irq_num < 0)
printk("gpio_to_irq error!\n");
ret = request_irq(gpio_data.irq_num, key_handler, IRQF_TRIGGER_FALLING, DEV_NAME, &gpio_data);
if (ret < 0)
{
printk("irq %d request failed!\r\n", gpio_data.irq_num);
}
printk("lcd_te_irq_init\n");
return 0;
}
static int esd_check(void)
{
static int loop = 0;
unsigned char buf[150];
memset(buf, 0, sizeof(buf));
struct dsi_master_ops *ops = lcd_to_master_ops(panel);
struct dsi_device *dsi = lcd_to_master(panel);
if(sg_suspend_flag) {
return 0;
}
if(sg_init_ignore_cnt) {
sg_init_ignore_cnt--;
return 0;
}
#if ST7102_TE_IRQ_USE
if(get_ms_time() - lcd_te_irq_ts > 1000) {
printk("LEC TE reset\n");
return -1;
}
#endif
msleep(20);
mipi_dsih_gen_rd_packet(dsi, 0, 0x14, 0, 0x0a, 4, buf);
printk("read buffer: \ncmd: 0x%x, parameter:0x%x,0x%x,0x%x,0x%x\n", 0x0a, buf[0], buf[1], buf[2], buf[3]);
//复位
if(0x9c != buf[0]) {
printk("0A reset\n");
return -1;
}
// mipi_dsih_gen_rd_packet(dsi, 0, 0x14, 0, 0xE5, 4, buf);
// printk("read buffer: \ncmd: 0x%x, parameter:0x%x,0x%x,0x%x,0x%x\n", 0xE5, buf[0], buf[1], buf[2], buf[3]);
// //复位
// if(0x00 != buf[0])
// {
// printk("E5 reset\n");
// return -1;
// }
unsigned int value = 0;
unsigned int addr = 0xb00030b0;
value = *(volatile unsigned int*)(addr);
printk("dsi phy address 0x100030b0 = 0x%x\n", value);
addr = 0xb00030bc;
value = *(volatile unsigned int*)(addr);
printk("dsi phy address 0x100030bc = 0x%x\n", value);
if(value != 0) {
printk("dsi phy 0x100030bc reset\n");
return -1;
}
addr = 0xb00030c0;
value = *(volatile unsigned int*)(addr);
printk("dsi phy address 0x100030c0 = 0x%x\n", value);
if(value != 0) {
printk("dsi phy 0xb00030c0 reset\n");
return -1;
}
// loop++;
// if(loop >= 10) {
// loop = 0;
// printk("timeout reset\n");
// return -1;
// }
return 0;
}
static int of_panel_parse(struct device *dev)
{
struct panel_dev *panel = dev_get_drvdata(dev);
struct device_node *np = dev->of_node;
enum of_gpio_flags flags;
int ret = 0;
panel->bl.gpio = of_get_named_gpio_flags(np, "ingenic,bl-gpio", 0, &flags);
if (gpio_is_valid(panel->bl.gpio)) {
panel->bl.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
ret = devm_gpio_request(dev, panel->bl.gpio, "backlight");
if (ret < 0) {
dev_err(dev, "Failed to request backlight pin!\n");
return ret;
}
} else
dev_warn(dev, "invalid gpio backlight.gpio: %d\n", panel->bl.gpio);
panel->rst.gpio = of_get_named_gpio_flags(np, "ingenic,rst-gpio", 0, &flags);
if (gpio_is_valid(panel->rst.gpio)) {
panel->rst.active_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
ret = devm_gpio_request(dev, panel->rst.gpio, "reset");
if (ret < 0) {
dev_err(dev, "Failed to request rst pin!\n");
return ret;
}
} else {
dev_warn(dev, "invalid gpio rst.gpio: %d\n", panel->rst.gpio);
}
return 0;
}
static void panel_dev_panel_init(struct panel_dev *lcd)
{
static int boot_flag = 0;
int i, j;
struct dsi_master_ops *ops = lcd_to_master_ops(lcd);
struct dsi_device *dsi = lcd_to_master(lcd);
unsigned char buf[MAX_WORD_COUNT];
unsigned char dsi_command_param[MAX_WORD_COUNT] = {0};
memset(buf, 0, sizeof(buf));
#if 0
//set maximum transfer datasize
dsi_command_param[0] = 4; //lsb
dsi_command_param[1] = 0; //msb
mipi_dsih_gen_wr_packet(dsi, 0, 0x37, dsi_command_param, 2);
printk("set maximum return packet size ok now...\n");
//read display ID
mipi_dsih_gen_rd_packet(dsi, 0, 0x14, 0, 0x04, 4, buf);
printk("read buffer: \ncmd: 0x04, parameter:0x%x,0x%x,0x%x,0x%x\n", buf[0], buf[1], buf[2], buf[3]);
#endif
#if 0
struct dsi_cmd_packet list[] =
{
{0x05, 0x10, 0x00},//{0x05, 0x01, 0x00},
};
if(boot_flag) { //ESD复位时做一个软复位,首次上电不需要
msleep(120);
ops->cmd_write(dsi, list[0]);
msleep(120);
}
#endif
for (i = 0; i < ARRAY_SIZE(st7102_xiaomi_cmd_list); i++) {
if (st7102_xiaomi_cmd_list[i].packet_type == 0x99) {
/* printk("\nsleep now. time: %dms\n", st7102_xiaomi_cmd_list[i].cmd0_or_wc_lsb+st7102_xiaomi_cmd_list[i].cmd1_or_wc_msb); */
if (st7102_xiaomi_cmd_list[i].cmd0_or_wc_lsb+st7102_xiaomi_cmd_list[i].cmd1_or_wc_msb == 510)
msleep(600);
else
msleep(st7102_xiaomi_cmd_list[i].cmd0_or_wc_lsb+st7102_xiaomi_cmd_list[i].cmd1_or_wc_msb);
continue;
}
ops->cmd_write(dsi, st7102_xiaomi_cmd_list[i]);
#if 0
//short packet read here
if (st7102_xiaomi_cmd_list[i].packet_type == 0x15) {
//we read command here, see whether we send command configure ok.
mipi_dsih_gen_rd_packet(dsi, 0, 0x14, 0, st7102_xiaomi_cmd_list[i].cmd0_or_wc_lsb, 4, buf);
printk("read buffer: \ncmd: 0x%x, parameter:0x%x,0x%x,0x%x,0x%x\n", st7102_xiaomi_cmd_list[i].cmd0_or_wc_lsb, buf[0], buf[1], buf[2], buf[3]);
}
//long packet read here
if (st7102_xiaomi_cmd_list[i].packet_type == 0x39 || st7102_xiaomi_cmd_list[i].packet_type == 0x29) {
//we read command here, see whether we send command configure ok.
printk("return value : %d\t", mipi_dsih_gen_rd_packet(dsi, 0, 0x14, 0, st7102_xiaomi_cmd_list[i].cmd_data[0], 110, buf));
printk("read buffer(data_type: 0x%x, cmd: 0x%x)\n", st7102_xiaomi_cmd_list[i].packet_type, st7102_xiaomi_cmd_list[i].cmd_data[0]);
for (j = 0 ; j < 110; j++)
printk("paramter list[%d]:0x%x\t", j, buf[j]);
printk("\n");
}
#endif
memset(buf, 0, sizeof(buf));
}
boot_flag = 1;
}
static int panel_dev_ioctl(struct mipi_dsim_lcd_device *dsim_dev, int cmd)
{
return esd_check();
}
static void panel_dev_set_sequence(struct mipi_dsim_lcd_device *dsim_dev)
{
struct st7102_xiaomi *lcd = dev_get_drvdata(&dsim_dev->dev);
dev_info(panel->dev, "panel_dev_panel_init\n");
panel_dev_panel_init(panel);
msleep(120);
sg_suspend_flag = 0;
dev_info(panel->dev, "panel_dev_panel_init done!\n");
lcd->power = FB_BLANK_UNBLANK;
}
static void panel_dev_power_on(struct mipi_dsim_lcd_device *dsim_dev, int power)
{
static int boot_flag = 0;
struct panel_dev *panel_st7102_xiaomi = dev_get_drvdata(panel->dev);
if( 0 <= panel_st7102_xiaomi->bl.gpio <= 22)
{
// 1: 1.8V
// 0: 3.3v
jzgpio_set_work_voltage(GPIO_PORT_A,1);
}
if (power == 1) {
//reset
dev_info(panel->dev, "Panel power on reset\n");
if (gpio_is_valid(panel_st7102_xiaomi->rst.gpio)) {
gpio_direction_output(panel_st7102_xiaomi->rst.gpio, !panel_st7102_xiaomi->rst.active_level);
msleep(120);
gpio_direction_output(panel_st7102_xiaomi->rst.gpio, panel_st7102_xiaomi->rst.active_level);
msleep(50);
gpio_direction_output(panel_st7102_xiaomi->rst.gpio, !panel_st7102_xiaomi->rst.active_level);
msleep(120);
// msleep(20);
boot_flag = 1;
}
//open backlight
if (gpio_is_valid(panel_st7102_xiaomi->bl.gpio)) {
gpio_direction_output(panel_st7102_xiaomi->bl.gpio, panel_st7102_xiaomi->bl.active_level);
}
} else {
dev_info(panel->dev, "Panel power on open backlight\n");
if (gpio_is_valid(panel_st7102_xiaomi->bl.gpio)) {
gpio_direction_output(panel_st7102_xiaomi->bl.gpio, panel_st7102_xiaomi->bl.active_level);
}
}
}
static int panel_dev_probe(struct mipi_dsim_lcd_device *dsim_dev)
{
struct st7102_xiaomi *lcd;
lcd = devm_kzalloc(&dsim_dev->dev, sizeof(struct st7102_xiaomi), GFP_KERNEL);
if (IS_ERR_OR_NULL(lcd)) {
dev_err(&dsim_dev->dev, "Failed to allocate st7102_xiaomi structure!\n");
return -ENOMEM;
}
lcd->dsim_dev = dsim_dev;
lcd->dev = &dsim_dev->dev;
lcd->ld = lcd_device_register("st7102_xiaomi", lcd->dev, lcd,
&panel_lcd_ops);
if (IS_ERR(lcd->ld)) {
dev_err(lcd->dev, "Failed to register lcd ops.");
return PTR_ERR(lcd->ld);
}
dev_set_drvdata(&dsim_dev->dev, lcd);
dev_dbg(lcd->dev, "Now probed st7102_xiaomi panel.\n");
#if ST7102_TE_IRQ_USE
lcd_te_irq_init();
#endif
panel->dsim_dev = dsim_dev;
return 0;
}
static int panel_dev_suspend(struct mipi_dsim_lcd_device *dsim_dev)
{
struct board_gpio *vdd_en = &panel->bl;
dev_info(panel->dev, "panel_dev_suspend\n");
sg_suspend_flag = 1;
sg_init_ignore_cnt = 3;
if (gpio_is_valid(vdd_en->gpio)) {
gpio_direction_output(vdd_en->gpio, !vdd_en->active_level);
}
return 0;
}
static int panel_dev_resume(struct mipi_dsim_lcd_device *dsim_dev)
{
struct board_gpio *vdd_en = &panel->bl;
dev_info(panel->dev, "panel_dev_resume\n");
if (gpio_is_valid(vdd_en->gpio)) {
gpio_direction_output(vdd_en->gpio, vdd_en->active_level);
}
return 0;
}
static struct mipi_dsim_lcd_driver panel_dev_dsim_ddi_driver = {
.name = "st7102_xiaomi",
.id = -1,
.power_on = panel_dev_power_on,
.set_sequence = panel_dev_set_sequence,
.probe = panel_dev_probe,
.suspend = panel_dev_suspend,
.resume = panel_dev_resume,
.ioctl = panel_dev_ioctl,
};
static struct mipi_dsim_lcd_device panel_dev_device = {
.name = "st7102_xiaomi",
.id = 0,
};
/**
* @panel_probe
*
* 1. register to ingenicfb
* 2. register to lcd
* 3. register to backlight if possible
*
* @pdev
*
* @return -
*/
static int panel_probe(struct platform_device *pdev)
{
int ret = 0;
panel = kzalloc(sizeof(struct panel_dev), GFP_KERNEL);
if (IS_ERR_OR_NULL(panel)) {
dev_err(&pdev->dev, "Failed to alloc memory!\n");
return -ENOMEM;
}
panel->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, panel);
ret = of_panel_parse(&pdev->dev);
if (ret < 0)
goto err_of_parse;
/* register to mipi-dsi devicelist*/
mipi_dsi_register_lcd_device(&panel_dev_device);
mipi_dsi_register_lcd_driver(&panel_dev_dsim_ddi_driver);
ret = ingenicfb_register_panel(&lcd_panel);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register lcd panel!\n");
goto err_of_parse;
}
return 0;
err_of_parse:
kfree(panel);
return ret;
}
static int panel_remove(struct platform_device *dev)
{
if (NULL != panel)
kfree(panel);
return 0;
}
#ifdef CONFIG_PM
static int panel_suspend(struct device *dev)
{
struct panel_dev *panel = dev_get_drvdata(dev);
panel_set_power(panel->lcd, FB_BLANK_POWERDOWN);
return 0;
}
static int panel_resume(struct device *dev)
{
struct panel_dev *panel = dev_get_drvdata(dev);
panel_set_power(panel->lcd, FB_BLANK_UNBLANK);
return 0;
}
static const struct dev_pm_ops panel_pm_ops = {
.suspend = panel_suspend,
.resume = panel_resume,
};
#endif
static const struct of_device_id panel_of_match[] = {
{ .compatible = "ingenic,st7102_xiaomi", },
{ .compatible = "st7102_xiaomi", },
{},
};
static struct platform_driver panel_driver = {
.probe = panel_probe,
.remove = panel_remove,
.driver = {
.name = "st7102_xiaomi",
.of_match_table = panel_of_match,
#ifdef CONFIG_PM
.pm = &panel_pm_ops,
#endif
},
};
// module_platform_driver(panel_driver);
static int __init panel_driver_init(void)
{
platform_driver_register(&panel_driver);
return 0;
}
static void __exit panel_driver_exit(void)
{
platform_driver_unregister(&panel_driver);
}
module_init(panel_driver_init);
module_exit(panel_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kevin");
MODULE_DESCRIPTION("Kernel panel driver");
2.Kconfig加进来该模块,路径:os/kernel/drivers/video/fbdev/ingenic/fb_v12/displays/Kconfig
menuconfig FB_INGENIC_DISPLAYS_V12
tristate "Supported lcd panels"
depends on FB_INGENIC_V12
select BACKLIGHT_LCD_SUPPORT
select LCD_CLASS_DEVICE
select BACKLIGHT_CLASS_DEVICE
config PANEL_V12_Y88249
tristate "lcd panel y88249"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel y88249, for ingenicfb drivers.
config PANEL_V12_KD050HDFIA019
tristate "lcd panel kd050hdfia019"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel kd050hdfia019, for ingenicfb drivers.
config PANEL_V12_MA0060
tristate "lcd panel MA0060"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel MA0060, for ingenicfb drivers.
config PANEL_V12_TL040WVS03CT
tristate "lcd panel tl040wvs03ct"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel tl040wvs03ct, for ingenicfb drivers.
config PANEL_V12_TL040HDS01CT
tristate "lcd panel tl040hds01ct"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel tl040hds01ct, for ingenicfb drivers.
config PANEL_V12_JD9161Z
tristate "lcd panel JD9161Z"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel JD9161Z, for ingenicfb drivers.
config PANEL_V12_ST7701S
tristate "lcd panel ST7701S"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel ST7701S, for ingenicfb drivers.
config PANEL_V12_YTS500XLAI
tristate "lcd panel YTS500XLAI"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel YTS500XLAI, for ingenicfb drivers.
config PANEL_V12_YLYM286A
tristate "lcd panel ylym286a"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel ylym286a with bridge lt9211, for ingenicfb drivers.
config PANEL_X2000_KD035HVFBD037
tristate "SLCD KD035HVFBD037 with control IC otm4802a (320x480)"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel KD035HVFBD037, for ingenicfb drivers.
config PANEL_BM8766
tristate "TFT BM8766 (800x480)"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel BM8766, for ingenicfb drivers.
config PANEL_TRULY240240
tristate "SLCD TRULY240240 (240x240)"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel TRULY240240, for ingenicfb drivers.
config PANEL_ST7789V240320
tristate "SLCD ST7789V240320 (240x320)"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel TRULY240240, for ingenicfb drivers.
config PANEL_EK79007
tristate "TFT EK79007 (1024x600)"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel EK79007, for ingenicfb drivers.
config PANEL_ST7703
tristate "TFT ST7703 (1280*720)"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel ST7703, for ingenicfb drivers.
config PANEL_ST7701SN
tristate "TFT ST7701SN (480*800)"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel ST7701SN, for ingenicfb drivers.
config PANEL_OTA7290B
tristate "TFT OTA7290B (1024*600 )"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel OTA7290B, for ingenicfb drivers.
config PANEL_ST7701S
tristate "TFT ST7701S"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel ST7701S, for ingenicfb drivers.
config PANEL_VX071FHP
tristate "TFT VX071FHP"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel VX071FHP, for ingenicfb drivers.
config PANEL_JD9852
tristate "TFT JD9852"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel VX071FHP, for ingenicfb drivers.
config PANEL_GC9503V
tristate "TFT GC9503V (480*800)"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel GC9503V, for ingenicfb drivers.
config PANEL_ST7701S_XIAOMI
tristate "TFT ST7701S XIAOMI"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel ST7701S, for ingenicfb drivers.
config PANEL_ST7102_XIAOMI
tristate "TFT ST7102 XIAOMI"
depends on FB_INGENIC_DISPLAYS_V12
help
lcd panel ST7102, for ingenicfb drivers.
3.Makefile添加该新驱动,路径:os/kernel/drivers/video/fbdev/ingenic/fb_v12/displays/Makefile
obj-$(CONFIG_PANEL_V12_Y88249) += panel-y88249.o
obj-$(CONFIG_PANEL_V12_KD050HDFIA019) += panel-kd050hdfia019.o
obj-$(CONFIG_PANEL_V12_MA0060) += panel-ma0060.o
obj-$(CONFIG_PANEL_V12_TL040WVS03CT) += panel-tl040wvs03ct.o
obj-$(CONFIG_PANEL_V12_TL040HDS01CT) += panel-tl040hds01ct.o
obj-$(CONFIG_PANEL_V12_JD9161Z) += panel-jd9161z.o
obj-$(CONFIG_PANEL_V12_ST7701S) += panel-st7701s.o
obj-$(CONFIG_PANEL_V12_YTS500XLAI) += panel-yts500xlai.o
obj-$(CONFIG_PANEL_V12_YLYM286A) += panel-ylym286a.o
obj-$(CONFIG_PANEL_X2000_KD035HVFBD037) += panel-kd035hvfbd037.o
obj-$(CONFIG_PANEL_BM8766) += panel-bm8766.o
obj-$(CONFIG_PANEL_TRULY240240) += panel-truly_240_240.o
obj-$(CONFIG_PANEL_ST7789V240320) += panel-st7789v_240_320.o
obj-$(CONFIG_PANEL_EK79007) += panel-ek79007.o
obj-$(CONFIG_PANEL_ST7703) += panel-st7703.o
obj-$(CONFIG_PANEL_ST7701SN) += panel-st7701sn.o
obj-$(CONFIG_PANEL_OTA7290B) += panel-ota7290b.o
obj-$(CONFIG_PANEL_ST7701S) += panel-st7701s.o
obj-$(CONFIG_PANEL_VX071FHP) += panel-vx071fhp.o
obj-$(CONFIG_PANEL_JD9852) += panel-jd9852.o
obj-$(CONFIG_PANEL_GC9503V) += panel-gc9503v.o
obj-$(CONFIG_PANEL_ST7701S_XIAOMI) += panel-st7701s-xiaomi.o
obj-$(CONFIG_PANEL_ST7102_XIAOMI) += panel-st7102-xiaomi.o
4.dts添加该驱动名字用于匹配,路径:os/kernel/arch/mips/boot/dts/ingenic/shark.dts
/dts-v1/;
#include <dt-bindings/input/input.h>
#include "t40.dtsi"
#include <dt-bindings/interrupt-controller/irq.h>
/ {
compatible = "ingenic,shark", "ingenic,t40";
mmc0_pwrseq: mmc0_pwrseq {
compatible = "mmc-pwrseq-simple";
reset-gpios = <&gpd 27 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
&uart0 {
status = "disable";
};
&uart1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart1_pb>;
};
&uart2 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart2_pb>;
};
&uart3 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart3_pc>;
};
&i2c0 {
pinctrl-0 = <&i2c0_pa>;
pinctrl-names = "default";
status = "okay";
};
&i2c1 {
pinctrl-0 = <&i2c1_pa>;
pinctrl-names = "default";
status = "okay";
};
&i2c2 {
pinctrl-0 = <&i2c2_pb>;
pinctrl-names = "default";
status = "disable";
};
&i2c3 {
pinctrl-0 = <&i2c3_pa>;
pinctrl-names = "default";
status = "okay";
};
&cpufreq {
status = "okay";
operating-points = <
/*KHZ uV */
1200000 900000
750000 900000
600000 900000
500000 900000
400000 900000
375000 900000
300000 900000
200000 900000
>;
};
//&pwm {
// ingenic,pwm-outputs = <0>; /* <0 - 15> select which pwms are really used */
//}
&pdma {
status = "okay";
};
&msc0 {
status = "disable";
pinctrl-names = "default";
/*mmc-hs200-1_8v;*/
cap-mmc-highspeed;
max-frequency = <50000000>;
bus-width = <4>;
voltage-ranges = <1800 3300>;
cd-inverted;
/* special property */
ingenic,wp-gpios = <0>;
ingenic,cd-gpios = <&gpd 25 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpios = <0>;
pinctrl-0 = <&msc0_pb>;
mmc-pwrseq = <&mmc0_pwrseq>;
};
&msc1 {
status = "okay";
pinctrl-names = "default";
/*mmc-hs200-1_8v;*/
cap-mmc-highspeed;
max-frequency = <50000000>;
bus-width = <4>;
voltage-ranges = <1800 3300>;
non-removable;
/* special property */
ingenic,wp-gpios = <0>;
ingenic,rst-gpios = <&gpc 22 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
pinctrl-0 = <&msc1_pc>;
};
&mac0 {
pinctrl-names = "default", "reset";
pinctrl-0 = <&mac0_rmii_p0_normal>, <&mac0_rmii_p1_normal>;
pinctrl-1 = <&mac0_rmii_p0_rst>, <&mac0_rmii_p1_normal>;
status = "okay";
ingenic,rst-gpio = <&gpb 12 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
ingenic,mac-rst-gpio = <&gpb 30 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
ingenic,rst-ms = <10>;
ingenic,mac-mode = <RMII>;
ingenic,mode-reg = <0xb00000e4>;
ingenic,phy-clk-freq = <50000000>;
};
&sfc {
status = "okay";
pinctrl-names = "default";
ingenic,sfc-max-frequency = <400000000>;
ingenic,use_board_info = /bits/ 8 <0>;
ingenic,spiflash_param_offset = <0>;
pinctrl-0 = <&sfc_pa>;
};
&spi0 {
status = "disable";
pinctrl-names = "default";
pinctrl-0 = <&spi0_pc>;
spi-max-frequency = <60000000>;
num-cs = <2>;
cs-gpios = <0>, <0>;
ingenic,chnl = <0>;
ingenic,allow_cs_same = <1>;
ingenic,bus_num = <0>;
ingenic,has_dma_support = <1>;
};
&spi1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&spi1_pc>;
spi-max-frequency = <50000000>;
num-cs = <2>;
cs-gpios = <0>, <0>;
// cs-gpios = <&gpc 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>, <&gpc 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,chnl = <0>;
ingenic,allow_cs_same = <1>;
ingenic,bus_num = <1>;
ingenic,has_dma_support = <1>;
// ingenic,spi-src-clk = <1>;
z7682inf: z7682inf@0 {
compatible = "z7682inf";
reg = <0>;
spi-max-frequency = <25000000>;
};
};
&dtrng {
status = "okay";
};
&otg {
g-use-dma;
dr_mode = "otg";
status = "okay";
};
&otg_phy {
dr_mode = "otg";
compatible = "ingenic,innophy", "syscon";
ingenic,drvvbus-gpio = <&gpb 27 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
status = "okay";
};
/ {
extclk: extclk {
clock-frequency = <24000000>;
};
gpio_keys: gpio_keys {
compatible = "gpio-keys";
power {
label = "Power";
linux,code = <KEY_POWER>;
gpios = <&gpa 31 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
gpio-key,wakeup;
};
bootsel0 {
label = "bootsel0";
linux,code = <KEY_HOME>;
gpios = <&gpc 0 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
};
bootsel1 {
label = "bootsel1";
linux,code = <KEY_BACK>;
gpios = <&gpc 1 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
};
};
};
&el150 {
status = "disable";
};
&dpu {
status = "okay";
};
/ {
display-dpi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_bm8766@0 {
compatible = "ingenic,bm8766";
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&tft_lcd_pd>;
ingenic,bl-gpio = <&gpa 15 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpa 16 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dbi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_truly240240@0 {
compatible = "ingenic,truly240240";
status = "disable";
pinctrl-names = "default";
pinctrl-0 = <&smart_lcd_pd>;
/*ingenic,rst-gpio = <&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;*/
ingenic,rst-gpio = <&gpd 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rd-gpio = <&gpd 12 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,cs-gpio = <&gpd 10 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dbi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_st7789v240320@0 {
compatible = "ingenic,st7789v240320";
status = "disable";
pinctrl-names = "default";
pinctrl-0 = <&smart_lcd_pd>;
/*ingenic,rst-gpio = <&gpc 7 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;*/
ingenic,rst-gpio = <&gpd 9 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rd-gpio = <&gpd 12 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,cs-gpio = <&gpd 10 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,bl-gpio = <&gpd 27 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_EK79007@0 {
compatible = "ingenic,ek79007";
status = "disable";
#pinctrl-names = "default";
#pinctrl-0 = <&tft_lcd_pd>;
ingenic,bl-gpio = <&gpd 26 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
//ingenic,rst-gpio = <&gpd 17 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_ST7701S@0 {
compatible = "ingenic,st7701s";
ingenic,vdd-en-gpio = <&gpc 26 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,lcd-pwd-gpio = <&gpc 28 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,lcd-te-gpio = <&gpc 23 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpc 22 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
status = "okay";
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_OTA7290B@0 {
compatible = "ingenic,ota7290b";
ingenic,bl-gpio = <&gpc 03 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpd 15 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
status = "okay";
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_ST7703@0 {
compatible = "ingenic,vx071fhp";
status = "okay";
#pinctrl-names = "default";
#pinctrl-0 = <&tft_lcd_pd>;
ingenic,bl-gpio = <&gpa 15 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpa 16 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_JD9852@0 {
compatible = "ingenic,jd9852";
status = "okay";
#pinctrl-names = "default";
#pinctrl-0 = <&tft_lcd_pd>;
ingenic,bl-gpio = <&gpc 28 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpa 16 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_ST7703@0 {
compatible = "ingenic,st7703";
status = "okay";
#pinctrl-names = "default";
#pinctrl-0 = <&tft_lcd_pd>;
ingenic,bl-gpio = <&gpa 15 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpa 16 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_ST7701SN@0 {
compatible = "ingenic,st7701sn";
status = "okay";
#pinctrl-names = "default";
#pinctrl-0 = <&tft_lcd_pd>;
ingenic,bl-gpio = <&gpc 6 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpa 16 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_GC9503V@0 {
compatible = "ingenic,gc9503v";
status = "okay";
#pinctrl-names = "default";
#pinctrl-0 = <&tft_lcd_pd>;
#ingenic,bl-gpio = <&gpd 26 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpb 8 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_ST7701SG2@0 {
compatible = "ingenic,st7701s_xiaomi";
status = "okay";
#pinctrl-names = "default";
#pinctrl-0 = <&tft_lcd_pd>;
#ingenic,bl-gpio = <&gpd 26 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpb 8 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
/ {
display-dsi {
compatible = "simple-bus";
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <>;
panel_ST7102@0 {
compatible = "ingenic,st7102_xiaomi";
status = "okay";
#pinctrl-names = "default";
#pinctrl-0 = <&tft_lcd_pd>;
#ingenic,bl-gpio = <&gpd 26 GPIO_ACTIVE_HIGH INGENIC_GPIO_NOBIAS>;
ingenic,rst-gpio = <&gpb 8 GPIO_ACTIVE_LOW INGENIC_GPIO_NOBIAS>;
};
};
};
5.mipi_dsi加入该时钟选择(jz_mipi_dsi.c)就在displays下面的jz_mipi_dsi目录下
路径:os/kernel/drivers/video/fbdev/ingenic/fb_v12/jz_mipi_dsi/jz_mipi_dsi.c
参照st7701s写
/*
* Ingenic SoC MIPI-DSI dsim driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/ctype.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/memory.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kthread.h>
#include <linux/notifier.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
#include <linux/gpio.h>
#include "../ingenicfb.h"
#include "../jz_dsim.h"
#include "jz_mipi_dsi_lowlevel.h"
#include "jz_mipi_dsih_hal.h"
#include "jz_mipi_dsi_regs.h"
extern struct jzfb_platform_data jzfb_platform_data;
#define jzfb_pdata jzfb_platform_data
#define DSI_IOBASE 0xb0003000
#define DSI_PHY_IOBASE 0xb0004000
/*64*/
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 DEFINE_MUTEX(mipi_dsim_lock);
void dump_dsi_reg(struct dsi_device *dsi);
static DEFINE_MUTEX(dsi_lock);
int jz_dsi_video_cfg(struct dsi_device *dsi)
{
dsih_error_t err_code = OK;
unsigned short bytes_per_pixel_x100 = 0; /* bpp x 100 because it can be 2.25 */
unsigned short video_size = 0;
unsigned int ratio_clock_xPF = 0; /* holds dpi clock/byte clock times precision factor */
unsigned short null_packet_size = 0;
unsigned char video_size_step = 1;
unsigned int total_bytes = 0;
unsigned int bytes_per_chunk = 0;
unsigned int no_of_chunks = 0;
unsigned int bytes_left = 0;
unsigned int chunk_overhead = 0;
struct video_config *video_config;
video_config = dsi->video_config;
/* check DSI controller dsi */
if ((dsi == NULL) || (video_config == NULL)) {
return ERR_DSI_INVALID_INSTANCE;
}
#if 1
if(dsi->state == UBOOT_INITIALIZED) {
/*no need to reconfig, just return*/
printk("dsi has already been initialized by uboot!!\n");
return OK;
}
#endif
if (dsi->state != INITIALIZED) {
return ERR_DSI_INVALID_INSTANCE;
}
ratio_clock_xPF = video_config->byte_clock * PRECISION_FACTOR;
if(video_config->refresh <= 10)
ratio_clock_xPF *= 15;
else if(video_config->refresh <= 15)
ratio_clock_xPF *= 11;
else if(video_config->refresh <= 20)
ratio_clock_xPF *= 8;
else if(video_config->refresh <= 25)
ratio_clock_xPF *= 6;
else if(video_config->refresh <= 30)
ratio_clock_xPF *= 5;
else if(video_config->refresh <= 50)
ratio_clock_xPF *= 4;
else if(video_config->refresh <= 60)
ratio_clock_xPF *= 3;
else if(video_config->refresh <= 120)
ratio_clock_xPF *= 2;
ratio_clock_xPF /= video_config->pixel_clock;
#ifdef CONFIG_PANEL_JD9852
ratio_clock_xPF = 14000;
#endif
#ifdef CONFIG_PANEL_VX071FHP
ratio_clock_xPF = 900;
#endif
#if (defined(CONFIG_PANEL_ST7701S_XIAOMI_MODULE)||defined(CONFIG_PANEL_ST7701S_XIAOMI)||defined(CONFIG_PANEL_ST7102_XIAOMI_MODULE)||defined(CONFIG_PANEL_ST7102_XIAOMI))
ratio_clock_xPF = 2400;
#endif
printk("####################### ratio_clock_xPF=%d\n",ratio_clock_xPF);
video_size = video_config->h_active_pixels;
/* disable set up ACKs and error reporting */
mipi_dsih_hal_dpi_frame_ack_en(dsi, video_config->receive_ack_packets);
if (video_config->receive_ack_packets) { /* if ACK is requested, enable BTA, otherwise leave as is */
mipi_dsih_hal_bta_en(dsi, 1);
}
/*0:switch to high speed transfer, 1 low power mode */
mipi_dsih_write_word(dsi, R_DSI_HOST_CMD_MODE_CFG, 0);
/*0:enable video mode, 1:enable cmd mode */
mipi_dsih_hal_gen_set_mode(dsi, 0);
err_code =
jz_dsi_video_coding(dsi, &bytes_per_pixel_x100, &video_size_step,
&video_size);
if (err_code) {
return err_code;
}
jz_dsi_dpi_cfg(dsi, &ratio_clock_xPF, &bytes_per_pixel_x100);
/* TX_ESC_CLOCK_DIV must be less than 20000KHz */
jz_dsih_hal_tx_escape_division(dsi, TX_ESC_CLK_DIV);
/* video packetisation */
if (video_config->video_mode == VIDEO_BURST_WITH_SYNC_PULSES) { /* BURST */
//mipi_dsih_hal_dpi_null_packet_en(dsi, 0);
mipi_dsih_hal_dpi_null_packet_size(dsi, 0);
//mipi_dsih_hal_dpi_multi_packet_en(dsi, 0);
err_code =
err_code ? err_code : mipi_dsih_hal_dpi_chunks_no(dsi, 1);
err_code =
err_code ? err_code :
mipi_dsih_hal_dpi_video_packet_size(dsi, video_size);
if (err_code != OK) {
return err_code;
}
/* BURST by default, returns to LP during ALL empty periods - energy saving */
mipi_dsih_hal_dpi_lp_during_hfp(dsi, 1);
mipi_dsih_hal_dpi_lp_during_hbp(dsi, 1);
mipi_dsih_hal_dpi_lp_during_vactive(dsi, 1);
mipi_dsih_hal_dpi_lp_during_vfp(dsi, 1);
mipi_dsih_hal_dpi_lp_during_vbp(dsi, 1);
mipi_dsih_hal_dpi_lp_during_vsync(dsi, 1);
#ifdef CONFIG_DSI_DPI_DEBUG
/* D E B U G */
{
pr_info("burst video");
pr_info("h line time %d ,",
(unsigned
short)((video_config->h_total_pixels *
ratio_clock_xPF) / PRECISION_FACTOR));
pr_info("video_size %d ,", video_size);
}
#endif
} else { /* non burst transmission */
null_packet_size = 0;
/* bytes to be sent - first as one chunk */
bytes_per_chunk =
(bytes_per_pixel_x100 * video_config->h_active_pixels) /
100 + VIDEO_PACKET_OVERHEAD;
/* bytes being received through the DPI interface per byte clock cycle */
total_bytes =
(ratio_clock_xPF * video_config->no_of_lanes *
(video_config->h_total_pixels -
video_config->h_back_porch_pixels -
video_config->h_sync_pixels)) / PRECISION_FACTOR;
pr_debug("---->total_bytes:%d, bytes_per_chunk:%d\n", total_bytes,
bytes_per_chunk);
/* check if the in pixels actually fit on the DSI link */
if (total_bytes >= bytes_per_chunk) {
chunk_overhead = total_bytes - bytes_per_chunk;
/* overhead higher than 1 -> enable multi packets */
if (chunk_overhead > 1) {
for (video_size = video_size_step; video_size < video_config->h_active_pixels; video_size += video_size_step) { /* determine no of chunks */
if ((((video_config->h_active_pixels *
PRECISION_FACTOR) / video_size) %
PRECISION_FACTOR) == 0) {
no_of_chunks =
video_config->
h_active_pixels /
video_size;
bytes_per_chunk =
(bytes_per_pixel_x100 *
video_size) / 100 +
VIDEO_PACKET_OVERHEAD;
if (total_bytes >=
(bytes_per_chunk *
no_of_chunks)) {
bytes_left =
total_bytes -
(bytes_per_chunk *
no_of_chunks);
break;
}
}
}
/* prevent overflow (unsigned - unsigned) */
if (bytes_left >
(NULL_PACKET_OVERHEAD * no_of_chunks)) {
null_packet_size =
(bytes_left -
(NULL_PACKET_OVERHEAD *
no_of_chunks)) / no_of_chunks;
if (null_packet_size > MAX_NULL_SIZE) { /* avoid register overflow */
null_packet_size =
MAX_NULL_SIZE;
}
}
} else { /* no multi packets */
no_of_chunks = 1;
#ifdef CONFIG_DSI_DPI_DEBUG
/* D E B U G */
{
pr_info("no multi no null video");
pr_info("h line time %d",
(unsigned
short)((video_config->
h_total_pixels *
ratio_clock_xPF) /
PRECISION_FACTOR));
pr_info("video_size %d", video_size);
}
#endif
/* video size must be a multiple of 4 when not 18 loosely */
for (video_size = video_config->h_active_pixels;
(video_size % video_size_step) != 0;
video_size++) {
;
}
}
} else {
pr_err
("resolution cannot be sent to display through current settings");
err_code = ERR_DSI_OVERFLOW;
}
}
err_code =
err_code ? err_code : mipi_dsih_hal_dpi_chunks_no(dsi,
no_of_chunks);
err_code =
err_code ? err_code : mipi_dsih_hal_dpi_video_packet_size(dsi,
video_size);
err_code =
err_code ? err_code : mipi_dsih_hal_dpi_null_packet_size(dsi,
null_packet_size);
// mipi_dsih_hal_dpi_null_packet_en(dsi, null_packet_size > 0? 1: 0);
// mipi_dsih_hal_dpi_multi_packet_en(dsi, (no_of_chunks > 1)? 1: 0);
#ifdef CONFIG_DSI_DPI_DEBUG
/* D E B U G */
{
pr_info("total_bytes %d ,", total_bytes);
pr_info("bytes_per_chunk %d ,", bytes_per_chunk);
pr_info("bytes left %d ,", bytes_left);
pr_info("null packets %d ,", null_packet_size);
pr_info("chunks %d ,", no_of_chunks);
pr_info("video_size %d ", video_size);
}
#endif
mipi_dsih_hal_dpi_video_vc(dsi, video_config->virtual_channel);
jz_dsih_dphy_no_of_lanes(dsi, video_config->no_of_lanes);
/* enable high speed clock */
mipi_dsih_dphy_enable_hs_clk(dsi, 1);
pr_debug("video configure is ok!\n");
return err_code;
}
/* set all register settings to MIPI DSI controller. */
dsih_error_t jz_dsi_phy_cfg(struct dsi_device * dsi)
{
dsih_error_t err = OK;
err = jz_dsi_set_clock(dsi);
if (err) {
return err;
}
err = jz_init_dsi(dsi);
if (err) {
return err;
}
return OK;
}
int jz_dsi_phy_open(struct dsi_device *dsi)
{
struct video_config *video_config;
video_config = dsi->video_config;
pr_debug("entry %s()\n", __func__);
jz_dsih_dphy_reset(dsi, 0);
jz_dsih_dphy_stop_wait_time(dsi, 0x1c); /* 0x1c: */
if (video_config->no_of_lanes > 4 || video_config->no_of_lanes < 1)
return ERR_DSI_OUT_OF_BOUND;
jz_dsih_dphy_no_of_lanes(dsi, video_config->no_of_lanes);
jz_dsih_dphy_clock_en(dsi, 1);
jz_dsih_dphy_shutdown(dsi, 1);
jz_dsih_dphy_reset(dsi, 1);
dsi->dsi_phy->status = INITIALIZED;
return OK;
}
void dump_dsi_reg(struct dsi_device *dsi)
{
pr_info("dsi->dev: ===========>dump dsi reg\n");
pr_info("dsi->dev: VERSION------------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VERSION));
pr_info("dsi->dev: PWR_UP:------------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PWR_UP));
pr_info("dsi->dev: CLKMGR_CFG---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_CLKMGR_CFG));
pr_info("dsi->dev: DPI_VCID-----------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_VCID));
pr_info("dsi->dev: DPI_COLOR_CODING---:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_COLOR_CODING));
pr_info("dsi->dev: DPI_CFG_POL--------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_CFG_POL));
pr_info("dsi->dev: DPI_LP_CMD_TIM-----:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_LP_CMD_TIM));
pr_info("dsi->dev: DBI_VCID-----------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DBI_VCID));
pr_info("dsi->dev: DBI_CFG------------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DBI_CFG));
pr_info("dsi->dev: DBI_PARTITIONING_EN:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DBI_PARTITIONING_EN));
pr_info("dsi->dev: DBI_CMDSIZE--------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DBI_CMDSIZE));
pr_info("dsi->dev: PCKHDL_CFG---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PCKHDL_CFG));
pr_info("dsi->dev: GEN_VCID-----------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_GEN_VCID));
pr_info("dsi->dev: MODE_CFG-----------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_MODE_CFG));
pr_info("dsi->dev: VID_MODE_CFG-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_MODE_CFG));
pr_info("dsi->dev: VID_PKT_SIZE-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_PKT_SIZE));
pr_info("dsi->dev: VID_NUM_CHUNKS-----:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_NUM_CHUNKS));
pr_info("dsi->dev: VID_NULL_SIZE------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_NULL_SIZE));
pr_info("dsi->dev: VID_HSA_TIME-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HSA_TIME));
pr_info("dsi->dev: VID_HBP_TIME-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HBP_TIME));
pr_info("dsi->dev: VID_HLINE_TIME-----:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HLINE_TIME));
pr_info("dsi->dev: VID_VSA_LINES------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VSA_LINES));
pr_info("dsi->dev: VID_VBP_LINES------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VBP_LINES));
pr_info("dsi->dev: VID_VFP_LINES------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VFP_LINES));
pr_info("dsi->dev: VID_VACTIVE_LINES--:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VACTIVE_LINES));
pr_info("dsi->dev: EDPI_CMD_SIZE------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_EDPI_CMD_SIZE));
pr_info("dsi->dev: CMD_MODE_CFG-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_CMD_MODE_CFG));
pr_info("dsi->dev: GEN_HDR------------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_GEN_HDR));
pr_info("dsi->dev: GEN_PLD_DATA-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_GEN_PLD_DATA));
pr_info("dsi->dev: CMD_PKT_STATUS-----:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_CMD_PKT_STATUS));
pr_info("dsi->dev: TO_CNT_CFG---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_TO_CNT_CFG));
pr_info("dsi->dev: HS_RD_TO_CNT-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_HS_RD_TO_CNT));
pr_info("dsi->dev: LP_RD_TO_CNT-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_LP_RD_TO_CNT));
pr_info("dsi->dev: HS_WR_TO_CNT-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_HS_WR_TO_CNT));
pr_info("dsi->dev: LP_WR_TO_CNT_CFG---:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_LP_WR_TO_CNT));
pr_info("dsi->dev: BTA_TO_CNT---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_BTA_TO_CNT));
pr_info("dsi->dev: SDF_3D-------------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_SDF_3D));
pr_info("dsi->dev: LPCLK_CTRL---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_LPCLK_CTRL));
pr_info("dsi->dev: PHY_TMR_LPCLK_CFG--:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TMR_LPCLK_CFG));
pr_info("dsi->dev: PHY_TMR_CFG--------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TMR_CFG));
pr_info("dsi->dev: PHY_RSTZ-----------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_RSTZ));
pr_info("dsi->dev: PHY_IF_CFG---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_IF_CFG));
pr_info("dsi->dev: PHY_ULPS_CTRL------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_ULPS_CTRL));
pr_info("dsi->dev: PHY_TX_TRIGGERS----:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TX_TRIGGERS));
pr_info("dsi->dev: PHY_STATUS---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_STATUS));
pr_info("dsi->dev: PHY_TST_CTRL0------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TST_CTRL0));
pr_info("dsi->dev: PHY_TST_CTRL1------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_TST_CTRL1));
pr_info("dsi->dev: INT_ST0------------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_INT_ST0));
pr_info("dsi->dev: INT_ST1------------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_INT_ST1));
pr_info("dsi->dev: INT_MSK0-----------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_INT_MSK0));
pr_info("dsi->dev: INT_MSK1-----------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_INT_MSK1));
pr_info("dsi->dev: INT_FORCE0---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_INT_FORCE0));
pr_info("dsi->dev: INT_FORCE1---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_INT_FORCE1));
pr_info("dsi->dev: VID_SHADOW_CTRL----:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_SHADOW_CTRL));
pr_info("dsi->dev: DPI_VCID_ACT-------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_VCID_ACT));
pr_info("dsi->dev: DPI_COLOR_CODING_AC:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_COLOR_CODING_ACT));
pr_info("dsi->dev: DPI_LP_CMD_TIM_ACT-:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_DPI_LP_CMD_TIM_ACT));
pr_info("dsi->dev: VID_MODE_CFG_ACT---:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_MODE_CFG_ACT));
pr_info("dsi->dev: VID_PKT_SIZE_ACT---:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_PKT_SIZE_ACT));
pr_info("dsi->dev: VID_NUM_CHUNKS_ACT-:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_NUM_CHUNKS_ACT));
pr_info("dsi->dev: VID_HSA_TIME_ACT---:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HSA_TIME_ACT));
pr_info("dsi->dev: VID_HBP_TIME_ACT---:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HBP_TIME_ACT));
pr_info("dsi->dev: VID_HLINE_TIME_ACT-:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_HLINE_TIME_ACT));
pr_info("dsi->dev: VID_VSA_LINES_ACT--:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VSA_LINES_ACT));
pr_info("dsi->dev: VID_VBP_LINES_ACT--:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VBP_LINES_ACT));
pr_info("dsi->dev: VID_VFP_LINES_ACT--:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VFP_LINES_ACT));
pr_info("dsi->dev: VID_VACTIVE_LINES_ACT:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_VID_VACTIVE_LINES_ACT));
pr_info("dsi->dev: SDF_3D_ACT---------:%08x\n",
mipi_dsih_read_word(dsi, R_DSI_HOST_SDF_3D_ACT));
}
void set_base_dir_tx(struct dsi_device *dsi, void *param)
{
int i = 0;
register_config_t phy_direction[] = {
{0xb4, 0x02},
{0xb8, 0xb0},
{0xb8, 0x100b0},
{0xb4, 0x00},
{0xb8, 0x000b0},
{0xb8, 0x0000},
{0xb4, 0x02},
{0xb4, 0x00}
};
i = mipi_dsih_write_register_configuration(dsi, phy_direction,
(sizeof(phy_direction) /
sizeof(register_config_t)));
if (i != (sizeof(phy_direction) / sizeof(register_config_t))) {
pr_err("ERROR setting up testchip %d", i);
}
}
static void init_dsi_phy(struct dsi_device *dsi)
{
unsigned int temp = 0xffffffff;
printk("dsi phy address = 0x%x\n", dsi->phy_address);
//power on ,reset, set pin_enable_ck/0/1/* of lanes to be used to high level and others to low
printk("%s,%d step0 do nothing now.\n", __func__, __LINE__);
//step1
temp = *(volatile unsigned int*)(dsi->phy_address+0x0C);
temp &= ~0xff;
#ifdef CONFIG_PANEL_VX071FHP
temp |= 0x01;
#else
temp |= 0x02;
#endif
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x0C));
if ((*(volatile unsigned int*)(dsi->phy_address+0x0C) & 0xff) != 0x02) {
printk("%s,%d reg write error. Step1\n", __func__, __LINE__);
}
printk("reg:0x03, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x0C));
//step2
temp = *(volatile unsigned int*)(dsi->phy_address+0x10);
temp &= ~0xff;
#if defined(CONFIG_PANEL_VX071FHP)
temp |= 0x8c;
#elif (defined(CONFIG_PANEL_ST7701S_XIAOMI_MODULE) || defined(CONFIG_PANEL_ST7701S_XIAOMI)||defined(CONFIG_PANEL_ST7102_XIAOMI_MODULE)||defined(CONFIG_PANEL_ST7102_XIAOMI))
#if 1 // 60fps
temp |= 0x96;
#else // 30fps
temp |= 0x50;
#endif
#else
temp |= 0xff;
#endif
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x10));
if ((*(volatile unsigned int*)(dsi->phy_address+0x10) & 0xff) != 0x53) {
printk("%s,%d reg write error. Step2\n", __func__, __LINE__);
}
printk("reg:0x04, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x10));
//step3
temp = *(volatile unsigned int*)(dsi->phy_address+0x04);
temp &= ~0xff;
temp |= 0xe4;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x04));
if ((*(volatile unsigned int*)(dsi->phy_address+0x04) & 0xff) != 0xe4) {
printk("%s,%d reg write error. Step3\n", __func__, __LINE__);
}
printk("reg:0x01, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x04));
//step4
if (dsi->video_config->no_of_lanes == 4) {
temp = *(volatile unsigned int*)(dsi->phy_address+0x00);
temp &= ~0xff;
temp |= 0x7d; //4lane
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x00));
if ((*(volatile unsigned int*)(dsi->phy_address+0x00) & 0xff) != 0x7d) {
printk("%s,%d reg write error. Step4\n", __func__, __LINE__);
}
}
else if (dsi->video_config->no_of_lanes == 2){
temp = *(volatile unsigned int*)(dsi->phy_address+0x00);
temp &= ~0xff;
temp |= 0x4d; //2lane
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x00));
if ((*(volatile unsigned int*)(dsi->phy_address+0x00) & 0xff) != 0x4d) {
printk("%s,%d reg write error. Step4\n", __func__, __LINE__);
}
}
else if (dsi->video_config->no_of_lanes == 1){
temp = *(volatile unsigned int*)(dsi->phy_address+0x00);
temp &= ~0xff;
temp |= 0x45; //1lane
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x00));
if ((*(volatile unsigned int*)(dsi->phy_address+0x00) & 0xff) != 0x45) {
printk("%s,%d reg write error. Step4\n", __func__, __LINE__);
}
}
printk("reg:0x00, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x00));
//step5
temp = *(volatile unsigned int*)(dsi->phy_address+0x04);
temp &= ~0xff;
temp |= 0xe0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x04));
if ((*(volatile unsigned int*)(dsi->phy_address+0x04) & 0xff) != 0xe0) {
printk("%s,%d reg write error. Step5\n", __func__, __LINE__);
}
printk("reg:0x01, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x04));
//step6
msleep(20); //at lease 20ms, shortening need validation
//step7
// temp = *(volatile unsigned int*)(dsi->phy_address+0x80);
// temp &= ~0xff;
// temp |= 0x1e;
// writel(temp, (volatile unsigned int*)(dsi->phy_address+0x80));
// if ((*(volatile unsigned int*)(dsi->phy_address+0x80) & 0xff) != 0x1e) {
// printk("%s,%d reg write error. Step7\n", __func__, __LINE__);
// }
// printk("reg:0x20, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x80));
//step8
temp = *(volatile unsigned int*)(dsi->phy_address+0x80);
temp &= ~0xff;
temp |= 0x1f;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x80));
if ((*(volatile unsigned int*)(dsi->phy_address+0x80) & 0xff) != 0x1f) {
printk("%s,%d reg write error. Step8\n", __func__, __LINE__);
}
printk("reg:0x20, value:0x%x\n", *(volatile unsigned int*)(dsi->phy_address+0x80));
//step9
msleep(10);
#if (defined(CONFIG_PANEL_ST7701S_XIAOMI) || defined(CONFIG_PANEL_ST7701S_XIAOMI_MODULE)||defined(CONFIG_PANEL_ST7102_XIAOMI_MODULE)||defined(CONFIG_PANEL_ST7102_XIAOMI))
#if 1 // 60fps
temp = *(volatile unsigned int*)(dsi->phy_address+0x018);
temp &= 0xfffffff0;
temp |= 0x8;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x018));
temp = *(volatile unsigned int*)(dsi->phy_address+0x020);
temp &= 0xfffffff0;
temp |= 0x8;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x020));
temp = *(volatile unsigned int*)(dsi->phy_address+0x02c);
temp &= 0xfffffff0;
temp |= 0x8;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x02c));
//LPX
temp = *(volatile unsigned int*)(dsi->phy_address+0x114);
temp &= ~0xff;
temp |= 0x3;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x114));
temp = *(volatile unsigned int*)(dsi->phy_address+0x194);
temp &= ~0xff;
temp |= 0x3;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x194));
temp = *(volatile unsigned int*)(dsi->phy_address+0x214);
temp &= ~0xff;
temp |= 0x3;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x214));
//THS-PREPARE
temp = *(volatile unsigned int*)(dsi->phy_address+0x118);
temp &= ~0xff;
temp |= 0x7c;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x118));
temp = *(volatile unsigned int*)(dsi->phy_address+0x198);
temp &= ~0xff;
temp |= 0x7c;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x198));
temp = *(volatile unsigned int*)(dsi->phy_address+0x218);
temp &= ~0xff;
temp |= 0x7c;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x218));
//THS-ZERO
temp = *(volatile unsigned int*)(dsi->phy_address+0x11c);
temp &= ~0xff;
temp |= 0x1b;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x11c));
temp = *(volatile unsigned int*)(dsi->phy_address+0x19c);
temp &= ~0xff;
temp |= 0x7;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x19c));
temp = *(volatile unsigned int*)(dsi->phy_address+0x21c);
temp &= ~0xff;
temp |= 0x7;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x21c));
//THS-TRAIL
temp = *(volatile unsigned int*)(dsi->phy_address+0x120);
temp &= ~0xff;
temp |= 0x8;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x120));
temp = *(volatile unsigned int*)(dsi->phy_address+0x1a0);
temp &= ~0xff;
temp |= 0x8;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x1a0));
temp = *(volatile unsigned int*)(dsi->phy_address+0x220);
temp &= ~0xff;
temp |= 0x8;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x220));
//THS-EXIT reg09
temp = *(volatile unsigned int*)(dsi->phy_address+0x124);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x124));
temp = *(volatile unsigned int*)(dsi->phy_address+0x1a4);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x1a4));
temp = *(volatile unsigned int*)(dsi->phy_address+0x224);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x224));
//THS-EXIT reg11
temp = *(volatile unsigned int*)(dsi->phy_address+0x144);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x144));
temp = *(volatile unsigned int*)(dsi->phy_address+0x1c4);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x1c4));
temp = *(volatile unsigned int*)(dsi->phy_address+0x244);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x244));
#else //30fps
//LPX
temp = *(volatile unsigned int*)(dsi->phy_address+0x114);
temp &= ~0xff;
temp |= 0x2;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x114));
temp = *(volatile unsigned int*)(dsi->phy_address+0x194);
temp &= ~0xff;
temp |= 0x2;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x194));
temp = *(volatile unsigned int*)(dsi->phy_address+0x214);
temp &= ~0xff;
temp |= 0x2;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x214));
//THS-PREPARE
temp = *(volatile unsigned int*)(dsi->phy_address+0x118);
temp &= ~0xff;
temp |= 0x7f;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x118));
temp = *(volatile unsigned int*)(dsi->phy_address+0x198);
temp &= ~0xff;
temp |= 0x7f;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x198));
temp = *(volatile unsigned int*)(dsi->phy_address+0x218);
temp &= ~0xff;
temp |= 0x7f;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x218));
//THS-ZERO
temp = *(volatile unsigned int*)(dsi->phy_address+0x11c);
temp &= ~0xff;
temp |= 0x17;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x11c));
temp = *(volatile unsigned int*)(dsi->phy_address+0x19c);
temp &= ~0xff;
temp |= 0x5;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x19c));
temp = *(volatile unsigned int*)(dsi->phy_address+0x21c);
temp &= ~0xff;
temp |= 0x5;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x21c));
//THS-TRAIL
temp = *(volatile unsigned int*)(dsi->phy_address+0x120);
temp &= ~0xff;
temp |= 0x4;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x120));
temp = *(volatile unsigned int*)(dsi->phy_address+0x1a0);
temp &= ~0xff;
temp |= 0x4;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x1a0));
temp = *(volatile unsigned int*)(dsi->phy_address+0x220);
temp &= ~0xff;
temp |= 0x4;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x220));
//THS-EXIT reg09
temp = *(volatile unsigned int*)(dsi->phy_address+0x124);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x124));
temp = *(volatile unsigned int*)(dsi->phy_address+0x1a4);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x1a4));
temp = *(volatile unsigned int*)(dsi->phy_address+0x224);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x224));
//THS-EXIT reg11
temp = *(volatile unsigned int*)(dsi->phy_address+0x144);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x144));
temp = *(volatile unsigned int*)(dsi->phy_address+0x1c4);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x1c4));
temp = *(volatile unsigned int*)(dsi->phy_address+0x244);
temp &= ~0xff;
temp |= 0x0;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x244));
#endif
#endif
#ifdef CONFIG_PANEL_OTA7290B /*Add this to adjust HS prepare time*/
//step10
temp = *(volatile unsigned int*)(dsi->phy_address+0x118);
temp &= ~0xff;
temp |= 0x40;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x118));
if ((*(volatile unsigned int*)(dsi->phy_address+0x118) & 0xff) != 0x40) {
printk("%s,%d reg write error. Step10\n", __func__, __LINE__);
}
//step11
temp = *(volatile unsigned int*)(dsi->phy_address+0x198);
temp &= ~0xff;
temp |= 0x40;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x198));
if ((*(volatile unsigned int*)(dsi->phy_address+0x198) & 0xff) != 0x40) {
pr_err("%s,%d reg write error. Step11\n", __func__, __LINE__);
}
//step12
temp = *(volatile unsigned int*)(dsi->phy_address+0x218);
temp &= ~0xff;
temp |= 0x40;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x218));
if ((*(volatile unsigned int*)(dsi->phy_address+0x218) & 0xff) != 0x40) {
pr_err("%s,%d reg write error. Step12\n", __func__, __LINE__);
}
//step13
temp = *(volatile unsigned int*)(dsi->phy_address+0x298);
temp &= ~0xff;
temp |= 0x40;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x298));
if ((*(volatile unsigned int*)(dsi->phy_address+0x298) & 0xff) != 0x40) {
pr_err("%s,%d reg write error. Step13\n", __func__, __LINE__);
}
//step14
temp = *(volatile unsigned int*)(dsi->phy_address+0x1318);
temp &= ~0xff;
temp |= 0x40;
writel(temp, (volatile unsigned int*)(dsi->phy_address+0x318));
if ((*(volatile unsigned int*)(dsi->phy_address+0x318) & 0xff) != 0x40) {
pr_err("%s,%d reg write error. Step14\n", __func__, __LINE__);
}
#endif
printk("%s,%d dsi phy init over now...\n", __func__, __LINE__);
}
static int jz_mipi_update_cfg(struct dsi_device *dsi)
{
int ret;
int st_mask = 0;
int retry = 5;
ret = jz_dsi_phy_open(dsi);
if (ret) {
pr_err("open the phy failed!\n");
return ret;
}
mipi_dsih_write_word(dsi, R_DSI_HOST_CMD_MODE_CFG,
0xffffff0);
/*set command mode */
mipi_dsih_write_word(dsi, R_DSI_HOST_MODE_CFG, 0x1);
/*set this register for cmd size, default 0x6 */
mipi_dsih_write_word(dsi, R_DSI_HOST_EDPI_CMD_SIZE, 0x6);
/*
* jz_dsi_phy_cfg:
* PLL programming, config the output freq to DEFAULT_DATALANE_BPS.
* */
init_dsi_phy(dsi);
ret = jz_dsi_phy_cfg(dsi);
if (ret) {
pr_err("phy configigure failed!\n");
return ret;
}
pr_debug("wait for phy config ready\n");
if (dsi->video_config->no_of_lanes == 2)
st_mask = 0x95;
else
st_mask = 0x15;
/*checkout phy clk lock and clklane, datalane stopstate */
udelay(10);
while ((mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_STATUS) & st_mask) !=
st_mask && retry--) {
pr_info("phy status = %08x\n", mipi_dsih_read_word(dsi, R_DSI_HOST_PHY_STATUS));
}
if (!retry){
pr_err("wait for phy config failed!\n");
return ret;
}
dsi->state = INITIALIZED;
return 0;
}
/* for debug lcd power on/off */
int jz_mipi_dsi_set_client(struct dsi_device *dsi, int power)
{
struct mipi_dsim_lcd_driver *client_drv = dsi->dsim_lcd_drv;
struct mipi_dsim_lcd_device *client_dev = dsi->dsim_lcd_dev;
switch (power) {
case FB_BLANK_POWERDOWN:
if (client_drv && client_drv->suspend)
client_drv->suspend(client_dev);
break;
case FB_BLANK_UNBLANK:
/* lcd panel power on. */
if (client_drv && client_drv->power_on)
client_drv->power_on(client_dev, POWER_ON_LCD);
/* set lcd panel sequence commands. */
if (client_drv && client_drv->set_sequence)
client_drv->set_sequence(client_dev);
break;
case FB_BLANK_NORMAL:
/* TODO. */
break;
default:
break;
}
return 0;
}
static int jz_mipi_dsi_blank_mode(struct dsi_device *dsi, int power)
{
struct mipi_dsim_lcd_driver *client_drv = dsi->dsim_lcd_drv;
struct mipi_dsim_lcd_device *client_dev = dsi->dsim_lcd_dev;
switch (power) {
case FB_BLANK_POWERDOWN:
if (dsi->suspended)
return 0;
if (client_drv && client_drv->suspend)
client_drv->suspend(client_dev);
jz_dsih_dphy_clock_en(dsi, 0);
jz_dsih_dphy_shutdown(dsi, 0);
clk_disable_unprepare(dsi->clk);
mipi_dsih_hal_power(dsi, 0);
dsi->state = NOT_INITIALIZED;
dsi->suspended = true;
break;
case FB_BLANK_UNBLANK:
if (!dsi->suspended)
return 0;
clk_prepare_enable(dsi->clk);
jz_mipi_update_cfg(dsi);
/* lcd panel power on. */
if (client_drv && client_drv->power_on)
client_drv->power_on(client_dev, POWER_ON_LCD);
/* set lcd panel sequence commands. */
if (client_drv && client_drv->set_sequence)
client_drv->set_sequence(client_dev);
dsi->suspended = false;
break;
case FB_BLANK_NORMAL:
/* TODO. */
break;
default:
break;
}
return 0;
}
static int jz_mipi_dsi_ioctl(struct dsi_device *dsi, int cmd)
{
struct mipi_dsim_lcd_driver *client_drv = dsi->dsim_lcd_drv;
struct mipi_dsim_lcd_device *client_dev = dsi->dsim_lcd_dev;
if (client_drv && client_drv->ioctl)
client_drv->ioctl(client_dev, cmd);
return 0;
}
int jz_dsi_mode_cfg(struct dsi_device *dsi, int mode)
{
struct video_config *video_config;
struct dsi_config *dsi_config;
video_config = dsi->video_config;
dsi_config = dsi->dsi_config;
if(mode == 1) {
/* video mode */
jz_dsih_hal_power(dsi, 0);
jz_dsi_video_cfg(dsi);
jz_dsih_hal_power(dsi, 1);
} else {
mipi_dsih_write_word(dsi, R_DSI_HOST_EDPI_CMD_SIZE, 1024); /* 当设置太小时, 对于M31传输数据会有卡死的现象??, 这里设置成1024。*/
mipi_dsih_dphy_enable_hs_clk(dsi, 1);
mipi_dsih_dphy_auto_clklane_ctrl(dsi, 1);
mipi_dsih_write_word(dsi, R_DSI_HOST_CMD_MODE_CFG, 1);
/* cmd mode */
/* color coding fix to 24bit ???? */
mipi_dsih_hal_dpi_frame_ack_en(dsi, video_config->receive_ack_packets);
if (video_config->receive_ack_packets) { /* if ACK is requested, enable BTA, otherwise leave as is */
mipi_dsih_hal_bta_en(dsi, 1);
}
if(dsi_config->te_mipi_en) {
mipi_dsih_hal_tear_effect_ack_en(dsi, 1);
} else {
mipi_dsih_hal_tear_effect_ack_en(dsi, 0);
}
mipi_dsih_hal_gen_set_mode(dsi, 1);
mipi_dsih_hal_dpi_color_coding(dsi, dsi->video_config->color_coding);
}
return 0;
}
static int jz_dsi_query_te(struct dsi_device *dsi)
{
struct dsi_cmd_packet set_tear_on = {0x15, 0x35, 0x00};
/* unsigned int cmd_mode_cfg; */
if(!dsi->dsi_config->te_mipi_en)
return 0;
//return 0;
/* According to DSI host spec. */
/*
Tearing effect request must always be triggered by a set_tear_on
command in the DWC_mipi_dsi_host implementation
*/
write_command(dsi, set_tear_on);
return 0;
}
/* define MIPI-DSI Master operations. */
static struct dsi_master_ops jz_master_ops = {
.video_cfg = jz_dsi_video_cfg,
.mode_cfg = jz_dsi_mode_cfg,
.cmd_write = write_command, /*jz_dsi_wr_data, */
.query_te = jz_dsi_query_te,
.cmd_read = NULL, /*jz_dsi_rd_data, */
.ioctl = jz_mipi_dsi_ioctl,
.set_blank_mode = jz_mipi_dsi_blank_mode,
};
int mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
{
struct mipi_dsim_ddi *dsim_ddi;
if (!lcd_dev->name) {
pr_err("dsim_lcd_device name is NULL.\n");
return -EFAULT;
}
dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
if (!dsim_ddi) {
pr_err("failed to allocate dsim_ddi object.\n");
return -ENOMEM;
}
dsim_ddi->dsim_lcd_dev = lcd_dev;
mutex_lock(&mipi_dsim_lock);
list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
mutex_unlock(&mipi_dsim_lock);
return 0;
}
static struct mipi_dsim_ddi *mipi_dsi_find_lcd_device(
struct mipi_dsim_lcd_driver *lcd_drv)
{
struct mipi_dsim_ddi *dsim_ddi, *next;
struct mipi_dsim_lcd_device *lcd_dev;
mutex_lock(&mipi_dsim_lock);
list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
if (!dsim_ddi)
goto out;
lcd_dev = dsim_ddi->dsim_lcd_dev;
if (!lcd_dev)
continue;
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;
mutex_unlock(&mipi_dsim_lock);
return dsim_ddi;
}
list_del(&dsim_ddi->list);
kfree(dsim_ddi);
}
out:
mutex_unlock(&mipi_dsim_lock);
return NULL;
}
int mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
{
struct mipi_dsim_ddi *dsim_ddi;
if (!lcd_drv->name) {
pr_err("dsim_lcd_driver name is NULL.\n");
return -EFAULT;
}
dsim_ddi = mipi_dsi_find_lcd_device(lcd_drv);
if (!dsim_ddi) {
pr_err("mipi_dsim_ddi object not found.\n");
return -EFAULT;
}
dsim_ddi->dsim_lcd_drv = lcd_drv;
pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
lcd_drv->name);
return 0;
}
static struct mipi_dsim_ddi *mipi_dsi_bind_lcd_ddi(
struct dsi_device *dsim,
const char *name)
{
struct mipi_dsim_ddi *dsim_ddi, *next;
struct mipi_dsim_lcd_driver *lcd_drv;
struct mipi_dsim_lcd_device *lcd_dev;
int ret;
mutex_lock(&dsim->lock);
list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
lcd_drv = dsim_ddi->dsim_lcd_drv;
lcd_dev = dsim_ddi->dsim_lcd_dev;
pr_debug("dsi->dev: lcd_drv->name = %s, name = %s\n",
lcd_drv->name, name);
if ((strcmp(lcd_drv->name, name) == 0)) {
lcd_dev->master = dsim;
dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
ret = device_register(&lcd_dev->dev);
if (ret < 0) {
pr_err("can't register %s, status %d\n",
dev_name(&lcd_dev->dev), ret);
mutex_unlock(&dsim->lock);
return NULL;
}
dsim->dsim_lcd_dev = lcd_dev;
dsim->dsim_lcd_drv = lcd_drv;
mutex_unlock(&dsim->lock);
return dsim_ddi;
}else{
pr_err("dsi->dev: lcd_drv->name is different with fb name\n");
}
}
mutex_unlock(&dsim->lock);
return NULL;
}
struct dsi_device * jzdsi_init(struct jzdsi_data *pdata)
{
struct dsi_device *dsi;
struct dsi_phy *dsi_phy;
struct mipi_dsim_ddi *dsim_ddi;
int ret = -EINVAL;
pr_debug("entry %s()\n", __func__);
dsi = (struct dsi_device *)kzalloc(sizeof(struct dsi_device), GFP_KERNEL);
if (!dsi) {
pr_err("dsi->dev: failed to allocate dsi object.\n");
ret = -ENOMEM;
goto err_dsi;
}
dsi_phy = (struct dsi_phy *)kzalloc(sizeof(struct dsi_phy), GFP_KERNEL);
if (!dsi_phy) {
pr_err("dsi->dev: failed to allocate dsi phy object.\n");
ret = -ENOMEM;
goto err_dsi_phy;
}
dsi->dsi_config = &(pdata->dsi_config);
dsi_phy->status = NOT_INITIALIZED;
dsi_phy->reference_freq = REFERENCE_FREQ;
dsi_phy->bsp_pre_config = set_base_dir_tx;
dsi->dsi_phy = dsi_phy;
dsi->video_config = &(pdata->video_config);
dsi->video_config->refresh = pdata->modes->refresh;
dsi->video_config->pixel_clock = PICOS2KHZ(pdata->modes->pixclock); // dpi_clock
dsi->video_config->h_polarity = pdata->modes->sync & FB_SYNC_HOR_HIGH_ACT;
dsi->video_config->h_active_pixels = pdata->modes->xres;
dsi->video_config->h_sync_pixels = pdata->modes->hsync_len;
dsi->video_config->h_back_porch_pixels = pdata->modes->left_margin;
dsi->video_config->h_total_pixels = pdata->modes->xres + pdata->modes->hsync_len + pdata->modes->left_margin + pdata->modes->right_margin;
dsi->video_config->v_active_lines = pdata->modes->yres;
dsi->video_config->v_polarity = pdata->modes->sync & FB_SYNC_VERT_HIGH_ACT;
dsi->video_config->v_sync_lines = pdata->modes->vsync_len;
dsi->video_config->v_back_porch_lines = pdata->modes->upper_margin;
dsi->video_config->v_total_lines = pdata->modes->yres + pdata->modes->upper_margin + pdata->modes->lower_margin + pdata->modes->vsync_len;
pr_debug("dsi->video_config->h_total_pixels: %d\n", dsi->video_config->h_total_pixels);
pr_debug("dsi->video_config->v_total_lines: %d\n", dsi->video_config->v_total_lines);
pr_debug("jzfb_pdata.modes->refresh: %d\n", pdata->modes->refresh);
pr_debug("jzfb_pdata.bpp: %d\n", pdata->bpp_info);
pr_debug("dsi->video_config->no_of_lanes: %d\n", dsi->video_config->no_of_lanes);
pr_debug("---dsi->video_config->byte_clock: %d\n", dsi->video_config->byte_clock);
printk("dsi->video_config->h_total_pixels: %d\n", dsi->video_config->h_total_pixels);
printk("dsi->video_config->v_total_lines: %d\n", dsi->video_config->v_total_lines);
printk("jzfb_pdata.modes->refresh: %d\n", pdata->modes->refresh);
printk("jzfb_pdata.bpp: %d\n", pdata->bpp_info);
printk("dsi->video_config->no_of_lanes: %d\n", dsi->video_config->no_of_lanes);
printk("---dsi->video_config->byte_clock: %d\n", dsi->video_config->byte_clock);
if(!dsi->video_config->byte_clock) {
dsi->video_config->byte_clock = dsi->video_config->h_total_pixels * dsi->video_config->v_total_lines *
pdata->modes->refresh * pdata->bpp_info / dsi->video_config->no_of_lanes / 8 / 1000 ;
#if 0
if (dsi->video_config->no_of_lanes == 2) {
if (pdata->modes->refresh == 15)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*6 + dsi->video_config->byte_clock / 2;
else if (pdata->modes->refresh == 20)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*5 + dsi->video_config->byte_clock / 2;
else if (pdata->modes->refresh == 25)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*4 + dsi->video_config->byte_clock / 2;
else if (pdata->modes->refresh == 30)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*3 + dsi->video_config->byte_clock / 2;
else if (pdata->modes->refresh == 60)
dsi->video_config->byte_clock = dsi->video_config->byte_clock + dsi->video_config->byte_clock / 2;
} else if (dsi->video_config->no_of_lanes == 4){
if (pdata->modes->refresh == 15)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*10;
else if (pdata->modes->refresh == 20)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*9;
else if (pdata->modes->refresh == 25)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*7;
else if (pdata->modes->refresh == 30)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*5;
else if (pdata->modes->refresh == 60)
dsi->video_config->byte_clock = dsi->video_config->byte_clock*3;
}
#endif
/* switch(dsi->video_config->byte_clock_coef) {
case MIPI_PHY_BYTE_CLK_COEF_MUL1:
break;
case MIPI_PHY_BYTE_CLK_COEF_MUL3_DIV2:
dsi->video_config->byte_clock = dsi->video_config->byte_clock * 3 / 2;
break;
case MIPI_PHY_BYTE_CLK_COEF_MUL4_DIV3:
dsi->video_config->byte_clock = dsi->video_config->byte_clock * 4 / 3;
break;
case MIPI_PHY_BYTE_CLK_COEF_MUL5_DIV4:
dsi->video_config->byte_clock = dsi->video_config->byte_clock * 5 / 4;
break;
case MIPI_PHY_BYTE_CLK_COEF_MUL6_DIV5:
dsi->video_config->byte_clock = dsi->video_config->byte_clock * 6 / 5;
break;
default:
break;
} */
}
if (dsi->video_config->byte_clock * 8 > dsi->dsi_config->max_bps * 1000) {
pr_err("+++++++++++++warning: DATALANE_BPS is over lcd max_bps allowed ,auto set it lcd max_bps %d\n", dsi->video_config->byte_clock);
//dsi->video_config->byte_clock = dsi->dsi_config->max_bps * 1000 / 8;
}
/*dsi->video_config->byte_clock = dsi->video_config->pixel_clock / 4;*/
pr_debug("%s, %d byte_clock %d KHz, pixel_clock:%d KHz\n", __func__, __LINE__, dsi->video_config->byte_clock, dsi->video_config->pixel_clock);
printk("%s, %d byte_clock %d KHz, pixel_clock:%d KHz\n", __func__, __LINE__, dsi->video_config->byte_clock, dsi->video_config->pixel_clock);
dsi->master_ops = &jz_master_ops;
dsi->clk = clk_get(NULL, "gate_dsi");
if (IS_ERR(dsi->clk)) {
pr_err("failed to get dsi clock source\n");
goto err_put_clk;
}
clk_prepare_enable(dsi->clk);
dsi->address = DSI_IOBASE;
if (!dsi->address) {
pr_err("Failed to ioremap register dsi memory region\n");
goto err_iounmap;
}
dsi->phy_address = DSI_PHY_IOBASE;
if(!dsi->phy_address) {
pr_err("Failed to ioremap dsi phy memory region!\n");
goto err_iounmap;
}
mutex_init(&dsi->lock);
dsim_ddi = mipi_dsi_bind_lcd_ddi(dsi, pdata->modes->name);
if (!dsim_ddi) {
pr_err("dsi->dev: mipi_dsim_ddi object not found.\n");
ret = -EINVAL;
goto err_bind_lcd;
}
if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
if (mipi_dsih_read_word(dsi, R_DSI_HOST_PWR_UP) & 0x1) {
dsi->state = UBOOT_INITIALIZED;
}
if(dsi->state == UBOOT_INITIALIZED) {
dsi->dsi_phy->status = INITIALIZED;
dsi->state = INITIALIZED; /*must be here for set_sequence function*/
} else {
dsi->state = NOT_INITIALIZED; /*must be here for set_sequence function*/
ret = jz_mipi_update_cfg(dsi);
if (ret) {
goto err_dsi_init;
}
if (dsim_ddi->dsim_lcd_drv) {
if (dsim_ddi->dsim_lcd_drv->power_on)
dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1);
if (dsim_ddi->dsim_lcd_drv->set_sequence)
dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev);
}else{
pr_err("lcd mipi panel init failed!\n");
goto err_panel_init;
}
}
/* jz_mipi_dsi_init_interrupt(dsi); */
dsi->suspended = false;
#ifdef CONFIG_DSI_DPI_DEBUG /*test pattern */
unsigned int tmp = 0;
jz_dsi_video_cfg(dsi);
tmp = mipi_dsih_read_word(dsi, R_DSI_HOST_VID_MODE_CFG);
tmp |= 1 << 16 | 0 << 20 | 1 << 24;
mipi_dsih_write_word(dsi, R_DSI_HOST_VID_MODE_CFG, tmp);
#endif
return dsi;
err_panel_init:
pr_err("dsi->dev: lcd mipi panel init error\n");
err_dsi_init:
pr_err("dsi->dev: lcd mipi dsi init error\n");
err_bind_lcd:
iounmap((void __iomem *)dsi->address);
err_iounmap:
clk_put(dsi->clk);
err_put_clk:
kfree(dsi_phy);
err_dsi_phy:
kfree(dsi);
err_dsi:
return NULL;
}
void jzdsi_remove(struct dsi_device *dsi)
{
struct dsi_phy *dsi_phy;
dsi_phy = dsi->dsi_phy;
iounmap((void __iomem *)dsi->address);
clk_disable(dsi->clk);
clk_put(dsi->clk);
kfree(dsi_phy);
kfree(dsi);
}