[PATCH v5 0/2] pinctrl: imx: Add driver for i.MX8MQ
This is the fifth version for the patch series sent by Lucas. https://www.spinics.net/lists/devicetree/msg212752.html Fourth version can be found here: https://lkml.org/lkml/2018/6/20/478 Changes since v4: * implemented all Aisheng's review comments Changes since v3: * dropped the SION generic pinconf changes * added examples to the bindings doc Changes since v2: * switch back to the 'fsl,pins' and hardcoded the config values inside the dts. * updated documentation accordingly Abel Vesa (1): dt-bindings: add binding for i.MX8MQ IOMUXC Lucas Stach (1): pinctrl: imx: add driver for i.MX8MQ .../bindings/pinctrl/fsl,imx8mq-pinctrl.txt| 32 ++ drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx8mq.c | 351 + 4 files changed, 391 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8mq.c -- 2.7.4
[PATCH v5 1/2] dt-bindings: add binding for i.MX8MQ IOMUXC
This adds the binding for the i.MX8MQ pin controller, in the same fashion as earlier i.MX SoCs. Signed-off-by: Abel Vesa Acked-by: Dong Aisheng --- .../bindings/pinctrl/fsl,imx8mq-pinctrl.txt| 32 ++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt new file mode 100644 index 000..e1c405d --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt @@ -0,0 +1,32 @@ +* Freescale IMX8MQ IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory +for common binding part and usage. + +Required properties: +- compatible: "fsl,imx8mq-iomuxc" +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx8mq-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX8M Quad + Reference Manual for detailed CONFIG settings. + +Examples: + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; +}; + +iomuxc: iomuxc@3033 { +compatible = "fsl,imx8mq-iomuxc"; +reg = <0x0 0x3033 0x0 0x1>; + +pinctrl_uart1: uart1grp { +fsl,pins = < +MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49 +MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49 +>; +}; +}; -- 2.7.4
[PATCH v5 2/2] pinctrl: imx: add driver for i.MX8MQ
From: Lucas Stach The i.MX8MQ pincontrol works in a similar way to the earlier i.MX SoCs. This driver builds on top of the imx specific pinconf handling. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Acked-by: Dong Aisheng --- drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx8mq.c | 351 + 3 files changed, 359 insertions(+) create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8mq.c diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 0d8ba1e..dccf64c 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -117,6 +117,13 @@ config PINCTRL_IMX7ULP help Say Y here to enable the imx7ulp pinctrl driver +config PINCTRL_IMX8MQ + bool "IMX8MQ pinctrl driver" + depends on SOC_IMX8MQ + select PINCTRL_IMX + help + Say Y here to enable the imx8mq pinctrl driver + config PINCTRL_VF610 bool "Freescale Vybrid VF610 pinctrl driver" depends on SOC_VF610 diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 368be8c..73175b3 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o obj-$(CONFIG_PINCTRL_IMX7D)+= pinctrl-imx7d.o obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o +obj-$(CONFIG_PINCTRL_IMX8MQ) += pinctrl-imx8mq.o obj-$(CONFIG_PINCTRL_VF610)+= pinctrl-vf610.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_IMX23)+= pinctrl-imx23.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mq.c b/drivers/pinctrl/freescale/pinctrl-imx8mq.c new file mode 100644 index 000..8d39af5 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx8mq.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + * Copyright (C) 2018 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx8mq_pads { + MX8MQ_PAD_RESERVE0 = 0, + MX8MQ_PAD_RESERVE1 = 1, + MX8MQ_PAD_RESERVE2 = 2, + MX8MQ_PAD_RESERVE3 = 3, + MX8MQ_PAD_RESERVE4 = 4, + MX8MQ_IOMUXC_PMIC_STBY_REQ_CCMSRCGPCMIX = 5, + MX8MQ_IOMUXC_PMIC_ON_REQ_SNVSMIX = 6, + MX8MQ_IOMUXC_ONOFF_SNVSMIX = 7, + MX8MQ_IOMUXC_POR_B_SNVSMIX = 8, + MX8MQ_IOMUXC_RTC_RESET_B_SNVSMIX = 9, + MX8MQ_IOMUXC_GPIO1_IO00 = 10, + MX8MQ_IOMUXC_GPIO1_IO01 = 11, + MX8MQ_IOMUXC_GPIO1_IO02 = 12, + MX8MQ_IOMUXC_GPIO1_IO03 = 13, + MX8MQ_IOMUXC_GPIO1_IO04 = 14, + MX8MQ_IOMUXC_GPIO1_IO05 = 15, + MX8MQ_IOMUXC_GPIO1_IO06 = 16, + MX8MQ_IOMUXC_GPIO1_IO07 = 17, + MX8MQ_IOMUXC_GPIO1_IO08 = 18, + MX8MQ_IOMUXC_GPIO1_IO09 = 19, + MX8MQ_IOMUXC_GPIO1_IO10 = 20, + MX8MQ_IOMUXC_GPIO1_IO11 = 21, + MX8MQ_IOMUXC_GPIO1_IO12 = 22, + MX8MQ_IOMUXC_GPIO1_IO13 = 23, + MX8MQ_IOMUXC_GPIO1_IO14 = 24, + MX8MQ_IOMUXC_GPIO1_IO15 = 25, + MX8MQ_IOMUXC_ENET_MDC = 26, + MX8MQ_IOMUXC_ENET_MDIO = 27, + MX8MQ_IOMUXC_ENET_TD3 = 28, + MX8MQ_IOMUXC_ENET_TD2 = 29, + MX8MQ_IOMUXC_ENET_TD1 = 30, + MX8MQ_IOMUXC_ENET_TD0 = 31, + MX8MQ_IOMUXC_ENET_TX_CTL = 32, + MX8MQ_IOMUXC_ENET_TXC = 33, + MX8MQ_IOMUXC_ENET_RX_CTL = 34, + MX8MQ_IOMUXC_ENET_RXC = 35, + MX8MQ_IOMUXC_ENET_RD0 = 36, + MX8MQ_IOMUXC_ENET_RD1 = 37, + MX8MQ_IOMUXC_ENET_RD2 = 38, + MX8MQ_IOMUXC_ENET_RD3 = 39, + MX8MQ_IOMUXC_SD1_CLK = 40, + MX8MQ_IOMUXC_SD1_CMD = 41, + MX8MQ_IOMUXC_SD1_DATA0 = 42, + MX8MQ_IOMUXC_SD1_DATA1 = 43, + MX8MQ_IOMUXC_SD1_DATA2 = 44, + MX8MQ_IOMUXC_SD1_DATA3 = 45, + MX8MQ_IOMUXC_SD1_DATA4 = 46, + MX8MQ_IOMUXC_SD1_DATA5 = 47, + MX8MQ_IOMUXC_SD1_DATA6 = 48, + MX8MQ_IOMUXC_SD1_DATA7 = 49, + MX8MQ_IOMUXC_SD1_RESET_B = 50, + MX8MQ_IOMUXC_SD1_STROBE = 51, + MX8MQ_IOMUXC_SD2_CD_B = 52, + MX8MQ_IOMUXC_SD2_CLK = 53, + MX8MQ_IOMUXC_SD2_CMD = 54, + MX8MQ_IOMUXC_SD2_DATA0 = 55, + MX8MQ_IOMUXC_SD2_DATA1 = 56, + MX8MQ_IOMUXC_SD2_DATA2 = 57, + MX8MQ_IOMUXC_SD2_DATA3 = 58, + MX8MQ_IOMUXC_SD2_RESET_B = 59, + MX8MQ_IOMUXC_SD2_WP = 60, + MX8MQ_IOMUXC_NAND_ALE = 61, + MX8MQ_IOMUXC_NAND_CE0_B = 62, + MX8MQ_IOMUXC_NAND_CE1_B = 63, + MX8MQ_IOMUXC_NAND_CE2_B = 64, + MX8MQ_IOMUXC_NAND_CE3_B = 65, + MX8MQ_IOMUXC_NAND_CLE = 66, + MX8MQ_IOMUXC_NAND_DATA00 = 67, + MX8MQ_IOMUXC_NAND_DATA01 = 68, + MX8MQ_IOMUXC_NAND_DATA02 = 69, + MX8MQ_IOMUXC_NAND_DATA03 = 70, + MX8MQ_IOMUXC_NAND_DATA04 = 71, +
Re: [PATCH v6 3/5] clk: imx: add SCCG PLL type
On Fri, Aug 24, 2018 at 09:40:11AM +0200, Sascha Hauer wrote: > +Cc Andrey Smirnov who made me aware of this issue. > > On Wed, Aug 22, 2018 at 04:48:21PM +0300, Abel Vesa wrote: > > From: Lucas Stach > > > > The SCCG is a new PLL type introduced on i.MX8. Add support for this. > > The driver currently misses the PLL lock check, as the preliminary > > documentation mentions lock configurations, but is quiet about where > > to find the actual lock status signal. > > > > Signed-off-by: Lucas Stach > > Signed-off-by: Abel Vesa > > --- > > +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, > > + unsigned long parent_rate) > > +{ > > + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); > > + u32 val; > > + u32 divf; > > + > > + divf = rate / (parent_rate * 2); > > + > > + val = readl_relaxed(pll->base + PLL_CFG2); > > + val &= ~(PLL_DIVF_MASK << PLL_DIVF1_SHIFT); > > + val |= (divf - 1) << PLL_DIVF1_SHIFT; > > + writel_relaxed(val, pll->base + PLL_CFG2); > > + > > + /* FIXME: PLL lock check */ > > Shouldn't be too hard to add, no? Added to the next version which I intend to send today. > > > + > > + return 0; > > +} > > + > > +static int clk_pll1_prepare(struct clk_hw *hw) > > +{ > > + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); > > + u32 val; > > + > > + val = readl_relaxed(pll->base); > > + val &= ~(1 << PLL_PD); > > + writel_relaxed(val, pll->base); > > pll->base + PLL_CFG0 please. Same as above. > > > +static const struct clk_ops clk_sccg_pll1_ops = { > > + .is_prepared= clk_pll1_is_prepared, > > + .recalc_rate= clk_pll1_recalc_rate, > > + .round_rate = clk_pll1_round_rate, > > + .set_rate = clk_pll1_set_rate, > > +}; > > + > > +static const struct clk_ops clk_sccg_pll2_ops = { > > + .prepare= clk_pll1_prepare, > > + .unprepare = clk_pll1_unprepare, > > + .recalc_rate= clk_pll2_recalc_rate, > > + .round_rate = clk_pll2_round_rate, > > + .set_rate = clk_pll2_set_rate, > > +}; > > So these are two PLLs that share the same enable register. Doing the > prepare/unprepare for only one PLL can lead to all kinds of trouble. > Finding a good abstraction the properly handles this case with the > clock framework is probably also not easy. > > I could imagine we'll need to track the enable state on both PLLs and > only if both are disabled we disable it in hardware. > > With the current code we disable the PLLs when all consumers are > reparented to pll1, which probably has bad effects. > So it took me a while to understand exactly why this needs to stay like it is. The PLL1 is never used by any device, instead it is used as a source for PLL2. But because the interlink between the two of them is too complicated, the PLLs 1 and 2 need to be separate clocks. As for the disabling, it's safe to disable just the second one because, as mentioned above, the first PLL is never used alone by a device. If there isn't anything else here to discuss, I would like to send the next version of this patchset with all the other comments taken care of. Abel > Sascha > > -- > Pengutronix e.K. | | > Industrial Linux Solutions | > https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.pengutronix.de%2F&data=02%7C01%7Cabel.vesa%40nxp.com%7C5e9c7c6f9e464ed522f108d60994d471%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C636706932168087639&sdata=XbfFq5z%2FRtkq6yGgwSyk6dNCZVuXOzY%2Fiygmwle3C2I%3D&reserved=0 > | > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0| > Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917- | --
[PATCH v3 0/4] Add i.MX8MQ clock driver
This is basically just a resend of the following patchset: https://www.spinics.net/lists/linux-clk/msg23141.html I've just updated the patchset and implemented Shawn's and Aisheng's comments. I hope I haven't missed any of their comments. Lucas Stach (4): dt-bindings: add binding for i.MX8MQ CCM clk: imx: add fractional PLL output clock clk: imx: add SCCG PLL type clk: imx: add clock driver for i.MX8MQ CCM .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + drivers/clk/imx/Makefile | 5 +- drivers/clk/imx/clk-frac-pll.c | 230 ++ drivers/clk/imx/clk-imx8mq.c | 856 + drivers/clk/imx/clk-sccg-pll.c | 231 ++ drivers/clk/imx/clk.h | 48 ++ include/dt-bindings/clock/imx8mq-clock.h | 629 +++ 7 files changed, 2018 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 drivers/clk/imx/clk-frac-pll.c create mode 100644 drivers/clk/imx/clk-imx8mq.c create mode 100644 drivers/clk/imx/clk-sccg-pll.c create mode 100644 include/dt-bindings/clock/imx8mq-clock.h -- 2.7.4
[PATCH v3 2/4] clk: imx: add fractional PLL output clock
From: Lucas Stach This is a new clock type introduced on i.MX8. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-frac-pll.c | 230 + drivers/clk/imx/clk.h | 3 + 3 files changed, 234 insertions(+) create mode 100644 drivers/clk/imx/clk-frac-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..4893c1f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -6,6 +6,7 @@ obj-y += \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ + clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pllv1.o \ diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 000..c80c6ed --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUSBIT(31) +#define PLL_PD 19 +#define PLL_PD_MASKBIT(PLL_PD) +#define PLL_BYPASS 14 +#define PLL_BYPASS_MASKBIT(PLL_BYPASS) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK 0xff +#define PLL_INT_DIV_MASK 0x7f +#define PLL_OUTPUT_DIV_MASK0x1f +#define PLL_FRAC_DENOM 0x100 + +struct clk_frac_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 val; + + /* Wait for PLL to lock */ + do { + if (readl_relaxed(pll->base) & PLL_LOCK_STATUS) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_LOCK_STATUS, 0, 1000); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(50); + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + do { + if (readl_relaxed(pll->base) & PLL_NEWDIV_ACK) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_NEWDIV_ACK, 0, 1000); +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val, divff, divfi, divq; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = ((val & PLL_OUTPUT_DIV_MASK) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = (val >> 7) & PLL_FRAC_DIV_MASK; + divfi = (val & PLL_INT_DIV_MASK); + + temp64 = (u64)parent_rate * 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + temp64 /= divq; + + return parent_rate * 8 * (divfi + 1) / divq + (unsigned long)temp64; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 divff, divfi; + u64 temp64; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = (u64)(rate - divfi * parent_rate); + temp64 *= PLL_FRAC_DENOM; + do_div(
[PATCH v3 1/4] dt-bindings: add binding for i.MX8MQ CCM
From: Lucas Stach This adds the binding for the i.MX8MQ Clock Controller Module. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + include/dt-bindings/clock/imx8mq-clock.h | 629 + 2 files changed, 649 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 include/dt-bindings/clock/imx8mq-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt new file mode 100644 index 000..52de826 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt @@ -0,0 +1,20 @@ +* Clock bindings for NXP i.MX8M Quad + +Required properties: +- compatible: Should be "fsl,imx8mq-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include the following entries: +- "ckil" +- "osc_25m" +- "osc_27m" +- "clk_ext1" +- "clk_ext2" +- "clk_ext3" +- "clk_ext4" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h +for the full list of i.MX8M Quad clock IDs. diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h new file mode 100644 index 000..7f88062 --- /dev/null +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -0,0 +1,629 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MQ_H +#define __DT_BINDINGS_CLOCK_IMX8MQ_H + +#define IMX8MQ_CLK_DUMMY 0 +#define IMX8MQ_CLK_32K 1 +#define IMX8MQ_CLK_25M 2 +#define IMX8MQ_CLK_27M 3 +#define IMX8MQ_CLK_EXT14 +#define IMX8MQ_CLK_EXT25 +#define IMX8MQ_CLK_EXT36 +#define IMX8MQ_CLK_EXT47 + +/* ANAMIX PLL clocks */ +/* FRAC PLLs */ +/* ARM PLL */ +#define IMX8MQ_ARM_PLL_REF_SEL 8 +#define IMX8MQ_ARM_PLL_REF_DIV 9 +#define IMX8MQ_ARM_PLL 10 +#define IMX8MQ_ARM_PLL_BYPASS 11 +#define IMX8MQ_ARM_PLL_OUT 12 + +/* GPU PLL */ +#define IMX8MQ_GPU_PLL_REF_SEL 13 +#define IMX8MQ_GPU_PLL_REF_DIV 14 +#define IMX8MQ_GPU_PLL 15 +#define IMX8MQ_GPU_PLL_BYPASS 16 +#define IMX8MQ_GPU_PLL_OUT 17 + +/* VPU PLL */ +#define IMX8MQ_VPU_PLL_REF_SEL 18 +#define IMX8MQ_VPU_PLL_REF_DIV 19 +#define IMX8MQ_VPU_PLL 20 +#define IMX8MQ_VPU_PLL_BYPASS 21 +#define IMX8MQ_VPU_PLL_OUT 22 + +/* AUDIO PLL1 */ +#define IMX8MQ_AUDIO_PLL1_REF_SEL 23 +#define IMX8MQ_AUDIO_PLL1_REF_DIV 24 +#define IMX8MQ_AUDIO_PLL1 25 +#define IMX8MQ_AUDIO_PLL1_BYPASS 26 +#define IMX8MQ_AUDIO_PLL1_OUT 27 + +/* AUDIO PLL2 */ +#define IMX8MQ_AUDIO_PLL2_REF_SEL 28 +#define IMX8MQ_AUDIO_PLL2_REF_DIV 29 +#define IMX8MQ_AUDIO_PLL2 30 +#define IMX8MQ_AUDIO_PLL2_BYPASS 31 +#define IMX8MQ_AUDIO_PLL2_OUT 32 + +/* VIDEO PLL1 */ +#define IMX8MQ_VIDEO_PLL1_REF_SEL 33 +#define IMX8MQ_VIDEO_PLL1_REF_DIV 34 +#define IMX8MQ_VIDEO_PLL1 35 +#define IMX8MQ_VIDEO_PLL1_BYPASS 36 +#define IMX8MQ_VIDEO_PLL1_OUT 37 + +/* SYS1 PLL */ +#define IMX8MQ_SYS1_PLL1_REF_SEL 38 +#define IMX8MQ_SYS1_PLL1_REF_DIV 39 +#define IMX8MQ_SYS1_PLL1 40 +#define IMX8MQ_SYS1_PLL1_OUT 41 +#define IMX8MQ_SYS1_PLL1_OUT_DIV 42 +#define IMX8MQ_SYS1_PLL2 43 +#define IMX8MQ_SYS1_PLL2_DIV 44 +#define IMX8MQ_SYS1_PLL2_OUT 45 + +/* SYS2 PLL */ +#define IMX8MQ_SYS2_PLL1_REF_SEL 46 +#define IMX8MQ_SYS2_PLL1_REF_DIV 47 +#define IMX8MQ_SYS2_PLL1 48 +#define IMX8MQ_SYS2_PLL1_OUT 49 +#define IMX8MQ_SYS2_PLL1_OUT_DIV 50 +#define IMX8MQ_SYS2_PLL2 51 +#define IMX8MQ_SYS2_PLL2_DIV 52 +#define IMX8MQ_SYS2_PLL2_OUT 53 + +/* SYS3 PLL */ +#define IMX8MQ_SYS3_PLL1_REF_SEL 54 +#define IMX8MQ_SYS3_PLL1_REF_DIV 55 +#define IMX8MQ_SYS3_PLL1 56 +#define IMX8MQ_SYS3_PLL1_OUT 57 +#define IMX8MQ_SYS3_PLL1_OUT_DIV 58 +#define IMX8MQ_SYS3_PLL2 59 +#define IMX8MQ_SYS3_PLL2_DIV 60 +#define IMX8MQ_SYS3_PLL2_OUT 61 + +/* DRAM PLL */ +#define IMX8MQ_DRAM_PLL1_REF_SEL 62 +#define IMX8MQ_DRAM_PLL1_REF_DIV 63 +#define IMX8MQ_DRAM_PLL1 64 +#define IMX8MQ_DRAM_PLL1_OUT 6
[PATCH v3 3/4] clk: imx: add SCCG PLL type
From: Lucas Stach The SCCG is a new PLL type introduced on i.MX8. Add support for this. The driver currently misses the PLL lock check, as the preliminary documentation mentions lock configurations, but is quiet about where to find the actual lock status signal. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-sccg-pll.c | 231 + drivers/clk/imx/clk.h | 9 ++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-sccg-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4893c1f..b87513c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pfd.o + clk-pfd.o \ + clk-sccg-pll.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c new file mode 100644 index 000..886ae03 --- /dev/null +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include + +#include "clk.h" + +/* PLL CFGs */ +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 +#define PLL_CFG2 0x8 + +#define PLL_DIVF1_SHIFT13 +#define PLL_DIVF2_SHIFT7 +#define PLL_DIVF_MASK 0x3f + +#define PLL_DIVR1_SHIFT25 +#define PLL_DIVR2_SHIFT19 +#define PLL_DIVR1_MASK 0x3 +#define PLL_DIVR2_MASK 0x3f +#define PLL_REF_SHIFT 0 +#define PLL_REF_MASK 0x3 + +#define PLL_LOCK 31 +#define PLL_PD 7 + +#define OSC_25M2500 +#define OSC_27M2700 + +struct clk_sccg_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) + +static int clk_pll1_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & (1 << PLL_PD)) ? 0 : 1; +} + +static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, divf; + + val = readl_relaxed(pll->base + PLL_CFG2); + divf = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + + return parent_rate * 2 * (divf + 1); +} + +static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 div; + + div = rate / (parent_rate * 2); + + return parent_rate * div * 2; +} + +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + u32 divf; + + divf = rate / (parent_rate * 2); + + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~(PLL_DIVF_MASK << PLL_DIVF1_SHIFT); + val |= (divf - 1) << PLL_DIVF1_SHIFT; + writel_relaxed(val, pll->base + PLL_CFG2); + + /* FIXME: PLL lock check */ + + return 0; +} + +static int clk_pll1_prepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~(1 << PLL_PD); + writel_relaxed(val, pll->base); + + /* FIXME: PLL lock check */ + + return 0; +} + +static void clk_pll1_unprepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= (1 << PLL_PD); + writel_relaxed(val, pll->base); +} + +static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, ref, divr1, divf1, divr2, divf2; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + switch ((val >> PLL_REF_SHIFT) & PLL_REF_MASK) { + case 0: + ref = OSC_25M; + break; + case 1: + ref = OSC_27M; + break; + default: + ref = OSC_25M; + break; + } + + val = readl_relaxed(pll->base + PLL_CFG2); + divr1 = (val >> PLL_DIVR1_SHIFT) & PLL_DIVR1_MASK; + divr2 = (val >> PLL_DIVR2_SHIFT) & PLL_DIVR2_MASK; + divf1 = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + divf2 = (val >> PLL_DIVF2_SHIFT) & PLL_DIVF_MASK; + + temp6
[PATCH v3 4/4] clk: imx: add clock driver for i.MX8MQ CCM
From: Lucas Stach Add driver for the Clock Control Module found on i.MX8MQ. This is largely based on the downstream driver from Anson Huang and Bai Ping at NXP, with only some small adaptions to mainline from me. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mq.c | 856 +++ drivers/clk/imx/clk.h| 36 ++ 3 files changed, 893 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mq.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b87513c..e2c5de9 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o +obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 000..6b9cba1 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,856 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + * Copyright (C) 2017 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai4; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_dcss; +static u32 share_count_nand; + +static struct clk *clks[IMX8MQ_CLK_END]; + +static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; +static const char *video2_pll1_out_sels[] = {"video2_pll1", "video2_pll1_ref_sel", }; + +static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; +static const char *video2_pll2_out_sels[] = {"video2_pll2_div", "video2_pll1_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", }; + +static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", + "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",}; + +static const ch
Re: [RESEND v5 4/5] clk: imx: add imx composite clock
On Tue, Aug 21, 2018 at 08:58:30AM +0200, Sascha Hauer wrote: > On Mon, Aug 20, 2018 at 10:16:06AM +0300, Abel Vesa wrote: > > + > > + val |= (u32)value << divider->shift; > > + val |= (u32)value << PCG_DIV_SHIFT; > > + clk_writel(val, divider->reg); > > + > > + spin_unlock_irqrestore(divider->lock, flags); > > + > > + return 0; > > +} > > Have you tested this works? I thought those are two cascaded dividers > and you program both to the same value. Normally you would have to > calculate individual values for each divider which together give you the > desired output rate. > My bad. Haven't properly tested it since there is no actual driver that calls set_rate on any of those clocks at this point. Sorry about that. I'll send another version today, where I've implemented it as I should've done from the start and I've tested it by explicitly calling the set_rate and read the value with clk_get_rate to make sure it's fine. > Sascha > > -- > Pengutronix e.K. | | > Industrial Linux Solutions | > https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.pengutronix.de%2F&data=02%7C01%7Cabel.vesa%40nxp.com%7C722eb3cdb15849a9d19608d6073382e4%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C636704315167487036&sdata=Q29pmTcLbqNPjotCFjZ%2BldD%2FBlbYpm6fN%2BzguHixwfA%3D&reserved=0 > | > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0| > Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917- | --
[PATCH v6 0/5] Add i.MX8MQ clock driver
Fifth version can be found here: https://lkml.org/lkml/2018/8/20/83 Changes since v5: * Fixed the predivider and divider register values as reported by Sascha. * Changed the commit message of the 4th patch to match with what the commit is adding Changes since v4: * Implemented divider ops and used clk-composite as suggested by Sascha Hauer. Changes since v3: * Added a composite clock type to get rid of some complexity from clk-imx8mq. This new composite clock type will also be used by all the imx8 socs that will follow. * Added back the reviewed-by tag. Abel Vesa (1): clk: imx: add imx composite clock Lucas Stach (4): dt-bindings: add binding for i.MX8MQ CCM clk: imx: add fractional PLL output clock clk: imx: add SCCG PLL type clk: imx: add clock driver for i.MX8MQ CCM .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-composite.c| 157 + drivers/clk/imx/clk-frac-pll.c | 230 drivers/clk/imx/clk-imx8mq.c | 631 + drivers/clk/imx/clk-sccg-pll.c | 231 drivers/clk/imx/clk.h | 57 ++ include/dt-bindings/clock/imx8mq-clock.h | 410 + 8 files changed, 1741 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 drivers/clk/imx/clk-composite.c create mode 100644 drivers/clk/imx/clk-frac-pll.c create mode 100644 drivers/clk/imx/clk-imx8mq.c create mode 100644 drivers/clk/imx/clk-sccg-pll.c create mode 100644 include/dt-bindings/clock/imx8mq-clock.h -- 2.7.4
[PATCH v6 1/5] dt-bindings: add binding for i.MX8MQ CCM
From: Lucas Stach This adds the binding for the i.MX8MQ Clock Controller Module. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Rob Herring --- .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + include/dt-bindings/clock/imx8mq-clock.h | 410 + 2 files changed, 430 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 include/dt-bindings/clock/imx8mq-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt new file mode 100644 index 000..52de826 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt @@ -0,0 +1,20 @@ +* Clock bindings for NXP i.MX8M Quad + +Required properties: +- compatible: Should be "fsl,imx8mq-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include the following entries: +- "ckil" +- "osc_25m" +- "osc_27m" +- "clk_ext1" +- "clk_ext2" +- "clk_ext3" +- "clk_ext4" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h +for the full list of i.MX8M Quad clock IDs. diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h new file mode 100644 index 000..0d19bd9 --- /dev/null +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -0,0 +1,410 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MQ_H +#define __DT_BINDINGS_CLOCK_IMX8MQ_H + +#define IMX8MQ_CLK_DUMMY 0 +#define IMX8MQ_CLK_32K 1 +#define IMX8MQ_CLK_25M 2 +#define IMX8MQ_CLK_27M 3 +#define IMX8MQ_CLK_EXT14 +#define IMX8MQ_CLK_EXT25 +#define IMX8MQ_CLK_EXT36 +#define IMX8MQ_CLK_EXT47 + +/* ANAMIX PLL clocks */ +/* FRAC PLLs */ +/* ARM PLL */ +#define IMX8MQ_ARM_PLL_REF_SEL 8 +#define IMX8MQ_ARM_PLL_REF_DIV 9 +#define IMX8MQ_ARM_PLL 10 +#define IMX8MQ_ARM_PLL_BYPASS 11 +#define IMX8MQ_ARM_PLL_OUT 12 + +/* GPU PLL */ +#define IMX8MQ_GPU_PLL_REF_SEL 13 +#define IMX8MQ_GPU_PLL_REF_DIV 14 +#define IMX8MQ_GPU_PLL 15 +#define IMX8MQ_GPU_PLL_BYPASS 16 +#define IMX8MQ_GPU_PLL_OUT 17 + +/* VPU PLL */ +#define IMX8MQ_VPU_PLL_REF_SEL 18 +#define IMX8MQ_VPU_PLL_REF_DIV 19 +#define IMX8MQ_VPU_PLL 20 +#define IMX8MQ_VPU_PLL_BYPASS 21 +#define IMX8MQ_VPU_PLL_OUT 22 + +/* AUDIO PLL1 */ +#define IMX8MQ_AUDIO_PLL1_REF_SEL 23 +#define IMX8MQ_AUDIO_PLL1_REF_DIV 24 +#define IMX8MQ_AUDIO_PLL1 25 +#define IMX8MQ_AUDIO_PLL1_BYPASS 26 +#define IMX8MQ_AUDIO_PLL1_OUT 27 + +/* AUDIO PLL2 */ +#define IMX8MQ_AUDIO_PLL2_REF_SEL 28 +#define IMX8MQ_AUDIO_PLL2_REF_DIV 29 +#define IMX8MQ_AUDIO_PLL2 30 +#define IMX8MQ_AUDIO_PLL2_BYPASS 31 +#define IMX8MQ_AUDIO_PLL2_OUT 32 + +/* VIDEO PLL1 */ +#define IMX8MQ_VIDEO_PLL1_REF_SEL 33 +#define IMX8MQ_VIDEO_PLL1_REF_DIV 34 +#define IMX8MQ_VIDEO_PLL1 35 +#define IMX8MQ_VIDEO_PLL1_BYPASS 36 +#define IMX8MQ_VIDEO_PLL1_OUT 37 + +/* SYS1 PLL */ +#define IMX8MQ_SYS1_PLL1_REF_SEL 38 +#define IMX8MQ_SYS1_PLL1_REF_DIV 39 +#define IMX8MQ_SYS1_PLL1 40 +#define IMX8MQ_SYS1_PLL1_OUT 41 +#define IMX8MQ_SYS1_PLL1_OUT_DIV 42 +#define IMX8MQ_SYS1_PLL2 43 +#define IMX8MQ_SYS1_PLL2_DIV 44 +#define IMX8MQ_SYS1_PLL2_OUT 45 + +/* SYS2 PLL */ +#define IMX8MQ_SYS2_PLL1_REF_SEL 46 +#define IMX8MQ_SYS2_PLL1_REF_DIV 47 +#define IMX8MQ_SYS2_PLL1 48 +#define IMX8MQ_SYS2_PLL1_OUT 49 +#define IMX8MQ_SYS2_PLL1_OUT_DIV 50 +#define IMX8MQ_SYS2_PLL2 51 +#define IMX8MQ_SYS2_PLL2_DIV 52 +#define IMX8MQ_SYS2_PLL2_OUT 53 + +/* SYS3 PLL */ +#define IMX8MQ_SYS3_PLL1_REF_SEL 54 +#define IMX8MQ_SYS3_PLL1_REF_DIV 55 +#define IMX8MQ_SYS3_PLL1 56 +#define IMX8MQ_SYS3_PLL1_OUT 57 +#define IMX8MQ_SYS3_PLL1_OUT_DIV 58 +#define IMX8MQ_SYS3_PLL2 59 +#define IMX8MQ_SYS3_PLL2_DIV 60 +#define IMX8MQ_SYS3_PLL2_OUT 61 + +/* DRAM PLL */ +#define IMX8MQ_DRAM_PLL1_REF_SEL 62 +#define IMX8MQ_DRAM_PLL1_REF_DIV 63 +#define IMX8MQ_DRAM_PLL1 64 +#define IMX8MQ
[PATCH v6 2/5] clk: imx: add fractional PLL output clock
From: Lucas Stach This is a new clock type introduced on i.MX8. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-frac-pll.c | 230 + drivers/clk/imx/clk.h | 3 + 3 files changed, 234 insertions(+) create mode 100644 drivers/clk/imx/clk-frac-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..4893c1f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -6,6 +6,7 @@ obj-y += \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ + clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pllv1.o \ diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 000..c80c6ed --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUSBIT(31) +#define PLL_PD 19 +#define PLL_PD_MASKBIT(PLL_PD) +#define PLL_BYPASS 14 +#define PLL_BYPASS_MASKBIT(PLL_BYPASS) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK 0xff +#define PLL_INT_DIV_MASK 0x7f +#define PLL_OUTPUT_DIV_MASK0x1f +#define PLL_FRAC_DENOM 0x100 + +struct clk_frac_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 val; + + /* Wait for PLL to lock */ + do { + if (readl_relaxed(pll->base) & PLL_LOCK_STATUS) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_LOCK_STATUS, 0, 1000); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(50); + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + do { + if (readl_relaxed(pll->base) & PLL_NEWDIV_ACK) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_NEWDIV_ACK, 0, 1000); +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val, divff, divfi, divq; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = ((val & PLL_OUTPUT_DIV_MASK) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = (val >> 7) & PLL_FRAC_DIV_MASK; + divfi = (val & PLL_INT_DIV_MASK); + + temp64 = (u64)parent_rate * 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + temp64 /= divq; + + return parent_rate * 8 * (divfi + 1) / divq + (unsigned long)temp64; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 divff, divfi; + u64 temp64; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = (u64)(rate - divfi * parent_rate); + temp64 *= PLL_FRAC_DENOM; + do_div(
[PATCH v6 3/5] clk: imx: add SCCG PLL type
From: Lucas Stach The SCCG is a new PLL type introduced on i.MX8. Add support for this. The driver currently misses the PLL lock check, as the preliminary documentation mentions lock configurations, but is quiet about where to find the actual lock status signal. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-sccg-pll.c | 231 + drivers/clk/imx/clk.h | 9 ++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-sccg-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4893c1f..b87513c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pfd.o + clk-pfd.o \ + clk-sccg-pll.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c new file mode 100644 index 000..886ae03 --- /dev/null +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include + +#include "clk.h" + +/* PLL CFGs */ +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 +#define PLL_CFG2 0x8 + +#define PLL_DIVF1_SHIFT13 +#define PLL_DIVF2_SHIFT7 +#define PLL_DIVF_MASK 0x3f + +#define PLL_DIVR1_SHIFT25 +#define PLL_DIVR2_SHIFT19 +#define PLL_DIVR1_MASK 0x3 +#define PLL_DIVR2_MASK 0x3f +#define PLL_REF_SHIFT 0 +#define PLL_REF_MASK 0x3 + +#define PLL_LOCK 31 +#define PLL_PD 7 + +#define OSC_25M2500 +#define OSC_27M2700 + +struct clk_sccg_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) + +static int clk_pll1_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & (1 << PLL_PD)) ? 0 : 1; +} + +static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, divf; + + val = readl_relaxed(pll->base + PLL_CFG2); + divf = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + + return parent_rate * 2 * (divf + 1); +} + +static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 div; + + div = rate / (parent_rate * 2); + + return parent_rate * div * 2; +} + +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + u32 divf; + + divf = rate / (parent_rate * 2); + + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~(PLL_DIVF_MASK << PLL_DIVF1_SHIFT); + val |= (divf - 1) << PLL_DIVF1_SHIFT; + writel_relaxed(val, pll->base + PLL_CFG2); + + /* FIXME: PLL lock check */ + + return 0; +} + +static int clk_pll1_prepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~(1 << PLL_PD); + writel_relaxed(val, pll->base); + + /* FIXME: PLL lock check */ + + return 0; +} + +static void clk_pll1_unprepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= (1 << PLL_PD); + writel_relaxed(val, pll->base); +} + +static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, ref, divr1, divf1, divr2, divf2; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + switch ((val >> PLL_REF_SHIFT) & PLL_REF_MASK) { + case 0: + ref = OSC_25M; + break; + case 1: + ref = OSC_27M; + break; + default: + ref = OSC_25M; + break; + } + + val = readl_relaxed(pll->base + PLL_CFG2); + divr1 = (val >> PLL_DIVR1_SHIFT) & PLL_DIVR1_MASK; + divr2 = (val >> PLL_DIVR2_SHIFT) & PLL_DIVR2_MASK; + divf1 = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + divf2 = (val >> PLL_DIVF2_SHIFT) & PLL_DIVF_MASK; + + temp6
[PATCH v6 5/5] clk: imx: add clock driver for i.MX8MQ CCM
From: Lucas Stach Add driver for the Clock Control Module found on i.MX8MQ. This is largely based on the downstream driver from Anson Huang and Bai Ping at NXP, with only some small adaptions to mainline from me. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mq.c | 631 +++ drivers/clk/imx/clk.h| 36 +++ 3 files changed, 668 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mq.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4fabb0a..64e695c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o +obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 000..d3a9e31 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,631 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * Copyright (C) 2017 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai4; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_dcss; +static u32 share_count_nand; + +static struct clk *clks[IMX8MQ_CLK_END]; + +static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; +static const char *video2_pll1_out_sels[] = {"video2_pll1", "video2_pll1_ref_sel", }; + +static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; +static const char *video2_pll2_out_sels[] = {"video2_pll2_div", "video2_pll1_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", }; + +static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", + "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",}; + +static const ch
[PATCH v6 4/5] clk: imx: add imx composite clock
Since a lot of clocks on imx8 are formed by a mux, gate, predivider and divider, the idea here is to combine all of those into one composite clock, but we need to deal with both predivider and divider at the same time and therefore we add the imx_clk_composite_divider_ops and register the composite clock with those. Signed-off-by: Abel Vesa Suggested-by: Sascha Hauer --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-composite.c | 157 drivers/clk/imx/clk.h | 9 +++ 3 files changed, 167 insertions(+) create mode 100644 drivers/clk/imx/clk-composite.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b87513c..4fabb0a 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -3,6 +3,7 @@ obj-y += \ clk.o \ clk-busy.o \ + clk-composite.o \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite.c b/drivers/clk/imx/clk-composite.c new file mode 100644 index 000..a5c0080 --- /dev/null +++ b/drivers/clk/imx/clk-composite.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +#include +#include +#include +#include + +#include "clk.h" + +#define PCG_PREDIV_SHIFT 16 +#define PCG_PREDIV_WIDTH 3 + +#define PCG_DIV_SHIFT 0 +#define PCG_DIV_WIDTH 6 + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 + +#define PCG_CGC_SHIFT 28 + +static unsigned long imx_clk_composite_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long prediv_rate; + unsigned int prediv_value; + unsigned int div_value; + + prediv_value = clk_readl(divider->reg) >> divider->shift; + prediv_value &= clk_div_mask(divider->width); + + prediv_rate = divider_recalc_rate(hw, parent_rate, prediv_value, + divider->table, divider->flags, + divider->width); + + div_value = clk_readl(divider->reg) >> PCG_DIV_SHIFT; + div_value &= clk_div_mask(PCG_DIV_WIDTH); + + return divider_recalc_rate(hw, prediv_rate, div_value, divider->table, + divider->flags, PCG_DIV_WIDTH); +} + +static long imx_clk_composite_divider_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long prediv_rate; + + prediv_rate = divider_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags); + return divider_round_rate(hw, rate, &prediv_rate, divider->table, + PCG_DIV_WIDTH, divider->flags); +} + +static int imx_clk_composite_divider_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long prediv_rate; + unsigned long flags = 0; + int prediv_value; + int div_value; + u32 val; + + prediv_value = divider_get_val(rate, parent_rate, NULL, + PCG_PREDIV_WIDTH, CLK_DIVIDER_ROUND_CLOSEST); + if (prediv_value < 0) + return prediv_value; + + prediv_rate = DIV_ROUND_UP_ULL((u64)parent_rate, prediv_value + 1); + + div_value = divider_get_val(rate, prediv_rate, NULL, + PCG_DIV_WIDTH, CLK_DIVIDER_ROUND_CLOSEST); + if (div_value < 0) + return div_value; + + spin_lock_irqsave(divider->lock, flags); + + val = clk_readl(divider->reg); + val &= ~((clk_div_mask(divider->width) << divider->shift) | + (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + + val |= (u32)prediv_value << divider->shift; + val |= (u32)div_value << PCG_DIV_SHIFT; + clk_writel(val, divider->reg); + + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} + +static const struct clk_ops imx_clk_composite_divider_ops = { + .recalc_rate = imx_clk_composite_divider_recalc_rate, + .round_rate = imx_clk_composite_divider_round_rate, + .set_rate = imx_clk_composite_divider_set_rate, +}; + +struct clk *imx_clk_composite_flags(const char *name, + const char **parent_names, + int num_parents, void __iomem *reg, + un
Re: [PATCH] arm: ftrace: Adds support for CONFIG_DYNAMIC_FTRACE_WITH_REGS
On Fri, May 12, 2017 at 09:38:37PM +0100, abelv...@gmail.com wrote: > From: Abel Vesa To be ignored, wrong git config. Will send another one without the From line. > > The DYNAMIC_FTRACE_WITH_REGS configuration makes it possible for a ftrace > operation to specify if registers need to saved/restored by the ftrace > handler. > This is needed by kgraft and possibly other ftrace-based tools, and the ARM > architecture is currently lacking this feature. It would also be the first > step > to support the "Kprobes-on-ftrace" optimization on ARM. > > This patch introduces a new ftrace handler that stores the registers on the > stack before calling the next stage. The registers are restored from the stack > before going back to the instrumented function. > > A side-effect of this patch is to activate the support for > ftrace_modify_call() > as it defines ARCH_SUPPORTS_FTRACE_OPS for the ARM architecture. > > Signed-off-by: Abel Vesa > --- > arch/arm/Kconfig | 1 + > arch/arm/include/asm/ftrace.h | 4 ++ > arch/arm/kernel/entry-ftrace.S | 100 > + > arch/arm/kernel/ftrace.c | 37 +++ > 4 files changed, 142 insertions(+) > > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig > index 4c1a35f..730d456 100644 > --- a/arch/arm/Kconfig > +++ b/arch/arm/Kconfig > @@ -56,6 +56,7 @@ config ARM > select HAVE_DMA_API_DEBUG > select HAVE_DMA_CONTIGUOUS if MMU > select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 && MMU > + select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE > select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) > && MMU > select HAVE_EXIT_THREAD > select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) > diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h > index 22b7311..f379881 100644 > --- a/arch/arm/include/asm/ftrace.h > +++ b/arch/arm/include/asm/ftrace.h > @@ -1,6 +1,10 @@ > #ifndef _ASM_ARM_FTRACE > #define _ASM_ARM_FTRACE > > +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS > +#define ARCH_SUPPORTS_FTRACE_OPS 1 > +#endif > + > #ifdef CONFIG_FUNCTION_TRACER > #define MCOUNT_ADDR ((unsigned long)(__gnu_mcount_nc)) > #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ > diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S > index c73c403..efcd9f2 100644 > --- a/arch/arm/kernel/entry-ftrace.S > +++ b/arch/arm/kernel/entry-ftrace.S > @@ -92,12 +92,95 @@ > 2: mcount_exit > .endm > > +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS > + > +.macro __ftrace_regs_caller > + > + sub sp, sp, #8 @ space for PC and CPSR OLD_R0, > + @ OLD_R0 will overwrite previous LR > + > + add ip, sp, #12 @ move in IP the value of SP as it was > + @ before the push {lr} of the mcount mechanism > + > + str lr, [sp, #0]@ store LR instead of PC > + > + ldr lr, [sp, #8]@ get previous LR > + > + str r0, [sp, #8]@ write r0 as OLD_R0 over previous LR > + > + stmdb sp!, {ip, lr} > + stmdb sp!, {r0-r11, lr} > + > + @ stack content at this point: > + @ 0 4 48 52 5660 6468 72 > + @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | > + > + mov r3, sp @ struct pt_regs* > + > + ldr r2, =function_trace_op > + ldr r2, [r2]@ pointer to the current > + @ function tracing op > + > + ldr r1, [sp, #S_LR] @ lr of instrumented func > + > + ldr lr, [sp, #S_PC] @ get LR > + > + mcount_adjust_addr r0, lr @ instrumented function > + > + .globl ftrace_regs_call > +ftrace_regs_call: > + bl ftrace_stub > + > +#ifdef CONFIG_FUNCTION_GRAPH_TRACER > + .globl ftrace_graph_regs_call > +ftrace_graph_regs_call: > + mov r0, r0 > +#endif > + > + @ pop saved regs > + ldmia sp!, {r0-r12} @ restore r0 through r12 > + ldr ip, [sp, #8]@ restore PC > + ldr lr, [sp, #4]@ restore LR > + ldr sp, [sp, #0]@ restore SP > + mov pc, ip @ return > +.endm > + > +#ifdef CONFIG_FUNCTION_GRAPH_TRACER > +.macro __ftrace_graph_regs_caller > + > + sub r0, fp, #4 @ lr of instrumented routine (parent) > + > +
[PATCH] arm: ftrace: Adds support for CONFIG_DYNAMIC_FTRACE_WITH_REGS
The DYNAMIC_FTRACE_WITH_REGS configuration makes it possible for a ftrace operation to specify if registers need to saved/restored by the ftrace handler. This is needed by kgraft and possibly other ftrace-based tools, and the ARM architecture is currently lacking this feature. It would also be the first step to support the "Kprobes-on-ftrace" optimization on ARM. This patch introduces a new ftrace handler that stores the registers on the stack before calling the next stage. The registers are restored from the stack before going back to the instrumented function. A side-effect of this patch is to activate the support for ftrace_modify_call() as it defines ARCH_SUPPORTS_FTRACE_OPS for the ARM architecture. Signed-off-by: Abel Vesa --- arch/arm/Kconfig | 1 + arch/arm/include/asm/ftrace.h | 4 ++ arch/arm/kernel/entry-ftrace.S | 100 + arch/arm/kernel/ftrace.c | 37 +++ 4 files changed, 142 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4c1a35f..730d456 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -56,6 +56,7 @@ config ARM select HAVE_DMA_API_DEBUG select HAVE_DMA_CONTIGUOUS if MMU select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 && MMU + select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU select HAVE_EXIT_THREAD select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) diff --git a/arch/arm/include/asm/ftrace.h b/arch/arm/include/asm/ftrace.h index 22b7311..f379881 100644 --- a/arch/arm/include/asm/ftrace.h +++ b/arch/arm/include/asm/ftrace.h @@ -1,6 +1,10 @@ #ifndef _ASM_ARM_FTRACE #define _ASM_ARM_FTRACE +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS +#define ARCH_SUPPORTS_FTRACE_OPS 1 +#endif + #ifdef CONFIG_FUNCTION_TRACER #define MCOUNT_ADDR((unsigned long)(__gnu_mcount_nc)) #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ diff --git a/arch/arm/kernel/entry-ftrace.S b/arch/arm/kernel/entry-ftrace.S index c73c403..efcd9f2 100644 --- a/arch/arm/kernel/entry-ftrace.S +++ b/arch/arm/kernel/entry-ftrace.S @@ -92,12 +92,95 @@ 2: mcount_exit .endm +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS + +.macro __ftrace_regs_caller + + sub sp, sp, #8 @ space for PC and CPSR OLD_R0, + @ OLD_R0 will overwrite previous LR + + add ip, sp, #12 @ move in IP the value of SP as it was + @ before the push {lr} of the mcount mechanism + + str lr, [sp, #0]@ store LR instead of PC + + ldr lr, [sp, #8]@ get previous LR + + str r0, [sp, #8]@ write r0 as OLD_R0 over previous LR + + stmdb sp!, {ip, lr} + stmdb sp!, {r0-r11, lr} + + @ stack content at this point: + @ 0 4 48 52 5660 6468 72 + @ R0 | R1 | ... | LR | SP + 4 | previous LR | LR | PSR | OLD_R0 | + + mov r3, sp @ struct pt_regs* + + ldr r2, =function_trace_op + ldr r2, [r2]@ pointer to the current + @ function tracing op + + ldr r1, [sp, #S_LR] @ lr of instrumented func + + ldr lr, [sp, #S_PC] @ get LR + + mcount_adjust_addr r0, lr @ instrumented function + + .globl ftrace_regs_call +ftrace_regs_call: + bl ftrace_stub + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + .globl ftrace_graph_regs_call +ftrace_graph_regs_call: + mov r0, r0 +#endif + + @ pop saved regs + ldmia sp!, {r0-r12} @ restore r0 through r12 + ldr ip, [sp, #8]@ restore PC + ldr lr, [sp, #4]@ restore LR + ldr sp, [sp, #0]@ restore SP + mov pc, ip @ return +.endm + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +.macro __ftrace_graph_regs_caller + + sub r0, fp, #4 @ lr of instrumented routine (parent) + + @ called from __ftrace_regs_caller + ldr r1, [sp, #S_PC] @ instrumented routine (func) + mcount_adjust_addr r1, r1 + + mov r2, fp @ frame pointer + bl prepare_ftrace_return + + @ pop registers saved in ftrace_regs_caller + ldmia sp!, {r0-r12} @ restore r0 through r12 + ldr ip, [sp, #8]@ restore PC + ldr lr, [sp, #4]@ restore LR + ldr sp, [sp, #0]@ restore SP + mov pc, ip @ return + +.endm +#endif +#endif + .macro __ftrace_caller suffix mcount_enter mcount_get_lr
[PATCH] clk: imx7d: Add USB clock information
From: Peter Chen Add USB clock information, the pll_usb_main_clk is USB_PLL at CCM which is the output of USBOTG2 PHY. Signed-off-by: Peter Chen Signed-off-by: Irina Tirdea Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx7d.c | 9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 89bfa75..39d110b 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -801,7 +801,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_OCOTP_CLK] = imx_clk_gate4("ocotp_clk", "ipg_root_clk", base + 0x4230, 0); clks[IMX7D_SNVS_CLK] = imx_clk_gate4("snvs_clk", "ipg_root_clk", base + 0x4250, 0); clks[IMX7D_CAAM_CLK] = imx_clk_gate4("caam_clk", "ipg_root_clk", base + 0x4240, 0); - clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4420, 0); + clks[IMX7D_USB_HSIC_ROOT_CLK] = imx_clk_gate4("usb_hsic_root_clk", "usb_hsic_post_div", base + 0x4690, 0); clks[IMX7D_SDMA_CORE_CLK] = imx_clk_gate4("sdma_root_clk", "ahb_root_clk", base + 0x4480, 0); clks[IMX7D_PCIE_CTRL_ROOT_CLK] = imx_clk_gate4("pcie_ctrl_root_clk", "pcie_ctrl_post_div", base + 0x4600, 0); clks[IMX7D_PCIE_PHY_ROOT_CLK] = imx_clk_gate4("pcie_phy_root_clk", "pcie_phy_post_div", base + 0x4600, 0); @@ -867,6 +867,9 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_CSI_MCLK_ROOT_CLK] = imx_clk_gate4("csi_mclk_root_clk", "csi_mclk_post_div", base + 0x4490, 0); clks[IMX7D_AUDIO_MCLK_ROOT_CLK] = imx_clk_gate4("audio_mclk_root_clk", "audio_mclk_post_div", base + 0x4790, 0); clks[IMX7D_WRCLK_ROOT_CLK] = imx_clk_gate4("wrclk_root_clk", "wrclk_post_div", base + 0x47a0, 0); + clks[IMX7D_USB_CTRL_CLK] = imx_clk_gate4("usb_ctrl_clk", "ahb_root_clk", base + 0x4680, 0); + clks[IMX7D_USB_PHY1_CLK] = imx_clk_gate4("usb_phy1_clk", "pll_usb1_main_clk", base + 0x46a0, 0); + clks[IMX7D_USB_PHY2_CLK] = imx_clk_gate4("usb_phy2_clk", "pll_usb_main_clk", base + 0x46b0, 0); clks[IMX7D_ADC_ROOT_CLK] = imx_clk_gate4("adc_root_clk", "ipg_root_clk", base + 0x4200, 0); clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8); @@ -892,6 +895,10 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) /* set uart module clock's parent clock source that must be great then 80MHz */ clk_set_parent(clks[IMX7D_UART1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]); + /* Set clock rate for USBPHY, the USB_PLL at CCM is from USBOTG2 */ + clks[IMX7D_USB1_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb1_main_clk", "osc", 20, 1); + clks[IMX7D_USB_MAIN_480M_CLK] = imx_clk_fixed_factor("pll_usb_main_clk", "osc", 20, 1); + imx_register_uart_clocks(uart_clks); } -- 2.7.4
[PATCH] clk: imx7d: Correct dram pll type
From: Anson Huang DRAM PLL is a audio/video type PLL, need to correct it to get correct ops of PLL. There is a test_div placed before DRAM PLL's gate, so add this test div clk. Signed-off-by: Anson Huang Signed-off-by: Irina Tirdea Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx7d.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 89bfa75..45c83b6 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -441,11 +441,13 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]); clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13); - clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_main_bypass", base + 0x70, 13); + clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13); clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13); clks[IMX7D_PLL_AUDIO_MAIN_CLK] = imx_clk_gate("pll_audio_main_clk", "pll_audio_main_bypass", base + 0xf0, 13); clks[IMX7D_PLL_VIDEO_MAIN_CLK] = imx_clk_gate("pll_video_main_clk", "pll_video_main_bypass", base + 0x130, 13); + clks[IMX7D_PLL_DRAM_TEST_DIV] = clk_register_divider_table(NULL, "pll_dram_test_div", "pll_dram_main_bypass", + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0x70, 21, 2, 0, test_div_table, &imx_ccm_lock); clks[IMX7D_PLL_AUDIO_TEST_DIV] = clk_register_divider_table(NULL, "pll_audio_test_div", "pll_audio_main_clk", CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, base + 0xf0, 19, 2, 0, test_div_table, &imx_ccm_lock); clks[IMX7D_PLL_AUDIO_POST_DIV] = clk_register_divider_table(NULL, "pll_audio_post_div", "pll_audio_test_div", -- 2.7.4
[PATCH] clk: imx7d: Correct ahb clk parent select
From: Anson Huang Design team change the ahb's clk parent options but did NOT update the DOC accordingly in time, so the AHB/IPG's clk rate in clk tree is incorrect, AHB is 67.5MHz and IPG is 33.75MHz, but using scope to monitor them, they are actually 135MHz and 67.5MHz, update the clk parent option to make clk tree info correct. Signed-off-by: Anson Huang Signed-off-by: Irina Tirdea Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx7d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 89bfa75..4d020dd 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -74,7 +74,7 @@ static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", - "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_post_div", + "pll_enet_250m_clk", "pll_usb_main_clk", "pll_audio_post_div", "pll_video_post_div", }; static const char *dram_phym_sel[] = { "pll_dram_main_clk", -- 2.7.4
[PATCH] clk: imx7d: Move clks_init_on before any clock operations
From: Dong Aisheng For init on clocks we should move it at the first place in imx7d_clocks_init() before any clock operations, else the clock operation may fail in case the clock is still not on. Acked-by: Ranjani Vaidyanathan Signed-off-by: Dong Aisheng Signed-off-by: Irina Tirdea Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx7d.c | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 89bfa75..9b17805 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -433,13 +433,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT); clks[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT); - clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]); - clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]); - clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]); - clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]); - clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]); - clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]); - clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13); clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_main_bypass", base + 0x70, 13); clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13); @@ -886,6 +879,13 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) clk_prepare_enable(clks[clks_init_on[i]]); + clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]); + clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]); + clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]); + clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]); + clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]); + clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]); + /* use old gpt clk setting, gpt1 root clk must be twice as gpt counter freq */ clk_set_parent(clks[IMX7D_GPT1_ROOT_SRC], clks[IMX7D_OSC_24M_CLK]); -- 2.7.4
[PATCH v2] clk: imx: Set CLK_SET_RATE_GATE for gate and divider clocks
From: Shawn Guo Add flag CLK_SET_RATE_GATE for i.MX gate and divider clocks on which the client drivers usually make clk_set_rate() call, so that the call will fail when clock is still on instead of standing the risk of running into glitch issue. Rate cannot be changed when the clock is enabled due to the glitchy multiplexers. Signed-off-by: Shawn Guo [initial patch from imx internal repo] Signed-off-by: Abel Vesa [carried over from 3.14 and also applied the flag to newer functions] --- Changes since v1: - changed ownership as per initial patch drivers/clk/imx/clk.h | 15 +-- 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 8076ec0..753ebc4 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -96,7 +96,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name, static inline struct clk *imx_clk_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { - return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + return clk_register_divider(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, shift, width, 0, &imx_ccm_lock); } @@ -140,7 +141,8 @@ static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent, static inline struct clk *imx_clk_gate2(const char *name, const char *parent, void __iomem *reg, u8 shift) { - return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + return clk_register_gate2(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, shift, 0x3, 0, &imx_ccm_lock, NULL); } @@ -155,7 +157,8 @@ static inline struct clk *imx_clk_gate2_shared(const char *name, const char *parent, void __iomem *reg, u8 shift, unsigned int *share_count) { - return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + return clk_register_gate2(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, shift, 0x3, 0, &imx_ccm_lock, share_count); } @@ -164,8 +167,8 @@ static inline struct clk *imx_clk_gate2_shared2(const char *name, unsigned int *share_count) { return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | - CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, - &imx_ccm_lock, share_count); + CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE, + reg, shift, 0x3, 0, &imx_ccm_lock, share_count); } static inline struct clk *imx_clk_gate2_cgr(const char *name, @@ -187,7 +190,7 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, void __iomem *reg, u8 shift) { return clk_register_gate2(NULL, name, parent, - CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, &imx_ccm_lock, NULL); } -- 2.7.4
[PATCH 1/4] arm: imx: Update clk driver API
This adds the following new wrappers: - imx_clk_gate2_flag - imx_clk_set_parent It also updates the flags for the old wrappers. Signed-off-by: Anson Huang Signed-off-by: Abel Vesa --- drivers/clk/imx/clk.h | 42 +++--- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index d69c4bb..466c37f3 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -4,6 +4,7 @@ #include #include +#include extern spinlock_t imx_ccm_lock; @@ -54,6 +55,15 @@ struct clk * imx_obtain_fixed_clock( struct clk *imx_clk_gate_exclusive(const char *name, const char *parent, void __iomem *reg, u8 shift, u32 exclusive_mask); +static inline void imx_clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = clk_set_parent(clk, parent); + + if (ret) + pr_err("failed to set parent of clk %s to %s: %d\n", + __clk_get_name(clk), __clk_get_name(parent), ret); +} + struct clk *imx_clk_pfd(const char *name, const char *parent_name, void __iomem *reg, u8 idx); @@ -96,7 +106,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name, static inline struct clk *imx_clk_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { - return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + return clk_register_divider(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, shift, width, 0, &imx_ccm_lock); } @@ -112,7 +123,7 @@ static inline struct clk *imx_clk_divider2(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { return clk_register_divider(NULL, name, parent, - CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE, reg, shift, width, 0, &imx_ccm_lock); } @@ -133,7 +144,15 @@ static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent, static inline struct clk *imx_clk_gate2(const char *name, const char *parent, void __iomem *reg, u8 shift) { - return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + return clk_register_gate2(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, + shift, 0x3, 0, &imx_ccm_lock, NULL); +} + +static inline struct clk *imx_clk_gate2_flags(const char *name, const char *parent, + void __iomem *reg, u8 shift, unsigned long flags) +{ + return clk_register_gate2(NULL, name, parent, flags, reg, shift, 0x3, 0, &imx_ccm_lock, NULL); } @@ -141,7 +160,8 @@ static inline struct clk *imx_clk_gate2_shared(const char *name, const char *parent, void __iomem *reg, u8 shift, unsigned int *share_count) { - return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + return clk_register_gate2(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, shift, 0x3, 0, &imx_ccm_lock, share_count); } @@ -150,8 +170,8 @@ static inline struct clk *imx_clk_gate2_shared2(const char *name, unsigned int *share_count) { return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | - CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, - &imx_ccm_lock, share_count); + CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE, + reg, shift, 0x3, 0, &imx_ccm_lock, share_count); } static inline struct clk *imx_clk_gate2_cgr(const char *name, @@ -173,7 +193,7 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, void __iomem *reg, u8 shift) { return clk_register_gate2(NULL, name, parent, - CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, &imx_ccm_lock, NULL); } @@ -181,8 +201,8 @@ static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg, u8 shift, u8 width, const char **parents, int num_parents) { return clk_register_mux(NULL, name, parents, num_parents, - CLK_SET_RATE_NO_REPARENT, reg, shift, - width, 0, &imx_ccm_lock); + CLK_SET_RATE_NO_REPARENT | CLK_SET_PARENT_GATE, + reg, shift, width, 0, &imx_ccm_lock); } static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, @@ -198,8 +218,8 @@ static inline struct clk *imx_clk_mux_flags(
[PATCH 3/4] arm: imx: Correct ahb clk parent select
From: Anson Huang Design team change the ahb's clk parent options but did NOT update the DOC accordingly in time, so the AHB/IPG's clk rate in clk tree is incorrect, AHB is 67.5MHz and IPG is 33.75MHz, but using scope to monitor them, they are actually 135MHz and 67.5MHz, update the clk parent option to make clk tree info correct. Signed-off-by: Anson Huang Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx7d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index d786f98..3553b68 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -74,7 +74,7 @@ static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", - "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_post_div", + "pll_enet_250m_clk", "pll_usb_main_clk", "pll_audio_post_div", "pll_video_post_div", }; static const char *dram_phym_sel[] = { "pll_dram_main_clk", -- 2.7.4
[PATCH 0/4] arm: imx: Clock related updates
This is part of the imx upstreaming effort. All the changes are related imx generic clk API and imx7d clk driver. The imx clk API updates will also be used by the new imx SOCs that will follow. Abel Vesa (1): arm: imx: Update clk driver API Anson Huang (3): arm: imx: Correct dram pll type arm: imx: Correct ahb clk parent select arm: imx: Update clk driver for imx7d drivers/clk/imx/clk-imx7d.c | 127 +++- drivers/clk/imx/clk.h | 42 +++ 2 files changed, 98 insertions(+), 71 deletions(-) -- 2.7.4
[PATCH 4/4] arm: imx: Update clk driver for imx7d
From: Anson Huang This patch updates the imx7d clk driver to make use of the new imx clk API. Signed-off-by: Anson Huang Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx7d.c | 28 ++-- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 3553b68..255563b 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -433,13 +433,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_PLL_AUDIO_MAIN_BYPASS] = imx_clk_mux_flags("pll_audio_main_bypass", base + 0xf0, 16, 1, pll_audio_bypass_sel, ARRAY_SIZE(pll_audio_bypass_sel), CLK_SET_RATE_PARENT); clks[IMX7D_PLL_VIDEO_MAIN_BYPASS] = imx_clk_mux_flags("pll_video_main_bypass", base + 0x130, 16, 1, pll_video_bypass_sel, ARRAY_SIZE(pll_video_bypass_sel), CLK_SET_RATE_PARENT); - clk_set_parent(clks[IMX7D_PLL_ARM_MAIN_BYPASS], clks[IMX7D_PLL_ARM_MAIN]); - clk_set_parent(clks[IMX7D_PLL_DRAM_MAIN_BYPASS], clks[IMX7D_PLL_DRAM_MAIN]); - clk_set_parent(clks[IMX7D_PLL_SYS_MAIN_BYPASS], clks[IMX7D_PLL_SYS_MAIN]); - clk_set_parent(clks[IMX7D_PLL_ENET_MAIN_BYPASS], clks[IMX7D_PLL_ENET_MAIN]); - clk_set_parent(clks[IMX7D_PLL_AUDIO_MAIN_BYPASS], clks[IMX7D_PLL_AUDIO_MAIN]); - clk_set_parent(clks[IMX7D_PLL_VIDEO_MAIN_BYPASS], clks[IMX7D_PLL_VIDEO_MAIN]); - clks[IMX7D_PLL_ARM_MAIN_CLK] = imx_clk_gate("pll_arm_main_clk", "pll_arm_main_bypass", base + 0x60, 13); clks[IMX7D_PLL_DRAM_MAIN_CLK] = imx_clk_gate("pll_dram_main_clk", "pll_dram_test_div", base + 0x70, 13); clks[IMX7D_PLL_SYS_MAIN_CLK] = imx_clk_gate("pll_sys_main_clk", "pll_sys_main_bypass", base + 0xb0, 13); @@ -525,7 +518,7 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_mux2("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel)); clks[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_mux2("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel)); clks[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_mux2("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel)); - clks[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_mux2("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel)); + clks[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_mux_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE); clks[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_mux2("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel)); clks[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_mux2("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel)); clks[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_mux2("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel)); @@ -719,13 +712,13 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_CLKO1_ROOT_PRE_DIV] = imx_clk_divider2("clko1_pre_div", "clko1_cg", base + 0xbd80, 16, 3); clks[IMX7D_CLKO2_ROOT_PRE_DIV] = imx_clk_divider2("clko2_pre_div", "clko2_cg", base + 0xbe00, 16, 3); - clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3); + clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider_flags("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3, CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE); clks[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3); - clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6); + clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider_flags("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6, CLK_OPS_PARENT_ENABLE); clks[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6); clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6); clks[IMX7D_NAND_USDHC_BUS_ROOT_CLK] = imx_clk_divider2("nand_usdhc_root_clk", "nand_usdhc_pre_div", base + 0x8980, 0, 6); - clks[IMX7D_AHB_CHANNEL_ROOT_DIV] = imx_clk_divider2("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6); + clks[IMX7D_AHB_CHANNEL_ROOT_CLK] = imx_clk_divider_flags("ahb_root_clk", "ahb_pre_div", base + 0x9000, 0, 6, CLK_OPS_PARENT_ENABLE); clks[IMX7D_IPG_
[PATCH 2/4] arm: imx: Correct dram pll type
From: Anson Huang DRAM PLL is a audio/video type PLL, need to correct it to get correct ops of PLL. There is a test_div placed before DRAM PLL's gate, so add this test div clk. Signed-off-by: Anson Huang Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-imx7d.c | 97 - 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 80dc211..d786f98 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -51,20 +51,20 @@ static const char *arm_a7_sel[] = { "osc", "pll_arm_main_clk", static const char *arm_m4_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_enet_250m_clk", "pll_sys_pfd2_270m_clk", - "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_post_div", "pll_usb_main_clk", }; static const char *axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd5_clk", - "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd7_clk", }; + "pll_audio_post_div", "pll_video_post_div", "pll_sys_pfd7_clk", }; static const char *disp_axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd6_clk", - "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_main_clk", }; + "pll_sys_pfd7_clk", "pll_audio_post_div", "pll_video_post_div", }; static const char *enet_axi_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", - "pll_sys_main_240m_clk", "pll_audio_post_div", "pll_video_main_clk", + "pll_sys_main_240m_clk", "pll_audio_post_div", "pll_video_post_div", "pll_sys_pfd4_clk", }; static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", @@ -75,7 +75,7 @@ static const char *nand_usdhc_bus_sel[] = { "osc", "pll_sys_pfd2_270m_clk", static const char *ahb_channel_sel[] = { "osc", "pll_sys_pfd2_270m_clk", "pll_dram_533m_clk", "pll_sys_pfd0_392m_clk", "pll_enet_125m_clk", "pll_usb_main_clk", "pll_audio_post_div", - "pll_video_main_clk", }; + "pll_video_post_div", }; static const char *dram_phym_sel[] = { "pll_dram_main_clk", "dram_phym_alt_clk", }; @@ -86,7 +86,7 @@ static const char *dram_sel[] = { "pll_dram_main_clk", static const char *dram_phym_alt_sel[] = { "osc", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_enet_500m_clk", "pll_usb_main_clk", "pll_sys_pfd7_clk", "pll_audio_post_div", - "pll_video_main_clk", }; + "pll_video_post_div", }; static const char *dram_alt_sel[] = { "osc", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_enet_500m_clk", @@ -108,62 +108,62 @@ static const char *pcie_phy_sel[] = { "osc", "pll_enet_100m_clk", static const char *epdc_pixel_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_sys_main_clk", "pll_sys_pfd5_clk", - "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", "pll_video_main_clk", }; + "pll_sys_pfd6_clk", "pll_sys_pfd7_clk", "pll_video_post_div", }; static const char *lcdif_pixel_sel[] = { "osc", "pll_sys_pfd5_clk", "pll_dram_533m_clk", "ext_clk_3", "pll_sys_pfd4_clk", - "pll_sys_pfd2_270m_clk", "pll_video_main_clk", + "pll_sys_pfd2_270m_clk", "pll_video_post_div", "pll_usb_main_clk", }; static const char *mipi_dsi_sel[] = { "osc", "pll_sys_pfd5_clk", "pll_sys_pfd3_clk", "pll_sys_main_clk", "pll_sys_pfd0_196m_clk", - "pll_dram_533m_clk", "pll_video_main_clk", "pll_audio_post_div", }; + "pll_dram_533m_clk", "pll_video_post_div", "pll_audio_post_div", }; static const char *mipi_csi_sel[] = { "osc", "pll_sys_pfd4_clk", "pll_sys_pfd3_clk", "pll_sys
Re: [PATCH 2/4] arm: imx: Correct dram pll type
Hi Fabio, On Thu, Mar 22, 2018 at 09:31:03AM -0300, Fabio Estevam wrote: > > This has already been applied in linux-next as commit: > > commit b716aad97eb5 ("clk: imx: imx7d: correct video pll clock tree) OK. Will create the patchset again without this one. > > Nit: the prefix in the Subject lines of all these patches should not > be "arm:imx". > > "clk: imx: imx7d" is better suited to reflect the subsystem that thes > patches touch. Will change this too. Which repo/branch should this patchset be created against ? --
Return checks for clock calls
Hi Shawn, Fabio, I'm trying to get the imx clks changes upstreamed. To that end, I reached this old commit that adds some wrappers over the generic clk API. Here is the commit message: ARM: imx6: add return check for clock calls There are a bunch of clk_enable_prepare, clk_set_parent and clk_set_rate calls in imx6 clock driver's initialization. They are called without retunr check. If there is something going wrong with the calls, they will just fail silently. The patch creates a set of helper functions imx_clk_enable_prepare, imx_clk_set_parent and imx_clk_set_rate, and use them instead from clock initialization to check the return and print error message to tell failures if any. Signed-off-by: Shawn Guo And it adds the imx_clk_set_parent, imx_clk_prepare_enable and imx_clk_set_rate which basically just print an error message if the generic functions have failed. The only plus of these wrappers is that we at least see that the generic functions have failed, but the behaviour is not changed in any way. Question is, do we want this upstreamed considering that we need to replace the calls throughout all the older imx socs ? Abel
[PATCH] clk: imx: Set CLK_SET_RATE_GATE for gate and divider clocks
Add flag CLK_SET_RATE_GATE for i.MX gate and divider clocks on which the client drivers usually make clk_set_rate() call, so that the call will fail when clock is still on instead of standing the risk of running into glitch issue. Rate cannot be changed when the clock is enabled due to the glitchy multiplexers. Signed-off-by: Shawn Guo [initial patch from imx internal repo] Signed-off-by: Abel Vesa [carried over from 3.14 and also applied the flag to newer functions] --- drivers/clk/imx/clk.h | 15 +-- 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index d69c4bb..4411719 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -96,7 +96,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name, static inline struct clk *imx_clk_divider(const char *name, const char *parent, void __iomem *reg, u8 shift, u8 width) { - return clk_register_divider(NULL, name, parent, CLK_SET_RATE_PARENT, + return clk_register_divider(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, shift, width, 0, &imx_ccm_lock); } @@ -133,7 +134,8 @@ static inline struct clk *imx_clk_gate_dis(const char *name, const char *parent, static inline struct clk *imx_clk_gate2(const char *name, const char *parent, void __iomem *reg, u8 shift) { - return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + return clk_register_gate2(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, shift, 0x3, 0, &imx_ccm_lock, NULL); } @@ -141,7 +143,8 @@ static inline struct clk *imx_clk_gate2_shared(const char *name, const char *parent, void __iomem *reg, u8 shift, unsigned int *share_count) { - return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT, reg, + return clk_register_gate2(NULL, name, parent, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, reg, shift, 0x3, 0, &imx_ccm_lock, share_count); } @@ -150,8 +153,8 @@ static inline struct clk *imx_clk_gate2_shared2(const char *name, unsigned int *share_count) { return clk_register_gate2(NULL, name, parent, CLK_SET_RATE_PARENT | - CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, - &imx_ccm_lock, share_count); + CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE, + reg, shift, 0x3, 0, &imx_ccm_lock, share_count); } static inline struct clk *imx_clk_gate2_cgr(const char *name, @@ -173,7 +176,7 @@ static inline struct clk *imx_clk_gate4(const char *name, const char *parent, void __iomem *reg, u8 shift) { return clk_register_gate2(NULL, name, parent, - CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE, + CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE | CLK_OPS_PARENT_ENABLE, reg, shift, 0x3, 0, &imx_ccm_lock, NULL); } -- 2.7.4
[PATCH v14 0/5] Add i.MX8MQ clock driver
Here is a link to the 13th version: https://lkml.org/lkml/2018/11/13/1020 Changes since v13: * included changes suggested by Stephen Boyd Abel Vesa (2): clk: imx: Add imx composite clock clk: imx: Add clock driver for i.MX8MQ CCM Lucas Stach (3): dt-bindings: Add binding for i.MX8MQ CCM clk: imx: Add fractional PLL output clock clk: imx: Add SCCG PLL type .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-composite-8m.c | 178 +++ drivers/clk/imx/clk-frac-pll.c | 223 drivers/clk/imx/clk-imx8mq.c | 589 + drivers/clk/imx/clk-sccg-pll.c | 256 + drivers/clk/imx/clk.h | 64 +++ include/dt-bindings/clock/imx8mq-clock.h | 395 ++ 8 files changed, 1730 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 drivers/clk/imx/clk-composite-8m.c create mode 100644 drivers/clk/imx/clk-frac-pll.c create mode 100644 drivers/clk/imx/clk-imx8mq.c create mode 100644 drivers/clk/imx/clk-sccg-pll.c create mode 100644 include/dt-bindings/clock/imx8mq-clock.h -- 2.7.4
[PATCH v14 2/5] clk: imx: Add fractional PLL output clock
From: Lucas Stach This is a new fractional clock type introduced on i.MX8. The description of this fractional clock can be found here: https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-frac-pll.c | 223 + drivers/clk/imx/clk.h | 3 + 3 files changed, 227 insertions(+) create mode 100644 drivers/clk/imx/clk-frac-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..4893c1f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -6,6 +6,7 @@ obj-y += \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ + clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pllv1.o \ diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 000..9872620 --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * + * This driver supports the fractional plls found in the imx8m SOCs + * + * Documentation for this fractional pll can be found at: + * https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUSBIT(31) +#define PLL_PD_MASKBIT(19) +#define PLL_BYPASS_MASKBIT(14) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK GENMASK(30, 7) +#define PLL_INT_DIV_MASK GENMASK(6, 0) +#define PLL_OUTPUT_DIV_MASKGENMASK(4, 0) +#define PLL_FRAC_DENOM 0x100 + +#define PLL_FRAC_LOCK_TIMEOUT 1 +#define PLL_FRAC_ACK_TIMEOUT 50 + +struct clk_frac_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_STATUS, 0, + PLL_FRAC_LOCK_TIMEOUT); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + return readl_poll_timeout(pll->base, val, val & PLL_NEWDIV_ACK, 0, + PLL_FRAC_ACK_TIMEOUT); +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val, divff, divfi, divq; + u64 temp64 = parent_rate; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = ((val & PLL_OUTPUT_DIV_MASK) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = FIELD_GET(PLL_FRAC_DIV_MASK, val); + divfi = val & PLL_INT_DIV_MASK; + + temp64 *= 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + do_div(temp64, divq); + + return parent_rate * 8 * (divfi + 1) / divq + (unsigned long)temp64; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u64 parent_rate = *prate; + u32 divff, divfi; + u64 temp64; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = rate - divfi * parent_rate; + temp64 *= PLL_FRAC_DENOM; + do_div(temp64, parent_rate); + divff = temp64; + + temp64 = parent_rate; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + + return (parent_rate * divfi + temp64) / 2; +} + +/* +
[PATCH v14 5/5] clk: imx: Add clock driver for i.MX8MQ CCM
Add driver for the Clock Control Module found on i.MX8MQ. Signed-off-by: Anson Huang Signed-off-by: Bai Ping Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mq.c | 589 +++ drivers/clk/imx/clk.h| 36 +++ 3 files changed, 626 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mq.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 237444b..6952f05 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 000..26b57f4 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * Copyright (C) 2017 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai4; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_dcss; +static u32 share_count_nand; + +static struct clk *clks[IMX8MQ_CLK_END]; + +static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; + +static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", }; + +static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", + "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",}; + +static const char *imx8mq_enet_axi_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_200m", "audio_pll1_out", "video_pll1_out", "sys3_pll2_out&q
[PATCH v14 1/5] dt-bindings: Add binding for i.MX8MQ CCM
From: Lucas Stach This adds the binding for the i.MX8MQ Clock Controller Module. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Rob Herring --- .../devicetree/bindings/clock/imx8mq-clock.txt | 20 ++ include/dt-bindings/clock/imx8mq-clock.h | 395 + 2 files changed, 415 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 include/dt-bindings/clock/imx8mq-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt new file mode 100644 index 000..52de826 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt @@ -0,0 +1,20 @@ +* Clock bindings for NXP i.MX8M Quad + +Required properties: +- compatible: Should be "fsl,imx8mq-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include the following entries: +- "ckil" +- "osc_25m" +- "osc_27m" +- "clk_ext1" +- "clk_ext2" +- "clk_ext3" +- "clk_ext4" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h +for the full list of i.MX8M Quad clock IDs. diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h new file mode 100644 index 000..b53be41 --- /dev/null +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -0,0 +1,395 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MQ_H +#define __DT_BINDINGS_CLOCK_IMX8MQ_H + +#define IMX8MQ_CLK_DUMMY 0 +#define IMX8MQ_CLK_32K 1 +#define IMX8MQ_CLK_25M 2 +#define IMX8MQ_CLK_27M 3 +#define IMX8MQ_CLK_EXT14 +#define IMX8MQ_CLK_EXT25 +#define IMX8MQ_CLK_EXT36 +#define IMX8MQ_CLK_EXT47 + +/* ANAMIX PLL clocks */ +/* FRAC PLLs */ +/* ARM PLL */ +#define IMX8MQ_ARM_PLL_REF_SEL 8 +#define IMX8MQ_ARM_PLL_REF_DIV 9 +#define IMX8MQ_ARM_PLL 10 +#define IMX8MQ_ARM_PLL_BYPASS 11 +#define IMX8MQ_ARM_PLL_OUT 12 + +/* GPU PLL */ +#define IMX8MQ_GPU_PLL_REF_SEL 13 +#define IMX8MQ_GPU_PLL_REF_DIV 14 +#define IMX8MQ_GPU_PLL 15 +#define IMX8MQ_GPU_PLL_BYPASS 16 +#define IMX8MQ_GPU_PLL_OUT 17 + +/* VPU PLL */ +#define IMX8MQ_VPU_PLL_REF_SEL 18 +#define IMX8MQ_VPU_PLL_REF_DIV 19 +#define IMX8MQ_VPU_PLL 20 +#define IMX8MQ_VPU_PLL_BYPASS 21 +#define IMX8MQ_VPU_PLL_OUT 22 + +/* AUDIO PLL1 */ +#define IMX8MQ_AUDIO_PLL1_REF_SEL 23 +#define IMX8MQ_AUDIO_PLL1_REF_DIV 24 +#define IMX8MQ_AUDIO_PLL1 25 +#define IMX8MQ_AUDIO_PLL1_BYPASS 26 +#define IMX8MQ_AUDIO_PLL1_OUT 27 + +/* AUDIO PLL2 */ +#define IMX8MQ_AUDIO_PLL2_REF_SEL 28 +#define IMX8MQ_AUDIO_PLL2_REF_DIV 29 +#define IMX8MQ_AUDIO_PLL2 30 +#define IMX8MQ_AUDIO_PLL2_BYPASS 31 +#define IMX8MQ_AUDIO_PLL2_OUT 32 + +/* VIDEO PLL1 */ +#define IMX8MQ_VIDEO_PLL1_REF_SEL 33 +#define IMX8MQ_VIDEO_PLL1_REF_DIV 34 +#define IMX8MQ_VIDEO_PLL1 35 +#define IMX8MQ_VIDEO_PLL1_BYPASS 36 +#define IMX8MQ_VIDEO_PLL1_OUT 37 + +/* SYS1 PLL */ +#define IMX8MQ_SYS1_PLL1_REF_SEL 38 +#define IMX8MQ_SYS1_PLL1_REF_DIV 39 +#define IMX8MQ_SYS1_PLL1 40 +#define IMX8MQ_SYS1_PLL1_OUT 41 +#define IMX8MQ_SYS1_PLL1_OUT_DIV 42 +#define IMX8MQ_SYS1_PLL2 43 +#define IMX8MQ_SYS1_PLL2_DIV 44 +#define IMX8MQ_SYS1_PLL2_OUT 45 + +/* SYS2 PLL */ +#define IMX8MQ_SYS2_PLL1_REF_SEL 46 +#define IMX8MQ_SYS2_PLL1_REF_DIV 47 +#define IMX8MQ_SYS2_PLL1 48 +#define IMX8MQ_SYS2_PLL1_OUT 49 +#define IMX8MQ_SYS2_PLL1_OUT_DIV 50 +#define IMX8MQ_SYS2_PLL2 51 +#define IMX8MQ_SYS2_PLL2_DIV 52 +#define IMX8MQ_SYS2_PLL2_OUT 53 + +/* SYS3 PLL */ +#define IMX8MQ_SYS3_PLL1_REF_SEL 54 +#define IMX8MQ_SYS3_PLL1_REF_DIV 55 +#define IMX8MQ_SYS3_PLL1 56 +#define IMX8MQ_SYS3_PLL1_OUT 57 +#define IMX8MQ_SYS3_PLL1_OUT_DIV 58 +#define IMX8MQ_SYS3_PLL2 59 +#define IMX8MQ_SYS3_PLL2_DIV 60 +#define IMX8MQ_SYS3_PLL2_OUT 61 + +/* DRAM PLL */ +#define IMX8MQ_DRAM_PLL1_REF_SEL 62 +#define IMX8MQ_DRAM_PLL1_REF_DIV 63 +#define IMX8MQ_DRAM_PLL1 64 +#define IMX8MQ
[PATCH v14 3/5] clk: imx: Add SCCG PLL type
From: Lucas Stach The SCCG is a new PLL type introduced on i.MX8. The description of this SCCG clock can be found here: https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-sccg-pll.c | 256 + drivers/clk/imx/clk.h | 9 ++ 3 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-sccg-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4893c1f..b87513c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pfd.o + clk-pfd.o \ + clk-sccg-pll.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c new file mode 100644 index 000..ee7752b --- /dev/null +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + * + * This driver supports the SCCG plls found in the imx8m SOCs + * + * Documentation for this SCCG pll can be found at: + * https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +/* PLL CFGs */ +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 +#define PLL_CFG2 0x8 + +#define PLL_DIVF1_MASK GENMASK(18, 13) +#define PLL_DIVF2_MASK GENMASK(12, 7) +#define PLL_DIVR1_MASK GENMASK(27, 25) +#define PLL_DIVR2_MASK GENMASK(24, 19) +#define PLL_REF_MASK GENMASK(2, 0) + +#define PLL_LOCK_MASK BIT(31) +#define PLL_PD_MASKBIT(7) + +#define OSC_25M2500 +#define OSC_27M2700 + +#define PLL_SCCG_LOCK_TIMEOUT 70 + +struct clk_sccg_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) + +static int clk_pll_wait_lock(struct clk_sccg_pll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK, 0, + PLL_SCCG_LOCK_TIMEOUT); +} + +static int clk_pll1_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, divf; + + val = readl_relaxed(pll->base + PLL_CFG2); + divf = FIELD_GET(PLL_DIVF1_MASK, val); + + return parent_rate * 2 * (divf + 1); +} + +static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 div; + + if (!parent_rate) + return 0; + + div = rate / (parent_rate * 2); + + return parent_rate * div * 2; +} + +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + u32 divf; + + if (!parent_rate) + return -EINVAL; + + divf = rate / (parent_rate * 2); + + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~PLL_DIVF1_MASK; + val |= FIELD_PREP(PLL_DIVF1_MASK, divf - 1); + writel_relaxed(val, pll->base + PLL_CFG2); + + return clk_pll_wait_lock(pll); +} + +static int clk_pll1_prepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_pll_wait_lock(pll); +} + +static void clk_pll1_unprepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + +} + +static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, ref, divr1, divf1, divr2, divf2; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + switch (FIELD_GET(PLL_REF_MASK, val)) { + case 0: + ref = OSC_25M; +
[PATCH v14 4/5] clk: imx: Add imx composite clock
Since a lot of clocks on imx8m are formed by a mux, gate, predivider and divider, the idea here is to combine all of those into one composite clock, but we need to deal with both predivider and divider at the same time and therefore we add the imx8m_clk_composite_divider_ops and register the composite clock with those. Signed-off-by: Abel Vesa Suggested-by: Sascha Hauer Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-composite-8m.c | 178 + drivers/clk/imx/clk.h | 16 3 files changed, 195 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-8m.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b87513c..237444b 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -3,6 +3,7 @@ obj-y += \ clk.o \ clk-busy.o \ + clk-composite-8m.o \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c new file mode 100644 index 000..6d9d371 --- /dev/null +++ b/drivers/clk/imx/clk-composite-8m.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +#include +#include +#include + +#include "clk.h" + +#define PCG_PREDIV_SHIFT 16 +#define PCG_PREDIV_WIDTH 3 +#define PCG_PREDIV_MAX 8 + +#define PCG_DIV_SHIFT 0 +#define PCG_DIV_WIDTH 6 +#define PCG_DIV_MAX64 + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 + +#define PCG_CGC_SHIFT 28 + +static unsigned long imx8m_clk_composite_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long prediv_rate; + unsigned int prediv_value; + unsigned int div_value; + + prediv_value = readl(divider->reg) >> divider->shift; + prediv_value &= clk_div_mask(divider->width); + + prediv_rate = divider_recalc_rate(hw, parent_rate, prediv_value, + NULL, divider->flags, + divider->width); + + div_value = readl(divider->reg) >> PCG_DIV_SHIFT; + div_value &= clk_div_mask(PCG_DIV_WIDTH); + + return divider_recalc_rate(hw, prediv_rate, div_value, NULL, + divider->flags, PCG_DIV_WIDTH); +} + +static int imx8m_clk_composite_compute_dividers(unsigned long rate, + unsigned long parent_rate, + int *prediv, int *postdiv) +{ + int div1, div2; + int error = INT_MAX; + int ret = -EINVAL; + + *prediv = 1; + *postdiv = 1; + + for (div1 = 1; div1 <= PCG_PREDIV_MAX; div1++) { + for (div2 = 1; div2 <= PCG_DIV_MAX; div2++) { + int new_error = ((parent_rate / div1) / div2) - rate; + + if (abs(new_error) < abs(error)) { + *prediv = div1; + *postdiv = div2; + error = new_error; + ret = 0; + } + } + } + return ret; +} + +static long imx8m_clk_composite_divider_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + int prediv_value; + int div_value; + + imx8m_clk_composite_compute_dividers(rate, *prate, + &prediv_value, &div_value); + rate = DIV_ROUND_UP(*prate, prediv_value); + + return DIV_ROUND_UP(rate, div_value); + +} + +static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + int prediv_value; + int div_value; + int ret = 0; + u32 val; + + ret = imx8m_clk_composite_compute_dividers(rate, parent_rate, + &prediv_value, &div_value); + if (ret) + return -EINVAL; + + spin_lock_irqsave(divider->lock, flags); + + val = readl(divider->reg); + val &= ~((clk_div_mask(divider->width) << divider->shift) | + (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + + val |= (u32)(prediv_value - 1) << divider->shift; + val |= (u32)(div_value - 1) << PCG_DIV_SHIFT; + writel(val, divider
[PATCH] clk: imx: Use do_div in SCCG due to 64-bit divisor
On arm32, a division with a 64-bit divisor has to be done through do_div() function otherwise there is a link failure like: drivers/clk/imx/clk-frac-pll.o: In function `clk_pll_round_rate': clk-frac-pll.c:(.text+0x54): undefined reference to `__aeabi_uldivmod' make: *** [Makefile:1040: vmlinux] Error 1 Fixes: 9fd680d0fafd ("clk: imx: add fractional PLL output clock") Signed-off-by: Abel Vesa Reported-by: Stephen Rothwell --- drivers/clk/imx/clk-frac-pll.c | 7 --- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c index 9872620..8b13df9 100644 --- a/drivers/clk/imx/clk-frac-pll.c +++ b/drivers/clk/imx/clk-frac-pll.c @@ -116,12 +116,13 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { u64 parent_rate = *prate; - u32 divff, divfi; - u64 temp64; + u64 divff, divfi; + u64 temp64 = rate; parent_rate *= 8; rate *= 2; - divfi = rate / parent_rate; + do_div(temp64, parent_rate); + divfi = temp64; temp64 = rate - divfi * parent_rate; temp64 *= PLL_FRAC_DENOM; do_div(temp64, parent_rate); -- 2.7.4
[PATCH v13 2/5] clk: imx: add fractional PLL output clock
From: Lucas Stach This is a new fractional clock type introduced on i.MX8. The description of this fractional clock can be found here: https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-frac-pll.c | 221 + drivers/clk/imx/clk.h | 3 + 3 files changed, 225 insertions(+) create mode 100644 drivers/clk/imx/clk-frac-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..4893c1f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -6,6 +6,7 @@ obj-y += \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ + clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pllv1.o \ diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 000..a3732be --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * + * This driver supports the fractional plls found in the imx8m SOCs + * + * Documentation for this fractional pll can be found at: + * https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 + */ + +#include +#include +#include +#include +#include + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUSBIT(31) +#define PLL_PD_MASKBIT(19) +#define PLL_BYPASS_MASKBIT(14) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK GENMASK(30, 7) +#define PLL_INT_DIV_MASK GENMASK(6, 0) +#define PLL_OUTPUT_DIV_MASKGENMASK(4, 0) +#define PLL_FRAC_DENOM 0x100 + +#define PLL_FRAC_LOCK_TIMEOUT 1 +#define PLL_FRAC_ACK_TIMEOUT 50 + +struct clk_frac_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_STATUS, 0, + PLL_FRAC_LOCK_TIMEOUT); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + return readl_poll_timeout(pll->base, val, val & PLL_NEWDIV_ACK, 0, + PLL_FRAC_ACK_TIMEOUT); +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val, divff, divfi, divq; + u64 temp64 = parent_rate; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = ((val & PLL_OUTPUT_DIV_MASK) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = FIELD_GET(PLL_FRAC_DIV_MASK, val); + divfi = val & PLL_INT_DIV_MASK; + + temp64 *= 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + do_div(temp64, divq); + + return parent_rate * 8 * (divfi + 1) / divq + (unsigned long)temp64; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u64 parent_rate = *prate; + u32 divff, divfi; + u64 temp64; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = rate - divfi * parent_rate; + temp64 *= PLL_FRAC_DENOM; + do_div(temp64, parent_rate); + divff = temp64; + + temp64 = parent_rate; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + + return (parent_rate * divfi + temp64) / 2; +} + +/* + * To simplify the clock calcu
[PATCH v13 1/5] dt-bindings: add binding for i.MX8MQ CCM
From: Lucas Stach This adds the binding for the i.MX8MQ Clock Controller Module. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Rob Herring --- .../devicetree/bindings/clock/imx8mq-clock.txt | 20 ++ include/dt-bindings/clock/imx8mq-clock.h | 395 + 2 files changed, 415 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 include/dt-bindings/clock/imx8mq-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt new file mode 100644 index 000..52de826 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt @@ -0,0 +1,20 @@ +* Clock bindings for NXP i.MX8M Quad + +Required properties: +- compatible: Should be "fsl,imx8mq-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include the following entries: +- "ckil" +- "osc_25m" +- "osc_27m" +- "clk_ext1" +- "clk_ext2" +- "clk_ext3" +- "clk_ext4" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h +for the full list of i.MX8M Quad clock IDs. diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h new file mode 100644 index 000..b53be41 --- /dev/null +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -0,0 +1,395 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MQ_H +#define __DT_BINDINGS_CLOCK_IMX8MQ_H + +#define IMX8MQ_CLK_DUMMY 0 +#define IMX8MQ_CLK_32K 1 +#define IMX8MQ_CLK_25M 2 +#define IMX8MQ_CLK_27M 3 +#define IMX8MQ_CLK_EXT14 +#define IMX8MQ_CLK_EXT25 +#define IMX8MQ_CLK_EXT36 +#define IMX8MQ_CLK_EXT47 + +/* ANAMIX PLL clocks */ +/* FRAC PLLs */ +/* ARM PLL */ +#define IMX8MQ_ARM_PLL_REF_SEL 8 +#define IMX8MQ_ARM_PLL_REF_DIV 9 +#define IMX8MQ_ARM_PLL 10 +#define IMX8MQ_ARM_PLL_BYPASS 11 +#define IMX8MQ_ARM_PLL_OUT 12 + +/* GPU PLL */ +#define IMX8MQ_GPU_PLL_REF_SEL 13 +#define IMX8MQ_GPU_PLL_REF_DIV 14 +#define IMX8MQ_GPU_PLL 15 +#define IMX8MQ_GPU_PLL_BYPASS 16 +#define IMX8MQ_GPU_PLL_OUT 17 + +/* VPU PLL */ +#define IMX8MQ_VPU_PLL_REF_SEL 18 +#define IMX8MQ_VPU_PLL_REF_DIV 19 +#define IMX8MQ_VPU_PLL 20 +#define IMX8MQ_VPU_PLL_BYPASS 21 +#define IMX8MQ_VPU_PLL_OUT 22 + +/* AUDIO PLL1 */ +#define IMX8MQ_AUDIO_PLL1_REF_SEL 23 +#define IMX8MQ_AUDIO_PLL1_REF_DIV 24 +#define IMX8MQ_AUDIO_PLL1 25 +#define IMX8MQ_AUDIO_PLL1_BYPASS 26 +#define IMX8MQ_AUDIO_PLL1_OUT 27 + +/* AUDIO PLL2 */ +#define IMX8MQ_AUDIO_PLL2_REF_SEL 28 +#define IMX8MQ_AUDIO_PLL2_REF_DIV 29 +#define IMX8MQ_AUDIO_PLL2 30 +#define IMX8MQ_AUDIO_PLL2_BYPASS 31 +#define IMX8MQ_AUDIO_PLL2_OUT 32 + +/* VIDEO PLL1 */ +#define IMX8MQ_VIDEO_PLL1_REF_SEL 33 +#define IMX8MQ_VIDEO_PLL1_REF_DIV 34 +#define IMX8MQ_VIDEO_PLL1 35 +#define IMX8MQ_VIDEO_PLL1_BYPASS 36 +#define IMX8MQ_VIDEO_PLL1_OUT 37 + +/* SYS1 PLL */ +#define IMX8MQ_SYS1_PLL1_REF_SEL 38 +#define IMX8MQ_SYS1_PLL1_REF_DIV 39 +#define IMX8MQ_SYS1_PLL1 40 +#define IMX8MQ_SYS1_PLL1_OUT 41 +#define IMX8MQ_SYS1_PLL1_OUT_DIV 42 +#define IMX8MQ_SYS1_PLL2 43 +#define IMX8MQ_SYS1_PLL2_DIV 44 +#define IMX8MQ_SYS1_PLL2_OUT 45 + +/* SYS2 PLL */ +#define IMX8MQ_SYS2_PLL1_REF_SEL 46 +#define IMX8MQ_SYS2_PLL1_REF_DIV 47 +#define IMX8MQ_SYS2_PLL1 48 +#define IMX8MQ_SYS2_PLL1_OUT 49 +#define IMX8MQ_SYS2_PLL1_OUT_DIV 50 +#define IMX8MQ_SYS2_PLL2 51 +#define IMX8MQ_SYS2_PLL2_DIV 52 +#define IMX8MQ_SYS2_PLL2_OUT 53 + +/* SYS3 PLL */ +#define IMX8MQ_SYS3_PLL1_REF_SEL 54 +#define IMX8MQ_SYS3_PLL1_REF_DIV 55 +#define IMX8MQ_SYS3_PLL1 56 +#define IMX8MQ_SYS3_PLL1_OUT 57 +#define IMX8MQ_SYS3_PLL1_OUT_DIV 58 +#define IMX8MQ_SYS3_PLL2 59 +#define IMX8MQ_SYS3_PLL2_DIV 60 +#define IMX8MQ_SYS3_PLL2_OUT 61 + +/* DRAM PLL */ +#define IMX8MQ_DRAM_PLL1_REF_SEL 62 +#define IMX8MQ_DRAM_PLL1_REF_DIV 63 +#define IMX8MQ_DRAM_PLL1 64 +#define IMX8MQ
[PATCH v13 0/5] Add i.MX8MQ clock driver
Here is a link to the 12th version: https://lkml.org/lkml/2018/11/7/642 Changes since v12: * replaced the division in clk_pll_recalc_rate in clk-frac with do_div as suggested by Stephen Abel Vesa (2): clk: imx: Add imx composite clock clk: imx: Add clock driver for i.MX8MQ CCM Lucas Stach (3): dt-bindings: add binding for i.MX8MQ CCM clk: imx: add fractional PLL output clock clk: imx: Add SCCG PLL type .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-composite-8m.c | 178 +++ drivers/clk/imx/clk-frac-pll.c | 221 drivers/clk/imx/clk-imx8mq.c | 589 + drivers/clk/imx/clk-sccg-pll.c | 256 + drivers/clk/imx/clk.h | 64 +++ include/dt-bindings/clock/imx8mq-clock.h | 395 ++ 8 files changed, 1728 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 drivers/clk/imx/clk-composite-8m.c create mode 100644 drivers/clk/imx/clk-frac-pll.c create mode 100644 drivers/clk/imx/clk-imx8mq.c create mode 100644 drivers/clk/imx/clk-sccg-pll.c create mode 100644 include/dt-bindings/clock/imx8mq-clock.h -- 2.7.4
[PATCH v13 3/5] clk: imx: Add SCCG PLL type
From: Lucas Stach The SCCG is a new PLL type introduced on i.MX8. The description of this SCCG clock can be found here: https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-sccg-pll.c | 256 + drivers/clk/imx/clk.h | 9 ++ 3 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-sccg-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4893c1f..b87513c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pfd.o + clk-pfd.o \ + clk-sccg-pll.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c new file mode 100644 index 000..4666b96 --- /dev/null +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + * + * This driver supports the SCCG plls found in the imx8m SOCs + * + * Documentation for this SCCG pll can be found at: + * https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +/* PLL CFGs */ +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 +#define PLL_CFG2 0x8 + +#define PLL_DIVF1_MASK GENMASK(18, 13) +#define PLL_DIVF2_MASK GENMASK(12, 7) +#define PLL_DIVR1_MASK GENMASK(27, 25) +#define PLL_DIVR2_MASK GENMASK(24, 19) +#define PLL_REF_MASK GENMASK(2, 0) + +#define PLL_LOCK_MASK BIT(31) +#define PLL_PD_MASKBIT(7) + +#define OSC_25M2500 +#define OSC_27M2700 + +#define PLL_SCCG_LOCK_TIMEOUT 70 + +struct clk_sccg_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) + +static int clk_pll_wait_lock(struct clk_sccg_pll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK, 0, + PLL_SCCG_LOCK_TIMEOUT); +} + +static int clk_pll1_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, divf; + + val = readl_relaxed(pll->base + PLL_CFG2); + divf = FIELD_GET(PLL_DIVF1_MASK, val); + + return parent_rate * 2 * (divf + 1); +} + +static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 div; + + if (!parent_rate) + return 0; + + div = rate / (parent_rate * 2); + + return parent_rate * div * 2; +} + +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + u32 divf; + + if (!parent_rate) + return -EINVAL; + + divf = rate / (parent_rate * 2); + + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~PLL_DIVF1_MASK; + val |= FIELD_PREP(PLL_DIVF1_MASK, divf - 1); + writel_relaxed(val, pll->base + PLL_CFG2); + + return clk_pll_wait_lock(pll); +} + +static int clk_pll1_prepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_pll_wait_lock(pll); +} + +static void clk_pll1_unprepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + +} + +static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, ref, divr1, divf1, divr2, divf2; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + switch (FIELD_GET(PLL_REF_MASK, val)) { + case 0: + ref = OSC_25M; +
[PATCH v13 5/5] clk: imx: Add clock driver for i.MX8MQ CCM
Add driver for the Clock Control Module found on i.MX8MQ. Signed-off-by: Anson Huang Signed-off-by: Bai Ping Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mq.c | 589 +++ drivers/clk/imx/clk.h| 36 +++ 3 files changed, 626 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mq.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 237444b..6952f05 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 000..26b57f4 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * Copyright (C) 2017 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai4; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_dcss; +static u32 share_count_nand; + +static struct clk *clks[IMX8MQ_CLK_END]; + +static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; + +static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", }; + +static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", + "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",}; + +static const char *imx8mq_enet_axi_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_200m", "audio_pll1_out", "video_pll1_out", "sys3_pll2_out&q
[PATCH v13 4/5] clk: imx: Add imx composite clock
Since a lot of clocks on imx8m are formed by a mux, gate, predivider and divider, the idea here is to combine all of those into one composite clock, but we need to deal with both predivider and divider at the same time and therefore we add the imx8m_clk_composite_divider_ops and register the composite clock with those. Signed-off-by: Abel Vesa Suggested-by: Sascha Hauer Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-composite-8m.c | 178 + drivers/clk/imx/clk.h | 16 3 files changed, 195 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-8m.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b87513c..237444b 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -3,6 +3,7 @@ obj-y += \ clk.o \ clk-busy.o \ + clk-composite-8m.o \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c new file mode 100644 index 000..bcd31d8 --- /dev/null +++ b/drivers/clk/imx/clk-composite-8m.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +#include +#include +#include + +#include "clk.h" + +#define PCG_PREDIV_SHIFT 16 +#define PCG_PREDIV_WIDTH 3 +#define PCG_PREDIV_MAX 8 + +#define PCG_DIV_SHIFT 0 +#define PCG_DIV_WIDTH 6 +#define PCG_DIV_MAX64 + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 + +#define PCG_CGC_SHIFT 28 + +static unsigned long imx8m_clk_composite_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long prediv_rate; + unsigned int prediv_value; + unsigned int div_value; + + prediv_value = readl(divider->reg) >> divider->shift; + prediv_value &= clk_div_mask(divider->width); + + prediv_rate = divider_recalc_rate(hw, parent_rate, prediv_value, + NULL, divider->flags, + divider->width); + + div_value = readl(divider->reg) >> PCG_DIV_SHIFT; + div_value &= clk_div_mask(PCG_DIV_WIDTH); + + return divider_recalc_rate(hw, prediv_rate, div_value, NULL, + divider->flags, PCG_DIV_WIDTH); +} + +static int imx8m_clk_composite_compute_dividers(unsigned long rate, + unsigned long parent_rate, + int *prediv, int *postdiv) +{ + int div1, div2; + int error = INT_MAX; + int ret = -EINVAL; + + *prediv = 1; + *postdiv = 1; + + for (div1 = 1; div1 <= PCG_PREDIV_MAX; div1++) { + for (div2 = 1; div2 <= PCG_DIV_MAX; div2++) { + int new_error = ((parent_rate / div1) / div2) - rate; + + if (abs(new_error) < abs(error)) { + *prediv = div1; + *postdiv = div2; + error = new_error; + ret = 0; + } + } + } + return ret; +} + +static long imx8m_clk_composite_divider_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + int prediv_value; + int div_value; + + imx8m_clk_composite_compute_dividers(rate, *prate, + &prediv_value, &div_value); + rate = DIV_ROUND_UP(*prate, prediv_value); + + return DIV_ROUND_UP(rate, div_value); + +} + +static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + int prediv_value; + int div_value; + int ret = 0; + u32 val; + + ret = imx8m_clk_composite_compute_dividers(rate, parent_rate, + &prediv_value, &div_value); + if (ret) + return -EINVAL; + + spin_lock_irqsave(divider->lock, flags); + + val = readl(divider->reg); + val &= ~((clk_div_mask(divider->width) << divider->shift) | + (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + + val |= (u32)(prediv_value - 1) << divider->shift; + val |= (u32)(div_value - 1) << PCG_DIV_SHIFT; + writel(val, divider
[PATCH v5 0/6] Add basic support for i.MX8MQ SoC and i.MX8MQ EVK board
Took this from Lucas since he's busy with some other work for the moment and I thought we might be able to get this ready for the merge window. Basically is just a respin with a minor fix for a comment from Rob. Lucas, thanks for all the effort with this. Changes since v5: * replaced the name of the node peripherals with soc in dts file Baruch Siach (2): arm64: dts: imx8mq: add watchdog devices arm64: dts: imx8mq-evk: enable watchdog Lucas Stach (4): arm64: add basic Kconfig symbols for i.MX8 arm64: add basic DTS for i.MX8MQ arm64: add support for i.MX8M EVK board MAINTAINERS: add i.MX8 DT path to i.MX architecture Documentation/devicetree/bindings/arm/fsl.txt | 8 + MAINTAINERS| 1 + arch/arm64/Kconfig.platforms | 14 + arch/arm64/boot/dts/freescale/Makefile | 2 + arch/arm64/boot/dts/freescale/imx8mq-evk.dts | 303 arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h | 623 + arch/arm64/boot/dts/freescale/imx8mq.dtsi | 416 + 7 files changed, 1367 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mq-evk.dts create mode 100644 arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h create mode 100644 arch/arm64/boot/dts/freescale/imx8mq.dtsi -- 2.7.4
[PATCH v5 1/6] arm64: add basic Kconfig symbols for i.MX8
From: Lucas Stach Add basic Kconfig symbols to make the MXC architecture available in the ARM64 world. Signed-off-by: Lucas Stach Reviewed-by: Fabio Estevam --- arch/arm64/Kconfig.platforms | 14 ++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 28f0521..7e1545a 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -142,6 +142,20 @@ config ARCH_MVEBU - Armada 7K SoC Family - Armada 8K SoC Family +config ARCH_MXC + bool "ARMv8 based NXP i.MX SoC family" + help + This enables support for the ARMv8 based SoCs in the + NXP i.MX family. + +config SOC_IMX8MQ + bool "i.MX8MQ support" + depends on ARCH_MXC + select ARM64_ERRATUM_843419 + select ARM64_ERRATUM_845719 + help + This enables support for the i.MX8MQ SoC. + config ARCH_QCOM bool "Qualcomm Platforms" select GPIOLIB -- 2.7.4
[PATCH v5 4/6] MAINTAINERS: add i.MX8 DT path to i.MX architecture
From: Lucas Stach Shawn agreed to take patches for the i.MX8 parts through his tree. Signed-off-by: Lucas Stach Reviewed-by: Dong Aisheng --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3625a8d..b41ebff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1530,6 +1530,7 @@ F:arch/arm/mach-imx/ F: arch/arm/mach-mxs/ F: arch/arm/boot/dts/imx* F: arch/arm/configs/imx*_defconfig +F: arch/arm64/boot/dts/freescale/imx* F: drivers/clk/imx/ F: drivers/firmware/imx/ F: drivers/soc/imx/ -- 2.7.4
[PATCH v5 2/6] arm64: add basic DTS for i.MX8MQ
From: Lucas Stach This adds the basic DTS for the i.MX8MQ. For now only the following peripherals are supported: - IOMUXC (pin controller) - CCM (clock controller) - GPIO - UART - uSDHC (SD/eMMC controller) - FEC (ethernet controller) - i2c This is enough to get a very basic board support up and running. One known limitation is that the driver for the GPC interrupt controller is still missing, rendering the CPU sleep states unusable as there is nothing waking them up anymore. Signed-off-by: Lucas Stach Reviewed-by: Dong Aisheng --- Documentation/devicetree/bindings/arm/fsl.txt | 4 + arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h | 623 + arch/arm64/boot/dts/freescale/imx8mq.dtsi | 392 3 files changed, 1019 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h create mode 100644 arch/arm64/boot/dts/freescale/imx8mq.dtsi diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt index 1ac461ae..9f4aba2 100644 --- a/Documentation/devicetree/bindings/arm/fsl.txt +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -131,6 +131,10 @@ i.MX7ULP generic board Required root node properties: - compatible = "fsl,imx7ulp"; +i.MX8MQ generic board +Required root node properties: +- compatible = "fsl,imx8mq"; + Freescale Vybrid Platform Device Tree Bindings -- diff --git a/arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h b/arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h new file mode 100644 index 000..b94b020 --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mq-pinfunc.h @@ -0,0 +1,623 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DTS_IMX8MQ_PINFUNC_H +#define __DTS_IMX8MQ_PINFUNC_H + +/* + * The pin function ID is a tuple of + * + */ + +#define MX8MQ_IOMUXC_PMIC_STBY_REQ_CCMSRCGPCMIX_PMIC_STBY_REQ 0x014 0x27C 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_PMIC_ON_REQ_SNVSMIX_PMIC_ON_REQ 0x018 0x280 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_ONOFF_SNVSMIX_ONOFF 0x01C 0x284 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_POR_B_SNVSMIX_POR_B 0x020 0x288 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_RTC_RESET_B_SNVSMIX_RTC_RESET_B 0x024 0x28C 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO00_GPIO1_IO0 0x028 0x290 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO00_CCMSRCGPCMIX_ENET_PHY_REF_CLK_ROOT 0x028 0x290 0x4C0 0x1 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO00_ANAMIX_REF_CLK_32K 0x028 0x290 0x000 0x5 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO00_CCMSRCGPCMIX_EXT_CLK1 0x028 0x290 0x000 0x6 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO00_SJC_FAIL 0x028 0x290 0x000 0x7 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO01_GPIO1_IO1 0x02C 0x294 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO01_PWM1_OUT 0x02C 0x294 0x000 0x1 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO01_ANAMIX_REF_CLK_24M 0x02C 0x294 0x4BC 0x5 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO01_CCMSRCGPCMIX_EXT_CLK2 0x02C 0x294 0x000 0x6 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO01_SJC_ACTIVE 0x02C 0x294 0x000 0x7 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO02_GPIO1_IO2 0x030 0x298 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0x030 0x298 0x000 0x1 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_ANY 0x030 0x298 0x000 0x5 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO02_SJC_DE_B 0x030 0x298 0x000 0x7 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO03_GPIO1_IO3 0x034 0x29C 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO03_USDHC1_VSELECT 0x034 0x29C 0x000 0x1 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO03_SDMA1_EXT_EVENT0 0x034 0x29C 0x000 0x5 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO03_ANAMIX_XTAL_OK 0x034 0x29C 0x000 0x6 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO03_SJC_DONE 0x034 0x29C 0x000 0x7 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO04_GPIO1_IO4 0x038 0x2A0 0x000 0x0 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0x038 0x2A0 0x000 0x1 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO04_SDMA1_EXT_EVENT1 0x038 0x2A0 0x000 0x5 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO04_ANAMIX_XTAL_OK_LV 0x038 0x2A0 0x000 0x6 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO04_USDHC1_TEST_TRIG 0x038 0x2A0 0x000 0x7 0x0 +#define MX8MQ_IOMUXC_GPIO1_IO05_
[PATCH v5 5/6] arm64: dts: imx8mq: add watchdog devices
From: Baruch Siach Signed-off-by: Baruch Siach Signed-off-by: Lucas Stach --- arch/arm64/boot/dts/freescale/imx8mq.dtsi | 24 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi index 3703bca..8e9d6d5 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi @@ -228,6 +228,30 @@ "clk_ext1", "clk_ext2", "clk_ext3", "clk_ext4"; }; + + wdog1: watchdog@3028 { + compatible = "fsl,imx8mq-wdt", "fsl,imx21-wdt"; + reg = <0x3028 0x1>; + interrupts = ; + clocks = <&clk IMX8MQ_CLK_WDOG1_ROOT>; + status = "disabled"; + }; + + wdog2: watchdog@3029 { + compatible = "fsl,imx8mq-wdt", "fsl,imx21-wdt"; + reg = <0x3029 0x1>; + interrupts = ; + clocks = <&clk IMX8MQ_CLK_WDOG2_ROOT>; + status = "disabled"; + }; + + wdog3: watchdog@302a { + compatible = "fsl,imx8mq-wdt", "fsl,imx21-wdt"; + reg = <0x302a 0x1>; + interrupts = ; + clocks = <&clk IMX8MQ_CLK_WDOG3_ROOT>; + status = "disabled"; + }; }; bus@3040 { /* AIPS2 */ -- 2.7.4
[PATCH v5 3/6] arm64: add support for i.MX8M EVK board
From: Lucas Stach This is the evaluation kit board for the i.MX8M. The current level of support yields a working console and is able to boot userspace from SD card or Network. Signed-off-by: Lucas Stach Reviewed-by: Fabio Estevam (v1) Reviewed-by: Rob Herring (v3) Tested-by: Tested-by: Baruch Siach (v1) Reviewed-by: Dong Aisheng --- Documentation/devicetree/bindings/arm/fsl.txt | 4 + arch/arm64/boot/dts/freescale/Makefile| 2 + arch/arm64/boot/dts/freescale/imx8mq-evk.dts | 290 ++ 3 files changed, 296 insertions(+) create mode 100644 arch/arm64/boot/dts/freescale/imx8mq-evk.dts diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt index 9f4aba2..71b78ff 100644 --- a/Documentation/devicetree/bindings/arm/fsl.txt +++ b/Documentation/devicetree/bindings/arm/fsl.txt @@ -105,6 +105,10 @@ i.MX7ULP Evaluation Kit Required root node properties: - compatible = "fsl,imx7ulp-evk", "fsl,imx7ulp"; +i.MX8MQ Evaluation Kit +Required root node properties: +- compatible = "fsl,imx8mq-evk", "fsl,imx8mq"; + Generic i.MX boards --- diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 7748e6d..0001361 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -18,3 +18,5 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-rdb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb + +dtb-$(CONFIG_SOC_IMX8MQ) += imx8mq-evk.dtb diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts new file mode 100644 index 000..04ce13f --- /dev/null +++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2017 NXP + * Copyright (C) 2017-2018 Pengutronix, Lucas Stach + */ + +/dts-v1/; + +#include "imx8mq.dtsi" + +/ { + model = "NXP i.MX8MQ EVK"; + compatible = "fsl,imx8mq-evk", "fsl,imx8mq"; + + chosen { + stdout-path = &uart1; + }; + + memory@4000 { + device_type = "memory"; + reg = <0x 0x4000 0 0xc000>; + }; + + reg_usdhc2_vmmc: regulator-vsd-3v3 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_reg_usdhc2>; + compatible = "regulator-fixed"; + regulator-name = "VSD_3V3"; + regulator-min-microvolt = <330>; + regulator-max-microvolt = <330>; + gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + phy-mode = "rgmii-id"; + status = "okay"; +}; + +&i2c1 { + clock-frequency = <10>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1>; + status = "okay"; + + pmic@8 { + compatible = "fsl,pfuze100"; + reg = <0x8>; + + regulators { + sw1a_reg: sw1ab { + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <110>; + }; + + sw1c_reg: sw1c { + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <110>; + }; + + sw2_reg: sw2 { + regulator-min-microvolt = <110>; + regulator-max-microvolt = <110>; + regulator-always-on; + }; + + sw3a_reg: sw3ab { + regulator-min-microvolt = <825000>; + regulator-max-microvolt = <110>; + regulator-always-on; + }; + + sw4_reg: sw4 { + regulator-min-microvolt = <180>; + regulator-max-microvolt = <180>; + regulator-always-on; + }; + + swbst_reg: swbst { + regulator-min-microvolt = <500>; + regulator-max-microvolt = <515>; + }; + + snvs_reg: vsnvs { + regulator-min-microvolt = <100>; + regulator-max-microvolt = <300>; + regulator-always-on; + }; + + vref_reg: vrefddr { + regulator-always-on; +
[PATCH v5 6/6] arm64: dts: imx8mq-evk: enable watchdog
From: Baruch Siach The external nWDOG signal connects to the EVK board reset circuit. Tested on the i.MX8MQ EVK rev B3. Signed-off-by: Baruch Siach Signed-off-by: Lucas Stach --- arch/arm64/boot/dts/freescale/imx8mq-evk.dts | 13 + 1 file changed, 13 insertions(+) diff --git a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts index 04ce13f..64a 100644 --- a/arch/arm64/boot/dts/freescale/imx8mq-evk.dts +++ b/arch/arm64/boot/dts/freescale/imx8mq-evk.dts @@ -160,6 +160,13 @@ status = "okay"; }; +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + &iomuxc { pinctrl_fec1: fec1grp { fsl,pins = < @@ -287,4 +294,10 @@ MX8MQ_IOMUXC_GPIO1_IO04_USDHC2_VSELECT 0xc1 >; }; + + pinctrl_wdog: wdog1grp { + fsl,pins = < + MX8MQ_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B0xc6 + >; + }; }; -- 2.7.4
[PATCH v15 4/5] clk: imx: Add imx composite clock
Since a lot of clocks on imx8m are formed by a mux, gate, predivider and divider, the idea here is to combine all of those into one composite clock, but we need to deal with both predivider and divider at the same time and therefore we add the imx8m_clk_composite_divider_ops and register the composite clock with those. Signed-off-by: Abel Vesa Suggested-by: Sascha Hauer Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-composite-8m.c | 178 + drivers/clk/imx/clk.h | 16 3 files changed, 195 insertions(+) create mode 100644 drivers/clk/imx/clk-composite-8m.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b87513c..237444b 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -3,6 +3,7 @@ obj-y += \ clk.o \ clk-busy.o \ + clk-composite-8m.o \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c new file mode 100644 index 000..6d9d371 --- /dev/null +++ b/drivers/clk/imx/clk-composite-8m.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +#include +#include +#include + +#include "clk.h" + +#define PCG_PREDIV_SHIFT 16 +#define PCG_PREDIV_WIDTH 3 +#define PCG_PREDIV_MAX 8 + +#define PCG_DIV_SHIFT 0 +#define PCG_DIV_WIDTH 6 +#define PCG_DIV_MAX64 + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 + +#define PCG_CGC_SHIFT 28 + +static unsigned long imx8m_clk_composite_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long prediv_rate; + unsigned int prediv_value; + unsigned int div_value; + + prediv_value = readl(divider->reg) >> divider->shift; + prediv_value &= clk_div_mask(divider->width); + + prediv_rate = divider_recalc_rate(hw, parent_rate, prediv_value, + NULL, divider->flags, + divider->width); + + div_value = readl(divider->reg) >> PCG_DIV_SHIFT; + div_value &= clk_div_mask(PCG_DIV_WIDTH); + + return divider_recalc_rate(hw, prediv_rate, div_value, NULL, + divider->flags, PCG_DIV_WIDTH); +} + +static int imx8m_clk_composite_compute_dividers(unsigned long rate, + unsigned long parent_rate, + int *prediv, int *postdiv) +{ + int div1, div2; + int error = INT_MAX; + int ret = -EINVAL; + + *prediv = 1; + *postdiv = 1; + + for (div1 = 1; div1 <= PCG_PREDIV_MAX; div1++) { + for (div2 = 1; div2 <= PCG_DIV_MAX; div2++) { + int new_error = ((parent_rate / div1) / div2) - rate; + + if (abs(new_error) < abs(error)) { + *prediv = div1; + *postdiv = div2; + error = new_error; + ret = 0; + } + } + } + return ret; +} + +static long imx8m_clk_composite_divider_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + int prediv_value; + int div_value; + + imx8m_clk_composite_compute_dividers(rate, *prate, + &prediv_value, &div_value); + rate = DIV_ROUND_UP(*prate, prediv_value); + + return DIV_ROUND_UP(rate, div_value); + +} + +static int imx8m_clk_composite_divider_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned long flags = 0; + int prediv_value; + int div_value; + int ret = 0; + u32 val; + + ret = imx8m_clk_composite_compute_dividers(rate, parent_rate, + &prediv_value, &div_value); + if (ret) + return -EINVAL; + + spin_lock_irqsave(divider->lock, flags); + + val = readl(divider->reg); + val &= ~((clk_div_mask(divider->width) << divider->shift) | + (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + + val |= (u32)(prediv_value - 1) << divider->shift; + val |= (u32)(div_value - 1) << PCG_DIV_SHIFT; + writel(val, divider
[PATCH v15 5/5] clk: imx: Add clock driver for i.MX8MQ CCM
Add driver for the Clock Control Module found on i.MX8MQ. Signed-off-by: Anson Huang Signed-off-by: Bai Ping Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mq.c | 589 +++ drivers/clk/imx/clk.h| 36 +++ 3 files changed, 626 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mq.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 237444b..6952f05 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -29,4 +29,5 @@ obj-$(CONFIG_SOC_IMX6SLL) += clk-imx6sll.o obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o +obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 000..26b57f4 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,589 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * Copyright (C) 2017 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai4; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_dcss; +static u32 share_count_nand; + +static struct clk *clks[IMX8MQ_CLK_END]; + +static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; + +static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", }; + +static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", + "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",}; + +static const char *imx8mq_enet_axi_sels[] = {"osc_25m", "sys1_pll_266m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_200m", "audio_pll1_out", "video_pll1_out", "sys3_pll2_out&q
[PATCH v15 0/5] Add i.MX8MQ clock driver
Unfortunately, there was a problem with some divisions by 64-bit values in the Fractional PLL which led to a link failuire on arm32. That has been fixed now without any kind of functionality changes. Though the v14 has made it to clk-next, due to the arm32 build failure, this patch series had to be dropped until the failure gets fixed. Stephen, please take this in one more time and sorry for all the trouble caused by this series. Thanks for all the support. Here is a link to the 14th version: https://lkml.org/lkml/2018/11/29/767 Changes since v14: * fixed all the divisions by 64-bit by replacing with do_divs in clk-frac-pll Abel Vesa (2): clk: imx: Add imx composite clock clk: imx: Add clock driver for i.MX8MQ CCM Lucas Stach (3): dt-bindings: Add binding for i.MX8MQ CCM clk: imx: Add fractional PLL output clock clk: imx: Add SCCG PLL type .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-composite-8m.c | 178 +++ drivers/clk/imx/clk-frac-pll.c | 232 drivers/clk/imx/clk-imx8mq.c | 589 + drivers/clk/imx/clk-sccg-pll.c | 256 + drivers/clk/imx/clk.h | 64 +++ include/dt-bindings/clock/imx8mq-clock.h | 395 ++ 8 files changed, 1739 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 drivers/clk/imx/clk-composite-8m.c create mode 100644 drivers/clk/imx/clk-frac-pll.c create mode 100644 drivers/clk/imx/clk-imx8mq.c create mode 100644 drivers/clk/imx/clk-sccg-pll.c create mode 100644 include/dt-bindings/clock/imx8mq-clock.h -- 2.7.4
[PATCH v15 3/5] clk: imx: Add SCCG PLL type
From: Lucas Stach The SCCG is a new PLL type introduced on i.MX8. The description of this SCCG clock can be found here: https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-sccg-pll.c | 256 + drivers/clk/imx/clk.h | 9 ++ 3 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-sccg-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4893c1f..b87513c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pfd.o + clk-pfd.o \ + clk-sccg-pll.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c new file mode 100644 index 000..ee7752b --- /dev/null +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + * + * This driver supports the SCCG plls found in the imx8m SOCs + * + * Documentation for this SCCG pll can be found at: + * https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +/* PLL CFGs */ +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 +#define PLL_CFG2 0x8 + +#define PLL_DIVF1_MASK GENMASK(18, 13) +#define PLL_DIVF2_MASK GENMASK(12, 7) +#define PLL_DIVR1_MASK GENMASK(27, 25) +#define PLL_DIVR2_MASK GENMASK(24, 19) +#define PLL_REF_MASK GENMASK(2, 0) + +#define PLL_LOCK_MASK BIT(31) +#define PLL_PD_MASKBIT(7) + +#define OSC_25M2500 +#define OSC_27M2700 + +#define PLL_SCCG_LOCK_TIMEOUT 70 + +struct clk_sccg_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) + +static int clk_pll_wait_lock(struct clk_sccg_pll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK, 0, + PLL_SCCG_LOCK_TIMEOUT); +} + +static int clk_pll1_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, divf; + + val = readl_relaxed(pll->base + PLL_CFG2); + divf = FIELD_GET(PLL_DIVF1_MASK, val); + + return parent_rate * 2 * (divf + 1); +} + +static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 div; + + if (!parent_rate) + return 0; + + div = rate / (parent_rate * 2); + + return parent_rate * div * 2; +} + +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + u32 divf; + + if (!parent_rate) + return -EINVAL; + + divf = rate / (parent_rate * 2); + + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~PLL_DIVF1_MASK; + val |= FIELD_PREP(PLL_DIVF1_MASK, divf - 1); + writel_relaxed(val, pll->base + PLL_CFG2); + + return clk_pll_wait_lock(pll); +} + +static int clk_pll1_prepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_pll_wait_lock(pll); +} + +static void clk_pll1_unprepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + +} + +static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, ref, divr1, divf1, divr2, divf2; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + switch (FIELD_GET(PLL_REF_MASK, val)) { + case 0: + ref = OSC_25M; +
[PATCH v15 2/5] clk: imx: Add fractional PLL output clock
From: Lucas Stach This is a new fractional clock type introduced on i.MX8. The description of this fractional clock can be found here: https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Sascha Hauer --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-frac-pll.c | 232 + drivers/clk/imx/clk.h | 3 + 3 files changed, 236 insertions(+) create mode 100644 drivers/clk/imx/clk-frac-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..4893c1f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -6,6 +6,7 @@ obj-y += \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ + clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pllv1.o \ diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 000..0026c39 --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * + * This driver supports the fractional plls found in the imx8m SOCs + * + * Documentation for this fractional pll can be found at: + * https://www.nxp.com/docs/en/reference-manual/IMX8MDQLQRM.pdf#page=834 + */ + +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUSBIT(31) +#define PLL_PD_MASKBIT(19) +#define PLL_BYPASS_MASKBIT(14) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK GENMASK(30, 7) +#define PLL_INT_DIV_MASK GENMASK(6, 0) +#define PLL_OUTPUT_DIV_MASKGENMASK(4, 0) +#define PLL_FRAC_DENOM 0x100 + +#define PLL_FRAC_LOCK_TIMEOUT 1 +#define PLL_FRAC_ACK_TIMEOUT 50 + +struct clk_frac_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_STATUS, 0, + PLL_FRAC_LOCK_TIMEOUT); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + return readl_poll_timeout(pll->base, val, val & PLL_NEWDIV_ACK, 0, + PLL_FRAC_ACK_TIMEOUT); +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val, divff, divfi, divq; + u64 temp64 = parent_rate; + u64 rate; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = (FIELD_GET(PLL_OUTPUT_DIV_MASK, val) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = FIELD_GET(PLL_FRAC_DIV_MASK, val); + divfi = FIELD_GET(PLL_INT_DIV_MASK, val); + + temp64 *= 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + do_div(temp64, divq); + + rate = parent_rate * 8 * (divfi + 1); + do_div(rate, divq); + rate += temp64; + + return rate; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u64 parent_rate = *prate; + u32 divff, divfi; + u64 temp64; + + parent_rate *= 8; + rate *= 2; + temp64 = rate; + do_div(temp64, parent_rate); + divfi = temp64; + temp64 = rate - divfi * parent_rate; + temp64 *= PLL_FRAC_DENOM; + do_div(temp64, parent_rate); + divff = temp64; + + temp64 = parent_rat
[PATCH v15 1/5] dt-bindings: Add binding for i.MX8MQ CCM
From: Lucas Stach This adds the binding for the i.MX8MQ Clock Controller Module. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Rob Herring --- .../devicetree/bindings/clock/imx8mq-clock.txt | 20 ++ include/dt-bindings/clock/imx8mq-clock.h | 395 + 2 files changed, 415 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 include/dt-bindings/clock/imx8mq-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt new file mode 100644 index 000..52de826 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt @@ -0,0 +1,20 @@ +* Clock bindings for NXP i.MX8M Quad + +Required properties: +- compatible: Should be "fsl,imx8mq-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include the following entries: +- "ckil" +- "osc_25m" +- "osc_27m" +- "clk_ext1" +- "clk_ext2" +- "clk_ext3" +- "clk_ext4" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h +for the full list of i.MX8M Quad clock IDs. diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h new file mode 100644 index 000..b53be41 --- /dev/null +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -0,0 +1,395 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MQ_H +#define __DT_BINDINGS_CLOCK_IMX8MQ_H + +#define IMX8MQ_CLK_DUMMY 0 +#define IMX8MQ_CLK_32K 1 +#define IMX8MQ_CLK_25M 2 +#define IMX8MQ_CLK_27M 3 +#define IMX8MQ_CLK_EXT14 +#define IMX8MQ_CLK_EXT25 +#define IMX8MQ_CLK_EXT36 +#define IMX8MQ_CLK_EXT47 + +/* ANAMIX PLL clocks */ +/* FRAC PLLs */ +/* ARM PLL */ +#define IMX8MQ_ARM_PLL_REF_SEL 8 +#define IMX8MQ_ARM_PLL_REF_DIV 9 +#define IMX8MQ_ARM_PLL 10 +#define IMX8MQ_ARM_PLL_BYPASS 11 +#define IMX8MQ_ARM_PLL_OUT 12 + +/* GPU PLL */ +#define IMX8MQ_GPU_PLL_REF_SEL 13 +#define IMX8MQ_GPU_PLL_REF_DIV 14 +#define IMX8MQ_GPU_PLL 15 +#define IMX8MQ_GPU_PLL_BYPASS 16 +#define IMX8MQ_GPU_PLL_OUT 17 + +/* VPU PLL */ +#define IMX8MQ_VPU_PLL_REF_SEL 18 +#define IMX8MQ_VPU_PLL_REF_DIV 19 +#define IMX8MQ_VPU_PLL 20 +#define IMX8MQ_VPU_PLL_BYPASS 21 +#define IMX8MQ_VPU_PLL_OUT 22 + +/* AUDIO PLL1 */ +#define IMX8MQ_AUDIO_PLL1_REF_SEL 23 +#define IMX8MQ_AUDIO_PLL1_REF_DIV 24 +#define IMX8MQ_AUDIO_PLL1 25 +#define IMX8MQ_AUDIO_PLL1_BYPASS 26 +#define IMX8MQ_AUDIO_PLL1_OUT 27 + +/* AUDIO PLL2 */ +#define IMX8MQ_AUDIO_PLL2_REF_SEL 28 +#define IMX8MQ_AUDIO_PLL2_REF_DIV 29 +#define IMX8MQ_AUDIO_PLL2 30 +#define IMX8MQ_AUDIO_PLL2_BYPASS 31 +#define IMX8MQ_AUDIO_PLL2_OUT 32 + +/* VIDEO PLL1 */ +#define IMX8MQ_VIDEO_PLL1_REF_SEL 33 +#define IMX8MQ_VIDEO_PLL1_REF_DIV 34 +#define IMX8MQ_VIDEO_PLL1 35 +#define IMX8MQ_VIDEO_PLL1_BYPASS 36 +#define IMX8MQ_VIDEO_PLL1_OUT 37 + +/* SYS1 PLL */ +#define IMX8MQ_SYS1_PLL1_REF_SEL 38 +#define IMX8MQ_SYS1_PLL1_REF_DIV 39 +#define IMX8MQ_SYS1_PLL1 40 +#define IMX8MQ_SYS1_PLL1_OUT 41 +#define IMX8MQ_SYS1_PLL1_OUT_DIV 42 +#define IMX8MQ_SYS1_PLL2 43 +#define IMX8MQ_SYS1_PLL2_DIV 44 +#define IMX8MQ_SYS1_PLL2_OUT 45 + +/* SYS2 PLL */ +#define IMX8MQ_SYS2_PLL1_REF_SEL 46 +#define IMX8MQ_SYS2_PLL1_REF_DIV 47 +#define IMX8MQ_SYS2_PLL1 48 +#define IMX8MQ_SYS2_PLL1_OUT 49 +#define IMX8MQ_SYS2_PLL1_OUT_DIV 50 +#define IMX8MQ_SYS2_PLL2 51 +#define IMX8MQ_SYS2_PLL2_DIV 52 +#define IMX8MQ_SYS2_PLL2_OUT 53 + +/* SYS3 PLL */ +#define IMX8MQ_SYS3_PLL1_REF_SEL 54 +#define IMX8MQ_SYS3_PLL1_REF_DIV 55 +#define IMX8MQ_SYS3_PLL1 56 +#define IMX8MQ_SYS3_PLL1_OUT 57 +#define IMX8MQ_SYS3_PLL1_OUT_DIV 58 +#define IMX8MQ_SYS3_PLL2 59 +#define IMX8MQ_SYS3_PLL2_DIV 60 +#define IMX8MQ_SYS3_PLL2_OUT 61 + +/* DRAM PLL */ +#define IMX8MQ_DRAM_PLL1_REF_SEL 62 +#define IMX8MQ_DRAM_PLL1_REF_DIV 63 +#define IMX8MQ_DRAM_PLL1 64 +#define IMX8MQ
[PATCH v6 2/2] pinctrl: imx: add driver for i.MX8MQ
From: Lucas Stach The i.MX8MQ pincontrol works in a similar way to the earlier i.MX SoCs. This driver builds on top of the imx specific pinconf handling. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Acked-by: Dong Aisheng --- drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx8mq.c | 351 + 3 files changed, 359 insertions(+) create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8mq.c diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 0d8ba1e..dccf64c 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -117,6 +117,13 @@ config PINCTRL_IMX7ULP help Say Y here to enable the imx7ulp pinctrl driver +config PINCTRL_IMX8MQ + bool "IMX8MQ pinctrl driver" + depends on SOC_IMX8MQ + select PINCTRL_IMX + help + Say Y here to enable the imx8mq pinctrl driver + config PINCTRL_VF610 bool "Freescale Vybrid VF610 pinctrl driver" depends on SOC_VF610 diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 368be8c..73175b3 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o obj-$(CONFIG_PINCTRL_IMX7D)+= pinctrl-imx7d.o obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o +obj-$(CONFIG_PINCTRL_IMX8MQ) += pinctrl-imx8mq.o obj-$(CONFIG_PINCTRL_VF610)+= pinctrl-vf610.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_IMX23)+= pinctrl-imx23.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mq.c b/drivers/pinctrl/freescale/pinctrl-imx8mq.c new file mode 100644 index 000..8d39af5 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx8mq.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + * Copyright (C) 2018 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx8mq_pads { + MX8MQ_PAD_RESERVE0 = 0, + MX8MQ_PAD_RESERVE1 = 1, + MX8MQ_PAD_RESERVE2 = 2, + MX8MQ_PAD_RESERVE3 = 3, + MX8MQ_PAD_RESERVE4 = 4, + MX8MQ_IOMUXC_PMIC_STBY_REQ_CCMSRCGPCMIX = 5, + MX8MQ_IOMUXC_PMIC_ON_REQ_SNVSMIX = 6, + MX8MQ_IOMUXC_ONOFF_SNVSMIX = 7, + MX8MQ_IOMUXC_POR_B_SNVSMIX = 8, + MX8MQ_IOMUXC_RTC_RESET_B_SNVSMIX = 9, + MX8MQ_IOMUXC_GPIO1_IO00 = 10, + MX8MQ_IOMUXC_GPIO1_IO01 = 11, + MX8MQ_IOMUXC_GPIO1_IO02 = 12, + MX8MQ_IOMUXC_GPIO1_IO03 = 13, + MX8MQ_IOMUXC_GPIO1_IO04 = 14, + MX8MQ_IOMUXC_GPIO1_IO05 = 15, + MX8MQ_IOMUXC_GPIO1_IO06 = 16, + MX8MQ_IOMUXC_GPIO1_IO07 = 17, + MX8MQ_IOMUXC_GPIO1_IO08 = 18, + MX8MQ_IOMUXC_GPIO1_IO09 = 19, + MX8MQ_IOMUXC_GPIO1_IO10 = 20, + MX8MQ_IOMUXC_GPIO1_IO11 = 21, + MX8MQ_IOMUXC_GPIO1_IO12 = 22, + MX8MQ_IOMUXC_GPIO1_IO13 = 23, + MX8MQ_IOMUXC_GPIO1_IO14 = 24, + MX8MQ_IOMUXC_GPIO1_IO15 = 25, + MX8MQ_IOMUXC_ENET_MDC = 26, + MX8MQ_IOMUXC_ENET_MDIO = 27, + MX8MQ_IOMUXC_ENET_TD3 = 28, + MX8MQ_IOMUXC_ENET_TD2 = 29, + MX8MQ_IOMUXC_ENET_TD1 = 30, + MX8MQ_IOMUXC_ENET_TD0 = 31, + MX8MQ_IOMUXC_ENET_TX_CTL = 32, + MX8MQ_IOMUXC_ENET_TXC = 33, + MX8MQ_IOMUXC_ENET_RX_CTL = 34, + MX8MQ_IOMUXC_ENET_RXC = 35, + MX8MQ_IOMUXC_ENET_RD0 = 36, + MX8MQ_IOMUXC_ENET_RD1 = 37, + MX8MQ_IOMUXC_ENET_RD2 = 38, + MX8MQ_IOMUXC_ENET_RD3 = 39, + MX8MQ_IOMUXC_SD1_CLK = 40, + MX8MQ_IOMUXC_SD1_CMD = 41, + MX8MQ_IOMUXC_SD1_DATA0 = 42, + MX8MQ_IOMUXC_SD1_DATA1 = 43, + MX8MQ_IOMUXC_SD1_DATA2 = 44, + MX8MQ_IOMUXC_SD1_DATA3 = 45, + MX8MQ_IOMUXC_SD1_DATA4 = 46, + MX8MQ_IOMUXC_SD1_DATA5 = 47, + MX8MQ_IOMUXC_SD1_DATA6 = 48, + MX8MQ_IOMUXC_SD1_DATA7 = 49, + MX8MQ_IOMUXC_SD1_RESET_B = 50, + MX8MQ_IOMUXC_SD1_STROBE = 51, + MX8MQ_IOMUXC_SD2_CD_B = 52, + MX8MQ_IOMUXC_SD2_CLK = 53, + MX8MQ_IOMUXC_SD2_CMD = 54, + MX8MQ_IOMUXC_SD2_DATA0 = 55, + MX8MQ_IOMUXC_SD2_DATA1 = 56, + MX8MQ_IOMUXC_SD2_DATA2 = 57, + MX8MQ_IOMUXC_SD2_DATA3 = 58, + MX8MQ_IOMUXC_SD2_RESET_B = 59, + MX8MQ_IOMUXC_SD2_WP = 60, + MX8MQ_IOMUXC_NAND_ALE = 61, + MX8MQ_IOMUXC_NAND_CE0_B = 62, + MX8MQ_IOMUXC_NAND_CE1_B = 63, + MX8MQ_IOMUXC_NAND_CE2_B = 64, + MX8MQ_IOMUXC_NAND_CE3_B = 65, + MX8MQ_IOMUXC_NAND_CLE = 66, + MX8MQ_IOMUXC_NAND_DATA00 = 67, + MX8MQ_IOMUXC_NAND_DATA01 = 68, + MX8MQ_IOMUXC_NAND_DATA02 = 69, + MX8MQ_IOMUXC_NAND_DATA03 = 70, + MX8MQ_IOMUXC_NAND_DATA04 = 71, +
[PATCH v6 0/2] pinctrl: imx: Add driver for i.MX8MQ
This is the sixth version for the patch series sent by Lucas. https://www.spinics.net/lists/devicetree/msg212752.html Fifth version can be found here: https://lkml.org/lkml/2018/6/22/501 Changes since v5: * implemented Rob's review comments related to bindings Changes since v4: * implemented all Aisheng's review comments Changes since v3: * dropped the SION generic pinconf changes * added examples to the bindings doc Changes since v2: * switch back to the 'fsl,pins' and hardcoded the config values inside the dts. * updated documentation accordingly Abel Vesa (1): dt-bindings: add binding for i.MX8MQ IOMUXC Lucas Stach (1): pinctrl: imx: add driver for i.MX8MQ .../bindings/pinctrl/fsl,imx8mq-pinctrl.txt| 36 +++ drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx8mq.c | 351 + 4 files changed, 395 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8mq.c -- 2.7.4
[PATCH v6 1/2] dt-bindings: add binding for i.MX8MQ IOMUXC
This adds the binding for the i.MX8MQ pin controller, in the same fashion as earlier i.MX SoCs. Signed-off-by: Abel Vesa Acked-by: Dong Aisheng --- .../bindings/pinctrl/fsl,imx8mq-pinctrl.txt| 36 ++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt new file mode 100644 index 000..66de750 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt @@ -0,0 +1,36 @@ +* Freescale IMX8MQ IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory +for common binding part and usage. + +Required properties: +- compatible: "fsl,imx8mq-iomuxc" +- reg: should contain the base physical address and size of the iomuxc + registers. + +Required properties in sub-nodes: +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx8mq-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX8M Quad + Reference Manual for detailed CONFIG settings. + +Examples: + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; +}; + +iomuxc: pinctrl@3033 { +compatible = "fsl,imx8mq-iomuxc"; +reg = <0x0 0x3033 0x0 0x1>; + +pinctrl_uart1: uart1grp { +fsl,pins = < +MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49 +MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49 +>; +}; +}; -- 2.7.4
[PATCH v3 3/3] pinctrl: imx: add driver for i.MX8MQ
From: Lucas Stach The i.MX8MQ pincontrol works in a similar way to the earlier i.MX SoCs. This driver builds on top of the generic pinconf handling introduced with the i.MX7ULP pinctrl driver. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx8mq.c | 356 + 3 files changed, 364 insertions(+) create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8mq.c diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 0d8ba1e..dccf64c 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -117,6 +117,13 @@ config PINCTRL_IMX7ULP help Say Y here to enable the imx7ulp pinctrl driver +config PINCTRL_IMX8MQ + bool "IMX8MQ pinctrl driver" + depends on SOC_IMX8MQ + select PINCTRL_IMX + help + Say Y here to enable the imx8mq pinctrl driver + config PINCTRL_VF610 bool "Freescale Vybrid VF610 pinctrl driver" depends on SOC_VF610 diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 368be8c..73175b3 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o obj-$(CONFIG_PINCTRL_IMX7D)+= pinctrl-imx7d.o obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o +obj-$(CONFIG_PINCTRL_IMX8MQ) += pinctrl-imx8mq.o obj-$(CONFIG_PINCTRL_VF610)+= pinctrl-vf610.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_IMX23)+= pinctrl-imx23.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mq.c b/drivers/pinctrl/freescale/pinctrl-imx8mq.c new file mode 100644 index 000..be2c9c2 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx8mq.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * Copyright (C) 2018 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx8mq_pads { + MX8MQ_PAD_RESERVE0 = 0, + MX8MQ_PAD_RESERVE1 = 1, + MX8MQ_PAD_RESERVE2 = 2, + MX8MQ_PAD_RESERVE3 = 3, + MX8MQ_PAD_RESERVE4 = 4, + MX8MQ_IOMUXC_PMIC_STBY_REQ_CCMSRCGPCMIX = 5, + MX8MQ_IOMUXC_PMIC_ON_REQ_SNVSMIX = 6, + MX8MQ_IOMUXC_ONOFF_SNVSMIX = 7, + MX8MQ_IOMUXC_POR_B_SNVSMIX = 8, + MX8MQ_IOMUXC_RTC_RESET_B_SNVSMIX = 9, + MX8MQ_IOMUXC_GPIO1_IO00 = 10, + MX8MQ_IOMUXC_GPIO1_IO01 = 11, + MX8MQ_IOMUXC_GPIO1_IO02 = 12, + MX8MQ_IOMUXC_GPIO1_IO03 = 13, + MX8MQ_IOMUXC_GPIO1_IO04 = 14, + MX8MQ_IOMUXC_GPIO1_IO05 = 15, + MX8MQ_IOMUXC_GPIO1_IO06 = 16, + MX8MQ_IOMUXC_GPIO1_IO07 = 17, + MX8MQ_IOMUXC_GPIO1_IO08 = 18, + MX8MQ_IOMUXC_GPIO1_IO09 = 19, + MX8MQ_IOMUXC_GPIO1_IO10 = 20, + MX8MQ_IOMUXC_GPIO1_IO11 = 21, + MX8MQ_IOMUXC_GPIO1_IO12 = 22, + MX8MQ_IOMUXC_GPIO1_IO13 = 23, + MX8MQ_IOMUXC_GPIO1_IO14 = 24, + MX8MQ_IOMUXC_GPIO1_IO15 = 25, + MX8MQ_IOMUXC_ENET_MDC = 26, + MX8MQ_IOMUXC_ENET_MDIO = 27, + MX8MQ_IOMUXC_ENET_TD3 = 28, + MX8MQ_IOMUXC_ENET_TD2 = 29, + MX8MQ_IOMUXC_ENET_TD1 = 30, + MX8MQ_IOMUXC_ENET_TD0 = 31, + MX8MQ_IOMUXC_ENET_TX_CTL = 32, + MX8MQ_IOMUXC_ENET_TXC = 33, + MX8MQ_IOMUXC_ENET_RX_CTL = 34, + MX8MQ_IOMUXC_ENET_RXC = 35, + MX8MQ_IOMUXC_ENET_RD0 = 36, + MX8MQ_IOMUXC_ENET_RD1 = 37, + MX8MQ_IOMUXC_ENET_RD2 = 38, + MX8MQ_IOMUXC_ENET_RD3 = 39, + MX8MQ_IOMUXC_SD1_CLK = 40, + MX8MQ_IOMUXC_SD1_CMD = 41, + MX8MQ_IOMUXC_SD1_DATA0 = 42, + MX8MQ_IOMUXC_SD1_DATA1 = 43, + MX8MQ_IOMUXC_SD1_DATA2 = 44, + MX8MQ_IOMUXC_SD1_DATA3 = 45, + MX8MQ_IOMUXC_SD1_DATA4 = 46, + MX8MQ_IOMUXC_SD1_DATA5 = 47, + MX8MQ_IOMUXC_SD1_DATA6 = 48, + MX8MQ_IOMUXC_SD1_DATA7 = 49, + MX8MQ_IOMUXC_SD1_RESET_B = 50, + MX8MQ_IOMUXC_SD1_STROBE = 51, + MX8MQ_IOMUXC_SD2_CD_B = 52, + MX8MQ_IOMUXC_SD2_CLK = 53, + MX8MQ_IOMUXC_SD2_CMD = 54, + MX8MQ_IOMUXC_SD2_DATA0 = 55, + MX8MQ_IOMUXC_SD2_DATA1 = 56, + MX8MQ_IOMUXC_SD2_DATA2 = 57, + MX8MQ_IOMUXC_SD2_DATA3 = 58, + MX8MQ_IOMUXC_SD2_RESET_B = 59, + MX8MQ_IOMUXC_SD2_WP = 60, + MX8MQ_IOMUXC_NAND_ALE = 61, + MX8MQ_IOMUXC_NAND_CE0_B = 62, + MX8MQ_IOMUXC_NAND_CE1_B = 63, + MX8MQ_IOMUXC_NAND_CE2_B = 64, + MX8MQ_IOMUXC_NAND_CE3_B = 65, + MX8MQ_IOMUXC_NAND_CLE = 66, + MX8MQ_IOMUXC_NAND_DATA00 = 67, + MX8MQ_IOMUXC_NAND_DATA01 = 68, + MX8MQ_IOMUXC_NAND_DATA02 = 69, + MX8MQ_IOMUXC_NAND_DATA03 = 70, +
[PATCH v3 1/3] dt-bindings: add binding for i.MX8MQ IOMUXC
This adds the binding for the i.MX8MQ pin controller, in the same fashion as earlier i.MX SoCs. Signed-off-by: Abel Vesa --- .../devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt | 13 + 1 file changed, 13 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt new file mode 100644 index 000..5cf7f8a --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt @@ -0,0 +1,13 @@ +* Freescale IMX8MQ IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory +for common binding part and usage. + +Required properties: +- compatible: "fsl,imx8mq-iomuxc" +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx8mq-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX8M Quad + Reference Manual for detailed CONFIG settings. -- 2.7.4
[PATCH v3 2/3] pinctrl: imx: allow to configure SION with generic pinconf
From: Lucas Stach The SION bit force enables the input buffer, overriding the configuration driven by the muxed module. It is not located in the pad config register, but in the mux register and thus needs special handling. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/pinctrl/freescale/pinctrl-imx.c | 19 +++ drivers/pinctrl/freescale/pinctrl-imx.h | 4 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c index 1c6bb15..335edc9 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx.c @@ -26,10 +26,6 @@ #include "../pinmux.h" #include "pinctrl-imx.h" -/* The bits in CONFIG cell defined in binding doc*/ -#define IMX_NO_PAD_CTL 0x8000 /* no pin config need */ -#define IMX_PAD_SION 0x4000/* set SION */ - static inline const struct group_desc *imx_pinctrl_find_group_by_name( struct pinctrl_dev *pctldev, const char *name) @@ -514,18 +510,17 @@ static int imx_pinctrl_parse_groups(struct device_node *np, pin->mux_mode = be32_to_cpu(*list++); pin->input_val = be32_to_cpu(*list++); - if (info->generic_pinconf) { + if (info->generic_pinconf) /* generic pin config decoded */ pin->config = config; - } else { + else /* legacy pin config read from devicetree */ - config = be32_to_cpu(*list++); + pin->config = be32_to_cpu(*list++); - /* SION bit is in mux register */ - if (config & IMX_PAD_SION) - pin->mux_mode |= IOMUXC_CONFIG_SION; - pin->config = config & ~IMX_PAD_SION; - } + /* SION bit is in mux register */ + if (pin->config & IMX_PAD_SION) + pin->mux_mode |= IOMUXC_CONFIG_SION; + pin->config = pin->config & ~IMX_PAD_SION; dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name, pin->mux_mode, pin->config); diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h b/drivers/pinctrl/freescale/pinctrl-imx.h index 4b8225c..44567a6 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx.h +++ b/drivers/pinctrl/freescale/pinctrl-imx.h @@ -14,6 +14,10 @@ #include #include +/* The bits in CONFIG cell defined in binding doc*/ +#define IMX_NO_PAD_CTL 0x8000 /* no pin config need */ +#define IMX_PAD_SION 0x4000/* set SION */ + struct platform_device; extern struct pinmux_ops imx_pmx_ops; -- 2.7.4
[PATCH v3 0/3] pinctrl: imx: Add driver for i.MX8MQ
This is the third version for the patch series sent by Lucas. https://www.spinics.net/lists/devicetree/msg212752.html Changes since v2: * switch back to the 'fsl,pins' and hardcoded the config values inside the dts. * updated documentation accordingly Abel Vesa (1): dt-bindings: add binding for i.MX8MQ IOMUXC Lucas Stach (2): pinctrl: imx: allow to configure SION with generic pinconf pinctrl: imx: add driver for i.MX8MQ .../bindings/pinctrl/fsl,imx8mq-pinctrl.txt| 13 + drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx.c| 19 +- drivers/pinctrl/freescale/pinctrl-imx.h| 4 + drivers/pinctrl/freescale/pinctrl-imx8mq.c | 356 + 6 files changed, 388 insertions(+), 12 deletions(-) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8mq.c -- 2.7.4
Re: [PATCH v3 2/3] pinctrl: imx: allow to configure SION with generic pinconf
On Wed, Jun 20, 2018 at 10:16:42AM +0200, Lucas Stach wrote: > Hi Abel, > > as this series switches back to using the raw padcfg values in DT > instead of generic pinconf (which I think is the right move), we can > drop this patch from the series. > Cool, will drop it in the next version. Thanks, Abel > Regards, > Lucas > > Am Mittwoch, den 20.06.2018, 10:24 +0300 schrieb Abel Vesa: > > > From: Lucas Stach > > > > The SION bit force enables the input buffer, overriding the configuration > > driven by the muxed module. It is not located in the pad config register, > > but in the mux register and thus needs special handling. > > > > > Signed-off-by: Lucas Stach > > > Signed-off-by: Abel Vesa > > --- > > drivers/pinctrl/freescale/pinctrl-imx.c | 19 +++ > > drivers/pinctrl/freescale/pinctrl-imx.h | 4 > > 2 files changed, 11 insertions(+), 12 deletions(-) > > > > diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c > > b/drivers/pinctrl/freescale/pinctrl-imx.c > > index 1c6bb15..335edc9 100644 > > --- a/drivers/pinctrl/freescale/pinctrl-imx.c > > +++ b/drivers/pinctrl/freescale/pinctrl-imx.c > > @@ -26,10 +26,6 @@ > > #include "../pinmux.h" > > #include "pinctrl-imx.h" > > > > -/* The bits in CONFIG cell defined in binding doc*/ > > > > -#define IMX_NO_PAD_CTL 0x8000 /* no pin config need */ > > > -#define IMX_PAD_SION 0x4000 /* set SION */ > > - > > static inline const struct group_desc *imx_pinctrl_find_group_by_name( > > > struct pinctrl_dev *pctldev, > > > const char *name) > > @@ -514,18 +510,17 @@ static int imx_pinctrl_parse_groups(struct > > device_node *np, > > > pin->mux_mode = be32_to_cpu(*list++); > > > pin->input_val = be32_to_cpu(*list++); > > > > > - if (info->generic_pinconf) { > > > + if (info->generic_pinconf) > > > /* generic pin config decoded */ > > > pin->config = config; > > > - } else { > > > + else > > > /* legacy pin config read from devicetree */ > > > - config = be32_to_cpu(*list++); > > > + pin->config = be32_to_cpu(*list++); > > > > > - /* SION bit is in mux register */ > > > - if (config & IMX_PAD_SION) > > > - pin->mux_mode |= IOMUXC_CONFIG_SION; > > > - pin->config = config & ~IMX_PAD_SION; > > > - } > > > + /* SION bit is in mux register */ > > > + if (pin->config & IMX_PAD_SION) > > > + pin->mux_mode |= IOMUXC_CONFIG_SION; > > > + pin->config = pin->config & ~IMX_PAD_SION; > > > > > dev_dbg(ipctl->dev, "%s: 0x%x 0x%08lx", info->pins[pin_id].name, > > > pin->mux_mode, pin->config); > > diff --git a/drivers/pinctrl/freescale/pinctrl-imx.h > > b/drivers/pinctrl/freescale/pinctrl-imx.h > > index 4b8225c..44567a6 100644 > > --- a/drivers/pinctrl/freescale/pinctrl-imx.h > > +++ b/drivers/pinctrl/freescale/pinctrl-imx.h > > @@ -14,6 +14,10 @@ > > #include > > #include > > > > +/* The bits in CONFIG cell defined in binding doc*/ > > > > +#define IMX_NO_PAD_CTL 0x8000 /* no pin config need */ > > > +#define IMX_PAD_SION 0x4000 /* set SION */ > > + > > struct platform_device; > > > > extern struct pinmux_ops imx_pmx_ops; --
[PATCH v4 1/2] dt-bindings: add binding for i.MX8MQ IOMUXC
This adds the binding for the i.MX8MQ pin controller, in the same fashion as earlier i.MX SoCs. Signed-off-by: Abel Vesa --- .../bindings/pinctrl/fsl,imx8mq-pinctrl.txt| 29 ++ 1 file changed, 29 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt new file mode 100644 index 000..f11a3f0 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt @@ -0,0 +1,29 @@ +* Freescale IMX8MQ IOMUX Controller + +Please refer to fsl,imx-pinctrl.txt and pinctrl-bindings.txt in this directory +for common binding part and usage. + +Required properties: +- compatible: "fsl,imx8mq-iomuxc" +- fsl,pins: each entry consists of 6 integers and represents the mux and config + setting for one pin. The first 5 integers are specified using a PIN_FUNC_ID macro, which can be found in + imx8mq-pinfunc.h under device tree source folder. The last integer CONFIG is + the pad setting value like pull-up on this pin. Please refer to i.MX8M Quad + Reference Manual for detailed CONFIG settings. + +Examples: + +&uart1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; +}; + +&iomuxc { + pinctrl_uart1: uart1grp { + fsl,pins = < + MX8MQ_IOMUXC_UART1_RXD_UART1_DCE_RX 0x49 + MX8MQ_IOMUXC_UART1_TXD_UART1_DCE_TX 0x49 + >; + }; +}; -- 2.7.4
[PATCH v4 2/2] pinctrl: imx: add driver for i.MX8MQ
From: Lucas Stach The i.MX8MQ pincontrol works in a similar way to the earlier i.MX SoCs. This driver builds on top of the generic pinconf handling introduced with the i.MX7ULP pinctrl driver. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx8mq.c | 356 + 3 files changed, 364 insertions(+) create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8mq.c diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 0d8ba1e..dccf64c 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -117,6 +117,13 @@ config PINCTRL_IMX7ULP help Say Y here to enable the imx7ulp pinctrl driver +config PINCTRL_IMX8MQ + bool "IMX8MQ pinctrl driver" + depends on SOC_IMX8MQ + select PINCTRL_IMX + help + Say Y here to enable the imx8mq pinctrl driver + config PINCTRL_VF610 bool "Freescale Vybrid VF610 pinctrl driver" depends on SOC_VF610 diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 368be8c..73175b3 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o obj-$(CONFIG_PINCTRL_IMX7D)+= pinctrl-imx7d.o obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o +obj-$(CONFIG_PINCTRL_IMX8MQ) += pinctrl-imx8mq.o obj-$(CONFIG_PINCTRL_VF610)+= pinctrl-vf610.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o obj-$(CONFIG_PINCTRL_IMX23)+= pinctrl-imx23.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mq.c b/drivers/pinctrl/freescale/pinctrl-imx8mq.c new file mode 100644 index 000..be2c9c2 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx8mq.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * Copyright (C) 2018 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx8mq_pads { + MX8MQ_PAD_RESERVE0 = 0, + MX8MQ_PAD_RESERVE1 = 1, + MX8MQ_PAD_RESERVE2 = 2, + MX8MQ_PAD_RESERVE3 = 3, + MX8MQ_PAD_RESERVE4 = 4, + MX8MQ_IOMUXC_PMIC_STBY_REQ_CCMSRCGPCMIX = 5, + MX8MQ_IOMUXC_PMIC_ON_REQ_SNVSMIX = 6, + MX8MQ_IOMUXC_ONOFF_SNVSMIX = 7, + MX8MQ_IOMUXC_POR_B_SNVSMIX = 8, + MX8MQ_IOMUXC_RTC_RESET_B_SNVSMIX = 9, + MX8MQ_IOMUXC_GPIO1_IO00 = 10, + MX8MQ_IOMUXC_GPIO1_IO01 = 11, + MX8MQ_IOMUXC_GPIO1_IO02 = 12, + MX8MQ_IOMUXC_GPIO1_IO03 = 13, + MX8MQ_IOMUXC_GPIO1_IO04 = 14, + MX8MQ_IOMUXC_GPIO1_IO05 = 15, + MX8MQ_IOMUXC_GPIO1_IO06 = 16, + MX8MQ_IOMUXC_GPIO1_IO07 = 17, + MX8MQ_IOMUXC_GPIO1_IO08 = 18, + MX8MQ_IOMUXC_GPIO1_IO09 = 19, + MX8MQ_IOMUXC_GPIO1_IO10 = 20, + MX8MQ_IOMUXC_GPIO1_IO11 = 21, + MX8MQ_IOMUXC_GPIO1_IO12 = 22, + MX8MQ_IOMUXC_GPIO1_IO13 = 23, + MX8MQ_IOMUXC_GPIO1_IO14 = 24, + MX8MQ_IOMUXC_GPIO1_IO15 = 25, + MX8MQ_IOMUXC_ENET_MDC = 26, + MX8MQ_IOMUXC_ENET_MDIO = 27, + MX8MQ_IOMUXC_ENET_TD3 = 28, + MX8MQ_IOMUXC_ENET_TD2 = 29, + MX8MQ_IOMUXC_ENET_TD1 = 30, + MX8MQ_IOMUXC_ENET_TD0 = 31, + MX8MQ_IOMUXC_ENET_TX_CTL = 32, + MX8MQ_IOMUXC_ENET_TXC = 33, + MX8MQ_IOMUXC_ENET_RX_CTL = 34, + MX8MQ_IOMUXC_ENET_RXC = 35, + MX8MQ_IOMUXC_ENET_RD0 = 36, + MX8MQ_IOMUXC_ENET_RD1 = 37, + MX8MQ_IOMUXC_ENET_RD2 = 38, + MX8MQ_IOMUXC_ENET_RD3 = 39, + MX8MQ_IOMUXC_SD1_CLK = 40, + MX8MQ_IOMUXC_SD1_CMD = 41, + MX8MQ_IOMUXC_SD1_DATA0 = 42, + MX8MQ_IOMUXC_SD1_DATA1 = 43, + MX8MQ_IOMUXC_SD1_DATA2 = 44, + MX8MQ_IOMUXC_SD1_DATA3 = 45, + MX8MQ_IOMUXC_SD1_DATA4 = 46, + MX8MQ_IOMUXC_SD1_DATA5 = 47, + MX8MQ_IOMUXC_SD1_DATA6 = 48, + MX8MQ_IOMUXC_SD1_DATA7 = 49, + MX8MQ_IOMUXC_SD1_RESET_B = 50, + MX8MQ_IOMUXC_SD1_STROBE = 51, + MX8MQ_IOMUXC_SD2_CD_B = 52, + MX8MQ_IOMUXC_SD2_CLK = 53, + MX8MQ_IOMUXC_SD2_CMD = 54, + MX8MQ_IOMUXC_SD2_DATA0 = 55, + MX8MQ_IOMUXC_SD2_DATA1 = 56, + MX8MQ_IOMUXC_SD2_DATA2 = 57, + MX8MQ_IOMUXC_SD2_DATA3 = 58, + MX8MQ_IOMUXC_SD2_RESET_B = 59, + MX8MQ_IOMUXC_SD2_WP = 60, + MX8MQ_IOMUXC_NAND_ALE = 61, + MX8MQ_IOMUXC_NAND_CE0_B = 62, + MX8MQ_IOMUXC_NAND_CE1_B = 63, + MX8MQ_IOMUXC_NAND_CE2_B = 64, + MX8MQ_IOMUXC_NAND_CE3_B = 65, + MX8MQ_IOMUXC_NAND_CLE = 66, + MX8MQ_IOMUXC_NAND_DATA00 = 67, + MX8MQ_IOMUXC_NAND_DATA01 = 68, + MX8MQ_IOMUXC_NAND_DATA02 = 69, + MX8MQ_IOMUXC_NAND_DATA03 = 70, +
[PATCH v4 0/2] pinctrl: imx: Add driver for i.MX8MQ
This is the fourth version for the patch series sent by Lucas. https://www.spinics.net/lists/devicetree/msg212752.html Third version can be found here: https://lkml.org/lkml/2018/6/20/343 Changes since v3: * dropped the SION generic pinconf changes * added examples to the bindings doc Changes since v2: * switch back to the 'fsl,pins' and hardcoded the config values inside the dts. * updated documentation accordingly Abel Vesa (1): dt-bindings: add binding for i.MX8MQ IOMUXC Lucas Stach (1): pinctrl: imx: add driver for i.MX8MQ .../bindings/pinctrl/fsl,imx8mq-pinctrl.txt| 29 ++ drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx8mq.c | 356 + 4 files changed, 393 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/fsl,imx8mq-pinctrl.txt create mode 100644 drivers/pinctrl/freescale/pinctrl-imx8mq.c -- 2.7.4
[PATCH] cpu/hotplug: Non-SMP machines do not make use of booted_once
Following commit breaks the non-SMP builds. [0cc3cd21657be04cb0] cpu/hotplug: Boot HT siblings at least once Signed-off-by: Abel Vesa --- kernel/cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kernel/cpu.c b/kernel/cpu.c index 099fb20cd7be..f06c513c5c42 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -2272,6 +2272,8 @@ void __init boot_cpu_init(void) */ void __init boot_cpu_hotplug_init(void) { +#ifdef CONFIG_SMP this_cpu_write(cpuhp_state.booted_once, true); +#endif this_cpu_write(cpuhp_state.state, CPUHP_ONLINE); } -- 2.18.0
[PATCH v4 1/5] dt-bindings: add binding for i.MX8MQ CCM
From: Lucas Stach This adds the binding for the i.MX8MQ Clock Controller Module. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Rob Herring --- .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + include/dt-bindings/clock/imx8mq-clock.h | 410 + 2 files changed, 430 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 include/dt-bindings/clock/imx8mq-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt new file mode 100644 index 000..52de826 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt @@ -0,0 +1,20 @@ +* Clock bindings for NXP i.MX8M Quad + +Required properties: +- compatible: Should be "fsl,imx8mq-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include the following entries: +- "ckil" +- "osc_25m" +- "osc_27m" +- "clk_ext1" +- "clk_ext2" +- "clk_ext3" +- "clk_ext4" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h +for the full list of i.MX8M Quad clock IDs. diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h new file mode 100644 index 000..0d19bd9 --- /dev/null +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -0,0 +1,410 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MQ_H +#define __DT_BINDINGS_CLOCK_IMX8MQ_H + +#define IMX8MQ_CLK_DUMMY 0 +#define IMX8MQ_CLK_32K 1 +#define IMX8MQ_CLK_25M 2 +#define IMX8MQ_CLK_27M 3 +#define IMX8MQ_CLK_EXT14 +#define IMX8MQ_CLK_EXT25 +#define IMX8MQ_CLK_EXT36 +#define IMX8MQ_CLK_EXT47 + +/* ANAMIX PLL clocks */ +/* FRAC PLLs */ +/* ARM PLL */ +#define IMX8MQ_ARM_PLL_REF_SEL 8 +#define IMX8MQ_ARM_PLL_REF_DIV 9 +#define IMX8MQ_ARM_PLL 10 +#define IMX8MQ_ARM_PLL_BYPASS 11 +#define IMX8MQ_ARM_PLL_OUT 12 + +/* GPU PLL */ +#define IMX8MQ_GPU_PLL_REF_SEL 13 +#define IMX8MQ_GPU_PLL_REF_DIV 14 +#define IMX8MQ_GPU_PLL 15 +#define IMX8MQ_GPU_PLL_BYPASS 16 +#define IMX8MQ_GPU_PLL_OUT 17 + +/* VPU PLL */ +#define IMX8MQ_VPU_PLL_REF_SEL 18 +#define IMX8MQ_VPU_PLL_REF_DIV 19 +#define IMX8MQ_VPU_PLL 20 +#define IMX8MQ_VPU_PLL_BYPASS 21 +#define IMX8MQ_VPU_PLL_OUT 22 + +/* AUDIO PLL1 */ +#define IMX8MQ_AUDIO_PLL1_REF_SEL 23 +#define IMX8MQ_AUDIO_PLL1_REF_DIV 24 +#define IMX8MQ_AUDIO_PLL1 25 +#define IMX8MQ_AUDIO_PLL1_BYPASS 26 +#define IMX8MQ_AUDIO_PLL1_OUT 27 + +/* AUDIO PLL2 */ +#define IMX8MQ_AUDIO_PLL2_REF_SEL 28 +#define IMX8MQ_AUDIO_PLL2_REF_DIV 29 +#define IMX8MQ_AUDIO_PLL2 30 +#define IMX8MQ_AUDIO_PLL2_BYPASS 31 +#define IMX8MQ_AUDIO_PLL2_OUT 32 + +/* VIDEO PLL1 */ +#define IMX8MQ_VIDEO_PLL1_REF_SEL 33 +#define IMX8MQ_VIDEO_PLL1_REF_DIV 34 +#define IMX8MQ_VIDEO_PLL1 35 +#define IMX8MQ_VIDEO_PLL1_BYPASS 36 +#define IMX8MQ_VIDEO_PLL1_OUT 37 + +/* SYS1 PLL */ +#define IMX8MQ_SYS1_PLL1_REF_SEL 38 +#define IMX8MQ_SYS1_PLL1_REF_DIV 39 +#define IMX8MQ_SYS1_PLL1 40 +#define IMX8MQ_SYS1_PLL1_OUT 41 +#define IMX8MQ_SYS1_PLL1_OUT_DIV 42 +#define IMX8MQ_SYS1_PLL2 43 +#define IMX8MQ_SYS1_PLL2_DIV 44 +#define IMX8MQ_SYS1_PLL2_OUT 45 + +/* SYS2 PLL */ +#define IMX8MQ_SYS2_PLL1_REF_SEL 46 +#define IMX8MQ_SYS2_PLL1_REF_DIV 47 +#define IMX8MQ_SYS2_PLL1 48 +#define IMX8MQ_SYS2_PLL1_OUT 49 +#define IMX8MQ_SYS2_PLL1_OUT_DIV 50 +#define IMX8MQ_SYS2_PLL2 51 +#define IMX8MQ_SYS2_PLL2_DIV 52 +#define IMX8MQ_SYS2_PLL2_OUT 53 + +/* SYS3 PLL */ +#define IMX8MQ_SYS3_PLL1_REF_SEL 54 +#define IMX8MQ_SYS3_PLL1_REF_DIV 55 +#define IMX8MQ_SYS3_PLL1 56 +#define IMX8MQ_SYS3_PLL1_OUT 57 +#define IMX8MQ_SYS3_PLL1_OUT_DIV 58 +#define IMX8MQ_SYS3_PLL2 59 +#define IMX8MQ_SYS3_PLL2_DIV 60 +#define IMX8MQ_SYS3_PLL2_OUT 61 + +/* DRAM PLL */ +#define IMX8MQ_DRAM_PLL1_REF_SEL 62 +#define IMX8MQ_DRAM_PLL1_REF_DIV 63 +#define IMX8MQ_DRAM_PLL1 64 +#define IMX8MQ
[PATCH v4 0/5] Add i.MX8MQ clock driver
Third version can be found here: https://www.spinics.net/lists/arm-kernel/msg671015.html Changes since v3: * Added a composite clock type to get rid of some complexity from clk-imx8mq. This new composite clock type will also be used by all the imx8 socs that will follow. * Added back the reviewed-by tag. Abel Vesa (1): clk: imx: add imx composite clock Lucas Stach (4): dt-bindings: add binding for i.MX8MQ CCM clk: imx: add fractional PLL output clock clk: imx: add SCCG PLL type clk: imx: add clock driver for i.MX8MQ CCM .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-composite.c| 471 +++ drivers/clk/imx/clk-frac-pll.c | 230 drivers/clk/imx/clk-imx8mq.c | 631 + drivers/clk/imx/clk-sccg-pll.c | 231 drivers/clk/imx/clk.h | 57 ++ include/dt-bindings/clock/imx8mq-clock.h | 410 + 8 files changed, 2055 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 drivers/clk/imx/clk-composite.c create mode 100644 drivers/clk/imx/clk-frac-pll.c create mode 100644 drivers/clk/imx/clk-imx8mq.c create mode 100644 drivers/clk/imx/clk-sccg-pll.c create mode 100644 include/dt-bindings/clock/imx8mq-clock.h -- 2.7.4
[PATCH v4 3/5] clk: imx: add SCCG PLL type
From: Lucas Stach The SCCG is a new PLL type introduced on i.MX8. Add support for this. The driver currently misses the PLL lock check, as the preliminary documentation mentions lock configurations, but is quiet about where to find the actual lock status signal. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-sccg-pll.c | 231 + drivers/clk/imx/clk.h | 9 ++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-sccg-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4893c1f..b87513c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pfd.o + clk-pfd.o \ + clk-sccg-pll.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c new file mode 100644 index 000..886ae03 --- /dev/null +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include + +#include "clk.h" + +/* PLL CFGs */ +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 +#define PLL_CFG2 0x8 + +#define PLL_DIVF1_SHIFT13 +#define PLL_DIVF2_SHIFT7 +#define PLL_DIVF_MASK 0x3f + +#define PLL_DIVR1_SHIFT25 +#define PLL_DIVR2_SHIFT19 +#define PLL_DIVR1_MASK 0x3 +#define PLL_DIVR2_MASK 0x3f +#define PLL_REF_SHIFT 0 +#define PLL_REF_MASK 0x3 + +#define PLL_LOCK 31 +#define PLL_PD 7 + +#define OSC_25M2500 +#define OSC_27M2700 + +struct clk_sccg_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) + +static int clk_pll1_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & (1 << PLL_PD)) ? 0 : 1; +} + +static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, divf; + + val = readl_relaxed(pll->base + PLL_CFG2); + divf = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + + return parent_rate * 2 * (divf + 1); +} + +static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 div; + + div = rate / (parent_rate * 2); + + return parent_rate * div * 2; +} + +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + u32 divf; + + divf = rate / (parent_rate * 2); + + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~(PLL_DIVF_MASK << PLL_DIVF1_SHIFT); + val |= (divf - 1) << PLL_DIVF1_SHIFT; + writel_relaxed(val, pll->base + PLL_CFG2); + + /* FIXME: PLL lock check */ + + return 0; +} + +static int clk_pll1_prepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~(1 << PLL_PD); + writel_relaxed(val, pll->base); + + /* FIXME: PLL lock check */ + + return 0; +} + +static void clk_pll1_unprepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= (1 << PLL_PD); + writel_relaxed(val, pll->base); +} + +static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, ref, divr1, divf1, divr2, divf2; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + switch ((val >> PLL_REF_SHIFT) & PLL_REF_MASK) { + case 0: + ref = OSC_25M; + break; + case 1: + ref = OSC_27M; + break; + default: + ref = OSC_25M; + break; + } + + val = readl_relaxed(pll->base + PLL_CFG2); + divr1 = (val >> PLL_DIVR1_SHIFT) & PLL_DIVR1_MASK; + divr2 = (val >> PLL_DIVR2_SHIFT) & PLL_DIVR2_MASK; + divf1 = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + divf2 = (val >> PLL_DIVF2_SHIFT) & PLL_DIVF_MASK; + + temp6
[PATCH v4 2/5] clk: imx: add fractional PLL output clock
From: Lucas Stach This is a new clock type introduced on i.MX8. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-frac-pll.c | 230 + drivers/clk/imx/clk.h | 3 + 3 files changed, 234 insertions(+) create mode 100644 drivers/clk/imx/clk-frac-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..4893c1f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -6,6 +6,7 @@ obj-y += \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ + clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pllv1.o \ diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 000..c80c6ed --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUSBIT(31) +#define PLL_PD 19 +#define PLL_PD_MASKBIT(PLL_PD) +#define PLL_BYPASS 14 +#define PLL_BYPASS_MASKBIT(PLL_BYPASS) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK 0xff +#define PLL_INT_DIV_MASK 0x7f +#define PLL_OUTPUT_DIV_MASK0x1f +#define PLL_FRAC_DENOM 0x100 + +struct clk_frac_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 val; + + /* Wait for PLL to lock */ + do { + if (readl_relaxed(pll->base) & PLL_LOCK_STATUS) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_LOCK_STATUS, 0, 1000); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(50); + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + do { + if (readl_relaxed(pll->base) & PLL_NEWDIV_ACK) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_NEWDIV_ACK, 0, 1000); +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val, divff, divfi, divq; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = ((val & PLL_OUTPUT_DIV_MASK) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = (val >> 7) & PLL_FRAC_DIV_MASK; + divfi = (val & PLL_INT_DIV_MASK); + + temp64 = (u64)parent_rate * 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + temp64 /= divq; + + return parent_rate * 8 * (divfi + 1) / divq + (unsigned long)temp64; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 divff, divfi; + u64 temp64; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = (u64)(rate - divfi * parent_rate); + temp64 *= PLL_FRAC_DENOM; + do_div(
[PATCH v4 4/5] clk: imx: add imx composite clock
Since a lot of clocks on imx8 are formed by a mux, gate, predivider and divider, the idea here is to combine all of those into one more complex clock type, therefore moving the complexity inside the composite clock and outside of the SoC specific clock driver. Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-composite.c | 471 drivers/clk/imx/clk.h | 9 + 3 files changed, 481 insertions(+) create mode 100644 drivers/clk/imx/clk-composite.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b87513c..4fabb0a 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -3,6 +3,7 @@ obj-y += \ clk.o \ clk-busy.o \ + clk-composite.o \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite.c b/drivers/clk/imx/clk-composite.c new file mode 100644 index 000..751dabf --- /dev/null +++ b/drivers/clk/imx/clk-composite.c @@ -0,0 +1,471 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +#include +#include +#include +#include + +#include "clk.h" + +#define PCG_PREDIV_SHIFT 16 +#define PCG_PREDIV_WIDTH 3 + +#define PCG_DIV_SHIFT 0 +#define PCG_DIV_WIDTH 6 + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 + +#define PCG_CGC_SHIFT 28 + +#define to_clk_imx_composite(_hw) \ + container_of(_hw, struct imx_clk_composite, hw) + +struct imx_clk_composite { + struct clk_hw hw; + struct clk_ops ops; + + struct clk_hw *mux_hw; + struct clk_hw *prediv_hw; + struct clk_hw *div_hw; + struct clk_hw *gate_hw; + + const struct clk_ops*mux_ops; + const struct clk_ops*prediv_ops; + const struct clk_ops*div_ops; + const struct clk_ops*gate_ops; +}; + +static u8 clk_imx_composite_get_parent(struct clk_hw *hw) +{ + struct imx_clk_composite *clk = to_clk_imx_composite(hw); + const struct clk_ops *mux_ops = clk->mux_ops; + struct clk_hw *mux_hw = clk->mux_hw; + + __clk_hw_set_clk(mux_hw, hw); + + return mux_ops->get_parent(mux_hw); +} + +static int clk_imx_composite_set_parent(struct clk_hw *hw, u8 index) +{ + struct imx_clk_composite *clk = to_clk_imx_composite(hw); + const struct clk_ops *mux_ops = clk->mux_ops; + struct clk_hw *mux_hw = clk->mux_hw; + + __clk_hw_set_clk(mux_hw, hw); + + return mux_ops->set_parent(mux_hw, index); +} + +static unsigned long clk_imx_composite_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct imx_clk_composite *clk = to_clk_imx_composite(hw); + const struct clk_ops *div_ops = clk->div_ops; + struct clk_hw *div_hw = clk->div_hw; + + __clk_hw_set_clk(div_hw, hw); + + return div_ops->recalc_rate(div_hw, parent_rate); +} + +static int clk_imx_composite_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct imx_clk_composite *clk = to_clk_imx_composite(hw); + const struct clk_ops *div_ops = clk->div_ops; + const struct clk_ops *mux_ops = clk->mux_ops; + struct clk_hw *div_hw = clk->div_hw; + struct clk_hw *mux_hw = clk->mux_hw; + struct clk_hw *parent; + unsigned long parent_rate; + long tmp_rate, best_rate = 0; + unsigned long rate_diff; + unsigned long best_rate_diff = ULONG_MAX; + long rate; + int i; + + if (div_hw && div_ops && div_ops->determine_rate) { + __clk_hw_set_clk(div_hw, hw); + return div_ops->determine_rate(div_hw, req); + } else if (div_hw && div_ops && div_ops->round_rate && + mux_hw && mux_ops && mux_ops->set_parent) { + req->best_parent_hw = NULL; + + if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) { + parent = clk_hw_get_parent(mux_hw); + req->best_parent_hw = parent; + req->best_parent_rate = clk_hw_get_rate(parent); + + rate = div_ops->round_rate(div_hw, req->rate, + &req->best_parent_rate); + if (rate < 0) + return rate; + + req->rate = rate; + return 0; + } + + for (i = 0; i < clk_hw_get_num_parents(mux_hw); i++) { + parent = clk_hw_get_parent_by_index(mux_hw, i); + if (!parent) +
[PATCH v4 5/5] clk: imx: add clock driver for i.MX8MQ CCM
From: Lucas Stach Add driver for the Clock Control Module found on i.MX8MQ. This is largely based on the downstream driver from Anson Huang and Bai Ping at NXP, with only some small adaptions to mainline from me. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mq.c | 631 +++ drivers/clk/imx/clk.h| 36 +++ 3 files changed, 668 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mq.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4fabb0a..64e695c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o +obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 000..d3a9e31 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,631 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * Copyright (C) 2017 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai4; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_dcss; +static u32 share_count_nand; + +static struct clk *clks[IMX8MQ_CLK_END]; + +static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; +static const char *video2_pll1_out_sels[] = {"video2_pll1", "video2_pll1_ref_sel", }; + +static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; +static const char *video2_pll2_out_sels[] = {"video2_pll2_div", "video2_pll1_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", }; + +static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", + "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",}; + +static const ch
[PATCH v5 0/5] Add i.MX8MQ clock driver
Fourth version can be found here: https://lore.kernel.org/patchwork/cover/974998/ Changes since v4: * Implemented divider ops and used clk-composite as suggested by Sascha Hauer. Changes since v3: * Added a composite clock type to get rid of some complexity from clk-imx8mq. This new composite clock type will also be used by all the imx8 socs that will follow. * Added back the reviewed-by tag. Abel Vesa (1): clk: imx: add imx composite clock Lucas Stach (4): dt-bindings: add binding for i.MX8MQ CCM clk: imx: add fractional PLL output clock clk: imx: add SCCG PLL type clk: imx: add clock driver for i.MX8MQ CCM .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-composite.c| 126 drivers/clk/imx/clk-frac-pll.c | 230 drivers/clk/imx/clk-imx8mq.c | 631 + drivers/clk/imx/clk-sccg-pll.c | 231 drivers/clk/imx/clk.h | 57 ++ include/dt-bindings/clock/imx8mq-clock.h | 410 + 8 files changed, 1710 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 drivers/clk/imx/clk-composite.c create mode 100644 drivers/clk/imx/clk-frac-pll.c create mode 100644 drivers/clk/imx/clk-imx8mq.c create mode 100644 drivers/clk/imx/clk-sccg-pll.c create mode 100644 include/dt-bindings/clock/imx8mq-clock.h -- 2.7.4
[PATCH v5 1/5] dt-bindings: add binding for i.MX8MQ CCM
From: Lucas Stach This adds the binding for the i.MX8MQ Clock Controller Module. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Rob Herring --- .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + include/dt-bindings/clock/imx8mq-clock.h | 410 + 2 files changed, 430 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 include/dt-bindings/clock/imx8mq-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt new file mode 100644 index 000..52de826 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt @@ -0,0 +1,20 @@ +* Clock bindings for NXP i.MX8M Quad + +Required properties: +- compatible: Should be "fsl,imx8mq-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include the following entries: +- "ckil" +- "osc_25m" +- "osc_27m" +- "clk_ext1" +- "clk_ext2" +- "clk_ext3" +- "clk_ext4" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h +for the full list of i.MX8M Quad clock IDs. diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h new file mode 100644 index 000..0d19bd9 --- /dev/null +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -0,0 +1,410 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MQ_H +#define __DT_BINDINGS_CLOCK_IMX8MQ_H + +#define IMX8MQ_CLK_DUMMY 0 +#define IMX8MQ_CLK_32K 1 +#define IMX8MQ_CLK_25M 2 +#define IMX8MQ_CLK_27M 3 +#define IMX8MQ_CLK_EXT14 +#define IMX8MQ_CLK_EXT25 +#define IMX8MQ_CLK_EXT36 +#define IMX8MQ_CLK_EXT47 + +/* ANAMIX PLL clocks */ +/* FRAC PLLs */ +/* ARM PLL */ +#define IMX8MQ_ARM_PLL_REF_SEL 8 +#define IMX8MQ_ARM_PLL_REF_DIV 9 +#define IMX8MQ_ARM_PLL 10 +#define IMX8MQ_ARM_PLL_BYPASS 11 +#define IMX8MQ_ARM_PLL_OUT 12 + +/* GPU PLL */ +#define IMX8MQ_GPU_PLL_REF_SEL 13 +#define IMX8MQ_GPU_PLL_REF_DIV 14 +#define IMX8MQ_GPU_PLL 15 +#define IMX8MQ_GPU_PLL_BYPASS 16 +#define IMX8MQ_GPU_PLL_OUT 17 + +/* VPU PLL */ +#define IMX8MQ_VPU_PLL_REF_SEL 18 +#define IMX8MQ_VPU_PLL_REF_DIV 19 +#define IMX8MQ_VPU_PLL 20 +#define IMX8MQ_VPU_PLL_BYPASS 21 +#define IMX8MQ_VPU_PLL_OUT 22 + +/* AUDIO PLL1 */ +#define IMX8MQ_AUDIO_PLL1_REF_SEL 23 +#define IMX8MQ_AUDIO_PLL1_REF_DIV 24 +#define IMX8MQ_AUDIO_PLL1 25 +#define IMX8MQ_AUDIO_PLL1_BYPASS 26 +#define IMX8MQ_AUDIO_PLL1_OUT 27 + +/* AUDIO PLL2 */ +#define IMX8MQ_AUDIO_PLL2_REF_SEL 28 +#define IMX8MQ_AUDIO_PLL2_REF_DIV 29 +#define IMX8MQ_AUDIO_PLL2 30 +#define IMX8MQ_AUDIO_PLL2_BYPASS 31 +#define IMX8MQ_AUDIO_PLL2_OUT 32 + +/* VIDEO PLL1 */ +#define IMX8MQ_VIDEO_PLL1_REF_SEL 33 +#define IMX8MQ_VIDEO_PLL1_REF_DIV 34 +#define IMX8MQ_VIDEO_PLL1 35 +#define IMX8MQ_VIDEO_PLL1_BYPASS 36 +#define IMX8MQ_VIDEO_PLL1_OUT 37 + +/* SYS1 PLL */ +#define IMX8MQ_SYS1_PLL1_REF_SEL 38 +#define IMX8MQ_SYS1_PLL1_REF_DIV 39 +#define IMX8MQ_SYS1_PLL1 40 +#define IMX8MQ_SYS1_PLL1_OUT 41 +#define IMX8MQ_SYS1_PLL1_OUT_DIV 42 +#define IMX8MQ_SYS1_PLL2 43 +#define IMX8MQ_SYS1_PLL2_DIV 44 +#define IMX8MQ_SYS1_PLL2_OUT 45 + +/* SYS2 PLL */ +#define IMX8MQ_SYS2_PLL1_REF_SEL 46 +#define IMX8MQ_SYS2_PLL1_REF_DIV 47 +#define IMX8MQ_SYS2_PLL1 48 +#define IMX8MQ_SYS2_PLL1_OUT 49 +#define IMX8MQ_SYS2_PLL1_OUT_DIV 50 +#define IMX8MQ_SYS2_PLL2 51 +#define IMX8MQ_SYS2_PLL2_DIV 52 +#define IMX8MQ_SYS2_PLL2_OUT 53 + +/* SYS3 PLL */ +#define IMX8MQ_SYS3_PLL1_REF_SEL 54 +#define IMX8MQ_SYS3_PLL1_REF_DIV 55 +#define IMX8MQ_SYS3_PLL1 56 +#define IMX8MQ_SYS3_PLL1_OUT 57 +#define IMX8MQ_SYS3_PLL1_OUT_DIV 58 +#define IMX8MQ_SYS3_PLL2 59 +#define IMX8MQ_SYS3_PLL2_DIV 60 +#define IMX8MQ_SYS3_PLL2_OUT 61 + +/* DRAM PLL */ +#define IMX8MQ_DRAM_PLL1_REF_SEL 62 +#define IMX8MQ_DRAM_PLL1_REF_DIV 63 +#define IMX8MQ_DRAM_PLL1 64 +#define IMX8MQ
[PATCH v5 2/5] clk: imx: add fractional PLL output clock
From: Lucas Stach This is a new clock type introduced on i.MX8. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-frac-pll.c | 230 + drivers/clk/imx/clk.h | 3 + 3 files changed, 234 insertions(+) create mode 100644 drivers/clk/imx/clk-frac-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..4893c1f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -6,6 +6,7 @@ obj-y += \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ + clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pllv1.o \ diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 000..c80c6ed --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUSBIT(31) +#define PLL_PD 19 +#define PLL_PD_MASKBIT(PLL_PD) +#define PLL_BYPASS 14 +#define PLL_BYPASS_MASKBIT(PLL_BYPASS) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK 0xff +#define PLL_INT_DIV_MASK 0x7f +#define PLL_OUTPUT_DIV_MASK0x1f +#define PLL_FRAC_DENOM 0x100 + +struct clk_frac_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 val; + + /* Wait for PLL to lock */ + do { + if (readl_relaxed(pll->base) & PLL_LOCK_STATUS) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_LOCK_STATUS, 0, 1000); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(50); + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + do { + if (readl_relaxed(pll->base) & PLL_NEWDIV_ACK) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_NEWDIV_ACK, 0, 1000); +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val, divff, divfi, divq; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = ((val & PLL_OUTPUT_DIV_MASK) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = (val >> 7) & PLL_FRAC_DIV_MASK; + divfi = (val & PLL_INT_DIV_MASK); + + temp64 = (u64)parent_rate * 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + temp64 /= divq; + + return parent_rate * 8 * (divfi + 1) / divq + (unsigned long)temp64; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 divff, divfi; + u64 temp64; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = (u64)(rate - divfi * parent_rate); + temp64 *= PLL_FRAC_DENOM; + do_div(
[PATCH v5 4/5] clk: imx: add imx composite clock
Since a lot of clocks on imx8 are formed by a mux, gate, predivider and divider, the idea here is to combine all of those into one more complex clock type, therefore moving the complexity inside the composite clock and outside of the SoC specific clock driver. Signed-off-by: Abel Vesa Suggested-by: Sascha Hauer --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-composite.c | 126 drivers/clk/imx/clk.h | 9 +++ 3 files changed, 136 insertions(+) create mode 100644 drivers/clk/imx/clk-composite.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b87513c..4fabb0a 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -3,6 +3,7 @@ obj-y += \ clk.o \ clk-busy.o \ + clk-composite.o \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite.c b/drivers/clk/imx/clk-composite.c new file mode 100644 index 000..717c6f1 --- /dev/null +++ b/drivers/clk/imx/clk-composite.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +#include +#include +#include +#include + +#include "clk.h" + +#define PCG_PREDIV_SHIFT 16 +#define PCG_PREDIV_WIDTH 3 + +#define PCG_DIV_SHIFT 0 +#define PCG_DIV_WIDTH 6 + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 + +#define PCG_CGC_SHIFT 28 + +static unsigned long imx_clk_composite_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return clk_divider_ops.recalc_rate(hw, parent_rate); +} + +static long imx_clk_composite_divider_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + return clk_divider_ops.round_rate(hw, rate, prate); +} + +static int imx_clk_composite_divider_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + int value; + unsigned long flags = 0; + u32 val; + + value = divider_get_val(rate, parent_rate, NULL, + PCG_PREDIV_WIDTH, CLK_DIVIDER_ROUND_CLOSEST); + if (value < 0) + return value; + + spin_lock_irqsave(divider->lock, flags); + + val = clk_readl(divider->reg); + val &= ~((clk_div_mask(divider->width) << divider->shift) | + (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + + val |= (u32)value << divider->shift; + val |= (u32)value << PCG_DIV_SHIFT; + clk_writel(val, divider->reg); + + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} + +static const struct clk_ops imx_clk_composite_divider_ops = { + .recalc_rate = imx_clk_composite_divider_recalc_rate, + .round_rate = imx_clk_composite_divider_round_rate, + .set_rate = imx_clk_composite_divider_set_rate, +}; + +struct clk *imx_clk_composite_flags(const char *name, + const char **parent_names, + int num_parents, void __iomem *reg, + unsigned long flags) +{ + struct clk_hw *mux_hw = NULL, *div_hw = NULL, *gate_hw = NULL; + struct clk_divider *div = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk *clk; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + mux_hw = &mux->hw; + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) { + kfree(mux); + return ERR_PTR(-ENOMEM); + } + div_hw = &div->hw; + div->reg = reg; + div->shift = PCG_PREDIV_SHIFT; + div->width = PCG_PREDIV_WIDTH; + div->lock = &imx_ccm_lock; + div->flags = CLK_DIVIDER_ROUND_CLOSEST; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + kfree(mux); + kfree(div); + return ERR_PTR(-ENOMEM); + } + gate_hw = &gate->hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + + flags |= CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE; + + clk = clk_register_composite(NULL, name, parent_names, num_parents, + mux_hw, &clk_mux_ops, div_hw, + &imx_clk_composite_divider_ops, gate_hw, + &cl
[PATCH v5 3/5] clk: imx: add SCCG PLL type
From: Lucas Stach The SCCG is a new PLL type introduced on i.MX8. Add support for this. The driver currently misses the PLL lock check, as the preliminary documentation mentions lock configurations, but is quiet about where to find the actual lock status signal. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-sccg-pll.c | 231 + drivers/clk/imx/clk.h | 9 ++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-sccg-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4893c1f..b87513c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pfd.o + clk-pfd.o \ + clk-sccg-pll.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c new file mode 100644 index 000..886ae03 --- /dev/null +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include + +#include "clk.h" + +/* PLL CFGs */ +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 +#define PLL_CFG2 0x8 + +#define PLL_DIVF1_SHIFT13 +#define PLL_DIVF2_SHIFT7 +#define PLL_DIVF_MASK 0x3f + +#define PLL_DIVR1_SHIFT25 +#define PLL_DIVR2_SHIFT19 +#define PLL_DIVR1_MASK 0x3 +#define PLL_DIVR2_MASK 0x3f +#define PLL_REF_SHIFT 0 +#define PLL_REF_MASK 0x3 + +#define PLL_LOCK 31 +#define PLL_PD 7 + +#define OSC_25M2500 +#define OSC_27M2700 + +struct clk_sccg_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) + +static int clk_pll1_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & (1 << PLL_PD)) ? 0 : 1; +} + +static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, divf; + + val = readl_relaxed(pll->base + PLL_CFG2); + divf = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + + return parent_rate * 2 * (divf + 1); +} + +static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 div; + + div = rate / (parent_rate * 2); + + return parent_rate * div * 2; +} + +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + u32 divf; + + divf = rate / (parent_rate * 2); + + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~(PLL_DIVF_MASK << PLL_DIVF1_SHIFT); + val |= (divf - 1) << PLL_DIVF1_SHIFT; + writel_relaxed(val, pll->base + PLL_CFG2); + + /* FIXME: PLL lock check */ + + return 0; +} + +static int clk_pll1_prepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~(1 << PLL_PD); + writel_relaxed(val, pll->base); + + /* FIXME: PLL lock check */ + + return 0; +} + +static void clk_pll1_unprepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= (1 << PLL_PD); + writel_relaxed(val, pll->base); +} + +static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, ref, divr1, divf1, divr2, divf2; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + switch ((val >> PLL_REF_SHIFT) & PLL_REF_MASK) { + case 0: + ref = OSC_25M; + break; + case 1: + ref = OSC_27M; + break; + default: + ref = OSC_25M; + break; + } + + val = readl_relaxed(pll->base + PLL_CFG2); + divr1 = (val >> PLL_DIVR1_SHIFT) & PLL_DIVR1_MASK; + divr2 = (val >> PLL_DIVR2_SHIFT) & PLL_DIVR2_MASK; + divf1 = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + divf2 = (val >> PLL_DIVF2_SHIFT) & PLL_DIVF_MASK; + + temp6
[PATCH v5 5/5] clk: imx: add clock driver for i.MX8MQ CCM
From: Lucas Stach Add driver for the Clock Control Module found on i.MX8MQ. This is largely based on the downstream driver from Anson Huang and Bai Ping at NXP, with only some small adaptions to mainline from me. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mq.c | 631 +++ drivers/clk/imx/clk.h| 36 +++ 3 files changed, 668 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mq.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4fabb0a..64e695c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o +obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 000..d3a9e31 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,631 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * Copyright (C) 2017 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai4; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_dcss; +static u32 share_count_nand; + +static struct clk *clks[IMX8MQ_CLK_END]; + +static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; +static const char *video2_pll1_out_sels[] = {"video2_pll1", "video2_pll1_ref_sel", }; + +static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; +static const char *video2_pll2_out_sels[] = {"video2_pll2_div", "video2_pll1_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", }; + +static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", + "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",}; + +static const ch
[RESEND v5 2/5] clk: imx: add fractional PLL output clock
From: Lucas Stach This is a new clock type introduced on i.MX8. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-frac-pll.c | 230 + drivers/clk/imx/clk.h | 3 + 3 files changed, 234 insertions(+) create mode 100644 drivers/clk/imx/clk-frac-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 8c3baa7..4893c1f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -6,6 +6,7 @@ obj-y += \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ + clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pllv1.o \ diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 000..c80c6ed --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUSBIT(31) +#define PLL_PD 19 +#define PLL_PD_MASKBIT(PLL_PD) +#define PLL_BYPASS 14 +#define PLL_BYPASS_MASKBIT(PLL_BYPASS) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK 0xff +#define PLL_INT_DIV_MASK 0x7f +#define PLL_OUTPUT_DIV_MASK0x1f +#define PLL_FRAC_DENOM 0x100 + +struct clk_frac_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_frac_pll(_hw) container_of(_hw, struct clk_frac_pll, hw) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(10); + u32 val; + + /* Wait for PLL to lock */ + do { + if (readl_relaxed(pll->base) & PLL_LOCK_STATUS) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_LOCK_STATUS, 0, 1000); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(50); + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + do { + if (readl_relaxed(pll->base) & PLL_NEWDIV_ACK) + break; + if (time_after(jiffies, timeout)) + break; + } while (1); + + return readl_poll_timeout(pll->base, val, + val & PLL_NEWDIV_ACK, 0, 1000); +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & PLL_PD_MASK) ? 0 : 1; +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(hw); + u32 val, divff, divfi, divq; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = ((val & PLL_OUTPUT_DIV_MASK) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = (val >> 7) & PLL_FRAC_DIV_MASK; + divfi = (val & PLL_INT_DIV_MASK); + + temp64 = (u64)parent_rate * 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + temp64 /= divq; + + return parent_rate * 8 * (divfi + 1) / divq + (unsigned long)temp64; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 divff, divfi; + u64 temp64; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = (u64)(rate - divfi * parent_rate); + temp64 *= PLL_FRAC_DENOM; + do_div(
[RESEND v5 3/5] clk: imx: add SCCG PLL type
From: Lucas Stach The SCCG is a new PLL type introduced on i.MX8. Add support for this. The driver currently misses the PLL lock check, as the preliminary documentation mentions lock configurations, but is quiet about where to find the actual lock status signal. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 3 +- drivers/clk/imx/clk-sccg-pll.c | 231 + drivers/clk/imx/clk.h | 9 ++ 3 files changed, 242 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/clk-sccg-pll.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4893c1f..b87513c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,7 +12,8 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pfd.o + clk-pfd.o \ + clk-sccg-pll.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c new file mode 100644 index 000..886ae03 --- /dev/null +++ b/drivers/clk/imx/clk-sccg-pll.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2018 NXP. + */ + +#include +#include +#include +#include + +#include "clk.h" + +/* PLL CFGs */ +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 +#define PLL_CFG2 0x8 + +#define PLL_DIVF1_SHIFT13 +#define PLL_DIVF2_SHIFT7 +#define PLL_DIVF_MASK 0x3f + +#define PLL_DIVR1_SHIFT25 +#define PLL_DIVR2_SHIFT19 +#define PLL_DIVR1_MASK 0x3 +#define PLL_DIVR2_MASK 0x3f +#define PLL_REF_SHIFT 0 +#define PLL_REF_MASK 0x3 + +#define PLL_LOCK 31 +#define PLL_PD 7 + +#define OSC_25M2500 +#define OSC_27M2700 + +struct clk_sccg_pll { + struct clk_hw hw; + void __iomem*base; +}; + +#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) + +static int clk_pll1_is_prepared(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + return (val & (1 << PLL_PD)) ? 0 : 1; +} + +static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, divf; + + val = readl_relaxed(pll->base + PLL_CFG2); + divf = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + + return parent_rate * 2 * (divf + 1); +} + +static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned long parent_rate = *prate; + u32 div; + + div = rate / (parent_rate * 2); + + return parent_rate * div * 2; +} + +static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + u32 divf; + + divf = rate / (parent_rate * 2); + + val = readl_relaxed(pll->base + PLL_CFG2); + val &= ~(PLL_DIVF_MASK << PLL_DIVF1_SHIFT); + val |= (divf - 1) << PLL_DIVF1_SHIFT; + writel_relaxed(val, pll->base + PLL_CFG2); + + /* FIXME: PLL lock check */ + + return 0; +} + +static int clk_pll1_prepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val &= ~(1 << PLL_PD); + writel_relaxed(val, pll->base); + + /* FIXME: PLL lock check */ + + return 0; +} + +static void clk_pll1_unprepare(struct clk_hw *hw) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val; + + val = readl_relaxed(pll->base); + val |= (1 << PLL_PD); + writel_relaxed(val, pll->base); +} + +static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, +unsigned long parent_rate) +{ + struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); + u32 val, ref, divr1, divf1, divr2, divf2; + u64 temp64; + + val = readl_relaxed(pll->base + PLL_CFG0); + switch ((val >> PLL_REF_SHIFT) & PLL_REF_MASK) { + case 0: + ref = OSC_25M; + break; + case 1: + ref = OSC_27M; + break; + default: + ref = OSC_25M; + break; + } + + val = readl_relaxed(pll->base + PLL_CFG2); + divr1 = (val >> PLL_DIVR1_SHIFT) & PLL_DIVR1_MASK; + divr2 = (val >> PLL_DIVR2_SHIFT) & PLL_DIVR2_MASK; + divf1 = (val >> PLL_DIVF1_SHIFT) & PLL_DIVF_MASK; + divf2 = (val >> PLL_DIVF2_SHIFT) & PLL_DIVF_MASK; + + temp6
[RESEND v5 1/5] dt-bindings: add binding for i.MX8MQ CCM
From: Lucas Stach This adds the binding for the i.MX8MQ Clock Controller Module. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa Reviewed-by: Rob Herring --- .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + include/dt-bindings/clock/imx8mq-clock.h | 410 + 2 files changed, 430 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 include/dt-bindings/clock/imx8mq-clock.h diff --git a/Documentation/devicetree/bindings/clock/imx8mq-clock.txt b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt new file mode 100644 index 000..52de826 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/imx8mq-clock.txt @@ -0,0 +1,20 @@ +* Clock bindings for NXP i.MX8M Quad + +Required properties: +- compatible: Should be "fsl,imx8mq-ccm" +- reg: Address and length of the register set +- #clock-cells: Should be <1> +- clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names +- clock-names: should include the following entries: +- "ckil" +- "osc_25m" +- "osc_27m" +- "clk_ext1" +- "clk_ext2" +- "clk_ext3" +- "clk_ext4" + +The clock consumer should specify the desired clock by having the clock +ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mq-clock.h +for the full list of i.MX8M Quad clock IDs. diff --git a/include/dt-bindings/clock/imx8mq-clock.h b/include/dt-bindings/clock/imx8mq-clock.h new file mode 100644 index 000..0d19bd9 --- /dev/null +++ b/include/dt-bindings/clock/imx8mq-clock.h @@ -0,0 +1,410 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + */ + +#ifndef __DT_BINDINGS_CLOCK_IMX8MQ_H +#define __DT_BINDINGS_CLOCK_IMX8MQ_H + +#define IMX8MQ_CLK_DUMMY 0 +#define IMX8MQ_CLK_32K 1 +#define IMX8MQ_CLK_25M 2 +#define IMX8MQ_CLK_27M 3 +#define IMX8MQ_CLK_EXT14 +#define IMX8MQ_CLK_EXT25 +#define IMX8MQ_CLK_EXT36 +#define IMX8MQ_CLK_EXT47 + +/* ANAMIX PLL clocks */ +/* FRAC PLLs */ +/* ARM PLL */ +#define IMX8MQ_ARM_PLL_REF_SEL 8 +#define IMX8MQ_ARM_PLL_REF_DIV 9 +#define IMX8MQ_ARM_PLL 10 +#define IMX8MQ_ARM_PLL_BYPASS 11 +#define IMX8MQ_ARM_PLL_OUT 12 + +/* GPU PLL */ +#define IMX8MQ_GPU_PLL_REF_SEL 13 +#define IMX8MQ_GPU_PLL_REF_DIV 14 +#define IMX8MQ_GPU_PLL 15 +#define IMX8MQ_GPU_PLL_BYPASS 16 +#define IMX8MQ_GPU_PLL_OUT 17 + +/* VPU PLL */ +#define IMX8MQ_VPU_PLL_REF_SEL 18 +#define IMX8MQ_VPU_PLL_REF_DIV 19 +#define IMX8MQ_VPU_PLL 20 +#define IMX8MQ_VPU_PLL_BYPASS 21 +#define IMX8MQ_VPU_PLL_OUT 22 + +/* AUDIO PLL1 */ +#define IMX8MQ_AUDIO_PLL1_REF_SEL 23 +#define IMX8MQ_AUDIO_PLL1_REF_DIV 24 +#define IMX8MQ_AUDIO_PLL1 25 +#define IMX8MQ_AUDIO_PLL1_BYPASS 26 +#define IMX8MQ_AUDIO_PLL1_OUT 27 + +/* AUDIO PLL2 */ +#define IMX8MQ_AUDIO_PLL2_REF_SEL 28 +#define IMX8MQ_AUDIO_PLL2_REF_DIV 29 +#define IMX8MQ_AUDIO_PLL2 30 +#define IMX8MQ_AUDIO_PLL2_BYPASS 31 +#define IMX8MQ_AUDIO_PLL2_OUT 32 + +/* VIDEO PLL1 */ +#define IMX8MQ_VIDEO_PLL1_REF_SEL 33 +#define IMX8MQ_VIDEO_PLL1_REF_DIV 34 +#define IMX8MQ_VIDEO_PLL1 35 +#define IMX8MQ_VIDEO_PLL1_BYPASS 36 +#define IMX8MQ_VIDEO_PLL1_OUT 37 + +/* SYS1 PLL */ +#define IMX8MQ_SYS1_PLL1_REF_SEL 38 +#define IMX8MQ_SYS1_PLL1_REF_DIV 39 +#define IMX8MQ_SYS1_PLL1 40 +#define IMX8MQ_SYS1_PLL1_OUT 41 +#define IMX8MQ_SYS1_PLL1_OUT_DIV 42 +#define IMX8MQ_SYS1_PLL2 43 +#define IMX8MQ_SYS1_PLL2_DIV 44 +#define IMX8MQ_SYS1_PLL2_OUT 45 + +/* SYS2 PLL */ +#define IMX8MQ_SYS2_PLL1_REF_SEL 46 +#define IMX8MQ_SYS2_PLL1_REF_DIV 47 +#define IMX8MQ_SYS2_PLL1 48 +#define IMX8MQ_SYS2_PLL1_OUT 49 +#define IMX8MQ_SYS2_PLL1_OUT_DIV 50 +#define IMX8MQ_SYS2_PLL2 51 +#define IMX8MQ_SYS2_PLL2_DIV 52 +#define IMX8MQ_SYS2_PLL2_OUT 53 + +/* SYS3 PLL */ +#define IMX8MQ_SYS3_PLL1_REF_SEL 54 +#define IMX8MQ_SYS3_PLL1_REF_DIV 55 +#define IMX8MQ_SYS3_PLL1 56 +#define IMX8MQ_SYS3_PLL1_OUT 57 +#define IMX8MQ_SYS3_PLL1_OUT_DIV 58 +#define IMX8MQ_SYS3_PLL2 59 +#define IMX8MQ_SYS3_PLL2_DIV 60 +#define IMX8MQ_SYS3_PLL2_OUT 61 + +/* DRAM PLL */ +#define IMX8MQ_DRAM_PLL1_REF_SEL 62 +#define IMX8MQ_DRAM_PLL1_REF_DIV 63 +#define IMX8MQ_DRAM_PLL1 64 +#define IMX8MQ
[RESEND v5 0/5] Add i.MX8MQ clock driver
Resent this time on the right list (linux-clk instead of linux-gpio). Fourth version can be found here: https://lore.kernel.org/patchwork/cover/974998/ Changes since v4: * Implemented divider ops and used clk-composite as suggested by Sascha Hauer. Changes since v3: * Added a composite clock type to get rid of some complexity from clk-imx8mq. This new composite clock type will also be used by all the imx8 socs that will follow. * Added back the reviewed-by tag. Abel Vesa (1): clk: imx: add imx composite clock Lucas Stach (4): dt-bindings: add binding for i.MX8MQ CCM clk: imx: add fractional PLL output clock clk: imx: add SCCG PLL type clk: imx: add clock driver for i.MX8MQ CCM .../devicetree/bindings/clock/imx8mq-clock.txt | 20 + drivers/clk/imx/Makefile | 6 +- drivers/clk/imx/clk-composite.c| 126 drivers/clk/imx/clk-frac-pll.c | 230 drivers/clk/imx/clk-imx8mq.c | 631 + drivers/clk/imx/clk-sccg-pll.c | 231 drivers/clk/imx/clk.h | 57 ++ include/dt-bindings/clock/imx8mq-clock.h | 410 + 8 files changed, 1710 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/clock/imx8mq-clock.txt create mode 100644 drivers/clk/imx/clk-composite.c create mode 100644 drivers/clk/imx/clk-frac-pll.c create mode 100644 drivers/clk/imx/clk-imx8mq.c create mode 100644 drivers/clk/imx/clk-sccg-pll.c create mode 100644 include/dt-bindings/clock/imx8mq-clock.h -- 2.7.4
[RESEND v5 4/5] clk: imx: add imx composite clock
Since a lot of clocks on imx8 are formed by a mux, gate, predivider and divider, the idea here is to combine all of those into one more complex clock type, therefore moving the complexity inside the composite clock and outside of the SoC specific clock driver. Signed-off-by: Abel Vesa Suggested-by: Sascha Hauer --- drivers/clk/imx/Makefile| 1 + drivers/clk/imx/clk-composite.c | 126 drivers/clk/imx/clk.h | 9 +++ 3 files changed, 136 insertions(+) create mode 100644 drivers/clk/imx/clk-composite.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index b87513c..4fabb0a 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -3,6 +3,7 @@ obj-y += \ clk.o \ clk-busy.o \ + clk-composite.o \ clk-cpu.o \ clk-fixup-div.o \ clk-fixup-mux.o \ diff --git a/drivers/clk/imx/clk-composite.c b/drivers/clk/imx/clk-composite.c new file mode 100644 index 000..717c6f1 --- /dev/null +++ b/drivers/clk/imx/clk-composite.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +#include +#include +#include +#include + +#include "clk.h" + +#define PCG_PREDIV_SHIFT 16 +#define PCG_PREDIV_WIDTH 3 + +#define PCG_DIV_SHIFT 0 +#define PCG_DIV_WIDTH 6 + +#define PCG_PCS_SHIFT 24 +#define PCG_PCS_MASK 0x7 + +#define PCG_CGC_SHIFT 28 + +static unsigned long imx_clk_composite_divider_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return clk_divider_ops.recalc_rate(hw, parent_rate); +} + +static long imx_clk_composite_divider_round_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long *prate) +{ + return clk_divider_ops.round_rate(hw, rate, prate); +} + +static int imx_clk_composite_divider_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + int value; + unsigned long flags = 0; + u32 val; + + value = divider_get_val(rate, parent_rate, NULL, + PCG_PREDIV_WIDTH, CLK_DIVIDER_ROUND_CLOSEST); + if (value < 0) + return value; + + spin_lock_irqsave(divider->lock, flags); + + val = clk_readl(divider->reg); + val &= ~((clk_div_mask(divider->width) << divider->shift) | + (clk_div_mask(PCG_DIV_WIDTH) << PCG_DIV_SHIFT)); + + val |= (u32)value << divider->shift; + val |= (u32)value << PCG_DIV_SHIFT; + clk_writel(val, divider->reg); + + spin_unlock_irqrestore(divider->lock, flags); + + return 0; +} + +static const struct clk_ops imx_clk_composite_divider_ops = { + .recalc_rate = imx_clk_composite_divider_recalc_rate, + .round_rate = imx_clk_composite_divider_round_rate, + .set_rate = imx_clk_composite_divider_set_rate, +}; + +struct clk *imx_clk_composite_flags(const char *name, + const char **parent_names, + int num_parents, void __iomem *reg, + unsigned long flags) +{ + struct clk_hw *mux_hw = NULL, *div_hw = NULL, *gate_hw = NULL; + struct clk_divider *div = NULL; + struct clk_gate *gate = NULL; + struct clk_mux *mux = NULL; + struct clk *clk; + + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) + return ERR_PTR(-ENOMEM); + mux_hw = &mux->hw; + mux->reg = reg; + mux->shift = PCG_PCS_SHIFT; + mux->mask = PCG_PCS_MASK; + + div = kzalloc(sizeof(*div), GFP_KERNEL); + if (!div) { + kfree(mux); + return ERR_PTR(-ENOMEM); + } + div_hw = &div->hw; + div->reg = reg; + div->shift = PCG_PREDIV_SHIFT; + div->width = PCG_PREDIV_WIDTH; + div->lock = &imx_ccm_lock; + div->flags = CLK_DIVIDER_ROUND_CLOSEST; + + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) { + kfree(mux); + kfree(div); + return ERR_PTR(-ENOMEM); + } + gate_hw = &gate->hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + + flags |= CLK_SET_RATE_NO_REPARENT | CLK_OPS_PARENT_ENABLE; + + clk = clk_register_composite(NULL, name, parent_names, num_parents, + mux_hw, &clk_mux_ops, div_hw, + &imx_clk_composite_divider_ops, gate_hw, + &cl
[RESEND v5 5/5] clk: imx: add clock driver for i.MX8MQ CCM
From: Lucas Stach Add driver for the Clock Control Module found on i.MX8MQ. This is largely based on the downstream driver from Anson Huang and Bai Ping at NXP, with only some small adaptions to mainline from me. Signed-off-by: Lucas Stach Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx8mq.c | 631 +++ drivers/clk/imx/clk.h| 36 +++ 3 files changed, 668 insertions(+) create mode 100644 drivers/clk/imx/clk-imx8mq.c diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 4fabb0a..64e695c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o +obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 000..d3a9e31 --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,631 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP. + * Copyright (C) 2017 Pengutronix, Lucas Stach + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static u32 share_count_sai1; +static u32 share_count_sai2; +static u32 share_count_sai3; +static u32 share_count_sai4; +static u32 share_count_sai5; +static u32 share_count_sai6; +static u32 share_count_dcss; +static u32 share_count_nand; + +static struct clk *clks[IMX8MQ_CLK_END]; + +static const char *pll_ref_sels[] = { "osc_25m", "osc_27m", "dummy", "dummy", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; +static const char *sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; +static const char *sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; +static const char *dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; +static const char *video2_pll1_out_sels[] = {"video2_pll1", "video2_pll1_ref_sel", }; + +static const char *sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", }; +static const char *sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", }; +static const char *sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", }; +static const char *dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", }; +static const char *video2_pll2_out_sels[] = {"video2_pll2_div", "video2_pll1_ref_sel", }; + +/* CCM ROOT */ +static const char *imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "sys3_pll2_out", }; + +static const char *imx8mq_vpu_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", + "sys1_pll_800m", "sys1_pll_400m", "audio_pll1_out", "vpu_pll_out", }; + +static const char *imx8mq_gpu_core_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_gpu_shader_sels[] = {"osc_25m", "gpu_pll_out", "sys1_pll_800m", "sys3_pll2_out", + "sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "audio_pll2_out", }; + +static const char *imx8mq_main_axi_sels[] = {"osc_25m", "sys2_pll_333m", "sys1_pll_800m", "sys2_pll_250m", +"sys2_pll_1000m", "audio_pll1_out", "video_pll1_out", "sys1_pll_100m",}; + +static const ch
[PATCH 0/3] i.MX8MQ build dependency fixes
These patches will probably have to be take through different trees, but the order has to be kept otherwise this won't work. I can resend as separate patches (if necessary) as long as we can get them in together. Abel Vesa (3): arm64: Remove CONFIG_SOC_IMX8MQ and use ARCH_MXC instead clk: imx: Build imx8mq clocks on arm64 only arm64: Add i.MX8 boot necesarry configs to defconfig arch/arm64/Kconfig.platforms | 8 arch/arm64/boot/dts/freescale/Makefile | 2 +- arch/arm64/configs/defconfig | 5 + drivers/clk/imx/Makefile | 11 ++- drivers/phy/freescale/Kconfig | 2 +- drivers/pinctrl/freescale/Kconfig | 2 +- drivers/soc/imx/Kconfig| 2 +- 7 files changed, 15 insertions(+), 17 deletions(-) -- 2.7.4
[PATCH 2/3] clk: imx: Build imx8mq clocks on arm64 only
The composite-8m, frac and sccg clocks are not used by any arm32 IMX SoC, therefore build them only on arm64. CONFIG_ARCH_MXC is arm64 only, use that. Signed-off-by: Abel Vesa --- drivers/clk/imx/Makefile | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 62a1882..cc95744 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -3,13 +3,11 @@ obj-y += \ clk.o \ clk-busy.o \ - clk-composite-8m.o \ clk-cpu.o \ clk-composite-7ulp.o \ clk-divider-gate.o \ clk-fixup-div.o \ clk-fixup-mux.o \ - clk-frac-pll.o \ clk-gate-exclusive.o \ clk-gate2.o \ clk-pfd.o \ @@ -17,8 +15,7 @@ obj-y += \ clk-pllv1.o \ clk-pllv2.o \ clk-pllv3.o \ - clk-pllv4.o \ - clk-sccg-pll.o + clk-pllv4.o obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o @@ -36,4 +33,7 @@ obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o -obj-$(CONFIG_ARCH_MXC) += clk-imx8mq.o +obj-$(CONFIG_ARCH_MXC) += clk-imx8mq.o \ + clk-composite-8m.o \ + clk-frac-pll.o \ + clk-sccg-pll.o -- 2.7.4
[PATCH 1/3] arm64: Remove CONFIG_SOC_IMX8MQ and use ARCH_MXC instead
To keep aligned with arm64, remove the unnecessary SOC_IMX8MQ and use ARCH_MXC instead. Signed-off-by: Abel Vesa --- arch/arm64/Kconfig.platforms | 8 arch/arm64/boot/dts/freescale/Makefile | 2 +- drivers/clk/imx/Makefile | 3 ++- drivers/phy/freescale/Kconfig | 2 +- drivers/pinctrl/freescale/Kconfig | 2 +- drivers/soc/imx/Kconfig| 2 +- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 7e1545a..318dbb9 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -148,14 +148,6 @@ config ARCH_MXC This enables support for the ARMv8 based SoCs in the NXP i.MX family. -config SOC_IMX8MQ - bool "i.MX8MQ support" - depends on ARCH_MXC - select ARM64_ERRATUM_843419 - select ARM64_ERRATUM_845719 - help - This enables support for the i.MX8MQ SoC. - config ARCH_QCOM bool "Qualcomm Platforms" select GPIOLIB diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile index 0001361..f9be242 100644 --- a/arch/arm64/boot/dts/freescale/Makefile +++ b/arch/arm64/boot/dts/freescale/Makefile @@ -19,4 +19,4 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a-rdb.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-qds.dtb dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb -dtb-$(CONFIG_SOC_IMX8MQ) += imx8mq-evk.dtb +dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 5c0b11e..62a1882 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -34,5 +34,6 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o -obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o + +obj-$(CONFIG_ARCH_MXC) += clk-imx8mq.o diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index f050bd4..923c0ef 100644 --- a/drivers/phy/freescale/Kconfig +++ b/drivers/phy/freescale/Kconfig @@ -2,4 +2,4 @@ config PHY_FSL_IMX8MQ_USB tristate "Freescale i.MX8M USB3 PHY" depends on OF && HAS_IOMEM select GENERIC_PHY - default SOC_IMX8MQ + default ARCH_MXC diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 2d6db43..9874a16 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -123,7 +123,7 @@ config PINCTRL_IMX7ULP config PINCTRL_IMX8MQ bool "IMX8MQ pinctrl driver" - depends on SOC_IMX8MQ + depends on ARCH_MXC select PINCTRL_IMX help Say Y here to enable the imx8mq pinctrl driver diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index 2112d18..7ffbb6b 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -2,7 +2,7 @@ menu "i.MX SoC drivers" config IMX_GPCV2_PM_DOMAINS bool "i.MX GPCv2 PM domains" - depends on SOC_IMX7D || SOC_IMX8MQ || (COMPILE_TEST && OF) + depends on SOC_IMX7D || ARCH_MXC || (COMPILE_TEST && OF) depends on PM select PM_GENERIC_DOMAINS default y if SOC_IMX7D -- 2.7.4
[PATCH 3/3] arm64: Add i.MX8 boot necesarry configs to defconfig
The CONFIG_ARCH_MXC will enable all the i.MX8 SoC. Also add the FEC config for ethernet support, the serial and the pinctrl for i.MX8MQ. Signed-off-by: Abel Vesa --- arch/arm64/configs/defconfig | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 5c2b1f6..a129e5e 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -45,6 +45,7 @@ CONFIG_ARCH_HISI=y CONFIG_ARCH_MEDIATEK=y CONFIG_ARCH_MESON=y CONFIG_ARCH_MVEBU=y +CONFIG_ARCH_MXC=y CONFIG_ARCH_QCOM=y CONFIG_ARCH_ROCKCHIP=y CONFIG_ARCH_SEATTLE=y @@ -226,6 +227,7 @@ CONFIG_NET_XGENE=y CONFIG_ATL1C=m CONFIG_MACB=y CONFIG_THUNDER_NIC_PF=y +CONFIG_FEC=y CONFIG_HIX5HD2_GMAC=y CONFIG_HNS_DSAF=y CONFIG_HNS_ENET=y @@ -300,6 +302,8 @@ CONFIG_SERIAL_MESON_CONSOLE=y CONFIG_SERIAL_SAMSUNG=y CONFIG_SERIAL_SAMSUNG_CONSOLE=y CONFIG_SERIAL_TEGRA=y +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y CONFIG_SERIAL_SH_SCI=y CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_CONSOLE=y @@ -346,6 +350,7 @@ CONFIG_SPI_SPIDEV=m CONFIG_SPMI=y CONFIG_PINCTRL_SINGLE=y CONFIG_PINCTRL_MAX77620=y +CONFIG_PINCTRL_IMX8MQ=y CONFIG_PINCTRL_IPQ8074=y CONFIG_PINCTRL_MSM8916=y CONFIG_PINCTRL_MSM8994=y -- 2.7.4
Re: [PATCH 0/3] i.MX8MQ build dependency fixes
On 18-12-13 13:17:40, Abel Vesa wrote: > These patches will probably have to be take through different > trees, but the order has to be kept otherwise this won't work. > > I can resend as separate patches (if necessary) as long as we can > get them in together. > Please ignore this patch series. Seems ARCH_MXC is a poor choice. Needs a proper look. Sorry about that. > Abel Vesa (3): > arm64: Remove CONFIG_SOC_IMX8MQ and use ARCH_MXC instead > clk: imx: Build imx8mq clocks on arm64 only > arm64: Add i.MX8 boot necesarry configs to defconfig > > arch/arm64/Kconfig.platforms | 8 > arch/arm64/boot/dts/freescale/Makefile | 2 +- > arch/arm64/configs/defconfig | 5 + > drivers/clk/imx/Makefile | 11 ++- > drivers/phy/freescale/Kconfig | 2 +- > drivers/pinctrl/freescale/Kconfig | 2 +- > drivers/soc/imx/Kconfig| 2 +- > 7 files changed, 15 insertions(+), 17 deletions(-) > > -- > 2.7.4 >
Re: [PATCH 1/3] arm64: Remove CONFIG_SOC_IMX8MQ and use ARCH_MXC instead
On 18-12-13 15:35:27, Lucas Stach wrote: > Am Donnerstag, den 13.12.2018, 13:17 + schrieb Abel Vesa: > > To keep aligned with arm64, remove the unnecessary SOC_IMX8MQ and use > > ARCH_MXC instead. > > > > Signed-off-by: Abel Vesa > > --- > > arch/arm64/Kconfig.platforms | 8 > > arch/arm64/boot/dts/freescale/Makefile | 2 +- > > drivers/clk/imx/Makefile | 3 ++- > > drivers/phy/freescale/Kconfig | 2 +- > > drivers/pinctrl/freescale/Kconfig | 2 +- > > drivers/soc/imx/Kconfig| 2 +- > > 6 files changed, 6 insertions(+), 13 deletions(-) > > > > diff --git a/arch/arm64/Kconfig.platforms > > b/arch/arm64/Kconfig.platforms > > index 7e1545a..318dbb9 100644 > > --- a/arch/arm64/Kconfig.platforms > > +++ b/arch/arm64/Kconfig.platforms > > @@ -148,14 +148,6 @@ config ARCH_MXC > > This enables support for the ARMv8 based SoCs in the > > NXP i.MX family. > > > > -config SOC_IMX8MQ > > - bool "i.MX8MQ support" > > - depends on ARCH_MXC > > - select ARM64_ERRATUM_843419 > > - select ARM64_ERRATUM_845719 > > - help > > - This enables support for the i.MX8MQ SoC. > > - > > NACK on this one. Having a single place where stuff that is absolutely > critical for proper SoC operation can be selected is very useful and > avoids hard to debug issues due to slightly wrong configs in the long > run. As mentioned in the cover letter, please ignore this patch set entirely. The ARCH_MXC is actually used on arm32 too, so it won't work. I'm working on a patchset that will add the Kconfig into drivers/clk/imx/ and in it will add CLK_IMX8MQ. That will fix the clock dependency since the CLK_IMX8MQ will depend on ARCH_MXC and ARM64. I believe the CLK_IMX8QXP will follow the same pattern. As for the SOC_IMX8MQ, all the other vendors have one single config for all the arm64 platforms. TBH, to control every SoC independently it's a little bit of an overkill. But maybe I'm the only one who thinks so. > > Regards, > Lucas > > > config ARCH_QCOM > > bool "Qualcomm Platforms" > > select GPIOLIB > > diff --git a/arch/arm64/boot/dts/freescale/Makefile > > b/arch/arm64/boot/dts/freescale/Makefile > > index 0001361..f9be242 100644 > > --- a/arch/arm64/boot/dts/freescale/Makefile > > +++ b/arch/arm64/boot/dts/freescale/Makefile > > @@ -19,4 +19,4 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2088a- > > rdb.dtb > > dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-qds.dtb > > dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-lx2160a-rdb.dtb > > > > -dtb-$(CONFIG_SOC_IMX8MQ) += imx8mq-evk.dtb > > +dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb > > diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile > > index 5c0b11e..62a1882 100644 > > --- a/drivers/clk/imx/Makefile > > +++ b/drivers/clk/imx/Makefile > > @@ -34,5 +34,6 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o > > obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o > > obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o > > obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o > > -obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o > > obj-$(CONFIG_SOC_VF610) += clk-vf610.o > > + > > +obj-$(CONFIG_ARCH_MXC) += clk-imx8mq.o > > diff --git a/drivers/phy/freescale/Kconfig > > b/drivers/phy/freescale/Kconfig > > index f050bd4..923c0ef 100644 > > --- a/drivers/phy/freescale/Kconfig > > +++ b/drivers/phy/freescale/Kconfig > > @@ -2,4 +2,4 @@ config PHY_FSL_IMX8MQ_USB > > tristate "Freescale i.MX8M USB3 PHY" > > depends on OF && HAS_IOMEM > > select GENERIC_PHY > > - default SOC_IMX8MQ > > + default ARCH_MXC > > diff --git a/drivers/pinctrl/freescale/Kconfig > > b/drivers/pinctrl/freescale/Kconfig > > index 2d6db43..9874a16 100644 > > --- a/drivers/pinctrl/freescale/Kconfig > > +++ b/drivers/pinctrl/freescale/Kconfig > > @@ -123,7 +123,7 @@ config PINCTRL_IMX7ULP > > > > config PINCTRL_IMX8MQ > > bool "IMX8MQ pinctrl driver" > > - depends on SOC_IMX8MQ > > + depends on ARCH_MXC > > select PINCTRL_IMX > > help > > Say Y here to enable the imx8mq pinctrl driver > > diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig > > index 2112d18..7ffbb6b 100644 > > --- a/drivers/soc/imx/Kconfig > > +++ b/drivers/soc/imx/Kconfig > > @@ -2,7 +2,7 @@ menu "i.MX SoC drivers" > > > > config IMX_GPCV2_PM_DOMAINS > > bool "i.MX GPCv2 PM domains" > > - depends on SOC_IMX7D || SOC_IMX8MQ || (COMPILE_TEST && OF) > > + depends on SOC_IMX7D || ARCH_MXC || (COMPILE_TEST && OF) > > depends on PM > > select PM_GENERIC_DOMAINS > > default y if SOC_IMX7D
[PATCH] clk: imx: Make the i.MX8MQ CCM clock driver CLK_IMX8MQ dependant
Remove the dependency between the i.MX8MQ CCM clock driver and the CONFIG_SOC_IMX8MQ and use CONFIG_CLK_IMX8MQ instead. CONFIG_CLK_IMX8MQ depends on ARCH_MXC && ARM64. Signed-off-by: Abel Vesa --- drivers/clk/Kconfig | 1 + drivers/clk/imx/Kconfig | 5 + drivers/clk/imx/Makefile | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/Kconfig diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 2dc12bf..833353c 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -293,6 +293,7 @@ config COMMON_CLK_BD718XX source "drivers/clk/actions/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" +source "drivers/clk/imx/Kconfig" source "drivers/clk/imgtec/Kconfig" source "drivers/clk/ingenic/Kconfig" source "drivers/clk/keystone/Kconfig" diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig new file mode 100644 index 000..98ede6a --- /dev/null +++ b/drivers/clk/imx/Kconfig @@ -0,0 +1,5 @@ +config CLK_IMX8MQ + bool "IMX8MQ CCM Clock Driver" + depends on ARCH_MXC && ARM64 + help + Build the driver for i.MX8MQ CCM Clock Driver diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 5c0b11e..01e5f55 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -34,5 +34,6 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o -obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o + +obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o -- 2.7.4
Re: [PATCH 0/3] clk: imx: Make all the parent_names arrays be const pointers
On 18-12-17 10:40:52, Stephen Boyd wrote: > Quoting Abel Vesa (2018-12-17 03:35:40) > > On 18-12-14 13:08:37, Stephen Boyd wrote: > > > Quoting Abel Vesa (2018-12-14 07:30:08) > > > > This is mainly to shut up the checkpatch.pl script warnings about the > > > > "static const char *" needing to be "static const char * const". > > > > > > > > Abel Vesa (3): > > > > clk: imx: Make parent_names const pointer in composite-8m > > > > clk: imx: Make parents const pointer in mux wrappers > > > > clk: imx8mq: Make parent names arrays const pointers > > > > > > > > > > I still see warnings though so there seems to be some more work to do. > > > > > > drivers/clk/imx/clk-imx8mq.c:401:89: warning: passing argument 5 of > > > 'imx_clk_mux2' discards 'const' qualifier from pointer target type > > > [-Wdiscarded-qualifiers] > > > clks[IMX8MQ_CLK_GPU_SHADER_SRC] = imx_clk_mux2("gpu_shader_src", base + > > > 0x8200, 24, 3, imx8mq_gpu_shader_sels, > > > ARRAY_SIZE(imx8mq_gpu_shader_sels)); > > > > > Hmm, I guess you applied this on top of clk-imx8mq, right ? > > This change is against linux-next. The actual problem is the imx_clk_mux2 > > which looks like this on branch clk-imx8mq: > > Yes. It would be great if you could indicate where patches are > generated. In fact, I see that 'git format-patch' now has an option to > do just this! > > git format-patch --base=commit > Sorry about that. Will do that in the future. > > > > static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, > > > > u8 shift, u8 width, const char **parents, int num_parents) > > > > > > but it looks like this on linux-next (which is exactly the same on > > clk-next): > > > > static inline struct clk *imx_clk_mux2(const char *name, void __iomem *reg, > > > > u8 shift, u8 width, const char * const *parents, > > > > int num_parents) > > > > Hrmm ok. I'll have to rejigger things and I probably won't be getting to > it until early next year. > I can rebase it on clk-imx8mq and resend if you want.
Re: [PATCH 1/3] arm64: Remove CONFIG_SOC_IMX8MQ and use ARCH_MXC instead
On 18-12-14 10:22:11, Lucas Stach wrote: > Hi Shawn, > > Am Freitag, den 14.12.2018, 09:12 +0800 schrieb Shawn Guo: > > On Thu, Dec 13, 2018 at 02:51:50PM +, Abel Vesa wrote: > > ... > > > > > diff --git a/arch/arm64/Kconfig.platforms > > > > > b/arch/arm64/Kconfig.platforms > > > > > index 7e1545a..318dbb9 100644 > > > > > --- a/arch/arm64/Kconfig.platforms > > > > > +++ b/arch/arm64/Kconfig.platforms > > > > > @@ -148,14 +148,6 @@ config ARCH_MXC > > > > > > > > > This enables support for the ARMv8 based SoCs in the > > > > > > > > > NXP i.MX family. > > > > > > > > > > -config SOC_IMX8MQ > > > > > > > > > - bool "i.MX8MQ support" > > > > > > > > > - depends on ARCH_MXC > > > > > > > > > - select ARM64_ERRATUM_843419 > > > > > > > > > - select ARM64_ERRATUM_845719 > > > > > > > > > - help > > > > > > > > > - This enables support for the i.MX8MQ SoC. > > > > > - > > > > > > > > NACK on this one. Having a single place where stuff that is absolutely > > > > critical for proper SoC operation can be selected is very useful and > > > > avoids hard to debug issues due to slightly wrong configs in the long > > > > run. > > > > > > As mentioned in the cover letter, please ignore this patch set entirely. > > > The ARCH_MXC is actually used on arm32 too, so it won't work. > > > > > > I'm working on a patchset that will add the Kconfig into > > > drivers/clk/imx/ and in it will add CLK_IMX8MQ. That will > > > fix the clock dependency since the CLK_IMX8MQ will depend on > > > ARCH_MXC and ARM64. I believe the CLK_IMX8QXP will follow > > > the same pattern. > > > > > > As for the SOC_IMX8MQ, all the other vendors have one single > > > config for all the arm64 platforms. TBH, to control every SoC > > > independently it's a little bit of an overkill. > > > > Lucas, > > > > We are still waiting for further comments from Olof [1]. But it sounds > > like SoC specific option is not welcomed on ARM64. > > While I personally would prefer to keep the SoC options, I see that we > need to align with the judgment of the arm-soc maintainers. > > But at the very least we should keep the select for vital system > workarounds. They need to move to the arch Kconfig symbol in that case > and might select stuff that isn't needed on each of the i.MX8 SoCs. But > better enabling more workaround and drivers than necessary than having > hard to debug system failures in the future. > I get your point. But that seems to be an issue with the whole arm64 approach. TBH, I believe now would be the perfect time to "get it right" on IMX since the 8MQ is the first one to get boot-up support upstream. It will be way much harder to change this later when more arm64 IMX SoCs get upstreamed. I would really love more opinions on this. I have patches on stand-by that remove the SOC_IMX8MQ in all the subsystems and a patch for the defconfig update which I'll keep on holding on to until there is a agreement on this. > Regards, > Lucas
[PATCH v2] clk: imx: Make the i.MX8MQ CCM clock driver CLK_IMX8MQ dependant
Remove the dependency between the i.MX8MQ CCM clock driver and the CONFIG_SOC_IMX8MQ and use CONFIG_CLK_IMX8MQ instead. CONFIG_CLK_IMX8MQ depends on ARCH_MXC && ARM64. Signed-off-by: Abel Vesa --- Changes since v1: * reordered the CONFIGs in clk/imx/Makefile as suggested by Daniel and Shawn drivers/clk/Kconfig | 1 + drivers/clk/imx/Kconfig | 5 + drivers/clk/imx/Makefile | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/imx/Kconfig diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 2dc12bf..833353c 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -293,6 +293,7 @@ config COMMON_CLK_BD718XX source "drivers/clk/actions/Kconfig" source "drivers/clk/bcm/Kconfig" source "drivers/clk/hisilicon/Kconfig" +source "drivers/clk/imx/Kconfig" source "drivers/clk/imgtec/Kconfig" source "drivers/clk/ingenic/Kconfig" source "drivers/clk/keystone/Kconfig" diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig new file mode 100644 index 000..98ede6a --- /dev/null +++ b/drivers/clk/imx/Kconfig @@ -0,0 +1,5 @@ +config CLK_IMX8MQ + bool "IMX8MQ CCM Clock Driver" + depends on ARCH_MXC && ARM64 + help + Build the driver for i.MX8MQ CCM Clock Driver diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 5c0b11e..7e55a4b 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -20,6 +20,8 @@ obj-y += \ clk-pllv4.o \ clk-sccg-pll.o +obj-$(CONFIG_CLK_IMX8MQ) += clk-imx8mq.o + obj-$(CONFIG_SOC_IMX1) += clk-imx1.o obj-$(CONFIG_SOC_IMX21) += clk-imx21.o obj-$(CONFIG_SOC_IMX25) += clk-imx25.o @@ -34,5 +36,5 @@ obj-$(CONFIG_SOC_IMX6SX) += clk-imx6sx.o obj-$(CONFIG_SOC_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_SOC_IMX7D) += clk-imx7d.o obj-$(CONFIG_SOC_IMX7ULP) += clk-imx7ulp.o -obj-$(CONFIG_SOC_IMX8MQ) += clk-imx8mq.o obj-$(CONFIG_SOC_VF610) += clk-vf610.o + -- 2.7.4
[PATCH 0/3] clk: imx: Make all the parent_names arrays be const pointers
This is mainly to shut up the checkpatch.pl script warnings about the "static const char *" needing to be "static const char * const". Abel Vesa (3): clk: imx: Make parent_names const pointer in composite-8m clk: imx: Make parents const pointer in mux wrappers clk: imx8mq: Make parent names arrays const pointers drivers/clk/imx/clk-composite-8m.c | 2 +- drivers/clk/imx/clk-imx8mq.c | 194 ++--- drivers/clk/imx/clk.h | 5 +- 3 files changed, 101 insertions(+), 100 deletions(-) -- 2.7.4
[PATCH 1/3] clk: imx: Make parent_names const pointer in composite-8m
The parent_names needs to be pointer to const pointer to const char. Signed-off-by: Abel Vesa --- drivers/clk/imx/clk-composite-8m.c | 2 +- drivers/clk/imx/clk.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c index 527ade1..574fac1 100644 --- a/drivers/clk/imx/clk-composite-8m.c +++ b/drivers/clk/imx/clk-composite-8m.c @@ -123,7 +123,7 @@ static const struct clk_ops imx8m_clk_composite_divider_ops = { }; struct clk *imx8m_clk_composite_flags(const char *name, - const char **parent_names, + const char * const *parent_names, int num_parents, void __iomem *reg, unsigned long flags) { diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 028312d..1363dbe 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -354,7 +354,7 @@ struct clk *imx_clk_cpu(const char *name, const char *parent_name, struct clk *step); struct clk *imx8m_clk_composite_flags(const char *name, - const char **parent_names, + const char * const *parent_names, int num_parents, void __iomem *reg, unsigned long flags); -- 2.7.4
[PATCH 2/3] clk: imx: Make parents const pointer in mux wrappers
The parents needs to be pointer to const pointer to const char. Signed-off-by: Abel Vesa --- drivers/clk/imx/clk.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 1363dbe..2e442d8 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -329,7 +329,8 @@ static inline struct clk *imx_clk_mux_flags(const char *name, } static inline struct clk *imx_clk_mux2_flags(const char *name, - void __iomem *reg, u8 shift, u8 width, const char **parents, + void __iomem *reg, u8 shift, u8 width, + const char * const *parents, int num_parents, unsigned long flags) { return clk_register_mux(NULL, name, parents, num_parents, -- 2.7.4