aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
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 =