|
@@ -200,6 +200,11 @@ struct dsi_reg { u16 idx; };
|
|
|
|
|
|
typedef void (*omap_dsi_isr_t) (void *arg, u32 mask);
|
|
|
|
|
|
+static int dsi_display_init_dispc(struct platform_device *dsidev,
|
|
|
+ struct omap_overlay_manager *mgr);
|
|
|
+static void dsi_display_uninit_dispc(struct platform_device *dsidev,
|
|
|
+ struct omap_overlay_manager *mgr);
|
|
|
+
|
|
|
#define DSI_MAX_NR_ISRS 2
|
|
|
#define DSI_MAX_NR_LANES 5
|
|
|
|
|
@@ -250,6 +255,24 @@ struct dsi_isr_tables {
|
|
|
struct dsi_isr_data isr_table_cio[DSI_MAX_NR_ISRS];
|
|
|
};
|
|
|
|
|
|
+struct dsi_clk_calc_ctx {
|
|
|
+ struct platform_device *dsidev;
|
|
|
+
|
|
|
+ /* inputs */
|
|
|
+
|
|
|
+ const struct omap_dss_dsi_config *config;
|
|
|
+
|
|
|
+ unsigned long req_pck_min, req_pck_nom, req_pck_max;
|
|
|
+
|
|
|
+ /* outputs */
|
|
|
+
|
|
|
+ struct dsi_clock_info dsi_cinfo;
|
|
|
+ struct dispc_clock_info dispc_cinfo;
|
|
|
+
|
|
|
+ struct omap_video_timings dispc_vm;
|
|
|
+ struct omap_dss_dsi_videomode_timings dsi_vm;
|
|
|
+};
|
|
|
+
|
|
|
struct dsi_data {
|
|
|
struct platform_device *pdev;
|
|
|
void __iomem *base;
|
|
@@ -261,6 +284,9 @@ struct dsi_data {
|
|
|
struct clk *dss_clk;
|
|
|
struct clk *sys_clk;
|
|
|
|
|
|
+ struct dispc_clock_info user_dispc_cinfo;
|
|
|
+ struct dsi_clock_info user_dsi_cinfo;
|
|
|
+
|
|
|
struct dsi_clock_info current_cinfo;
|
|
|
|
|
|
bool vdds_dsi_enabled;
|
|
@@ -324,6 +350,7 @@ struct dsi_data {
|
|
|
unsigned long lpdiv_max;
|
|
|
|
|
|
unsigned num_lanes_supported;
|
|
|
+ unsigned line_buffer_size;
|
|
|
|
|
|
struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
|
|
|
unsigned num_lanes_used;
|
|
@@ -1192,15 +1219,33 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
-static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
|
|
|
+static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
|
|
|
+ unsigned long lp_clk_min, unsigned long lp_clk_max)
|
|
|
+{
|
|
|
+ unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk;
|
|
|
+ unsigned lp_clk_div;
|
|
|
+ unsigned long lp_clk;
|
|
|
+
|
|
|
+ lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk_max * 2);
|
|
|
+ lp_clk = dsi_fclk / 2 / lp_clk_div;
|
|
|
+
|
|
|
+ if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ cinfo->lp_clk_div = lp_clk_div;
|
|
|
+ cinfo->lp_clk = lp_clk;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
unsigned long dsi_fclk;
|
|
|
unsigned lp_clk_div;
|
|
|
unsigned long lp_clk;
|
|
|
|
|
|
- lp_clk_div = dssdev->clocks.dsi.lp_clk_div;
|
|
|
+ lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div;
|
|
|
|
|
|
if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
|
|
|
return -EINVAL;
|
|
@@ -1272,6 +1317,75 @@ static int dsi_pll_power(struct platform_device *dsidev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
|
|
|
+{
|
|
|
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
+ return clk_get_rate(dsi->sys_clk);
|
|
|
+}
|
|
|
+
|
|
|
+bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
|
|
|
+ unsigned long out_min, dsi_hsdiv_calc_func func, void *data)
|
|
|
+{
|
|
|
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
+ int regm, regm_start, regm_stop;
|
|
|
+ unsigned long out_max;
|
|
|
+ unsigned long out;
|
|
|
+
|
|
|
+ out_min = out_min ? out_min : 1;
|
|
|
+ out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
|
|
|
+
|
|
|
+ regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul);
|
|
|
+ regm_stop = min(pll / out_min, dsi->regm_dispc_max);
|
|
|
+
|
|
|
+ for (regm = regm_start; regm <= regm_stop; ++regm) {
|
|
|
+ out = pll / regm;
|
|
|
+
|
|
|
+ if (func(regm, out, data))
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
|
|
|
+ unsigned long pll_min, unsigned long pll_max,
|
|
|
+ dsi_pll_calc_func func, void *data)
|
|
|
+{
|
|
|
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
+ int regn, regn_start, regn_stop;
|
|
|
+ int regm, regm_start, regm_stop;
|
|
|
+ unsigned long fint, pll;
|
|
|
+ const unsigned long pll_hw_max = 1800000000;
|
|
|
+ unsigned long fint_hw_min, fint_hw_max;
|
|
|
+
|
|
|
+ fint_hw_min = dsi->fint_min;
|
|
|
+ fint_hw_max = dsi->fint_max;
|
|
|
+
|
|
|
+ regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
|
|
|
+ regn_stop = min(clkin / fint_hw_min, dsi->regn_max);
|
|
|
+
|
|
|
+ pll_max = pll_max ? pll_max : ULONG_MAX;
|
|
|
+
|
|
|
+ for (regn = regn_start; regn <= regn_stop; ++regn) {
|
|
|
+ fint = clkin / regn;
|
|
|
+
|
|
|
+ regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
|
|
|
+ 1ul);
|
|
|
+ regm_stop = min3(pll_max / fint / 2,
|
|
|
+ pll_hw_max / fint / 2,
|
|
|
+ dsi->regm_max);
|
|
|
+
|
|
|
+ for (regm = regm_start; regm <= regm_stop; ++regm) {
|
|
|
+ pll = 2 * regm * fint;
|
|
|
+
|
|
|
+ if (func(regn, regm, fint, pll, data))
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
/* calculate clock rates using dividers in cinfo */
|
|
|
static int dsi_calc_clock_rates(struct platform_device *dsidev,
|
|
|
struct dsi_clock_info *cinfo)
|
|
@@ -1316,192 +1430,7 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev,
|
|
|
- unsigned long req_pck, struct dsi_clock_info *dsi_cinfo,
|
|
|
- struct dispc_clock_info *dispc_cinfo)
|
|
|
-{
|
|
|
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct dsi_clock_info cur, best;
|
|
|
- struct dispc_clock_info best_dispc;
|
|
|
- int min_fck_per_pck;
|
|
|
- int match = 0;
|
|
|
- unsigned long dss_sys_clk, max_dss_fck;
|
|
|
-
|
|
|
- dss_sys_clk = clk_get_rate(dsi->sys_clk);
|
|
|
-
|
|
|
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
|
|
|
-
|
|
|
- if (req_pck == dsi->cache_req_pck &&
|
|
|
- dsi->cache_cinfo.clkin == dss_sys_clk) {
|
|
|
- DSSDBG("DSI clock info found from cache\n");
|
|
|
- *dsi_cinfo = dsi->cache_cinfo;
|
|
|
- dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk,
|
|
|
- dispc_cinfo);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
|
|
|
-
|
|
|
- if (min_fck_per_pck &&
|
|
|
- req_pck * min_fck_per_pck > max_dss_fck) {
|
|
|
- DSSERR("Requested pixel clock not possible with the current "
|
|
|
- "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
|
|
|
- "the constraint off.\n");
|
|
|
- min_fck_per_pck = 0;
|
|
|
- }
|
|
|
-
|
|
|
- DSSDBG("dsi_pll_calc\n");
|
|
|
-
|
|
|
-retry:
|
|
|
- memset(&best, 0, sizeof(best));
|
|
|
- memset(&best_dispc, 0, sizeof(best_dispc));
|
|
|
-
|
|
|
- memset(&cur, 0, sizeof(cur));
|
|
|
- cur.clkin = dss_sys_clk;
|
|
|
-
|
|
|
- /* 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) {
|
|
|
- cur.fint = cur.clkin / cur.regn;
|
|
|
-
|
|
|
- if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min)
|
|
|
- continue;
|
|
|
-
|
|
|
- /* 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.clkin4ddr = a / b * 1000;
|
|
|
-
|
|
|
- if (cur.clkin4ddr > 1800 * 1000 * 1000)
|
|
|
- break;
|
|
|
-
|
|
|
- /* dsi_pll_hsdiv_dispc_clk(MHz) =
|
|
|
- * DSIPHY(MHz) / regm_dispc < 173MHz/186Mhz */
|
|
|
- for (cur.regm_dispc = 1; cur.regm_dispc <
|
|
|
- dsi->regm_dispc_max; ++cur.regm_dispc) {
|
|
|
- struct dispc_clock_info cur_dispc;
|
|
|
- cur.dsi_pll_hsdiv_dispc_clk =
|
|
|
- cur.clkin4ddr / cur.regm_dispc;
|
|
|
-
|
|
|
- if (cur.regm_dispc > 1 &&
|
|
|
- cur.regm_dispc % 2 != 0 &&
|
|
|
- req_pck >= 1000000)
|
|
|
- continue;
|
|
|
-
|
|
|
- /* this will narrow down the search a bit,
|
|
|
- * but still give pixclocks below what was
|
|
|
- * requested */
|
|
|
- if (cur.dsi_pll_hsdiv_dispc_clk < req_pck)
|
|
|
- break;
|
|
|
-
|
|
|
- if (cur.dsi_pll_hsdiv_dispc_clk > max_dss_fck)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (min_fck_per_pck &&
|
|
|
- cur.dsi_pll_hsdiv_dispc_clk <
|
|
|
- req_pck * min_fck_per_pck)
|
|
|
- continue;
|
|
|
-
|
|
|
- match = 1;
|
|
|
-
|
|
|
- dispc_find_clk_divs(req_pck,
|
|
|
- cur.dsi_pll_hsdiv_dispc_clk,
|
|
|
- &cur_dispc);
|
|
|
-
|
|
|
- if (abs(cur_dispc.pck - req_pck) <
|
|
|
- abs(best_dispc.pck - req_pck)) {
|
|
|
- best = cur;
|
|
|
- best_dispc = cur_dispc;
|
|
|
-
|
|
|
- if (cur_dispc.pck == req_pck)
|
|
|
- goto found;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-found:
|
|
|
- if (!match) {
|
|
|
- if (min_fck_per_pck) {
|
|
|
- DSSERR("Could not find suitable clock settings.\n"
|
|
|
- "Turning FCK/PCK constraint off and"
|
|
|
- "trying again.\n");
|
|
|
- min_fck_per_pck = 0;
|
|
|
- goto retry;
|
|
|
- }
|
|
|
-
|
|
|
- DSSERR("Could not find suitable clock settings.\n");
|
|
|
-
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- /* dsi_pll_hsdiv_dsi_clk (regm_dsi) is not used */
|
|
|
- best.regm_dsi = 0;
|
|
|
- best.dsi_pll_hsdiv_dsi_clk = 0;
|
|
|
-
|
|
|
- if (dsi_cinfo)
|
|
|
- *dsi_cinfo = best;
|
|
|
- if (dispc_cinfo)
|
|
|
- *dispc_cinfo = best_dispc;
|
|
|
-
|
|
|
- dsi->cache_req_pck = req_pck;
|
|
|
- dsi->cache_clk_freq = 0;
|
|
|
- dsi->cache_cinfo = best;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
|
|
|
- unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
|
|
|
-{
|
|
|
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct dsi_clock_info cur, best;
|
|
|
-
|
|
|
- DSSDBG("dsi_pll_calc_ddrfreq\n");
|
|
|
-
|
|
|
- memset(&best, 0, sizeof(best));
|
|
|
- memset(&cur, 0, sizeof(cur));
|
|
|
-
|
|
|
- cur.clkin = clk_get_rate(dsi->sys_clk);
|
|
|
-
|
|
|
- for (cur.regn = 1; cur.regn < dsi->regn_max; ++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 */
|
|
|
- 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.clkin4ddr = a / b * 1000;
|
|
|
-
|
|
|
- if (cur.clkin4ddr > 1800 * 1000 * 1000)
|
|
|
- break;
|
|
|
-
|
|
|
- if (abs(cur.clkin4ddr - req_clkin4ddr) <
|
|
|
- abs(best.clkin4ddr - req_clkin4ddr)) {
|
|
|
- best = cur;
|
|
|
- DSSDBG("best %ld\n", best.clkin4ddr);
|
|
|
- }
|
|
|
-
|
|
|
- if (cur.clkin4ddr == req_clkin4ddr)
|
|
|
- goto found;
|
|
|
- }
|
|
|
- }
|
|
|
-found:
|
|
|
- if (cinfo)
|
|
|
- *cinfo = best;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
|
|
|
- struct dsi_clock_info *cinfo)
|
|
|
+static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
|
|
|
{
|
|
|
unsigned long max_dsi_fck;
|
|
|
|
|
@@ -1511,90 +1440,6 @@ static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
|
|
|
cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
|
|
|
}
|
|
|
|
|
|
-static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev,
|
|
|
- unsigned long req_pck, struct dsi_clock_info *cinfo,
|
|
|
- struct dispc_clock_info *dispc_cinfo)
|
|
|
-{
|
|
|
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- unsigned regm_dispc, best_regm_dispc;
|
|
|
- unsigned long dispc_clk, best_dispc_clk;
|
|
|
- int min_fck_per_pck;
|
|
|
- unsigned long max_dss_fck;
|
|
|
- struct dispc_clock_info best_dispc;
|
|
|
- bool match;
|
|
|
-
|
|
|
- max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
|
|
|
-
|
|
|
- min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
|
|
|
-
|
|
|
- if (min_fck_per_pck &&
|
|
|
- req_pck * min_fck_per_pck > max_dss_fck) {
|
|
|
- DSSERR("Requested pixel clock not possible with the current "
|
|
|
- "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
|
|
|
- "the constraint off.\n");
|
|
|
- min_fck_per_pck = 0;
|
|
|
- }
|
|
|
-
|
|
|
-retry:
|
|
|
- best_regm_dispc = 0;
|
|
|
- best_dispc_clk = 0;
|
|
|
- memset(&best_dispc, 0, sizeof(best_dispc));
|
|
|
- match = false;
|
|
|
-
|
|
|
- for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) {
|
|
|
- struct dispc_clock_info cur_dispc;
|
|
|
-
|
|
|
- dispc_clk = cinfo->clkin4ddr / regm_dispc;
|
|
|
-
|
|
|
- /* this will narrow down the search a bit,
|
|
|
- * but still give pixclocks below what was
|
|
|
- * requested */
|
|
|
- if (dispc_clk < req_pck)
|
|
|
- break;
|
|
|
-
|
|
|
- if (dispc_clk > max_dss_fck)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck)
|
|
|
- continue;
|
|
|
-
|
|
|
- match = true;
|
|
|
-
|
|
|
- dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc);
|
|
|
-
|
|
|
- if (abs(cur_dispc.pck - req_pck) <
|
|
|
- abs(best_dispc.pck - req_pck)) {
|
|
|
- best_regm_dispc = regm_dispc;
|
|
|
- best_dispc_clk = dispc_clk;
|
|
|
- best_dispc = cur_dispc;
|
|
|
-
|
|
|
- if (cur_dispc.pck == req_pck)
|
|
|
- goto found;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (!match) {
|
|
|
- if (min_fck_per_pck) {
|
|
|
- DSSERR("Could not find suitable clock settings.\n"
|
|
|
- "Turning FCK/PCK constraint off and"
|
|
|
- "trying again.\n");
|
|
|
- min_fck_per_pck = 0;
|
|
|
- goto retry;
|
|
|
- }
|
|
|
-
|
|
|
- DSSERR("Could not find suitable clock settings.\n");
|
|
|
-
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-found:
|
|
|
- cinfo->regm_dispc = best_regm_dispc;
|
|
|
- cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk;
|
|
|
-
|
|
|
- *dispc_cinfo = best_dispc;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
int dsi_pll_set_clock_div(struct platform_device *dsidev,
|
|
|
struct dsi_clock_info *cinfo)
|
|
|
{
|
|
@@ -2783,6 +2628,7 @@ static int dsi_vc_enable(struct platform_device *dsidev, int channel,
|
|
|
|
|
|
static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
|
|
|
{
|
|
|
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
u32 r;
|
|
|
|
|
|
DSSDBG("Initial config of virtual channel %d", channel);
|
|
@@ -2807,6 +2653,8 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
|
|
|
r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
|
|
|
|
|
|
dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r);
|
|
|
+
|
|
|
+ dsi->vc[channel].source = DSI_VC_SOURCE_L4;
|
|
|
}
|
|
|
|
|
|
static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
|
|
@@ -3777,13 +3625,12 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
|
|
|
|
|
|
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
|
|
|
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
|
|
|
- unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
|
|
|
struct omap_video_timings *timings = &dsi->timings;
|
|
|
/*
|
|
|
* Don't use line buffers if width is greater than the video
|
|
|
* port's line buffer size
|
|
|
*/
|
|
|
- if (line_buf_size <= timings->x_res * bpp / 8)
|
|
|
+ if (dsi->line_buffer_size <= timings->x_res * bpp / 8)
|
|
|
num_line_buffers = 0;
|
|
|
else
|
|
|
num_line_buffers = 2;
|
|
@@ -3799,18 +3646,22 @@ static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev)
|
|
|
static void dsi_config_vp_sync_events(struct platform_device *dsidev)
|
|
|
{
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- bool vsync_end = dsi->vm_timings.vp_vsync_end;
|
|
|
- bool hsync_end = dsi->vm_timings.vp_hsync_end;
|
|
|
+ bool sync_end;
|
|
|
u32 r;
|
|
|
|
|
|
+ if (dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE)
|
|
|
+ sync_end = true;
|
|
|
+ else
|
|
|
+ sync_end = false;
|
|
|
+
|
|
|
r = dsi_read_reg(dsidev, DSI_CTRL);
|
|
|
r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */
|
|
|
r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */
|
|
|
r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */
|
|
|
r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */
|
|
|
- r = FLD_MOD(r, vsync_end, 16, 16); /* VP_VSYNC_END */
|
|
|
+ r = FLD_MOD(r, sync_end, 16, 16); /* VP_VSYNC_END */
|
|
|
r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */
|
|
|
- r = FLD_MOD(r, hsync_end, 18, 18); /* VP_HSYNC_END */
|
|
|
+ r = FLD_MOD(r, sync_end, 18, 18); /* VP_HSYNC_END */
|
|
|
dsi_write_reg(dsidev, DSI_CTRL, r);
|
|
|
}
|
|
|
|
|
@@ -3897,9 +3748,8 @@ static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs,
|
|
|
return max(lp_inter, 0);
|
|
|
}
|
|
|
|
|
|
-static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
|
|
|
+static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev)
|
|
|
{
|
|
|
- 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;
|
|
@@ -3910,7 +3760,7 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
|
|
|
struct omap_video_timings *timings = &dsi->timings;
|
|
|
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
|
|
|
int ndl = dsi->num_lanes_used - 1;
|
|
|
- int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1;
|
|
|
+ int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.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;
|
|
@@ -4015,9 +3865,8 @@ static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev)
|
|
|
dsi_write_reg(dsidev, DSI_VM_TIMING6, r);
|
|
|
}
|
|
|
|
|
|
-static int dsi_proto_config(struct omap_dss_device *dssdev)
|
|
|
+static int dsi_proto_config(struct platform_device *dsidev)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
u32 r;
|
|
|
int buswidth = 0;
|
|
@@ -4075,7 +3924,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
|
|
|
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
|
|
|
dsi_config_vp_sync_events(dsidev);
|
|
|
dsi_config_blanking_modes(dsidev);
|
|
|
- dsi_config_cmd_mode_interleaving(dssdev);
|
|
|
+ dsi_config_cmd_mode_interleaving(dsidev);
|
|
|
}
|
|
|
|
|
|
dsi_vc_initial_config(dsidev, 0);
|
|
@@ -4159,11 +4008,12 @@ static void dsi_proto_timings(struct platform_device *dsidev)
|
|
|
int vfp = dsi->vm_timings.vfp;
|
|
|
int vbp = dsi->vm_timings.vbp;
|
|
|
int window_sync = dsi->vm_timings.window_sync;
|
|
|
- bool hsync_end = dsi->vm_timings.vp_hsync_end;
|
|
|
+ bool hsync_end;
|
|
|
struct omap_video_timings *timings = &dsi->timings;
|
|
|
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
|
|
|
int tl, t_he, width_bytes;
|
|
|
|
|
|
+ hsync_end = dsi->vm_timings.trans_mode == OMAP_DSS_DSI_PULSE_MODE;
|
|
|
t_he = hsync_end ?
|
|
|
((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0;
|
|
|
|
|
@@ -4266,82 +4116,26 @@ int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
|
|
|
}
|
|
|
EXPORT_SYMBOL(omapdss_dsi_configure_pins);
|
|
|
|
|
|
-int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
|
|
|
- unsigned long ddr_clk, unsigned long lp_clk)
|
|
|
-{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct dsi_clock_info cinfo;
|
|
|
- struct dispc_clock_info dispc_cinfo;
|
|
|
- unsigned lp_clk_div;
|
|
|
- unsigned long dsi_fclk;
|
|
|
- int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt);
|
|
|
- unsigned long pck;
|
|
|
- int r;
|
|
|
-
|
|
|
- DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk);
|
|
|
-
|
|
|
- mutex_lock(&dsi->lock);
|
|
|
-
|
|
|
- /* Calculate PLL output clock */
|
|
|
- r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
|
|
|
- if (r)
|
|
|
- goto err;
|
|
|
-
|
|
|
- /* Calculate PLL's DSI clock */
|
|
|
- dsi_pll_calc_dsi_fck(dsidev, &cinfo);
|
|
|
-
|
|
|
- /* Calculate PLL's DISPC clock and pck & lck divs */
|
|
|
- pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
|
|
|
- DSSDBG("finding dispc dividers for pck %lu\n", pck);
|
|
|
- r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo);
|
|
|
- if (r)
|
|
|
- goto err;
|
|
|
-
|
|
|
- /* Calculate LP clock */
|
|
|
- dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
|
|
|
- lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
|
|
|
-
|
|
|
- dssdev->clocks.dsi.regn = cinfo.regn;
|
|
|
- dssdev->clocks.dsi.regm = cinfo.regm;
|
|
|
- dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
|
|
|
- dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
|
|
|
-
|
|
|
- dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
|
|
|
-
|
|
|
- dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
|
|
|
- dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
|
|
|
-
|
|
|
- dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK;
|
|
|
-
|
|
|
- dssdev->clocks.dispc.channel.lcd_clk_src =
|
|
|
- dsi->module_id == 0 ?
|
|
|
- OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
|
|
|
- OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
|
|
|
-
|
|
|
- dssdev->clocks.dsi.dsi_fclk_src =
|
|
|
- dsi->module_id == 0 ?
|
|
|
- OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
|
|
|
- OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI;
|
|
|
-
|
|
|
- mutex_unlock(&dsi->lock);
|
|
|
- return 0;
|
|
|
-err:
|
|
|
- mutex_unlock(&dsi->lock);
|
|
|
- return r;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(omapdss_dsi_set_clocks);
|
|
|
-
|
|
|
int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
|
|
|
{
|
|
|
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct omap_overlay_manager *mgr = dssdev->output->manager;
|
|
|
+ struct omap_overlay_manager *mgr = dsi->output.manager;
|
|
|
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
|
|
|
+ struct omap_dss_output *out = &dsi->output;
|
|
|
u8 data_type;
|
|
|
u16 word_count;
|
|
|
int r;
|
|
|
|
|
|
+ if (out == NULL || out->manager == NULL) {
|
|
|
+ DSSERR("failed to enable display: no output/manager\n");
|
|
|
+ return -ENODEV;
|
|
|
+ }
|
|
|
+
|
|
|
+ r = dsi_display_init_dispc(dsidev, mgr);
|
|
|
+ if (r)
|
|
|
+ goto err_init_dispc;
|
|
|
+
|
|
|
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
|
|
|
switch (dsi->pix_fmt) {
|
|
|
case OMAP_DSS_DSI_FMT_RGB888:
|
|
@@ -4357,8 +4151,8 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
|
|
|
data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16;
|
|
|
break;
|
|
|
default:
|
|
|
- BUG();
|
|
|
- return -EINVAL;
|
|
|
+ r = -EINVAL;
|
|
|
+ goto err_pix_fmt;
|
|
|
};
|
|
|
|
|
|
dsi_if_enable(dsidev, false);
|
|
@@ -4377,16 +4171,20 @@ int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
|
|
|
}
|
|
|
|
|
|
r = dss_mgr_enable(mgr);
|
|
|
- if (r) {
|
|
|
- if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
|
|
|
- dsi_if_enable(dsidev, false);
|
|
|
- dsi_vc_enable(dsidev, channel, false);
|
|
|
- }
|
|
|
-
|
|
|
- return r;
|
|
|
- }
|
|
|
+ if (r)
|
|
|
+ goto err_mgr_enable;
|
|
|
|
|
|
return 0;
|
|
|
+
|
|
|
+err_mgr_enable:
|
|
|
+ if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
|
|
|
+ dsi_if_enable(dsidev, false);
|
|
|
+ dsi_vc_enable(dsidev, channel, false);
|
|
|
+ }
|
|
|
+err_pix_fmt:
|
|
|
+ dsi_display_uninit_dispc(dsidev, mgr);
|
|
|
+err_init_dispc:
|
|
|
+ return r;
|
|
|
}
|
|
|
EXPORT_SYMBOL(dsi_enable_video_output);
|
|
|
|
|
@@ -4394,7 +4192,7 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
|
|
|
{
|
|
|
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct omap_overlay_manager *mgr = dssdev->output->manager;
|
|
|
+ struct omap_overlay_manager *mgr = dsi->output.manager;
|
|
|
|
|
|
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
|
|
|
dsi_if_enable(dsidev, false);
|
|
@@ -4408,14 +4206,15 @@ void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel)
|
|
|
}
|
|
|
|
|
|
dss_mgr_disable(mgr);
|
|
|
+
|
|
|
+ dsi_display_uninit_dispc(dsidev, mgr);
|
|
|
}
|
|
|
EXPORT_SYMBOL(dsi_disable_video_output);
|
|
|
|
|
|
-static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
|
|
|
+static void dsi_update_screen_dispc(struct platform_device *dsidev)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct omap_overlay_manager *mgr = dssdev->output->manager;
|
|
|
+ struct omap_overlay_manager *mgr = dsi->output.manager;
|
|
|
unsigned bytespp;
|
|
|
unsigned bytespl;
|
|
|
unsigned bytespf;
|
|
@@ -4425,7 +4224,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev)
|
|
|
u32 l;
|
|
|
int r;
|
|
|
const unsigned channel = dsi->update_channel;
|
|
|
- const unsigned line_buf_size = dsi_get_line_buf_size(dsidev);
|
|
|
+ const unsigned line_buf_size = dsi->line_buffer_size;
|
|
|
u16 w = dsi->timings.x_res;
|
|
|
u16 h = dsi->timings.y_res;
|
|
|
|
|
@@ -4571,7 +4370,7 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
|
|
|
dsi->update_bytes = dw * dh *
|
|
|
dsi_get_pixel_size(dsi->pix_fmt) / 8;
|
|
|
#endif
|
|
|
- dsi_update_screen_dispc(dssdev);
|
|
|
+ dsi_update_screen_dispc(dsidev);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -4579,18 +4378,17 @@ EXPORT_SYMBOL(omap_dsi_update);
|
|
|
|
|
|
/* Display funcs */
|
|
|
|
|
|
-static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
|
|
|
+static int dsi_configure_dispc_clocks(struct platform_device *dsidev)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
struct dispc_clock_info dispc_cinfo;
|
|
|
int r;
|
|
|
- unsigned long long fck;
|
|
|
+ unsigned long fck;
|
|
|
|
|
|
fck = dsi_get_pll_hsdiv_dispc_rate(dsidev);
|
|
|
|
|
|
- dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div;
|
|
|
- dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div;
|
|
|
+ dispc_cinfo.lck_div = dsi->user_dispc_cinfo.lck_div;
|
|
|
+ dispc_cinfo.pck_div = dsi->user_dispc_cinfo.pck_div;
|
|
|
|
|
|
r = dispc_calc_clock_rates(fck, &dispc_cinfo);
|
|
|
if (r) {
|
|
@@ -4603,21 +4401,17 @@ static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
|
|
|
+static int dsi_display_init_dispc(struct platform_device *dsidev,
|
|
|
+ struct omap_overlay_manager *mgr)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct omap_overlay_manager *mgr = dssdev->output->manager;
|
|
|
int r;
|
|
|
|
|
|
- if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
|
|
|
- dsi->timings.hsw = 1;
|
|
|
- dsi->timings.hfp = 1;
|
|
|
- dsi->timings.hbp = 1;
|
|
|
- dsi->timings.vsw = 1;
|
|
|
- dsi->timings.vfp = 0;
|
|
|
- dsi->timings.vbp = 0;
|
|
|
+ dss_select_lcd_clk_source(mgr->id, dsi->module_id == 0 ?
|
|
|
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
|
|
|
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC);
|
|
|
|
|
|
+ if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) {
|
|
|
r = dss_mgr_register_framedone_handler(mgr,
|
|
|
dsi_framedone_irq_callback, dsidev);
|
|
|
if (r) {
|
|
@@ -4645,7 +4439,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
|
|
|
|
|
|
dss_mgr_set_timings(mgr, &dsi->timings);
|
|
|
|
|
|
- r = dsi_configure_dispc_clocks(dssdev);
|
|
|
+ r = dsi_configure_dispc_clocks(dsidev);
|
|
|
if (r)
|
|
|
goto err1;
|
|
|
|
|
@@ -4662,30 +4456,30 @@ err1:
|
|
|
dss_mgr_unregister_framedone_handler(mgr,
|
|
|
dsi_framedone_irq_callback, dsidev);
|
|
|
err:
|
|
|
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
-static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
|
|
|
+static void dsi_display_uninit_dispc(struct platform_device *dsidev,
|
|
|
+ struct omap_overlay_manager *mgr)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct omap_overlay_manager *mgr = dssdev->output->manager;
|
|
|
|
|
|
if (dsi->mode == OMAP_DSS_DSI_CMD_MODE)
|
|
|
dss_mgr_unregister_framedone_handler(mgr,
|
|
|
dsi_framedone_irq_callback, dsidev);
|
|
|
+
|
|
|
+ dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
|
|
}
|
|
|
|
|
|
-static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
|
|
|
+static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
struct dsi_clock_info cinfo;
|
|
|
int r;
|
|
|
|
|
|
- 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;
|
|
|
+ cinfo = dsi->user_dsi_cinfo;
|
|
|
+
|
|
|
r = dsi_calc_clock_rates(dsidev, &cinfo);
|
|
|
if (r) {
|
|
|
DSSERR("Failed to calc dsi clocks\n");
|
|
@@ -4701,24 +4495,22 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
|
|
|
+static int dsi_display_init_dsi(struct platform_device *dsidev)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct omap_overlay_manager *mgr = dssdev->output->manager;
|
|
|
int r;
|
|
|
|
|
|
r = dsi_pll_init(dsidev, true, true);
|
|
|
if (r)
|
|
|
goto err0;
|
|
|
|
|
|
- r = dsi_configure_dsi_clocks(dssdev);
|
|
|
+ r = dsi_configure_dsi_clocks(dsidev);
|
|
|
if (r)
|
|
|
goto err1;
|
|
|
|
|
|
- dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src);
|
|
|
- dss_select_lcd_clk_source(mgr->id,
|
|
|
- dssdev->clocks.dispc.channel.lcd_clk_src);
|
|
|
+ dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ?
|
|
|
+ OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
|
|
|
+ OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI);
|
|
|
|
|
|
DSSDBG("PLL OK\n");
|
|
|
|
|
@@ -4729,12 +4521,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
|
|
|
_dsi_print_reset_status(dsidev);
|
|
|
|
|
|
dsi_proto_timings(dsidev);
|
|
|
- dsi_set_lp_clk_divisor(dssdev);
|
|
|
+ dsi_set_lp_clk_divisor(dsidev);
|
|
|
|
|
|
if (1)
|
|
|
_dsi_print_reset_status(dsidev);
|
|
|
|
|
|
- r = dsi_proto_config(dssdev);
|
|
|
+ r = dsi_proto_config(dsidev);
|
|
|
if (r)
|
|
|
goto err3;
|
|
|
|
|
@@ -4751,20 +4543,16 @@ err3:
|
|
|
dsi_cio_uninit(dsidev);
|
|
|
err2:
|
|
|
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
|
|
|
- dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
|
|
-
|
|
|
err1:
|
|
|
dsi_pll_uninit(dsidev, true);
|
|
|
err0:
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
-static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
|
|
|
+static void dsi_display_uninit_dsi(struct platform_device *dsidev,
|
|
|
bool disconnect_lanes, bool enter_ulps)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct omap_overlay_manager *mgr = dssdev->output->manager;
|
|
|
|
|
|
if (enter_ulps && !dsi->ulps_enabled)
|
|
|
dsi_enter_ulps(dsidev);
|
|
@@ -4777,7 +4565,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev,
|
|
|
dsi_vc_enable(dsidev, 3, 0);
|
|
|
|
|
|
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
|
|
|
- dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
|
|
dsi_cio_uninit(dsidev);
|
|
|
dsi_pll_uninit(dsidev, disconnect_lanes);
|
|
|
}
|
|
@@ -4786,7 +4573,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
|
|
|
{
|
|
|
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
- struct omap_dss_output *out = dssdev->output;
|
|
|
int r = 0;
|
|
|
|
|
|
DSSDBG("dsi_display_enable\n");
|
|
@@ -4795,12 +4581,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
|
|
|
|
|
|
mutex_lock(&dsi->lock);
|
|
|
|
|
|
- if (out == NULL || out->manager == NULL) {
|
|
|
- DSSERR("failed to enable display: no output/manager\n");
|
|
|
- r = -ENODEV;
|
|
|
- goto err_start_dev;
|
|
|
- }
|
|
|
-
|
|
|
r = omap_dss_start_device(dssdev);
|
|
|
if (r) {
|
|
|
DSSERR("failed to start device\n");
|
|
@@ -4815,11 +4595,7 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
|
|
|
|
|
|
_dsi_initialize_irq(dsidev);
|
|
|
|
|
|
- r = dsi_display_init_dispc(dssdev);
|
|
|
- if (r)
|
|
|
- goto err_init_dispc;
|
|
|
-
|
|
|
- r = dsi_display_init_dsi(dssdev);
|
|
|
+ r = dsi_display_init_dsi(dsidev);
|
|
|
if (r)
|
|
|
goto err_init_dsi;
|
|
|
|
|
@@ -4828,8 +4604,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev)
|
|
|
return 0;
|
|
|
|
|
|
err_init_dsi:
|
|
|
- dsi_display_uninit_dispc(dssdev);
|
|
|
-err_init_dispc:
|
|
|
dsi_enable_pll_clock(dsidev, 0);
|
|
|
dsi_runtime_put(dsidev);
|
|
|
err_get_dsi:
|
|
@@ -4858,9 +4632,7 @@ void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
|
|
|
dsi_sync_vc(dsidev, 2);
|
|
|
dsi_sync_vc(dsidev, 3);
|
|
|
|
|
|
- dsi_display_uninit_dispc(dssdev);
|
|
|
-
|
|
|
- dsi_display_uninit_dsi(dssdev, disconnect_lanes, enter_ulps);
|
|
|
+ dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
|
|
|
|
|
|
dsi_runtime_put(dsidev);
|
|
|
dsi_enable_pll_clock(dsidev, 0);
|
|
@@ -4881,75 +4653,577 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable)
|
|
|
}
|
|
|
EXPORT_SYMBOL(omapdss_dsi_enable_te);
|
|
|
|
|
|
-void omapdss_dsi_set_timings(struct omap_dss_device *dssdev,
|
|
|
- struct omap_video_timings *timings)
|
|
|
+#ifdef PRINT_VERBOSE_VM_TIMINGS
|
|
|
+static void print_dsi_vm(const char *str,
|
|
|
+ const struct omap_dss_dsi_videomode_timings *t)
|
|
|
+{
|
|
|
+ unsigned long byteclk = t->hsclk / 4;
|
|
|
+ int bl, wc, pps, tot;
|
|
|
+
|
|
|
+ wc = DIV_ROUND_UP(t->hact * t->bitspp, 8);
|
|
|
+ pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */
|
|
|
+ bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp;
|
|
|
+ tot = bl + pps;
|
|
|
+
|
|
|
+#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
|
|
|
+
|
|
|
+ pr_debug("%s bck %lu, %u/%u/%u/%u/%u/%u = %u+%u = %u, "
|
|
|
+ "%u/%u/%u/%u/%u/%u = %u + %u = %u\n",
|
|
|
+ str,
|
|
|
+ byteclk,
|
|
|
+ t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp,
|
|
|
+ bl, pps, tot,
|
|
|
+ TO_DSI_T(t->hss),
|
|
|
+ TO_DSI_T(t->hsa),
|
|
|
+ TO_DSI_T(t->hse),
|
|
|
+ TO_DSI_T(t->hbp),
|
|
|
+ TO_DSI_T(pps),
|
|
|
+ TO_DSI_T(t->hfp),
|
|
|
+
|
|
|
+ TO_DSI_T(bl),
|
|
|
+ TO_DSI_T(pps),
|
|
|
+
|
|
|
+ TO_DSI_T(tot));
|
|
|
+#undef TO_DSI_T
|
|
|
+}
|
|
|
+
|
|
|
+static void print_dispc_vm(const char *str, const struct omap_video_timings *t)
|
|
|
+{
|
|
|
+ unsigned long pck = t->pixel_clock * 1000;
|
|
|
+ int hact, bl, tot;
|
|
|
+
|
|
|
+ hact = t->x_res;
|
|
|
+ bl = t->hsw + t->hbp + t->hfp;
|
|
|
+ tot = hact + bl;
|
|
|
+
|
|
|
+#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
|
|
|
+
|
|
|
+ pr_debug("%s pck %lu, %u/%u/%u/%u = %u+%u = %u, "
|
|
|
+ "%u/%u/%u/%u = %u + %u = %u\n",
|
|
|
+ str,
|
|
|
+ pck,
|
|
|
+ t->hsw, t->hbp, hact, t->hfp,
|
|
|
+ bl, hact, tot,
|
|
|
+ TO_DISPC_T(t->hsw),
|
|
|
+ TO_DISPC_T(t->hbp),
|
|
|
+ TO_DISPC_T(hact),
|
|
|
+ TO_DISPC_T(t->hfp),
|
|
|
+ TO_DISPC_T(bl),
|
|
|
+ TO_DISPC_T(hact),
|
|
|
+ TO_DISPC_T(tot));
|
|
|
+#undef TO_DISPC_T
|
|
|
+}
|
|
|
+
|
|
|
+/* note: this is not quite accurate */
|
|
|
+static void print_dsi_dispc_vm(const char *str,
|
|
|
+ const struct omap_dss_dsi_videomode_timings *t)
|
|
|
+{
|
|
|
+ struct omap_video_timings vm = { 0 };
|
|
|
+ unsigned long byteclk = t->hsclk / 4;
|
|
|
+ unsigned long pck;
|
|
|
+ u64 dsi_tput;
|
|
|
+ int dsi_hact, dsi_htot;
|
|
|
+
|
|
|
+ dsi_tput = (u64)byteclk * t->ndl * 8;
|
|
|
+ pck = (u32)div64_u64(dsi_tput, t->bitspp);
|
|
|
+ dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl);
|
|
|
+ dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp;
|
|
|
+
|
|
|
+ vm.pixel_clock = pck / 1000;
|
|
|
+ vm.hsw = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk);
|
|
|
+ vm.hbp = div64_u64((u64)t->hbp * pck, byteclk);
|
|
|
+ vm.hfp = div64_u64((u64)t->hfp * pck, byteclk);
|
|
|
+ vm.x_res = t->hact;
|
|
|
+
|
|
|
+ print_dispc_vm(str, &vm);
|
|
|
+}
|
|
|
+#endif /* PRINT_VERBOSE_VM_TIMINGS */
|
|
|
+
|
|
|
+static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
|
|
|
+ unsigned long pck, void *data)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
+ struct dsi_clk_calc_ctx *ctx = data;
|
|
|
+ struct omap_video_timings *t = &ctx->dispc_vm;
|
|
|
|
|
|
- mutex_lock(&dsi->lock);
|
|
|
+ ctx->dispc_cinfo.lck_div = lckd;
|
|
|
+ ctx->dispc_cinfo.pck_div = pckd;
|
|
|
+ ctx->dispc_cinfo.lck = lck;
|
|
|
+ ctx->dispc_cinfo.pck = pck;
|
|
|
|
|
|
- dsi->timings = *timings;
|
|
|
+ *t = *ctx->config->timings;
|
|
|
+ t->pixel_clock = pck / 1000;
|
|
|
+ t->x_res = ctx->config->timings->x_res;
|
|
|
+ t->y_res = ctx->config->timings->y_res;
|
|
|
+ t->hsw = t->hfp = t->hbp = t->vsw = 1;
|
|
|
+ t->vfp = t->vbp = 0;
|
|
|
|
|
|
- mutex_unlock(&dsi->lock);
|
|
|
+ return true;
|
|
|
}
|
|
|
-EXPORT_SYMBOL(omapdss_dsi_set_timings);
|
|
|
|
|
|
-void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h)
|
|
|
+static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
|
|
|
+ void *data)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
+ struct dsi_clk_calc_ctx *ctx = data;
|
|
|
|
|
|
- mutex_lock(&dsi->lock);
|
|
|
+ ctx->dsi_cinfo.regm_dispc = regm_dispc;
|
|
|
+ ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
|
|
|
|
|
|
- dsi->timings.x_res = w;
|
|
|
- dsi->timings.y_res = h;
|
|
|
+ return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
|
|
|
+ dsi_cm_calc_dispc_cb, ctx);
|
|
|
+}
|
|
|
|
|
|
- mutex_unlock(&dsi->lock);
|
|
|
+static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint,
|
|
|
+ unsigned long pll, void *data)
|
|
|
+{
|
|
|
+ struct dsi_clk_calc_ctx *ctx = data;
|
|
|
+
|
|
|
+ ctx->dsi_cinfo.regn = regn;
|
|
|
+ ctx->dsi_cinfo.regm = regm;
|
|
|
+ ctx->dsi_cinfo.fint = fint;
|
|
|
+ ctx->dsi_cinfo.clkin4ddr = pll;
|
|
|
+
|
|
|
+ return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
|
|
|
+ dsi_cm_calc_hsdiv_cb, ctx);
|
|
|
}
|
|
|
-EXPORT_SYMBOL(omapdss_dsi_set_size);
|
|
|
|
|
|
-void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev,
|
|
|
- enum omap_dss_dsi_pixel_format fmt)
|
|
|
+static bool dsi_cm_calc(struct dsi_data *dsi,
|
|
|
+ const struct omap_dss_dsi_config *cfg,
|
|
|
+ struct dsi_clk_calc_ctx *ctx)
|
|
|
{
|
|
|
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
+ unsigned long clkin;
|
|
|
+ int bitspp, ndl;
|
|
|
+ unsigned long pll_min, pll_max;
|
|
|
+ unsigned long pck, txbyteclk;
|
|
|
|
|
|
- mutex_lock(&dsi->lock);
|
|
|
+ clkin = clk_get_rate(dsi->sys_clk);
|
|
|
+ bitspp = dsi_get_pixel_size(cfg->pixel_format);
|
|
|
+ ndl = dsi->num_lanes_used - 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Here we should calculate minimum txbyteclk to be able to send the
|
|
|
+ * frame in time, and also to handle TE. That's not very simple, though,
|
|
|
+ * especially as we go to LP between each pixel packet due to HW
|
|
|
+ * "feature". So let's just estimate very roughly and multiply by 1.5.
|
|
|
+ */
|
|
|
+ pck = cfg->timings->pixel_clock * 1000;
|
|
|
+ pck = pck * 3 / 2;
|
|
|
+ txbyteclk = pck * bitspp / 8 / ndl;
|
|
|
|
|
|
- dsi->pix_fmt = fmt;
|
|
|
+ memset(ctx, 0, sizeof(*ctx));
|
|
|
+ ctx->dsidev = dsi->pdev;
|
|
|
+ ctx->config = cfg;
|
|
|
+ ctx->req_pck_min = pck;
|
|
|
+ ctx->req_pck_nom = pck;
|
|
|
+ ctx->req_pck_max = pck * 3 / 2;
|
|
|
+ ctx->dsi_cinfo.clkin = clkin;
|
|
|
|
|
|
- mutex_unlock(&dsi->lock);
|
|
|
+ pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
|
|
|
+ pll_max = cfg->hs_clk_max * 4;
|
|
|
+
|
|
|
+ return dsi_pll_calc(dsi->pdev, clkin,
|
|
|
+ pll_min, pll_max,
|
|
|
+ dsi_cm_calc_pll_cb, ctx);
|
|
|
}
|
|
|
-EXPORT_SYMBOL(omapdss_dsi_set_pixel_format);
|
|
|
|
|
|
-void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev,
|
|
|
- enum omap_dss_dsi_mode mode)
|
|
|
+static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
|
|
|
{
|
|
|
- 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(ctx->dsidev);
|
|
|
+ const struct omap_dss_dsi_config *cfg = ctx->config;
|
|
|
+ int bitspp = dsi_get_pixel_size(cfg->pixel_format);
|
|
|
+ int ndl = dsi->num_lanes_used - 1;
|
|
|
+ unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4;
|
|
|
+ unsigned long byteclk = hsclk / 4;
|
|
|
|
|
|
- mutex_lock(&dsi->lock);
|
|
|
+ unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
|
|
|
+ int xres;
|
|
|
+ int panel_htot, panel_hbl; /* pixels */
|
|
|
+ int dispc_htot, dispc_hbl; /* pixels */
|
|
|
+ int dsi_htot, dsi_hact, dsi_hbl, hss, hse; /* byteclks */
|
|
|
+ int hfp, hsa, hbp;
|
|
|
+ const struct omap_video_timings *req_vm;
|
|
|
+ struct omap_video_timings *dispc_vm;
|
|
|
+ struct omap_dss_dsi_videomode_timings *dsi_vm;
|
|
|
+ u64 dsi_tput, dispc_tput;
|
|
|
|
|
|
- dsi->mode = mode;
|
|
|
+ dsi_tput = (u64)byteclk * ndl * 8;
|
|
|
|
|
|
- mutex_unlock(&dsi->lock);
|
|
|
+ req_vm = cfg->timings;
|
|
|
+ req_pck_min = ctx->req_pck_min;
|
|
|
+ req_pck_max = ctx->req_pck_max;
|
|
|
+ req_pck_nom = ctx->req_pck_nom;
|
|
|
+
|
|
|
+ dispc_pck = ctx->dispc_cinfo.pck;
|
|
|
+ dispc_tput = (u64)dispc_pck * bitspp;
|
|
|
+
|
|
|
+ xres = req_vm->x_res;
|
|
|
+
|
|
|
+ panel_hbl = req_vm->hfp + req_vm->hbp + req_vm->hsw;
|
|
|
+ panel_htot = xres + panel_hbl;
|
|
|
+
|
|
|
+ dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(xres * bitspp, 8) + 6, ndl);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * When there are no line buffers, DISPC and DSI must have the
|
|
|
+ * same tput. Otherwise DISPC tput needs to be higher than DSI's.
|
|
|
+ */
|
|
|
+ if (dsi->line_buffer_size < xres * bitspp / 8) {
|
|
|
+ if (dispc_tput != dsi_tput)
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ if (dispc_tput < dsi_tput)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* DSI tput must be over the min requirement */
|
|
|
+ if (dsi_tput < (u64)bitspp * req_pck_min)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* When non-burst mode, DSI tput must be below max requirement. */
|
|
|
+ if (cfg->trans_mode != OMAP_DSS_DSI_BURST_MODE) {
|
|
|
+ if (dsi_tput > (u64)bitspp * req_pck_max)
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ hss = DIV_ROUND_UP(4, ndl);
|
|
|
+
|
|
|
+ if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
|
|
|
+ if (ndl == 3 && req_vm->hsw == 0)
|
|
|
+ hse = 1;
|
|
|
+ else
|
|
|
+ hse = DIV_ROUND_UP(4, ndl);
|
|
|
+ } else {
|
|
|
+ hse = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* DSI htot to match the panel's nominal pck */
|
|
|
+ dsi_htot = div64_u64((u64)panel_htot * byteclk, req_pck_nom);
|
|
|
+
|
|
|
+ /* fail if there would be no time for blanking */
|
|
|
+ if (dsi_htot < hss + hse + dsi_hact)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* total DSI blanking needed to achieve panel's TL */
|
|
|
+ dsi_hbl = dsi_htot - dsi_hact;
|
|
|
+
|
|
|
+ /* DISPC htot to match the DSI TL */
|
|
|
+ dispc_htot = div64_u64((u64)dsi_htot * dispc_pck, byteclk);
|
|
|
+
|
|
|
+ /* verify that the DSI and DISPC TLs are the same */
|
|
|
+ if ((u64)dsi_htot * dispc_pck != (u64)dispc_htot * byteclk)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ dispc_hbl = dispc_htot - xres;
|
|
|
+
|
|
|
+ /* setup DSI videomode */
|
|
|
+
|
|
|
+ dsi_vm = &ctx->dsi_vm;
|
|
|
+ memset(dsi_vm, 0, sizeof(*dsi_vm));
|
|
|
+
|
|
|
+ dsi_vm->hsclk = hsclk;
|
|
|
+
|
|
|
+ dsi_vm->ndl = ndl;
|
|
|
+ dsi_vm->bitspp = bitspp;
|
|
|
+
|
|
|
+ if (cfg->trans_mode != OMAP_DSS_DSI_PULSE_MODE) {
|
|
|
+ hsa = 0;
|
|
|
+ } else if (ndl == 3 && req_vm->hsw == 0) {
|
|
|
+ hsa = 0;
|
|
|
+ } else {
|
|
|
+ hsa = div64_u64((u64)req_vm->hsw * byteclk, req_pck_nom);
|
|
|
+ hsa = max(hsa - hse, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ hbp = div64_u64((u64)req_vm->hbp * byteclk, req_pck_nom);
|
|
|
+ hbp = max(hbp, 1);
|
|
|
+
|
|
|
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
|
|
|
+ if (hfp < 1) {
|
|
|
+ int t;
|
|
|
+ /* we need to take cycles from hbp */
|
|
|
+
|
|
|
+ t = 1 - hfp;
|
|
|
+ hbp = max(hbp - t, 1);
|
|
|
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
|
|
|
+
|
|
|
+ if (hfp < 1 && hsa > 0) {
|
|
|
+ /* we need to take cycles from hsa */
|
|
|
+ t = 1 - hfp;
|
|
|
+ hsa = max(hsa - t, 1);
|
|
|
+ hfp = dsi_hbl - (hss + hsa + hse + hbp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hfp < 1)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ dsi_vm->hss = hss;
|
|
|
+ dsi_vm->hsa = hsa;
|
|
|
+ dsi_vm->hse = hse;
|
|
|
+ dsi_vm->hbp = hbp;
|
|
|
+ dsi_vm->hact = xres;
|
|
|
+ dsi_vm->hfp = hfp;
|
|
|
+
|
|
|
+ dsi_vm->vsa = req_vm->vsw;
|
|
|
+ dsi_vm->vbp = req_vm->vbp;
|
|
|
+ dsi_vm->vact = req_vm->y_res;
|
|
|
+ dsi_vm->vfp = req_vm->vfp;
|
|
|
+
|
|
|
+ dsi_vm->trans_mode = cfg->trans_mode;
|
|
|
+
|
|
|
+ dsi_vm->blanking_mode = 0;
|
|
|
+ dsi_vm->hsa_blanking_mode = 1;
|
|
|
+ dsi_vm->hfp_blanking_mode = 1;
|
|
|
+ dsi_vm->hbp_blanking_mode = 1;
|
|
|
+
|
|
|
+ dsi_vm->ddr_clk_always_on = cfg->ddr_clk_always_on;
|
|
|
+ dsi_vm->window_sync = 4;
|
|
|
+
|
|
|
+ /* setup DISPC videomode */
|
|
|
+
|
|
|
+ dispc_vm = &ctx->dispc_vm;
|
|
|
+ *dispc_vm = *req_vm;
|
|
|
+ dispc_vm->pixel_clock = dispc_pck / 1000;
|
|
|
+
|
|
|
+ if (cfg->trans_mode == OMAP_DSS_DSI_PULSE_MODE) {
|
|
|
+ hsa = div64_u64((u64)req_vm->hsw * dispc_pck,
|
|
|
+ req_pck_nom);
|
|
|
+ hsa = max(hsa, 1);
|
|
|
+ } else {
|
|
|
+ hsa = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ hbp = div64_u64((u64)req_vm->hbp * dispc_pck, req_pck_nom);
|
|
|
+ hbp = max(hbp, 1);
|
|
|
+
|
|
|
+ hfp = dispc_hbl - hsa - hbp;
|
|
|
+ if (hfp < 1) {
|
|
|
+ int t;
|
|
|
+ /* we need to take cycles from hbp */
|
|
|
+
|
|
|
+ t = 1 - hfp;
|
|
|
+ hbp = max(hbp - t, 1);
|
|
|
+ hfp = dispc_hbl - hsa - hbp;
|
|
|
+
|
|
|
+ if (hfp < 1) {
|
|
|
+ /* we need to take cycles from hsa */
|
|
|
+ t = 1 - hfp;
|
|
|
+ hsa = max(hsa - t, 1);
|
|
|
+ hfp = dispc_hbl - hsa - hbp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (hfp < 1)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ dispc_vm->hfp = hfp;
|
|
|
+ dispc_vm->hsw = hsa;
|
|
|
+ dispc_vm->hbp = hbp;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
|
|
|
+ unsigned long pck, void *data)
|
|
|
+{
|
|
|
+ struct dsi_clk_calc_ctx *ctx = data;
|
|
|
+
|
|
|
+ ctx->dispc_cinfo.lck_div = lckd;
|
|
|
+ ctx->dispc_cinfo.pck_div = pckd;
|
|
|
+ ctx->dispc_cinfo.lck = lck;
|
|
|
+ ctx->dispc_cinfo.pck = pck;
|
|
|
+
|
|
|
+ if (dsi_vm_calc_blanking(ctx) == false)
|
|
|
+ return false;
|
|
|
+
|
|
|
+#ifdef PRINT_VERBOSE_VM_TIMINGS
|
|
|
+ print_dispc_vm("dispc", &ctx->dispc_vm);
|
|
|
+ print_dsi_vm("dsi ", &ctx->dsi_vm);
|
|
|
+ print_dispc_vm("req ", ctx->config->timings);
|
|
|
+ print_dsi_dispc_vm("act ", &ctx->dsi_vm);
|
|
|
+#endif
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
|
|
|
+ void *data)
|
|
|
+{
|
|
|
+ struct dsi_clk_calc_ctx *ctx = data;
|
|
|
+ unsigned long pck_max;
|
|
|
+
|
|
|
+ ctx->dsi_cinfo.regm_dispc = regm_dispc;
|
|
|
+ ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * In burst mode we can let the dispc pck be arbitrarily high, but it
|
|
|
+ * limits our scaling abilities. So for now, don't aim too high.
|
|
|
+ */
|
|
|
+
|
|
|
+ if (ctx->config->trans_mode == OMAP_DSS_DSI_BURST_MODE)
|
|
|
+ pck_max = ctx->req_pck_max + 10000000;
|
|
|
+ else
|
|
|
+ pck_max = ctx->req_pck_max;
|
|
|
+
|
|
|
+ return dispc_div_calc(dispc, ctx->req_pck_min, pck_max,
|
|
|
+ dsi_vm_calc_dispc_cb, ctx);
|
|
|
+}
|
|
|
+
|
|
|
+static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint,
|
|
|
+ unsigned long pll, void *data)
|
|
|
+{
|
|
|
+ struct dsi_clk_calc_ctx *ctx = data;
|
|
|
+
|
|
|
+ ctx->dsi_cinfo.regn = regn;
|
|
|
+ ctx->dsi_cinfo.regm = regm;
|
|
|
+ ctx->dsi_cinfo.fint = fint;
|
|
|
+ ctx->dsi_cinfo.clkin4ddr = pll;
|
|
|
+
|
|
|
+ return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
|
|
|
+ dsi_vm_calc_hsdiv_cb, ctx);
|
|
|
+}
|
|
|
+
|
|
|
+static bool dsi_vm_calc(struct dsi_data *dsi,
|
|
|
+ const struct omap_dss_dsi_config *cfg,
|
|
|
+ struct dsi_clk_calc_ctx *ctx)
|
|
|
+{
|
|
|
+ const struct omap_video_timings *t = cfg->timings;
|
|
|
+ unsigned long clkin;
|
|
|
+ unsigned long pll_min;
|
|
|
+ unsigned long pll_max;
|
|
|
+ int ndl = dsi->num_lanes_used - 1;
|
|
|
+ int bitspp = dsi_get_pixel_size(cfg->pixel_format);
|
|
|
+ unsigned long byteclk_min;
|
|
|
+
|
|
|
+ clkin = clk_get_rate(dsi->sys_clk);
|
|
|
+
|
|
|
+ memset(ctx, 0, sizeof(*ctx));
|
|
|
+ ctx->dsidev = dsi->pdev;
|
|
|
+ ctx->config = cfg;
|
|
|
+
|
|
|
+ ctx->dsi_cinfo.clkin = clkin;
|
|
|
+
|
|
|
+ /* these limits should come from the panel driver */
|
|
|
+ ctx->req_pck_min = t->pixel_clock * 1000 - 1000;
|
|
|
+ ctx->req_pck_nom = t->pixel_clock * 1000;
|
|
|
+ ctx->req_pck_max = t->pixel_clock * 1000 + 1000;
|
|
|
+
|
|
|
+ byteclk_min = div64_u64((u64)ctx->req_pck_min * bitspp, ndl * 8);
|
|
|
+ pll_min = max(cfg->hs_clk_min * 4, byteclk_min * 4 * 4);
|
|
|
+
|
|
|
+ if (cfg->trans_mode == OMAP_DSS_DSI_BURST_MODE) {
|
|
|
+ pll_max = cfg->hs_clk_max * 4;
|
|
|
+ } else {
|
|
|
+ unsigned long byteclk_max;
|
|
|
+ byteclk_max = div64_u64((u64)ctx->req_pck_max * bitspp,
|
|
|
+ ndl * 8);
|
|
|
+
|
|
|
+ pll_max = byteclk_max * 4 * 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ return dsi_pll_calc(dsi->pdev, clkin,
|
|
|
+ pll_min, pll_max,
|
|
|
+ dsi_vm_calc_pll_cb, ctx);
|
|
|
}
|
|
|
-EXPORT_SYMBOL(omapdss_dsi_set_operation_mode);
|
|
|
|
|
|
-void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev,
|
|
|
- struct omap_dss_dsi_videomode_timings *timings)
|
|
|
+int omapdss_dsi_set_config(struct omap_dss_device *dssdev,
|
|
|
+ const struct omap_dss_dsi_config *config)
|
|
|
{
|
|
|
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
+ struct dsi_clk_calc_ctx ctx;
|
|
|
+ bool ok;
|
|
|
+ int r;
|
|
|
|
|
|
mutex_lock(&dsi->lock);
|
|
|
|
|
|
- dsi->vm_timings = *timings;
|
|
|
+ dsi->pix_fmt = config->pixel_format;
|
|
|
+ dsi->mode = config->mode;
|
|
|
+
|
|
|
+ if (config->mode == OMAP_DSS_DSI_VIDEO_MODE)
|
|
|
+ ok = dsi_vm_calc(dsi, config, &ctx);
|
|
|
+ else
|
|
|
+ ok = dsi_cm_calc(dsi, config, &ctx);
|
|
|
+
|
|
|
+ if (!ok) {
|
|
|
+ DSSERR("failed to find suitable DSI clock settings\n");
|
|
|
+ r = -EINVAL;
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
|
|
|
+
|
|
|
+ r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min,
|
|
|
+ config->lp_clk_max);
|
|
|
+ if (r) {
|
|
|
+ DSSERR("failed to find suitable DSI LP clock settings\n");
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
+ dsi->user_dsi_cinfo = ctx.dsi_cinfo;
|
|
|
+ dsi->user_dispc_cinfo = ctx.dispc_cinfo;
|
|
|
+
|
|
|
+ dsi->timings = ctx.dispc_vm;
|
|
|
+ dsi->vm_timings = ctx.dsi_vm;
|
|
|
|
|
|
mutex_unlock(&dsi->lock);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+err:
|
|
|
+ mutex_unlock(&dsi->lock);
|
|
|
+
|
|
|
+ return r;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(omapdss_dsi_set_config);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Return a hardcoded channel for the DSI output. This should work for
|
|
|
+ * current use cases, but this can be later expanded to either resolve
|
|
|
+ * the channel in some more dynamic manner, or get the channel as a user
|
|
|
+ * parameter.
|
|
|
+ */
|
|
|
+static enum omap_channel dsi_get_channel(int module_id)
|
|
|
+{
|
|
|
+ switch (omapdss_get_version()) {
|
|
|
+ case OMAPDSS_VER_OMAP24xx:
|
|
|
+ DSSWARN("DSI not supported\n");
|
|
|
+ return OMAP_DSS_CHANNEL_LCD;
|
|
|
+
|
|
|
+ case OMAPDSS_VER_OMAP34xx_ES1:
|
|
|
+ case OMAPDSS_VER_OMAP34xx_ES3:
|
|
|
+ case OMAPDSS_VER_OMAP3630:
|
|
|
+ case OMAPDSS_VER_AM35xx:
|
|
|
+ return OMAP_DSS_CHANNEL_LCD;
|
|
|
+
|
|
|
+ case OMAPDSS_VER_OMAP4430_ES1:
|
|
|
+ case OMAPDSS_VER_OMAP4430_ES2:
|
|
|
+ case OMAPDSS_VER_OMAP4:
|
|
|
+ switch (module_id) {
|
|
|
+ case 0:
|
|
|
+ return OMAP_DSS_CHANNEL_LCD;
|
|
|
+ case 1:
|
|
|
+ return OMAP_DSS_CHANNEL_LCD2;
|
|
|
+ default:
|
|
|
+ DSSWARN("unsupported module id\n");
|
|
|
+ return OMAP_DSS_CHANNEL_LCD;
|
|
|
+ }
|
|
|
+
|
|
|
+ case OMAPDSS_VER_OMAP5:
|
|
|
+ switch (module_id) {
|
|
|
+ case 0:
|
|
|
+ return OMAP_DSS_CHANNEL_LCD;
|
|
|
+ case 1:
|
|
|
+ return OMAP_DSS_CHANNEL_LCD3;
|
|
|
+ default:
|
|
|
+ DSSWARN("unsupported module id\n");
|
|
|
+ return OMAP_DSS_CHANNEL_LCD;
|
|
|
+ }
|
|
|
+
|
|
|
+ default:
|
|
|
+ DSSWARN("unsupported DSS version\n");
|
|
|
+ return OMAP_DSS_CHANNEL_LCD;
|
|
|
+ }
|
|
|
}
|
|
|
-EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings);
|
|
|
|
|
|
static int __init dsi_init_display(struct omap_dss_device *dssdev)
|
|
|
{
|
|
@@ -5073,7 +5347,7 @@ static int dsi_get_clocks(struct platform_device *dsidev)
|
|
|
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
struct clk *clk;
|
|
|
|
|
|
- clk = clk_get(&dsidev->dev, "fck");
|
|
|
+ clk = devm_clk_get(&dsidev->dev, "fck");
|
|
|
if (IS_ERR(clk)) {
|
|
|
DSSERR("can't get fck\n");
|
|
|
return PTR_ERR(clk);
|
|
@@ -5081,11 +5355,9 @@ static int dsi_get_clocks(struct platform_device *dsidev)
|
|
|
|
|
|
dsi->dss_clk = clk;
|
|
|
|
|
|
- clk = clk_get(&dsidev->dev, "sys_clk");
|
|
|
+ clk = devm_clk_get(&dsidev->dev, "sys_clk");
|
|
|
if (IS_ERR(clk)) {
|
|
|
DSSERR("can't get sys_clk\n");
|
|
|
- clk_put(dsi->dss_clk);
|
|
|
- dsi->dss_clk = NULL;
|
|
|
return PTR_ERR(clk);
|
|
|
}
|
|
|
|
|
@@ -5094,16 +5366,6 @@ static int dsi_get_clocks(struct platform_device *dsidev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void dsi_put_clocks(struct platform_device *dsidev)
|
|
|
-{
|
|
|
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
|
|
|
-
|
|
|
- if (dsi->dss_clk)
|
|
|
- clk_put(dsi->dss_clk);
|
|
|
- if (dsi->sys_clk)
|
|
|
- clk_put(dsi->sys_clk);
|
|
|
-}
|
|
|
-
|
|
|
static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev)
|
|
|
{
|
|
|
struct omap_dss_board_info *pdata = pdev->dev.platform_data;
|
|
@@ -5188,6 +5450,8 @@ static void __init dsi_init_output(struct platform_device *dsidev)
|
|
|
OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
|
|
|
|
|
|
out->type = OMAP_DISPLAY_TYPE_DSI;
|
|
|
+ out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
|
|
|
+ out->dispc_channel = dsi_get_channel(dsi->module_id);
|
|
|
|
|
|
dss_register_output(out);
|
|
|
}
|
|
@@ -5293,6 +5557,8 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
|
|
|
else
|
|
|
dsi->num_lanes_supported = 3;
|
|
|
|
|
|
+ dsi->line_buffer_size = dsi_get_line_buf_size(dsidev);
|
|
|
+
|
|
|
dsi_init_output(dsidev);
|
|
|
|
|
|
dsi_probe_pdata(dsidev);
|
|
@@ -5314,7 +5580,6 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev)
|
|
|
|
|
|
err_runtime_get:
|
|
|
pm_runtime_disable(&dsidev->dev);
|
|
|
- dsi_put_clocks(dsidev);
|
|
|
return r;
|
|
|
}
|
|
|
|
|
@@ -5330,8 +5595,6 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
|
|
|
|
|
|
pm_runtime_disable(&dsidev->dev);
|
|
|
|
|
|
- dsi_put_clocks(dsidev);
|
|
|
-
|
|
|
if (dsi->vdds_dsi_reg != NULL) {
|
|
|
if (dsi->vdds_dsi_enabled) {
|
|
|
regulator_disable(dsi->vdds_dsi_reg);
|