.. | .. |
---|
332 | 332 | return rate_table; |
---|
333 | 333 | } |
---|
334 | 334 | |
---|
| 335 | +static u32 |
---|
| 336 | +rockchip_rk3588_pll_frac_get(u32 m, u32 p, u32 s, u64 fin_hz, u64 fvco) |
---|
| 337 | +{ |
---|
| 338 | + u64 fref, fout, ffrac; |
---|
| 339 | + u32 k = 0; |
---|
| 340 | + |
---|
| 341 | + fref = fin_hz / p; |
---|
| 342 | + ffrac = fvco - (m * fref); |
---|
| 343 | + fout = ffrac * 65536; |
---|
| 344 | + k = fout / fref; |
---|
| 345 | + if (k > 32767) { |
---|
| 346 | + fref = fin_hz / p; |
---|
| 347 | + ffrac = ((m + 1) * fref) - fvco; |
---|
| 348 | + fout = ffrac * 65536; |
---|
| 349 | + k = ((fout * 10 / fref) + 7) / 10; |
---|
| 350 | + if (k > 32767) |
---|
| 351 | + k = 0; |
---|
| 352 | + else |
---|
| 353 | + k = ~k + 1; |
---|
| 354 | + } |
---|
| 355 | + return k; |
---|
| 356 | +} |
---|
| 357 | + |
---|
| 358 | +static struct rockchip_pll_rate_table * |
---|
| 359 | +rockchip_rk3588_pll_frac_by_auto(unsigned long fin_hz, unsigned long fout_hz) |
---|
| 360 | +{ |
---|
| 361 | + struct rockchip_pll_rate_table *rate_table = rk_pll_rate_table_get(); |
---|
| 362 | + u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ; |
---|
| 363 | + u32 p, m, s, k; |
---|
| 364 | + u64 fvco; |
---|
| 365 | + |
---|
| 366 | + for (s = 0; s <= 6; s++) { |
---|
| 367 | + fvco = (u64)fout_hz << s; |
---|
| 368 | + if (fvco < fvco_min || fvco > fvco_max) |
---|
| 369 | + continue; |
---|
| 370 | + for (p = 1; p <= 4; p++) { |
---|
| 371 | + for (m = 64; m <= 1023; m++) { |
---|
| 372 | + if ((fvco >= m * fin_hz / p) && (fvco < (m + 1) * fin_hz / p)) { |
---|
| 373 | + k = rockchip_rk3588_pll_frac_get(m, p, s, |
---|
| 374 | + (u64)fin_hz, |
---|
| 375 | + fvco); |
---|
| 376 | + if (!k) |
---|
| 377 | + continue; |
---|
| 378 | + rate_table->p = p; |
---|
| 379 | + rate_table->s = s; |
---|
| 380 | + rate_table->k = k; |
---|
| 381 | + if (k > 32767) |
---|
| 382 | + rate_table->m = m + 1; |
---|
| 383 | + else |
---|
| 384 | + rate_table->m = m; |
---|
| 385 | + return rate_table; |
---|
| 386 | + } |
---|
| 387 | + } |
---|
| 388 | + } |
---|
| 389 | + } |
---|
| 390 | + return NULL; |
---|
| 391 | +} |
---|
| 392 | + |
---|
335 | 393 | static struct rockchip_pll_rate_table * |
---|
336 | 394 | rockchip_rk3588_pll_clk_set_by_auto(struct rockchip_clk_pll *pll, |
---|
337 | 395 | unsigned long fin_hz, |
---|
.. | .. |
---|
341 | 399 | u64 fvco_min = 2250 * MHZ, fvco_max = 4500 * MHZ; |
---|
342 | 400 | u64 fout_min = 37 * MHZ, fout_max = 4500 * MHZ; |
---|
343 | 401 | u32 p, m, s; |
---|
344 | | - u64 fvco, fref, fout, ffrac; |
---|
| 402 | + u64 fvco; |
---|
345 | 403 | |
---|
346 | 404 | if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz) |
---|
347 | 405 | return NULL; |
---|
.. | .. |
---|
368 | 426 | } |
---|
369 | 427 | pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz); |
---|
370 | 428 | } else { |
---|
371 | | - for (s = 0; s <= 6; s++) { |
---|
372 | | - fvco = (u64)fout_hz << s; |
---|
373 | | - if (fvco < fvco_min || fvco > fvco_max) |
---|
374 | | - continue; |
---|
375 | | - for (p = 1; p <= 4; p++) { |
---|
376 | | - for (m = 64; m <= 1023; m++) { |
---|
377 | | - if ((fvco >= m * fin_hz / p) && (fvco < (m + 1) * fin_hz / p)) { |
---|
378 | | - rate_table->p = p; |
---|
379 | | - rate_table->m = m; |
---|
380 | | - rate_table->s = s; |
---|
381 | | - fref = fin_hz / p; |
---|
382 | | - ffrac = fvco - (m * fref); |
---|
383 | | - fout = ffrac * 65536; |
---|
384 | | - rate_table->k = fout / fref; |
---|
385 | | - return rate_table; |
---|
386 | | - } |
---|
387 | | - } |
---|
388 | | - } |
---|
389 | | - } |
---|
390 | | - pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz); |
---|
| 429 | + rate_table = rockchip_rk3588_pll_frac_by_auto(fin_hz, fout_hz); |
---|
| 430 | + if (!rate_table) |
---|
| 431 | + pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz); |
---|
| 432 | + else |
---|
| 433 | + return rate_table; |
---|
391 | 434 | } |
---|
392 | 435 | return NULL; |
---|
393 | 436 | } |
---|
.. | .. |
---|
1345 | 1388 | rate64 *= cur.m; |
---|
1346 | 1389 | do_div(rate64, cur.p); |
---|
1347 | 1390 | |
---|
1348 | | - if (cur.k) { |
---|
| 1391 | + if (cur.k & BIT(15)) { |
---|
| 1392 | + /* fractional mode */ |
---|
| 1393 | + u64 frac_rate64; |
---|
| 1394 | + |
---|
| 1395 | + cur.k = (~(cur.k - 1)) & RK3588_PLLCON2_K_MASK; |
---|
| 1396 | + frac_rate64 = prate * cur.k; |
---|
| 1397 | + postdiv = cur.p; |
---|
| 1398 | + postdiv *= 65536; |
---|
| 1399 | + do_div(frac_rate64, postdiv); |
---|
| 1400 | + rate64 -= frac_rate64; |
---|
| 1401 | + } else { |
---|
1349 | 1402 | /* fractional mode */ |
---|
1350 | 1403 | u64 frac_rate64 = prate * cur.k; |
---|
1351 | 1404 | |
---|
.. | .. |
---|
1516 | 1569 | { |
---|
1517 | 1570 | struct clk *parent = clk_get_parent(clk); |
---|
1518 | 1571 | struct rockchip_clk_pll *pll; |
---|
1519 | | - static u32 frac, fbdiv; |
---|
| 1572 | + static u32 frac, fbdiv, s, p; |
---|
1520 | 1573 | bool negative; |
---|
1521 | 1574 | u32 pllcon, pllcon0, pllcon2, fbdiv_mask, frac_mask, frac_shift; |
---|
1522 | 1575 | u64 fracdiv, m, n; |
---|
.. | .. |
---|
1567 | 1620 | negative = !!(ppm & BIT(31)); |
---|
1568 | 1621 | ppm = negative ? ~ppm + 1 : ppm; |
---|
1569 | 1622 | |
---|
1570 | | - if (!frac) { |
---|
1571 | | - frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask; |
---|
1572 | | - fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask; |
---|
1573 | | - } |
---|
1574 | | - |
---|
1575 | 1623 | switch (pll->type) { |
---|
1576 | 1624 | case pll_rk3036: |
---|
1577 | 1625 | case pll_rk3328: |
---|
.. | .. |
---|
1583 | 1631 | * 1 << 24 1 << 24 1000000 |
---|
1584 | 1632 | * |
---|
1585 | 1633 | */ |
---|
| 1634 | + if (!frac) { |
---|
| 1635 | + frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask; |
---|
| 1636 | + fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask; |
---|
| 1637 | + } |
---|
1586 | 1638 | m = div64_u64((uint64_t)frac * ppm, 1000000); |
---|
1587 | 1639 | n = div64_u64((uint64_t)ppm << 24, 1000000) * fbdiv; |
---|
1588 | 1640 | |
---|
.. | .. |
---|
1597 | 1649 | writel_relaxed(pllcon, pll->reg_base + pllcon2); |
---|
1598 | 1650 | break; |
---|
1599 | 1651 | case pll_rk3588: |
---|
1600 | | - m = div64_u64((uint64_t)frac * ppm, 100000); |
---|
1601 | | - n = div64_u64((uint64_t)ppm * 65535 * fbdiv, 100000); |
---|
| 1652 | + if (!fbdiv) { |
---|
| 1653 | + frac = readl_relaxed(pll->reg_base + pllcon2) & frac_mask; |
---|
| 1654 | + fbdiv = readl_relaxed(pll->reg_base + pllcon0) & fbdiv_mask; |
---|
| 1655 | + } |
---|
| 1656 | + if (!frac) { |
---|
| 1657 | + pllcon = readl_relaxed(pll->reg_base + RK3588_PLLCON(1)); |
---|
| 1658 | + s = ((pllcon >> RK3588_PLLCON1_S_SHIFT) |
---|
| 1659 | + & RK3588_PLLCON1_S_MASK); |
---|
| 1660 | + p = ((pllcon >> RK3588_PLLCON1_P_SHIFT) |
---|
| 1661 | + & RK3588_PLLCON1_P_MASK); |
---|
| 1662 | + m = div64_u64((uint64_t)clk_get_rate(clk) * ppm, 24000000); |
---|
| 1663 | + n = div64_u64((uint64_t)m * 65536 * p * (1 << s), 1000000); |
---|
1602 | 1664 | |
---|
1603 | | - fracdiv = negative ? frac - (div64_u64(m + n, 10)) : frac + (div64_u64(m + n, 10)); |
---|
1604 | | - |
---|
1605 | | - if (!frac || fracdiv > frac_mask) |
---|
1606 | | - return -EINVAL; |
---|
| 1665 | + if (n > 32767) |
---|
| 1666 | + return -EINVAL; |
---|
| 1667 | + fracdiv = negative ? ~n + 1 : n; |
---|
| 1668 | + } else if (frac & BIT(15)) { |
---|
| 1669 | + frac = (~(frac - 1)) & RK3588_PLLCON2_K_MASK; |
---|
| 1670 | + m = div64_u64((uint64_t)frac * ppm, 100000); |
---|
| 1671 | + n = div64_u64((uint64_t)ppm * 65536 * fbdiv, 100000); |
---|
| 1672 | + if (negative) { |
---|
| 1673 | + fracdiv = frac + (div64_u64(m + n, 10)); |
---|
| 1674 | + if (fracdiv > 32767) |
---|
| 1675 | + return -EINVAL; |
---|
| 1676 | + fracdiv = ~fracdiv + 1; |
---|
| 1677 | + } else { |
---|
| 1678 | + s = div64_u64(m + n, 10); |
---|
| 1679 | + if (frac >= s) { |
---|
| 1680 | + fracdiv = frac - s; |
---|
| 1681 | + if (fracdiv > 32767) |
---|
| 1682 | + return -EINVAL; |
---|
| 1683 | + fracdiv = ~fracdiv + 1; |
---|
| 1684 | + } else { |
---|
| 1685 | + fracdiv = s - frac; |
---|
| 1686 | + if (fracdiv > 32767) |
---|
| 1687 | + return -EINVAL; |
---|
| 1688 | + } |
---|
| 1689 | + } |
---|
| 1690 | + } else { |
---|
| 1691 | + m = div64_u64((uint64_t)frac * ppm, 100000); |
---|
| 1692 | + n = div64_u64((uint64_t)ppm * 65536 * fbdiv, 100000); |
---|
| 1693 | + if (!negative) { |
---|
| 1694 | + fracdiv = frac + (div64_u64(m + n, 10)); |
---|
| 1695 | + if (fracdiv > 32767) |
---|
| 1696 | + return -EINVAL; |
---|
| 1697 | + } else { |
---|
| 1698 | + s = div64_u64(m + n, 10); |
---|
| 1699 | + if (frac >= s) { |
---|
| 1700 | + fracdiv = frac - s; |
---|
| 1701 | + if (fracdiv > 32767) |
---|
| 1702 | + return -EINVAL; |
---|
| 1703 | + } else { |
---|
| 1704 | + fracdiv = s - frac; |
---|
| 1705 | + if (fracdiv > 32767) |
---|
| 1706 | + return -EINVAL; |
---|
| 1707 | + fracdiv = ~fracdiv + 1; |
---|
| 1708 | + } |
---|
| 1709 | + } |
---|
| 1710 | + } |
---|
1607 | 1711 | |
---|
1608 | 1712 | writel_relaxed(HIWORD_UPDATE(fracdiv, frac_mask, frac_shift), |
---|
1609 | 1713 | pll->reg_base + pllcon2); |
---|