Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 23 May 2018 19:07:04 +0000 (UTC)
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r334112 - in head/sys: arm64/rockchip/clk conf
Message-ID:  <201805231907.w4NJ74KD013723@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: manu
Date: Wed May 23 19:07:03 2018
New Revision: 334112
URL: https://svnweb.freebsd.org/changeset/base/334112

Log:
  arm64: rockchip: Add proper armclock support
  
  The core clock (armclk) on RockChip SoC is special.
  It can derive it's clock from many PLLs but RockChip recommand to do it
  from "apll" on old SoC and "npll" on new SoC. The reason for choosing npll
  is that it's have less jitter and is more close to the arm core on the SoC.
  r333314 added the core clock as a composite clock but due to it's specials
  property we need to deal with it differently.
  A new rk_clk_armclk type is added for this and it supports only the "npll"
  as we don't run on old RockChip SoC that only have the "apll".
  It will always reparent to "npll" and set the frequency according to a rate
  table that is known to be good.
  For now we set the "npll" to the desired frequency and just set the core clk
  divider to 1 as its parent it just used for the core clk.

Added:
  head/sys/arm64/rockchip/clk/rk_clk_armclk.c   (contents, props changed)
  head/sys/arm64/rockchip/clk/rk_clk_armclk.h   (contents, props changed)
Modified:
  head/sys/arm64/rockchip/clk/rk3328_cru.c
  head/sys/arm64/rockchip/clk/rk_cru.c
  head/sys/arm64/rockchip/clk/rk_cru.h
  head/sys/conf/files.arm64

Modified: head/sys/arm64/rockchip/clk/rk3328_cru.c
==============================================================================
--- head/sys/arm64/rockchip/clk/rk3328_cru.c	Wed May 23 17:55:30 2018	(r334111)
+++ head/sys/arm64/rockchip/clk/rk3328_cru.c	Wed May 23 19:07:03 2018	(r334112)
@@ -593,9 +593,60 @@ static struct rk_clk_composite_def aclk_bus_pre = {
 	.flags = RK_CLK_COMPOSITE_HAVE_MUX | RK_CLK_COMPOSITE_HAVE_GATE,
 };
 
+static struct rk_clk_armclk_rates rk3328_armclk_rates[] = {
+	{
+		.freq = 1296000000,
+		.div = 1,
+	},
+	{
+		.freq = 1200000000,
+		.div = 1,
+	},
+	{
+		.freq = 1104000000,
+		.div = 1,
+	},
+	{
+		.freq = 1008000000,
+		.div = 1,
+	},
+	{
+		.freq = 912000000,
+		.div = 1,
+	},
+	{
+		.freq = 816000000,
+		.div = 1,
+	},
+	{
+		.freq = 696000000,
+		.div = 1,
+	},
+	{
+		.freq = 600000000,
+		.div = 1,
+	},
+	{
+		.freq = 408000000,
+		.div = 1,
+	},
+	{
+		.freq = 312000000,
+		.div = 1,
+	},
+	{
+		.freq = 216000000,
+		.div = 1,
+	},
+	{
+		.freq = 96000000,
+		.div = 1,
+	},
+};
+
 #define	ARMCLK	6
 static const char *armclk_parents[] = {"apll", "gpll", "dpll", "npll" };
-static struct rk_clk_composite_def armclk = {
+static struct rk_clk_armclk_def armclk = {
 	.clkdef = {
 		.id = ARMCLK,
 		.name = "armclk",
@@ -610,6 +661,11 @@ static struct rk_clk_composite_def armclk = {
 	.div_width = 5,
 
 	.flags = RK_CLK_COMPOSITE_HAVE_MUX,
+	.main_parent = 3, /* npll */
+	.alt_parent = 0, /* apll */
+
+	.rates = rk3328_armclk_rates,
+	.nrates = nitems(rk3328_armclk_rates),
 };
 
 /* CRU_CLKSEL_CON1 */
@@ -825,15 +881,16 @@ static struct rk_clk rk3328_clks[] = {
 	},
 	{
 		.type = RK_CLK_COMPOSITE,
-		.clk.composite = &armclk
-	},
-	{
-		.type = RK_CLK_COMPOSITE,
 		.clk.composite = &hclk_bus_pre
 	},
 	{
 		.type = RK_CLK_COMPOSITE,
 		.clk.composite = &pclk_bus_pre
+	},
+
+	{
+		.type = RK_CLK_ARMCLK,
+		.clk.armclk = &armclk,
 	},
 
 	{

Added: head/sys/arm64/rockchip/clk/rk_clk_armclk.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/rockchip/clk/rk_clk_armclk.c	Wed May 23 19:07:03 2018	(r334112)
@@ -0,0 +1,237 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2018 Emmanuel Vadot <manu@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm64/rockchip/clk/rk_clk_armclk.h>
+
+#include "clkdev_if.h"
+
+struct rk_clk_armclk_sc {
+	uint32_t	muxdiv_offset;
+	uint32_t	mux_shift;
+	uint32_t	mux_width;
+	uint32_t	mux_mask;
+
+	uint32_t	div_shift;
+	uint32_t	div_width;
+	uint32_t	div_mask;
+
+	uint32_t	gate_offset;
+	uint32_t	gate_shift;
+
+	uint32_t	flags;
+
+	uint32_t	main_parent;
+	uint32_t	alt_parent;
+
+	struct rk_clk_armclk_rates	*rates;
+	int		nrates;
+};
+
+#define	WRITE4(_clk, off, val)						\
+	CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
+#define	READ4(_clk, off, val)						\
+	CLKDEV_READ_4(clknode_get_device(_clk), off, val)
+#define	DEVICE_LOCK(_clk)							\
+	CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
+#define	DEVICE_UNLOCK(_clk)						\
+	CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
+
+#define	RK_ARMCLK_WRITE_MASK	0xFFFF0000
+
+static int
+rk_clk_armclk_init(struct clknode *clk, device_t dev)
+{
+	struct rk_clk_armclk_sc *sc;
+	uint32_t val, idx;
+
+	sc = clknode_get_softc(clk);
+
+	idx = 0;
+	DEVICE_LOCK(clk);
+	READ4(clk, sc->muxdiv_offset, &val);
+	DEVICE_UNLOCK(clk);
+
+	idx = (val & sc->mux_mask) >> sc->mux_shift;
+
+	clknode_init_parent_idx(clk, idx);
+
+	return (0);
+}
+
+static int
+rk_clk_armclk_set_mux(struct clknode *clk, int index)
+{
+	struct rk_clk_armclk_sc *sc;
+	uint32_t val;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(clk);
+	READ4(clk, sc->muxdiv_offset, &val);
+	val &= ~(sc->mux_mask >> sc->mux_shift);
+	val |= index << sc->mux_shift;
+	WRITE4(clk, sc->muxdiv_offset, val);
+	DEVICE_UNLOCK(clk);
+
+	return (0);
+}
+
+static int
+rk_clk_armclk_recalc(struct clknode *clk, uint64_t *freq)
+{
+	struct rk_clk_armclk_sc *sc;
+	uint32_t reg, div;
+
+	sc = clknode_get_softc(clk);
+
+	DEVICE_LOCK(clk);
+
+	READ4(clk, sc->muxdiv_offset, &reg);
+
+	DEVICE_UNLOCK(clk);
+
+	div = ((reg & sc->div_mask) >> sc->div_shift) + 1;
+
+	*freq = *freq / div;
+
+	return (0);
+}
+
+static int
+rk_clk_armclk_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
+    int flags, int *stop)
+{
+	struct rk_clk_armclk_sc *sc;
+	struct clknode *p_main;
+	const char **p_names;
+	uint64_t best = 0, best_p = 0;
+	uint32_t div = 0, val;
+	int err, i, rate = 0;
+
+	sc = clknode_get_softc(clk);
+
+	p_names = clknode_get_parent_names(clk);
+	p_main = clknode_find_by_name(p_names[sc->main_parent]);
+	clknode_set_parent_by_idx(clk, sc->main_parent);
+
+	for (i = 0; i < sc->nrates; i++) {
+		if (sc->rates[i].freq == *fout) {
+			best = sc->rates[i].freq;
+			div = sc->rates[i].div;
+			best_p = best * (div + 1);
+			rate = i;
+		}
+	}
+
+	if (rate == 0)
+		return (0);
+
+	err = clknode_set_freq(p_main, best_p, 0, 1);
+	if (err != 0)
+		printf("Cannot set %s to %lu\n",
+		    clknode_get_name(p_main),
+		    best_p);
+
+	if ((flags & CLK_SET_DRYRUN) != 0) {
+		*fout = best;
+		*stop = 1;
+		return (0);
+	}
+
+	DEVICE_LOCK(clk);
+	READ4(clk, sc->muxdiv_offset, &val);
+	val &= ~sc->div_mask;
+	val |= div << sc->div_shift;
+	WRITE4(clk, sc->muxdiv_offset, val | RK_CLK_ARMCLK_MASK);
+	DEVICE_UNLOCK(clk);
+
+	*fout = best;
+	*stop = 1;
+
+	return (0);
+}
+
+static clknode_method_t rk_clk_armclk_clknode_methods[] = {
+	/* Device interface */
+	CLKNODEMETHOD(clknode_init,		rk_clk_armclk_init),
+	CLKNODEMETHOD(clknode_set_mux,		rk_clk_armclk_set_mux),
+	CLKNODEMETHOD(clknode_recalc_freq,	rk_clk_armclk_recalc),
+	CLKNODEMETHOD(clknode_set_freq,		rk_clk_armclk_set_freq),
+	CLKNODEMETHOD_END
+};
+
+DEFINE_CLASS_1(rk_clk_armclk_clknode, rk_clk_armclk_clknode_class,
+    rk_clk_armclk_clknode_methods, sizeof(struct rk_clk_armclk_sc),
+    clknode_class);
+
+int
+rk_clk_armclk_register(struct clkdom *clkdom, struct rk_clk_armclk_def *clkdef)
+{
+	struct clknode *clk;
+	struct rk_clk_armclk_sc *sc;
+
+	clk = clknode_create(clkdom, &rk_clk_armclk_clknode_class,
+	    &clkdef->clkdef);
+	if (clk == NULL)
+		return (1);
+
+	sc = clknode_get_softc(clk);
+
+	sc->muxdiv_offset = clkdef->muxdiv_offset;
+
+	sc->mux_shift = clkdef->mux_shift;
+	sc->mux_width = clkdef->mux_width;
+	sc->mux_mask = ((1 << clkdef->mux_width) - 1) << sc->mux_shift;
+
+	sc->div_shift = clkdef->div_shift;
+	sc->div_width = clkdef->div_width;
+	sc->div_mask = ((1 << clkdef->div_width) - 1) << sc->div_shift;
+
+	sc->flags = clkdef->flags;
+
+	sc->main_parent = clkdef->main_parent;
+	sc->alt_parent = clkdef->alt_parent;
+
+	sc->rates = clkdef->rates;
+	sc->nrates = clkdef->nrates;
+
+	clknode_register(clkdom, clk);
+
+	return (0);
+}

Added: head/sys/arm64/rockchip/clk/rk_clk_armclk.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm64/rockchip/clk/rk_clk_armclk.h	Wed May 23 19:07:03 2018	(r334112)
@@ -0,0 +1,66 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright 2018 Emmanuel Vadot <manu@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RK_CLK_ARMCLK_H_
+#define _RK_CLK_ARMCLK_H_
+
+#include <dev/extres/clk/clk.h>
+
+struct rk_clk_armclk_rates {
+	uint64_t	freq;
+	uint32_t	div;
+};
+
+struct rk_clk_armclk_def {
+	struct clknode_init_def	clkdef;
+
+	uint32_t	muxdiv_offset;
+
+	uint32_t	mux_shift;
+	uint32_t	mux_width;
+
+	uint32_t	div_shift;
+	uint32_t	div_width;
+
+	uint32_t	flags;
+
+	uint32_t	main_parent;
+	uint32_t	alt_parent;
+
+	struct rk_clk_armclk_rates	*rates;
+	int				nrates;
+};
+
+#define	RK_CLK_ARMCLK_MASK	0xFFFF0000
+
+int rk_clk_armclk_register(struct clkdom *clkdom,
+    struct rk_clk_armclk_def *clkdef);
+
+#endif /* _RK_CLK_ARMCLK_H_ */

Modified: head/sys/arm64/rockchip/clk/rk_cru.c
==============================================================================
--- head/sys/arm64/rockchip/clk/rk_cru.c	Wed May 23 17:55:30 2018	(r334111)
+++ head/sys/arm64/rockchip/clk/rk_cru.c	Wed May 23 19:07:03 2018	(r334112)
@@ -230,6 +230,9 @@ rk_cru_attach(device_t dev)
 		case RK_CLK_MUX:
 			rk_clk_mux_register(sc->clkdom, sc->clks[i].clk.mux);
 			break;
+		case RK_CLK_ARMCLK:
+			rk_clk_armclk_register(sc->clkdom, sc->clks[i].clk.armclk);
+			break;
 		default:
 			device_printf(dev, "Unknown clock type\n");
 			return (ENXIO);

Modified: head/sys/arm64/rockchip/clk/rk_cru.h
==============================================================================
--- head/sys/arm64/rockchip/clk/rk_cru.h	Wed May 23 17:55:30 2018	(r334111)
+++ head/sys/arm64/rockchip/clk/rk_cru.h	Wed May 23 19:07:03 2018	(r334112)
@@ -31,6 +31,7 @@
 #ifndef __RK_CRU_H__
 #define __RK_CRU_H__
 
+#include <arm64/rockchip/clk/rk_clk_armclk.h>
 #include <arm64/rockchip/clk/rk_clk_composite.h>
 #include <arm64/rockchip/clk/rk_clk_gate.h>
 #include <arm64/rockchip/clk/rk_clk_mux.h>
@@ -63,6 +64,7 @@ enum rk_clk_type {
 	RK_CLK_PLL,
 	RK_CLK_COMPOSITE,
 	RK_CLK_MUX,
+	RK_CLK_ARMCLK,
 };
 
 struct rk_clk {
@@ -71,6 +73,7 @@ struct rk_clk {
 		struct rk_clk_pll_def		*pll;
 		struct rk_clk_composite_def	*composite;
 		struct rk_clk_mux_def		*mux;
+		struct rk_clk_armclk_def	*armclk;
 	} clk;
 };
 
@@ -86,6 +89,9 @@ struct rk_cru_softc {
 	int			ngates;
 	struct rk_clk		*clks;
 	int			nclks;
+	struct rk_clk_armclk_def	*armclk;
+	struct rk_clk_armclk_rates	*armclk_rates;
+	int			narmclk_rates;
 };
 
 DECLARE_CLASS(rk_cru_driver);

Modified: head/sys/conf/files.arm64
==============================================================================
--- head/sys/conf/files.arm64	Wed May 23 17:55:30 2018	(r334111)
+++ head/sys/conf/files.arm64	Wed May 23 19:07:03 2018	(r334112)
@@ -248,6 +248,7 @@ arm64/rockchip/rk_grf.c			optional fdt soc_rockchip_rk
 arm64/rockchip/rk_pinctrl.c		optional fdt soc_rockchip_rk3328
 arm64/rockchip/rk_gpio.c		optional fdt soc_rockchip_rk3328
 arm64/rockchip/clk/rk_cru.c		optional fdt soc_rockchip_rk3328
+arm64/rockchip/clk/rk_clk_armclk.c	optional fdt soc_rockchip_rk3328
 arm64/rockchip/clk/rk_clk_composite.c	optional fdt soc_rockchip_rk3328
 arm64/rockchip/clk/rk_clk_gate.c	optional fdt soc_rockchip_rk3328
 arm64/rockchip/clk/rk_clk_mux.c		optional fdt soc_rockchip_rk3328



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201805231907.w4NJ74KD013723>