Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Apr 2016 11:02:49 +0000 (UTC)
From:      Stanislav Galabov <sgalabov@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r297666 - head/sys/mips/mediatek
Message-ID:  <201604071102.u37B2nIe042779@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sgalabov
Date: Thu Apr  7 11:02:49 2016
New Revision: 297666
URL: https://svnweb.freebsd.org/changeset/base/297666

Log:
  This revision adds the following parts:
  
  - machine dependent low level init code
  - SoC clocks detection and some utility functions
  - Common interface to read/write/modify SoC system control registers, used
    by some of the other drivers and utility functions
  - simple FDT resets support, based on the fdt_clock implementation already
    in the tree. For the moment resets and clocks are managed using these
    implementations. I am planning to port those to the new extres framework
    in the future, but currently I simply don't have time to do this part too.
  
  Approved by:	adrian (mentor)
  Sponsored by:	Smartcom - Bulgaria AD
  Differential Revision:	https://reviews.freebsd.org/D5826

Added:
  head/sys/mips/mediatek/
  head/sys/mips/mediatek/fdt_reset.c   (contents, props changed)
  head/sys/mips/mediatek/fdt_reset.h   (contents, props changed)
  head/sys/mips/mediatek/fdt_reset_if.m   (contents, props changed)
  head/sys/mips/mediatek/mtk_machdep.c   (contents, props changed)
  head/sys/mips/mediatek/mtk_soc.c   (contents, props changed)
  head/sys/mips/mediatek/mtk_soc.h   (contents, props changed)
  head/sys/mips/mediatek/mtk_sysctl.c   (contents, props changed)
  head/sys/mips/mediatek/mtk_sysctl.h   (contents, props changed)

Added: head/sys/mips/mediatek/fdt_reset.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/mediatek/fdt_reset.c	Thu Apr  7 11:02:49 2016	(r297666)
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 2016 Stanislav Galabov
+ * Copyright (c) 2014 Ian Lepore <ian@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$
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "fdt_reset_if.h"
+#include <mips/mediatek/fdt_reset.h>
+
+/*
+ * Loop through all the tuples in the resets= property for a device, asserting
+ * or deasserting each reset.
+ *
+ * Be liberal about errors for now: warn about a failure to (de)assert but keep
+ * trying with any other resets in the list.  Return ENXIO if any errors were
+ * found, and let the caller decide whether the problem is fatal.
+ */
+static int
+assert_deassert_all(device_t consumer, boolean_t assert)
+{
+	phandle_t rnode;
+	device_t resetdev;
+	int resetnum, err, i, ncells;
+	uint32_t *resets;
+	boolean_t anyerrors;
+
+	rnode = ofw_bus_get_node(consumer);
+	ncells = OF_getencprop_alloc(rnode, "resets", sizeof(*resets),
+	    (void **)&resets);
+	if (!assert && ncells < 2) {
+		device_printf(consumer, "Warning: No resets specified in fdt "
+		    "data; device may not function.");
+		return (ENXIO);
+	}
+	anyerrors = false;
+	for (i = 0; i < ncells; i += 2) {
+		resetdev = OF_device_from_xref(resets[i]);
+		resetnum = resets[i + 1];
+		if (resetdev == NULL) {
+			if (!assert)
+				device_printf(consumer, "Warning: can not find "
+				    "driver for reset number %u; device may "
+				    "not function\n", resetnum);
+			anyerrors = true;
+			continue;
+		}
+		if (assert)
+			err = FDT_RESET_ASSERT(resetdev, resetnum);
+		else
+			err = FDT_RESET_DEASSERT(resetdev, resetnum);
+		if (err != 0) {
+			if (!assert)
+				device_printf(consumer, "Warning: failed to "
+				    "deassert reset number %u; device may not "
+				    "function\n", resetnum);
+			anyerrors = true;
+		}
+	}
+	free(resets, M_OFWPROP);
+	return (anyerrors ? ENXIO : 0);
+}
+
+int
+fdt_reset_assert_all(device_t consumer)
+{
+
+	return (assert_deassert_all(consumer, true));
+}
+
+int
+fdt_reset_deassert_all(device_t consumer)
+{
+
+	return (assert_deassert_all(consumer, false));
+}
+
+void
+fdt_reset_register_provider(device_t provider)
+{
+
+	OF_device_register_xref(
+	    OF_xref_from_node(ofw_bus_get_node(provider)), provider);
+}
+
+void
+fdt_reset_unregister_provider(device_t provider)
+{
+
+	OF_device_register_xref(OF_xref_from_device(provider), NULL);
+}
+

Added: head/sys/mips/mediatek/fdt_reset.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/mediatek/fdt_reset.h	Thu Apr  7 11:02:49 2016	(r297666)
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2016 Stanislav Galabov
+ * Copyright (c) 2014 Ian Lepore <ian@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$
+ */
+
+#ifndef DEV_FDT_RESET_H
+#define DEV_FDT_RESET_H
+
+#include "fdt_reset_if.h"
+
+/*
+ * Look up "resets" property in consumer's fdt data and assert or deassert all
+ * configured resets.
+ */
+int fdt_reset_assert_all(device_t consumer);
+int fdt_reset_deassert_all(device_t consumer);
+
+/*
+ * [Un]register the given device instance as a driver that implements the
+ * fdt_clock interface.
+ */
+void fdt_reset_register_provider(device_t provider);
+void fdt_reset_unregister_provider(device_t provider);
+
+#endif /* DEV_FDT_RESET_H */
+

Added: head/sys/mips/mediatek/fdt_reset_if.m
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/mediatek/fdt_reset_if.m	Thu Apr  7 11:02:49 2016	(r297666)
@@ -0,0 +1,58 @@
+#-
+# Copyright (c) 2016 Stanislav Galabov
+# Copyright (c) 2014 Ian Lepore
+# 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$
+#
+
+#include <sys/types.h>
+
+#
+# This is the interface that fdt_reset drivers provide to other drivers.
+# In this context, reset refers to a reset signal provided to some other
+# hardware component within the system.  They are most often found within
+# embedded processors that have on-chip IO controllers.
+#
+
+INTERFACE fdt_reset;
+
+#
+# Enable/assert/apply the specified reset.
+# Returns 0 on success or a standard errno value.
+#
+METHOD int assert {
+	device_t	provider;
+	int		index;
+};
+
+#
+# Disable/de-assert/remove the specified reset.
+# Returns 0 on success or a standard errno value.
+#
+METHOD int deassert {
+	device_t	provider;
+	int		index;
+};
+

Added: head/sys/mips/mediatek/mtk_machdep.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/mediatek/mtk_machdep.c	Thu Apr  7 11:02:49 2016	(r297666)
@@ -0,0 +1,286 @@
+/*-
+ * Copyright (C) 2015-2016 by Stanislav Galabov. All rights reserved.
+ * Copyright (C) 2010-2011 by Aleksandr Rybalko. All rights reserved.
+ * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 OR HIS RELATIVES 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 MIND, 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/cons.h>
+#include <sys/exec.h>
+#include <sys/ucontext.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+
+#include <machine/cache.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/intr_machdep.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+#include <machine/pte.h>
+#include <machine/sigframe.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#include <mips/mediatek/mtk_sysctl.h>
+#include <mips/mediatek/mtk_soc.h>
+
+#include "opt_platform.h"
+#include "opt_rt305x.h"
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+extern int	*edata;
+extern int	*end;
+static char 	boot1_env[0x1000];
+
+void
+platform_cpu_init()
+{
+	/* Nothing special */
+}
+
+static void
+mips_init(void)
+{
+	struct mem_region mr[FDT_MEM_REGIONS];
+	uint64_t val;
+	int i, j, mr_cnt;
+	char *memsize;
+
+	printf("entry: mips_init()\n");
+
+	bootverbose = 1;
+
+	for (i = 0; i < 10; i++)
+		phys_avail[i] = 0;
+
+	dump_avail[0] = phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end);
+
+	/*
+	 * The most low memory MT7621 can have. Currently MT7621 is the chip
+	 * that supports the most memory, so that seems reasonable.
+	 */
+	realmem = btoc(448 * 1024 * 1024);
+
+	if (fdt_get_mem_regions(mr, &mr_cnt, &val) == 0) {
+		physmem = btoc(val);
+
+		printf("RAM size: %ldMB (from FDT)\n",
+		    ctob(physmem) / (1024 * 1024));
+
+		KASSERT((phys_avail[0] >= mr[0].mr_start) && \
+			(phys_avail[0] < (mr[0].mr_start + mr[0].mr_size)),
+			("First region is not within FDT memory range"));
+
+		/* Limit size of the first region */
+		phys_avail[1] = (mr[0].mr_start +
+		    MIN(mr[0].mr_size, ctob(realmem)));
+		dump_avail[1] = phys_avail[1];
+
+		/* Add the rest of the regions */
+		for (i = 1, j = 2; i < mr_cnt; i++, j+=2) {
+			phys_avail[j] = mr[i].mr_start;
+			phys_avail[j+1] = (mr[i].mr_start + mr[i].mr_size);
+			dump_avail[j] = phys_avail[j];
+			dump_avail[j+1] = phys_avail[j+1];
+		}
+	} else {
+		if ((memsize = kern_getenv("memsize")) != NULL) {
+			physmem = btoc(strtol(memsize, NULL, 0) << 20);
+			printf("RAM size: %ldMB (from memsize)\n",
+			    ctob(physmem) / (1024 * 1024));
+		} else { /* All else failed, assume 32MB */
+			physmem = btoc(32 * 1024 * 1024);
+			printf("RAM size: %ldMB (assumed)\n",
+			    ctob(physmem) / (1024 * 1024));
+		}
+
+		if (ctob(physmem) < (448 * 1024 * 1024)) {
+			/*
+			 * Anything up to 448MB is assumed to be directly
+			 * mappable as low memory...
+			 */
+			dump_avail[1] = phys_avail[1] = ctob(physmem);
+		} else if (mtk_soc_get_socid() == MTK_SOC_MT7621) {
+			/*
+			 * On MT7621 the low memory is limited to 448MB, the
+			 * rest is high memory, mapped at 0x20000000
+			 */
+			phys_avail[1] = 448 * 1024 * 1024;
+			phys_avail[2] = 0x20000000;
+			phys_avail[3] = phys_avail[2] + ctob(physmem) -
+			    phys_avail[1];
+			dump_avail[1] = phys_avail[1] - phys_avail[0];
+			dump_avail[2] = phys_avail[2];
+			dump_avail[3] = phys_avail[3] - phys_avail[2];
+		} else {
+			/*
+			 * We have > 448MB RAM and we're not MT7621? Currently
+			 * there is no such chip, so we'll just limit the RAM to
+			 * 32MB and let the user know...
+			 */
+			printf("Unknown chip, assuming 32MB RAM\n");
+			physmem = btoc(32 * 1024 * 1024);
+			dump_avail[1] = phys_avail[1] = ctob(physmem);
+		}
+	}
+
+	if (physmem < realmem)
+		realmem = physmem;
+
+	init_param1();
+	init_param2(physmem);
+	mips_cpu_init();
+	pmap_bootstrap();
+	mips_proc0_init();
+	mutex_init();
+	kdb_init();
+#ifdef KDB
+	if (boothowto & RB_KDB)
+		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
+#endif
+}
+
+void
+platform_reset(void)
+{
+
+	mtk_soc_reset();
+}
+
+void
+platform_start(__register_t a0 __unused, __register_t a1 __unused, 
+    __register_t a2 __unused, __register_t a3 __unused)
+{
+	vm_offset_t kernend;
+	int argc = a0, i;//, res;
+	uint32_t timer_clk;
+	char **argv = (char **)MIPS_PHYS_TO_KSEG0(a1);
+	char **envp = (char **)MIPS_PHYS_TO_KSEG0(a2);
+	void *dtbp;
+
+	/* clear the BSS and SBSS segments */
+	kernend = (vm_offset_t)&end;
+	memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+	mips_postboot_fixup();
+
+	/* Initialize pcpu stuff */
+	mips_pcpu0_init();
+
+	dtbp = &fdt_static_dtb;
+	if (OF_install(OFW_FDT, 0) == FALSE)
+		while (1);
+	if (OF_init((void *)dtbp) != 0)
+		while (1);
+
+	mtk_soc_try_early_detect();
+	if ((timer_clk = mtk_soc_get_timerclk()) == 0)
+		timer_clk = 1000000000; /* no such speed yet */
+
+	mips_timer_early_init(timer_clk);
+
+	/* initialize console so that we have printf */
+	boothowto |= (RB_SERIAL | RB_MULTIPLE);	/* Use multiple consoles */
+	boothowto |= (RB_VERBOSE);
+	cninit();
+
+	init_static_kenv(boot1_env, sizeof(boot1_env));
+
+	printf("FDT DTB  at: 0x%08x\n", (uint32_t)dtbp);
+
+	printf("CPU   clock: %4dMHz\n", mtk_soc_get_cpuclk()/(1000*1000));
+	printf("Timer clock: %4dMHz\n", timer_clk/(1000*1000));
+	printf("UART  clock: %4dMHz\n\n", mtk_soc_get_uartclk()/(1000*1000));
+
+	printf("U-Boot args (from %d args):\n", argc - 1);
+
+	if (argc == 1)
+		printf("\tNone\n");
+
+	for (i = 1; i < argc; i++) {
+		char *n = "argv  ", *arg;
+
+		if (i > 99)
+			break;
+
+		if (argv[i])
+		{
+			arg = (char *)(intptr_t)MIPS_PHYS_TO_KSEG0(argv[i]);
+			printf("\targv[%d] = %s\n", i, arg);
+			sprintf(n, "argv%d", i);
+			kern_setenv(n, arg);
+		}
+	}
+
+	printf("Environment:\n");
+
+	for (i = 0; envp[i] && MIPS_IS_VALID_PTR(envp[i]); i++) {
+		char *n, *arg;
+
+		arg = (char *)(intptr_t)MIPS_PHYS_TO_KSEG0(envp[i]);
+		if (! MIPS_IS_VALID_PTR(arg))
+			continue;
+		printf("\t%s\n", arg);
+		n = strsep(&arg, "=");
+		if (arg == NULL)
+			kern_setenv(n, "1");
+		else
+			kern_setenv(n, arg);
+	}
+
+
+	mips_init();
+	mips_timer_init_params(timer_clk, 0);
+}

Added: head/sys/mips/mediatek/mtk_soc.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/mediatek/mtk_soc.c	Thu Apr  7 11:02:49 2016	(r297666)
@@ -0,0 +1,438 @@
+/*-
+ * Copyright (c) 2016 Stanislav Galabov.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/fdt/fdt_clock.h>
+
+#include <mips/mediatek/fdt_reset.h>
+#include <mips/mediatek/mtk_sysctl.h>
+#include <mips/mediatek/mtk_soc.h>
+
+static uint32_t mtk_soc_socid = MTK_SOC_UNKNOWN;
+static uint32_t mtk_soc_uartclk = 0;
+static uint32_t mtk_soc_cpuclk = MTK_CPU_CLK_880MHZ;
+static uint32_t mtk_soc_timerclk = MTK_CPU_CLK_880MHZ / 2;
+
+static const struct ofw_compat_data compat_data[] = {
+	{ "ralink,rt3050-soc",		MTK_SOC_RT3050 },
+	{ "ralink,rt3052-soc",		MTK_SOC_RT3052 },
+	{ "ralink,rt3350-soc",		MTK_SOC_RT3350 },
+	{ "ralink,rt3352-soc",		MTK_SOC_RT3352 },
+	{ "ralink,rt3662-soc",		MTK_SOC_RT3662 },
+	{ "ralink,rt3883-soc",		MTK_SOC_RT3883 },
+	{ "ralink,rt5350-soc",		MTK_SOC_RT5350 },
+	{ "ralink,mtk7620a-soc",	MTK_SOC_MT7620A },
+	{ "ralink,mtk7620n-soc",	MTK_SOC_MT7620N },
+	{ "mediatek,mtk7621-soc",	MTK_SOC_MT7621 },
+	{ "ralink,mtk7621-soc",		MTK_SOC_MT7621 },
+	{ "ralink,mtk7628an-soc",	MTK_SOC_MT7628 },
+	{ "mediatek,mt7628an-soc",	MTK_SOC_MT7628 },
+	{ "ralink,mtk7688-soc",		MTK_SOC_MT7688 },
+
+	/* Sentinel */
+	{ NULL,				MTK_SOC_UNKNOWN },
+};
+
+static uint32_t
+mtk_detect_cpuclk_rt305x(bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+	uint32_t clk;
+
+	clk = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
+	clk >>= RT305X_CPU_CLKSEL_OFF;
+	clk &= RT305X_CPU_CLKSEL_MSK;
+
+	return ((clk == 0) ? MTK_CPU_CLK_320MHZ : MTK_CPU_CLK_384MHZ);
+}
+
+static uint32_t
+mtk_detect_cpuclk_rt3352(bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+	uint32_t val;
+
+	val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
+	val >>= RT3352_CPU_CLKSEL_OFF;
+	val &= RT3352_CPU_CLKSEL_MSK;
+
+	if (val)
+		return (MTK_CPU_CLK_400MHZ);
+
+	return (MTK_CPU_CLK_384MHZ);
+}
+
+static uint32_t
+mtk_detect_cpuclk_rt3883(bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+	uint32_t val;
+
+	val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
+	val >>= RT3883_CPU_CLKSEL_OFF;
+	val &= RT3883_CPU_CLKSEL_MSK;
+
+	switch (val) {
+	case 0:
+		return (MTK_CPU_CLK_250MHZ);
+	case 1:
+		return (MTK_CPU_CLK_384MHZ);
+	case 2:
+		return (MTK_CPU_CLK_480MHZ);
+	case 3:
+		return (MTK_CPU_CLK_500MHZ);
+	}
+
+	/* Never reached */
+	return (0);
+}
+
+static uint32_t
+mtk_detect_cpuclk_rt5350(bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+	uint32_t val1, val2;
+
+	val1 = val2 = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
+
+	val1 >>= RT5350_CPU_CLKSEL_OFF1;
+	val2 >>= RT5350_CPU_CLKSEL_OFF2;
+	val1 &= RT5350_CPU_CLKSEL_MSK;
+	val2 &= RT5350_CPU_CLKSEL_MSK;
+	val1 |= (val2 << 1);
+
+	switch (val1) {
+	case 0:
+		return (MTK_CPU_CLK_360MHZ);
+	case 1:
+		/* Reserved value, but we return UNKNOWN */
+		return (MTK_CPU_CLK_UNKNOWN);
+	case 2:
+		return (MTK_CPU_CLK_320MHZ);
+	case 3:
+		return (MTK_CPU_CLK_300MHZ);
+	}
+
+	/* Never reached */
+	return (0);
+}
+
+static uint32_t
+mtk_detect_cpuclk_mt7620(bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+	uint32_t val, mul, div, res;
+
+	val = bus_space_read_4(bst, bsh, SYSCTL_MT7620_CPLL_CFG1);
+	if (val & MT7620_CPU_CLK_AUX0)
+		return (MTK_CPU_CLK_480MHZ);
+
+	val = bus_space_read_4(bst, bsh, SYSCTL_MT7620_CPLL_CFG0);
+	if (!(val & MT7620_CPLL_SW_CFG))
+		return (MTK_CPU_CLK_600MHZ);
+
+	mul = MT7620_PLL_MULT_RATIO_BASE + ((val >> MT7620_PLL_MULT_RATIO_OFF) &
+	    MT7620_PLL_MULT_RATIO_MSK);
+	div = (val >> MT7620_PLL_DIV_RATIO_OFF) & MT7620_PLL_DIV_RATIO_MSK;
+
+	if (div != MT7620_PLL_DIV_RATIO_MSK)
+		div += MT7620_PLL_DIV_RATIO_BASE;
+	else
+		div = MT7620_PLL_DIV_RATIO_MAX;
+
+	res = (MT7620_XTAL_40 * mul) / div;
+
+	return (MTK_MHZ(res));
+}
+
+static uint32_t
+mtk_detect_cpuclk_mt7621(bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+	uint32_t val, div, res;
+
+	val = bus_space_read_4(bst, bsh, SYSCTL_CLKCFG0);
+	if (val & MT7621_USES_MEMDIV) {
+		div = bus_space_read_4(bst, bsh, MTK_MT7621_CLKDIV_REG);
+		div >>= MT7621_MEMDIV_OFF;
+		div &= MT7621_MEMDIV_MSK;
+		div += MT7621_MEMDIV_BASE;
+
+		val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
+		val >>= MT7621_CLKSEL_OFF;
+		val &= MT7621_CLKSEL_MSK;
+
+		if (val >= MT7621_CLKSEL_25MHZ_VAL)
+			res = div * MT7621_CLKSEL_25MHZ;
+		else if (val >= MT7621_CLKSEL_20MHZ_VAL)
+			res = div * MT7621_CLKSEL_20MHZ;
+		else
+			res = div * 0; /* XXX: not sure about this */
+	} else {
+		val = bus_space_read_4(bst, bsh, SYSCTL_CUR_CLK_STS);
+		div = (val >> MT7621_CLK_STS_DIV_OFF) & MT7621_CLK_STS_MSK;
+		val &= MT7621_CLK_STS_MSK;
+
+		res = (MT7621_CLK_STS_BASE * val) / div;
+	}
+
+	return (MTK_MHZ(res));
+}
+
+static uint32_t
+mtk_detect_cpuclk_mt7628(bus_space_tag_t bst, bus_space_handle_t bsh)
+{
+	uint32_t val;
+
+	val = bus_space_read_4(bst, bsh, SYSCTL_SYSCFG);
+	val >>= MT7628_CPU_CLKSEL_OFF;
+	val &= MT7628_CPU_CLKSEL_MSK;
+
+	if (val)
+		return (MTK_CPU_CLK_580MHZ);
+
+	return (MTK_CPU_CLK_575MHZ);
+}
+
+void
+mtk_soc_try_early_detect(void)
+{
+	bus_space_tag_t bst;
+	bus_space_handle_t bsh;
+	uint32_t base;
+	phandle_t node;
+	int i;
+
+	if ((node = OF_finddevice("/")) == -1)
+		return;
+
+	for (i = 0; compat_data[i].ocd_str != NULL; i++) {
+		if (fdt_is_compatible(node, compat_data[i].ocd_str)) {
+			mtk_soc_socid = compat_data[i].ocd_data;
+			break;
+		}
+	}
+
+	if (mtk_soc_socid == MTK_SOC_UNKNOWN) {
+		/* We don't know the SoC, so we don't know how to get clocks */
+		return;
+	}
+
+	bst = fdtbus_bs_tag;
+	if (mtk_soc_socid == MTK_SOC_MT7621)
+		base = MTK_MT7621_BASE;
+	else
+		base = MTK_DEFAULT_BASE;
+
+	if (bus_space_map(bst, MTK_DEFAULT_BASE, MTK_DEFAULT_SIZE, 0, &bsh))
+		return;
+
+	/* First, figure out the CPU clock */
+	switch (mtk_soc_socid) {
+	case MTK_SOC_RT3050:  /* fallthrough */
+	case MTK_SOC_RT3052:
+		mtk_soc_cpuclk = mtk_detect_cpuclk_rt305x(bst, bsh);
+		break;
+	case MTK_SOC_RT3350:
+		mtk_soc_cpuclk = MTK_CPU_CLK_320MHZ;
+		break;
+	case MTK_SOC_RT3352:
+		mtk_soc_cpuclk = mtk_detect_cpuclk_rt3352(bst, bsh);
+		break;
+	case MTK_SOC_RT3662:  /* fallthrough */
+	case MTK_SOC_RT3883:
+		mtk_soc_cpuclk = mtk_detect_cpuclk_rt3883(bst, bsh);
+		break;
+	case MTK_SOC_RT5350:
+		mtk_soc_cpuclk = mtk_detect_cpuclk_rt5350(bst, bsh);
+		break;
+	case MTK_SOC_MT7620A: /* fallthrough */
+	case MTK_SOC_MT7620N:
+		mtk_soc_cpuclk = mtk_detect_cpuclk_mt7620(bst, bsh);
+		break;
+	case MTK_SOC_MT7621:
+		mtk_soc_cpuclk = mtk_detect_cpuclk_mt7621(bst, bsh);
+		break;
+	case MTK_SOC_MT7628:  /* fallthrough */
+	case MTK_SOC_MT7688:
+		mtk_soc_cpuclk = mtk_detect_cpuclk_mt7628(bst, bsh);
+		break;
+	default:
+		/* We don't know the SoC, so we can't find the CPU clock */
+		break;
+	}
+
+	/* Now figure out the timer clock */
+	if (mtk_soc_socid == MTK_SOC_MT7621) {
+#ifdef notyet
+		/* 
+		 * We use the GIC timer for timing source and its clock freq is
+		 * the same as the CPU's clock freq
+		 */
+		mtk_soc_timerclk = mtk_soc_cpuclk;
+#else
+		/*
+		 * When GIC timer and MIPS timer are ready to co-exist and
+		 * GIC timer is actually implemented, we need to switch to it.
+		 * Until then we use a fake GIC timer, which is actually a
+		 * normal MIPS ticker, so the timer clock is half the CPU clock
+		 */
+		mtk_soc_timerclk = mtk_soc_cpuclk / 2;
+#endif
+	} else {
+		/*
+		 * We use the MIPS ticker for the rest for now, so
+		 * the CPU clock is divided by 2
+		 */
+		mtk_soc_timerclk = mtk_soc_cpuclk / 2;
+	}
+
+	switch (mtk_soc_socid) {
+	case MTK_SOC_RT3350:  /* fallthrough */
+	case MTK_SOC_RT3050:  /* fallthrough */
+	case MTK_SOC_RT3052:
+		/* UART clock is CPU clock / 3 */
+		mtk_soc_uartclk = mtk_soc_cpuclk / MTK_UARTDIV_3;
+		break;
+	case MTK_SOC_RT3352:  /* fallthrough */
+	case MTK_SOC_RT3662:  /* fallthrough */
+	case MTK_SOC_RT3883:  /* fallthrough */
+	case MTK_SOC_RT5350:  /* fallthrough */
+	case MTK_SOC_MT7620A: /* fallthrough */
+	case MTK_SOC_MT7620N: /* fallthrough */
+	case MTK_SOC_MT7628:  /* fallthrough */
+	case MTK_SOC_MT7688:
+		/* UART clock is always 40MHz */
+		mtk_soc_uartclk = MTK_UART_CLK_40MHZ;
+		break;
+	case MTK_SOC_MT7621:
+		/* UART clock is always 50MHz */
+		mtk_soc_uartclk = MTK_UART_CLK_50MHZ;
+		break;
+	default:
+		/* We don't know the SoC, so we don't know the UART clock */
+		break;
+	}
+
+	bus_space_unmap(bst, bsh, MTK_DEFAULT_SIZE);
+}
+
+uint32_t
+mtk_soc_get_uartclk(void)
+{
+
+	return mtk_soc_uartclk;
+}
+
+uint32_t
+mtk_soc_get_cpuclk(void)
+{
+
+	return mtk_soc_cpuclk;
+}
+
+uint32_t
+mtk_soc_get_timerclk(void)
+{
+
+	return mtk_soc_timerclk;
+}
+
+uint32_t
+mtk_soc_get_socid(void)
+{
+
+	return mtk_soc_socid;
+}
+
+/*
+ * The following are generic reset and clock functions
+ */
+
+/* Default reset time is 100ms */
+#define DEFAULT_RESET_TIME	100000
+
+int
+mtk_soc_reset_device(device_t dev)
+{
+	int res;
+
+	res = fdt_reset_assert_all(dev);
+	if (res == 0) {
+		DELAY(DEFAULT_RESET_TIME);
+		res = fdt_reset_deassert_all(dev);
+		if (res == 0)
+			DELAY(DEFAULT_RESET_TIME);
+	}
+
+	return (res);
+}
+
+int
+mtk_soc_stop_clock(device_t dev)
+{
+
+	return (fdt_clock_disable_all(dev));
+}
+
+int
+mtk_soc_start_clock(device_t dev)
+{
+
+	return (fdt_clock_enable_all(dev));
+}
+
+int
+mtk_soc_assert_reset(device_t dev)
+{
+
+	return (fdt_reset_assert_all(dev));
+}
+
+int
+mtk_soc_deassert_reset(device_t dev)
+{
+
+	return (fdt_reset_deassert_all(dev));
+}
+
+void
+mtk_soc_reset(void)
+{
+
+	mtk_sysctl_clr_set(SYSCTL_RSTCTRL, 0, 1);
+	mtk_sysctl_clr_set(SYSCTL_RSTCTRL, 1, 0);
+}

Added: head/sys/mips/mediatek/mtk_soc.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/mediatek/mtk_soc.h	Thu Apr  7 11:02:49 2016	(r297666)
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2016 Stanislav Galabov.
+ * 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 unmodified, 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.
+ *

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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