On 01/11/2016 09:46 PM, Daniel Schwierzeck wrote:

> Am Montag, den 04.01.2016, 19:30 +0530 schrieb Purna Chandra Mandal:
>> Signed-off-by: Purna Chandra Mandal <purna.man...@microchip.com>
>>
>> ---
>>
>> Changes in v2:
>> - add get clock rate for mpll clock
>>
>>  .../clock/microchip,pic32-clock.txt                |  28 ++
>>  drivers/clk/Makefile                               |   1 +
>>  drivers/clk/clk-pic32.c                            | 427
>> +++++++++++++++++++++
>>  include/dt-bindings/clock/microchip,clock.h        |  29 ++
>>  4 files changed, 485 insertions(+)
>>  create mode 100644 doc/device-tree-bindings/clock/microchip,pic32
>> -clock.txt
>>  create mode 100644 drivers/clk/clk-pic32.c
>>  create mode 100644 include/dt-bindings/clock/microchip,clock.h
>>
>> diff --git a/doc/device-tree-bindings/clock/microchip,pic32-clock.txt
>> b/doc/device-tree-bindings/clock/microchip,pic32-clock.txt
>> new file mode 100644
>> index 0000000..d02b9d7
>> --- /dev/null
>> +++ b/doc/device-tree-bindings/clock/microchip,pic32-clock.txt
>> @@ -0,0 +1,28 @@
>> +* Microchip PIC32 Clock and Oscillator
>> +
>> +The PIC32 clock controller generates and supplies clock to various
>> +controllers within the SoC.
>> +
>> +Required Properties:
>> +
>> +- compatible: should be "microchip,pic32mzda_clk"
>> +- reg: physical base address of the controller and length of memory
>> mapped
>> +  region.
>> +- #clock-cells: should be 1.
>> +
>> +Example: Clock controller node:
>> +
>> +    clock: clk@1f801200 {
>> +            compatible = "microchip,pic32mzda_clk";
>> +            reg = <0xbf801200 0x1000>;
>> +    };
>> +
>> +Example: UART controller node that consumes the clock generated by
>> the clock
>> +  controller:
>> +
>> +    uart1: serial@1f822000 {
>> +            compatible = "microchip,pic32mzda-uart";
>> +            reg = <0xbf822000 0x50>;
>> +            interrupts = <112 IRQ_TYPE_LEVEL_HIGH>;
>> +            clocks = <&clock PB2CLK>;
>> +    };
>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>> index 4a6a4a8..3c84e08 100644
>> --- a/drivers/clk/Makefile
>> +++ b/drivers/clk/Makefile
>> @@ -9,3 +9,4 @@ obj-$(CONFIG_CLK) += clk-uclass.o
>>  obj-$(CONFIG_ROCKCHIP_RK3036) += clk_rk3036.o
>>  obj-$(CONFIG_ROCKCHIP_RK3288) += clk_rk3288.o
>>  obj-$(CONFIG_SANDBOX) += clk_sandbox.o
>> +obj-$(CONFIG_MACH_PIC32) += clk-pic32.o
>> diff --git a/drivers/clk/clk-pic32.c b/drivers/clk/clk-pic32.c
>> new file mode 100644
>> index 0000000..70aac05
>> --- /dev/null
>> +++ b/drivers/clk/clk-pic32.c
>> @@ -0,0 +1,427 @@
>> +/*
>> + * Copyright (C) 2015 Purna Chandra Mandal <
>> purna.man...@microchip.com>
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + *
>> + */
>> +
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <clk.h>
>> +#include <div64.h>
>> +#include <wait_bit.h>
> I can't find wait_bit.h in mainline. Is there an unmerged patch which
> adds this file and you depend on? Could you point me to it? Thanks.

Yes, this is not on mainline. Based on review (from Marek Vesut)
to use wait_for_bit() for unbounded loops I have pulled the
under-review patch from [1].

[1] http://patchwork.ozlabs.org/patch/561185/

>> +#include <dm/lists.h>
>> +#include <asm/io.h>
>> +#include <mach/pic32.h>
>> +#include <dt-bindings/clock/microchip,clock.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +
>> +/* Primary oscillator */
>> +#define SYS_POSC_CLK_HZ     24000000
>> +
>> +/* FRC clk rate */
>> +#define SYS_FRC_CLK_HZ      8000000
>> +
>> +/* Clock registers */
>> +#define OSCCON              0x0000
>> +#define OSCTUNE             0x0010
>> +#define SPLLCON             0x0020
>> +#define REFO1CON    0x0080
>> +#define REFO1TRIM   0x0090
>> +#define PB1DIV              0x0140
>> +
>> +/* PLL */
>> +#define ICLK_MASK   0x00000080
>> +#define PLLIDIV_MASK        0x00000007
>> +#define PLLODIV_MASK        0x00000007
>> +#define CUROSC_MASK 0x00000007
>> +#define PLLMUL_MASK 0x0000007F
>> +#define FRCDIV_MASK 0x00000007
>> +
>> +/* PBCLK */
>> +#define PBDIV_MASK  0x00000007
>> +
>> +/* SYSCLK MUX */
>> +#define SCLK_SRC_FRC1       0
>> +#define SCLK_SRC_SPLL       1
>> +#define SCLK_SRC_POSC       2
>> +#define SCLK_SRC_FRC2       7
>> +
>> +/* Reference Oscillator Control Reg fields */
>> +#define REFO_SEL_MASK       0x0f
>> +#define REFO_SEL_SHIFT      0
>> +#define REFO_ACTIVE BIT(8)
>> +#define REFO_DIVSW_EN       BIT(9)
>> +#define REFO_OE             BIT(12)
>> +#define REFO_ON             BIT(15)
>> +#define REFO_DIV_SHIFT      16
>> +#define REFO_DIV_MASK       0x7fff
>> +
>> +/* Reference Oscillator Trim Register Fields */
>> +#define REFO_TRIM_REG       0x10
>> +#define REFO_TRIM_MASK      0x1ff
>> +#define REFO_TRIM_SHIFT     23
>> +#define REFO_TRIM_MAX       511
>> +
>> +#define ROCLK_SRC_SCLK              0x0
>> +#define ROCLK_SRC_SPLL              0x7
>> +#define ROCLK_SRC_ROCLKI    0x8
>> +
>> +/* Memory PLL */
>> +#define MPLL_IDIV           0x03
>> +#define MPLL_MULT           0x32
>> +#define MPLL_ODIV1          0x02
>> +#define MPLL_ODIV2          0x01
>> +#define MPLL_VREG_RDY               BIT(23)
>> +#define MPLL_RDY            BIT(31)
>> +#define MPLL_IDIV_SHIFT             0
>> +#define MPLL_MULT_SHIFT             8
>> +#define MPLL_ODIV1_SHIFT    24
>> +#define MPLL_ODIV2_SHIFT    27
>> +
>> +struct pic32_clk_priv {
>> +    void __iomem *iobase;
>> +    void __iomem *syscfg_base;
>> +};
>> +
>> +static ulong pic32_get_pll_rate(struct pic32_clk_priv *priv)
>> +{
>> +    u32 iclk, idiv, odiv, mult;
>> +    ulong plliclk, v;
>> +
>> +    v = readl(priv->iobase + SPLLCON);
>> +    iclk = (v & ICLK_MASK);
>> +    idiv = ((v >> 8) & PLLIDIV_MASK) + 1;
>> +    odiv = ((v >> 24) & PLLODIV_MASK);
>> +    mult = ((v >> 16) & PLLMUL_MASK) + 1;
>> +
>> +    plliclk = iclk ? SYS_FRC_CLK_HZ : SYS_POSC_CLK_HZ;
>> +
>> +    if (odiv < 2)
>> +            odiv = 2;
>> +    else if (odiv < 5)
>> +            odiv = (1 << odiv);
>> +    else
>> +            odiv = 32;
>> +
>> +    return ((plliclk / idiv) * mult) / odiv;
>> +}
>> +
>> +static ulong pic32_get_sysclk(struct pic32_clk_priv *priv)
>> +{
>> +    ulong v;
>> +    ulong hz;
>> +    ulong div, frcdiv;
>> +    ulong curr_osc;
>> +
>> +    /* get clk source */
>> +    v = readl(priv->iobase + OSCCON);
>> +    curr_osc = (v >> 12) & CUROSC_MASK;
>> +    switch (curr_osc) {
>> +    case SCLK_SRC_FRC1:
>> +    case SCLK_SRC_FRC2:
>> +            frcdiv = ((v >> 24) & FRCDIV_MASK);
>> +            div = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7));
>> +            hz = SYS_FRC_CLK_HZ / div;
>> +            break;
>> +
>> +    case SCLK_SRC_SPLL:
>> +            hz = pic32_get_pll_rate(priv);
>> +            break;
>> +
>> +    case SCLK_SRC_POSC:
>> +            hz = SYS_POSC_CLK_HZ;
>> +            break;
>> +
>> +    default:
>> +            hz = 0;
>> +            printf("clk: unknown sclk_src.\n");
>> +            break;
>> +    }
>> +
>> +    return hz;
>> +}
>> +
>> +static ulong pic32_get_pbclk(struct pic32_clk_priv *priv, int
>> periph)
>> +{
>> +    void __iomem *reg;
>> +    ulong div, clk_freq;
>> +
>> +    WARN_ON((periph < PB1CLK) || (periph > PB7CLK));
>> +
>> +    clk_freq = pic32_get_sysclk(priv);
>> +
>> +    reg = priv->iobase + PB1DIV + (periph - PB1CLK) * 0x10;
>> +    div = (readl(reg) & PBDIV_MASK) + 1;
>> +
>> +    return clk_freq / div;
>> +}
>> +
>> +static ulong pic32_get_cpuclk(struct pic32_clk_priv *priv)
>> +{
>> +    return pic32_get_pbclk(priv, PB7CLK);
>> +}
>> +
>> +static ulong pic32_set_refclk(struct pic32_clk_priv *priv, int
>> periph,
>> +                          int parent_rate, int rate, int
>> parent_id)
>> +{
>> +    void __iomem *reg;
>> +    u32 div, trim, v;
>> +    u64 frac;
>> +
>> +    WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
>> +
>> +    /* calculate dividers,
>> +     *   rate = parent_rate / [2 * (div + (trim / 512))]
>> +     */
>> +    if (parent_rate <= rate) {
>> +            div = 0;
>> +            trim = 0;
>> +    } else {
>> +            div = parent_rate / (rate << 1);
>> +            frac = parent_rate;
>> +            frac <<= 8;
>> +            do_div(frac, rate);
>> +            frac -= (u64)(div << 9);
>> +            trim = (frac >= REFO_TRIM_MAX) ? REFO_TRIM_MAX :
>> (u32)frac;
>> +    }
>> +
>> +    reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
>> +
>> +    /* disable clk */
>> +    writel(REFO_ON | REFO_OE, reg + _CLR_OFFSET);
>> +
>> +    /* wait till previous src change is active */
>> +    wait_for_bit(__func__, reg, REFO_DIVSW_EN | REFO_ACTIVE,
>> +                 false, CONFIG_SYS_HZ, false);
>> +
>> +    /* parent_id */
>> +    v = readl(reg);
>> +    v &= ~(REFO_SEL_MASK << REFO_SEL_SHIFT);
>> +    v |= (parent_id << REFO_SEL_SHIFT);
>> +
>> +    /* apply rodiv */
>> +    v &= ~(REFO_DIV_MASK << REFO_DIV_SHIFT);
>> +    v |= (div << REFO_DIV_SHIFT);
>> +    writel(v, reg);
>> +
>> +    /* apply trim */
>> +    v = readl(reg + REFO_TRIM_REG);
>> +    v &= ~(REFO_TRIM_MASK << REFO_TRIM_SHIFT);
>> +    v |= (trim << REFO_TRIM_SHIFT);
>> +    writel(v, reg + REFO_TRIM_REG);
>> +
>> +    /* enable clk */
>> +    writel(REFO_ON | REFO_OE, reg + _SET_OFFSET);
>> +
>> +    /* switch divider */
>> +    writel(REFO_DIVSW_EN, reg + _SET_OFFSET);
>> +
>> +    /* wait for divider switching to complete */
>> +    wait_for_bit(__func__, reg, REFO_DIVSW_EN, false,
>> +                 CONFIG_SYS_HZ, false);
>> +
>> +    return 0;
>> +}
>> +
>> +static ulong pic32_get_refclk(struct pic32_clk_priv *priv, int
>> periph)
>> +{
>> +    u32 rodiv, rotrim, rosel, v, parent_rate;
>> +    void __iomem *reg;
>> +    u64 rate64;
>> +
>> +    WARN_ON((periph < REF1CLK) || (periph > REF5CLK));
>> +
>> +    reg = priv->iobase + REFO1CON + (periph - REF1CLK) * 0x20;
>> +    v = readl(reg);
>> +    /* get rosel */
>> +    rosel = (v >> REFO_SEL_SHIFT) & REFO_SEL_MASK;
>> +    /* get div */
>> +    rodiv = (v >> REFO_DIV_SHIFT) & REFO_DIV_MASK;
>> +
>> +    /* get trim */
>> +    v = readl(reg + REFO_TRIM_REG);
>> +    rotrim = (v >> REFO_TRIM_SHIFT) & REFO_TRIM_MASK;
>> +
>> +    if (!rodiv)
>> +            return 0;
>> +
>> +    /* get parent rate */
>> +    switch (rosel) {
>> +    case ROCLK_SRC_SCLK:
>> +            parent_rate = pic32_get_cpuclk(priv);
>> +            break;
>> +    case ROCLK_SRC_SPLL:
>> +            parent_rate = pic32_get_pll_rate(priv);
>> +            break;
>> +    default:
>> +            parent_rate = 0;
>> +            break;
>> +    }
>> +
>> +    /* Calculation
>> +     * rate = parent_rate / [2 * (div + (trim / 512))]
>> +     */
>> +    if (rotrim) {
>> +            rodiv <<= 9;
>> +            rodiv += rotrim;
>> +            rate64 = parent_rate;
>> +            rate64 <<= 8;
>> +            do_div(rate64, rodiv);
>> +            v = (u32)rate64;
>> +    } else {
>> +            v = parent_rate / (rodiv << 1);
>> +    }
>> +    return v;
>> +}
>> +
>> +static ulong pic32_get_mpll_rate(struct pic32_clk_priv *priv)
>> +{
>> +    u32 v, idiv, mul;
>> +    u32 odiv1, odiv2;
>> +    u64 rate;
>> +
>> +    v = readl(priv->syscfg_base + CFGMPLL);
>> +    idiv = v & 0x3f;
>> +    mul = (v >> MPLL_MULT_SHIFT) & 0xff;
>> +    odiv1 = (v >> MPLL_ODIV1_SHIFT) & 0x7;
>> +    odiv2 = (v >> MPLL_ODIV2_SHIFT) & 0x7;
>> +
>> +    rate = (SYS_POSC_CLK_HZ / idiv) * mul;
>> +    do_div(rate, odiv1);
>> +    do_div(rate, odiv2);
>> +
>> +    return (ulong)rate;
>> +}
>> +
>> +static void pic32_mpll_init(struct pic32_clk_priv *priv)
>> +{
>> +    u32 v, mask;
>> +
>> +    /* initialize */
>> +    v = (MPLL_IDIV << MPLL_IDIV_SHIFT) |
>> +        (MPLL_MULT << MPLL_MULT_SHIFT) |
>> +        (MPLL_ODIV1 << MPLL_ODIV1_SHIFT) |
>> +        (MPLL_ODIV2 << MPLL_ODIV2_SHIFT);
>> +
>> +    writel(v, priv->syscfg_base + CFGMPLL);
>> +
>> +    /* Wait for ready */
>> +    mask = MPLL_RDY | MPLL_VREG_RDY;
>> +    wait_for_bit(__func__, priv->syscfg_base + CFGMPLL, mask,
>> +                 true, get_tbclk(), false);
>> +}
>> +
>> +static void pic32_clk_init(struct udevice *dev)
>> +{
>> +    const void *blob = gd->fdt_blob;
>> +    struct pic32_clk_priv *priv;
>> +    ulong rate, pll_hz;
>> +    char propname[50];
>> +    int i;
>> +
>> +    priv = dev_get_priv(dev);
>> +    pll_hz = pic32_get_pll_rate(priv);
>> +
>> +    /* Initialize REFOs as not initialized and enabled on reset.
>> */
>> +    for (i = REF1CLK; i <= REF5CLK; i++) {
>> +            snprintf(propname, sizeof(propname),
>> +                     "microchip,refo%d-frequency", i - REF1CLK +
>> 1);
>> +            rate = fdtdec_get_int(blob, dev->of_offset,
>> propname, 0);
>> +            if (rate)
>> +                    pic32_set_refclk(priv, i, pll_hz, rate,
>> ROCLK_SRC_SPLL);
>> +    }
>> +
>> +    /* Memory PLL */
>> +    pic32_mpll_init(priv);
>> +}
>> +
>> +static ulong pic32_clk_get_rate(struct udevice *dev)
>> +{
>> +    struct pic32_clk_priv *priv = dev_get_priv(dev);
>> +
>> +    return pic32_get_cpuclk(priv);
>> +}
>> +
>> +static ulong pic32_get_periph_rate(struct udevice *dev, int periph)
>> +{
>> +    struct pic32_clk_priv *priv = dev_get_priv(dev);
>> +    ulong rate;
>> +
>> +    switch (periph) {
>> +    case PB1CLK ... PB7CLK:
>> +            rate = pic32_get_pbclk(priv, periph);
>> +            break;
>> +    case REF1CLK ... REF5CLK:
>> +            rate = pic32_get_refclk(priv, periph);
>> +            break;
>> +    case PLLCLK:
>> +            rate = pic32_get_pll_rate(priv);
>> +            break;
>> +    case MPLL:
>> +            rate = pic32_get_mpll_rate(priv);
>> +            break;
>> +    default:
>> +            rate = 0;
>> +            break;
>> +    }
>> +
>> +    return rate;
>> +}
>> +
>> +static ulong pic32_set_periph_rate(struct udevice *dev, int periph,
>> ulong rate)
>> +{
>> +    struct pic32_clk_priv *priv = dev_get_priv(dev);
>> +    ulong pll_hz;
>> +
>> +    switch (periph) {
>> +    case REF1CLK ... REF5CLK:
>> +            pll_hz = pic32_get_pll_rate(priv);
>> +            pic32_set_refclk(priv, periph, pll_hz, rate,
>> ROCLK_SRC_SPLL);
>> +            break;
>> +    default:
>> +            break;
>> +    }
>> +
>> +    return rate;
>> +}
>> +
>> +static struct clk_ops pic32_pic32_clk_ops = {
>> +    .get_rate = pic32_clk_get_rate,
>> +    .set_periph_rate = pic32_set_periph_rate,
>> +    .get_periph_rate = pic32_get_periph_rate,
>> +};
>> +
>> +static int pic32_clk_probe(struct udevice *dev)
>> +{
>> +    struct pic32_clk_priv *priv = dev_get_priv(dev);
>> +    fdt_addr_t addr;
>> +
>> +    addr = dev_get_addr(dev);
>> +    if (addr == FDT_ADDR_T_NONE)
>> +            return -EINVAL;
>> +
>> +    priv->iobase = pic32_ioremap(addr);
>> +    priv->syscfg_base = pic32_ioremap(PIC32_CFG_BASE);
>> +
>> +    /* initialize clocks */
>> +    pic32_clk_init(dev);
>> +
>> +    return 0;
>> +}
>> +
>> +static const struct udevice_id pic32_clk_ids[] = {
>> +    { .compatible = "microchip,pic32mzda_clk"},
>> +    {}
>> +};
>> +
>> +U_BOOT_DRIVER(pic32_clk) = {
>> +    .name           = "pic32_clk",
>> +    .id             = UCLASS_CLK,
>> +    .of_match       = pic32_clk_ids,
>> +    .flags          = DM_FLAG_PRE_RELOC,
>> +    .ops            = &pic32_pic32_clk_ops,
>> +    .probe          = pic32_clk_probe,
>> +    .priv_auto_alloc_size = sizeof(struct pic32_clk_priv),
>> +};
>> diff --git a/include/dt-bindings/clock/microchip,clock.h b/include/dt
>> -bindings/clock/microchip,clock.h
>> new file mode 100644
>> index 0000000..93c222d
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/microchip,clock.h
>> @@ -0,0 +1,29 @@
>> +/*
>> + * (c) 2015 Purna Chandra Mandal <purna.man...@microchip.com>
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + *
>> + */
>> +
>> +#ifndef __CLK_MICROCHIP_PIC32
>> +#define __CLK_MICROCHIP_PIC32
>> +
>> +/* clock output indices */
>> +#define BASECLK     0
>> +#define PLLCLK      1
>> +#define MPLL        2
>> +#define SYSCLK      3
>> +#define PB1CLK      4
>> +#define PB2CLK      5
>> +#define PB3CLK      6
>> +#define PB4CLK      7
>> +#define PB5CLK      8
>> +#define PB6CLK      9
>> +#define PB7CLK      10
>> +#define REF1CLK     11
>> +#define REF2CLK     12
>> +#define REF3CLK     13
>> +#define REF4CLK     14
>> +#define REF5CLK     15
>> +
>> +#endif      /* __CLK_MICROCHIP_PIC32 */

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to