@@ -201,6 +201,9 @@ static const struct clk_ops samsung_pll3000_clk_ops = {
201201#define PLL35XX_LOCK_STAT_SHIFT (29)
202202#define PLL35XX_ENABLE_SHIFT (31)
203203
204+ /* A9FRACM is similar to PLL35xx, except that MDIV is bit different */
205+ #define PLLA9FRACM_MDIV_SHIFT (14)
206+
204207static unsigned long samsung_pll35xx_recalc_rate (struct clk_hw * hw ,
205208 unsigned long parent_rate )
206209{
@@ -209,7 +212,12 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
209212 u64 fvco = parent_rate ;
210213
211214 pll_con = readl_relaxed (pll -> con_reg );
212- mdiv = (pll_con >> PLL35XX_MDIV_SHIFT ) & PLL35XX_MDIV_MASK ;
215+
216+ if (pll -> type == pll_a9fracm )
217+ mdiv = (pll_con >> PLLA9FRACM_MDIV_SHIFT ) & PLL35XX_MDIV_MASK ;
218+ else
219+ mdiv = (pll_con >> PLL35XX_MDIV_SHIFT ) & PLL35XX_MDIV_MASK ;
220+
213221 pdiv = (pll_con >> PLL35XX_PDIV_SHIFT ) & PLL35XX_PDIV_MASK ;
214222 sdiv = (pll_con >> PLL35XX_SDIV_SHIFT ) & PLL35XX_SDIV_MASK ;
215223
@@ -219,12 +227,15 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
219227 return (unsigned long )fvco ;
220228}
221229
222- static inline bool samsung_pll35xx_mp_change (
223- const struct samsung_pll_rate_table * rate , u32 pll_con )
230+ static inline bool samsung_pll35xx_mp_change (u32 pll_type ,
231+ const struct samsung_pll_rate_table * rate , u32 pll_con )
224232{
225233 u32 old_mdiv , old_pdiv ;
226234
227- old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT ) & PLL35XX_MDIV_MASK ;
235+ if (pll_type == pll_a9fracm )
236+ old_mdiv = (pll_con >> PLLA9FRACM_MDIV_SHIFT ) & PLL35XX_MDIV_MASK ;
237+ else
238+ old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT ) & PLL35XX_MDIV_MASK ;
228239 old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT ) & PLL35XX_PDIV_MASK ;
229240
230241 return (rate -> mdiv != old_mdiv || rate -> pdiv != old_pdiv );
@@ -236,6 +247,12 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
236247 struct samsung_clk_pll * pll = to_clk_pll (hw );
237248 const struct samsung_pll_rate_table * rate ;
238249 u32 tmp ;
250+ u32 mdiv_shift ;
251+
252+ if (pll -> type == pll_a9fracm )
253+ mdiv_shift = PLLA9FRACM_MDIV_SHIFT ;
254+ else
255+ mdiv_shift = PLL35XX_MDIV_SHIFT ;
239256
240257 /* Get required rate settings from table */
241258 rate = samsung_get_pll_settings (pll , drate );
@@ -247,7 +264,7 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
247264
248265 tmp = readl_relaxed (pll -> con_reg );
249266
250- if (!(samsung_pll35xx_mp_change (rate , tmp ))) {
267+ if (!(samsung_pll35xx_mp_change (pll -> type , rate , tmp ))) {
251268 /* If only s change, change just s value only*/
252269 tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT );
253270 tmp |= rate -> sdiv << PLL35XX_SDIV_SHIFT ;
@@ -257,18 +274,18 @@ static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
257274 }
258275
259276 /* Set PLL lock time. */
260- if (pll -> type == pll_142xx || pll -> type == pll_1017x )
277+ if (pll -> type == pll_142xx || pll -> type == pll_1017x || pll -> type == pll_a9fracm )
261278 writel_relaxed (rate -> pdiv * PLL142XX_LOCK_FACTOR ,
262279 pll -> lock_reg );
263280 else
264281 writel_relaxed (rate -> pdiv * PLL35XX_LOCK_FACTOR ,
265282 pll -> lock_reg );
266283
267284 /* Change PLL PMS values */
268- tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT ) |
285+ tmp &= ~((PLL35XX_MDIV_MASK << mdiv_shift ) |
269286 (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT ) |
270287 (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT ));
271- tmp |= (rate -> mdiv << PLL35XX_MDIV_SHIFT ) |
288+ tmp |= (rate -> mdiv << mdiv_shift ) |
272289 (rate -> pdiv << PLL35XX_PDIV_SHIFT ) |
273290 (rate -> sdiv << PLL35XX_SDIV_SHIFT );
274291 writel_relaxed (tmp , pll -> con_reg );
@@ -1428,6 +1445,149 @@ static const struct clk_ops samsung_pll1031x_clk_min_ops = {
14281445 .recalc_rate = samsung_pll1031x_recalc_rate ,
14291446};
14301447
1448+ /*
1449+ * PLLA9FRACO Clock Type
1450+ */
1451+ #define PLLA9FRACO_LOCK_FACTOR (500)
1452+
1453+ #define PLLA9FRACO_MDIV_MASK (0x3ff)
1454+ #define PLLA9FRACO_PDIV_MASK (0x3f)
1455+ #define PLLA9FRACO_SDIV_MASK (0x7)
1456+ #define PLLA9FRACO_MDIV_SHIFT (14)
1457+ #define PLLA9FRACO_PDIV_SHIFT (8)
1458+ #define PLLA9FRACO_SDIV_SHIFT (0)
1459+
1460+ #define PLLA9FRACO_PLL_CON5_DIV_FRAC (0x14)
1461+ #define PLLA9FRACO_KDIV_MASK (0xffffff)
1462+ #define PLLA9FRACO_KDIV_SHIFT (0)
1463+ #define PLLA9FRACO_DAC_MODE BIT(30)
1464+ #define PLLA9FRACO_DSM_EN BIT(31)
1465+ #define PLLA9FRACO_FOUTPOSTDIVEN BIT(3)
1466+ #define PLLA9FRACO_MUX_SEL BIT(4)
1467+ #define PLLA9FRACO_ENABLE_SHIFT (31)
1468+ #define PLLA9FRACO_LOCK_STAT_SHIFT (29)
1469+
1470+ static unsigned long samsung_a9fraco_recalc_rate (struct clk_hw * hw ,
1471+ unsigned long parent_rate )
1472+ {
1473+ struct samsung_clk_pll * pll = to_clk_pll (hw );
1474+ u32 pll_con0 , pll_con5 ;
1475+ u64 mdiv , pdiv , sdiv , kdiv ;
1476+ u64 fvco = parent_rate ;
1477+
1478+ pll_con0 = readl_relaxed (pll -> con_reg );
1479+ pll_con5 = readl_relaxed (pll -> con_reg + PLLA9FRACO_PLL_CON5_DIV_FRAC );
1480+ mdiv = (pll_con0 >> PLLA9FRACO_MDIV_SHIFT ) & PLLA9FRACO_MDIV_MASK ;
1481+ pdiv = (pll_con0 >> PLLA9FRACO_PDIV_SHIFT ) & PLLA9FRACO_PDIV_MASK ;
1482+ sdiv = (pll_con0 >> PLLA9FRACO_SDIV_SHIFT ) & PLLA9FRACO_SDIV_MASK ;
1483+ kdiv = (pll_con5 & PLLA9FRACO_KDIV_MASK );
1484+
1485+ /* fvco = fref * (M + K/2^24) / p * (S+1) */
1486+ fvco *= mdiv ;
1487+ fvco = (fvco << 24 ) + kdiv ;
1488+ do_div (fvco , ((pdiv * (sdiv + 1 )) << 24 ));
1489+
1490+ return (unsigned long )fvco ;
1491+ }
1492+
1493+ static bool samsung_a9fraco_mpk_change (u32 pll_con0 , u32 pll_con5 ,
1494+ const struct samsung_pll_rate_table * rate )
1495+ {
1496+ u32 old_mdiv , old_pdiv , old_kdiv ;
1497+
1498+ old_mdiv = (pll_con0 >> PLLA9FRACO_MDIV_SHIFT ) & PLLA9FRACO_MDIV_MASK ;
1499+ old_pdiv = (pll_con0 >> PLLA9FRACO_PDIV_SHIFT ) & PLLA9FRACO_PDIV_MASK ;
1500+ old_kdiv = (pll_con5 >> PLLA9FRACO_KDIV_SHIFT ) & PLLA9FRACO_KDIV_MASK ;
1501+
1502+ return (old_mdiv != rate -> mdiv || old_pdiv != rate -> pdiv || old_kdiv != rate -> kdiv );
1503+ }
1504+
1505+ static int samsung_a9fraco_set_rate (struct clk_hw * hw , unsigned long drate , unsigned long prate )
1506+ {
1507+ struct samsung_clk_pll * pll = to_clk_pll (hw );
1508+ const struct samsung_pll_rate_table * rate ;
1509+ u32 con0 , con5 ;
1510+ int ret ;
1511+
1512+ /* Get required rate settings from table */
1513+ rate = samsung_get_pll_settings (pll , drate );
1514+ if (!rate ) {
1515+ pr_err ("%s: Invalid rate : %lu for pll clk %s\n" , __func__ ,
1516+ drate , clk_hw_get_name (hw ));
1517+ return - EINVAL ;
1518+ }
1519+
1520+ con0 = readl_relaxed (pll -> con_reg );
1521+ con5 = readl_relaxed (pll -> con_reg + PLLA9FRACO_PLL_CON5_DIV_FRAC );
1522+
1523+ if (!(samsung_a9fraco_mpk_change (con0 , con5 , rate ))) {
1524+ /* If only s change, change just s value only */
1525+ con0 &= ~(PLLA9FRACO_SDIV_MASK << PLLA9FRACO_SDIV_SHIFT );
1526+ con0 |= rate -> sdiv << PLLA9FRACO_SDIV_SHIFT ;
1527+ writel_relaxed (con0 , pll -> con_reg );
1528+
1529+ return 0 ;
1530+ }
1531+
1532+ /* Select OSCCLK (0) */
1533+ con0 = readl_relaxed (pll -> con_reg );
1534+ con0 &= ~(PLLA9FRACO_MUX_SEL );
1535+ writel_relaxed (con0 , pll -> con_reg );
1536+
1537+ /* Disable PLL */
1538+ con0 &= ~BIT (PLLA9FRACO_ENABLE_SHIFT );
1539+ writel_relaxed (con0 , pll -> con_reg );
1540+
1541+ /* Set PLL lock time. */
1542+ writel_relaxed (rate -> pdiv * PLLA9FRACO_LOCK_FACTOR , pll -> lock_reg );
1543+
1544+ /* Set PLL M, P, and S values. */
1545+ con0 &= ~((PLLA9FRACO_MDIV_MASK << PLLA9FRACO_MDIV_SHIFT ) |
1546+ (PLLA9FRACO_PDIV_MASK << PLLA9FRACO_PDIV_SHIFT ) |
1547+ (PLLA9FRACO_SDIV_MASK << PLLA9FRACO_SDIV_SHIFT ));
1548+
1549+ /* The field FOUTPOSTDIVEN should always be 1, else FOUT might be 0 Hz. */
1550+ con0 |= (rate -> mdiv << PLLA9FRACO_MDIV_SHIFT ) |
1551+ (rate -> pdiv << PLLA9FRACO_PDIV_SHIFT ) |
1552+ (rate -> sdiv << PLLA9FRACO_SDIV_SHIFT ) | (PLLA9FRACO_FOUTPOSTDIVEN );
1553+
1554+ /* Set PLL K, DSM_EN and DAC_MODE values. */
1555+ con5 = readl_relaxed (pll -> con_reg + PLLA9FRACO_PLL_CON5_DIV_FRAC );
1556+ con5 &= ~((PLLA9FRACO_KDIV_MASK << PLLA9FRACO_KDIV_SHIFT ) |
1557+ PLLA9FRACO_DSM_EN | PLLA9FRACO_DAC_MODE );
1558+ con5 |= (rate -> kdiv << PLLA9FRACO_KDIV_SHIFT ) | PLLA9FRACO_DSM_EN | PLLA9FRACO_DAC_MODE ;
1559+
1560+ /* Write configuration to PLL */
1561+ writel_relaxed (con0 , pll -> con_reg );
1562+ writel_relaxed (con5 , pll -> con_reg + PLLA9FRACO_PLL_CON5_DIV_FRAC );
1563+
1564+ /* Enable PLL */
1565+ con0 = readl_relaxed (pll -> con_reg );
1566+ con0 |= BIT (PLLA9FRACO_ENABLE_SHIFT );
1567+ writel_relaxed (con0 , pll -> con_reg );
1568+
1569+ /* Wait for PLL lock if the PLL is enabled */
1570+ ret = samsung_pll_lock_wait (pll , BIT (pll -> lock_offs ));
1571+ if (ret < 0 )
1572+ return ret ;
1573+
1574+ /* Select FOUT (1) */
1575+ con0 |= (PLLA9FRACO_MUX_SEL );
1576+ writel_relaxed (con0 , pll -> con_reg );
1577+
1578+ return 0 ;
1579+ }
1580+
1581+ static const struct clk_ops samsung_a9fraco_clk_ops = {
1582+ .recalc_rate = samsung_a9fraco_recalc_rate ,
1583+ .determine_rate = samsung_pll_determine_rate ,
1584+ .set_rate = samsung_a9fraco_set_rate ,
1585+ };
1586+
1587+ static const struct clk_ops samsung_a9fraco_clk_min_ops = {
1588+ .recalc_rate = samsung_a9fraco_recalc_rate ,
1589+ };
1590+
14311591static void __init _samsung_clk_register_pll (struct samsung_clk_provider * ctx ,
14321592 const struct samsung_pll_clock * pll_clk )
14331593{
@@ -1477,6 +1637,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
14771637 case pll_1452x :
14781638 case pll_142xx :
14791639 case pll_1017x :
1640+ case pll_a9fracm :
14801641 pll -> enable_offs = PLL35XX_ENABLE_SHIFT ;
14811642 pll -> lock_offs = PLL35XX_LOCK_STAT_SHIFT ;
14821643 if (!pll -> rate_table )
@@ -1578,6 +1739,14 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
15781739 else
15791740 init .ops = & samsung_pll1031x_clk_ops ;
15801741 break ;
1742+ case pll_a9fraco :
1743+ pll -> enable_offs = PLLA9FRACO_ENABLE_SHIFT ;
1744+ pll -> lock_offs = PLLA9FRACO_LOCK_STAT_SHIFT ;
1745+ if (!pll -> rate_table )
1746+ init .ops = & samsung_a9fraco_clk_min_ops ;
1747+ else
1748+ init .ops = & samsung_a9fraco_clk_ops ;
1749+ break ;
15811750 default :
15821751 pr_warn ("%s: Unknown pll type for pll clk %s\n" ,
15831752 __func__ , pll_clk -> name );
0 commit comments