diff options
Diffstat (limited to 'drivers/video/omap2/dss/dsi.c')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 167 |
1 files changed, 132 insertions, 35 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 1dd019cf9649..4d748139315d 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 | { |
@@ -1591,21 +1671,27 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
1591 | 1671 | ||
1592 | BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); | 1672 | BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); |
1593 | 1673 | ||
1674 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); | ||
1675 | |||
1594 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { | 1676 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { |
1595 | f = cinfo->fint < 1000000 ? 0x3 : | 1677 | f = cinfo->fint < 1000000 ? 0x3 : |
1596 | cinfo->fint < 1250000 ? 0x4 : | 1678 | cinfo->fint < 1250000 ? 0x4 : |
1597 | cinfo->fint < 1500000 ? 0x5 : | 1679 | cinfo->fint < 1500000 ? 0x5 : |
1598 | cinfo->fint < 1750000 ? 0x6 : | 1680 | cinfo->fint < 1750000 ? 0x6 : |
1599 | 0x7; | 1681 | 0x7; |
1600 | } | ||
1601 | 1682 | ||
1602 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); | ||
1603 | |||
1604 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) | ||
1605 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ | 1683 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ |
1684 | } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) { | ||
1685 | f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4; | ||
1686 | |||
1687 | l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */ | ||
1688 | } | ||
1689 | |||
1606 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ | 1690 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ |
1607 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ | 1691 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ |
1608 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ | 1692 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ |
1693 | if (dss_has_feature(FEAT_DSI_PLL_REFSEL)) | ||
1694 | l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */ | ||
1609 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); | 1695 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); |
1610 | 1696 | ||
1611 | REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ | 1697 | REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ |
@@ -2069,6 +2155,8 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | |||
2069 | return 1194 * 3; /* 1194x24 bits */ | 2155 | return 1194 * 3; /* 1194x24 bits */ |
2070 | case 6: | 2156 | case 6: |
2071 | return 1365 * 3; /* 1365x24 bits */ | 2157 | return 1365 * 3; /* 1365x24 bits */ |
2158 | case 7: | ||
2159 | return 1920 * 3; /* 1920x24 bits */ | ||
2072 | default: | 2160 | default: |
2073 | BUG(); | 2161 | BUG(); |
2074 | return 0; | 2162 | return 0; |
@@ -2204,6 +2292,13 @@ static void dsi_cio_timings(struct platform_device *dsidev) | |||
2204 | r = FLD_MOD(r, tlpx_half, 22, 16); | 2292 | r = FLD_MOD(r, tlpx_half, 22, 16); |
2205 | r = FLD_MOD(r, tclk_trail, 15, 8); | 2293 | r = FLD_MOD(r, tclk_trail, 15, 8); |
2206 | r = FLD_MOD(r, tclk_zero, 7, 0); | 2294 | r = FLD_MOD(r, tclk_zero, 7, 0); |
2295 | |||
2296 | if (dss_has_feature(FEAT_DSI_PHY_DCC)) { | ||
2297 | r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */ | ||
2298 | r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */ | ||
2299 | r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ | ||
2300 | } | ||
2301 | |||
2207 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); | 2302 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); |
2208 | 2303 | ||
2209 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); | 2304 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); |
@@ -4188,33 +4283,35 @@ int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, | |||
4188 | 4283 | ||
4189 | mutex_lock(&dsi->lock); | 4284 | mutex_lock(&dsi->lock); |
4190 | 4285 | ||
4191 | r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk, &cinfo); | 4286 | /* Calculate PLL output clock */ |
4287 | r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo); | ||
4192 | if (r) | 4288 | if (r) |
4193 | goto err; | 4289 | goto err; |
4194 | 4290 | ||
4195 | dssdev->clocks.dsi.regn = cinfo.regn; | 4291 | /* Calculate PLL's DSI clock */ |
4196 | dssdev->clocks.dsi.regm = cinfo.regm; | 4292 | 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 | 4293 | ||
4294 | /* Calculate PLL's DISPC clock and pck & lck divs */ | ||
4295 | pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; | ||
4296 | DSSDBG("finding dispc dividers for pck %lu\n", pck); | ||
4297 | r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo); | ||
4298 | if (r) | ||
4299 | goto err; | ||
4200 | 4300 | ||
4301 | /* Calculate LP clock */ | ||
4201 | dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; | 4302 | dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; |
4202 | lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); | 4303 | lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); |
4203 | 4304 | ||
4204 | dssdev->clocks.dsi.lp_clk_div = lp_clk_div; | 4305 | dssdev->clocks.dsi.regn = cinfo.regn; |
4205 | 4306 | dssdev->clocks.dsi.regm = cinfo.regm; | |
4206 | /* pck = TxByteClkHS * datalanes * 8 / bitsperpixel */ | 4307 | dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc; |
4207 | 4308 | 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 | 4309 | ||
4212 | dispc_find_clk_divs(pck, cinfo.dsi_pll_hsdiv_dispc_clk, &dispc_cinfo); | 4310 | dssdev->clocks.dsi.lp_clk_div = lp_clk_div; |
4213 | 4311 | ||
4214 | dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; | 4312 | dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; |
4215 | dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; | 4313 | dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; |
4216 | 4314 | ||
4217 | |||
4218 | dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; | 4315 | dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; |
4219 | 4316 | ||
4220 | dssdev->clocks.dispc.channel.lcd_clk_src = | 4317 | dssdev->clocks.dispc.channel.lcd_clk_src = |