diff options
Diffstat (limited to 'drivers/video/omap2/dss/dsi.c')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 537 |
1 files changed, 338 insertions, 199 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 662d14f8c2c3..ec363d8390ed 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -256,14 +256,13 @@ struct dsi_data { struct platform_device *pdev; void __iomem *base; + int module_id; + int irq; struct clk *dss_clk; struct clk *sys_clk; - int (*enable_pads)(int dsi_id, unsigned lane_mask); - void (*disable_pads)(int dsi_id, unsigned lane_mask); - struct dsi_clock_info current_cinfo; bool vdds_dsi_enabled; @@ -361,11 +360,6 @@ struct platform_device *dsi_get_dsidev_from_id(int module) return dsi_pdev_map[module]; } -static inline int dsi_get_dsidev_id(struct platform_device *dsidev) -{ - return dsidev->id; -} - static inline void dsi_write_reg(struct platform_device *dsidev, const struct dsi_reg idx, u32 val) { @@ -452,6 +446,7 @@ u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) return 16; default: BUG(); + return 0; } } @@ -1184,10 +1179,9 @@ static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev) static unsigned long dsi_fclk_rate(struct platform_device *dsidev) { unsigned long r; - int dsi_module = dsi_get_dsidev_id(dsidev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) { + if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS_CLK_FCK */ r = clk_get_rate(dsi->dss_clk); } else { @@ -1279,10 +1273,9 @@ static int dsi_pll_power(struct platform_device *dsidev, } /* calculate clock rates using dividers in cinfo */ -static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, +static int dsi_calc_clock_rates(struct platform_device *dsidev, struct dsi_clock_info *cinfo) { - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max) @@ -1297,21 +1290,8 @@ static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, if (cinfo->regm_dsi > dsi->regm_dsi_max) return -EINVAL; - if (cinfo->use_sys_clk) { - cinfo->clkin = clk_get_rate(dsi->sys_clk); - /* XXX it is unclear if highfreq should be used - * with DSS_SYS_CLK source also */ - cinfo->highfreq = 0; - } else { - cinfo->clkin = dispc_mgr_pclk_rate(dssdev->manager->id); - - if (cinfo->clkin < 32000000) - cinfo->highfreq = 0; - else - cinfo->highfreq = 1; - } - - cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1)); + cinfo->clkin = clk_get_rate(dsi->sys_clk); + cinfo->fint = cinfo->clkin / cinfo->regn; if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min) return -EINVAL; @@ -1378,27 +1358,21 @@ retry: memset(&cur, 0, sizeof(cur)); cur.clkin = dss_sys_clk; - cur.use_sys_clk = 1; - cur.highfreq = 0; - /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */ - /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */ + /* 0.75MHz < Fint = clkin / regn < 2.1MHz */ /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { - if (cur.highfreq == 0) - cur.fint = cur.clkin / cur.regn; - else - cur.fint = cur.clkin / (2 * cur.regn); + cur.fint = cur.clkin / cur.regn; if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) continue; - /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */ + /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { unsigned long a, b; a = 2 * cur.regm * (cur.clkin/1000); - b = cur.regn * (cur.highfreq + 1); + b = cur.regn; cur.clkin4ddr = a / b * 1000; if (cur.clkin4ddr > 1800 * 1000 * 1000) @@ -1486,9 +1460,7 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, DSSDBGF(); - dsi->current_cinfo.use_sys_clk = cinfo->use_sys_clk; - dsi->current_cinfo.highfreq = cinfo->highfreq; - + dsi->current_cinfo.clkin = cinfo->clkin; dsi->current_cinfo.fint = cinfo->fint; dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr; dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk = @@ -1503,17 +1475,13 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, DSSDBG("DSI Fint %ld\n", cinfo->fint); - DSSDBG("clkin (%s) rate %ld, highfreq %d\n", - cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree", - cinfo->clkin, - cinfo->highfreq); + DSSDBG("clkin rate %ld\n", cinfo->clkin); /* DSIPHY == CLKIN4DDR */ - DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n", + DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n", cinfo->regm, cinfo->regn, cinfo->clkin, - cinfo->highfreq + 1, cinfo->clkin4ddr); DSSDBG("Data rate on 1 DSI lane %ld Mbps\n", @@ -1568,10 +1536,6 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ - l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1, - 11, 11); /* DSI_PLL_CLKSEL */ - l = FLD_MOD(l, cinfo->highfreq, - 12, 12); /* DSI_PLL_HIGHFREQ */ l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ @@ -1716,7 +1680,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dsi_clock_info *cinfo = &dsi->current_cinfo; enum omap_dss_clk_source dispc_clk_src, dsi_clk_src; - int dsi_module = dsi_get_dsidev_id(dsidev); + int dsi_module = dsi->module_id; dispc_clk_src = dss_get_dispc_clk_source(); dsi_clk_src = dss_get_dsi_clk_source(dsi_module); @@ -1726,8 +1690,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); - seq_printf(s, "dsi pll source = %s\n", - cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree"); + seq_printf(s, "dsi pll clkin\t%lu\n", cinfo->clkin); seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn); @@ -1789,7 +1752,6 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); unsigned long flags; struct dsi_irq_stats stats; - int dsi_module = dsi_get_dsidev_id(dsidev); spin_lock_irqsave(&dsi->irq_stats_lock, flags); @@ -1806,7 +1768,7 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, #define PIS(x) \ seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]); - seq_printf(s, "-- DSI%d interrupts --\n", dsi_module + 1); + seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1); PIS(VC0); PIS(VC1); PIS(VC2); @@ -1886,22 +1848,6 @@ static void dsi2_dump_irqs(struct seq_file *s) dsi_dump_dsidev_irqs(dsidev, s); } - -void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir, - const struct file_operations *debug_fops) -{ - struct platform_device *dsidev; - - dsidev = dsi_get_dsidev_from_id(0); - if (dsidev) - debugfs_create_file("dsi1_irqs", S_IRUGO, debugfs_dir, - &dsi1_dump_irqs, debug_fops); - - dsidev = dsi_get_dsidev_from_id(1); - if (dsidev) - debugfs_create_file("dsi2_irqs", S_IRUGO, debugfs_dir, - &dsi2_dump_irqs, debug_fops); -} #endif static void dsi_dump_dsidev_regs(struct platform_device *dsidev, @@ -2002,21 +1948,6 @@ static void dsi2_dump_regs(struct seq_file *s) dsi_dump_dsidev_regs(dsidev, s); } -void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, - const struct file_operations *debug_fops) -{ - struct platform_device *dsidev; - - dsidev = dsi_get_dsidev_from_id(0); - if (dsidev) - debugfs_create_file("dsi1_regs", S_IRUGO, debugfs_dir, - &dsi1_dump_regs, debug_fops); - - dsidev = dsi_get_dsidev_from_id(1); - if (dsidev) - debugfs_create_file("dsi2_regs", S_IRUGO, debugfs_dir, - &dsi2_dump_regs, debug_fops); -} enum dsi_cio_power_state { DSI_COMPLEXIO_POWER_OFF = 0x0, DSI_COMPLEXIO_POWER_ON = 0x1, @@ -2073,68 +2004,10 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) return 1365 * 3; /* 1365x24 bits */ default: BUG(); + return 0; } } -static int dsi_parse_lane_config(struct omap_dss_device *dssdev) -{ - struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - u8 lanes[DSI_MAX_NR_LANES]; - u8 polarities[DSI_MAX_NR_LANES]; - int num_lanes, i; - - static const enum dsi_lane_function functions[] = { - DSI_LANE_CLK, - DSI_LANE_DATA1, - DSI_LANE_DATA2, - DSI_LANE_DATA3, - DSI_LANE_DATA4, - }; - - lanes[0] = dssdev->phy.dsi.clk_lane; - lanes[1] = dssdev->phy.dsi.data1_lane; - lanes[2] = dssdev->phy.dsi.data2_lane; - lanes[3] = dssdev->phy.dsi.data3_lane; - lanes[4] = dssdev->phy.dsi.data4_lane; - polarities[0] = dssdev->phy.dsi.clk_pol; - polarities[1] = dssdev->phy.dsi.data1_pol; - polarities[2] = dssdev->phy.dsi.data2_pol; - polarities[3] = dssdev->phy.dsi.data3_pol; - polarities[4] = dssdev->phy.dsi.data4_pol; - - num_lanes = 0; - - for (i = 0; i < dsi->num_lanes_supported; ++i) - dsi->lanes[i].function = DSI_LANE_UNUSED; - - for (i = 0; i < dsi->num_lanes_supported; ++i) { - int num; - - if (lanes[i] == DSI_LANE_UNUSED) - break; - - num = lanes[i] - 1; - - if (num >= dsi->num_lanes_supported) - return -EINVAL; - - if (dsi->lanes[num].function != DSI_LANE_UNUSED) - return -EINVAL; - - dsi->lanes[num].function = functions[i]; - dsi->lanes[num].polarity = polarities[i]; - num_lanes++; - } - - if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported) - return -EINVAL; - - dsi->num_lanes_used = num_lanes; - - return 0; -} - static int dsi_set_lane_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -2396,7 +2269,7 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) DSSDBGF(); - r = dsi->enable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); + r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); if (r) return r; @@ -2506,7 +2379,7 @@ err_cio_pwr: dsi_cio_disable_lane_override(dsidev); err_scp_clk_dom: dsi_disable_scp_clk(dsidev); - dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); + dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); return r; } @@ -2520,7 +2393,7 @@ static void dsi_cio_uninit(struct omap_dss_device *dssdev) dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); dsi_disable_scp_clk(dsidev); - dsi->disable_pads(dsidev->id, dsi_get_lane_mask(dssdev)); + dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dssdev)); } static void dsi_config_tx_fifo(struct platform_device *dsidev, @@ -2544,6 +2417,7 @@ static void dsi_config_tx_fifo(struct platform_device *dsidev, if (add + size > 4) { DSSERR("Illegal FIFO configuration\n"); BUG(); + return; } v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); @@ -2576,6 +2450,7 @@ static void dsi_config_rx_fifo(struct platform_device *dsidev, if (add + size > 4) { DSSERR("Illegal FIFO configuration\n"); BUG(); + return; } v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); @@ -2717,6 +2592,7 @@ static int dsi_sync_vc(struct platform_device *dsidev, int channel) return dsi_sync_vc_l4(dsidev, channel); default: BUG(); + return -EINVAL; } } @@ -3285,6 +3161,7 @@ static int dsi_vc_generic_send_read_request(struct omap_dss_device *dssdev, data = reqdata[0] | (reqdata[1] << 8); } else { BUG(); + return -EINVAL; } r = dsi_vc_send_short(dsidev, channel, data_type, data, 0); @@ -3399,7 +3276,6 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, goto err; } - BUG(); err: DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel, type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS"); @@ -3794,6 +3670,186 @@ static void dsi_config_blanking_modes(struct omap_dss_device *dssdev) dsi_write_reg(dsidev, DSI_CTRL, r); } +/* + * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3 + * results in maximum transition time for data and clock lanes to enter and + * exit HS mode. Hence, this is the scenario where the least amount of command + * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS + * clock cycles that can be used to interleave command mode data in HS so that + * all scenarios are satisfied. + */ +static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs, + int exit_hs, int exiths_clk, int ddr_pre, int ddr_post) +{ + int transition; + + /* + * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition + * time of data lanes only, if it isn't set, we need to consider HS + * transition time of both data and clock lanes. HS transition time + * of Scenario 3 is considered. + */ + if (ddr_alwon) { + transition = enter_hs + exit_hs + max(enter_hs, 2) + 1; + } else { + int trans1, trans2; + trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1; + trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre + + enter_hs + 1; + transition = max(trans1, trans2); + } + + return blank > transition ? blank - transition : 0; +} + +/* + * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1 + * results in maximum transition time for data lanes to enter and exit LP mode. + * Hence, this is the scenario where the least amount of command mode data can + * be interleaved. We program the minimum amount of bytes that can be + * interleaved in LP so that all scenarios are satisfied. + */ +static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs, + int lp_clk_div, int tdsi_fclk) +{ + int trans_lp; /* time required for a LP transition, in TXBYTECLKHS */ + int tlp_avail; /* time left for interleaving commands, in CLKIN4DDR */ + int ttxclkesc; /* period of LP transmit escape clock, in CLKIN4DDR */ + int thsbyte_clk = 16; /* Period of TXBYTECLKHS clock, in CLKIN4DDR */ + int lp_inter; /* cmd mode data that can be interleaved, in bytes */ + + /* maximum LP transition time according to Scenario 1 */ + trans_lp = exit_hs + max(enter_hs, 2) + 1; + + /* CLKIN4DDR = 16 * TXBYTECLKHS */ + tlp_avail = thsbyte_clk * (blank - trans_lp); + + ttxclkesc = tdsi_fclk / lp_clk_div; + + lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc - + 26) / 16; + + return max(lp_inter, 0); +} + +static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + int blanking_mode; + int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; + int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div; + int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; + int tclk_trail, ths_exit, exiths_clk; + bool ddr_alwon; + struct omap_video_timings *timings = &dssdev->panel.timings; + int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); + int ndl = dsi->num_lanes_used - 1; + int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; + int hsa_interleave_hs = 0, hsa_interleave_lp = 0; + int hfp_interleave_hs = 0, hfp_interleave_lp = 0; + int hbp_interleave_hs = 0, hbp_interleave_lp = 0; + int bl_interleave_hs = 0, bl_interleave_lp = 0; + u32 r; + + r = dsi_read_reg(dsidev, DSI_CTRL); + blanking_mode = FLD_GET(r, 20, 20); + hfp_blanking_mode = FLD_GET(r, 21, 21); + hbp_blanking_mode = FLD_GET(r, 22, 22); + hsa_blanking_mode = FLD_GET(r, 23, 23); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING1); + hbp = FLD_GET(r, 11, 0); + hfp = FLD_GET(r, 23, 12); + hsa = FLD_GET(r, 31, 24); + + r = dsi_read_reg(dsidev, DSI_CLK_TIMING); + ddr_clk_post = FLD_GET(r, 7, 0); + ddr_clk_pre = FLD_GET(r, 15, 8); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING7); + exit_hs_mode_lat = FLD_GET(r, 15, 0); + enter_hs_mode_lat = FLD_GET(r, 31, 16); + + r = dsi_read_reg(dsidev, DSI_CLK_CTRL); + lp_clk_div = FLD_GET(r, 12, 0); + ddr_alwon = FLD_GET(r, 13, 13); + + r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); + ths_exit = FLD_GET(r, 7, 0); + + r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); + tclk_trail = FLD_GET(r, 15, 8); + + exiths_clk = ths_exit + tclk_trail; + + width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8); + bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl); + + if (!hsa_blanking_mode) { + hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon, + enter_hs_mode_lat, exit_hs_mode_lat, + exiths_clk, ddr_clk_pre, ddr_clk_post); + hsa_interleave_lp = dsi_compute_interleave_lp(hsa, + enter_hs_mode_lat, exit_hs_mode_lat, + lp_clk_div, dsi_fclk_hsdiv); + } + + if (!hfp_blanking_mode) { + hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon, + enter_hs_mode_lat, exit_hs_mode_lat, + exiths_clk, ddr_clk_pre, ddr_clk_post); + hfp_interleave_lp = dsi_compute_interleave_lp(hfp, + enter_hs_mode_lat, exit_hs_mode_lat, + lp_clk_div, dsi_fclk_hsdiv); + } + + if (!hbp_blanking_mode) { + hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon, + enter_hs_mode_lat, exit_hs_mode_lat, + exiths_clk, ddr_clk_pre, ddr_clk_post); + + hbp_interleave_lp = dsi_compute_interleave_lp(hbp, + enter_hs_mode_lat, exit_hs_mode_lat, + lp_clk_div, dsi_fclk_hsdiv); + } + + if (!blanking_mode) { + bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon, + enter_hs_mode_lat, exit_hs_mode_lat, + exiths_clk, ddr_clk_pre, ddr_clk_post); + + bl_interleave_lp = dsi_compute_interleave_lp(bllp, + enter_hs_mode_lat, exit_hs_mode_lat, + lp_clk_div, dsi_fclk_hsdiv); + } + + DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n", + hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs, + bl_interleave_hs); + + DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n", + hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp, + bl_interleave_lp); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING4); + r = FLD_MOD(r, hsa_interleave_hs, 23, 16); + r = FLD_MOD(r, hfp_interleave_hs, 15, 8); + r = FLD_MOD(r, hbp_interleave_hs, 7, 0); + dsi_write_reg(dsidev, DSI_VM_TIMING4, r); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING5); + r = FLD_MOD(r, hsa_interleave_lp, 23, 16); + r = FLD_MOD(r, hfp_interleave_lp, 15, 8); + r = FLD_MOD(r, hbp_interleave_lp, 7, 0); + dsi_write_reg(dsidev, DSI_VM_TIMING5, r); + + r = dsi_read_reg(dsidev, DSI_VM_TIMING6); + r = FLD_MOD(r, bl_interleave_hs, 31, 15); + r = FLD_MOD(r, bl_interleave_lp, 16, 0); + dsi_write_reg(dsidev, DSI_VM_TIMING6, r); +} + static int dsi_proto_config(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -3828,6 +3884,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) break; default: BUG(); + return -EINVAL; } r = dsi_read_reg(dsidev, DSI_CTRL); @@ -3852,6 +3909,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { dsi_config_vp_sync_events(dssdev); dsi_config_blanking_modes(dssdev); + dsi_config_cmd_mode_interleaving(dssdev); } dsi_vc_initial_config(dsidev, 0); @@ -3975,6 +4033,74 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) } } +int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, + const struct omap_dsi_pin_config *pin_cfg) +{ + struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + int num_pins; + const int *pins; + struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; + int num_lanes; + int i; + + static const enum dsi_lane_function functions[] = { + DSI_LANE_CLK, + DSI_LANE_DATA1, + DSI_LANE_DATA2, + DSI_LANE_DATA3, + DSI_LANE_DATA4, + }; + + num_pins = pin_cfg->num_pins; + pins = pin_cfg->pins; + + if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2 + || num_pins % 2 != 0) + return -EINVAL; + + for (i = 0; i < DSI_MAX_NR_LANES; ++i) + lanes[i].function = DSI_LANE_UNUSED; + + num_lanes = 0; + + for (i = 0; i < num_pins; i += 2) { + u8 lane, pol; + int dx, dy; + + dx = pins[i]; + dy = pins[i + 1]; + + if (dx < 0 || dx >= dsi->num_lanes_supported * 2) + return -EINVAL; + + if (dy < 0 || dy >= dsi->num_lanes_supported * 2) + return -EINVAL; + + if (dx & 1) { + if (dy != dx - 1) + return -EINVAL; + pol = 1; + } else { + if (dy != dx + 1) + return -EINVAL; + pol = 0; + } + + lane = dx / 2; + + lanes[lane].function = functions[i / 2]; + lanes[lane].polarity = pol; + num_lanes++; + } + + memcpy(dsi->lanes, lanes, sizeof(dsi->lanes)); + dsi->num_lanes_used = num_lanes; + + return 0; +} +EXPORT_SYMBOL(omapdss_dsi_configure_pins); + int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); @@ -3999,6 +4125,7 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) break; default: BUG(); + return -EINVAL; }; dsi_if_enable(dsidev, false); @@ -4183,10 +4310,6 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) __cancel_delayed_work(&dsi->framedone_timeout_work); dsi_handle_framedone(dsidev, 0); - -#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC - dispc_fake_vsync_irq(); -#endif } int omap_dsi_update(struct omap_dss_device *dssdev, int channel, @@ -4250,13 +4373,12 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) dispc_mgr_enable_stallmode(dssdev->manager->id, true); dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 1); - dispc_mgr_set_lcd_timings(dssdev->manager->id, &timings); + dss_mgr_set_timings(dssdev->manager, &timings); } else { dispc_mgr_enable_stallmode(dssdev->manager->id, false); dispc_mgr_enable_fifohandcheck(dssdev->manager->id, 0); - dispc_mgr_set_lcd_timings(dssdev->manager->id, - &dssdev->panel.timings); + dss_mgr_set_timings(dssdev->manager, &dssdev->panel.timings); } dispc_mgr_set_lcd_display_type(dssdev->manager->id, @@ -4285,13 +4407,11 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) struct dsi_clock_info cinfo; int r; - /* we always use DSS_CLK_SYSCK as input clock */ - cinfo.use_sys_clk = true; cinfo.regn = dssdev->clocks.dsi.regn; cinfo.regm = dssdev->clocks.dsi.regm; cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc; cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi; - r = dsi_calc_clock_rates(dssdev, &cinfo); + r = dsi_calc_clock_rates(dsidev, &cinfo); if (r) { DSSERR("Failed to calc dsi clocks\n"); return r; @@ -4336,15 +4456,9 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) static int dsi_display_init_dsi(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); - int dsi_module = dsi_get_dsidev_id(dsidev); + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); int r; - r = dsi_parse_lane_config(dssdev); - if (r) { - DSSERR("illegal lane config"); - goto err0; - } - r = dsi_pll_init(dsidev, true, true); if (r) goto err0; @@ -4354,7 +4468,7 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) goto err1; dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); - dss_select_dsi_clk_source(dsi_module, dssdev->clocks.dsi.dsi_fclk_src); + dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); dss_select_lcd_clk_source(dssdev->manager->id, dssdev->clocks.dispc.channel.lcd_clk_src); @@ -4393,7 +4507,7 @@ err3: dsi_cio_uninit(dssdev); err2: dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); - dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); err1: @@ -4407,7 +4521,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - int dsi_module = dsi_get_dsidev_id(dsidev); if (enter_ulps && !dsi->ulps_enabled) dsi_enter_ulps(dsidev); @@ -4420,7 +4533,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, dsi_vc_enable(dsidev, 3, 0); dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); - dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(dssdev->manager->id, OMAP_DSS_CLK_SRC_FCK); dsi_cio_uninit(dssdev); dsi_pll_uninit(dsidev, disconnect_lanes); @@ -4524,7 +4637,7 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) } EXPORT_SYMBOL(omapdss_dsi_enable_te); -int dsi_init_display(struct omap_dss_device *dssdev) +static int __init dsi_init_display(struct omap_dss_device *dssdev) { struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); @@ -4677,13 +4790,39 @@ static void dsi_put_clocks(struct platform_device *dsidev) clk_put(dsi->sys_clk); } +static void __init dsi_probe_pdata(struct platform_device *dsidev) +{ + struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + struct omap_dss_board_info *pdata = dsidev->dev.platform_data; + int i, r; + + for (i = 0; i < pdata->num_devices; ++i) { + struct omap_dss_device *dssdev = pdata->devices[i]; + + if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) + continue; + + if (dssdev->phy.dsi.module != dsi->module_id) + continue; + + r = dsi_init_display(dssdev); + if (r) { + DSSERR("device %s init failed: %d\n", dssdev->name, r); + continue; + } + + r = omap_dss_register_device(dssdev, &dsidev->dev, i); + if (r) + DSSERR("device %s register failed: %d\n", + dssdev->name, r); + } +} + /* DSI1 HW IP initialisation */ -static int omap_dsihw_probe(struct platform_device *dsidev) +static int __init omap_dsihw_probe(struct platform_device *dsidev) { - struct omap_display_platform_data *dss_plat_data; - struct omap_dss_board_info *board_info; u32 rev; - int r, i, dsi_module = dsi_get_dsidev_id(dsidev); + int r, i; struct resource *dsi_mem; struct dsi_data *dsi; @@ -4691,15 +4830,11 @@ static int omap_dsihw_probe(struct platform_device *dsidev) if (!dsi) return -ENOMEM; + dsi->module_id = dsidev->id; dsi->pdev = dsidev; - dsi_pdev_map[dsi_module] = dsidev; + dsi_pdev_map[dsi->module_id] = dsidev; dev_set_drvdata(&dsidev->dev, dsi); - dss_plat_data = dsidev->dev.platform_data; - board_info = dss_plat_data->board_data; - dsi->enable_pads = board_info->dsi_enable_pads; - dsi->disable_pads = board_info->dsi_disable_pads; - spin_lock_init(&dsi->irq_lock); spin_lock_init(&dsi->errors_lock); dsi->errors = 0; @@ -4777,8 +4912,21 @@ static int omap_dsihw_probe(struct platform_device *dsidev) else dsi->num_lanes_supported = 3; + dsi_probe_pdata(dsidev); + dsi_runtime_put(dsidev); + if (dsi->module_id == 0) + dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs); + else if (dsi->module_id == 1) + dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs); + +#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS + if (dsi->module_id == 0) + dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs); + else if (dsi->module_id == 1) + dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); +#endif return 0; err_runtime_get: @@ -4787,12 +4935,14 @@ err_runtime_get: return r; } -static int omap_dsihw_remove(struct platform_device *dsidev) +static int __exit omap_dsihw_remove(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); WARN_ON(dsi->scp_clk_refcount > 0); + omap_dss_unregister_child_devices(&dsidev->dev); + pm_runtime_disable(&dsidev->dev); dsi_put_clocks(dsidev); @@ -4813,7 +4963,6 @@ static int omap_dsihw_remove(struct platform_device *dsidev) static int dsi_runtime_suspend(struct device *dev) { dispc_runtime_put(); - dss_runtime_put(); return 0; } @@ -4822,20 +4971,11 @@ static int dsi_runtime_resume(struct device *dev) { int r; - r = dss_runtime_get(); - if (r) - goto err_get_dss; - r = dispc_runtime_get(); if (r) - goto err_get_dispc; + return r; return 0; - -err_get_dispc: - dss_runtime_put(); -err_get_dss: - return r; } static const struct dev_pm_ops dsi_pm_ops = { @@ -4844,8 +4984,7 @@ static const struct dev_pm_ops dsi_pm_ops = { }; static struct platform_driver omap_dsihw_driver = { - .probe = omap_dsihw_probe, - .remove = omap_dsihw_remove, + .remove = __exit_p(omap_dsihw_remove), .driver = { .name = "omapdss_dsi", .owner = THIS_MODULE, @@ -4853,12 +4992,12 @@ static struct platform_driver omap_dsihw_driver = { }, }; -int dsi_init_platform_driver(void) +int __init dsi_init_platform_driver(void) { - return platform_driver_register(&omap_dsihw_driver); + return platform_driver_probe(&omap_dsihw_driver, omap_dsihw_probe); } -void dsi_uninit_platform_driver(void) +void __exit dsi_uninit_platform_driver(void) { - return platform_driver_unregister(&omap_dsihw_driver); + platform_driver_unregister(&omap_dsihw_driver); } |