diff --git a/distrib/evbarm/instkernel/ramdisk/Makefile b/distrib/evbarm/instkernel/ramdisk/Makefile index cd303d89ff01..6f4cb2827f7e 100644 --- a/distrib/evbarm/instkernel/ramdisk/Makefile +++ b/distrib/evbarm/instkernel/ramdisk/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.16 2017/01/27 15:20:31 rin Exp $ +# $NetBSD: Makefile,v 1.16.4.1 2017/07/18 19:13:07 snj Exp $ .include .include "${NETBSDSRCDIR}/distrib/common/Makefile.distrib" @@ -38,6 +38,11 @@ ${CRUNCHBIN}: libhack.o .include "${DISTRIBDIR}/common/Makefile.makedev" .include "${DISTRIBDIR}/common/Makefile.image" -release: +release: ${IMAGE} + ${RELEASE_INSTALL} ${IMAGE} \ + ${RELEASEDIR}/${RELEASEMACHINEDIR}/installation/ramdisk/ + ${TOOL_MKUBOOTIMAGE} -A arm -C none -O linux -T ramdisk \ + -a 0 -n "NetBSD/${MACHINE_ARCH} ramdisk" ${IMAGE} \ + ${RELEASEDIR}/${RELEASEMACHINEDIR}/installation/ramdisk/${IMAGE:S/.fs/.ub/} .include diff --git a/distrib/utils/embedded/conf/armv7.conf b/distrib/utils/embedded/conf/armv7.conf index 5476d58df31e..f05c33fe5e21 100644 --- a/distrib/utils/embedded/conf/armv7.conf +++ b/distrib/utils/embedded/conf/armv7.conf @@ -1,4 +1,4 @@ -# $NetBSD: armv7.conf,v 1.12 2017/04/12 23:35:29 jmcneill Exp $ +# $NetBSD: armv7.conf,v 1.12.4.1 2017/07/18 19:13:07 snj Exp $ # ARMv7 customization script used by mkimage # board=armv7 @@ -8,10 +8,11 @@ resize=true . ${DIR}/conf/evbarm.conf kernels_beagle="BEAGLEBOARD BEAGLEBONE" -kernels_awin="BPI CUBIEBOARD CUBIETRUCK HUMMINGBIRD_A31" +kernels_awin="BPI CUBIEBOARD CUBIETRUCK" kernels_rpi="RPI2" kernels_amlogic="ODROID-C1" kernels_tegra="TEGRA" +kernels_sunxi="SUNXI" make_label() { make_label_evbarm @@ -105,6 +106,10 @@ run bootcmd EOF } +populate_sunxi() { + : +} + populate_tegra() { tegra_kernelimg=netbsd-TEGRA.ub tegra_loadaddr=0x90000000 @@ -124,7 +129,7 @@ populate() { echo "${bar} looking for kernels in ${kernel} ${bar}" kernels="" # .ub kernels - for k in $kernels_beagle $kernels_awin $kernels_amlogic $kernels_tegra; do + for k in $kernels_beagle $kernels_awin $kernels_sunxi $kernels_amlogic $kernels_tegra; do f="${kernel}/netbsd-${k}.ub.gz" test -f "${f}" && kernels="${kernels} ${f}" done @@ -133,6 +138,16 @@ populate() { f="${kernel}/netbsd-${k}.bin.gz" test -f "${f}" && kernels="${kernels} ${f}" done + # .dtb files + for k in $kernels_sunxi $kernels_tegra; do + test -d "${KERNOBJDIR}/${k}" && \ + dtbs="$(${MAKE} -C ${KERNOBJDIR}/${k} -v DTB)" || \ + dtbs= + for dtb in $dtbs; do + f="${kernel}/${dtb}.gz" + test -f "${f}" && kernels="${kernels} ${f}" + done + done # install kernels to /boot partition for k in ${kernels}; do @@ -154,4 +169,5 @@ populate() { populate_rpi populate_amlogic populate_tegra + populate_sunxi } diff --git a/distrib/utils/embedded/mkimage b/distrib/utils/embedded/mkimage index 5e3f13675a5e..c5aac0ea67b9 100755 --- a/distrib/utils/embedded/mkimage +++ b/distrib/utils/embedded/mkimage @@ -1,5 +1,5 @@ #!/bin/sh -# $NetBSD: mkimage,v 1.64 2017/04/11 21:06:30 jmcneill Exp $ +# $NetBSD: mkimage,v 1.64.4.1 2017/07/18 19:13:07 snj Exp $ # # Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. # All rights reserved. @@ -51,6 +51,7 @@ set -e DIR="$(cd "$(dirname "$0")" && pwd)" PROG="$(basename "$0")" +MAKE=${TOOL_MAKE:-make} DISKLABEL=${TOOL_DISKLABEL:-disklabel} FDISK=${TOOL_FDISK:-fdisk} MAKEFS=${TOOL_MAKEFS:-makefs} diff --git a/etc/Makefile b/etc/Makefile index 5be070c93812..557e2034a169 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.428 2017/05/21 15:28:38 riastradh Exp $ +# $NetBSD: Makefile,v 1.428.2.1 2017/07/18 19:13:07 snj Exp $ # from: @(#)Makefile 8.7 (Berkeley) 5/25/95 # Environment variables without default values: @@ -605,7 +605,7 @@ build_kernelsets: .PHONY .if ${configfile} == ${configsel} build_kernelsets: kernset-${configfile} kernset-${configfile}: .PHONY build_kernels snap_pre - @ kernlist=$$(${GETKERNELAWK} ${KERNCONFDIR}/${configfile}); \ + @kernlist=$$(${GETKERNELAWK} ${KERNCONFDIR}/${configfile}); \ kerndir=${KERNOBJDIR}/${configfile:C/.*\///}; \ kernsuffixes="${KERNEL_SUFFIXES:S/^/./}"; \ kern_tgz=${RELEASEDIR}/${RELEASEMACHINEDIR}/binary/sets/kern-${configfile}.tgz; \ @@ -625,6 +625,10 @@ kernset-${configfile}: .PHONY build_kernels snap_pre echo "echo $${kernels} | $${pax_cmd}"; \ ( echo "/set uname=${BINOWN} gname=${BINGRP}"; \ echo ". type=dir optional"; \ + dtblist=$$(${MAKE} -v DTB); \ + for dtb in $${dtblist}; do \ + echo "./$${dtb} type=file"; \ + done; \ for kernel in $${kernels}; do \ echo "./$${kernel} type=file"; \ done ) | eval $${pax_cmd}; \ @@ -643,15 +647,25 @@ build_releasekernels: .PHONY .if ${configfile} == ${configsel} build_releasekernels: releasekern-${configfile} releasekern-${configfile}: .PHONY build_kernels snap_pre - @ kernlist=$$(${GETKERNELAWK} ${KERNCONFDIR}/${configfile:C/.*\///}); \ + @kernlist=$$(${GETKERNELAWK} ${KERNCONFDIR}/${configfile:C/.*\///}); \ kerndir=${KERNOBJDIR}/${configfile:C/.*\///}; \ kernsuffixes="${KERNEL_SUFFIXES:S/^/./}"; \ + dest="${RELEASEDIR}/${RELEASEMACHINEDIR}/binary/kernel"; \ cd $${kerndir} && { \ + dtblist=$$(${MAKE} -v DTB); \ + for dtb in $${dtblist}; do \ + [ ! -f $${dtb} ] && continue; \ + dtb_gz="$${dest}/$${dtb}.gz"; \ + [ $${dtb_gz} -nt $${dtb} ] && continue; \ + rm -f $${dtb_gz}; \ + echo "${TOOL_GZIP} ${GZIP_FLAGS} -c < $${kerndir}/$${dtb} > $${dtb_gz}"; \ + ${TOOL_GZIP} ${GZIP_FLAGS} -c < $${dtb} > $${dtb_gz}; \ + done; \ for kernel in $${kernlist}; do \ for s in "" $${kernsuffixes}; do \ ks="$${kernel}$${s}"; \ [ ! -f $${ks} ] && continue; \ - knl_gz="${RELEASEDIR}/${RELEASEMACHINEDIR}/binary/kernel/$${kernel}-${configfile:C/.*\///}$${s}.gz"; \ + knl_gz="$${dest}/$${kernel}-${configfile:C/.*\///}$${s}.gz"; \ [ $${knl_gz} -nt $${ks} ] && continue; \ rm -f $${knl_gz}; \ echo "${TOOL_GZIP} ${GZIP_FLAGS} -c < $${kerndir}/$${ks} > $${knl_gz}"; \ diff --git a/etc/etc.evbarm/Makefile.inc b/etc/etc.evbarm/Makefile.inc index 01c558497f47..17173b210212 100644 --- a/etc/etc.evbarm/Makefile.inc +++ b/etc/etc.evbarm/Makefile.inc @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.inc,v 1.81 2017/01/07 16:29:04 kiyohara Exp $ +# $NetBSD: Makefile.inc,v 1.81.6.1 2017/07/18 19:13:08 snj Exp $ # # etc.evbarm/Makefile.inc -- evbarm-specific etc Makefile targets # @@ -134,6 +134,7 @@ IMAGE.kern= ${IMAGE.rel}/binary/kernel IMAGE.instk= ${IMAGE.rel}/installation/instkernel __mkimage: .USE + TOOL_MAKE=${MAKE} \ TOOL_MAKEFS=${TOOL_MAKEFS} \ TOOL_DISKLABEL=${TOOL_DISKLABEL} \ TOOL_FDISK=${TOOL_FDISK} \ @@ -143,6 +144,8 @@ __mkimage: .USE TOOL_MKUBOOTIMAGE=${TOOL_MKUBOOTIMAGE} \ TOOL_MTREE=${TOOL_MTREE} \ HOST_SH=${HOST_SH} \ + KERNOBJDIR=${KERNOBJDIR} \ + MACHINE=${MACHINE} \ ${HOST_SH} ${MKIMAGE} -x -h ${.TARGET:S/smp_//} -D ${DESTDIR} \ -S ${NETBSDSRCDIR} -B ${IMAGEENDIAN} ${MKI_OPTS.${.TARGET}} \ ${IMAGE.dir}/${.TARGET:S/smp_//}.img.gz @@ -197,4 +200,5 @@ snap_md_post: check_DESTDIR check_RELEASEDIR snap_post .WAIT ${SNAP_MD_POST_DEPS KERNEL_SUFFIXES= bin srec ub INSTALLATION_DIRS+= binary/gzimg \ - installation/instkernel + installation/instkernel \ + installation/ramdisk diff --git a/external/bsd/elftosb/usr.sbin/elftosb/Makefile b/external/bsd/elftosb/usr.sbin/elftosb/Makefile index f49d33d9cb6e..0a726f953d0d 100644 --- a/external/bsd/elftosb/usr.sbin/elftosb/Makefile +++ b/external/bsd/elftosb/usr.sbin/elftosb/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.4 2013/05/02 03:56:39 matt Exp $ +# $NetBSD: Makefile,v 1.4.22.1 2017/07/18 19:13:08 snj Exp $ .include .include @@ -19,7 +19,7 @@ SRCS= BootImageGenerator.cpp \ elftosb_parser.tab.cpp .ifdef HOSTPROG -SRCS.lib!=cd ${.PARSEDIR}/../../lib && ${MAKE} -V '$${SRCS}' +SRCS.lib!=cd ${.PARSEDIR}/../../lib && ${MAKE} -v SRCS SRCS+=${SRCS.lib} .endif diff --git a/external/bsd/mdocml/bin/mandoc/Makefile b/external/bsd/mdocml/bin/mandoc/Makefile index c7a6b3c79796..9ebbe424248d 100644 --- a/external/bsd/mdocml/bin/mandoc/Makefile +++ b/external/bsd/mdocml/bin/mandoc/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.11 2016/07/15 19:40:42 christos Exp $ +# $NetBSD: Makefile,v 1.11.6.1 2017/07/18 19:13:08 snj Exp $ .include @@ -15,7 +15,7 @@ DPADD+= ${MDOCMLLIB.mandoc} ${LIBZ} LDADD+= -L${MDOCMLOBJDIR.mandoc} -lmandoc -lz CPPFLAGS+= -DUSE_WCHAR .else -SRCS.libmandoc!=cd ${.PARSEDIR}/../../lib/libmandoc && ${MAKE} -V '$${SRCS}' +SRCS.libmandoc!=cd ${.PARSEDIR}/../../lib/libmandoc && ${MAKE} -v SRCS SRCS+= ${SRCS.libmandoc} compat_strtonum.c compat_reallocarray.c .endif diff --git a/sys/arch/arm/arm/psci.c b/sys/arch/arm/arm/psci.c new file mode 100644 index 000000000000..056eb8bd9067 --- /dev/null +++ b/sys/arch/arm/arm/psci.c @@ -0,0 +1,120 @@ +/* $NetBSD: psci.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include "opt_diagnostic.h" + +#include +__KERNEL_RCSID(0, "$NetBSD: psci.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include + +#include + +/* PSCI methods */ +#define PSCI_VERSION 0x84000000 +#define PSCI_SYSTEM_OFF 0x84000008 +#define PSCI_SYSTEM_RESET 0x84000009 +#if defined(__aarch64__) +#define PSCI_CPU_ON 0xc4000002 +#else +#define PSCI_CPU_ON 0x84000002 +#endif + +static psci_fn psci_call_fn; + +static uint32_t psci_functions[PSCI_FUNC_MAX] = { + [PSCI_FUNC_VERSION] = PSCI_VERSION, + [PSCI_FUNC_SYSTEM_OFF] = PSCI_SYSTEM_OFF, + [PSCI_FUNC_SYSTEM_RESET] = PSCI_SYSTEM_RESET, + [PSCI_FUNC_CPU_ON] = PSCI_CPU_ON, +}; + +static int +psci_call(register_t fid, register_t arg1, register_t arg2, register_t arg3) +{ + KASSERT(psci_call_fn != NULL); + + if (fid == 0) + return PSCI_NOT_SUPPORTED; + + return psci_call_fn(fid, arg1, arg2, arg3); +} + +uint32_t +psci_version(void) +{ + if (psci_functions[PSCI_FUNC_VERSION] == 0) { + /* Pre-0.2 implementation */ + return __SHIFTIN(0, PSCI_VERSION_MAJOR) | + __SHIFTIN(1, PSCI_VERSION_MINOR); + } + + return psci_call(psci_functions[PSCI_FUNC_VERSION], 0, 0, 0); +} + +int +psci_cpu_on(register_t target_cpu, register_t entry_point_address, + register_t context_id) +{ + return psci_call(psci_functions[PSCI_FUNC_CPU_ON], target_cpu, + entry_point_address, context_id); +} + +void +psci_system_off(void) +{ + psci_call(psci_functions[PSCI_FUNC_SYSTEM_OFF], 0, 0, 0); +} + +void +psci_system_reset(void) +{ + psci_call(psci_functions[PSCI_FUNC_SYSTEM_RESET], 0, 0, 0); +} + +void +psci_init(psci_fn fn) +{ + psci_call_fn = fn; +} + +void +psci_clearfunc(void) +{ + for (int i = 0; i < PSCI_FUNC_MAX; i++) + psci_setfunc(i, 0); +} + +void +psci_setfunc(enum psci_function func, uint32_t fid) +{ + psci_functions[func] = fid; +} diff --git a/sys/arch/arm/arm/psci.h b/sys/arch/arm/arm/psci.h new file mode 100644 index 000000000000..d78e05b69254 --- /dev/null +++ b/sys/arch/arm/arm/psci.h @@ -0,0 +1,106 @@ +/* $NetBSD: psci.h,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#ifndef _ARM_PSCI_H +#define _ARM_PSCI_H + +/* + * List of supported PSCI functions. + */ +enum psci_function { + PSCI_FUNC_VERSION, + PSCI_FUNC_CPU_ON, + PSCI_FUNC_SYSTEM_OFF, + PSCI_FUNC_SYSTEM_RESET, + PSCI_FUNC_MAX +}; + +/* + * PSCI error codes + */ +#define PSCI_SUCCESS 0 +#define PSCI_NOT_SUPPORTED -1 +#define PSCI_INVALID_PARAMETERS -2 +#define PSCI_DENIED -3 +#define PSCI_ALREADY_ON -4 +#define PSCI_ON_PENDING -5 +#define PSCI_INTERNAL_FAILURE -6 +#define PSCI_NOT_PRESENT -7 +#define PSCI_DISABLED -8 +#define PSCI_INVALID_ADDRESS -9 + +/* + * PSCI call method interface. + */ +typedef int (*psci_fn)(register_t, register_t, register_t, register_t); + +/* + * Set the PSCI call method. Pass either psci_call_smc or psci_call_hvc. + */ +void psci_init(psci_fn); + +/* + * PSCI call methods, implemented in psci.S + */ +int psci_call_smc(register_t, register_t, register_t, register_t); +int psci_call_hvc(register_t, register_t, register_t, register_t); + +/* + * Clear PSCI function table. The default table includes function IDs for + * PSCI 0.2+. A PSCI 0.1 implementation will use its own function ID mappings. + */ +void psci_clearfunc(void); + +/* + * Set PSCI function ID for a given PSCI function. + */ +void psci_setfunc(enum psci_function, uint32_t); + +/* + * Return the version of PSCI implemented. + */ +uint32_t psci_version(void); +#define PSCI_VERSION_MAJOR __BITS(31,16) +#define PSCI_VERSION_MINOR __BITS(15,0) + +/* + * Power up a core. Args: target_cpu, entry_point_address, context_id + */ +int psci_cpu_on(register_t, register_t, register_t); + +/* + * Shut down the system. + */ +void psci_system_off(void); + +/* + * Reset the system. + */ +void psci_system_reset(void); + +#endif /* _ARM_PSCI_H */ diff --git a/sys/arch/arm/arm/psci_arm.S b/sys/arch/arm/arm/psci_arm.S new file mode 100644 index 000000000000..7a76b3903670 --- /dev/null +++ b/sys/arch/arm/arm/psci_arm.S @@ -0,0 +1,47 @@ +/* $NetBSD: psci_arm.S,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include + +RCSID("$NetBSD: psci_arm.S,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $"); + + .arch armv7a + .arch_extension sec + .arch_extension virt + +/* Invoke PSCI function using Secure Monitor Call interface */ +ENTRY(psci_call_smc) + smc #0 + RET +END(psci_call_smc) + +/* Invoke PSCI function using Hypervisor Call interface */ +ENTRY(psci_call_hvc) + hvc #0 + RET +END(psci_call_hvc) diff --git a/sys/arch/arm/conf/files.arm b/sys/arch/arm/conf/files.arm index 8a330f4a4532..f1ba3ec0fcfd 100644 --- a/sys/arch/arm/conf/files.arm +++ b/sys/arch/arm/conf/files.arm @@ -1,4 +1,4 @@ -# $NetBSD: files.arm,v 1.132 2017/05/26 21:17:46 jmcneill Exp $ +# $NetBSD: files.arm,v 1.132.2.1 2017/07/18 19:13:08 snj Exp $ # temporary define to allow easy moving to ../arch/arm/arm32 defflag ARM32 @@ -91,6 +91,11 @@ obsolete defflag ARMFPE file arch/arm/vfp/vfp_init.c arm32 #file arch/arm/vfp/pmap_vfp.S arm32 & fpu_vfp +# Power State Coordination Interface (PSCI) +device psci +file arch/arm/arm/psci.c psci +file arch/arm/arm/psci_arm.S psci + # PMAP_DEBUG (heavily abused option) defflag PMAP_DEBUG diff --git a/sys/arch/arm/cortex/gic.c b/sys/arch/arm/cortex/gic.c index 352cc41bad22..61541b7a4311 100644 --- a/sys/arch/arm/cortex/gic.c +++ b/sys/arch/arm/cortex/gic.c @@ -1,4 +1,4 @@ -/* $NetBSD: gic.c,v 1.21.2.1 2017/06/05 08:20:36 snj Exp $ */ +/* $NetBSD: gic.c,v 1.21.2.2 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2012 The NetBSD Foundation, Inc. * All rights reserved. @@ -34,7 +34,7 @@ #define _INTR_PRIVATE #include -__KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.21.2.1 2017/06/05 08:20:36 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.21.2.2 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -53,7 +53,12 @@ __KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.21.2.1 2017/06/05 08:20:36 snj Exp $"); void armgic_irq_handler(void *); -#define ARMGIC_SGI_IPIBASE (16 - NIPI) +#define ARMGIC_SGI_IPIBASE 0 + +/* + * SGIs 8-16 are reserved for use by ARM Trusted Firmware. + */ +__CTASSERT(ARMGIC_SGI_IPIBASE + NIPI <= 8); static int armgic_match(device_t, cfdata_t, void *); static void armgic_attach(device_t, device_t, void *); @@ -100,6 +105,7 @@ static struct armgic_softc { #ifdef MULTIPROCESSOR uint32_t sc_mptargets; #endif + uint32_t sc_bptargets; } armgic_softc = { .sc_pic = { .pic_ops = &armgic_picops, @@ -139,6 +145,29 @@ gicd_write(struct armgic_softc *sc, bus_size_t o, uint32_t v) bus_space_write_4(sc->sc_memt, sc->sc_gicdh, o, v); } +static uint32_t +gicd_find_targets(struct armgic_softc *sc) +{ + uint32_t targets = 0; + + /* + * GICD_ITARGETSR0 through 7 are read-only, and each field returns + * a value that corresponds only to the processor reading the + * register. Use this to determine the current processor's + * CPU interface number. + */ + for (int i = 0; i < 8; i++) { + targets = gicd_read(sc, GICD_ITARGETSRn(i)); + if (targets != 0) + break; + } + targets |= (targets >> 16); + targets |= (targets >> 8); + targets &= 0xff; + + return targets ? targets : 1; +} + /* * In the GIC prioritization scheme, lower numbers have higher priority. * Only write priorities that could be non-secure. @@ -356,7 +385,7 @@ armgic_establish_irq(struct pic_softc *pic, struct intrsource *is) } else #endif #endif - targets |= 1 << byte_shift; + targets |= sc->sc_bptargets << byte_shift; gicd_write(sc, targets_reg, targets); /* @@ -458,11 +487,11 @@ void armgic_cpu_init(struct pic_softc *pic, struct cpu_info *ci) { struct armgic_softc * const sc = PICTOSOFTC(pic); - sc->sc_mptargets |= 1 << cpu_index(ci); + sc->sc_mptargets |= gicd_find_targets(sc); KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl); armgic_cpu_init_priorities(sc); if (!CPU_IS_PRIMARY(ci)) { - if (sc->sc_mptargets != 1) { + if (popcount(sc->sc_mptargets) != 1) { armgic_cpu_init_targets(sc); } if (sc->sc_enabled_local) { @@ -544,6 +573,11 @@ armgic_attach(device_t parent, device_t self, void *aux) uint32_t pmr = gicc_read(sc, GICC_PMR); u_int priorities = 1 << popcount32(pmr); + /* + * Find the boot processor's CPU interface number. + */ + sc->sc_bptargets = gicd_find_targets(sc); + /* * Let's find out how many real sources we have. */ diff --git a/sys/arch/arm/fdt/arm_fdt.c b/sys/arch/arm/fdt/arm_fdt.c index 4c5c62b5ab63..ccf8387d4752 100644 --- a/sys/arch/arm/fdt/arm_fdt.c +++ b/sys/arch/arm/fdt/arm_fdt.c @@ -1,4 +1,4 @@ -/* $NetBSD: arm_fdt.c,v 1.3 2017/05/30 22:00:25 jmcneill Exp $ */ +/* $NetBSD: arm_fdt.c,v 1.3.2.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2017 Jared D. McNeill @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: arm_fdt.c,v 1.3 2017/05/30 22:00:25 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: arm_fdt.c,v 1.3.2.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -143,3 +143,26 @@ arm_fdt_irq_handler(void *tf) { _arm_fdt_irq_handler(tf); } + +void +arm_fdt_memory_dump(paddr_t pa) +{ + const struct arm_platform *plat = arm_fdt_platform(); + struct fdt_attach_args faa; + bus_space_tag_t bst; + bus_space_handle_t bsh; + + plat->init_attach_args(&faa); + + bst = faa.faa_bst; + bus_space_map(bst, pa, 0x100, 0, &bsh); + + for (int i = 0; i < 0x100; i += 0x10) { + printf("%" PRIxPTR ": %08x %08x %08x %08x\n", + (uintptr_t)(pa + i), + bus_space_read_4(bst, bsh, i + 0), + bus_space_read_4(bst, bsh, i + 4), + bus_space_read_4(bst, bsh, i + 8), + bus_space_read_4(bst, bsh, i + 12)); + } +} diff --git a/sys/arch/arm/fdt/arm_fdtvar.h b/sys/arch/arm/fdt/arm_fdtvar.h index 8998bb2d4328..1f9b6882f5bf 100644 --- a/sys/arch/arm/fdt/arm_fdtvar.h +++ b/sys/arch/arm/fdt/arm_fdtvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: arm_fdtvar.h,v 1.5 2017/06/02 13:53:28 jmcneill Exp $ */ +/* $NetBSD: arm_fdtvar.h,v 1.5.2.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2017 Jared D. McNeill @@ -71,4 +71,6 @@ void arm_fdt_cpu_hatch(struct cpu_info *); void arm_fdt_irq_set_handler(void (*)(void *)); void arm_fdt_irq_handler(void *); +void arm_fdt_memory_dump(paddr_t); + #endif /* !_ARM_ARM_FDTVAR_H */ diff --git a/sys/arch/arm/fdt/files.fdt b/sys/arch/arm/fdt/files.fdt index 76b26ed233f9..5c6eea232f3f 100644 --- a/sys/arch/arm/fdt/files.fdt +++ b/sys/arch/arm/fdt/files.fdt @@ -1,4 +1,4 @@ -# $NetBSD: files.fdt,v 1.9.2.2 2017/06/10 05:57:08 snj Exp $ +# $NetBSD: files.fdt,v 1.9.2.3 2017/07/18 19:13:08 snj Exp $ include "dev/pckbport/files.pckbport" @@ -38,5 +38,8 @@ file arch/arm/fdt/aaci_fdt.c aaci_fdt attach plrtc at fdt with plrtc_fdt file arch/arm/fdt/plrtc_fdt.c plrtc_fdt +attach psci at fdt with psci_fdt +file arch/arm/fdt/psci_fdt.c psci_fdt + # Console parameters defparam opt_fdt_arm.h CONSADDR diff --git a/sys/arch/arm/fdt/gic_fdt.c b/sys/arch/arm/fdt/gic_fdt.c index 04c8a62af781..c4a8e59d81de 100644 --- a/sys/arch/arm/fdt/gic_fdt.c +++ b/sys/arch/arm/fdt/gic_fdt.c @@ -1,4 +1,4 @@ -/* $NetBSD: gic_fdt.c,v 1.4 2017/05/30 22:00:25 jmcneill Exp $ */ +/* $NetBSD: gic_fdt.c,v 1.4.2.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2015-2017 Jared McNeill @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: gic_fdt.c,v 1.4 2017/05/30 22:00:25 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gic_fdt.c,v 1.4.2.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -35,6 +35,7 @@ __KERNEL_RCSID(0, "$NetBSD: gic_fdt.c,v 1.4 2017/05/30 22:00:25 jmcneill Exp $") #include #include #include +#include #include #include @@ -42,9 +43,13 @@ __KERNEL_RCSID(0, "$NetBSD: gic_fdt.c,v 1.4 2017/05/30 22:00:25 jmcneill Exp $") #include +#define GIC_MAXIRQ 1020 + static int gic_fdt_match(device_t, cfdata_t, void *); static void gic_fdt_attach(device_t, device_t, void *); +static int gic_fdt_intr(void *); + static void * gic_fdt_establish(device_t, u_int *, int, int, int (*)(void *), void *); static void gic_fdt_disestablish(device_t, void *); @@ -56,9 +61,32 @@ struct fdtbus_interrupt_controller_func gic_fdt_funcs = { .intrstr = gic_fdt_intrstr }; +struct gic_fdt_softc; +struct gic_fdt_irq; + +struct gic_fdt_irqhandler { + struct gic_fdt_irq *ih_irq; + int (*ih_fn)(void *); + void *ih_arg; + bool ih_mpsafe; + TAILQ_ENTRY(gic_fdt_irqhandler) ih_next; +}; + +struct gic_fdt_irq { + struct gic_fdt_softc *intr_sc; + void *intr_ih; + int intr_refcnt; + int intr_ipl; + int intr_level; + int intr_mpsafe; + TAILQ_HEAD(, gic_fdt_irqhandler) intr_handlers; +}; + struct gic_fdt_softc { device_t sc_dev; int sc_phandle; + + struct gic_fdt_irq *sc_irq[GIC_MAXIRQ]; }; CFATTACH_DECL_NEW(gic_fdt, sizeof(struct gic_fdt_softc), @@ -137,7 +165,9 @@ static void * gic_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags, int (*func)(void *), void *arg) { - int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0; + struct gic_fdt_softc * const sc = device_private(dev); + struct gic_fdt_irq *firq; + struct gic_fdt_irqhandler *firqh; /* 1st cell is the interrupt type; 0 is SPI, 1 is PPI */ /* 2nd cell is the interrupt number */ @@ -149,13 +179,80 @@ gic_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags, const u_int trig = be32toh(specifier[2]) & 0xf; const u_int level = (trig & 0x3) ? IST_EDGE : IST_LEVEL; - return intr_establish(irq, ipl, level | iflags, func, arg); + const u_int mpsafe = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0; + + firq = sc->sc_irq[irq]; + if (firq == NULL) { + firq = kmem_alloc(sizeof(*firq), KM_SLEEP); + firq->intr_sc = sc; + firq->intr_refcnt = 0; + firq->intr_ipl = ipl; + firq->intr_level = level; + firq->intr_mpsafe = mpsafe; + TAILQ_INIT(&firq->intr_handlers); + firq->intr_ih = intr_establish(irq, ipl, level | mpsafe, + gic_fdt_intr, firq); + if (firq->intr_ih == NULL) { + kmem_free(firq, sizeof(*firq)); + return NULL; + } + sc->sc_irq[irq] = firq; + } + + if (firq->intr_ipl != ipl) { + device_printf(dev, "cannot share irq with different ipl\n"); + return NULL; + } + if (firq->intr_level != level) { + device_printf(dev, "cannot share edge and level interrupts\n"); + return NULL; + } + if (firq->intr_mpsafe != mpsafe) { + device_printf(dev, "cannot share between mpsafe/non-mpsafe\n"); + return NULL; + } + + firq->intr_refcnt++; + + firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP); + firqh->ih_mpsafe = (flags & FDT_INTR_MPSAFE) != 0; + firqh->ih_irq = firq; + firqh->ih_fn = func; + firqh->ih_arg = arg; + TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next); + + return firqh; } static void gic_fdt_disestablish(device_t dev, void *ih) { - intr_disestablish(ih); + struct gic_fdt_irqhandler *firqh = ih; + struct gic_fdt_irq *firq = firqh->ih_irq; + + KASSERT(firq->intr_refcnt > 0); + + TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next); + kmem_free(firqh, sizeof(*firqh)); + + firq->intr_refcnt--; + if (firq->intr_refcnt == 0) { + intr_disestablish(firq->intr_ih); + kmem_free(firq, sizeof(*firq)); + } +} + +static int +gic_fdt_intr(void *priv) +{ + struct gic_fdt_irq *firq = priv; + struct gic_fdt_irqhandler *firqh; + int handled = 0; + + TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) + handled += firqh->ih_fn(firqh->ih_arg); + + return handled; } static bool diff --git a/sys/arch/arm/fdt/psci_fdt.c b/sys/arch/arm/fdt/psci_fdt.c new file mode 100644 index 000000000000..802f578b743a --- /dev/null +++ b/sys/arch/arm/fdt/psci_fdt.c @@ -0,0 +1,176 @@ +/* $NetBSD: psci_fdt.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: psci_fdt.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +static int psci_fdt_match(device_t, cfdata_t, void *); +static void psci_fdt_attach(device_t, device_t, void *); + +static int psci_fdt_init(const int); + +static const char * const compatible[] = { + "arm,psci", + "arm,psci-0.2", + "arm,psci-1.0", + NULL +}; + +CFATTACH_DECL_NEW(psci_fdt, 0, psci_fdt_match, psci_fdt_attach, NULL, NULL); + +static int +psci_fdt_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +psci_fdt_attach(device_t parent, device_t self, void *aux) +{ + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + + psci_fdt_init(phandle); + + const uint32_t ver = psci_version(); + const u_int ver_maj = __SHIFTOUT(ver, PSCI_VERSION_MAJOR); + const u_int ver_min = __SHIFTOUT(ver, PSCI_VERSION_MINOR); + + aprint_naive("\n"); + aprint_normal(": PSCI %u.%u\n", ver_maj, ver_min); +} + +static int +psci_fdt_init(const int phandle) +{ + char method[4]; + uint32_t val; + + if (!of_hasprop(phandle, "method")) { + aprint_error("PSCI: missing 'method' property\n"); + return EINVAL; + } + + OF_getprop(phandle, "method", method, sizeof(method)); + if (strcmp(method, "smc") == 0) + psci_init(psci_call_smc); + else if (strcmp(method, "hvc") == 0) + psci_init(psci_call_hvc); + else { + aprint_error("PSCI: unsupported method '%s'\n", method); + return EINVAL; + } + + const char * const compat_0_1[] = { "arm,psci", NULL }; + if (of_match_compatible(phandle, compat_0_1)) { + psci_clearfunc(); + if (of_getprop_uint32(phandle, "cpu_on", &val) == 0) + psci_setfunc(PSCI_FUNC_CPU_ON, val); + } + + return 0; +} + +void +psci_fdt_bootstrap(void) +{ + extern void cortex_mpstart(void); + bus_addr_t mpidr; + uint32_t bp_mpidr; + int child; + + const int cpus = OF_finddevice("/cpus"); + if (cpus == -1) { + aprint_error("PSCI: no /cpus node found\n"); + arm_cpu_max = 1; + return; + } + + /* Count CPUs */ + arm_cpu_max = 0; + for (child = OF_child(cpus); child; child = OF_peer(child)) + if (fdtbus_status_okay(child)) + arm_cpu_max++; + + const int phandle = OF_finddevice("/psci"); + if (phandle == -1) { + aprint_error("PSCI: no /psci node found\n"); + return; + } + + if (psci_fdt_init(phandle) != 0) + return; + + /* MPIDR affinity levels of boot processor. */ + bp_mpidr = armreg_mpidr_read() & (MPIDR_AFF2|MPIDR_AFF1|MPIDR_AFF0); + + /* Boot APs */ + uint32_t started = 0; + for (child = OF_child(cpus); child; child = OF_peer(child)) { + if (!fdtbus_status_okay(child)) + continue; + if (fdtbus_get_reg(child, 0, &mpidr, NULL) != 0) + continue; + if (mpidr == bp_mpidr) + continue; /* BP already started */ + + /* XXX NetBSD requires all CPUs to be in the same cluster */ + const u_int bp_clid = __SHIFTOUT(bp_mpidr, CORTEXA9_MPIDR_CLID); + const u_int clid = __SHIFTOUT(mpidr, CORTEXA9_MPIDR_CLID); + if (bp_clid != clid) + continue; + + const u_int cpuid = __SHIFTOUT(mpidr, CORTEXA9_MPIDR_CPUID); + int ret = psci_cpu_on(cpuid, (register_t)cortex_mpstart, 0); + if (ret == PSCI_SUCCESS) + started |= __BIT(cpuid); + } + + /* Wait for APs to start */ + for (u_int i = 0x10000000; i > 0; i--) { + arm_dmb(); + if (arm_cpu_hatched == started) + break; + } +} diff --git a/sys/arch/arm/fdt/psci_fdt.h b/sys/arch/arm/fdt/psci_fdt.h new file mode 100644 index 000000000000..8045d112b0c1 --- /dev/null +++ b/sys/arch/arm/fdt/psci_fdt.h @@ -0,0 +1,35 @@ +/* $NetBSD: psci_fdt.h,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#ifndef _ARM_PSCI_FDT_H +#define _ARM_PSCI_FDT_H + +/* Initialize PSCI and boot APs */ +void psci_fdt_bootstrap(void); + +#endif /* !_ARM_PSCI_FDT_H */ diff --git a/sys/arch/arm/rockchip/rockchip_dwcmmc.c b/sys/arch/arm/rockchip/rockchip_dwcmmc.c index cb860ad626e6..99a30e85bc2b 100644 --- a/sys/arch/arm/rockchip/rockchip_dwcmmc.c +++ b/sys/arch/arm/rockchip/rockchip_dwcmmc.c @@ -1,4 +1,4 @@ -/* $NetBSD: rockchip_dwcmmc.c,v 1.5 2015/01/03 13:29:02 jmcneill Exp $ */ +/* $NetBSD: rockchip_dwcmmc.c,v 1.5.12.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2014 Jared D. McNeill @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: rockchip_dwcmmc.c,v 1.5 2015/01/03 13:29:02 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rockchip_dwcmmc.c,v 1.5.12.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -46,8 +46,6 @@ __KERNEL_RCSID(0, "$NetBSD: rockchip_dwcmmc.c,v 1.5 2015/01/03 13:29:02 jmcneill static int rk_dwcmmc_match(device_t, cfdata_t, void *); static void rk_dwcmmc_attach(device_t, device_t, void *); -static void rk_dwcmmc_attach_i(device_t); - CFATTACH_DECL_NEW(rkdwcmmc, sizeof(struct dwc_mmc_softc), rk_dwcmmc_match, rk_dwcmmc_attach, NULL, NULL); @@ -68,8 +66,7 @@ rk_dwcmmc_attach(device_t parent, device_t self, void *aux) sc->sc_dev = self; sc->sc_bst = obio->obio_bst; sc->sc_dmat = obio->obio_dmat; - sc->sc_flags = DWC_MMC_F_USE_HOLD_REG | DWC_MMC_F_PWREN_CLEAR | - DWC_MMC_F_FORCE_CLK; + sc->sc_flags = DWC_MMC_F_USE_HOLD_REG; sc->sc_clock_freq = rockchip_mmc0_get_rate(); #if 0 sc->sc_clock_max = 24000; @@ -82,6 +79,9 @@ rk_dwcmmc_attach(device_t parent, device_t self, void *aux) aprint_naive("\n"); aprint_normal(": SD/MMC controller\n"); + if (dwc_mmc_init(sc) != 0) + return; + sc->sc_ih = intr_establish(obio->obio_intr, IPL_BIO, IST_LEVEL, dwc_mmc_intr, sc); if (sc->sc_ih == NULL) { @@ -89,14 +89,4 @@ rk_dwcmmc_attach(device_t parent, device_t self, void *aux) obio->obio_intr); return; } - - config_interrupts(self, rk_dwcmmc_attach_i); -} - -static void -rk_dwcmmc_attach_i(device_t self) -{ - struct dwc_mmc_softc *sc = device_private(self); - - dwc_mmc_init(sc); } diff --git a/sys/arch/arm/samsung/exynos5410_clock.c b/sys/arch/arm/samsung/exynos5410_clock.c new file mode 100644 index 000000000000..9e84cd90bf05 --- /dev/null +++ b/sys/arch/arm/samsung/exynos5410_clock.c @@ -0,0 +1,864 @@ +/* $NetBSD: exynos5410_clock.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2015-2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: exynos5410_clock.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +static struct clk *exynos5410_clock_decode(device_t, const void *, size_t); + +static const struct fdtbus_clock_controller_func exynos5410_car_fdtclock_funcs = { + .decode = exynos5410_clock_decode +}; + +/* DT clock ID to clock name mappings */ +static struct exynos5410_clock_id { + u_int id; + const char *name; +} exynos5410_clock_ids[] = { + /* core clocks */ + { 1, "fin_pll" }, + { 2, "fout_apll" }, + { 3, "fout_cpll" }, + { 4, "fout_dpll" }, + { 5, "fout_mpll" }, + { 6, "fout_kpll" }, + { 7, "fout_epll" }, + + /* gate for special clocks (sclk) */ + { 128, "sclk_uart0" }, + { 129, "sclk_uart1" }, + { 130, "sclk_uart2" }, + { 131, "sclk_uart3" }, + { 132, "sclk_mmc0" }, + { 133, "sclk_mmc1" }, + { 134, "sclk_mmc2" }, + { 150, "sclk_usbd300" }, + { 151, "sclk_usbd301" }, + { 152, "sclk_usbphy300" }, + { 153, "sclk_usbphy301" }, + { 155, "sclk_pwm" }, + + /* gate clocks */ + { 257, "uart0" }, + { 258, "uart1" }, + { 259, "uart2" }, + { 260, "uart3" }, + { 261, "i2c0" }, + { 262, "i2c1" }, + { 263, "i2c2" }, + { 264, "i2c3" }, + { 265, "usi0" }, + { 266, "usi1" }, + { 267, "usi2" }, + { 268, "usi3" }, + { 279, "pwm" }, + { 315, "mct" }, + { 316, "wdt" }, + { 317, "rtc" }, + { 318, "tmu" }, + { 351, "mmc0" }, + { 352, "mmc1" }, + { 353, "mmc2" }, + { 362, "pdma0" }, + { 363, "pdma1" }, + { 365, "usbh20" }, + { 366, "usbd300" }, + { 367, "usbd301" }, + { 471, "sss" }, +}; + +static struct clk *exynos5410_clock_get(void *, const char *); +static void exynos5410_clock_put(void *, struct clk *); +static u_int exynos5410_clock_get_rate(void *, struct clk *); +static int exynos5410_clock_set_rate(void *, struct clk *, u_int); +static int exynos5410_clock_enable(void *, struct clk *); +static int exynos5410_clock_disable(void *, struct clk *); +static int exynos5410_clock_set_parent(void *, struct clk *, struct clk *); +static struct clk *exynos5410_clock_get_parent(void *, struct clk *); + +static const struct clk_funcs exynos5410_clock_funcs = { + .get = exynos5410_clock_get, + .put = exynos5410_clock_put, + .get_rate = exynos5410_clock_get_rate, + .set_rate = exynos5410_clock_set_rate, + .enable = exynos5410_clock_enable, + .disable = exynos5410_clock_disable, + .set_parent = exynos5410_clock_set_parent, + .get_parent = exynos5410_clock_get_parent, +}; + +#define CLK_FIXED(_name, _rate) { \ + .base = { .name = (_name) }, .type = EXYNOS_CLK_FIXED, \ + .u = { .fixed = { .rate = (_rate) } } \ +} + +#define CLK_PLL(_name, _parent, _lock, _con0) { \ + .base = { .name = (_name) }, .type = EXYNOS_CLK_PLL, \ + .parent = (_parent), \ + .u = { \ + .pll = { \ + .lock_reg = (_lock), \ + .con0_reg = (_con0), \ + } \ + } \ +} + +#define CLK_MUXF(_name, _alias, _reg, _bits, _f, _p) { \ + .base = { .name = (_name), .flags = (_f) }, \ + .type = EXYNOS_CLK_MUX, \ + .alias = (_alias), \ + .u = { \ + .mux = { \ + .nparents = __arraycount(_p), \ + .parents = (_p), \ + .reg = (_reg), \ + .bits = (_bits) \ + } \ + } \ +} + +#define CLK_MUXA(_name, _alias, _reg, _bits, _p) \ + CLK_MUXF(_name, _alias, _reg, _bits, 0, _p) + +#define CLK_MUX(_name, _reg, _bits, _p) \ + CLK_MUXF(_name, NULL, _reg, _bits, 0, _p) + +#define CLK_DIVF(_name, _parent, _reg, _bits, _f) { \ + .base = { .name = (_name), .flags = (_f) }, \ + .type = EXYNOS_CLK_DIV, \ + .parent = (_parent), \ + .u = { \ + .div = { \ + .reg = (_reg), \ + .bits = (_bits) \ + } \ + } \ +} + +#define CLK_DIV(_name, _parent, _reg, _bits) \ + CLK_DIVF(_name, _parent, _reg, _bits, 0) + +#define CLK_GATE(_name, _parent, _reg, _bits, _f) { \ + .base = { .name = (_name), .flags = (_f) }, \ + .type = EXYNOS_CLK_GATE, \ + .parent = (_parent), \ + .u = { \ + .gate = { \ + .reg = (_reg), \ + .bits = (_bits) \ + } \ + } \ +} + +#define EXYNOS5410_APLL_LOCK 0x00000 +#define EXYNOS5410_APLL_CON0 0x00100 +#define EXYNOS5410_MPLL_LOCK 0x04000 +#define EXYNOS5410_MPLL_CON0 0x04100 +#define EXYNOS5410_CPLL_LOCK 0x10020 +#define EXYNOS5410_EPLL_LOCK 0x10040 +#define EXYNOS5410_CPLL_CON0 0x10120 +#define EXYNOS5410_EPLL_CON0 0x10130 +#define EXYNOS5410_EPLL_CON1 0x10134 +#define EXYNOS5410_EPLL_CON2 0x10138 +#define EXYNOS5410_BPLL_LOCK 0x20010 +#define EXYNOS5410_BPLL_CON0 0x20110 +#define EXYNOS5410_KPLL_LOCK 0x28000 +#define EXYNOS5410_KPLL_CON0 0x28100 + +#define EXYNOS5410_SRC_CPU 0x00200 +#define EXYNOS5410_SRC_CPERI1 0x04204 +#define EXYNOS5410_SRC_TOP0 0x10210 +#define EXYNOS5410_SRC_TOP1 0x10214 +#define EXYNOS5410_SRC_TOP2 0x10218 +#define EXYNOS5410_SRC_FSYS 0x10244 +#define EXYNOS5410_SRC_PERIC0 0x10250 +#define EXYNOS5410_SRC_MASK_FSYS 0x10340 +#define EXYNOS5410_SRC_MASK_PERIC0 0x10350 +#define EXYNOS5410_SRC_CDREX 0x20200 +#define EXYNOS5410_SRC_KFC 0x28200 + +#define EXYNOS5410_DIV_CPU0 0x00500 +#define EXYNOS5410_DIV_TOP0 0x10510 +#define EXYNOS5410_DIV_TOP1 0x10514 +#define EXYNOS5410_DIV_FSYS0 0x10548 +#define EXYNOS5410_DIV_FSYS1 0x1054c +#define EXYNOS5410_DIV_FSYS2 0x10550 +#define EXYNOS5410_DIV_PERIC0 0x10558 +#define EXYNOS5410_DIV_PERIC3 0x10564 +#define EXYNOS5410_DIV_KFC0 0x28500 + +#define EXYNOS5410_GATE_IP_G2D 0x08800 +#define EXYNOS5410_GATE_BUS_FSYS0 0x10740 +#define EXYNOS5410_GATE_TOP_SCLK_FSYS 0x10840 +#define EXYNOS5410_GATE_TOP_SCLK_PERIC 0x10850 +#define EXYNOS5410_GATE_IP_FSYS 0x10944 +#define EXYNOS5410_GATE_IP_PERIC 0x10950 +#define EXYNOS5410_GATE_IP_PERIS 0x10960 + +static const char *mout_apll_p[] = { "fin_pll", "fout_apll" }; +static const char *mout_bpll_p[] = { "fin_pll", "fout_bpll" }; +static const char *mout_cpll_p[] = { "fin_pll", "fout_cpll" }; +static const char *mout_epll_p[] = { "fin_pll", "fout_epll" }; +static const char *mout_mpll_p[] = { "fin_pll", "fout_mpll" }; +static const char *mout_kpll_p[] = { "fin_pll", "fout_kpll" }; + +static const char *mout_cpu_p[] = { "mout_apll", "sclk_mpll" }; +static const char *mout_kfc_p[] = { "mout_kpll", "sclk_mpll" }; + +static const char *mout_mpll_user_p[] = { "fin_pll", "sclk_mpll" }; +static const char *mout_bpll_user_p[] = { "fin_pll", "sclk_bpll" }; +static const char *mout_mpll_bpll_p[] = + { "sclk_mpll_muxed", "sclk_bpll_muxed" }; +static const char *mout_sclk_mpll_bpll_p[] = { "sclk_mpll_bpll", "fin_pll" }; + +static const char *mout_group2_p[] = + { "fin_pll", "fin_pll", "none", "none", "none", "none", + "sclk_mpll_bpll", "none", "none", "sclk_cpll" }; + +static struct exynos_clk exynos5410_clocks[] = { + CLK_FIXED("fin_pll", EXYNOS_F_IN_FREQ), + + CLK_PLL("fout_apll", "fin_pll", EXYNOS5410_APLL_LOCK, + EXYNOS5410_APLL_CON0), + CLK_PLL("fout_bpll", "fin_pll", EXYNOS5410_BPLL_LOCK, + EXYNOS5410_BPLL_CON0), + CLK_PLL("fout_cpll", "fin_pll", EXYNOS5410_CPLL_LOCK, + EXYNOS5410_CPLL_CON0), + CLK_PLL("fout_epll", "fin_pll", EXYNOS5410_EPLL_LOCK, + EXYNOS5410_EPLL_CON0), + CLK_PLL("fout_mpll", "fin_pll", EXYNOS5410_MPLL_LOCK, + EXYNOS5410_MPLL_CON0), + CLK_PLL("fout_kpll", "fin_pll", EXYNOS5410_KPLL_LOCK, + EXYNOS5410_KPLL_CON0), + + CLK_MUX("mout_apll", EXYNOS5410_SRC_CPU, __BIT(0), mout_apll_p), + CLK_MUX("mout_cpu", EXYNOS5410_SRC_CPU, __BIT(16), mout_cpu_p), + CLK_MUX("mout_kpll", EXYNOS5410_SRC_KFC, __BIT(0), mout_kpll_p), + CLK_MUX("mout_kfc", EXYNOS5410_SRC_KFC, __BIT(16), mout_kfc_p), + + CLK_MUX("sclk_mpll", EXYNOS5410_SRC_CPERI1, __BIT(8), mout_mpll_p), + CLK_MUX("sclk_mpll_muxed", EXYNOS5410_SRC_TOP2, __BIT(20), mout_mpll_user_p), + CLK_MUX("sclk_bpll", EXYNOS5410_SRC_CDREX, __BIT(0), mout_bpll_p), + CLK_MUX("sclk_bpll_muxed", EXYNOS5410_SRC_TOP2, __BIT(24), mout_bpll_user_p), + CLK_MUX("sclk_epll", EXYNOS5410_SRC_TOP2, __BIT(12), mout_epll_p), + CLK_MUX("sclk_cpll", EXYNOS5410_SRC_TOP2, __BIT(8), mout_cpll_p), + CLK_MUX("sclk_mpll_bpll", EXYNOS5410_SRC_TOP1, __BIT(20), mout_mpll_bpll_p), + + CLK_MUX("mout_mmc0", EXYNOS5410_SRC_FSYS, __BITS(3,0), mout_group2_p), + CLK_MUX("mout_mmc1", EXYNOS5410_SRC_FSYS, __BITS(7,4), mout_group2_p), + CLK_MUX("mout_mmc2", EXYNOS5410_SRC_FSYS, __BITS(11,8), mout_group2_p), + CLK_MUX("mout_usbd300", EXYNOS5410_SRC_FSYS, __BIT(28), mout_sclk_mpll_bpll_p), + CLK_MUX("mout_usbd301", EXYNOS5410_SRC_FSYS, __BIT(29), mout_sclk_mpll_bpll_p), + CLK_MUX("mout_uart0", EXYNOS5410_SRC_PERIC0, __BITS(3,0), mout_group2_p), + CLK_MUX("mout_uart1", EXYNOS5410_SRC_PERIC0, __BITS(7,4), mout_group2_p), + CLK_MUX("mout_uart2", EXYNOS5410_SRC_PERIC0, __BITS(11,8), mout_group2_p), + CLK_MUX("mout_uart3", EXYNOS5410_SRC_PERIC0, __BITS(15,12), mout_group2_p), + CLK_MUX("mout_pwm", EXYNOS5410_SRC_PERIC0, __BITS(27,24), mout_group2_p), + CLK_MUX("mout_aclk200", EXYNOS5410_SRC_TOP0, __BIT(12), mout_mpll_bpll_p), + CLK_MUX("mout_aclk400", EXYNOS5410_SRC_TOP0, __BIT(20), mout_mpll_bpll_p), + + CLK_DIV("div_arm", "mout_cpu", EXYNOS5410_DIV_CPU0, __BITS(2,0)), + CLK_DIV("div_arm2", "div_arm", EXYNOS5410_DIV_CPU0, __BITS(30,28)), + + CLK_DIV("div_acp", "div_arm2", EXYNOS5410_DIV_CPU0, __BITS(10,8)), + CLK_DIV("div_cpud", "div_arm2", EXYNOS5410_DIV_CPU0, __BITS(6,4)), + CLK_DIV("div_atb", "div_arm2", EXYNOS5410_DIV_CPU0, __BITS(18,16)), + CLK_DIV("pclk_dbg", "div_arm2", EXYNOS5410_DIV_CPU0, __BITS(22,20)), + + CLK_DIV("div_kfc", "mout_kfc", EXYNOS5410_DIV_KFC0, __BITS(2,0)), + CLK_DIV("div_aclk", "div_kfc", EXYNOS5410_DIV_KFC0, __BITS(6,4)), + CLK_DIV("div_pclk", "div_kfc", EXYNOS5410_DIV_KFC0, __BITS(22,20)), + + CLK_DIV("aclk66_pre", "sclk_mpll_muxed", EXYNOS5410_DIV_TOP1, __BITS(26,24)), + CLK_DIV("aclk66", "aclk66_pre", EXYNOS5410_DIV_TOP0, __BITS(2,0)), + + CLK_DIV("dout_usbphy300", "mout_usbd300", EXYNOS5410_DIV_FSYS0, __BITS(19,16)), + CLK_DIV("dout_usbphy301", "mout_usbd301", EXYNOS5410_DIV_FSYS0, __BITS(23,20)), + CLK_DIV("dout_usbd300", "mout_usbd300", EXYNOS5410_DIV_FSYS0, __BITS(27,24)), + CLK_DIV("dout_usbd301", "mout_usbd301", EXYNOS5410_DIV_FSYS0, __BITS(31,28)), + + CLK_DIV("dout_mmc0", "mout_mmc0", EXYNOS5410_DIV_FSYS1, __BITS(3,0)), + CLK_DIV("dout_mmc1", "mout_mmc1", EXYNOS5410_DIV_FSYS1, __BITS(19,16)), + CLK_DIV("dout_mmc2", "mout_mmc2", EXYNOS5410_DIV_FSYS2, __BITS(3,0)), + + CLK_DIVF("dout_mmc_pre0", "dout_mmc0", EXYNOS5410_DIV_FSYS1, __BITS(15,8), + CLK_SET_RATE_PARENT), + CLK_DIVF("dout_mmc_pre1", "dout_mmc1", EXYNOS5410_DIV_FSYS1, __BITS(31,24), + CLK_SET_RATE_PARENT), + CLK_DIVF("dout_mmc_pre2", "dout_mmc2", EXYNOS5410_DIV_FSYS2, __BITS(15,8), + CLK_SET_RATE_PARENT), + + CLK_DIV("div_uart0", "mout_uart0", EXYNOS5410_DIV_PERIC0, __BITS(3,0)), + CLK_DIV("div_uart1", "mout_uart1", EXYNOS5410_DIV_PERIC0, __BITS(7,4)), + CLK_DIV("div_uart2", "mout_uart2", EXYNOS5410_DIV_PERIC0, __BITS(11,8)), + CLK_DIV("div_uart3", "mout_uart3", EXYNOS5410_DIV_PERIC0, __BITS(15,12)), + + CLK_DIV("dout_pwm", "mout_pwm", EXYNOS5410_DIV_PERIC3, __BITS(3,0)), + + CLK_DIV("aclk200", "mout_aclk200", EXYNOS5410_DIV_TOP0, __BITS(14,12)), + CLK_DIV("aclk266", "sclk_mpll_muxed", EXYNOS5410_DIV_TOP0, __BITS(18,16)), + CLK_DIV("aclk400", "mout_aclk400", EXYNOS5410_DIV_TOP0, __BITS(26,24)), + + CLK_GATE("sss", "aclk266", EXYNOS5410_GATE_IP_G2D, __BIT(2), 0), + + CLK_GATE("mct", "aclk66", EXYNOS5410_GATE_IP_PERIS, __BIT(18), 0), + CLK_GATE("wdt", "aclk66", EXYNOS5410_GATE_IP_PERIS, __BIT(19), 0), + CLK_GATE("rtc", "aclk66", EXYNOS5410_GATE_IP_PERIS, __BIT(20), 0), + CLK_GATE("tmu", "aclk66", EXYNOS5410_GATE_IP_PERIS, __BIT(21), 0), + + CLK_GATE("sclk_mmc0", "dout_mmc_pre0", EXYNOS5410_SRC_MASK_FSYS, + __BIT(0), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_mmc1", "dout_mmc_pre1", EXYNOS5410_SRC_MASK_FSYS, + __BIT(4), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_mmc2", "dout_mmc_pre2", EXYNOS5410_SRC_MASK_FSYS, + __BIT(8), CLK_SET_RATE_PARENT), + + CLK_GATE("mmc0", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(12), 0), + CLK_GATE("mmc1", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(13), 0), + CLK_GATE("mmc2", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(14), 0), + CLK_GATE("pdma1", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(2), 0), + CLK_GATE("pdma0", "aclk200", EXYNOS5410_GATE_BUS_FSYS0, __BIT(1), 0), + + CLK_GATE("sclk_usbphy301", "dout_usbphy301", EXYNOS5410_GATE_TOP_SCLK_FSYS, + __BIT(7), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_usbphy300", "dout_usbphy300", EXYNOS5410_GATE_TOP_SCLK_FSYS, + __BIT(8), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_usbd301", "dout_usbd301", EXYNOS5410_GATE_TOP_SCLK_FSYS, + __BIT(9), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_usbd301", "dout_usbd301", EXYNOS5410_GATE_TOP_SCLK_FSYS, + __BIT(10), CLK_SET_RATE_PARENT), + + CLK_GATE("sclk_pwm", "dout_pwm", EXYNOS5410_GATE_TOP_SCLK_PERIC, + __BIT(11), CLK_SET_RATE_PARENT), + + CLK_GATE("uart0", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(0), 0), + CLK_GATE("uart1", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(1), 0), + CLK_GATE("uart2", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(2), 0), + CLK_GATE("uart3", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(3), 0), + CLK_GATE("i2c0", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(6), 0), + CLK_GATE("i2c1", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(7), 0), + CLK_GATE("i2c2", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(8), 0), + CLK_GATE("i2c3", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(9), 0), + CLK_GATE("usi0", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(10), 0), + CLK_GATE("usi1", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(11), 0), + CLK_GATE("usi2", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(12), 0), + CLK_GATE("usi3", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(13), 0), + CLK_GATE("pwm", "aclk66", EXYNOS5410_GATE_IP_PERIC, __BIT(24), 0), + + CLK_GATE("sclk_uart0", "div_uart0", EXYNOS5410_SRC_MASK_PERIC0, + __BIT(0), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_uart1", "div_uart1", EXYNOS5410_SRC_MASK_PERIC0, + __BIT(4), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_uart2", "div_uart2", EXYNOS5410_SRC_MASK_PERIC0, + __BIT(8), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_uart3", "div_uart3", EXYNOS5410_SRC_MASK_PERIC0, + __BIT(12), CLK_SET_RATE_PARENT), + + CLK_GATE("usbh20", "aclk200", EXYNOS5410_GATE_IP_FSYS, __BIT(18), 0), + CLK_GATE("usbd301", "aclk200", EXYNOS5410_GATE_IP_FSYS, __BIT(19), 0), + CLK_GATE("usbd300", "aclk200", EXYNOS5410_GATE_IP_FSYS, __BIT(20), 0), +}; + +static int exynos5410_clock_match(device_t, cfdata_t, void *); +static void exynos5410_clock_attach(device_t, device_t, void *); + +struct exynos5410_clock_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + + struct clk_domain sc_clkdom; +}; + +static void exynos5410_clock_print_header(void); +static void exynos5410_clock_print(struct exynos5410_clock_softc *, + struct exynos_clk *); + +CFATTACH_DECL_NEW(exynos5410_clock, sizeof(struct exynos5410_clock_softc), + exynos5410_clock_match, exynos5410_clock_attach, NULL, NULL); + +#define CLOCK_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define CLOCK_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static int +exynos5410_clock_match(device_t parent, cfdata_t cf, void *aux) +{ + const char * const compatible[] = { "samsung,exynos5410-clock", NULL }; + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +exynos5410_clock_attach(device_t parent, device_t self, void *aux) +{ + struct exynos5410_clock_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + bus_addr_t addr; + bus_size_t size; + int error; + + if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bst = faa->faa_bst; + + error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); + if (error) { + aprint_error(": couldn't map %#llx: %d", + (uint64_t)addr, error); + return; + } + + aprint_naive("\n"); + aprint_normal(": Exynos5410 Clock Controller\n"); + + sc->sc_clkdom.funcs = &exynos5410_clock_funcs; + sc->sc_clkdom.priv = sc; + for (u_int n = 0; n < __arraycount(exynos5410_clocks); n++) { + exynos5410_clocks[n].base.domain = &sc->sc_clkdom; + } + + fdtbus_register_clock_controller(self, faa->faa_phandle, + &exynos5410_car_fdtclock_funcs); + + exynos5410_clock_print_header(); + for (u_int n = 0; n < __arraycount(exynos5410_clocks); n++) { + exynos5410_clock_print(sc, &exynos5410_clocks[n]); + } +} + +static struct exynos_clk * +exynos5410_clock_find(const char *name) +{ + u_int n; + + for (n = 0; n < __arraycount(exynos5410_clocks); n++) { + if (strcmp(exynos5410_clocks[n].base.name, name) == 0) { + return &exynos5410_clocks[n]; + } + } + + return NULL; +} + +static struct exynos_clk * +exynos5410_clock_find_by_id(u_int clock_id) +{ + u_int n; + + for (n = 0; n < __arraycount(exynos5410_clock_ids); n++) { + if (exynos5410_clock_ids[n].id == clock_id) { + const char *name = exynos5410_clock_ids[n].name; + return exynos5410_clock_find(name); + } + } + + return NULL; +} + +static void +exynos5410_clock_print_header(void) +{ + printf(" %-10s %2s %-10s %-5s %10s\n", + "clock", "", "parent", "type", "rate"); + printf(" %-10s %2s %-10s %-5s %10s\n", + "=====", "", "======", "====", "===="); +} + +static void +exynos5410_clock_print(struct exynos5410_clock_softc *sc, + struct exynos_clk *eclk) +{ + struct exynos_clk *eclk_parent; + struct clk *clk_parent; + const char *type = "?"; + + switch (eclk->type) { + case EXYNOS_CLK_FIXED: + type = "fixed"; + break; + case EXYNOS_CLK_PLL: + type = "pll"; + break; + case EXYNOS_CLK_MUX: + type = "mux"; + break; + case EXYNOS_CLK_DIV: + type = "div"; + break; + case EXYNOS_CLK_GATE: + type = "gate"; + break; + } + + clk_parent = exynos5410_clock_get_parent(sc, &eclk->base); + eclk_parent = (struct exynos_clk *)clk_parent; + + printf(" %-10s %2s %-10s %-5s %10d Hz\n", + eclk->base.name, + eclk_parent ? "<-" : "", + eclk_parent ? eclk_parent->base.name : "", + type, clk_get_rate(&eclk->base)); +} + +static struct clk * +exynos5410_clock_decode(device_t dev, const void *data, size_t len) +{ + struct exynos_clk *eclk; + + /* #clock-cells should be 1 */ + if (len != 4) { + return NULL; + } + + const u_int clock_id = be32dec(data); + + eclk = exynos5410_clock_find_by_id(clock_id); + if (eclk) + return &eclk->base; + + return NULL; +} + +static u_int +exynos5410_clock_get_rate_pll(struct exynos5410_clock_softc *sc, + struct exynos_clk *eclk) +{ + struct exynos_pll_clk *epll = &eclk->u.pll; + struct exynos_clk *clk_parent; + + KASSERT(eclk->type == EXYNOS_CLK_PLL); + + clk_parent = exynos5410_clock_find(eclk->parent); + KASSERT(clk_parent != NULL); + const u_int rate_parent = exynos5410_clock_get_rate(sc, + &clk_parent->base); + + const uint32_t v = CLOCK_READ(sc, epll->con0_reg); + + return PLL_FREQ(rate_parent, v); +} + +static int +exynos5410_clock_set_rate_pll(struct exynos5410_clock_softc *sc, + struct exynos_clk *eclk, u_int rate) +{ + /* TODO */ + return EOPNOTSUPP; +} + +static int +exynos5410_clock_set_parent_mux(struct exynos5410_clock_softc *sc, + struct exynos_clk *eclk, struct exynos_clk *eclk_parent) +{ + struct exynos_mux_clk *emux = &eclk->u.mux; + const char *pname = eclk_parent->base.name; + u_int sel; + + KASSERT(eclk->type == EXYNOS_CLK_MUX); + + for (sel = 0; sel < emux->nparents; sel++) { + if (strcmp(pname, emux->parents[sel]) == 0) { + break; + } + } + if (sel == emux->nparents) { + return EINVAL; + } + + uint32_t v = CLOCK_READ(sc, emux->reg); + v &= ~emux->bits; + v |= __SHIFTIN(sel, emux->bits); + CLOCK_WRITE(sc, emux->reg, v); + + return 0; +} + +static struct exynos_clk * +exynos5410_clock_get_parent_mux(struct exynos5410_clock_softc *sc, + struct exynos_clk *eclk) +{ + struct exynos_mux_clk *emux = &eclk->u.mux; + + KASSERT(eclk->type == EXYNOS_CLK_MUX); + + const uint32_t v = CLOCK_READ(sc, emux->reg); + const u_int sel = __SHIFTOUT(v, emux->bits); + + KASSERT(sel < emux->nparents); + + return exynos5410_clock_find(emux->parents[sel]); +} + +static u_int +exynos5410_clock_get_rate_div(struct exynos5410_clock_softc *sc, + struct exynos_clk *eclk) +{ + struct exynos_div_clk *ediv = &eclk->u.div; + struct clk *clk_parent; + + KASSERT(eclk->type == EXYNOS_CLK_DIV); + + clk_parent = exynos5410_clock_get_parent(sc, &eclk->base); + const u_int parent_rate = exynos5410_clock_get_rate(sc, clk_parent); + + const uint32_t v = CLOCK_READ(sc, ediv->reg); + const u_int div = __SHIFTOUT(v, ediv->bits); + + return parent_rate / (div + 1); +} + +static int +exynos5410_clock_set_rate_div(struct exynos5410_clock_softc *sc, + struct exynos_clk *eclk, u_int rate) +{ + struct exynos_div_clk *ediv = &eclk->u.div; + struct clk *clk_parent; + int tmp_div, new_div = -1; + u_int tmp_rate; + + KASSERT(eclk->type == EXYNOS_CLK_DIV); + + clk_parent = exynos5410_clock_get_parent(sc, &eclk->base); + const u_int parent_rate = exynos5410_clock_get_rate(sc, clk_parent); + + for (tmp_div = 0; tmp_div < popcount32(ediv->bits); tmp_div++) { + tmp_rate = parent_rate / (tmp_div + 1); + if (tmp_rate <= rate) { + new_div = tmp_div; + break; + } + } + if (new_div == -1) + return EINVAL; + + uint32_t v = CLOCK_READ(sc, ediv->reg); + v &= ~ediv->bits; + v |= __SHIFTIN(new_div, ediv->bits); + CLOCK_WRITE(sc, ediv->reg, v); + + return 0; +} + +static int +exynos5410_clock_enable_gate(struct exynos5410_clock_softc *sc, + struct exynos_clk *eclk, bool enable) +{ + struct exynos_gate_clk *egate = &eclk->u.gate; + + KASSERT(eclk->type == EXYNOS_CLK_GATE); + + uint32_t v = CLOCK_READ(sc, egate->reg); + if (enable) { + v |= egate->bits; + } else { + v &= ~egate->bits; + } + CLOCK_WRITE(sc, egate->reg, v); + + return 0; +} + +/* + * clk api + */ + +static struct clk * +exynos5410_clock_get(void *priv, const char *name) +{ + struct exynos_clk *eclk; + + eclk = exynos5410_clock_find(name); + if (eclk == NULL) + return NULL; + + atomic_inc_uint(&eclk->refcnt); + + return &eclk->base; +} + +static void +exynos5410_clock_put(void *priv, struct clk *clk) +{ + struct exynos_clk *eclk = (struct exynos_clk *)clk; + + KASSERT(eclk->refcnt > 0); + + atomic_dec_uint(&eclk->refcnt); +} + +static u_int +exynos5410_clock_get_rate(void *priv, struct clk *clk) +{ + struct exynos_clk *eclk = (struct exynos_clk *)clk; + struct clk *clk_parent; + + switch (eclk->type) { + case EXYNOS_CLK_FIXED: + return eclk->u.fixed.rate; + case EXYNOS_CLK_PLL: + return exynos5410_clock_get_rate_pll(priv, eclk); + case EXYNOS_CLK_MUX: + case EXYNOS_CLK_GATE: + clk_parent = exynos5410_clock_get_parent(priv, clk); + return exynos5410_clock_get_rate(priv, clk_parent); + case EXYNOS_CLK_DIV: + return exynos5410_clock_get_rate_div(priv, eclk); + default: + panic("exynos5410: unknown eclk type %d", eclk->type); + } +} + +static int +exynos5410_clock_set_rate(void *priv, struct clk *clk, u_int rate) +{ + struct exynos_clk *eclk = (struct exynos_clk *)clk; + + KASSERT((clk->flags & CLK_SET_RATE_PARENT) == 0); + + switch (eclk->type) { + case EXYNOS_CLK_FIXED: + return EIO; + case EXYNOS_CLK_PLL: + return exynos5410_clock_set_rate_pll(priv, eclk, rate); + case EXYNOS_CLK_MUX: + return EIO; + case EXYNOS_CLK_DIV: + return exynos5410_clock_set_rate_div(priv, eclk, rate); + case EXYNOS_CLK_GATE: + return EINVAL; + default: + panic("exynos5410: unknown eclk type %d", eclk->type); + } +} + +static int +exynos5410_clock_enable(void *priv, struct clk *clk) +{ + struct exynos_clk *eclk = (struct exynos_clk *)clk; + + switch (eclk->type) { + case EXYNOS_CLK_FIXED: + return 0; /* always on */ + case EXYNOS_CLK_PLL: + return 0; /* XXX */ + case EXYNOS_CLK_MUX: + case EXYNOS_CLK_DIV: + return 0; + case EXYNOS_CLK_GATE: + return exynos5410_clock_enable_gate(priv, eclk, true); + default: + panic("exynos5410: unknown eclk type %d", eclk->type); + } +} + +static int +exynos5410_clock_disable(void *priv, struct clk *clk) +{ + struct exynos_clk *eclk = (struct exynos_clk *)clk; + + switch (eclk->type) { + case EXYNOS_CLK_FIXED: + return EINVAL; /* always on */ + case EXYNOS_CLK_PLL: + return EINVAL; /* XXX */ + case EXYNOS_CLK_MUX: + case EXYNOS_CLK_DIV: + return EINVAL; + case EXYNOS_CLK_GATE: + return exynos5410_clock_enable_gate(priv, eclk, false); + default: + panic("exynos5410: unknown eclk type %d", eclk->type); + } +} + +static int +exynos5410_clock_set_parent(void *priv, struct clk *clk, struct clk *clk_parent) +{ + struct exynos_clk *eclk = (struct exynos_clk *)clk; + struct exynos_clk *eclk_parent = (struct exynos_clk *)clk_parent; + + switch (eclk->type) { + case EXYNOS_CLK_FIXED: + case EXYNOS_CLK_PLL: + case EXYNOS_CLK_DIV: + case EXYNOS_CLK_GATE: + return EINVAL; + case EXYNOS_CLK_MUX: + return exynos5410_clock_set_parent_mux(priv, eclk, eclk_parent); + default: + panic("exynos5410: unknown eclk type %d", eclk->type); + } +} + +static struct clk * +exynos5410_clock_get_parent(void *priv, struct clk *clk) +{ + struct exynos_clk *eclk = (struct exynos_clk *)clk; + struct exynos_clk *eclk_parent = NULL; + + switch (eclk->type) { + case EXYNOS_CLK_FIXED: + case EXYNOS_CLK_PLL: + case EXYNOS_CLK_DIV: + case EXYNOS_CLK_GATE: + if (eclk->parent != NULL) { + eclk_parent = exynos5410_clock_find(eclk->parent); + } + break; + case EXYNOS_CLK_MUX: + eclk_parent = exynos5410_clock_get_parent_mux(priv, eclk); + break; + default: + panic("exynos5410: unknown eclk type %d", eclk->type); + } + + return (struct clk *)eclk_parent; +} diff --git a/sys/arch/arm/samsung/exynos5422_clock.c b/sys/arch/arm/samsung/exynos5422_clock.c index c884d019b15d..31e1ef238651 100644 --- a/sys/arch/arm/samsung/exynos5422_clock.c +++ b/sys/arch/arm/samsung/exynos5422_clock.c @@ -1,4 +1,4 @@ -/* $NetBSD: exynos5422_clock.c,v 1.5 2017/04/16 15:52:43 jmcneill Exp $ */ +/* $NetBSD: exynos5422_clock.c,v 1.5.4.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill @@ -29,7 +29,7 @@ #include "locators.h" #include -__KERNEL_RCSID(0, "$NetBSD: exynos5422_clock.c,v 1.5 2017/04/16 15:52:43 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exynos5422_clock.c,v 1.5.4.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -277,13 +277,13 @@ static const struct clk_funcs exynos5422_clock_funcs = { .u = { .fixed = { .rate = (_rate) } } \ } -#define CLK_PLL(_name, _parent, _base) { \ +#define CLK_PLL(_name, _parent, _lock, _con0) { \ .base = { .name = (_name) }, .type = EXYNOS_CLK_PLL, \ .parent = (_parent), \ .u = { \ .pll = { \ - .con0_reg = (_base) + PLL_CON0_OFFSET, \ - .lock_reg = (_base) + PLL_LOCK_OFFSET, \ + .lock_reg = (_lock), \ + .con0_reg = (_con0), \ } \ } \ } @@ -331,17 +331,32 @@ static const struct clk_funcs exynos5422_clock_funcs = { } \ } -#define EXYNOS5422_APLL_BASE 0x00000 -#define EXYNOS5422_CPLL_BASE 0x10020 -#define EXYNOS5422_DPLL_BASE 0x10030 -#define EXYNOS5422_EPLL_BASE 0x10040 -#define EXYNOS5422_RPLL_BASE 0x10050 -#define EXYNOS5422_IPLL_BASE 0x10060 -#define EXYNOS5422_SPLL_BASE 0x10070 -#define EXYNOS5422_VPLL_BASE 0x10080 -#define EXYNOS5422_MPLL_BASE 0x10090 -#define EXYNOS5422_BPLL_BASE 0x20010 -#define EXYNOS5422_KPLL_BASE 0x28000 +#define EXYNOS5422_APLL_LOCK 0x00000 +#define EXYNOS5422_APLL_CON0 0x00100 +#define EXYNOS5422_CPLL_LOCK 0x10020 +#define EXYNOS5422_DPLL_LOCK 0x10030 +#define EXYNOS5422_EPLL_LOCK 0x10040 +#define EXYNOS5422_RPLL_LOCK 0x10050 +#define EXYNOS5422_IPLL_LOCK 0x10060 +#define EXYNOS5422_SPLL_LOCK 0x10070 +#define EXYNOS5422_VPLL_LOCK 0x10080 +#define EXYNOS5422_MPLL_LOCK 0x10090 +#define EXYNOS5422_CPLL_CON0 0x10120 +#define EXYNOS5422_DPLL_CON0 0x10128 +#define EXYNOS5422_EPLL_CON0 0x10130 +#define EXYNOS5422_EPLL_CON1 0x10134 +#define EXYNOS5422_EPLL_CON2 0x10138 +#define EXYNOS5422_RPLL_CON0 0x10140 +#define EXYNOS5422_RPLL_CON1 0x10144 +#define EXYNOS5422_RPLL_CON2 0x10148 +#define EXYNOS5422_IPLL_CON0 0x10150 +#define EXYNOS5422_SPLL_CON0 0x10160 +#define EXYNOS5422_VPLL_CON0 0x10170 +#define EXYNOS5422_MPLL_CON0 0x10180 +#define EXYNOS5422_BPLL_LOCK 0x20010 +#define EXYNOS5422_BPLL_CON0 0x20110 +#define EXYNOS5422_KPLL_LOCK 0x28000 +#define EXYNOS5422_KPLL_CON0 0x28100 #define EXYNOS5422_SRC_CPU 0x00200 #define EXYNOS5422_SRC_TOP0 0x10200 @@ -363,8 +378,10 @@ static const struct clk_funcs exynos5422_clock_funcs = { #define EXYNOS5422_SRC_TOP12 0x10280 #define EXYNOS5422_DIV_FSYS1 0x1054c +#define EXYNOS5422_DIV_PERIC0 0x10558 #define EXYNOS5422_GATE_TOP_SCLK_FSYS 0x10840 +#define EXYNOS5422_GATE_TOP_SCLK_PERIC 0x10850 static const char *mout_cpll_p[] = { "fin_pll", "fout_cpll" }; static const char *mout_dpll_p[] = { "fin_pll", "fout_dpll" }; @@ -380,17 +397,28 @@ static const char *mout_group2_p[] = static struct exynos_clk exynos5422_clocks[] = { CLK_FIXED("fin_pll", EXYNOS_F_IN_FREQ), - CLK_PLL("fout_apll", "fin_pll", EXYNOS5422_APLL_BASE), - CLK_PLL("fout_cpll", "fin_pll", EXYNOS5422_CPLL_BASE), - CLK_PLL("fout_dpll", "fin_pll", EXYNOS5422_DPLL_BASE), - CLK_PLL("fout_epll", "fin_pll", EXYNOS5422_EPLL_BASE), - CLK_PLL("fout_rpll", "fin_pll", EXYNOS5422_RPLL_BASE), - CLK_PLL("fout_ipll", "fin_pll", EXYNOS5422_IPLL_BASE), - CLK_PLL("fout_spll", "fin_pll", EXYNOS5422_SPLL_BASE), - CLK_PLL("fout_vpll", "fin_pll", EXYNOS5422_VPLL_BASE), - CLK_PLL("fout_mpll", "fin_pll", EXYNOS5422_MPLL_BASE), - CLK_PLL("fout_bpll", "fin_pll", EXYNOS5422_BPLL_BASE), - CLK_PLL("fout_kpll", "fin_pll", EXYNOS5422_KPLL_BASE), + CLK_PLL("fout_apll", "fin_pll", EXYNOS5422_APLL_LOCK, + EXYNOS5422_APLL_CON0), + CLK_PLL("fout_cpll", "fin_pll", EXYNOS5422_CPLL_LOCK, + EXYNOS5422_CPLL_CON0), + CLK_PLL("fout_dpll", "fin_pll", EXYNOS5422_DPLL_LOCK, + EXYNOS5422_DPLL_CON0), + CLK_PLL("fout_epll", "fin_pll", EXYNOS5422_EPLL_LOCK, + EXYNOS5422_EPLL_CON0), + CLK_PLL("fout_rpll", "fin_pll", EXYNOS5422_RPLL_LOCK, + EXYNOS5422_RPLL_CON0), + CLK_PLL("fout_ipll", "fin_pll", EXYNOS5422_IPLL_LOCK, + EXYNOS5422_IPLL_CON0), + CLK_PLL("fout_spll", "fin_pll", EXYNOS5422_SPLL_LOCK, + EXYNOS5422_SPLL_CON0), + CLK_PLL("fout_vpll", "fin_pll", EXYNOS5422_VPLL_LOCK, + EXYNOS5422_VPLL_CON0), + CLK_PLL("fout_mpll", "fin_pll", EXYNOS5422_MPLL_LOCK, + EXYNOS5422_MPLL_CON0), + CLK_PLL("fout_bpll", "fin_pll", EXYNOS5422_BPLL_LOCK, + EXYNOS5422_BPLL_CON0), + CLK_PLL("fout_kpll", "fin_pll", EXYNOS5422_KPLL_LOCK, + EXYNOS5422_KPLL_CON0), CLK_MUXA("sclk_cpll", "mout_cpll", EXYNOS5422_SRC_TOP6, __BIT(28), mout_cpll_p), @@ -413,10 +441,26 @@ static struct exynos_clk exynos5422_clocks[] = { mout_group2_p), CLK_MUX("mout_mmc2", EXYNOS5422_SRC_FSYS, __BITS(18,16), mout_group2_p), + CLK_MUX("mout_uart0", EXYNOS5422_SRC_PERIC0, __BITS(6,4), + mout_group2_p), + CLK_MUX("mout_uart1", EXYNOS5422_SRC_PERIC0, __BITS(10,8), + mout_group2_p), + CLK_MUX("mout_uart2", EXYNOS5422_SRC_PERIC0, __BITS(14,12), + mout_group2_p), + CLK_MUX("mout_uart3", EXYNOS5422_SRC_PERIC0, __BITS(18,16), + mout_group2_p), CLK_DIV("dout_mmc0", "mout_mmc0", EXYNOS5422_DIV_FSYS1, __BITS(9,0)), CLK_DIV("dout_mmc1", "mout_mmc1", EXYNOS5422_DIV_FSYS1, __BITS(19,10)), CLK_DIV("dout_mmc2", "mout_mmc2", EXYNOS5422_DIV_FSYS1, __BITS(29,20)), + CLK_DIV("dout_uart0", "mout_uart0", EXYNOS5422_DIV_PERIC0, + __BITS(11,8)), + CLK_DIV("dout_uart1", "mout_uart1", EXYNOS5422_DIV_PERIC0, + __BITS(15,12)), + CLK_DIV("dout_uart2", "mout_uart2", EXYNOS5422_DIV_PERIC0, + __BITS(19,16)), + CLK_DIV("dout_uart3", "mout_uart3", EXYNOS5422_DIV_PERIC0, + __BITS(23,20)), CLK_GATE("sclk_mmc0", "dout_mmc0", EXYNOS5422_GATE_TOP_SCLK_FSYS, __BIT(0), CLK_SET_RATE_PARENT), @@ -424,6 +468,14 @@ static struct exynos_clk exynos5422_clocks[] = { __BIT(1), CLK_SET_RATE_PARENT), CLK_GATE("sclk_mmc2", "dout_mmc2", EXYNOS5422_GATE_TOP_SCLK_FSYS, __BIT(2), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_uart0", "dout_uart0", EXYNOS5422_GATE_TOP_SCLK_PERIC, + __BIT(0), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_uart1", "dout_uart1", EXYNOS5422_GATE_TOP_SCLK_PERIC, + __BIT(1), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_uart2", "dout_uart2", EXYNOS5422_GATE_TOP_SCLK_PERIC, + __BIT(2), CLK_SET_RATE_PARENT), + CLK_GATE("sclk_uart3", "dout_uart3", EXYNOS5422_GATE_TOP_SCLK_PERIC, + __BIT(3), CLK_SET_RATE_PARENT), }; static int exynos5422_clock_match(device_t, cfdata_t, void *); @@ -886,5 +938,5 @@ exynos5422_clock_get_parent(void *priv, struct clk *clk) panic("exynos5422: unknown eclk type %d", eclk->type); } - return &eclk_parent->base; + return (struct clk *)eclk_parent; } diff --git a/sys/arch/arm/samsung/exynos5422_dma.c b/sys/arch/arm/samsung/exynos5422_dma.c deleted file mode 100644 index 408e0c197600..000000000000 --- a/sys/arch/arm/samsung/exynos5422_dma.c +++ /dev/null @@ -1,77 +0,0 @@ -/* $NetBSD: exynos5422_dma.c,v 1.1 2015/12/11 04:05:54 marty Exp $ */ - -/*- - * Copyright (c) 2012 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Nick Hudson - * - * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 "opt_exynos.h" - -#include -__KERNEL_RCSID(0, "$NetBSD: exynos5422_dma.c,v 1.1 2015/12/11 04:05:54 marty Exp $"); - -#define _ARM32_BUS_DMA_PRIVATE - -#include -#include - -#include -#include - -struct arm32_bus_dma_tag exynos_bus_dma_tag = { - _BUS_DMAMAP_FUNCS, - _BUS_DMAMEM_FUNCS, - _BUS_DMATAG_FUNCS, -}; - -struct arm32_dma_range exynos_coherent_dma_ranges[1] = { - [0] = { - .dr_sysbase = 0, /* filled in */ - .dr_busbase = 0, /* filled in */ - .dr_flags = _BUS_DMAMAP_COHERENT, - }, -}; - -struct arm32_bus_dma_tag exynos_coherent_bus_dma_tag = { - ._ranges = exynos_coherent_dma_ranges, - ._nranges = __arraycount(exynos_coherent_dma_ranges), - _BUS_DMAMAP_FUNCS, - _BUS_DMAMEM_FUNCS, - _BUS_DMATAG_FUNCS, -}; - -void -exynos_dma_bootstrap(psize_t memsize) -{ - bus_addr_t dram_base = EXYNOS5_SDRAM_PBASE; - - KASSERT(dram_base); - exynos_coherent_dma_ranges[0].dr_sysbase = dram_base; - exynos_coherent_dma_ranges[0].dr_busbase = dram_base; - exynos_coherent_dma_ranges[0].dr_len = memsize; -} - diff --git a/sys/arch/arm/samsung/exynos_combiner.c b/sys/arch/arm/samsung/exynos_combiner.c index 09fa581a5f21..239ee6f9787e 100644 --- a/sys/arch/arm/samsung/exynos_combiner.c +++ b/sys/arch/arm/samsung/exynos_combiner.c @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_combiner.c,v 1.6 2016/01/05 21:53:48 marty Exp $ */ +/* $NetBSD: exynos_combiner.c,v 1.6.10.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ #include "gpio.h" #include -__KERNEL_RCSID(1, "$NetBSD: exynos_combiner.c,v 1.6 2016/01/05 21:53:48 marty Exp $"); +__KERNEL_RCSID(1, "$NetBSD: exynos_combiner.c,v 1.6.10.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -66,6 +66,7 @@ struct exynos_combiner_irq_entry { int (*irq_handler)(void *); void * irq_arg; struct exynos_combiner_irq_entry *irq_next; + bool irq_mpsafe; }; struct exynos_combiner_irq_block { @@ -73,6 +74,7 @@ struct exynos_combiner_irq_block { struct exynos_combiner_softc *irq_sc; struct exynos_combiner_irq_entry *irq_entries; struct exynos_combiner_irq_block *irq_block_next; + void *irq_ih; }; struct exynos_combiner_softc { @@ -173,7 +175,7 @@ exynos_combiner_get_block(struct exynos_combiner_softc *sc, int block) static struct exynos_combiner_irq_entry * exynos_combiner_new_irq(struct exynos_combiner_irq_block *block, - int irq, int (*func)(void *), void *arg) + int irq, bool mpsafe, int (*func)(void *), void *arg) { struct exynos_combiner_irq_entry * n = kmem_zalloc(sizeof(*n), KM_SLEEP); @@ -181,6 +183,7 @@ exynos_combiner_new_irq(struct exynos_combiner_irq_block *block, n->irq_handler = func; n->irq_next = block->irq_entries; n->irq_arg = arg; + n->irq_mpsafe = mpsafe; block->irq_entries = n; return n; } @@ -196,7 +199,8 @@ exynos_combiner_get_irq(struct exynos_combiner_irq_block *b, int irq) return NULL; } -static int exynos_combiner_irq(void *cookie) +static int +exynos_combiner_irq(void *cookie) { struct exynos_combiner_irq_block *blockp = cookie; struct exynos_combiner_softc *sc = blockp->irq_sc; @@ -211,9 +215,13 @@ static int exynos_combiner_irq(void *cookie) if (istatus & 1 << irq) { struct exynos_combiner_irq_entry *e = exynos_combiner_get_irq(blockp, irq); - if (e) + if (e) { + if (!e->irq_mpsafe) + KERNEL_LOCK(1, curlwp); e->irq_handler(e->irq_arg); - else + if (!e->irq_mpsafe) + KERNEL_UNLOCK_ONE(curlwp); + } else printf("%s: Unexpected irq %d, %d\n", __func__, intr, irq); } @@ -229,6 +237,7 @@ exynos_combiner_establish(device_t dev, u_int *specifier, struct exynos_combiner_softc * const sc = device_private(dev); struct exynos_combiner_irq_block *blockp; struct exynos_combiner_irq_entry *entryp; + const bool mpsafe = (flags & FDT_INTR_MPSAFE) != 0; const u_int intr = be32toh(specifier[0]); const u_int irq = be32toh(specifier[1]); @@ -237,18 +246,19 @@ exynos_combiner_establish(device_t dev, u_int *specifier, intr / COMBINER_BLOCKS_PER_GROUP * COMBINER_GROUP_SIZE + COMBINER_IESR_OFFSET; - blockp = exynos_combiner_get_block(sc, intr); + blockp = exynos_combiner_get_block(sc, intr); if (!blockp) { blockp = exynos_combiner_new_block(sc, intr); KASSERT(blockp); - intr_establish(intr, ipl, IST_LEVEL, exynos_combiner_irq, - blockp); + blockp->irq_ih = fdtbus_intr_establish(sc->sc_phandle, intr, + IPL_VM /* XXX */, FDT_INTR_MPSAFE, exynos_combiner_irq, + blockp); } entryp = exynos_combiner_get_irq(blockp, irq); if (entryp) return NULL; - entryp = exynos_combiner_new_irq(blockp, irq, func, arg); + entryp = exynos_combiner_new_irq(blockp, irq, mpsafe, func, arg); KASSERT(entryp); int istatus = @@ -262,7 +272,7 @@ static void exynos_combiner_disestablish(device_t dev, void *ih) { /* MJF: Find the ih and disable the handler. */ - intr_disestablish(ih); + panic("exynos_combiner_disestablish not implemented"); } static bool diff --git a/sys/arch/arm/samsung/exynos_dwcmmc.c b/sys/arch/arm/samsung/exynos_dwcmmc.c index b28a1048f338..0eeec80d8502 100644 --- a/sys/arch/arm/samsung/exynos_dwcmmc.c +++ b/sys/arch/arm/samsung/exynos_dwcmmc.c @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_dwcmmc.c,v 1.3 2016/05/30 16:38:35 dholland Exp $ */ +/* $NetBSD: exynos_dwcmmc.c,v 1.3.10.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: exynos_dwcmmc.c,v 1.3 2016/05/30 16:38:35 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exynos_dwcmmc.c,v 1.3.10.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -43,11 +43,18 @@ __KERNEL_RCSID(0, "$NetBSD: exynos_dwcmmc.c,v 1.3 2016/05/30 16:38:35 dholland E #include #include +#define FIFO_REG 0x200 +#define MPS_BEGIN 0x200 +#define MPS_END 0x204 +#define MPS_CTRL 0x20c +#define MPS_CTRL_SECURE_WRITE __BIT(6) +#define MPS_CTRL_NON_SECURE_READ __BIT(5) +#define MPS_CTRL_NON_SECURE_WRITE __BIT(4) +#define MPS_CTRL_VALID __BIT(0) + static int exynos_dwcmmc_match(device_t, cfdata_t, void *); static void exynos_dwcmmc_attach(device_t, device_t, void *); -static void exynos_dwcmmc_attach_i(device_t); - static int exynos_dwcmmc_card_detect(struct dwc_mmc_softc *); struct exynos_dwcmmc_softc { @@ -137,12 +144,13 @@ exynos_dwcmmc_attach(device_t parent, device_t self, void *aux) sc->sc_clock_freq = clk_get_rate(esc->sc_clk_ciu) / (ciu_div + 1); sc->sc_fifo_depth = fifo_depth; + sc->sc_fifo_reg = FIFO_REG; + sc->sc_flags = DWC_MMC_F_USE_HOLD_REG | DWC_MMC_F_DMA; esc->sc_pin_cd = fdtbus_gpio_acquire(phandle, "cd-gpios", GPIO_PIN_INPUT); - if (esc->sc_pin_cd) { + if (esc->sc_pin_cd) sc->sc_card_detect = exynos_dwcmmc_card_detect; - } aprint_naive("\n"); aprint_normal(": MHS (%u Hz)\n", sc->sc_clock_freq); @@ -152,6 +160,9 @@ exynos_dwcmmc_attach(device_t parent, device_t self, void *aux) return; } + if (dwc_mmc_init(sc) != 0) + return; + sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_BIO, 0, dwc_mmc_intr, sc); if (sc->sc_ih == NULL) { @@ -161,16 +172,15 @@ exynos_dwcmmc_attach(device_t parent, device_t self, void *aux) } aprint_normal_dev(self, "interrupting on %s\n", intrstr); - config_interrupts(self, exynos_dwcmmc_attach_i); -} - -static void -exynos_dwcmmc_attach_i(device_t self) -{ - struct exynos_dwcmmc_softc *esc = device_private(self); - struct dwc_mmc_softc *sc = &esc->sc; - - dwc_mmc_init(sc); + /* Disable encryption mode */ + const char * compat_enc[] = { "samsung,exynos5420-dw-mshc-smu", NULL }; + if (of_match_compatible(phandle, compat_enc)) { + bus_space_write_4(sc->sc_bst, sc->sc_bsh, MPS_BEGIN, 0); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, MPS_END, ~0U); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, MPS_CTRL, + MPS_CTRL_NON_SECURE_READ | MPS_CTRL_NON_SECURE_WRITE | + MPS_CTRL_SECURE_WRITE | MPS_CTRL_VALID); + } } static int diff --git a/sys/arch/arm/samsung/exynos_i2c.c b/sys/arch/arm/samsung/exynos_i2c.c index 1a78d849a351..3ed0e0555cfc 100644 --- a/sys/arch/arm/samsung/exynos_i2c.c +++ b/sys/arch/arm/samsung/exynos_i2c.c @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_i2c.c,v 1.11 2016/02/14 19:54:20 chs Exp $ */ +/* $NetBSD: exynos_i2c.c,v 1.11.10.1 2017/07/18 19:13:08 snj Exp $ */ /* * Copyright (c) 2015 Jared D. McNeill @@ -31,7 +31,7 @@ #include "opt_arm_debug.h" #include -__KERNEL_RCSID(0, "$NetBSD: exynos_i2c.c,v 1.11 2016/02/14 19:54:20 chs Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exynos_i2c.c,v 1.11.10.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -138,7 +138,8 @@ exynos_i2c_attach(device_t parent, device_t self, void *aux) struct fdt_attach_args * const faa = aux; const int phandle = faa->faa_phandle; struct i2cbus_attach_args iba; - + prop_dictionary_t devs; + uint32_t address_cells; char intrstr[128]; bus_addr_t addr; bus_size_t size; @@ -176,8 +177,6 @@ exynos_i2c_attach(device_t parent, device_t self, void *aux) } aprint_normal_dev(self, "interrupting on %s\n", intrstr); - fdtbus_pinctrl_set_config_index(phandle, 0); - sc->sc_ic.ic_cookie = sc; sc->sc_ic.ic_acquire_bus = exynos_i2c_acquire_bus; sc->sc_ic.ic_release_bus = exynos_i2c_release_bus; @@ -187,7 +186,22 @@ exynos_i2c_attach(device_t parent, device_t self, void *aux) sc->sc_ic.ic_read_byte = exynos_i2c_read_byte; sc->sc_ic.ic_write_byte = exynos_i2c_write_byte; + fdtbus_register_i2c_controller(self, phandle, &exynos_i2c_funcs); + + devs = prop_dictionary_create(); + if (of_getprop_uint32(phandle, "#address-cells", &address_cells)) + address_cells = 1; + of_enter_i2c_devs(devs, phandle, address_cells * 4, 0); + memset(&iba, 0, sizeof(iba)); + iba.iba_tag = &sc->sc_ic; + iba.iba_child_devices = prop_dictionary_get(devs, "i2c-child-devices"); + if (iba.iba_child_devices != NULL) + prop_object_retain(iba.iba_child_devices); + else + iba.iba_child_devices = prop_array_create(); + prop_object_release(devs); + sc->sc_i2cdev = config_found_ia(self, "i2cbus", &iba, iicbus_print); } diff --git a/sys/arch/arm/samsung/exynos_intr.h b/sys/arch/arm/samsung/exynos_intr.h index 591da6145a7e..ec1479fc3724 100644 --- a/sys/arch/arm/samsung/exynos_intr.h +++ b/sys/arch/arm/samsung/exynos_intr.h @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_intr.h,v 1.2 2014/09/05 08:01:05 skrll Exp $ */ +/* $NetBSD: exynos_intr.h,v 1.2.12.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -32,18 +32,6 @@ #ifndef _ARM_SAMSUNG_EXYNOS_INTR_H_ #define _ARM_SAMSUNG_EXYNOS_INTR_H_ -#define PIC_MAXSOURCES GIC_MAXSOURCES(224) -#define PIC_MAXMAXSOURCES (PIC_MAXSOURCES + 32) /* XXX */ - -/* - * The Exynos uses a generic interrupt controller - */ -#include - -#ifdef _KERNEL_OPT -#include "opt_exynos.h" -#endif - /* * The GIC supports * - 16 Software Generated Interrupts (SGIs) @@ -61,9 +49,5 @@ #define IRQ_MCT_LTIMER IRQ_PPI(12) -#ifdef EXYNOS5 -#include -#endif - #endif /* _ARM_SAMSUNG_EXYNOS_INTR_H_ */ diff --git a/sys/arch/arm/samsung/exynos_pinctrl.c b/sys/arch/arm/samsung/exynos_pinctrl.c index d66f0abd2e98..4858ec10a576 100644 --- a/sys/arch/arm/samsung/exynos_pinctrl.c +++ b/sys/arch/arm/samsung/exynos_pinctrl.c @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_pinctrl.c,v 1.9 2016/01/01 22:37:07 marty Exp $ */ +/* $NetBSD: exynos_pinctrl.c,v 1.9.10.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ #include "gpio.h" #include -__KERNEL_RCSID(1, "$NetBSD: exynos_pinctrl.c,v 1.9 2016/01/01 22:37:07 marty Exp $"); +__KERNEL_RCSID(1, "$NetBSD: exynos_pinctrl.c,v 1.9.10.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -55,16 +55,15 @@ __KERNEL_RCSID(1, "$NetBSD: exynos_pinctrl.c,v 1.9 2016/01/01 22:37:07 marty Exp struct exynos_pinctrl_config { int pc_phandle; - struct exynos_gpio_pin_cfg *pc_pincfg; + struct exynos_gpio_pin_cfg pc_pincfg; struct exynos_pinctrl_softc *pc_sc; }; static int exynos_pinctrl_match(device_t, cfdata_t, void *); static void exynos_pinctrl_attach(device_t, device_t, void *); -static int exynos_pinctrl_set_cfg(void *); -static struct exynos_gpio_pin_cfg * -exynos_parse_config(struct exynos_pinctrl_config *pc); +static int exynos_pinctrl_set_cfg(device_t, const void *, size_t); +static void exynos_parse_config(int, struct exynos_gpio_pin_cfg *); static struct fdtbus_pinctrl_controller_func exynos_pinctrl_controller_func = { .set_config = exynos_pinctrl_set_cfg @@ -126,90 +125,61 @@ exynos_pinctrl_attach(device_t parent, device_t self, void *aux) } if (is_pinctrl(child)) { - struct exynos_pinctrl_config *pc; - pc = kmem_alloc(sizeof(*pc), KM_SLEEP); - pc->pc_phandle = child; - pc->pc_sc = sc; - pc->pc_pincfg = exynos_parse_config(pc); - fdtbus_register_pinctrl_config(pc, child, + fdtbus_register_pinctrl_config(self, child, &exynos_pinctrl_controller_func); } } + + fdtbus_pinctrl_configure(); } -static struct exynos_gpio_pin_cfg * -exynos_parse_config(struct exynos_pinctrl_config *pc) +static void +exynos_parse_config(int phandle, struct exynos_gpio_pin_cfg *gc) { - struct exynos_gpio_pin_cfg *gc = kmem_zalloc(sizeof(*gc), KM_SLEEP); - int len; - int value; - - len = OF_getprop(pc->pc_phandle, "samsung,pin-function", - &value, sizeof(value)); - if (len > 0) { - gc->cfg = be32toh(value); - } - - len = OF_getprop(pc->pc_phandle, "samsung,pin-pud", &value, - sizeof(&value)); - if (len > 0) { - gc->pud = be32toh(value); - } - - len = OF_getprop(pc->pc_phandle, "samsung,pin-drv", &value, - sizeof(&value)); - if (len > 0) { - gc->drv = be32toh(value); - } - - len = OF_getprop(pc->pc_phandle, "samsung,pin-conpwd", &value, - sizeof(&value)); - if (len > 0) { - gc->conpwd = be32toh(value); - } - - len = OF_getprop(pc->pc_phandle, "samsung,pin-pudpwd", &value, - sizeof(&value)); - if (len > 0) { - gc->pudpwd = be32toh(value); - } - return gc; + of_getprop_uint32(phandle, "samsung,pin-function", &gc->cfg); + of_getprop_uint32(phandle, "samsung,pin-pud", &gc->pud); + of_getprop_uint32(phandle, "samsung,pin-drv", &gc->drv); + of_getprop_uint32(phandle, "samsung,pin-conpwd", &gc->conpwd); + of_getprop_uint32(phandle, "samsung,pin-pudpwd", &gc->pudpwd); } static int exynos_do_config(struct exynos_pinctrl_config *pc) { - struct exynos_gpio_pin_cfg *gc = pc->pc_pincfg; + struct exynos_gpio_pin_cfg *gc = &pc->pc_pincfg; struct exynos_gpio_bank *bank; - int len; - char result[20]; + const char *pins; - if (gc == NULL) { - printf("%s: No configuration available\n", __func__); + int pins_len = OF_getproplen(pc->pc_phandle, "samsung,pins"); + if (pins_len <= 0) return -1; + + for (pins = fdtbus_get_string(pc->pc_phandle, "samsung,pins"); + pins_len > 0; + pins_len -= strlen(pins) + 1, pins += strlen(pins) + 1) { + bank = exynos_gpio_bank_lookup(pins); + if (bank == NULL) { + aprint_error_dev(pc->pc_sc->sc_dev, + "unknown pin name '%s'\n", pins); + continue; + } + exynos_gpio_pin_ctl_write(bank, gc); } - len = OF_getprop(pc->pc_phandle, "samsung,pins", result, - sizeof(result)); - if (len <= 0) { - printf("%s: couldn't get pins. (%d)\n", __func__, - pc->pc_phandle); - return -1; - } - - bank = exynos_gpio_bank_lookup(&result[0]); - if (!bank) { - printf("%s: Couldn't get bank \"%s\".\n", __func__, result); - return -1; - } - - exynos_gpio_pin_ctl_write(bank, gc); return 0; } static int -exynos_pinctrl_set_cfg(void *cookie) +exynos_pinctrl_set_cfg(device_t dev, const void *data, size_t len) { - struct exynos_pinctrl_config *pc = cookie; - return exynos_do_config(pc); + struct exynos_pinctrl_config pc; + + if (len != 4) + return -1; + + pc.pc_phandle = fdtbus_get_phandle_from_native(be32dec(data)); + pc.pc_sc = device_private(dev); + exynos_parse_config(pc.pc_phandle, &pc.pc_pincfg); + + return exynos_do_config(&pc); } diff --git a/sys/arch/arm/samsung/exynos_platform.c b/sys/arch/arm/samsung/exynos_platform.c new file mode 100644 index 000000000000..cb173dde728b --- /dev/null +++ b/sys/arch/arm/samsung/exynos_platform.c @@ -0,0 +1,161 @@ +/* $NetBSD: exynos_platform.c,v 1.6.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared D. McNeill + * 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. + */ + +#include "opt_exynos.h" +#include "opt_multiprocessor.h" +#include "opt_fdt_arm.h" + +#include "ukbd.h" + +#include +__KERNEL_RCSID(0, "$NetBSD: exynos_platform.c,v 1.6.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + +#define EXYNOS5_SWRESET_REG 0x10040400 + +#define DEVMAP_ALIGN(a) ((a) & ~L1_S_OFFSET) +#define DEVMAP_SIZE(s) roundup2((s), L1_S_SIZE) +#define DEVMAP_ENTRY(va, pa, sz) \ + { \ + .pd_va = DEVMAP_ALIGN(va), \ + .pd_pa = DEVMAP_ALIGN(pa), \ + .pd_size = DEVMAP_SIZE(sz), \ + .pd_prot = VM_PROT_READ|VM_PROT_WRITE, \ + .pd_cache = PTE_NOCACHE \ + } +#define DEVMAP_ENTRY_END { 0 } + +static const struct pmap_devmap * +exynos_platform_devmap(void) +{ + static const struct pmap_devmap devmap[] = { + DEVMAP_ENTRY(EXYNOS_CORE_VBASE, + EXYNOS_CORE_PBASE, + EXYNOS5_CORE_SIZE), + DEVMAP_ENTRY(EXYNOS5_AUDIOCORE_VBASE, + EXYNOS5_AUDIOCORE_PBASE, + EXYNOS5_AUDIOCORE_SIZE), + DEVMAP_ENTRY_END + }; + + return devmap; +} + +#define EXYNOS_IOPHYSTOVIRT(a) \ + ((vaddr_t)(((a) - EXYNOS_CORE_PBASE) + EXYNOS_CORE_VBASE)) + +static void +exynos_platform_bootstrap(void) +{ + paddr_t uart_address = armreg_tpidruro_read(); /* XXX */ + exynos_bootstrap(EXYNOS_CORE_VBASE, EXYNOS_IOPHYSTOVIRT(uart_address)); +} + +static void +exynos_platform_init_attach_args(struct fdt_attach_args *faa) +{ + extern struct bus_space armv7_generic_bs_tag; + extern struct bus_space armv7_generic_a4x_bs_tag; + extern struct arm32_bus_dma_tag armv7_generic_dma_tag; + + faa->faa_bst = &armv7_generic_bs_tag; + faa->faa_a4x_bst = &armv7_generic_a4x_bs_tag; + faa->faa_dmat = &armv7_generic_dma_tag; +} + +static void +exynos_platform_early_putchar(char c) +{ +#if defined(VERBOSE_INIT_ARM) + extern void exynos_putchar(int); /* XXX from exynos_start.S */ + + exynos_putchar(c); +#endif +} + +static void +exynos_platform_device_register(device_t self, void *aux) +{ + exynos_device_register(self, aux); +} + +static void +exynos5_platform_reset(void) +{ + bus_space_tag_t bst = &armv7_generic_bs_tag; + bus_space_handle_t bsh; + + bus_space_map(bst, EXYNOS5_SWRESET_REG, 4, 0, &bsh); + bus_space_write_4(bst, bsh, 0, 1); +} + +static void +exynos_platform_delay(u_int us) +{ + gtmr_delay(us); +} + +static u_int +exynos_platform_uart_freq(void) +{ + return EXYNOS_UART_FREQ; +} + +static const struct arm_platform exynos5_platform = { + .devmap = exynos_platform_devmap, + .bootstrap = exynos_platform_bootstrap, + .init_attach_args = exynos_platform_init_attach_args, + .early_putchar = exynos_platform_early_putchar, + .device_register = exynos_platform_device_register, + .reset = exynos5_platform_reset, + .delay = exynos_platform_delay, + .uart_freq = exynos_platform_uart_freq, +}; + +ARM_PLATFORM(exynos5, "samsung,exynos5", &exynos5_platform); diff --git a/sys/arch/arm/samsung/exynos_reg.h b/sys/arch/arm/samsung/exynos_reg.h index 24e19a78f315..05d6f42b6707 100644 --- a/sys/arch/arm/samsung/exynos_reg.h +++ b/sys/arch/arm/samsung/exynos_reg.h @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_reg.h,v 1.13 2014/09/30 14:20:55 reinoud Exp $ */ +/* $NetBSD: exynos_reg.h,v 1.13.12.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -97,10 +97,10 @@ #define EXYNOS_BLOCK_SIZE 0x00010000 -#if defined(EXYNOS5) +#if defined(SOC_EXYNOS5) #include #endif -#if defined(EXYNOS4) +#if defined(SOC_EXYNOS4) #include #endif @@ -124,7 +124,8 @@ #define PLL_CON0_P __BITS( 8,13) /* PLL P divide value */ #define PLL_CON0_S __BITS( 0, 2) /* PLL S divide value */ -#define PLL_PMS2FREQ(F, M, P, S) (((M)*(F))/((P)*(1<<(S)))) +#define PLL_PMS2FREQ(F, M, P, S) \ + ((P) == 0 ? 0 : (((M)*(F))/((P)*(1<<(S))))) #define PLL_FREQ(f, v) PLL_PMS2FREQ( \ (f),\ __SHIFTOUT((v), PLL_CON0_M),\ diff --git a/sys/arch/arm/samsung/exynos_soc.c b/sys/arch/arm/samsung/exynos_soc.c index 73c4eb0380ca..41c986cf53a5 100644 --- a/sys/arch/arm/samsung/exynos_soc.c +++ b/sys/arch/arm/samsung/exynos_soc.c @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_soc.c,v 1.31 2015/12/21 04:58:50 marty Exp $ */ +/* $NetBSD: exynos_soc.c,v 1.31.10.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -31,10 +31,8 @@ #include "opt_exynos.h" -#define _ARM32_BUS_DMA_PRIVATE - #include -__KERNEL_RCSID(1, "$NetBSD: exynos_soc.c,v 1.31 2015/12/21 04:58:50 marty Exp $"); +__KERNEL_RCSID(1, "$NetBSD: exynos_soc.c,v 1.31.10.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -76,7 +74,7 @@ struct cpu_freq { }; -#ifdef EXYNOS4 +#ifdef SOC_EXYNOS4 const struct cpu_freq cpu_freq_settings_exynos4[] = { { 200, 3, 100, 2}, { 300, 4, 200, 2}, @@ -100,7 +98,7 @@ const struct cpu_freq cpu_freq_settings_exynos4[] = { #endif -#ifdef EXYNOS5 +#ifdef SOC_EXYNOS5 #define EXYNOS5_DEFAULT_ENTRY 7 const struct cpu_freq cpu_freq_settings_exynos5[] = { { 200, 3, 100, 2}, @@ -207,7 +205,7 @@ exynos_cpu_boot(int cpu) } -#ifdef EXYNOS4 +#ifdef SOC_EXYNOS4 /* * The latency values used below are `magic' and probably chosen empirically. * For the 4210 variant the data latency is lower, a 0x110. This is currently @@ -456,13 +454,13 @@ exynos_dump_clocks(void) uint32_t freq; printf("Initial PLL settings\n"); -#ifdef EXYNOS4 +#ifdef SOC_EXYNOS4 DUMP_PLL(4, APLL); DUMP_PLL(4, MPLL); DUMP_PLL(4, EPLL); DUMP_PLL(4, VPLL); #endif -#ifdef EXYNOS5 +#ifdef SOC_EXYNOS5 DUMP_PLL(5, APLL); DUMP_PLL(5, MPLL); DUMP_PLL(5, KPLL); @@ -479,6 +477,15 @@ exynos_dump_clocks(void) /* XXX clock stuff needs major work XXX */ +void +exynos_init_clkout_for_usb(void) +{ + /* Select XUSBXTI as source for CLKOUT */ + bus_space_write_4(&armv7_generic_bs_tag, exynos_pmu_bsh, + EXYNOS_PMU_DEBUG_CLKOUT, 0x1000); +} + + void exynos_clocks_bootstrap(void) { @@ -493,7 +500,7 @@ exynos_clocks_bootstrap(void) /* set (max) cpufreq */ fsel = ncpu_freq_settings-1; -#ifdef EXYNOS5 +#ifdef SOC_EXYNOS5 /* XXX BUGFIX selecting freq on E5 goes wrong for now XXX */ fsel = EXYNOS5_DEFAULT_ENTRY; #endif @@ -524,7 +531,7 @@ exynos_bootstrap(vaddr_t iobase, vaddr_t uartbase) printf("Exynos early console operational\n\n"); #endif -#ifdef EXYNOS4 +#ifdef SOC_EXYNOS4 core_size = EXYNOS4_CORE_SIZE; audiocore_size = EXYNOS4_AUDIOCORE_SIZE; audiocore_pbase = EXYNOS4_AUDIOCORE_PBASE; @@ -538,7 +545,7 @@ exynos_bootstrap(vaddr_t iobase, vaddr_t uartbase) ncpu_freq_settings = __arraycount(cpu_freq_settings_exynos4); #endif -#ifdef EXYNOS5 +#ifdef SOC_EXYNOS5 core_size = EXYNOS5_CORE_SIZE; audiocore_size = EXYNOS5_AUDIOCORE_SIZE; audiocore_pbase = EXYNOS5_AUDIOCORE_PBASE; @@ -594,9 +601,6 @@ exynos_bootstrap(vaddr_t iobase, vaddr_t uartbase) panic("%s: failed to subregion cmu apll registers: %d", __func__, error); - /* init bus dma tags */ - exynos_dma_bootstrap(physmem * PAGE_SIZE); - /* gpio bootstrapping delayed */ } @@ -625,7 +629,7 @@ exynos_device_register(device_t self, void *aux) extern uint32_t exynos_soc_id; switch (EXYNOS_PRODUCT_ID(exynos_soc_id)) { -#ifdef EXYNOS5 +#ifdef SOC_EXYNOS5 case 0xe5410: /* offsets not changed on matt's request */ #if 0 @@ -643,7 +647,7 @@ exynos_device_register(device_t self, void *aux) break; } #endif -#ifdef EXYNOS4 +#ifdef SOC_EXYNOS4 case 0xe4410: case 0xe4412: { struct mpcore_attach_args * const mpcaa = aux; @@ -661,7 +665,7 @@ exynos_device_register(device_t self, void *aux) return; } if (device_is_a(self, "armgtmr") || device_is_a(self, "mct")) { -#ifdef EXYNOS5 +#ifdef SOC_EXYNOS5 /* * The global timer is dependent on the MCT running. */ @@ -733,7 +737,7 @@ exynos_usb2_set_isolation(bool on) } -#ifdef EXYNOS4 +#ifdef SOC_EXYNOS4 static void exynos4_usb2phy_enable(bus_space_handle_t usb2phy_bsh) { @@ -794,7 +798,7 @@ exynos4_usb2phy_enable(bus_space_handle_t usb2phy_bsh) #endif -#ifdef EXYNOS5 +#ifdef SOC_EXYNOS5 static void exynos5410_usb2phy_enable(bus_space_handle_t usb2phy_bsh) { @@ -909,10 +913,10 @@ exynos_usb_phy_init(bus_space_handle_t usb2phy_bsh) /* disable phy isolation */ exynos_usb2_set_isolation(false); -#ifdef EXYNOS4 +#ifdef SOC_EXYNOS4 exynos4_usb2phy_enable(usb2phy_bsh); #endif -#ifdef EXYNOS5 +#ifdef SOC_EXYNOS5 if (IS_EXYNOS5410_P()) { exynos5410_usb2phy_enable(usb2phy_bsh); /* TBD: USB3 phy init */ diff --git a/sys/arch/arm/samsung/exynos_sscom.c b/sys/arch/arm/samsung/exynos_sscom.c index 948ed78f524d..f334dae62a71 100644 --- a/sys/arch/arm/samsung/exynos_sscom.c +++ b/sys/arch/arm/samsung/exynos_sscom.c @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_sscom.c,v 1.7 2015/12/21 00:54:35 marty Exp $ */ +/* $NetBSD: exynos_sscom.c,v 1.7.10.1 2017/07/18 19:13:08 snj Exp $ */ /* * Copyright (c) 2014 Reinoud Zandijk @@ -34,7 +34,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: exynos_sscom.c,v 1.7 2015/12/21 00:54:35 marty Exp $"); +__KERNEL_RCSID(0, "$NetBSD: exynos_sscom.c,v 1.7.10.1 2017/07/18 19:13:08 snj Exp $"); #include "opt_sscom.h" #include "opt_ddb.h" @@ -79,10 +79,14 @@ static void sscom_attach(device_t, device_t, void *); CFATTACH_DECL_NEW(exynos_sscom, sizeof(struct sscom_softc), sscom_match, sscom_attach, NULL, NULL); +static const char * const compatible[] = { + "samsung,exynos4210-uart", + NULL +}; + static int sscom_match(device_t parent, cfdata_t cf, void *aux) { - const char * const compatible[] = { "samsung,exynos4210-uart", NULL }; struct fdt_attach_args * const faa = aux; return of_match_compatible(faa->faa_phandle, compatible); @@ -147,32 +151,46 @@ sscom_attach(device_t parent, device_t self, void *aux) { struct sscom_softc *sc = device_private(self); struct fdt_attach_args *faa = aux; - int unit = -1; + const int phandle = faa->faa_phandle; + bus_space_tag_t bst = faa->faa_bst; bus_space_handle_t bsh; - bus_space_tag_t bst; + struct clk *clk_uart, *clk_uart_baud0; + char intrstr[128]; bus_addr_t addr; bus_size_t size; - int error; - int i; - if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { aprint_error(": couldn't get registers\n"); return; } - /* unit is required for the sscom driver, which desperately - * needs to be rewritten. For now, this hack gets the answer. - * MJF: FIX ME - */ - for (i = 1; i < num_exynos_uarts_entries; i += 2) - if (EXYNOS_CORE_PBASE + exynos_uarts[i] == addr) - break; - unit = exynos_uarts[i-1]; + + if (bus_space_map(bst, addr, size, 0, &bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + clk_uart = fdtbus_clock_get(phandle, "uart"); + if (clk_uart != NULL) { + if (clk_enable(clk_uart) != 0) { + aprint_error(": couldn't enable uart clock\n"); + return; + } + } + clk_uart_baud0 = fdtbus_clock_get(phandle, "clk_uart_baud0"); + if (clk_uart_baud0 == NULL) { + aprint_error(": couldn't get baud clock\n"); + return; + } + if (clk_enable(clk_uart_baud0) != 0) { + aprint_error(": couldn't enable baud clock\n"); + return; + } sc->sc_dev = self; sc->sc_iot = bst = faa->faa_bst; - sc->sc_ioh = exynos_uarts[i] + EXYNOS_CORE_VBASE; - sc->sc_unit = unit; - sc->sc_frequency = EXYNOS_UART_FREQ; + sc->sc_ioh = bsh; + sc->sc_unit = phandle; + sc->sc_frequency = clk_get_rate(clk_uart_baud0); sc->sc_change_txrx_interrupts = exynos_change_txrx_interrupts; sc->sc_clear_interrupts = exynos_clear_interrupts; @@ -181,26 +199,22 @@ sscom_attach(device_t parent, device_t self, void *aux) sc->sc_rx_irqno = 0; sc->sc_tx_irqno = 0; - if (!sscom_is_console(sc->sc_iot, unit, &sc->sc_ioh)) { - error = bus_space_map(bst, addr, size, 0, &bsh); - if (error) { - aprint_error(": couldn't map %#llx: %d\n", - (uint64_t)addr, error); - return; - } - sc->sc_ioh = bsh; - } else { - aprint_normal(" (console) "); - } + if (sscom_is_console(sc->sc_iot, phandle, &sc->sc_ioh)) + aprint_normal(" (console)"); aprint_normal("\n"); -#if 0 - void *ih = fdtbus_intr_establish(faa->faa_phandle, 0, IPL_SERIAL, + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); + return; + } + + void *ih = fdtbus_intr_establish(phandle, 0, IPL_SERIAL, FDT_INTR_MPSAFE, sscomintr, sc); if (ih == NULL) aprint_error_dev(self, "failed to establish interrupt\n"); -#endif + + aprint_normal_dev(self, "interrupting on %s\n", intrstr); sscom_attach_subr(sc); @@ -226,3 +240,56 @@ exynos_sscom_kgdb_attach(bus_space_tag_t iot, int unit, int rate, } #endif /* KGDB */ #endif + + +/* + * Console support + */ + +static int +exynos_sscom_console_match(int phandle) +{ + return of_match_compatible(phandle, compatible); +} + +static void +exynos_sscom_console_consinit(struct fdt_attach_args *faa, u_int uart_freq) +{ + const struct sscom_uart_info info = { + .iobase = 0, /* Offset from bsh */ + .unit = faa->faa_phandle + }; + const int phandle = faa->faa_phandle; + bus_space_tag_t bst = faa->faa_bst; + bus_space_handle_t bsh; + bus_addr_t addr; + bus_size_t size; + tcflag_t flags; + int speed; + + fdtbus_get_reg(phandle, 0, &addr, &size); + speed = fdtbus_get_stdout_speed(); + if (speed < 0) + speed = 115200; /* default */ + flags = fdtbus_get_stdout_flags(); + + if (bus_space_map(bst, addr, size, 0, &bsh) != 0) + panic("cannot map console UART"); + + /* Calculate UART frequency from bootloader (XXX) */ + uint32_t freq = speed + * (16 * (bus_space_read_4(bst, bsh, SSCOM_UBRDIV) + 1) + + bus_space_read_4(bst, bsh, SSCOM_UFRACVAL)); + freq = (freq + speed / 2) / 1000; + freq *= 1000; + + if (sscom_cnattach(bst, bsh, &info, speed, freq, flags) != 0) + panic("cannot attach console UART"); +} + +static const struct fdt_console exynos_sscom_console = { + .match = exynos_sscom_console_match, + .consinit = exynos_sscom_console_consinit, +}; + +FDT_CONSOLE(exynos_sscom, &exynos_sscom_console); diff --git a/sys/arch/arm/samsung/exynos_sysmmu.c b/sys/arch/arm/samsung/exynos_sysmmu.c index c5c80d3201c9..9b12c34dae66 100644 --- a/sys/arch/arm/samsung/exynos_sysmmu.c +++ b/sys/arch/arm/samsung/exynos_sysmmu.c @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_sysmmu.c,v 1.1 2016/01/03 04:10:58 marty Exp $ */ +/* $NetBSD: exynos_sysmmu.c,v 1.1.12.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ #include "gpio.h" #include -__KERNEL_RCSID(1, "$NetBSD: exynos_sysmmu.c,v 1.1 2016/01/03 04:10:58 marty Exp $"); +__KERNEL_RCSID(1, "$NetBSD: exynos_sysmmu.c,v 1.1.12.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -102,6 +102,10 @@ exynos_sysmmu_attach(device_t parent, device_t self, void *aux) return; } + aprint_normal(" @ 0x%08x: SYSMMU - NOT IMPLEMENTED", (uint)addr); + aprint_naive("\n"); + aprint_normal("\n"); + if (!fdtbus_intr_str(faa->faa_phandle, 0, intrstr, sizeof(intrstr))) { aprint_error_dev(self, "failed to decode interrupt\n"); return; @@ -116,9 +120,6 @@ exynos_sysmmu_attach(device_t parent, device_t self, void *aux) } aprint_normal_dev(self, "interrupting on %s\n", intrstr); - aprint_normal(" @ 0x%08x: SYSMMU - NOT IMPLEMENTED", (uint)addr); - aprint_naive("\n"); - aprint_normal("\n"); } diff --git a/sys/arch/arm/samsung/files.exynos b/sys/arch/arm/samsung/files.exynos index 75167a0e0495..271d52fabb30 100644 --- a/sys/arch/arm/samsung/files.exynos +++ b/sys/arch/arm/samsung/files.exynos @@ -1,4 +1,4 @@ -# $NetBSD: files.exynos,v 1.21 2016/01/03 04:10:58 marty Exp $ +# $NetBSD: files.exynos,v 1.21.10.1 2017/07/18 19:13:08 snj Exp $ # # Configuration info for Samsung Exynos SoC ARM Peripherals # @@ -13,10 +13,10 @@ file arch/arm/arm32/arm32_kvminit.c file arch/arm/arm32/arm32_reboot.c file arch/arm/arm32/irq_dispatch.S file arch/arm/arm32/armv7_generic_space.c +file arch/arm/arm32/armv7_generic_dma.c file arch/arm/arm/bus_space_a4x.S file arch/arm/samsung/exynos_soc.c -#file arch/arm/samsung/exynos_space.c file arch/arm/samsung/exynos_smc.S arm_trustzone_firmware # Console parameters @@ -30,23 +30,20 @@ defparam opt_exynos.h EXYNOS_WDT_DEFAULT_PERIOD defflag opt_exynos.h EXYNOS_CONSOLE_EARLY # -defflag opt_exynos.h EXYNOS4: CPU_CORTEXA9 -defflag opt_exynos.h EXYNOS4120: EXYNOS4 -defflag opt_exynos.h EXYNOS4212: EXYNOS4 -defflag opt_exynos.h EXYNOS4412: EXYNOS4 -defflag opt_exynos.h EXYNOS4412P: EXYNOS4 -defflag opt_exynos.h EXYNOS5: CPU_CORTEXA15 -defflag opt_exynos.h EXYNOS5250: EXYNOS5 -defflag opt_exynos.h EXYNOS5260: EXYNOS5 -defflag opt_exynos.h EXYNOS5410: EXYNOS5 -defflag opt_exynos.h EXYNOS5420: EXYNOS5 -defflag opt_exynos.h EXYNOS5440: EXYNOS5 -defflag opt_exynos.h EXYNOS5422: EXYNOS5 +defflag opt_exynos.h SOC_EXYNOS4: CPU_CORTEXA9 +defflag opt_exynos.h SOC_EXYNOS4120: SOC_EXYNOS4 +defflag opt_exynos.h SOC_EXYNOS4212: SOC_EXYNOS4 +defflag opt_exynos.h SOC_EXYNOS4412: SOC_EXYNOS4 +defflag opt_exynos.h SOC_EXYNOS4412P: SOC_EXYNOS4 +defflag opt_exynos.h SOC_EXYNOS5: CPU_CORTEXA15 +defflag opt_exynos.h SOC_EXYNOS5250: SOC_EXYNOS5 +defflag opt_exynos.h SOC_EXYNOS5260: SOC_EXYNOS5 +defflag opt_exynos.h SOC_EXYNOS5410: SOC_EXYNOS5 +defflag opt_exynos.h SOC_EXYNOS5420: SOC_EXYNOS5 +defflag opt_exynos.h SOC_EXYNOS5440: SOC_EXYNOS5 +defflag opt_exynos.h SOC_EXYNOS5422: SOC_EXYNOS5 -# On-board I/O -device exynosfdt : bus_space_generic, fdtbus -attach exynosfdt at mainbus with exynos_fdt -file arch/arm/samsung/exynos_fdt.c exynos_fdt +file arch/arm/samsung/exynos_platform.c soc_exynos5 # Interrupt combiner device exyointr @@ -64,12 +61,12 @@ attach sysmmu at fdt with exynos_sysmmu file arch/arm/samsung/exynos_sysmmu.c exynos_sysmmu # real time clock -device exyortc : ftdbus +device exyortc : fdtbus attach exyortc at fdt with exynos_rtc file arch/arm/samsung/exynos_rtc.c exynos_rtc # Multi Core timer -device mct : ftdbus +device mct { } : fdtbus, mpcorebus attach mct at fdt with exyo_mct file arch/arm/samsung/mct.c exyo_mct @@ -120,8 +117,10 @@ device exyoi2c: i2cbus, i2c_bitbang attach exyoi2c at fdt with exynos_i2c file arch/arm/samsung/exynos_i2c.c exynos_i2c needs-flag -file arch/arm/samsung/exynos5422_dma.c - device exy5422clk: clk attach exy5422clk at fdt with exynos5422_clock file arch/arm/samsung/exynos5422_clock.c exynos5422_clock + +device exy5410clk: clk +attach exy5410clk at fdt with exynos5410_clock +file arch/arm/samsung/exynos5410_clock.c exynos5410_clock diff --git a/sys/arch/arm/samsung/mct.c b/sys/arch/arm/samsung/mct.c index 9b66a6e354f0..16fe51c051b0 100644 --- a/sys/arch/arm/samsung/mct.c +++ b/sys/arch/arm/samsung/mct.c @@ -1,4 +1,4 @@ -/* $NetBSD: mct.c,v 1.10 2016/01/07 04:45:10 marty Exp $ */ +/* $NetBSD: mct.c,v 1.10.10.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #include -__KERNEL_RCSID(1, "$NetBSD: mct.c,v 1.10 2016/01/07 04:45:10 marty Exp $"); +__KERNEL_RCSID(1, "$NetBSD: mct.c,v 1.10.10.1 2017/07/18 19:13:08 snj Exp $"); #include #include @@ -50,36 +50,24 @@ __KERNEL_RCSID(1, "$NetBSD: mct.c,v 1.10 2016/01/07 04:45:10 marty Exp $"); #include #include +#include +#include +#include + #include +#include static int mct_match(device_t, cfdata_t, void *); static void mct_attach(device_t, device_t, void *); -static int clockhandler(void *); - CFATTACH_DECL_NEW(exyo_mct, 0, mct_match, mct_attach, NULL, NULL); - -#if 0 -static struct timecounter mct_timecounter = { - .tc_get_timecount = mct_get_timecount, - .tc_poll_pps = 0, - .tc_counter_mask = ~0u, - .tc_frequency = 0, /* set by cpu_initclocks() */ - .tc_name = NULL, /* set by cpu_initclocks() */ - .tc_quality = 500, /* why 500? */ - .tc_priv = &mct_sc, - .tc_next = NULL, -}; -#endif - static inline uint32_t mct_read_global(struct mct_softc *sc, bus_size_t o) { return bus_space_read_4(sc->sc_bst, sc->sc_bsh, o); } - static inline void mct_write_global(struct mct_softc *sc, bus_size_t o, uint32_t v) { @@ -129,6 +117,12 @@ mct_write_global(struct mct_softc *sc, bus_size_t o, uint32_t v) panic("MCT hangs after writing %#x at %#x", v, (uint32_t) o); } +static void +mct_fdt_cpu_hatch(void *priv, struct cpu_info *ci) +{ + gtmr_init_cpu_clock(ci); +} + static int mct_match(device_t parent, cfdata_t cf, void *aux) { @@ -139,7 +133,6 @@ mct_match(device_t parent, cfdata_t cf, void *aux) return of_match_compatible(faa->faa_phandle, compatible); } - static void mct_attach(device_t parent, device_t self, void *aux) { @@ -157,6 +150,7 @@ mct_attach(device_t parent, device_t self, void *aux) self->dv_private = sc; sc->sc_dev = self; sc->sc_bst = faa->faa_bst; + sc->sc_freq = EXYNOS_F_IN_FREQ; error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh); if (error) { @@ -166,122 +160,20 @@ mct_attach(device_t parent, device_t self, void *aux) } aprint_naive("\n"); - aprint_normal(": Exynos SoC multi core timer (64 bits) - NOT IMPLEMENTED\n"); + aprint_normal(": Exynos SoC multi core timer (64 bits)\n"); - evcnt_attach_dynamic(&sc->sc_ev_missing_ticks, EVCNT_TYPE_MISC, NULL, - device_xname(self), "missing interrupts"); - - for (int i = 0; i < 12; i++) - fdtbus_intr_establish(faa->faa_phandle, i, 0, 0, - clockhandler, 0); -} - -static inline uint64_t -mct_gettime(struct mct_softc *sc) -{ - uint32_t lo, hi; - do { - hi = mct_read_global(sc, MCT_G_CNT_U); - lo = mct_read_global(sc, MCT_G_CNT_L); - } while (hi != mct_read_global(sc, MCT_G_CNT_U)); - return ((uint64_t) hi << 32) | lo; -} - - -/* interrupt handler */ -static int -clockhandler(void *arg) -{ - struct clockframe * const cf = arg; - struct mct_softc * const sc = &mct_sc; - const uint64_t now = mct_gettime(sc); - int64_t delta = now - sc->sc_lastintr; - int64_t periods = delta / sc->sc_autoinc; - - KASSERT(delta >= 0); - KASSERT(periods >= 0); - - /* ack the interrupt */ - mct_write_global(sc, MCT_G_INT_CSTAT, G_INT_CSTAT_CLEAR); - - /* check if we missed clock interrupts */ - if (periods > 1) - sc->sc_ev_missing_ticks.ev_count += periods - 1; - - sc->sc_lastintr = now; - hardclock(cf); - - /* handled */ - return 1; -} - -void -mct_init_cpu_clock(struct cpu_info *ci) -{ - struct mct_softc * const sc = &mct_sc; - uint64_t now = mct_gettime(sc); - uint64_t then; - uint32_t tcon; - - KASSERT(ci == curcpu()); - - sc->sc_lastintr = now; - - /* get current config */ - tcon = mct_read_global(sc, MCT_G_TCON); - - /* setup auto increment */ - mct_write_global(sc, MCT_G_COMP0_ADD_INCR, sc->sc_autoinc); - - /* (re)setup comparator */ - then = now + sc->sc_autoinc; - mct_write_global(sc, MCT_G_COMP0_L, (uint32_t) then); - mct_write_global(sc, MCT_G_COMP0_U, (uint32_t) (then >> 32)); - tcon |= G_TCON_COMP0_AUTOINC; - tcon |= G_TCON_COMP0_ENABLE; - - /* start timer */ + /* Start the timer */ + uint32_t tcon = mct_read_global(sc, MCT_G_TCON); tcon |= G_TCON_START; - - /* enable interrupt */ - mct_write_global(sc, MCT_G_INT_ENB, G_INT_ENB_ENABLE); - - /* update config, starting the thing */ mct_write_global(sc, MCT_G_TCON, tcon); + + /* Attach ARMv7 generic timer */ + struct mpcore_attach_args mpcaa = { + .mpcaa_name = "armgtmr", + .mpcaa_irq = IRQ_GTMR_PPI_VTIMER + }; + + config_found(self, &mpcaa, NULL); + + arm_fdt_cpu_hatch_register(self, mct_fdt_cpu_hatch); } - - -#if 0 -void -cpu_initclocks(void) -{ - struct mct_softc * const sc = &mct_sc; - - sc->sc_autoinc = sc->sc_freq / hz; - mct_init_cpu_clock(curcpu()); - - mct_timecounter.tc_name = device_xname(sc->sc_dev); - mct_timecounter.tc_frequency = sc->sc_freq; - - tc_init(&mct_timecounter); - -#if 0 - { - uint64_t then, now; - - printf("testing timer\n"); - for (int i = 0; i < 200; i++) { - printf("cstat %d\n", mct_read_global(sc, MCT_G_INT_CSTAT)); - then = mct_get_timecount(&mct_timecounter); - do { - now = mct_get_timecount(&mct_timecounter); - } while (now == then); - printf("\tgot %"PRIu64"\n", now); - for (int j = 0; j < 90000; j++); - } - printf("passed\n"); - } -#endif -} - -#endif diff --git a/sys/arch/arm/samsung/mct_var.h b/sys/arch/arm/samsung/mct_var.h index 55d11a50d18f..6e9b30b6844a 100644 --- a/sys/arch/arm/samsung/mct_var.h +++ b/sys/arch/arm/samsung/mct_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: mct_var.h,v 1.4 2015/12/21 00:54:35 marty Exp $ */ +/* $NetBSD: mct_var.h,v 1.4.10.1 2017/07/18 19:13:08 snj Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -52,6 +52,7 @@ static struct mct_softc { } mct_sc; void mct_init_cpu_clock(struct cpu_info *ci); +void mct_delay(u_int); #endif /* _ARM_SAMSUNG_MCT_VAR_H_ */ diff --git a/sys/arch/arm/samsung/sscom.c b/sys/arch/arm/samsung/sscom.c index bc9842dc109f..413160ae67ae 100644 --- a/sys/arch/arm/samsung/sscom.c +++ b/sys/arch/arm/samsung/sscom.c @@ -1,4 +1,4 @@ -/* $NetBSD: sscom.c,v 1.8 2015/04/13 21:18:41 riastradh Exp $ */ +/* $NetBSD: sscom.c,v 1.8.10.1 2017/07/18 19:13:08 snj Exp $ */ /* * Copyright (c) 2002, 2003 Fujitsu Component Limited @@ -98,7 +98,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: sscom.c,v 1.8 2015/04/13 21:18:41 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sscom.c,v 1.8.10.1 2017/07/18 19:13:08 snj Exp $"); #include "opt_sscom.h" #include "opt_ddb.h" @@ -179,13 +179,9 @@ static int sscom_to_tiocm(struct sscom_softc *); static void sscom_iflush(struct sscom_softc *); static int sscomhwiflow(struct tty *tp, int block); -#if defined(KGDB) || \ - defined(SSCOM0CONSOLE) || defined(SSCOM1CONSOLE) || \ - defined(SSCOM2CONSOLE) || defined(SSCOM3CONSOLE) static int sscom_init(bus_space_tag_t, bus_space_handle_t, const struct sscom_uart_info *, int, int, tcflag_t, bus_space_handle_t *); -#endif extern struct cfdriver sscom_cd; @@ -1836,9 +1832,6 @@ sscomintr(void *v) } -#if defined(KGDB) || \ - defined(SSCOM0CONSOLE) || defined(SSCOM1CONSOLE) || \ - defined(SSCOM2CONSOLE) || defined(SSCOM3CONSOLE) /* * Initialize UART for use as console or KGDB line. */ @@ -1882,11 +1875,6 @@ sscom_init(bus_space_tag_t iot, bus_space_handle_t base_ioh, return 0; } -#endif - -#if \ - defined(SSCOM0CONSOLE) || defined(SSCOM1CONSOLE) || \ - defined(SSCOM2CONSOLE) || defined(SSCOM3CONSOLE) /* * Following are all routines needed for SSCOM to act as console */ @@ -2024,8 +2012,6 @@ sscomcnpollc(dev_t dev, int on) sscom_readaheadcount = 0; } -#endif /* SSCOM0CONSOLE||SSCOM1CONSOLE */ - #ifdef KGDB int sscom_kgdb_attach(bus_space_tag_t iot, bus_space_handle_t ioh, diff --git a/sys/arch/arm/sunxi/files.sunxi b/sys/arch/arm/sunxi/files.sunxi new file mode 100644 index 000000000000..1751b44bc6d3 --- /dev/null +++ b/sys/arch/arm/sunxi/files.sunxi @@ -0,0 +1,110 @@ +# $NetBSD: files.sunxi,v 1.12.4.2 2017/07/18 19:13:08 snj Exp $ +# +# Configuration info for Allwinner sunxi family SoCs +# +# + +include "arch/arm/pic/files.pic" +include "arch/arm/cortex/files.cortex" + +file arch/arm/arm32/arm32_boot.c +file arch/arm/arm32/arm32_kvminit.c +file arch/arm/arm32/arm32_reboot.c +file arch/arm/arm32/irq_dispatch.S +file arch/arm/arm32/armv7_generic_space.c +file arch/arm/arm32/armv7_generic_dma.c +file arch/arm/arm/bus_space_a4x.S + +file arch/arm/sunxi/sunxi_platform.c soc_sunxi + +# CCU +define sunxi_ccu +file arch/arm/sunxi/sunxi_ccu.c sunxi_ccu +file arch/arm/sunxi/sunxi_ccu_div.c sunxi_ccu +file arch/arm/sunxi/sunxi_ccu_gate.c sunxi_ccu +file arch/arm/sunxi/sunxi_ccu_nm.c sunxi_ccu +file arch/arm/sunxi/sunxi_ccu_nkmp.c sunxi_ccu +file arch/arm/sunxi/sunxi_ccu_prediv.c sunxi_ccu + +# CCU (A31) +device sun6ia31ccu: sunxi_ccu +attach sun6ia31ccu at fdt with sunxi_a31_ccu +file arch/arm/sunxi/sun6i_a31_ccu.c sunxi_a31_ccu + +# CCU (A83T) +device sun8ia83tccu: sunxi_ccu +attach sun8ia83tccu at fdt with sunxi_a83t_ccu +file arch/arm/sunxi/sun8i_a83t_ccu.c sunxi_a83t_ccu + +# CCU (H3) +device sun8ih3ccu: sunxi_ccu +attach sun8ih3ccu at fdt with sunxi_h3_ccu +file arch/arm/sunxi/sun8i_h3_ccu.c sunxi_h3_ccu + +# Misc. clock resets +device sunxiresets +attach sunxiresets at fdt with sunxi_resets +file arch/arm/sunxi/sunxi_resets.c sunxi_resets + +# Misc. clock gates +device sunxigates +attach sunxigates at fdt with sunxi_gates +file arch/arm/sunxi/sunxi_gates.c sunxi_gates + +# GPIO +device sunxigpio: gpiobus +attach sunxigpio at fdt with sunxi_gpio +file arch/arm/sunxi/sunxi_gpio.c sunxi_gpio +file arch/arm/sunxi/sun6i_a31_gpio.c sunxi_gpio & soc_sun6i_a31 +file arch/arm/sunxi/sun8i_a83t_gpio.c sunxi_gpio & soc_sun8i_a83t +file arch/arm/sunxi/sun8i_h3_gpio.c sunxi_gpio & soc_sun8i_h3 + +# UART +attach com at fdt with sunxi_com +file arch/arm/sunxi/sunxi_com.c sunxi_com needs-flag + +# SD/MMC +device sunximmc: sdmmcbus +attach sunximmc at fdt with sunxi_mmc +file arch/arm/sunxi/sunxi_mmc.c sunxi_mmc + +# USB PHY +device sunxiusbphy +attach sunxiusbphy at fdt with sunxi_usbphy +file arch/arm/sunxi/sunxi_usbphy.c sunxi_usbphy + +# EHCI +attach ehci at fdt with ehci_fdt +file dev/fdt/ehci_fdt.c ehci_fdt + +# OHCI +attach ohci at fdt with ohci_fdt +file dev/fdt/ohci_fdt.c ohci_fdt + +# TWI +device sunxitwi: i2cbus, i2cexec, mvi2c +attach sunxitwi at fdt with sunxi_twi +file arch/arm/sunxi/sunxi_twi.c sunxi_twi + +# P2WI/RSB +device sunxirsb: i2cbus, i2cexec +attach sunxirsb at fdt with sunxi_rsb +file arch/arm/sunxi/sunxi_rsb.c sunxi_rsb + +# RTC +device sunxirtc +attach sunxirtc at fdt with sunxi_rtc +file arch/arm/sunxi/sunxi_rtc.c sunxi_rtc + +# EMAC +device sunxiemac: arp, ether, ifnet, mii +attach sunxiemac at fdt with sunxi_emac +file arch/arm/sunxi/sunxi_emac.c sunxi_emac + +# SOC parameters +defflag opt_soc.h SOC_SUNXI +defflag opt_soc.h SOC_SUN8I: SOC_SUNXI +defflag opt_soc.h SOC_SUN8I_A83T: SOC_SUN8I +defflag opt_soc.h SOC_SUN8I_H3: SOC_SUN8I +defflag opt_soc.h SOC_SUN6I: SOC_SUNXI +defflag opt_soc.h SOC_SUN6I_A31: SOC_SUN6I diff --git a/sys/arch/arm/sunxi/sun6i_a31_ccu.c b/sys/arch/arm/sunxi/sun6i_a31_ccu.c new file mode 100644 index 000000000000..2854af869b81 --- /dev/null +++ b/sys/arch/arm/sunxi/sun6i_a31_ccu.c @@ -0,0 +1,280 @@ +/* $NetBSD: sun6i_a31_ccu.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * Copyright (c) 2017 Emmanuel Vadot + * 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. + */ + +#include + +__KERNEL_RCSID(1, "$NetBSD: sun6i_a31_ccu.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include + +#include + +#include +#include + +#define PLL_PERIPH_CTRL_REG 0x028 +#define AHB1_APB1_CFG_REG 0x054 +#define APB2_CLK_DIV_REG 0x058 +#define AHB1_GATING_REG0 0x060 +#define AHB1_GATING_REG1 0x064 +#define APB1_GATING_REG 0x068 +#define APB2_GATING_REG 0x06c +#define SD0_CLK_REG 0x088 +#define SD1_CLK_REG 0x08c +#define SD2_CLK_REG 0x090 +#define SD3_CLK_REG 0x094 +#define USBPHY_CFG_REG 0x0cc +#define BUS_SOFT_RST_REG0 0x2c0 +#define BUS_SOFT_RST_REG1 0x2c4 +#define BUS_SOFT_RST_REG2 0x2c8 +#define BUS_SOFT_RST_REG3 0x2d0 +#define BUS_SOFT_RST_REG4 0x2d8 + +static int sun6i_a31_ccu_match(device_t, cfdata_t, void *); +static void sun6i_a31_ccu_attach(device_t, device_t, void *); + +static const char * const compatible[] = { + "allwinner,sun6i-a31-ccu", + NULL +}; + +CFATTACH_DECL_NEW(sunxi_a31_ccu, sizeof(struct sunxi_ccu_softc), + sun6i_a31_ccu_match, sun6i_a31_ccu_attach, NULL, NULL); + +static struct sunxi_ccu_reset sun6i_a31_ccu_resets[] = { + SUNXI_CCU_RESET(A31_RST_USB_PHY0, USBPHY_CFG_REG, 0), + SUNXI_CCU_RESET(A31_RST_USB_PHY1, USBPHY_CFG_REG, 1), + SUNXI_CCU_RESET(A31_RST_USB_PHY2, USBPHY_CFG_REG, 2), + + SUNXI_CCU_RESET(A31_RST_AHB1_MIPI_DSI, BUS_SOFT_RST_REG0, 1), + SUNXI_CCU_RESET(A31_RST_AHB1_SS, BUS_SOFT_RST_REG0, 5), + SUNXI_CCU_RESET(A31_RST_AHB1_DMA, BUS_SOFT_RST_REG0, 6), + SUNXI_CCU_RESET(A31_RST_AHB1_MMC0, BUS_SOFT_RST_REG0, 8), + SUNXI_CCU_RESET(A31_RST_AHB1_MMC1, BUS_SOFT_RST_REG0, 9), + SUNXI_CCU_RESET(A31_RST_AHB1_MMC2, BUS_SOFT_RST_REG0, 10), + SUNXI_CCU_RESET(A31_RST_AHB1_MMC3, BUS_SOFT_RST_REG0, 11), + SUNXI_CCU_RESET(A31_RST_AHB1_NAND1, BUS_SOFT_RST_REG0, 12), + SUNXI_CCU_RESET(A31_RST_AHB1_NAND0, BUS_SOFT_RST_REG0, 13), + SUNXI_CCU_RESET(A31_RST_AHB1_SDRAM, BUS_SOFT_RST_REG0, 14), + SUNXI_CCU_RESET(A31_RST_AHB1_EMAC, BUS_SOFT_RST_REG0, 17), + SUNXI_CCU_RESET(A31_RST_AHB1_TS, BUS_SOFT_RST_REG0, 18), + SUNXI_CCU_RESET(A31_RST_AHB1_HSTIMER, BUS_SOFT_RST_REG0, 19), + SUNXI_CCU_RESET(A31_RST_AHB1_SPI0, BUS_SOFT_RST_REG0, 20), + SUNXI_CCU_RESET(A31_RST_AHB1_SPI1, BUS_SOFT_RST_REG0, 21), + SUNXI_CCU_RESET(A31_RST_AHB1_SPI2, BUS_SOFT_RST_REG0, 22), + SUNXI_CCU_RESET(A31_RST_AHB1_SPI3, BUS_SOFT_RST_REG0, 23), + SUNXI_CCU_RESET(A31_RST_AHB1_OTG, BUS_SOFT_RST_REG0, 24), + SUNXI_CCU_RESET(A31_RST_AHB1_EHCI0, BUS_SOFT_RST_REG0, 26), + SUNXI_CCU_RESET(A31_RST_AHB1_EHCI1, BUS_SOFT_RST_REG0, 27), + SUNXI_CCU_RESET(A31_RST_AHB1_OHCI0, BUS_SOFT_RST_REG0, 29), + SUNXI_CCU_RESET(A31_RST_AHB1_OHCI1, BUS_SOFT_RST_REG0, 30), + SUNXI_CCU_RESET(A31_RST_AHB1_OHCI2, BUS_SOFT_RST_REG0, 31), + + SUNXI_CCU_RESET(A31_RST_AHB1_VE, BUS_SOFT_RST_REG1, 0), + SUNXI_CCU_RESET(A31_RST_AHB1_LCD0, BUS_SOFT_RST_REG1, 4), + SUNXI_CCU_RESET(A31_RST_AHB1_LCD1, BUS_SOFT_RST_REG1, 5), + SUNXI_CCU_RESET(A31_RST_AHB1_CSI, BUS_SOFT_RST_REG1, 8), + SUNXI_CCU_RESET(A31_RST_AHB1_HDMI, BUS_SOFT_RST_REG1, 11), + SUNXI_CCU_RESET(A31_RST_AHB1_BE0, BUS_SOFT_RST_REG1, 12), + SUNXI_CCU_RESET(A31_RST_AHB1_BE1, BUS_SOFT_RST_REG1, 13), + SUNXI_CCU_RESET(A31_RST_AHB1_FE0, BUS_SOFT_RST_REG1, 14), + SUNXI_CCU_RESET(A31_RST_AHB1_FE1, BUS_SOFT_RST_REG1, 15), + SUNXI_CCU_RESET(A31_RST_AHB1_MP, BUS_SOFT_RST_REG1, 16), + SUNXI_CCU_RESET(A31_RST_AHB1_GPU, BUS_SOFT_RST_REG1, 20), + SUNXI_CCU_RESET(A31_RST_AHB1_DEU0, BUS_SOFT_RST_REG1, 23), + SUNXI_CCU_RESET(A31_RST_AHB1_DEU1, BUS_SOFT_RST_REG1, 24), + SUNXI_CCU_RESET(A31_RST_AHB1_DRC0, BUS_SOFT_RST_REG1, 25), + SUNXI_CCU_RESET(A31_RST_AHB1_DRC1, BUS_SOFT_RST_REG1, 26), + + SUNXI_CCU_RESET(A31_RST_AHB1_LVDS, BUS_SOFT_RST_REG2, 0), + + SUNXI_CCU_RESET(A31_RST_APB1_CODEC, BUS_SOFT_RST_REG3, 0), + SUNXI_CCU_RESET(A31_RST_APB1_SPDIF, BUS_SOFT_RST_REG3, 1), + SUNXI_CCU_RESET(A31_RST_APB1_DIGITAL_MIC, BUS_SOFT_RST_REG3, 4), + SUNXI_CCU_RESET(A31_RST_APB1_DAUDIO0, BUS_SOFT_RST_REG3, 12), + SUNXI_CCU_RESET(A31_RST_APB1_DAUDIO1, BUS_SOFT_RST_REG3, 13), + + SUNXI_CCU_RESET(A31_RST_APB2_I2C0, BUS_SOFT_RST_REG4, 0), + SUNXI_CCU_RESET(A31_RST_APB2_I2C1, BUS_SOFT_RST_REG4, 1), + SUNXI_CCU_RESET(A31_RST_APB2_I2C2, BUS_SOFT_RST_REG4, 2), + SUNXI_CCU_RESET(A31_RST_APB2_I2C3, BUS_SOFT_RST_REG4, 3), + SUNXI_CCU_RESET(A31_RST_APB2_UART0, BUS_SOFT_RST_REG4, 16), + SUNXI_CCU_RESET(A31_RST_APB2_UART1, BUS_SOFT_RST_REG4, 17), + SUNXI_CCU_RESET(A31_RST_APB2_UART2, BUS_SOFT_RST_REG4, 18), + SUNXI_CCU_RESET(A31_RST_APB2_UART3, BUS_SOFT_RST_REG4, 19), + SUNXI_CCU_RESET(A31_RST_APB2_UART4, BUS_SOFT_RST_REG4, 20), + SUNXI_CCU_RESET(A31_RST_APB2_UART5, BUS_SOFT_RST_REG4, 21), +}; + +static const char *ahb1_parents[] = { "losc", "hosc", "axi", "pll_periph" }; +static const char *apb1_parents[] = { "ahb1" }; +static const char *apb2_parents[] = { "losc", "hosc", "pll_periph", "pll_periph" }; +static const char *mod_parents[] = { "hosc", "pll_periph" }; + +static struct sunxi_ccu_clk sun6i_a31_ccu_clks[] = { + SUNXI_CCU_NKMP(A31_CLK_PLL_PERIPH, "pll_periph", "hosc", + PLL_PERIPH_CTRL_REG, /* reg */ + __BITS(12,8), /* n */ + __BITS(5,4), /* k */ + 0, /* m */ + 0, /* p */ + __BIT(31), /* enable */ + SUNXI_CCU_NKMP_DIVIDE_BY_TWO), + + SUNXI_CCU_DIV(A31_CLK_APB1, "apb1", apb1_parents, + AHB1_APB1_CFG_REG, /* reg */ + __BITS(9,8), /* div */ + 0, /* sel */ + SUNXI_CCU_DIV_POWER_OF_TWO|SUNXI_CCU_DIV_ZERO_IS_ONE), + + SUNXI_CCU_PREDIV(A31_CLK_AHB1, "ahb1", ahb1_parents, + AHB1_APB1_CFG_REG, /* reg */ + __BITS(7,6), /* prediv */ + __BIT(3), /* prediv_sel */ + __BITS(5,4), /* div */ + __BITS(13,12), /* sel */ + SUNXI_CCU_PREDIV_POWER_OF_TWO), + + SUNXI_CCU_NM(A31_CLK_APB2, "apb2", apb2_parents, + APB2_CLK_DIV_REG, /* reg */ + __BITS(17,16), /* n */ + __BITS(4,0), /* m */ + __BITS(25,24), /* sel */ + 0, /* enable */ + SUNXI_CCU_NM_POWER_OF_TWO), + + SUNXI_CCU_NM(A31_CLK_MMC0, "mmc0", mod_parents, + SD0_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + SUNXI_CCU_NM(A31_CLK_MMC1, "mmc1", mod_parents, + SD1_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + SUNXI_CCU_NM(A31_CLK_MMC2, "mmc2", mod_parents, + SD2_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + SUNXI_CCU_NM(A31_CLK_MMC3, "mmc3", mod_parents, + SD3_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + + SUNXI_CCU_GATE(A31_CLK_AHB1_MMC0, "ahb1-mmc0", "ahb1", + AHB1_GATING_REG0, 8), + SUNXI_CCU_GATE(A31_CLK_AHB1_MMC1, "ahb1-mmc1", "ahb1", + AHB1_GATING_REG0, 9), + SUNXI_CCU_GATE(A31_CLK_AHB1_MMC2, "ahb1-mmc2", "ahb1", + AHB1_GATING_REG0, 10), + SUNXI_CCU_GATE(A31_CLK_AHB1_MMC3, "ahb1-mmc3", "ahb1", + AHB1_GATING_REG0, 11), + SUNXI_CCU_GATE(A31_CLK_AHB1_EMAC, "ahb1-emac", "ahb1", + AHB1_GATING_REG0, 17), + SUNXI_CCU_GATE(A31_CLK_AHB1_OTG, "ahb1-otg", "ahb1", + AHB1_GATING_REG0, 24), + SUNXI_CCU_GATE(A31_CLK_AHB1_EHCI0, "ahb1-ehci0", "ahb1", + AHB1_GATING_REG0, 26), + SUNXI_CCU_GATE(A31_CLK_AHB1_EHCI1, "ahb1-ehci1", "ahb1", + AHB1_GATING_REG0, 27), + SUNXI_CCU_GATE(A31_CLK_AHB1_OHCI0, "ahb1-ohci0", "ahb1", + AHB1_GATING_REG0, 29), + SUNXI_CCU_GATE(A31_CLK_AHB1_OHCI1, "ahb1-ohci1", "ahb1", + AHB1_GATING_REG0, 30), + SUNXI_CCU_GATE(A31_CLK_AHB1_OHCI2, "ahb1-ohci2", "ahb1", + AHB1_GATING_REG0, 31), + + SUNXI_CCU_GATE(A31_CLK_APB1_PIO, "ahb1-pio", "apb1", + APB1_GATING_REG, 5), + + SUNXI_CCU_GATE(A31_CLK_APB2_I2C0, "apb2-i2c0", "apb2", + APB2_GATING_REG, 0), + SUNXI_CCU_GATE(A31_CLK_APB2_I2C1, "apb2-i2c1", "apb2", + APB2_GATING_REG, 1), + SUNXI_CCU_GATE(A31_CLK_APB2_I2C2, "apb2-i2c2", "apb2", + APB2_GATING_REG, 2), + SUNXI_CCU_GATE(A31_CLK_APB2_I2C3, "apb2-i2c3", "apb2", + APB2_GATING_REG, 3), + SUNXI_CCU_GATE(A31_CLK_APB2_UART0, "apb2-uart0", "apb2", + APB2_GATING_REG, 16), + SUNXI_CCU_GATE(A31_CLK_APB2_UART1, "apb2-uart1", "apb2", + APB2_GATING_REG, 17), + SUNXI_CCU_GATE(A31_CLK_APB2_UART2, "apb2-uart2", "apb2", + APB2_GATING_REG, 18), + SUNXI_CCU_GATE(A31_CLK_APB2_UART3, "apb2-uart3", "apb2", + APB2_GATING_REG, 19), + SUNXI_CCU_GATE(A31_CLK_APB2_UART4, "apb2-uart4", "apb2", + APB2_GATING_REG, 20), + SUNXI_CCU_GATE(A31_CLK_APB2_UART5, "apb2-uart5", "apb2", + APB2_GATING_REG, 21), + + SUNXI_CCU_GATE(A31_CLK_USB_PHY0, "usb-phy0", "hosc", + USBPHY_CFG_REG, 8), + SUNXI_CCU_GATE(A31_CLK_USB_PHY1, "usb-phy1", "hosc", + USBPHY_CFG_REG, 9), + SUNXI_CCU_GATE(A31_CLK_USB_PHY2, "usb-phy2", "hosc", + USBPHY_CFG_REG, 10), + SUNXI_CCU_GATE(A31_CLK_USB_OHCI0, "usb-ohci0", "hosc", + USBPHY_CFG_REG, 16), + SUNXI_CCU_GATE(A31_CLK_USB_OHCI1, "usb-ohci1", "hosc", + USBPHY_CFG_REG, 17), + SUNXI_CCU_GATE(A31_CLK_USB_OHCI2, "usb-ohci2", "hosc", + USBPHY_CFG_REG, 18), +}; + +static int +sun6i_a31_ccu_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sun6i_a31_ccu_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_ccu_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + + sc->sc_dev = self; + sc->sc_phandle = faa->faa_phandle; + sc->sc_bst = faa->faa_bst; + + sc->sc_resets = sun6i_a31_ccu_resets; + sc->sc_nresets = __arraycount(sun6i_a31_ccu_resets); + + sc->sc_clks = sun6i_a31_ccu_clks; + sc->sc_nclks = __arraycount(sun6i_a31_ccu_clks); + + if (sunxi_ccu_attach(sc) != 0) + return; + + aprint_naive("\n"); + aprint_normal(": A31 CCU\n"); + + sunxi_ccu_print(sc); +} diff --git a/sys/arch/arm/sunxi/sun6i_a31_ccu.h b/sys/arch/arm/sunxi/sun6i_a31_ccu.h new file mode 100644 index 000000000000..68bd9d9038a1 --- /dev/null +++ b/sys/arch/arm/sunxi/sun6i_a31_ccu.h @@ -0,0 +1,250 @@ +/* $NetBSD: sun6i_a31_ccu.h,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Emmanuel Vadot + * 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 __CCU_A31_H__ +#define __CCU_A31_H__ + +#define A31_RST_USB_PHY0 0 +#define A31_RST_USB_PHY1 1 +#define A31_RST_USB_PHY2 2 +#define A31_RST_AHB1_MIPI_DSI 3 +#define A31_RST_AHB1_SS 4 +#define A31_RST_AHB1_DMA 5 +#define A31_RST_AHB1_MMC0 6 +#define A31_RST_AHB1_MMC1 7 +#define A31_RST_AHB1_MMC2 8 +#define A31_RST_AHB1_MMC3 9 +#define A31_RST_AHB1_NAND1 10 +#define A31_RST_AHB1_NAND0 11 +#define A31_RST_AHB1_SDRAM 12 +#define A31_RST_AHB1_EMAC 13 +#define A31_RST_AHB1_TS 14 +#define A31_RST_AHB1_HSTIMER 15 +#define A31_RST_AHB1_SPI0 16 +#define A31_RST_AHB1_SPI1 17 +#define A31_RST_AHB1_SPI2 18 +#define A31_RST_AHB1_SPI3 19 +#define A31_RST_AHB1_OTG 20 +#define A31_RST_AHB1_EHCI0 21 +#define A31_RST_AHB1_EHCI1 22 +#define A31_RST_AHB1_OHCI0 23 +#define A31_RST_AHB1_OHCI1 24 +#define A31_RST_AHB1_OHCI2 25 +#define A31_RST_AHB1_VE 26 +#define A31_RST_AHB1_LCD0 27 +#define A31_RST_AHB1_LCD1 28 +#define A31_RST_AHB1_CSI 29 +#define A31_RST_AHB1_HDMI 30 +#define A31_RST_AHB1_BE0 31 +#define A31_RST_AHB1_BE1 32 +#define A31_RST_AHB1_FE0 33 +#define A31_RST_AHB1_FE1 34 +#define A31_RST_AHB1_MP 35 +#define A31_RST_AHB1_GPU 36 +#define A31_RST_AHB1_DEU0 37 +#define A31_RST_AHB1_DEU1 38 +#define A31_RST_AHB1_DRC0 39 +#define A31_RST_AHB1_DRC1 40 +#define A31_RST_AHB1_LVDS 41 +#define A31_RST_APB1_CODEC 42 +#define A31_RST_APB1_SPDIF 43 +#define A31_RST_APB1_DIGITAL_MIC 44 +#define A31_RST_APB1_DAUDIO0 45 +#define A31_RST_APB1_DAUDIO1 46 +#define A31_RST_APB2_I2C0 47 +#define A31_RST_APB2_I2C1 48 +#define A31_RST_APB2_I2C2 49 +#define A31_RST_APB2_I2C3 50 +#define A31_RST_APB2_UART0 51 +#define A31_RST_APB2_UART1 52 +#define A31_RST_APB2_UART2 53 +#define A31_RST_APB2_UART3 54 +#define A31_RST_APB2_UART4 55 +#define A31_RST_APB2_UART5 56 + +#define A31_CLK_PLL_CPU 0 +#define A31_CLK_PLL_AUDIO_BASE 1 +#define A31_CLK_PLL_AUDIO 2 +#define A31_CLK_PLL_AUDIO_2X 3 +#define A31_CLK_PLL_AUDIO_4X 4 +#define A31_CLK_PLL_AUDIO_8X 5 +#define A31_CLK_PLL_VIDEO0 6 +#define A31_CLK_PLL_VIDEO0_2X 7 +#define A31_CLK_PLL_VE 8 +#define A31_CLK_PLL_DDR 9 +#define A31_CLK_PLL_PERIPH 10 +#define A31_CLK_PLL_PERIPH_2X 11 +#define A31_CLK_PLL_VIDEO1 12 +#define A31_CLK_PLL_VIDEO1_2X 13 +#define A31_CLK_PLL_GPU 14 +#define A31_CLK_PLL_MIPI 15 +#define A31_CLK_PLL9 16 +#define A31_CLK_PLL10 17 +#define A31_CLK_CPU 18 +#define A31_CLK_AXI 19 +#define A31_CLK_AHB1 20 +#define A31_CLK_APB1 21 +#define A31_CLK_APB2 22 +#define A31_CLK_AHB1_MIPIDSI 23 +#define A31_CLK_AHB1_SS 24 +#define A31_CLK_AHB1_DMA 25 +#define A31_CLK_AHB1_MMC0 26 +#define A31_CLK_AHB1_MMC1 27 +#define A31_CLK_AHB1_MMC2 28 +#define A31_CLK_AHB1_MMC3 29 +#define A31_CLK_AHB1_NAND1 30 +#define A31_CLK_AHB1_NAND0 31 +#define A31_CLK_AHB1_SDRAM 32 +#define A31_CLK_AHB1_EMAC 33 +#define A31_CLK_AHB1_TS 34 +#define A31_CLK_AHB1_HSTIMER 35 +#define A31_CLK_AHB1_SPI0 36 +#define A31_CLK_AHB1_SPI1 37 +#define A31_CLK_AHB1_SPI2 38 +#define A31_CLK_AHB1_SPI3 39 +#define A31_CLK_AHB1_OTG 40 +#define A31_CLK_AHB1_EHCI0 41 +#define A31_CLK_AHB1_EHCI1 42 +#define A31_CLK_AHB1_OHCI0 43 +#define A31_CLK_AHB1_OHCI1 44 +#define A31_CLK_AHB1_OHCI2 45 +#define A31_CLK_AHB1_VE 46 +#define A31_CLK_AHB1_LCD0 47 +#define A31_CLK_AHB1_LCD1 48 +#define A31_CLK_AHB1_CSI 49 +#define A31_CLK_AHB1_HDMI 50 +#define A31_CLK_AHB1_BE0 51 +#define A31_CLK_AHB1_BE1 52 +#define A31_CLK_AHB1_FE0 53 +#define A31_CLK_AHB1_FE1 54 +#define A31_CLK_AHB1_MP 55 +#define A31_CLK_AHB1_GPU 56 +#define A31_CLK_AHB1_DEU0 57 +#define A31_CLK_AHB1_DEU1 58 +#define A31_CLK_AHB1_DRC0 59 +#define A31_CLK_AHB1_DRC1 60 +#define A31_CLK_APB1_CODEC 61 +#define A31_CLK_APB1_SPDIF 62 +#define A31_CLK_APB1_DIGITAL_MIC 63 +#define A31_CLK_APB1_PIO 64 +#define A31_CLK_APB1_DAUDIO0 65 +#define A31_CLK_APB1_DAUDIO1 66 +#define A31_CLK_APB2_I2C0 67 +#define A31_CLK_APB2_I2C1 68 +#define A31_CLK_APB2_I2C2 69 +#define A31_CLK_APB2_I2C3 70 +#define A31_CLK_APB2_UART0 71 +#define A31_CLK_APB2_UART1 72 +#define A31_CLK_APB2_UART2 73 +#define A31_CLK_APB2_UART3 74 +#define A31_CLK_APB2_UART4 75 +#define A31_CLK_APB2_UART5 76 +#define A31_CLK_NAND0 77 +#define A31_CLK_NAND1 78 +#define A31_CLK_MMC0 79 +#define A31_CLK_MMC0_SAMPLE 80 +#define A31_CLK_MMC0_OUTPUT 81 +#define A31_CLK_MMC1 82 +#define A31_CLK_MMC1_SAMPLE 83 +#define A31_CLK_MMC1_OUTPUT 84 +#define A31_CLK_MMC2 85 +#define A31_CLK_MMC2_SAMPLE 86 +#define A31_CLK_MMC2_OUTPUT 87 +#define A31_CLK_MMC3 88 +#define A31_CLK_MMC3_SAMPLE 89 +#define A31_CLK_MMC3_OUTPUT 90 +#define A31_CLK_TS 91 +#define A31_CLK_SS 92 +#define A31_CLK_SPI0 93 +#define A31_CLK_SPI1 94 +#define A31_CLK_SPI2 95 +#define A31_CLK_SPI3 96 +#define A31_CLK_DAUDIO0 97 +#define A31_CLK_DAUDIO1 98 +#define A31_CLK_SPDIF 99 +#define A31_CLK_USB_PHY0 100 +#define A31_CLK_USB_PHY1 101 +#define A31_CLK_USB_PHY2 102 +#define A31_CLK_USB_OHCI0 103 +#define A31_CLK_USB_OHCI1 104 +#define A31_CLK_USB_OHCI2 105 +#define A31_CLK_MDFS 107 +#define A31_CLK_SDRAM0 108 +#define A31_CLK_SDRAM1 109 +#define A31_CLK_DRAM_VE 110 +#define A31_CLK_DRAM_CSI_ISP 111 +#define A31_CLK_DRAM_TS 112 +#define A31_CLK_DRAM_DRC0 113 +#define A31_CLK_DRAM_DRC1 114 +#define A31_CLK_DRAM_DEU0 115 +#define A31_CLK_DRAM_DEU1 116 +#define A31_CLK_DRAM_FE0 117 +#define A31_CLK_DRAM_FE1 118 +#define A31_CLK_DRAM_BE0 119 +#define A31_CLK_DRAM_BE1 120 +#define A31_CLK_DRAM_MP 121 +#define A31_CLK_BE0 122 +#define A31_CLK_BE1 123 +#define A31_CLK_FE0 124 +#define A31_CLK_FE1 125 +#define A31_CLK_MP 126 +#define A31_CLK_LCD0_CH0 127 +#define A31_CLK_LCD1_CH0 128 +#define A31_CLK_LCD0_CH1 129 +#define A31_CLK_LCD1_CH1 130 +#define A31_CLK_CSI0_SCLK 131 +#define A31_CLK_CSI0_MCLK 132 +#define A31_CLK_CSI1_MCLK 133 +#define A31_CLK_VE 134 +#define A31_CLK_CODEC 135 +#define A31_CLK_AVS 136 +#define A31_CLK_DIGITAL_MIC 137 +#define A31_CLK_HDMI 138 +#define A31_CLK_HDMI_DDC 139 +#define A31_CLK_PS 140 +#define A31_CLK_MBUS0 141 +#define A31_CLK_MBUS1 142 +#define A31_CLK_MIPI_DSI 143 +#define A31_CLK_MIPI_DSI_DPHY 144 +#define A31_CLK_MIPI_CSI_DPHY 145 +#define A31_CLK_IEP_DRC0 146 +#define A31_CLK_IEP_DRC1 147 +#define A31_CLK_IEP_DEU0 148 +#define A31_CLK_IEP_DEU1 149 +#define A31_CLK_GPU_CORE 150 +#define A31_CLK_GPU_MEMORY 151 +#define A31_CLK_GPU_HYD 152 +#define A31_CLK_ATS 153 +#define A31_CLK_TRACE 154 +#define A31_CLK_OUT_A 155 +#define A31_CLK_OUT_B 156 +#define A31_CLK_OUT_C 157 + +#endif /* __CCU_A31 H__ */ diff --git a/sys/arch/arm/sunxi/sun6i_a31_gpio.c b/sys/arch/arm/sunxi/sun6i_a31_gpio.c new file mode 100644 index 000000000000..6e2c8670423a --- /dev/null +++ b/sys/arch/arm/sunxi/sun6i_a31_gpio.c @@ -0,0 +1,244 @@ +/* $NetBSD: sun6i_a31_gpio.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2016 Emmanuel Vadot + * 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 +__KERNEL_RCSID(0, "$NetBSD: sun6i_a31_gpio.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include + +#include + +static const struct sunxi_gpio_pins a31_pins[] = { + {"PA0", 0, 0, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint0", NULL}, 6, 0}, + {"PA1", 0, 1, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint1", NULL}, 6, 1}, + {"PA2", 0, 2, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint2", NULL}, 6, 2}, + {"PA3", 0, 3, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint3", NULL}, 6, 3}, + {"PA4", 0, 4, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint4", NULL}, 6, 4}, + {"PA5", 0, 5, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint5", NULL}, 6, 5}, + {"PA6", 0, 6, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint6", NULL}, 6, 6}, + {"PA7", 0, 7, {"gpio_in", "gpio_out", "gmac", "lcd1", "uart1", NULL, "pa_eint7", NULL}, 6, 7}, + {"PA8", 0, 8, {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, NULL, "pa_eint8", NULL}, 6, 8}, + {"PA9", 0, 9, {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, "mmc2", "pa_eint9", NULL}, 6, 9}, + {"PA10", 0, 10, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint10", NULL}, 6, 10}, + {"PA11", 0, 11, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint11", NULL}, 6, 11}, + {"PA12", 0, 12, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint12", NULL}, 6, 12}, + {"PA13", 0, 13, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint13", NULL}, 6, 13}, + {"PA14", 0, 14, {"gpio_in", "gpio_out", "gmac", "lcd1", "mmc3", "mmc2", "pa_eint14", NULL}, 6, 14}, + {"PA15", 0, 15, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_a", NULL, "pa_eint15", NULL}, 6, 15}, + {"PA16", 0, 16, {"gpio_in", "gpio_out", "gmac", "lcd1", "dmic", NULL, "pa_eint16", NULL}, 6, 16}, + {"PA17", 0, 17, {"gpio_in", "gpio_out", "gmac", "lcd1", "dmic", NULL, "pa_eint17", NULL}, 6, 17}, + {"PA18", 0, 18, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_b", NULL, "pa_eint18", NULL}, 6, 18}, + {"PA19", 0, 19, {"gpio_in", "gpio_out", "gmac", "lcd1", "pwm3", NULL, "pa_eint19", NULL}, 6, 19}, + {"PA20", 0, 20, {"gpio_in", "gpio_out", "gmac", "lcd1", "pwm3", NULL, "pa_eint20", NULL}, 6, 20}, + {"PA21", 0, 21, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint21", NULL}, 6, 21}, + {"PA22", 0, 22, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint22", NULL}, 6, 22}, + {"PA23", 0, 23, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint23", NULL}, 6, 23}, + {"PA24", 0, 24, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint24", NULL}, 6, 24}, + {"PA25", 0, 25, {"gpio_in", "gpio_out", "gmac", "lcd1", "spi3", NULL, "pa_eint25", NULL}, 6, 25}, + {"PA26", 0, 26, {"gpio_in", "gpio_out", "gmac", "lcd1", "clk_out_c", NULL, "pa_eint26", NULL}, 6, 26}, + {"PA27", 0, 27, {"gpio_in", "gpio_out", "gmac", "lcd1", NULL, NULL, "pa_eint27", NULL}, 6, 27}, + + {"PB0", 1, 0, {"gpio_in", "gpio_out", "i2s0", "uart3", "csi", NULL, "pb_eint0", NULL}, 6, 0}, + {"PB1", 1, 1, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint1", NULL}, 6, 1}, + {"PB2", 1, 2, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint2", NULL}, 6, 2}, + {"PB3", 1, 3, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint3", NULL}, 6, 3}, + {"PB4", 1, 4, {"gpio_in", "gpio_out", "i2s0", "uart3", NULL, NULL, "pb_eint4", NULL}, 6, 4}, + {"PB5", 1, 5, {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, "pb_eint5", NULL}, 6, 5}, + {"PB6", 1, 6, {"gpio_in", "gpio_out", "i2s0", "uart3", "i2c3", NULL, "pb_eint6", NULL}, 6, 6}, + {"PB7", 1, 7, {"gpio_in", "gpio_out", "i2s0", NULL, NULL, NULL, "pb_eint7", NULL}, 6, 7}, + + {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, + {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, + {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand0", "spi0", NULL, NULL, NULL, NULL}}, + {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, + {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, + {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, + {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC16", 2, 16, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, + {"PC17", 2, 17, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, + {"PC18", 2, 18, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, + {"PC19", 2, 19, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, + {"PC20", 2, 20, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, + {"PC21", 2, 21, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, + {"PC22", 2, 22, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, + {"PC23", 2, 23, {"gpio_in", "gpio_out", "nand0", "nand1", NULL, NULL, NULL, NULL}}, + {"PC24", 2, 24, {"gpio_in", "gpio_out", "nand0", "mmc2", "mmc3", NULL, NULL, NULL}}, + {"PC25", 2, 25, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, + {"PC26", 2, 26, {"gpio_in", "gpio_out", "nand0", NULL, NULL, NULL, NULL, NULL}}, + {"PC27", 2, 27, {"gpio_in", "gpio_out", NULL, "spi0",NULL, NULL, NULL, NULL}}, + + {"PD0", 3, 0, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD1", 3, 1, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD2", 3, 2, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD3", 3, 3, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD4", 3, 4, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD5", 3, 5, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD6", 3, 6, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD7", 3, 7, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD8", 3, 8, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD9", 3, 9, {"gpio_in", "gpio_out", "lcd0", "lvds0", NULL, NULL, NULL, NULL}}, + {"PD10", 3, 10, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD11", 3, 11, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD12", 3, 12, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD13", 3, 13, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD14", 3, 14, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD15", 3, 15, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD16", 3, 16, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD17", 3, 17, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD18", 3, 18, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD19", 3, 19, {"gpio_in", "gpio_out", "lcd0", "lvds1", NULL, NULL, NULL, NULL}}, + {"PD20", 3, 20, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, + {"PD21", 3, 21, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, + {"PD22", 3, 22, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, + {"PD23", 3, 23, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, + {"PD24", 3, 24, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, + {"PD25", 3, 25, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, + {"PD26", 3, 26, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, + {"PD27", 3, 27, {"gpio_in", "gpio_out", "lcd0", NULL, NULL, NULL, NULL, NULL}}, + + {"PE0", 4, 0, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint0", NULL}, 6, 0}, + {"PE1", 4, 1, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint1", NULL}, 6, 1}, + {"PE2", 4, 2, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint2", NULL}, 6, 2}, + {"PE3", 4, 3, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint3", NULL}, 6, 3}, + {"PE4", 4, 4, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint4", NULL}, 6, 4}, + {"PE5", 4, 5, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint5", NULL}, 6, 5}, + {"PE6", 4, 6, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint6", NULL}, 6, 6}, + {"PE7", 4, 7, {"gpio_in", "gpio_out", "csi", "uart5", NULL, NULL, "pe_eint7", NULL}, 6, 7}, + {"PE8", 4, 8, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint8", NULL}, 6, 8}, + {"PE9", 4, 9, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint9", NULL}, 6, 9}, + {"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint10", NULL}, 6, 10}, + {"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint11", NULL}, 6, 11}, + {"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint12", NULL}, 6, 12}, + {"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint13", NULL}, 6, 13}, + {"PE14", 4, 14, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint14", NULL}, 6, 14}, + {"PE15", 4, 15, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, "pe_eint15", NULL}, 6, 15}, + {"PE16", 4, 16, {"gpio_in", "gpio_out", "csi", NULL, NULL, NULL, "pe_eint16", NULL}, 6, 16}, + + {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, + {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, + {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, + {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, + {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", NULL, "uart0", NULL, NULL, NULL}}, + {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", NULL, "jtag", NULL, NULL, NULL}}, + + {"PG0", 6, 0, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint0", NULL}, 6, 0}, + {"PG1", 6, 1, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint1", NULL}, 6, 1}, + {"PG2", 6, 2, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint2", NULL}, 6, 2}, + {"PG3", 6, 3, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint3", NULL}, 6, 3}, + {"PG4", 6, 4, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint4", NULL}, 6, 4}, + {"PG5", 6, 5, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint5", NULL}, 6, 5}, + {"PG6", 6, 6, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint6", NULL}, 6, 6}, + {"PG7", 6, 7, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint7", NULL}, 6, 7}, + {"PG8", 6, 8, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint8", NULL}, 6, 8}, + {"PG9", 6, 9, {"gpio_in", "gpio_out", "uart2", NULL, NULL, NULL, "pg_eint9", NULL}, 6, 9}, + {"PG10", 6, 10, {"gpio_in", "gpio_out", "i2c3", "usb", NULL, NULL, "pg_eint10", NULL}, 6, 10}, + {"PG11", 6, 11, {"gpio_in", "gpio_out", "i2c3", "usb", NULL, NULL, "pg_eint11", NULL}, 6, 11}, + {"PG12", 6, 12, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint12", NULL}, 6, 12}, + {"PG13", 6, 13, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint13", NULL}, 6, 13}, + {"PG14", 6, 14, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint14", NULL}, 6, 14}, + {"PG15", 6, 15, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint15", NULL}, 6, 15}, + {"PG16", 6, 16, {"gpio_in", "gpio_out", "spi1", "i2s1", NULL, NULL, "pg_eint16", NULL}, 6, 16}, + {"PG17", 6, 17, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, "pg_eint17", NULL}, 6, 17}, + {"PG18", 6, 18, {"gpio_in", "gpio_out", "uart4", NULL, NULL, NULL, "pg_eint18", NULL}, 6, 18}, + + {"PH0", 7, 0, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH1", 7, 1, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH2", 7, 2, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH3", 7, 3, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH4", 7, 4, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH5", 7, 5, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH6", 7, 6, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH7", 7, 7, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH8", 7, 8, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH9", 7, 9, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}}, + {"PH10", 7, 10, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm1", NULL, NULL, NULL}}, + {"PH11", 7, 11, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}}, + {"PH12", 7, 12, {"gpio_in", "gpio_out", "spi2", "jtag", "pwm2", NULL, NULL, NULL}}, + {"PH13", 7, 13, {"gpio_in", "gpio_out", "pwm0", NULL, NULL, NULL, NULL, NULL}}, + {"PH14", 7, 14, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, + {"PH15", 7, 15, {"gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, NULL, NULL}}, + {"PH16", 7, 16, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, + {"PH17", 7, 17, {"gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, NULL, NULL}}, + {"PH18", 7, 18, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, + {"PH19", 7, 19, {"gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, NULL, NULL}}, + {"PH20", 7, 20, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}}, + {"PH21", 7, 21, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, NULL, NULL}}, + {"PH22", 7, 22, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + {"PH23", 7, 23, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + {"PH24", 7, 24, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + {"PH25", 7, 25, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + {"PH26", 7, 26, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + {"PH27", 7, 27, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + {"PH28", 7, 28, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + {"PH29", 7, 29, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, + {"PH30", 7, 30, {"gpio_in", "gpio_out", "nand1", NULL, NULL, NULL, NULL, NULL}}, +}; + +static const struct sunxi_gpio_pins a31_r_pins[] = { + {"PL0", 0, 0, {"gpio_in", "gpio_out", "s_twi", "s_p2wi", NULL, NULL, NULL, NULL}}, + {"PL1", 0, 1, {"gpio_in", "gpio_out", "s_twi", "s_p2wi", NULL, NULL, NULL, NULL}}, + {"PL2", 0, 2, {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, NULL, NULL}}, + {"PL3", 0, 3, {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, NULL, NULL}}, + {"PL4", 0, 4, {"gpio_in", "gpio_out", "s_ir", NULL, NULL, NULL, NULL, NULL}}, + {"PL5", 0, 5, {"gpio_in", "gpio_out", "pl_eint0", "s_jtag", NULL, NULL, NULL, NULL}, 2, 0}, + {"PL6", 0, 6, {"gpio_in", "gpio_out", "pl_eint1", "s_jtag", NULL, NULL, NULL, NULL}, 2, 1}, + {"PL7", 0, 7, {"gpio_in", "gpio_out", "pl_eint2", "s_jtag", NULL, NULL, NULL, NULL}, 2, 2}, + {"PL8", 0, 8, {"gpio_in", "gpio_out", "pl_eint3", "s_jtag", NULL, NULL, NULL, NULL}, 2, 3}, + + {"PM0", 1, 0, {"gpio_in", "gpio_out", "pm_eint0", NULL, NULL, NULL, NULL, NULL}, 2, 0}, + {"PM1", 1, 1, {"gpio_in", "gpio_out", "pm_eint1", NULL, NULL, NULL, NULL, NULL}, 2, 1}, + {"PM2", 1, 2, {"gpio_in", "gpio_out", "pm_eint2", "1wire", NULL, NULL, NULL, NULL}, 2, 2}, + {"PM3", 1, 3, {"gpio_in", "gpio_out", "pm_eint3", NULL, NULL, NULL, NULL, NULL}, 2, 3}, + {"PM4", 1, 4, {"gpio_in", "gpio_out", "pm_eint4", NULL, NULL, NULL, NULL, NULL}, 2, 4}, + {"PM5", 1, 5, {"gpio_in", "gpio_out", "pm_eint5", NULL, NULL, NULL, NULL, NULL}, 2, 5}, + {"PM6", 1, 6, {"gpio_in", "gpio_out", "pm_eint6", NULL, NULL, NULL, NULL, NULL}, 2, 6}, + {"PM7", 1, 7, {"gpio_in", "gpio_out", "pm_eint7", "rtc", NULL, NULL, NULL, NULL}, 2, 7}, +}; + +const struct sunxi_gpio_padconf sun6i_a31_padconf = { + .npins = __arraycount(a31_pins), + .pins = a31_pins, +}; + +const struct sunxi_gpio_padconf sun6i_a31_r_padconf = { + .npins = __arraycount(a31_r_pins), + .pins = a31_r_pins, +}; diff --git a/sys/arch/arm/sunxi/sun8i_a83t_ccu.c b/sys/arch/arm/sunxi/sun8i_a83t_ccu.c new file mode 100644 index 000000000000..523377c781c1 --- /dev/null +++ b/sys/arch/arm/sunxi/sun8i_a83t_ccu.c @@ -0,0 +1,285 @@ +/* $NetBSD: sun8i_a83t_ccu.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * Copyright (c) 2017 Emmanuel Vadot + * 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. + */ + +#include + +__KERNEL_RCSID(1, "$NetBSD: sun8i_a83t_ccu.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include + +#include + +#include +#include + +#define PLL_PERIPH0_CTRL_REG 0x028 +#define AHB1_APB1_CFG_REG 0x054 +#define APB2_CFG_REG 0x058 +#define BUS_CLK_GATING_REG0 0x060 +#define BUS_CLK_GATING_REG2 0x068 +#define BUS_CLK_GATING_REG3 0x06c +#define SDMMC0_CLK_REG 0x088 +#define SDMMC1_CLK_REG 0x08c +#define SDMMC2_CLK_REG 0x090 +#define USBPHY_CFG_REG 0x0cc +#define MBUS_RST_REG 0x0fc +#define BUS_SOFT_RST_REG0 0x2c0 +#define BUS_SOFT_RST_REG1 0x2c4 +#define BUS_SOFT_RST_REG2 0x2c8 +#define BUS_SOFT_RST_REG3 0x2d0 +#define BUS_SOFT_RST_REG4 0x2d8 + +static int sun8i_a83t_ccu_match(device_t, cfdata_t, void *); +static void sun8i_a83t_ccu_attach(device_t, device_t, void *); + +static const char * const compatible[] = { + "allwinner,sun8i-a83t-ccu", + NULL +}; + +CFATTACH_DECL_NEW(sunxi_a83t_ccu, sizeof(struct sunxi_ccu_softc), + sun8i_a83t_ccu_match, sun8i_a83t_ccu_attach, NULL, NULL); + +static struct sunxi_ccu_reset sun8i_a83t_ccu_resets[] = { + SUNXI_CCU_RESET(H3_RST_USB_PHY0, USBPHY_CFG_REG, 0), + SUNXI_CCU_RESET(H3_RST_USB_PHY1, USBPHY_CFG_REG, 1), + SUNXI_CCU_RESET(H3_RST_USB_PHY2, USBPHY_CFG_REG, 2), + SUNXI_CCU_RESET(H3_RST_USB_PHY3, USBPHY_CFG_REG, 3), + + SUNXI_CCU_RESET(H3_RST_MBUS, MBUS_RST_REG, 31), + + SUNXI_CCU_RESET(H3_RST_BUS_CE, BUS_SOFT_RST_REG0, 5), + SUNXI_CCU_RESET(H3_RST_BUS_DMA, BUS_SOFT_RST_REG0, 6), + SUNXI_CCU_RESET(H3_RST_BUS_MMC0, BUS_SOFT_RST_REG0, 8), + SUNXI_CCU_RESET(H3_RST_BUS_MMC1, BUS_SOFT_RST_REG0, 9), + SUNXI_CCU_RESET(H3_RST_BUS_MMC2, BUS_SOFT_RST_REG0, 10), + SUNXI_CCU_RESET(H3_RST_BUS_NAND, BUS_SOFT_RST_REG0, 13), + SUNXI_CCU_RESET(H3_RST_BUS_DRAM, BUS_SOFT_RST_REG0, 14), + SUNXI_CCU_RESET(H3_RST_BUS_EMAC, BUS_SOFT_RST_REG0, 17), + SUNXI_CCU_RESET(H3_RST_BUS_TS, BUS_SOFT_RST_REG0, 18), + SUNXI_CCU_RESET(H3_RST_BUS_HSTIMER, BUS_SOFT_RST_REG0, 19), + SUNXI_CCU_RESET(H3_RST_BUS_SPI0, BUS_SOFT_RST_REG0, 20), + SUNXI_CCU_RESET(H3_RST_BUS_SPI1, BUS_SOFT_RST_REG0, 21), + SUNXI_CCU_RESET(H3_RST_BUS_OTG, BUS_SOFT_RST_REG0, 23), + SUNXI_CCU_RESET(H3_RST_BUS_EHCI0, BUS_SOFT_RST_REG0, 24), + SUNXI_CCU_RESET(H3_RST_BUS_EHCI1, BUS_SOFT_RST_REG0, 25), + SUNXI_CCU_RESET(H3_RST_BUS_EHCI2, BUS_SOFT_RST_REG0, 26), + SUNXI_CCU_RESET(H3_RST_BUS_EHCI3, BUS_SOFT_RST_REG0, 27), + SUNXI_CCU_RESET(H3_RST_BUS_OHCI0, BUS_SOFT_RST_REG0, 28), + SUNXI_CCU_RESET(H3_RST_BUS_OHCI1, BUS_SOFT_RST_REG0, 29), + SUNXI_CCU_RESET(H3_RST_BUS_OHCI2, BUS_SOFT_RST_REG0, 30), + SUNXI_CCU_RESET(H3_RST_BUS_OHCI3, BUS_SOFT_RST_REG0, 31), + + SUNXI_CCU_RESET(H3_RST_BUS_VE, BUS_SOFT_RST_REG1, 0), + SUNXI_CCU_RESET(H3_RST_BUS_TCON0, BUS_SOFT_RST_REG1, 3), + SUNXI_CCU_RESET(H3_RST_BUS_TCON1, BUS_SOFT_RST_REG1, 4), + SUNXI_CCU_RESET(H3_RST_BUS_DEINTERLACE, BUS_SOFT_RST_REG1, 5), + SUNXI_CCU_RESET(H3_RST_BUS_CSI, BUS_SOFT_RST_REG1, 8), + SUNXI_CCU_RESET(H3_RST_BUS_TVE, BUS_SOFT_RST_REG1, 9), + SUNXI_CCU_RESET(H3_RST_BUS_HDMI0, BUS_SOFT_RST_REG1, 10), + SUNXI_CCU_RESET(H3_RST_BUS_HDMI1, BUS_SOFT_RST_REG1, 11), + SUNXI_CCU_RESET(H3_RST_BUS_DE, BUS_SOFT_RST_REG1, 12), + SUNXI_CCU_RESET(H3_RST_BUS_GPU, BUS_SOFT_RST_REG1, 20), + SUNXI_CCU_RESET(H3_RST_BUS_MSGBOX, BUS_SOFT_RST_REG1, 21), + SUNXI_CCU_RESET(H3_RST_BUS_SPINLOCK, BUS_SOFT_RST_REG1, 22), + SUNXI_CCU_RESET(H3_RST_BUS_DBG, BUS_SOFT_RST_REG1, 31), + + SUNXI_CCU_RESET(H3_RST_BUS_EPHY, BUS_SOFT_RST_REG2, 2), + + SUNXI_CCU_RESET(H3_RST_BUS_CODEC, BUS_SOFT_RST_REG3, 0), + SUNXI_CCU_RESET(H3_RST_BUS_SPDIF, BUS_SOFT_RST_REG3, 1), + SUNXI_CCU_RESET(H3_RST_BUS_THS, BUS_SOFT_RST_REG3, 8), + SUNXI_CCU_RESET(H3_RST_BUS_I2S0, BUS_SOFT_RST_REG3, 12), + SUNXI_CCU_RESET(H3_RST_BUS_I2S1, BUS_SOFT_RST_REG3, 13), + SUNXI_CCU_RESET(H3_RST_BUS_I2S2, BUS_SOFT_RST_REG3, 14), + + SUNXI_CCU_RESET(H3_RST_BUS_I2C0, BUS_SOFT_RST_REG4, 0), + SUNXI_CCU_RESET(H3_RST_BUS_I2C1, BUS_SOFT_RST_REG4, 1), + SUNXI_CCU_RESET(H3_RST_BUS_I2C2, BUS_SOFT_RST_REG4, 2), + SUNXI_CCU_RESET(H3_RST_BUS_UART0, BUS_SOFT_RST_REG4, 16), + SUNXI_CCU_RESET(H3_RST_BUS_UART1, BUS_SOFT_RST_REG4, 17), + SUNXI_CCU_RESET(H3_RST_BUS_UART2, BUS_SOFT_RST_REG4, 18), + SUNXI_CCU_RESET(H3_RST_BUS_UART3, BUS_SOFT_RST_REG4, 19), + SUNXI_CCU_RESET(H3_RST_BUS_SCR, BUS_SOFT_RST_REG4, 20), +}; + +static const char *ahb1_parents[] = { "losc", "hosc", "pll_periph" }; +static const char *ahb2_parents[] = { "ahb1", "pll_periph" }; +static const char *apb1_parents[] = { "ahb1" }; +static const char *apb2_parents[] = { "losc", "hosc", "pll_periph" }; +static const char *mod_parents[] = { "hosc", "pll_periph" }; + +static struct sunxi_ccu_clk sun8i_a83t_ccu_clks[] = { + SUNXI_CCU_NKMP(H3_CLK_PLL_PERIPH0, "pll_periph", "hosc", + PLL_PERIPH0_CTRL_REG, /* reg */ + __BITS(15,8), /* n */ + 0, /* k */ + __BIT(18), /* m */ + __BIT(16), /* p */ + __BIT(31), /* enable */ + SUNXI_CCU_NKMP_FACTOR_N_EXACT), + + SUNXI_CCU_PREDIV(H3_CLK_AHB1, "ahb1", ahb1_parents, + AHB1_APB1_CFG_REG, /* reg */ + __BITS(7,6), /* prediv */ + __BIT(3), /* prediv_sel */ + __BITS(5,4), /* div */ + __BITS(13,12), /* sel */ + SUNXI_CCU_PREDIV_POWER_OF_TWO), + + SUNXI_CCU_PREDIV(H3_CLK_AHB2, "ahb2", ahb2_parents, + APB2_CFG_REG, /* reg */ + 0, /* prediv */ + __BIT(1), /* prediv_sel */ + 0, /* div */ + __BITS(1,0), /* sel */ + SUNXI_CCU_PREDIV_DIVIDE_BY_TWO), + + SUNXI_CCU_DIV(H3_CLK_APB1, "apb1", apb1_parents, + AHB1_APB1_CFG_REG, /* reg */ + __BITS(9,8), /* div */ + 0, /* sel */ + SUNXI_CCU_DIV_POWER_OF_TWO|SUNXI_CCU_DIV_ZERO_IS_ONE), + + SUNXI_CCU_NM(H3_CLK_APB2, "apb2", apb2_parents, + APB2_CFG_REG, /* reg */ + __BITS(17,16), /* n */ + __BITS(4,0), /* m */ + __BITS(25,24), /* sel */ + 0, /* enable */ + SUNXI_CCU_NM_POWER_OF_TWO), + + SUNXI_CCU_NM(H3_CLK_MMC0, "mmc0", mod_parents, + SDMMC0_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + SUNXI_CCU_NM(H3_CLK_MMC1, "mmc1", mod_parents, + SDMMC1_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + SUNXI_CCU_NM(H3_CLK_MMC2, "mmc2", mod_parents, + SDMMC2_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + + SUNXI_CCU_GATE(H3_CLK_BUS_MMC0, "bus-mmc0", "ahb1", + BUS_CLK_GATING_REG0, 8), + SUNXI_CCU_GATE(H3_CLK_BUS_MMC1, "bus-mmc1", "ahb1", + BUS_CLK_GATING_REG0, 9), + SUNXI_CCU_GATE(H3_CLK_BUS_MMC2, "bus-mmc2", "ahb1", + BUS_CLK_GATING_REG0, 10), + SUNXI_CCU_GATE(H3_CLK_BUS_EMAC, "bus-emac", "ahb2", + BUS_CLK_GATING_REG0, 17), + SUNXI_CCU_GATE(H3_CLK_BUS_OTG, "bus-otg", "ahb1", + BUS_CLK_GATING_REG0, 23), + SUNXI_CCU_GATE(H3_CLK_BUS_EHCI0, "bus-ehci0", "ahb1", + BUS_CLK_GATING_REG0, 24), + SUNXI_CCU_GATE(H3_CLK_BUS_EHCI1, "bus-ehci1", "ahb2", + BUS_CLK_GATING_REG0, 25), + SUNXI_CCU_GATE(H3_CLK_BUS_EHCI2, "bus-ehci2", "ahb2", + BUS_CLK_GATING_REG0, 26), + SUNXI_CCU_GATE(H3_CLK_BUS_EHCI3, "bus-ehci3", "ahb2", + BUS_CLK_GATING_REG0, 27), + SUNXI_CCU_GATE(H3_CLK_BUS_OHCI0, "bus-ohci0", "ahb1", + BUS_CLK_GATING_REG0, 28), + SUNXI_CCU_GATE(H3_CLK_BUS_OHCI1, "bus-ohci1", "ahb2", + BUS_CLK_GATING_REG0, 29), + SUNXI_CCU_GATE(H3_CLK_BUS_OHCI2, "bus-ohci2", "ahb2", + BUS_CLK_GATING_REG0, 30), + SUNXI_CCU_GATE(H3_CLK_BUS_OHCI3, "bus-ohci3", "ahb2", + BUS_CLK_GATING_REG0, 31), + + SUNXI_CCU_GATE(H3_CLK_BUS_PIO, "bus-pio", "apb1", + BUS_CLK_GATING_REG2, 5), + + SUNXI_CCU_GATE(H3_CLK_BUS_I2C0, "bus-i2c0", "apb2", + BUS_CLK_GATING_REG3, 0), + SUNXI_CCU_GATE(H3_CLK_BUS_I2C1, "bus-i2c1", "apb2", + BUS_CLK_GATING_REG3, 1), + SUNXI_CCU_GATE(H3_CLK_BUS_I2C2, "bus-i2c2", "apb2", + BUS_CLK_GATING_REG3, 2), + SUNXI_CCU_GATE(H3_CLK_BUS_UART0, "bus-uart0", "apb2", + BUS_CLK_GATING_REG3, 16), + SUNXI_CCU_GATE(H3_CLK_BUS_UART1, "bus-uart1", "apb2", + BUS_CLK_GATING_REG3, 17), + SUNXI_CCU_GATE(H3_CLK_BUS_UART2, "bus-uart2", "apb2", + BUS_CLK_GATING_REG3, 18), + SUNXI_CCU_GATE(H3_CLK_BUS_UART3, "bus-uart3", "apb2", + BUS_CLK_GATING_REG3, 19), + + SUNXI_CCU_GATE(H3_CLK_USBPHY0, "usb-phy0", "hosc", + USBPHY_CFG_REG, 8), + SUNXI_CCU_GATE(H3_CLK_USBPHY1, "usb-phy1", "hosc", + USBPHY_CFG_REG, 9), + SUNXI_CCU_GATE(H3_CLK_USBPHY2, "usb-phy2", "hosc", + USBPHY_CFG_REG, 10), + SUNXI_CCU_GATE(H3_CLK_USBPHY3, "usb-phy3", "hosc", + USBPHY_CFG_REG, 11), + SUNXI_CCU_GATE(H3_CLK_USBOHCI0, "usb-ohci0", "hosc", + USBPHY_CFG_REG, 16), + SUNXI_CCU_GATE(H3_CLK_USBOHCI1, "usb-ohci1", "hosc", + USBPHY_CFG_REG, 17), + SUNXI_CCU_GATE(H3_CLK_USBOHCI2, "usb-ohci2", "hosc", + USBPHY_CFG_REG, 18), + SUNXI_CCU_GATE(H3_CLK_USBOHCI3, "usb-ohci3", "hosc", + USBPHY_CFG_REG, 19), +}; + +static int +sun8i_a83t_ccu_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sun8i_a83t_ccu_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_ccu_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + + sc->sc_dev = self; + sc->sc_phandle = faa->faa_phandle; + sc->sc_bst = faa->faa_bst; + + sc->sc_resets = sun8i_a83t_ccu_resets; + sc->sc_nresets = __arraycount(sun8i_a83t_ccu_resets); + + sc->sc_clks = sun8i_a83t_ccu_clks; + sc->sc_nclks = __arraycount(sun8i_a83t_ccu_clks); + + if (sunxi_ccu_attach(sc) != 0) + return; + + aprint_naive("\n"); + aprint_normal(": A83T CCU\n"); + + sunxi_ccu_print(sc); +} diff --git a/sys/arch/arm/sunxi/sun8i_a83t_ccu.h b/sys/arch/arm/sunxi/sun8i_a83t_ccu.h new file mode 100644 index 000000000000..ea0addd1a932 --- /dev/null +++ b/sys/arch/arm/sunxi/sun8i_a83t_ccu.h @@ -0,0 +1,34 @@ +/* $NetBSD: sun8i_a83t_ccu.h,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#ifndef _SUN8I_A83T_CCU_H +#define _SUN8I_A83T_CCU_H + +#include + +#endif /* !_SUN8I_A83T_CCU_H */ diff --git a/sys/arch/arm/sunxi/sun8i_a83t_gpio.c b/sys/arch/arm/sunxi/sun8i_a83t_gpio.c new file mode 100644 index 000000000000..fa2c252b21f2 --- /dev/null +++ b/sys/arch/arm/sunxi/sun8i_a83t_gpio.c @@ -0,0 +1,181 @@ +/* $NetBSD: sun8i_a83t_gpio.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2016-2017 Jared McNeill + * 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 +__KERNEL_RCSID(0, "$NetBSD: sun8i_a83t_gpio.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include + +#include + +static const struct sunxi_gpio_pins a83t_pins[] = { + { "PB0", 1, 0, { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } }, + { "PB1", 1, 1, { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } }, + { "PB2", 1, 2, { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } }, + { "PB3", 1, 3, { "gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "eint" } }, + { "PB4", 1, 4, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB5", 1, 5, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB6", 1, 6, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB7", 1, 7, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB8", 1, 8, { "gpio_in", "gpio_out", "i2s0", "tdm", NULL, NULL, "eint" } }, + { "PB9", 1, 9, { "gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "eint" } }, + { "PB10", 1, 10, { "gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "eint" } }, + + { "PC0", 2, 0, { "gpio_in", "gpio_out", "nand", "spi0" } }, + { "PC1", 2, 1, { "gpio_in", "gpio_out", "nand", "spi0" } }, + { "PC2", 2, 2, { "gpio_in", "gpio_out", "nand", "spi0" } }, + { "PC3", 2, 3, { "gpio_in", "gpio_out", "nand", "spi0" } }, + { "PC4", 2, 4, { "gpio_in", "gpio_out", "nand" } }, + { "PC5", 2, 5, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC6", 2, 6, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC7", 2, 7, { "gpio_in", "gpio_out", "nand" } }, + { "PC8", 2, 8, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC9", 2, 9, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC10", 2, 10, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC11", 2, 11, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC12", 2, 12, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC13", 2, 13, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC14", 2, 14, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC15", 2, 15, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC16", 2, 16, { "gpio_in", "gpio_out", "nand", "mmc2" } }, + { "PC17", 2, 17, { "gpio_in", "gpio_out", "nand" } }, + { "PC18", 2, 18, { "gpio_in", "gpio_out", "nand" } }, + + { "PD2", 3, 2, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD3", 3, 3, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD4", 3, 4, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD5", 3, 5, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD6", 3, 6, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD7", 3, 7, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD10", 3, 10, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD11", 3, 11, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD12", 3, 12, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD13", 3, 13, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD14", 3, 14, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD15", 3, 15, { "gpio_in", "gpio_out", "lcd", NULL, "emac" } }, + { "PD18", 3, 18, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD19", 3, 19, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD20", 3, 20, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD21", 3, 21, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD22", 3, 22, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD23", 3, 23, { "gpio_in", "gpio_out", "lcd", "lvds", "emac" } }, + { "PD24", 3, 24, { "gpio_in", "gpio_out", "lcd", "lvds" } }, + { "PD25", 3, 25, { "gpio_in", "gpio_out", "lcd", "lvds" } }, + { "PD26", 3, 26, { "gpio_in", "gpio_out", "lcd", "lvds" } }, + { "PD27", 3, 27, { "gpio_in", "gpio_out", "lcd", "lvds" } }, + { "PD28", 3, 28, { "gpio_in", "gpio_out", "pwm" } }, + { "PD29", 3, 29, { "gpio_in", "gpio_out" } }, + + { "PE0", 4, 0, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE1", 4, 1, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE2", 4, 2, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE3", 4, 3, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE4", 4, 4, { "gpio_in", "gpio_out", "csi" } }, + { "PE5", 4, 5, { "gpio_in", "gpio_out", "csi" } }, + { "PE6", 4, 6, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE7", 4, 7, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE8", 4, 8, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE9", 4, 9, { "gpio_in", "gpio_out", "csi", NULL, "ccir" } }, + { "PE10", 4, 10, { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } }, + { "PE11", 4, 11, { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } }, + { "PE12", 4, 12, { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } }, + { "PE13", 4, 13, { "gpio_in", "gpio_out", "csi", "uart4", "ccir" } }, + { "PE14", 4, 14, { "gpio_in", "gpio_out", "csi", "twi2" } }, + { "PE15", 4, 15, { "gpio_in", "gpio_out", "csi", "twi2" } }, + { "PE16", 4, 16, { "gpio_in", "gpio_out" } }, + { "PE17", 4, 17, { "gpio_in", "gpio_out" } }, + { "PE18", 4, 18, { "gpio_in", "gpio_out", NULL, "owa" } }, + { "PE19", 4, 19, { "gpio_in", "gpio_out" } }, + + { "PF0", 5, 0, { "gpio_in", "gpio_out", "mmc0", "jtag" } }, + { "PF1", 5, 1, { "gpio_in", "gpio_out", "mmc0", "jtag" } }, + { "PF2", 5, 2, { "gpio_in", "gpio_out", "mmc0", "uart0" } }, + { "PF3", 5, 3, { "gpio_in", "gpio_out", "mmc0", "jtag" } }, + { "PF4", 5, 4, { "gpio_in", "gpio_out", "mmc0", "uart0" } }, + { "PF5", 5, 5, { "gpio_in", "gpio_out", "mmc0", "jtag" } }, + { "PF6", 5, 6, { "gpio_in", "gpio_out" } }, + + { "PG0", 6, 0, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG1", 6, 1, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG2", 6, 2, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG3", 6, 3, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG4", 6, 4, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG5", 6, 5, { "gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "eint" } }, + { "PG6", 6, 6, { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } }, + { "PG7", 6, 7, { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } }, + { "PG8", 6, 8, { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } }, + { "PG9", 6, 9, { "gpio_in", "gpio_out", "uart1", "spi1", NULL, NULL, "eint" } }, + { "PG10", 6, 10, { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } }, + { "PG11", 6, 11, { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } }, + { "PG12", 6, 12, { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } }, + { "PG13", 6, 13, { "gpio_in", "gpio_out", "i2s1", "uart3", NULL, NULL, "eint" } }, + + { "PH0", 7, 0, { "gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, "eint" } }, + { "PH1", 7, 1, { "gpio_in", "gpio_out", "i2c0", NULL, NULL, NULL, "eint" } }, + { "PH2", 7, 2, { "gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, "eint" } }, + { "PH3", 7, 3, { "gpio_in", "gpio_out", "i2c1", NULL, NULL, NULL, "eint" } }, + { "PH4", 7, 4, { "gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, "eint" } }, + { "PH5", 7, 5, { "gpio_in", "gpio_out", "i2c2", NULL, NULL, NULL, "eint" } }, + { "PH6", 7, 6, { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } }, + { "PH7", 7, 7, { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } }, + { "PH8", 7, 8, { "gpio_in", "gpio_out", "hdmiddc", NULL, NULL, NULL, "eint" } }, + { "PH9", 7, 9, { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } }, + { "PH10", 7, 10, { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } }, + { "PH11", 7, 11, { "gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "eint" } }, +}; + +static const struct sunxi_gpio_pins a83t_r_pins[] = { + { "PL0", 0, 0, { "gpio_in", "gpio_out", "s_rsb", "s_i2c", NULL, NULL, "eint" } }, + { "PL1", 0, 1, { "gpio_in", "gpio_out", "s_rsb", "s_i2c", NULL, NULL, "eint" } }, + { "PL2", 0, 2, { "gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "eint" } }, + { "PL3", 0, 3, { "gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "eint" } }, + { "PL4", 0, 4, { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } }, + { "PL5", 0, 5, { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } }, + { "PL6", 0, 6, { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } }, + { "PL7", 0, 7, { "gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "eint" } }, + { "PL8", 0, 8, { "gpio_in", "gpio_out", "s_i2c", NULL, NULL, NULL, "eint" } }, + { "PL9", 0, 9, { "gpio_in", "gpio_out", "s_i2c", NULL, NULL, NULL, "eint" } }, + { "PL10", 0, 10, { "gpio_in", "gpio_out", "s_pwm", NULL, NULL, NULL, "eint" } }, + { "PL11", 0, 11, { "gpio_in", "gpio_out", NULL, NULL, NULL, "eint" } }, + { "PL12", 0, 12, { "gpio_in", "gpio_out", "s_cir", NULL, NULL, NULL, "eint" } }, +}; + +const struct sunxi_gpio_padconf sun8i_a83t_padconf = { + .npins = __arraycount(a83t_pins), + .pins = a83t_pins, +}; + +const struct sunxi_gpio_padconf sun8i_a83t_r_padconf = { + .npins = __arraycount(a83t_r_pins), + .pins = a83t_r_pins, +}; diff --git a/sys/arch/arm/sunxi/sun8i_h3_ccu.c b/sys/arch/arm/sunxi/sun8i_h3_ccu.c new file mode 100644 index 000000000000..a36002aa8a88 --- /dev/null +++ b/sys/arch/arm/sunxi/sun8i_h3_ccu.c @@ -0,0 +1,302 @@ +/* $NetBSD: sun8i_h3_ccu.c,v 1.8.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * Copyright (c) 2017 Emmanuel Vadot + * 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. + */ + +#include + +__KERNEL_RCSID(1, "$NetBSD: sun8i_h3_ccu.c,v 1.8.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include + +#include + +#include +#include + +#define PLL_PERIPH0_CTRL_REG 0x028 +#define AHB1_APB1_CFG_REG 0x054 +#define APB2_CFG_REG 0x058 +#define AHB2_CFG_REG 0x05c +#define AHB2_CLK_CFG __BITS(1,0) +#define AHB2_CLK_CFG_PLL_PERIPH0_2 1 +#define BUS_CLK_GATING_REG0 0x060 +#define BUS_CLK_GATING_REG2 0x068 +#define BUS_CLK_GATING_REG3 0x06c +#define SDMMC0_CLK_REG 0x088 +#define SDMMC1_CLK_REG 0x08c +#define SDMMC2_CLK_REG 0x090 +#define USBPHY_CFG_REG 0x0cc +#define MBUS_RST_REG 0x0fc +#define BUS_SOFT_RST_REG0 0x2c0 +#define BUS_SOFT_RST_REG1 0x2c4 +#define BUS_SOFT_RST_REG2 0x2c8 +#define BUS_SOFT_RST_REG3 0x2d0 +#define BUS_SOFT_RST_REG4 0x2d8 + +static int sun8i_h3_ccu_match(device_t, cfdata_t, void *); +static void sun8i_h3_ccu_attach(device_t, device_t, void *); + +static const char * const compatible[] = { + "allwinner,sun8i-h3-ccu", + NULL +}; + +CFATTACH_DECL_NEW(sunxi_h3_ccu, sizeof(struct sunxi_ccu_softc), + sun8i_h3_ccu_match, sun8i_h3_ccu_attach, NULL, NULL); + +static struct sunxi_ccu_reset sun8i_h3_ccu_resets[] = { + SUNXI_CCU_RESET(H3_RST_USB_PHY0, USBPHY_CFG_REG, 0), + SUNXI_CCU_RESET(H3_RST_USB_PHY1, USBPHY_CFG_REG, 1), + SUNXI_CCU_RESET(H3_RST_USB_PHY2, USBPHY_CFG_REG, 2), + SUNXI_CCU_RESET(H3_RST_USB_PHY3, USBPHY_CFG_REG, 3), + + SUNXI_CCU_RESET(H3_RST_MBUS, MBUS_RST_REG, 31), + + SUNXI_CCU_RESET(H3_RST_BUS_CE, BUS_SOFT_RST_REG0, 5), + SUNXI_CCU_RESET(H3_RST_BUS_DMA, BUS_SOFT_RST_REG0, 6), + SUNXI_CCU_RESET(H3_RST_BUS_MMC0, BUS_SOFT_RST_REG0, 8), + SUNXI_CCU_RESET(H3_RST_BUS_MMC1, BUS_SOFT_RST_REG0, 9), + SUNXI_CCU_RESET(H3_RST_BUS_MMC2, BUS_SOFT_RST_REG0, 10), + SUNXI_CCU_RESET(H3_RST_BUS_NAND, BUS_SOFT_RST_REG0, 13), + SUNXI_CCU_RESET(H3_RST_BUS_DRAM, BUS_SOFT_RST_REG0, 14), + SUNXI_CCU_RESET(H3_RST_BUS_EMAC, BUS_SOFT_RST_REG0, 17), + SUNXI_CCU_RESET(H3_RST_BUS_TS, BUS_SOFT_RST_REG0, 18), + SUNXI_CCU_RESET(H3_RST_BUS_HSTIMER, BUS_SOFT_RST_REG0, 19), + SUNXI_CCU_RESET(H3_RST_BUS_SPI0, BUS_SOFT_RST_REG0, 20), + SUNXI_CCU_RESET(H3_RST_BUS_SPI1, BUS_SOFT_RST_REG0, 21), + SUNXI_CCU_RESET(H3_RST_BUS_OTG, BUS_SOFT_RST_REG0, 23), + SUNXI_CCU_RESET(H3_RST_BUS_EHCI0, BUS_SOFT_RST_REG0, 24), + SUNXI_CCU_RESET(H3_RST_BUS_EHCI1, BUS_SOFT_RST_REG0, 25), + SUNXI_CCU_RESET(H3_RST_BUS_EHCI2, BUS_SOFT_RST_REG0, 26), + SUNXI_CCU_RESET(H3_RST_BUS_EHCI3, BUS_SOFT_RST_REG0, 27), + SUNXI_CCU_RESET(H3_RST_BUS_OHCI0, BUS_SOFT_RST_REG0, 28), + SUNXI_CCU_RESET(H3_RST_BUS_OHCI1, BUS_SOFT_RST_REG0, 29), + SUNXI_CCU_RESET(H3_RST_BUS_OHCI2, BUS_SOFT_RST_REG0, 30), + SUNXI_CCU_RESET(H3_RST_BUS_OHCI3, BUS_SOFT_RST_REG0, 31), + + SUNXI_CCU_RESET(H3_RST_BUS_VE, BUS_SOFT_RST_REG1, 0), + SUNXI_CCU_RESET(H3_RST_BUS_TCON0, BUS_SOFT_RST_REG1, 3), + SUNXI_CCU_RESET(H3_RST_BUS_TCON1, BUS_SOFT_RST_REG1, 4), + SUNXI_CCU_RESET(H3_RST_BUS_DEINTERLACE, BUS_SOFT_RST_REG1, 5), + SUNXI_CCU_RESET(H3_RST_BUS_CSI, BUS_SOFT_RST_REG1, 8), + SUNXI_CCU_RESET(H3_RST_BUS_TVE, BUS_SOFT_RST_REG1, 9), + SUNXI_CCU_RESET(H3_RST_BUS_HDMI0, BUS_SOFT_RST_REG1, 10), + SUNXI_CCU_RESET(H3_RST_BUS_HDMI1, BUS_SOFT_RST_REG1, 11), + SUNXI_CCU_RESET(H3_RST_BUS_DE, BUS_SOFT_RST_REG1, 12), + SUNXI_CCU_RESET(H3_RST_BUS_GPU, BUS_SOFT_RST_REG1, 20), + SUNXI_CCU_RESET(H3_RST_BUS_MSGBOX, BUS_SOFT_RST_REG1, 21), + SUNXI_CCU_RESET(H3_RST_BUS_SPINLOCK, BUS_SOFT_RST_REG1, 22), + SUNXI_CCU_RESET(H3_RST_BUS_DBG, BUS_SOFT_RST_REG1, 31), + + SUNXI_CCU_RESET(H3_RST_BUS_EPHY, BUS_SOFT_RST_REG2, 2), + + SUNXI_CCU_RESET(H3_RST_BUS_CODEC, BUS_SOFT_RST_REG3, 0), + SUNXI_CCU_RESET(H3_RST_BUS_SPDIF, BUS_SOFT_RST_REG3, 1), + SUNXI_CCU_RESET(H3_RST_BUS_THS, BUS_SOFT_RST_REG3, 8), + SUNXI_CCU_RESET(H3_RST_BUS_I2S0, BUS_SOFT_RST_REG3, 12), + SUNXI_CCU_RESET(H3_RST_BUS_I2S1, BUS_SOFT_RST_REG3, 13), + SUNXI_CCU_RESET(H3_RST_BUS_I2S2, BUS_SOFT_RST_REG3, 14), + + SUNXI_CCU_RESET(H3_RST_BUS_I2C0, BUS_SOFT_RST_REG4, 0), + SUNXI_CCU_RESET(H3_RST_BUS_I2C1, BUS_SOFT_RST_REG4, 1), + SUNXI_CCU_RESET(H3_RST_BUS_I2C2, BUS_SOFT_RST_REG4, 2), + SUNXI_CCU_RESET(H3_RST_BUS_UART0, BUS_SOFT_RST_REG4, 16), + SUNXI_CCU_RESET(H3_RST_BUS_UART1, BUS_SOFT_RST_REG4, 17), + SUNXI_CCU_RESET(H3_RST_BUS_UART2, BUS_SOFT_RST_REG4, 18), + SUNXI_CCU_RESET(H3_RST_BUS_UART3, BUS_SOFT_RST_REG4, 19), + SUNXI_CCU_RESET(H3_RST_BUS_SCR, BUS_SOFT_RST_REG4, 20), +}; + +static const char *ahb1_parents[] = { "losc", "hosc", "axi", "pll_periph0" }; +static const char *ahb2_parents[] = { "ahb1", "pll_periph0" }; +static const char *apb1_parents[] = { "ahb1" }; +static const char *apb2_parents[] = { "losc", "hosc", "pll_periph0" }; +static const char *mod_parents[] = { "hosc", "pll_periph0", "pll_periph1" }; + +static struct sunxi_ccu_clk sun8i_h3_ccu_clks[] = { + SUNXI_CCU_NKMP(H3_CLK_PLL_PERIPH0, "pll_periph0", "hosc", + PLL_PERIPH0_CTRL_REG, /* reg */ + __BITS(12,8), /* n */ + __BITS(5,4), /* k */ + 0, /* m */ + __BITS(17,16), /* p */ + __BIT(31), /* enable */ + SUNXI_CCU_NKMP_DIVIDE_BY_TWO), + + SUNXI_CCU_PREDIV(H3_CLK_AHB1, "ahb1", ahb1_parents, + AHB1_APB1_CFG_REG, /* reg */ + __BITS(7,6), /* prediv */ + __BIT(3), /* prediv_sel */ + __BITS(5,4), /* div */ + __BITS(13,12), /* sel */ + SUNXI_CCU_PREDIV_POWER_OF_TWO), + + SUNXI_CCU_PREDIV(H3_CLK_AHB2, "ahb2", ahb2_parents, + AHB2_CFG_REG, /* reg */ + 0, /* prediv */ + __BIT(1), /* prediv_sel */ + 0, /* div */ + __BITS(1,0), /* sel */ + SUNXI_CCU_PREDIV_DIVIDE_BY_TWO), + + SUNXI_CCU_DIV(H3_CLK_APB1, "apb1", apb1_parents, + AHB1_APB1_CFG_REG, /* reg */ + __BITS(9,8), /* div */ + 0, /* sel */ + SUNXI_CCU_DIV_POWER_OF_TWO|SUNXI_CCU_DIV_ZERO_IS_ONE), + + SUNXI_CCU_NM(H3_CLK_APB2, "apb2", apb2_parents, + APB2_CFG_REG, /* reg */ + __BITS(17,16), /* n */ + __BITS(4,0), /* m */ + __BITS(25,24), /* sel */ + 0, /* enable */ + SUNXI_CCU_NM_POWER_OF_TWO), + + SUNXI_CCU_NM(H3_CLK_MMC0, "mmc0", mod_parents, + SDMMC0_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + SUNXI_CCU_NM(H3_CLK_MMC1, "mmc1", mod_parents, + SDMMC1_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + SUNXI_CCU_NM(H3_CLK_MMC2, "mmc2", mod_parents, + SDMMC2_CLK_REG, __BITS(17, 16), __BITS(3,0), __BITS(25, 24), __BIT(31), + SUNXI_CCU_NM_POWER_OF_TWO|SUNXI_CCU_NM_ROUND_DOWN), + + SUNXI_CCU_GATE(H3_CLK_BUS_MMC0, "bus-mmc0", "ahb1", + BUS_CLK_GATING_REG0, 8), + SUNXI_CCU_GATE(H3_CLK_BUS_MMC1, "bus-mmc1", "ahb1", + BUS_CLK_GATING_REG0, 9), + SUNXI_CCU_GATE(H3_CLK_BUS_MMC2, "bus-mmc2", "ahb1", + BUS_CLK_GATING_REG0, 10), + SUNXI_CCU_GATE(H3_CLK_BUS_EMAC, "bus-emac", "ahb2", + BUS_CLK_GATING_REG0, 17), + SUNXI_CCU_GATE(H3_CLK_BUS_OTG, "bus-otg", "ahb1", + BUS_CLK_GATING_REG0, 23), + SUNXI_CCU_GATE(H3_CLK_BUS_EHCI0, "bus-ehci0", "ahb1", + BUS_CLK_GATING_REG0, 24), + SUNXI_CCU_GATE(H3_CLK_BUS_EHCI1, "bus-ehci1", "ahb2", + BUS_CLK_GATING_REG0, 25), + SUNXI_CCU_GATE(H3_CLK_BUS_EHCI2, "bus-ehci2", "ahb2", + BUS_CLK_GATING_REG0, 26), + SUNXI_CCU_GATE(H3_CLK_BUS_EHCI3, "bus-ehci3", "ahb2", + BUS_CLK_GATING_REG0, 27), + SUNXI_CCU_GATE(H3_CLK_BUS_OHCI0, "bus-ohci0", "ahb1", + BUS_CLK_GATING_REG0, 28), + SUNXI_CCU_GATE(H3_CLK_BUS_OHCI1, "bus-ohci1", "ahb2", + BUS_CLK_GATING_REG0, 29), + SUNXI_CCU_GATE(H3_CLK_BUS_OHCI2, "bus-ohci2", "ahb2", + BUS_CLK_GATING_REG0, 30), + SUNXI_CCU_GATE(H3_CLK_BUS_OHCI3, "bus-ohci3", "ahb2", + BUS_CLK_GATING_REG0, 31), + + SUNXI_CCU_GATE(H3_CLK_BUS_PIO, "bus-pio", "apb1", + BUS_CLK_GATING_REG2, 5), + + SUNXI_CCU_GATE(H3_CLK_BUS_I2C0, "bus-i2c0", "apb2", + BUS_CLK_GATING_REG3, 0), + SUNXI_CCU_GATE(H3_CLK_BUS_I2C1, "bus-i2c1", "apb2", + BUS_CLK_GATING_REG3, 1), + SUNXI_CCU_GATE(H3_CLK_BUS_I2C2, "bus-i2c2", "apb2", + BUS_CLK_GATING_REG3, 2), + SUNXI_CCU_GATE(H3_CLK_BUS_UART0, "bus-uart0", "apb2", + BUS_CLK_GATING_REG3, 16), + SUNXI_CCU_GATE(H3_CLK_BUS_UART1, "bus-uart1", "apb2", + BUS_CLK_GATING_REG3, 17), + SUNXI_CCU_GATE(H3_CLK_BUS_UART2, "bus-uart2", "apb2", + BUS_CLK_GATING_REG3, 18), + SUNXI_CCU_GATE(H3_CLK_BUS_UART3, "bus-uart3", "apb2", + BUS_CLK_GATING_REG3, 19), + + SUNXI_CCU_GATE(H3_CLK_USBPHY0, "usb-phy0", "hosc", + USBPHY_CFG_REG, 8), + SUNXI_CCU_GATE(H3_CLK_USBPHY1, "usb-phy1", "hosc", + USBPHY_CFG_REG, 9), + SUNXI_CCU_GATE(H3_CLK_USBPHY2, "usb-phy2", "hosc", + USBPHY_CFG_REG, 10), + SUNXI_CCU_GATE(H3_CLK_USBPHY3, "usb-phy3", "hosc", + USBPHY_CFG_REG, 11), + SUNXI_CCU_GATE(H3_CLK_USBOHCI0, "usb-ohci0", "hosc", + USBPHY_CFG_REG, 16), + SUNXI_CCU_GATE(H3_CLK_USBOHCI1, "usb-ohci1", "hosc", + USBPHY_CFG_REG, 17), + SUNXI_CCU_GATE(H3_CLK_USBOHCI2, "usb-ohci2", "hosc", + USBPHY_CFG_REG, 18), + SUNXI_CCU_GATE(H3_CLK_USBOHCI3, "usb-ohci3", "hosc", + USBPHY_CFG_REG, 19), +}; + +static void +sun8i_h3_ccu_init(struct sunxi_ccu_softc *sc) +{ + uint32_t val; + + /* Set AHB2 source to PLL_PERIPH/2 */ + val = CCU_READ(sc, AHB2_CFG_REG); + val &= ~AHB2_CLK_CFG; + val |= __SHIFTIN(AHB2_CLK_CFG_PLL_PERIPH0_2, AHB2_CLK_CFG); + CCU_WRITE(sc, AHB2_CFG_REG, val); +} + +static int +sun8i_h3_ccu_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sun8i_h3_ccu_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_ccu_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + + sc->sc_dev = self; + sc->sc_phandle = faa->faa_phandle; + sc->sc_bst = faa->faa_bst; + + sc->sc_resets = sun8i_h3_ccu_resets; + sc->sc_nresets = __arraycount(sun8i_h3_ccu_resets); + + sc->sc_clks = sun8i_h3_ccu_clks; + sc->sc_nclks = __arraycount(sun8i_h3_ccu_clks); + + if (sunxi_ccu_attach(sc) != 0) + return; + + aprint_naive("\n"); + aprint_normal(": H3 CCU\n"); + + sun8i_h3_ccu_init(sc); + + sunxi_ccu_print(sc); +} diff --git a/sys/arch/arm/sunxi/sun8i_h3_ccu.h b/sys/arch/arm/sunxi/sun8i_h3_ccu.h new file mode 100644 index 000000000000..3b722608034b --- /dev/null +++ b/sys/arch/arm/sunxi/sun8i_h3_ccu.h @@ -0,0 +1,205 @@ +/* $NetBSD: sun8i_h3_ccu.h,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Emmanuel Vadot + * 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 __CCU_H3_H__ +#define __CCU_H3_H__ + +#define H3_RST_USB_PHY0 0 +#define H3_RST_USB_PHY1 1 +#define H3_RST_USB_PHY2 2 +#define H3_RST_USB_PHY3 3 +#define H3_RST_MBUS 4 +#define H3_RST_BUS_CE 5 +#define H3_RST_BUS_DMA 6 +#define H3_RST_BUS_MMC0 7 +#define H3_RST_BUS_MMC1 8 +#define H3_RST_BUS_MMC2 9 +#define H3_RST_BUS_NAND 10 +#define H3_RST_BUS_DRAM 11 +#define H3_RST_BUS_EMAC 12 +#define H3_RST_BUS_TS 13 +#define H3_RST_BUS_HSTIMER 14 +#define H3_RST_BUS_SPI0 15 +#define H3_RST_BUS_SPI1 16 +#define H3_RST_BUS_OTG 17 +#define H3_RST_BUS_EHCI0 18 +#define H3_RST_BUS_EHCI1 19 +#define H3_RST_BUS_EHCI2 20 +#define H3_RST_BUS_EHCI3 21 +#define H3_RST_BUS_OHCI0 22 +#define H3_RST_BUS_OHCI1 23 +#define H3_RST_BUS_OHCI2 24 +#define H3_RST_BUS_OHCI3 25 +#define H3_RST_BUS_VE 26 +#define H3_RST_BUS_TCON0 27 +#define H3_RST_BUS_TCON1 28 +#define H3_RST_BUS_DEINTERLACE 29 +#define H3_RST_BUS_CSI 30 +#define H3_RST_BUS_TVE 31 +#define H3_RST_BUS_HDMI0 32 +#define H3_RST_BUS_HDMI1 33 +#define H3_RST_BUS_DE 34 +#define H3_RST_BUS_GPU 35 +#define H3_RST_BUS_MSGBOX 36 +#define H3_RST_BUS_SPINLOCK 37 +#define H3_RST_BUS_DBG 38 +#define H3_RST_BUS_EPHY 39 +#define H3_RST_BUS_CODEC 40 +#define H3_RST_BUS_SPDIF 41 +#define H3_RST_BUS_THS 42 +#define H3_RST_BUS_I2S0 43 +#define H3_RST_BUS_I2S1 44 +#define H3_RST_BUS_I2S2 45 +#define H3_RST_BUS_I2C0 46 +#define H3_RST_BUS_I2C1 47 +#define H3_RST_BUS_I2C2 48 +#define H3_RST_BUS_UART0 49 +#define H3_RST_BUS_UART1 50 +#define H3_RST_BUS_UART2 51 +#define H3_RST_BUS_UART3 52 +#define H3_RST_BUS_SCR 53 + +#define H3_CLK_PLL_CPUX 0 +#define H3_CLK_PLL_AUDIO_BASE 1 +#define H3_CLK_PLL_AUDIO 2 +#define H3_CLK_PLL_AUDIO_2X 3 +#define H3_CLK_PLL_AUDIO_4X 4 +#define H3_CLK_PLL_AUDIO_8X 5 +#define H3_CLK_PLL_VIDEO 6 +#define H3_CLK_PLL_VE 7 +#define H3_CLK_PLL_DDR 8 +#define H3_CLK_PLL_PERIPH0 9 +#define H3_CLK_PLL_PERIPH0_2X 10 +#define H3_CLK_PLL_GPU 11 +#define H3_CLK_PLL_PERIPH1 12 +#define H3_CLK_PLL_DE 13 +#define H3_CLK_CPUX 14 +#define H3_CLK_AXI 15 +#define H3_CLK_AHB1 16 +#define H3_CLK_APB1 17 +#define H3_CLK_APB2 18 +#define H3_CLK_AHB2 19 +#define H3_CLK_BUS_CE 20 +#define H3_CLK_BUS_DMA 21 +#define H3_CLK_BUS_MMC0 22 +#define H3_CLK_BUS_MMC1 23 +#define H3_CLK_BUS_MMC2 24 +#define H3_CLK_BUS_NAND 25 +#define H3_CLK_BUS_DRAM 26 +#define H3_CLK_BUS_EMAC 27 +#define H3_CLK_BUS_TS 28 +#define H3_CLK_BUS_HSTIMER 29 +#define H3_CLK_BUS_SPI0 30 +#define H3_CLK_BUS_SPI1 31 +#define H3_CLK_BUS_OTG 32 +#define H3_CLK_BUS_EHCI0 33 +#define H3_CLK_BUS_EHCI1 34 +#define H3_CLK_BUS_EHCI2 35 +#define H3_CLK_BUS_EHCI3 36 +#define H3_CLK_BUS_OHCI0 37 +#define H3_CLK_BUS_OHCI1 38 +#define H3_CLK_BUS_OHCI2 39 +#define H3_CLK_BUS_OHCI3 40 +#define H3_CLK_BUS_VE 41 +#define H3_CLK_BUS_TCON0 42 +#define H3_CLK_BUS_TCON1 43 +#define H3_CLK_BUS_DEINTERLACE 44 +#define H3_CLK_BUS_CSI 45 +#define H3_CLK_BUS_TVE 46 +#define H3_CLK_BUS_HDMI 47 +#define H3_CLK_BUS_DE 48 +#define H3_CLK_BUS_GPU 49 +#define H3_CLK_BUS_MSGBOX 50 +#define H3_CLK_BUS_SPINLOCK 51 +#define H3_CLK_BUS_CODEC 52 +#define H3_CLK_BUS_SPDIF 53 +#define H3_CLK_BUS_PIO 54 +#define H3_CLK_BUS_THS 55 +#define H3_CLK_BUS_I2S0 56 +#define H3_CLK_BUS_I2S1 57 +#define H3_CLK_BUS_I2S2 58 +#define H3_CLK_BUS_I2C0 59 +#define H3_CLK_BUS_I2C1 60 +#define H3_CLK_BUS_I2C2 61 +#define H3_CLK_BUS_UART0 62 +#define H3_CLK_BUS_UART1 63 +#define H3_CLK_BUS_UART2 64 +#define H3_CLK_BUS_UART3 65 +#define H3_CLK_BUS_SCR 66 +#define H3_CLK_BUS_EPHY 67 +#define H3_CLK_BUS_DBG 68 +#define H3_CLK_THS 69 +#define H3_CLK_NAND 70 +#define H3_CLK_MMC0 71 +#define H3_CLK_MMC0_SAMPLE 72 +#define H3_CLK_MMC0_OUTPUT 73 +#define H3_CLK_MMC1 74 +#define H3_CLK_MMC1_SAMPLE 75 +#define H3_CLK_MMC1_OUTPUT 76 +#define H3_CLK_MMC2 77 +#define H3_CLK_MMC2_SAMPLE 78 +#define H3_CLK_MMC2_OUTPUT 79 +#define H3_CLK_TS 80 +#define H3_CLK_CE 81 +#define H3_CLK_SPI0 82 +#define H3_CLK_SPI1 83 +#define H3_CLK_I2S0 84 +#define H3_CLK_I2S1 85 +#define H3_CLK_I2S2 86 +#define H3_CLK_SPDIF 87 +#define H3_CLK_USBPHY0 88 +#define H3_CLK_USBPHY1 89 +#define H3_CLK_USBPHY2 90 +#define H3_CLK_USBPHY3 91 +#define H3_CLK_USBOHCI0 92 +#define H3_CLK_USBOHCI1 93 +#define H3_CLK_USBOHCI2 94 +#define H3_CLK_USBOHCI3 95 +#define H3_CLK_DRAM 96 +#define H3_CLK_DRAM_VE 97 +#define H3_CLK_DRAM_CSI 98 +#define H3_CLK_DRAM_DEINTERLACE 99 +#define H3_CLK_DRAM_TS 100 +#define H3_CLK_DE 101 +#define H3_CLK_TCON0 102 +#define H3_CLK_TVE 103 +#define H3_CLK_DEINTERLACE 104 +#define H3_CLK_CSI_MISC 105 +#define H3_CLK_CSI_SCLK 106 +#define H3_CLK_CSI_MCLK 107 +#define H3_CLK_VE 108 +#define H3_CLK_AC_DIG 109 +#define H3_CLK_AVS 110 +#define H3_CLK_HDMI 111 +#define H3_CLK_HDMI_DDC 112 +#define H3_CLK_MBUS 113 +#define H3_CLK_GPU 114 + +#endif /* __CCU_H3_H__ */ diff --git a/sys/arch/arm/sunxi/sun8i_h3_gpio.c b/sys/arch/arm/sunxi/sun8i_h3_gpio.c new file mode 100644 index 000000000000..4a81c5a9c15e --- /dev/null +++ b/sys/arch/arm/sunxi/sun8i_h3_gpio.c @@ -0,0 +1,165 @@ +/* $NetBSD: sun8i_h3_gpio.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2016 Emmanuel Vadot + * 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 +__KERNEL_RCSID(0, "$NetBSD: sun8i_h3_gpio.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include + +#include + +static const struct sunxi_gpio_pins h3_pins[] = { + {"PA0", 0, 0, {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint0", NULL}, 6, 0}, + {"PA1", 0, 1, {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint1", NULL}, 6, 1}, + {"PA2", 0, 2, {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint2", NULL}, 6, 2}, + {"PA3", 0, 3, {"gpio_in", "gpio_out", "uart2", "jtag", NULL, NULL, "pa_eint3", NULL}, 6, 3}, + {"PA4", 0, 4, {"gpio_in", "gpio_out", "uart0", NULL, NULL, NULL, "pa_eint4", NULL}, 6, 4}, + {"PA5", 0, 5, {"gpio_in", "gpio_out", "uart0", "pwm0", NULL, NULL, "pa_eint5", NULL}, 6, 5}, + {"PA6", 0, 6, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint6", NULL}, 6, 6}, + {"PA7", 0, 7, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint7", NULL}, 6, 7}, + {"PA8", 0, 8, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint8", NULL}, 6, 8}, + {"PA9", 0, 9, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint9", NULL}, 6, 9}, + {"PA10", 0, 10, {"gpio_in", "gpio_out", "sim", NULL, NULL, NULL, "pa_eint10", NULL}, 6, 10}, + {"PA11", 0, 11, {"gpio_in", "gpio_out", "i2c0", "di", NULL, NULL, "pa_eint11", NULL}, 6, 11}, + {"PA12", 0, 12, {"gpio_in", "gpio_out", "i2c0", "di", NULL, NULL, "pa_eint12", NULL}, 6, 12}, + {"PA13", 0, 13, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint13", NULL}, 6, 13}, + {"PA14", 0, 14, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint14", NULL}, 6, 14}, + {"PA15", 0, 15, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint15", NULL}, 6, 15}, + {"PA16", 0, 16, {"gpio_in", "gpio_out", "spi1", "uart3", NULL, NULL, "pa_eint16", NULL}, 6, 16}, + {"PA17", 0, 17, {"gpio_in", "gpio_out", "spdif", NULL, NULL, NULL, "pa_eint17", NULL}, 6, 17}, + {"PA18", 0, 18, {"gpio_in", "gpio_out", "i2s0", "i2c1", NULL, NULL, "pa_eint18", NULL}, 6, 18}, + {"PA19", 0, 19, {"gpio_in", "gpio_out", "i2s0", "i2c1", NULL, NULL, "pa_eint19", NULL}, 6, 19}, + {"PA20", 0, 20, {"gpio_in", "gpio_out", "i2s0", "sim", NULL, NULL, "pa_eint20", NULL}, 6, 20}, + {"PA21", 0, 21, {"gpio_in", "gpio_out", "i2s0", "sim", NULL, NULL, "pa_eint21", NULL}, 6, 21}, + + {"PC0", 2, 0, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, + {"PC1", 2, 1, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, + {"PC2", 2, 2, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, + {"PC3", 2, 3, {"gpio_in", "gpio_out", "nand", "spi0", NULL, NULL, NULL, NULL}}, + {"PC4", 2, 4, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, + {"PC5", 2, 5, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC6", 2, 6, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC7", 2, 7, {"gpio_in", "gpio_out", "nand", NULL, NULL, NULL, NULL, NULL}}, + {"PC8", 2, 8, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC9", 2, 9, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC10", 2, 10, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC11", 2, 11, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC12", 2, 12, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC13", 2, 13, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC14", 2, 14, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC15", 2, 15, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + {"PC16", 2, 16, {"gpio_in", "gpio_out", "nand", "mmc2", NULL, NULL, NULL, NULL}}, + + {"PD0", 3, 0, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD1", 3, 1, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD2", 3, 2, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD3", 3, 3, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD4", 3, 4, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD5", 3, 5, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD6", 3, 6, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD7", 3, 7, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD8", 3, 8, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD9", 3, 9, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD10", 3, 10, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD11", 3, 11, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD12", 3, 12, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD13", 3, 13, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD14", 3, 14, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD15", 3, 15, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD16", 3, 16, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + {"PD17", 3, 17, {"gpio_in", "gpio_out", "emac", NULL, NULL, NULL, NULL, NULL}}, + + {"PE0", 4, 0, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE1", 4, 1, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE2", 4, 2, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE3", 4, 3, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE4", 4, 4, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE5", 4, 5, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE6", 4, 6, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE7", 4, 7, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE8", 4, 8, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE9", 4, 9, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE10", 4, 10, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE11", 4, 11, {"gpio_in", "gpio_out", "csi", "ts", NULL, NULL, NULL, NULL}}, + {"PE12", 4, 12, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}}, + {"PE13", 4, 13, {"gpio_in", "gpio_out", "csi", "i2c2", NULL, NULL, NULL, NULL}}, + {"PE14", 4, 14, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + {"PE15", 4, 15, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + + {"PF0", 5, 0, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}}, + {"PF1", 5, 1, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}}, + {"PF2", 5, 2, {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL, NULL}}, + {"PF3", 5, 3, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}}, + {"PF4", 5, 4, {"gpio_in", "gpio_out", "mmc0", "uart0", NULL, NULL, NULL, NULL}}, + {"PF5", 5, 5, {"gpio_in", "gpio_out", "mmc0", "jtag", NULL, NULL, NULL, NULL}}, + {"PF6", 5, 6, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, NULL, NULL}}, + + {"PG0", 6, 0, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint0", NULL}, 6, 0}, + {"PG1", 6, 1, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint1", NULL}, 6, 1}, + {"PG2", 6, 2, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint2", NULL}, 6, 2}, + {"PG3", 6, 3, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint3", NULL}, 6, 3}, + {"PG4", 6, 4, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint4", NULL}, 6, 4}, + {"PG5", 6, 5, {"gpio_in", "gpio_out", "mmc1", NULL, NULL, NULL, "pg_eint5", NULL}, 6, 5}, + {"PG6", 6, 6, {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint6", NULL}, 6, 6}, + {"PG7", 6, 7, {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint7", NULL}, 6, 7}, + {"PG8", 6, 8, {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint8", NULL}, 6, 8}, + {"PG9", 6, 9, {"gpio_in", "gpio_out", "uart1", NULL, NULL, NULL, "pg_eint9", NULL}, 6, 9}, + {"PG10", 6, 10, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint10", NULL}, 6, 10}, + {"PG11", 6, 11, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint11", NULL}, 6, 11}, + {"PG12", 6, 12, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint12", NULL}, 6, 12}, + {"PG13", 6, 13, {"gpio_in", "gpio_out", "i2s1", NULL, NULL, NULL, "pg_eint13", NULL}, 6, 13}, +}; + +static const struct sunxi_gpio_pins h3_r_pins[] = { + {"PL0", 0, 0, {"gpio_in", "gpio_out", "s_twi", NULL, NULL, NULL, "pl_eint0", NULL}, 6, 0}, + {"PL1", 0, 1, {"gpio_in", "gpio_out", "s_twi", NULL, NULL, NULL, "pl_eint1", NULL}, 6, 1}, + {"PL2", 0, 2, {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "pl_eint2", NULL}, 6, 2}, + {"PL3", 0, 3, {"gpio_in", "gpio_out", "s_uart", NULL, NULL, NULL, "pl_eint3", NULL}, 6, 3}, + {"PL4", 0, 4, {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "pl_eint4", NULL}, 6, 4}, + {"PL5", 0, 5, {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "pl_eint5", NULL}, 6, 5}, + {"PL6", 0, 6, {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "pl_eint6", NULL}, 6, 6}, + {"PL7", 0, 7, {"gpio_in", "gpio_out", "s_jtag", NULL, NULL, NULL, "pl_eint7", NULL}, 6, 7}, + {"PL8", 0, 8, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "pl_eint8", NULL}, 6, 8}, + {"PL9", 0, 9, {"gpio_in", "gpio_out", NULL, NULL, NULL, NULL, "pl_eint9", NULL}, 6, 9}, + {"PL10", 0, 10, {"gpio_in", "gpio_out", "s_pwm", NULL, NULL, NULL, "pl_eint10", NULL}, 6, 10}, + {"PL11", 0, 11, {"gpio_in", "gpio_out", "s_cir_rx", NULL, NULL, NULL, "pl_eint11", NULL}, 6, 11}, +}; + +const struct sunxi_gpio_padconf sun8i_h3_padconf = { + .npins = __arraycount(h3_pins), + .pins = h3_pins, +}; + +const struct sunxi_gpio_padconf sun8i_h3_r_padconf = { + .npins = __arraycount(h3_r_pins), + .pins = h3_r_pins, +}; diff --git a/sys/arch/arm/sunxi/sunxi_ccu.c b/sys/arch/arm/sunxi/sunxi_ccu.c new file mode 100644 index 000000000000..e5d37050e973 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_ccu.c @@ -0,0 +1,344 @@ +/* $NetBSD: sunxi_ccu.c,v 1.6.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include "opt_soc.h" +#include "opt_multiprocessor.h" +#include "opt_fdt_arm.h" + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_ccu.c,v 1.6.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include + +#include + +#include + +#include + +static void * +sunxi_ccu_reset_acquire(device_t dev, const void *data, size_t len) +{ + struct sunxi_ccu_softc * const sc = device_private(dev); + struct sunxi_ccu_reset *reset; + + if (len != 4) + return NULL; + + const u_int reset_id = be32dec(data); + + if (reset_id >= sc->sc_nresets) + return NULL; + + reset = &sc->sc_resets[reset_id]; + if (reset->mask == 0) + return NULL; + + return reset; +} + +static void +sunxi_ccu_reset_release(device_t dev, void *priv) +{ +} + +static int +sunxi_ccu_reset_assert(device_t dev, void *priv) +{ + struct sunxi_ccu_softc * const sc = device_private(dev); + struct sunxi_ccu_reset * const reset = priv; + + const uint32_t val = CCU_READ(sc, reset->reg); + CCU_WRITE(sc, reset->reg, val & ~reset->mask); + + return 0; +} + +static int +sunxi_ccu_reset_deassert(device_t dev, void *priv) +{ + struct sunxi_ccu_softc * const sc = device_private(dev); + struct sunxi_ccu_reset * const reset = priv; + + const uint32_t val = CCU_READ(sc, reset->reg); + CCU_WRITE(sc, reset->reg, val | reset->mask); + + return 0; +} + +static const struct fdtbus_reset_controller_func sunxi_ccu_fdtreset_funcs = { + .acquire = sunxi_ccu_reset_acquire, + .release = sunxi_ccu_reset_release, + .reset_assert = sunxi_ccu_reset_assert, + .reset_deassert = sunxi_ccu_reset_deassert, +}; + +static struct clk * +sunxi_ccu_clock_decode(device_t dev, const void *data, size_t len) +{ + struct sunxi_ccu_softc * const sc = device_private(dev); + struct sunxi_ccu_clk *clk; + + if (len != 4) + return NULL; + + const u_int clock_id = be32dec(data); + if (clock_id >= sc->sc_nclks) + return NULL; + + clk = &sc->sc_clks[clock_id]; + if (clk->type == SUNXI_CCU_UNKNOWN) + return NULL; + + return &clk->base; +} + +static const struct fdtbus_clock_controller_func sunxi_ccu_fdtclock_funcs = { + .decode = sunxi_ccu_clock_decode, +}; + +static struct clk * +sunxi_ccu_clock_get(void *priv, const char *name) +{ + struct sunxi_ccu_softc * const sc = priv; + struct sunxi_ccu_clk *clk; + + clk = sunxi_ccu_clock_find(sc, name); + if (clk == NULL) + return NULL; + + return &clk->base; +} + +static void +sunxi_ccu_clock_put(void *priv, struct clk *clk) +{ +} + +static u_int +sunxi_ccu_clock_get_rate(void *priv, struct clk *clkp) +{ + struct sunxi_ccu_softc * const sc = priv; + struct sunxi_ccu_clk *clk = (struct sunxi_ccu_clk *)clkp; + struct clk *clkp_parent; + + if (clk->get_rate) + return clk->get_rate(sc, clk); + + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) { + aprint_error("%s: no parent for %s\n", __func__, clk->base.name); + return 0; + } + + return clk_get_rate(clkp_parent); +} + +static int +sunxi_ccu_clock_set_rate(void *priv, struct clk *clkp, u_int rate) +{ + struct sunxi_ccu_softc * const sc = priv; + struct sunxi_ccu_clk *clk = (struct sunxi_ccu_clk *)clkp; + struct clk *clkp_parent; + + if (clkp->flags & CLK_SET_RATE_PARENT) { + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) { + aprint_error("%s: no parent for %s\n", __func__, clk->base.name); + return ENXIO; + } + return clk_set_rate(clkp_parent, rate); + } + + if (clk->set_rate) + return clk->set_rate(sc, clk, rate); + + return ENXIO; +} + +static int +sunxi_ccu_clock_enable(void *priv, struct clk *clkp) +{ + struct sunxi_ccu_softc * const sc = priv; + struct sunxi_ccu_clk *clk = (struct sunxi_ccu_clk *)clkp; + struct clk *clkp_parent; + int error = 0; + + clkp_parent = clk_get_parent(clkp); + if (clkp_parent != NULL) { + error = clk_enable(clkp_parent); + if (error != 0) + return error; + } + + if (clk->enable) + error = clk->enable(sc, clk, 1); + + return error; +} + +static int +sunxi_ccu_clock_disable(void *priv, struct clk *clkp) +{ + struct sunxi_ccu_softc * const sc = priv; + struct sunxi_ccu_clk *clk = (struct sunxi_ccu_clk *)clkp; + int error = EINVAL; + + if (clk->enable) + error = clk->enable(sc, clk, 0); + + return error; +} + +static int +sunxi_ccu_clock_set_parent(void *priv, struct clk *clkp, + struct clk *clkp_parent) +{ + struct sunxi_ccu_softc * const sc = priv; + struct sunxi_ccu_clk *clk = (struct sunxi_ccu_clk *)clkp; + + if (clk->set_parent == NULL) + return EINVAL; + + return clk->set_parent(sc, clk, clkp_parent->name); +} + +static struct clk * +sunxi_ccu_clock_get_parent(void *priv, struct clk *clkp) +{ + struct sunxi_ccu_softc * const sc = priv; + struct sunxi_ccu_clk *clk = (struct sunxi_ccu_clk *)clkp; + struct sunxi_ccu_clk *clk_parent; + const char *parent; + + if (clk->get_parent == NULL) + return NULL; + + parent = clk->get_parent(sc, clk); + if (parent == NULL) + return NULL; + + clk_parent = sunxi_ccu_clock_find(sc, parent); + if (clk_parent != NULL) + return &clk_parent->base; + + /* No parent in this domain, try FDT */ + return fdtbus_clock_get(sc->sc_phandle, parent); +} + +static const struct clk_funcs sunxi_ccu_clock_funcs = { + .get = sunxi_ccu_clock_get, + .put = sunxi_ccu_clock_put, + .get_rate = sunxi_ccu_clock_get_rate, + .set_rate = sunxi_ccu_clock_set_rate, + .enable = sunxi_ccu_clock_enable, + .disable = sunxi_ccu_clock_disable, + .set_parent = sunxi_ccu_clock_set_parent, + .get_parent = sunxi_ccu_clock_get_parent, +}; + +struct sunxi_ccu_clk * +sunxi_ccu_clock_find(struct sunxi_ccu_softc *sc, const char *name) +{ + for (int i = 0; i < sc->sc_nclks; i++) { + if (sc->sc_clks[i].base.name == NULL) + continue; + if (strcmp(sc->sc_clks[i].base.name, name) == 0) + return &sc->sc_clks[i]; + } + + return NULL; +} + +int +sunxi_ccu_attach(struct sunxi_ccu_softc *sc) +{ + bus_addr_t addr; + bus_size_t size; + int i; + + if (fdtbus_get_reg(sc->sc_phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return ENXIO; + } + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return ENXIO; + } + + sc->sc_clkdom.funcs = &sunxi_ccu_clock_funcs; + sc->sc_clkdom.priv = sc; + for (i = 0; i < sc->sc_nclks; i++) + sc->sc_clks[i].base.domain = &sc->sc_clkdom; + + fdtbus_register_clock_controller(sc->sc_dev, sc->sc_phandle, + &sunxi_ccu_fdtclock_funcs); + + fdtbus_register_reset_controller(sc->sc_dev, sc->sc_phandle, + &sunxi_ccu_fdtreset_funcs); + + return 0; +} + +void +sunxi_ccu_print(struct sunxi_ccu_softc *sc) +{ + struct sunxi_ccu_clk *clk; + struct clk *clkp_parent; + const char *type; + int i; + + for (i = 0; i < sc->sc_nclks; i++) { + clk = &sc->sc_clks[i]; + if (clk->type == SUNXI_CCU_UNKNOWN) + continue; + + clkp_parent = clk_get_parent(&clk->base); + + switch (clk->type) { + case SUNXI_CCU_GATE: type = "gate"; break; + case SUNXI_CCU_NM: type = "nm"; break; + case SUNXI_CCU_NKMP: type = "nkmp"; break; + case SUNXI_CCU_PREDIV: type = "prediv"; break; + case SUNXI_CCU_DIV: type = "div"; break; + default: type = "???"; break; + } + + aprint_debug_dev(sc->sc_dev, + "%3d %-12s %2s %-12s %-7s ", + i, + clk->base.name, + clkp_parent ? "<-" : "", + clkp_parent ? clkp_parent->name : "", + type); + aprint_debug("%10d Hz\n", clk_get_rate(&clk->base)); + } +} diff --git a/sys/arch/arm/sunxi/sunxi_ccu.h b/sys/arch/arm/sunxi/sunxi_ccu.h new file mode 100644 index 000000000000..f357ca1fa5ab --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_ccu.h @@ -0,0 +1,304 @@ +/* $NetBSD: sunxi_ccu.h,v 1.7.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#ifndef _ARM_SUNXI_CCU_H +#define _ARM_SUNXI_CCU_H + +#include + +struct sunxi_ccu_softc; +struct sunxi_ccu_clk; +struct sunxi_ccu_reset; + +/* + * Resets + */ + +struct sunxi_ccu_reset { + bus_size_t reg; + uint32_t mask; +}; + +#define SUNXI_CCU_RESET(_id, _reg, _bit) \ + [_id] = { \ + .reg = (_reg), \ + .mask = __BIT(_bit), \ + } + +/* + * Clocks + */ + +enum sunxi_ccu_clktype { + SUNXI_CCU_UNKNOWN, + SUNXI_CCU_GATE, + SUNXI_CCU_NM, + SUNXI_CCU_NKMP, + SUNXI_CCU_PREDIV, + SUNXI_CCU_DIV, +}; + +struct sunxi_ccu_gate { + bus_size_t reg; + uint32_t mask; + const char *parent; +}; + +int sunxi_ccu_gate_enable(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, int); +const char *sunxi_ccu_gate_get_parent(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); + +#define SUNXI_CCU_GATE(_id, _name, _pname, _reg, _bit) \ + [_id] = { \ + .type = SUNXI_CCU_GATE, \ + .base.name = (_name), \ + .u.gate.parent = (_pname), \ + .u.gate.reg = (_reg), \ + .u.gate.mask = __BIT(_bit), \ + .enable = sunxi_ccu_gate_enable, \ + .get_parent = sunxi_ccu_gate_get_parent, \ + } + +struct sunxi_ccu_nkmp { + bus_size_t reg; + const char *parent; + uint32_t n; + uint32_t k; + uint32_t m; + uint32_t p; + uint32_t lock; + uint32_t enable; + uint32_t flags; +#define SUNXI_CCU_NKMP_DIVIDE_BY_TWO __BIT(0) +#define SUNXI_CCU_NKMP_FACTOR_N_EXACT __BIT(1) +}; + +int sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, int); +u_int sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); +int sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, u_int); +const char *sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); + +#define SUNXI_CCU_NKMP(_id, _name, _parent, _reg, _n, _k, _m, \ + _p, _enable, _flags) \ + [_id] = { \ + .type = SUNXI_CCU_NKMP, \ + .base.name = (_name), \ + .u.nkmp.reg = (_reg), \ + .u.nkmp.parent = (_parent), \ + .u.nkmp.n = (_n), \ + .u.nkmp.k = (_k), \ + .u.nkmp.m = (_m), \ + .u.nkmp.p = (_p), \ + .u.nkmp.enable = (_enable), \ + .u.nkmp.flags = (_flags), \ + .enable = sunxi_ccu_nkmp_enable, \ + .get_rate = sunxi_ccu_nkmp_get_rate, \ + .set_rate = sunxi_ccu_nkmp_set_rate, \ + .get_parent = sunxi_ccu_nkmp_get_parent, \ + } + +struct sunxi_ccu_nm { + bus_size_t reg; + const char **parents; + u_int nparents; + uint32_t n; + uint32_t m; + uint32_t sel; + uint32_t enable; + uint32_t flags; +#define SUNXI_CCU_NM_POWER_OF_TWO __BIT(0) +#define SUNXI_CCU_NM_ROUND_DOWN __BIT(1) +}; + +int sunxi_ccu_nm_enable(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, int); +u_int sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); +int sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, u_int); +int sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, + const char *); +const char *sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); + +#define SUNXI_CCU_NM(_id, _name, _parents, _reg, _n, _m, _sel, \ + _enable, _flags) \ + [_id] = { \ + .type = SUNXI_CCU_NM, \ + .base.name = (_name), \ + .u.nm.reg = (_reg), \ + .u.nm.parents = (_parents), \ + .u.nm.nparents = __arraycount(_parents), \ + .u.nm.n = (_n), \ + .u.nm.m = (_m), \ + .u.nm.sel = (_sel), \ + .u.nm.enable = (_enable), \ + .u.nm.flags = (_flags), \ + .enable = sunxi_ccu_nm_enable, \ + .get_rate = sunxi_ccu_nm_get_rate, \ + .set_rate = sunxi_ccu_nm_set_rate, \ + .set_parent = sunxi_ccu_nm_set_parent, \ + .get_parent = sunxi_ccu_nm_get_parent, \ + } + +struct sunxi_ccu_div { + bus_size_t reg; + const char **parents; + u_int nparents; + uint32_t div; + uint32_t sel; + uint32_t flags; +#define SUNXI_CCU_DIV_POWER_OF_TWO __BIT(0) +#define SUNXI_CCU_DIV_ZERO_IS_ONE __BIT(1) +}; + +u_int sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); +int sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, u_int); +int sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, + const char *); +const char *sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); + +#define SUNXI_CCU_DIV(_id, _name, _parents, _reg, _div, \ + _sel, _flags) \ + [_id] = { \ + .type = SUNXI_CCU_DIV, \ + .base.name = (_name), \ + .u.div.reg = (_reg), \ + .u.div.parents = (_parents), \ + .u.div.nparents = __arraycount(_parents), \ + .u.div.div = (_div), \ + .u.div.sel = (_sel), \ + .u.div.flags = (_flags), \ + .get_rate = sunxi_ccu_div_get_rate, \ + .set_rate = sunxi_ccu_div_set_rate, \ + .set_parent = sunxi_ccu_div_set_parent, \ + .get_parent = sunxi_ccu_div_get_parent, \ + } + +struct sunxi_ccu_prediv { + bus_size_t reg; + const char **parents; + u_int nparents; + uint32_t prediv; + uint32_t prediv_sel; + uint32_t div; + uint32_t sel; + uint32_t flags; +#define SUNXI_CCU_PREDIV_POWER_OF_TWO __BIT(0) +#define SUNXI_CCU_PREDIV_DIVIDE_BY_TWO __BIT(1) +}; + +u_int sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); +int sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, u_int); +int sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, + const char *); +const char *sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); + +#define SUNXI_CCU_PREDIV(_id, _name, _parents, _reg, _prediv, \ + _prediv_sel, _div, _sel, _flags) \ + [_id] = { \ + .type = SUNXI_CCU_PREDIV, \ + .base.name = (_name), \ + .u.prediv.reg = (_reg), \ + .u.prediv.parents = (_parents), \ + .u.prediv.nparents = __arraycount(_parents), \ + .u.prediv.prediv = (_prediv), \ + .u.prediv.prediv_sel = (_prediv_sel), \ + .u.prediv.div = (_div), \ + .u.prediv.sel = (_sel), \ + .u.prediv.flags = (_flags), \ + .get_rate = sunxi_ccu_prediv_get_rate, \ + .set_rate = sunxi_ccu_prediv_set_rate, \ + .set_parent = sunxi_ccu_prediv_set_parent, \ + .get_parent = sunxi_ccu_prediv_get_parent, \ + } + +struct sunxi_ccu_clk { + struct clk base; + enum sunxi_ccu_clktype type; + union { + struct sunxi_ccu_gate gate; + struct sunxi_ccu_nm nm; + struct sunxi_ccu_nkmp nkmp; + struct sunxi_ccu_prediv prediv; + struct sunxi_ccu_div div; + } u; + + int (*enable)(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, int); + u_int (*get_rate)(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); + int (*set_rate)(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, u_int); + const char * (*get_parent)(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *); + int (*set_parent)(struct sunxi_ccu_softc *, + struct sunxi_ccu_clk *, + const char *); +}; + +struct sunxi_ccu_softc { + device_t sc_dev; + int sc_phandle; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + + struct clk_domain sc_clkdom; + + struct sunxi_ccu_reset *sc_resets; + u_int sc_nresets; + + struct sunxi_ccu_clk *sc_clks; + u_int sc_nclks; +}; + +int sunxi_ccu_attach(struct sunxi_ccu_softc *); +struct sunxi_ccu_clk *sunxi_ccu_clock_find(struct sunxi_ccu_softc *, + const char *); +void sunxi_ccu_print(struct sunxi_ccu_softc *); + +#define CCU_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define CCU_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +#endif /* _ARM_SUNXI_CCU_H */ diff --git a/sys/arch/arm/sunxi/sunxi_ccu_div.c b/sys/arch/arm/sunxi/sunxi_ccu_div.c new file mode 100644 index 000000000000..e1805d43b0c3 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_ccu_div.c @@ -0,0 +1,124 @@ +/* $NetBSD: sunxi_ccu_div.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_ccu_div.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include + +#include + +#include + +u_int +sunxi_ccu_div_get_rate(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk) +{ + struct sunxi_ccu_div *div = &clk->u.div; + struct clk *clkp, *clkp_parent; + u_int rate, ratio; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_DIV); + + clkp = &clk->base; + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) + return 0; + + rate = clk_get_rate(clkp_parent); + if (rate == 0) + return 0; + + val = CCU_READ(sc, div->reg); + ratio = __SHIFTOUT(val, div->div); + if ((div->flags & SUNXI_CCU_DIV_ZERO_IS_ONE) != 0 && ratio == 0) + ratio = 1; + if (div->flags & SUNXI_CCU_DIV_POWER_OF_TWO) + ratio = 1 << ratio; + else + ratio++; + + return rate / ratio; +} + +int +sunxi_ccu_div_set_rate(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk, u_int new_rate) +{ + return EINVAL; +} + +int +sunxi_ccu_div_set_parent(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk, const char *name) +{ + struct sunxi_ccu_div *div = &clk->u.div; + uint32_t val; + u_int index; + + KASSERT(clk->type == SUNXI_CCU_DIV); + + if (div->sel == 0) + return ENODEV; + + for (index = 0; index < div->nparents; index++) { + if (div->parents[index] != NULL && + strcmp(div->parents[index], name) == 0) + break; + } + if (index == div->nparents) + return EINVAL; + + val = CCU_READ(sc, div->reg); + val &= ~div->sel; + val |= __SHIFTIN(index, div->sel); + CCU_WRITE(sc, div->reg, val); + + return 0; +} + +const char * +sunxi_ccu_div_get_parent(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk) +{ + struct sunxi_ccu_div *div = &clk->u.div; + u_int index; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_DIV); + + if (div->sel == 0) + return div->parents[0]; + + val = CCU_READ(sc, div->reg); + index = __SHIFTOUT(val, div->sel); + + return div->parents[index]; +} diff --git a/sys/arch/arm/samsung/exynos_fdt.c b/sys/arch/arm/sunxi/sunxi_ccu_gate.c similarity index 53% rename from sys/arch/arm/samsung/exynos_fdt.c rename to sys/arch/arm/sunxi/sunxi_ccu_gate.c index 7ba4c00f3492..4c5255cd494f 100644 --- a/sys/arch/arm/samsung/exynos_fdt.c +++ b/sys/arch/arm/sunxi/sunxi_ccu_gate.c @@ -1,7 +1,7 @@ -/* $NetBSD: exynos_fdt.c,v 1.4 2017/04/16 15:52:16 jmcneill Exp $ */ +/* $NetBSD: sunxi_ccu_gate.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $ */ /*- - * Copyright (c) 2015 Jared D. McNeill + * Copyright (c) 2017 Jared McNeill * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,55 +26,41 @@ * SUCH DAMAGE. */ -#include "opt_exynos.h" - #include -__KERNEL_RCSID(0, "$NetBSD: exynos_fdt.c,v 1.4 2017/04/16 15:52:16 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sunxi_ccu_gate.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $"); #include -#include -#include - -#include #include -#include -#include -#include +#include -#include -#include - -static int exynosfdt_match(device_t, cfdata_t, void *); -static void exynosfdt_attach(device_t, device_t, void *); - -CFATTACH_DECL_NEW(exynos_fdt, 0, - exynosfdt_match, exynosfdt_attach, NULL, NULL); - -static bool exynosfdt_found = false; +#include int -exynosfdt_match(device_t parent, cfdata_t cf, void *aux) +sunxi_ccu_gate_enable(struct sunxi_ccu_softc *sc, struct sunxi_ccu_clk *clk, + int enable) { - if (exynosfdt_found) - return 0; - return 1; + struct sunxi_ccu_gate *gate = &clk->u.gate; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_GATE); + + val = CCU_READ(sc, gate->reg); + if (enable) + val |= gate->mask; + else + val &= ~gate->mask; + CCU_WRITE(sc, gate->reg, val); + + return 0; } -void -exynosfdt_attach(device_t parent, device_t self, void *aux) +const char * +sunxi_ccu_gate_get_parent(struct sunxi_ccu_softc *sc, struct sunxi_ccu_clk *clk) { - exynosfdt_found = true; + struct sunxi_ccu_gate *gate = &clk->u.gate; - aprint_naive("\n"); - aprint_normal("\n"); + KASSERT(clk->type == SUNXI_CCU_GATE); - struct fdt_attach_args faa = { - .faa_name = "", - .faa_bst = &armv7_generic_bs_tag, - .faa_a4x_bst = &armv7_generic_a4x_bs_tag, - .faa_dmat = &exynos_bus_dma_tag, - .faa_phandle = OF_peer(0), - }; - config_found(self, &faa, NULL); + return gate->parent; } diff --git a/sys/arch/arm/sunxi/sunxi_ccu_nkmp.c b/sys/arch/arm/sunxi/sunxi_ccu_nkmp.c new file mode 100644 index 000000000000..4f3946d91bf0 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_ccu_nkmp.c @@ -0,0 +1,130 @@ +/* $NetBSD: sunxi_ccu_nkmp.c,v 1.4.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_ccu_nkmp.c,v 1.4.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include + +#include + +#include + +int +sunxi_ccu_nkmp_enable(struct sunxi_ccu_softc *sc, struct sunxi_ccu_clk *clk, + int enable) +{ + struct sunxi_ccu_nkmp *nkmp = &clk->u.nkmp; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_NKMP); + + if (!nkmp->enable) + return enable ? 0 : EINVAL; + + val = CCU_READ(sc, nkmp->reg); + if (enable) + val |= nkmp->enable; + else + val &= ~nkmp->enable; + CCU_WRITE(sc, nkmp->reg, val); + + return 0; +} + +u_int +sunxi_ccu_nkmp_get_rate(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk) +{ + struct sunxi_ccu_nkmp *nkmp = &clk->u.nkmp; + struct clk *clkp, *clkp_parent; + u_int rate, n, k, m, p; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_NKMP); + + clkp = &clk->base; + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) + return 0; + + rate = clk_get_rate(clkp_parent); + if (rate == 0) + return 0; + + val = CCU_READ(sc, nkmp->reg); + if (nkmp->n) + n = __SHIFTOUT(val, nkmp->n); + else + n = 0; + if (nkmp->k) + k = __SHIFTOUT(val, nkmp->k); + else + k = 0; + if (nkmp->m) + m = __SHIFTOUT(val, nkmp->m); + else + m = 0; + if (nkmp->p) + p = __SHIFTOUT(val, nkmp->p); + else + p = 0; + + if (nkmp->enable && !(val & nkmp->enable)) + return 0; + + if ((nkmp->flags & SUNXI_CCU_NKMP_FACTOR_N_EXACT) == 0) + n++; + k++; + m++; + p++; + + if (nkmp->flags & SUNXI_CCU_NKMP_DIVIDE_BY_TWO) + m *= 2; + + return (u_int)((uint64_t)rate * n * k) / (m * p); +} + +int +sunxi_ccu_nkmp_set_rate(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk, u_int rate) +{ + return EIO; +} + +const char * +sunxi_ccu_nkmp_get_parent(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk) +{ + struct sunxi_ccu_nkmp *nkmp = &clk->u.nkmp; + + KASSERT(clk->type == SUNXI_CCU_NKMP); + + return nkmp->parent; +} diff --git a/sys/arch/arm/sunxi/sunxi_ccu_nm.c b/sys/arch/arm/sunxi/sunxi_ccu_nm.c new file mode 100644 index 000000000000..c25115ab5734 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_ccu_nm.c @@ -0,0 +1,227 @@ +/* $NetBSD: sunxi_ccu_nm.c,v 1.3.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_ccu_nm.c,v 1.3.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include + +#include + +#include + +int +sunxi_ccu_nm_enable(struct sunxi_ccu_softc *sc, struct sunxi_ccu_clk *clk, + int enable) +{ + struct sunxi_ccu_nm *nm = &clk->u.nm; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_NM); + + if (!nm->enable) + return enable ? 0 : EINVAL; + + val = CCU_READ(sc, nm->reg); + if (enable) + val |= nm->enable; + else + val &= ~nm->enable; + CCU_WRITE(sc, nm->reg, val); + + return 0; +} + +u_int +sunxi_ccu_nm_get_rate(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk) +{ + struct sunxi_ccu_nm *nm = &clk->u.nm; + struct clk *clkp, *clkp_parent; + u_int rate, n, m; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_NM); + + clkp = &clk->base; + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) + return 0; + + rate = clk_get_rate(clkp_parent); + if (rate == 0) + return 0; + + val = CCU_READ(sc, nm->reg); + n = __SHIFTOUT(val, nm->n); + m = __SHIFTOUT(val, nm->m); + + if (nm->enable && !(val & nm->enable)) + return 0; + + if (nm->flags & SUNXI_CCU_NM_POWER_OF_TWO) + n = 1 << n; + else + n++; + + m++; + + return rate / n / m; +} + +int +sunxi_ccu_nm_set_rate(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk, u_int new_rate) +{ + struct sunxi_ccu_nm *nm = &clk->u.nm; + struct clk *clkp, *clkp_parent; + u_int parent_rate, best_rate, best_n, best_m, best_parent; + u_int n, m, pindex, rate; + int best_diff; + uint32_t val; + + const u_int n_max = __SHIFTOUT(nm->n, nm->n); + const u_int m_max = __SHIFTOUT(nm->m, nm->m); + + clkp = &clk->base; + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) + return 0; + + rate = clk_get_rate(clkp_parent); + if (rate == 0) + return 0; + + best_rate = 0; + best_diff = INT_MAX; + for (pindex = 0; pindex < nm->nparents; pindex++) { + /* XXX + * Shouldn't have to set parent to get potential parent clock rate + */ + val = CCU_READ(sc, nm->reg); + val &= ~nm->sel; + val |= __SHIFTIN(pindex, nm->sel); + CCU_WRITE(sc, nm->reg, val); + + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) + continue; + parent_rate = clk_get_rate(clkp_parent); + if (parent_rate == 0) + continue; + + for (n = 0; n <= n_max; n++) { + for (m = 0; m <= m_max; m++) { + if (nm->flags & SUNXI_CCU_NM_POWER_OF_TWO) + rate = parent_rate / (1 << n) / (m + 1); + else + rate = parent_rate / (n + 1) / (m + 1); + + if (nm->flags & SUNXI_CCU_NM_ROUND_DOWN) { + const int diff = new_rate - rate; + if (diff >= 0 && rate > best_rate) { + best_diff = diff; + best_rate = rate; + best_n = n; + best_m = m; + best_parent = pindex; + } + } else { + const int diff = abs(new_rate - rate); + if (diff < best_diff) { + best_diff = diff; + best_rate = rate; + best_n = n; + best_m = m; + best_parent = pindex; + } + } + } + } + } + + if (best_rate == 0) + return ERANGE; + + val = CCU_READ(sc, nm->reg); + val &= ~nm->sel; + val |= __SHIFTIN(best_parent, nm->sel); + val &= ~nm->n; + val |= __SHIFTIN(best_n, nm->n); + val &= ~nm->m; + val |= __SHIFTIN(best_m, nm->m); + CCU_WRITE(sc, nm->reg, val); + + return 0; +} + +int +sunxi_ccu_nm_set_parent(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk, const char *name) +{ + struct sunxi_ccu_nm *nm = &clk->u.nm; + uint32_t val; + u_int index; + + KASSERT(clk->type == SUNXI_CCU_NM); + + if (nm->sel == 0) + return ENODEV; + + for (index = 0; index < nm->nparents; index++) { + if (nm->parents[index] != NULL && + strcmp(nm->parents[index], name) == 0) + break; + } + if (index == nm->nparents) + return EINVAL; + + val = CCU_READ(sc, nm->reg); + val &= ~nm->sel; + val |= __SHIFTIN(index, nm->sel); + CCU_WRITE(sc, nm->reg, val); + + return 0; +} + +const char * +sunxi_ccu_nm_get_parent(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk) +{ + struct sunxi_ccu_nm *nm = &clk->u.nm; + u_int index; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_NM); + + val = CCU_READ(sc, nm->reg); + index = __SHIFTOUT(val, nm->sel); + + return nm->parents[index]; +} diff --git a/sys/arch/arm/sunxi/sunxi_ccu_prediv.c b/sys/arch/arm/sunxi/sunxi_ccu_prediv.c new file mode 100644 index 000000000000..911f39ed3aa6 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_ccu_prediv.c @@ -0,0 +1,136 @@ +/* $NetBSD: sunxi_ccu_prediv.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_ccu_prediv.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include + +#include + +#include + +u_int +sunxi_ccu_prediv_get_rate(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk) +{ + struct sunxi_ccu_prediv *prediv = &clk->u.prediv; + struct clk *clkp, *clkp_parent; + u_int rate, pre, div, sel; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_PREDIV); + + clkp = &clk->base; + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) + return 0; + + rate = clk_get_rate(clkp_parent); + if (rate == 0) + return 0; + + val = CCU_READ(sc, prediv->reg); + if (prediv->prediv) + pre = __SHIFTOUT(val, prediv->prediv); + else + pre = 0; + if (prediv->div) + div = __SHIFTOUT(val, prediv->div); + else + div = 0; + sel = __SHIFTOUT(val, prediv->sel); + + if (prediv->flags & SUNXI_CCU_PREDIV_POWER_OF_TWO) + div = 1 << div; + else + div++; + + pre++; + + if (prediv->flags & SUNXI_CCU_PREDIV_DIVIDE_BY_TWO) + pre *= 2; + + if (prediv->prediv_sel & __BIT(sel)) + return rate / pre / div; + else + return rate / div; +} + +int +sunxi_ccu_prediv_set_rate(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk, u_int new_rate) +{ + return EINVAL; +} + +int +sunxi_ccu_prediv_set_parent(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk, const char *name) +{ + struct sunxi_ccu_prediv *prediv = &clk->u.prediv; + uint32_t val; + u_int index; + + KASSERT(clk->type == SUNXI_CCU_PREDIV); + + if (prediv->sel == 0) + return ENODEV; + + for (index = 0; index < prediv->nparents; index++) { + if (prediv->parents[index] != NULL && + strcmp(prediv->parents[index], name) == 0) + break; + } + if (index == prediv->nparents) + return EINVAL; + + val = CCU_READ(sc, prediv->reg); + val &= ~prediv->sel; + val |= __SHIFTIN(index, prediv->sel); + CCU_WRITE(sc, prediv->reg, val); + + return 0; +} + +const char * +sunxi_ccu_prediv_get_parent(struct sunxi_ccu_softc *sc, + struct sunxi_ccu_clk *clk) +{ + struct sunxi_ccu_prediv *prediv = &clk->u.prediv; + u_int index; + uint32_t val; + + KASSERT(clk->type == SUNXI_CCU_PREDIV); + + val = CCU_READ(sc, prediv->reg); + index = __SHIFTOUT(val, prediv->sel); + + return prediv->parents[index]; +} diff --git a/sys/arch/arm/sunxi/sunxi_com.c b/sys/arch/arm/sunxi/sunxi_com.c new file mode 100644 index 000000000000..9e2b845f2504 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_com.c @@ -0,0 +1,178 @@ +/* $NetBSD: sunxi_com.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 + +__KERNEL_RCSID(1, "$NetBSD: sunxi_com.c,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +static int sunxi_com_match(device_t, cfdata_t, void *); +static void sunxi_com_attach(device_t, device_t, void *); + +static const char * const compatible[] = { + "snps,dw-apb-uart", + NULL +}; + +struct sunxi_com_softc { + struct com_softc ssc_sc; + void *ssc_ih; + + struct clk *ssc_clk; + struct fdtbus_reset *ssc_rst; +}; + +CFATTACH_DECL_NEW(sunxi_com, sizeof(struct sunxi_com_softc), + sunxi_com_match, sunxi_com_attach, NULL, NULL); + +static int +sunxi_com_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sunxi_com_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_com_softc * const ssc = device_private(self); + struct com_softc * const sc = &ssc->ssc_sc; + struct fdt_attach_args * const faa = aux; + bus_space_handle_t bsh; + bus_space_tag_t bst; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + u_int reg_shift; + int error; + + if (fdtbus_get_reg(faa->faa_phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + if (of_getprop_uint32(faa->faa_phandle, "reg-shift", ®_shift)) { + /* missing or bad reg-shift property, assume 2 */ + bst = faa->faa_a4x_bst; + } else { + if (reg_shift == 2) { + bst = faa->faa_a4x_bst; + } else if (reg_shift == 0) { + bst = faa->faa_bst; + } else { + aprint_error(": unsupported reg-shift value %d\n", + reg_shift); + return; + } + } + + sc->sc_dev = self; + + ssc->ssc_clk = fdtbus_clock_get_index(faa->faa_phandle, 0); + ssc->ssc_rst = fdtbus_reset_get_index(faa->faa_phandle, 0); + + if (ssc->ssc_clk == NULL) { + aprint_error(": couldn't get frequency\n"); + return; + } + + sc->sc_frequency = clk_get_rate(ssc->ssc_clk); + sc->sc_type = COM_TYPE_NORMAL; + + error = bus_space_map(bst, addr, size, 0, &bsh); + if (error) { + aprint_error(": couldn't map %#llx: %d", (uint64_t)addr, error); + return; + } + + COM_INIT_REGS(sc->sc_regs, bst, bsh, addr); + + com_attach_subr(sc); + aprint_naive("\n"); + + if (!fdtbus_intr_str(faa->faa_phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); + return; + } + + ssc->ssc_ih = fdtbus_intr_establish(faa->faa_phandle, 0, IPL_SERIAL, + FDT_INTR_MPSAFE, comintr, sc); + if (ssc->ssc_ih == NULL) { + aprint_error_dev(self, "failed to establish interrupt on %s\n", + intrstr); + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); +} + +/* + * Console support + */ + +static int +sunxi_com_console_match(int phandle) +{ + return of_match_compatible(phandle, compatible); +} + +static void +sunxi_com_console_consinit(struct fdt_attach_args *faa, u_int uart_freq) +{ + const int phandle = faa->faa_phandle; + bus_space_tag_t bst = faa->faa_a4x_bst; + bus_addr_t addr; + tcflag_t flags; + int speed; + + fdtbus_get_reg(phandle, 0, &addr, NULL); + speed = fdtbus_get_stdout_speed(); + if (speed < 0) + speed = 115200; /* default */ + flags = fdtbus_get_stdout_flags(); + + if (comcnattach(bst, addr, speed, uart_freq, COM_TYPE_NORMAL, flags)) + panic("Cannot initialize sunxi com console"); +} + +static const struct fdt_console sunxi_com_console = { + .match = sunxi_com_console_match, + .consinit = sunxi_com_console_consinit, +}; + +FDT_CONSOLE(sunxi_com, &sunxi_com_console); diff --git a/sys/arch/arm/sunxi/sunxi_emac.c b/sys/arch/arm/sunxi/sunxi_emac.c new file mode 100644 index 000000000000..f2526843484f --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_emac.c @@ -0,0 +1,1414 @@ +/* $NetBSD: sunxi_emac.c,v 1.4.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2016-2017 Jared McNeill + * 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. + */ + +/* + * Allwinner Gigabit Ethernet MAC (EMAC) controller + */ + +#include "opt_net_mpsafe.h" + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_emac.c,v 1.4.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#ifdef NET_MPSAFE +#define EMAC_MPSAFE 1 +#define CALLOUT_FLAGS CALLOUT_MPSAFE +#define FDT_INTR_FLAGS FDT_INTR_MPSAFE +#else +#define CALLOUT_FLAGS 0 +#define FDT_INTR_FLAGS 0 +#endif + +#define EMAC_IFNAME "emac%d" + +#define ETHER_ALIGN 2 + +#define EMAC_LOCK(sc) mutex_enter(&(sc)->mtx) +#define EMAC_UNLOCK(sc) mutex_exit(&(sc)->mtx) +#define EMAC_ASSERT_LOCKED(sc) KASSERT(mutex_owned(&(sc)->mtx)) + +#define DESC_ALIGN sizeof(struct sunxi_emac_desc) +#define TX_DESC_COUNT 1024 +#define TX_DESC_SIZE (sizeof(struct sunxi_emac_desc) * TX_DESC_COUNT) +#define RX_DESC_COUNT 256 +#define RX_DESC_SIZE (sizeof(struct sunxi_emac_desc) * RX_DESC_COUNT) + +#define DESC_OFF(n) ((n) * sizeof(struct sunxi_emac_desc)) +#define TX_NEXT(n) (((n) + 1) & (TX_DESC_COUNT - 1)) +#define TX_SKIP(n, o) (((n) + (o)) & (TX_DESC_COUNT - 1)) +#define RX_NEXT(n) (((n) + 1) & (RX_DESC_COUNT - 1)) + +#define TX_MAX_SEGS 128 + +#define SOFT_RST_RETRY 1000 +#define MII_BUSY_RETRY 1000 +#define MDIO_FREQ 2500000 + +#define BURST_LEN_DEFAULT 8 +#define RX_TX_PRI_DEFAULT 0 +#define PAUSE_TIME_DEFAULT 0x400 +#define TX_INTERVAL_DEFAULT 64 + +/* syscon EMAC clock register */ +#define EMAC_CLK_EPHY_ADDR (0x1f << 20) /* H3 */ +#define EMAC_CLK_EPHY_ADDR_SHIFT 20 +#define EMAC_CLK_EPHY_LED_POL (1 << 17) /* H3 */ +#define EMAC_CLK_EPHY_SHUTDOWN (1 << 16) /* H3 */ +#define EMAC_CLK_EPHY_SELECT (1 << 15) /* H3 */ +#define EMAC_CLK_RMII_EN (1 << 13) +#define EMAC_CLK_ETXDC (0x7 << 10) +#define EMAC_CLK_ETXDC_SHIFT 10 +#define EMAC_CLK_ERXDC (0x1f << 5) +#define EMAC_CLK_ERXDC_SHIFT 5 +#define EMAC_CLK_PIT (0x1 << 2) +#define EMAC_CLK_PIT_MII (0 << 2) +#define EMAC_CLK_PIT_RGMII (1 << 2) +#define EMAC_CLK_SRC (0x3 << 0) +#define EMAC_CLK_SRC_MII (0 << 0) +#define EMAC_CLK_SRC_EXT_RGMII (1 << 0) +#define EMAC_CLK_SRC_RGMII (2 << 0) + +/* Burst length of RX and TX DMA transfers */ +static int sunxi_emac_burst_len = BURST_LEN_DEFAULT; + +/* RX / TX DMA priority. If 1, RX DMA has priority over TX DMA. */ +static int sunxi_emac_rx_tx_pri = RX_TX_PRI_DEFAULT; + +/* Pause time field in the transmitted control frame */ +static int sunxi_emac_pause_time = PAUSE_TIME_DEFAULT; + +/* Request a TX interrupt every descriptors */ +static int sunxi_emac_tx_interval = TX_INTERVAL_DEFAULT; + +enum sunxi_emac_type { + EMAC_A83T = 1, + EMAC_H3, +}; + +static const struct of_compat_data compat_data[] = { + { "allwinner,sun8i-a83t-emac", EMAC_A83T }, + { "allwinner,sun8i-h3-emac", EMAC_H3 }, + { NULL } +}; + +struct sunxi_emac_bufmap { + bus_dmamap_t map; + struct mbuf *mbuf; +}; + +struct sunxi_emac_txring { + bus_dma_tag_t desc_tag; + bus_dmamap_t desc_map; + bus_dma_segment_t desc_dmaseg; + struct sunxi_emac_desc *desc_ring; + bus_addr_t desc_ring_paddr; + bus_dma_tag_t buf_tag; + struct sunxi_emac_bufmap buf_map[TX_DESC_COUNT]; + u_int cur, next, queued; +}; + +struct sunxi_emac_rxring { + bus_dma_tag_t desc_tag; + bus_dmamap_t desc_map; + bus_dma_segment_t desc_dmaseg; + struct sunxi_emac_desc *desc_ring; + bus_addr_t desc_ring_paddr; + bus_dma_tag_t buf_tag; + struct sunxi_emac_bufmap buf_map[RX_DESC_COUNT]; + u_int cur; +}; + +enum { + _RES_EMAC, + _RES_SYSCON, + _RES_NITEMS +}; + +struct sunxi_emac_softc { + device_t dev; + int phandle; + enum sunxi_emac_type type; + bus_space_tag_t bst; + bus_dma_tag_t dmat; + + bus_space_handle_t bsh[_RES_NITEMS]; + struct clk *clk_ahb; + struct clk *clk_ephy; + struct fdtbus_reset *rst_ahb; + struct fdtbus_reset *rst_ephy; + struct fdtbus_regulator *reg_phy; + struct fdtbus_gpio_pin *pin_reset; + + kmutex_t mtx; + struct ethercom ec; + struct mii_data mii; + callout_t stat_ch; + void *ih; + u_int mdc_div_ratio_m; + + struct sunxi_emac_txring tx; + struct sunxi_emac_rxring rx; +}; + +#define RD4(sc, reg) \ + bus_space_read_4((sc)->bst, (sc)->bsh[_RES_EMAC], (reg)) +#define WR4(sc, reg, val) \ + bus_space_write_4((sc)->bst, (sc)->bsh[_RES_EMAC], (reg), (val)) + +#define SYSCONRD4(sc, reg) \ + bus_space_read_4((sc)->bst, (sc)->bsh[_RES_SYSCON], (reg)) +#define SYSCONWR4(sc, reg, val) \ + bus_space_write_4((sc)->bst, (sc)->bsh[_RES_SYSCON], (reg), (val)) + +static int +sunxi_emac_mii_readreg(device_t dev, int phy, int reg) +{ + struct sunxi_emac_softc *sc = device_private(dev); + int retry, val; + + val = 0; + + WR4(sc, EMAC_MII_CMD, + (sc->mdc_div_ratio_m << MDC_DIV_RATIO_M_SHIFT) | + (phy << PHY_ADDR_SHIFT) | + (reg << PHY_REG_ADDR_SHIFT) | + MII_BUSY); + for (retry = MII_BUSY_RETRY; retry > 0; retry--) { + if ((RD4(sc, EMAC_MII_CMD) & MII_BUSY) == 0) { + val = RD4(sc, EMAC_MII_DATA); + break; + } + delay(10); + } + + if (retry == 0) + device_printf(dev, "phy read timeout, phy=%d reg=%d\n", + phy, reg); + + return val; +} + +static void +sunxi_emac_mii_writereg(device_t dev, int phy, int reg, int val) +{ + struct sunxi_emac_softc *sc = device_private(dev); + int retry; + + WR4(sc, EMAC_MII_DATA, val); + WR4(sc, EMAC_MII_CMD, + (sc->mdc_div_ratio_m << MDC_DIV_RATIO_M_SHIFT) | + (phy << PHY_ADDR_SHIFT) | + (reg << PHY_REG_ADDR_SHIFT) | + MII_WR | MII_BUSY); + for (retry = MII_BUSY_RETRY; retry > 0; retry--) { + if ((RD4(sc, EMAC_MII_CMD) & MII_BUSY) == 0) + break; + delay(10); + } + + if (retry == 0) + device_printf(dev, "phy write timeout, phy=%d reg=%d\n", + phy, reg); +} + +static void +sunxi_emac_update_link(struct sunxi_emac_softc *sc) +{ + struct mii_data *mii = &sc->mii; + uint32_t val; + + val = RD4(sc, EMAC_BASIC_CTL_0); + val &= ~(BASIC_CTL_SPEED | BASIC_CTL_DUPLEX); + + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || + IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) + val |= BASIC_CTL_SPEED_1000 << BASIC_CTL_SPEED_SHIFT; + else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) + val |= BASIC_CTL_SPEED_100 << BASIC_CTL_SPEED_SHIFT; + else + val |= BASIC_CTL_SPEED_10 << BASIC_CTL_SPEED_SHIFT; + + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + val |= BASIC_CTL_DUPLEX; + + WR4(sc, EMAC_BASIC_CTL_0, val); + + val = RD4(sc, EMAC_RX_CTL_0); + val &= ~RX_FLOW_CTL_EN; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) + val |= RX_FLOW_CTL_EN; + WR4(sc, EMAC_RX_CTL_0, val); + + val = RD4(sc, EMAC_TX_FLOW_CTL); + val &= ~(PAUSE_TIME|TX_FLOW_CTL_EN); + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) + val |= TX_FLOW_CTL_EN; + if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) + val |= sunxi_emac_pause_time << PAUSE_TIME_SHIFT; + WR4(sc, EMAC_TX_FLOW_CTL, val); +} + +static void +sunxi_emac_mii_statchg(struct ifnet *ifp) +{ + struct sunxi_emac_softc * const sc = ifp->if_softc; + + sunxi_emac_update_link(sc); +} + +static void +sunxi_emac_dma_sync(struct sunxi_emac_softc *sc, bus_dma_tag_t dmat, + bus_dmamap_t map, int start, int end, int total, int flags) +{ + if (end > start) { + bus_dmamap_sync(dmat, map, DESC_OFF(start), + DESC_OFF(end) - DESC_OFF(start), flags); + } else { + bus_dmamap_sync(dmat, map, DESC_OFF(start), + DESC_OFF(total) - DESC_OFF(start), flags); + if (DESC_OFF(end) - DESC_OFF(0) > 0) + bus_dmamap_sync(dmat, map, DESC_OFF(0), + DESC_OFF(end) - DESC_OFF(0), flags); + } +} + +static void +sunxi_emac_setup_txdesc(struct sunxi_emac_softc *sc, int index, int flags, + bus_addr_t paddr, u_int len) +{ + uint32_t status, size; + + if (paddr == 0 || len == 0) { + status = 0; + size = 0; + --sc->tx.queued; + } else { + status = TX_DESC_CTL; + size = flags | len; + if ((index & (sunxi_emac_tx_interval - 1)) == 0) + size |= TX_INT_CTL; + ++sc->tx.queued; + } + + sc->tx.desc_ring[index].addr = htole32((uint32_t)paddr); + sc->tx.desc_ring[index].size = htole32(size); + sc->tx.desc_ring[index].status = htole32(status); +} + +static int +sunxi_emac_setup_txbuf(struct sunxi_emac_softc *sc, int index, struct mbuf *m) +{ + bus_dma_segment_t *segs; + int error, nsegs, cur, i, flags; + u_int csum_flags; + + error = bus_dmamap_load_mbuf(sc->tx.buf_tag, + sc->tx.buf_map[index].map, m, BUS_DMA_WRITE|BUS_DMA_NOWAIT); + if (error == EFBIG) { + device_printf(sc->dev, + "TX packet needs too many DMA segments, dropping...\n"); + m_freem(m); + return 0; + } + if (error != 0) + return 0; + + segs = sc->tx.buf_map[index].map->dm_segs; + nsegs = sc->tx.buf_map[index].map->dm_nsegs; + + flags = TX_FIR_DESC; + if ((m->m_pkthdr.csum_flags & M_CSUM_IPv4) != 0) { + if ((m->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) != 0) + csum_flags = TX_CHECKSUM_CTL_FULL; + else + csum_flags = TX_CHECKSUM_CTL_IP; + flags |= (csum_flags << TX_CHECKSUM_CTL_SHIFT); + } + + for (cur = index, i = 0; i < nsegs; i++) { + sc->tx.buf_map[cur].mbuf = (i == 0 ? m : NULL); + if (i == nsegs - 1) + flags |= TX_LAST_DESC; + + sunxi_emac_setup_txdesc(sc, cur, flags, segs[i].ds_addr, + segs[i].ds_len); + flags &= ~TX_FIR_DESC; + cur = TX_NEXT(cur); + } + + bus_dmamap_sync(sc->tx.buf_tag, sc->tx.buf_map[index].map, + 0, sc->tx.buf_map[index].map->dm_mapsize, BUS_DMASYNC_PREWRITE); + + return nsegs; +} + +static void +sunxi_emac_setup_rxdesc(struct sunxi_emac_softc *sc, int index, + bus_addr_t paddr) +{ + uint32_t status, size; + + status = RX_DESC_CTL; + size = MCLBYTES - 1; + + sc->rx.desc_ring[index].addr = htole32((uint32_t)paddr); + sc->rx.desc_ring[index].size = htole32(size); + sc->rx.desc_ring[index].next = + htole32(sc->rx.desc_ring_paddr + DESC_OFF(RX_NEXT(index))); + sc->rx.desc_ring[index].status = htole32(status); +} + +static int +sunxi_emac_setup_rxbuf(struct sunxi_emac_softc *sc, int index, struct mbuf *m) +{ + int error; + + m_adj(m, ETHER_ALIGN); + + error = bus_dmamap_load_mbuf(sc->rx.buf_tag, + sc->rx.buf_map[index].map, m, BUS_DMA_READ|BUS_DMA_NOWAIT); + if (error != 0) + return error; + + bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map, + 0, sc->rx.buf_map[index].map->dm_mapsize, + BUS_DMASYNC_PREREAD); + + sc->rx.buf_map[index].mbuf = m; + sunxi_emac_setup_rxdesc(sc, index, + sc->rx.buf_map[index].map->dm_segs[0].ds_addr); + + return 0; +} + +static struct mbuf * +sunxi_emac_alloc_mbufcl(struct sunxi_emac_softc *sc) +{ + struct mbuf *m; + + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (m != NULL) + m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; + + return m; +} + +static void +sunxi_emac_start_locked(struct sunxi_emac_softc *sc) +{ + struct ifnet *ifp = &sc->ec.ec_if; + struct mbuf *m; + uint32_t val; + int cnt, nsegs, start; + + EMAC_ASSERT_LOCKED(sc); + + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) + return; + + for (cnt = 0, start = sc->tx.cur; ; cnt++) { + if (sc->tx.queued >= TX_DESC_COUNT - TX_MAX_SEGS) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + + IFQ_POLL(&ifp->if_snd, m); + if (m == NULL) + break; + + nsegs = sunxi_emac_setup_txbuf(sc, sc->tx.cur, m); + if (nsegs == 0) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + IFQ_DEQUEUE(&ifp->if_snd, m); + bpf_mtap(ifp, m); + + sc->tx.cur = TX_SKIP(sc->tx.cur, nsegs); + } + + if (cnt != 0) { + sunxi_emac_dma_sync(sc, sc->tx.desc_tag, sc->tx.desc_map, + start, sc->tx.cur, TX_DESC_COUNT, + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + + /* Start and run TX DMA */ + val = RD4(sc, EMAC_TX_CTL_1); + WR4(sc, EMAC_TX_CTL_1, val | TX_DMA_START); + } +} + +static void +sunxi_emac_start(struct ifnet *ifp) +{ + struct sunxi_emac_softc *sc = ifp->if_softc; + + EMAC_LOCK(sc); + sunxi_emac_start_locked(sc); + EMAC_UNLOCK(sc); +} + +static void +sunxi_emac_tick(void *softc) +{ + struct sunxi_emac_softc *sc = softc; + struct mii_data *mii = &sc->mii; +#ifndef EMAC_MPSAFE + int s = splnet(); +#endif + + EMAC_LOCK(sc); + mii_tick(mii); + callout_schedule(&sc->stat_ch, hz); + EMAC_UNLOCK(sc); + +#ifndef EMAC_MPSAFE + splx(s); +#endif +} + +/* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */ +static uint32_t +bitrev32(uint32_t x) +{ + x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); + x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); + x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); + x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); + + return (x >> 16) | (x << 16); +} + +static void +sunxi_emac_setup_rxfilter(struct sunxi_emac_softc *sc) +{ + struct ifnet *ifp = &sc->ec.ec_if; + uint32_t val, crc, hashreg, hashbit, hash[2], machi, maclo; + struct ether_multi *enm; + struct ether_multistep step; + const uint8_t *eaddr; + + EMAC_ASSERT_LOCKED(sc); + + val = 0; + hash[0] = hash[1] = 0; + + if ((ifp->if_flags & IFF_PROMISC) != 0) + val |= DIS_ADDR_FILTER; + else if ((ifp->if_flags & IFF_ALLMULTI) != 0) { + val |= RX_ALL_MULTICAST; + hash[0] = hash[1] = ~0; + } else { + val |= HASH_MULTICAST; + ETHER_FIRST_MULTI(step, &sc->ec, enm); + while (enm != NULL) { + crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); + crc &= 0x7f; + crc = bitrev32(~crc) >> 26; + hashreg = (crc >> 5); + hashbit = (crc & 0x1f); + hash[hashreg] |= (1 << hashbit); + ETHER_NEXT_MULTI(step, enm); + } + } + + /* Write our unicast address */ + eaddr = CLLADDR(ifp->if_sadl); + machi = (eaddr[5] << 8) | eaddr[4]; + maclo = (eaddr[3] << 24) | (eaddr[2] << 16) | (eaddr[1] << 8) | + (eaddr[0] << 0); + WR4(sc, EMAC_ADDR_HIGH(0), machi); + WR4(sc, EMAC_ADDR_LOW(0), maclo); + + /* Multicast hash filters */ + WR4(sc, EMAC_RX_HASH_0, hash[1]); + WR4(sc, EMAC_RX_HASH_1, hash[0]); + + /* RX frame filter config */ + WR4(sc, EMAC_RX_FRM_FLT, val); +} + +static void +sunxi_emac_enable_intr(struct sunxi_emac_softc *sc) +{ + /* Enable interrupts */ + WR4(sc, EMAC_INT_EN, RX_INT_EN | TX_INT_EN | TX_BUF_UA_INT_EN); +} + +static void +sunxi_emac_disable_intr(struct sunxi_emac_softc *sc) +{ + /* Disable interrupts */ + WR4(sc, EMAC_INT_EN, 0); +} + +static int +sunxi_emac_init_locked(struct sunxi_emac_softc *sc) +{ + struct ifnet *ifp = &sc->ec.ec_if; + struct mii_data *mii = &sc->mii; + uint32_t val; + + EMAC_ASSERT_LOCKED(sc); + + if ((ifp->if_flags & IFF_RUNNING) != 0) + return 0; + + sunxi_emac_setup_rxfilter(sc); + + /* Configure DMA burst length and priorities */ + val = sunxi_emac_burst_len << BASIC_CTL_BURST_LEN_SHIFT; + if (sunxi_emac_rx_tx_pri) + val |= BASIC_CTL_RX_TX_PRI; + WR4(sc, EMAC_BASIC_CTL_1, val); + + /* Enable interrupts */ + sunxi_emac_enable_intr(sc); + + /* Enable transmit DMA */ + val = RD4(sc, EMAC_TX_CTL_1); + WR4(sc, EMAC_TX_CTL_1, val | TX_DMA_EN | TX_MD | TX_NEXT_FRAME); + + /* Enable receive DMA */ + val = RD4(sc, EMAC_RX_CTL_1); + WR4(sc, EMAC_RX_CTL_1, val | RX_DMA_EN | RX_MD); + + /* Enable transmitter */ + val = RD4(sc, EMAC_TX_CTL_0); + WR4(sc, EMAC_TX_CTL_0, val | TX_EN); + + /* Enable receiver */ + val = RD4(sc, EMAC_RX_CTL_0); + WR4(sc, EMAC_RX_CTL_0, val | RX_EN | CHECK_CRC); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + mii_mediachg(mii); + callout_schedule(&sc->stat_ch, hz); + + return 0; +} + +static int +sunxi_emac_init(struct ifnet *ifp) +{ + struct sunxi_emac_softc *sc = ifp->if_softc; + int error; + + EMAC_LOCK(sc); + error = sunxi_emac_init_locked(sc); + EMAC_UNLOCK(sc); + + return error; +} + +static void +sunxi_emac_stop_locked(struct sunxi_emac_softc *sc, int disable) +{ + struct ifnet *ifp = &sc->ec.ec_if; + uint32_t val; + + EMAC_ASSERT_LOCKED(sc); + + callout_stop(&sc->stat_ch); + + mii_down(&sc->mii); + + /* Stop transmit DMA and flush data in the TX FIFO */ + val = RD4(sc, EMAC_TX_CTL_1); + val &= ~TX_DMA_EN; + val |= FLUSH_TX_FIFO; + WR4(sc, EMAC_TX_CTL_1, val); + + /* Disable transmitter */ + val = RD4(sc, EMAC_TX_CTL_0); + WR4(sc, EMAC_TX_CTL_0, val & ~TX_EN); + + /* Disable receiver */ + val = RD4(sc, EMAC_RX_CTL_0); + WR4(sc, EMAC_RX_CTL_0, val & ~RX_EN); + + /* Disable interrupts */ + sunxi_emac_disable_intr(sc); + + /* Disable transmit DMA */ + val = RD4(sc, EMAC_TX_CTL_1); + WR4(sc, EMAC_TX_CTL_1, val & ~TX_DMA_EN); + + /* Disable receive DMA */ + val = RD4(sc, EMAC_RX_CTL_1); + WR4(sc, EMAC_RX_CTL_1, val & ~RX_DMA_EN); + + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); +} + +static void +sunxi_emac_stop(struct ifnet *ifp, int disable) +{ + struct sunxi_emac_softc * const sc = ifp->if_softc; + + EMAC_LOCK(sc); + sunxi_emac_stop_locked(sc, disable); + EMAC_UNLOCK(sc); +} + +static int +sunxi_emac_rxintr(struct sunxi_emac_softc *sc) +{ + struct ifnet *ifp = &sc->ec.ec_if; + int error, index, len, npkt; + struct mbuf *m, *m0; + uint32_t status; + + npkt = 0; + + for (index = sc->rx.cur; ; index = RX_NEXT(index)) { + sunxi_emac_dma_sync(sc, sc->rx.desc_tag, sc->rx.desc_map, + index, index + 1, + RX_DESC_COUNT, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + + status = le32toh(sc->rx.desc_ring[index].status); + if ((status & RX_DESC_CTL) != 0) + break; + + bus_dmamap_sync(sc->rx.buf_tag, sc->rx.buf_map[index].map, + 0, sc->rx.buf_map[index].map->dm_mapsize, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->rx.buf_tag, sc->rx.buf_map[index].map); + + len = (status & RX_FRM_LEN) >> RX_FRM_LEN_SHIFT; + if (len != 0) { + m = sc->rx.buf_map[index].mbuf; + m_set_rcvif(m, ifp); + m->m_flags |= M_HASFCS; + m->m_pkthdr.len = len; + m->m_len = len; + m->m_nextpkt = NULL; + + if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) != 0 && + (status & RX_FRM_TYPE) != 0) { + m->m_pkthdr.csum_flags = M_CSUM_IPv4; + if ((status & RX_HEADER_ERR) != 0) + m->m_pkthdr.csum_flags |= + M_CSUM_IPv4_BAD; + if ((status & RX_PAYLOAD_ERR) == 0) { + m->m_pkthdr.csum_flags |= + M_CSUM_DATA; + m->m_pkthdr.csum_data = 0xffff; + } + } + + ++npkt; + + if_percpuq_enqueue(ifp->if_percpuq, m); + } + + if ((m0 = sunxi_emac_alloc_mbufcl(sc)) != NULL) { + error = sunxi_emac_setup_rxbuf(sc, index, m0); + if (error != 0) { + /* XXX hole in RX ring */ + } + } else + ifp->if_ierrors++; + + sunxi_emac_dma_sync(sc, sc->rx.desc_tag, sc->rx.desc_map, + index, index + 1, + RX_DESC_COUNT, BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); + } + + sc->rx.cur = index; + + return npkt; +} + +static void +sunxi_emac_txintr(struct sunxi_emac_softc *sc) +{ + struct ifnet *ifp = &sc->ec.ec_if; + struct sunxi_emac_bufmap *bmap; + struct sunxi_emac_desc *desc; + uint32_t status; + int i; + + EMAC_ASSERT_LOCKED(sc); + + for (i = sc->tx.next; sc->tx.queued > 0; i = TX_NEXT(i)) { + KASSERT(sc->tx.queued > 0 && sc->tx.queued <= TX_DESC_COUNT); + sunxi_emac_dma_sync(sc, sc->tx.desc_tag, sc->tx.desc_map, + i, i + 1, TX_DESC_COUNT, + BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + desc = &sc->tx.desc_ring[i]; + status = le32toh(desc->status); + if ((status & TX_DESC_CTL) != 0) + break; + bmap = &sc->tx.buf_map[i]; + if (bmap->mbuf != NULL) { + bus_dmamap_sync(sc->tx.buf_tag, bmap->map, + 0, bmap->map->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->tx.buf_tag, bmap->map); + m_freem(bmap->mbuf); + bmap->mbuf = NULL; + } + + sunxi_emac_setup_txdesc(sc, i, 0, 0, 0); + sunxi_emac_dma_sync(sc, sc->tx.desc_tag, sc->tx.desc_map, + i, i + 1, TX_DESC_COUNT, + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + + ifp->if_flags &= ~IFF_OACTIVE; + ifp->if_opackets++; + } + + sc->tx.next = i; +} + +static int +sunxi_emac_intr(void *arg) +{ + struct sunxi_emac_softc *sc = arg; + struct ifnet *ifp = &sc->ec.ec_if; + uint32_t val; + + EMAC_LOCK(sc); + + val = RD4(sc, EMAC_INT_STA); + WR4(sc, EMAC_INT_STA, val); + + if (val & RX_INT) + sunxi_emac_rxintr(sc); + + if (val & (TX_INT|TX_BUF_UA_INT)) { + sunxi_emac_txintr(sc); + if_schedule_deferred_start(ifp); + } + + EMAC_UNLOCK(sc); + + return 1; +} + +static int +sunxi_emac_ioctl(struct ifnet *ifp, u_long cmd, void *data) +{ + struct sunxi_emac_softc *sc = ifp->if_softc; + struct mii_data *mii = &sc->mii; + struct ifreq *ifr = data; + int error, s; + +#ifndef EMAC_MPSAFE + s = splnet(); +#endif + + switch (cmd) { + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: +#ifdef EMAC_MPSAFE + s = splnet(); +#endif + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); +#ifdef EMAC_MPSAFE + splx(s); +#endif + break; + default: +#ifdef EMAC_MPSAFE + s = splnet(); +#endif + error = ether_ioctl(ifp, cmd, data); +#ifdef EMAC_MPSAFE + splx(s); +#endif + if (error != ENETRESET) + break; + + error = 0; + + if (cmd == SIOCSIFCAP) + error = (*ifp->if_init)(ifp); + else if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) + ; + else if ((ifp->if_flags & IFF_RUNNING) != 0) { + EMAC_LOCK(sc); + sunxi_emac_setup_rxfilter(sc); + EMAC_UNLOCK(sc); + } + break; + } + +#ifndef EMAC_MPSAFE + splx(s); +#endif + + return error; +} + +static int +sunxi_emac_setup_phy(struct sunxi_emac_softc *sc) +{ + uint32_t reg, tx_delay, rx_delay; + const char *phy_type; + + phy_type = fdtbus_get_string(sc->phandle, "phy-mode"); + if (phy_type == NULL) + return 0; + + aprint_debug_dev(sc->dev, "PHY type: %s\n", phy_type); + + reg = SYSCONRD4(sc, 0); + + reg &= ~(EMAC_CLK_PIT | EMAC_CLK_SRC | EMAC_CLK_RMII_EN); + if (strcmp(phy_type, "rgmii") == 0) + reg |= EMAC_CLK_PIT_RGMII | EMAC_CLK_SRC_RGMII; + else if (strcmp(phy_type, "rmii") == 0) + reg |= EMAC_CLK_RMII_EN; + else + reg |= EMAC_CLK_PIT_MII | EMAC_CLK_SRC_MII; + + if (of_getprop_uint32(sc->phandle, "tx-delay", &tx_delay) == 0) { + reg &= ~EMAC_CLK_ETXDC; + reg |= (tx_delay << EMAC_CLK_ETXDC_SHIFT); + } + if (of_getprop_uint32(sc->phandle, "rx-delay", &rx_delay) == 0) { + reg &= ~EMAC_CLK_ERXDC; + reg |= (rx_delay << EMAC_CLK_ERXDC_SHIFT); + } + + if (sc->type == EMAC_H3) { + if (of_hasprop(sc->phandle, "allwinner,use-internal-phy")) { + reg |= EMAC_CLK_EPHY_SELECT; + reg &= ~EMAC_CLK_EPHY_SHUTDOWN; + if (of_hasprop(sc->phandle, + "allwinner,leds-active-low")) + reg |= EMAC_CLK_EPHY_LED_POL; + else + reg &= ~EMAC_CLK_EPHY_LED_POL; + + /* Set internal PHY addr to 1 */ + reg &= ~EMAC_CLK_EPHY_ADDR; + reg |= (1 << EMAC_CLK_EPHY_ADDR_SHIFT); + } else { + reg &= ~EMAC_CLK_EPHY_SELECT; + } + } + + aprint_debug_dev(sc->dev, "EMAC clock: 0x%08x\n", reg); + + SYSCONWR4(sc, 0, reg); + + return 0; +} + +static int +sunxi_emac_setup_resources(struct sunxi_emac_softc *sc) +{ + u_int freq; + int error, div; + + /* Configure PHY for MII or RGMII mode */ + if (sunxi_emac_setup_phy(sc) != 0) + return ENXIO; + + /* Enable clocks */ + error = clk_enable(sc->clk_ahb); + if (error != 0) { + aprint_error_dev(sc->dev, "cannot enable ahb clock\n"); + return error; + } + + if (sc->clk_ephy != NULL) { + error = clk_enable(sc->clk_ephy); + if (error != 0) { + aprint_error_dev(sc->dev, "cannot enable ephy clock\n"); + return error; + } + } + + /* De-assert reset */ + error = fdtbus_reset_deassert(sc->rst_ahb); + if (error != 0) { + aprint_error_dev(sc->dev, "cannot de-assert ahb reset\n"); + return error; + } + if (sc->rst_ephy != NULL) { + error = fdtbus_reset_deassert(sc->rst_ephy); + if (error != 0) { + aprint_error_dev(sc->dev, + "cannot de-assert ephy reset\n"); + return error; + } + } + + /* Enable PHY regulator if applicable */ + if (sc->reg_phy != NULL) { + error = fdtbus_regulator_enable(sc->reg_phy); + if (error != 0) { + aprint_error_dev(sc->dev, + "cannot enable PHY regulator\n"); + return error; + } + } + + /* Determine MDC clock divide ratio based on AHB clock */ + freq = clk_get_rate(sc->clk_ahb); + if (freq == 0) { + aprint_error_dev(sc->dev, "cannot get AHB clock frequency\n"); + return ENXIO; + } + div = freq / MDIO_FREQ; + if (div <= 16) + sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_16; + else if (div <= 32) + sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_32; + else if (div <= 64) + sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_64; + else if (div <= 128) + sc->mdc_div_ratio_m = MDC_DIV_RATIO_M_128; + else { + aprint_error_dev(sc->dev, + "cannot determine MDC clock divide ratio\n"); + return ENXIO; + } + + aprint_debug_dev(sc->dev, "AHB frequency %u Hz, MDC div: 0x%x\n", + freq, sc->mdc_div_ratio_m); + + return 0; +} + +static void +sunxi_emac_get_eaddr(struct sunxi_emac_softc *sc, uint8_t *eaddr) +{ + uint32_t maclo, machi; +#if notyet + u_char rootkey[16]; +#endif + + machi = RD4(sc, EMAC_ADDR_HIGH(0)) & 0xffff; + maclo = RD4(sc, EMAC_ADDR_LOW(0)); + + if (maclo == 0xffffffff && machi == 0xffff) { +#if notyet + /* MAC address in hardware is invalid, create one */ + if (aw_sid_get_rootkey(rootkey) == 0 && + (rootkey[3] | rootkey[12] | rootkey[13] | rootkey[14] | + rootkey[15]) != 0) { + /* MAC address is derived from the root key in SID */ + maclo = (rootkey[13] << 24) | (rootkey[12] << 16) | + (rootkey[3] << 8) | 0x02; + machi = (rootkey[15] << 8) | rootkey[14]; + } else { +#endif + /* Create one */ + maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); + machi = cprng_strong32() & 0xffff; +#if notyet + } +#endif + } + + eaddr[0] = maclo & 0xff; + eaddr[1] = (maclo >> 8) & 0xff; + eaddr[2] = (maclo >> 16) & 0xff; + eaddr[3] = (maclo >> 24) & 0xff; + eaddr[4] = machi & 0xff; + eaddr[5] = (machi >> 8) & 0xff; +} + +#ifdef SUNXI_EMAC_DEBUG +static void +sunxi_emac_dump_regs(struct sunxi_emac_softc *sc) +{ + static const struct { + const char *name; + u_int reg; + } regs[] = { + { "BASIC_CTL_0", EMAC_BASIC_CTL_0 }, + { "BASIC_CTL_1", EMAC_BASIC_CTL_1 }, + { "INT_STA", EMAC_INT_STA }, + { "INT_EN", EMAC_INT_EN }, + { "TX_CTL_0", EMAC_TX_CTL_0 }, + { "TX_CTL_1", EMAC_TX_CTL_1 }, + { "TX_FLOW_CTL", EMAC_TX_FLOW_CTL }, + { "TX_DMA_LIST", EMAC_TX_DMA_LIST }, + { "RX_CTL_0", EMAC_RX_CTL_0 }, + { "RX_CTL_1", EMAC_RX_CTL_1 }, + { "RX_DMA_LIST", EMAC_RX_DMA_LIST }, + { "RX_FRM_FLT", EMAC_RX_FRM_FLT }, + { "RX_HASH_0", EMAC_RX_HASH_0 }, + { "RX_HASH_1", EMAC_RX_HASH_1 }, + { "MII_CMD", EMAC_MII_CMD }, + { "ADDR_HIGH0", EMAC_ADDR_HIGH(0) }, + { "ADDR_LOW0", EMAC_ADDR_LOW(0) }, + { "TX_DMA_STA", EMAC_TX_DMA_STA }, + { "TX_DMA_CUR_DESC", EMAC_TX_DMA_CUR_DESC }, + { "TX_DMA_CUR_BUF", EMAC_TX_DMA_CUR_BUF }, + { "RX_DMA_STA", EMAC_RX_DMA_STA }, + { "RX_DMA_CUR_DESC", EMAC_RX_DMA_CUR_DESC }, + { "RX_DMA_CUR_BUF", EMAC_RX_DMA_CUR_BUF }, + { "RGMII_STA", EMAC_RGMII_STA }, + }; + u_int n; + + for (n = 0; n < __arraycount(regs); n++) + device_printf(dev, " %-20s %08x\n", regs[n].name, + RD4(sc, regs[n].reg)); +} +#endif + +static int +sunxi_emac_phy_reset(struct sunxi_emac_softc *sc) +{ + uint32_t delay_prop[3]; + int pin_value; + + if (sc->pin_reset == NULL) + return 0; + + if (OF_getprop(sc->phandle, "allwinner,reset-delays-us", delay_prop, + sizeof(delay_prop)) <= 0) + return ENXIO; + + pin_value = of_hasprop(sc->phandle, "allwinner,reset-active-low"); + + fdtbus_gpio_write(sc->pin_reset, pin_value); + delay(htole32(delay_prop[0])); + fdtbus_gpio_write(sc->pin_reset, !pin_value); + delay(htole32(delay_prop[1])); + fdtbus_gpio_write(sc->pin_reset, pin_value); + delay(htole32(delay_prop[2])); + + return 0; +} + +static int +sunxi_emac_reset(struct sunxi_emac_softc *sc) +{ + int retry; + + /* Reset PHY if necessary */ + if (sunxi_emac_phy_reset(sc) != 0) { + aprint_error_dev(sc->dev, "failed to reset PHY\n"); + return ENXIO; + } + + /* Soft reset all registers and logic */ + WR4(sc, EMAC_BASIC_CTL_1, BASIC_CTL_SOFT_RST); + + /* Wait for soft reset bit to self-clear */ + for (retry = SOFT_RST_RETRY; retry > 0; retry--) { + if ((RD4(sc, EMAC_BASIC_CTL_1) & BASIC_CTL_SOFT_RST) == 0) + break; + delay(10); + } + if (retry == 0) { + aprint_error_dev(sc->dev, "soft reset timed out\n"); +#ifdef SUNXI_EMAC_DEBUG + sunxi_emac_dump_regs(sc); +#endif + return ETIMEDOUT; + } + + return 0; +} + +static int +sunxi_emac_setup_dma(struct sunxi_emac_softc *sc) +{ + struct mbuf *m; + int error, nsegs, i; + + /* Setup TX ring */ + sc->tx.buf_tag = sc->tx.desc_tag = sc->dmat; + error = bus_dmamap_create(sc->dmat, TX_DESC_SIZE, 1, TX_DESC_SIZE, 0, + BUS_DMA_WAITOK, &sc->tx.desc_map); + if (error) + return error; + error = bus_dmamem_alloc(sc->dmat, TX_DESC_SIZE, DESC_ALIGN, 0, + &sc->tx.desc_dmaseg, 1, &nsegs, BUS_DMA_WAITOK); + if (error) + return error; + error = bus_dmamem_map(sc->dmat, &sc->tx.desc_dmaseg, nsegs, + TX_DESC_SIZE, (void *)&sc->tx.desc_ring, + BUS_DMA_WAITOK); + if (error) + return error; + error = bus_dmamap_load(sc->dmat, sc->tx.desc_map, sc->tx.desc_ring, + TX_DESC_SIZE, NULL, BUS_DMA_WAITOK); + if (error) + return error; + sc->tx.desc_ring_paddr = sc->tx.desc_map->dm_segs[0].ds_addr; + + memset(sc->tx.desc_ring, 0, TX_DESC_SIZE); + bus_dmamap_sync(sc->dmat, sc->tx.desc_map, 0, TX_DESC_SIZE, + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + + for (i = 0; i < TX_DESC_COUNT; i++) + sc->tx.desc_ring[i].next = + htole32(sc->tx.desc_ring_paddr + DESC_OFF(TX_NEXT(i))); + + sc->tx.queued = TX_DESC_COUNT; + for (i = 0; i < TX_DESC_COUNT; i++) { + error = bus_dmamap_create(sc->tx.buf_tag, MCLBYTES, + TX_MAX_SEGS, MCLBYTES, 0, BUS_DMA_WAITOK, + &sc->tx.buf_map[i].map); + if (error != 0) { + device_printf(sc->dev, "cannot create TX buffer map\n"); + return error; + } + sunxi_emac_setup_txdesc(sc, i, 0, 0, 0); + } + + /* Setup RX ring */ + sc->rx.buf_tag = sc->rx.desc_tag = sc->dmat; + error = bus_dmamap_create(sc->dmat, RX_DESC_SIZE, 1, RX_DESC_SIZE, 0, + BUS_DMA_WAITOK, &sc->rx.desc_map); + if (error) + return error; + error = bus_dmamem_alloc(sc->dmat, RX_DESC_SIZE, DESC_ALIGN, 0, + &sc->rx.desc_dmaseg, 1, &nsegs, BUS_DMA_WAITOK); + if (error) + return error; + error = bus_dmamem_map(sc->dmat, &sc->rx.desc_dmaseg, nsegs, + RX_DESC_SIZE, (void *)&sc->rx.desc_ring, + BUS_DMA_WAITOK); + if (error) + return error; + error = bus_dmamap_load(sc->dmat, sc->rx.desc_map, sc->rx.desc_ring, + RX_DESC_SIZE, NULL, BUS_DMA_WAITOK); + if (error) + return error; + sc->rx.desc_ring_paddr = sc->rx.desc_map->dm_segs[0].ds_addr; + + memset(sc->rx.desc_ring, 0, RX_DESC_SIZE); + + for (i = 0; i < RX_DESC_COUNT; i++) { + error = bus_dmamap_create(sc->rx.buf_tag, MCLBYTES, + RX_DESC_COUNT, MCLBYTES, 0, BUS_DMA_WAITOK, + &sc->rx.buf_map[i].map); + if (error != 0) { + device_printf(sc->dev, "cannot create RX buffer map\n"); + return error; + } + if ((m = sunxi_emac_alloc_mbufcl(sc)) == NULL) { + device_printf(sc->dev, "cannot allocate RX mbuf\n"); + return ENOMEM; + } + error = sunxi_emac_setup_rxbuf(sc, i, m); + if (error != 0) { + device_printf(sc->dev, "cannot create RX buffer\n"); + return error; + } + } + bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map, + 0, sc->rx.desc_map->dm_mapsize, + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + + /* Write transmit and receive descriptor base address registers */ + WR4(sc, EMAC_TX_DMA_LIST, sc->tx.desc_ring_paddr); + WR4(sc, EMAC_RX_DMA_LIST, sc->rx.desc_ring_paddr); + + return 0; +} + +static int +sunxi_emac_get_resources(struct sunxi_emac_softc *sc) +{ + const int phandle = sc->phandle; + bus_addr_t addr, size; + u_int n; + + /* Map registers */ + for (n = 0; n < _RES_NITEMS; n++) { + if (fdtbus_get_reg(phandle, n, &addr, &size) != 0) + return ENXIO; + if (bus_space_map(sc->bst, addr, size, 0, &sc->bsh[n]) != 0) + return ENXIO; + } + + /* Get clocks and resets. "ahb" is required, "ephy" is optional. */ + + if ((sc->clk_ahb = fdtbus_clock_get(phandle, "ahb")) == NULL) + return ENXIO; + sc->clk_ephy = fdtbus_clock_get(phandle, "ephy"); + + if ((sc->rst_ahb = fdtbus_reset_get(phandle, "ahb")) == NULL) + return ENXIO; + sc->rst_ahb = fdtbus_reset_get(phandle, "ephy"); + + /* Regulator is optional */ + sc->reg_phy = fdtbus_regulator_acquire(phandle, "phy-supply"); + + /* Reset GPIO is optional */ + sc->pin_reset = fdtbus_gpio_acquire(sc->phandle, + "allwinner,reset-gpio", GPIO_PIN_OUTPUT); + + return 0; +} + +static int +sunxi_emac_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compat_data(faa->faa_phandle, compat_data); +} + +static void +sunxi_emac_attach(device_t parent, device_t self, void *aux) +{ + struct fdt_attach_args * const faa = aux; + struct sunxi_emac_softc * const sc = device_private(self); + const int phandle = faa->faa_phandle; + struct mii_data *mii = &sc->mii; + struct ifnet *ifp = &sc->ec.ec_if; + uint8_t eaddr[ETHER_ADDR_LEN]; + char intrstr[128]; + + sc->dev = self; + sc->phandle = phandle; + sc->bst = faa->faa_bst; + sc->dmat = faa->faa_dmat; + sc->type = of_search_compatible(phandle, compat_data)->data; + + if (sunxi_emac_get_resources(sc) != 0) { + aprint_error(": cannot allocate resources for device\n"); + return; + } + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error(": cannot decode interrupt\n"); + return; + } + + mutex_init(&sc->mtx, MUTEX_DEFAULT, IPL_NET); + callout_init(&sc->stat_ch, CALLOUT_FLAGS); + callout_setfunc(&sc->stat_ch, sunxi_emac_tick, sc); + + aprint_naive("\n"); + aprint_normal(": EMAC\n"); + + /* Setup clocks and regulators */ + if (sunxi_emac_setup_resources(sc) != 0) + return; + + /* Read MAC address before resetting the chip */ + sunxi_emac_get_eaddr(sc, eaddr); + + /* Soft reset EMAC core */ + if (sunxi_emac_reset(sc) != 0) + return; + + /* Setup DMA descriptors */ + if (sunxi_emac_setup_dma(sc) != 0) { + aprint_error_dev(self, "failed to setup DMA descriptors\n"); + return; + } + + /* Install interrupt handler */ + sc->ih = fdtbus_intr_establish(phandle, 0, IPL_NET, + FDT_INTR_FLAGS, sunxi_emac_intr, sc); + if (sc->ih == NULL) { + aprint_error_dev(self, "failed to establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); + + /* Setup ethernet interface */ + ifp->if_softc = sc; + snprintf(ifp->if_xname, IFNAMSIZ, EMAC_IFNAME, device_unit(self)); + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; +#ifdef EMAC_MPSAFE + ifp->if_extflags = IFEF_START_MPSAFE; +#endif + ifp->if_start = sunxi_emac_start; + ifp->if_ioctl = sunxi_emac_ioctl; + ifp->if_init = sunxi_emac_init; + ifp->if_stop = sunxi_emac_stop; + ifp->if_capabilities = IFCAP_CSUM_IPv4_Rx | + IFCAP_CSUM_IPv4_Tx | + IFCAP_CSUM_TCPv4_Rx | + IFCAP_CSUM_TCPv4_Tx | + IFCAP_CSUM_UDPv4_Rx | + IFCAP_CSUM_UDPv4_Tx; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + IFQ_SET_READY(&ifp->if_snd); + + /* 802.1Q VLAN-sized frames are supported */ + sc->ec.ec_capabilities |= ETHERCAP_VLAN_MTU; + + /* Attach MII driver */ + sc->ec.ec_mii = mii; + ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus); + mii->mii_ifp = ifp; + mii->mii_readreg = sunxi_emac_mii_readreg; + mii->mii_writereg = sunxi_emac_mii_writereg; + mii->mii_statchg = sunxi_emac_mii_statchg; + mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, + MIIF_DOPAUSE); + + if (LIST_EMPTY(&mii->mii_phys)) { + aprint_error_dev(self, "no PHY found!\n"); + return; + } + ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO); + + /* Attach interface */ + if_attach(ifp); + if_deferred_start_init(ifp, NULL); + + /* Attach ethernet interface */ + ether_ifattach(ifp, eaddr); +} + +CFATTACH_DECL_NEW(sunxi_emac, sizeof(struct sunxi_emac_softc), + sunxi_emac_match, sunxi_emac_attach, NULL, NULL); diff --git a/sys/arch/arm/sunxi/sunxi_emac.h b/sys/arch/arm/sunxi/sunxi_emac.h new file mode 100644 index 000000000000..817fbed9b695 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_emac.h @@ -0,0 +1,184 @@ +/*- + * Copyright (c) 2016 Jared McNeill + * 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$ + */ + +/* + * Allwinner Gigabit Ethernet + */ + +#ifndef __SUNXI_EMAC_H__ +#define __SUNXI_EMAC_H__ + +#define EMAC_BASIC_CTL_0 0x00 +#define BASIC_CTL_SPEED (0x3 << 2) +#define BASIC_CTL_SPEED_SHIFT 2 +#define BASIC_CTL_SPEED_1000 0 +#define BASIC_CTL_SPEED_10 2 +#define BASIC_CTL_SPEED_100 3 +#define BASIC_CTL_LOOPBACK (1 << 1) +#define BASIC_CTL_DUPLEX (1 << 0) +#define EMAC_BASIC_CTL_1 0x04 +#define BASIC_CTL_BURST_LEN (0x3f << 24) +#define BASIC_CTL_BURST_LEN_SHIFT 24 +#define BASIC_CTL_RX_TX_PRI (1 << 1) +#define BASIC_CTL_SOFT_RST (1 << 0) +#define EMAC_INT_STA 0x08 +#define RX_BUF_UA_INT (1 << 10) +#define RX_INT (1 << 8) +#define TX_UNDERFLOW_INT (1 << 4) +#define TX_BUF_UA_INT (1 << 2) +#define TX_DMA_STOPPED_INT (1 << 1) +#define TX_INT (1 << 0) +#define EMAC_INT_EN 0x0c +#define RX_BUF_UA_INT_EN (1 << 10) +#define RX_INT_EN (1 << 8) +#define TX_UNDERFLOW_INT_EN (1 << 4) +#define TX_BUF_UA_INT_EN (1 << 2) +#define TX_DMA_STOPPED_INT_EN (1 << 1) +#define TX_INT_EN (1 << 0) +#define EMAC_TX_CTL_0 0x10 +#define TX_EN (1 << 31) +#define EMAC_TX_CTL_1 0x14 +#define TX_DMA_START (1 << 31) +#define TX_DMA_EN (1 << 30) +#define TX_NEXT_FRAME (1 << 2) +#define TX_MD (1 << 1) +#define FLUSH_TX_FIFO (1 << 0) +#define EMAC_TX_FLOW_CTL 0x1c +#define PAUSE_TIME (0xffff << 4) +#define PAUSE_TIME_SHIFT 4 +#define TX_FLOW_CTL_EN (1 << 0) +#define EMAC_TX_DMA_LIST 0x20 +#define EMAC_RX_CTL_0 0x24 +#define RX_EN (1 << 31) +#define JUMBO_FRM_EN (1 << 29) +#define STRIP_FCS (1 << 28) +#define CHECK_CRC (1 << 27) +#define RX_FLOW_CTL_EN (1 << 16) +#define EMAC_RX_CTL_1 0x28 +#define RX_DMA_START (1 << 31) +#define RX_DMA_EN (1 << 30) +#define RX_MD (1 << 1) +#define EMAC_RX_DMA_LIST 0x34 +#define EMAC_RX_FRM_FLT 0x38 +#define DIS_ADDR_FILTER (1 << 31) +#define DIS_BROADCAST (1 << 17) +#define RX_ALL_MULTICAST (1 << 16) +#define CTL_FRM_FILTER (0x3 << 12) +#define CTL_FRM_FILTER_SHIFT 12 +#define HASH_MULTICAST (1 << 9) +#define HASH_UNICAST (1 << 8) +#define SA_FILTER_EN (1 << 6) +#define SA_INV_FILTER (1 << 5) +#define DA_INV_FILTER (1 << 4) +#define FLT_MD (1 << 1) +#define RX_ALL (1 << 0) +#define EMAC_RX_HASH_0 0x40 +#define EMAC_RX_HASH_1 0x44 +#define EMAC_MII_CMD 0x48 +#define MDC_DIV_RATIO_M (0x7 << 20) +#define MDC_DIV_RATIO_M_16 0 +#define MDC_DIV_RATIO_M_32 1 +#define MDC_DIV_RATIO_M_64 2 +#define MDC_DIV_RATIO_M_128 3 +#define MDC_DIV_RATIO_M_SHIFT 20 +#define PHY_ADDR (0x1f << 12) +#define PHY_ADDR_SHIFT 12 +#define PHY_REG_ADDR (0x1f << 4) +#define PHY_REG_ADDR_SHIFT 4 +#define MII_WR (1 << 1) +#define MII_BUSY (1 << 0) +#define EMAC_MII_DATA 0x4c +#define EMAC_ADDR_HIGH(n) (0x50 + (n) * 8) +#define EMAC_ADDR_LOW(n) (0x54 + (n) * 8) +#define EMAC_TX_DMA_STA 0x80 +#define EMAC_TX_DMA_CUR_DESC 0x84 +#define EMAC_TX_DMA_CUR_BUF 0x88 +#define EMAC_RX_DMA_STA 0xc0 +#define EMAC_RX_DMA_CUR_DESC 0xc4 +#define EMAC_RX_DMA_CUR_BUF 0xc8 +#define EMAC_RGMII_STA 0xd0 + +struct sunxi_emac_desc { + uint32_t status; +/* Transmit */ +#define TX_DESC_CTL (1 << 31) +#define TX_HEADER_ERR (1 << 16) +#define TX_LENGTH_ERR (1 << 14) +#define TX_PAYLOAD_ERR (1 << 12) +#define TX_CRS_ERR (1 << 10) +#define TX_COL_ERR_0 (1 << 9) +#define TX_COL_ERR_1 (1 << 8) +#define TX_COL_CNT (0xf << 3) +#define TX_COL_CNT_SHIFT 3 +#define TX_DEFER_ERR (1 << 2) +#define TX_UNDERFLOW_ERR (1 << 1) +#define TX_DEFER (1 << 0) +/* Receive */ +#define RX_DESC_CTL (1 << 31) +#define RX_DAF_FAIL (1 << 30) +#define RX_FRM_LEN (0x3fff << 16) +#define RX_FRM_LEN_SHIFT 16 +#define RX_NO_ENOUGH_BUF_ERR (1 << 14) +#define RX_SAF_FAIL (1 << 13) +#define RX_OVERFLOW_ERR (1 << 11) +#define RX_FIR_DESC (1 << 9) +#define RX_LAST_DESC (1 << 8) +#define RX_HEADER_ERR (1 << 7) +#define RX_COL_ERR (1 << 6) +#define RX_FRM_TYPE (1 << 5) +#define RX_LENGTH_ERR (1 << 4) +#define RX_PHY_ERR (1 << 3) +#define RX_CRC_ERR (1 << 1) +#define RX_PAYLOAD_ERR (1 << 0) + + uint32_t size; +/* Transmit */ +#define TX_INT_CTL (1 << 31) +#define TX_LAST_DESC (1 << 30) +#define TX_FIR_DESC (1 << 29) +#define TX_CHECKSUM_CTL (0x3 << 27) +#define TX_CHECKSUM_CTL_IP 1 +#define TX_CHECKSUM_CTL_NO_PSE 2 +#define TX_CHECKSUM_CTL_FULL 3 +#define TX_CHECKSUM_CTL_SHIFT 27 +#define TX_CRC_CTL (1 << 26) +#define TX_BUF_SIZE (0xfff << 0) +#define TX_BUF_SIZE_SHIFT 0 +/* Receive */ +#define RX_INT_CTL (1 << 31) +#define RX_BUF_SIZE (0xfff << 0) +#define RX_BUF_SIZE_SHIFT 0 + + uint32_t addr; + + uint32_t next; +} __packed __aligned(CACHE_LINE_SIZE); + +__CTASSERT(sizeof(struct sunxi_emac_desc) == CACHE_LINE_SIZE); + +#endif /* !__SUNXI_EMAC_H__ */ diff --git a/sys/arch/arm/sunxi/sunxi_gates.c b/sys/arch/arm/sunxi/sunxi_gates.c new file mode 100644 index 000000000000..2b0c77084f92 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_gates.c @@ -0,0 +1,277 @@ +/* $NetBSD: sunxi_gates.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_gates.c,v 1.1.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include + +#include + +#include + +#define GATE_REG(index) (((index) / 32) * 4) +#define GATE_MASK(index) __BIT((index) % 32) + +static const char * compatible[] = { + "allwinner,sun4i-a10-gates-clk", + NULL +}; + +struct sunxi_gate { + struct clk base; + u_int index; + + TAILQ_ENTRY(sunxi_gate) gates; +}; + +struct sunxi_gates_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + int sc_phandle; + + struct clk_domain sc_clkdom; + TAILQ_HEAD(, sunxi_gate) sc_gates; +}; + +#define GATE_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define GATE_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static struct clk * +sunxi_gates_clock_decode(device_t dev, const void *data, size_t len) +{ + struct sunxi_gates_softc * const sc = device_private(dev); + struct sunxi_gate *gate; + + if (len != 4) + return NULL; + + const u_int index = be32dec(data); + + TAILQ_FOREACH(gate, &sc->sc_gates, gates) + if (gate->index == index) + return &gate->base; + + return NULL; +} + +static const struct fdtbus_clock_controller_func sunxi_gates_fdtclock_funcs = { + .decode = sunxi_gates_clock_decode, +}; + +static struct clk * +sunxi_gates_clock_get(void *priv, const char *name) +{ + struct sunxi_gates_softc * const sc = priv; + struct sunxi_gate *gate; + + TAILQ_FOREACH(gate, &sc->sc_gates, gates) + if (strcmp(gate->base.name, name) == 0) + return &gate->base; + + return NULL; +} + +static void +sunxi_gates_clock_put(void *priv, struct clk *clk) +{ +} + +static u_int +sunxi_gates_clock_get_rate(void *priv, struct clk *clkp) +{ + struct sunxi_gates_softc * const sc = priv; + struct sunxi_gate *gate = (struct sunxi_gate *)clkp; + struct clk *clkp_parent; + + clkp_parent = clk_get_parent(clkp); + if (clkp_parent == NULL) + return 0; + + const bus_size_t gate_reg = GATE_REG(gate->index); + const uint32_t gate_mask = GATE_MASK(gate->index); + + if ((GATE_READ(sc, gate_reg) & gate_mask) == 0) + return 0; + + return clk_get_rate(clkp_parent); +} + +static int +sunxi_gates_clock_enable(void *priv, struct clk *clkp) +{ + struct sunxi_gates_softc * const sc = priv; + struct sunxi_gate *gate = (struct sunxi_gate *)clkp; + uint32_t val; + + const bus_size_t gate_reg = GATE_REG(gate->index); + const uint32_t gate_mask = GATE_MASK(gate->index); + + val = GATE_READ(sc, gate_reg); + val |= gate_mask; + GATE_WRITE(sc, gate_reg, val); + + return 0; +} + +static int +sunxi_gates_clock_disable(void *priv, struct clk *clkp) +{ + struct sunxi_gates_softc * const sc = priv; + struct sunxi_gate *gate = (struct sunxi_gate *)clkp; + uint32_t val; + + const bus_size_t gate_reg = GATE_REG(gate->index); + const uint32_t gate_mask = GATE_MASK(gate->index); + + val = GATE_READ(sc, gate_reg); + val &= ~gate_mask; + GATE_WRITE(sc, gate_reg, val); + + return 0; +} + +static struct clk * +sunxi_gates_clock_get_parent(void *priv, struct clk *clkp) +{ + struct sunxi_gates_softc * const sc = priv; + + return fdtbus_clock_get_index(sc->sc_phandle, 0); +} + +static const struct clk_funcs sunxi_gates_clock_funcs = { + .get = sunxi_gates_clock_get, + .put = sunxi_gates_clock_put, + .get_rate = sunxi_gates_clock_get_rate, + .enable = sunxi_gates_clock_enable, + .disable = sunxi_gates_clock_disable, + .get_parent = sunxi_gates_clock_get_parent, +}; + +static void +sunxi_gates_print(struct sunxi_gates_softc *sc) +{ + struct sunxi_gate *gate; + struct clk *clkp_parent; + + TAILQ_FOREACH(gate, &sc->sc_gates, gates) { + clkp_parent = clk_get_parent(&gate->base); + + aprint_debug_dev(sc->sc_dev, + "%3d %-12s %2s %-12s %-7s ", + gate->index, + gate->base.name, + clkp_parent ? "<-" : "", + clkp_parent ? clkp_parent->name : "", + "gate"); + aprint_debug("%10d Hz\n", clk_get_rate(&gate->base)); + } +} + +static int +sunxi_gates_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sunxi_gates_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_gates_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct sunxi_gate *gate; + const u_int *indices; + bus_addr_t addr; + bus_size_t size; + int len, i; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_phandle = phandle; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + TAILQ_INIT(&sc->sc_gates); + + aprint_naive("\n"); + aprint_normal("\n"); + + sc->sc_clkdom.funcs = &sunxi_gates_clock_funcs; + sc->sc_clkdom.priv = sc; + + indices = fdtbus_get_prop(phandle, "clock-indices", &len); + if (indices == NULL) { + aprint_error_dev(self, "no clock-indices property\n"); + return; + } + + for (i = 0; + len >= sizeof(u_int); + len -= sizeof(u_int), i++, indices++) { + const u_int index = be32dec(indices); + const char *name = fdtbus_get_string_index(phandle, + "clock-output-names", i); + + if (name == NULL) { + aprint_error_dev(self, "no name for clk index %d\n", + index); + continue; + } + + gate = kmem_zalloc(sizeof(*gate), KM_SLEEP); + gate->base.domain = &sc->sc_clkdom; + gate->base.name = name; + gate->index = index; + + TAILQ_INSERT_TAIL(&sc->sc_gates, gate, gates); + } + + fdtbus_register_clock_controller(sc->sc_dev, phandle, + &sunxi_gates_fdtclock_funcs); + + sunxi_gates_print(sc); +} + +CFATTACH_DECL_NEW(sunxi_gates, sizeof(struct sunxi_gates_softc), + sunxi_gates_match, sunxi_gates_attach, NULL, NULL); diff --git a/sys/arch/arm/sunxi/sunxi_gpio.c b/sys/arch/arm/sunxi/sunxi_gpio.c new file mode 100644 index 000000000000..5274fe6b53df --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_gpio.c @@ -0,0 +1,556 @@ +/* $NetBSD: sunxi_gpio.c,v 1.8.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include "opt_soc.h" + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_gpio.c,v 1.8.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#define SUNXI_GPIO_PORT(port) (0x24 * (port)) +#define SUNXI_GPIO_CFG(port, pin) (SUNXI_GPIO_PORT(port) + 0x00 + (0x4 * ((pin) / 8))) +#define SUNXI_GPIO_CFG_PINMASK(pin) (0x7 << (((pin) % 8) * 4)) +#define SUNXI_GPIO_DATA(port) (SUNXI_GPIO_PORT(port) + 0x10) +#define SUNXI_GPIO_DRV(port, pin) (SUNXI_GPIO_PORT(port) + 0x14 + (0x4 * ((pin) / 16))) +#define SUNXI_GPIO_DRV_PINMASK(pin) (0x3 << (((pin) % 16) * 2)) +#define SUNXI_GPIO_PULL(port, pin) (SUNXI_GPIO_PORT(port) + 0x1c + (0x4 * ((pin) / 16))) +#define SUNXI_GPIO_PULL_DISABLE 0 +#define SUNXI_GPIO_PULL_UP 1 +#define SUNXI_GPIO_PULL_DOWN 2 +#define SUNXI_GPIO_PULL_PINMASK(pin) (0x3 << (((pin) % 16) * 2)) + +static const struct of_compat_data compat_data[] = { +#ifdef SOC_SUN6I_A31 + { "allwinner,sun6i-a31-pinctrl", (uintptr_t)&sun6i_a31_padconf }, + { "allwinner,sun6i-a31-r-pinctrl", (uintptr_t)&sun6i_a31_r_padconf }, +#endif +#ifdef SOC_SUN8I_A83T + { "allwinner,sun8i-a83t-pinctrl", (uintptr_t)&sun8i_a83t_padconf }, + { "allwinner,sun8i-a83t-r-pinctrl", (uintptr_t)&sun8i_a83t_r_padconf }, +#endif +#ifdef SOC_SUN8I_H3 + { "allwinner,sun8i-h3-pinctrl", (uintptr_t)&sun8i_h3_padconf }, + { "allwinner,sun8i-h3-r-pinctrl", (uintptr_t)&sun8i_h3_r_padconf }, +#endif + { NULL } +}; + +struct sunxi_gpio_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + const struct sunxi_gpio_padconf *sc_padconf; + kmutex_t sc_lock; + + struct gpio_chipset_tag sc_gp; + gpio_pin_t *sc_pins; + device_t sc_gpiodev; +}; + +struct sunxi_gpio_pin { + struct sunxi_gpio_softc *pin_sc; + const struct sunxi_gpio_pins *pin_def; + int pin_flags; + bool pin_actlo; +}; + +#define GPIO_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define GPIO_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static int sunxi_gpio_match(device_t, cfdata_t, void *); +static void sunxi_gpio_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(sunxi_gpio, sizeof(struct sunxi_gpio_softc), + sunxi_gpio_match, sunxi_gpio_attach, NULL, NULL); + +static const struct sunxi_gpio_pins * +sunxi_gpio_lookup(struct sunxi_gpio_softc *sc, uint8_t port, uint8_t pin) +{ + const struct sunxi_gpio_pins *pin_def; + u_int n; + + for (n = 0; n < sc->sc_padconf->npins; n++) { + pin_def = &sc->sc_padconf->pins[n]; + if (pin_def->port == port && pin_def->pin == pin) + return pin_def; + } + + return NULL; +} + +static const struct sunxi_gpio_pins * +sunxi_gpio_lookup_byname(struct sunxi_gpio_softc *sc, const char *name) +{ + const struct sunxi_gpio_pins *pin_def; + u_int n; + + for (n = 0; n < sc->sc_padconf->npins; n++) { + pin_def = &sc->sc_padconf->pins[n]; + if (strcmp(pin_def->name, name) == 0) + return pin_def; + } + + return NULL; +} + +static int +sunxi_gpio_setfunc(struct sunxi_gpio_softc *sc, + const struct sunxi_gpio_pins *pin_def, const char *func) +{ + uint32_t cfg; + u_int n; + + KASSERT(mutex_owned(&sc->sc_lock)); + + const bus_size_t cfg_reg = SUNXI_GPIO_CFG(pin_def->port, pin_def->pin); + const uint32_t cfg_mask = SUNXI_GPIO_CFG_PINMASK(pin_def->pin); + + for (n = 0; n < SUNXI_GPIO_MAXFUNC; n++) { + if (pin_def->functions[n] == NULL) + continue; + if (strcmp(pin_def->functions[n], func) == 0) { + cfg = GPIO_READ(sc, cfg_reg); + cfg &= ~cfg_mask; + cfg |= __SHIFTIN(n, cfg_mask); +#ifdef SUNXI_GPIO_DEBUG + device_printf(sc->sc_dev, "P%c%02d cfg %08x -> %08x\n", + pin_def->port + 'A', pin_def->pin, GPIO_READ(sc, cfg_reg), cfg); +#endif + GPIO_WRITE(sc, cfg_reg, cfg); + return 0; + } + } + + /* Function not found */ + device_printf(sc->sc_dev, "function '%s' not supported on P%c%02d\n", + func, pin_def->port + 'A', pin_def->pin); + + return ENXIO; +} + +static int +sunxi_gpio_setpull(struct sunxi_gpio_softc *sc, + const struct sunxi_gpio_pins *pin_def, int flags) +{ + uint32_t pull; + + KASSERT(mutex_owned(&sc->sc_lock)); + + const bus_size_t pull_reg = SUNXI_GPIO_PULL(pin_def->port, pin_def->pin); + const uint32_t pull_mask = SUNXI_GPIO_PULL_PINMASK(pin_def->pin); + + pull = GPIO_READ(sc, pull_reg); + pull &= ~pull_mask; + if (flags & GPIO_PIN_PULLUP) + pull |= __SHIFTIN(SUNXI_GPIO_PULL_UP, pull_mask); + else if (flags & GPIO_PIN_PULLDOWN) + pull |= __SHIFTIN(SUNXI_GPIO_PULL_DOWN, pull_mask); + else + pull |= __SHIFTIN(SUNXI_GPIO_PULL_DISABLE, pull_mask); +#ifdef SUNXI_GPIO_DEBUG + device_printf(sc->sc_dev, "P%c%02d pull %08x -> %08x\n", + pin_def->port + 'A', pin_def->pin, GPIO_READ(sc, pull_reg), pull); +#endif + GPIO_WRITE(sc, pull_reg, pull); + + return 0; +} + +static int +sunxi_gpio_setdrv(struct sunxi_gpio_softc *sc, + const struct sunxi_gpio_pins *pin_def, int drive_strength) +{ + uint32_t drv; + + KASSERT(mutex_owned(&sc->sc_lock)); + + if (drive_strength < 10 || drive_strength > 40) + return EINVAL; + + const bus_size_t drv_reg = SUNXI_GPIO_DRV(pin_def->port, pin_def->pin); + const uint32_t drv_mask = SUNXI_GPIO_DRV_PINMASK(pin_def->pin); + + drv = GPIO_READ(sc, drv_reg); + drv &= ~drv_mask; + drv |= __SHIFTIN((drive_strength / 10) - 1, drv_mask); +#ifdef SUNXI_GPIO_DEBUG + device_printf(sc->sc_dev, "P%c%02d drv %08x -> %08x\n", + pin_def->port + 'A', pin_def->pin, GPIO_READ(sc, drv_reg), drv); +#endif + GPIO_WRITE(sc, drv_reg, drv); + + return 0; +} + +static int +sunxi_gpio_ctl(struct sunxi_gpio_softc *sc, const struct sunxi_gpio_pins *pin_def, + int flags) +{ + KASSERT(mutex_owned(&sc->sc_lock)); + + if (flags & GPIO_PIN_INPUT) + return sunxi_gpio_setfunc(sc, pin_def, "gpio_in"); + if (flags & GPIO_PIN_OUTPUT) + return sunxi_gpio_setfunc(sc, pin_def, "gpio_out"); + + return EINVAL; +} + +static void * +sunxi_gpio_acquire(device_t dev, const void *data, size_t len, int flags) +{ + struct sunxi_gpio_softc * const sc = device_private(dev); + const struct sunxi_gpio_pins *pin_def; + struct sunxi_gpio_pin *gpin; + const u_int *gpio = data; + int error; + + if (len != 16) + return NULL; + + const uint8_t port = be32toh(gpio[1]) & 0xff; + const uint8_t pin = be32toh(gpio[2]) & 0xff; + const bool actlo = be32toh(gpio[3]) & 1; + + pin_def = sunxi_gpio_lookup(sc, port, pin); + if (pin_def == NULL) + return NULL; + + mutex_enter(&sc->sc_lock); + error = sunxi_gpio_ctl(sc, pin_def, flags); + mutex_exit(&sc->sc_lock); + + if (error != 0) + return NULL; + + gpin = kmem_zalloc(sizeof(*gpin), KM_SLEEP); + gpin->pin_sc = sc; + gpin->pin_def = pin_def; + gpin->pin_flags = flags; + gpin->pin_actlo = actlo; + + return gpin; +} + +static void +sunxi_gpio_release(device_t dev, void *priv) +{ + struct sunxi_gpio_pin *pin = priv; + + sunxi_gpio_ctl(pin->pin_sc, pin->pin_def, GPIO_PIN_INPUT); + + kmem_free(pin, sizeof(*pin)); +} + +static int +sunxi_gpio_read(device_t dev, void *priv, bool raw) +{ + struct sunxi_gpio_softc * const sc = device_private(dev); + struct sunxi_gpio_pin *pin = priv; + const struct sunxi_gpio_pins *pin_def = pin->pin_def; + uint32_t data; + int val; + + KASSERT(sc == pin->pin_sc); + + const bus_size_t data_reg = SUNXI_GPIO_DATA(pin_def->port); + const uint32_t data_mask = __BIT(pin_def->pin); + + /* No lock required for reads */ + data = GPIO_READ(sc, data_reg); + val = __SHIFTOUT(data, data_mask); + if (!raw && pin->pin_actlo) + val = !val; + +#ifdef SUNXI_GPIO_DEBUG + device_printf(dev, "P%c%02d rd %08x (%d %d)\n", + pin_def->port + 'A', pin_def->pin, data, + __SHIFTOUT(val, data_mask), val); +#endif + + return val; +} + +static void +sunxi_gpio_write(device_t dev, void *priv, int val, bool raw) +{ + struct sunxi_gpio_softc * const sc = device_private(dev); + struct sunxi_gpio_pin *pin = priv; + const struct sunxi_gpio_pins *pin_def = pin->pin_def; + uint32_t data; + + KASSERT(sc == pin->pin_sc); + + const bus_size_t data_reg = SUNXI_GPIO_DATA(pin_def->port); + const uint32_t data_mask = __BIT(pin_def->pin); + + if (!raw && pin->pin_actlo) + val = !val; + + mutex_enter(&sc->sc_lock); + data = GPIO_READ(sc, data_reg); + data &= ~data_mask; + data |= __SHIFTIN(val, data_mask); +#ifdef SUNXI_GPIO_DEBUG + device_printf(dev, "P%c%02d wr %08x -> %08x\n", + pin_def->port + 'A', pin_def->pin, GPIO_READ(sc, data_reg), data); +#endif + GPIO_WRITE(sc, data_reg, data); + mutex_exit(&sc->sc_lock); +} + +static struct fdtbus_gpio_controller_func sunxi_gpio_funcs = { + .acquire = sunxi_gpio_acquire, + .release = sunxi_gpio_release, + .read = sunxi_gpio_read, + .write = sunxi_gpio_write, +}; + +static int +sunxi_pinctrl_set_config(device_t dev, const void *data, size_t len) +{ + struct sunxi_gpio_softc * const sc = device_private(dev); + const struct sunxi_gpio_pins *pin_def; + u_int drive_strength; + + if (len != 4) + return -1; + + const int phandle = fdtbus_get_phandle_from_native(be32dec(data)); + + /* + * Required: pins, function + * Optional: bias-disable, bias-pull-up, bias-pull-down, drive-strength + */ + + const char *function = fdtbus_get_string(phandle, "function"); + if (function == NULL) + return -1; + int pins_len = OF_getproplen(phandle, "pins"); + if (pins_len <= 0) + return -1; + const char *pins = fdtbus_get_string(phandle, "pins"); + + mutex_enter(&sc->sc_lock); + + for (pins = fdtbus_get_string(phandle, "pins"); + pins_len > 0; + pins_len -= strlen(pins) + 1, pins += strlen(pins) + 1) { + pin_def = sunxi_gpio_lookup_byname(sc, pins); + if (pin_def == NULL) { + aprint_error_dev(dev, "unknown pin name '%s'\n", pins); + continue; + } + if (sunxi_gpio_setfunc(sc, pin_def, function) != 0) + continue; + + if (of_hasprop(phandle, "bias-disable")) + sunxi_gpio_setpull(sc, pin_def, 0); + else if (of_hasprop(phandle, "bias-pull-up")) + sunxi_gpio_setpull(sc, pin_def, GPIO_PIN_PULLUP); + else if (of_hasprop(phandle, "bias-pull-down")) + sunxi_gpio_setpull(sc, pin_def, GPIO_PIN_PULLDOWN); + + if (of_getprop_uint32(phandle, "drive-strength", &drive_strength) == 0) + sunxi_gpio_setdrv(sc, pin_def, drive_strength); + } + + mutex_exit(&sc->sc_lock); + + return 0; +} + +static struct fdtbus_pinctrl_controller_func sunxi_pinctrl_funcs = { + .set_config = sunxi_pinctrl_set_config, +}; + +static int +sunxi_gpio_pin_read(void *priv, int pin) +{ + struct sunxi_gpio_softc * const sc = priv; + const struct sunxi_gpio_pins *pin_def = &sc->sc_padconf->pins[pin]; + uint32_t data; + int val; + + KASSERT(pin < sc->sc_padconf->npins); + + const bus_size_t data_reg = SUNXI_GPIO_DATA(pin_def->port); + const uint32_t data_mask = __BIT(pin_def->pin); + + /* No lock required for reads */ + data = GPIO_READ(sc, data_reg); + val = __SHIFTOUT(data, data_mask); + + return val; +} + +static void +sunxi_gpio_pin_write(void *priv, int pin, int val) +{ + struct sunxi_gpio_softc * const sc = priv; + const struct sunxi_gpio_pins *pin_def = &sc->sc_padconf->pins[pin]; + uint32_t data; + + KASSERT(pin < sc->sc_padconf->npins); + + const bus_size_t data_reg = SUNXI_GPIO_DATA(pin_def->port); + const uint32_t data_mask = __BIT(pin_def->pin); + + mutex_enter(&sc->sc_lock); + data = GPIO_READ(sc, data_reg); + if (val) + data |= data_mask; + else + data &= ~data_mask; + GPIO_WRITE(sc, data_reg, data); + mutex_exit(&sc->sc_lock); +} + +static void +sunxi_gpio_pin_ctl(void *priv, int pin, int flags) +{ + struct sunxi_gpio_softc * const sc = priv; + const struct sunxi_gpio_pins *pin_def = &sc->sc_padconf->pins[pin]; + + KASSERT(pin < sc->sc_padconf->npins); + + mutex_enter(&sc->sc_lock); + sunxi_gpio_ctl(sc, pin_def, flags); + sunxi_gpio_setpull(sc, pin_def, flags); + mutex_exit(&sc->sc_lock); +} + +static void +sunxi_gpio_attach_ports(struct sunxi_gpio_softc *sc) +{ + const struct sunxi_gpio_pins *pin_def; + struct gpio_chipset_tag *gp = &sc->sc_gp; + struct gpiobus_attach_args gba; + u_int pin; + + gp->gp_cookie = sc; + gp->gp_pin_read = sunxi_gpio_pin_read; + gp->gp_pin_write = sunxi_gpio_pin_write; + gp->gp_pin_ctl = sunxi_gpio_pin_ctl; + + const u_int npins = sc->sc_padconf->npins; + sc->sc_pins = kmem_zalloc(sizeof(*sc->sc_pins) * npins, KM_SLEEP); + + for (pin = 0; pin < sc->sc_padconf->npins; pin++) { + pin_def = &sc->sc_padconf->pins[pin]; + sc->sc_pins[pin].pin_num = pin; + sc->sc_pins[pin].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | + GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN; + sc->sc_pins[pin].pin_state = sunxi_gpio_pin_read(sc, pin); + strlcpy(sc->sc_pins[pin].pin_defname, pin_def->name, + sizeof(sc->sc_pins[pin].pin_defname)); + } + + memset(&gba, 0, sizeof(gba)); + gba.gba_gc = gp; + gba.gba_pins = sc->sc_pins; + gba.gba_npins = npins; + sc->sc_gpiodev = config_found_ia(sc->sc_dev, "gpiobus", &gba, NULL); +} + +static int +sunxi_gpio_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compat_data(faa->faa_phandle, compat_data); +} + +static void +sunxi_gpio_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_gpio_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct fdtbus_reset *rst; + struct clk *clk; + bus_addr_t addr; + bus_size_t size; + int child; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + if ((clk = fdtbus_clock_get_index(phandle, 0)) != NULL) + if (clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock\n"); + return; + } + + if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) + if (fdtbus_reset_deassert(rst) != 0) { + aprint_error(": couldn't de-assert reset\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM); + sc->sc_padconf = (void *)of_search_compatible(phandle, compat_data)->data; + + aprint_naive("\n"); + aprint_normal(": PIO\n"); + + fdtbus_register_gpio_controller(self, phandle, &sunxi_gpio_funcs); + + for (child = OF_child(phandle); child; child = OF_peer(child)) { + if (!of_hasprop(child, "function") || !of_hasprop(child, "pins")) + continue; + fdtbus_register_pinctrl_config(self, child, &sunxi_pinctrl_funcs); + } + + fdtbus_pinctrl_configure(); + + sunxi_gpio_attach_ports(sc); +} diff --git a/sys/arch/arm/sunxi/sunxi_gpio.h b/sys/arch/arm/sunxi/sunxi_gpio.h new file mode 100644 index 000000000000..5bf421a86c2c --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_gpio.h @@ -0,0 +1,68 @@ +/* $NetBSD: sunxi_gpio.h,v 1.3.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * Copyright (c) 2016 Emmanuel Vadot + * 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 _ARM_SUNXI_GPIO_H +#define _ARM_SUNXI_GPIO_H + +#include "opt_soc.h" + +#define SUNXI_GPIO_MAXFUNC 8 + +struct sunxi_gpio_pins { + const char *name; + uint8_t port; + uint8_t pin; + const char *functions[SUNXI_GPIO_MAXFUNC]; + uint8_t eint_func; + uint8_t eint_num; +}; + +struct sunxi_gpio_padconf { + uint32_t npins; + const struct sunxi_gpio_pins *pins; +}; + +#ifdef SOC_SUN6I_A31 +extern const struct sunxi_gpio_padconf sun6i_a31_padconf; +extern const struct sunxi_gpio_padconf sun6i_a31_r_padconf; +#endif + +#ifdef SOC_SUN8I_A83T +extern const struct sunxi_gpio_padconf sun8i_a83t_padconf; +extern const struct sunxi_gpio_padconf sun8i_a83t_r_padconf; +#endif + +#ifdef SOC_SUN8I_H3 +extern const struct sunxi_gpio_padconf sun8i_h3_padconf; +extern const struct sunxi_gpio_padconf sun8i_h3_r_padconf; +#endif + +#endif /* _ARM_SUNXI_GPIO_H */ diff --git a/sys/arch/arm/sunxi/sunxi_mmc.c b/sys/arch/arm/sunxi/sunxi_mmc.c new file mode 100644 index 000000000000..6c4181b0af0d --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_mmc.c @@ -0,0 +1,857 @@ +/* $NetBSD: sunxi_mmc.c,v 1.3.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2014-2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_mmc.c,v 1.3.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#define SUNXI_MMC_NDESC 16 +#define SUNXI_MMC_DMA_XFERLEN 0x10000 +#define SUNXI_MMC_DMA_FTRGLEVEL 0x20070008 + +struct sunxi_mmc_softc; + +static int sunxi_mmc_match(device_t, cfdata_t, void *); +static void sunxi_mmc_attach(device_t, device_t, void *); +static void sunxi_mmc_attach_i(device_t); + +static int sunxi_mmc_intr(void *); +static int sunxi_mmc_idma_setup(struct sunxi_mmc_softc *); + +static int sunxi_mmc_host_reset(sdmmc_chipset_handle_t); +static uint32_t sunxi_mmc_host_ocr(sdmmc_chipset_handle_t); +static int sunxi_mmc_host_maxblklen(sdmmc_chipset_handle_t); +static int sunxi_mmc_card_detect(sdmmc_chipset_handle_t); +static int sunxi_mmc_write_protect(sdmmc_chipset_handle_t); +static int sunxi_mmc_bus_power(sdmmc_chipset_handle_t, uint32_t); +static int sunxi_mmc_bus_clock(sdmmc_chipset_handle_t, int); +static int sunxi_mmc_bus_width(sdmmc_chipset_handle_t, int); +static int sunxi_mmc_bus_rod(sdmmc_chipset_handle_t, int); +static void sunxi_mmc_exec_command(sdmmc_chipset_handle_t, + struct sdmmc_command *); +static void sunxi_mmc_card_enable_intr(sdmmc_chipset_handle_t, int); +static void sunxi_mmc_card_intr_ack(sdmmc_chipset_handle_t); + +static struct sdmmc_chip_functions sunxi_mmc_chip_functions = { + .host_reset = sunxi_mmc_host_reset, + .host_ocr = sunxi_mmc_host_ocr, + .host_maxblklen = sunxi_mmc_host_maxblklen, + .card_detect = sunxi_mmc_card_detect, + .write_protect = sunxi_mmc_write_protect, + .bus_power = sunxi_mmc_bus_power, + .bus_clock = sunxi_mmc_bus_clock, + .bus_width = sunxi_mmc_bus_width, + .bus_rod = sunxi_mmc_bus_rod, + .exec_command = sunxi_mmc_exec_command, + .card_enable_intr = sunxi_mmc_card_enable_intr, + .card_intr_ack = sunxi_mmc_card_intr_ack, +}; + +struct sunxi_mmc_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + bus_dma_tag_t sc_dmat; + int sc_phandle; + + void *sc_ih; + kmutex_t sc_intr_lock; + kcondvar_t sc_intr_cv; + kcondvar_t sc_idst_cv; + + int sc_mmc_width; + int sc_mmc_present; + + device_t sc_sdmmc_dev; + + uint32_t sc_dma_ftrglevel; + + uint32_t sc_idma_xferlen; + bus_dma_segment_t sc_idma_segs[1]; + int sc_idma_nsegs; + bus_size_t sc_idma_size; + bus_dmamap_t sc_idma_map; + int sc_idma_ndesc; + void *sc_idma_desc; + + uint32_t sc_intr_rint; + uint32_t sc_intr_mint; + uint32_t sc_idma_idst; + + struct clk *sc_clk_ahb; + struct clk *sc_clk_mmc; + struct clk *sc_clk_output; + struct clk *sc_clk_sample; + + struct fdtbus_reset *sc_rst_ahb; + + struct fdtbus_gpio_pin *sc_gpio_cd; + int sc_gpio_cd_inverted; + struct fdtbus_gpio_pin *sc_gpio_wp; + int sc_gpio_wp_inverted; +}; + +CFATTACH_DECL_NEW(sunxi_mmc, sizeof(struct sunxi_mmc_softc), + sunxi_mmc_match, sunxi_mmc_attach, NULL, NULL); + +#define MMC_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) +#define MMC_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) + +static const char * const compatible[] = { + "allwinner,sun7i-a20-mmc", + NULL +}; + +static int +sunxi_mmc_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sunxi_mmc_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_mmc_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_clk_ahb = fdtbus_clock_get(phandle, "ahb"); + sc->sc_clk_mmc = fdtbus_clock_get(phandle, "mmc"); + sc->sc_clk_output = fdtbus_clock_get(phandle, "output"); + sc->sc_clk_sample = fdtbus_clock_get(phandle, "sample"); + +#if notyet + if (sc->sc_clk_ahb == NULL || sc->sc_clk_mmc == NULL || + sc->sc_clk_output == NULL || sc->sc_clk_sample == NULL) { +#else + if (sc->sc_clk_ahb == NULL || sc->sc_clk_mmc == NULL) { +#endif + aprint_error(": couldn't get clocks\n"); + return; + } + + sc->sc_rst_ahb = fdtbus_reset_get(phandle, "ahb"); + if (sc->sc_rst_ahb == NULL) { + aprint_error(": couldn't get resets\n"); + return; + } + + if (clk_enable(sc->sc_clk_ahb) != 0 || + clk_enable(sc->sc_clk_mmc) != 0) { + aprint_error(": couldn't enable clocks\n"); + return; + } + + if (fdtbus_reset_deassert(sc->sc_rst_ahb) != 0) { + aprint_error(": couldn't de-assert resets\n"); + return; + } + + sc->sc_dev = self; + sc->sc_phandle = phandle; + sc->sc_bst = faa->faa_bst; + sc->sc_dmat = faa->faa_dmat; + mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO); + cv_init(&sc->sc_intr_cv, "awinmmcirq"); + cv_init(&sc->sc_idst_cv, "awinmmcdma"); + + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": SD/MMC controller\n"); + + sc->sc_gpio_cd = fdtbus_gpio_acquire(phandle, "cd-gpios", + GPIO_PIN_INPUT); + sc->sc_gpio_wp = fdtbus_gpio_acquire(phandle, "wp-gpios", + GPIO_PIN_INPUT); + + sc->sc_gpio_cd_inverted = of_hasprop(phandle, "cd-inverted") ? 0 : 1; + sc->sc_gpio_wp_inverted = of_hasprop(phandle, "wp-inverted") ? 0 : 1; + + sc->sc_dma_ftrglevel = SUNXI_MMC_DMA_FTRGLEVEL; + + if (sunxi_mmc_idma_setup(sc) != 0) { + aprint_error_dev(self, "failed to setup DMA\n"); + return; + } + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); + return; + } + + sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_BIO, FDT_INTR_MPSAFE, + sunxi_mmc_intr, sc); + if (sc->sc_ih == NULL) { + aprint_error_dev(self, "failed to establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); + + config_interrupts(self, sunxi_mmc_attach_i); +} + +static int +sunxi_mmc_idma_setup(struct sunxi_mmc_softc *sc) +{ + int error; + + sc->sc_idma_xferlen = SUNXI_MMC_DMA_XFERLEN; + + sc->sc_idma_ndesc = SUNXI_MMC_NDESC; + sc->sc_idma_size = sizeof(struct sunxi_mmc_idma_descriptor) * + sc->sc_idma_ndesc; + error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_idma_size, 0, + sc->sc_idma_size, sc->sc_idma_segs, 1, + &sc->sc_idma_nsegs, BUS_DMA_WAITOK); + if (error) + return error; + error = bus_dmamem_map(sc->sc_dmat, sc->sc_idma_segs, + sc->sc_idma_nsegs, sc->sc_idma_size, + &sc->sc_idma_desc, BUS_DMA_WAITOK); + if (error) + goto free; + error = bus_dmamap_create(sc->sc_dmat, sc->sc_idma_size, 1, + sc->sc_idma_size, 0, BUS_DMA_WAITOK, &sc->sc_idma_map); + if (error) + goto unmap; + error = bus_dmamap_load(sc->sc_dmat, sc->sc_idma_map, + sc->sc_idma_desc, sc->sc_idma_size, NULL, BUS_DMA_WAITOK); + if (error) + goto destroy; + return 0; + +destroy: + bus_dmamap_destroy(sc->sc_dmat, sc->sc_idma_map); +unmap: + bus_dmamem_unmap(sc->sc_dmat, sc->sc_idma_desc, sc->sc_idma_size); +free: + bus_dmamem_free(sc->sc_dmat, sc->sc_idma_segs, sc->sc_idma_nsegs); + return error; +} + +static int +sunxi_mmc_set_clock(struct sunxi_mmc_softc *sc, u_int freq) +{ + return clk_set_rate(sc->sc_clk_mmc, freq * 1000); +} + +static void +sunxi_mmc_attach_i(device_t self) +{ + struct sunxi_mmc_softc *sc = device_private(self); + struct sdmmcbus_attach_args saa; + uint32_t width; + + sunxi_mmc_host_reset(sc); + sunxi_mmc_bus_width(sc, 1); + sunxi_mmc_set_clock(sc, 400); + + if (of_getprop_uint32(sc->sc_phandle, "bus-width", &width) != 0) + width = 4; + + memset(&saa, 0, sizeof(saa)); + saa.saa_busname = "sdmmc"; + saa.saa_sct = &sunxi_mmc_chip_functions; + saa.saa_sch = sc; + saa.saa_dmat = sc->sc_dmat; + saa.saa_clkmin = 400; + saa.saa_clkmax = 52000; + saa.saa_caps = SMC_CAPS_DMA | + SMC_CAPS_MULTI_SEG_DMA | + SMC_CAPS_AUTO_STOP | + SMC_CAPS_SD_HIGHSPEED | + SMC_CAPS_MMC_HIGHSPEED; + if (width == 4) + saa.saa_caps |= SMC_CAPS_4BIT_MODE; + if (width == 8) + saa.saa_caps |= SMC_CAPS_8BIT_MODE; + + if (sc->sc_gpio_cd) + saa.saa_caps |= SMC_CAPS_POLL_CARD_DET; + + sc->sc_sdmmc_dev = config_found(self, &saa, NULL); +} + +static int +sunxi_mmc_intr(void *priv) +{ + struct sunxi_mmc_softc *sc = priv; + uint32_t idst, rint, mint; + + mutex_enter(&sc->sc_intr_lock); + idst = MMC_READ(sc, SUNXI_MMC_IDST); + rint = MMC_READ(sc, SUNXI_MMC_RINT); + mint = MMC_READ(sc, SUNXI_MMC_MINT); + if (!idst && !rint && !mint) { + mutex_exit(&sc->sc_intr_lock); + return 0; + } + MMC_WRITE(sc, SUNXI_MMC_IDST, idst); + MMC_WRITE(sc, SUNXI_MMC_RINT, rint); + MMC_WRITE(sc, SUNXI_MMC_MINT, mint); + +#ifdef SUNXI_MMC_DEBUG + device_printf(sc->sc_dev, "mmc intr idst=%08X rint=%08X mint=%08X\n", + idst, rint, mint); +#endif + + if (idst) { + sc->sc_idma_idst |= idst; + cv_broadcast(&sc->sc_idst_cv); + } + + if (rint) { + sc->sc_intr_rint |= rint; + cv_broadcast(&sc->sc_intr_cv); + } + + mutex_exit(&sc->sc_intr_lock); + + return 1; +} + +static int +sunxi_mmc_wait_rint(struct sunxi_mmc_softc *sc, uint32_t mask, int timeout) +{ + int retry; + int error; + + KASSERT(mutex_owned(&sc->sc_intr_lock)); + + if (sc->sc_intr_rint & mask) + return 0; + + retry = timeout / hz; + + while (retry > 0) { + error = cv_timedwait(&sc->sc_intr_cv, + &sc->sc_intr_lock, hz); + if (error && error != EWOULDBLOCK) + return error; + if (sc->sc_intr_rint & mask) + return 0; + --retry; + } + + return ETIMEDOUT; +} + +static int +sunxi_mmc_host_reset(sdmmc_chipset_handle_t sch) +{ + struct sunxi_mmc_softc *sc = sch; + int retry = 1000; + +#ifdef SUNXI_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, "host reset\n"); +#endif + + MMC_WRITE(sc, SUNXI_MMC_GCTRL, + MMC_READ(sc, SUNXI_MMC_GCTRL) | SUNXI_MMC_GCTRL_RESET); + while (--retry > 0) { + if (!(MMC_READ(sc, SUNXI_MMC_GCTRL) & SUNXI_MMC_GCTRL_RESET)) + break; + delay(100); + } + + MMC_WRITE(sc, SUNXI_MMC_TIMEOUT, 0xffffffff); + + MMC_WRITE(sc, SUNXI_MMC_IMASK, + SUNXI_MMC_INT_CMD_DONE | SUNXI_MMC_INT_ERROR | + SUNXI_MMC_INT_DATA_OVER | SUNXI_MMC_INT_AUTO_CMD_DONE); + + MMC_WRITE(sc, SUNXI_MMC_GCTRL, + MMC_READ(sc, SUNXI_MMC_GCTRL) | SUNXI_MMC_GCTRL_INTEN); + + + return 0; +} + +static uint32_t +sunxi_mmc_host_ocr(sdmmc_chipset_handle_t sch) +{ + return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V | MMC_OCR_HCS; +} + +static int +sunxi_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) +{ + return 8192; +} + +static int +sunxi_mmc_card_detect(sdmmc_chipset_handle_t sch) +{ + struct sunxi_mmc_softc *sc = sch; + + if (sc->sc_gpio_cd == NULL) { + return 1; /* no card detect pin, assume present */ + } else { + int v = 0, i; + for (i = 0; i < 5; i++) { + v += (fdtbus_gpio_read(sc->sc_gpio_cd) ^ + sc->sc_gpio_cd_inverted); + delay(1000); + } + if (v == 5) + sc->sc_mmc_present = 0; + else if (v == 0) + sc->sc_mmc_present = 1; + return sc->sc_mmc_present; + } +} + +static int +sunxi_mmc_write_protect(sdmmc_chipset_handle_t sch) +{ + struct sunxi_mmc_softc *sc = sch; + + if (sc->sc_gpio_wp == NULL) { + return 0; /* no write protect pin, assume rw */ + } else { + return fdtbus_gpio_read(sc->sc_gpio_wp) ^ + sc->sc_gpio_wp_inverted; + } +} + +static int +sunxi_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) +{ + return 0; +} + +static int +sunxi_mmc_update_clock(struct sunxi_mmc_softc *sc) +{ + uint32_t cmd; + int retry; + +#ifdef SUNXI_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, "update clock\n"); +#endif + + cmd = SUNXI_MMC_CMD_START | + SUNXI_MMC_CMD_UPCLK_ONLY | + SUNXI_MMC_CMD_WAIT_PRE_OVER; + MMC_WRITE(sc, SUNXI_MMC_CMD, cmd); + retry = 0xfffff; + while (--retry > 0) { + if (!(MMC_READ(sc, SUNXI_MMC_CMD) & SUNXI_MMC_CMD_START)) + break; + delay(10); + } + + if (retry == 0) { + aprint_error_dev(sc->sc_dev, "timeout updating clock\n"); +#ifdef SUNXI_MMC_DEBUG + device_printf(sc->sc_dev, "GCTRL: 0x%08x\n", + MMC_READ(sc, SUNXI_MMC_GCTRL)); + device_printf(sc->sc_dev, "CLKCR: 0x%08x\n", + MMC_READ(sc, SUNXI_MMC_CLKCR)); + device_printf(sc->sc_dev, "TIMEOUT: 0x%08x\n", + MMC_READ(sc, SUNXI_MMC_TIMEOUT)); + device_printf(sc->sc_dev, "WIDTH: 0x%08x\n", + MMC_READ(sc, SUNXI_MMC_WIDTH)); + device_printf(sc->sc_dev, "CMD: 0x%08x\n", + MMC_READ(sc, SUNXI_MMC_CMD)); + device_printf(sc->sc_dev, "MINT: 0x%08x\n", + MMC_READ(sc, SUNXI_MMC_MINT)); + device_printf(sc->sc_dev, "RINT: 0x%08x\n", + MMC_READ(sc, SUNXI_MMC_RINT)); + device_printf(sc->sc_dev, "STATUS: 0x%08x\n", + MMC_READ(sc, SUNXI_MMC_STATUS)); +#endif + return ETIMEDOUT; + } + + return 0; +} + +static int +sunxi_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +{ + struct sunxi_mmc_softc *sc = sch; + uint32_t clkcr; + + clkcr = MMC_READ(sc, SUNXI_MMC_CLKCR); + if (clkcr & SUNXI_MMC_CLKCR_CARDCLKON) { + clkcr &= ~SUNXI_MMC_CLKCR_CARDCLKON; + MMC_WRITE(sc, SUNXI_MMC_CLKCR, clkcr); + if (sunxi_mmc_update_clock(sc) != 0) + return 1; + } + + if (freq) { + + clkcr &= ~SUNXI_MMC_CLKCR_DIV; + MMC_WRITE(sc, SUNXI_MMC_CLKCR, clkcr); + if (sunxi_mmc_update_clock(sc) != 0) + return 1; + + if (sunxi_mmc_set_clock(sc, freq) != 0) + return 1; + + clkcr |= SUNXI_MMC_CLKCR_CARDCLKON; + MMC_WRITE(sc, SUNXI_MMC_CLKCR, clkcr); + if (sunxi_mmc_update_clock(sc) != 0) + return 1; + } + + return 0; +} + +static int +sunxi_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) +{ + struct sunxi_mmc_softc *sc = sch; + +#ifdef SUNXI_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, "width = %d\n", width); +#endif + + switch (width) { + case 1: + MMC_WRITE(sc, SUNXI_MMC_WIDTH, SUNXI_MMC_WIDTH_1); + break; + case 4: + MMC_WRITE(sc, SUNXI_MMC_WIDTH, SUNXI_MMC_WIDTH_4); + break; + case 8: + MMC_WRITE(sc, SUNXI_MMC_WIDTH, SUNXI_MMC_WIDTH_8); + break; + default: + return 1; + } + + sc->sc_mmc_width = width; + + return 0; +} + +static int +sunxi_mmc_bus_rod(sdmmc_chipset_handle_t sch, int on) +{ + return -1; +} + +static int +sunxi_mmc_dma_prepare(struct sunxi_mmc_softc *sc, struct sdmmc_command *cmd) +{ + struct sunxi_mmc_idma_descriptor *dma = sc->sc_idma_desc; + bus_addr_t desc_paddr = sc->sc_idma_map->dm_segs[0].ds_addr; + bus_size_t off; + int desc, resid, seg; + uint32_t val; + + desc = 0; + for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) { + bus_addr_t paddr = cmd->c_dmamap->dm_segs[seg].ds_addr; + bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len; + resid = min(len, cmd->c_resid); + off = 0; + while (resid > 0) { + if (desc == sc->sc_idma_ndesc) + break; + len = min(sc->sc_idma_xferlen, resid); + dma[desc].dma_buf_size = htole32(len); + dma[desc].dma_buf_addr = htole32(paddr + off); + dma[desc].dma_config = htole32(SUNXI_MMC_IDMA_CONFIG_CH | + SUNXI_MMC_IDMA_CONFIG_OWN); + cmd->c_resid -= len; + resid -= len; + off += len; + if (desc == 0) { + dma[desc].dma_config |= htole32(SUNXI_MMC_IDMA_CONFIG_FD); + } + if (cmd->c_resid == 0) { + dma[desc].dma_config |= htole32(SUNXI_MMC_IDMA_CONFIG_LD); + dma[desc].dma_config |= htole32(SUNXI_MMC_IDMA_CONFIG_ER); + dma[desc].dma_next = 0; + } else { + dma[desc].dma_config |= + htole32(SUNXI_MMC_IDMA_CONFIG_DIC); + dma[desc].dma_next = htole32( + desc_paddr + ((desc+1) * + sizeof(struct sunxi_mmc_idma_descriptor))); + } + ++desc; + } + } + if (desc == sc->sc_idma_ndesc) { + aprint_error_dev(sc->sc_dev, + "not enough descriptors for %d byte transfer!\n", + cmd->c_datalen); + return EIO; + } + + bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0, + sc->sc_idma_size, BUS_DMASYNC_PREWRITE); + + sc->sc_idma_idst = 0; + + val = MMC_READ(sc, SUNXI_MMC_GCTRL); + val |= SUNXI_MMC_GCTRL_DMAEN; + val |= SUNXI_MMC_GCTRL_INTEN; + MMC_WRITE(sc, SUNXI_MMC_GCTRL, val); + val |= SUNXI_MMC_GCTRL_DMARESET; + MMC_WRITE(sc, SUNXI_MMC_GCTRL, val); + MMC_WRITE(sc, SUNXI_MMC_DMAC, SUNXI_MMC_DMAC_SOFTRESET); + MMC_WRITE(sc, SUNXI_MMC_DMAC, + SUNXI_MMC_DMAC_IDMA_ON|SUNXI_MMC_DMAC_FIX_BURST); + val = MMC_READ(sc, SUNXI_MMC_IDIE); + val &= ~(SUNXI_MMC_IDST_RECEIVE_INT|SUNXI_MMC_IDST_TRANSMIT_INT); + if (cmd->c_flags & SCF_CMD_READ) + val |= SUNXI_MMC_IDST_RECEIVE_INT; + else + val |= SUNXI_MMC_IDST_TRANSMIT_INT; + MMC_WRITE(sc, SUNXI_MMC_IDIE, val); + MMC_WRITE(sc, SUNXI_MMC_DLBA, desc_paddr); + MMC_WRITE(sc, SUNXI_MMC_FTRGLEVEL, sc->sc_dma_ftrglevel); + + return 0; +} + +static void +sunxi_mmc_dma_complete(struct sunxi_mmc_softc *sc) +{ + bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0, + sc->sc_idma_size, BUS_DMASYNC_POSTWRITE); +} + +static void +sunxi_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) +{ + struct sunxi_mmc_softc *sc = sch; + uint32_t cmdval = SUNXI_MMC_CMD_START; + int retry; + +#ifdef SUNXI_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, + "opcode %d flags 0x%x data %p datalen %d blklen %d\n", + cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen, + cmd->c_blklen); +#endif + + mutex_enter(&sc->sc_intr_lock); + + if (cmd->c_opcode == 0) + cmdval |= SUNXI_MMC_CMD_SEND_INIT_SEQ; + if (cmd->c_flags & SCF_RSP_PRESENT) + cmdval |= SUNXI_MMC_CMD_RSP_EXP; + if (cmd->c_flags & SCF_RSP_136) + cmdval |= SUNXI_MMC_CMD_LONG_RSP; + if (cmd->c_flags & SCF_RSP_CRC) + cmdval |= SUNXI_MMC_CMD_CHECK_RSP_CRC; + + if (cmd->c_datalen > 0) { + unsigned int nblks; + + cmdval |= SUNXI_MMC_CMD_DATA_EXP | SUNXI_MMC_CMD_WAIT_PRE_OVER; + if (!ISSET(cmd->c_flags, SCF_CMD_READ)) { + cmdval |= SUNXI_MMC_CMD_WRITE; + } + + nblks = cmd->c_datalen / cmd->c_blklen; + if (nblks == 0 || (cmd->c_datalen % cmd->c_blklen) != 0) + ++nblks; + + if (nblks > 1) { + cmdval |= SUNXI_MMC_CMD_SEND_AUTO_STOP; + } + + MMC_WRITE(sc, SUNXI_MMC_BLKSZ, cmd->c_blklen); + MMC_WRITE(sc, SUNXI_MMC_BYTECNT, nblks * cmd->c_blklen); + } + + sc->sc_intr_rint = 0; + + MMC_WRITE(sc, SUNXI_MMC_A12A, + (cmdval & SUNXI_MMC_CMD_SEND_AUTO_STOP) ? 0 : 0xffff); + + MMC_WRITE(sc, SUNXI_MMC_ARG, cmd->c_arg); + +#ifdef SUNXI_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, "cmdval = %08x\n", cmdval); +#endif + + if (cmd->c_datalen == 0) { + MMC_WRITE(sc, SUNXI_MMC_CMD, cmdval | cmd->c_opcode); + } else { + cmd->c_resid = cmd->c_datalen; + cmd->c_error = sunxi_mmc_dma_prepare(sc, cmd); + MMC_WRITE(sc, SUNXI_MMC_CMD, cmdval | cmd->c_opcode); + if (cmd->c_error == 0) { + const uint32_t idst_mask = + SUNXI_MMC_IDST_ERROR | SUNXI_MMC_IDST_COMPLETE; + retry = 10; + while ((sc->sc_idma_idst & idst_mask) == 0) { + if (retry-- == 0) { + cmd->c_error = ETIMEDOUT; + break; + } + cv_timedwait(&sc->sc_idst_cv, + &sc->sc_intr_lock, hz); + } + } + sunxi_mmc_dma_complete(sc); + if (sc->sc_idma_idst & SUNXI_MMC_IDST_ERROR) { + cmd->c_error = EIO; + } else if (!(sc->sc_idma_idst & SUNXI_MMC_IDST_COMPLETE)) { + cmd->c_error = ETIMEDOUT; + } + if (cmd->c_error) { +#ifdef SUNXI_MMC_DEBUG + aprint_error_dev(sc->sc_dev, + "xfer failed, error %d\n", cmd->c_error); +#endif + goto done; + } + } + + cmd->c_error = sunxi_mmc_wait_rint(sc, + SUNXI_MMC_INT_ERROR|SUNXI_MMC_INT_CMD_DONE, hz * 10); + if (cmd->c_error == 0 && (sc->sc_intr_rint & SUNXI_MMC_INT_ERROR)) { + if (sc->sc_intr_rint & SUNXI_MMC_INT_RESP_TIMEOUT) { + cmd->c_error = ETIMEDOUT; + } else { + cmd->c_error = EIO; + } + } + if (cmd->c_error) { +#ifdef SUNXI_MMC_DEBUG + aprint_error_dev(sc->sc_dev, + "cmd failed, error %d\n", cmd->c_error); +#endif + goto done; + } + + if (cmd->c_datalen > 0) { + cmd->c_error = sunxi_mmc_wait_rint(sc, + SUNXI_MMC_INT_ERROR| + SUNXI_MMC_INT_AUTO_CMD_DONE| + SUNXI_MMC_INT_DATA_OVER, + hz*10); + if (cmd->c_error == 0 && + (sc->sc_intr_rint & SUNXI_MMC_INT_ERROR)) { + cmd->c_error = ETIMEDOUT; + } + if (cmd->c_error) { +#ifdef SUNXI_MMC_DEBUG + aprint_error_dev(sc->sc_dev, + "data timeout, rint = %08x\n", + sc->sc_intr_rint); +#endif + cmd->c_error = ETIMEDOUT; + goto done; + } + } + + if (cmd->c_flags & SCF_RSP_PRESENT) { + if (cmd->c_flags & SCF_RSP_136) { + cmd->c_resp[0] = MMC_READ(sc, SUNXI_MMC_RESP0); + cmd->c_resp[1] = MMC_READ(sc, SUNXI_MMC_RESP1); + cmd->c_resp[2] = MMC_READ(sc, SUNXI_MMC_RESP2); + cmd->c_resp[3] = MMC_READ(sc, SUNXI_MMC_RESP3); + if (cmd->c_flags & SCF_RSP_CRC) { + cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | + (cmd->c_resp[1] << 24); + cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | + (cmd->c_resp[2] << 24); + cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | + (cmd->c_resp[3] << 24); + cmd->c_resp[3] = (cmd->c_resp[3] >> 8); + } + } else { + cmd->c_resp[0] = MMC_READ(sc, SUNXI_MMC_RESP0); + } + } + +done: + cmd->c_flags |= SCF_ITSDONE; + mutex_exit(&sc->sc_intr_lock); + + if (cmd->c_error) { +#ifdef SUNXI_MMC_DEBUG + aprint_error_dev(sc->sc_dev, "i/o error %d\n", cmd->c_error); +#endif + MMC_WRITE(sc, SUNXI_MMC_GCTRL, + MMC_READ(sc, SUNXI_MMC_GCTRL) | + SUNXI_MMC_GCTRL_DMARESET | SUNXI_MMC_GCTRL_FIFORESET); + for (retry = 0; retry < 1000; retry++) { + if (!(MMC_READ(sc, SUNXI_MMC_GCTRL) & SUNXI_MMC_GCTRL_RESET)) + break; + delay(10); + } + sunxi_mmc_update_clock(sc); + } + + MMC_WRITE(sc, SUNXI_MMC_GCTRL, + MMC_READ(sc, SUNXI_MMC_GCTRL) | SUNXI_MMC_GCTRL_FIFORESET); +} + +static void +sunxi_mmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) +{ +} + +static void +sunxi_mmc_card_intr_ack(sdmmc_chipset_handle_t sch) +{ +} diff --git a/sys/arch/arm/sunxi/sunxi_mmc.h b/sys/arch/arm/sunxi/sunxi_mmc.h new file mode 100644 index 000000000000..dfe9f11350f7 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_mmc.h @@ -0,0 +1,179 @@ +/* $NetBSD: sunxi_mmc.h,v 1.2.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#ifndef _ARM_SUNXI_MMC_H +#define _ARM_SUNXI_MMC_H + +#define SUNXI_MMC_GCTRL 0x0000 +#define SUNXI_MMC_CLKCR 0x0004 +#define SUNXI_MMC_TIMEOUT 0x0008 +#define SUNXI_MMC_WIDTH 0x000C +#define SUNXI_MMC_BLKSZ 0x0010 +#define SUNXI_MMC_BYTECNT 0x0014 +#define SUNXI_MMC_CMD 0x0018 +#define SUNXI_MMC_ARG 0x001C +#define SUNXI_MMC_RESP0 0x0020 +#define SUNXI_MMC_RESP1 0x0024 +#define SUNXI_MMC_RESP2 0x0028 +#define SUNXI_MMC_RESP3 0x002C +#define SUNXI_MMC_IMASK 0x0030 +#define SUNXI_MMC_MINT 0x0034 +#define SUNXI_MMC_RINT 0x0038 +#define SUNXI_MMC_STATUS 0x003C +#define SUNXI_MMC_FTRGLEVEL 0x0040 +#define SUNXI_MMC_FUNCSEL 0x0044 +#define SUNXI_MMC_CBCR 0x0048 +#define SUNXI_MMC_BBCR 0x004C +#define SUNXI_MMC_DBGC 0x0050 +#define SUNXI_MMC_A12A 0x0058 /* A80 */ +#define SUNXI_MMC_HWRST 0x0078 /* A80 */ +#define SUNXI_MMC_DMAC 0x0080 +#define SUNXI_MMC_DLBA 0x0084 +#define SUNXI_MMC_IDST 0x0088 +#define SUNXI_MMC_IDIE 0x008C +#define SUNXI_MMC_CHDA 0x0090 +#define SUNXI_MMC_CBDA 0x0094 +#define SUNXI_MMC_FIFO 0x0100 +#define SUNXI_MMC_GCTRL_ACCESS_BY_AHB __BIT(31) +#define SUNXI_MMC_GCTRL_WAIT_MEM_ACCESS_DONE __BIT(30) +#define SUNXI_MMC_GCTRL_DDR_MODE __BIT(10) +#define SUNXI_MMC_GCTRL_DEBOUNCEEN __BIT(8) +#define SUNXI_MMC_GCTRL_DMAEN __BIT(5) +#define SUNXI_MMC_GCTRL_INTEN __BIT(4) +#define SUNXI_MMC_GCTRL_DMARESET __BIT(2) +#define SUNXI_MMC_GCTRL_FIFORESET __BIT(1) +#define SUNXI_MMC_GCTRL_SOFTRESET __BIT(0) +#define SUNXI_MMC_GCTRL_RESET \ + (SUNXI_MMC_GCTRL_SOFTRESET | SUNXI_MMC_GCTRL_FIFORESET | \ + SUNXI_MMC_GCTRL_DMARESET) +#define SUNXI_MMC_CLKCR_LOWPOWERON __BIT(17) +#define SUNXI_MMC_CLKCR_CARDCLKON __BIT(16) +#define SUNXI_MMC_CLKCR_DIV __BITS(15,0) +#define SUNXI_MMC_WIDTH_1 0 +#define SUNXI_MMC_WIDTH_4 1 +#define SUNXI_MMC_WIDTH_8 2 +#define SUNXI_MMC_CMD_START __BIT(31) +#define SUNXI_MMC_CMD_USE_HOLD_REG __BIT(29) +#define SUNXI_MMC_CMD_VOL_SWITCH __BIT(28) +#define SUNXI_MMC_CMD_BOOT_ABORT __BIT(27) +#define SUNXI_MMC_CMD_BOOT_ACK_EXP __BIT(26) +#define SUNXI_MMC_CMD_ALT_BOOT_OPT __BIT(25) +#define SUNXI_MMC_CMD_ENBOOT __BIT(24) +#define SUNXI_MMC_CMD_CCS_EXP __BIT(23) +#define SUNXI_MMC_CMD_RD_CEATA_DEV __BIT(22) +#define SUNXI_MMC_CMD_UPCLK_ONLY __BIT(21) +#define SUNXI_MMC_CMD_SEND_INIT_SEQ __BIT(15) +#define SUNXI_MMC_CMD_STOP_ABORT_CMD __BIT(14) +#define SUNXI_MMC_CMD_WAIT_PRE_OVER __BIT(13) +#define SUNXI_MMC_CMD_SEND_AUTO_STOP __BIT(12) +#define SUNXI_MMC_CMD_SEQMOD __BIT(11) +#define SUNXI_MMC_CMD_WRITE __BIT(10) +#define SUNXI_MMC_CMD_DATA_EXP __BIT(9) +#define SUNXI_MMC_CMD_CHECK_RSP_CRC __BIT(8) +#define SUNXI_MMC_CMD_LONG_RSP __BIT(7) +#define SUNXI_MMC_CMD_RSP_EXP __BIT(6) +#define SUNXI_MMC_INT_CARD_REMOVE __BIT(31) +#define SUNXI_MMC_INT_CARD_INSERT __BIT(30) +#define SUNXI_MMC_INT_SDIO_INT __BIT(16) +#define SUNXI_MMC_INT_END_BIT_ERR __BIT(15) +#define SUNXI_MMC_INT_AUTO_CMD_DONE __BIT(14) +#define SUNXI_MMC_INT_START_BIT_ERR __BIT(13) +#define SUNXI_MMC_INT_HW_LOCKED __BIT(12) +#define SUNXI_MMC_INT_FIFO_RUN_ERR __BIT(11) +#define SUNXI_MMC_INT_VOL_CHG_DONE __BIT(10) +#define SUNXI_MMC_INT_DATA_STARVE __BIT(10) +#define SUNXI_MMC_INT_BOOT_START __BIT(9) +#define SUNXI_MMC_INT_DATA_TIMEOUT __BIT(9) +#define SUNXI_MMC_INT_ACK_RCV __BIT(8) +#define SUNXI_MMC_INT_RESP_TIMEOUT __BIT(8) +#define SUNXI_MMC_INT_DATA_CRC_ERR __BIT(7) +#define SUNXI_MMC_INT_RESP_CRC_ERR __BIT(6) +#define SUNXI_MMC_INT_RX_DATA_REQ __BIT(5) +#define SUNXI_MMC_INT_TX_DATA_REQ __BIT(4) +#define SUNXI_MMC_INT_DATA_OVER __BIT(3) +#define SUNXI_MMC_INT_CMD_DONE __BIT(2) +#define SUNXI_MMC_INT_RESP_ERR __BIT(1) +#define SUNXI_MMC_INT_ERROR \ + (SUNXI_MMC_INT_RESP_ERR | SUNXI_MMC_INT_RESP_CRC_ERR | \ + SUNXI_MMC_INT_DATA_CRC_ERR | SUNXI_MMC_INT_RESP_TIMEOUT | \ + SUNXI_MMC_INT_FIFO_RUN_ERR | SUNXI_MMC_INT_HW_LOCKED | \ + SUNXI_MMC_INT_START_BIT_ERR | SUNXI_MMC_INT_END_BIT_ERR) +#define SUNXI_MMC_STATUS_DMAREQ __BIT(31) +#define SUNXI_MMC_STATUS_DATA_FSM_BUSY __BIT(10) +#define SUNXI_MMC_STATUS_CARD_DATA_BUSY __BIT(9) +#define SUNXI_MMC_STATUS_CARD_PRESENT __BIT(8) +#define SUNXI_MMC_STATUS_FIFO_FULL __BIT(3) +#define SUNXI_MMC_STATUS_FIFO_EMPTY __BIT(2) +#define SUNXI_MMC_STATUS_TXWL_FLAG __BIT(1) +#define SUNXI_MMC_STATUS_RXWL_FLAG __BIT(0) +#define SUNXI_MMC_FUNCSEL_CEATA_DEV_INTEN __BIT(10) +#define SUNXI_MMC_FUNCSEL_SEND_AUTO_STOP_CCSD __BIT(9) +#define SUNXI_MMC_FUNCSEL_SEND_CCSD __BIT(8) +#define SUNXI_MMC_FUNCSEL_ABT_RD_DATA __BIT(2) +#define SUNXI_MMC_FUNCSEL_SDIO_RD_WAIT __BIT(1) +#define SUNXI_MMC_FUNCSEL_SEND_IRQ_RSP __BIT(0) +#define SUNXI_MMC_DMAC_REFETCH_DES __BIT(31) +#define SUNXI_MMC_DMAC_IDMA_ON __BIT(7) +#define SUNXI_MMC_DMAC_FIX_BURST __BIT(1) +#define SUNXI_MMC_DMAC_SOFTRESET __BIT(0) +#define SUNXI_MMC_IDST_HOST_ABT __BIT(10) +#define SUNXI_MMC_IDST_ABNORMAL_INT_SUM __BIT(9) +#define SUNXI_MMC_IDST_NORMAL_INT_SUM __BIT(8) +#define SUNXI_MMC_IDST_CARD_ERR_SUM __BIT(5) +#define SUNXI_MMC_IDST_DES_INVALID __BIT(4) +#define SUNXI_MMC_IDST_FATAL_BUS_ERR __BIT(2) +#define SUNXI_MMC_IDST_RECEIVE_INT __BIT(1) +#define SUNXI_MMC_IDST_TRANSMIT_INT __BIT(0) +#define SUNXI_MMC_IDST_ERROR \ + (SUNXI_MMC_IDST_ABNORMAL_INT_SUM | SUNXI_MMC_IDST_CARD_ERR_SUM | \ + SUNXI_MMC_IDST_DES_INVALID | SUNXI_MMC_IDST_FATAL_BUS_ERR) +#define SUNXI_MMC_IDST_COMPLETE \ + (SUNXI_MMC_IDST_RECEIVE_INT | SUNXI_MMC_IDST_TRANSMIT_INT) +#define SUNXI_MMC_IDMA_CONFIG_DIC __BIT(1) +#define SUNXI_MMC_IDMA_CONFIG_LD __BIT(2) +#define SUNXI_MMC_IDMA_CONFIG_FD __BIT(3) +#define SUNXI_MMC_IDMA_CONFIG_CH __BIT(4) +#define SUNXI_MMC_IDMA_CONFIG_ER __BIT(5) +#define SUNXI_MMC_IDMA_CONFIG_CES __BIT(30) +#define SUNXI_MMC_IDMA_CONFIG_OWN __BIT(31) + +struct sunxi_mmc_idma_descriptor { + uint32_t dma_config; +#define SUNXI_MMC_IDMA_CONFIG_DIC __BIT(1) +#define SUNXI_MMC_IDMA_CONFIG_LD __BIT(2) +#define SUNXI_MMC_IDMA_CONFIG_FD __BIT(3) +#define SUNXI_MMC_IDMA_CONFIG_CH __BIT(4) +#define SUNXI_MMC_IDMA_CONFIG_ER __BIT(5) +#define SUNXI_MMC_IDMA_CONFIG_CES __BIT(30) +#define SUNXI_MMC_IDMA_CONFIG_OWN __BIT(31) + uint32_t dma_buf_size; + uint32_t dma_buf_addr; + uint32_t dma_next; +} __packed; + +#endif /* _ARM_SUNXI_MMC_H */ diff --git a/sys/arch/arm/sunxi/sunxi_platform.c b/sys/arch/arm/sunxi/sunxi_platform.c new file mode 100644 index 000000000000..93d04ee601ff --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_platform.c @@ -0,0 +1,170 @@ +/* $NetBSD: sunxi_platform.c,v 1.5.4.2 2017/07/18 19:13:08 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include "opt_soc.h" +#include "opt_multiprocessor.h" +#include "opt_fdt_arm.h" + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_platform.c,v 1.5.4.2 2017/07/18 19:13:08 snj Exp $"); + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#define SUNXI_REF_FREQ 24000000 + +#define SUN6I_WDT_BASE 0x01c20ca0 +#define SUN6I_WDT_SIZE 0x20 +#define SUN6I_WDT_CFG 0x14 +#define SUN6I_WDT_CFG_SYS 1 +#define SUN6I_WDT_MODE 0x18 +#define SUN6I_WDT_MODE_EN 1 + + +#define DEVMAP_ALIGN(a) ((a) & ~L1_S_OFFSET) +#define DEVMAP_SIZE(s) roundup2((s), L1_S_SIZE) +#define DEVMAP_ENTRY(va, pa, sz) \ + { \ + .pd_va = DEVMAP_ALIGN(va), \ + .pd_pa = DEVMAP_ALIGN(pa), \ + .pd_size = DEVMAP_SIZE(sz), \ + .pd_prot = VM_PROT_READ|VM_PROT_WRITE, \ + .pd_cache = PTE_NOCACHE \ + } +#define DEVMAP_ENTRY_END { 0 } + +extern struct bus_space armv7_generic_bs_tag; +extern struct bus_space armv7_generic_a4x_bs_tag; +extern struct arm32_bus_dma_tag armv7_generic_dma_tag; + +static const struct pmap_devmap * +sunxi_platform_devmap(void) +{ + static const struct pmap_devmap devmap[] = { + DEVMAP_ENTRY(SUNXI_CORE_VBASE, + SUNXI_CORE_PBASE, + SUNXI_CORE_SIZE), + DEVMAP_ENTRY_END + }; + + return devmap; +} + +static void +sunxi_platform_init_attach_args(struct fdt_attach_args *faa) +{ + faa->faa_bst = &armv7_generic_bs_tag; + faa->faa_a4x_bst = &armv7_generic_a4x_bs_tag; + faa->faa_dmat = &armv7_generic_dma_tag; +} + +static void +sunxi_platform_early_putchar(char c) +{ +#ifdef CONSADDR +#define CONSADDR_VA ((CONSADDR - SUNXI_CORE_PBASE) + SUNXI_CORE_VBASE) + volatile uint32_t *uartaddr = (volatile uint32_t *)CONSADDR_VA; + + while ((uartaddr[com_lsr] & LSR_TXRDY) == 0) + ; + + uartaddr[com_data] = c; +#endif +} + +static void +sunxi_platform_device_register(device_t self, void *aux) +{ +} + +static u_int +sunxi_platform_uart_freq(void) +{ + return SUNXI_REF_FREQ; +} + +static void +sun6i_platform_reset(void) +{ + bus_space_tag_t bst = &armv7_generic_bs_tag; + bus_space_handle_t bsh; + + bus_space_map(bst, SUN6I_WDT_BASE, SUN6I_WDT_SIZE, 0, &bsh); + + bus_space_write_4(bst, bsh, SUN6I_WDT_CFG, SUN6I_WDT_CFG_SYS); + bus_space_write_4(bst, bsh, SUN6I_WDT_MODE, SUN6I_WDT_MODE_EN); +} + +static const struct arm_platform sun8i_platform = { + .devmap = sunxi_platform_devmap, + .bootstrap = psci_fdt_bootstrap, + .init_attach_args = sunxi_platform_init_attach_args, + .early_putchar = sunxi_platform_early_putchar, + .device_register = sunxi_platform_device_register, + .reset = sun6i_platform_reset, + .delay = gtmr_delay, + .uart_freq = sunxi_platform_uart_freq, +}; + +ARM_PLATFORM(sun8i_h3, "allwinner,sun8i-h3", &sun8i_platform); +ARM_PLATFORM(sun8i_a83t, "allwinner,sun8i-a83t", &sun8i_platform); + +static const struct arm_platform sun6i_platform = { + .devmap = sunxi_platform_devmap, + .bootstrap = psci_fdt_bootstrap, + .init_attach_args = sunxi_platform_init_attach_args, + .early_putchar = sunxi_platform_early_putchar, + .device_register = sunxi_platform_device_register, + .reset = sun6i_platform_reset, + .delay = gtmr_delay, + .uart_freq = sunxi_platform_uart_freq, +}; + +ARM_PLATFORM(sun6i_a31, "allwinner,sun6i-a31", &sun6i_platform); diff --git a/sys/arch/arm/sunxi/sunxi_platform.h b/sys/arch/arm/sunxi/sunxi_platform.h new file mode 100644 index 000000000000..7abfddf9db07 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_platform.h @@ -0,0 +1,38 @@ +/* $NetBSD: sunxi_platform.h,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#ifndef _ARM_SUNXI_PLATFORM_H +#define _ARM_SUNXI_PLATFORM_H + +#include + +#define SUNXI_CORE_VBASE (KERNEL_VM_BASE + KERNEL_VM_SIZE) +#define SUNXI_CORE_PBASE 0x01c00000 +#define SUNXI_CORE_SIZE 0x00400000 + +#endif /* _ARM_SUNXI_PLATFORM_H */ diff --git a/sys/arch/arm/sunxi/sunxi_resets.c b/sys/arch/arm/sunxi/sunxi_resets.c new file mode 100644 index 000000000000..2e01bd61bf60 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_resets.c @@ -0,0 +1,149 @@ +/* $NetBSD: sunxi_resets.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_resets.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include + +#include + +#include + +#define RESET_REG(index) (((index) / 32) * 4) +#define RESET_MASK(index) __BIT((index) % 32) + +static const char * compatible[] = { + "allwinner,sun6i-a31-clock-reset", + NULL +}; + +struct sunxi_resets_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; +}; + +#define RESET_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define RESET_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static void * +sunxi_resets_acquire(device_t dev, const void *data, size_t len) +{ + if (len != 4) + return NULL; + + /* Specifier is an index. Just return it. */ + return (void *)(uintptr_t)be32dec(data); +} + +static void +sunxi_resets_release(device_t dev, void *priv) +{ +} + +static int +sunxi_resets_assert(device_t dev, void *priv) +{ + struct sunxi_resets_softc * const sc = device_private(dev); + const uintptr_t index = (uintptr_t)priv; + + const bus_size_t reset_reg = RESET_REG(index); + const uint32_t reset_mask = RESET_MASK(index); + + const uint32_t val = RESET_READ(sc, reset_reg); + RESET_WRITE(sc, reset_reg, val & ~reset_mask); + + return 0; +} + +static int +sunxi_resets_deassert(device_t dev, void *priv) +{ + struct sunxi_resets_softc * const sc = device_private(dev); + const uintptr_t index = (uintptr_t)priv; + + const bus_size_t reset_reg = RESET_REG(index); + const uint32_t reset_mask = RESET_MASK(index); + + const uint32_t val = RESET_READ(sc, reset_reg); + RESET_WRITE(sc, reset_reg, val | reset_mask); + + return 0; +} + +static const struct fdtbus_reset_controller_func sunxi_fdtreset_funcs = { + .acquire = sunxi_resets_acquire, + .release = sunxi_resets_release, + .reset_assert = sunxi_resets_assert, + .reset_deassert = sunxi_resets_deassert, +}; + +static int +sunxi_resets_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sunxi_resets_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_resets_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal("\n"); + + fdtbus_register_reset_controller(sc->sc_dev, phandle, + &sunxi_fdtreset_funcs); +} + +CFATTACH_DECL_NEW(sunxi_resets, sizeof(struct sunxi_resets_softc), + sunxi_resets_match, sunxi_resets_attach, NULL, NULL); diff --git a/sys/arch/arm/sunxi/sunxi_rsb.c b/sys/arch/arm/sunxi/sunxi_rsb.c new file mode 100644 index 000000000000..b2f2c6e2ddac --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_rsb.c @@ -0,0 +1,479 @@ +/* $NetBSD: sunxi_rsb.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2014-2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_rsb.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +enum sunxi_rsb_type { + SUNXI_P2WI, + SUNXI_RSB, +}; + +static const struct of_compat_data compat_data[] = { + { "allwinner,sun6i-a31-p2wi", SUNXI_P2WI }, + { "allwinner,sun8i-a23-rsb", SUNXI_RSB }, + { NULL } +}; + +#define RSB_ADDR_PMIC_PRIMARY 0x3a3 +#define RSB_ADDR_PMIC_SECONDARY 0x745 +#define RSB_ADDR_PERIPH_IC 0xe89 + +/* + * Device address to Run-time address mappings. + * + * Run-time address (RTA) is an 8-bit value used to address the device during + * a read or write transaction. The following are valid RTAs: + * 0x17 0x2d 0x3a 0x4e 0x59 0x63 0x74 0x8b 0x9c 0xa6 0xb1 0xc5 0xd2 0xe8 0xff + * + * Allwinner uses RTA 0x2d for the primary PMIC, 0x3a for the secondary PMIC, + * and 0x4e for the peripheral IC (where applicable). + */ +static const struct { + uint16_t addr; + uint8_t rta; +} rsb_rtamap[] = { + { .addr = RSB_ADDR_PMIC_PRIMARY, .rta = 0x2d }, + { .addr = RSB_ADDR_PMIC_SECONDARY, .rta = 0x3a }, + { .addr = RSB_ADDR_PERIPH_IC, .rta = 0x4e }, + { .addr = 0, .rta = 0 } +}; + +struct sunxi_rsb_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + enum sunxi_rsb_type sc_type; + struct i2c_controller sc_ic; + kmutex_t sc_lock; + kcondvar_t sc_cv; + device_t sc_i2cdev; + void *sc_ih; + uint32_t sc_stat; + + uint16_t sc_rsb_last_da; +}; + +#define RSB_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define RSB_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static int sunxi_rsb_acquire_bus(void *, int); +static void sunxi_rsb_release_bus(void *, int); +static int sunxi_rsb_exec(void *, i2c_op_t, i2c_addr_t, const void *, + size_t, void *, size_t, int); + +static int sunxi_rsb_intr(void *); +static int sunxi_rsb_wait(struct sunxi_rsb_softc *, int); +static int sunxi_rsb_rsb_config(struct sunxi_rsb_softc *, + uint8_t, i2c_addr_t, int); + +static int sunxi_rsb_match(device_t, cfdata_t, void *); +static void sunxi_rsb_attach(device_t, device_t, void *); + +static i2c_tag_t +sunxi_rsb_get_tag(device_t dev) +{ + struct sunxi_rsb_softc * const sc = device_private(dev); + + return &sc->sc_ic; +} + +static const struct fdtbus_i2c_controller_func sunxi_rsb_funcs = { + .get_tag = sunxi_rsb_get_tag, +}; + +CFATTACH_DECL_NEW(sunxi_rsb, sizeof(struct sunxi_rsb_softc), + sunxi_rsb_match, sunxi_rsb_attach, NULL, NULL); + +static int +sunxi_rsb_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compat_data(faa->faa_phandle, compat_data); +} + +static void +sunxi_rsb_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_rsb_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct i2cbus_attach_args iba; + prop_dictionary_t devs; + uint32_t address_cells; + struct fdtbus_reset *rst; + struct clk *clk; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error(": couldn't decode interrupt\n"); + return; + } + + if ((clk = fdtbus_clock_get_index(phandle, 0)) != NULL) + if (clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock\n"); + return; + } + if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) + if (fdtbus_reset_deassert(rst) != 0) { + aprint_error(": couldn't de-assert reset\n"); + return; + } + + sc->sc_dev = self; + sc->sc_type = of_search_compatible(phandle, compat_data)->data; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SCHED); + cv_init(&sc->sc_cv, "awinp2wi"); + + aprint_naive("\n"); + aprint_normal(": %s\n", sc->sc_type == SUNXI_P2WI ? "P2WI" : "RSB"); + + sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM, 0, + sunxi_rsb_intr, sc); + if (sc->sc_ih == NULL) { + aprint_error_dev(self, "couldn't establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); + + /* Enable interrupts */ + RSB_WRITE(sc, RSB_INTE_REG, + RSB_INTE_LOAD_BSY_ENB | + RSB_INTE_TRANS_ERR_ENB | + RSB_INTE_TRANS_OVER_ENB); + RSB_WRITE(sc, RSB_CTRL_REG, + RSB_CTRL_GLOBAL_INT_ENB); + + sc->sc_ic.ic_cookie = sc; + sc->sc_ic.ic_acquire_bus = sunxi_rsb_acquire_bus; + sc->sc_ic.ic_release_bus = sunxi_rsb_release_bus; + sc->sc_ic.ic_exec = sunxi_rsb_exec; + + fdtbus_register_i2c_controller(self, phandle, &sunxi_rsb_funcs); + + devs = prop_dictionary_create(); + if (of_getprop_uint32(phandle, "#address-cells", &address_cells)) + address_cells = 1; + + of_enter_i2c_devs(devs, phandle, address_cells * 4, 0); + + memset(&iba, 0, sizeof(iba)); + iba.iba_tag = &sc->sc_ic; + iba.iba_child_devices = prop_dictionary_get(devs, "i2c-child-devices"); + if (iba.iba_child_devices) + prop_object_retain(iba.iba_child_devices); + else + iba.iba_child_devices = prop_array_create(); + prop_object_release(devs); + + sc->sc_i2cdev = config_found_ia(self, "i2cbus", &iba, iicbus_print); +} + +static int +sunxi_rsb_intr(void *priv) +{ + struct sunxi_rsb_softc *sc = priv; + uint32_t stat; + + stat = RSB_READ(sc, RSB_STAT_REG); + if ((stat & RSB_STAT_MASK) == 0) + return 0; + + RSB_WRITE(sc, RSB_STAT_REG, stat & RSB_STAT_MASK); + + mutex_enter(&sc->sc_lock); + sc->sc_stat |= stat; + cv_broadcast(&sc->sc_cv); + mutex_exit(&sc->sc_lock); + + return 1; +} + +static int +sunxi_rsb_wait(struct sunxi_rsb_softc *sc, int flags) +{ + int error = 0, retry; + + /* Wait up to 5 seconds for a transfer to complete */ + sc->sc_stat = 0; + for (retry = (flags & I2C_F_POLL) ? 100 : 5; retry > 0; retry--) { + if (flags & I2C_F_POLL) { + sc->sc_stat |= RSB_READ(sc, RSB_STAT_REG); + } else { + error = cv_timedwait(&sc->sc_cv, &sc->sc_lock, hz); + if (error && error != EWOULDBLOCK) { + break; + } + } + if (sc->sc_stat & RSB_STAT_MASK) { + break; + } + if (flags & I2C_F_POLL) { + delay(10000); + } + } + if (retry == 0) + error = EAGAIN; + + if (flags & I2C_F_POLL) { + RSB_WRITE(sc, RSB_STAT_REG, + sc->sc_stat & RSB_STAT_MASK); + } + + if (error) { + /* Abort transaction */ + device_printf(sc->sc_dev, "transfer timeout, error = %d\n", + error); + RSB_WRITE(sc, RSB_CTRL_REG, + RSB_CTRL_ABORT_TRANS); + return error; + } + + if (sc->sc_stat & RSB_STAT_LOAD_BSY) { + device_printf(sc->sc_dev, "transfer busy\n"); + return EBUSY; + } + if (sc->sc_stat & RSB_STAT_TRANS_ERR) { + device_printf(sc->sc_dev, "transfer error, id 0x%02llx\n", + __SHIFTOUT(sc->sc_stat, RSB_STAT_TRANS_ERR_ID)); + return EIO; + } + + return 0; +} + +static int +sunxi_rsb_rsb_config(struct sunxi_rsb_softc *sc, uint8_t rta, i2c_addr_t da, + int flags) +{ + uint32_t dar, ctrl; + + KASSERT(mutex_owned(&sc->sc_lock)); + + RSB_WRITE(sc, RSB_STAT_REG, + RSB_READ(sc, RSB_STAT_REG) & RSB_STAT_MASK); + + dar = __SHIFTIN(rta, RSB_DAR_RTA); + dar |= __SHIFTIN(da, RSB_DAR_DA); + RSB_WRITE(sc, RSB_DAR_REG, dar); + RSB_WRITE(sc, RSB_CMD_REG, RSB_CMD_IDX_SRTA); + + /* Make sure the controller is idle */ + ctrl = RSB_READ(sc, RSB_CTRL_REG); + if (ctrl & RSB_CTRL_START_TRANS) { + device_printf(sc->sc_dev, "device is busy\n"); + return EBUSY; + } + + /* Start the transfer */ + RSB_WRITE(sc, RSB_CTRL_REG, + ctrl | RSB_CTRL_START_TRANS); + + return sunxi_rsb_wait(sc, flags); +} + +static int +sunxi_rsb_acquire_bus(void *priv, int flags) +{ + struct sunxi_rsb_softc *sc = priv; + + if (flags & I2C_F_POLL) { + if (!mutex_tryenter(&sc->sc_lock)) + return EBUSY; + } else { + mutex_enter(&sc->sc_lock); + } + + return 0; +} + +static void +sunxi_rsb_release_bus(void *priv, int flags) +{ + struct sunxi_rsb_softc *sc = priv; + + mutex_exit(&sc->sc_lock); +} + +static int +sunxi_rsb_exec(void *priv, i2c_op_t op, i2c_addr_t addr, + const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags) +{ + struct sunxi_rsb_softc *sc = priv; + uint32_t dlen, ctrl; + uint8_t rta; + int error, i; + + KASSERT(mutex_owned(&sc->sc_lock)); + + if (cmdlen != 1 || (len != 1 && len != 2 && len != 4)) + return EINVAL; + + if (sc->sc_type == SUNXI_RSB && sc->sc_rsb_last_da != addr) { + /* Lookup run-time address for given device address */ + for (rta = 0, i = 0; rsb_rtamap[i].rta != 0; i++) + if (rsb_rtamap[i].addr == addr) { + rta = rsb_rtamap[i].rta; + break; + } + if (rta == 0) { + device_printf(sc->sc_dev, + "RTA not known for address %#x\n", addr); + return ENXIO; + } + error = sunxi_rsb_rsb_config(sc, rta, addr, flags); + if (error) { + device_printf(sc->sc_dev, + "SRTA failed, flags = %x, error = %d\n", + flags, error); + sc->sc_rsb_last_da = 0; + return error; + } + + sc->sc_rsb_last_da = addr; + } + + /* Data byte register */ + RSB_WRITE(sc, RSB_DADDR0_REG, *(const uint8_t *)cmdbuf); + + if (I2C_OP_WRITE_P(op)) { + uint8_t *pbuf = buf; + uint32_t data; + /* Write data */ + switch (len) { + case 1: + data = pbuf[0]; + break; + case 2: + data = pbuf[0] | (pbuf[1] << 8); + break; + case 4: + data = pbuf[0] | (pbuf[1] << 8) | + (pbuf[2] << 16) | (pbuf[3] << 24); + break; + default: + return EINVAL; + } + RSB_WRITE(sc, RSB_DATA0_REG, data); + } + + if (sc->sc_type == SUNXI_RSB) { + uint8_t cmd; + if (I2C_OP_WRITE_P(op)) { + switch (len) { + case 1: cmd = RSB_CMD_IDX_WR8; break; + case 2: cmd = RSB_CMD_IDX_WR16; break; + case 4: cmd = RSB_CMD_IDX_WR32; break; + default: return EINVAL; + } + } else { + switch (len) { + case 1: cmd = RSB_CMD_IDX_RD8; break; + case 2: cmd = RSB_CMD_IDX_RD16; break; + case 4: cmd = RSB_CMD_IDX_RD32; break; + default: return EINVAL; + } + } + RSB_WRITE(sc, RSB_CMD_REG, cmd); + } + + /* Program data length register; if reading, set read/write bit */ + dlen = __SHIFTIN(len - 1, RSB_DLEN_ACCESS_LENGTH); + if (I2C_OP_READ_P(op)) { + dlen |= RSB_DLEN_READ_WRITE_FLAG; + } + RSB_WRITE(sc, RSB_DLEN_REG, dlen); + + /* Make sure the controller is idle */ + ctrl = RSB_READ(sc, RSB_CTRL_REG); + if (ctrl & RSB_CTRL_START_TRANS) { + device_printf(sc->sc_dev, "device is busy\n"); + return EBUSY; + } + + /* Start the transfer */ + RSB_WRITE(sc, RSB_CTRL_REG, + ctrl | RSB_CTRL_START_TRANS); + + error = sunxi_rsb_wait(sc, flags); + if (error) { + return error; + } + + if (I2C_OP_READ_P(op)) { + uint32_t data = RSB_READ(sc, RSB_DATA0_REG); + switch (len) { + case 4: + *(uint32_t *)buf = data; + break; + case 2: + *(uint16_t *)buf = data & 0xffff; + break; + case 1: + *(uint8_t *)buf = data & 0xff; + break; + default: + return EINVAL; + } + } + + return 0; +} diff --git a/sys/arch/arm/sunxi/sunxi_rsb.h b/sys/arch/arm/sunxi/sunxi_rsb.h new file mode 100644 index 000000000000..9a7408ad0e8f --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_rsb.h @@ -0,0 +1,85 @@ +/* $NetBSD: sunxi_rsb.h,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#ifndef _ARM_SUNXI_RSB_H +#define _ARM_SUNXI_RSB_H + +#define RSB_CTRL_REG 0x0000 +#define RSB_CTRL_START_TRANS __BIT(7) +#define RSB_CTRL_ABORT_TRANS __BIT(6) +#define RSB_CTRL_GLOBAL_INT_ENB __BIT(1) +#define RSB_CTRL_SOFT_RESET __BIT(0) +#define RSB_CCR_REG 0x0004 +#define RSB_CCR_SDA_ODLY __BITS(10,8) +#define RSB_CCR_CLK_DIV __BITS(7,0) +#define RSB_INTE_REG 0x0008 +#define RSB_INTE_LOAD_BSY_ENB __BIT(2) +#define RSB_INTE_TRANS_ERR_ENB __BIT(1) +#define RSB_INTE_TRANS_OVER_ENB __BIT(0) +#define RSB_STAT_REG 0x000c +#define RSB_STAT_TRANS_ERR_ID __BITS(15,8) +#define RSB_STAT_LOAD_BSY __BIT(2) +#define RSB_STAT_TRANS_ERR __BIT(1) +#define RSB_STAT_TRANS_OVER __BIT(0) +#define RSB_STAT_MASK \ + (RSB_STAT_LOAD_BSY | \ + RSB_STAT_TRANS_ERR | \ + RSB_STAT_TRANS_OVER) +#define RSB_DADDR0_REG 0x0010 +#define RSB_DADDR1_REG 0x0014 +#define RSB_DLEN_REG 0x0018 +#define RSB_DLEN_READ_WRITE_FLAG __BIT(4) +#define RSB_DLEN_ACCESS_LENGTH __BITS(2,0) +#define RSB_DATA0_REG 0x001c +#define RSB_DATA1_REG 0x0020 +#define RSB_LCR_REG 0x0024 +#define RSB_LCR_SCL_STATE __BIT(5) +#define RSB_LCR_SDA_STATE __BIT(4) +#define RSB_LCR_SCL_CTL __BIT(3) +#define RSB_LCR_SCL_CTL_EN __BIT(2) +#define RSB_LCR_SDA_CTL __BIT(1) +#define RSB_LCR_SDA_CTL_EN __BIT(0) +#define RSB_PMCR_REG 0x0028 +#define RSB_PMCR_PMU_INIT_SEND __BIT(31) +#define RSB_PMCR_PMU_INIT_DATA __BITS(23,16) +#define RSB_PMCR_PMU_MODE_CTRL_REG_ADDR __BITS(15,8) +#define RSB_PMCR_PMU_DEVICE_ADDR __BITS(7,0) +#define RSB_CMD_REG 0x002c +#define RSB_CMD_IDX __BITS(7,0) +#define RSB_CMD_IDX_SRTA 0xe8 +#define RSB_CMD_IDX_RD8 0x8b +#define RSB_CMD_IDX_RD16 0x9c +#define RSB_CMD_IDX_RD32 0xa6 +#define RSB_CMD_IDX_WR8 0x4e +#define RSB_CMD_IDX_WR16 0x59 +#define RSB_CMD_IDX_WR32 0x63 +#define RSB_DAR_REG 0x0030 +#define RSB_DAR_RTA __BITS(23,16) +#define RSB_DAR_DA __BITS(15,0) + +#endif /* _ARM_SUNXI_RSB_H */ diff --git a/sys/arch/arm/sunxi/sunxi_rtc.c b/sys/arch/arm/sunxi/sunxi_rtc.c new file mode 100644 index 000000000000..68889e14b3b0 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_rtc.c @@ -0,0 +1,174 @@ +/* $NetBSD: sunxi_rtc.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2014-2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: sunxi_rtc.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define RTC_YY_MM_DD_REG 0x10 +#define SUNXI_RTC_LEAP __BIT(22) +#define SUNXI_RTC_YEAR __BITS(21,16) +#define SUNXI_RTC_MONTH __BITS(11,8) +#define SUNXI_RTC_DAY __BITS(4,0) +#define RTC_HH_MM_SS_REG 0x14 +#define SUNXI_RTC_WK_NO __BITS(31,29) +#define SUNXI_RTC_HOUR __BITS(20,16) +#define SUNXI_RTC_MINUTE __BITS(13,8) +#define SUNXI_RTC_SECOND __BITS(5,0) + +#define SUNXI_RTC_BASE_YEAR 2000 + +static const char * const compatible[] = { + "allwinner,sun6i-a31-rtc", + NULL +}; + +struct sunxi_rtc_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + struct todr_chip_handle sc_todr; +}; + +#define RTC_READ(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define RTC_WRITE(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +static int sunxi_rtc_match(device_t, cfdata_t, void *); +static void sunxi_rtc_attach(device_t, device_t, void *); + +static int sunxi_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *); +static int sunxi_rtc_settime(todr_chip_handle_t, struct clock_ymdhms *); + +CFATTACH_DECL_NEW(sunxi_rtc, sizeof(struct sunxi_rtc_softc), + sunxi_rtc_match, sunxi_rtc_attach, NULL, NULL); + +static int +sunxi_rtc_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sunxi_rtc_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_rtc_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + bus_addr_t addr; + bus_size_t size; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bst = faa->faa_bst; + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": RTC\n"); + + sc->sc_todr.todr_gettime_ymdhms = sunxi_rtc_gettime; + sc->sc_todr.todr_settime_ymdhms = sunxi_rtc_settime; + sc->sc_todr.cookie = sc; + + fdtbus_todr_attach(self, phandle, &sc->sc_todr); +} + +static int +sunxi_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt) +{ + struct sunxi_rtc_softc *sc = tch->cookie; + + const uint32_t yymmdd = RTC_READ(sc, RTC_YY_MM_DD_REG); + const uint32_t hhmmss = RTC_READ(sc, RTC_HH_MM_SS_REG); + + dt->dt_year = __SHIFTOUT(yymmdd, SUNXI_RTC_YEAR) + SUNXI_RTC_BASE_YEAR; + dt->dt_mon = __SHIFTOUT(yymmdd, SUNXI_RTC_MONTH); + dt->dt_day = __SHIFTOUT(yymmdd, SUNXI_RTC_DAY); + dt->dt_wday = __SHIFTOUT(hhmmss, SUNXI_RTC_WK_NO); + dt->dt_hour = __SHIFTOUT(hhmmss, SUNXI_RTC_HOUR); + dt->dt_min = __SHIFTOUT(hhmmss, SUNXI_RTC_MINUTE); + dt->dt_sec = __SHIFTOUT(hhmmss, SUNXI_RTC_SECOND); + + return 0; +} + +static int +sunxi_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt) +{ + struct sunxi_rtc_softc *sc = tch->cookie; + uint32_t yymmdd, hhmmss, maxyear; + + /* + * Sanity check the date before writing it back + */ + if (dt->dt_year < SUNXI_RTC_BASE_YEAR) { + aprint_normal_dev(sc->sc_dev, "year pre the epoch: %llu, " + "not writing back time\n", dt->dt_year); + return EIO; + } + maxyear = __SHIFTOUT(0xffffffff, SUNXI_RTC_YEAR) + SUNXI_RTC_BASE_YEAR; + if (dt->dt_year > maxyear) { + aprint_normal_dev(sc->sc_dev, "year exceeds available field:" + " %llu, not writing back time\n", dt->dt_year); + return EIO; + } + + yymmdd = __SHIFTIN(dt->dt_year - SUNXI_RTC_BASE_YEAR, SUNXI_RTC_YEAR); + yymmdd |= __SHIFTIN(dt->dt_mon, SUNXI_RTC_MONTH); + yymmdd |= __SHIFTIN(dt->dt_day, SUNXI_RTC_DAY); + + hhmmss = __SHIFTIN(dt->dt_wday, SUNXI_RTC_WK_NO); + hhmmss |= __SHIFTIN(dt->dt_hour, SUNXI_RTC_HOUR); + hhmmss |= __SHIFTIN(dt->dt_min, SUNXI_RTC_MINUTE); + hhmmss |= __SHIFTIN(dt->dt_sec, SUNXI_RTC_SECOND); + + RTC_WRITE(sc, RTC_YY_MM_DD_REG, yymmdd); + RTC_WRITE(sc, RTC_HH_MM_SS_REG, hhmmss); + + return 0; +} diff --git a/sys/arch/arm/sunxi/sunxi_twi.c b/sys/arch/arm/sunxi/sunxi_twi.c new file mode 100644 index 000000000000..d889a8fa3354 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_twi.c @@ -0,0 +1,148 @@ +/* $NetBSD: sunxi_twi.c,v 1.2.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 + +__KERNEL_RCSID(0, "$NetBSD: sunxi_twi.c,v 1.2.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static int sunxi_twi_match(device_t, cfdata_t, void *); +static void sunxi_twi_attach(device_t, device_t, void *); + +static const char * const compatible[] = { + "allwinner,sun6i-a31-i2c", + NULL +}; + +CFATTACH_DECL_NEW(sunxi_twi, sizeof(struct gttwsi_softc), + sunxi_twi_match, sunxi_twi_attach, NULL, NULL); + +static i2c_tag_t +sunxi_twi_get_tag(device_t dev) +{ + struct gttwsi_softc * const sc = device_private(dev); + + return &sc->sc_i2c; +} + +const struct fdtbus_i2c_controller_func sunxi_twi_funcs = { + .get_tag = sunxi_twi_get_tag, +}; + +static int +sunxi_twi_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +sunxi_twi_attach(device_t parent, device_t self, void *aux) +{ + struct gttwsi_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + struct i2cbus_attach_args iba; + const int phandle = faa->faa_phandle; + bus_space_tag_t bst = faa->faa_bst; + bus_space_handle_t bsh; + prop_dictionary_t devs; + uint32_t address_cells; + struct fdtbus_reset *rst; + struct clk *clk; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + void *ih; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + if (bus_space_map(bst, addr, size, 0, &bsh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error(": failed to decode interrupt\n"); + return; + } + + if ((clk = fdtbus_clock_get_index(phandle, 0)) != NULL) + if (clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock\n"); + return; + } + if ((rst = fdtbus_reset_get_index(phandle, 0)) != NULL) + if (fdtbus_reset_deassert(rst) != 0) { + aprint_error(": couldn't de-assert reset\n"); + return; + } + + gttwsi_attach_subr(self, bst, bsh); + + ih = fdtbus_intr_establish(phandle, 0, IPL_VM, 0, gttwsi_intr, sc); + if (ih == NULL) { + aprint_error_dev(self, "couldn't establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); + + fdtbus_register_i2c_controller(self, phandle, &sunxi_twi_funcs); + + devs = prop_dictionary_create(); + if (of_getprop_uint32(phandle, "#address-cells", &address_cells)) + address_cells = 1; + + of_enter_i2c_devs(devs, phandle, address_cells * 4, 0); + + memset(&iba, 0, sizeof(iba)); + iba.iba_tag = &sc->sc_i2c; + iba.iba_child_devices = prop_dictionary_get(devs, "i2c-child-devices"); + if (iba.iba_child_devices) + prop_object_retain(iba.iba_child_devices); + else + iba.iba_child_devices = prop_array_create(); + prop_object_release(devs); + + config_found_ia(self, "i2cbus", &iba, iicbus_print); +} diff --git a/sys/arch/arm/sunxi/sunxi_usbphy.c b/sys/arch/arm/sunxi/sunxi_usbphy.c new file mode 100644 index 000000000000..8c896a19fed8 --- /dev/null +++ b/sys/arch/arm/sunxi/sunxi_usbphy.c @@ -0,0 +1,235 @@ +/* $NetBSD: sunxi_usbphy.c,v 1.3.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 + +__KERNEL_RCSID(0, "$NetBSD: sunxi_usbphy.c,v 1.3.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include +#include + +#include + +#define OTG_PHY_CFG 0x20 +#define OTG_PHY_ROUTE_OTG __BIT(0) + +#define HCI_ICR 0x00 +#define HCI_AHB_INCR8 __BIT(10) +#define HCI_AHB_INCR4 __BIT(9) +#define HCI_AHB_INCRX_ALIGN __BIT(8) +#define HCI_ULPI_BYPASS __BIT(0) +#define PMU_UNK_H3 0x10 +#define PMU_UNK_H3_CLR __BIT(1) + +static int sunxi_usbphy_match(device_t, cfdata_t, void *); +static void sunxi_usbphy_attach(device_t, device_t, void *); + +enum sunxi_usbphy_type { + USBPHY_A31, + USBPHY_H3, +}; + +static const struct of_compat_data compat_data[] = { + { "allwinner,sun6i-a31-usb-phy", USBPHY_A31 }, + { "allwinner,sun8i-h3-usb-phy", USBPHY_H3 }, + { NULL } +}; + +#define SUNXI_MAXUSBPHY 4 + +struct sunxi_usbphy { + u_int phy_index; + bus_space_handle_t phy_bsh; + struct fdtbus_regulator *phy_reg; +}; + +struct sunxi_usbphy_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh_phy_ctrl; + enum sunxi_usbphy_type sc_type; + + struct sunxi_usbphy sc_phys[SUNXI_MAXUSBPHY]; + u_int sc_nphys; + + struct fdtbus_gpio_pin *sc_gpio_id_det; + struct fdtbus_gpio_pin *sc_gpio_vbus_det; +}; + +#define USBPHY_READ(sc, id, reg) \ + bus_space_read_4((sc)->sc_bst, \ + (sc)->sc_phys[(id)].phy_bsh, (reg)) +#define USBPHY_WRITE(sc, id, reg, val) \ + bus_space_write_4((sc)->sc_bst, \ + (sc)->sc_phys[(id)].phy_bsh, (reg), (val)) + +CFATTACH_DECL_NEW(sunxi_usbphy, sizeof(struct sunxi_usbphy_softc), + sunxi_usbphy_match, sunxi_usbphy_attach, NULL, NULL); + +static bool +sunxi_usbphy_vbus_detect(struct sunxi_usbphy_softc *sc) +{ + if (sc->sc_gpio_vbus_det) + return fdtbus_gpio_read(sc->sc_gpio_vbus_det); + return 1; +} + +static void * +sunxi_usbphy_acquire(device_t dev, const void *data, size_t len) +{ + struct sunxi_usbphy_softc * const sc = device_private(dev); + + if (len != 4) + return NULL; + + const int phy_id = be32dec(data); + if (phy_id >= sc->sc_nphys) + return NULL; + + return &sc->sc_phys[phy_id]; +} + +static void +sunxi_usbphy_release(device_t dev, void *priv) +{ +} + +static int +sunxi_usbphy_enable(device_t dev, void *priv, bool enable) +{ + struct sunxi_usbphy_softc * const sc = device_private(dev); + struct sunxi_usbphy * const phy = priv; + uint32_t val; + + if (phy->phy_index > 0) { + /* Enable passby */ + val = USBPHY_READ(sc, phy->phy_index, HCI_ICR); + val |= HCI_ULPI_BYPASS; + val |= HCI_AHB_INCR8; + val |= HCI_AHB_INCR4; + val |= HCI_AHB_INCRX_ALIGN; + USBPHY_WRITE(sc, phy->phy_index, HCI_ICR, val); + } + + if (sc->sc_type == USBPHY_H3) { + /* H3-specific */ + val = USBPHY_READ(sc, phy->phy_index, PMU_UNK_H3); + val &= ~PMU_UNK_H3_CLR; + USBPHY_WRITE(sc, phy->phy_index, PMU_UNK_H3, val); + } + + if (phy->phy_reg == NULL) + return 0; + + if (enable) { + /* If an external vbus is detected, do not enable phy 0 */ + if (phy->phy_index == 0 && sunxi_usbphy_vbus_detect(sc)) + return 0; + return fdtbus_regulator_enable(phy->phy_reg); + } else { + return fdtbus_regulator_disable(phy->phy_reg); + } +} + +const struct fdtbus_phy_controller_func sunxi_usbphy_funcs = { + .acquire = sunxi_usbphy_acquire, + .release = sunxi_usbphy_release, + .enable = sunxi_usbphy_enable, +}; + +static int +sunxi_usbphy_match(device_t parent, cfdata_t cf, void *aux) +{ + struct fdt_attach_args * const faa = aux; + + return of_match_compat_data(faa->faa_phandle, compat_data); +} + +static void +sunxi_usbphy_attach(device_t parent, device_t self, void *aux) +{ + struct sunxi_usbphy_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct fdtbus_reset *rst; + struct sunxi_usbphy *phy; + struct clk *clk; + bus_addr_t addr; + bus_size_t size; + char pname[20]; + u_int n; + + sc->sc_dev = self; + sc->sc_bst = faa->faa_bst; + sc->sc_type = of_search_compatible(phandle, compat_data)->data; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get phy ctrl registers\n"); + return; + } + if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh_phy_ctrl) != 0) { + aprint_error(": couldn't map phy ctrl registers\n"); + return; + } + + for (sc->sc_nphys = 0; sc->sc_nphys < SUNXI_MAXUSBPHY; sc->sc_nphys++) { + if (fdtbus_get_reg(phandle, sc->sc_nphys + 1, &addr, &size) != 0) + break; + phy = &sc->sc_phys[sc->sc_nphys]; + phy->phy_index = sc->sc_nphys; + if (bus_space_map(sc->sc_bst, addr, size, 0, &phy->phy_bsh) != 0) { + aprint_error(": failed to map reg #%d\n", sc->sc_nphys); + return; + } + /* Get optional regulator */ + snprintf(pname, sizeof(pname), "usb%d_vbus-supply", sc->sc_nphys); + phy->phy_reg = fdtbus_regulator_acquire(phandle, pname); + } + + /* Enable clocks */ + for (n = 0; (clk = fdtbus_clock_get_index(phandle, n)) != NULL; n++) + if (clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock #%d\n", n); + return; + } + /* De-assert resets */ + for (n = 0; (rst = fdtbus_reset_get_index(phandle, n)) != NULL; n++) + if (fdtbus_reset_deassert(rst) != 0) { + aprint_error(": couldn't de-assert reset #%d\n", n); + return; + } + + aprint_naive("\n"); + aprint_normal(": USB PHY\n"); + + fdtbus_register_phy_controller(self, phandle, &sunxi_usbphy_funcs); +} diff --git a/sys/arch/evbarm/conf/EXYNOS b/sys/arch/evbarm/conf/EXYNOS index dcf325e413a5..d60403e9afb1 100644 --- a/sys/arch/evbarm/conf/EXYNOS +++ b/sys/arch/evbarm/conf/EXYNOS @@ -1,301 +1,94 @@ # -# $NetBSD: EXYNOS,v 1.14 2017/04/16 15:49:26 jmcneill Exp $ +# $NetBSD: EXYNOS,v 1.14.4.1 2017/07/18 19:13:09 snj Exp $ # -# ODROID-XU -- ODROID-XU4 Exynos5422 based kernel +# Samsung Exynos SoC kernel # include "arch/evbarm/conf/std.exynos" +include "arch/evbarm/conf/GENERIC.common" -no makeoptions CPUFLAGS -makeoptions CPUFLAGS="-mcpu=cortex-a7 -mfpu=neon" -no makeoptions BOARDTYPE -makeoptions BOARDTYPE="hardkernel_odroid_xu4" -no makeoptions KERNEL_BASE_PHYS -no makeoptions KERNEL_BASE_VIRT -makeoptions KERNEL_BASE_PHYS="0x80000000" -makeoptions KERNEL_BASE_VIRT="0x80000000" -options PMAP_NEED_ALLOC_POOLPAGE -options MEMSIZE=2048 - -# estimated number of users - -maxusers 8 - -# Standard system options - -options RTC_OFFSET=0 # hardware clock is this many mins. west of GMT -#options NTP # NTP phase/frequency locked loop - -# CPU options -options CPU_CORTEX options CPU_CORTEXA7 options CPU_CORTEXA15 -options EXYNOS5422 -#options MULTIPROCESSOR +options SOC_EXYNOS5422 +options MULTIPROCESSOR -options FDT # not really but soon -pseudo-device openfirm # jmcneill: oops, fdtbus should depend on - # openfirm. don't let me forget. +pseudo-device openfirm # /dev/openfirm - -options PMAPCOUNTERS -options BUSDMA_COUNTERS -options EXYNOS_CONSOLE_EARLY -#options UVMHIST -options USBHIST -options USBHIST_SIZE=100000 -#options UVMHIST_PRINT,KERNHIST_DELAY=0 -options __HAVE_MM_MD_DIRECT_MAPPED_PHYS -#options PMAP_NEED_ALLOC_POOLPAGE - -# Specify the memory size in megabytes (optional). -#options MEMSIZE=2048 - -# File systems -file-system FFS # UFS -#file-system LFS # log-structured file system -file-system MFS # memory file system -file-system NFS # Network file system -#file-system ADOSFS # AmigaDOS-compatible file system -#file-system EXT2FS # second extended file system (linux) -#file-system CD9660 # ISO 9660 + Rock Ridge file system -file-system MSDOSFS # MS-DOS file system -#file-system FDESC # /dev/fd -file-system KERNFS # /kern -#file-system NULLFS # loopback file system -file-system PROCFS # /proc -#file-system PUFFS # Userspace file systems (e.g. ntfs-3g & sshfs) -#file-system UMAPFS # NULLFS + uid and gid remapping -#file-system UNION # union file system -file-system TMPFS # memory file system -file-system PTYFS # /dev/pts/N support - -# File system options -#options QUOTA # legacy UFS quotas -#options QUOTA2 # new, in-filesystem UFS quotas -#options DISKLABEL_EI # disklabel Endian Independent support -#options FFS_EI # FFS Endian Independent support -options NFSSERVER -options WAPBL # File system journaling support -#options FFS_NO_SNAPSHOT # No FFS snapshot support - -# Networking options - -#options GATEWAY # packet forwarding -options INET # IP + ICMP + TCP + UDP -options INET6 # IPV6 -#options IPSEC # IP security -#options IPSEC_DEBUG # debug for IP security -#options MROUTING # IP multicast routing -#options PIM # Protocol Independent Multicast -#options NETATALK # AppleTalk networking -#options PPP_BSDCOMP # BSD-Compress compression support for PPP -#options PPP_DEFLATE # Deflate compression support for PPP -#options PPP_FILTER # Active filter support for PPP (requires bpf) -#options TCP_DEBUG # Record last TCP_NDEBUG packets with SO_DEBUG - -#options NFS_BOOT_BOOTP -#options NFS_BOOT_DHCP -#options NFS_BOOT_BOOTSTATIC -#options NFS_BOOTSTATIC_MYIP="\"192.168.0.22\"" -#options NFS_BOOTSTATIC_GWIP="\"192.168.0.1\"" -#options NFS_BOOTSTATIC_MASK="\"255.255.255.0\"" -#options NFS_BOOTSTATIC_SERVADDR="\"192.168.0.5\"" -#options NFS_BOOTSTATIC_SERVER="\"192.168.0.5:/stuff/nfs/odroid\"" - -#options NFS_BOOT_RWSIZE=1024 - -# Compatibility options - -options COMPAT_NETBSD32 # allow running arm (e.g. non-earm) binaries -#options COMPAT_43 # 4.3BSD compatibility. -#options COMPAT_09 # NetBSD 0.9, -#options COMPAT_10 # NetBSD 1.0, -#options COMPAT_11 # NetBSD 1.1, -#options COMPAT_12 # NetBSD 1.2, -#options COMPAT_13 # NetBSD 1.3, -#options COMPAT_14 # NetBSD 1.4, -#options COMPAT_15 # NetBSD 1.5, -#options COMPAT_16 # NetBSD 1.6, -#options COMPAT_20 # NetBSD 2.0, -#options COMPAT_30 # NetBSD 3.0, -#options COMPAT_40 # NetBSD 4.0, -#options COMPAT_50 # NetBSD 5.0, -options COMPAT_60 # NetBSD 6.0, and -options COMPAT_70 # NetBSD 7.0 binary compatibility. -#options TCP_COMPAT_42 # 4.2BSD TCP/IP bug compat. Not recommended. -#options COMPAT_BSDPTY # /dev/[pt]ty?? ptys. - -# Shared memory options - -options SYSVMSG # System V-like message queues -options SYSVSEM # System V-like semaphores -options SYSVSHM # System V-like memory sharing - -# Device options - -#options MEMORY_DISK_HOOKS # boottime setup of ramdisk -#options MEMORY_DISK_ROOT_SIZE=8192 # Size in blocks -#options MEMORY_DISK_DYNAMIC -#options MINIROOTSIZE=1000 # Size in blocks -#options MEMORY_DISK_IS_ROOT # use memory disk as root - -# Wedge support -options DKWEDGE_AUTODISCOVER # Automatically add dk(4) instances -options DKWEDGE_METHOD_GPT # Supports GPT partitions as wedges - -# Miscellaneous kernel options -options KTRACE # system call tracing, a la ktrace(1) -#options SCSIVERBOSE # Verbose SCSI errors -#options MIIVERBOSE # Verbose MII autoconfuration messages -options DDB_KEYCODE=0x40 -#options USERCONF # userconf(4) support -#options PIPE_SOCKETPAIR # smaller, but slower pipe(2) - -# Development and Debugging options - -#options PERFCTRS # performance counters -options DIAGNOSTIC # internal consistency checks -options DEBUG -options LOCKDEBUG -options PMAP_DEBUG # Enable pmap_debug_level code +#options DIAGNOSTIC # internal consistency checks +#options DEBUG +#options LOCKDEBUG +#options PMAP_DEBUG # Enable pmap_debug_level code #options IPKDB # remote kernel debugging -options VERBOSE_INIT_ARM # verbose bootstraping messages -options DDB # in-kernel debugger -options DDB_ONPANIC=1 -options DDB_HISTORY_SIZE=100 # Enable history editing in DDB -options DDB_VERBOSE_HELP -#options KGDB +#options VERBOSE_INIT_ARM # verbose bootstrapping messages +# SSCOMnCONSOLE is required for early init messages from VERBOSE_INIT_ARM. +#options SSCOM2CONSOLE + makeoptions DEBUG="-g" # compile full symbol table makeoptions COPY_SYMTAB=1 -## USB Debugging options -options USB_DEBUG -options EHCI_DEBUG -options OHCI_DEBUG -options UHUB_DEBUG -options USBVERBOSE - - -# Valid options for BOOT_ARGS: -# single Boot to single user only -# kdb Give control to kernel debugger -# ask Ask for file name to reboot from -# memorydisk= Set memorydisk size to KB -# quiet Show aprint_naive output -# verbose Show aprint_normal and aprint_verbose output -#options BOOT_ARGS="\"\"" -options BOOT_ARGS="\"verbose\"" - config netbsd root on ? type ? -# The main bus device -mainbus0 at root - -# The boot cpu and secondary CPUs -cpu0 at mainbus? -cpu* at mainbus? # Multiprocessor - -# core devices -armperiph0 at mainbus? -armgic0 at armperiph? # Interrupt Controller -armgtmr0 at armperiph? # Generic Timer - -# On-board I/O -exynosfdt0 at mainbus? +# Device tree support +armfdt0 at root fdt* at fdtbus? -fregulator* at fdt? +# CPUs +cpus* at fdt? pass 0 +cpu* at cpus? -#interrupt controller -exyointr0 at fdt? -gic* at fdt? +fclock* at fdt? pass 4 +fregulator* at fdt? pass 4 +gpiokeys* at fdt? + +# Timer +mct* at fdt? # Exynos Multi Core Timer (MCT) +armgtmr0 at mct? # ARM Generic Timer + +# Interrupt controller +exyointr* at fdt? pass 1 +gic* at fdt? pass 1 # GIC +armgic0 at gic? # Clock controller -exy5422clk* at fdt? # Exynos5422 clock controller +exy5410clk* at fdt? pass 3 # Exynos5410 clock controller +exy5422clk* at fdt? pass 3 # Exynos5422 clock controller -# Integrated Samsung UARTs -sscom* at fdt? # UART ? - -# Exynos Watchdog Timer -exyowdt* at fdt? # watchdog - -# Exynos chip id -chipid* at fdt? - -# Exynos system MMUs -sysmmu* at fdt? - -# Exynos RTC -exyortc* at fdt? - -# Exynos Multi Core timer (MCT) -mct* at fdt? - -# GPIO -exyopctl* at fdt? +# GPIO controller +exyopctl* at fdt? pass 2 # GPIO gpio* at gpiobus? -# On-board USB 2.0 -exyousbphy* at fdt? -ohci* at fdt? -ehci* at fdt? -usb* at ohci? -usb* at ehci? +# Exynos SoC support +chipid* at fdt? +sysmmu* at fdt? -# On-board USB 3.0 -exyousb* at fdt? -#xhci* at fdt? -#usb* at xhci? +# UART +sscom* at fdt? # UART -# I2C devices -exyoi2c* at fdt? -#i2c* at exyoi2c? +# I2C +exyoi2c* at fdt? # I2C +iic* at exyoi2c? -# SD/MMC -dwcmmc* at fdt? +# RTC +#exyortc* at fdt? # RTC + +# SDMMC +dwcmmc* at fdt? # SDMMC sdmmc* at dwcmmc? ld0 at sdmmc0 ld1 at sdmmc1 ld2 at sdmmc2 +ld3 at sdmmc3 ld* at sdmmc? -# MISSING SUPPORT -# eMMC -# uSD -# SPI -# ADC -# PMIC (via I2C #4) -# PWM for Cooling fan -# HDMI -# I2S -# GPU +# USB +exyousbphy* at fdt? +exyousb* at fdt? +ohci* at fdt? # OUSB +ehci* at fdt? # EUSB +usb* at ohci? +usb* at ehci? -# serial console connectivity -options SSCOM2CONSOLE, CONSPEED=115200 - -# include all USB devices include "dev/usb/usbdevices.config" - midi* at midibus? -# Pseudo-Devices - -# disk/mass storage pseudo-devices -#pseudo-device md # memory disk device (ramdisk) -#pseudo-device vnd # disk-like interface to files -#pseudo-device fss # file system snapshot device -#pseudo-device putter # for puffs and pud -pseudo-device drvctl # driver control - -# network pseudo-devices -pseudo-device bpfilter # Berkeley packet filter -pseudo-device loop # network loopback -#pseudo-device kttcp # network loopback - -# miscellaneous pseudo-devices -pseudo-device pty # pseudo-terminals -#options RND_COM -#pseudo-device clockctl # user control of clock subsystem -pseudo-device ksyms # /dev/ksyms -#pseudo-device lockstat # lock profiling +cinclude "arch/evbarm/conf/EXYNOS.local" diff --git a/sys/arch/evbarm/conf/ODROID-U b/sys/arch/evbarm/conf/ODROID-U deleted file mode 100644 index da53c1c39cb6..000000000000 --- a/sys/arch/evbarm/conf/ODROID-U +++ /dev/null @@ -1,248 +0,0 @@ -# -# $NetBSD: ODROID-U,v 1.20 2017/02/19 07:47:00 rin Exp $ -# -# ODROID-U -- ODROID-U{2,3} series Exynos4x12(P) based kernel -# - -include "arch/evbarm/conf/std.odroid" - -# estimated number of users - -maxusers 32 - -# Standard system options - -options RTC_OFFSET=0 # hardware clock is this many mins. west of GMT -#options NTP # NTP phase/frequency locked loop - -# CPU options -options CPU_CORTEX -options CPU_CORTEXA9 -options EXYNOS4212 -options EXYNOS4412 -options EXYNOS4412P -#options MULTIPROCESSOR - -options PMAPCOUNTERS -options BUSDMA_COUNTERS -options EXYNOS_CONSOLE_EARLY -#options UVMHIST -#options UVMHIST_PRINT,KERNHIST_DELAY=0 -#options KERNHIST -#options USB_DEBUG -#options USBHIST_SIZE=100000 -options __HAVE_MM_MD_DIRECT_MAPPED_PHYS -options PMAP_NEED_ALLOC_POOLPAGE - -# Specify the memory size in megabytes (optional). -#options MEMSIZE=2048 - -# File systems -file-system FFS # UFS -#file-system LFS # log-structured file system -file-system MFS # memory file system -file-system NFS # Network file system -#file-system ADOSFS # AmigaDOS-compatible file system -#file-system EXT2FS # second extended file system (linux) -#file-system CD9660 # ISO 9660 + Rock Ridge file system -file-system MSDOSFS # MS-DOS file system -#file-system FDESC # /dev/fd -file-system KERNFS # /kern -#file-system NULLFS # loopback file system -file-system PROCFS # /proc -#file-system PUFFS # Userspace file systems (e.g. ntfs-3g & sshfs) -#file-system UMAPFS # NULLFS + uid and gid remapping -#file-system UNION # union file system -file-system TMPFS # memory file system -file-system PTYFS # /dev/pts/N support - -# File system options -#options QUOTA # legacy UFS quotas -#options QUOTA2 # new, in-filesystem UFS quotas -#options DISKLABEL_EI # disklabel Endian Independent support -#options FFS_EI # FFS Endian Independent support -#options NFSSERVER -options WAPBL # File system journaling support -#options FFS_NO_SNAPSHOT # No FFS snapshot support - -# Networking options - -#options GATEWAY # packet forwarding -options INET # IP + ICMP + TCP + UDP -options INET6 # IPV6 -#options IPSEC # IP security -#options IPSEC_DEBUG # debug for IP security -#options MROUTING # IP multicast routing -#options PIM # Protocol Independent Multicast -#options NETATALK # AppleTalk networking -#options PPP_BSDCOMP # BSD-Compress compression support for PPP -#options PPP_DEFLATE # Deflate compression support for PPP -#options PPP_FILTER # Active filter support for PPP (requires bpf) -#options TCP_DEBUG # Record last TCP_NDEBUG packets with SO_DEBUG - -options NFS_BOOT_BOOTP -options NFS_BOOT_DHCP -#options NFS_BOOT_BOOTSTATIC -#options NFS_BOOTSTATIC_MYIP="\"192.168.1.4\"" -#options NFS_BOOTSTATIC_GWIP="\"192.168.1.1\"" -#options NFS_BOOTSTATIC_MASK="\"255.255.255.0\"" -#options NFS_BOOTSTATIC_SERVADDR="\"192.168.1.1\"" -#options NFS_BOOTSTATIC_SERVER="\"192.168.1.1:/nfs/sdp2430\"" - -options NFS_BOOT_RWSIZE=1024 - -# Compatibility options - -options COMPAT_NETBSD32 # allow running arm (e.g. non-earm) binaries -#options COMPAT_43 # 4.3BSD compatibility. -#options COMPAT_09 # NetBSD 0.9, -#options COMPAT_10 # NetBSD 1.0, -#options COMPAT_11 # NetBSD 1.1, -#options COMPAT_12 # NetBSD 1.2, -#options COMPAT_13 # NetBSD 1.3, -#options COMPAT_14 # NetBSD 1.4, -#options COMPAT_15 # NetBSD 1.5, -#options COMPAT_16 # NetBSD 1.6, -#options COMPAT_20 # NetBSD 2.0, -options COMPAT_30 # NetBSD 3.0, -options COMPAT_40 # NetBSD 4.0, -options COMPAT_50 # NetBSD 5.0, -options COMPAT_60 # NetBSD 6.0, and -options COMPAT_70 # NetBSD 7.0 binary compatibility. -#options TCP_COMPAT_42 # 4.2BSD TCP/IP bug compat. Not recommended. -#options COMPAT_BSDPTY # /dev/[pt]ty?? ptys. - -# Shared memory options - -options SYSVMSG # System V-like message queues -options SYSVSEM # System V-like semaphores -options SYSVSHM # System V-like memory sharing - -# Device options - -#options MEMORY_DISK_HOOKS # boottime setup of ramdisk -#options MEMORY_DISK_ROOT_SIZE=8192 # Size in blocks -#options MEMORY_DISK_DYNAMIC -#options MINIROOTSIZE=1000 # Size in blocks -#options MEMORY_DISK_IS_ROOT # use memory disk as root - -# Wedge support -options DKWEDGE_AUTODISCOVER # Automatically add dk(4) instances -options DKWEDGE_METHOD_GPT # Supports GPT partitions as wedges - -# Miscellaneous kernel options -options KTRACE # system call tracing, a la ktrace(1) -#options SCSIVERBOSE # Verbose SCSI errors -options MIIVERBOSE # Verbose MII autoconfuration messages -#options DDB_KEYCODE=0x40 -#options USERCONF # userconf(4) support -#options PIPE_SOCKETPAIR # smaller, but slower pipe(2) - -# Development and Debugging options - -#options PERFCTRS # performance counters -options DIAGNOSTIC # internal consistency checks -options DEBUG -options LOCKDEBUG -#options PMAP_DEBUG # Enable pmap_debug_level code -#options IPKDB # remote kernel debugging -options VERBOSE_INIT_ARM # verbose bootstraping messages -options DDB # in-kernel debugger -options DDB_ONPANIC=1 -options DDB_HISTORY_SIZE=100 # Enable history editing in DDB -#options KGDB -makeoptions DEBUG="-g" # compile full symbol table -makeoptions COPY_SYMTAB=1 - -## USB Debugging options -options USB_DEBUG -options EHCI_DEBUG -options OHCI_DEBUG -options UHUB_DEBUG -options USBVERBOSE - - -# Valid options for BOOT_ARGS: -# single Boot to single user only -# kdb Give control to kernel debugger -# ask Ask for file name to reboot from -# memorydisk= Set memorydisk size to KB -# quiet Show aprint_naive output -# verbose Show aprint_normal and aprint_verbose output -options BOOT_ARGS="\"verbose\"" - -config netbsd root on ? type ? - -# The main bus device -mainbus0 at root - -# The boot cpu and secondary CPUs -cpu0 at mainbus? -#cpu? at mainbus? # Multiprocessor - -# A9 core devices -armperiph0 at mainbus? -armgic0 at armperiph? # Interrupt Controller -arml2cc0 at armperiph? # L2 Cache Controller - -# Exynos SoC -exyo0 at mainbus? - -# Integrated Samsung devices -mct0 at exyo0 - -# Integrated Samsung UARTs -sscom0 at exyo0 port 0 # UART0, expansion -sscom1 at exyo0 port 1 # UART1, console - -# Exynos Watchdog Timer -exyowdt0 at exyo0 flags 0 # watchdog - -# GPIO -exyogpio0 at exyo0 -gpio* at exyogpio? - -# On-board USB -exyousb* at exyo0 -ohci* at exyousb? -ehci* at exyousb? -usb* at ohci? -usb* at ehci? - -# Network phy for the LAN9730 -ukphy* at mii? phy ? # generic unknown PHYs - -# I2C devices -exyoiic0 at exyo0 -iic* at exyoiic? - -# serial console connectivity -options SSCOM1CONSOLE, CONSPEED=115200 - -# include all USB devices -include "dev/usb/usbdevices.config" - -midi* at midibus? - - -# Pseudo-Devices - -# disk/mass storage pseudo-devices -#pseudo-device md # memory disk device (ramdisk) -#pseudo-device vnd # disk-like interface to files -#pseudo-device fss # file system snapshot device -#pseudo-device putter # for puffs and pud -pseudo-device drvctl # driver control - -# network pseudo-devices -pseudo-device bpfilter # Berkeley packet filter -pseudo-device loop # network loopback -#pseudo-device kttcp # network loopback - -# miscellaneous pseudo-devices -pseudo-device pty # pseudo-terminals -#options RND_COM -#pseudo-device clockctl # user control of clock subsystem -pseudo-device ksyms # /dev/ksyms -#pseudo-device lockstat # lock profiling - diff --git a/sys/arch/evbarm/conf/ODROID-XU b/sys/arch/evbarm/conf/ODROID-XU deleted file mode 100644 index 415e6804f121..000000000000 --- a/sys/arch/evbarm/conf/ODROID-XU +++ /dev/null @@ -1,249 +0,0 @@ -# -# $NetBSD: ODROID-XU,v 1.7 2017/02/19 07:47:00 rin Exp $ -# -# ODROID-XU -- ODROID-XU Exynos5410 based kernel -# - -include "arch/evbarm/conf/std.odroid" - -# estimated number of users - -maxusers 32 - -# Standard system options - -options RTC_OFFSET=0 # hardware clock is this many mins. west of GMT -#options NTP # NTP phase/frequency locked loop - -# CPU options -options CPU_CORTEX -options CPU_CORTEXA7 -options CPU_CORTEXA15 -options EXYNOS5410 -#options MULTIPROCESSOR - -options PMAPCOUNTERS -options BUSDMA_COUNTERS -options EXYNOS_CONSOLE_EARLY -#options UVMHIST -options USB_DEBUG -options USBHIST_SIZE=100000 -#options UVMHIST_PRINT,KERNHIST_DELAY=0 -options __HAVE_MM_MD_DIRECT_MAPPED_PHYS -options PMAP_NEED_ALLOC_POOLPAGE - -# Specify the memory size in megabytes (optional). -#options MEMSIZE=2048 - -# File systems -file-system FFS # UFS -#file-system LFS # log-structured file system -file-system MFS # memory file system -file-system NFS # Network file system -#file-system ADOSFS # AmigaDOS-compatible file system -#file-system EXT2FS # second extended file system (linux) -#file-system CD9660 # ISO 9660 + Rock Ridge file system -file-system MSDOSFS # MS-DOS file system -#file-system FDESC # /dev/fd -file-system KERNFS # /kern -#file-system NULLFS # loopback file system -file-system PROCFS # /proc -#file-system PUFFS # Userspace file systems (e.g. ntfs-3g & sshfs) -#file-system UMAPFS # NULLFS + uid and gid remapping -#file-system UNION # union file system -file-system TMPFS # memory file system -file-system PTYFS # /dev/pts/N support - -# File system options -#options QUOTA # legacy UFS quotas -#options QUOTA2 # new, in-filesystem UFS quotas -#options DISKLABEL_EI # disklabel Endian Independent support -#options FFS_EI # FFS Endian Independent support -#options NFSSERVER -options WAPBL # File system journaling support -#options FFS_NO_SNAPSHOT # No FFS snapshot support - -# Networking options - -#options GATEWAY # packet forwarding -options INET # IP + ICMP + TCP + UDP -options INET6 # IPV6 -#options IPSEC # IP security -#options IPSEC_DEBUG # debug for IP security -#options MROUTING # IP multicast routing -#options PIM # Protocol Independent Multicast -#options NETATALK # AppleTalk networking -#options PPP_BSDCOMP # BSD-Compress compression support for PPP -#options PPP_DEFLATE # Deflate compression support for PPP -#options PPP_FILTER # Active filter support for PPP (requires bpf) -#options TCP_DEBUG # Record last TCP_NDEBUG packets with SO_DEBUG - -options NFS_BOOT_BOOTP -options NFS_BOOT_DHCP -#options NFS_BOOT_BOOTSTATIC -#options NFS_BOOTSTATIC_MYIP="\"192.168.1.4\"" -#options NFS_BOOTSTATIC_GWIP="\"192.168.1.1\"" -#options NFS_BOOTSTATIC_MASK="\"255.255.255.0\"" -#options NFS_BOOTSTATIC_SERVADDR="\"192.168.1.1\"" -#options NFS_BOOTSTATIC_SERVER="\"192.168.1.1:/nfs/sdp2430\"" - -options NFS_BOOT_RWSIZE=1024 - -# Compatibility options - -options COMPAT_NETBSD32 # allow running arm (e.g. non-earm) binaries -#options COMPAT_43 # 4.3BSD compatibility. -#options COMPAT_09 # NetBSD 0.9, -#options COMPAT_10 # NetBSD 1.0, -#options COMPAT_11 # NetBSD 1.1, -#options COMPAT_12 # NetBSD 1.2, -#options COMPAT_13 # NetBSD 1.3, -#options COMPAT_14 # NetBSD 1.4, -#options COMPAT_15 # NetBSD 1.5, -#options COMPAT_16 # NetBSD 1.6, -#options COMPAT_20 # NetBSD 2.0, -options COMPAT_30 # NetBSD 3.0, -options COMPAT_40 # NetBSD 4.0, -options COMPAT_50 # NetBSD 5.0, -options COMPAT_60 # NetBSD 6.0, and -options COMPAT_70 # NetBSD 7.0 binary compatibility. -#options TCP_COMPAT_42 # 4.2BSD TCP/IP bug compat. Not recommended. -#options COMPAT_BSDPTY # /dev/[pt]ty?? ptys. - -# Shared memory options - -options SYSVMSG # System V-like message queues -options SYSVSEM # System V-like semaphores -options SYSVSHM # System V-like memory sharing - -# Device options - -#options MEMORY_DISK_HOOKS # boottime setup of ramdisk -#options MEMORY_DISK_ROOT_SIZE=8192 # Size in blocks -#options MEMORY_DISK_DYNAMIC -#options MINIROOTSIZE=1000 # Size in blocks -#options MEMORY_DISK_IS_ROOT # use memory disk as root - -# Wedge support -options DKWEDGE_AUTODISCOVER # Automatically add dk(4) instances -options DKWEDGE_METHOD_GPT # Supports GPT partitions as wedges - -# Miscellaneous kernel options -options KTRACE # system call tracing, a la ktrace(1) -#options SCSIVERBOSE # Verbose SCSI errors -#options MIIVERBOSE # Verbose MII autoconfuration messages -#options DDB_KEYCODE=0x40 -#options USERCONF # userconf(4) support -#options PIPE_SOCKETPAIR # smaller, but slower pipe(2) - -# Development and Debugging options - -#options PERFCTRS # performance counters -options DIAGNOSTIC # internal consistency checks -options DEBUG -options LOCKDEBUG -#options PMAP_DEBUG # Enable pmap_debug_level code -#options IPKDB # remote kernel debugging -options VERBOSE_INIT_ARM # verbose bootstraping messages -options DDB # in-kernel debugger -options DDB_ONPANIC=1 -options DDB_HISTORY_SIZE=100 # Enable history editing in DDB -#options KGDB -makeoptions DEBUG="-g" # compile full symbol table -makeoptions COPY_SYMTAB=1 - -## USB Debugging options -options USB_DEBUG -options EHCI_DEBUG -options OHCI_DEBUG -options UHUB_DEBUG -options USBVERBOSE - - -# Valid options for BOOT_ARGS: -# single Boot to single user only -# kdb Give control to kernel debugger -# ask Ask for file name to reboot from -# memorydisk= Set memorydisk size to KB -# quiet Show aprint_naive output -# verbose Show aprint_normal and aprint_verbose output -#options BOOT_ARGS="\"\"" -options BOOT_ARGS="\"verbose\"" - -config netbsd root on ? type ? - -# The main bus device -mainbus0 at root - -# The boot cpu and secondary CPUs -cpu0 at mainbus? -#cpu? at mainbus? # Multiprocessor - -# A9 core devices -armperiph0 at mainbus? -armgic0 at armperiph? # Interrupt Controller -armgtmr0 at armperiph? # Generic Timer - -# Exynos SoC -exyo0 at mainbus? - -# Integrated Samsung UARTs -#sscom* at exyo0 port ? # UART ? -sscom2 at exyo0 port 2 # UART2 - -# Exynos Watchdog Timer -#exyowdt0 at exyo0 # watchdog - -# GPIO -exyogpio0 at exyo0 -gpio* at exyogpio? - -# On-board USB -exyousb* at exyo0 -ohci* at exyousb? -ehci* at exyousb? -usb* at ohci? -usb* at ehci? - -# Network phy for the LAN9730 -ukphy* at mii? phy ? # generic unknown PHYs - -# I2C devices -exyoiic0 at exyo0 -iic* at exyoiic? - -# SATA -#ahcisata* at exyno0 -#atabus* at ata? -#wd* at atabus? drive ? - - -# serial console connectivity -options SSCOM2CONSOLE, CONSPEED=115200 - -# include all USB devices -include "dev/usb/usbdevices.config" - -midi* at midibus? - - -# Pseudo-Devices - -# disk/mass storage pseudo-devices -#pseudo-device md # memory disk device (ramdisk) -#pseudo-device vnd # disk-like interface to files -#pseudo-device fss # file system snapshot device -#pseudo-device putter # for puffs and pud -pseudo-device drvctl # driver control - -# network pseudo-devices -pseudo-device bpfilter # Berkeley packet filter -pseudo-device loop # network loopback -#pseudo-device kttcp # network loopback - -# miscellaneous pseudo-devices -pseudo-device pty # pseudo-terminals -#options RND_COM -#pseudo-device clockctl # user control of clock subsystem -pseudo-device ksyms # /dev/ksyms -#pseudo-device lockstat # lock profiling diff --git a/sys/arch/evbarm/conf/ODROID-XU_INSTALL b/sys/arch/evbarm/conf/ODROID-XU_INSTALL deleted file mode 100644 index 9dd5808fb3b3..000000000000 --- a/sys/arch/evbarm/conf/ODROID-XU_INSTALL +++ /dev/null @@ -1,11 +0,0 @@ -# $NetBSD: ODROID-XU_INSTALL,v 1.1 2014/09/26 15:33:58 reinoud Exp $ -# -# ODROID_INSTALL -- ODROID kernel with installation-sized -# ramdisk -# - -include "arch/evbarm/conf/ODROID-XU" -include "arch/evbarm/conf/INSTALL" - -options BOOTHOWTO=RB_SINGLE -no makeoptions DEBUG diff --git a/sys/arch/evbarm/conf/SUNXI b/sys/arch/evbarm/conf/SUNXI new file mode 100644 index 000000000000..52d533c9adc4 --- /dev/null +++ b/sys/arch/evbarm/conf/SUNXI @@ -0,0 +1,131 @@ +# +# $NetBSD: SUNXI,v 1.17.4.2 2017/07/18 19:13:09 snj Exp $ +# +# Allwinner sunxi family +# + +include "arch/evbarm/conf/std.sunxi" +include "arch/evbarm/conf/GENERIC.common" + +makeoptions DTS=" + sun6i-a31-app4-evb1.dts + sun6i-a31-colombus.dts + sun6i-a31-hummingbird.dts + sun6i-a31-i7.dts + sun6i-a31-m9.dts + sun6i-a31-mele-a1000g-quad.dts + + sun8i-h3-bananapi-m2-plus.dts + sun8i-h3-beelink-x2.dts + sun8i-h3-nanopi-m1.dts + sun8i-h3-nanopi-neo.dts + sun8i-h3-orangepi-2.dts + sun8i-h3-orangepi-lite.dts + sun8i-h3-orangepi-pc-plus.dts + sun8i-h3-orangepi-pc.dts + sun8i-h3-orangepi-plus.dts + sun8i-h3-orangepi-plus2e.dts +" + +options CPU_CORTEXA7 +options SOC_SUN6I_A31 +options SOC_SUN8I_A83T +options SOC_SUN8I_H3 +options MULTIPROCESSOR + +pseudo-device openfirm # /dev/openfirm + +#options DIAGNOSTIC # internal consistency checks +#options DEBUG +#options LOCKDEBUG +#options PMAP_DEBUG # Enable pmap_debug_level code +#options IPKDB # remote kernel debugging +#options VERBOSE_INIT_ARM # verbose bootstrapping messages +# CONSADDR is required for early init messages from VERBOSE_INIT_ARM. +#options CONSADDR=0x01c28000 + +makeoptions DEBUG="-g" # compile full symbol table +makeoptions COPY_SYMTAB=1 + +config netbsd root on ? type ? + +# Device tree support +armfdt0 at root +fdt* at fdtbus? + +# CPUs +cpus* at fdt? pass 0 +cpu* at cpus? + +# Power state coordination interface +psci* at fdt? + +# Clock and reset controllers +sun6ia31ccu* at fdt? pass 4 # A31 CCU +sun8ia83tccu* at fdt? pass 4 # A83T CCU +sun8ih3ccu* at fdt? pass 4 # H3 CCU +sunxiresets* at fdt? pass 1 # Misc. clock resets +sunxigates* at fdt? pass 1 # Misc. clock gates + +fclock* at fdt? pass 1 +ffclock* at fdt? pass 1 +fregulator* at fdt? pass 4 +gpiokeys* at fdt? +gpioleds* at fdt? + +# Timer +gtmr* at fdt? pass 1 # ARM Generic Timer +armgtmr0 at gtmr? + +# Interrupt controller +gic* at fdt? pass 1 # GIC +armgic0 at gic? + +# Memory controller + +# DMA controller + +# Clock and Reset controller + +# GPIO controller +sunxigpio* at fdt? pass 2 # GPIO +gpio* at gpiobus? + +# Ethernet +sunxiemac* at fdt? # Allwinner Gigabit Ethernet +rgephy* at mii? phy ? +ukphy* at mii? phy ? + +# UART +com* at fdt? # UART +options COM_AWIN # XXX this should be a driver flag + +# I2C +sunxitwi* at fdt? # TWI +options GTTWSI_ALLWINNER # XXX this should be a driver flag +sunxirsb* at fdt? # P2WI/RSB +iic* at i2cbus? + +# RTC +sunxirtc* at fdt? # RTC + +# SDMMC +sunximmc* at fdt? # SDMMC +sdmmc* at sunximmc? +ld0 at sdmmc0 +ld1 at sdmmc1 +ld2 at sdmmc2 +ld3 at sdmmc3 +ld* at sdmmc? + +# USB 2.0 +sunxiusbphy* at fdt? pass 9 # USB PHY +ehci* at fdt? # EHCI +ohci* at fdt? # OHCI +usb* at ehci? +usb* at ohci? + +include "dev/usb/usbdevices.config" +midi* at midibus? + +cinclude "arch/evbarm/conf/SUNXI.local" diff --git a/sys/arch/evbarm/conf/TEGRA b/sys/arch/evbarm/conf/TEGRA index 17464c99dfed..589829315324 100644 --- a/sys/arch/evbarm/conf/TEGRA +++ b/sys/arch/evbarm/conf/TEGRA @@ -1,5 +1,5 @@ # -# $NetBSD: TEGRA,v 1.23 2017/06/02 00:09:56 jmcneill Exp $ +# $NetBSD: TEGRA,v 1.23.2.1 2017/07/18 19:13:09 snj Exp $ # # NVIDIA Tegra K1 (T124) # @@ -7,6 +7,14 @@ include "arch/evbarm/conf/std.tegra" include "arch/evbarm/conf/GENERIC.common" +makeoptions DTS=" + tegra124-apalis-eval.dts + tegra124-jetson-tk1.dts + tegra124-nyan-big.dts + tegra124-nyan-blaze.dts + tegra124-venice2.dts +" + options CPU_CORTEXA15 options SOC_TEGRA124 options MULTIPROCESSOR diff --git a/sys/arch/evbarm/conf/VEXPRESS_A15 b/sys/arch/evbarm/conf/VEXPRESS_A15 index 95004b10f736..d88254f51c3f 100644 --- a/sys/arch/evbarm/conf/VEXPRESS_A15 +++ b/sys/arch/evbarm/conf/VEXPRESS_A15 @@ -1,5 +1,5 @@ # -# $NetBSD: VEXPRESS_A15,v 1.12.2.3 2017/06/10 05:57:08 snj Exp $ +# $NetBSD: VEXPRESS_A15,v 1.12.2.4 2017/07/18 19:13:09 snj Exp $ # # ARM Versatile Express A15 # @@ -7,6 +7,8 @@ include "arch/evbarm/conf/std.vexpress" include "arch/evbarm/conf/GENERIC.common" +makeoptions DTS="vexpress-v2p-ca15-tc1.dts" + options CPU_CORTEXA15 options MULTIPROCESSOR diff --git a/sys/arch/evbarm/conf/files.evbarm b/sys/arch/evbarm/conf/files.evbarm index c1d2e1f2f7ff..edaf44c5a8c6 100644 --- a/sys/arch/evbarm/conf/files.evbarm +++ b/sys/arch/evbarm/conf/files.evbarm @@ -1,4 +1,4 @@ -# $NetBSD: files.evbarm,v 1.25 2014/12/04 21:15:48 joerg Exp $ +# $NetBSD: files.evbarm,v 1.25.10.1 2017/07/18 19:13:09 snj Exp $ # # First try for arm-specific configuration info # @@ -48,4 +48,9 @@ defflag opt_plcom.h PLCOM_DEBUG device plcom { }: tty file arch/evbarm/dev/plcom.c plcom needs-flag +# +# Maximum number of memory ranges +# +defparam opt_machdep.h DRAM_BLOCKS + include "arch/arm/conf/majors.arm32" diff --git a/sys/arch/evbarm/conf/files.exynos b/sys/arch/evbarm/conf/files.exynos index b52a2ab9d070..5dc9f62246da 100644 --- a/sys/arch/evbarm/conf/files.exynos +++ b/sys/arch/evbarm/conf/files.exynos @@ -1,18 +1,8 @@ -# $NetBSD: files.exynos,v 1.2 2015/12/14 22:06:57 marty Exp $ +# $NetBSD: files.exynos,v 1.2.12.1 2017/07/18 19:13:09 snj Exp $ # -# EXYNOS 5422 board configuration info +# EXYNOS board configuration info # -file arch/evbarm/exynos/exynos_machdep.c +include "arch/evbarm/conf/files.fdt" -# Kernel boot arguments -defparam opt_machdep.h BOOT_ARGS - -# FDT - -include "dev/ofw/files.ofw" -include "dev/fdt/files.fdt" -include "arch/arm/fdt/files.fdt" - -# Pull in Exynos SoC default -include "arch/arm/samsung/files.exynos" +include "arch/arm/samsung/files.exynos" diff --git a/sys/arch/evbarm/conf/files.sunxi b/sys/arch/evbarm/conf/files.sunxi new file mode 100644 index 000000000000..235ff4ad6640 --- /dev/null +++ b/sys/arch/evbarm/conf/files.sunxi @@ -0,0 +1,8 @@ +# $NetBSD: files.sunxi,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ +# +# Allwinner sunxi configuration info +# + +include "arch/evbarm/conf/files.fdt" + +include "arch/arm/sunxi/files.sunxi" diff --git a/sys/arch/evbarm/conf/mk.sunxi b/sys/arch/evbarm/conf/mk.sunxi new file mode 100644 index 000000000000..0de8691734e0 --- /dev/null +++ b/sys/arch/evbarm/conf/mk.sunxi @@ -0,0 +1,32 @@ +# $NetBSD: mk.sunxi,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ + +SYSTEM_FIRST_OBJ= sunxi_start.o +SYSTEM_FIRST_SFILE= ${THISARM}/sunxi/sunxi_start.S + +AFLAGS.sunxi_start.S+= -Wa,-march=armv7-a+virt +AFLAGS.psci_arm.S+= -Wa,-march=armv7-a+sec+virt + +GENASSYM_EXTRAS+= ${THISARM}/sunxi/genassym.cf + +_OSRELEASE!= ${HOST_SH} $S/conf/osrelease.sh + +MKUBOOTIMAGEARGS= -A arm -T kernel -O linux +MKUBOOTIMAGEARGS+= -a $(KERNEL_BASE_PHYS) -e $(KERNEL_BASE_PHYS) +MKUBOOTIMAGEARGS+= -n "NetBSD/$(BOARDTYPE) ${_OSRELEASE}" +MKUBOOTIMAGEARGS_NONE= ${MKUBOOTIMAGEARGS} -C none +MKUBOOTIMAGEARGS_GZ= ${MKUBOOTIMAGEARGS} -C gz + +SYSTEM_LD_TAIL_EXTRA+=; \ + echo ${OBJCOPY} -S -O binary $@ $@.bin; \ + ${OBJCOPY} -S -O binary $@ $@.bin; \ + echo ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_NONE} $@.bin $@.ub; \ + ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_NONE} $@.bin $@.ub; \ + echo ${TOOL_GZIP} -c $@.bin > $@.bin.gz; \ + ${TOOL_GZIP} -c $@.bin > $@.bin.gz; \ + echo ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_GZ} $@.bin.gz $@.gz.ub; \ + ${TOOL_MKUBOOTIMAGE} ${MKUBOOTIMAGEARGS_GZ} $@.bin.gz $@.gz.ub + +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin@} +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.ub@} +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin.gz@} +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.gz.ub@} diff --git a/sys/arch/evbarm/conf/std.exynos b/sys/arch/evbarm/conf/std.exynos index 31da5d219af0..ed9e6d4f6a64 100644 --- a/sys/arch/evbarm/conf/std.exynos +++ b/sys/arch/evbarm/conf/std.exynos @@ -1,35 +1,36 @@ -# $NetBSD: std.exynos,v 1.1 2015/12/06 00:31:24 marty Exp $ +# $NetBSD: std.exynos,v 1.1.12.1 2017/07/18 19:13:09 snj Exp $ # -# standard NetBSD/evbarm for EXYNOS options machine evbarm arm include "arch/evbarm/conf/std.evbarm" -# Pull in EXYNOS config definitions -include "arch/evbarm/conf/files.exynos" +include "arch/evbarm/conf/files.exynos" -makeoptions CPUFLAGS="-march=armv7-a -mfpu=neon" +makeoptions CPUFLAGS="-march=armv7-a -mfpu=neon" -# To support easy transit to ../arch/arm/arm32 -options MODULAR -options MODULAR_DEFAULT_AUTOLOAD -options ARM_HAS_VBAR -options CORTEX_PMC -options __HAVE_CPU_COUNTER -options __HAVE_FAST_SOFTINTS # should be in types.h -#options __HAVE_MM_MD_DIRECT_MAPPED_PHYS -options TPIDRPRW_IS_CURCPU -options KERNEL_BASE_EXT=0x80000000 -options FPU_VFP - -# All shipped Samsung SoC's that are not Samsung products have this options ARM_TRUSTZONE_FIRMWARE options __NO_FIQ -makeoptions KERNEL_BASE_PHYS="0x80000000" +options FDT # Flattened Device Tree support +options DRAM_BLOCKS=256 +options MODULAR +options MODULAR_DEFAULT_AUTOLOAD +options __HAVE_CPU_COUNTER +options __HAVE_FAST_SOFTINTS # should be in types.h +options ARM_HAS_VBAR +#options __HAVE_MM_MD_DIRECT_MAPPED_PHYS +#options PMAP_NEED_ALLOC_POOLPAGE +options TPIDRPRW_IS_CURCPU +options KERNEL_BASE_EXT=0x80000000 +options FPU_VFP +options PCI_NETBSD_CONFIGURE +options __HAVE_PCI_CONF_HOOK +options __BUS_SPACE_HAS_STREAM_METHODS + +makeoptions KERNEL_BASE_PHYS="0x40000000" makeoptions KERNEL_BASE_VIRT="0x80000000" makeoptions BOARDTYPE="exynos" makeoptions BOARDMKFRAG="${THISARM}/conf/mk.exynos" -options ARM_INTR_IMPL="" +options ARM_INTR_IMPL="" options ARM_GENERIC_TODR diff --git a/sys/arch/evbarm/conf/std.sunxi b/sys/arch/evbarm/conf/std.sunxi new file mode 100644 index 000000000000..8eb87fea95f6 --- /dev/null +++ b/sys/arch/evbarm/conf/std.sunxi @@ -0,0 +1,36 @@ +# $NetBSD: std.sunxi,v 1.3.4.2 2017/07/18 19:13:09 snj Exp $ +# + +machine evbarm arm +include "arch/evbarm/conf/std.evbarm" + +include "arch/evbarm/conf/files.sunxi" + +options FDT # Flattened Device Tree support +options DRAM_BLOCKS=256 +options MODULAR +options MODULAR_DEFAULT_AUTOLOAD +options __HAVE_CPU_COUNTER +options __HAVE_FAST_SOFTINTS # should be in types.h +options __HAVE_CPU_UAREA_ALLOC_IDLELWP +options ARM_HAS_VBAR +#options __HAVE_MM_MD_DIRECT_MAPPED_PHYS +#options PMAP_NEED_ALLOC_POOLPAGE +options TPIDRPRW_IS_CURCPU +options KERNEL_BASE_EXT=0x80000000 +options FPU_VFP +options __BUS_SPACE_HAS_STREAM_METHODS + +makeoptions KERNEL_BASE_PHYS="0x40008000" +makeoptions KERNEL_BASE_VIRT="0x80008000" +makeoptions BOARDTYPE="sunxi" +makeoptions BOARDMKFRAG="${THISARM}/conf/mk.sunxi" +makeoptions CPUFLAGS="-march=armv7-a -mfpu=neon" + +options ARM_INTR_IMPL="" +options ARM_GENERIC_TODR + +# initrd support +options MEMORY_DISK_HOOKS +options MEMORY_DISK_DYNAMIC +pseudo-device md diff --git a/sys/arch/evbarm/conf/std.tegra b/sys/arch/evbarm/conf/std.tegra index 62ac2ab90c86..193f5999e3ea 100644 --- a/sys/arch/evbarm/conf/std.tegra +++ b/sys/arch/evbarm/conf/std.tegra @@ -1,4 +1,4 @@ -# $NetBSD: std.tegra,v 1.13.2.1 2017/07/05 19:57:46 snj Exp $ +# $NetBSD: std.tegra,v 1.13.2.2 2017/07/18 19:13:09 snj Exp $ # machine evbarm arm @@ -7,6 +7,7 @@ include "arch/evbarm/conf/std.evbarm" include "arch/evbarm/conf/files.tegra" options FDT # Flattened Device Tree support +options DRAM_BLOCKS=256 options MODULAR options MODULAR_DEFAULT_AUTOLOAD options __HAVE_CPU_COUNTER diff --git a/sys/arch/evbarm/conf/std.vexpress b/sys/arch/evbarm/conf/std.vexpress index b34ffd0effe8..6395a0c4dd11 100644 --- a/sys/arch/evbarm/conf/std.vexpress +++ b/sys/arch/evbarm/conf/std.vexpress @@ -1,4 +1,4 @@ -# $NetBSD: std.vexpress,v 1.4 2017/06/02 15:22:47 jmcneill Exp $ +# $NetBSD: std.vexpress,v 1.4.2.1 2017/07/18 19:13:09 snj Exp $ # # standard NetBSD/evbarm for VEXPRESS options @@ -9,6 +9,7 @@ include "arch/evbarm/conf/std.evbarm" include "arch/evbarm/conf/files.vexpress" options FDT # Flattened Device Tree support +options DRAM_BLOCKS=256 options MODULAR options MODULAR_DEFAULT_AUTOLOAD options ARM_HAS_VBAR diff --git a/sys/arch/evbarm/exynos/exynos_machdep.c b/sys/arch/evbarm/exynos/exynos_machdep.c deleted file mode 100644 index 7f6db4523527..000000000000 --- a/sys/arch/evbarm/exynos/exynos_machdep.c +++ /dev/null @@ -1,567 +0,0 @@ -/* $NetBSD: exynos_machdep.c,v 1.7 2015/12/21 04:58:50 marty Exp $ */ - -/* - * Copyright (c) 2014 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Reinoud Zandijk. - * - * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 -__KERNEL_RCSID(0, "$NetBSD: exynos_machdep.c,v 1.7 2015/12/21 04:58:50 marty Exp $"); - -#include "opt_evbarm_boardtype.h" -#include "opt_exynos.h" -#include "opt_machdep.h" -#include "opt_ddb.h" -#include "opt_kgdb.h" -#include "opt_ipkdb.h" -#include "opt_md.h" -#include "opt_sscom.h" -#include "opt_arm_debug.h" - -#include "ukbd.h" -#include "arml2cc.h" // RPZ why is it not called opt_l2cc.h? - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include -#ifdef KGDB -#include -#endif - -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#include -#include - -#include -#include - -/* serial console stuff */ -#include "sscom.h" -#include "opt_sscom.h" - -#include -#include - -/* so we can load the device tree. NOTE: This requires the kernel to be - * made into a linux (not netbsd) uboot image. - */ -#include -#include -#define FDT_BUF_SIZE (128*1024) -static uint8_t fdt_data[FDT_BUF_SIZE]; - -extern const int num_exynos_uarts_entries; -extern const struct sscom_uart_info exynos_uarts[]; - -#ifndef CONSPEED -#define CONSPEED 115200 -#endif /* CONSPEED */ -#ifndef CONMODE -#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB | HUPCL)) | CS8) /* 8N1 */ -#endif /* CONMODE */ - -static const int conspeed = CONSPEED; -static const int conmode = CONMODE; - -/* - * uboot passes 4 arguments to us. - * - * arg0 arg1 arg2 arg3 : the `bootargs' environment variable from the uboot - * context (in PA!) - * - * Note that the storage has to be in .data and not in .bss. On kernel start - * the .bss is cleared and this information would get lost. - */ -uintptr_t uboot_args[4] = { 0 }; - -/* - * argument and boot configure storage - */ -BootConfig bootconfig; /* for pmap's sake */ -char bootargs[MAX_BOOT_STRING] = ""; /* copied string from uboot */ -char *boot_args = NULL; /* MI bootargs */ -char *boot_file = NULL; /* MI bootfile */ -uint8_t uboot_enaddr[ETHER_ADDR_LEN] = {}; - - -void -odroid_device_register(device_t self, void *aux); - -/* - * kernel start and end from the linker - */ -extern char KERNEL_BASE_phys[]; /* physical start of kernel */ -extern char _end[]; /* physical end of kernel */ -#define KERNEL_BASE_PHYS ((paddr_t)KERNEL_BASE_phys) - -#define EXYNOS_IOPHYSTOVIRT(a) \ - ((vaddr_t)(((a) - EXYNOS_CORE_PBASE) + EXYNOS_CORE_VBASE)) - -static void exynos_reset(void); -static void exynos_powerdown(void); -/* XXX we have no framebuffer implementation yet so com is console XXX */ -int use_fb_console = false; - - -/* prototypes */ -void consinit(void); -#ifdef KGDB -static void kgdb_port_init(void); -#endif -static void exynos_extract_mac_adress(void); -void exynos_device_register(device_t self, void *aux); -void exynos_device_register_post_config(device_t self, void *aux); - -/* - * Our static device mappings at fixed virtual addresses so we can use them - * while booting the kernel. - * - * Map the extents segment-aligned and segment-rounded in size to avoid L2 - * page tables - */ - -#define _A(a) ((a) & ~L1_S_OFFSET) -#define _S(s) (((s) + L1_S_SIZE - 1) & (~(L1_S_SIZE-1))) - -static const struct pmap_devmap e5_devmap[] = { - { - /* map in core IO space */ - .pd_va = _A(EXYNOS_CORE_VBASE), - .pd_pa = _A(EXYNOS_CORE_PBASE), - .pd_size = _S(EXYNOS5_CORE_SIZE), - .pd_prot = VM_PROT_READ | VM_PROT_WRITE, - .pd_cache = PTE_NOCACHE - }, - { - /* map in audiocore IO space */ - .pd_va = _A(EXYNOS5_AUDIOCORE_VBASE), - .pd_pa = _A(EXYNOS5_AUDIOCORE_PBASE), - .pd_size = _S(EXYNOS5_AUDIOCORE_SIZE), - .pd_prot = VM_PROT_READ | VM_PROT_WRITE, - .pd_cache = PTE_NOCACHE - }, - {0} -}; -#undef _A -#undef _S - -#ifdef PMAP_NEED_ALLOC_POOLPAGE -static struct boot_physmem bp_highgig = { - .bp_pages = (KERNEL_VM_BASE - KERNEL_BASE) / NBPG, - .bp_freelist = VM_FREELIST_ISADMA, - .bp_flags = 0, -}; -#endif - -static struct gpio_pin_entry { - const char *pin_name; - const char *pin_user; -} gpio_pin_entries[] = { - /* mux@13400000 (muxa) */ - { "gpx3-7", "hdmi-hpd-irq"}, - { "gpx3-6", "hdmi_cec" }, - { "gpx0-7", "dp_hpd_gpio" }, - { "gpx0-4", "pmic-irq" }, - { "gpx3-2", "audio-irq" }, - { "gpx3-4", "b-sess1-irq" }, - { "gpx3-5", "b-sess0-irq" }, - { "gpx1-1", "id2-irq" }, - /* mux@134100000 (muxb) */ - { "gpc0-0", "sd0-clk" }, - { "gpc0-1", "sd0-cmd" }, - { "gpc0-7", "sd0-rdqs" }, - { "gpd1-3", "sd0-qrdy" }, - { "gpc0-3", "sd0-bus-width1" }, - { "gpc0-3", "sd0-bus-width4-bit1" }, - { "gpc0-4", "sd0-bus-width4-bit2" }, - { "gpc0-5", "sd0-bus-width4-bit3" }, - { "gpc0-6", "sd0-bus-width4-bit4" }, - { "gpc1-0", "sd1-clk" }, - { "gpc1-1", "sd1-cmd" }, - { "gpc1-3", "sd1-bus-width1" }, - { "gpc1-3", "sd1-bus-width4-bit1" }, - { "gpc1-4", "sd1-bus-width4-bit2" }, - { "gpc1-5", "sd1-bus-width4-bit3" }, - { "gpc1-6", "sd1-bus-width4-bit4" }, - /* TODO: muxc and muxd as needed */ - { 0, 0} -}; - -#ifdef VERBOSE_INIT_ARM -extern void exynos_putchar(int); - -static void -exynos_putstr(const char *s) -{ - for (const char *p = s; *p; p++) { - exynos_putchar(*p); - } -} - -static void -exynos_printn(u_int n, int base) -{ - char *p, buf[(sizeof(u_int) * NBBY / 3) + 1 + 2 /* ALT + SIGN */]; - - p = buf; - do { - *p++ = hexdigits[n % base]; - } while (n /= base); - - do { - exynos_putchar(*--p); - } while (p > buf); -} -#define DPRINTF(...) printf(__VA_ARGS__) -#define DPRINT(x) exynos_putstr(x) -#define DPRINTN(x,b) exynos_printn((x), (b)) -#else -#define DPRINTF(...) -#define DPRINT(x) -#define DPRINTN(x,b) -#endif - -extern void cortex_mpstart(void); - -/* - * void init_gpio_dictionary(...) - * - * Setup the dictionary of gpio pin names for the drivers to use - */ -static void init_gpio_dictionary(struct gpio_pin_entry *pins, - prop_dictionary_t dict) -{ - while (pins->pin_name) { - prop_dictionary_set_cstring(dict, pins->pin_user, - pins->pin_name); - pins++; - } -} -/* - * u_int initarm(...) - * - * Our entry point from the assembly before main() is called. - * - take a copy of the config we got from uboot - * - init the physical console - * - setting up page tables for the kernel - */ - -u_int -initarm(void *arg) -{ - const struct pmap_devmap const *devmap; - bus_addr_t rambase; - psize_t ram_size; - DPRINT("initarm:"); - - DPRINT(" mpstart<0x"); - DPRINTN((uint32_t)cortex_mpstart, 16); - DPRINT(">"); - - /* allocate/map our basic memory mapping */ - switch (EXYNOS_PRODUCT_FAMILY(exynos_soc_id)) { -#if defined(EXYNOS5) - case EXYNOS5_PRODUCT_FAMILY: - devmap = e5_devmap; - rambase = EXYNOS5_SDRAM_PBASE; - break; -#endif - default: - /* Won't work, but... */ - panic("Unknown product family %llx", - EXYNOS_PRODUCT_FAMILY(exynos_soc_id)); - } - pmap_devmap_register(devmap); - - /* bootstrap soc. uart_address is determined in exynos_start */ - paddr_t uart_address = armreg_tpidruro_read(); - exynos_bootstrap(EXYNOS_CORE_VBASE, EXYNOS_IOPHYSTOVIRT(uart_address)); - - /* set up CPU / MMU / TLB functions */ - if (set_cpufuncs()) - panic("cpu not recognized!"); - - /* get normal console working */ - consinit(); - -#ifdef KGDB - kgdb_port_init(); -#endif - -#ifdef VERBOSE_INIT_ARM - printf("\nuboot arg = %#"PRIxPTR", %#"PRIxPTR", %#"PRIxPTR", %#"PRIxPTR"\n", - uboot_args[0], uboot_args[1], uboot_args[2], uboot_args[3]); - printf("Exynos SoC ID %08x\n", exynos_soc_id); - - printf("initarm: cbar=%#x\n", armreg_cbar_read()); -#endif - - /* determine cpu0 clock rate */ - exynos_clocks_bootstrap(); -#ifdef VERBOSE_INIT_ARM - printf("CPU0 now running on %"PRIu64" Mhz\n", exynos_get_cpufreq()/(1000*1000)); -#endif - - cpu_reset_address = exynos_reset; - cpu_powerdown_address = exynos_powerdown; - -#ifdef VERBOSE_INIT_ARM - printf("\nNetBSD/evbarm (Exynnos 5422) booting ...\n"); -#endif - -#ifdef BOOT_ARGS - char mi_bootargs[] = BOOT_ARGS; - parse_mi_bootargs(mi_bootargs); -#endif - - boot_args = bootargs; - parse_mi_bootargs(boot_args); - exynos_extract_mac_adress(); - - /* Don't map the DMA reserved region */ -// ram_size = (psize_t) 0xC0000000 - 0x40000000; - ram_size = (psize_t) 0xb0000000 - 0x40000000; - -#ifdef __HAVE_MM_MD_DIRECT_MAPPED_PHYS - const bool mapallmem_p = true; -#ifndef PMAP_NEED_ALLOC_POOLPAGE - if (ram_size > KERNEL_VM_BASE - KERNEL_BASE) { - printf("%s: dropping RAM size from %luMB to %uMB\n", - __func__, (unsigned long) (ram_size >> 20), - (KERNEL_VM_BASE - KERNEL_BASE) >> 20); - ram_size = KERNEL_VM_BASE - KERNEL_BASE; - } -#endif -#else - const bool mapallmem_p = false; -#endif - - /* Load the dtb */ - const uint8_t *fdt_addr_r = (const uint8_t *)uboot_args[2]; - printf("fdt addr 0x%08x\n", (uint)fdt_addr_r); - int error = fdt_check_header(fdt_addr_r); - printf("fdt check header returns %d\n", error); - if (error == 0) { - error = fdt_move(fdt_addr_r, fdt_data, sizeof(fdt_data)); - printf("fdt move returns %d\n", error); - if (error != 0) { - panic("fdt_move failed: %s", fdt_strerror(error)); - } - fdtbus_set_data(fdt_data); - } else { - panic("fdt_check_header failed: %s", fdt_strerror(error)); - } - - /* Fake bootconfig structure for the benefit of pmap.c. */ - bootconfig.dramblocks = 1; - bootconfig.dram[0].address = rambase; - bootconfig.dram[0].pages = ram_size / PAGE_SIZE; - KASSERT((armreg_pfr1_read() & ARM_PFR1_SEC_MASK) != 0); - - arm32_bootmem_init(bootconfig.dram[0].address, ram_size, - KERNEL_BASE_PHYS); - arm32_kernel_vm_init(KERNEL_VM_BASE, ARM_VECTORS_LOW, 0, devmap, - mapallmem_p); - - /* we've a specific device_register routine */ - evbarm_device_register = odroid_device_register; -// evbarm_device_register_post_config = exynos_device_register_post_config; - /* - * If we couldn't map all of memory via TTBR1, limit the memory the - * kernel can allocate from to be from the highest available 1GB. - */ -#ifdef PMAP_NEED_ALLOC_POOLPAGE - if (atop(ram_size) > bp_highgig.bp_pages) { - arm_poolpage_vmfreelist = bp_highgig.bp_freelist; - return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, - &bp_highgig, 1); - } -#endif - - return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, NULL, 0); -} - -void -consinit(void) -{ - static bool consinit_called; - - if (consinit_called) - return; - consinit_called = true; - -#if NSSCOM > 0 - bus_space_tag_t bst = &armv7_generic_bs_tag; - bus_addr_t iobase = armreg_tpidruro_read(); - bus_space_handle_t bsh = EXYNOS_IOPHYSTOVIRT(iobase); - u_int i; - /* - * No need to guess at the UART frequency since we can calculate it. - */ - uint32_t freq = conspeed - * (16 * (bus_space_read_4(bst, bsh, SSCOM_UBRDIV) + 1) - + bus_space_read_4(bst, bsh, SSCOM_UFRACVAL)); - freq = (freq + conspeed / 2) / 1000; - freq *= 1000; - - /* go through all entries */ - for (i = 0; i < num_exynos_uarts_entries; i++) { - /* attach console */ - if (exynos_uarts[i].iobase + EXYNOS_CORE_PBASE == iobase) - break; - } - KASSERT(i < num_exynos_uarts_entries); - printf("%s: attaching console @ %#"PRIxPTR" (%u HZ, %u bps)\n", - __func__, iobase, freq, conspeed); - if (sscom_cnattach(bst, exynos_core_bsh, &exynos_uarts[i], - conspeed, freq, conmode)) - panic("Serial console can not be initialized"); -#ifdef VERBOSE_INIT_ARM - printf("Console initialized\n"); -#endif -#else -#error only serial console is supported -#if NUKBD > 0 - /* allow USB keyboards to become console */ - ukbd_cnattach(); -#endif /* NUKBD */ -#endif -} - - -/* extract ethernet mac address from bootargs */ -static void -exynos_extract_mac_adress(void) -{ - char *str, *ptr; - int i, v1, v2, val; - -#define EXPECT_COLON() {\ - v1 = *ptr++; \ - if (v1 != ':') break; \ - } -#define EXPECT_HEX(v) {\ - (v) = (v) >= '0' && (v) <= '9'? (v) - '0' : \ - (v) >= 'a' && (v) <= 'f'? (v) - 'a' + 10 : \ - (v) >= 'A' && (v) <= 'F'? (v) - 'A' + 10 : -1; \ - if ((v) < 0) break; \ - } -#define EXPECT_2HEX(val) {\ - v1 = *ptr++; EXPECT_HEX(v1); \ - v2 = *ptr++; EXPECT_HEX(v2); \ - val = (v1 << 4) | v2; \ - } - if (get_bootconf_option(boot_args, "ethaddr", - BOOTOPT_TYPE_STRING, &str)) { - for (i = 0, ptr = str; i < sizeof(uboot_enaddr); i++) { - if (i) - EXPECT_COLON(); - EXPECT_2HEX(val); - uboot_enaddr[i] = val; - } - if (i != sizeof(uboot_enaddr)) { - printf( "Ignoring invalid MAC address '%s' passed " - "as boot paramter `ethaddr'\n", str); - memset((char *) uboot_enaddr, 0, sizeof(uboot_enaddr)); - } - } -#undef EXPECT_2HEX -#undef EXPECT_HEX -#undef EXPECT_COLON -} - -void -odroid_device_register(device_t self, void *aux) -{ - prop_dictionary_t dict = device_properties(self); - exynos_device_register(self, aux); - if (device_is_a(self, "exyogpio")) { - init_gpio_dictionary(gpio_pin_entries, dict); - } else if (device_is_a(self, "exyowdt")) { - prop_dictionary_set_uint32(dict, "frequency", - EXYNOS_F_IN_FREQ); - } -} - -/* - * Exynos specific tweaks - */ -/* - * The external USB devices are clocked trough the DEBUG clkout - * XXX is this Odroid specific? XXX - */ -void -exynos_init_clkout_for_usb(void) -{ - /* Select XUSBXTI as source for CLKOUT */ - bus_space_write_4(&armv7_generic_bs_tag, exynos_pmu_bsh, - EXYNOS_PMU_DEBUG_CLKOUT, 0x1000); -} - -static void -exynos_reset(void) -{ -} - -static void -exynos_powerdown(void) -{ -} diff --git a/sys/arch/evbarm/exynos/exynos_start.S b/sys/arch/evbarm/exynos/exynos_start.S index 2e17175a82fb..013d7e9f4828 100644 --- a/sys/arch/evbarm/exynos/exynos_start.S +++ b/sys/arch/evbarm/exynos/exynos_start.S @@ -1,4 +1,4 @@ -/* $NetBSD: exynos_start.S,v 1.3 2015/12/17 08:03:06 skrll Exp $ */ +/* $NetBSD: exynos_start.S,v 1.3.12.1 2017/07/18 19:13:09 snj Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -45,7 +45,7 @@ #include -RCSID("$NetBSD: exynos_start.S,v 1.3 2015/12/17 08:03:06 skrll Exp $") +RCSID("$NetBSD: exynos_start.S,v 1.3.12.1 2017/07/18 19:13:09 snj Exp $") #if defined(VERBOSE_INIT_ARM) @@ -68,7 +68,7 @@ RCSID("$NetBSD: exynos_start.S,v 1.3 2015/12/17 08:03:06 skrll Exp $") #define TEMP_L1_TABLE (KERNEL_BASE - KERNEL_BASE_VOFFSET + INIT_MEMSIZE * L1_S_SIZE - L1_TABLE_SIZE) -#define MD_CPU_HATCH _C_LABEL(gtmr_init_cpu_clock) +#define MD_CPU_HATCH _C_LABEL(arm_fdt_cpu_hatch) /* * Kernel start routine for Exynos 5422 boards running on uboot firmware @@ -100,6 +100,18 @@ _C_LABEL(exynos_start): #endif stmia r4, {r0-r3} // Save the arguments + /* Add DTB PA (1MB) from r2 to MMU init table */ + movw r3, #:lower16:(L1_S_SIZE - 1) /* align DTB PA to 1M */ + movt r3, #:upper16:(L1_S_SIZE - 1) + bic r0, r2, r3 + orr r0, r0, #1 /* 1MB mapping */ + bic r1, r2, r3 + movw r3, #:lower16:(L1_S_PROTO_armv7|L1_S_APv7_KRW|L1_S_CACHEABLE) + movt r3, #:upper16:(L1_S_PROTO_armv7|L1_S_APv7_KRW|L1_S_CACHEABLE) + orr r1, r1, r3 + adrl r3, .Lmmu_init_table_dtb /* table entry addr */ + stmia r3, {r0-r1} /* patch table entry */ + /* * For easy and early SoC / PoP dependency, retrieve the IDs */ @@ -268,6 +280,11 @@ mmu_init_table: EXYNOS_CORE_SIZE / L1_S_SIZE, L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_V6_XN) + /* Map DTB location in SDRAM, patched in later */ +.Lmmu_init_table_dtb: + MMU_INIT(0, 0, 0, 0) + + /* end of table */ MMU_INIT(0, 0, 0, 0) diff --git a/sys/arch/evbarm/exynos/platform.h b/sys/arch/evbarm/exynos/platform.h index 1b7bca976ccf..d796426a7e5c 100644 --- a/sys/arch/evbarm/exynos/platform.h +++ b/sys/arch/evbarm/exynos/platform.h @@ -1,4 +1,4 @@ -/* $NetBSD: platform.h,v 1.1 2015/12/06 00:33:44 marty Exp $ */ +/* $NetBSD: platform.h,v 1.1.12.1 2017/07/18 19:13:09 snj Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -32,11 +32,7 @@ #ifndef _ARM_EXYNOS_PLATFORM_H #define _ARM_EXYNOS_PLATFORM_H -/* - * Kernel VM space 16Mb behind KERNEL_BASE upto 0xeff00000 - */ -#define KERNEL_VM_BASE 0xc0000000 -#define KERNEL_VM_SIZE (EXYNOS_CORE_VBASE - KERNEL_VM_BASE) +#include /* * IO space diff --git a/sys/arch/evbarm/fdt/fdt_machdep.c b/sys/arch/evbarm/fdt/fdt_machdep.c index 5290cac35c12..ddad0ba6e0ce 100644 --- a/sys/arch/evbarm/fdt/fdt_machdep.c +++ b/sys/arch/evbarm/fdt/fdt_machdep.c @@ -1,4 +1,4 @@ -/* $NetBSD: fdt_machdep.c,v 1.4.2.2 2017/06/14 04:54:21 snj Exp $ */ +/* $NetBSD: fdt_machdep.c,v 1.4.2.3 2017/07/18 19:13:09 snj Exp $ */ /*- * Copyright (c) 2015-2017 Jared McNeill @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.4.2.2 2017/06/14 04:54:21 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.4.2.3 2017/07/18 19:13:09 snj Exp $"); #include "opt_machdep.h" #include "opt_ddb.h" @@ -50,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.4.2.2 2017/06/14 04:54:21 snj Exp #include #include #include +#include #include @@ -70,6 +71,10 @@ __KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.4.2.2 2017/06/14 04:54:21 snj Exp #include +#ifdef MEMORY_DISK_DYNAMIC +#include +#endif + #ifndef FDT_MAX_BOOT_STRING #define FDT_MAX_BOOT_STRING 1024 #endif @@ -79,6 +84,11 @@ char bootargs[FDT_MAX_BOOT_STRING] = ""; char *boot_args = NULL; u_int uboot_args[4] = { 0 }; /* filled in by xxx_start.S (not in bss) */ +static char fdt_memory_ext_storage[EXTENT_FIXED_STORAGE_SIZE(DRAM_BLOCKS)]; +static struct extent *fdt_memory_ext; + +static uint64_t initrd_start, initrd_end; + #include #include #define FDT_BUF_SIZE (128*1024) @@ -167,6 +177,155 @@ fdt_get_memory(uint64_t *paddr, uint64_t *psize) } } +static void +fdt_add_reserved_memory_range(uint64_t addr, uint64_t size) +{ + int error; + + error = extent_free(fdt_memory_ext, addr, size, EX_NOWAIT); + if (error != 0) + printf("MEM ERROR: add %llx-%llx failed: %d\n", + addr, size, error); + DPRINTF("MEM: res %llx-%llx: %d\n", addr, size, error); +} + +/* + * Exclude memory ranges from memory config from a /reserved-memory/ child + */ +static void +fdt_add_reserved_memory(int phandle, uint64_t max_addr) +{ + uint64_t addr, size; + int index; + + for (index = 0; + fdtbus_get_reg64(phandle, index, &addr, &size) == 0; + index++) { + if (addr >= max_addr) + continue; + if (addr + size > max_addr) + size = max_addr - addr; + fdt_add_reserved_memory_range(addr, size); + } +} + +/* + * Define usable memory regions. + */ +static void +fdt_build_bootconfig(uint64_t mem_addr, uint64_t mem_size) +{ + const int memory = OF_finddevice("/memory"); + const uint64_t max_addr = mem_addr + mem_size; + BootConfig *bc = &bootconfig; + struct extent_region *er; + uint64_t addr, size; + int index, child, error; + + fdt_memory_ext = extent_create("FDT Memory", mem_addr, max_addr, + fdt_memory_ext_storage, sizeof(fdt_memory_ext_storage), 0); + + for (index = 0; + fdtbus_get_reg64(memory, index, &addr, &size) == 0; + index++) { + if (addr >= max_addr) + continue; + if (addr + size > max_addr) + size = max_addr - addr; + + error = extent_alloc_region(fdt_memory_ext, addr, size, + EX_NOWAIT); + if (error != 0) + printf("MEM ERROR: add %llx-%llx failed: %d\n", + addr, size, error); + DPRINTF("MEM: add %llx-%llx\n", addr, size); + } + + const int reserved = OF_finddevice("/reserved-memory"); + if (reserved > 0) + for (child = OF_child(reserved); child; child = OF_peer(child)) + fdt_add_reserved_memory(child, max_addr); + + const uint64_t initrd_size = initrd_end - initrd_start; + if (initrd_size > 0) + fdt_add_reserved_memory_range(initrd_start, initrd_size); + + DPRINTF("Usable memory:\n"); + bc->dramblocks = 0; + LIST_FOREACH(er, &fdt_memory_ext->ex_regions, er_link) { + DPRINTF(" %lx - %lx\n", er->er_start, er->er_end); + bc->dram[bc->dramblocks].address = er->er_start; + bc->dram[bc->dramblocks].pages = + (er->er_end - er->er_start) / PAGE_SIZE; + bc->dramblocks++; + } +} + +static void +fdt_probe_initrd(uint64_t *pstart, uint64_t *pend) +{ + *pstart = *pend = 0; + +#ifdef MEMORY_DISK_DYNAMIC + const int chosen = OF_finddevice("/chosen"); + if (chosen < 0) + return; + + int len; + const void *start_data = fdtbus_get_prop(chosen, + "linux,initrd-start", &len); + const void *end_data = fdtbus_get_prop(chosen, + "linux,initrd-end", NULL); + if (start_data == NULL || end_data == NULL) + return; + + switch (len) { + case 4: + *pstart = be32dec(start_data); + *pend = be32dec(end_data); + break; + case 8: + *pstart = be64dec(start_data); + *pend = be64dec(end_data); + break; + default: + printf("Unsupported len %d for /chosen/initrd-start\n", len); + return; + } +#endif +} + +static void +fdt_setup_initrd(void) +{ +#ifdef MEMORY_DISK_DYNAMIC + const uint64_t initrd_size = initrd_end - initrd_start; + paddr_t startpa = trunc_page(initrd_start); + paddr_t endpa = round_page(initrd_end); + paddr_t pa; + vaddr_t va; + void *md_start; + + if (initrd_size == 0) + return; + + va = uvm_km_alloc(kernel_map, initrd_size, 0, + UVM_KMF_VAONLY | UVM_KMF_NOWAIT); + if (va == 0) { + printf("Failed to allocate VA for initrd\n"); + return; + } + + md_start = (void *)va; + + for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) + pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, 0); + pmap_update(pmap_kernel()); + + md_root_setconf(md_start, initrd_size); +#endif +} + u_int initarm(void *arg) { @@ -251,8 +410,8 @@ initarm(void *arg) #if !defined(_LP64) /* Cannot map memory above 4GB */ - if (memory_addr + memory_size > 0x100000000) - memory_size = 0x100000000 - memory_addr; + if (memory_addr + memory_size >= 0x100000000) + memory_size = 0x100000000 - memory_addr - PAGE_SIZE; #endif ram_size = (bus_size_t)memory_size; @@ -271,10 +430,11 @@ initarm(void *arg) const bool mapallmem_p = false; #endif - /* Fake bootconfig structure for the benefit of pmap.c. */ - bootconfig.dramblocks = 1; - bootconfig.dram[0].address = (bus_addr_t)memory_addr; - bootconfig.dram[0].pages = ram_size / PAGE_SIZE; + /* Parse ramdisk info */ + fdt_probe_initrd(&initrd_start, &initrd_end); + + /* Populate bootconfig structure for the benefit of pmap.c. */ + fdt_build_bootconfig(memory_addr, memory_size); arm32_bootmem_init(bootconfig.dram[0].address, ram_size, KERNEL_BASE_PHYS); @@ -295,7 +455,6 @@ initarm(void *arg) #endif return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, NULL, 0); - } static void @@ -360,6 +519,9 @@ fdt_device_register(device_t self, void *aux) { const struct arm_platform *plat = arm_fdt_platform(); + if (device_is_a(self, "armfdt")) + fdt_setup_initrd(); + if (plat && plat->device_register) plat->device_register(self, aux); } diff --git a/sys/arch/evbarm/include/bootconfig.h b/sys/arch/evbarm/include/bootconfig.h index 04f471348d80..c7b036eb95ed 100644 --- a/sys/arch/evbarm/include/bootconfig.h +++ b/sys/arch/evbarm/include/bootconfig.h @@ -1,4 +1,4 @@ -/* $NetBSD: bootconfig.h,v 1.6 2006/02/06 14:03:22 hamajima Exp $ */ +/* $NetBSD: bootconfig.h,v 1.6.152.1 2017/07/18 19:13:09 snj Exp $ */ /* * Copyright (c) 1994 Mark Brinicombe. @@ -36,6 +36,8 @@ * SUCH DAMAGE. */ +#include "opt_machdep.h" + #include typedef struct _PhysMem { diff --git a/sys/arch/evbarm/sunxi/genassym.cf b/sys/arch/evbarm/sunxi/genassym.cf new file mode 100644 index 000000000000..1fdce7ca82cb --- /dev/null +++ b/sys/arch/evbarm/sunxi/genassym.cf @@ -0,0 +1,38 @@ +# $NetBSD: genassym.cf,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ + +#- +# Copyright (c) 2013 The NetBSD Foundation, Inc. +# All rights reserved. +# +# This code is derived from software contributed to The NetBSD Foundation +# by Matt Thomas of 3am Software Foundry. +# +# 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +include + +define LSR_TXRDY LSR_TXRDY +define LSR_TSRE LSR_TSRE +define COM_DATA com_data +define COM_LSR com_lsr diff --git a/sys/arch/evbarm/sunxi/sunxi_start.S b/sys/arch/evbarm/sunxi/sunxi_start.S new file mode 100644 index 000000000000..2c028e7ba7ad --- /dev/null +++ b/sys/arch/evbarm/sunxi/sunxi_start.S @@ -0,0 +1,192 @@ +/* $NetBSD: sunxi_start.S,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2014, 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas of 3am Software Foundry. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 "opt_soc.h" +#include "opt_cpuoptions.h" +#include "opt_cputypes.h" +#include "opt_multiprocessor.h" +#include "opt_arm_debug.h" +#include "opt_fdt_arm.h" + +#include +#include +#include "assym.h" + +#include + +RCSID("$NetBSD: sunxi_start.S,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $") + +#if defined(VERBOSE_INIT_ARM) && defined(CONSADDR) +#define XPUTC(n) mov r0, n; bl xputc +#if KERNEL_BASE_VOFFSET == 0 +#define XPUTC2(n) mov r0, n; bl xputc +#else +#define XPUTC2(n) mov r0, n; blx r11 +#endif +#ifdef __ARMEB__ +#define COM_BSWAP +#endif +#define COM_MULT 4 +#define XPUTC_COM 1 +#else +#define XPUTC(n) +#define XPUTC2(n) +#endif + +#define INIT_MEMSIZE 64 +#define TEMP_L1_TABLE (KERNEL_BASE - KERNEL_BASE_VOFFSET + INIT_MEMSIZE * L1_S_SIZE - L1_TABLE_SIZE) + +#define MD_CPU_HATCH _C_LABEL(arm_fdt_cpu_hatch) + +/* + * Kernel start routine for Allwinner sunxi SoCs + * At this point, this code has been loaded into SDRAM + * and the MMU maybe on or maybe off. + */ +#ifdef KERNEL_BASES_EQUAL + .text +#else + .section .start,"ax",%progbits +#endif + + .global _C_LABEL(sunxi_start) +_C_LABEL(sunxi_start): +#ifdef __ARMEB__ + setend be /* force big endian */ +#endif + mov r9, #0 + + /* Move into supervisor mode and disable IRQs/FIQs. */ + cpsid if, #PSR_SVC32_MODE + + /* + * Save any arguments passed to us. + */ + movw r4, #:lower16:uboot_args + movt r4, #:upper16:uboot_args + sub r4, r4, #KERNEL_BASE_VOFFSET + + stmia r4, {r0-r3} // Save the arguments + + /* Add DTB PA (1MB) from r2 to MMU init table */ + movw r3, #:lower16:(L1_S_SIZE - 1) /* align DTB PA to 1M */ + movt r3, #:upper16:(L1_S_SIZE - 1) + bic r0, r2, r3 + orr r0, r0, #1 /* 1MB mapping */ + bic r1, r2, r3 + movw r3, #:lower16:(L1_S_PROTO_armv7|L1_S_APv7_KRW|L1_S_CACHEABLE) + movt r3, #:upper16:(L1_S_PROTO_armv7|L1_S_APv7_KRW|L1_S_CACHEABLE) + orr r1, r1, r3 + adr r3, .Lmmu_init_table_dtb /* table entry addr */ + stmia r3, {r0-r1} /* patch table entry */ + + /* + * Turn on the SMP bit + */ + bl cortex_init + + /* + * Set up a preliminary mapping in the MMU to allow us to run + * at KERNEL_BASE with caches on. + */ + movw r0, #:lower16:TEMP_L1_TABLE + movt r0, #:upper16:TEMP_L1_TABLE + movw r1, #:lower16:.Lmmu_init_table + movt r1, #:upper16:.Lmmu_init_table + bl arm_boot_l1pt_init + XPUTC(#'D') + + /* + * Turn on the MMU, Caches, etc. Return to new enabled address space. + */ + movw r0, #:lower16:TEMP_L1_TABLE + movt r0, #:upper16:TEMP_L1_TABLE +#if KERNEL_BASE_VOFFSET == 0 + bl arm_cpuinit +#else + /* + * After the MMU is on, we can execute in the normal .text segment + * so setup the lr to be in .text. Cache the address for xputc + * before we go. + */ +#if defined(VERBOSE_INIT_ARM) + adr r11, xputc @ for XPUTC2 +#endif + movw lr, #:lower16:1f + movt lr, #:upper16:1f + b arm_cpuinit + .pushsection .text,"ax",%progbits +1: +#endif + XPUTC2(#'Z') + + /* + * Jump to start in locore.S, which in turn will call initarm and main. + */ + b start + + /* NOTREACHED */ + +#ifndef KERNEL_BASES_EQUAL + .popsection +#endif + +#include + +.Lmmu_init_table: + MMU_INIT(KERNEL_BASE, KERNEL_BASE - KERNEL_BASE_VOFFSET, INIT_MEMSIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_CACHEABLE) + +#if KERNEL_BASE_VOFFSET != 0 + /* Map KERNEL_BASE VA to SDRAM PA, write-back cacheable, shareable */ + MMU_INIT(KERNEL_BASE - KERNEL_BASE_VOFFSET, + KERNEL_BASE - KERNEL_BASE_VOFFSET, INIT_MEMSIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_CACHEABLE) +#endif + + /* Map CORE */ + MMU_INIT(SUNXI_CORE_VBASE, SUNXI_CORE_PBASE, + (SUNXI_CORE_SIZE + L1_S_SIZE - 1) / L1_S_SIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_V6_XN) + + /* Map CORE */ + MMU_INIT(SUNXI_CORE_PBASE, SUNXI_CORE_PBASE, + (SUNXI_CORE_SIZE + L1_S_SIZE - 1) / L1_S_SIZE, + L1_S_PROTO_armv7 | L1_S_APv7_KRW | L1_S_V6_XN) + +.Lmmu_init_table_dtb: + /* Map DTB from bootloader (patched in later) */ + MMU_INIT(0, 0, 0, 0) + + /* end of table */ + MMU_INIT(0, 0, 0, 0) + +END(_C_LABEL(sunxi_start)) diff --git a/sys/conf/Makefile.kern.inc b/sys/conf/Makefile.kern.inc index cb50f76c5f33..47b0383cb48a 100644 --- a/sys/conf/Makefile.kern.inc +++ b/sys/conf/Makefile.kern.inc @@ -1,4 +1,4 @@ -# $NetBSD: Makefile.kern.inc,v 1.256 2017/01/11 12:19:43 joerg Exp $ +# $NetBSD: Makefile.kern.inc,v 1.256.8.1 2017/07/18 19:13:09 snj Exp $ # # This file contains common `MI' targets and definitions and it is included # at the bottom of each `MD' ${MACHINE}/conf/Makefile.${MACHINE}. @@ -534,6 +534,26 @@ build_kernel: .USE @${KCOMPILE.s} -pg .endif # ___USE_SUFFIX_RULES___ +# Begin DTS handling + +DTSINC?=$S/external/gpl2/dts/dist/include +DTSPATH?=$S/external/gpl2/dts/dist/arch/${MACHINE_CPU}/boot/dts +DTSPADDING?=1024 + +.SUFFIXES: .dtb .dts +.dts.dtb: + ${CPP} -P -xassembler-with-cpp -I ${DTSINC} -I ${DTSPATH} \ + -include ${.IMPSRC} /dev/null | \ + ${TOOL_DTC} -i ${DTSINC} -i ${DTSPATH} -I dts -O dtb \ + -p ${DTSPADDING} -b 0 -o ${.TARGET} + +.PATH.dts: ${DTSPATH} + +DTB= ${DTS:.dts=.dtb} +all: ${DTB} + +# End DTS handling + ## ## the end ## diff --git a/sys/conf/files b/sys/conf/files index be65932e63cc..11cd7078373f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,7 +1,7 @@ -# $NetBSD: files,v 1.1173.2.2 2017/06/10 05:57:08 snj Exp $ +# $NetBSD: files,v 1.1173.2.3 2017/07/18 19:13:09 snj Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 -version 20150846 +version 20170615 # # device classes @@ -1505,6 +1505,9 @@ file dev/pud/pud_dev.c pud # device-mapper driver for LVM include "dev/dm/files.dm" +# LED framework +file dev/led.c leds + # # File systems # diff --git a/sys/dev/fdt/ehci_fdt.c b/sys/dev/fdt/ehci_fdt.c new file mode 100644 index 000000000000..e0a40f9b9ecc --- /dev/null +++ b/sys/dev/fdt/ehci_fdt.c @@ -0,0 +1,153 @@ +/* $NetBSD: ehci_fdt.c,v 1.2.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2015-2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ehci_fdt.c,v 1.2.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +static int ehci_fdt_match(device_t, cfdata_t, void *); +static void ehci_fdt_attach(device_t, device_t, void *); + +CFATTACH_DECL2_NEW(ehci_fdt, sizeof(struct ehci_softc), + ehci_fdt_match, ehci_fdt_attach, NULL, + ehci_activate, NULL, ehci_childdet); + +static int +ehci_fdt_match(device_t parent, cfdata_t cf, void *aux) +{ + const char * const compatible[] = { + "generic-ehci", + NULL + }; + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +ehci_fdt_attach(device_t parent, device_t self, void *aux) +{ + struct ehci_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct fdtbus_reset *rst; + struct fdtbus_phy *phy; + struct clk *clk; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + int error; + void *ih; + u_int n; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + /* Enable clocks */ + for (n = 0; (clk = fdtbus_clock_get_index(phandle, n)) != NULL; n++) + if (clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock #%d\n", n); + return; + } + /* De-assert resets */ + for (n = 0; (rst = fdtbus_reset_get_index(phandle, n)) != NULL; n++) + if (fdtbus_reset_deassert(rst) != 0) { + aprint_error(": couldn't de-assert reset #%d\n", n); + return; + } + + /* Enable optional phy */ + phy = fdtbus_phy_get(phandle, "usb"); + if (phy && fdtbus_phy_enable(phy, true) != 0) { + aprint_error(": couldn't enable phy\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bus.ub_hcpriv = sc; + sc->sc_bus.ub_dmatag = faa->faa_dmat; + sc->sc_bus.ub_revision = USBREV_2_0; + if (of_hasprop(phandle, "has-transaction-translator")) + sc->sc_flags |= EHCIF_ETTF; + else + sc->sc_ncomp = 1; + sc->sc_id_vendor = 0; + strlcpy(sc->sc_vendor, "Generic", sizeof(sc->sc_vendor)); + sc->sc_size = size; + sc->iot = faa->faa_bst; + if (bus_space_map(sc->iot, addr, size, 0, &sc->ioh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": EHCI\n"); + + /* Disable interrupts */ + sc->sc_offs = EREAD1(sc, EHCI_CAPLENGTH); + EOWRITE4(sc, EHCI_USBINTR, 0); + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); + return; + } + + ih = fdtbus_intr_establish(phandle, 0, IPL_USB, FDT_INTR_MPSAFE, + ehci_intr, sc); + if (ih == NULL) { + aprint_error_dev(self, "couldn't establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); + + error = ehci_init(sc); + if (error) { + aprint_error_dev(self, "init failed, error = %d\n", error); + return; + } + + sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); +} diff --git a/sys/dev/fdt/fdt_phy.c b/sys/dev/fdt/fdt_phy.c new file mode 100644 index 000000000000..121217ef5dd0 --- /dev/null +++ b/sys/dev/fdt/fdt_phy.c @@ -0,0 +1,181 @@ +/* $NetBSD: fdt_phy.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2015-2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: fdt_phy.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include + +#include +#include + +struct fdtbus_phy_controller { + device_t pc_dev; + int pc_phandle; + const struct fdtbus_phy_controller_func *pc_funcs; + + struct fdtbus_phy_controller *pc_next; +}; + +static struct fdtbus_phy_controller *fdtbus_pc = NULL; + +int +fdtbus_register_phy_controller(device_t dev, int phandle, + const struct fdtbus_phy_controller_func *funcs) +{ + struct fdtbus_phy_controller *pc; + + pc = kmem_alloc(sizeof(*pc), KM_SLEEP); + pc->pc_dev = dev; + pc->pc_phandle = phandle; + pc->pc_funcs = funcs; + + pc->pc_next = fdtbus_pc; + fdtbus_pc = pc; + + return 0; +} + +static struct fdtbus_phy_controller * +fdtbus_get_phy_controller(int phandle) +{ + struct fdtbus_phy_controller *pc; + + for (pc = fdtbus_pc; pc; pc = pc->pc_next) { + if (pc->pc_phandle == phandle) { + return pc; + } + } + + return NULL; +} + +struct fdtbus_phy * +fdtbus_phy_get_index(int phandle, u_int index) +{ + struct fdtbus_phy_controller *pc; + struct fdtbus_phy *phy = NULL; + void *phy_priv = NULL; + uint32_t *phys = NULL; + uint32_t *p; + u_int n, phy_cells; + int len, resid; + + len = OF_getproplen(phandle, "phys"); + if (len <= 0) + return NULL; + + phys = kmem_alloc(len, KM_SLEEP); + if (OF_getprop(phandle, "phys", phys, len) != len) { + kmem_free(phys, len); + return NULL; + } + + p = phys; + for (n = 0, resid = len; resid > 0; n++) { + const int pc_phandle = + fdtbus_get_phandle_from_native(be32toh(p[0])); + if (of_getprop_uint32(pc_phandle, "#phy-cells", &phy_cells)) + break; + if (n == index) { + pc = fdtbus_get_phy_controller(pc_phandle); + if (pc == NULL) + goto done; + phy_priv = pc->pc_funcs->acquire(pc->pc_dev, + phy_cells > 0 ? &p[1] : NULL, phy_cells * 4); + if (phy_priv) { + phy = kmem_alloc(sizeof(*phy), KM_SLEEP); + phy->phy_pc = pc; + phy->phy_priv = phy_priv; + } + break; + } + resid -= (phy_cells + 1) * 4; + p += phy_cells + 1; + } + +done: + if (phys) + kmem_free(phys, len); + + return phy; +} + +struct fdtbus_phy * +fdtbus_phy_get(int phandle, const char *phyname) +{ + struct fdtbus_phy *phy = NULL; + char *phy_names = NULL; + const char *p; + u_int index; + int len, resid; + + len = OF_getproplen(phandle, "phy-names"); + if (len <= 0) + return NULL; + + phy_names = kmem_alloc(len, KM_SLEEP); + if (OF_getprop(phandle, "phy-names", phy_names, len) != len) { + kmem_free(phy_names, len); + return NULL; + } + + p = phy_names; + for (index = 0, resid = len; resid > 0; index++) { + if (strcmp(p, phyname) == 0) { + phy = fdtbus_phy_get_index(phandle, index); + break; + } + resid -= strlen(p); + p += strlen(p) + 1; + } + + if (phy_names) + kmem_free(phy_names, len); + + return phy; +} + +void +fdtbus_phy_put(struct fdtbus_phy *phy) +{ + struct fdtbus_phy_controller *pc = phy->phy_pc; + + pc->pc_funcs->release(pc->pc_dev, phy->phy_priv); + kmem_free(phy, sizeof(*phy)); +} + +int +fdtbus_phy_enable(struct fdtbus_phy *phy, bool enable) +{ + struct fdtbus_phy_controller *pc = phy->phy_pc; + + return pc->pc_funcs->enable(pc->pc_dev, phy->phy_priv, enable); +} diff --git a/sys/dev/fdt/fdt_pinctrl.c b/sys/dev/fdt/fdt_pinctrl.c index 93e755c96fe2..318986f09b23 100644 --- a/sys/dev/fdt/fdt_pinctrl.c +++ b/sys/dev/fdt/fdt_pinctrl.c @@ -1,6 +1,7 @@ -/* $NetBSD: fdt_pinctrl.c,v 1.3 2016/10/11 13:04:57 maxv Exp $ */ +/* $NetBSD: fdt_pinctrl.c,v 1.3.8.1 2017/07/18 19:13:09 snj Exp $ */ /*- + * Copyright (c) 2017 Jared McNeill * Copyright (c) 2015 Martin Fouts * All rights reserved. * @@ -27,7 +28,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: fdt_pinctrl.c,v 1.3 2016/10/11 13:04:57 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fdt_pinctrl.c,v 1.3.8.1 2017/07/18 19:13:09 snj Exp $"); #include #include @@ -37,8 +38,8 @@ __KERNEL_RCSID(0, "$NetBSD: fdt_pinctrl.c,v 1.3 2016/10/11 13:04:57 maxv Exp $") #include struct fdtbus_pinctrl_controller { + device_t pc_dev; int pc_phandle; - void *pc_cookie; const struct fdtbus_pinctrl_controller_func *pc_funcs; struct fdtbus_pinctrl_controller *pc_next; @@ -47,13 +48,13 @@ struct fdtbus_pinctrl_controller { static struct fdtbus_pinctrl_controller *fdtbus_pc = NULL; int -fdtbus_register_pinctrl_config(void *cookie, int phandle, +fdtbus_register_pinctrl_config(device_t dev, int phandle, const struct fdtbus_pinctrl_controller_func *funcs) { struct fdtbus_pinctrl_controller *pc; pc = kmem_alloc(sizeof(*pc), KM_SLEEP); - pc->pc_cookie = cookie; + pc->pc_dev = dev; pc->pc_phandle = phandle; pc->pc_funcs = funcs; @@ -78,57 +79,88 @@ fdtbus_pinctrl_lookup(int phandle) int fdtbus_pinctrl_set_config_index(int phandle, u_int index) { - char buf[80]; - int len, handle; struct fdtbus_pinctrl_controller *pc; + const u_int *pinctrl_data; + char buf[16]; + u_int xref, pinctrl_cells; + int len, error; - snprintf(buf, 80, "pinctrl-%d", index); + snprintf(buf, sizeof(buf), "pinctrl-%u", index); - len = OF_getprop(phandle, buf, (char *)&handle, - sizeof(handle)); - if (len != sizeof(int)) { - printf("%s: couldn't get %s.\n", __func__, buf); - return -1; - } + pinctrl_data = fdtbus_get_prop(phandle, buf, &len); + if (pinctrl_data == NULL) + return ENOENT; - handle = fdtbus_get_phandle_from_native(be32toh(handle)); + while (len > 0) { + xref = fdtbus_get_phandle_from_native(be32toh(pinctrl_data[0])); + pc = fdtbus_pinctrl_lookup(xref); + if (pc == NULL) + return ENXIO; - pc = fdtbus_pinctrl_lookup(handle); - if (!pc) { - printf("%s: Couldn't get handle %d for %s\n", __func__, handle, - buf); - return -1; + if (of_getprop_uint32(OF_parent(xref), "#pinctrl-cells", &pinctrl_cells) != 0) + pinctrl_cells = 1; + + error = pc->pc_funcs->set_config(pc->pc_dev, pinctrl_data, pinctrl_cells * 4); + if (error != 0) + return error; + + pinctrl_data += pinctrl_cells; + len -= (pinctrl_cells * 4); } - return pc->pc_funcs->set_config(pc->pc_cookie); + return 0; } int fdtbus_pinctrl_set_config(int phandle, const char *cfgname) { - int index = 0; - int len; - char *result; - char *next; + const char *pinctrl_names, *name; + int len, index; - len = OF_getproplen(phandle, "pinctrl-names"); - if (len <= 0) + if ((len = OF_getproplen(phandle, "pinctrl-names")) < 0) return -1; - result = kmem_zalloc(len, KM_SLEEP); - OF_getprop(phandle, "pinctrl-names", result, len); - next = result; - while (next - result < len) { - if (!strcmp(next, cfgname)) { - kmem_free(result, len); + pinctrl_names = fdtbus_get_string(phandle, "pinctrl-names"); + + for (name = pinctrl_names, index = 0; len > 0; + name += strlen(name) + 1, index++) { + if (strcmp(name, cfgname) == 0) return fdtbus_pinctrl_set_config_index(phandle, index); - } - index++; - while (*next) - next++; - next++; } - kmem_free(result, len); + /* Not found */ return -1; } + +static void +fdtbus_pinctrl_configure_node(int phandle) +{ + char buf[256]; + int child, error; + + for (child = OF_child(phandle); child; child = OF_peer(child)) { + if (!fdtbus_status_okay(child)) + continue; + + /* Configure child nodes */ + fdtbus_pinctrl_configure_node(child); + + /* + * Set configuration 0 for this node. This may fail if the + * pinctrl provider is missing; that's OK, we will re-configure + * when that provider attaches. + */ + fdtbus_get_path(child, buf, sizeof(buf)); + error = fdtbus_pinctrl_set_config_index(child, 0); + if (error == 0) + aprint_debug("pinctrl: set config pinctrl-0 for %s\n", buf); + else if (error != ENOENT) + aprint_debug("pinctrl: failed to set config pinctrl-0 for %s: %d\n", buf, error); + } +} + +void +fdtbus_pinctrl_configure(void) +{ + fdtbus_pinctrl_configure_node(OF_finddevice("/")); +} diff --git a/sys/dev/fdt/fdt_subr.c b/sys/dev/fdt/fdt_subr.c index 681b8793911c..9a6aa0e3b022 100644 --- a/sys/dev/fdt/fdt_subr.c +++ b/sys/dev/fdt/fdt_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: fdt_subr.c,v 1.13 2017/06/02 01:07:53 jmcneill Exp $ */ +/* $NetBSD: fdt_subr.c,v 1.13.2.1 2017/07/18 19:13:09 snj Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.13 2017/06/02 01:07:53 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.13.2.1 2017/07/18 19:13:09 snj Exp $"); #include #include @@ -406,3 +406,39 @@ fdtbus_status_okay(int phandle) return strncmp(prop, "ok", 2) == 0; } + +const void * +fdtbus_get_prop(int phandle, const char *prop, int *plen) +{ + const int off = fdtbus_phandle2offset(phandle); + + return fdt_getprop(fdtbus_get_data(), off, prop, plen); +} + +const char * +fdtbus_get_string(int phandle, const char *prop) +{ + const int off = fdtbus_phandle2offset(phandle); + + return fdt_getprop(fdtbus_get_data(), off, prop, NULL); +} + +const char * +fdtbus_get_string_index(int phandle, const char *prop, u_int index) +{ + const char *names, *name; + int len, cur; + + if ((len = OF_getproplen(phandle, prop)) < 0) + return NULL; + + names = fdtbus_get_string(phandle, prop); + + for (name = names, cur = 0; len > 0; + name += strlen(name) + 1, cur++) { + if (index == cur) + return name; + } + + return NULL; +} diff --git a/sys/dev/fdt/fdtbus.c b/sys/dev/fdt/fdtbus.c index 90d83601d88e..701a54b8df8f 100644 --- a/sys/dev/fdt/fdtbus.c +++ b/sys/dev/fdt/fdtbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: fdtbus.c,v 1.13 2017/05/28 00:28:17 jmcneill Exp $ */ +/* $NetBSD: fdtbus.c,v 1.13.2.1 2017/07/18 19:13:09 snj Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: fdtbus.c,v 1.13 2017/05/28 00:28:17 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: fdtbus.c,v 1.13.2.1 2017/07/18 19:13:09 snj Exp $"); #include #include @@ -40,6 +40,8 @@ __KERNEL_RCSID(0, "$NetBSD: fdtbus.c,v 1.13 2017/05/28 00:28:17 jmcneill Exp $") #include +#include + #include "locators.h" #define FDT_MAX_PATH 256 @@ -82,13 +84,21 @@ static int fdt_match(device_t parent, cfdata_t cf, void *aux) { const struct fdt_attach_args *faa = aux; + const int phandle = faa->faa_phandle; int match; - match = of_match_compatible(faa->faa_phandle, fdtbus_compatible); + /* Check compatible string */ + match = of_match_compatible(phandle, fdtbus_compatible); if (match) return match; - return OF_finddevice("/") == faa->faa_phandle; + /* Some /clocks nodes have no compatible string */ + if (!of_hasprop(phandle, "compatible") && + OF_finddevice("/clocks") == phandle) + return 1; + + /* Always match the root node */ + return OF_finddevice("/") == phandle; } static void @@ -275,6 +285,7 @@ fdtbus_print(void *aux, const char *pnp) const struct fdt_attach_args * const faa = aux; char buf[FDT_MAX_PATH]; const char *name = buf; + int len; if (pnp && faa->faa_quiet) return QUIET; @@ -286,9 +297,17 @@ fdtbus_print(void *aux, const char *pnp) if (!fdtbus_get_path(faa->faa_phandle, buf, sizeof(buf))) name = faa->faa_name; - if (pnp) + if (pnp) { aprint_normal("%s at %s", name, pnp); - else + const char *compat = fdt_getprop(fdtbus_get_data(), + fdtbus_phandle2offset(faa->faa_phandle), "compatible", + &len); + while (len > 0) { + aprint_debug(" <%s>", compat); + len -= (strlen(compat) + 1); + compat += (strlen(compat) + 1); + } + } else aprint_debug(" (%s)", name); return UNCONF; diff --git a/sys/dev/fdt/fdtvar.h b/sys/dev/fdt/fdtvar.h index 391e2eb765ff..029d9d89f01e 100644 --- a/sys/dev/fdt/fdtvar.h +++ b/sys/dev/fdt/fdtvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: fdtvar.h,v 1.20 2017/06/02 13:53:29 jmcneill Exp $ */ +/* $NetBSD: fdtvar.h,v 1.20.2.1 2017/07/18 19:13:09 snj Exp $ */ /*- * Copyright (c) 2015 Jared D. McNeill @@ -85,7 +85,7 @@ struct fdtbus_pinctrl_pin { }; struct fdtbus_pinctrl_controller_func { - int (*set_config)(void *); + int (*set_config)(device_t, const void *, size_t); }; struct fdtbus_regulator_controller; @@ -172,6 +172,19 @@ struct fdtbus_power_controller_func { void (*poweroff)(device_t); }; +struct fdtbus_phy_controller; + +struct fdtbus_phy { + struct fdtbus_phy_controller *phy_pc; + void *phy_priv; +}; + +struct fdtbus_phy_controller_func { + void * (*acquire)(device_t, const void *, size_t); + void (*release)(device_t, void *); + int (*enable)(device_t, void *, bool); +}; + struct fdt_console { int (*match)(int); void (*consinit)(struct fdt_attach_args *, u_int); @@ -198,7 +211,7 @@ int fdtbus_register_i2c_controller(device_t, int, const struct fdtbus_i2c_controller_func *); int fdtbus_register_gpio_controller(device_t, int, const struct fdtbus_gpio_controller_func *); -int fdtbus_register_pinctrl_config(void *, int, +int fdtbus_register_pinctrl_config(device_t, int, const struct fdtbus_pinctrl_controller_func *); int fdtbus_register_regulator_controller(device_t, int, const struct fdtbus_regulator_controller_func *); @@ -210,6 +223,8 @@ int fdtbus_register_dma_controller(device_t, int, const struct fdtbus_dma_controller_func *); int fdtbus_register_power_controller(device_t, int, const struct fdtbus_power_controller_func *); +int fdtbus_register_phy_controller(device_t, int, + const struct fdtbus_phy_controller_func *); int fdtbus_get_reg(int, u_int, bus_addr_t *, bus_size_t *); int fdtbus_get_reg64(int, u_int, uint64_t *, uint64_t *); @@ -226,6 +241,7 @@ int fdtbus_gpio_read(struct fdtbus_gpio_pin *); void fdtbus_gpio_write(struct fdtbus_gpio_pin *, int); int fdtbus_gpio_read_raw(struct fdtbus_gpio_pin *); void fdtbus_gpio_write_raw(struct fdtbus_gpio_pin *, int); +void fdtbus_pinctrl_configure(void); int fdtbus_pinctrl_set_config_index(int, u_int); int fdtbus_pinctrl_set_config(int, const char *); struct fdtbus_regulator *fdtbus_regulator_acquire(int, const char *); @@ -254,6 +270,11 @@ void fdtbus_reset_put(struct fdtbus_reset *); int fdtbus_reset_assert(struct fdtbus_reset *); int fdtbus_reset_deassert(struct fdtbus_reset *); +struct fdtbus_phy *fdtbus_phy_get(int, const char *); +struct fdtbus_phy *fdtbus_phy_get_index(int, u_int); +void fdtbus_phy_put(struct fdtbus_phy *); +int fdtbus_phy_enable(struct fdtbus_phy *, bool); + int fdtbus_todr_attach(device_t, int, todr_chip_handle_t); void fdtbus_power_reset(void); @@ -274,6 +295,10 @@ tcflag_t fdtbus_get_stdout_flags(void); bool fdtbus_status_okay(int); +const void * fdtbus_get_prop(int, const char *, int *); +const char * fdtbus_get_string(int, const char *); +const char * fdtbus_get_string_index(int, const char *, u_int); + int fdtbus_print(void *, const char *); #endif /* _DEV_FDT_FDTVAR_H */ diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 3c30db840101..3f846a65e65a 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $NetBSD: files.fdt,v 1.16 2017/06/03 14:48:03 jmcneill Exp $ +# $NetBSD: files.fdt,v 1.16.2.1 2017/07/18 19:13:09 snj Exp $ include "external/bsd/libfdt/conf/files.libfdt" @@ -18,10 +18,18 @@ device fclock: clk attach fclock at fdt file dev/fdt/fixedclock.c fclock +device ffclock: clk +attach ffclock at fdt +file dev/fdt/fixedfactorclock.c ffclock + device gpiokeys: sysmon_envsys, sysmon_power attach gpiokeys at fdt file dev/fdt/gpiokeys.c gpiokeys +device gpioleds: leds +attach gpioleds at fdt +file dev/fdt/gpioleds.c gpioleds + file dev/fdt/fdt_openfirm.c fdtbus file dev/fdt/fdt_subr.c fdtbus file dev/fdt/fdt_clock.c fdtbus @@ -29,6 +37,7 @@ file dev/fdt/fdt_dma.c fdtbus file dev/fdt/fdt_gpio.c fdtbus file dev/fdt/fdt_i2c.c fdtbus file dev/fdt/fdt_intr.c fdtbus +file dev/fdt/fdt_phy.c fdtbus file dev/fdt/fdt_power.c fdtbus file dev/fdt/fdt_regulator.c fdtbus file dev/fdt/fdt_reset.c fdtbus diff --git a/sys/dev/fdt/fixedfactorclock.c b/sys/dev/fdt/fixedfactorclock.c new file mode 100644 index 000000000000..f522ae75f847 --- /dev/null +++ b/sys/dev/fdt/fixedfactorclock.c @@ -0,0 +1,164 @@ +/* $NetBSD: fixedfactorclock.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: fixedfactorclock.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include + +#include + +#include + +static int fixedfactorclock_match(device_t, cfdata_t, void *); +static void fixedfactorclock_attach(device_t, device_t, void *); + +static struct clk *fixedfactorclock_decode(device_t, const void *, size_t); + +static const struct fdtbus_clock_controller_func fixedfactorclock_fdt_funcs = { + .decode = fixedfactorclock_decode +}; + +static struct clk *fixedfactorclock_get(void *, const char *); +static void fixedfactorclock_put(void *, struct clk *); +static u_int fixedfactorclock_get_rate(void *, struct clk *); + +static const struct clk_funcs fixedfactorclock_clk_funcs = { + .get = fixedfactorclock_get, + .put = fixedfactorclock_put, + .get_rate = fixedfactorclock_get_rate, +}; + +struct fixedfactorclock_clk { + struct clk base; + + u_int div; + u_int mult; +}; + +struct fixedfactorclock_softc { + device_t sc_dev; + int sc_phandle; + + struct clk_domain sc_clkdom; + struct fixedfactorclock_clk sc_clk; +}; + +CFATTACH_DECL_NEW(ffclock, sizeof(struct fixedfactorclock_softc), + fixedfactorclock_match, fixedfactorclock_attach, NULL, NULL); + +static int +fixedfactorclock_match(device_t parent, cfdata_t cf, void *aux) +{ + const char * const compatible[] = { "fixed-factor-clock", NULL }; + const struct fdt_attach_args *faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +fixedfactorclock_attach(device_t parent, device_t self, void *aux) +{ + struct fixedfactorclock_softc * const sc = device_private(self); + const struct fdt_attach_args *faa = aux; + const int phandle = faa->faa_phandle; + const char *name; + + sc->sc_dev = self; + sc->sc_phandle = phandle; + sc->sc_clkdom.funcs = &fixedfactorclock_clk_funcs; + sc->sc_clkdom.priv = sc; + + of_getprop_uint32(phandle, "clock-div", &sc->sc_clk.div); + of_getprop_uint32(phandle, "clock-mult", &sc->sc_clk.mult); + + if (sc->sc_clk.div == 0 || sc->sc_clk.mult == 0) { + aprint_error(": invalid properties\n"); + return; + } + + name = fdtbus_get_string(phandle, "clock-output-names"); + if (name == NULL) + name = faa->faa_name; + + sc->sc_clk.base.domain = &sc->sc_clkdom; + sc->sc_clk.base.name = name; + + aprint_naive("\n"); + aprint_normal(": x%u /%u fixed-factor clock\n", + sc->sc_clk.mult, sc->sc_clk.div); + + fdtbus_register_clock_controller(self, phandle, + &fixedfactorclock_fdt_funcs); +} + +static struct clk * +fixedfactorclock_decode(device_t dev, const void *data, size_t len) +{ + struct fixedfactorclock_softc * const sc = device_private(dev); + + /* #clock-cells for a fixed factor clock is always 0 */ + if (len != 0) + return NULL; + + return &sc->sc_clk.base; +} + +static struct clk * +fixedfactorclock_get(void *priv, const char *name) +{ + struct fixedfactorclock_softc * const sc = priv; + + if (strcmp(name, sc->sc_clk.base.name) != 0) + return NULL; + + return &sc->sc_clk.base; +} + +static void +fixedfactorclock_put(void *priv, struct clk *clk) +{ +} + +static u_int +fixedfactorclock_get_rate(void *priv, struct clk *clk) +{ + struct fixedfactorclock_softc * const sc = priv; + struct fixedfactorclock_clk *fclk = (struct fixedfactorclock_clk *)clk; + struct clk *clkp_parent; + + clkp_parent = fdtbus_clock_get_index(sc->sc_phandle, 0); + if (clkp_parent == NULL) + return 0; + + return (clk_get_rate(clkp_parent) * fclk->mult) / fclk->div; +} diff --git a/sys/dev/fdt/gpioleds.c b/sys/dev/fdt/gpioleds.c new file mode 100644 index 000000000000..43c67b41ae19 --- /dev/null +++ b/sys/dev/fdt/gpioleds.c @@ -0,0 +1,113 @@ +/* $NetBSD: gpioleds.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: gpioleds.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +static int gpioleds_match(device_t, cfdata_t, void *); +static void gpioleds_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(gpioleds, 0, gpioleds_match, gpioleds_attach, NULL, NULL); + +static int +gpioleds_get(void *priv) +{ + struct fdtbus_gpio_pin *pin = priv; + + return fdtbus_gpio_read(pin); +} + +static void +gpioleds_set(void *priv, int state) +{ + struct fdtbus_gpio_pin *pin = priv; + + fdtbus_gpio_write(pin, state); +} + +static int +gpioleds_match(device_t parent, cfdata_t cf, void *aux) +{ + const char * const compatible[] = { "gpio-leds", NULL }; + const struct fdt_attach_args *faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +gpioleds_attach(device_t parent, device_t self, void *aux) +{ + const struct fdt_attach_args *faa = aux; + const int phandle = faa->faa_phandle; + struct fdtbus_gpio_pin *pin; + const char *default_state; + char label[64]; + int child; + + aprint_naive("\n"); + aprint_normal(":"); + + for (child = OF_child(phandle); child; child = OF_peer(child)) { + /* Get the label, fallback to node name */ + if (OF_getprop(child, "label", label, sizeof(label)) <= 0 && + OF_getprop(child, "name", label, sizeof(label)) <= 0) + continue; + + /* Get the output pin */ + pin = fdtbus_gpio_acquire(child, "gpios", GPIO_PIN_OUTPUT); + if (pin == NULL) + continue; + + /* Attach the LED */ + if (led_attach(label, pin, gpioleds_get, gpioleds_set) == NULL) + continue; + + aprint_normal(" %s", label); + + /* Set default state */ + default_state = fdtbus_get_string(child, "default-state"); + if (default_state && strcmp(default_state, "on") == 0) + gpioleds_set(pin, LED_STATE_ON); + else if (default_state && strcmp(default_state, "off") == 0) + gpioleds_set(pin, LED_STATE_OFF); + } + + aprint_normal("\n"); +} diff --git a/sys/dev/fdt/ohci_fdt.c b/sys/dev/fdt/ohci_fdt.c new file mode 100644 index 000000000000..0daa0e50e0b1 --- /dev/null +++ b/sys/dev/fdt/ohci_fdt.c @@ -0,0 +1,149 @@ +/* $NetBSD: ohci_fdt.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2015-2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: ohci_fdt.c,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +static int ohci_fdt_match(device_t, cfdata_t, void *); +static void ohci_fdt_attach(device_t, device_t, void *); + +CFATTACH_DECL2_NEW(ohci_fdt, sizeof(struct ohci_softc), + ohci_fdt_match, ohci_fdt_attach, NULL, + ohci_activate, NULL, ohci_childdet); + +static int +ohci_fdt_match(device_t parent, cfdata_t cf, void *aux) +{ + const char * const compatible[] = { + "generic-ohci", + NULL + }; + struct fdt_attach_args * const faa = aux; + + return of_match_compatible(faa->faa_phandle, compatible); +} + +static void +ohci_fdt_attach(device_t parent, device_t self, void *aux) +{ + struct ohci_softc * const sc = device_private(self); + struct fdt_attach_args * const faa = aux; + const int phandle = faa->faa_phandle; + struct fdtbus_reset *rst; + struct fdtbus_phy *phy; + struct clk *clk; + char intrstr[128]; + bus_addr_t addr; + bus_size_t size; + int error; + void *ih; + u_int n; + + if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { + aprint_error(": couldn't get registers\n"); + return; + } + + /* Enable clocks */ + for (n = 0; (clk = fdtbus_clock_get_index(phandle, n)) != NULL; n++) + if (clk_enable(clk) != 0) { + aprint_error(": couldn't enable clock #%d\n", n); + return; + } + /* De-assert resets */ + for (n = 0; (rst = fdtbus_reset_get_index(phandle, n)) != NULL; n++) + if (fdtbus_reset_deassert(rst) != 0) { + aprint_error(": couldn't de-assert reset #%d\n", n); + return; + } + + /* Enable optional phy */ + phy = fdtbus_phy_get(phandle, "usb"); + if (phy && fdtbus_phy_enable(phy, true) != 0) { + aprint_error(": couldn't enable phy\n"); + return; + } + + sc->sc_dev = self; + sc->sc_bus.ub_hcpriv = sc; + sc->sc_bus.ub_dmatag = faa->faa_dmat; + sc->sc_flags = 0; + sc->sc_id_vendor = 0; + strlcpy(sc->sc_vendor, "Generic", sizeof(sc->sc_vendor)); + sc->sc_size = size; + sc->iot = faa->faa_bst; + if (bus_space_map(sc->iot, addr, size, 0, &sc->ioh) != 0) { + aprint_error(": couldn't map registers\n"); + return; + } + + aprint_naive("\n"); + aprint_normal(": OHCI\n"); + + /* Disable interrupts */ + bus_space_write_4(sc->iot, sc->ioh, OHCI_INTERRUPT_DISABLE, + OHCI_ALL_INTRS); + + if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { + aprint_error_dev(self, "failed to decode interrupt\n"); + return; + } + + ih = fdtbus_intr_establish(phandle, 0, IPL_USB, FDT_INTR_MPSAFE, + ohci_intr, sc); + if (ih == NULL) { + aprint_error_dev(self, "couldn't establish interrupt on %s\n", + intrstr); + return; + } + aprint_normal_dev(self, "interrupting on %s\n", intrstr); + + error = ohci_init(sc); + if (error) { + aprint_error_dev(self, "init failed, error = %d\n", error); + return; + } + + sc->sc_child = config_found(self, &sc->sc_bus, usbctlprint); +} diff --git a/sys/dev/gpio/gpio.c b/sys/dev/gpio/gpio.c index c2f2c3ad20d1..9fa2834dac92 100644 --- a/sys/dev/gpio/gpio.c +++ b/sys/dev/gpio/gpio.c @@ -1,4 +1,4 @@ -/* $NetBSD: gpio.c,v 1.58 2016/05/11 18:33:40 bouyer Exp $ */ +/* $NetBSD: gpio.c,v 1.58.10.1 2017/07/18 19:13:09 snj Exp $ */ /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */ /* @@ -19,7 +19,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.58 2016/05/11 18:33:40 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.58.10.1 2017/07/18 19:13:09 snj Exp $"); /* * General Purpose Input/Output framework. @@ -202,6 +202,8 @@ gpio_attach(device_t parent, device_t self, void *aux) { struct gpio_softc *sc = device_private(self); struct gpiobus_attach_args *gba = aux; + struct gpio_name *nm; + int pin; sc->sc_dev = self; sc->sc_gc = gba->gba_gc; @@ -211,6 +213,17 @@ gpio_attach(device_t parent, device_t self, void *aux) aprint_normal(": %d pins\n", sc->sc_npins); aprint_naive("\n"); + /* Configure default pin names */ + for (pin = 0; pin < sc->sc_npins; pin++) { + if (sc->sc_pins[pin].pin_defname[0] == '\0') + continue; + nm = kmem_alloc(sizeof(*nm), KM_SLEEP); + strlcpy(nm->gp_name, sc->sc_pins[pin].pin_defname, + sizeof(nm->gp_name)); + nm->gp_pin = pin; + LIST_INSERT_HEAD(&sc->sc_names, nm, gp_next); + } + if (!pmf_device_register(self, NULL, gpio_resume)) aprint_error_dev(self, "couldn't establish power handler\n"); mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM); diff --git a/sys/dev/gpio/gpiovar.h b/sys/dev/gpio/gpiovar.h index 5a97ee4a70b6..6bad39764f3a 100644 --- a/sys/dev/gpio/gpiovar.h +++ b/sys/dev/gpio/gpiovar.h @@ -1,4 +1,4 @@ -/* $NetBSD: gpiovar.h,v 1.16 2016/05/11 18:33:40 bouyer Exp $ */ +/* $NetBSD: gpiovar.h,v 1.16.10.1 2017/07/18 19:13:09 snj Exp $ */ /* $OpenBSD: gpiovar.h,v 1.3 2006/01/14 12:33:49 grange Exp $ */ /* @@ -44,6 +44,7 @@ typedef struct gpio_pin { gpio_chipset_tag_t pin_gc; /* reference the controller */ void (*pin_callback)(void *); /* irq callback */ void * pin_callback_arg; /* callback arg */ + char pin_defname[GPIOMAXNAME]; /* default name */ } gpio_pin_t; /* Attach GPIO framework to the controller */ diff --git a/sys/dev/ic/dwc_mmc.c b/sys/dev/ic/dwc_mmc.c index 0c4b1f236c0d..e22f1b320f91 100644 --- a/sys/dev/ic/dwc_mmc.c +++ b/sys/dev/ic/dwc_mmc.c @@ -1,7 +1,7 @@ -/* $NetBSD: dwc_mmc.c,v 1.10 2015/12/27 18:35:29 jmcneill Exp $ */ +/* $NetBSD: dwc_mmc.c,v 1.10.10.1 2017/07/18 19:13:10 snj Exp $ */ /*- - * Copyright (c) 2014 Jared D. McNeill + * Copyright (c) 2014-2017 Jared McNeill * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,10 +26,8 @@ * SUCH DAMAGE. */ -#include "opt_dwc_mmc.h" - #include -__KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.10 2015/12/27 18:35:29 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.10.10.1 2017/07/18 19:13:10 snj Exp $"); #include #include @@ -45,6 +43,8 @@ __KERNEL_RCSID(0, "$NetBSD: dwc_mmc.c,v 1.10 2015/12/27 18:35:29 jmcneill Exp $" #include #include +#define DWC_MMC_NDESC 64 + static int dwc_mmc_host_reset(sdmmc_chipset_handle_t); static uint32_t dwc_mmc_host_ocr(sdmmc_chipset_handle_t); static int dwc_mmc_host_maxblklen(sdmmc_chipset_handle_t); @@ -55,25 +55,10 @@ static int dwc_mmc_bus_clock(sdmmc_chipset_handle_t, int); static int dwc_mmc_bus_width(sdmmc_chipset_handle_t, int); static int dwc_mmc_bus_rod(sdmmc_chipset_handle_t, int); static void dwc_mmc_exec_command(sdmmc_chipset_handle_t, - struct sdmmc_command *); + struct sdmmc_command *); static void dwc_mmc_card_enable_intr(sdmmc_chipset_handle_t, int); static void dwc_mmc_card_intr_ack(sdmmc_chipset_handle_t); -static int dwc_mmc_set_clock(struct dwc_mmc_softc *, u_int); -static int dwc_mmc_update_clock(struct dwc_mmc_softc *); -static int dwc_mmc_wait_rint(struct dwc_mmc_softc *, uint32_t, int); -static int dwc_mmc_pio_wait(struct dwc_mmc_softc *, - struct sdmmc_command *); -static int dwc_mmc_pio_transfer(struct dwc_mmc_softc *, - struct sdmmc_command *); - -#ifdef DWC_MMC_DEBUG -static void dwc_mmc_print_rint(struct dwc_mmc_softc *, const char *, - uint32_t); -#endif - -void dwc_mmc_dump_regs(int); - static struct sdmmc_chip_functions dwc_mmc_chip_functions = { .host_reset = dwc_mmc_host_reset, .host_ocr = dwc_mmc_host_ocr, @@ -89,24 +74,68 @@ static struct sdmmc_chip_functions dwc_mmc_chip_functions = { .card_intr_ack = dwc_mmc_card_intr_ack, }; -#define MMC_WRITE(sc, reg, val) \ +#define MMC_WRITE(sc, reg, val) \ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) #define MMC_READ(sc, reg) \ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) -void -dwc_mmc_init(struct dwc_mmc_softc *sc) +static void +dwc_mmc_dump_regs(struct dwc_mmc_softc *sc) { + device_printf(sc->sc_dev, "device registers:\n"); + for (u_int off = 0x00; off < 0x100; off += 16) { + device_printf(sc->sc_dev, "xxxxxx%02x: %08x %08x %08x %08x\n", + off, + MMC_READ(sc, off + 0), MMC_READ(sc, off + 4), + MMC_READ(sc, off + 8), MMC_READ(sc, off + 12)); + } +} + +static int +dwc_mmc_idma_setup(struct dwc_mmc_softc *sc) +{ + int error; + + sc->sc_idma_xferlen = 0x1000; + + sc->sc_idma_ndesc = DWC_MMC_NDESC; + sc->sc_idma_size = sizeof(struct dwc_mmc_idma_desc) * + sc->sc_idma_ndesc; + error = bus_dmamem_alloc(sc->sc_dmat, sc->sc_idma_size, 8, + sc->sc_idma_size, sc->sc_idma_segs, 1, + &sc->sc_idma_nsegs, BUS_DMA_WAITOK); + if (error) + return error; + error = bus_dmamem_map(sc->sc_dmat, sc->sc_idma_segs, + sc->sc_idma_nsegs, sc->sc_idma_size, + &sc->sc_idma_desc, BUS_DMA_WAITOK); + if (error) + goto free; + error = bus_dmamap_create(sc->sc_dmat, sc->sc_idma_size, 1, + sc->sc_idma_size, 0, BUS_DMA_WAITOK, &sc->sc_idma_map); + if (error) + goto unmap; + error = bus_dmamap_load(sc->sc_dmat, sc->sc_idma_map, + sc->sc_idma_desc, sc->sc_idma_size, NULL, BUS_DMA_WAITOK); + if (error) + goto destroy; + return 0; + +destroy: + bus_dmamap_destroy(sc->sc_dmat, sc->sc_idma_map); +unmap: + bus_dmamem_unmap(sc->sc_dmat, sc->sc_idma_desc, sc->sc_idma_size); +free: + bus_dmamem_free(sc->sc_dmat, sc->sc_idma_segs, sc->sc_idma_nsegs); + return error; +} + +static void +dwc_mmc_attach_i(device_t self) +{ + struct dwc_mmc_softc *sc = device_private(self); struct sdmmcbus_attach_args saa; - mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO); - cv_init(&sc->sc_intr_cv, "dwcmmcirq"); - -#ifdef DWC_MMC_DEBUG - const uint32_t verid = MMC_READ(sc, DWC_MMC_VERID_REG); - aprint_normal_dev(sc->sc_dev, "version 0x%04x\n", verid & 0xffff); -#endif - dwc_mmc_host_reset(sc); dwc_mmc_bus_width(sc, 1); @@ -115,114 +144,27 @@ dwc_mmc_init(struct dwc_mmc_softc *sc) saa.saa_sct = &dwc_mmc_chip_functions; saa.saa_sch = sc; saa.saa_clkmin = 400; - if (sc->sc_clock_max) { - saa.saa_clkmax = sc->sc_clock_max; - } else { - saa.saa_clkmax = sc->sc_clock_freq / 1000; - } + saa.saa_clkmax = sc->sc_clock_freq / 1000; saa.saa_caps = SMC_CAPS_4BIT_MODE| SMC_CAPS_8BIT_MODE| SMC_CAPS_SD_HIGHSPEED| SMC_CAPS_MMC_HIGHSPEED| SMC_CAPS_AUTO_STOP; - -#if notyet - saa.saa_dmat = sc->sc_dmat; - saa.saa_caps |= SMC_CAPS_DMA| - SMC_CAPS_MULTI_SEG_DMA; -#endif - - sc->sc_sdmmc_dev = config_found(sc->sc_dev, &saa, NULL); -} - -int -dwc_mmc_intr(void *priv) -{ - struct dwc_mmc_softc *sc = priv; - uint32_t mint, rint; - - mutex_enter(&sc->sc_intr_lock); - rint = MMC_READ(sc, DWC_MMC_RINTSTS_REG); - mint = MMC_READ(sc, DWC_MMC_MINTSTS_REG); - if (!rint && !mint) { - mutex_exit(&sc->sc_intr_lock); - return 0; + if (ISSET(sc->sc_flags, DWC_MMC_F_DMA)) { + saa.saa_dmat = sc->sc_dmat; + saa.saa_caps |= SMC_CAPS_DMA | + SMC_CAPS_MULTI_SEG_DMA; } - MMC_WRITE(sc, DWC_MMC_RINTSTS_REG, rint); - MMC_WRITE(sc, DWC_MMC_MINTSTS_REG, mint); + if (sc->sc_card_detect) + saa.saa_caps |= SMC_CAPS_POLL_CARD_DET; -#ifdef DWC_MMC_DEBUG - dwc_mmc_print_rint(sc, "irq", rint); -#endif - - if (rint & DWC_MMC_INT_CARDDET) { - rint &= ~DWC_MMC_INT_CARDDET; - if (sc->sc_sdmmc_dev) { - sdmmc_needs_discover(sc->sc_sdmmc_dev); - } - } - - if (rint) { - sc->sc_intr_rint |= rint; - cv_broadcast(&sc->sc_intr_cv); - } - - mutex_exit(&sc->sc_intr_lock); - - return 1; -} - -static int -dwc_mmc_set_clock(struct dwc_mmc_softc *sc, u_int freq) -{ - const u_int pll_freq = sc->sc_clock_freq / 1000; - const u_int clk_div = howmany(pll_freq, freq * 2); - -#ifdef DWC_MMC_DEBUG - printf("%s: using clk_div %d for freq %d (act %u)\n", - __func__, clk_div, freq, pll_freq / (clk_div * 2)); -#endif - - MMC_WRITE(sc, DWC_MMC_CLKDIV_REG, - __SHIFTIN(clk_div, DWC_MMC_CLKDIV_CLK_DIVIDER0)); - MMC_WRITE(sc, DWC_MMC_CLKSRC_REG, 0); /* clock divider 0 */ - - return dwc_mmc_update_clock(sc); -} - -static int -dwc_mmc_update_clock(struct dwc_mmc_softc *sc) -{ - uint32_t cmd; - int retry; - - cmd = DWC_MMC_CMD_START_CMD | - DWC_MMC_CMD_UPDATE_CLOCK_REGS_ONLY | - DWC_MMC_CMD_WAIT_PRVDATA_COMPLETE; - - if (sc->sc_flags & DWC_MMC_F_USE_HOLD_REG) - cmd |= DWC_MMC_CMD_USE_HOLD_REG; - - MMC_WRITE(sc, DWC_MMC_CMD_REG, cmd); - retry = 0xfffff; - while (--retry > 0) { - cmd = MMC_READ(sc, DWC_MMC_CMD_REG); - if ((cmd & DWC_MMC_CMD_START_CMD) == 0) - break; - delay(10); - } - - if (retry == 0) { - device_printf(sc->sc_dev, "timeout updating clock\n"); - return ETIMEDOUT; - } - - return 0; + sc->sc_sdmmc_dev = config_found(self, &saa, NULL); } static int dwc_mmc_wait_rint(struct dwc_mmc_softc *sc, uint32_t mask, int timeout) { + const bool use_dma = ISSET(sc->sc_flags, DWC_MMC_F_DMA); int retry, error; KASSERT(mutex_owned(&sc->sc_intr_lock)); @@ -233,17 +175,254 @@ dwc_mmc_wait_rint(struct dwc_mmc_softc *sc, uint32_t mask, int timeout) retry = timeout / hz; while (retry > 0) { - error = cv_timedwait(&sc->sc_intr_cv, &sc->sc_intr_lock, hz); - if (error && error != EWOULDBLOCK) - return error; - if (sc->sc_intr_rint & mask) - return 0; + if (use_dma) { + error = cv_timedwait(&sc->sc_intr_cv, + &sc->sc_intr_lock, hz); + if (error && error != EWOULDBLOCK) + return error; + if (sc->sc_intr_rint & mask) + return 0; + } else { + sc->sc_intr_rint |= MMC_READ(sc, DWC_MMC_RINT); + if (sc->sc_intr_rint & mask) + return 0; + delay(1000); + } --retry; } return ETIMEDOUT; } +static void +dwc_mmc_led(struct dwc_mmc_softc *sc, int on) +{ + if (sc->sc_set_led) + sc->sc_set_led(sc, on); +} + +static int +dwc_mmc_host_reset(sdmmc_chipset_handle_t sch) +{ + struct dwc_mmc_softc *sc = sch; + uint32_t fifoth, ctrl; + int retry = 1000; + +#ifdef DWC_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, "host reset\n"); +#endif + + MMC_WRITE(sc, DWC_MMC_PWREN, 1); + + MMC_WRITE(sc, DWC_MMC_GCTRL, + MMC_READ(sc, DWC_MMC_GCTRL) | DWC_MMC_GCTRL_RESET); + while (--retry > 0) { + if (!(MMC_READ(sc, DWC_MMC_GCTRL) & DWC_MMC_GCTRL_RESET)) + break; + delay(100); + } + + MMC_WRITE(sc, DWC_MMC_CLKSRC, 0); + + MMC_WRITE(sc, DWC_MMC_TIMEOUT, 0xffffffff); + + MMC_WRITE(sc, DWC_MMC_IMASK, + DWC_MMC_INT_CMD_DONE | DWC_MMC_INT_ERROR | + DWC_MMC_INT_DATA_OVER | DWC_MMC_INT_AUTO_CMD_DONE); + + const uint32_t rx_wmark = (sc->sc_fifo_depth / 2) - 1; + const uint32_t tx_wmark = sc->sc_fifo_depth / 2; + fifoth = __SHIFTIN(DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_16, + DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE); + fifoth |= __SHIFTIN(rx_wmark, DWC_MMC_FIFOTH_RX_WMARK); + fifoth |= __SHIFTIN(tx_wmark, DWC_MMC_FIFOTH_TX_WMARK); + MMC_WRITE(sc, DWC_MMC_FIFOTH, fifoth); + + MMC_WRITE(sc, DWC_MMC_UHS, 0); + + ctrl = MMC_READ(sc, DWC_MMC_GCTRL); + ctrl |= DWC_MMC_GCTRL_INTEN; + ctrl |= DWC_MMC_GCTRL_DMAEN; + ctrl |= DWC_MMC_GCTRL_SEND_AUTO_STOP_CCSD; + ctrl |= DWC_MMC_GCTRL_USE_INTERNAL_DMAC; + MMC_WRITE(sc, DWC_MMC_GCTRL, ctrl); + + return 0; +} + +static uint32_t +dwc_mmc_host_ocr(sdmmc_chipset_handle_t sch) +{ + return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V | MMC_OCR_HCS; +} + +static int +dwc_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) +{ + return 32768; +} + +static int +dwc_mmc_card_detect(sdmmc_chipset_handle_t sch) +{ + struct dwc_mmc_softc *sc = sch; + int v = 0, i; + + if (!sc->sc_card_detect) + return 1; /* no card detect pin, assume present */ + + for (i = 0; i < 5; i++) { + v += sc->sc_card_detect(sc); + delay(1000); + } + if (v == 5) + sc->sc_mmc_present = 0; + else if (v == 0) + sc->sc_mmc_present = 1; + return sc->sc_mmc_present; +} + +static int +dwc_mmc_write_protect(sdmmc_chipset_handle_t sch) +{ + struct dwc_mmc_softc *sc = sch; + + if (!sc->sc_write_protect) + return 0; /* no write protect pin, assume rw */ + + return sc->sc_write_protect(sc); +} + +static int +dwc_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) +{ + return 0; +} + +static int +dwc_mmc_update_clock(struct dwc_mmc_softc *sc) +{ + uint32_t cmd; + int retry; + +#ifdef DWC_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, "update clock\n"); +#endif + + cmd = DWC_MMC_CMD_START | + DWC_MMC_CMD_UPCLK_ONLY | + DWC_MMC_CMD_WAIT_PRE_OVER; + if (ISSET(sc->sc_flags, DWC_MMC_F_USE_HOLD_REG)) + cmd |= DWC_MMC_CMD_USE_HOLD_REG; + MMC_WRITE(sc, DWC_MMC_ARG, 0); + MMC_WRITE(sc, DWC_MMC_CMD, cmd); + retry = 0xfffff; + while (--retry > 0) { + if (!(MMC_READ(sc, DWC_MMC_CMD) & DWC_MMC_CMD_START)) + break; + delay(10); + } + + if (retry == 0) { + aprint_error_dev(sc->sc_dev, "timeout updating clock\n"); +#ifdef DWC_MMC_DEBUG + device_printf(sc->sc_dev, "GCTRL: 0x%08x\n", + MMC_READ(sc, DWC_MMC_GCTRL)); + device_printf(sc->sc_dev, "CLKENA: 0x%08x\n", + MMC_READ(sc, DWC_MMC_CLKENA)); + device_printf(sc->sc_dev, "CLKDIV: 0x%08x\n", + MMC_READ(sc, DWC_MMC_CLKDIV)); + device_printf(sc->sc_dev, "TIMEOUT: 0x%08x\n", + MMC_READ(sc, DWC_MMC_TIMEOUT)); + device_printf(sc->sc_dev, "WIDTH: 0x%08x\n", + MMC_READ(sc, DWC_MMC_WIDTH)); + device_printf(sc->sc_dev, "CMD: 0x%08x\n", + MMC_READ(sc, DWC_MMC_CMD)); + device_printf(sc->sc_dev, "MINT: 0x%08x\n", + MMC_READ(sc, DWC_MMC_MINT)); + device_printf(sc->sc_dev, "RINT: 0x%08x\n", + MMC_READ(sc, DWC_MMC_RINT)); + device_printf(sc->sc_dev, "STATUS: 0x%08x\n", + MMC_READ(sc, DWC_MMC_STATUS)); +#endif + return ETIMEDOUT; + } + + return 0; +} + +static int +dwc_mmc_set_clock(struct dwc_mmc_softc *sc, u_int freq) +{ + const u_int pll_freq = sc->sc_clock_freq / 1000; + const u_int clk_div = howmany(pll_freq, freq * 2); + + MMC_WRITE(sc, DWC_MMC_CLKDIV, clk_div); + + return dwc_mmc_update_clock(sc); +} + +static int +dwc_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +{ + struct dwc_mmc_softc *sc = sch; + uint32_t clkena; + + MMC_WRITE(sc, DWC_MMC_CLKSRC, 0); + MMC_WRITE(sc, DWC_MMC_CLKENA, 0); + if (dwc_mmc_update_clock(sc) != 0) + return 1; + + if (freq) { + if (dwc_mmc_set_clock(sc, freq) != 0) + return 1; + + clkena = DWC_MMC_CLKENA_CARDCLKON; + MMC_WRITE(sc, DWC_MMC_CLKENA, clkena); + if (dwc_mmc_update_clock(sc) != 0) + return 1; + } + + delay(1000); + + return 0; +} + +static int +dwc_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) +{ + struct dwc_mmc_softc *sc = sch; + +#ifdef DWC_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, "width = %d\n", width); +#endif + + switch (width) { + case 1: + MMC_WRITE(sc, DWC_MMC_WIDTH, DWC_MMC_WIDTH_1); + break; + case 4: + MMC_WRITE(sc, DWC_MMC_WIDTH, DWC_MMC_WIDTH_4); + break; + case 8: + MMC_WRITE(sc, DWC_MMC_WIDTH, DWC_MMC_WIDTH_8); + break; + default: + return 1; + } + + sc->sc_mmc_width = width; + + return 0; +} + +static int +dwc_mmc_bus_rod(sdmmc_chipset_handle_t sch, int on) +{ + return -1; +} + + static int dwc_mmc_pio_wait(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd) { @@ -252,16 +431,12 @@ dwc_mmc_pio_wait(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd) DWC_MMC_STATUS_FIFO_EMPTY : DWC_MMC_STATUS_FIFO_FULL; while (--retry > 0) { - uint32_t status = MMC_READ(sc, DWC_MMC_STATUS_REG); + uint32_t status = MMC_READ(sc, DWC_MMC_STATUS); if (!(status & bit)) return 0; delay(10); } -#ifdef DWC_MMC_DEBUG - device_printf(sc->sc_dev, "%s: timed out\n", __func__); -#endif - return ETIMEDOUT; } @@ -275,210 +450,148 @@ dwc_mmc_pio_transfer(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd) if (dwc_mmc_pio_wait(sc, cmd)) return ETIMEDOUT; if (cmd->c_flags & SCF_CMD_READ) { - datap[i] = MMC_READ(sc, DWC_MMC_FIFO_BASE_REG); + datap[i] = MMC_READ(sc, sc->sc_fifo_reg); } else { - MMC_WRITE(sc, DWC_MMC_FIFO_BASE_REG, datap[i]); + MMC_WRITE(sc, sc->sc_fifo_reg, datap[i]); } } return 0; } - + static int -dwc_mmc_host_reset(sdmmc_chipset_handle_t sch) +dwc_mmc_dma_prepare(struct dwc_mmc_softc *sc, struct sdmmc_command *cmd) { - struct dwc_mmc_softc *sc = sch; - int retry = 1000; - uint32_t ctrl, fifoth; - uint32_t rx_wmark, tx_wmark; + struct dwc_mmc_idma_desc *dma = sc->sc_idma_desc; + bus_addr_t desc_paddr = sc->sc_idma_map->dm_segs[0].ds_addr; + bus_size_t off; + int desc, resid, seg; + uint32_t val; - if (sc->sc_flags & DWC_MMC_F_PWREN_CLEAR) { - MMC_WRITE(sc, DWC_MMC_PWREN_REG, 0); - } else { - MMC_WRITE(sc, DWC_MMC_PWREN_REG, DWC_MMC_PWREN_POWER_ENABLE); + desc = 0; + for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) { + bus_addr_t paddr = cmd->c_dmamap->dm_segs[seg].ds_addr; + bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len; + resid = min(len, cmd->c_resid); + off = 0; + while (resid > 0) { + if (desc == sc->sc_idma_ndesc) + break; + len = min(sc->sc_idma_xferlen, resid); + dma[desc].dma_buf_size = htole32(len); + dma[desc].dma_buf_addr = htole32(paddr + off); + dma[desc].dma_config = htole32( + DWC_MMC_IDMA_CONFIG_OWN); + cmd->c_resid -= len; + resid -= len; + off += len; + dma[desc].dma_next = htole32( + desc_paddr + ((desc+1) * + sizeof(struct dwc_mmc_idma_desc))); + if (desc == 0) { + dma[desc].dma_config |= htole32( + DWC_MMC_IDMA_CONFIG_FD); + } + if (cmd->c_resid == 0) { + dma[desc].dma_config |= htole32( + DWC_MMC_IDMA_CONFIG_LD); + } else { + dma[desc].dma_config |= + htole32(DWC_MMC_IDMA_CONFIG_CH| + DWC_MMC_IDMA_CONFIG_DIC); + } + ++desc; + } + } + if (desc == sc->sc_idma_ndesc) { + aprint_error_dev(sc->sc_dev, + "not enough descriptors for %d byte transfer!\n", + cmd->c_datalen); + return EIO; } - MMC_WRITE(sc, DWC_MMC_CTRL_REG, DWC_MMC_CTRL_RESET_ALL); - while (--retry > 0) { - ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); - if ((ctrl & DWC_MMC_CTRL_RESET_ALL) == 0) - break; - delay(100); - } + bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0, + sc->sc_idma_size, BUS_DMASYNC_PREWRITE); - MMC_WRITE(sc, DWC_MMC_CLKSRC_REG, 0); + sc->sc_idma_idst = 0; - MMC_WRITE(sc, DWC_MMC_TMOUT_REG, 0xffffff40); - MMC_WRITE(sc, DWC_MMC_RINTSTS_REG, 0xffffffff); - - MMC_WRITE(sc, DWC_MMC_INTMASK_REG, - DWC_MMC_INT_CD | DWC_MMC_INT_ACD | DWC_MMC_INT_DTO | - DWC_MMC_INT_ERROR | DWC_MMC_INT_CARDDET | - DWC_MMC_INT_RXDR | DWC_MMC_INT_TXDR); - - rx_wmark = (sc->sc_fifo_depth / 2) - 1; - tx_wmark = sc->sc_fifo_depth / 2; - fifoth = __SHIFTIN(DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_16, - DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE); - fifoth |= __SHIFTIN(rx_wmark, DWC_MMC_FIFOTH_RX_WMARK); - fifoth |= __SHIFTIN(tx_wmark, DWC_MMC_FIFOTH_TX_WMARK); - MMC_WRITE(sc, DWC_MMC_FIFOTH_REG, fifoth); - - ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); - ctrl |= DWC_MMC_CTRL_INT_ENABLE; - MMC_WRITE(sc, DWC_MMC_CTRL_REG, ctrl); + val = MMC_READ(sc, DWC_MMC_GCTRL); + val |= DWC_MMC_GCTRL_DMAEN; + val |= DWC_MMC_GCTRL_INTEN; + MMC_WRITE(sc, DWC_MMC_GCTRL, val); + val |= DWC_MMC_GCTRL_DMARESET; + MMC_WRITE(sc, DWC_MMC_GCTRL, val); + MMC_WRITE(sc, DWC_MMC_DMAC, DWC_MMC_DMAC_SOFTRESET); + MMC_WRITE(sc, DWC_MMC_DMAC, + DWC_MMC_DMAC_IDMA_ON|DWC_MMC_DMAC_FIX_BURST); + val = MMC_READ(sc, DWC_MMC_IDIE); + val &= ~(DWC_MMC_IDST_RECEIVE_INT|DWC_MMC_IDST_TRANSMIT_INT); + if (cmd->c_flags & SCF_CMD_READ) + val |= DWC_MMC_IDST_RECEIVE_INT; + else + val |= DWC_MMC_IDST_TRANSMIT_INT; + MMC_WRITE(sc, DWC_MMC_IDIE, val); + MMC_WRITE(sc, DWC_MMC_DLBA, desc_paddr); return 0; } -static uint32_t -dwc_mmc_host_ocr(sdmmc_chipset_handle_t sch) +static void +dwc_mmc_dma_complete(struct dwc_mmc_softc *sc) { - return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; -} - -static int -dwc_mmc_host_maxblklen(sdmmc_chipset_handle_t sch) -{ - return 32768; -} - -static int -dwc_mmc_card_detect(sdmmc_chipset_handle_t sch) -{ - struct dwc_mmc_softc *sc = sch; - uint32_t cdetect; - - if (sc->sc_flags & DWC_MMC_F_BROKEN_CD) { - return 1; - } else if (sc->sc_card_detect) { - return sc->sc_card_detect(sc); - } else { - cdetect = MMC_READ(sc, DWC_MMC_CDETECT_REG); - return !(cdetect & DWC_MMC_CDETECT_CARD_DETECT_N); - } -} - -static int -dwc_mmc_write_protect(sdmmc_chipset_handle_t sch) -{ - struct dwc_mmc_softc *sc = sch; - uint32_t wrtprt; - - wrtprt = MMC_READ(sc, DWC_MMC_WRTPRT_REG); - return !!(wrtprt & DWC_MMC_WRTPRT_WRITE_PROTECT); -} - -static int -dwc_mmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) -{ - return 0; -} - -static int -dwc_mmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) -{ - struct dwc_mmc_softc *sc = sch; - uint32_t clkena; - -#ifdef DWC_MMC_DEBUG - device_printf(sc->sc_dev, "%s: freq %d\n", __func__, freq); -#endif - - MMC_WRITE(sc, DWC_MMC_CLKENA_REG, 0); - if (dwc_mmc_update_clock(sc) != 0) - return ETIMEDOUT; - - if (freq) { - if (dwc_mmc_set_clock(sc, freq) != 0) - return EIO; - - clkena = DWC_MMC_CLKENA_CCLK_ENABLE; - clkena |= DWC_MMC_CLKENA_CCLK_LOW_POWER; /* XXX SD/MMC only */ - MMC_WRITE(sc, DWC_MMC_CLKENA_REG, clkena); - if (dwc_mmc_update_clock(sc) != 0) - return ETIMEDOUT; - } - - delay(1000); - - sc->sc_cur_freq = freq; - - return 0; -} - -static int -dwc_mmc_bus_width(sdmmc_chipset_handle_t sch, int width) -{ - struct dwc_mmc_softc *sc = sch; - uint32_t ctype; - - switch (width) { - case 1: - ctype = DWC_MMC_CTYPE_CARD_WIDTH_1; - break; - case 4: - ctype = DWC_MMC_CTYPE_CARD_WIDTH_4; - break; - case 8: - ctype = DWC_MMC_CTYPE_CARD_WIDTH_8; - break; - default: - return EINVAL; - } - - MMC_WRITE(sc, DWC_MMC_CTYPE_REG, ctype); - - return 0; -} - -static int -dwc_mmc_bus_rod(sdmmc_chipset_handle_t sch, int on) -{ - return ENOTSUP; + bus_dmamap_sync(sc->sc_dmat, sc->sc_idma_map, 0, + sc->sc_idma_size, BUS_DMASYNC_POSTWRITE); } static void dwc_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) { struct dwc_mmc_softc *sc = sch; - uint32_t cmdval = DWC_MMC_CMD_START_CMD; - uint32_t ctrl; + uint32_t cmdval = DWC_MMC_CMD_START; + int retry = 0xfffff; #ifdef DWC_MMC_DEBUG - device_printf(sc->sc_dev, "exec opcode=%d flags=%#x\n", - cmd->c_opcode, cmd->c_flags); + aprint_normal_dev(sc->sc_dev, + "opcode %d flags 0x%x data %p datalen %d blklen %d\n", + cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen, + cmd->c_blklen); #endif - if (sc->sc_flags & DWC_MMC_F_FORCE_CLK) { - cmd->c_error = dwc_mmc_bus_clock(sc, sc->sc_cur_freq); - if (cmd->c_error) - return; - } - - if (sc->sc_flags & DWC_MMC_F_USE_HOLD_REG) - cmdval |= DWC_MMC_CMD_USE_HOLD_REG; - mutex_enter(&sc->sc_intr_lock); - MMC_WRITE(sc, DWC_MMC_RINTSTS_REG, 0xffffffff); + do { + const uint32_t status = MMC_READ(sc, DWC_MMC_STATUS); + if ((status & DWC_MMC_STATUS_CARD_DATA_BUSY) == 0) + break; + delay(10); + } while (--retry > 0); + if (retry == 0) { + aprint_error_dev(sc->sc_dev, "timeout waiting for data busy\n"); + cmd->c_error = ETIMEDOUT; + goto done; + } + + MMC_WRITE(sc, DWC_MMC_IDST, 0xffffffff); + MMC_WRITE(sc, DWC_MMC_RINT, 0xffffffff); + + if (ISSET(sc->sc_flags, DWC_MMC_F_USE_HOLD_REG)) + cmdval |= DWC_MMC_CMD_USE_HOLD_REG; if (cmd->c_opcode == 0) - cmdval |= DWC_MMC_CMD_SEND_INIT; + cmdval |= DWC_MMC_CMD_SEND_INIT_SEQ; if (cmd->c_flags & SCF_RSP_PRESENT) - cmdval |= DWC_MMC_CMD_RESP_EXPECTED; + cmdval |= DWC_MMC_CMD_RSP_EXP; if (cmd->c_flags & SCF_RSP_136) - cmdval |= DWC_MMC_CMD_RESP_LEN; + cmdval |= DWC_MMC_CMD_LONG_RSP; if (cmd->c_flags & SCF_RSP_CRC) - cmdval |= DWC_MMC_CMD_CHECK_RESP_CRC; + cmdval |= DWC_MMC_CMD_CHECK_RSP_CRC; if (cmd->c_datalen > 0) { unsigned int nblks; - cmdval |= DWC_MMC_CMD_DATA_EXPECTED; - cmdval |= DWC_MMC_CMD_WAIT_PRVDATA_COMPLETE; + cmdval |= DWC_MMC_CMD_DATA_EXP | DWC_MMC_CMD_WAIT_PRE_OVER; if (!ISSET(cmd->c_flags, SCF_CMD_READ)) { - cmdval |= DWC_MMC_CMD_WR; + cmdval |= DWC_MMC_CMD_WRITE; } nblks = cmd->c_datalen / cmd->c_blklen; @@ -489,60 +602,107 @@ dwc_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) cmdval |= DWC_MMC_CMD_SEND_AUTO_STOP; } - MMC_WRITE(sc, DWC_MMC_BLKSIZ_REG, cmd->c_blklen); - MMC_WRITE(sc, DWC_MMC_BYTCNT_REG, nblks * cmd->c_blklen); + MMC_WRITE(sc, DWC_MMC_BLKSZ, cmd->c_blklen); + MMC_WRITE(sc, DWC_MMC_BYTECNT, nblks * cmd->c_blklen); } sc->sc_intr_rint = 0; - MMC_WRITE(sc, DWC_MMC_CMDARG_REG, cmd->c_arg); + MMC_WRITE(sc, DWC_MMC_ARG, cmd->c_arg); - cmd->c_resid = cmd->c_datalen; - MMC_WRITE(sc, DWC_MMC_CMD_REG, cmdval | cmd->c_opcode); +#ifdef DWC_MMC_DEBUG + aprint_normal_dev(sc->sc_dev, "cmdval = %08x\n", cmdval); +#endif + + if (cmd->c_datalen > 0) { + cmd->c_resid = cmd->c_datalen; + dwc_mmc_led(sc, 0); + if (ISSET(sc->sc_flags, DWC_MMC_F_DMA)) { + cmd->c_error = dwc_mmc_dma_prepare(sc, cmd); + MMC_WRITE(sc, DWC_MMC_CMD, cmdval | cmd->c_opcode); + MMC_WRITE(sc, DWC_MMC_PLDMND, 1); + if (cmd->c_error == 0) { + const uint32_t idst_mask = + DWC_MMC_IDST_ERROR | DWC_MMC_IDST_COMPLETE; + retry = 10; + while ((sc->sc_idma_idst & idst_mask) == 0) { + if (retry == 0) { + cmd->c_error = ETIMEDOUT; + break; + } + cv_timedwait(&sc->sc_idst_cv, + &sc->sc_intr_lock, hz); + } + } + dwc_mmc_dma_complete(sc); + if (sc->sc_idma_idst & DWC_MMC_IDST_ERROR) { + cmd->c_error = EIO; + } else if (!(sc->sc_idma_idst & DWC_MMC_IDST_COMPLETE)) { + cmd->c_error = ETIMEDOUT; + } + } else { + mutex_exit(&sc->sc_intr_lock); + MMC_WRITE(sc, DWC_MMC_CMD, cmdval | cmd->c_opcode); + cmd->c_error = dwc_mmc_pio_transfer(sc, cmd); + mutex_enter(&sc->sc_intr_lock); + } + dwc_mmc_led(sc, 1); + if (cmd->c_error) { +#ifdef DWC_MMC_DEBUG + aprint_error_dev(sc->sc_dev, + "xfer failed, error %d\n", cmd->c_error); +#endif + goto done; + } + } else { + MMC_WRITE(sc, DWC_MMC_CMD, cmdval | cmd->c_opcode); + } cmd->c_error = dwc_mmc_wait_rint(sc, - DWC_MMC_INT_ERROR|DWC_MMC_INT_CD, hz * 5); + DWC_MMC_INT_ERROR|DWC_MMC_INT_CMD_DONE, hz * 10); if (cmd->c_error == 0 && (sc->sc_intr_rint & DWC_MMC_INT_ERROR)) { -#ifdef DWC_MMC_DEBUG - dwc_mmc_print_rint(sc, "exec1", sc->sc_intr_rint); -#endif - if (sc->sc_intr_rint & DWC_MMC_INT_RTO) { + if (sc->sc_intr_rint & DWC_MMC_INT_RESP_TIMEOUT) { cmd->c_error = ETIMEDOUT; } else { cmd->c_error = EIO; } } if (cmd->c_error) { +#ifdef DWC_MMC_DEBUG + aprint_error_dev(sc->sc_dev, + "cmd failed, error %d\n", cmd->c_error); +#endif goto done; } if (cmd->c_datalen > 0) { - cmd->c_error = dwc_mmc_pio_transfer(sc, cmd); - if (cmd->c_error) { - goto done; - } - cmd->c_error = dwc_mmc_wait_rint(sc, - DWC_MMC_INT_ERROR|DWC_MMC_INT_ACD|DWC_MMC_INT_DTO, - hz * 5); + DWC_MMC_INT_ERROR| + DWC_MMC_INT_AUTO_CMD_DONE| + DWC_MMC_INT_DATA_OVER, + hz*10); if (cmd->c_error == 0 && (sc->sc_intr_rint & DWC_MMC_INT_ERROR)) { -#ifdef DWC_MMC_DEBUG - dwc_mmc_print_rint(sc, "exec2", sc->sc_intr_rint); -#endif cmd->c_error = ETIMEDOUT; } if (cmd->c_error) { +#ifdef DWC_MMC_DEBUG + aprint_error_dev(sc->sc_dev, + "data timeout, rint = %08x\n", + sc->sc_intr_rint); +#endif + dwc_mmc_dump_regs(sc); + cmd->c_error = ETIMEDOUT; goto done; } } if (cmd->c_flags & SCF_RSP_PRESENT) { if (cmd->c_flags & SCF_RSP_136) { - cmd->c_resp[0] = MMC_READ(sc, DWC_MMC_RESP0_REG); - cmd->c_resp[1] = MMC_READ(sc, DWC_MMC_RESP1_REG); - cmd->c_resp[2] = MMC_READ(sc, DWC_MMC_RESP2_REG); - cmd->c_resp[3] = MMC_READ(sc, DWC_MMC_RESP3_REG); + cmd->c_resp[0] = MMC_READ(sc, DWC_MMC_RESP0); + cmd->c_resp[1] = MMC_READ(sc, DWC_MMC_RESP1); + cmd->c_resp[2] = MMC_READ(sc, DWC_MMC_RESP2); + cmd->c_resp[3] = MMC_READ(sc, DWC_MMC_RESP3); if (cmd->c_flags & SCF_RSP_CRC) { cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | (cmd->c_resp[1] << 24); @@ -553,7 +713,7 @@ dwc_mmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) cmd->c_resp[3] = (cmd->c_resp[3] >> 8); } } else { - cmd->c_resp[0] = MMC_READ(sc, DWC_MMC_RESP0_REG); + cmd->c_resp[0] = MMC_READ(sc, DWC_MMC_RESP0); } } @@ -561,14 +721,25 @@ done: cmd->c_flags |= SCF_ITSDONE; mutex_exit(&sc->sc_intr_lock); - if (cmd->c_error == ETIMEDOUT && !ISSET(cmd->c_flags, SCF_TOUT_OK)) { - device_printf(sc->sc_dev, "Device timeout!\n"); - dwc_mmc_dump_regs(device_unit(sc->sc_dev)); + if (cmd->c_error) { +#ifdef DWC_MMC_DEBUG + aprint_error_dev(sc->sc_dev, "i/o error %d\n", cmd->c_error); +#endif + MMC_WRITE(sc, DWC_MMC_GCTRL, + MMC_READ(sc, DWC_MMC_GCTRL) | + DWC_MMC_GCTRL_DMARESET | DWC_MMC_GCTRL_FIFORESET); + for (retry = 0; retry < 1000; retry++) { + if (!(MMC_READ(sc, DWC_MMC_GCTRL) & DWC_MMC_GCTRL_RESET)) + break; + delay(10); + } + dwc_mmc_update_clock(sc); } - ctrl = MMC_READ(sc, DWC_MMC_CTRL_REG); - ctrl |= DWC_MMC_CTRL_FIFO_RESET; - MMC_WRITE(sc, DWC_MMC_CTRL_REG, ctrl); + if (!ISSET(sc->sc_flags, DWC_MMC_F_DMA)) { + MMC_WRITE(sc, DWC_MMC_GCTRL, + MMC_READ(sc, DWC_MMC_GCTRL) | DWC_MMC_GCTRL_FIFORESET); + } } static void @@ -581,51 +752,62 @@ dwc_mmc_card_intr_ack(sdmmc_chipset_handle_t sch) { } -#ifdef DWC_MMC_DEBUG -static void -dwc_mmc_print_rint(struct dwc_mmc_softc *sc, const char *tag, uint32_t rint) +int +dwc_mmc_init(struct dwc_mmc_softc *sc) { - char buf[128]; - snprintb(buf, sizeof(buf), DWC_MMC_INT_BITS, rint); - device_printf(sc->sc_dev, "[%s] rint %s\n", tag, buf); + mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_BIO); + cv_init(&sc->sc_intr_cv, "dwcmmcirq"); + cv_init(&sc->sc_idst_cv, "dwcmmcdma"); + + const bool use_dma = ISSET(sc->sc_flags, DWC_MMC_F_DMA); + + aprint_debug_dev(sc->sc_dev, "using %s for transfers\n", + use_dma ? "DMA" : "PIO"); + + if (use_dma && dwc_mmc_idma_setup(sc) != 0) { + aprint_error_dev(sc->sc_dev, "failed to setup DMA\n"); + return ENOMEM; + } + + config_interrupts(sc->sc_dev, dwc_mmc_attach_i); + + return 0; } + +int +dwc_mmc_intr(void *priv) +{ + struct dwc_mmc_softc *sc = priv; + uint32_t idst, rint, mint; + + mutex_enter(&sc->sc_intr_lock); + idst = MMC_READ(sc, DWC_MMC_IDST); + rint = MMC_READ(sc, DWC_MMC_RINT); + mint = MMC_READ(sc, DWC_MMC_MINT); + if (!idst && !rint && !mint) { + mutex_exit(&sc->sc_intr_lock); + return 0; + } + MMC_WRITE(sc, DWC_MMC_IDST, idst); + MMC_WRITE(sc, DWC_MMC_RINT, rint); + MMC_WRITE(sc, DWC_MMC_MINT, mint); + +#ifdef DWC_MMC_DEBUG + device_printf(sc->sc_dev, "mmc intr idst=%08X rint=%08X mint=%08X\n", + idst, rint, mint); #endif -void -dwc_mmc_dump_regs(int unit) -{ - static const struct { - const char *name; - unsigned int reg; - } regs[] = { - { "CTRL", DWC_MMC_CTRL_REG }, - { "PWREN", DWC_MMC_PWREN_REG }, - { "CLKDIV", DWC_MMC_CLKDIV_REG }, - { "CLKENA", DWC_MMC_CLKENA_REG }, - { "TMOUT", DWC_MMC_TMOUT_REG }, - { "CTYPE", DWC_MMC_CTYPE_REG }, - { "BLKSIZ", DWC_MMC_BLKSIZ_REG }, - { "BYTCNT", DWC_MMC_BYTCNT_REG }, - { "INTMASK", DWC_MMC_INTMASK_REG }, - { "MINTSTS", DWC_MMC_MINTSTS_REG }, - { "RINTSTS", DWC_MMC_RINTSTS_REG }, - { "STATUS", DWC_MMC_STATUS_REG }, - { "CDETECT", DWC_MMC_CDETECT_REG }, - { "WRTPRT", DWC_MMC_WRTPRT_REG }, - { "USRID", DWC_MMC_USRID_REG }, - { "VERID", DWC_MMC_VERID_REG }, - { "RST", DWC_MMC_RST_REG }, - { "BACK_END_POWER", DWC_MMC_BACK_END_POWER_REG }, - }; - device_t self = device_find_by_driver_unit("dwcmmc", unit); - if (self == NULL) - return; - struct dwc_mmc_softc *sc = device_private(self); - int i; - - for (i = 0; i < __arraycount(regs); i += 2) { - device_printf(sc->sc_dev, " %s: 0x%08x\t%s: 0x%08x\n", - regs[i+0].name, MMC_READ(sc, regs[i+0].reg), - regs[i+1].name, MMC_READ(sc, regs[i+1].reg)); + if (idst) { + sc->sc_idma_idst |= idst; + cv_broadcast(&sc->sc_idst_cv); } + + if (rint) { + sc->sc_intr_rint |= rint; + cv_broadcast(&sc->sc_intr_cv); + } + + mutex_exit(&sc->sc_intr_lock); + + return 1; } diff --git a/sys/dev/ic/dwc_mmc_reg.h b/sys/dev/ic/dwc_mmc_reg.h index 3d226ff94fd2..ef78b77346b1 100644 --- a/sys/dev/ic/dwc_mmc_reg.h +++ b/sys/dev/ic/dwc_mmc_reg.h @@ -1,7 +1,7 @@ -/* $NetBSD: dwc_mmc_reg.h,v 1.5 2015/12/27 18:35:01 jmcneill Exp $ */ +/* $NetBSD: dwc_mmc_reg.h,v 1.5.10.1 2017/07/18 19:13:10 snj Exp $ */ /*- - * Copyright (c) 2014 Jared D. McNeill + * Copyright (c) 2014-2017 Jared McNeill * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,178 +29,153 @@ #ifndef _DWC_MMC_REG_H #define _DWC_MMC_REG_H -#define DWC_MMC_CTRL_REG 0x0000 -#define DWC_MMC_PWREN_REG 0x0004 -#define DWC_MMC_CLKDIV_REG 0x0008 -#define DWC_MMC_CLKSRC_REG 0x000c -#define DWC_MMC_CLKENA_REG 0x0010 -#define DWC_MMC_TMOUT_REG 0x0014 -#define DWC_MMC_CTYPE_REG 0x0018 -#define DWC_MMC_BLKSIZ_REG 0x001c -#define DWC_MMC_BYTCNT_REG 0x0020 -#define DWC_MMC_INTMASK_REG 0x0024 -#define DWC_MMC_CMDARG_REG 0x0028 -#define DWC_MMC_CMD_REG 0x002c -#define DWC_MMC_RESP0_REG 0x0030 -#define DWC_MMC_RESP1_REG 0x0034 -#define DWC_MMC_RESP2_REG 0x0038 -#define DWC_MMC_RESP3_REG 0x003c -#define DWC_MMC_MINTSTS_REG 0x0040 -#define DWC_MMC_RINTSTS_REG 0x0044 -#define DWC_MMC_STATUS_REG 0x0048 -#define DWC_MMC_FIFOTH_REG 0x004c -#define DWC_MMC_CDETECT_REG 0x0050 -#define DWC_MMC_WRTPRT_REG 0x0054 -#define DWC_MMC_TCBCNT_REG 0x005c -#define DWC_MMC_TBBCNT_REG 0x0060 -#define DWC_MMC_DEBNCE_REG 0x0064 -#define DWC_MMC_USRID_REG 0x0068 -#define DWC_MMC_VERID_REG 0x006c -#define DWC_MMC_UHS_REG 0x0074 -#define DWC_MMC_RST_REG 0x0078 -#define DWC_MMC_BMODE_REG 0x0080 -#define DWC_MMC_PLDMND_REG 0x0084 -#define DWC_MMC_DBADDR_REG 0x0088 -#define DWC_MMC_IDSTS_REG 0x008c -#define DWC_MMC_IDINTEN_REG 0x0090 -#define DWC_MMC_DSCADDR_REG 0x0094 -#define DWC_MMC_BUFADDR_REG 0x0098 -#define DWC_MMC_CARDTHRCTL_REG 0x0100 -#define DWC_MMC_BACK_END_POWER_REG 0x0104 -#define DWC_MMC_FIFO_BASE_REG 0x0200 +#define DWC_MMC_GCTRL 0x0000 +#define DWC_MMC_PWREN 0x0004 +#define DWC_MMC_CLKDIV 0x0008 +#define DWC_MMC_CLKSRC 0x000c +#define DWC_MMC_CLKENA 0x0010 +#define DWC_MMC_TIMEOUT 0x0014 +#define DWC_MMC_WIDTH 0x0018 +#define DWC_MMC_BLKSZ 0x001c +#define DWC_MMC_BYTECNT 0x0020 +#define DWC_MMC_IMASK 0x0024 +#define DWC_MMC_ARG 0x0028 +#define DWC_MMC_CMD 0x002c +#define DWC_MMC_RESP0 0x0030 +#define DWC_MMC_RESP1 0x0034 +#define DWC_MMC_RESP2 0x0038 +#define DWC_MMC_RESP3 0x003c +#define DWC_MMC_MINT 0x0040 +#define DWC_MMC_RINT 0x0044 +#define DWC_MMC_STATUS 0x0048 +#define DWC_MMC_FIFOTH 0x004c +#define DWC_MMC_CDETECT 0x0050 +#define DWC_MMC_WRITEPROT 0x0054 +#define DWC_MMC_GPIO 0x0058 +#define DWC_MMC_CBCR 0x005c +#define DWC_MMC_BBCR 0x0060 +#define DWC_MMC_DEBNCE 0x0064 +#define DWC_MMC_USRID 0x0068 +#define DWC_MMC_VERID 0x006c +#define DWC_MMC_HCON 0x0070 +#define DWC_MMC_UHS 0x0074 +#define DWC_MMC_RST 0x0078 +#define DWC_MMC_DMAC 0x0080 +#define DWC_MMC_PLDMND 0x0084 +#define DWC_MMC_DLBA 0x0088 +#define DWC_MMC_IDST 0x008c +#define DWC_MMC_IDIE 0x0090 +#define DWC_MMC_DSCADDR 0x0094 +#define DWC_MMC_BUFADDR 0x0098 -#define DWC_MMC_CTRL_SEND_AUTO_STOP __BIT(10) -#define DWC_MMC_CTRL_ABORT_READ_DATA __BIT(8) -#define DWC_MMC_CTRL_SEND_IRQ_RESPONSE __BIT(7) -#define DWC_MMC_CTRL_READ_WAIT __BIT(6) -#define DWC_MMC_CTRL_DMA_ENABLE __BIT(5) -#define DWC_MMC_CTRL_INT_ENABLE __BIT(4) -#define DWC_MMC_CTRL_DMA_RESET __BIT(2) -#define DWC_MMC_CTRL_FIFO_RESET __BIT(1) -#define DWC_MMC_CTRL_CONTROLLER_RESET __BIT(0) -#define DWC_MMC_CTRL_RESET_ALL \ - (DWC_MMC_CTRL_CONTROLLER_RESET | \ - DWC_MMC_CTRL_FIFO_RESET | \ - DWC_MMC_CTRL_DMA_RESET) +#define DWC_MMC_GCTRL_USE_INTERNAL_DMAC __BIT(25) +#define DWC_MMC_GCTRL_SEND_AUTO_STOP_CCSD __BIT(10) +#define DWC_MMC_GCTRL_DMAEN __BIT(5) +#define DWC_MMC_GCTRL_INTEN __BIT(4) +#define DWC_MMC_GCTRL_DMARESET __BIT(2) +#define DWC_MMC_GCTRL_FIFORESET __BIT(1) +#define DWC_MMC_GCTRL_SOFTRESET __BIT(0) +#define DWC_MMC_GCTRL_RESET \ + (DWC_MMC_GCTRL_SOFTRESET | DWC_MMC_GCTRL_FIFORESET | \ + DWC_MMC_GCTRL_DMARESET) -#define DWC_MMC_PWREN_POWER_ENABLE __BIT(0) +#define DWC_MMC_CLKENA_LOWPOWERON __BIT(16) +#define DWC_MMC_CLKENA_CARDCLKON __BIT(0) -#define DWC_MMC_CLKDIV_CLK_DIVIDER0 __BITS(7,0) +#define DWC_MMC_WIDTH_1 0x00000000 +#define DWC_MMC_WIDTH_4 0x00000001 +#define DWC_MMC_WIDTH_8 0x00010000 -#define DWC_MMC_CLKENA_CCLK_LOW_POWER __BIT(16) -#define DWC_MMC_CLKENA_CCLK_ENABLE __BIT(0) +#define DWC_MMC_CMD_START __BIT(31) +#define DWC_MMC_CMD_USE_HOLD_REG __BIT(29) +#define DWC_MMC_CMD_VOL_SWITCH __BIT(28) +#define DWC_MMC_CMD_BOOT_MODE __BIT(27) +#define DWC_MMC_CMD_DISABLE_BOOT __BIT(26) +#define DWC_MMC_CMD_EXPECT_BOOT_ACT __BIT(25) +#define DWC_MMC_CMD_ENABLE_BOOT __BIT(24) +#define DWC_MMC_CMD_UPCLK_ONLY __BIT(21) +#define DWC_MMC_CMD_SEND_INIT_SEQ __BIT(15) +#define DWC_MMC_CMD_STOP_ABORT_CMD __BIT(14) +#define DWC_MMC_CMD_WAIT_PRE_OVER __BIT(13) +#define DWC_MMC_CMD_SEND_AUTO_STOP __BIT(12) +#define DWC_MMC_CMD_SEQMOD __BIT(11) +#define DWC_MMC_CMD_WRITE __BIT(10) +#define DWC_MMC_CMD_DATA_EXP __BIT(9) +#define DWC_MMC_CMD_CHECK_RSP_CRC __BIT(8) +#define DWC_MMC_CMD_LONG_RSP __BIT(7) +#define DWC_MMC_CMD_RSP_EXP __BIT(6) -#define DWC_MMC_TMOUT_DATA_TIMEOUT __BITS(31,8) -#define DWC_MMC_TMOUT_RESPONSE_TIMEOUT __BITS(7,0) +#define DWC_MMC_INT_CARD_REMOVE __BIT(31) +#define DWC_MMC_INT_CARD_INSERT __BIT(30) +#define DWC_MMC_INT_SDIO_INT __BIT(16) +#define DWC_MMC_INT_END_BIT_ERR __BIT(15) +#define DWC_MMC_INT_AUTO_CMD_DONE __BIT(14) +#define DWC_MMC_INT_START_BIT_ERR __BIT(13) +#define DWC_MMC_INT_HW_LOCKED __BIT(12) +#define DWC_MMC_INT_FIFO_RUN_ERR __BIT(11) +#define DWC_MMC_INT_VOL_CHG_DONE __BIT(10) +#define DWC_MMC_INT_DATA_STARVE __BIT(10) +#define DWC_MMC_INT_BOOT_START __BIT(9) +#define DWC_MMC_INT_DATA_TIMEOUT __BIT(9) +#define DWC_MMC_INT_ACK_RCV __BIT(8) +#define DWC_MMC_INT_RESP_TIMEOUT __BIT(8) +#define DWC_MMC_INT_DATA_CRC_ERR __BIT(7) +#define DWC_MMC_INT_RESP_CRC_ERR __BIT(6) +#define DWC_MMC_INT_RX_DATA_REQ __BIT(5) +#define DWC_MMC_INT_TX_DATA_REQ __BIT(4) +#define DWC_MMC_INT_DATA_OVER __BIT(3) +#define DWC_MMC_INT_CMD_DONE __BIT(2) +#define DWC_MMC_INT_RESP_ERR __BIT(1) +#define DWC_MMC_INT_ERROR \ + (DWC_MMC_INT_RESP_ERR | DWC_MMC_INT_RESP_CRC_ERR | \ + DWC_MMC_INT_DATA_CRC_ERR | DWC_MMC_INT_RESP_TIMEOUT | \ + DWC_MMC_INT_FIFO_RUN_ERR | DWC_MMC_INT_HW_LOCKED | \ + DWC_MMC_INT_START_BIT_ERR | DWC_MMC_INT_END_BIT_ERR) -#define DWC_MMC_CTYPE_CARD_WIDTH_8 __BIT(16) -#define DWC_MMC_CTYPE_CARD_WIDTH_4 __BIT(0) -#define DWC_MMC_CTYPE_CARD_WIDTH_1 0 +#define DWC_MMC_STATUS_DMAREQ __BIT(31) +#define DWC_MMC_STATUS_DATA_FSM_BUSY __BIT(10) +#define DWC_MMC_STATUS_CARD_DATA_BUSY __BIT(9) +#define DWC_MMC_STATUS_CARD_PRESENT __BIT(8) +#define DWC_MMC_STATUS_FIFO_FULL __BIT(3) +#define DWC_MMC_STATUS_FIFO_EMPTY __BIT(2) +#define DWC_MMC_STATUS_TXWL_FLAG __BIT(1) +#define DWC_MMC_STATUS_RXWL_FLAG __BIT(0) -#define DWC_MMC_INT_SDIO_INT __BIT(24) -#define DWC_MMC_INT_NEW_INT __BIT(16) -#define DWC_MMC_INT_MASK __BITS(15,0) -#define DWC_MMC_INT_EBE __BIT(15) -#define DWC_MMC_INT_ACD __BIT(14) -#define DWC_MMC_INT_SBE __BIT(13) -#define DWC_MMC_INT_HLE __BIT(12) -#define DWC_MMC_INT_FRUN __BIT(11) -#define DWC_MMC_INT_HTO __BIT(10) -#define DWC_MMC_INT_DRTO __BIT(9) -#define DWC_MMC_INT_RTO __BIT(8) -#define DWC_MMC_INT_DCRC __BIT(7) -#define DWC_MMC_INT_RCRC __BIT(6) -#define DWC_MMC_INT_RXDR __BIT(5) -#define DWC_MMC_INT_TXDR __BIT(4) -#define DWC_MMC_INT_DTO __BIT(3) -#define DWC_MMC_INT_CD __BIT(2) -#define DWC_MMC_INT_RE __BIT(1) -#define DWC_MMC_INT_CARDDET __BIT(0) -#define DWC_MMC_INT_ERROR \ - (DWC_MMC_INT_RE | DWC_MMC_INT_RCRC | DWC_MMC_INT_DCRC | \ - DWC_MMC_INT_RTO | DWC_MMC_INT_DRTO | DWC_MMC_INT_HTO | \ - DWC_MMC_INT_HLE | DWC_MMC_INT_SBE | DWC_MMC_INT_EBE) +#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE __BITS(30,28) +#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_16 3 +#define DWC_MMC_FIFOTH_RX_WMARK __BITS(27,16) +#define DWC_MMC_FIFOTH_TX_WMARK __BITS(11,0) -#define DWC_MMC_INT_BITS \ - "\20" \ - "\x19" "SDIO_INT" \ - "\x11" "NEW_INT" \ - "\x10" "EBE" \ - "\x0f" "ACD" \ - "\x0e" "SBE" \ - "\x0d" "HLE" \ - "\x0c" "FRUN" \ - "\x0b" "HTO" \ - "\x0a" "DRTO" \ - "\x09" "RTO" \ - "\x08" "DCRC" \ - "\x07" "RCRC" \ - "\x06" "RXDR" \ - "\x05" "TXDR" \ - "\x04" "DTO" \ - "\x03" "CD" \ - "\x02" "RE" \ - "\x01" "CARDDET" +#define DWC_MMC_DMAC_IDMA_ON __BIT(7) +#define DWC_MMC_DMAC_FIX_BURST __BIT(1) +#define DWC_MMC_DMAC_SOFTRESET __BIT(0) -#define DWC_MMC_CMD_START_CMD __BIT(31) -#define DWC_MMC_CMD_USE_HOLD_REG __BIT(29) -#define DWC_MMC_CMD_VOLT_SWITCH __BIT(28) -#define DWC_MMC_CMD_BOOT_MODE __BIT(27) -#define DWC_MMC_CMD_DISABLE_BOOT __BIT(26) -#define DWC_MMC_CMD_EXPECT_BOOT_ACK __BIT(25) -#define DWC_MMC_CMD_ENABLE_BOOT __BIT(24) -#define DWC_MMC_CMD_UPDATE_CLOCK_REGS_ONLY __BIT(21) -#define DWC_MMC_CMD_SEND_INIT __BIT(15) -#define DWC_MMC_CMD_STOP_ABORT_CMD __BIT(14) -#define DWC_MMC_CMD_WAIT_PRVDATA_COMPLETE __BIT(13) -#define DWC_MMC_CMD_SEND_AUTO_STOP __BIT(12) -#define DWC_MMC_CMD_TRANSFER_MODE __BIT(11) -#define DWC_MMC_CMD_WR __BIT(10) -#define DWC_MMC_CMD_DATA_EXPECTED __BIT(9) -#define DWC_MMC_CMD_CHECK_RESP_CRC __BIT(8) -#define DWC_MMC_CMD_RESP_LEN __BIT(7) -#define DWC_MMC_CMD_RESP_EXPECTED __BIT(6) -#define DWC_MMC_CMD_INDEX __BITS(5,0) +#define DWC_MMC_IDST_HOST_ABT __BIT(10) +#define DWC_MMC_IDST_ABNORMAL_INT_SUM __BIT(9) +#define DWC_MMC_IDST_NORMAL_INT_SUM __BIT(8) +#define DWC_MMC_IDST_CARD_ERR_SUM __BIT(5) +#define DWC_MMC_IDST_DES_INVALID __BIT(4) +#define DWC_MMC_IDST_FATAL_BUS_ERR __BIT(2) +#define DWC_MMC_IDST_RECEIVE_INT __BIT(1) +#define DWC_MMC_IDST_TRANSMIT_INT __BIT(0) +#define DWC_MMC_IDST_ERROR \ + (DWC_MMC_IDST_ABNORMAL_INT_SUM | DWC_MMC_IDST_CARD_ERR_SUM | \ + DWC_MMC_IDST_DES_INVALID | DWC_MMC_IDST_FATAL_BUS_ERR) +#define DWC_MMC_IDST_COMPLETE \ + (DWC_MMC_IDST_RECEIVE_INT | DWC_MMC_IDST_TRANSMIT_INT) -#define DWC_MMC_STATUS_DMA_REQ __BIT(31) -#define DWC_MMC_STATUS_DMA_ACK __BIT(30) -#define DWC_MMC_STATUS_FIFO_COUNT __BITS(29,17) -#define DWC_MMC_STATUS_RESP_INDEX __BITS(16,11) -#define DWC_MMC_STATUS_DATA_STATE_MC_BUSY __BIT(10) -#define DWC_MMC_STATUS_DATA_BUSY __BIT(9) -#define DWC_MMC_STATUS_DATA_3_STATUS __BIT(8) -#define DWC_MMC_STATUS_COMMAND_FSM_STATES __BITS(7,4) -#define DWC_MMC_STATUS_FIFO_FULL __BIT(3) -#define DWC_MMC_STATUS_FIFO_EMPTY __BIT(2) -#define DWC_MMC_STATUS_FIFO_TX_WATERMARK __BIT(1) -#define DWC_MMC_STATUS_FIFO_RX_WATERMARK __BIT(0) - -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE __BITS(30,28) -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_1 0 -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_4 1 -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_8 2 -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_16 3 -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_32 4 -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_64 5 -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_128 6 -#define DWC_MMC_FIFOTH_DMA_MULTIPLE_TXN_SIZE_256 7 -#define DWC_MMC_FIFOTH_RX_WMARK __BITS(27,16) -#define DWC_MMC_FIFOTH_TX_WMARK __BITS(11,0) - -#define DWC_MMC_CDETECT_CARD_DETECT_N __BIT(0) - -#define DWC_MMC_WRTPRT_WRITE_PROTECT __BIT(0) - -#define DWC_MMC_DEBNCE_DEBOUNCE_COUNT __BITS(23,0) - -#define DWC_MMC_UHS_DDR __BIT(16) -#define DWC_MMC_UHS_VOLT __BIT(0) - -#define DWC_MMC_RST_CARD_RESET __BIT(0) - -#define DWC_MMC_CARDTHRCTL_CARDRDTHRESHOLD __BITS(27,16) -#define DWC_MMC_CARDTHRCTL_CARDRDTHREN __BIT(0) - -#define DWC_MMC_BACK_END_POWER_ENABLE __BIT(0) +struct dwc_mmc_idma_desc { + uint32_t dma_config; +#define DWC_MMC_IDMA_CONFIG_DIC __BIT(1) +#define DWC_MMC_IDMA_CONFIG_LD __BIT(2) +#define DWC_MMC_IDMA_CONFIG_FD __BIT(3) +#define DWC_MMC_IDMA_CONFIG_CH __BIT(4) +#define DWC_MMC_IDMA_CONFIG_ER __BIT(5) +#define DWC_MMC_IDMA_CONFIG_CES __BIT(30) +#define DWC_MMC_IDMA_CONFIG_OWN __BIT(31) + uint32_t dma_buf_size; + uint32_t dma_buf_addr; + uint32_t dma_next; +} __packed; #endif /* !_DWC_MMC_REG_H */ diff --git a/sys/dev/ic/dwc_mmc_var.h b/sys/dev/ic/dwc_mmc_var.h index 92b4616393f9..762346e20b8f 100644 --- a/sys/dev/ic/dwc_mmc_var.h +++ b/sys/dev/ic/dwc_mmc_var.h @@ -1,7 +1,7 @@ -/* $NetBSD: dwc_mmc_var.h,v 1.5 2015/12/26 23:13:10 jmcneill Exp $ */ +/* $NetBSD: dwc_mmc_var.h,v 1.5.10.1 2017/07/18 19:13:10 snj Exp $ */ /*- - * Copyright (c) 2014 Jared D. McNeill + * Copyright (c) 2014-2017 Jared McNeill * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,31 +30,48 @@ #define _DWC_MMC_VAR_H struct dwc_mmc_softc { - device_t sc_dev; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; - bus_dma_tag_t sc_dmat; - void *sc_ih; - unsigned int sc_clock_freq; - unsigned int sc_clock_max; - unsigned int sc_fifo_depth; - uint32_t sc_flags; -#define DWC_MMC_F_USE_HOLD_REG 0x0001 /* set USE_HOLD_REG with every cmd */ -#define DWC_MMC_F_PWREN_CLEAR 0x0002 /* clear POWER_ENABLE bit to enable */ -#define DWC_MMC_F_FORCE_CLK 0x0004 /* update clk div with every cmd */ -#define DWC_MMC_F_BROKEN_CD 0x0008 /* card detect doesn't work */ - int (*sc_set_clkdiv)(struct dwc_mmc_softc *, int); - int (*sc_card_detect)(struct dwc_mmc_softc *); + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + bus_space_handle_t sc_clk_bsh; + bus_dma_tag_t sc_dmat; - device_t sc_sdmmc_dev; - kmutex_t sc_intr_lock; - kcondvar_t sc_intr_cv; + u_int sc_flags; +#define DWC_MMC_F_DMA __BIT(0) +#define DWC_MMC_F_USE_HOLD_REG __BIT(1) + uint32_t sc_fifo_reg; + uint32_t sc_fifo_depth; + u_int sc_clock_freq; - uint32_t sc_intr_rint; - u_int sc_cur_freq; + void *sc_ih; + kmutex_t sc_intr_lock; + kcondvar_t sc_intr_cv; + kcondvar_t sc_idst_cv; + + int sc_mmc_width; + int sc_mmc_present; + int sc_mmc_port; + + device_t sc_sdmmc_dev; + + uint32_t sc_idma_xferlen; + bus_dma_segment_t sc_idma_segs[1]; + int sc_idma_nsegs; + bus_size_t sc_idma_size; + bus_dmamap_t sc_idma_map; + int sc_idma_ndesc; + void *sc_idma_desc; + + uint32_t sc_intr_rint; + uint32_t sc_intr_mint; + uint32_t sc_idma_idst; + + int (*sc_card_detect)(struct dwc_mmc_softc *); + int (*sc_write_protect)(struct dwc_mmc_softc *); + void (*sc_set_led)(struct dwc_mmc_softc *, int); }; -void dwc_mmc_init(struct dwc_mmc_softc *); +int dwc_mmc_init(struct dwc_mmc_softc *); int dwc_mmc_intr(void *); #endif /* !_DWC_MMC_VAR_H */ diff --git a/sys/dev/led.c b/sys/dev/led.c new file mode 100644 index 000000000000..d963def345a2 --- /dev/null +++ b/sys/dev/led.c @@ -0,0 +1,192 @@ +/* $NetBSD: led.c,v 1.2.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: led.c,v 1.2.4.2 2017/07/18 19:13:09 snj Exp $"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +struct led_device { + char *name; + led_getstate_fn getstate; + led_setstate_fn setstate; + void *priv; + + struct sysctllog *slog; + + TAILQ_ENTRY(led_device) devices; +}; + +static TAILQ_HEAD(, led_device) led_devices = + TAILQ_HEAD_INITIALIZER(led_devices); +static kmutex_t led_lock; + +static int +led_init(void) +{ + mutex_init(&led_lock, MUTEX_DEFAULT, IPL_NONE); + + return 0; +} + +static struct led_device * +led_lookup(const char *name) +{ + struct led_device *led; + + KASSERT(mutex_owned(&led_lock)); + + TAILQ_FOREACH(led, &led_devices, devices) + if (strcmp(led->name, name) == 0) + return led; + + return NULL; +} + +static void +led_normalize_name(char *name) +{ + unsigned char *p; + + for (p = (unsigned char *)name; *p; p++) + if (!isalpha(*p) && !isdigit(*p) && *p != '-' && *p != '_') + *p = '_'; +} + +static void +led_free(struct led_device *led) +{ + KASSERT(mutex_owned(&led_lock)); + + kmem_free(led->name, strlen(led->name) + 1); + kmem_free(led, sizeof(*led)); +} + +static int +led_sysctl_handler(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + struct led_device *led; + int error, state; + + mutex_enter(&led_lock); + + node = *rnode; + led = node.sysctl_data; + state = led->getstate(led->priv); + node.sysctl_data = &state; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) { + mutex_exit(&led_lock); + return error; + } + + if (state < LED_STATE_OFF || state > LED_STATE_ON) { + mutex_exit(&led_lock); + return EINVAL; + } + + led->setstate(led->priv, state); + + mutex_exit(&led_lock); + + return 0; +} + +void * +led_attach(const char *name, void *priv, led_getstate_fn getstate, + led_setstate_fn setstate) +{ + static ONCE_DECL(control); + struct led_device *led; + const struct sysctlnode *node; + int error; + + if (RUN_ONCE(&control, led_init) != 0) + return NULL; + + led = kmem_zalloc(sizeof(*led), KM_SLEEP); + led->name = kmem_asprintf("%s", name); + led->getstate = getstate; + led->setstate = setstate; + led->priv = priv; + + /* Convert invalid sysctl node name characters to underscores */ + led_normalize_name(led->name); + + mutex_enter(&led_lock); + if (led_lookup(name) != NULL) { + led_free(led); + led = NULL; + } else { + error = sysctl_createv(&led->slog, 0, NULL, &node, + CTLFLAG_PERMANENT, CTLTYPE_NODE, "led", NULL, + NULL, 0, NULL, 0, + CTL_HW, CTL_CREATE, CTL_EOL); + if (error == 0) { + error = sysctl_createv(&led->slog, 0, &node, NULL, + CTLFLAG_READWRITE, CTLTYPE_BOOL, led->name, NULL, + led_sysctl_handler, 0, + (void *)led, 0, + CTL_CREATE, CTL_EOL); + } + if (error != 0) { + printf("led: failed to create sysctl hw.led.%s: %d\n", + led->name, error); + led_free(led); + led = NULL; + } + } + if (led != NULL) + TAILQ_INSERT_TAIL(&led_devices, led, devices); + mutex_exit(&led_lock); + + return led; +} + +void +led_detach(void *handle) +{ + struct led_device *led = handle; + + mutex_enter(&led_lock); + + TAILQ_REMOVE(&led_devices, led, devices); + sysctl_teardown(&led->slog); + led_free(led); + + mutex_exit(&led_lock); +} diff --git a/sys/dev/led.h b/sys/dev/led.h new file mode 100644 index 000000000000..2e27c37f3c76 --- /dev/null +++ b/sys/dev/led.h @@ -0,0 +1,51 @@ +/* $NetBSD: led.h,v 1.1.4.2 2017/07/18 19:13:09 snj Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill + * 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. + */ + +#ifndef _DEV_LED_H +#define _DEV_LED_H + +enum { + LED_STATE_OFF, + LED_STATE_ON +}; + +typedef int (*led_getstate_fn)(void *); +typedef void (*led_setstate_fn)(void *, int); + +/* + * Attach an LED device. Returns an opaque handle on success and NULL + * on failure. + */ +void * led_attach(const char *, void *, led_getstate_fn, led_setstate_fn); + +/* + * Detach a previously attached LED device. + */ +void led_detach(void *); + +#endif /* !_DEV_LED_H */ diff --git a/sys/dev/ofw/ofw_subr.c b/sys/dev/ofw/ofw_subr.c index 79df125b4fb8..c5677f33e49f 100644 --- a/sys/dev/ofw/ofw_subr.c +++ b/sys/dev/ofw/ofw_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: ofw_subr.c,v 1.28 2017/04/30 16:46:09 jmcneill Exp $ */ +/* $NetBSD: ofw_subr.c,v 1.28.2.1 2017/07/18 19:13:10 snj Exp $ */ /* * Copyright 1998 @@ -34,7 +34,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ofw_subr.c,v 1.28 2017/04/30 16:46:09 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ofw_subr.c,v 1.28.2.1 2017/07/18 19:13:10 snj Exp $"); #include #include @@ -185,6 +185,75 @@ of_match_compatible(int phandle, const char * const *strings) return of_compatible(phandle, strings) + 1; } +/* + * int of_match_compat_data(phandle, compat_data) + * + * This routine searches an array of compat_data structures for a + * matching "compatible" entry matching the supplied OFW node. + * + * It should be used when determining whether a driver can drive + * a particular device. + * + * Arguments: + * phandle OFW phandle of device to be checked for + * compatibility. + * compat_data Array of possible compat entry strings and + * associated metadata. The last entry in the + * list should have a "compat" of NULL to terminate + * the list. + * + * Return Value: + * 0 if none of the strings are found in phandle's "compatibility" + * property, or a positive number based on the reverse index of the + * matching string in the phandle's "compatibility" property, plus 1. + * + * Side Effects: + * None. + */ +int +of_match_compat_data(int phandle, const struct of_compat_data *compat_data) +{ + for (; compat_data->compat != NULL; compat_data++) { + const char *compat[] = { compat_data->compat, NULL }; + const int match = of_match_compatible(phandle, compat); + if (match) + return match; + } + return 0; +} + +/* + * const struct of_compat_data *of_search_compatible(phandle, compat_data) + * + * This routine searches an array of compat_data structures for a + * matching "compatible" entry matching the supplied OFW node. + * + * Arguments: + * phandle OFW phandle of device to be checked for + * compatibility. + * compat_data Array of possible compat entry strings and + * associated metadata. The last entry in the + * list should have a "compat" of NULL to terminate + * the list. + * + * Return Value: + * The first matching compat_data entry in the array. If no matches + * are found, the terminating ("compat" of NULL) record is returned. + * + * Side Effects: + * None. + */ +const struct of_compat_data * +of_search_compatible(int phandle, const struct of_compat_data *compat_data) +{ + for (; compat_data->compat != NULL; compat_data++) { + const char *compat[] = { compat_data->compat, NULL }; + if (of_match_compatible(phandle, compat)) + break; + } + return compat_data; +} + /* * int of_packagename(phandle, buf, bufsize) * diff --git a/sys/dev/ofw/openfirm.h b/sys/dev/ofw/openfirm.h index 9beeba3abef4..0862ef81807f 100644 --- a/sys/dev/ofw/openfirm.h +++ b/sys/dev/ofw/openfirm.h @@ -1,4 +1,4 @@ -/* $NetBSD: openfirm.h,v 1.34 2017/04/30 16:46:09 jmcneill Exp $ */ +/* $NetBSD: openfirm.h,v 1.34.2.1 2017/07/18 19:13:10 snj Exp $ */ /* * Copyright (C) 1995, 1996 Wolfgang Solfrank. @@ -65,6 +65,10 @@ struct ofbus_attach_args { int oba_unit; }; +struct of_compat_data { + const char *compat; + uintptr_t data; +}; /* * Functions and variables provided by machine-dependent code. @@ -106,6 +110,9 @@ int openfirmware(void *); */ int of_compatible(int, const char * const *); int of_match_compatible(int, const char * const *); +int of_match_compat_data(int, const struct of_compat_data *); +const struct of_compat_data * + of_search_compatible(int, const struct of_compat_data *); int of_decode_int(const unsigned char *); int of_packagename(int, char *, int); int of_find_firstchild_byname(int, const char *); diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c index 97ffe22a3f2c..0b70c6f5c35d 100644 --- a/sys/dev/usb/ehci.c +++ b/sys/dev/usb/ehci.c @@ -1,4 +1,4 @@ -/* $NetBSD: ehci.c,v 1.254 2016/10/03 00:32:37 dholland Exp $ */ +/* $NetBSD: ehci.c,v 1.254.8.1 2017/07/18 19:13:10 snj Exp $ */ /* * Copyright (c) 2004-2012 The NetBSD Foundation, Inc. @@ -53,7 +53,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.254 2016/10/03 00:32:37 dholland Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.254.8.1 2017/07/18 19:13:10 snj Exp $"); #include "ohci.h" #include "uhci.h" @@ -447,12 +447,18 @@ ehci_init(ehci_softc_t *sc) } if (sc->sc_ncomp > 0) { KASSERT(!(sc->sc_flags & EHCIF_ETTF)); - aprint_normal("%s: companion controller%s, %d port%s each:", - device_xname(sc->sc_dev), sc->sc_ncomp!=1 ? "s" : "", + aprint_normal("%s: %d companion controller%s, %d port%s%s", + device_xname(sc->sc_dev), sc->sc_ncomp, + sc->sc_ncomp!=1 ? "s" : "", EHCI_HCS_N_PCC(sparams), - EHCI_HCS_N_PCC(sparams)!=1 ? "s" : ""); - for (i = 0; i < sc->sc_ncomp; i++) - aprint_normal(" %s", device_xname(sc->sc_comps[i])); + EHCI_HCS_N_PCC(sparams)!=1 ? "s" : "", + sc->sc_ncomp!=1 ? " each" : ""); + if (sc->sc_comps[0]) { + aprint_normal(":"); + for (i = 0; i < sc->sc_ncomp; i++) + aprint_normal(" %s", + device_xname(sc->sc_comps[i])); + } aprint_normal("\n"); } sc->sc_noport = EHCI_HCS_N_PORTS(sparams); @@ -2594,7 +2600,9 @@ ehci_disown(ehci_softc_t *sc, int index, int lowspeed) "port %d to %s\n", device_xname(sc->sc_dev), lowspeed ? "low" : "full", - index, device_xname(sc->sc_comps[i])); + index, sc->sc_comps[i] ? + device_xname(sc->sc_comps[i]) : + "companion controller"); } else { printf("%s: npcomp == 0\n", device_xname(sc->sc_dev)); } diff --git a/usr.bin/config/defs.h b/usr.bin/config/defs.h index a08c87469272..3122260b93f0 100644 --- a/usr.bin/config/defs.h +++ b/usr.bin/config/defs.h @@ -1,4 +1,4 @@ -/* $NetBSD: defs.h,v 1.98 2016/09/09 21:09:11 christos Exp $ */ +/* $NetBSD: defs.h,v 1.98.6.1 2017/07/18 19:13:10 snj Exp $ */ /* * Copyright (c) 1992, 1993 @@ -107,7 +107,7 @@ extern const char *progname; * The next two lines define the current version of the config(1) binary, * and the minimum version of the configuration files it supports. */ -#define CONFIG_VERSION 20160808 +#define CONFIG_VERSION 20170615 #define CONFIG_MINVERSION 0 /* diff --git a/usr.bin/config/mkmakefile.c b/usr.bin/config/mkmakefile.c index d848ef15ad42..aa057d082ca6 100644 --- a/usr.bin/config/mkmakefile.c +++ b/usr.bin/config/mkmakefile.c @@ -1,4 +1,4 @@ -/* $NetBSD: mkmakefile.c,v 1.68 2015/09/04 10:16:35 uebayasi Exp $ */ +/* $NetBSD: mkmakefile.c,v 1.68.8.1 2017/07/18 19:13:10 snj Exp $ */ /* * Copyright (c) 1992, 1993 @@ -45,7 +45,7 @@ #endif #include -__RCSID("$NetBSD: mkmakefile.c,v 1.68 2015/09/04 10:16:35 uebayasi Exp $"); +__RCSID("$NetBSD: mkmakefile.c,v 1.68.8.1 2017/07/18 19:13:10 snj Exp $"); #include #include @@ -77,6 +77,7 @@ static void emitrules(FILE *); static void emitload(FILE *); static void emitincludes(FILE *); static void emitappmkoptions(FILE *); +static void emitmkoption(FILE *, const char *, const struct nvlist *); static void emitsubs(FILE *, const char *, const char *, int); static int selectopt(const char *, void *); @@ -210,6 +211,20 @@ mkmakefile(void) return (1); } +static void +emitmkoption(FILE *fp, const char *ass, const struct nvlist *nv) +{ + const char *p; + + fprintf(fp, "%s%s", nv->nv_name, ass); + for (p = nv->nv_str; *p; p++) { + if (*p == '\n') + fputs(" \\", fp); + fputc(*p, fp); + } + fputc('\n', fp); +} + static void emitsubs(FILE *fp, const char *line, const char *file, int lineno) { @@ -292,7 +307,7 @@ emitdefs(FILE *fp) fprintf(fp, "___USE_SUFFIX_RULES___=1\n"); } for (nv = mkoptions; nv != NULL; nv = nv->nv_next) - fprintf(fp, "%s=%s\n", nv->nv_name, nv->nv_str); + emitmkoption(fp, "=", nv); } static void @@ -583,7 +598,7 @@ emitappmkoptions(FILE *fp) for (nv = condmkoptions; nv != NULL; nv = nv->nv_next) { cond = nv->nv_ptr; if (expr_eval(cond, selectopt, NULL)) - fprintf(fp, "%s+=%s\n", nv->nv_name, nv->nv_str); + emitmkoption(fp, "+=", nv); condexpr_destroy(cond); nv->nv_ptr = NULL; }