OMAP: DSS2: DSI: Get number of DSI data lanes using DSI_GNQ register

On OMAP3, the DSI module has 2 data lanes. On OMAP4, DSI1 has 4 data lanes
and DSI2 has 2 data lanes. Introduce function dsi_get_num_data_lanes() which
returns the number of data lanes on the dsi interface, introduce function
dsi_get_num_data_lanes_dssdev() which returns the number of data lanes used by
the omap_dss_device connected to the lanes.

Use the DSI_GNQ register on OMAP4 to get the number of data lanes, modify
dsi.c to use the number of lanes and the extra data lanes on DSI1.

Signed-off-by: Archit Taneja <archit@ti.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
This commit is contained in:
Archit Taneja 2011-05-16 15:17:08 +05:30 committed by Tomi Valkeinen
parent 49dbf5892f
commit 75d7247c07
4 changed files with 95 additions and 10 deletions

View file

@ -59,6 +59,7 @@ struct dsi_reg { u16 idx; };
#define DSI_IRQSTATUS DSI_REG(0x0018) #define DSI_IRQSTATUS DSI_REG(0x0018)
#define DSI_IRQENABLE DSI_REG(0x001C) #define DSI_IRQENABLE DSI_REG(0x001C)
#define DSI_CTRL DSI_REG(0x0040) #define DSI_CTRL DSI_REG(0x0040)
#define DSI_GNQ DSI_REG(0x0044)
#define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048) #define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048)
#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C) #define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C)
#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050) #define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050)
@ -238,6 +239,10 @@ enum dsi_lane {
DSI_DATA1_N = 1 << 3, DSI_DATA1_N = 1 << 3,
DSI_DATA2_P = 1 << 4, DSI_DATA2_P = 1 << 4,
DSI_DATA2_N = 1 << 5, DSI_DATA2_N = 1 << 5,
DSI_DATA3_P = 1 << 6,
DSI_DATA3_N = 1 << 7,
DSI_DATA4_P = 1 << 8,
DSI_DATA4_N = 1 << 9,
}; };
struct dsi_update_region { struct dsi_update_region {
@ -326,6 +331,8 @@ struct dsi_data {
unsigned long fint_min, fint_max; unsigned long fint_min, fint_max;
unsigned long lpdiv_max; unsigned long lpdiv_max;
int num_data_lanes;
unsigned scp_clk_refcount; unsigned scp_clk_refcount;
}; };
@ -2001,10 +2008,39 @@ static int dsi_cio_power(struct platform_device *dsidev,
return 0; return 0;
} }
/* Number of data lanes present on DSI interface */
static inline int dsi_get_num_data_lanes(struct platform_device *dsidev)
{
/* DSI on OMAP3 doesn't have register DSI_GNQ, set number
* of data lanes as 2 by default */
if (dss_has_feature(FEAT_DSI_GNQ))
return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */
else
return 2;
}
/* Number of data lanes used by the dss device */
static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev)
{
int num_data_lanes = 0;
if (dssdev->phy.dsi.data1_lane != 0)
num_data_lanes++;
if (dssdev->phy.dsi.data2_lane != 0)
num_data_lanes++;
if (dssdev->phy.dsi.data3_lane != 0)
num_data_lanes++;
if (dssdev->phy.dsi.data4_lane != 0)
num_data_lanes++;
return num_data_lanes;
}
static void dsi_set_lane_config(struct omap_dss_device *dssdev) static void dsi_set_lane_config(struct omap_dss_device *dssdev)
{ {
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
u32 r; u32 r;
int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
int clk_lane = dssdev->phy.dsi.clk_lane; int clk_lane = dssdev->phy.dsi.clk_lane;
int data1_lane = dssdev->phy.dsi.data1_lane; int data1_lane = dssdev->phy.dsi.data1_lane;
@ -2020,6 +2056,20 @@ static void dsi_set_lane_config(struct omap_dss_device *dssdev)
r = FLD_MOD(r, data1_pol, 7, 7); r = FLD_MOD(r, data1_pol, 7, 7);
r = FLD_MOD(r, data2_lane, 10, 8); r = FLD_MOD(r, data2_lane, 10, 8);
r = FLD_MOD(r, data2_pol, 11, 11); r = FLD_MOD(r, data2_pol, 11, 11);
if (num_data_lanes_dssdev > 2) {
int data3_lane = dssdev->phy.dsi.data3_lane;
int data3_pol = dssdev->phy.dsi.data3_pol;
r = FLD_MOD(r, data3_lane, 14, 12);
r = FLD_MOD(r, data3_pol, 15, 15);
}
if (num_data_lanes_dssdev > 3) {
int data4_lane = dssdev->phy.dsi.data4_lane;
int data4_pol = dssdev->phy.dsi.data4_pol;
r = FLD_MOD(r, data4_lane, 18, 16);
r = FLD_MOD(r, data4_pol, 19, 19);
}
dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r);
/* The configuration of the DSI complex I/O (number of data lanes, /* The configuration of the DSI complex I/O (number of data lanes,
@ -2132,14 +2182,20 @@ static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
enum dsi_lane lanes) enum dsi_lane lanes)
{ {
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int clk_lane = dssdev->phy.dsi.clk_lane; int clk_lane = dssdev->phy.dsi.clk_lane;
int data1_lane = dssdev->phy.dsi.data1_lane; int data1_lane = dssdev->phy.dsi.data1_lane;
int data2_lane = dssdev->phy.dsi.data2_lane; int data2_lane = dssdev->phy.dsi.data2_lane;
int data3_lane = dssdev->phy.dsi.data3_lane;
int data4_lane = dssdev->phy.dsi.data4_lane;
int clk_pol = dssdev->phy.dsi.clk_pol; int clk_pol = dssdev->phy.dsi.clk_pol;
int data1_pol = dssdev->phy.dsi.data1_pol; int data1_pol = dssdev->phy.dsi.data1_pol;
int data2_pol = dssdev->phy.dsi.data2_pol; int data2_pol = dssdev->phy.dsi.data2_pol;
int data3_pol = dssdev->phy.dsi.data3_pol;
int data4_pol = dssdev->phy.dsi.data4_pol;
u32 l = 0; u32 l = 0;
u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26;
if (lanes & DSI_CLK_P) if (lanes & DSI_CLK_P)
l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1)); l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1));
@ -2156,17 +2212,28 @@ static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev,
if (lanes & DSI_DATA2_N) if (lanes & DSI_DATA2_N)
l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0)); l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0));
if (lanes & DSI_DATA3_P)
l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1));
if (lanes & DSI_DATA3_N)
l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0));
if (lanes & DSI_DATA4_P)
l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1));
if (lanes & DSI_DATA4_N)
l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0));
/* /*
* Bits in REGLPTXSCPDAT4TO0DXDY: * Bits in REGLPTXSCPDAT4TO0DXDY:
* 17: DY0 18: DX0 * 17: DY0 18: DX0
* 19: DY1 20: DX1 * 19: DY1 20: DX1
* 21: DY2 22: DX2 * 21: DY2 22: DX2
* 23: DY3 24: DX3
* 25: DY4 26: DX4
*/ */
/* Set the lane override configuration */ /* Set the lane override configuration */
/* REGLPTXSCPDAT4TO0DXDY */ /* REGLPTXSCPDAT4TO0DXDY */
REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, 22, 17); REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, l, lptxscp_start, 17);
/* Enable lane override */ /* Enable lane override */
@ -2248,6 +2315,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int r; int r;
int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev);
u32 l; u32 l;
DSSDBGF(); DSSDBGF();
@ -2279,6 +2347,8 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
dsi_write_reg(dsidev, DSI_TIMING1, l); dsi_write_reg(dsidev, DSI_TIMING1, l);
if (dsi->ulps_enabled) { if (dsi->ulps_enabled) {
u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P;
DSSDBG("manual ulps exit\n"); DSSDBG("manual ulps exit\n");
/* ULPS is exited by Mark-1 state for 1ms, followed by /* ULPS is exited by Mark-1 state for 1ms, followed by
@ -2289,8 +2359,13 @@ static int dsi_cio_init(struct omap_dss_device *dssdev)
* manually. * manually.
*/ */
dsi_cio_enable_lane_override(dssdev, if (num_data_lanes_dssdev > 2)
DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P); lane_mask |= DSI_DATA3_P;
if (num_data_lanes_dssdev > 3)
lane_mask |= DSI_DATA4_P;
dsi_cio_enable_lane_override(dssdev, lane_mask);
} }
r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON);
@ -3495,12 +3570,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
/* min 60ns + 52*UI */ /* min 60ns + 52*UI */
tclk_post = ns2ddr(dsidev, 60) + 26; tclk_post = ns2ddr(dsidev, 60) + 26;
/* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */ ths_eot = DIV_ROUND_UP(4, dsi_get_num_data_lanes_dssdev(dssdev));
if (dssdev->phy.dsi.data1_lane != 0 &&
dssdev->phy.dsi.data2_lane != 0)
ths_eot = 2;
else
ths_eot = 4;
ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare, ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
4); 4);
@ -4220,6 +4290,7 @@ int dsi_init_display(struct omap_dss_device *dssdev)
{ {
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int dsi_module = dsi_get_dsidev_id(dsidev);
DSSDBG("DSI init\n"); DSSDBG("DSI init\n");
@ -4240,6 +4311,12 @@ int dsi_init_display(struct omap_dss_device *dssdev)
dsi->vdds_dsi_reg = vdds_dsi; dsi->vdds_dsi_reg = vdds_dsi;
} }
if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) {
DSSERR("DSI%d can't support more than %d data lanes\n",
dsi_module + 1, dsi->num_data_lanes);
return -EINVAL;
}
return 0; return 0;
} }
@ -4416,6 +4493,8 @@ static int dsi_init(struct platform_device *dsidev)
dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev);
enable_clocks(0); enable_clocks(0);
return 0; return 0;

View file

@ -294,7 +294,8 @@ static const struct omap_dss_features omap4_dss_features = {
FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA |
FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 |
FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC |
FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH, FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH |
FEAT_DSI_GNQ,
.num_mgrs = 3, .num_mgrs = 3,
.num_ovls = 3, .num_ovls = 3,

View file

@ -47,6 +47,7 @@ enum dss_feat_id {
FEAT_DSI_DCS_CMD_CONFIG_VC = 1 << 15, FEAT_DSI_DCS_CMD_CONFIG_VC = 1 << 15,
FEAT_DSI_VC_OCP_WIDTH = 1 << 16, FEAT_DSI_VC_OCP_WIDTH = 1 << 16,
FEAT_DSI_REVERSE_TXCLKESC = 1 << 17, FEAT_DSI_REVERSE_TXCLKESC = 1 << 17,
FEAT_DSI_GNQ = 1 << 18,
}; };
/* DSS register field id */ /* DSS register field id */

View file

@ -420,6 +420,10 @@ struct omap_dss_device {
u8 data1_pol; u8 data1_pol;
u8 data2_lane; u8 data2_lane;
u8 data2_pol; u8 data2_pol;
u8 data3_lane;
u8 data3_pol;
u8 data4_lane;
u8 data4_pol;
int module; int module;