uboot/drivers/clk/at91/clk-sam9x60-pll.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * SAM9X60's PLL clock support.
   4 *
   5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
   6 *
   7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
   8 *
   9 * Based on drivers/clk/at91/clk-sam9x60-pll.c from Linux.
  10 *
  11 */
  12
  13#include <asm/processor.h>
  14#include <common.h>
  15#include <clk-uclass.h>
  16#include <div64.h>
  17#include <dm.h>
  18#include <linux/clk-provider.h>
  19#include <linux/clk/at91_pmc.h>
  20#include <linux/delay.h>
  21
  22#include "pmc.h"
  23
  24#define UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL       "at91-sam9x60-div-pll-clk"
  25#define UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL      "at91-sam9x60-frac-pll-clk"
  26
  27#define PMC_PLL_CTRL0_DIV_MSK   GENMASK(7, 0)
  28#define PMC_PLL_CTRL1_MUL_MSK   GENMASK(31, 24)
  29#define PMC_PLL_CTRL1_FRACR_MSK GENMASK(21, 0)
  30
  31#define PLL_DIV_MAX             (FIELD_GET(PMC_PLL_CTRL0_DIV_MSK, UINT_MAX) + 1)
  32#define UPLL_DIV                2
  33#define PLL_MUL_MAX             (FIELD_GET(PMC_PLL_CTRL1_MUL_MSK, UINT_MAX) + 1)
  34
  35#define FCORE_MIN               (600000000)
  36#define FCORE_MAX               (1200000000)
  37
  38#define PLL_MAX_ID              7
  39
  40struct sam9x60_pll {
  41        void __iomem *base;
  42        const struct clk_pll_characteristics *characteristics;
  43        const struct clk_pll_layout *layout;
  44        struct clk clk;
  45        u8 id;
  46};
  47
  48#define to_sam9x60_pll(_clk)    container_of(_clk, struct sam9x60_pll, clk)
  49
  50static inline bool sam9x60_pll_ready(void __iomem *base, int id)
  51{
  52        unsigned int status;
  53
  54        pmc_read(base, AT91_PMC_PLL_ISR0, &status);
  55
  56        return !!(status & BIT(id));
  57}
  58
  59static long sam9x60_frac_pll_compute_mul_frac(u32 *mul, u32 *frac, ulong rate,
  60                                              ulong parent_rate)
  61{
  62        unsigned long tmprate, remainder;
  63        unsigned long nmul = 0;
  64        unsigned long nfrac = 0;
  65
  66        if (rate < FCORE_MIN || rate > FCORE_MAX)
  67                return -ERANGE;
  68
  69        /*
  70         * Calculate the multiplier associated with the current
  71         * divider that provide the closest rate to the requested one.
  72         */
  73        nmul = mult_frac(rate, 1, parent_rate);
  74        tmprate = mult_frac(parent_rate, nmul, 1);
  75        remainder = rate - tmprate;
  76
  77        if (remainder) {
  78                nfrac = DIV_ROUND_CLOSEST_ULL((u64)remainder * (1 << 22),
  79                                              parent_rate);
  80
  81                tmprate += DIV_ROUND_CLOSEST_ULL((u64)nfrac * parent_rate,
  82                                                 (1 << 22));
  83        }
  84
  85        /* Check if resulted rate is valid.  */
  86        if (tmprate < FCORE_MIN || tmprate > FCORE_MAX)
  87                return -ERANGE;
  88
  89        *mul = nmul - 1;
  90        *frac = nfrac;
  91
  92        return tmprate;
  93}
  94
  95static ulong sam9x60_frac_pll_set_rate(struct clk *clk, ulong rate)
  96{
  97        struct sam9x60_pll *pll = to_sam9x60_pll(clk);
  98        void __iomem *base = pll->base;
  99        ulong parent_rate = clk_get_parent_rate(clk);
 100        u32 nmul, cmul, nfrac, cfrac, val;
 101        bool ready = sam9x60_pll_ready(base, pll->id);
 102        long ret;
 103
 104        if (!parent_rate)
 105                return 0;
 106
 107        ret = sam9x60_frac_pll_compute_mul_frac(&nmul, &nfrac, rate,
 108                                                parent_rate);
 109        if (ret < 0)
 110                return 0;
 111
 112        pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
 113                        pll->id);
 114        pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
 115        cmul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
 116        cfrac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
 117
 118        /* Check against current values. */
 119        if (sam9x60_pll_ready(base, pll->id) &&
 120            nmul == cmul && nfrac == cfrac)
 121                return 0;
 122
 123        /* Update it to hardware. */
 124        pmc_write(base, AT91_PMC_PLL_CTRL1,
 125                  (nmul << pll->layout->mul_shift) |
 126                  (nfrac << pll->layout->frac_shift));
 127
 128        pmc_update_bits(base, AT91_PMC_PLL_UPDT,
 129                        AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
 130                        AT91_PMC_PLL_UPDT_UPDATE | pll->id);
 131
 132        while (ready && !sam9x60_pll_ready(base, pll->id)) {
 133                debug("waiting for pll %u...\n", pll->id);
 134                cpu_relax();
 135        }
 136
 137        return parent_rate * (nmul + 1) + ((u64)parent_rate * nfrac >> 22);
 138}
 139
 140static ulong sam9x60_frac_pll_get_rate(struct clk *clk)
 141{
 142        struct sam9x60_pll *pll = to_sam9x60_pll(clk);
 143        void __iomem *base = pll->base;
 144        ulong parent_rate = clk_get_parent_rate(clk);
 145        u32 mul, frac, val;
 146
 147        if (!parent_rate)
 148                return 0;
 149
 150        pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
 151                        pll->id);
 152        pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
 153        mul = (val & pll->layout->mul_mask) >> pll->layout->mul_shift;
 154        frac = (val & pll->layout->frac_mask) >> pll->layout->frac_shift;
 155
 156        return (parent_rate * (mul + 1) + ((u64)parent_rate * frac >> 22));
 157}
 158
 159static int sam9x60_frac_pll_enable(struct clk *clk)
 160{
 161        struct sam9x60_pll *pll = to_sam9x60_pll(clk);
 162        void __iomem *base = pll->base;
 163        unsigned int val;
 164        ulong crate;
 165
 166        crate = sam9x60_frac_pll_get_rate(clk);
 167        if (crate < FCORE_MIN || crate > FCORE_MAX)
 168                return -ERANGE;
 169
 170        pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
 171                        pll->id);
 172        pmc_read(base, AT91_PMC_PLL_CTRL1, &val);
 173
 174        if (sam9x60_pll_ready(base, pll->id))
 175                return 0;
 176
 177        pmc_update_bits(base, AT91_PMC_PLL_UPDT,
 178                        AT91_PMC_PMM_UPDT_STUPTIM_MSK |
 179                        AT91_PMC_PLL_UPDT_ID_MSK,
 180                        AT91_PMC_PLL_UPDT_STUPTIM(0x3f) | pll->id);
 181
 182        /* Recommended value for AT91_PMC_PLL_ACR */
 183        if (pll->characteristics->upll)
 184                val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
 185        else
 186                val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
 187        pmc_write(base, AT91_PMC_PLL_ACR, val);
 188
 189        if (pll->characteristics->upll) {
 190                /* Enable the UTMI internal bandgap */
 191                val |= AT91_PMC_PLL_ACR_UTMIBG;
 192                pmc_write(base, AT91_PMC_PLL_ACR, val);
 193
 194                udelay(10);
 195
 196                /* Enable the UTMI internal regulator */
 197                val |= AT91_PMC_PLL_ACR_UTMIVR;
 198                pmc_write(base, AT91_PMC_PLL_ACR, val);
 199
 200                udelay(10);
 201
 202                pmc_update_bits(base, AT91_PMC_PLL_UPDT,
 203                                AT91_PMC_PLL_UPDT_UPDATE |
 204                                AT91_PMC_PLL_UPDT_ID_MSK,
 205                                AT91_PMC_PLL_UPDT_UPDATE | pll->id);
 206        }
 207
 208        pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
 209                        AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL,
 210                        AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL);
 211
 212        pmc_update_bits(base, AT91_PMC_PLL_UPDT,
 213                        AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
 214                        AT91_PMC_PLL_UPDT_UPDATE | pll->id);
 215
 216        while (!sam9x60_pll_ready(base, pll->id)) {
 217                debug("waiting for pll %u...\n", pll->id);
 218                cpu_relax();
 219        }
 220
 221        return 0;
 222}
 223
 224static int sam9x60_frac_pll_disable(struct clk *clk)
 225{
 226        struct sam9x60_pll *pll = to_sam9x60_pll(clk);
 227        void __iomem *base = pll->base;
 228
 229        pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
 230                        pll->id);
 231
 232        pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
 233                        AT91_PMC_PLL_CTRL0_ENPLL, 0);
 234
 235        if (pll->characteristics->upll)
 236                pmc_update_bits(base, AT91_PMC_PLL_ACR,
 237                                AT91_PMC_PLL_ACR_UTMIBG |
 238                                AT91_PMC_PLL_ACR_UTMIVR, 0);
 239
 240        pmc_update_bits(base, AT91_PMC_PLL_UPDT,
 241                        AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
 242                        AT91_PMC_PLL_UPDT_UPDATE | pll->id);
 243
 244        return 0;
 245}
 246
 247static const struct clk_ops sam9x60_frac_pll_ops = {
 248        .enable = sam9x60_frac_pll_enable,
 249        .disable = sam9x60_frac_pll_disable,
 250        .set_rate = sam9x60_frac_pll_set_rate,
 251        .get_rate = sam9x60_frac_pll_get_rate,
 252};
 253
 254static int sam9x60_div_pll_enable(struct clk *clk)
 255{
 256        struct sam9x60_pll *pll = to_sam9x60_pll(clk);
 257        void __iomem *base = pll->base;
 258        unsigned int val;
 259
 260        pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
 261                        pll->id);
 262        pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
 263
 264        /* Stop if enabled. */
 265        if (val & pll->layout->endiv_mask)
 266                return 0;
 267
 268        pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
 269                        pll->layout->endiv_mask,
 270                        (1 << pll->layout->endiv_shift));
 271
 272        pmc_update_bits(base, AT91_PMC_PLL_UPDT,
 273                        AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
 274                        AT91_PMC_PLL_UPDT_UPDATE | pll->id);
 275
 276        while (!sam9x60_pll_ready(base, pll->id)) {
 277                debug("waiting for pll %u...\n", pll->id);
 278                cpu_relax();
 279        }
 280
 281        return 0;
 282}
 283
 284static int sam9x60_div_pll_disable(struct clk *clk)
 285{
 286        struct sam9x60_pll *pll = to_sam9x60_pll(clk);
 287        void __iomem *base = pll->base;
 288
 289        pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
 290                        pll->id);
 291
 292        pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
 293                        pll->layout->endiv_mask, 0);
 294
 295        pmc_update_bits(base, AT91_PMC_PLL_UPDT,
 296                        AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
 297                        AT91_PMC_PLL_UPDT_UPDATE | pll->id);
 298
 299        return 0;
 300}
 301
 302static ulong sam9x60_div_pll_set_rate(struct clk *clk, ulong rate)
 303{
 304        struct sam9x60_pll *pll = to_sam9x60_pll(clk);
 305        void __iomem *base = pll->base;
 306        const struct clk_pll_characteristics *characteristics =
 307                                                        pll->characteristics;
 308        ulong parent_rate = clk_get_parent_rate(clk);
 309        u8 div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate) - 1;
 310        ulong req_rate = parent_rate / (div + 1);
 311        bool ready = sam9x60_pll_ready(base, pll->id);
 312        u32 val;
 313
 314        if (!parent_rate || div > pll->layout->div_mask ||
 315            req_rate < characteristics->output[0].min ||
 316            req_rate > characteristics->output[0].max)
 317                return 0;
 318
 319        pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
 320                        pll->id);
 321        pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
 322        /* Compare against current value. */
 323        if (div == ((val & pll->layout->div_mask) >> pll->layout->div_shift))
 324                return 0;
 325
 326        /* Update it to hardware. */
 327        pmc_update_bits(base, AT91_PMC_PLL_CTRL0,
 328                        pll->layout->div_mask,
 329                        div << pll->layout->div_shift);
 330
 331        pmc_update_bits(base, AT91_PMC_PLL_UPDT,
 332                        AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
 333                        AT91_PMC_PLL_UPDT_UPDATE | pll->id);
 334
 335        while (ready && !sam9x60_pll_ready(base, pll->id)) {
 336                debug("waiting for pll %u...\n", pll->id);
 337                cpu_relax();
 338        }
 339
 340        return req_rate;
 341}
 342
 343static ulong sam9x60_div_pll_get_rate(struct clk *clk)
 344{
 345        struct sam9x60_pll *pll = to_sam9x60_pll(clk);
 346        void __iomem *base = pll->base;
 347        ulong parent_rate = clk_get_parent_rate(clk);
 348        u32 val;
 349        u8 div;
 350
 351        if (!parent_rate)
 352                return 0;
 353
 354        pmc_update_bits(base, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
 355                        pll->id);
 356
 357        pmc_read(base, AT91_PMC_PLL_CTRL0, &val);
 358
 359        div = (val & pll->layout->div_mask) >> pll->layout->div_shift;
 360
 361        return parent_rate / (div + 1);
 362}
 363
 364static const struct clk_ops sam9x60_div_pll_ops = {
 365        .enable = sam9x60_div_pll_enable,
 366        .disable = sam9x60_div_pll_disable,
 367        .set_rate = sam9x60_div_pll_set_rate,
 368        .get_rate = sam9x60_div_pll_get_rate,
 369};
 370
 371static struct clk *
 372sam9x60_clk_register_pll(void __iomem *base, const char *type,
 373                         const char *name, const char *parent_name, u8 id,
 374                         const struct clk_pll_characteristics *characteristics,
 375                         const struct clk_pll_layout *layout, u32 flags)
 376{
 377        struct sam9x60_pll *pll;
 378        struct clk *clk;
 379        int ret;
 380
 381        if (!base || !type || !name || !parent_name || !characteristics ||
 382            !layout || id > PLL_MAX_ID)
 383                return ERR_PTR(-EINVAL);
 384
 385        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 386        if (!pll)
 387                return ERR_PTR(-ENOMEM);
 388
 389        pll->id = id;
 390        pll->characteristics = characteristics;
 391        pll->layout = layout;
 392        pll->base = base;
 393        clk = &pll->clk;
 394        clk->flags = flags;
 395
 396        ret = clk_register(clk, type, name, parent_name);
 397        if (ret) {
 398                kfree(pll);
 399                clk = ERR_PTR(ret);
 400        }
 401
 402        return clk;
 403}
 404
 405struct clk *
 406sam9x60_clk_register_div_pll(void __iomem *base, const char *name,
 407                             const char *parent_name, u8 id,
 408                             const struct clk_pll_characteristics *characteristics,
 409                             const struct clk_pll_layout *layout, bool critical)
 410{
 411        return sam9x60_clk_register_pll(base,
 412                UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL, name, parent_name, id,
 413                characteristics, layout,
 414                CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
 415}
 416
 417struct clk *
 418sam9x60_clk_register_frac_pll(void __iomem *base, const char *name,
 419                              const char *parent_name, u8 id,
 420                              const struct clk_pll_characteristics *characteristics,
 421                              const struct clk_pll_layout *layout, bool critical)
 422{
 423        return sam9x60_clk_register_pll(base,
 424                UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL, name, parent_name, id,
 425                characteristics, layout,
 426                CLK_GET_RATE_NOCACHE | (critical ? CLK_IS_CRITICAL : 0));
 427}
 428
 429U_BOOT_DRIVER(at91_sam9x60_div_pll_clk) = {
 430        .name = UBOOT_DM_CLK_AT91_SAM9X60_DIV_PLL,
 431        .id = UCLASS_CLK,
 432        .ops = &sam9x60_div_pll_ops,
 433        .flags = DM_FLAG_PRE_RELOC,
 434};
 435
 436U_BOOT_DRIVER(at91_sam9x60_frac_pll_clk) = {
 437        .name = UBOOT_DM_CLK_AT91_SAM9X60_FRAC_PLL,
 438        .id = UCLASS_CLK,
 439        .ops = &sam9x60_frac_pll_ops,
 440        .flags = DM_FLAG_PRE_RELOC,
 441};
 442
 443