* [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller.
@ 2016-01-04 14:00 Purna Chandra Mandal
2016-01-05 19:31 ` Daniel Schwierzeck
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Purna Chandra Mandal @ 2016-01-04 14:00 UTC (permalink / raw)
To: u-boot
Signed-off-by: Purna Chandra Mandal <purna.mandal@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 at 1f801200 {
+ compatible = "microchip,pic32mzda_clk";
+ reg = <0xbf801200 0x1000>;
+ };
+
+Example: UART controller node that consumes the clock generated by the clock
+ controller:
+
+ uart1: serial at 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.mandal@microchip.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <clk.h>
+#include <div64.h>
+#include <wait_bit.h>
+#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.mandal@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 */
--
1.8.3.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller.
2016-01-04 14:00 [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller Purna Chandra Mandal
@ 2016-01-05 19:31 ` Daniel Schwierzeck
2016-01-06 6:56 ` Purna Chandra Mandal
2016-01-11 16:16 ` Daniel Schwierzeck
2016-01-11 16:57 ` Simon Glass
2 siblings, 1 reply; 7+ messages in thread
From: Daniel Schwierzeck @ 2016-01-05 19:31 UTC (permalink / raw)
To: u-boot
2016-01-04 15:00 GMT+01:00 Purna Chandra Mandal <purna.mandal@microchip.com>:
> Signed-off-by: Purna Chandra Mandal <purna.mandal@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 at 1f801200 {
> + compatible = "microchip,pic32mzda_clk";
> + reg = <0xbf801200 0x1000>;
> + };
> +
> +Example: UART controller node that consumes the clock generated by the clock
> + controller:
> +
> + uart1: serial at 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
please rename to 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.mandal@microchip.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + *
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <clk.h>
> +#include <div64.h>
> +#include <wait_bit.h>
> +#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.mandal@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 */
> --
> 1.8.3.1
>
>
--
- Daniel
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller.
2016-01-05 19:31 ` Daniel Schwierzeck
@ 2016-01-06 6:56 ` Purna Chandra Mandal
0 siblings, 0 replies; 7+ messages in thread
From: Purna Chandra Mandal @ 2016-01-06 6:56 UTC (permalink / raw)
To: u-boot
On 01/06/2016 01:01 AM, Daniel Schwierzeck wrote:
> 2016-01-04 15:00 GMT+01:00 Purna Chandra Mandal <purna.mandal@microchip.com>:
>> Signed-off-by: Purna Chandra Mandal <purna.mandal@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 at 1f801200 {
>> + compatible = "microchip,pic32mzda_clk";
>> + reg = <0xbf801200 0x1000>;
>> + };
>> +
>> +Example: UART controller node that consumes the clock generated by the clock
>> + controller:
>> +
>> + uart1: serial at 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
> please rename to clk_pic32.o
ack.
>> 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.mandal@microchip.com>
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + *
>> + */
>> +
[...]
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller.
2016-01-04 14:00 [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller Purna Chandra Mandal
2016-01-05 19:31 ` Daniel Schwierzeck
@ 2016-01-11 16:16 ` Daniel Schwierzeck
2016-01-12 4:55 ` Purna Chandra Mandal
2016-01-11 16:57 ` Simon Glass
2 siblings, 1 reply; 7+ messages in thread
From: Daniel Schwierzeck @ 2016-01-11 16:16 UTC (permalink / raw)
To: u-boot
Am Montag, den 04.01.2016, 19:30 +0530 schrieb Purna Chandra Mandal:
> Signed-off-by: Purna Chandra Mandal <purna.mandal@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 at 1f801200 {
> + compatible = "microchip,pic32mzda_clk";
> + reg = <0xbf801200 0x1000>;
> + };
> +
> +Example: UART controller node that consumes the clock generated by
> the clock
> + controller:
> +
> + uart1: serial at 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.mandal at 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.
> +#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.mandal@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 */
--
- Daniel
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller.
2016-01-04 14:00 [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller Purna Chandra Mandal
2016-01-05 19:31 ` Daniel Schwierzeck
2016-01-11 16:16 ` Daniel Schwierzeck
@ 2016-01-11 16:57 ` Simon Glass
2016-01-12 4:59 ` Purna Chandra Mandal
2 siblings, 1 reply; 7+ messages in thread
From: Simon Glass @ 2016-01-11 16:57 UTC (permalink / raw)
To: u-boot
Hi,
On 4 January 2016 at 07:00, Purna Chandra Mandal
<purna.mandal@microchip.com> wrote:
> Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com>
>
Commit message please.
> ---
>
> 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
>
Reviewed-by: Simon Glass <sjg@chromium.org>
nits below
> 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 at 1f801200 {
> + compatible = "microchip,pic32mzda_clk";
> + reg = <0xbf801200 0x1000>;
> + };
> +
> +Example: UART controller node that consumes the clock generated by the clock
> + controller:
> +
> + uart1: serial at 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
As the other review mentions, should use underscore in filenames
unless it is a uclass.
> 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.mandal@microchip.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0+
> + *
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <clk.h>
nit: clk.h should go above dm.h, below common.h
> +#include <div64.h>
> +#include <wait_bit.h>
> +#include <dm/lists.h>
> +#include <asm/io.h>
> +#include <mach/pic32.h>
> +#include <dt-bindings/clock/microchip,clock.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
Regards,
Simon
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller.
2016-01-11 16:16 ` Daniel Schwierzeck
@ 2016-01-12 4:55 ` Purna Chandra Mandal
0 siblings, 0 replies; 7+ messages in thread
From: Purna Chandra Mandal @ 2016-01-12 4:55 UTC (permalink / raw)
To: u-boot
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.mandal@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 at 1f801200 {
>> + compatible = "microchip,pic32mzda_clk";
>> + reg = <0xbf801200 0x1000>;
>> + };
>> +
>> +Example: UART controller node that consumes the clock generated by
>> the clock
>> + controller:
>> +
>> + uart1: serial at 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.mandal at 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.mandal@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 */
^ permalink raw reply [flat|nested] 7+ messages in thread
* [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller.
2016-01-11 16:57 ` Simon Glass
@ 2016-01-12 4:59 ` Purna Chandra Mandal
0 siblings, 0 replies; 7+ messages in thread
From: Purna Chandra Mandal @ 2016-01-12 4:59 UTC (permalink / raw)
To: u-boot
On 01/11/2016 10:27 PM, Simon Glass wrote:
> Hi,
>
> On 4 January 2016 at 07:00, Purna Chandra Mandal
> <purna.mandal@microchip.com> wrote:
>> Signed-off-by: Purna Chandra Mandal <purna.mandal@microchip.com>
>>
> Commit message please.
Ack. Will add.
>> ---
>>
>> 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
>>
> Reviewed-by: Simon Glass <sjg@chromium.org>
>
> nits below
>
>> 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 at 1f801200 {
>> + compatible = "microchip,pic32mzda_clk";
>> + reg = <0xbf801200 0x1000>;
>> + };
>> +
>> +Example: UART controller node that consumes the clock generated by the clock
>> + controller:
>> +
>> + uart1: serial at 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
> As the other review mentions, should use underscore in filenames
> unless it is a uclass.
Agreed.
>> 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.mandal@microchip.com>
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + *
>> + */
>> +
>> +#include <common.h>
>> +#include <dm.h>
>> +#include <clk.h>
> nit: clk.h should go above dm.h, below common.h
ack. If you could share *specific* reason behind this order (like dependencies)?
>> +#include <div64.h>
>> +#include <wait_bit.h>
>> +#include <dm/lists.h>
>> +#include <asm/io.h>
>> +#include <mach/pic32.h>
>> +#include <dt-bindings/clock/microchip,clock.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
> Regards,
> Simon
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2016-01-12 4:59 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-04 14:00 [U-Boot] [PATCH v2 02/13] drivers: clk: Add clock driver for Microchip PIC32 Microcontroller Purna Chandra Mandal
2016-01-05 19:31 ` Daniel Schwierzeck
2016-01-06 6:56 ` Purna Chandra Mandal
2016-01-11 16:16 ` Daniel Schwierzeck
2016-01-12 4:55 ` Purna Chandra Mandal
2016-01-11 16:57 ` Simon Glass
2016-01-12 4:59 ` Purna Chandra Mandal
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.