aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2012-09-24 08:15:06 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2012-09-24 09:50:07 -0400
commitd66b15818c16af35ddb5da7b53905d9f6f62a45b (patch)
treeb153fd653e8704d2cfad2e1cbd923692932a7dde /drivers
parentfda7c362f9ef59de6d6db67a854e1a114af0c69a (diff)
OMAPDSS: DSI: improve DSI clock calcs for DISPC
Commit ee144e645a081daad5de1ccac77f0a0e98e6a67b added dsi_pll_calc_ddrfreq() which calculates PLL dividers based on given DSI bus clock speed. The function works ok, but it can be improved for the DISPC clock calc. The current version calculates the clock going from the PLL to the DISPC simply by setting the clock as close to DISPC maximum as possible, and the pixel clock is calculated based on that. This patch changes the function to calculate DISPC clock more dynamically, iterating through different DISPC clocks and pixel clock values, and thus we'll get more suitable pixel clocks. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/omap2/dss/dsi.c144
1 files changed, 113 insertions, 31 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 8d815e39e45d..8d47fb7c4b8f 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -1454,26 +1454,17 @@ found:
1454} 1454}
1455 1455
1456static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, 1456static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
1457 unsigned long req_clk, struct dsi_clock_info *cinfo) 1457 unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo)
1458{ 1458{
1459 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); 1459 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1460 struct dsi_clock_info cur, best; 1460 struct dsi_clock_info cur, best;
1461 unsigned long dss_sys_clk, max_dss_fck, max_dsi_fck;
1462 unsigned long req_clkin4ddr;
1463 1461
1464 DSSDBG("dsi_pll_calc_ddrfreq\n"); 1462 DSSDBG("dsi_pll_calc_ddrfreq\n");
1465 1463
1466 dss_sys_clk = clk_get_rate(dsi->sys_clk);
1467
1468 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
1469 max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
1470
1471 memset(&best, 0, sizeof(best)); 1464 memset(&best, 0, sizeof(best));
1472 memset(&cur, 0, sizeof(cur)); 1465 memset(&cur, 0, sizeof(cur));
1473 1466
1474 cur.clkin = dss_sys_clk; 1467 cur.clkin = clk_get_rate(dsi->sys_clk);
1475
1476 req_clkin4ddr = req_clk * 4;
1477 1468
1478 for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { 1469 for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) {
1479 cur.fint = cur.clkin / cur.regn; 1470 cur.fint = cur.clkin / cur.regn;
@@ -1503,18 +1494,107 @@ static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev,
1503 } 1494 }
1504 } 1495 }
1505found: 1496found:
1506 best.regm_dispc = DIV_ROUND_UP(best.clkin4ddr, max_dss_fck);
1507 best.dsi_pll_hsdiv_dispc_clk = best.clkin4ddr / best.regm_dispc;
1508
1509 best.regm_dsi = DIV_ROUND_UP(best.clkin4ddr, max_dsi_fck);
1510 best.dsi_pll_hsdiv_dsi_clk = best.clkin4ddr / best.regm_dsi;
1511
1512 if (cinfo) 1497 if (cinfo)
1513 *cinfo = best; 1498 *cinfo = best;
1514 1499
1515 return 0; 1500 return 0;
1516} 1501}
1517 1502
1503static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev,
1504 struct dsi_clock_info *cinfo)
1505{
1506 unsigned long max_dsi_fck;
1507
1508 max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
1509
1510 cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
1511 cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
1512}
1513
1514static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev,
1515 unsigned long req_pck, struct dsi_clock_info *cinfo,
1516 struct dispc_clock_info *dispc_cinfo)
1517{
1518 struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
1519 unsigned regm_dispc, best_regm_dispc;
1520 unsigned long dispc_clk, best_dispc_clk;
1521 int min_fck_per_pck;
1522 unsigned long max_dss_fck;
1523 struct dispc_clock_info best_dispc;
1524 bool match;
1525
1526 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
1527
1528 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
1529
1530 if (min_fck_per_pck &&
1531 req_pck * min_fck_per_pck > max_dss_fck) {
1532 DSSERR("Requested pixel clock not possible with the current "
1533 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
1534 "the constraint off.\n");
1535 min_fck_per_pck = 0;
1536 }
1537
1538retry:
1539 best_regm_dispc = 0;
1540 best_dispc_clk = 0;
1541 memset(&best_dispc, 0, sizeof(best_dispc));
1542 match = false;
1543
1544 for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) {
1545 struct dispc_clock_info cur_dispc;
1546
1547 dispc_clk = cinfo->clkin4ddr / regm_dispc;
1548
1549 /* this will narrow down the search a bit,
1550 * but still give pixclocks below what was
1551 * requested */
1552 if (dispc_clk < req_pck)
1553 break;
1554
1555 if (dispc_clk > max_dss_fck)
1556 continue;
1557
1558 if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck)
1559 continue;
1560
1561 match = true;
1562
1563 dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc);
1564
1565 if (abs(cur_dispc.pck - req_pck) <
1566 abs(best_dispc.pck - req_pck)) {
1567 best_regm_dispc = regm_dispc;
1568 best_dispc_clk = dispc_clk;
1569 best_dispc = cur_dispc;
1570
1571 if (cur_dispc.pck == req_pck)
1572 goto found;
1573 }
1574 }
1575
1576 if (!match) {
1577 if (min_fck_per_pck) {
1578 DSSERR("Could not find suitable clock settings.\n"
1579 "Turning FCK/PCK constraint off and"
1580 "trying again.\n");
1581 min_fck_per_pck = 0;
1582 goto retry;
1583 }
1584
1585 DSSERR("Could not find suitable clock settings.\n");
1586
1587 return -EINVAL;
1588 }
1589found:
1590 cinfo->regm_dispc = best_regm_dispc;
1591 cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk;
1592
1593 *dispc_cinfo = best_dispc;
1594
1595 return 0;
1596}
1597
1518int dsi_pll_set_clock_div(struct platform_device *dsidev, 1598int dsi_pll_set_clock_div(struct platform_device *dsidev,
1519 struct dsi_clock_info *cinfo) 1599 struct dsi_clock_info *cinfo)
1520{ 1600{
@@ -4188,33 +4268,35 @@ int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev,
4188 4268
4189 mutex_lock(&dsi->lock); 4269 mutex_lock(&dsi->lock);
4190 4270
4191 r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk, &cinfo); 4271 /* Calculate PLL output clock */
4272 r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo);
4192 if (r) 4273 if (r)
4193 goto err; 4274 goto err;
4194 4275
4195 dssdev->clocks.dsi.regn = cinfo.regn; 4276 /* Calculate PLL's DSI clock */
4196 dssdev->clocks.dsi.regm = cinfo.regm; 4277 dsi_pll_calc_dsi_fck(dsidev, &cinfo);
4197 dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
4198 dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
4199 4278
4279 /* Calculate PLL's DISPC clock and pck & lck divs */
4280 pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
4281 DSSDBG("finding dispc dividers for pck %lu\n", pck);
4282 r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo);
4283 if (r)
4284 goto err;
4200 4285
4286 /* Calculate LP clock */
4201 dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; 4287 dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk;
4202 lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); 4288 lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2);
4203 4289
4204 dssdev->clocks.dsi.lp_clk_div = lp_clk_div; 4290 dssdev->clocks.dsi.regn = cinfo.regn;
4205 4291 dssdev->clocks.dsi.regm = cinfo.regm;
4206 /* pck = TxByteClkHS * datalanes * 8 / bitsperpixel */ 4292 dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc;
4207 4293 dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi;
4208 pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp;
4209
4210 DSSDBG("finding dispc dividers for pck %lu\n", pck);
4211 4294
4212 dispc_find_clk_divs(pck, cinfo.dsi_pll_hsdiv_dispc_clk, &dispc_cinfo); 4295 dssdev->clocks.dsi.lp_clk_div = lp_clk_div;
4213 4296
4214 dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; 4297 dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div;
4215 dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; 4298 dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div;
4216 4299
4217
4218 dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; 4300 dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK;
4219 4301
4220 dssdev->clocks.dispc.channel.lcd_clk_src = 4302 dssdev->clocks.dispc.channel.lcd_clk_src =