summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Bauer <anders.bauer@stericsson.com>2011-11-04 17:05:28 +0100
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:04:19 +0200
commitfdf669e16c492c38dba87263755e0e0077d6f0bd (patch)
tree45fcddecda0bcd31344fb0f2cc9d3b4f301e3891
parentd45e9778387f6dcc7a517ade1792807f280836cd (diff)
video: mcde: add DSI video mode support
This patch adds support for DSI video mode. ST-Ericsson Linux next: - ST-Ericsson ID: 365705 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I103bed18f814e85e48bc687b6b08b4829be347a6 Signed-off-by: Anders Bauer <anders.bauer@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/36517 Reviewed-by: QABUILD Reviewed-by: Jimmy RUBIN <jimmy.rubin@stericsson.com> Reviewed-by: Per PERSSON <per.xb.persson@stericsson.com>
-rw-r--r--drivers/video/mcde/mcde_display.c23
-rw-r--r--drivers/video/mcde/mcde_hw.c282
-rw-r--r--include/video/mcde.h20
3 files changed, 321 insertions, 4 deletions
diff --git a/drivers/video/mcde/mcde_display.c b/drivers/video/mcde/mcde_display.c
index 28409166c7d..a461b36c9b6 100644
--- a/drivers/video/mcde/mcde_display.c
+++ b/drivers/video/mcde/mcde_display.c
@@ -122,7 +122,28 @@ static inline int mcde_display_try_video_mode_default(
struct mcde_display_device *ddev,
struct mcde_video_mode *video_mode)
{
- /* TODO Check if inside native_xres and native_yres */
+ /*
+ * DSI video mode:
+ * This function is intended for configuring supported video mode(s).
+ * Overload it into the panel driver file and set up blanking
+ * intervals and pixel clock according to below recommendations.
+ *
+ * vertical blanking parameters vbp, vfp, vsw are given in lines
+ * horizontal blanking parameters hbp, hfp, hsw are given in pixels
+ *
+ * video_mode->pixclock is the time between two pixels (in picoseconds)
+ * The source of the pixel clock is DSI PLL and it shall be set to
+ * meet the requirement
+ *
+ * non-burst mode:
+ * pixel clock (Hz) = (VACT+VBP+VFP+VSA) * (HACT+HBP+HFP+HSA) *
+ * framerate * bpp / num_data_lanes
+ *
+ * burst mode:
+ * pixel clock (Hz) > (VACT+VBP+VFP+VSA) * (HACT+HBP+HFP+HSA) *
+ * framerate * bpp / num_data_lanes * 1.1
+ * (1.1 is a 10% margin needed for burst mode calculations)
+ */
return 0;
}
diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c
index 720b94db30f..0baffc246d7 100644
--- a/drivers/video/mcde/mcde_hw.c
+++ b/drivers/video/mcde/mcde_hw.c
@@ -921,6 +921,87 @@ static int wait_for_vcmp(struct mcde_chnl_state *chnl)
return ret;
}
+static void get_vid_operating_mode(const struct mcde_port *port,
+ bool *burst_mode, bool *sync_is_pulse, bool *tvg_enable)
+{
+ switch (port->phy.dsi.vid_mode) {
+ case NON_BURST_MODE_WITH_SYNC_EVENT:
+ *burst_mode = false;
+ *sync_is_pulse = false;
+ *tvg_enable = false;
+ break;
+ case NON_BURST_MODE_WITH_SYNC_EVENT_TVG_ENABLED:
+ *burst_mode = false;
+ *sync_is_pulse = false;
+ *tvg_enable = true;
+ break;
+ case BURST_MODE_WITH_SYNC_EVENT:
+ *burst_mode = true;
+ *sync_is_pulse = false;
+ *tvg_enable = false;
+ break;
+ case BURST_MODE_WITH_SYNC_PULSE:
+ *burst_mode = true;
+ *sync_is_pulse = true;
+ *tvg_enable = false;
+ break;
+ default:
+ dev_err(&mcde_dev->dev, "Unsupported video mode");
+ break;
+ }
+}
+
+static void update_vid_static_registers(const struct mcde_port *port)
+{
+ u8 link = port->link;
+ bool burst_mode, sync_is_pulse, tvg_enable;
+
+ get_vid_operating_mode(port, &burst_mode, &sync_is_pulse, &tvg_enable);
+
+ /* burst mode or non-burst mode */
+ dsi_wfld(link, DSI_VID_MAIN_CTL, BURST_MODE, burst_mode);
+
+ /* sync is pulse or event */
+ dsi_wfld(link, DSI_VID_MAIN_CTL, SYNC_PULSE_ACTIVE, sync_is_pulse);
+ dsi_wfld(link, DSI_VID_MAIN_CTL, SYNC_PULSE_HORIZONTAL, sync_is_pulse);
+
+ /* disable video stream when using TVG */
+ if (tvg_enable) {
+ dsi_wfld(link, DSI_MCTL_MAIN_EN, IF1_EN, false);
+ dsi_wfld(link, DSI_MCTL_MAIN_EN, IF2_EN, false);
+ }
+
+ /*
+ * behavior during blanking time
+ * 00: NULL packet 1x:LP 01:blanking-packet
+ */
+ dsi_wfld(link, DSI_VID_MAIN_CTL, REG_BLKLINE_MODE, 1);
+
+ /*
+ * behavior during eol
+ * 00: NULL packet 1x:LP 01:blanking-packet
+ */
+ dsi_wfld(link, DSI_VID_MAIN_CTL, REG_BLKEOL_MODE, 2);
+
+ /* time to perform LP->HS on D-PHY */
+ dsi_wfld(link, DSI_VID_DPHY_TIME, REG_WAKEUP_TIME,
+ port->phy.dsi.vid_wakeup_time);
+
+ /*
+ * video stream starts on VSYNC packet
+ * and stops at the end of a frame
+ */
+ dsi_wfld(link, DSI_VID_MAIN_CTL, VID_ID, port->phy.dsi.virt_id);
+ dsi_wfld(link, DSI_VID_MAIN_CTL, START_MODE, 0);
+ dsi_wfld(link, DSI_VID_MAIN_CTL, STOP_MODE, 0);
+
+ /* 1: if1 in video mode, 0: if1 in command mode */
+ dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, IF1_MODE, 1);
+
+ /* 1: enables the link, 0: disables the link */
+ dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, VID_EN, 1);
+}
+
static int update_channel_static_registers(struct mcde_chnl_state *chnl)
{
const struct mcde_port *port = &chnl->port;
@@ -1081,7 +1162,9 @@ static int update_channel_static_registers(struct mcde_chnl_state *chnl)
MCDE_DSIVID0CONF0_BYTE_SWAP(false) |
MCDE_DSIVID0CONF0_DCSVID_NOTGEN(true));
- if (port->mode == MCDE_PORTMODE_CMD) {
+ if (port->mode == MCDE_PORTMODE_VID) {
+ update_vid_static_registers(port);
+ } else {
if (port->ifc == 0)
dsi_wfld(port->link, DSI_CMD_MODE_CTL, IF1_ID,
port->phy.dsi.virt_id);
@@ -1529,6 +1612,192 @@ static u32 get_pkt_div(u32 disp_ppl,
return 1;
}
+static void update_vid_horizontal_blanking(struct mcde_port *port,
+ struct mcde_video_mode *vmode, bool sync_is_pulse, u8 bpp)
+{
+ int hfp, hbp, hsa;
+ u8 link = port->link;
+
+ /*
+ * vmode->hfp, vmode->hbp and vmode->hsw are given in pixels
+ * and must be re-calculated into bytes
+ *
+ * 6 + 2 is HFP header + checksum
+ */
+ hfp = vmode->hfp * bpp - 6 - 2;
+ if (sync_is_pulse) {
+ /*
+ * 6 is HBP header + checksum
+ * 4 is RGB header + checksum
+ */
+ hbp = vmode->hbp * bpp - 4 - 6;
+ /*
+ * 6 is HBP header + checksum
+ * 4 is HSW packet bytes
+ * 4 is RGB header + checksum
+ */
+ hsa = vmode->hsw * bpp - 4 - 4 - 6;
+ } else {
+ /*
+ * 6 is HBP header + checksum
+ * 4 is HSW packet bytes
+ * 4 is RGB header + checksum
+ */
+ hbp = (vmode->hbp + vmode->hsw) * bpp - 4 - 4 - 6;
+ /* HSA is not considered in this mode and set to 0 */
+ hsa = 0;
+ }
+ if (hfp < 0) {
+ hfp = 0;
+ dev_warn(&mcde_dev->dev,
+ "%s: negative calc for hfp, set to 0\n", __func__);
+ }
+ if (hbp < 0) {
+ hbp = 0;
+ dev_warn(&mcde_dev->dev,
+ "%s: negative calc for hbp, set to 0\n", __func__);
+ }
+ if (hsa < 0) {
+ hsa = 0;
+ dev_warn(&mcde_dev->dev,
+ "%s: negative calc for hsa, set to 0\n", __func__);
+ }
+
+ dsi_wfld(link, DSI_VID_HSIZE1, HFP_LENGTH, hfp);
+ dsi_wfld(link, DSI_VID_HSIZE1, HBP_LENGTH, hbp);
+ dsi_wfld(link, DSI_VID_HSIZE1, HSA_LENGTH, hsa);
+}
+
+static void update_vid_frame_parameters(struct mcde_port *port,
+ struct mcde_video_mode *vmode, u8 bpp)
+{
+ u8 link = port->link;
+ bool burst_mode, sync_is_pulse, tvg_enable;
+ u32 hs_byte_clk, pck_len, blkline_pck, line_duration;
+ u32 blkeol_pck, blkeol_duration;
+ u8 pixel_mode;
+ u8 rgb_header;
+
+ get_vid_operating_mode(port, &burst_mode, &sync_is_pulse, &tvg_enable);
+
+ dsi_wfld(link, DSI_VID_VSIZE, VFP_LENGTH, vmode->vfp);
+ dsi_wfld(link, DSI_VID_VSIZE, VBP_LENGTH, vmode->vbp);
+ dsi_wfld(link, DSI_VID_VSIZE, VSA_LENGTH, vmode->vsw);
+ update_vid_horizontal_blanking(port, vmode, sync_is_pulse, bpp);
+
+ dsi_wfld(link, DSI_VID_VSIZE, VACT_LENGTH, vmode->yres);
+ dsi_wfld(link, DSI_VID_HSIZE2, RGB_SIZE, vmode->xres * bpp);
+
+ /*
+ * The rgb_header identifies the pixel stream format,
+ * as described in the MIPI DSI Specification:
+ *
+ * 0x0E: Packed pixel stream, 16-bit RGB, 565 format
+ * 0x1E: Packed pixel stream, 18-bit RGB, 666 format
+ * 0x2E: Loosely Packed pixel stream, 18-bit RGB, 666 format
+ * 0x3E: Packed pixel stream, 24-bit RGB, 888 format
+ */
+ switch (port->pixel_format) {
+ case MCDE_PORTPIXFMT_DSI_16BPP:
+ pixel_mode = 0;
+ rgb_header = 0x0E;
+ break;
+ case MCDE_PORTPIXFMT_DSI_18BPP:
+ pixel_mode = 2;
+ rgb_header = 0x2E;
+ break;
+ case MCDE_PORTPIXFMT_DSI_18BPP_PACKED:
+ pixel_mode = 1;
+ rgb_header = 0x1E;
+ break;
+ case MCDE_PORTPIXFMT_DSI_24BPP:
+ pixel_mode = 3;
+ rgb_header = 0x3E;
+ break;
+ default:
+ pixel_mode = 3;
+ rgb_header = 0x3E;
+ dev_warn(&mcde_dev->dev,
+ "%s: invalid pixel format %d\n",
+ __func__, port->pixel_format);
+ break;
+ }
+
+ dsi_wfld(link, DSI_VID_MAIN_CTL, VID_PIXEL_MODE, pixel_mode);
+ dsi_wfld(link, DSI_VID_MAIN_CTL, HEADER, rgb_header);
+
+ if (tvg_enable) {
+ /*
+ * with these settings, expect to see 64 pixels wide
+ * red and green vertical stripes on the screen when
+ * tvg_enable = 1
+ */
+ dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, TVG_SEL, 1);
+
+ dsi_wfld(link, DSI_TVG_CTL, TVG_STRIPE_SIZE, 6);
+ dsi_wfld(link, DSI_TVG_CTL, TVG_MODE, 2);
+ dsi_wfld(link, DSI_TVG_CTL, TVG_STOPMODE, 2);
+ dsi_wfld(link, DSI_TVG_CTL, TVG_RUN, 1);
+
+ dsi_wfld(link, DSI_TVG_IMG_SIZE, TVG_NBLINE, vmode->yres);
+ dsi_wfld(link, DSI_TVG_IMG_SIZE, TVG_LINE_SIZE,
+ vmode->xres * bpp);
+
+ dsi_wfld(link, DSI_TVG_COLOR1, COL1_BLUE, 0);
+ dsi_wfld(link, DSI_TVG_COLOR1, COL1_GREEN, 0);
+ dsi_wfld(link, DSI_TVG_COLOR1, COL1_RED, 0xFF);
+
+ dsi_wfld(link, DSI_TVG_COLOR2, COL2_BLUE, 0);
+ dsi_wfld(link, DSI_TVG_COLOR2, COL2_GREEN, 0xFF);
+ dsi_wfld(link, DSI_TVG_COLOR2, COL2_RED, 0);
+ }
+
+ /*
+ * vid->pixclock is the time between two pixels (in picoseconds)
+ *
+ * hs_byte_clk is the amount of transferred bytes per lane and
+ * second (in MHz)
+ */
+ hs_byte_clk = 1000000 / vmode->pixclock / 8;
+ pck_len = 1000000 * hs_byte_clk / port->refresh_rate /
+ (vmode->vsw + vmode->vbp + vmode->yres + vmode->vfp) *
+ port->phy.dsi.num_data_lanes;
+
+ /*
+ * 6 is header + checksum, header = 4 bytes, checksum = 2 bytes
+ * 4 is short packet for vsync/hsync
+ */
+ if (sync_is_pulse)
+ blkline_pck = pck_len - vmode->hsw - 6;
+ else
+ blkline_pck = pck_len - 4 - 6;
+
+ line_duration = (blkline_pck + 6) / port->phy.dsi.num_data_lanes;
+ blkeol_pck = pck_len -
+ (vmode->hsw + vmode->hbp + vmode->xres + vmode->hfp) * bpp - 6;
+ blkeol_duration = (blkeol_pck + 6) / port->phy.dsi.num_data_lanes;
+
+ if (sync_is_pulse)
+ dsi_wfld(link, DSI_VID_BLKSIZE2, BLKLINE_PULSE_PCK,
+ blkline_pck);
+ else
+ dsi_wfld(link, DSI_VID_BLKSIZE1, BLKLINE_EVENT_PCK,
+ blkline_pck);
+ dsi_wfld(link, DSI_VID_DPHY_TIME, REG_LINE_DURATION, line_duration);
+ if (burst_mode) {
+ dsi_wfld(link, DSI_VID_BLKSIZE1, BLKEOL_PCK, blkeol_pck);
+ dsi_wfld(link, DSI_VID_PCK_TIME, BLKEOL_DURATION,
+ blkeol_duration);
+ dsi_wfld(link, DSI_VID_VCA_SETTING1, MAX_BURST_LIMIT,
+ blkeol_pck - 6);
+ dsi_wfld(link, DSI_VID_VCA_SETTING2, EXACT_BURST_LIMIT,
+ blkeol_pck);
+ }
+ if (sync_is_pulse)
+ dsi_wfld(link, DSI_VID_VCA_SETTING2, MAX_LINE_LIMIT,
+ blkline_pck - 6);
+}
+
void update_channel_registers(enum mcde_chnl chnl_id, struct chnl_regs *regs,
struct mcde_port *port, enum mcde_fifo fifo,
struct mcde_video_mode *video_mode)
@@ -1699,8 +1968,11 @@ void update_channel_registers(enum mcde_chnl chnl_id, struct chnl_regs *regs,
fidx * MCDE_DSIVID0CONF0_GROUPOFFSET,
(temp & ~MCDE_DSIVID0CONF0_PACKING_MASK) |
MCDE_DSIVID0CONF0_PACKING(regs->dsipacking));
- /* 1==CMD8 */
- packet = ((screen_ppl / pkt_div * regs->bpp) >> 3) + 1;
+ /* no extra command byte in video mode */
+ if (port->mode == MCDE_PORTMODE_CMD)
+ packet = ((screen_ppl / pkt_div * regs->bpp) >> 3) + 1;
+ else
+ packet = ((screen_ppl / pkt_div * regs->bpp) >> 3);
mcde_wreg(MCDE_DSIVID0FRAME +
fidx * MCDE_DSIVID0FRAME_GROUPOFFSET,
MCDE_DSIVID0FRAME_FRAME(packet * pkt_div * screen_lpf));
@@ -1721,6 +1993,10 @@ void update_channel_registers(enum mcde_chnl chnl_id, struct chnl_regs *regs,
fidx * MCDE_DSIVID0DELAY1_GROUPOFFSET,
MCDE_DSIVID0DELAY1_TEREQDEL(0) |
MCDE_DSIVID0DELAY1_FRAMESTARTDEL(0));
+
+ if (port->mode == MCDE_PORTMODE_VID)
+ update_vid_frame_parameters(port, video_mode,
+ regs->bpp / 8);
} else if (port->type == MCDE_PORTTYPE_DPI &&
!port->phy.dpi.tv_mode) {
/* DPI LCD Mode */
diff --git a/include/video/mcde.h b/include/video/mcde.h
index ae456743827..8e1c772fdaa 100644
--- a/include/video/mcde.h
+++ b/include/video/mcde.h
@@ -91,6 +91,15 @@ struct mcde_col_transform {
u16 offset[3];
};
+/* DSI video mode */
+enum mcde_dsi_vid_mode {
+ NON_BURST_MODE_WITH_SYNC_EVENT = 0,
+ /* enables tvg, test video generator */
+ NON_BURST_MODE_WITH_SYNC_EVENT_TVG_ENABLED = 1,
+ BURST_MODE_WITH_SYNC_EVENT = 2,
+ BURST_MODE_WITH_SYNC_PULSE = 3,
+};
+
#define MCDE_PORT_DPI_NO_CLOCK_DIV 0
#define DPI_ACT_HIGH_ALL 0 /* all signals are active high */
@@ -105,6 +114,7 @@ struct mcde_port {
enum mcde_port_type type;
enum mcde_port_mode mode;
enum mcde_port_pix_fmt pixel_format;
+ u8 refresh_rate; /* display refresh rate given in Hz */
u8 ifc;
u8 link;
enum mcde_sync_src sync_src;
@@ -118,6 +128,16 @@ struct mcde_port {
bool clk_cont;
bool host_eot_gen;
+ /* DSI video mode operating modes */
+ enum mcde_dsi_vid_mode vid_mode;
+
+ /*
+ * wakeup_time is the time to perform
+ * LP->HS on D-PHY. Given in clock
+ * cycles of byte clock frequency.
+ */
+ u32 vid_wakeup_time;
+
/* DSI data lanes are swapped if true */
bool data_lanes_swap;
} dsi;