uboot/arch/arm/cpu/armv7/bcm281xx/clk-core.c
<<
>>
Prefs
   1/*
   2 * Copyright 2013 Broadcom Corporation.
   3 *
   4 * SPDX-License-Identifier:      GPL-2.0+
   5 */
   6
   7/*
   8 *
   9 * bcm281xx architecture clock framework
  10 *
  11 */
  12
  13#include <common.h>
  14#include <asm/io.h>
  15#include <linux/errno.h>
  16#include <bitfield.h>
  17#include <asm/arch/sysmap.h>
  18#include <asm/kona-common/clk.h>
  19#include "clk-core.h"
  20
  21#define CLK_WR_ACCESS_PASSWORD  0x00a5a501
  22#define WR_ACCESS_OFFSET        0       /* common to all clock blocks */
  23#define POLICY_CTL_GO           1       /* Load and refresh policy masks */
  24#define POLICY_CTL_GO_ATL       4       /* Active Load */
  25
  26/* Helper function */
  27int clk_get_and_enable(char *clkstr)
  28{
  29        int ret = 0;
  30        struct clk *c;
  31
  32        debug("%s: %s\n", __func__, clkstr);
  33
  34        c = clk_get(clkstr);
  35        if (c) {
  36                ret = clk_enable(c);
  37                if (ret)
  38                        return ret;
  39        } else {
  40                printf("%s: Couldn't find %s\n", __func__, clkstr);
  41                return -EINVAL;
  42        }
  43        return ret;
  44}
  45
  46/*
  47 * Poll a register in a CCU's address space, returning when the
  48 * specified bit in that register's value is set (or clear).  Delay
  49 * a microsecond after each read of the register.  Returns true if
  50 * successful, or false if we gave up trying.
  51 *
  52 * Caller must ensure the CCU lock is held.
  53 */
  54#define CLK_GATE_DELAY_USEC 2000
  55static inline int wait_bit(void *base, u32 offset, u32 bit, bool want)
  56{
  57        unsigned int tries;
  58        u32 bit_mask = 1 << bit;
  59
  60        for (tries = 0; tries < CLK_GATE_DELAY_USEC; tries++) {
  61                u32 val;
  62                bool bit_val;
  63
  64                val = readl(base + offset);
  65                bit_val = (val & bit_mask) ? 1 : 0;
  66                if (bit_val == want)
  67                        return 0;       /* success */
  68                udelay(1);
  69        }
  70
  71        debug("%s: timeout on addr 0x%p, waiting for bit %d to go to %d\n",
  72              __func__, base + offset, bit, want);
  73
  74        return -ETIMEDOUT;
  75}
  76
  77/* Enable a peripheral clock */
  78static int peri_clk_enable(struct clk *c, int enable)
  79{
  80        int ret = 0;
  81        u32 reg;
  82        struct peri_clock *peri_clk = to_peri_clk(c);
  83        struct peri_clk_data *cd = peri_clk->data;
  84        struct bcm_clk_gate *gate = &cd->gate;
  85        void *base = (void *)c->ccu_clk_mgr_base;
  86
  87
  88        debug("%s: %s\n", __func__, c->name);
  89
  90        clk_get_rate(c);        /* Make sure rate and sel are filled in */
  91
  92        /* enable access */
  93        writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
  94
  95        if (enable) {
  96                debug("%s %s set rate %lu div %lu sel %d parent %lu\n",
  97                      __func__, c->name, c->rate, c->div, c->sel,
  98                      c->parent->rate);
  99
 100                /*
 101                 * clkgate - only software controllable gates are
 102                 * supported by u-boot which includes all clocks
 103                 * that matter. This avoids bringing in a lot of extra
 104                 * complexity as done in the kernel framework.
 105                 */
 106                if (gate_exists(gate)) {
 107                        reg = readl(base + cd->gate.offset);
 108                        reg |= (1 << cd->gate.en_bit);
 109                        writel(reg, base + cd->gate.offset);
 110                }
 111
 112                /* div and pll select */
 113                if (divider_exists(&cd->div)) {
 114                        reg = readl(base + cd->div.offset);
 115                        bitfield_replace(reg, cd->div.shift, cd->div.width,
 116                                         c->div - 1);
 117                        writel(reg, base + cd->div.offset);
 118                }
 119
 120                /* frequency selector */
 121                if (selector_exists(&cd->sel)) {
 122                        reg = readl(base + cd->sel.offset);
 123                        bitfield_replace(reg, cd->sel.shift, cd->sel.width,
 124                                         c->sel);
 125                        writel(reg, base + cd->sel.offset);
 126                }
 127
 128                /* trigger */
 129                if (trigger_exists(&cd->trig)) {
 130                        writel((1 << cd->trig.bit), base + cd->trig.offset);
 131
 132                        /* wait for trigger status bit to go to 0 */
 133                        ret = wait_bit(base, cd->trig.offset, cd->trig.bit, 0);
 134                        if (ret)
 135                                return ret;
 136                }
 137
 138                /* wait for running (status_bit = 1) */
 139                ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 1);
 140                if (ret)
 141                        return ret;
 142        } else {
 143                debug("%s disable clock %s\n", __func__, c->name);
 144
 145                /* clkgate */
 146                reg = readl(base + cd->gate.offset);
 147                reg &= ~(1 << cd->gate.en_bit);
 148                writel(reg, base + cd->gate.offset);
 149
 150                /* wait for stop (status_bit = 0) */
 151                ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 0);
 152        }
 153
 154        /* disable access */
 155        writel(0, base + WR_ACCESS_OFFSET);
 156
 157        return ret;
 158}
 159
 160/* Set the rate of a peripheral clock */
 161static int peri_clk_set_rate(struct clk *c, unsigned long rate)
 162{
 163        int ret = 0;
 164        int i;
 165        unsigned long diff;
 166        unsigned long new_rate = 0, div = 1;
 167        struct peri_clock *peri_clk = to_peri_clk(c);
 168        struct peri_clk_data *cd = peri_clk->data;
 169        const char **clock;
 170
 171        debug("%s: %s\n", __func__, c->name);
 172        diff = rate;
 173
 174        i = 0;
 175        for (clock = cd->clocks; *clock; clock++, i++) {
 176                struct refclk *ref = refclk_str_to_clk(*clock);
 177                if (!ref) {
 178                        printf("%s: Lookup of %s failed\n", __func__, *clock);
 179                        return -EINVAL;
 180                }
 181
 182                /* round to the new rate */
 183                div = ref->clk.rate / rate;
 184                if (div == 0)
 185                        div = 1;
 186
 187                new_rate = ref->clk.rate / div;
 188
 189                /* get the min diff */
 190                if (abs(new_rate - rate) < diff) {
 191                        diff = abs(new_rate - rate);
 192                        c->sel = i;
 193                        c->parent = &ref->clk;
 194                        c->rate = new_rate;
 195                        c->div = div;
 196                }
 197        }
 198
 199        debug("%s %s set rate %lu div %lu sel %d parent %lu\n", __func__,
 200              c->name, c->rate, c->div, c->sel, c->parent->rate);
 201        return ret;
 202}
 203
 204/* Get the rate of a peripheral clock */
 205static unsigned long peri_clk_get_rate(struct clk *c)
 206{
 207        struct peri_clock *peri_clk = to_peri_clk(c);
 208        struct peri_clk_data *cd = peri_clk->data;
 209        void *base = (void *)c->ccu_clk_mgr_base;
 210        int div = 1;
 211        const char **clock;
 212        struct refclk *ref;
 213        u32 reg;
 214
 215        debug("%s: %s\n", __func__, c->name);
 216        if (selector_exists(&cd->sel)) {
 217                reg = readl(base + cd->sel.offset);
 218                c->sel = bitfield_extract(reg, cd->sel.shift, cd->sel.width);
 219        } else {
 220                /*
 221                 * For peri clocks that don't have a selector, the single
 222                 * reference clock will always exist at index 0.
 223                 */
 224                c->sel = 0;
 225        }
 226
 227        if (divider_exists(&cd->div)) {
 228                reg = readl(base + cd->div.offset);
 229                div = bitfield_extract(reg, cd->div.shift, cd->div.width);
 230                div += 1;
 231        }
 232
 233        clock = cd->clocks;
 234        ref = refclk_str_to_clk(clock[c->sel]);
 235        if (!ref) {
 236                printf("%s: Can't lookup %s\n", __func__, clock[c->sel]);
 237                return 0;
 238        }
 239
 240        c->parent = &ref->clk;
 241        c->div = div;
 242        c->rate = c->parent->rate / c->div;
 243        debug("%s parent rate %lu div %d sel %d rate %lu\n", __func__,
 244              c->parent->rate, div, c->sel, c->rate);
 245
 246        return c->rate;
 247}
 248
 249/* Peripheral clock operations */
 250struct clk_ops peri_clk_ops = {
 251        .enable = peri_clk_enable,
 252        .set_rate = peri_clk_set_rate,
 253        .get_rate = peri_clk_get_rate,
 254};
 255
 256/* Enable a CCU clock */
 257static int ccu_clk_enable(struct clk *c, int enable)
 258{
 259        struct ccu_clock *ccu_clk = to_ccu_clk(c);
 260        void *base = (void *)c->ccu_clk_mgr_base;
 261        int ret = 0;
 262        u32 reg;
 263
 264        debug("%s: %s\n", __func__, c->name);
 265        if (!enable)
 266                return -EINVAL; /* CCU clock cannot shutdown */
 267
 268        /* enable access */
 269        writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
 270
 271        /* config enable for policy engine */
 272        writel(1, base + ccu_clk->lvm_en_offset);
 273
 274        /* wait for bit to go to 0 */
 275        ret = wait_bit(base, ccu_clk->lvm_en_offset, 0, 0);
 276        if (ret)
 277                return ret;
 278
 279        /* freq ID */
 280        if (!ccu_clk->freq_bit_shift)
 281                ccu_clk->freq_bit_shift = 8;
 282
 283        /* Set frequency id for each of the 4 policies */
 284        reg = ccu_clk->freq_id |
 285            (ccu_clk->freq_id << (ccu_clk->freq_bit_shift)) |
 286            (ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 2)) |
 287            (ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 3));
 288        writel(reg, base + ccu_clk->policy_freq_offset);
 289
 290        /* enable all clock mask */
 291        writel(0x7fffffff, base + ccu_clk->policy0_mask_offset);
 292        writel(0x7fffffff, base + ccu_clk->policy1_mask_offset);
 293        writel(0x7fffffff, base + ccu_clk->policy2_mask_offset);
 294        writel(0x7fffffff, base + ccu_clk->policy3_mask_offset);
 295
 296        if (ccu_clk->num_policy_masks == 2) {
 297                writel(0x7fffffff, base + ccu_clk->policy0_mask2_offset);
 298                writel(0x7fffffff, base + ccu_clk->policy1_mask2_offset);
 299                writel(0x7fffffff, base + ccu_clk->policy2_mask2_offset);
 300                writel(0x7fffffff, base + ccu_clk->policy3_mask2_offset);
 301        }
 302
 303        /* start policy engine */
 304        reg = readl(base + ccu_clk->policy_ctl_offset);
 305        reg |= (POLICY_CTL_GO + POLICY_CTL_GO_ATL);
 306        writel(reg, base + ccu_clk->policy_ctl_offset);
 307
 308        /* wait till started */
 309        ret = wait_bit(base, ccu_clk->policy_ctl_offset, 0, 0);
 310        if (ret)
 311                return ret;
 312
 313        /* disable access */
 314        writel(0, base + WR_ACCESS_OFFSET);
 315
 316        return ret;
 317}
 318
 319/* Get the CCU clock rate */
 320static unsigned long ccu_clk_get_rate(struct clk *c)
 321{
 322        struct ccu_clock *ccu_clk = to_ccu_clk(c);
 323        debug("%s: %s\n", __func__, c->name);
 324        c->rate = ccu_clk->freq_tbl[ccu_clk->freq_id];
 325        return c->rate;
 326}
 327
 328/* CCU clock operations */
 329struct clk_ops ccu_clk_ops = {
 330        .enable = ccu_clk_enable,
 331        .get_rate = ccu_clk_get_rate,
 332};
 333
 334/* Enable a bus clock */
 335static int bus_clk_enable(struct clk *c, int enable)
 336{
 337        struct bus_clock *bus_clk = to_bus_clk(c);
 338        struct bus_clk_data *cd = bus_clk->data;
 339        void *base = (void *)c->ccu_clk_mgr_base;
 340        int ret = 0;
 341        u32 reg;
 342
 343        debug("%s: %s\n", __func__, c->name);
 344        /* enable access */
 345        writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET);
 346
 347        /* enable gating */
 348        reg = readl(base + cd->gate.offset);
 349        if (!!(reg & (1 << cd->gate.status_bit)) == !!enable)
 350                debug("%s already %s\n", c->name,
 351                      enable ? "enabled" : "disabled");
 352        else {
 353                int want = (enable) ? 1 : 0;
 354                reg |= (1 << cd->gate.hw_sw_sel_bit);
 355
 356                if (enable)
 357                        reg |= (1 << cd->gate.en_bit);
 358                else
 359                        reg &= ~(1 << cd->gate.en_bit);
 360
 361                writel(reg, base + cd->gate.offset);
 362                ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit,
 363                               want);
 364                if (ret)
 365                        return ret;
 366        }
 367
 368        /* disable access */
 369        writel(0, base + WR_ACCESS_OFFSET);
 370
 371        return ret;
 372}
 373
 374/* Get the rate of a bus clock */
 375static unsigned long bus_clk_get_rate(struct clk *c)
 376{
 377        struct bus_clock *bus_clk = to_bus_clk(c);
 378        struct ccu_clock *ccu_clk;
 379
 380        debug("%s: %s\n", __func__, c->name);
 381        ccu_clk = to_ccu_clk(c->parent);
 382
 383        c->rate = bus_clk->freq_tbl[ccu_clk->freq_id];
 384        c->div = ccu_clk->freq_tbl[ccu_clk->freq_id] / c->rate;
 385        return c->rate;
 386}
 387
 388/* Bus clock operations */
 389struct clk_ops bus_clk_ops = {
 390        .enable = bus_clk_enable,
 391        .get_rate = bus_clk_get_rate,
 392};
 393
 394/* Enable a reference clock */
 395static int ref_clk_enable(struct clk *c, int enable)
 396{
 397        debug("%s: %s\n", __func__, c->name);
 398        return 0;
 399}
 400
 401/* Reference clock operations */
 402struct clk_ops ref_clk_ops = {
 403        .enable = ref_clk_enable,
 404};
 405
 406/*
 407 * clk.h implementation follows
 408 */
 409
 410/* Initialize the clock framework */
 411int clk_init(void)
 412{
 413        debug("%s:\n", __func__);
 414        return 0;
 415}
 416
 417/* Get a clock handle, give a name string */
 418struct clk *clk_get(const char *con_id)
 419{
 420        int i;
 421        struct clk_lookup *clk_tblp;
 422
 423        debug("%s: %s\n", __func__, con_id);
 424
 425        clk_tblp = arch_clk_tbl;
 426        for (i = 0; i < arch_clk_tbl_array_size; i++, clk_tblp++) {
 427                if (clk_tblp->con_id) {
 428                        if (!con_id || strcmp(clk_tblp->con_id, con_id))
 429                                continue;
 430                        return clk_tblp->clk;
 431                }
 432        }
 433        return NULL;
 434}
 435
 436/* Enable a clock */
 437int clk_enable(struct clk *c)
 438{
 439        int ret = 0;
 440
 441        debug("%s: %s\n", __func__, c->name);
 442        if (!c->ops || !c->ops->enable)
 443                return -1;
 444
 445        /* enable parent clock first */
 446        if (c->parent)
 447                ret = clk_enable(c->parent);
 448
 449        if (ret)
 450                return ret;
 451
 452        if (!c->use_cnt) {
 453                c->use_cnt++;
 454                ret = c->ops->enable(c, 1);
 455        }
 456
 457        return ret;
 458}
 459
 460/* Disable a clock */
 461void clk_disable(struct clk *c)
 462{
 463        debug("%s: %s\n", __func__, c->name);
 464        if (!c->ops || !c->ops->enable)
 465                return;
 466
 467        if (c->use_cnt) {
 468                c->use_cnt--;
 469                c->ops->enable(c, 0);
 470        }
 471
 472        /* disable parent */
 473        if (c->parent)
 474                clk_disable(c->parent);
 475}
 476
 477/* Get the clock rate */
 478unsigned long clk_get_rate(struct clk *c)
 479{
 480        unsigned long rate;
 481
 482        debug("%s: %s\n", __func__, c->name);
 483        if (!c || !c->ops || !c->ops->get_rate)
 484                return 0;
 485
 486        rate = c->ops->get_rate(c);
 487        debug("%s: rate = %ld\n", __func__, rate);
 488        return rate;
 489}
 490
 491/* Set the clock rate */
 492int clk_set_rate(struct clk *c, unsigned long rate)
 493{
 494        int ret;
 495
 496        debug("%s: %s rate=%ld\n", __func__, c->name, rate);
 497        if (!c || !c->ops || !c->ops->set_rate)
 498                return -EINVAL;
 499
 500        if (c->use_cnt)
 501                return -EINVAL;
 502
 503        ret = c->ops->set_rate(c, rate);
 504
 505        return ret;
 506}
 507
 508/* Not required for this arch */
 509/*
 510long clk_round_rate(struct clk *clk, unsigned long rate);
 511int clk_set_parent(struct clk *clk, struct clk *parent);
 512struct clk *clk_get_parent(struct clk *clk);
 513*/
 514