diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 144 |
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 | ||
1456 | static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, | 1456 | static 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 | } |
1505 | found: | 1496 | found: |
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 | ||
1503 | static 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 | |||
1514 | static 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 | |||
1538 | retry: | ||
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 | } | ||
1589 | found: | ||
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 | |||
1518 | int dsi_pll_set_clock_div(struct platform_device *dsidev, | 1598 | int 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 = |