mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: Andrey Smirnov <andrew.smirnov@gmail.com>
Cc: barebox@lists.infradead.org
Subject: Re: [PATCH 06/16] i.MX: vf610: Ramp CPU clock to maximum frequency
Date: Wed, 7 Dec 2016 20:27:33 +0100	[thread overview]
Message-ID: <20161207192733.l3w4nc2s5cz47d22@pengutronix.de> (raw)
In-Reply-To: <1480949684-18520-7-git-send-email-andrew.smirnov@gmail.com>

On Mon, Dec 05, 2016 at 06:54:34AM -0800, Andrey Smirnov wrote:
> Mask ROM leaves the CPU running at 264Mhz, so configure the clock tree
> to such that CPU runs at maximum supported frequency, based on speed
> grading burned into OCOTP fusebox.
> 
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  arch/arm/mach-imx/Kconfig   |  13 +++
>  drivers/clk/imx/clk-vf610.c | 187 +++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 198 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
> index af533ea..1752335 100644
> --- a/arch/arm/mach-imx/Kconfig
> +++ b/arch/arm/mach-imx/Kconfig
> @@ -750,6 +750,19 @@ config HABV3_IMG_CRT_DER
>  
>  endif
>  
> +config ADJUST_CPU_CLOCK
> +       bool "Adjust CPU clock based on its speed grading"
> +       select IMX_OCOTP
> +       depends on ARCH_VF610
> +       default y
> +       help
> +	  Some i.MX SoCs (e. g. Vybrid) are manufactured to have
> +	  several variants of the same chip different only in maxumum

s/maxumum/maximum/

> +	  CPU frequency supported. MaskROM on such chips plays it safe
> +	  and uses the lowest possible frequency. This option
> +	  configures Barebox to read chip's speed grade information
> +	  and increase CPU clock to it's highest possible value.

Why do we need this configurable?

> +
>  endmenu
>  
>  endif
> diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c
> index 04cb02f..1cf2b65 100644
> --- a/drivers/clk/imx/clk-vf610.c
> +++ b/drivers/clk/imx/clk-vf610.c
> @@ -16,7 +16,9 @@
>  #include <of_address.h>
>  #include <linux/clkdev.h>
>  #include <linux/clk.h>
> +#include <notifier.h>
>  #include <dt-bindings/clock/vf610-clock.h>
> +#include <mach/vf610-regs.h>
>  
>  #include "clk.h"
>  
> @@ -76,6 +78,7 @@
>  #define PLL6_CTRL		(anatop_base + 0xa0)
>  #define PLL7_CTRL		(anatop_base + 0x20)
>  #define ANA_MISC1		(anatop_base + 0x160)
> +#define PLL_LOCK		(anatop_base + 0x2c0)
>  
>  static void __iomem *anatop_base;
>  static void __iomem *ccm_base;
> @@ -188,8 +191,9 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
>  	clk[VF610_CLK_PLL6_BYPASS_SRC] = imx_clk_mux("pll6_bypass_src", PLL6_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
>  	clk[VF610_CLK_PLL7_BYPASS_SRC] = imx_clk_mux("pll7_bypass_src", PLL7_CTRL, 14, 1, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
>  
> -	clk[VF610_CLK_PLL1] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1);
> -	clk[VF610_CLK_PLL2] = imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1);
> +	clk[VF610_CLK_PLL1] = imx_clk_pllv3_locked(IMX_PLLV3_SYS_VF610, "pll1", "pll1_bypass_src", PLL1_CTRL, 0x1, PLL_LOCK, BIT(6));
> +	clk[VF610_CLK_PLL2] = imx_clk_pllv3_locked(IMX_PLLV3_SYS_VF610, "pll2", "pll2_bypass_src", PLL2_CTRL, 0x1, PLL_LOCK, BIT(5));
> +
>  	clk[VF610_CLK_PLL3] = imx_clk_pllv3(IMX_PLLV3_USB_VF610,     "pll3", "pll3_bypass_src", PLL3_CTRL, 0x2);
>  	clk[VF610_CLK_PLL4] = imx_clk_pllv3(IMX_PLLV3_AV,      "pll4", "pll4_bypass_src", PLL4_CTRL, 0x7f);
>  	clk[VF610_CLK_PLL5] = imx_clk_pllv3(IMX_PLLV3_ENET,    "pll5", "pll5_bypass_src", PLL5_CTRL, 0x3);
> @@ -441,3 +445,182 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
>  	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
>  }
>  CLK_OF_DECLARE(vf610, "fsl,vf610-ccm", vf610_clocks_init);
> +
> +#ifdef CONFIG_ADJUST_CPU_CLOCK
> +
> +enum {
> +	OCOTP_SPEED_GRADING_OFFSET = (0x4 * sizeof(uint32_t)),
> +	OCOTP_SPEED_GRADING_SHIFT  = 18,
> +	OCOTP_SPEED_GRADING_MASK   = 0b1111,
> +
> +	VF610_SPEED_500 = 0b1110,
> +	VF610_SPEED_400 = 0b1001,
> +	VF610_SPEED_266 = 0b0001,
> +
> +	DDRMC_CR117 = 0x01d4,
> +	DDRMC_CR117_AXI0_FITYPEREG_SYNC = 0b01 << 16,
> +};
> +
> +static int vf610_switch_cpu_clock_to_500mhz(void)
> +{
> +	int ret;
> +
> +	/*
> +	 * When switching A5 CPU to 500Mhz we expect DDRC to be
> +	 * clocked by PLL2_PFD2 and the system to be configured in
> +	 * asynchronous mode.
> +	 *
> +	 * We also can't just use default PFD1 output of PLL1 due to
> +	 * Errata e6235, so we have to re-clock the PLL itself and use
> +	 * its output to clock the CPU directly.
> +	 */
> +
> +	if (clk_get_parent(clk[VF610_CLK_DDR_SEL]) != clk[VF610_CLK_PLL2_PFD2]) {
> +		pr_warn("DDRC is clocked by PLL1, can't switch CPU clock");
> +		return -EINVAL;
> +	}
> +
> +	ret = clk_set_parent(clk[VF610_CLK_SYS_SEL], clk[VF610_CLK_PLL2_BUS]);
> +	if (ret < 0) {
> +		pr_crit("Unable to re-parent '%s'\n",
> +			clk[VF610_CLK_SYS_SEL]->name);
> +		return ret;
> +	}
> +
> +	ret = clk_set_rate(clk[VF610_CLK_PLL1], 500000000);
> +	if (ret < 0) {
> +		pr_crit("Unable to set %s to 500Mhz %d\n",
> +			clk[VF610_CLK_PLL1]->name, ret);
> +		return ret;
> +	}
> +
> +	ret = clk_set_parent(clk[VF610_CLK_PLL1_PFD_SEL], clk[VF610_CLK_PLL1_SYS]);
> +	if (ret < 0) {
> +		pr_crit("Unable to re-parent '%s'\n",
> +			clk[VF610_CLK_PLL1_PFD_SEL]->name);
> +		return ret;
> +	}
> +
> +	ret = clk_set_parent(clk[VF610_CLK_SYS_SEL], clk[VF610_CLK_PLL1_PFD_SEL]);
> +	if (ret < 0) {
> +		pr_crit("Unable to re-parent '%s'\n",
> +			clk[VF610_CLK_SYS_SEL]->name);
> +		return ret;
> +	}
> +
> +	/*
> +	 * imx_clk_divider has no error path in its set_rate hook
> +	 */
> +	clk_set_rate(clk[VF610_CLK_SYS_BUS], clk_get_rate(clk[VF610_CLK_SYS_SEL]));
> +	clk_set_rate(clk[VF610_CLK_PLATFORM_BUS], clk_get_rate(clk[VF610_CLK_SYS_BUS]) / 3);
> +
> +	return ret;
> +}
> +
> +static int vf610_switch_cpu_clock_to_400mhz(void)
> +{
> +	int ret;
> +	uint32_t cr117;
> +	void * __iomem ddrmc = IOMEM(VF610_DDR_BASE_ADDR);
> +
> +	if (clk_get_parent(clk[VF610_CLK_DDR_SEL]) != clk[VF610_CLK_PLL2_PFD2]) {
> +		pr_warn("DDRC is clocked by PLL1, can't switch CPU clock");
> +		return -EINVAL;
> +	}
> +
> +	ret = clk_set_parent(clk[VF610_CLK_PLL2_PFD_SEL], clk[VF610_CLK_PLL2_PFD2]);
> +	if (ret < 0) {
> +		pr_crit("Unable to re-parent '%s'\n",
> +			clk[VF610_CLK_PLL2_PFD_SEL]->name);
> +		return ret;
> +	}
> +
> +	ret = clk_set_parent(clk[VF610_CLK_SYS_SEL], clk[VF610_CLK_PLL2_PFD_SEL]);
> +	if (ret < 0) {
> +		pr_crit("Unable to re-parent '%s'\n",
> +			clk[VF610_CLK_SYS_SEL]->name);
> +		return ret;
> +	}
> +
> +	/*
> +	 * imx_clk_divider has no error path in its set_rate hook
> +	 */
> +	clk_set_rate(clk[VF610_CLK_SYS_BUS], clk_get_rate(clk[VF610_CLK_SYS_SEL]));
> +	clk_set_rate(clk[VF610_CLK_PLATFORM_BUS], clk_get_rate(clk[VF610_CLK_SYS_BUS]) / 3);
> +
> +	/*
> +	 * Now that we are running off of the same clock as DDRMC we
> +	 * shouldn't need to use clock domain corssing FIFO and

s/corssing/crossing/?

> +	 * asynchronous mode and instead can swithch to sychronous
> +	 * mode for AXI0 accesses
> +	 */
> +	cr117 =  readl(ddrmc + DDRMC_CR117);
> +	cr117 |= DDRMC_CR117_AXI0_FITYPEREG_SYNC;
> +	writel(cr117, ddrmc + DDRMC_CR117);
> +
> +	return 0;
> +}
> +
> +static int vf610_switch_cpu_clock(void)
> +{
> +	int ret;
> +	struct device_node *ocotp_node;
> +	struct cdev *ocotp;
> +	uint32_t speed_grading;
> +
> +	if (!of_machine_is_compatible("fsl,vf610"))
> +		return 0;
> +
> +	ocotp_node = of_find_compatible_node(NULL, NULL, "fsl,vf610-ocotp");
> +	if (!ocotp_node) {
> +		pr_err("Unable to find OCOTP DT node\n");
> +		return -ENODEV;
> +	}
> +
> +	ocotp = cdev_by_device_node(ocotp_node);
> +	if (!ocotp) {
> +		pr_err("No OCOTP character device\n");
> +		return -ENODEV;
> +	}
> +
> +	ret = cdev_read(ocotp, &speed_grading, sizeof(speed_grading),
> +		       OCOTP_SPEED_GRADING_OFFSET, 0);
> +	if (ret != sizeof(speed_grading)) {
> +		pr_err("Failed to read speed grading data\n");
> +		return ret < 0 ? ret : -EIO;
> +	}

There's a better way to access ocotp registers. see
imx_ocotp_read_field().

> +
> +	speed_grading >>= OCOTP_SPEED_GRADING_SHIFT;
> +	speed_grading &=  OCOTP_SPEED_GRADING_MASK;
> +
> +	switch (speed_grading) {
> +	default:
> +		pr_err("Unknown CPU speed grading %x\n", speed_grading);
> +		return -EINVAL;
> +
> +	case VF610_SPEED_266:
> +		return 0;
> +
> +	case VF610_SPEED_500:
> +		ret = vf610_switch_cpu_clock_to_500mhz();
> +		break;
> +
> +	case VF610_SPEED_400:
> +		ret = vf610_switch_cpu_clock_to_400mhz();
> +		break;
> +	}
> +
> +	clock_notifier_call_chain();
> +	return ret;
> +}
> +/*
> + * We can probably gain a bit of a boot speed if we switch CPU clock
> + * earlier, but if we do this we'd need to figure out a way how to
> + * re-adjust the baud rate settings of the UART for DEBUG_LL
> + * functionality, or, accept the fact that it will be unavailbe after

s/unavailbe/unavailable/

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  reply	other threads:[~2016-12-07 19:27 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-05 14:54 [PATCH 00/16] Vybrid related patches Andrey Smirnov
2016-12-05 14:54 ` [PATCH 01/16] i.MX: esdhc: Enable host->clk during initialization Andrey Smirnov
2016-12-05 14:54 ` [PATCH 02/16] i.MX: ocotp: Add provisions for storing multiple MAC addresses Andrey Smirnov
2016-12-05 15:14   ` Stefan Lengfeld
2016-12-06 14:48     ` Andrey Smirnov
2016-12-07  8:51       ` Stefan Lengfeld
2016-12-07 19:13         ` Sascha Hauer
2016-12-07 19:36           ` Andrey Smirnov
2016-12-07 20:57             ` Sascha Hauer
2016-12-07 19:32         ` Andrey Smirnov
2016-12-05 14:54 ` [PATCH 03/16] i.MX: ocotp: Initialize OCOTP as early as possible Andrey Smirnov
2016-12-05 14:54 ` [PATCH 04/16] i.MX: ocotp: Initialize 'sense_enable' to true on Vybrid Andrey Smirnov
2016-12-05 14:54 ` [PATCH 05/16] i.MX: clk: Add IMX_PLLV3_SYS_VF610 subtype Andrey Smirnov
2016-12-05 14:54 ` [PATCH 06/16] i.MX: vf610: Ramp CPU clock to maximum frequency Andrey Smirnov
2016-12-07 19:27   ` Sascha Hauer [this message]
2016-12-12  5:24     ` Andrey Smirnov
2016-12-05 14:54 ` [PATCH 07/16] i.MX: iomuxv3: Add low-level pad code to headers Andrey Smirnov
2016-12-05 14:54 ` [PATCH 08/16] i.MX: iomuxv3: Add helper type to deconstruct iomux_v3_cfg_t values Andrey Smirnov
2016-12-05 14:54 ` [PATCH 09/16] i.MX: iomuxv3: Add low-level pad configuration routine Andrey Smirnov
2016-12-05 14:54 ` [PATCH 10/16] i.MX6: sabresd: Remove magic numbers in setup_uart Andrey Smirnov
2016-12-05 14:54 ` [PATCH 11/16] i.MX: iomuxv3: Use helper functions in iomux-v3.h Andrey Smirnov
2016-12-05 14:54 ` [PATCH 12/16] i.MX: vf610: Add low-level pin configuration helper Andrey Smirnov
2016-12-05 14:54 ` [PATCH 13/16] i.MX: iomux-vf610: Add missing pad definitions Andrey Smirnov
2016-12-05 14:54 ` [PATCH 14/16] i.MX: imx-usb-phy: Add VF610 OF compatiblity string Andrey Smirnov
2016-12-05 14:54 ` [PATCH 15/16] i.MX: Default CONFI_USB_IMX_PHY to 'y' on Vybrid Andrey Smirnov
2016-12-05 14:54 ` [PATCH 16/16] i.MX: imx-usb-misc: Add Vybrid support Andrey Smirnov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161207192733.l3w4nc2s5cz47d22@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=andrew.smirnov@gmail.com \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox