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