From owner-svn-src-all@freebsd.org Thu Apr 7 11:02:51 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 1FDBCB06098; Thu, 7 Apr 2016 11:02:51 +0000 (UTC) (envelope-from sgalabov@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id AF1CD1340; Thu, 7 Apr 2016 11:02:50 +0000 (UTC) (envelope-from sgalabov@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u37B2nlx042785; Thu, 7 Apr 2016 11:02:49 GMT (envelope-from sgalabov@FreeBSD.org) Received: (from sgalabov@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u37B2nIe042779; Thu, 7 Apr 2016 11:02:49 GMT (envelope-from sgalabov@FreeBSD.org) Message-Id: <201604071102.u37B2nIe042779@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: sgalabov set sender to sgalabov@FreeBSD.org using -f From: Stanislav Galabov Date: Thu, 7 Apr 2016 11:02:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r297666 - head/sys/mips/mediatek X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Apr 2016 11:02:51 -0000 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 + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "fdt_reset_if.h" +#include + +/* + * 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 + * 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 + +# +# 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 +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "opt_platform.h" +#include "opt_rt305x.h" + +#include +#include + +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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +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 ***