Index: head/UPDATING =================================================================== --- head/UPDATING (revision 283275) +++ head/UPDATING (revision 283276) @@ -1,1191 +1,1204 @@ Updating Information for FreeBSD current users. This file is maintained and copyrighted by M. Warner Losh . See end of file for further details. For commonly done items, please see the COMMON ITEMS: section later in the file. These instructions assume that you basically know what you are doing. If not, then please consult the FreeBSD handbook: http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. NOTE: FreeBSD has switched from gcc to clang. If you have trouble bootstrapping from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to the tip of head, and then rebuild without this option. The bootstrap process from older version of current across the gcc/clang cutover is a bit fragile. NOTE TO PEOPLE WHO THINK THAT FreeBSD 11.x IS SLOW: FreeBSD 11.x has many debugging features turned on, in both the kernel and userland. These features attempt to detect incorrect use of system primitives, and encourage loud failure through extra sanity checking and fail stop semantics. They also substantially impact system performance. If you want to do performance measurement, benchmarking, and optimization, you'll want to turn them off. This includes various WITNESS- related kernel options, INVARIANTS, malloc debugging flags in userland, and various verbose features in the kernel. Many developers choose to disable these features on build machines to maximize performance. (To completely disable malloc debugging, define MALLOC_PRODUCTION in /etc/make.conf, or to merely disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20150521: + TI platform code switched to using vendor DTS files and this update + may break existing systems running on Beaglebone, Beaglebone Black, + and Pandaboard: + + - dtb files should be regenerated/reinstalled. Filenames are the + same but content is different now + - GPIO addressing was changed, now each GPIO bank (32 pins per bank) + has its own /dev/gpiocX device, e.g. pin 121 on /dev/gpioc0 in old + addressing scheme is now pin 25 on /dev/gpioc3. + - Pandaboard: /etc/ttys should be updated, serial console device is + now /dev/ttyu2, not /dev/ttyu0 + 20150501: soelim(1) from gnu/usr.bin/groff has been replaced by usr.bin/soelim. If you need the GNU extension from groff soelim(1), install groff from package: pkg install groff, or via ports: textproc/groff. 20150423: chmod, chflags, chown and chgrp now affect symlinks in -R mode as defined in symlink(7); previously symlinks were silently ignored. 20150415: The const qualifier has been removed from iconv(3) to comply with POSIX. The ports tree is aware of this from r384038 onwards. 20150416: Libraries specified by LIBADD in Makefiles must have a corresponding DPADD_ variable to ensure correct dependencies. This is now enforced in src.libnames.mk. 20150324: From legacy ata(4) driver was removed support for SATA controllers supported by more functional drivers ahci(4), siis(4) and mvs(4). Kernel modules ataahci and ataadaptec were removed completely, replaced by ahci and mvs modules respectively. 20150315: Clang, llvm and lldb have been upgraded to 3.6.0 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150307: The 32-bit PowerPC kernel has been changed to a position-independent executable. This can only be booted with a version of loader(8) newer than January 31, 2015, so make sure to update both world and kernel before rebooting. 20150217: If you are running a -CURRENT kernel since r273872 (Oct 30th, 2014), but before r278950, the RNG was not seeded properly. Immediately upgrade the kernel to r278950 or later and regenerate any keys (e.g. ssh keys or openssl keys) that were generated w/ a kernel from that range. This does not affect programs that directly used /dev/random or /dev/urandom. All userland uses of arc4random(3) are affected. 20150210: The autofs(4) ABI was changed in order to restore binary compatibility with 10.1-RELEASE. The automountd(8) daemon needs to be rebuilt to work with the new kernel. 20150131: The powerpc64 kernel has been changed to a position-independent executable. This can only be booted with a new version of loader(8), so make sure to update both world and kernel before rebooting. 20150118: Clang and llvm have been upgraded to 3.5.1 release. This is a bugfix only release, no new features have been added. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0. 20150107: ELF tools addr2line, elfcopy (strip), nm, size, and strings are now taken from the ELF Tool Chain project rather than GNU binutils. They should be drop-in replacements, with the addition of arm64 support. The WITHOUT_ELFTOOLCHAIN_TOOLS= knob may be used to obtain the binutils tools, if necessary. 20150105: The default Unbound configuration now enables remote control using a local socket. Users who have already enabled the local_unbound service should regenerate their configuration by running "service local_unbound setup" as root. 20150102: The GNU texinfo and GNU info pages have been removed. To be able to view GNU info pages please install texinfo from ports. 20141231: Clang, llvm and lldb have been upgraded to 3.5.0 release. As of this release, a prerequisite for building clang, llvm and lldb is a C++11 capable compiler and C++11 standard library. This means that to be able to successfully build the cross-tools stage of buildworld, with clang as the bootstrap compiler, your system compiler or cross compiler should either be clang 3.3 or later, or gcc 4.8 or later, and your system C++ library should be libc++, or libdstdc++ from gcc 4.8 or later. On any standard FreeBSD 10.x or 11.x installation, where clang and libc++ are on by default (that is, on x86 or arm), this should work out of the box. On 9.x installations where clang is enabled by default, e.g. on x86 and powerpc, libc++ will not be enabled by default, so libc++ should be built (with clang) and installed first. If both clang and libc++ are missing, build clang first, then use it to build libc++. On 8.x and earlier installations, upgrade to 9.x first, and then follow the instructions for 9.x above. Sparc64 and mips users are unaffected, as they still use gcc 4.2.1 by default, and do not build clang. Many embedded systems are resource constrained, and will not be able to build clang in a reasonable time, or in some cases at all. In those cases, cross building bootable systems on amd64 is a workaround. This new version of clang introduces a number of new warnings, of which the following are most likely to appear: -Wabsolute-value This warns in two cases, for both C and C++: * When the code is trying to take the absolute value of an unsigned quantity, which is effectively a no-op, and almost never what was intended. The code should be fixed, if at all possible. If you are sure that the unsigned quantity can be safely cast to signed, without loss of information or undefined behavior, you can add an explicit cast, or disable the warning. * When the code is trying to take an absolute value, but the called abs() variant is for the wrong type, which can lead to truncation. If you want to disable the warning instead of fixing the code, please make sure that truncation will not occur, or it might lead to unwanted side-effects. -Wtautological-undefined-compare and -Wundefined-bool-conversion These warn when C++ code is trying to compare 'this' against NULL, while 'this' should never be NULL in well-defined C++ code. However, there is some legacy (pre C++11) code out there, which actively abuses this feature, which was less strictly defined in previous C++ versions. Squid and openjdk do this, for example. The warning can be turned off for C++98 and earlier, but compiling the code in C++11 mode might result in unexpected behavior; for example, the parts of the program that are unreachable could be optimized away. 20141222: The old NFS client and server (kernel options NFSCLIENT, NFSSERVER) kernel sources have been removed. The .h files remain, since some utilities include them. This will need to be fixed later. If "mount -t oldnfs ..." is attempted, it will fail. If the "-o" option on mountd(8), nfsd(8) or nfsstat(1) is used, the utilities will report errors. 20141121: The handling of LOCAL_LIB_DIRS has been altered to skip addition of directories to top level SUBDIR variable when their parent directory is included in LOCAL_DIRS. Users with build systems with such hierarchies and without SUBDIR entries in the parent directory Makefiles should add them or add the directories to LOCAL_DIRS. 20141109: faith(4) and faithd(8) have been removed from the base system. Faith has been obsolete for a very long time. 20141104: vt(4), the new console driver, is enabled by default. It brings support for Unicode and double-width characters, as well as support for UEFI and integration with the KMS kernel video drivers. You may need to update your console settings in /etc/rc.conf, most probably the keymap. During boot, /etc/rc.d/syscons will indicate what you need to do. vt(4) still has issues and lacks some features compared to syscons(4). See the wiki for up-to-date information: https://wiki.freebsd.org/Newcons If you want to keep using syscons(4), you can do so by adding the following line to /boot/loader.conf: kern.vty=sc 20141102: pjdfstest has been integrated into kyua as an opt-in test suite. Please see share/doc/pjdfstest/README for more details on how to execute it. 20141009: gperf has been removed from the base system for architectures that use clang. Ports that require gperf will obtain it from the devel/gperf port. 20140923: pjdfstest has been moved from tools/regression/pjdfstest to contrib/pjdfstest . 20140922: At svn r271982, The default linux compat kernel ABI has been adjusted to 2.6.18 in support of the linux-c6 compat ports infrastructure update. If you wish to continue using the linux-f10 compat ports, add compat.linux.osrelease=2.6.16 to your local sysctl.conf. Users are encouraged to update their linux-compat packages to linux-c6 during their next update cycle. 20140729: The ofwfb driver, used to provide a graphics console on PowerPC when using vt(4), no longer allows mmap() of all physical memory. This will prevent Xorg on PowerPC with some ATI graphics cards from initializing properly unless x11-servers/xorg-server is updated to 1.12.4_8 or newer. 20140723: The xdev targets have been converted to using TARGET and TARGET_ARCH instead of XDEV and XDEV_ARCH. 20140719: The default unbound configuration has been modified to address issues with reverse lookups on networks that use private address ranges. If you use the local_unbound service, run "service local_unbound setup" as root to regenerate your configuration, then "service local_unbound reload" to load the new configuration. 20140709: The GNU texinfo and GNU info pages are not built and installed anymore, WITH_INFO knob has been added to allow to built and install them again. UPDATE: see 20150102 entry on texinfo's removal 20140708: The GNU readline library is now an INTERNALLIB - that is, it is statically linked into consumers (GDB and variants) in the base system, and the shared library is no longer installed. The devel/readline port is available for third party software that requires readline. 20140702: The Itanium architecture (ia64) has been removed from the list of known architectures. This is the first step in the removal of the architecture. 20140701: Commit r268115 has added NFSv4.1 server support, merged from projects/nfsv4.1-server. Since this includes changes to the internal interfaces between the NFS related modules, a full build of the kernel and modules will be necessary. __FreeBSD_version has been bumped. 20140629: The WITHOUT_VT_SUPPORT kernel config knob has been renamed WITHOUT_VT. (The other _SUPPORT knobs have a consistent meaning which differs from the behaviour controlled by this knob.) 20140619: Maximal length of the serial number in CTL was increased from 16 to 64 chars, that breaks ABI. All CTL-related tools, such as ctladm and ctld, need to be rebuilt to work with a new kernel. 20140606: The libatf-c and libatf-c++ major versions were downgraded to 0 and 1 respectively to match the upstream numbers. They were out of sync because, when they were originally added to FreeBSD, the upstream versions were not respected. These libraries are private and not yet built by default, so renumbering them should be a non-issue. However, unclean source trees will yield broken test programs once the operator executes "make delete-old-libs" after a "make installworld". Additionally, the atf-sh binary was made private by moving it into /usr/libexec/. Already-built shell test programs will keep the path to the old binary so they will break after "make delete-old" is run. If you are using WITH_TESTS=yes (not the default), wipe the object tree and rebuild from scratch to prevent spurious test failures. This is only needed once: the misnumbered libraries and misplaced binaries have been added to OptionalObsoleteFiles.inc so they will be removed during a clean upgrade. 20140512: Clang and llvm have been upgraded to 3.4.1 release. 20140508: We bogusly installed src.opts.mk in /usr/share/mk. This file should be removed to avoid issues in the future (and has been added to ObsoleteFiles.inc). 20140505: /etc/src.conf now affects only builds of the FreeBSD src tree. In the past, it affected all builds that used the bsd.*.mk files. The old behavior was a bug, but people may have relied upon it. To get this behavior back, you can .include /etc/src.conf from /etc/make.conf (which is still global and isn't changed). This also changes the behavior of incremental builds inside the tree of individual directories. Set MAKESYSPATH to ".../share/mk" to do that. Although this has survived make universe and some upgrade scenarios, other upgrade scenarios may have broken. At least one form of temporary breakage was fixed with MAKESYSPATH settings for buildworld as well... In cases where MAKESYSPATH isn't working with this setting, you'll need to set it to the full path to your tree. One side effect of all this cleaning up is that bsd.compiler.mk is no longer implicitly included by bsd.own.mk. If you wish to use COMPILER_TYPE, you must now explicitly include bsd.compiler.mk as well. 20140430: The lindev device has been removed since /dev/full has been made a standard device. __FreeBSD_version has been bumped. 20140424: The knob WITHOUT_VI was added to the base system, which controls building ex(1), vi(1), etc. Older releases of FreeBSD required ex(1) in order to reorder files share/termcap and didn't build ex(1) as a build tool, so building/installing with WITH_VI is highly advised for build hosts for older releases. This issue has been fixed in stable/9 and stable/10 in r277022 and r276991, respectively. 20140418: The YES_HESIOD knob has been removed. It has been obsolete for a decade. Please move to using WITH_HESIOD instead or your builds will silently lack HESIOD. 20140405: The uart(4) driver has been changed with respect to its handling of the low-level console. Previously the uart(4) driver prevented any process from changing the baudrate or the CLOCAL and HUPCL control flags. By removing the restrictions, operators can make changes to the serial console port without having to reboot. However, when getty(8) is started on the serial device that is associated with the low-level console, a misconfigured terminal line in /etc/ttys will now have a real impact. Before upgrading the kernel, make sure that /etc/ttys has the serial console device configured as 3wire without baudrate to preserve the previous behaviour. E.g: ttyu0 "/usr/libexec/getty 3wire" vt100 on secure 20140306: Support for libwrap (TCP wrappers) in rpcbind was disabled by default to improve performance. To re-enable it, if needed, run rpcbind with command line option -W. 20140226: Switched back to the GPL dtc compiler due to updates in the upstream dts files not being supported by the BSDL dtc compiler. You will need to rebuild your kernel toolchain to pick up the new compiler. Core dumps may result while building dtb files during a kernel build if you fail to do so. Set WITHOUT_GPL_DTC if you require the BSDL compiler. 20140216: Clang and llvm have been upgraded to 3.4 release. 20140216: The nve(4) driver has been removed. Please use the nfe(4) driver for NVIDIA nForce MCP Ethernet adapters instead. 20140212: An ABI incompatibility crept into the libc++ 3.4 import in r261283. This could cause certain C++ applications using shared libraries built against the previous version of libc++ to crash. The incompatibility has now been fixed, but any C++ applications or shared libraries built between r261283 and r261801 should be recompiled. 20140204: OpenSSH will now ignore errors caused by kernel lacking of Capsicum capability mode support. Please note that enabling the feature in kernel is still highly recommended. 20140131: OpenSSH is now built with sandbox support, and will use sandbox as the default privilege separation method. This requires Capsicum capability mode support in kernel. 20140128: The libelf and libdwarf libraries have been updated to newer versions from upstream. Shared library version numbers for these two libraries were bumped. Any ports or binaries requiring these two libraries should be recompiled. __FreeBSD_version is bumped to 1100006. 20140110: If a Makefile in a tests/ directory was auto-generating a Kyuafile instead of providing an explicit one, this would prevent such Makefile from providing its own Kyuafile in the future during NO_CLEAN builds. This has been fixed in the Makefiles but manual intervention is needed to clean an objdir if you use NO_CLEAN: # find /usr/obj -name Kyuafile | xargs rm -f 20131213: The behavior of gss_pseudo_random() for the krb5 mechanism has changed, for applications requesting a longer random string than produced by the underlying enctype's pseudo-random() function. In particular, the random string produced from a session key of enctype aes256-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 will be different at the 17th octet and later, after this change. The counter used in the PRF+ construction is now encoded as a big-endian integer in accordance with RFC 4402. __FreeBSD_version is bumped to 1100004. 20131108: The WITHOUT_ATF build knob has been removed and its functionality has been subsumed into the more generic WITHOUT_TESTS. If you were using the former to disable the build of the ATF libraries, you should change your settings to use the latter. 20131025: The default version of mtree is nmtree which is obtained from NetBSD. The output is generally the same, but may vary slightly. If you found you need identical output adding "-F freebsd9" to the command line should do the trick. For the time being, the old mtree is available as fmtree. 20131014: libbsdyml has been renamed to libyaml and moved to /usr/lib/private. This will break ports-mgmt/pkg. Rebuild the port, or upgrade to pkg 1.1.4_8 and verify bsdyml not linked in, before running "make delete-old-libs": # make -C /usr/ports/ports-mgmt/pkg build deinstall install clean or # pkg install pkg; ldd /usr/local/sbin/pkg | grep bsdyml 20131010: The rc.d/jail script has been updated to support jail(8) configuration file. The "jail__*" rc.conf(5) variables for per-jail configuration are automatically converted to /var/run/jail..conf before the jail(8) utility is invoked. This is transparently backward compatible. See below about some incompatibilities and rc.conf(5) manual page for more details. These variables are now deprecated in favor of jail(8) configuration file. One can use "rc.d/jail config " command to generate a jail(8) configuration file in /var/run/jail..conf without running the jail(8) utility. The default pathname of the configuration file is /etc/jail.conf and can be specified by using $jail_conf or $jail__conf variables. Please note that jail_devfs_ruleset accepts an integer at this moment. Please consider to rewrite the ruleset name with an integer. 20130930: BIND has been removed from the base system. If all you need is a local resolver, simply enable and start the local_unbound service instead. Otherwise, several versions of BIND are available in the ports tree. The dns/bind99 port is one example. With this change, nslookup(1) and dig(1) are no longer in the base system. Users should instead use host(1) and drill(1) which are in the base system. Alternatively, nslookup and dig can be obtained by installing the dns/bind-tools port. 20130916: With the addition of unbound(8), a new unbound user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20130911: OpenSSH is now built with DNSSEC support, and will by default silently trust signed SSHFP records. This can be controlled with the VerifyHostKeyDNS client configuration setting. DNSSEC support can be disabled entirely with the WITHOUT_LDNS option in src.conf. 20130906: The GNU Compiler Collection and C++ standard library (libstdc++) are no longer built by default on platforms where clang is the system compiler. You can enable them with the WITH_GCC and WITH_GNUCXX options in src.conf. 20130905: The PROCDESC kernel option is now part of the GENERIC kernel configuration and is required for the rwhod(8) to work. If you are using custom kernel configuration, you should include 'options PROCDESC'. 20130905: The API and ABI related to the Capsicum framework was modified in backward incompatible way. The userland libraries and programs have to be recompiled to work with the new kernel. This includes the following libraries and programs, but the whole buildworld is advised: libc, libprocstat, dhclient, tcpdump, hastd, hastctl, kdump, procstat, rwho, rwhod, uniq. 20130903: AES-NI intrinsic support has been added to gcc. The AES-NI module has been updated to use this support. A new gcc is required to build the aesni module on both i386 and amd64. 20130821: The PADLOCK_RNG and RDRAND_RNG kernel options are now devices. Thus "device padlock_rng" and "device rdrand_rng" should be used instead of "options PADLOCK_RNG" & "options RDRAND_RNG". 20130813: WITH_ICONV has been split into two feature sets. WITH_ICONV now enables just the iconv* functionality and is now on by default. WITH_LIBICONV_COMPAT enables the libiconv api and link time compatability. Set WITHOUT_ICONV to build the old way. If you have been using WITH_ICONV before, you will very likely need to turn on WITH_LIBICONV_COMPAT. 20130806: INVARIANTS option now enables DEBUG for code with OpenSolaris and Illumos origin, including ZFS. If you have INVARIANTS in your kernel configuration, then there is no need to set DEBUG or ZFS_DEBUG explicitly. DEBUG used to enable witness(9) tracking of OpenSolaris (mostly ZFS) locks if WITNESS option was set. Because that generated a lot of witness(9) reports and all of them were believed to be false positives, this is no longer done. New option OPENSOLARIS_WITNESS can be used to achieve the previous behavior. 20130806: Timer values in IPv6 data structures now use time_uptime instead of time_second. Although this is not a user-visible functional change, userland utilities which directly use them---ndp(8), rtadvd(8), and rtsold(8) in the base system---need to be updated to r253970 or later. 20130802: find -delete can now delete the pathnames given as arguments, instead of only files found below them or if the pathname did not contain any slashes. Formerly, the following error message would result: find: -delete: : relative path potentially not safe Deleting the pathnames given as arguments can be prevented without error messages using -mindepth 1 or by changing directory and passing "." as argument to find. This works in the old as well as the new version of find. 20130726: Behavior of devfs rules path matching has been changed. Pattern is now always matched against fully qualified devfs path and slash characters must be explicitly matched by slashes in pattern (FNM_PATHNAME). Rulesets involving devfs subdirectories must be reviewed. 20130716: The default ARM ABI has changed to the ARM EABI. The old ABI is incompatible with the ARM EABI and all programs and modules will need to be rebuilt to work with a new kernel. To keep using the old ABI ensure the WITHOUT_ARM_EABI knob is set. NOTE: Support for the old ABI will be removed in the future and users are advised to upgrade. 20130709: pkg_install has been disconnected from the build if you really need it you should add WITH_PKGTOOLS in your src.conf(5). 20130709: Most of network statistics structures were changed to be able keep 64-bits counters. Thus all tools, that work with networking statistics, must be rebuilt (netstat(1), bsnmpd(1), etc.) 20130629: Fix targets that run multiple make's to use && rather than ; so that subsequent steps depend on success of previous. NOTE: if building 'universe' with -j* on stable/8 or stable/9 it would be better to start the build using bmake, to avoid overloading the machine. 20130618: Fix a bug that allowed a tracing process (e.g. gdb) to write to a memory-mapped file in the traced process's address space even if neither the traced process nor the tracing process had write access to that file. 20130615: CVS has been removed from the base system. An exact copy of the code is available from the devel/cvs port. 20130613: Some people report the following error after the switch to bmake: make: illegal option -- J usage: make [-BPSXeiknpqrstv] [-C directory] [-D variable] ... *** [buildworld] Error code 2 this likely due to an old instance of make in ${MAKEPATH} (${MAKEOBJDIRPREFIX}${.CURDIR}/make.${MACHINE}) which src/Makefile will use that blindly, if it exists, so if you see the above error: rm -rf `make -V MAKEPATH` should resolve it. 20130516: Use bmake by default. Whereas before one could choose to build with bmake via -DWITH_BMAKE one must now use -DWITHOUT_BMAKE to use the old make. The goal is to remove these knobs for 10-RELEASE. It is worth noting that bmake (like gmake) treats the command line as the unit of failure, rather than statements within the command line. Thus '(cd some/where && dosomething)' is safer than 'cd some/where; dosomething'. The '()' allows consistent behavior in parallel build. 20130429: Fix a bug that allows NFS clients to issue READDIR on files. 20130426: The WITHOUT_IDEA option has been removed because the IDEA patent expired. 20130426: The sysctl which controls TRIM support under ZFS has been renamed from vfs.zfs.trim_disable -> vfs.zfs.trim.enabled and has been enabled by default. 20130425: The mergemaster command now uses the default MAKEOBJDIRPREFIX rather than creating it's own in the temporary directory in order allow access to bootstrapped versions of tools such as install and mtree. When upgrading from version of FreeBSD where the install command does not support -l, you will need to install a new mergemaster command if mergemaster -p is required. This can be accomplished with the command (cd src/usr.sbin/mergemaster && make install). 20130404: Legacy ATA stack, disabled and replaced by new CAM-based one since FreeBSD 9.0, completely removed from the sources. Kernel modules atadisk and atapi*, user-level tools atacontrol and burncd are removed. Kernel option `options ATA_CAM` is now permanently enabled and removed. 20130319: SOCK_CLOEXEC and SOCK_NONBLOCK flags have been added to socket(2) and socketpair(2). Software, in particular Kerberos, may automatically detect and use these during building. The resulting binaries will not work on older kernels. 20130308: CTL_DISABLE has also been added to the sparc64 GENERIC (for further information, see the respective 20130304 entry). 20130304: Recent commits to callout(9) changed the size of struct callout, so the KBI is probably heavily disturbed. Also, some functions in callout(9)/sleep(9)/sleepqueue(9)/condvar(9) KPIs were replaced by macros. Every kernel module using it won't load, so rebuild is requested. The ctl device has been re-enabled in GENERIC for i386 and amd64, but does not initialize by default (because of the new CTL_DISABLE option) to save memory. To re-enable it, remove the CTL_DISABLE option from the kernel config file or set kern.cam.ctl.disable=0 in /boot/loader.conf. 20130301: The ctl device has been disabled in GENERIC for i386 and amd64. This was done due to the extra memory being allocated at system initialisation time by the ctl driver which was only used if a CAM target device was created. This makes a FreeBSD system unusable on 128MB or less of RAM. 20130208: A new compression method (lz4) has been merged to -HEAD. Please refer to zpool-features(7) for more information. Please refer to the "ZFS notes" section of this file for information on upgrading boot ZFS pools. 20130129: A BSD-licensed patch(1) variant has been added and is installed as bsdpatch, being the GNU version the default patch. To inverse the logic and use the BSD-licensed one as default, while having the GNU version installed as gnupatch, rebuild and install world with the WITH_BSD_PATCH knob set. 20130121: Due to the use of the new -l option to install(1) during build and install, you must take care not to directly set the INSTALL make variable in your /etc/make.conf, /etc/src.conf, or on the command line. If you wish to use the -C flag for all installs you may be able to add INSTALL+=-C to /etc/make.conf or /etc/src.conf. 20130118: The install(1) option -M has changed meaning and now takes an argument that is a file or path to append logs to. In the unlikely event that -M was the last option on the command line and the command line contained at least two files and a target directory the first file will have logs appended to it. The -M option served little practical purpose in the last decade so its use is expected to be extremely rare. 20121223: After switching to Clang as the default compiler some users of ZFS on i386 systems started to experience stack overflow kernel panics. Please consider using 'options KSTACK_PAGES=4' in such configurations. 20121222: GEOM_LABEL now mangles label names read from file system metadata. Mangling affect labels containing spaces, non-printable characters, '%' or '"'. Device names in /etc/fstab and other places may need to be updated. 20121217: By default, only the 10 most recent kernel dumps will be saved. To restore the previous behaviour (no limit on the number of kernel dumps stored in the dump directory) add the following line to /etc/rc.conf: savecore_flags="" 20121201: With the addition of auditdistd(8), a new auditdistd user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20121117: The sin6_scope_id member variable in struct sockaddr_in6 is now filled by the kernel before passing the structure to the userland via sysctl or routing socket. This means the KAME-specific embedded scope id in sin6_addr.s6_addr[2] is always cleared in userland application. This behavior can be controlled by net.inet6.ip6.deembed_scopeid. __FreeBSD_version is bumped to 1000025. 20121105: On i386 and amd64 systems WITH_CLANG_IS_CC is now the default. This means that the world and kernel will be compiled with clang and that clang will be installed as /usr/bin/cc, /usr/bin/c++, and /usr/bin/cpp. To disable this behavior and revert to building with gcc, compile with WITHOUT_CLANG_IS_CC. Really old versions of current may need to bootstrap WITHOUT_CLANG first if the clang build fails (its compatibility window doesn't extend to the 9 stable branch point). 20121102: The IPFIREWALL_FORWARD kernel option has been removed. Its functionality now turned on by default. 20121023: The ZERO_COPY_SOCKET kernel option has been removed and split into SOCKET_SEND_COW and SOCKET_RECV_PFLIP. NB: SOCKET_SEND_COW uses the VM page based copy-on-write mechanism which is not safe and may result in kernel crashes. NB: The SOCKET_RECV_PFLIP mechanism is useless as no current driver supports disposeable external page sized mbuf storage. Proper replacements for both zero-copy mechanisms are under consideration and will eventually lead to complete removal of the two kernel options. 20121023: The IPv4 network stack has been converted to network byte order. The following modules need to be recompiled together with kernel: carp(4), divert(4), gif(4), siftr(4), gre(4), pf(4), ipfw(4), ng_ipfw(4), stf(4). 20121022: Support for non-MPSAFE filesystems was removed from VFS. The VFS_VERSION was bumped, all filesystem modules shall be recompiled. 20121018: All the non-MPSAFE filesystems have been disconnected from the build. The full list includes: codafs, hpfs, ntfs, nwfs, portalfs, smbfs, xfs. 20121016: The interface cloning API and ABI has changed. The following modules need to be recompiled together with kernel: ipfw(4), pfsync(4), pflog(4), usb(4), wlan(4), stf(4), vlan(4), disc(4), edsc(4), if_bridge(4), gif(4), tap(4), faith(4), epair(4), enc(4), tun(4), if_lagg(4), gre(4). 20121015: The sdhci driver was split in two parts: sdhci (generic SD Host Controller logic) and sdhci_pci (actual hardware driver). No kernel config modifications are required, but if you load sdhc as a module you must switch to sdhci_pci instead. 20121014: Import the FUSE kernel and userland support into base system. 20121013: The GNU sort(1) program has been removed since the BSD-licensed sort(1) has been the default for quite some time and no serious problems have been reported. The corresponding WITH_GNU_SORT knob has also gone. 20121006: The pfil(9) API/ABI for AF_INET family has been changed. Packet filtering modules: pf(4), ipfw(4), ipfilter(4) need to be recompiled with new kernel. 20121001: The net80211(4) ABI has been changed to allow for improved driver PS-POLL and power-save support. All wireless drivers need to be recompiled to work with the new kernel. 20120913: The random(4) support for the VIA hardware random number generator (`PADLOCK') is no longer enabled unconditionally. Add the padlock_rng device in the custom kernel config if needed. The GENERIC kernels on i386 and amd64 do include the device, so the change only affects the custom kernel configurations. 20120908: The pf(4) packet filter ABI has been changed. pfctl(8) and snmp_pf module need to be recompiled to work with new kernel. 20120828: A new ZFS feature flag "com.delphix:empty_bpobj" has been merged to -HEAD. Pools that have empty_bpobj in active state can not be imported read-write with ZFS implementations that do not support this feature. For more information read the zpool-features(5) manual page. 20120727: The sparc64 ZFS loader has been changed to no longer try to auto- detect ZFS providers based on diskN aliases but now requires these to be explicitly listed in the OFW boot-device environment variable. 20120712: The OpenSSL has been upgraded to 1.0.1c. Any binaries requiring libcrypto.so.6 or libssl.so.6 must be recompiled. Also, there are configuration changes. Make sure to merge /etc/ssl/openssl.cnf. 20120712: The following sysctls and tunables have been renamed for consistency with other variables: kern.cam.da.da_send_ordered -> kern.cam.da.send_ordered kern.cam.ada.ada_send_ordered -> kern.cam.ada.send_ordered 20120628: The sort utility has been replaced with BSD sort. For now, GNU sort is also available as "gnusort" or the default can be set back to GNU sort by setting WITH_GNU_SORT. In this case, BSD sort will be installed as "bsdsort". 20120611: A new version of ZFS (pool version 5000) has been merged to -HEAD. Starting with this version the old system of ZFS pool versioning is superseded by "feature flags". This concept enables forward compatibility against certain future changes in functionality of ZFS pools. The first read-only compatible "feature flag" for ZFS pools is named "com.delphix:async_destroy". For more information read the new zpool-features(5) manual page. Please refer to the "ZFS notes" section of this file for information on upgrading boot ZFS pools. 20120417: The malloc(3) implementation embedded in libc now uses sources imported as contrib/jemalloc. The most disruptive API change is to /etc/malloc.conf. If your system has an old-style /etc/malloc.conf, delete it prior to installworld, and optionally re-create it using the new format after rebooting. See malloc.conf(5) for details (specifically the TUNING section and the "opt.*" entries in the MALLCTL NAMESPACE section). 20120328: Big-endian MIPS TARGET_ARCH values no longer end in "eb". mips64eb is now spelled mips64. mipsn32eb is now spelled mipsn32. mipseb is now spelled mips. This is to aid compatibility with third-party software that expects this naming scheme in uname(3). Little-endian settings are unchanged. If you are updating a big-endian mips64 machine from before this change, you may need to set MACHINE_ARCH=mips64 in your environment before the new build system will recognize your machine. 20120306: Disable by default the option VFS_ALLOW_NONMPSAFE for all supported platforms. 20120229: Now unix domain sockets behave "as expected" on nullfs(5). Previously nullfs(5) did not pass through all behaviours to the underlying layer, as a result if we bound to a socket on the lower layer we could connect only to the lower path; if we bound to the upper layer we could connect only to the upper path. The new behavior is one can connect to both the lower and the upper paths regardless what layer path one binds to. 20120211: The getifaddrs upgrade path broken with 20111215 has been restored. If you have upgraded in between 20111215 and 20120209 you need to recompile libc again with your kernel. You still need to recompile world to be able to configure CARP but this restriction already comes from 20111215. 20120114: The set_rcvar() function has been removed from /etc/rc.subr. All base and ports rc.d scripts have been updated, so if you have a port installed with a script in /usr/local/etc/rc.d you can either hand-edit the rcvar= line, or reinstall the port. An easy way to handle the mass-update of /etc/rc.d: rm /etc/rc.d/* && mergemaster -i 20120109: panic(9) now stops other CPUs in the SMP systems, disables interrupts on the current CPU and prevents other threads from running. This behavior can be reverted using the kern.stop_scheduler_on_panic tunable/sysctl. The new behavior can be incompatible with kern.sync_on_panic. 20111215: The carp(4) facility has been changed significantly. Configuration of the CARP protocol via ifconfig(8) has changed, as well as format of CARP events submitted to devd(8) has changed. See manual pages for more information. The arpbalance feature of carp(4) is currently not supported anymore. Size of struct in_aliasreq, struct in6_aliasreq has changed. User utilities using SIOCAIFADDR, SIOCAIFADDR_IN6, e.g. ifconfig(8), need to be recompiled. 20111122: The acpi_wmi(4) status device /dev/wmistat has been renamed to /dev/wmistat0. 20111108: The option VFS_ALLOW_NONMPSAFE option has been added in order to explicitely support non-MPSAFE filesystems. It is on by default for all supported platform at this present time. 20111101: The broken amd(4) driver has been replaced with esp(4) in the amd64, i386 and pc98 GENERIC kernel configuration files. 20110930: sysinstall has been removed 20110923: The stable/9 branch created in subversion. This corresponds to the RELENG_9 branch in CVS. COMMON ITEMS: General Notes ------------- Avoid using make -j when upgrading. While generally safe, there are sometimes problems using -j to upgrade. If your upgrade fails with -j, please try again without -j. From time to time in the past there have been problems using -j with buildworld and/or installworld. This is especially true when upgrading between "distant" versions (eg one that cross a major release boundary or several minor releases, or when several months have passed on the -current branch). Sometimes, obscure build problems are the result of environment poisoning. This can happen because the make utility reads its environment when searching for values for global variables. To run your build attempts in an "environmental clean room", prefix all make commands with 'env -i '. See the env(1) manual page for more details. When upgrading from one major version to another it is generally best to upgrade to the latest code in the currently installed branch first, then do an upgrade to the new branch. This is the best-tested upgrade path, and has the highest probability of being successful. Please try this approach before reporting problems with a major version upgrade. When upgrading a live system, having a root shell around before installing anything can help undo problems. Not having a root shell around can lead to problems if pam has changed too much from your starting point to allow continued authentication after the upgrade. ZFS notes --------- When upgrading the boot ZFS pool to a new version, always follow these two steps: 1.) recompile and reinstall the ZFS boot loader and boot block (this is part of "make buildworld" and "make installworld") 2.) update the ZFS boot block on your boot drive The following example updates the ZFS boot block on the first partition (freebsd-boot) of a GPT partitioned drive ada0: "gpart bootcode -p /boot/gptzfsboot -i 1 ada0" Non-boot pools do not need these updates. To build a kernel ----------------- If you are updating from a prior version of FreeBSD (even one just a few days old), you should follow this procedure. It is the most failsafe as it uses a /usr/obj tree with a fresh mini-buildworld, make kernel-toolchain make -DALWAYS_CHECK_MAKE buildkernel KERNCONF=YOUR_KERNEL_HERE make -DALWAYS_CHECK_MAKE installkernel KERNCONF=YOUR_KERNEL_HERE To test a kernel once --------------------- If you just want to boot a kernel once (because you are not sure if it works, or if you want to boot a known bad kernel to provide debugging information) run make installkernel KERNCONF=YOUR_KERNEL_HERE KODIR=/boot/testkernel nextboot -k testkernel To just build a kernel when you know that it won't mess you up -------------------------------------------------------------- This assumes you are already running a CURRENT system. Replace ${arch} with the architecture of your machine (e.g. "i386", "arm", "amd64", "ia64", "pc98", "sparc64", "powerpc", "mips", etc). cd src/sys/${arch}/conf config KERNEL_NAME_HERE cd ../compile/KERNEL_NAME_HERE make depend make make install If this fails, go to the "To build a kernel" section. To rebuild everything and install it on the current system. ----------------------------------------------------------- # Note: sometimes if you are running current you gotta do more than # is listed here if you are upgrading from a really old current. make buildworld make kernel KERNCONF=YOUR_KERNEL_HERE [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] To cross-install current onto a separate partition -------------------------------------------------- # In this approach we use a separate partition to hold # current's root, 'usr', and 'var' directories. A partition # holding "/", "/usr" and "/var" should be about 2GB in # size. make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installworld DESTDIR=${CURRENT_ROOT} -DDB_FROM_SRC make distribution DESTDIR=${CURRENT_ROOT} # if newfs'd make installkernel KERNCONF=YOUR_KERNEL_HERE DESTDIR=${CURRENT_ROOT} cp /etc/fstab ${CURRENT_ROOT}/etc/fstab # if newfs'd To upgrade in-place from stable to current ---------------------------------------------- make buildworld [9] make kernel KERNCONF=YOUR_KERNEL_HERE [8] [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] Make sure that you've read the UPDATING file to understand the tweaks to various things you need. At this point in the life cycle of current, things change often and you are on your own to cope. The defaults can also change, so please read ALL of the UPDATING entries. Also, if you are tracking -current, you must be subscribed to freebsd-current@freebsd.org. Make sure that before you update your sources that you have read and understood all the recent messages there. If in doubt, please track -stable which has much fewer pitfalls. [1] If you have third party modules, such as vmware, you should disable them at this point so they don't crash your system on reboot. [3] From the bootblocks, boot -s, and then do fsck -p mount -u / mount -a cd src adjkerntz -i # if CMOS is wall time Also, when doing a major release upgrade, it is required that you boot into single user mode to do the installworld. [4] Note: This step is non-optional. Failure to do this step can result in a significant reduction in the functionality of the system. Attempting to do it by hand is not recommended and those that pursue this avenue should read this file carefully, as well as the archives of freebsd-current and freebsd-hackers mailing lists for potential gotchas. The -U option is also useful to consider. See mergemaster(8) for more information. [5] Usually this step is a noop. However, from time to time you may need to do this if you get unknown user in the following step. It never hurts to do it all the time. You may need to install a new mergemaster (cd src/usr.sbin/mergemaster && make install) after the buildworld before this step if you last updated from current before 20130425 or from -stable before 20130430. [6] This only deletes old files and directories. Old libraries can be deleted by "make delete-old-libs", but you have to make sure that no program is using those libraries anymore. [8] In order to have a kernel that can run the 4.x binaries needed to do an installworld, you must include the COMPAT_FREEBSD4 option in your kernel. Failure to do so may leave you with a system that is hard to boot to recover. A similar kernel option COMPAT_FREEBSD5 is required to run the 5.x binaries on more recent kernels. And so on for COMPAT_FREEBSD6 and COMPAT_FREEBSD7. Make sure that you merge any new devices from GENERIC since the last time you updated your kernel config file. [9] When checking out sources, you must include the -P flag to have cvs prune empty directories. If CPUTYPE is defined in your /etc/make.conf, make sure to use the "?=" instead of the "=" assignment operator, so that buildworld can override the CPUTYPE if it needs to. MAKEOBJDIRPREFIX must be defined in an environment variable, and not on the command line, or in /etc/make.conf. buildworld will warn if it is improperly defined. FORMAT: This file contains a list, in reverse chronological order, of major breakages in tracking -current. It is not guaranteed to be a complete list of such breakages, and only contains entries since October 10, 2007. If you need to see UPDATING entries from before that date, you will need to fetch an UPDATING file from an older FreeBSD release. Copyright information: Copyright 1998-2009 M. Warner Losh. All Rights Reserved. Redistribution, publication, translation and use, with or without modification, in full or in part, in any form or format of this document are permitted without further permission from the author. THIS DOCUMENT IS PROVIDED BY WARNER LOSH ``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 WARNER LOSH 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. Contact Warner Losh if you have any questions about your use of this document. $FreeBSD$ Index: head/sys/arm/conf/BEAGLEBONE =================================================================== --- head/sys/arm/conf/BEAGLEBONE (revision 283275) +++ head/sys/arm/conf/BEAGLEBONE (revision 283276) @@ -1,137 +1,140 @@ # # BEAGLEBONE -- Custom configuration for the BeagleBone ARM development # platforms, check out http://www.beagleboard.org/bone and # http://www.beagleboard.org/black. This kernel config file is used for the # original BeagleBone and the BeagleBone Black. # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ ident BEAGLEBONE include "std.armv6" include "../ti/am335x/std.am335x" makeoptions MODULES_EXTRA="dtb/am335x" # DTrace support options KDTRACE_HOOKS # Kernel DTrace hooks options DDB_CTF # all architectures - kernel ELF linker loads CTF data makeoptions WITH_CTF=1 makeoptions MODULES_EXTRA+="opensolaris dtrace dtrace/lockstat dtrace/profile dtrace/fbt" options HZ=100 options SCHED_4BSD # 4BSD scheduler options PLATFORM # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options BREAK_TO_DEBUGGER #options VERBOSE_SYSINIT # Enable verbose sysinit messages options KDB # Enable kernel debugger support # For minimum debugger support (stable branch) use: #options KDB_TRACE # Print a stack trace for a panic # For full debugger support use this instead: options DDB # Enable the kernel debugger options INVARIANTS # Enable calls of extra sanity checking options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options DIAGNOSTIC # NFS server support #options NFSD # NFS root from boopt/dhcp #options BOOTP #options BOOTP_NFSROOT #options BOOTP_COMPAT #options BOOTP_NFSV3 #options BOOTP_WIRED_TO=cpsw0 # Boot device is 2nd slice on MMC/SD card options ROOTDEVNAME=\"ufs:mmcsd0s2\" # MMC/SD/SDIO Card slot support device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards device sdhci # mmc/sd host controller # I2C support device iicbus device iic device ti_i2c device am335x_pmic # AM335x Power Management IC (TPC65217) device am335x_rtc # RTC support (power management only) # Console and misc device uart device uart_ns8250 device pty device snp device md device random # Entropy device # GPIO device gpio device gpioled # ADC support device ti_adc # Watchdog support # If we don't enable the watchdog driver, the system could potentially # reboot automatically because the boot loader might have enabled the # watchdog. device ti_wdt # TI Programmable Realtime Unit support device ti_pruss # Mailbox support device ti_mbox # USB support device usb options USB_HOST_ALIGN=64 # Align usb buffers to cache line size. options USB_DEBUG #options USB_REQ_DEBUG #options USB_VERBOSE device musb device umass device scbus # SCSI bus (required for ATA/SCSI) device da # Direct Access (disks) # Ethernet device loop device ether device mii device smscphy device cpsw device bpf # USB Ethernet support, requires miibus device miibus device axe # ASIX Electronics USB Ethernet # Device mode support and USFS template device usb_template # Control of the gadget device usfs +# Pinmux +device fdt_pinctrl + # Flattened Device Tree options FDT # Configure using FDT/DTB data Index: head/sys/arm/conf/PANDABOARD =================================================================== --- head/sys/arm/conf/PANDABOARD (revision 283275) +++ head/sys/arm/conf/PANDABOARD (revision 283276) @@ -1,127 +1,129 @@ # # PANDABOARD -- Custom configuration for the PandaBoard ARM development # platform, check out www.pandaboard.org # # For more information on this file, please read the config(5) manual page, # and/or the handbook section on Kernel Configuration Files: # # http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html # # The handbook is also available locally in /usr/share/doc/handbook # if you've installed the doc distribution, otherwise always see the # FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the # latest information. # # An exhaustive list of options and more detailed explanations of the # device lines is also present in the ../../conf/NOTES and NOTES files. # If you are in doubt as to the purpose or necessity of a line, check first # in NOTES. # # $FreeBSD$ ident PANDABOARD # This probably wants to move somewhere else. Maybe we can create a basic # OMAP4340 config, then make a PANDABOARD config that includes the basic one, # adds the start addresses and custom devices plus pulls in this hints file. hints "PANDABOARD.hints" include "std.armv6" include "../ti/omap4/pandaboard/std.pandaboard" options HZ=100 options SCHED_ULE # ULE scheduler options PLATFORM options SMP # Enable multiple cores # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols options BREAK_TO_DEBUGGER #options VERBOSE_SYSINIT # Enable verbose sysinit messages options KDB # Enable kernel debugger support # For minimum debugger support (stable branch) use: #options KDB_TRACE # Print a stack trace for a panic # For full debugger support use this instead: options DDB # Enable the kernel debugger #options INVARIANTS # Enable calls of extra sanity checking #options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS #options WITNESS # Enable checks to detect deadlocks and cycles #options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options DIAGNOSTIC # NFS root from boopt/dhcp #options BOOTP #options BOOTP_NFSROOT #options BOOTP_COMPAT #options BOOTP_NFSV3 #options BOOTP_WIRED_TO=ue0 +device fdt_pinctrl # Interrupt controller device gic # MMC/SD/SDIO Card slot support device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards device sdhci # mmc/sd host controller # I2C support device iicbus device iic device ti_i2c # Console and misc device uart device uart_ns8250 device pty device snp device md device random # Entropy device device pl310 # PL310 L2 cache controller # GPIO device gpio +device gpioled # The following enables MFS as root, this seems similar to an initramfs or initrd # as used in Linux. #options MD_ROOT #options MD_ROOT_SIZE=7560 # USB support device usb options USB_HOST_ALIGN=64 # Align usb buffers to cache line size. options USB_DEBUG #options USB_REQ_DEBUG #options USB_VERBOSE device ohci device ehci device umass device scbus # SCSI bus (required for ATA/SCSI) device da # Direct Access (disks) # Ethernet device loop device ether device mii device smc device smcphy device bpf # USB Ethernet support, requires miibus device miibus #device axe # ASIX Electronics USB Ethernet device smsc # SMSC LAN95xx USB Ethernet # OMAP-specific devices device ti_sdma device twl device twl_vreg device twl_clks # Flattened Device Tree options FDT # Configure using FDT/DTB data options FDT_DTB_STATIC makeoptions FDT_DTS_FILE=pandaboard.dts Index: head/sys/arm/ti/aintc.c =================================================================== --- head/sys/arm/ti/aintc.c (revision 283275) +++ head/sys/arm/ti/aintc.c (revision 283276) @@ -1,195 +1,200 @@ /*- * Copyright (c) 2012 Damjan Marion * All rights reserved. * * Based on OMAP3 INTC code by Ben Gray * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #define INTC_REVISION 0x00 #define INTC_SYSCONFIG 0x10 #define INTC_SYSSTATUS 0x14 #define INTC_SIR_IRQ 0x40 #define INTC_CONTROL 0x48 #define INTC_THRESHOLD 0x68 #define INTC_MIR_CLEAR(x) (0x88 + ((x) * 0x20)) #define INTC_MIR_SET(x) (0x8C + ((x) * 0x20)) #define INTC_ISR_SET(x) (0x90 + ((x) * 0x20)) #define INTC_ISR_CLEAR(x) (0x94 + ((x) * 0x20)) struct ti_aintc_softc { device_t sc_dev; struct resource * aintc_res[3]; bus_space_tag_t aintc_bst; bus_space_handle_t aintc_bsh; uint8_t ver; }; static struct resource_spec ti_aintc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; - static struct ti_aintc_softc *ti_aintc_sc = NULL; #define aintc_read_4(_sc, reg) \ bus_space_read_4((_sc)->aintc_bst, (_sc)->aintc_bsh, (reg)) #define aintc_write_4(_sc, reg, val) \ bus_space_write_4((_sc)->aintc_bst, (_sc)->aintc_bsh, (reg), (val)) +/* List of compatible strings for FDT tree */ +static struct ofw_compat_data compat_data[] = { + {"ti,am33xx-intc", 1}, + {"ti,omap2-intc", 1}, + {NULL, 0}, +}; static void aintc_post_filter(void *arg) { arm_irq_memory_barrier(0); aintc_write_4(ti_aintc_sc, INTC_CONTROL, 1); /* EOI */ } static int ti_aintc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "ti,aintc")) + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); + device_set_desc(dev, "TI AINTC Interrupt Controller"); return (BUS_PROBE_DEFAULT); } static int ti_aintc_attach(device_t dev) { struct ti_aintc_softc *sc = device_get_softc(dev); uint32_t x; sc->sc_dev = dev; if (ti_aintc_sc) return (ENXIO); if (bus_alloc_resources(dev, ti_aintc_spec, sc->aintc_res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->aintc_bst = rman_get_bustag(sc->aintc_res[0]); sc->aintc_bsh = rman_get_bushandle(sc->aintc_res[0]); ti_aintc_sc = sc; x = aintc_read_4(sc, INTC_REVISION); device_printf(dev, "Revision %u.%u\n",(x >> 4) & 0xF, x & 0xF); /* SoftReset */ aintc_write_4(sc, INTC_SYSCONFIG, 2); /* Wait for reset to complete */ while(!(aintc_read_4(sc, INTC_SYSSTATUS) & 1)); /*Set Priority Threshold */ aintc_write_4(sc, INTC_THRESHOLD, 0xFF); arm_post_filter = aintc_post_filter; return (0); } static device_method_t ti_aintc_methods[] = { DEVMETHOD(device_probe, ti_aintc_probe), DEVMETHOD(device_attach, ti_aintc_attach), { 0, 0 } }; static driver_t ti_aintc_driver = { "aintc", ti_aintc_methods, sizeof(struct ti_aintc_softc), }; static devclass_t ti_aintc_devclass; DRIVER_MODULE(aintc, simplebus, ti_aintc_driver, ti_aintc_devclass, 0, 0); int arm_get_next_irq(int last_irq) { struct ti_aintc_softc *sc = ti_aintc_sc; uint32_t active_irq; /* Get the next active interrupt */ active_irq = aintc_read_4(sc, INTC_SIR_IRQ); /* Check for spurious interrupt */ if ((active_irq & 0xffffff80)) { device_printf(sc->sc_dev, "Spurious interrupt detected (0x%08x)\n", active_irq); aintc_write_4(sc, INTC_SIR_IRQ, 0); return -1; } if (active_irq != last_irq) return active_irq; else return -1; } void arm_mask_irq(uintptr_t nb) { struct ti_aintc_softc *sc = ti_aintc_sc; aintc_write_4(sc, INTC_MIR_SET(nb >> 5), (1UL << (nb & 0x1F))); aintc_write_4(sc, INTC_CONTROL, 1); /* EOI */ } void arm_unmask_irq(uintptr_t nb) { struct ti_aintc_softc *sc = ti_aintc_sc; arm_irq_memory_barrier(nb); aintc_write_4(sc, INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F))); } Index: head/sys/arm/ti/am335x/am335x_pwm.c =================================================================== --- head/sys/arm/ti/am335x/am335x_pwm.c (revision 283275) +++ head/sys/arm/ti/am335x/am335x_pwm.c (nonexistent) @@ -1,542 +0,0 @@ -/*- - * Copyright (c) 2013 Oleksandr Tymoshenko - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include - -#include "am335x_pwm.h" -#include "am335x_scm.h" - -/* In ticks */ -#define DEFAULT_PWM_PERIOD 1000 -#define PWM_CLOCK 100000000UL - -#define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) -#define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) -#define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ - device_get_nameunit(_sc->sc_dev), "am335x_pwm softc", MTX_DEF) -#define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) - -static struct resource_spec am335x_pwm_mem_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* PWMSS */ - { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* eCAP */ - { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* eQEP */ - { SYS_RES_MEMORY, 3, RF_ACTIVE }, /*ePWM */ - { -1, 0, 0 } -}; - -#define PWMSS_READ4(_sc, reg) bus_read_4((_sc)->sc_mem_res[0], reg); -#define PWMSS_WRITE4(_sc, reg, value) \ - bus_write_4((_sc)->sc_mem_res[0], reg, value); - -#define ECAP_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res[1], reg); -#define ECAP_WRITE2(_sc, reg, value) \ - bus_write_2((_sc)->sc_mem_res[1], reg, value); -#define ECAP_READ4(_sc, reg) bus_read_4((_sc)->sc_mem_res[1], reg); -#define ECAP_WRITE4(_sc, reg, value) \ - bus_write_4((_sc)->sc_mem_res[1], reg, value); - -#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res[3], reg); -#define EPWM_WRITE2(_sc, reg, value) \ - bus_write_2((_sc)->sc_mem_res[3], reg, value); - -#define PWMSS_IDVER 0x00 -#define PWMSS_SYSCONFIG 0x04 -#define PWMSS_CLKCONFIG 0x08 -#define CLKCONFIG_EPWMCLK_EN (1 << 8) -#define PWMSS_CLKSTATUS 0x0C - -#define ECAP_TSCTR 0x00 -#define ECAP_CAP1 0x08 -#define ECAP_CAP2 0x0C -#define ECAP_CAP3 0x10 -#define ECAP_CAP4 0x14 -#define ECAP_ECCTL2 0x2A -#define ECCTL2_MODE_APWM (1 << 9) -#define ECCTL2_SYNCO_SEL (3 << 6) -#define ECCTL2_TSCTRSTOP_FREERUN (1 << 4) - -#define EPWM_TBCTL 0x00 -#define TBCTL_FREERUN (2 << 14) -#define TBCTL_PHDIR_UP (1 << 13) -#define TBCTL_PHDIR_DOWN (0 << 13) -#define TBCTL_CLKDIV(x) ((x) << 10) -#define TBCTL_CLKDIV_MASK (3 << 10) -#define TBCTL_HSPCLKDIV(x) ((x) << 7) -#define TBCTL_HSPCLKDIV_MASK (3 << 7) -#define TBCTL_SYNCOSEL_DISABLED (3 << 4) -#define TBCTL_PRDLD_SHADOW (0 << 3) -#define TBCTL_PRDLD_IMMEDIATE (0 << 3) -#define TBCTL_PHSEN_ENABLED (1 << 2) -#define TBCTL_PHSEN_DISABLED (0 << 2) -#define TBCTL_CTRMODE_MASK (3) -#define TBCTL_CTRMODE_UP (0 << 0) -#define TBCTL_CTRMODE_DOWN (1 << 0) -#define TBCTL_CTRMODE_UPDOWN (2 << 0) -#define TBCTL_CTRMODE_FREEZE (3 << 0) - -#define EPWM_TBSTS 0x02 -#define EPWM_TBPHSHR 0x04 -#define EPWM_TBPHS 0x06 -#define EPWM_TBCNT 0x08 -#define EPWM_TBPRD 0x0a -/* Counter-compare */ -#define EPWM_CMPCTL 0x0e -#define CMPCTL_SHDWBMODE_SHADOW (1 << 6) -#define CMPCTL_SHDWBMODE_IMMEDIATE (0 << 6) -#define CMPCTL_SHDWAMODE_SHADOW (1 << 4) -#define CMPCTL_SHDWAMODE_IMMEDIATE (0 << 4) -#define CMPCTL_LOADBMODE_ZERO (0 << 2) -#define CMPCTL_LOADBMODE_PRD (1 << 2) -#define CMPCTL_LOADBMODE_EITHER (2 << 2) -#define CMPCTL_LOADBMODE_FREEZE (3 << 2) -#define CMPCTL_LOADAMODE_ZERO (0 << 0) -#define CMPCTL_LOADAMODE_PRD (1 << 0) -#define CMPCTL_LOADAMODE_EITHER (2 << 0) -#define CMPCTL_LOADAMODE_FREEZE (3 << 0) -#define EPWM_CMPAHR 0x10 -#define EPWM_CMPA 0x12 -#define EPWM_CMPB 0x14 -/* CMPCTL_LOADAMODE_ZERO */ -#define EPWM_AQCTLA 0x16 -#define EPWM_AQCTLB 0x18 -#define AQCTL_CBU_NONE (0 << 8) -#define AQCTL_CBU_CLEAR (1 << 8) -#define AQCTL_CBU_SET (2 << 8) -#define AQCTL_CBU_TOGGLE (3 << 8) -#define AQCTL_CAU_NONE (0 << 4) -#define AQCTL_CAU_CLEAR (1 << 4) -#define AQCTL_CAU_SET (2 << 4) -#define AQCTL_CAU_TOGGLE (3 << 4) -#define AQCTL_ZRO_NONE (0 << 0) -#define AQCTL_ZRO_CLEAR (1 << 0) -#define AQCTL_ZRO_SET (2 << 0) -#define AQCTL_ZRO_TOGGLE (3 << 0) -#define EPWM_AQSFRC 0x1a -#define EPWM_AQCSFRC 0x1c - -/* Trip-Zone module */ -#define EPWM_TZCTL 0x28 -#define EPWM_TZFLG 0x2C -/* High-Resolution PWM */ -#define EPWM_HRCTL 0x40 -#define HRCTL_DELMODE_BOTH 3 -#define HRCTL_DELMODE_FALL 2 -#define HRCTL_DELMODE_RISE 1 - -static device_probe_t am335x_pwm_probe; -static device_attach_t am335x_pwm_attach; -static device_detach_t am335x_pwm_detach; - -static int am335x_pwm_clkdiv[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - -struct am335x_pwm_softc { - device_t sc_dev; - struct mtx sc_mtx; - struct resource *sc_mem_res[4]; - int sc_id; - /* sysctl for configuration */ - int sc_pwm_clkdiv; - int sc_pwm_freq; - struct sysctl_oid *sc_clkdiv_oid; - struct sysctl_oid *sc_freq_oid; - struct sysctl_oid *sc_period_oid; - struct sysctl_oid *sc_chanA_oid; - struct sysctl_oid *sc_chanB_oid; - uint32_t sc_pwm_period; - uint32_t sc_pwm_dutyA; - uint32_t sc_pwm_dutyB; -}; - -static device_method_t am335x_pwm_methods[] = { - DEVMETHOD(device_probe, am335x_pwm_probe), - DEVMETHOD(device_attach, am335x_pwm_attach), - DEVMETHOD(device_detach, am335x_pwm_detach), - - DEVMETHOD_END -}; - -static driver_t am335x_pwm_driver = { - "am335x_pwm", - am335x_pwm_methods, - sizeof(struct am335x_pwm_softc), -}; - -static devclass_t am335x_pwm_devclass; - -/* - * API function to set period/duty cycles for ECASx - */ -int -am335x_pwm_config_ecas(int unit, int period, int duty) -{ - device_t dev; - struct am335x_pwm_softc *sc; - uint16_t reg; - - dev = devclass_get_device(am335x_pwm_devclass, unit); - if (dev == NULL) - return (ENXIO); - - if (duty > period) - return (EINVAL); - - if (period == 0) - return (EINVAL); - - sc = device_get_softc(dev); - PWM_LOCK(sc); - - reg = ECAP_READ2(sc, ECAP_ECCTL2); - reg |= ECCTL2_MODE_APWM | ECCTL2_TSCTRSTOP_FREERUN | ECCTL2_SYNCO_SEL; - ECAP_WRITE2(sc, ECAP_ECCTL2, reg); - - /* CAP3 in APWM mode is APRD shadow register */ - ECAP_WRITE4(sc, ECAP_CAP3, period - 1); - - /* CAP4 in APWM mode is ACMP shadow register */ - ECAP_WRITE4(sc, ECAP_CAP4, duty); - /* Restart counter */ - ECAP_WRITE4(sc, ECAP_TSCTR, 0); - - PWM_UNLOCK(sc); - - return (0); -} - -static void -am335x_pwm_freq(struct am335x_pwm_softc *sc) -{ - int clkdiv; - - clkdiv = am335x_pwm_clkdiv[sc->sc_pwm_clkdiv]; - sc->sc_pwm_freq = PWM_CLOCK / (1 * clkdiv) / sc->sc_pwm_period; -} - -static int -am335x_pwm_sysctl_freq(SYSCTL_HANDLER_ARGS) -{ - int clkdiv, error, freq, i, period; - struct am335x_pwm_softc *sc; - uint32_t reg; - - sc = (struct am335x_pwm_softc *)arg1; - - PWM_LOCK(sc); - freq = sc->sc_pwm_freq; - PWM_UNLOCK(sc); - - error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); - if (error != 0 || req->newptr == NULL) - return (error); - - if (freq > PWM_CLOCK) - freq = PWM_CLOCK; - - PWM_LOCK(sc); - if (freq != sc->sc_pwm_freq) { - for (i = nitems(am335x_pwm_clkdiv) - 1; i >= 0; i--) { - clkdiv = am335x_pwm_clkdiv[i]; - period = PWM_CLOCK / clkdiv / freq; - if (period > USHRT_MAX) - break; - sc->sc_pwm_clkdiv = i; - sc->sc_pwm_period = period; - } - /* Reset the duty cycle settings. */ - sc->sc_pwm_dutyA = 0; - sc->sc_pwm_dutyB = 0; - EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); - EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); - /* Update the clkdiv settings. */ - reg = EPWM_READ2(sc, EPWM_TBCTL); - reg &= ~TBCTL_CLKDIV_MASK; - reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv); - EPWM_WRITE2(sc, EPWM_TBCTL, reg); - /* Update the period settings. */ - EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1); - am335x_pwm_freq(sc); - } - PWM_UNLOCK(sc); - - return (0); -} - -static int -am335x_pwm_sysctl_clkdiv(SYSCTL_HANDLER_ARGS) -{ - int error, i, clkdiv; - struct am335x_pwm_softc *sc; - uint32_t reg; - - sc = (struct am335x_pwm_softc *)arg1; - - PWM_LOCK(sc); - clkdiv = am335x_pwm_clkdiv[sc->sc_pwm_clkdiv]; - PWM_UNLOCK(sc); - - error = sysctl_handle_int(oidp, &clkdiv, sizeof(clkdiv), req); - if (error != 0 || req->newptr == NULL) - return (error); - - PWM_LOCK(sc); - if (clkdiv != am335x_pwm_clkdiv[sc->sc_pwm_clkdiv]) { - for (i = 0; i < nitems(am335x_pwm_clkdiv); i++) - if (clkdiv >= am335x_pwm_clkdiv[i]) - sc->sc_pwm_clkdiv = i; - - reg = EPWM_READ2(sc, EPWM_TBCTL); - reg &= ~TBCTL_CLKDIV_MASK; - reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv); - EPWM_WRITE2(sc, EPWM_TBCTL, reg); - am335x_pwm_freq(sc); - } - PWM_UNLOCK(sc); - - return (0); -} - -static int -am335x_pwm_sysctl_duty(SYSCTL_HANDLER_ARGS) -{ - struct am335x_pwm_softc *sc = (struct am335x_pwm_softc*)arg1; - int error; - uint32_t duty; - - if (oidp == sc->sc_chanA_oid) - duty = sc->sc_pwm_dutyA; - else - duty = sc->sc_pwm_dutyB; - error = sysctl_handle_int(oidp, &duty, 0, req); - - if (error != 0 || req->newptr == NULL) - return (error); - - if (duty > sc->sc_pwm_period) { - device_printf(sc->sc_dev, "Duty cycle can't be greater then period\n"); - return (EINVAL); - } - - PWM_LOCK(sc); - if (oidp == sc->sc_chanA_oid) { - sc->sc_pwm_dutyA = duty; - EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); - } - else { - sc->sc_pwm_dutyB = duty; - EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); - } - PWM_UNLOCK(sc); - - return (error); -} - -static int -am335x_pwm_sysctl_period(SYSCTL_HANDLER_ARGS) -{ - struct am335x_pwm_softc *sc = (struct am335x_pwm_softc*)arg1; - int error; - uint32_t period; - - period = sc->sc_pwm_period; - error = sysctl_handle_int(oidp, &period, 0, req); - - if (error != 0 || req->newptr == NULL) - return (error); - - if (period < 1) - return (EINVAL); - - if (period > USHRT_MAX) - period = USHRT_MAX; - - PWM_LOCK(sc); - /* Reset the duty cycle settings. */ - sc->sc_pwm_dutyA = 0; - sc->sc_pwm_dutyB = 0; - EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); - EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); - /* Update the period settings. */ - sc->sc_pwm_period = period; - EPWM_WRITE2(sc, EPWM_TBPRD, period - 1); - am335x_pwm_freq(sc); - PWM_UNLOCK(sc); - - return (error); -} - -static int -am335x_pwm_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "ti,am335x-pwm")) - return (ENXIO); - - device_set_desc(dev, "AM335x PWM"); - - return (BUS_PROBE_DEFAULT); -} - -static int -am335x_pwm_attach(device_t dev) -{ - struct am335x_pwm_softc *sc; - int err; - uint32_t reg; - phandle_t node; - pcell_t did; - struct sysctl_ctx_list *ctx; - struct sysctl_oid *tree; - - sc = device_get_softc(dev); - sc->sc_dev = dev; - /* Get the PWM module id */ - node = ofw_bus_get_node(dev); - if ((OF_getprop(node, "pwm-device-id", &did, sizeof(did))) <= 0) { - device_printf(dev, "missing pwm-device-id attribute in FDT\n"); - return (ENXIO); - } - sc->sc_id = fdt32_to_cpu(did); - - PWM_LOCK_INIT(sc); - - err = bus_alloc_resources(dev, am335x_pwm_mem_spec, - sc->sc_mem_res); - if (err) { - device_printf(dev, "cannot allocate memory resources\n"); - goto fail; - } - - ti_prcm_clk_enable(PWMSS0_CLK + sc->sc_id); - ti_scm_reg_read_4(SCM_PWMSS_CTRL, ®); - reg |= (1 << sc->sc_id); - ti_scm_reg_write_4(SCM_PWMSS_CTRL, reg); - - /* Init backlight interface */ - ctx = device_get_sysctl_ctx(sc->sc_dev); - tree = device_get_sysctl_tree(sc->sc_dev); - - sc->sc_clkdiv_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "clkdiv", CTLTYPE_INT | CTLFLAG_RW, sc, 0, - am335x_pwm_sysctl_clkdiv, "I", "PWM clock prescaler"); - - sc->sc_freq_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, - am335x_pwm_sysctl_freq, "I", "PWM frequency"); - - sc->sc_period_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "period", CTLTYPE_INT | CTLFLAG_RW, sc, 0, - am335x_pwm_sysctl_period, "I", "PWM period"); - - sc->sc_chanA_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "dutyA", CTLTYPE_INT | CTLFLAG_RW, sc, 0, - am335x_pwm_sysctl_duty, "I", "Channel A duty cycles"); - - sc->sc_chanB_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "dutyB", CTLTYPE_INT | CTLFLAG_RW, sc, 0, - am335x_pwm_sysctl_duty, "I", "Channel B duty cycles"); - - /* CONFIGURE EPWM1 */ - reg = EPWM_READ2(sc, EPWM_TBCTL); - reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); - EPWM_WRITE2(sc, EPWM_TBCTL, reg); - - sc->sc_pwm_period = DEFAULT_PWM_PERIOD; - sc->sc_pwm_dutyA = 0; - sc->sc_pwm_dutyB = 0; - am335x_pwm_freq(sc); - - EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1); - EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); - EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); - - EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); - EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); - - /* START EPWM */ - reg &= ~TBCTL_CTRMODE_MASK; - reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN; - EPWM_WRITE2(sc, EPWM_TBCTL, reg); - - EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); - reg = EPWM_READ2(sc, EPWM_TZFLG); - - return (0); -fail: - PWM_LOCK_DESTROY(sc); - if (sc->sc_mem_res[0]) - bus_release_resources(dev, am335x_pwm_mem_spec, - sc->sc_mem_res); - - return(ENXIO); -} - -static int -am335x_pwm_detach(device_t dev) -{ - struct am335x_pwm_softc *sc; - - sc = device_get_softc(dev); - - PWM_LOCK(sc); - if (sc->sc_mem_res[0]) - bus_release_resources(dev, am335x_pwm_mem_spec, - sc->sc_mem_res); - PWM_UNLOCK(sc); - - PWM_LOCK_DESTROY(sc); - - return (0); -} - -DRIVER_MODULE(am335x_pwm, simplebus, am335x_pwm_driver, am335x_pwm_devclass, 0, 0); -MODULE_VERSION(am335x_pwm, 1); -MODULE_DEPEND(am335x_pwm, simplebus, 1, 1, 1); Property changes on: head/sys/arm/ti/am335x/am335x_pwm.c ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/arm/ti/am335x/am335x_dmtimer.c =================================================================== --- head/sys/arm/ti/am335x/am335x_dmtimer.c (revision 283275) +++ head/sys/arm/ti/am335x/am335x_dmtimer.c (revision 283276) @@ -1,695 +1,724 @@ /*- * Copyright (c) 2012 Damjan Marion * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "opt_ntp.h" #include #include #include #include #include #include -#include +#include +#include #define AM335X_NUM_TIMERS 8 #define DMT_TIDR 0x00 /* Identification Register */ #define DMT_TIOCP_CFG 0x10 /* OCP Configuration Reg */ #define DMT_TIOCP_RESET (1 << 0) /* TIOCP perform soft reset */ #define DMT_IQR_EOI 0x20 /* IRQ End-Of-Interrupt Reg */ #define DMT_IRQSTATUS_RAW 0x24 /* IRQSTATUS Raw Reg */ #define DMT_IRQSTATUS 0x28 /* IRQSTATUS Reg */ #define DMT_IRQENABLE_SET 0x2c /* IRQSTATUS Set Reg */ #define DMT_IRQENABLE_CLR 0x30 /* IRQSTATUS Clear Reg */ #define DMT_IRQWAKEEN 0x34 /* IRQ Wakeup Enable Reg */ #define DMT_IRQ_MAT (1 << 0) /* IRQ: Match */ #define DMT_IRQ_OVF (1 << 1) /* IRQ: Overflow */ #define DMT_IRQ_TCAR (1 << 2) /* IRQ: Capture */ #define DMT_IRQ_MASK (DMT_IRQ_TCAR | DMT_IRQ_OVF | DMT_IRQ_MAT) #define DMT_TCLR 0x38 /* Control Register */ #define DMT_TCLR_START (1 << 0) /* Start timer */ #define DMT_TCLR_AUTOLOAD (1 << 1) /* Auto-reload on overflow */ #define DMT_TCLR_PRES_MASK (7 << 2) /* Prescaler mask */ #define DMT_TCLR_PRES_ENABLE (1 << 5) /* Prescaler enable */ #define DMT_TCLR_COMP_ENABLE (1 << 6) /* Compare enable */ #define DMT_TCLR_PWM_HIGH (1 << 7) /* PWM default output high */ #define DMT_TCLR_CAPTRAN_MASK (3 << 8) /* Capture transition mask */ #define DMT_TCLR_CAPTRAN_NONE (0 << 8) /* Capture: none */ #define DMT_TCLR_CAPTRAN_LOHI (1 << 8) /* Capture lo->hi transition */ #define DMT_TCLR_CAPTRAN_HILO (2 << 8) /* Capture hi->lo transition */ #define DMT_TCLR_CAPTRAN_BOTH (3 << 8) /* Capture both transitions */ #define DMT_TCLR_TRGMODE_MASK (3 << 10) /* Trigger output mode mask */ #define DMT_TCLR_TRGMODE_NONE (0 << 10) /* Trigger off */ #define DMT_TCLR_TRGMODE_OVFL (1 << 10) /* Trigger on overflow */ #define DMT_TCLR_TRGMODE_BOTH (2 << 10) /* Trigger on match + ovflow */ #define DMT_TCLR_PWM_PTOGGLE (1 << 12) /* PWM toggles */ #define DMT_TCLR_CAP_MODE_2ND (1 << 13) /* Capture second event mode */ #define DMT_TCLR_GPO_CFG (1 << 14) /* (no descr in datasheet) */ #define DMT_TCRR 0x3C /* Counter Register */ #define DMT_TLDR 0x40 /* Load Reg */ #define DMT_TTGR 0x44 /* Trigger Reg */ #define DMT_TWPS 0x48 /* Write Posted Status Reg */ #define DMT_TMAR 0x4C /* Match Reg */ #define DMT_TCAR1 0x50 /* Capture Reg */ #define DMT_TSICR 0x54 /* Synchr. Interface Ctrl Reg */ #define DMT_TSICR_RESET (1 << 1) /* TSICR perform soft reset */ #define DMT_TCAR2 0x48 /* Capture Reg */ /* * Use timer 2 for the eventtimer. When PPS support is not compiled in, there's * no need to use a timer that has an associated capture-input pin, so use timer * 3 for timecounter. When PPS is compiled in we ignore the default and use * whichever of timers 4-7 have the capture pin configured. */ #define DEFAULT_ET_TIMER 2 #define DEFAULT_TC_TIMER 3 +#define DMTIMER_READ4(sc, reg) (bus_read_4((sc)->tmr_mem_res, (reg))) +#define DMTIMER_WRITE4(sc, reg, val) (bus_write_4((sc)->tmr_mem_res, (reg), (val))) + struct am335x_dmtimer_softc { - struct resource * tmr_mem_res[AM335X_NUM_TIMERS]; - struct resource * tmr_irq_res[AM335X_NUM_TIMERS]; + device_t dev; + int tmr_mem_rid; + struct resource * tmr_mem_res; + int tmr_irq_rid; + struct resource * tmr_irq_res; + void *tmr_irq_handler; uint32_t sysclk_freq; - uint32_t tc_num; /* Which timer number is tc. */ - uint32_t tc_tclr; /* Cached tc TCLR register. */ - struct resource * tc_memres; /* Resources for tc timer. */ - uint32_t et_num; /* Which timer number is et. */ - uint32_t et_tclr; /* Cached et TCLR register. */ - struct resource * et_memres; /* Resources for et timer. */ + uint32_t tclr; /* Cached TCLR register. */ int pps_curmode; /* Edge mode now set in hw. */ struct task pps_task; /* For pps_event handling. */ struct cdev * pps_cdev; struct pps_state pps; - struct timecounter tc; - struct eventtimer et; -}; -static struct am335x_dmtimer_softc *am335x_dmtimer_sc; - -static struct resource_spec am335x_dmtimer_mem_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_MEMORY, 1, RF_ACTIVE }, - { SYS_RES_MEMORY, 2, RF_ACTIVE }, - { SYS_RES_MEMORY, 3, RF_ACTIVE }, - { SYS_RES_MEMORY, 4, RF_ACTIVE }, - { SYS_RES_MEMORY, 5, RF_ACTIVE }, - { SYS_RES_MEMORY, 6, RF_ACTIVE }, - { SYS_RES_MEMORY, 7, RF_ACTIVE }, - { -1, 0, 0 } + union { + struct timecounter tc; + struct eventtimer et; + } func; }; -static struct resource_spec am335x_dmtimer_irq_spec[] = { - { SYS_RES_IRQ, 0, RF_ACTIVE }, - { SYS_RES_IRQ, 1, RF_ACTIVE }, - { SYS_RES_IRQ, 2, RF_ACTIVE }, - { SYS_RES_IRQ, 3, RF_ACTIVE }, - { SYS_RES_IRQ, 4, RF_ACTIVE }, - { SYS_RES_IRQ, 5, RF_ACTIVE }, - { SYS_RES_IRQ, 6, RF_ACTIVE }, - { SYS_RES_IRQ, 7, RF_ACTIVE }, - { -1, 0, 0 } -}; -static inline uint32_t -am335x_dmtimer_tc_read_4(struct am335x_dmtimer_softc *sc, uint32_t reg) -{ +static struct am335x_dmtimer_softc *am335x_dmtimer_et_sc = NULL; +static struct am335x_dmtimer_softc *am335x_dmtimer_tc_sc = NULL; - return (bus_read_4(sc->tc_memres, reg)); -} -static inline void -am335x_dmtimer_tc_write_4(struct am335x_dmtimer_softc *sc, uint32_t reg, - uint32_t val) -{ +#ifdef PPS_SYNC +/* -1 - not detected, 0 - not found, > 0 - timerX module */ +static int am335x_dmtimer_pps_module = -1; +static const char *am335x_dmtimer_pps_hwmod = NULL; +#endif - bus_write_4(sc->tc_memres, reg, val); -} - -static inline uint32_t -am335x_dmtimer_et_read_4(struct am335x_dmtimer_softc *sc, uint32_t reg) -{ - - return (bus_read_4(sc->et_memres, reg)); -} - -static inline void -am335x_dmtimer_et_write_4(struct am335x_dmtimer_softc *sc, uint32_t reg, - uint32_t val) -{ - - bus_write_4(sc->et_memres, reg, val); -} - /* * PPS driver routines, included when the kernel is built with option PPS_SYNC. * * Note that this PPS driver does not use an interrupt. Instead it uses the * hardware's ability to latch the timer's count register in response to a * signal on an IO pin. Each of timers 4-7 have an associated pin, and this * code allows any one of those to be used. * * The timecounter routines in kern_tc.c call the pps poll routine periodically * to see if a new counter value has been latched. When a new value has been * latched, the only processing done in the poll routine is to capture the * current set of timecounter timehands (done with pps_capture()) and the * latched value from the timer. The remaining work (done by pps_event()) is * scheduled to be done later in a non-interrupt context. */ #ifdef PPS_SYNC #define PPS_CDEV_NAME "dmtpps" static void am335x_dmtimer_set_capture_mode(struct am335x_dmtimer_softc *sc, bool force_off) { int newmode; if (force_off) newmode = 0; else newmode = sc->pps.ppsparam.mode & PPS_CAPTUREBOTH; if (newmode == sc->pps_curmode) return; sc->pps_curmode = newmode; - sc->tc_tclr &= ~DMT_TCLR_CAPTRAN_MASK; + sc->tclr &= ~DMT_TCLR_CAPTRAN_MASK; switch (newmode) { case PPS_CAPTUREASSERT: - sc->tc_tclr |= DMT_TCLR_CAPTRAN_LOHI; + sc->tclr |= DMT_TCLR_CAPTRAN_LOHI; break; case PPS_CAPTURECLEAR: - sc->tc_tclr |= DMT_TCLR_CAPTRAN_HILO; + sc->tclr |= DMT_TCLR_CAPTRAN_HILO; break; default: /* It can't be BOTH, so it's disabled. */ break; } - am335x_dmtimer_tc_write_4(sc, DMT_TCLR, sc->tc_tclr); + DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr); } static void am335x_dmtimer_tc_poll_pps(struct timecounter *tc) { struct am335x_dmtimer_softc *sc; sc = tc->tc_priv; /* * Note that we don't have the TCAR interrupt enabled, but the hardware * still provides the status bits in the "RAW" status register even when * they're masked from generating an irq. However, when clearing the * TCAR status to re-arm the capture for the next second, we have to * write to the IRQ status register, not the RAW register. Quirky. */ - if (am335x_dmtimer_tc_read_4(sc, DMT_IRQSTATUS_RAW) & DMT_IRQ_TCAR) { + if (DMTIMER_READ4(sc, DMT_IRQSTATUS_RAW) & DMT_IRQ_TCAR) { pps_capture(&sc->pps); - sc->pps.capcount = am335x_dmtimer_tc_read_4(sc, DMT_TCAR1); - am335x_dmtimer_tc_write_4(sc, DMT_IRQSTATUS, DMT_IRQ_TCAR); + sc->pps.capcount = DMTIMER_READ4(sc, DMT_TCAR1); + DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_TCAR); taskqueue_enqueue_fast(taskqueue_fast, &sc->pps_task); } } static void am335x_dmtimer_process_pps_event(void *arg, int pending) { struct am335x_dmtimer_softc *sc; sc = arg; /* This is the task function that gets enqueued by poll_pps. Once the * time has been captured in the hw interrupt context, the remaining * (more expensive) work to process the event is done later in a * non-fast-interrupt context. * * We only support capture of the rising or falling edge, not both at * once; tell the kernel to process whichever mode is currently active. */ pps_event(&sc->pps, sc->pps.ppsparam.mode & PPS_CAPTUREBOTH); } static int am335x_dmtimer_pps_open(struct cdev *dev, int flags, int fmt, struct thread *td) { struct am335x_dmtimer_softc *sc; sc = dev->si_drv1; /* Enable capture on open. Harmless if already open. */ am335x_dmtimer_set_capture_mode(sc, 0); return 0; } static int am335x_dmtimer_pps_close(struct cdev *dev, int flags, int fmt, struct thread *td) { struct am335x_dmtimer_softc *sc; sc = dev->si_drv1; /* * Disable capture on last close. Use the force-off flag to override * the configured mode and turn off the hardware capture. */ am335x_dmtimer_set_capture_mode(sc, 1); return 0; } static int am335x_dmtimer_pps_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) { struct am335x_dmtimer_softc *sc; int err; sc = dev->si_drv1; /* * The hardware has a "capture both edges" mode, but we can't do * anything useful with it in terms of PPS capture, so don't even try. */ if ((sc->pps.ppsparam.mode & PPS_CAPTUREBOTH) == PPS_CAPTUREBOTH) return (EINVAL); /* Let the kernel do the heavy lifting for ioctl. */ err = pps_ioctl(cmd, data, &sc->pps); if (err != 0) return (err); /* * The capture mode could have changed, set the hardware to whatever * mode is now current. Effectively a no-op if nothing changed. */ am335x_dmtimer_set_capture_mode(sc, 0); return (err); } static struct cdevsw am335x_dmtimer_pps_cdevsw = { .d_version = D_VERSION, .d_open = am335x_dmtimer_pps_open, .d_close = am335x_dmtimer_pps_close, .d_ioctl = am335x_dmtimer_pps_ioctl, .d_name = PPS_CDEV_NAME, }; -/* - * Set up the PPS cdev and the the kernel timepps stuff. - * - * Note that this routine cannot touch the hardware, because bus space resources - * are not fully set up yet when this is called. - */ -static int -am335x_dmtimer_pps_init(device_t dev, struct am335x_dmtimer_softc *sc) +static void +am335x_dmtimer_pps_find() { - int i, timer_num, unit; + int i; unsigned int padstate; const char * padmux; struct padinfo { char * ballname; - char * muxname; + const char * muxname; int timer_num; } padinfo[] = { {"GPMC_ADVn_ALE", "timer4", 4}, {"GPMC_BEn0_CLE", "timer5", 5}, {"GPMC_WEn", "timer6", 6}, {"GPMC_OEn_REn", "timer7", 7}, }; /* * Figure out which pin the user has set up for pps. We'll use the * first timer that has an external caputure pin configured as input. * * XXX The hieroglyphic "(padstate & (0x01 << 5)))" checks that the pin * is configured for input. The right symbolic values aren't exported * yet from ti_scm.h. */ - timer_num = 0; - for (i = 0; i < nitems(padinfo) && timer_num == 0; ++i) { - if (ti_scm_padconf_get(padinfo[i].ballname, &padmux, + am335x_dmtimer_pps_module = 0; + for (i = 0; i < nitems(padinfo) && am335x_dmtimer_pps_module == 0; ++i) { + if (ti_pinmux_padconf_get(padinfo[i].ballname, &padmux, &padstate) == 0) { if (strcasecmp(padinfo[i].muxname, padmux) == 0 && - (padstate & (0x01 << 5))) - timer_num = padinfo[i].timer_num; + (padstate & (0x01 << 5))) { + am335x_dmtimer_pps_module = padinfo[i].timer_num; + am335x_dmtimer_pps_hwmod = padinfo[i].muxname; + } } } - if (timer_num == 0) { - device_printf(dev, "No DMTimer found with capture pin " + + if (am335x_dmtimer_pps_module == 0) { + printf("am335x_dmtimer: No DMTimer found with capture pin " "configured as input; PPS driver disabled.\n"); - return (DEFAULT_TC_TIMER); } +} +/* + * Set up the PPS cdev and the the kernel timepps stuff. + * + * Note that this routine cannot touch the hardware, because bus space resources + * are not fully set up yet when this is called. + */ +static void +am335x_dmtimer_pps_init(device_t dev, struct am335x_dmtimer_softc *sc) +{ + int unit; + + if (am335x_dmtimer_pps_module == -1) + am335x_dmtimer_pps_find(); + + /* No PPS input */ + if (am335x_dmtimer_pps_module == 0) + return; + + /* Not PPS-enabled input */ + if ((am335x_dmtimer_pps_module > 0) && + (!ti_hwmods_contains(dev, am335x_dmtimer_pps_hwmod))) + return; + /* * Indicate our capabilities (pretty much just capture of either edge). * Have the kernel init its part of the pps_state struct and add its * capabilities. */ sc->pps.ppscap = PPS_CAPTUREBOTH; pps_init(&sc->pps); /* * Set up to capture the PPS via timecounter polling, and init the task * that does deferred pps_event() processing after capture. */ - sc->tc.tc_poll_pps = am335x_dmtimer_tc_poll_pps; + sc->func.tc.tc_poll_pps = am335x_dmtimer_tc_poll_pps; TASK_INIT(&sc->pps_task, 0, am335x_dmtimer_process_pps_event, sc); /* Create the PPS cdev. */ - unit = device_get_unit(dev); sc->pps_cdev = make_dev(&am335x_dmtimer_pps_cdevsw, unit, - UID_ROOT, GID_WHEEL, 0600, PPS_CDEV_NAME "%d", unit); + UID_ROOT, GID_WHEEL, 0600, PPS_CDEV_NAME); sc->pps_cdev->si_drv1 = sc; + unit = device_get_unit(sc->pps_cdev); device_printf(dev, "Using DMTimer%d for PPS device /dev/%s%d\n", - timer_num, PPS_CDEV_NAME, unit); - - return (timer_num); + am335x_dmtimer_pps_module, PPS_CDEV_NAME, unit); } -#else /* PPS_SYNC */ +#endif -static int -am335x_dmtimer_pps_init(device_t dev, struct am335x_dmtimer_softc *sc) -{ - - /* - * When PPS support is not compiled in, there's no need to use a timer - * that has an associated capture-input pin, so use the default. - */ - return (DEFAULT_TC_TIMER); -} - -#endif /* PPS_SYNC */ /* * End of PPS driver code. */ static unsigned am335x_dmtimer_tc_get_timecount(struct timecounter *tc) { struct am335x_dmtimer_softc *sc; sc = tc->tc_priv; - return (am335x_dmtimer_tc_read_4(sc, DMT_TCRR)); + return (DMTIMER_READ4(sc, DMT_TCRR)); } static int am335x_dmtimer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { struct am335x_dmtimer_softc *sc; uint32_t initial_count, reload_count; sc = et->et_priv; /* * Stop the timer before changing it. This routine will often be called * while the timer is still running, to either lengthen or shorten the * current event time. We need to ensure the timer doesn't expire while * we're working with it. * * Also clear any pending interrupt status, because it's at least * theoretically possible that we're running in a primary interrupt * context now, and a timer interrupt could be pending even before we * stopped the timer. The more likely case is that we're being called * from the et_event_cb() routine dispatched from our own handler, but * it's not clear to me that that's the only case possible. */ - sc->et_tclr &= ~(DMT_TCLR_START | DMT_TCLR_AUTOLOAD); - am335x_dmtimer_et_write_4(sc, DMT_TCLR, sc->et_tclr); - am335x_dmtimer_et_write_4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF); + sc->tclr &= ~(DMT_TCLR_START | DMT_TCLR_AUTOLOAD); + DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr); + DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF); if (period != 0) { reload_count = ((uint32_t)et->et_frequency * period) >> 32; - sc->et_tclr |= DMT_TCLR_AUTOLOAD; + sc->tclr |= DMT_TCLR_AUTOLOAD; } else { reload_count = 0; } if (first != 0) initial_count = ((uint32_t)et->et_frequency * first) >> 32; else initial_count = reload_count; /* * Set auto-reload and current-count values. This timer hardware counts * up from the initial/reload value and interrupts on the zero rollover. */ - am335x_dmtimer_et_write_4(sc, DMT_TLDR, 0xFFFFFFFF - reload_count); - am335x_dmtimer_et_write_4(sc, DMT_TCRR, 0xFFFFFFFF - initial_count); + DMTIMER_WRITE4(sc, DMT_TLDR, 0xFFFFFFFF - reload_count); + DMTIMER_WRITE4(sc, DMT_TCRR, 0xFFFFFFFF - initial_count); /* Enable overflow interrupt, and start the timer. */ - am335x_dmtimer_et_write_4(sc, DMT_IRQENABLE_SET, DMT_IRQ_OVF); - sc->et_tclr |= DMT_TCLR_START; - am335x_dmtimer_et_write_4(sc, DMT_TCLR, sc->et_tclr); + DMTIMER_WRITE4(sc, DMT_IRQENABLE_SET, DMT_IRQ_OVF); + sc->tclr |= DMT_TCLR_START; + DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr); return (0); } static int am335x_dmtimer_stop(struct eventtimer *et) { struct am335x_dmtimer_softc *sc; sc = et->et_priv; /* Stop timer, disable and clear interrupt. */ - sc->et_tclr &= ~(DMT_TCLR_START | DMT_TCLR_AUTOLOAD); - am335x_dmtimer_et_write_4(sc, DMT_TCLR, sc->et_tclr); - am335x_dmtimer_et_write_4(sc, DMT_IRQENABLE_CLR, DMT_IRQ_OVF); - am335x_dmtimer_et_write_4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF); + sc->tclr &= ~(DMT_TCLR_START | DMT_TCLR_AUTOLOAD); + DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr); + DMTIMER_WRITE4(sc, DMT_IRQENABLE_CLR, DMT_IRQ_OVF); + DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF); return (0); } static int am335x_dmtimer_intr(void *arg) { struct am335x_dmtimer_softc *sc; sc = arg; /* Ack the interrupt, and invoke the callback if it's still enabled. */ - am335x_dmtimer_et_write_4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF); - if (sc->et.et_active) - sc->et.et_event_cb(&sc->et, sc->et.et_arg); + DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_OVF); + if (sc->func.et.et_active) + sc->func.et.et_event_cb(&sc->func.et, sc->func.et.et_arg); return (FILTER_HANDLED); } +/* + * Checks if timer is suitable to be system timer + */ static int +am335x_dmtimer_system_compatible(device_t dev) +{ + phandle_t node; + + node = ofw_bus_get_node(dev); + if (OF_hasprop(node, "ti,timer-alwon")) + return (0); + + return (1); +} + +static int +am335x_dmtimer_init_et(struct am335x_dmtimer_softc *sc) +{ + if (am335x_dmtimer_et_sc != NULL) + return (EEXIST); + +#ifdef PPS_SYNC + if ((am335x_dmtimer_pps_module > 0) && + (!ti_hwmods_contains(sc->dev, am335x_dmtimer_pps_hwmod))) { + device_printf(sc->dev, "not PPS enabled\n"); + return (ENXIO); + } +#endif + + /* Setup eventtimer interrupt handler. */ + if (bus_setup_intr(sc->dev, sc->tmr_irq_res, INTR_TYPE_CLK, + am335x_dmtimer_intr, NULL, sc, &sc->tmr_irq_handler) != 0) { + device_printf(sc->dev, "Unable to setup the clock irq handler.\n"); + return (ENXIO); + } + + sc->func.et.et_name = "AM335x Eventtimer"; + sc->func.et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; + sc->func.et.et_quality = 1000; + sc->func.et.et_frequency = sc->sysclk_freq; + sc->func.et.et_min_period = + ((0x00000005LLU << 32) / sc->func.et.et_frequency); + sc->func.et.et_max_period = + (0xfffffffeLLU << 32) / sc->func.et.et_frequency; + sc->func.et.et_start = am335x_dmtimer_start; + sc->func.et.et_stop = am335x_dmtimer_stop; + sc->func.et.et_priv = sc; + et_register(&sc->func.et); + + am335x_dmtimer_et_sc = sc; + + return (0); +} + +static int +am335x_dmtimer_init_tc(struct am335x_dmtimer_softc *sc) +{ + if (am335x_dmtimer_tc_sc != NULL) + return (EEXIST); + + /* Set up timecounter, start it, register it. */ + DMTIMER_WRITE4(sc, DMT_TSICR, DMT_TSICR_RESET); + while (DMTIMER_READ4(sc, DMT_TIOCP_CFG) & DMT_TIOCP_RESET) + continue; + + sc->tclr |= DMT_TCLR_START | DMT_TCLR_AUTOLOAD; + DMTIMER_WRITE4(sc, DMT_TLDR, 0); + DMTIMER_WRITE4(sc, DMT_TCRR, 0); + DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr); + + sc->func.tc.tc_name = "AM335x Timecounter"; + sc->func.tc.tc_get_timecount = am335x_dmtimer_tc_get_timecount; + sc->func.tc.tc_counter_mask = ~0u; + sc->func.tc.tc_frequency = sc->sysclk_freq; + sc->func.tc.tc_quality = 1000; + sc->func.tc.tc_priv = sc; + tc_init(&sc->func.tc); + + am335x_dmtimer_tc_sc = sc; + + return (0); +} + +static int am335x_dmtimer_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (ofw_bus_is_compatible(dev, "ti,am335x-dmtimer")) { + if (ofw_bus_is_compatible(dev, "ti,am335x-timer-1ms") || + ofw_bus_is_compatible(dev, "ti,am335x-timer")) { device_set_desc(dev, "AM335x DMTimer"); return(BUS_PROBE_DEFAULT); } return (ENXIO); } static int am335x_dmtimer_attach(device_t dev) { struct am335x_dmtimer_softc *sc; - void *ihl; int err; + clk_ident_t timer_id; + int enable; /* * Note that if this routine returns an error status rather than running * to completion it makes no attempt to clean up allocated resources; * the system is essentially dead anyway without functional timers. */ sc = device_get_softc(dev); + sc->dev = dev; - if (am335x_dmtimer_sc != NULL) - return (EINVAL); - /* Get the base clock frequency. */ err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq); if (err) { device_printf(dev, "Error: could not get sysclk frequency\n"); return (ENXIO); } /* Request the memory resources. */ - err = bus_alloc_resources(dev, am335x_dmtimer_mem_spec, - sc->tmr_mem_res); - if (err) { + sc->tmr_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->tmr_mem_rid, RF_ACTIVE); + if (sc->tmr_mem_res == NULL) { device_printf(dev, "Error: could not allocate mem resources\n"); return (ENXIO); } /* Request the IRQ resources. */ - err = bus_alloc_resources(dev, am335x_dmtimer_irq_spec, - sc->tmr_irq_res); + sc->tmr_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->tmr_irq_rid, RF_ACTIVE); if (err) { + bus_release_resource(dev, SYS_RES_MEMORY, sc->tmr_mem_rid, + sc->tmr_mem_res); device_printf(dev, "Error: could not allocate irq resources\n"); return (ENXIO); } - /* - * Use the default eventtimer. Let the PPS init routine decide which - * timer to use for the timecounter. - */ - sc->et_num = DEFAULT_ET_TIMER; - sc->tc_num = am335x_dmtimer_pps_init(dev, sc); +#ifdef PPS_SYNC + am335x_dmtimer_pps_init(dev, sc); +#endif - sc->et_memres = sc->tmr_mem_res[sc->et_num]; - sc->tc_memres = sc->tmr_mem_res[sc->tc_num]; - - /* Enable clocks and power on the chosen devices. */ - err = ti_prcm_clk_set_source(DMTIMER0_CLK + sc->et_num, SYSCLK_CLK); - err |= ti_prcm_clk_enable(DMTIMER0_CLK + sc->et_num); - err |= ti_prcm_clk_set_source(DMTIMER0_CLK + sc->tc_num, SYSCLK_CLK); - err |= ti_prcm_clk_enable(DMTIMER0_CLK + sc->tc_num); - if (err) { - device_printf(dev, "Error: could not enable timer clock\n"); - return (ENXIO); + enable = 0; + /* Try to use as a timecounter or event timer */ + if (am335x_dmtimer_system_compatible(dev)) { + if (am335x_dmtimer_init_tc(sc) == 0) + enable = 1; + else if (am335x_dmtimer_init_et(sc) == 0) + enable = 1; } - /* Setup eventtimer interrupt handler. */ - if (bus_setup_intr(dev, sc->tmr_irq_res[sc->et_num], INTR_TYPE_CLK, - am335x_dmtimer_intr, NULL, sc, &ihl) != 0) { - device_printf(dev, "Unable to setup the clock irq handler.\n"); - return (ENXIO); - } + if (enable) { + /* Enable clocks and power on the chosen devices. */ + timer_id = ti_hwmods_get_clock(dev); + if (timer_id == INVALID_CLK_IDENT) { + bus_release_resource(dev, SYS_RES_MEMORY, sc->tmr_mem_rid, + sc->tmr_mem_res); + bus_release_resource(dev, SYS_RES_IRQ, sc->tmr_irq_rid, + sc->tmr_irq_res); + device_printf(dev, "failed to get device id using ti,hwmods\n"); + return (ENXIO); + } - /* Set up timecounter, start it, register it. */ - am335x_dmtimer_tc_write_4(sc, DMT_TSICR, DMT_TSICR_RESET); - while (am335x_dmtimer_tc_read_4(sc, DMT_TIOCP_CFG) & DMT_TIOCP_RESET) - continue; + err = ti_prcm_clk_set_source(timer_id, SYSCLK_CLK); + err |= ti_prcm_clk_enable(timer_id); - sc->tc_tclr |= DMT_TCLR_START | DMT_TCLR_AUTOLOAD; - am335x_dmtimer_tc_write_4(sc, DMT_TLDR, 0); - am335x_dmtimer_tc_write_4(sc, DMT_TCRR, 0); - am335x_dmtimer_tc_write_4(sc, DMT_TCLR, sc->tc_tclr); + if (err) { + bus_release_resource(dev, SYS_RES_MEMORY, sc->tmr_mem_rid, + sc->tmr_mem_res); + bus_release_resource(dev, SYS_RES_IRQ, sc->tmr_irq_rid, + sc->tmr_irq_res); + device_printf(dev, "Error: could not enable timer clock\n"); + return (ENXIO); + } + } - sc->tc.tc_name = "AM335x Timecounter"; - sc->tc.tc_get_timecount = am335x_dmtimer_tc_get_timecount; - sc->tc.tc_counter_mask = ~0u; - sc->tc.tc_frequency = sc->sysclk_freq; - sc->tc.tc_quality = 1000; - sc->tc.tc_priv = sc; - tc_init(&sc->tc); - - sc->et.et_name = "AM335x Eventtimer"; - sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT; - sc->et.et_quality = 1000; - sc->et.et_frequency = sc->sysclk_freq; - sc->et.et_min_period = - ((0x00000005LLU << 32) / sc->et.et_frequency); - sc->et.et_max_period = - (0xfffffffeLLU << 32) / sc->et.et_frequency; - sc->et.et_start = am335x_dmtimer_start; - sc->et.et_stop = am335x_dmtimer_stop; - sc->et.et_priv = sc; - et_register(&sc->et); - - /* Store a pointer to the softc for use in DELAY(). */ - am335x_dmtimer_sc = sc; - return (0); } static device_method_t am335x_dmtimer_methods[] = { DEVMETHOD(device_probe, am335x_dmtimer_probe), DEVMETHOD(device_attach, am335x_dmtimer_attach), { 0, 0 } }; static driver_t am335x_dmtimer_driver = { "am335x_dmtimer", am335x_dmtimer_methods, sizeof(struct am335x_dmtimer_softc), }; static devclass_t am335x_dmtimer_devclass; DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0); MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1); void DELAY(int usec) { struct am335x_dmtimer_softc *sc; int32_t counts; uint32_t first, last; - sc = am335x_dmtimer_sc; + sc = am335x_dmtimer_tc_sc; if (sc == NULL) { for (; usec > 0; usec--) for (counts = 200; counts > 0; counts--) /* Prevent gcc from optimizing out the loop */ cpufunc_nullop(); return; } /* Get the number of times to count */ counts = (usec + 1) * (sc->sysclk_freq / 1000000); - first = am335x_dmtimer_tc_read_4(sc, DMT_TCRR); + first = DMTIMER_READ4(sc, DMT_TCRR); while (counts > 0) { - last = am335x_dmtimer_tc_read_4(sc, DMT_TCRR); + last = DMTIMER_READ4(sc, DMT_TCRR); if (last > first) { counts -= (int32_t)(last - first); } else { counts -= (int32_t)((0xFFFFFFFF - first) + last); } first = last; } } Index: head/sys/arm/ti/am335x/am335x_ecap.c =================================================================== --- head/sys/arm/ti/am335x/am335x_ecap.c (nonexistent) +++ head/sys/arm/ti/am335x/am335x_ecap.c (revision 283276) @@ -0,0 +1,201 @@ +/*- + * Copyright (c) 2013 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "am335x_pwm.h" + +#define ECAP_TSCTR 0x00 +#define ECAP_CAP1 0x08 +#define ECAP_CAP2 0x0C +#define ECAP_CAP3 0x10 +#define ECAP_CAP4 0x14 +#define ECAP_ECCTL2 0x2A +#define ECCTL2_MODE_APWM (1 << 9) +#define ECCTL2_SYNCO_SEL (3 << 6) +#define ECCTL2_TSCTRSTOP_FREERUN (1 << 4) + +#define ECAP_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg); +#define ECAP_WRITE2(_sc, reg, value) \ + bus_write_2((_sc)->sc_mem_res, reg, value); +#define ECAP_READ4(_sc, reg) bus_read_4((_sc)->sc_mem_res, reg); +#define ECAP_WRITE4(_sc, reg, value) \ + bus_write_4((_sc)->sc_mem_res, reg, value); + +#define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ + device_get_nameunit(_sc->sc_dev), "am335x_ecap softc", MTX_DEF) +#define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) + +static device_probe_t am335x_ecap_probe; +static device_attach_t am335x_ecap_attach; +static device_detach_t am335x_ecap_detach; + +struct am335x_ecap_softc { + device_t sc_dev; + struct mtx sc_mtx; + struct resource *sc_mem_res; + int sc_mem_rid; +}; + +static device_method_t am335x_ecap_methods[] = { + DEVMETHOD(device_probe, am335x_ecap_probe), + DEVMETHOD(device_attach, am335x_ecap_attach), + DEVMETHOD(device_detach, am335x_ecap_detach), + + DEVMETHOD_END +}; + +static driver_t am335x_ecap_driver = { + "am335x_ecap", + am335x_ecap_methods, + sizeof(struct am335x_ecap_softc), +}; + +static devclass_t am335x_ecap_devclass; + +/* + * API function to set period/duty cycles for ECAPx + */ +int +am335x_pwm_config_ecap(int unit, int period, int duty) +{ + device_t dev; + struct am335x_ecap_softc *sc; + uint16_t reg; + + dev = devclass_get_device(am335x_ecap_devclass, unit); + if (dev == NULL) + return (ENXIO); + + if (duty > period) + return (EINVAL); + + if (period == 0) + return (EINVAL); + + sc = device_get_softc(dev); + PWM_LOCK(sc); + + reg = ECAP_READ2(sc, ECAP_ECCTL2); + reg |= ECCTL2_MODE_APWM | ECCTL2_TSCTRSTOP_FREERUN | ECCTL2_SYNCO_SEL; + ECAP_WRITE2(sc, ECAP_ECCTL2, reg); + + /* CAP3 in APWM mode is APRD shadow register */ + ECAP_WRITE4(sc, ECAP_CAP3, period - 1); + + /* CAP4 in APWM mode is ACMP shadow register */ + ECAP_WRITE4(sc, ECAP_CAP4, duty); + /* Restart counter */ + ECAP_WRITE4(sc, ECAP_TSCTR, 0); + + PWM_UNLOCK(sc); + + return (0); +} + +static int +am335x_ecap_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ti,am33xx-ecap")) + return (ENXIO); + + device_set_desc(dev, "AM335x eCAP"); + + return (BUS_PROBE_DEFAULT); +} + +static int +am335x_ecap_attach(device_t dev) +{ + struct am335x_ecap_softc *sc; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + PWM_LOCK_INIT(sc); + + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->sc_mem_rid, RF_ACTIVE); + if (sc->sc_mem_res == NULL) { + device_printf(dev, "cannot allocate memory resources\n"); + goto fail; + } + + return (0); + +fail: + PWM_LOCK_DESTROY(sc); + return (ENXIO); +} + +static int +am335x_ecap_detach(device_t dev) +{ + struct am335x_ecap_softc *sc; + + sc = device_get_softc(dev); + + PWM_LOCK(sc); + if (sc->sc_mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, + sc->sc_mem_rid, sc->sc_mem_res); + PWM_UNLOCK(sc); + + PWM_LOCK_DESTROY(sc); + + + return (0); +} + +DRIVER_MODULE(am335x_ecap, am335x_pwmss, am335x_ecap_driver, am335x_ecap_devclass, 0, 0); +MODULE_VERSION(am335x_ecap, 1); +MODULE_DEPEND(am335x_ecap, am335x_pwmss, 1, 1, 1); Property changes on: head/sys/arm/ti/am335x/am335x_ecap.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/am335x/am335x_ehrpwm.c =================================================================== --- head/sys/arm/ti/am335x/am335x_ehrpwm.c (nonexistent) +++ head/sys/arm/ti/am335x/am335x_ehrpwm.c (revision 283276) @@ -0,0 +1,448 @@ +/*- + * Copyright (c) 2013 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "am335x_pwm.h" + +/* In ticks */ +#define DEFAULT_PWM_PERIOD 1000 +#define PWM_CLOCK 100000000UL + +#define PWM_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define PWM_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define PWM_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ + device_get_nameunit(_sc->sc_dev), "am335x_ehrpwm softc", MTX_DEF) +#define PWM_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) + +#define EPWM_READ2(_sc, reg) bus_read_2((_sc)->sc_mem_res, reg); +#define EPWM_WRITE2(_sc, reg, value) \ + bus_write_2((_sc)->sc_mem_res, reg, value); + +#define EPWM_TBCTL 0x00 +#define TBCTL_FREERUN (2 << 14) +#define TBCTL_PHDIR_UP (1 << 13) +#define TBCTL_PHDIR_DOWN (0 << 13) +#define TBCTL_CLKDIV(x) ((x) << 10) +#define TBCTL_CLKDIV_MASK (3 << 10) +#define TBCTL_HSPCLKDIV(x) ((x) << 7) +#define TBCTL_HSPCLKDIV_MASK (3 << 7) +#define TBCTL_SYNCOSEL_DISABLED (3 << 4) +#define TBCTL_PRDLD_SHADOW (0 << 3) +#define TBCTL_PRDLD_IMMEDIATE (0 << 3) +#define TBCTL_PHSEN_ENABLED (1 << 2) +#define TBCTL_PHSEN_DISABLED (0 << 2) +#define TBCTL_CTRMODE_MASK (3) +#define TBCTL_CTRMODE_UP (0 << 0) +#define TBCTL_CTRMODE_DOWN (1 << 0) +#define TBCTL_CTRMODE_UPDOWN (2 << 0) +#define TBCTL_CTRMODE_FREEZE (3 << 0) + +#define EPWM_TBSTS 0x02 +#define EPWM_TBPHSHR 0x04 +#define EPWM_TBPHS 0x06 +#define EPWM_TBCNT 0x08 +#define EPWM_TBPRD 0x0a +/* Counter-compare */ +#define EPWM_CMPCTL 0x0e +#define CMPCTL_SHDWBMODE_SHADOW (1 << 6) +#define CMPCTL_SHDWBMODE_IMMEDIATE (0 << 6) +#define CMPCTL_SHDWAMODE_SHADOW (1 << 4) +#define CMPCTL_SHDWAMODE_IMMEDIATE (0 << 4) +#define CMPCTL_LOADBMODE_ZERO (0 << 2) +#define CMPCTL_LOADBMODE_PRD (1 << 2) +#define CMPCTL_LOADBMODE_EITHER (2 << 2) +#define CMPCTL_LOADBMODE_FREEZE (3 << 2) +#define CMPCTL_LOADAMODE_ZERO (0 << 0) +#define CMPCTL_LOADAMODE_PRD (1 << 0) +#define CMPCTL_LOADAMODE_EITHER (2 << 0) +#define CMPCTL_LOADAMODE_FREEZE (3 << 0) +#define EPWM_CMPAHR 0x10 +#define EPWM_CMPA 0x12 +#define EPWM_CMPB 0x14 +/* CMPCTL_LOADAMODE_ZERO */ +#define EPWM_AQCTLA 0x16 +#define EPWM_AQCTLB 0x18 +#define AQCTL_CBU_NONE (0 << 8) +#define AQCTL_CBU_CLEAR (1 << 8) +#define AQCTL_CBU_SET (2 << 8) +#define AQCTL_CBU_TOGGLE (3 << 8) +#define AQCTL_CAU_NONE (0 << 4) +#define AQCTL_CAU_CLEAR (1 << 4) +#define AQCTL_CAU_SET (2 << 4) +#define AQCTL_CAU_TOGGLE (3 << 4) +#define AQCTL_ZRO_NONE (0 << 0) +#define AQCTL_ZRO_CLEAR (1 << 0) +#define AQCTL_ZRO_SET (2 << 0) +#define AQCTL_ZRO_TOGGLE (3 << 0) +#define EPWM_AQSFRC 0x1a +#define EPWM_AQCSFRC 0x1c + +/* Trip-Zone module */ +#define EPWM_TZCTL 0x28 +#define EPWM_TZFLG 0x2C +/* High-Resolution PWM */ +#define EPWM_HRCTL 0x40 +#define HRCTL_DELMODE_BOTH 3 +#define HRCTL_DELMODE_FALL 2 +#define HRCTL_DELMODE_RISE 1 + +static device_probe_t am335x_ehrpwm_probe; +static device_attach_t am335x_ehrpwm_attach; +static device_detach_t am335x_ehrpwm_detach; + +static int am335x_ehrpwm_clkdiv[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +struct am335x_ehrpwm_softc { + device_t sc_dev; + struct mtx sc_mtx; + struct resource *sc_mem_res; + int sc_mem_rid; + /* sysctl for configuration */ + int sc_pwm_clkdiv; + int sc_pwm_freq; + struct sysctl_oid *sc_clkdiv_oid; + struct sysctl_oid *sc_freq_oid; + struct sysctl_oid *sc_period_oid; + struct sysctl_oid *sc_chanA_oid; + struct sysctl_oid *sc_chanB_oid; + uint32_t sc_pwm_period; + uint32_t sc_pwm_dutyA; + uint32_t sc_pwm_dutyB; +}; + +static device_method_t am335x_ehrpwm_methods[] = { + DEVMETHOD(device_probe, am335x_ehrpwm_probe), + DEVMETHOD(device_attach, am335x_ehrpwm_attach), + DEVMETHOD(device_detach, am335x_ehrpwm_detach), + + DEVMETHOD_END +}; + +static driver_t am335x_ehrpwm_driver = { + "am335x_ehrpwm", + am335x_ehrpwm_methods, + sizeof(struct am335x_ehrpwm_softc), +}; + +static devclass_t am335x_ehrpwm_devclass; + +static void +am335x_ehrpwm_freq(struct am335x_ehrpwm_softc *sc) +{ + int clkdiv; + + clkdiv = am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]; + sc->sc_pwm_freq = PWM_CLOCK / (1 * clkdiv) / sc->sc_pwm_period; +} + +static int +am335x_ehrpwm_sysctl_freq(SYSCTL_HANDLER_ARGS) +{ + int clkdiv, error, freq, i, period; + struct am335x_ehrpwm_softc *sc; + uint32_t reg; + + sc = (struct am335x_ehrpwm_softc *)arg1; + + PWM_LOCK(sc); + freq = sc->sc_pwm_freq; + PWM_UNLOCK(sc); + + error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); + if (error != 0 || req->newptr == NULL) + return (error); + + if (freq > PWM_CLOCK) + freq = PWM_CLOCK; + + PWM_LOCK(sc); + if (freq != sc->sc_pwm_freq) { + for (i = nitems(am335x_ehrpwm_clkdiv) - 1; i >= 0; i--) { + clkdiv = am335x_ehrpwm_clkdiv[i]; + period = PWM_CLOCK / clkdiv / freq; + if (period > USHRT_MAX) + break; + sc->sc_pwm_clkdiv = i; + sc->sc_pwm_period = period; + } + /* Reset the duty cycle settings. */ + sc->sc_pwm_dutyA = 0; + sc->sc_pwm_dutyB = 0; + EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); + EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); + /* Update the clkdiv settings. */ + reg = EPWM_READ2(sc, EPWM_TBCTL); + reg &= ~TBCTL_CLKDIV_MASK; + reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv); + EPWM_WRITE2(sc, EPWM_TBCTL, reg); + /* Update the period settings. */ + EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1); + am335x_ehrpwm_freq(sc); + } + PWM_UNLOCK(sc); + + return (0); +} + +static int +am335x_ehrpwm_sysctl_clkdiv(SYSCTL_HANDLER_ARGS) +{ + int error, i, clkdiv; + struct am335x_ehrpwm_softc *sc; + uint32_t reg; + + sc = (struct am335x_ehrpwm_softc *)arg1; + + PWM_LOCK(sc); + clkdiv = am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]; + PWM_UNLOCK(sc); + + error = sysctl_handle_int(oidp, &clkdiv, sizeof(clkdiv), req); + if (error != 0 || req->newptr == NULL) + return (error); + + PWM_LOCK(sc); + if (clkdiv != am335x_ehrpwm_clkdiv[sc->sc_pwm_clkdiv]) { + for (i = 0; i < nitems(am335x_ehrpwm_clkdiv); i++) + if (clkdiv >= am335x_ehrpwm_clkdiv[i]) + sc->sc_pwm_clkdiv = i; + + reg = EPWM_READ2(sc, EPWM_TBCTL); + reg &= ~TBCTL_CLKDIV_MASK; + reg |= TBCTL_CLKDIV(sc->sc_pwm_clkdiv); + EPWM_WRITE2(sc, EPWM_TBCTL, reg); + am335x_ehrpwm_freq(sc); + } + PWM_UNLOCK(sc); + + return (0); +} + +static int +am335x_ehrpwm_sysctl_duty(SYSCTL_HANDLER_ARGS) +{ + struct am335x_ehrpwm_softc *sc = (struct am335x_ehrpwm_softc*)arg1; + int error; + uint32_t duty; + + if (oidp == sc->sc_chanA_oid) + duty = sc->sc_pwm_dutyA; + else + duty = sc->sc_pwm_dutyB; + error = sysctl_handle_int(oidp, &duty, 0, req); + + if (error != 0 || req->newptr == NULL) + return (error); + + if (duty > sc->sc_pwm_period) { + device_printf(sc->sc_dev, "Duty cycle can't be greater then period\n"); + return (EINVAL); + } + + PWM_LOCK(sc); + if (oidp == sc->sc_chanA_oid) { + sc->sc_pwm_dutyA = duty; + EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); + } + else { + sc->sc_pwm_dutyB = duty; + EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); + } + PWM_UNLOCK(sc); + + return (error); +} + +static int +am335x_ehrpwm_sysctl_period(SYSCTL_HANDLER_ARGS) +{ + struct am335x_ehrpwm_softc *sc = (struct am335x_ehrpwm_softc*)arg1; + int error; + uint32_t period; + + period = sc->sc_pwm_period; + error = sysctl_handle_int(oidp, &period, 0, req); + + if (error != 0 || req->newptr == NULL) + return (error); + + if (period < 1) + return (EINVAL); + + if (period > USHRT_MAX) + period = USHRT_MAX; + + PWM_LOCK(sc); + /* Reset the duty cycle settings. */ + sc->sc_pwm_dutyA = 0; + sc->sc_pwm_dutyB = 0; + EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); + EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); + /* Update the period settings. */ + sc->sc_pwm_period = period; + EPWM_WRITE2(sc, EPWM_TBPRD, period - 1); + am335x_ehrpwm_freq(sc); + PWM_UNLOCK(sc); + + return (error); +} + +static int +am335x_ehrpwm_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ti,am33xx-ehrpwm")) + return (ENXIO); + + device_set_desc(dev, "AM335x EHRPWM"); + + return (BUS_PROBE_DEFAULT); +} + +static int +am335x_ehrpwm_attach(device_t dev) +{ + struct am335x_ehrpwm_softc *sc; + uint32_t reg; + struct sysctl_ctx_list *ctx; + struct sysctl_oid *tree; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + PWM_LOCK_INIT(sc); + + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->sc_mem_rid, RF_ACTIVE); + if (sc->sc_mem_res == NULL) { + device_printf(dev, "cannot allocate memory resources\n"); + goto fail; + } + + /* Init backlight interface */ + ctx = device_get_sysctl_ctx(sc->sc_dev); + tree = device_get_sysctl_tree(sc->sc_dev); + + sc->sc_clkdiv_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "clkdiv", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + am335x_ehrpwm_sysctl_clkdiv, "I", "PWM clock prescaler"); + + sc->sc_freq_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + am335x_ehrpwm_sysctl_freq, "I", "PWM frequency"); + + sc->sc_period_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "period", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + am335x_ehrpwm_sysctl_period, "I", "PWM period"); + + sc->sc_chanA_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "dutyA", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + am335x_ehrpwm_sysctl_duty, "I", "Channel A duty cycles"); + + sc->sc_chanB_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "dutyB", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + am335x_ehrpwm_sysctl_duty, "I", "Channel B duty cycles"); + + /* CONFIGURE EPWM1 */ + reg = EPWM_READ2(sc, EPWM_TBCTL); + reg &= ~(TBCTL_CLKDIV_MASK | TBCTL_HSPCLKDIV_MASK); + EPWM_WRITE2(sc, EPWM_TBCTL, reg); + + sc->sc_pwm_period = DEFAULT_PWM_PERIOD; + sc->sc_pwm_dutyA = 0; + sc->sc_pwm_dutyB = 0; + am335x_ehrpwm_freq(sc); + + EPWM_WRITE2(sc, EPWM_TBPRD, sc->sc_pwm_period - 1); + EPWM_WRITE2(sc, EPWM_CMPA, sc->sc_pwm_dutyA); + EPWM_WRITE2(sc, EPWM_CMPB, sc->sc_pwm_dutyB); + + EPWM_WRITE2(sc, EPWM_AQCTLA, (AQCTL_ZRO_SET | AQCTL_CAU_CLEAR)); + EPWM_WRITE2(sc, EPWM_AQCTLB, (AQCTL_ZRO_SET | AQCTL_CBU_CLEAR)); + + /* START EPWM */ + reg &= ~TBCTL_CTRMODE_MASK; + reg |= TBCTL_CTRMODE_UP | TBCTL_FREERUN; + EPWM_WRITE2(sc, EPWM_TBCTL, reg); + + EPWM_WRITE2(sc, EPWM_TZCTL, 0xf); + reg = EPWM_READ2(sc, EPWM_TZFLG); + + return (0); +fail: + PWM_LOCK_DESTROY(sc); + if (sc->sc_mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, + sc->sc_mem_rid, sc->sc_mem_res); + + return(ENXIO); +} + +static int +am335x_ehrpwm_detach(device_t dev) +{ + struct am335x_ehrpwm_softc *sc; + + sc = device_get_softc(dev); + + PWM_LOCK(sc); + if (sc->sc_mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, + sc->sc_mem_rid, sc->sc_mem_res); + PWM_UNLOCK(sc); + + PWM_LOCK_DESTROY(sc); + + return (0); +} + +DRIVER_MODULE(am335x_ehrpwm, am335x_pwmss, am335x_ehrpwm_driver, am335x_ehrpwm_devclass, 0, 0); +MODULE_VERSION(am335x_ehrpwm, 1); +MODULE_DEPEND(am335x_ehrpwm, am335x_pwmss, 1, 1, 1); Property changes on: head/sys/arm/ti/am335x/am335x_ehrpwm.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/am335x/am335x_gpio.c =================================================================== --- head/sys/arm/ti/am335x/am335x_gpio.c (revision 283275) +++ head/sys/arm/ti/am335x/am335x_gpio.c (revision 283276) @@ -1,156 +1,159 @@ /*- * Copyright (c) 2012 Damjan Marion * Copyright (c) 2014 Andrew Turner * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "ti_gpio_if.h" static struct ofw_compat_data compat_data[] = { {"ti,am335x-gpio", 1}, /* Linux uses ti,omap4-gpio on am335x so we need to support it */ {"ti,omap4-gpio", 1}, {"ti,gpio", 1}, {NULL, 0}, }; static int am335x_gpio_probe(device_t dev) { if (ti_chip() != CHIP_AM335X) return (ENXIO); if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Ti AM335x General Purpose I/O (GPIO)"); return (0); } static int am335x_gpio_set_flags(device_t dev, uint32_t gpio, uint32_t flags) { unsigned int state = 0; + struct ti_gpio_softc *sc = device_get_softc(dev); + if (flags & GPIO_PIN_OUTPUT) { if (flags & GPIO_PIN_PULLUP) state = PADCONF_OUTPUT_PULLUP; else state = PADCONF_OUTPUT; } else if (flags & GPIO_PIN_INPUT) { if (flags & GPIO_PIN_PULLUP) state = PADCONF_INPUT_PULLUP; else if (flags & GPIO_PIN_PULLDOWN) state = PADCONF_INPUT_PULLDOWN; else state = PADCONF_INPUT; } - return ti_scm_padconf_set_gpiomode(gpio, state); + return ti_pinmux_padconf_set_gpiomode(sc->sc_bank*32 + gpio, state); } static int am335x_gpio_get_flags(device_t dev, uint32_t gpio, uint32_t *flags) { unsigned int state; + struct ti_gpio_softc *sc = device_get_softc(dev); - if (ti_scm_padconf_get_gpiomode(gpio, &state) != 0) { + if (ti_pinmux_padconf_get_gpiomode(sc->sc_bank*32 + gpio, &state) != 0) { *flags = 0; return (EINVAL); } else { switch (state) { case PADCONF_OUTPUT: *flags = GPIO_PIN_OUTPUT; break; case PADCONF_OUTPUT_PULLUP: *flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP; break; case PADCONF_INPUT: *flags = GPIO_PIN_INPUT; break; case PADCONF_INPUT_PULLUP: *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP; break; case PADCONF_INPUT_PULLDOWN: *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLDOWN; break; default: *flags = 0; break; } } return (0); } static device_method_t am335x_gpio_methods[] = { /* bus interface */ DEVMETHOD(device_probe, am335x_gpio_probe), /* ti_gpio interface */ DEVMETHOD(ti_gpio_set_flags, am335x_gpio_set_flags), DEVMETHOD(ti_gpio_get_flags, am335x_gpio_get_flags), DEVMETHOD_END }; extern driver_t ti_gpio_driver; static devclass_t am335x_gpio_devclass; DEFINE_CLASS_1(gpio, am335x_gpio_driver, am335x_gpio_methods, sizeof(struct ti_gpio_softc), ti_gpio_driver); DRIVER_MODULE(am335x_gpio, simplebus, am335x_gpio_driver, am335x_gpio_devclass, 0, 0); Index: head/sys/arm/ti/am335x/am335x_lcd.c =================================================================== --- head/sys/arm/ti/am335x/am335x_lcd.c (revision 283275) +++ head/sys/arm/ti/am335x/am335x_lcd.c (revision 283276) @@ -1,759 +1,808 @@ /*- * Copyright 2013 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "opt_syscons.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEV_SC #include #else /* VT */ #include #endif #include #include #include "am335x_lcd.h" #include "am335x_pwm.h" #include "fb_if.h" #define LCD_PID 0x00 #define LCD_CTRL 0x04 #define CTRL_DIV_MASK 0xff #define CTRL_DIV_SHIFT 8 #define CTRL_AUTO_UFLOW_RESTART (1 << 1) #define CTRL_RASTER_MODE 1 #define CTRL_LIDD_MODE 0 #define LCD_LIDD_CTRL 0x0C #define LCD_LIDD_CS0_CONF 0x10 #define LCD_LIDD_CS0_ADDR 0x14 #define LCD_LIDD_CS0_DATA 0x18 #define LCD_LIDD_CS1_CONF 0x1C #define LCD_LIDD_CS1_ADDR 0x20 #define LCD_LIDD_CS1_DATA 0x24 #define LCD_RASTER_CTRL 0x28 #define RASTER_CTRL_TFT24_UNPACKED (1 << 26) #define RASTER_CTRL_TFT24 (1 << 25) #define RASTER_CTRL_STN565 (1 << 24) #define RASTER_CTRL_TFTPMAP (1 << 23) #define RASTER_CTRL_NIBMODE (1 << 22) #define RASTER_CTRL_PALMODE_SHIFT 20 #define PALETTE_PALETTE_AND_DATA 0x00 #define PALETTE_PALETTE_ONLY 0x01 #define PALETTE_DATA_ONLY 0x02 #define RASTER_CTRL_REQDLY_SHIFT 12 #define RASTER_CTRL_MONO8B (1 << 9) #define RASTER_CTRL_RBORDER (1 << 8) #define RASTER_CTRL_LCDTFT (1 << 7) #define RASTER_CTRL_LCDBW (1 << 1) #define RASTER_CTRL_LCDEN (1 << 0) #define LCD_RASTER_TIMING_0 0x2C #define RASTER_TIMING_0_HBP_SHIFT 24 #define RASTER_TIMING_0_HFP_SHIFT 16 #define RASTER_TIMING_0_HSW_SHIFT 10 #define RASTER_TIMING_0_PPLLSB_SHIFT 4 #define RASTER_TIMING_0_PPLMSB_SHIFT 3 #define LCD_RASTER_TIMING_1 0x30 #define RASTER_TIMING_1_VBP_SHIFT 24 #define RASTER_TIMING_1_VFP_SHIFT 16 #define RASTER_TIMING_1_VSW_SHIFT 10 #define RASTER_TIMING_1_LPP_SHIFT 0 #define LCD_RASTER_TIMING_2 0x34 #define RASTER_TIMING_2_HSWHI_SHIFT 27 #define RASTER_TIMING_2_LPP_B10_SHIFT 26 #define RASTER_TIMING_2_PHSVS (1 << 25) #define RASTER_TIMING_2_PHSVS_RISE (1 << 24) #define RASTER_TIMING_2_PHSVS_FALL (0 << 24) #define RASTER_TIMING_2_IOE (1 << 23) #define RASTER_TIMING_2_IPC (1 << 22) #define RASTER_TIMING_2_IHS (1 << 21) #define RASTER_TIMING_2_IVS (1 << 20) #define RASTER_TIMING_2_ACBI_SHIFT 16 #define RASTER_TIMING_2_ACB_SHIFT 8 #define RASTER_TIMING_2_HBPHI_SHIFT 4 #define RASTER_TIMING_2_HFPHI_SHIFT 0 #define LCD_RASTER_SUBPANEL 0x38 #define LCD_RASTER_SUBPANEL2 0x3C #define LCD_LCDDMA_CTRL 0x40 #define LCDDMA_CTRL_DMA_MASTER_PRIO_SHIFT 16 #define LCDDMA_CTRL_TH_FIFO_RDY_SHIFT 8 #define LCDDMA_CTRL_BURST_SIZE_SHIFT 4 #define LCDDMA_CTRL_BYTES_SWAP (1 << 3) #define LCDDMA_CTRL_BE (1 << 1) #define LCDDMA_CTRL_FB0_ONLY 0 #define LCDDMA_CTRL_FB0_FB1 (1 << 0) #define LCD_LCDDMA_FB0_BASE 0x44 #define LCD_LCDDMA_FB0_CEILING 0x48 #define LCD_LCDDMA_FB1_BASE 0x4C #define LCD_LCDDMA_FB1_CEILING 0x50 #define LCD_SYSCONFIG 0x54 #define SYSCONFIG_STANDBY_FORCE (0 << 4) #define SYSCONFIG_STANDBY_NONE (1 << 4) #define SYSCONFIG_STANDBY_SMART (2 << 4) #define SYSCONFIG_IDLE_FORCE (0 << 2) #define SYSCONFIG_IDLE_NONE (1 << 2) #define SYSCONFIG_IDLE_SMART (2 << 2) #define LCD_IRQSTATUS_RAW 0x58 #define LCD_IRQSTATUS 0x5C #define LCD_IRQENABLE_SET 0x60 #define LCD_IRQENABLE_CLEAR 0x64 #define IRQ_EOF1 (1 << 9) #define IRQ_EOF0 (1 << 8) #define IRQ_PL (1 << 6) #define IRQ_FUF (1 << 5) #define IRQ_ACB (1 << 3) #define IRQ_SYNC_LOST (1 << 2) #define IRQ_RASTER_DONE (1 << 1) #define IRQ_FRAME_DONE (1 << 0) #define LCD_END_OF_INT_IND 0x68 #define LCD_CLKC_ENABLE 0x6C #define CLKC_ENABLE_DMA (1 << 2) #define CLKC_ENABLE_LDID (1 << 1) #define CLKC_ENABLE_CORE (1 << 0) #define LCD_CLKC_RESET 0x70 #define CLKC_RESET_MAIN (1 << 3) #define CLKC_RESET_DMA (1 << 2) #define CLKC_RESET_LDID (1 << 1) #define CLKC_RESET_CORE (1 << 0) #define LCD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define LCD_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define LCD_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ device_get_nameunit(_sc->sc_dev), "am335x_lcd", MTX_DEF) #define LCD_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx); #define LCD_READ4(_sc, reg) bus_read_4((_sc)->sc_mem_res, reg); #define LCD_WRITE4(_sc, reg, value) \ bus_write_4((_sc)->sc_mem_res, reg, value); /* Backlight is controlled by eCAS interface on PWM unit 0 */ #define PWM_UNIT 0 #define PWM_PERIOD 100 struct am335x_lcd_softc { device_t sc_dev; struct fb_info sc_fb_info; struct resource *sc_mem_res; struct resource *sc_irq_res; void *sc_intr_hl; struct mtx sc_mtx; int sc_backlight; struct sysctl_oid *sc_oid; /* Framebuffer */ bus_dma_tag_t sc_dma_tag; bus_dmamap_t sc_dma_map; size_t sc_fb_size; bus_addr_t sc_fb_phys; uint8_t *sc_fb_base; }; static void am335x_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) { bus_addr_t *addr; if (err) return; addr = (bus_addr_t*)arg; *addr = segs[0].ds_addr; } static uint32_t am335x_lcd_calc_divisor(uint32_t reference, uint32_t freq) { uint32_t div; /* Raster mode case: divisors are in range from 2 to 255 */ for (div = 2; div < 255; div++) if (reference/div <= freq) return (div); return (255); } static int am335x_lcd_sysctl_backlight(SYSCTL_HANDLER_ARGS) { struct am335x_lcd_softc *sc = (struct am335x_lcd_softc*)arg1; int error; int backlight; backlight = sc->sc_backlight; error = sysctl_handle_int(oidp, &backlight, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (backlight < 0) backlight = 0; if (backlight > 100) backlight = 100; LCD_LOCK(sc); - error = am335x_pwm_config_ecas(PWM_UNIT, PWM_PERIOD, + error = am335x_pwm_config_ecap(PWM_UNIT, PWM_PERIOD, backlight*PWM_PERIOD/100); if (error == 0) sc->sc_backlight = backlight; LCD_UNLOCK(sc); return (error); } static int -am335x_read_panel_property(device_t dev, const char *name, uint32_t *val) +am335x_read_property(device_t dev, phandle_t node, const char *name, uint32_t *val) { - phandle_t node; pcell_t cell; - node = ofw_bus_get_node(dev); if ((OF_getprop(node, name, &cell, sizeof(cell))) <= 0) { device_printf(dev, "missing '%s' attribute in LCD panel info\n", name); return (ENXIO); } *val = fdt32_to_cpu(cell); return (0); } static int -am335x_read_panel_info(device_t dev, struct panel_info *panel) +am335x_read_timing(device_t dev, phandle_t node, struct panel_info *panel) { int error; + phandle_t timings_node, timing_node, native; + timings_node = fdt_find_child(node, "display-timings"); + if (timings_node == 0) { + device_printf(dev, "no \"display-timings\" node\n"); + return (-1); + } + + if (OF_searchencprop(timings_node, "native-mode", &native, + sizeof(native)) == -1) { + device_printf(dev, "no \"native-mode\" reference in \"timings\" node\n"); + return (-1); + } + + timing_node = OF_node_from_xref(native); + error = 0; - if ((error = am335x_read_panel_property(dev, - "panel_width", &panel->panel_width))) + if ((error = am335x_read_property(dev, timing_node, + "hactive", &panel->panel_width))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_height", &panel->panel_height))) + if ((error = am335x_read_property(dev, timing_node, + "vactive", &panel->panel_height))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_hfp", &panel->panel_hfp))) + if ((error = am335x_read_property(dev, timing_node, + "hfront-porch", &panel->panel_hfp))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_hbp", &panel->panel_hbp))) + if ((error = am335x_read_property(dev, timing_node, + "hback-porch", &panel->panel_hbp))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_hsw", &panel->panel_hsw))) + if ((error = am335x_read_property(dev, timing_node, + "hsync-len", &panel->panel_hsw))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_vfp", &panel->panel_vfp))) + if ((error = am335x_read_property(dev, timing_node, + "vfront-porch", &panel->panel_vfp))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_vbp", &panel->panel_vbp))) + if ((error = am335x_read_property(dev, timing_node, + "vback-porch", &panel->panel_vbp))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_vsw", &panel->panel_vsw))) + if ((error = am335x_read_property(dev, timing_node, + "vsync-len", &panel->panel_vsw))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_pxl_clk", &panel->panel_pxl_clk))) + if ((error = am335x_read_property(dev, timing_node, + "clock-frequency", &panel->panel_pxl_clk))) goto out; - if ((error = am335x_read_panel_property(dev, - "panel_invert_pxl_clk", &panel->panel_invert_pxl_clk))) + if ((error = am335x_read_property(dev, timing_node, + "pixelclk-active", &panel->pixelclk_active))) goto out; - if ((error = am335x_read_panel_property(dev, - "ac_bias", &panel->ac_bias))) + if ((error = am335x_read_property(dev, timing_node, + "hsync-active", &panel->hsync_active))) goto out; - if ((error = am335x_read_panel_property(dev, - "ac_bias_intrpt", &panel->ac_bias_intrpt))) + if ((error = am335x_read_property(dev, timing_node, + "vsync-active", &panel->vsync_active))) goto out; - if ((error = am335x_read_panel_property(dev, - "dma_burst_sz", &panel->dma_burst_sz))) +out: + return (error); +} + +static int +am335x_read_panel_info(device_t dev, phandle_t node, struct panel_info *panel) +{ + int error; + phandle_t panel_info_node; + + panel_info_node = fdt_find_child(node, "panel-info"); + if (panel_info_node == 0) + return (-1); + + error = 0; + + if ((error = am335x_read_property(dev, panel_info_node, + "ac-bias", &panel->ac_bias))) goto out; - if ((error = am335x_read_panel_property(dev, - "bpp", &panel->bpp))) + if ((error = am335x_read_property(dev, panel_info_node, + "ac-bias-intrpt", &panel->ac_bias_intrpt))) goto out; - if ((error = am335x_read_panel_property(dev, - "fdd", &panel->fdd))) + if ((error = am335x_read_property(dev, panel_info_node, + "dma-burst-sz", &panel->dma_burst_sz))) goto out; - if ((error = am335x_read_panel_property(dev, - "invert_line_clock", &panel->invert_line_clock))) + if ((error = am335x_read_property(dev, panel_info_node, + "bpp", &panel->bpp))) goto out; - if ((error = am335x_read_panel_property(dev, - "invert_frm_clock", &panel->invert_frm_clock))) + if ((error = am335x_read_property(dev, panel_info_node, + "fdd", &panel->fdd))) goto out; - if ((error = am335x_read_panel_property(dev, - "sync_edge", &panel->sync_edge))) + if ((error = am335x_read_property(dev, panel_info_node, + "sync-edge", &panel->sync_edge))) goto out; - error = am335x_read_panel_property(dev, - "sync_ctrl", &panel->sync_ctrl); + error = am335x_read_property(dev, panel_info_node, + "sync-ctrl", &panel->sync_ctrl); out: return (error); } static void am335x_lcd_intr(void *arg) { struct am335x_lcd_softc *sc = arg; uint32_t reg; reg = LCD_READ4(sc, LCD_IRQSTATUS); LCD_WRITE4(sc, LCD_IRQSTATUS, reg); /* Read value back to make sure it reached the hardware */ reg = LCD_READ4(sc, LCD_IRQSTATUS); if (reg & IRQ_SYNC_LOST) { reg = LCD_READ4(sc, LCD_RASTER_CTRL); reg &= ~RASTER_CTRL_LCDEN; LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); reg = LCD_READ4(sc, LCD_RASTER_CTRL); reg |= RASTER_CTRL_LCDEN; LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); goto done; } if (reg & IRQ_PL) { reg = LCD_READ4(sc, LCD_RASTER_CTRL); reg &= ~RASTER_CTRL_LCDEN; LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); reg = LCD_READ4(sc, LCD_RASTER_CTRL); reg |= RASTER_CTRL_LCDEN; LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); goto done; } if (reg & IRQ_EOF0) { LCD_WRITE4(sc, LCD_LCDDMA_FB0_BASE, sc->sc_fb_phys); LCD_WRITE4(sc, LCD_LCDDMA_FB0_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); reg &= ~IRQ_EOF0; } if (reg & IRQ_EOF1) { LCD_WRITE4(sc, LCD_LCDDMA_FB1_BASE, sc->sc_fb_phys); LCD_WRITE4(sc, LCD_LCDDMA_FB1_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); reg &= ~IRQ_EOF1; } if (reg & IRQ_FUF) { /* TODO: Handle FUF */ } if (reg & IRQ_ACB) { /* TODO: Handle ACB */ } done: LCD_WRITE4(sc, LCD_END_OF_INT_IND, 0); /* Read value back to make sure it reached the hardware */ reg = LCD_READ4(sc, LCD_END_OF_INT_IND); } static int am335x_lcd_probe(device_t dev) { #ifdef DEV_SC int err; #endif if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,am335x-lcd")) + if (!ofw_bus_is_compatible(dev, "ti,am33xx-tilcdc")) return (ENXIO); device_set_desc(dev, "AM335x LCD controller"); #ifdef DEV_SC err = sc_probe_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD); if (err != 0) return (err); #endif return (BUS_PROBE_DEFAULT); } static int am335x_lcd_attach(device_t dev) { struct am335x_lcd_softc *sc; int rid; int div; struct panel_info panel; uint32_t reg, timing0, timing1, timing2; struct sysctl_ctx_list *ctx; struct sysctl_oid *tree; uint32_t burst_log; int err; size_t dma_size; uint32_t hbp, hfp, hsw; uint32_t vbp, vfp, vsw; uint32_t width, height; + phandle_t root, panel_node; sc = device_get_softc(dev); sc->sc_dev = dev; - if (am335x_read_panel_info(dev, &panel)) + root = OF_finddevice("/"); + if (root == 0) { + device_printf(dev, "failed to get FDT root node\n"); return (ENXIO); + } + panel_node = fdt_find_compatible(root, "ti,tilcdc,panel", 1); + if (panel_node == 0) { + device_printf(dev, "failed to find compatible panel in FDT blob\n"); + return (ENXIO); + } + + if (am335x_read_panel_info(dev, panel_node, &panel)) { + device_printf(dev, "failed to read panel info\n"); + return (ENXIO); + } + + if (am335x_read_timing(dev, panel_node, &panel)) { + device_printf(dev, "failed to read timings\n"); + return (ENXIO); + } + int ref_freq = 0; ti_prcm_clk_enable(LCDC_CLK); if (ti_prcm_clk_get_source_freq(LCDC_CLK, &ref_freq)) { device_printf(dev, "Can't get reference frequency\n"); return (ENXIO); } rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_mem_res) { device_printf(dev, "cannot allocate memory window\n"); return (ENXIO); } rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (!sc->sc_irq_res) { bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); device_printf(dev, "cannot allocate interrupt\n"); return (ENXIO); } if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, am335x_lcd_intr, sc, &sc->sc_intr_hl) != 0) { bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_irq_res); bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->sc_mem_res); device_printf(dev, "Unable to setup the irq handler.\n"); return (ENXIO); } LCD_LOCK_INIT(sc); /* Panle initialization */ dma_size = round_page(panel.panel_width*panel.panel_height*panel.bpp/8); /* * Now allocate framebuffer memory */ err = bus_dma_tag_create( bus_get_dma_tag(dev), 4, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ dma_size, 1, /* maxsize, nsegments */ dma_size, 0, /* maxsegsize, flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->sc_dma_tag); if (err) goto fail; err = bus_dmamem_alloc(sc->sc_dma_tag, (void **)&sc->sc_fb_base, BUS_DMA_COHERENT, &sc->sc_dma_map); if (err) { device_printf(dev, "cannot allocate framebuffer\n"); goto fail; } err = bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, sc->sc_fb_base, dma_size, am335x_fb_dmamap_cb, &sc->sc_fb_phys, BUS_DMA_NOWAIT); if (err) { device_printf(dev, "cannot load DMA map\n"); goto fail; } /* Make sure it's blank */ memset(sc->sc_fb_base, 0x00, dma_size); /* Calculate actual FB Size */ sc->sc_fb_size = panel.panel_width*panel.panel_height*panel.bpp/8; /* Only raster mode is supported */ reg = CTRL_RASTER_MODE; div = am335x_lcd_calc_divisor(ref_freq, panel.panel_pxl_clk); reg |= (div << CTRL_DIV_SHIFT); LCD_WRITE4(sc, LCD_CTRL, reg); /* Set timing */ timing0 = timing1 = timing2 = 0; hbp = panel.panel_hbp - 1; hfp = panel.panel_hfp - 1; hsw = panel.panel_hsw - 1; vbp = panel.panel_vbp; vfp = panel.panel_vfp; vsw = panel.panel_vsw - 1; height = panel.panel_height - 1; width = panel.panel_width - 1; /* Horizontal back porch */ timing0 |= (hbp & 0xff) << RASTER_TIMING_0_HBP_SHIFT; timing2 |= ((hbp >> 8) & 3) << RASTER_TIMING_2_HBPHI_SHIFT; /* Horizontal front porch */ timing0 |= (hfp & 0xff) << RASTER_TIMING_0_HFP_SHIFT; timing2 |= ((hfp >> 8) & 3) << RASTER_TIMING_2_HFPHI_SHIFT; /* Horizontal sync width */ timing0 |= (hsw & 0x3f) << RASTER_TIMING_0_HSW_SHIFT; timing2 |= ((hsw >> 6) & 0xf) << RASTER_TIMING_2_HSWHI_SHIFT; /* Vertical back porch, front porch, sync width */ timing1 |= (vbp & 0xff) << RASTER_TIMING_1_VBP_SHIFT; timing1 |= (vfp & 0xff) << RASTER_TIMING_1_VFP_SHIFT; timing1 |= (vsw & 0x3f) << RASTER_TIMING_1_VSW_SHIFT; /* Pixels per line */ timing0 |= ((width >> 10) & 1) << RASTER_TIMING_0_PPLMSB_SHIFT; timing0 |= ((width >> 4) & 0x3f) << RASTER_TIMING_0_PPLLSB_SHIFT; /* Lines per panel */ timing1 |= (height & 0x3ff) << RASTER_TIMING_1_LPP_SHIFT; timing2 |= ((height >> 10 ) & 1) << RASTER_TIMING_2_LPP_B10_SHIFT; /* clock signal settings */ if (panel.sync_ctrl) timing2 |= RASTER_TIMING_2_PHSVS; if (panel.sync_edge) timing2 |= RASTER_TIMING_2_PHSVS_RISE; else timing2 |= RASTER_TIMING_2_PHSVS_FALL; - if (panel.invert_line_clock) + if (panel.hsync_active == 0) timing2 |= RASTER_TIMING_2_IHS; - if (panel.invert_frm_clock) + if (panel.vsync_active == 0) timing2 |= RASTER_TIMING_2_IVS; - if (panel.panel_invert_pxl_clk) + if (panel.pixelclk_active == 0) timing2 |= RASTER_TIMING_2_IPC; /* AC bias */ timing2 |= (panel.ac_bias << RASTER_TIMING_2_ACB_SHIFT); timing2 |= (panel.ac_bias_intrpt << RASTER_TIMING_2_ACBI_SHIFT); LCD_WRITE4(sc, LCD_RASTER_TIMING_0, timing0); LCD_WRITE4(sc, LCD_RASTER_TIMING_1, timing1); LCD_WRITE4(sc, LCD_RASTER_TIMING_2, timing2); /* DMA settings */ reg = LCDDMA_CTRL_FB0_FB1; /* Find power of 2 for current burst size */ switch (panel.dma_burst_sz) { case 1: burst_log = 0; break; case 2: burst_log = 1; break; case 4: burst_log = 2; break; case 8: burst_log = 3; break; case 16: default: burst_log = 4; break; } reg |= (burst_log << LCDDMA_CTRL_BURST_SIZE_SHIFT); /* XXX: FIFO TH */ reg |= (0 << LCDDMA_CTRL_TH_FIFO_RDY_SHIFT); LCD_WRITE4(sc, LCD_LCDDMA_CTRL, reg); LCD_WRITE4(sc, LCD_LCDDMA_FB0_BASE, sc->sc_fb_phys); LCD_WRITE4(sc, LCD_LCDDMA_FB0_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); LCD_WRITE4(sc, LCD_LCDDMA_FB1_BASE, sc->sc_fb_phys); LCD_WRITE4(sc, LCD_LCDDMA_FB1_CEILING, sc->sc_fb_phys + sc->sc_fb_size - 1); /* Enable LCD */ reg = RASTER_CTRL_LCDTFT; reg |= (panel.fdd << RASTER_CTRL_REQDLY_SHIFT); reg |= (PALETTE_DATA_ONLY << RASTER_CTRL_PALMODE_SHIFT); if (panel.bpp >= 24) reg |= RASTER_CTRL_TFT24; if (panel.bpp == 32) reg |= RASTER_CTRL_TFT24_UNPACKED; LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); LCD_WRITE4(sc, LCD_CLKC_ENABLE, CLKC_ENABLE_DMA | CLKC_ENABLE_LDID | CLKC_ENABLE_CORE); LCD_WRITE4(sc, LCD_CLKC_RESET, CLKC_RESET_MAIN); DELAY(100); LCD_WRITE4(sc, LCD_CLKC_RESET, 0); reg = IRQ_EOF1 | IRQ_EOF0 | IRQ_FUF | IRQ_PL | IRQ_ACB | IRQ_SYNC_LOST | IRQ_RASTER_DONE | IRQ_FRAME_DONE; LCD_WRITE4(sc, LCD_IRQENABLE_SET, reg); reg = LCD_READ4(sc, LCD_RASTER_CTRL); reg |= RASTER_CTRL_LCDEN; LCD_WRITE4(sc, LCD_RASTER_CTRL, reg); LCD_WRITE4(sc, LCD_SYSCONFIG, SYSCONFIG_STANDBY_SMART | SYSCONFIG_IDLE_SMART); /* Init backlight interface */ ctx = device_get_sysctl_ctx(sc->sc_dev); tree = device_get_sysctl_tree(sc->sc_dev); sc->sc_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "backlight", CTLTYPE_INT | CTLFLAG_RW, sc, 0, am335x_lcd_sysctl_backlight, "I", "LCD backlight"); sc->sc_backlight = 0; /* Check if eCAS interface is available at this point */ - if (am335x_pwm_config_ecas(PWM_UNIT, + if (am335x_pwm_config_ecap(PWM_UNIT, PWM_PERIOD, PWM_PERIOD) == 0) sc->sc_backlight = 100; sc->sc_fb_info.fb_name = device_get_nameunit(sc->sc_dev); sc->sc_fb_info.fb_vbase = (intptr_t)sc->sc_fb_base; sc->sc_fb_info.fb_pbase = sc->sc_fb_phys; sc->sc_fb_info.fb_size = sc->sc_fb_size; sc->sc_fb_info.fb_bpp = sc->sc_fb_info.fb_depth = panel.bpp; sc->sc_fb_info.fb_stride = panel.panel_width*panel.bpp / 8; sc->sc_fb_info.fb_width = panel.panel_width; sc->sc_fb_info.fb_height = panel.panel_height; #ifdef DEV_SC err = (sc_attach_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD)); if (err) { device_printf(dev, "failed to attach syscons\n"); goto fail; } am335x_lcd_syscons_setup((vm_offset_t)sc->sc_fb_base, sc->sc_fb_phys, &panel); #else /* VT */ device_t fbd = device_add_child(dev, "fbd", device_get_unit(dev)); if (fbd == NULL) { device_printf(dev, "Failed to add fbd child\n"); goto fail; } if (device_probe_and_attach(fbd) != 0) { device_printf(dev, "Failed to attach fbd device\n"); goto fail; } #endif return (0); fail: return (err); } static int am335x_lcd_detach(device_t dev) { /* Do not let unload driver */ return (EBUSY); } static struct fb_info * am335x_lcd_fb_getinfo(device_t dev) { struct am335x_lcd_softc *sc; sc = device_get_softc(dev); return (&sc->sc_fb_info); } static device_method_t am335x_lcd_methods[] = { DEVMETHOD(device_probe, am335x_lcd_probe), DEVMETHOD(device_attach, am335x_lcd_attach), DEVMETHOD(device_detach, am335x_lcd_detach), /* Framebuffer service methods */ DEVMETHOD(fb_getinfo, am335x_lcd_fb_getinfo), DEVMETHOD_END }; static driver_t am335x_lcd_driver = { "fb", am335x_lcd_methods, sizeof(struct am335x_lcd_softc), }; static devclass_t am335x_lcd_devclass; DRIVER_MODULE(am335x_lcd, simplebus, am335x_lcd_driver, am335x_lcd_devclass, 0, 0); MODULE_VERSION(am335x_lcd, 1); MODULE_DEPEND(am335x_lcd, simplebus, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_lcd.h =================================================================== --- head/sys/arm/ti/am335x/am335x_lcd.h (revision 283275) +++ head/sys/arm/ti/am335x/am335x_lcd.h (revision 283276) @@ -1,56 +1,56 @@ /*- * Copyright (c) 2013 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 __AM335X_LCD_H__ #define __AM335X_LCD_H__ struct panel_info { uint32_t panel_width; uint32_t panel_height; uint32_t panel_hfp; uint32_t panel_hbp; uint32_t panel_hsw; uint32_t panel_vfp; uint32_t panel_vbp; uint32_t panel_vsw; uint32_t ac_bias; uint32_t ac_bias_intrpt; uint32_t dma_burst_sz; uint32_t bpp; uint32_t fdd; - uint32_t invert_line_clock; - uint32_t invert_frm_clock; + uint32_t hsync_active; + uint32_t vsync_active; uint32_t sync_edge; uint32_t sync_ctrl; uint32_t panel_pxl_clk; - uint32_t panel_invert_pxl_clk; + uint32_t pixelclk_active; }; int am335x_lcd_syscons_setup(vm_offset_t vaddr, vm_paddr_t paddr, struct panel_info *panel); #endif /* __AM335X_LCD_H__ */ Index: head/sys/arm/ti/am335x/am335x_musb.c =================================================================== --- head/sys/arm/ti/am335x/am335x_musb.c (nonexistent) +++ head/sys/arm/ti/am335x/am335x_musb.c (revision 283276) @@ -0,0 +1,417 @@ +/*- + * Copyright (c) 2013 Oleksandr Tymoshenko + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define USB_DEBUG_VAR usbssdebug + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#define USBCTRL_REV 0x00 +#define USBCTRL_CTRL 0x14 +#define USBCTRL_STAT 0x18 +#define USBCTRL_IRQ_STAT0 0x30 +#define IRQ_STAT0_RXSHIFT 16 +#define IRQ_STAT0_TXSHIFT 0 +#define USBCTRL_IRQ_STAT1 0x34 +#define IRQ_STAT1_DRVVBUS (1 << 8) +#define USBCTRL_INTEN_SET0 0x38 +#define USBCTRL_INTEN_SET1 0x3C +#define USBCTRL_INTEN_USB_ALL 0x1ff +#define USBCTRL_INTEN_USB_SOF (1 << 3) +#define USBCTRL_INTEN_CLR0 0x40 +#define USBCTRL_INTEN_CLR1 0x44 +#define USBCTRL_UTMI 0xE0 +#define USBCTRL_UTMI_FSDATAEXT (1 << 1) +#define USBCTRL_MODE 0xE8 +#define USBCTRL_MODE_IDDIG (1 << 8) +#define USBCTRL_MODE_IDDIGMUX (1 << 7) + +/* USBSS resource + 2 MUSB ports */ + +#define RES_USBCORE 0 +#define RES_USBCTRL 1 + +#define USB_WRITE4(sc, idx, reg, val) do { \ + bus_write_4((sc)->sc_mem_res[idx], (reg), (val)); \ +} while (0) + +#define USB_READ4(sc, idx, reg) bus_read_4((sc)->sc_mem_res[idx], (reg)) + +#define USBCTRL_WRITE4(sc, reg, val) \ + USB_WRITE4((sc), RES_USBCTRL, (reg), (val)) +#define USBCTRL_READ4(sc, reg) \ + USB_READ4((sc), RES_USBCTRL, (reg)) + +static struct resource_spec am335x_musbotg_mem_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_MEMORY, 1, RF_ACTIVE }, + { -1, 0, 0 } +}; + +#ifdef USB_DEBUG +static int usbssdebug = 0; + +static SYSCTL_NODE(_hw_usb, OID_AUTO, am335x_usbss, CTLFLAG_RW, 0, "AM335x USBSS"); +SYSCTL_INT(_hw_usb_am335x_usbss, OID_AUTO, debug, CTLFLAG_RW, + &usbssdebug, 0, "Debug level"); +#endif + +static device_probe_t musbotg_probe; +static device_attach_t musbotg_attach; +static device_detach_t musbotg_detach; + +struct musbotg_super_softc { + struct musbotg_softc sc_otg; + struct resource *sc_mem_res[2]; + int sc_irq_rid; +}; + +static void +musbotg_vbus_poll(struct musbotg_super_softc *sc) +{ + uint32_t stat; + + if (sc->sc_otg.sc_mode == MUSB2_DEVICE_MODE) + musbotg_vbus_interrupt(&sc->sc_otg, 1); + else { + stat = USBCTRL_READ4(sc, USBCTRL_STAT); + musbotg_vbus_interrupt(&sc->sc_otg, stat & 1); + } +} + +/* + * Arg to musbotg_clocks_on and musbot_clocks_off is + * a uint32_t * pointing to the SCM register offset. + */ +static uint32_t USB_CTRL[] = {SCM_USB_CTRL0, SCM_USB_CTRL1}; + +static void +musbotg_clocks_on(void *arg) +{ + struct musbotg_softc *sc; + uint32_t c, reg; + + sc = arg; + reg = USB_CTRL[sc->sc_id]; + + ti_scm_reg_read_4(reg, &c); + c &= ~3; /* Enable power */ + c |= 1 << 19; /* VBUS detect enable */ + c |= 1 << 20; /* Session end enable */ + ti_scm_reg_write_4(reg, c); +} + +static void +musbotg_clocks_off(void *arg) +{ + struct musbotg_softc *sc; + uint32_t c, reg; + + sc = arg; + reg = USB_CTRL[sc->sc_id]; + + /* Disable power to PHY */ + ti_scm_reg_read_4(reg, &c); + ti_scm_reg_write_4(reg, c | 3); +} + +static void +musbotg_ep_int_set(struct musbotg_softc *sc, int ep, int on) +{ + struct musbotg_super_softc *ssc = sc->sc_platform_data; + uint32_t epmask; + + epmask = ((1 << ep) << IRQ_STAT0_RXSHIFT); + epmask |= ((1 << ep) << IRQ_STAT0_TXSHIFT); + if (on) + USBCTRL_WRITE4(ssc, USBCTRL_INTEN_SET0, epmask); + else + USBCTRL_WRITE4(ssc, USBCTRL_INTEN_CLR0, epmask); +} + +static void +musbotg_wrapper_interrupt(void *arg) +{ + struct musbotg_softc *sc = arg; + struct musbotg_super_softc *ssc = sc->sc_platform_data; + uint32_t stat, stat0, stat1; + + stat = USBCTRL_READ4(ssc, USBCTRL_STAT); + stat0 = USBCTRL_READ4(ssc, USBCTRL_IRQ_STAT0); + stat1 = USBCTRL_READ4(ssc, USBCTRL_IRQ_STAT1); + if (stat0) + USBCTRL_WRITE4(ssc, USBCTRL_IRQ_STAT0, stat0); + if (stat1) + USBCTRL_WRITE4(ssc, USBCTRL_IRQ_STAT1, stat1); + + DPRINTFN(4, "port%d: stat0=%08x stat1=%08x, stat=%08x\n", + sc->sc_id, stat0, stat1, stat); + + if (stat1 & IRQ_STAT1_DRVVBUS) + musbotg_vbus_interrupt(sc, stat & 1); + + musbotg_interrupt(arg, ((stat0 >> 16) & 0xffff), + stat0 & 0xffff, stat1 & 0xff); +} + +static int +musbotg_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ti,musb-am33xx")) + return (ENXIO); + + device_set_desc(dev, "TI AM33xx integrated USB OTG controller"); + + return (BUS_PROBE_DEFAULT); +} + +static int +musbotg_attach(device_t dev) +{ + struct musbotg_super_softc *sc = device_get_softc(dev); + int err; + uint32_t reg; + + sc->sc_otg.sc_id = device_get_unit(dev); + + /* Request the memory resources */ + err = bus_alloc_resources(dev, am335x_musbotg_mem_spec, + sc->sc_mem_res); + if (err) { + device_printf(dev, + "Error: could not allocate mem resources\n"); + return (ENXIO); + } + + /* Request the IRQ resources */ + sc->sc_otg.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->sc_irq_rid, RF_ACTIVE); + if (sc->sc_otg.sc_irq_res == NULL) { + device_printf(dev, + "Error: could not allocate irq resources\n"); + return (ENXIO); + } + + /* setup MUSB OTG USB controller interface softc */ + sc->sc_otg.sc_clocks_on = &musbotg_clocks_on; + sc->sc_otg.sc_clocks_off = &musbotg_clocks_off; + sc->sc_otg.sc_clocks_arg = &sc->sc_otg; + + sc->sc_otg.sc_ep_int_set = musbotg_ep_int_set; + + /* initialise some bus fields */ + sc->sc_otg.sc_bus.parent = dev; + sc->sc_otg.sc_bus.devices = sc->sc_otg.sc_devices; + sc->sc_otg.sc_bus.devices_max = MUSB2_MAX_DEVICES; + sc->sc_otg.sc_bus.dma_bits = 32; + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_otg.sc_bus, + USB_GET_DMA_TAG(dev), NULL)) { + device_printf(dev, + "Failed allocate bus mem for musb\n"); + return (ENOMEM); + } + sc->sc_otg.sc_io_res = sc->sc_mem_res[RES_USBCORE]; + sc->sc_otg.sc_io_tag = + rman_get_bustag(sc->sc_otg.sc_io_res); + sc->sc_otg.sc_io_hdl = + rman_get_bushandle(sc->sc_otg.sc_io_res); + sc->sc_otg.sc_io_size = + rman_get_size(sc->sc_otg.sc_io_res); + + sc->sc_otg.sc_bus.bdev = device_add_child(dev, "usbus", -1); + if (!(sc->sc_otg.sc_bus.bdev)) { + device_printf(dev, "No busdev for musb\n"); + goto error; + } + device_set_ivars(sc->sc_otg.sc_bus.bdev, + &sc->sc_otg.sc_bus); + + err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, + INTR_TYPE_BIO | INTR_MPSAFE, + NULL, (driver_intr_t *)musbotg_wrapper_interrupt, + &sc->sc_otg, &sc->sc_otg.sc_intr_hdl); + if (err) { + sc->sc_otg.sc_intr_hdl = NULL; + device_printf(dev, + "Failed to setup interrupt for musb\n"); + goto error; + } + + sc->sc_otg.sc_platform_data = sc; + if (sc->sc_otg.sc_id == 0) + sc->sc_otg.sc_mode = MUSB2_DEVICE_MODE; + else + sc->sc_otg.sc_mode = MUSB2_HOST_MODE; + + /* + * software-controlled function + */ + + if (sc->sc_otg.sc_mode == MUSB2_HOST_MODE) { + reg = USBCTRL_READ4(sc, USBCTRL_MODE); + reg |= USBCTRL_MODE_IDDIGMUX; + reg &= ~USBCTRL_MODE_IDDIG; + USBCTRL_WRITE4(sc, USBCTRL_MODE, reg); + USBCTRL_WRITE4(sc, USBCTRL_UTMI, + USBCTRL_UTMI_FSDATAEXT); + } else { + reg = USBCTRL_READ4(sc, USBCTRL_MODE); + reg |= USBCTRL_MODE_IDDIGMUX; + reg |= USBCTRL_MODE_IDDIG; + USBCTRL_WRITE4(sc, USBCTRL_MODE, reg); + } + + reg = USBCTRL_INTEN_USB_ALL & ~USBCTRL_INTEN_USB_SOF; + USBCTRL_WRITE4(sc, USBCTRL_INTEN_SET1, reg); + USBCTRL_WRITE4(sc, USBCTRL_INTEN_CLR0, 0xffffffff); + + err = musbotg_init(&sc->sc_otg); + if (!err) + err = device_probe_and_attach(sc->sc_otg.sc_bus.bdev); + + if (err) + goto error; + + /* poll VBUS one time */ + musbotg_vbus_poll(sc); + + return (0); + +error: + musbotg_detach(dev); + return (ENXIO); +} + +static int +musbotg_detach(device_t dev) +{ + struct musbotg_super_softc *sc = device_get_softc(dev); + device_t bdev; + int err; + + if (sc->sc_otg.sc_bus.bdev) { + bdev = sc->sc_otg.sc_bus.bdev; + device_detach(bdev); + device_delete_child(dev, bdev); + } + + if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { + /* + * only call musbotg_uninit() after musbotg_init() + */ + musbotg_uninit(&sc->sc_otg); + + err = bus_teardown_intr(dev, sc->sc_otg.sc_irq_res, + sc->sc_otg.sc_intr_hdl); + sc->sc_otg.sc_intr_hdl = NULL; + } + + usb_bus_mem_free_all(&sc->sc_otg.sc_bus, NULL); + + /* Free resources if any */ + if (sc->sc_mem_res[0]) + bus_release_resources(dev, am335x_musbotg_mem_spec, + sc->sc_mem_res); + + if (sc->sc_otg.sc_irq_res) + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, + sc->sc_otg.sc_irq_res); + + /* during module unload there are lots of children leftover */ + device_delete_children(dev); + + return (0); +} + +static device_method_t musbotg_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, musbotg_probe), + DEVMETHOD(device_attach, musbotg_attach), + DEVMETHOD(device_detach, musbotg_detach), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + DEVMETHOD_END +}; + +static driver_t musbotg_driver = { + .name = "musbotg", + .methods = musbotg_methods, + .size = sizeof(struct musbotg_super_softc), +}; + +static devclass_t musbotg_devclass; + +DRIVER_MODULE(musbotg, usbss, musbotg_driver, musbotg_devclass, 0, 0); +MODULE_DEPEND(musbotg, usbss, 1, 1, 1); Property changes on: head/sys/arm/ti/am335x/am335x_musb.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/am335x/am335x_pmic.c =================================================================== --- head/sys/arm/ti/am335x/am335x_pmic.c (revision 283275) +++ head/sys/arm/ti/am335x/am335x_pmic.c (revision 283276) @@ -1,278 +1,279 @@ /*- * Copyright (c) 2012 Damjan Marion * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * TPS65217 PMIC companion chip for AM335x SoC sitting on I2C bus */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" #define TPS65217A 0x7 #define TPS65217B 0xF #define TPS65217C 0xE #define TPS65217D 0x6 /* TPS65217 Reisters */ #define TPS65217_CHIPID_REG 0x00 #define TPS65217_INT_REG 0x02 #define TPS65217_INT_PBM (1U << 6) #define TPS65217_INT_ACM (1U << 5) #define TPS65217_INT_USBM (1U << 4) #define TPS65217_INT_PBI (1U << 2) #define TPS65217_INT_ACI (1U << 1) #define TPS65217_INT_USBI (1U << 0) #define TPS65217_STATUS_REG 0x0A #define TPS65217_STATUS_OFF (1U << 7) #define TPS65217_STATUS_ACPWR (1U << 3) #define TPS65217_STATUS_USBPWR (1U << 2) #define TPS65217_STATUS_BT (1U << 0) #define MAX_IIC_DATA_SIZE 2 struct am335x_pmic_softc { device_t sc_dev; uint32_t sc_addr; struct intr_config_hook enum_hook; struct resource *sc_irq_res; void *sc_intrhand; }; static void am335x_pmic_shutdown(void *, int); static int am335x_pmic_read(device_t dev, uint8_t addr, uint8_t *data, uint8_t size) { struct am335x_pmic_softc *sc = device_get_softc(dev); struct iic_msg msg[] = { { sc->sc_addr, IIC_M_WR, 1, &addr }, { sc->sc_addr, IIC_M_RD, size, data }, }; return (iicbus_transfer(dev, msg, 2)); } static int am335x_pmic_write(device_t dev, uint8_t address, uint8_t *data, uint8_t size) { uint8_t buffer[MAX_IIC_DATA_SIZE + 1]; struct am335x_pmic_softc *sc = device_get_softc(dev); struct iic_msg msg[] = { { sc->sc_addr, IIC_M_WR, size + 1, buffer }, }; if (size > MAX_IIC_DATA_SIZE) return (ENOMEM); buffer[0] = address; memcpy(buffer + 1, data, size); return (iicbus_transfer(dev, msg, 1)); } static void am335x_pmic_intr(void *arg) { struct am335x_pmic_softc *sc = (struct am335x_pmic_softc *)arg; uint8_t int_reg, status_reg; int rv; char notify_buf[16]; THREAD_SLEEPING_OK(); rv = am335x_pmic_read(sc->sc_dev, TPS65217_INT_REG, &int_reg, 1); if (rv != 0) { device_printf(sc->sc_dev, "Cannot read interrupt register\n"); THREAD_NO_SLEEPING(); return; } rv = am335x_pmic_read(sc->sc_dev, TPS65217_STATUS_REG, &status_reg, 1); if (rv != 0) { device_printf(sc->sc_dev, "Cannot read status register\n"); THREAD_NO_SLEEPING(); return; } THREAD_NO_SLEEPING(); if ((int_reg & TPS65217_INT_PBI) && (status_reg & TPS65217_STATUS_BT)) shutdown_nice(RB_POWEROFF); if (int_reg & TPS65217_INT_ACI) { snprintf(notify_buf, sizeof(notify_buf), "notify=0x%02x", (status_reg & TPS65217_STATUS_ACPWR) ? 1 : 0); devctl_notify_f("ACPI", "ACAD", "power", notify_buf, M_NOWAIT); } } static int am335x_pmic_probe(device_t dev) { struct am335x_pmic_softc *sc; - if (!ofw_bus_is_compatible(dev, "ti,am335x-pmic")) + if (!ofw_bus_is_compatible(dev, "ti,tps65217")) return (ENXIO); sc = device_get_softc(dev); sc->sc_dev = dev; - sc->sc_addr = iicbus_get_addr(dev); + /* Convert to 8-bit addressing */ + sc->sc_addr = iicbus_get_addr(dev) << 1; device_set_desc(dev, "TI TPS65217 Power Management IC"); return (0); } static void am335x_pmic_start(void *xdev) { struct am335x_pmic_softc *sc; device_t dev = (device_t)xdev; uint8_t reg; char name[20]; char pwr[4][11] = {"Unknown", "USB", "AC", "USB and AC"}; int rv; sc = device_get_softc(dev); am335x_pmic_read(dev, TPS65217_CHIPID_REG, ®, 1); switch (reg>>4) { case TPS65217A: sprintf(name, "TPS65217A ver 1.%u", reg & 0xF); break; case TPS65217B: sprintf(name, "TPS65217B ver 1.%u", reg & 0xF); break; case TPS65217C: sprintf(name, "TPS65217C ver 1.%u", reg & 0xF); break; case TPS65217D: sprintf(name, "TPS65217D ver 1.%u", reg & 0xF); break; default: sprintf(name, "Unknown PMIC"); } am335x_pmic_read(dev, TPS65217_STATUS_REG, ®, 1); device_printf(dev, "%s powered by %s\n", name, pwr[(reg>>2)&0x03]); EVENTHANDLER_REGISTER(shutdown_final, am335x_pmic_shutdown, dev, SHUTDOWN_PRI_LAST); config_intrhook_disestablish(&sc->enum_hook); /* Unmask all interrupts and clear pending status */ reg = 0; am335x_pmic_write(dev, TPS65217_INT_REG, ®, 1); am335x_pmic_read(dev, TPS65217_INT_REG, ®, 1); if (sc->sc_irq_res != NULL) { rv = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, am335x_pmic_intr, sc, &sc->sc_intrhand); if (rv != 0) device_printf(dev, "Unable to setup the irq handler.\n"); } } static int am335x_pmic_attach(device_t dev) { struct am335x_pmic_softc *sc; int rid; sc = device_get_softc(dev); rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (!sc->sc_irq_res) { device_printf(dev, "cannot allocate interrupt\n"); /* return (ENXIO); */ } sc->enum_hook.ich_func = am335x_pmic_start; sc->enum_hook.ich_arg = dev; if (config_intrhook_establish(&sc->enum_hook) != 0) return (ENOMEM); return (0); } static void am335x_pmic_shutdown(void *xdev, int howto) { device_t dev; uint8_t reg; if (!(howto & RB_POWEROFF)) return; dev = (device_t)xdev; /* Set the OFF bit on status register to start the shutdown sequence. */ reg = TPS65217_STATUS_OFF; am335x_pmic_write(dev, TPS65217_STATUS_REG, ®, 1); /* Toggle pmic_pwr_enable to shutdown the PMIC. */ am335x_rtc_pmic_pwr_toggle(); } static device_method_t am335x_pmic_methods[] = { DEVMETHOD(device_probe, am335x_pmic_probe), DEVMETHOD(device_attach, am335x_pmic_attach), {0, 0}, }; static driver_t am335x_pmic_driver = { "am335x_pmic", am335x_pmic_methods, sizeof(struct am335x_pmic_softc), }; static devclass_t am335x_pmic_devclass; DRIVER_MODULE(am335x_pmic, iicbus, am335x_pmic_driver, am335x_pmic_devclass, 0, 0); MODULE_VERSION(am335x_pmic, 1); MODULE_DEPEND(am335x_pmic, iicbus, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_prcm.c =================================================================== --- head/sys/arm/ti/am335x/am335x_prcm.c (revision 283275) +++ head/sys/arm/ti/am335x/am335x_prcm.c (revision 283276) @@ -1,797 +1,802 @@ /*- * Copyright (c) 2012 Damjan Marion * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CM_PER 0 #define CM_PER_L4LS_CLKSTCTRL (CM_PER + 0x000) #define CM_PER_L3S_CLKSTCTRL (CM_PER + 0x004) #define CM_PER_L3_CLKSTCTRL (CM_PER + 0x00C) #define CM_PER_CPGMAC0_CLKCTRL (CM_PER + 0x014) #define CM_PER_LCDC_CLKCTRL (CM_PER + 0x018) #define CM_PER_USB0_CLKCTRL (CM_PER + 0x01C) #define CM_PER_TPTC0_CLKCTRL (CM_PER + 0x024) #define CM_PER_UART5_CLKCTRL (CM_PER + 0x038) #define CM_PER_MMC0_CLKCTRL (CM_PER + 0x03C) #define CM_PER_I2C2_CLKCTRL (CM_PER + 0x044) #define CM_PER_I2C1_CLKCTRL (CM_PER + 0x048) #define CM_PER_UART1_CLKCTRL (CM_PER + 0x06C) #define CM_PER_UART2_CLKCTRL (CM_PER + 0x070) #define CM_PER_UART3_CLKCTRL (CM_PER + 0x074) #define CM_PER_UART4_CLKCTRL (CM_PER + 0x078) #define CM_PER_TIMER7_CLKCTRL (CM_PER + 0x07C) #define CM_PER_TIMER2_CLKCTRL (CM_PER + 0x080) #define CM_PER_TIMER3_CLKCTRL (CM_PER + 0x084) #define CM_PER_TIMER4_CLKCTRL (CM_PER + 0x088) #define CM_PER_GPIO1_CLKCTRL (CM_PER + 0x0AC) #define CM_PER_GPIO2_CLKCTRL (CM_PER + 0x0B0) #define CM_PER_GPIO3_CLKCTRL (CM_PER + 0x0B4) #define CM_PER_TPCC_CLKCTRL (CM_PER + 0x0BC) #define CM_PER_EPWMSS1_CLKCTRL (CM_PER + 0x0CC) #define CM_PER_EPWMSS0_CLKCTRL (CM_PER + 0x0D4) #define CM_PER_EPWMSS2_CLKCTRL (CM_PER + 0x0D8) #define CM_PER_L3_INSTR_CLKCTRL (CM_PER + 0x0DC) #define CM_PER_L3_CLKCTRL (CM_PER + 0x0E0) #define CM_PER_PRUSS_CLKCTRL (CM_PER + 0x0E8) #define CM_PER_TIMER5_CLKCTRL (CM_PER + 0x0EC) #define CM_PER_TIMER6_CLKCTRL (CM_PER + 0x0F0) #define CM_PER_MMC1_CLKCTRL (CM_PER + 0x0F4) #define CM_PER_MMC2_CLKCTRL (CM_PER + 0x0F8) #define CM_PER_TPTC1_CLKCTRL (CM_PER + 0x0FC) #define CM_PER_TPTC2_CLKCTRL (CM_PER + 0x100) #define CM_PER_SPINLOCK0_CLKCTRL (CM_PER + 0x10C) #define CM_PER_MAILBOX0_CLKCTRL (CM_PER + 0x110) #define CM_PER_OCPWP_L3_CLKSTCTRL (CM_PER + 0x12C) #define CM_PER_OCPWP_CLKCTRL (CM_PER + 0x130) #define CM_PER_CPSW_CLKSTCTRL (CM_PER + 0x144) #define CM_PER_PRUSS_CLKSTCTRL (CM_PER + 0x140) #define CM_WKUP 0x400 #define CM_WKUP_CLKSTCTRL (CM_WKUP + 0x000) #define CM_WKUP_CONTROL_CLKCTRL (CM_WKUP + 0x004) #define CM_WKUP_GPIO0_CLKCTRL (CM_WKUP + 0x008) #define CM_WKUP_CM_L3_AON_CLKSTCTRL (CM_WKUP + 0x01C) #define CM_WKUP_CM_CLKSEL_DPLL_MPU (CM_WKUP + 0x02C) #define CM_WKUP_CM_IDLEST_DPLL_DISP (CM_WKUP + 0x048) #define CM_WKUP_CM_CLKSEL_DPLL_DISP (CM_WKUP + 0x054) #define CM_WKUP_CM_CLKDCOLDO_DPLL_PER (CM_WKUP + 0x07C) #define CM_WKUP_CM_CLKMODE_DPLL_DISP (CM_WKUP + 0x098) #define CM_WKUP_I2C0_CLKCTRL (CM_WKUP + 0x0B8) #define CM_WKUP_ADC_TSC_CLKCTRL (CM_WKUP + 0x0BC) #define CM_DPLL 0x500 #define CLKSEL_TIMER7_CLK (CM_DPLL + 0x004) #define CLKSEL_TIMER2_CLK (CM_DPLL + 0x008) #define CLKSEL_TIMER3_CLK (CM_DPLL + 0x00C) #define CLKSEL_TIMER4_CLK (CM_DPLL + 0x010) #define CLKSEL_TIMER5_CLK (CM_DPLL + 0x018) #define CLKSEL_TIMER6_CLK (CM_DPLL + 0x01C) #define CLKSEL_PRUSS_OCP_CLK (CM_DPLL + 0x030) #define CM_RTC 0x800 #define CM_RTC_RTC_CLKCTRL (CM_RTC + 0x000) #define CM_RTC_CLKSTCTRL (CM_RTC + 0x004) #define PRM_PER 0xC00 #define PRM_PER_RSTCTRL (PRM_PER + 0x00) #define PRM_DEVICE_OFFSET 0xF00 #define PRM_RSTCTRL (PRM_DEVICE_OFFSET + 0x00) struct am335x_prcm_softc { struct resource * res[2]; bus_space_tag_t bst; bus_space_handle_t bsh; }; static struct resource_spec am335x_prcm_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; static struct am335x_prcm_softc *am335x_prcm_sc = NULL; static int am335x_clk_noop_activate(struct ti_clock_dev *clkdev); static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev); static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev); static int am335x_clk_noop_deactivate(struct ti_clock_dev *clkdev); static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev); static int am335x_clk_noop_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static void am335x_prcm_reset(void); static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev); static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev); static int am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev); static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev); #define AM335X_NOOP_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = am335x_clk_noop_activate, \ .clk_deactivate = am335x_clk_noop_deactivate, \ .clk_set_source = am335x_clk_noop_set_source, \ .clk_accessible = NULL, \ .clk_get_source_freq = NULL \ } #define AM335X_GENERIC_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = am335x_clk_generic_activate, \ .clk_deactivate = am335x_clk_generic_deactivate, \ .clk_set_source = am335x_clk_generic_set_source, \ .clk_accessible = NULL, \ .clk_get_source_freq = NULL \ } #define AM335X_GPIO_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = am335x_clk_gpio_activate, \ .clk_deactivate = am335x_clk_generic_deactivate, \ .clk_set_source = am335x_clk_generic_set_source, \ .clk_accessible = NULL, \ .clk_get_source_freq = NULL \ } #define AM335X_MMCHS_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = am335x_clk_generic_activate, \ .clk_deactivate = am335x_clk_generic_deactivate, \ .clk_set_source = am335x_clk_generic_set_source, \ .clk_accessible = NULL, \ .clk_get_source_freq = am335x_clk_hsmmc_get_source_freq \ } struct ti_clock_dev ti_am335x_clk_devmap[] = { /* System clocks */ { .id = SYS_CLK, .clk_activate = NULL, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = am335x_clk_get_sysclk_freq, }, /* MPU (ARM) core clocks */ { .id = MPU_CLK, .clk_activate = NULL, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = am335x_clk_get_arm_fclk_freq, }, /* CPSW Ethernet Switch core clocks */ { .id = CPSW_CLK, .clk_activate = am335x_clk_cpsw_activate, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = NULL, }, /* Mentor USB HS controller core clocks */ { .id = MUSB0_CLK, .clk_activate = am335x_clk_musb0_activate, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = NULL, }, /* LCD controller clocks */ { .id = LCDC_CLK, .clk_activate = am335x_clk_lcdc_activate, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = am335x_clk_get_arm_disp_freq, }, - /* UART. Uart0 clock cannot be controlled. */ - AM335X_NOOP_CLOCK_DEV(UART0_CLK), - AM335X_GENERIC_CLOCK_DEV(UART1_CLK), + /* UART */ + AM335X_NOOP_CLOCK_DEV(UART1_CLK), AM335X_GENERIC_CLOCK_DEV(UART2_CLK), AM335X_GENERIC_CLOCK_DEV(UART3_CLK), AM335X_GENERIC_CLOCK_DEV(UART4_CLK), AM335X_GENERIC_CLOCK_DEV(UART5_CLK), + AM335X_GENERIC_CLOCK_DEV(UART6_CLK), /* DMTimer */ - AM335X_GENERIC_CLOCK_DEV(DMTIMER2_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER3_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER4_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER5_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER6_CLK), - AM335X_GENERIC_CLOCK_DEV(DMTIMER7_CLK), + AM335X_GENERIC_CLOCK_DEV(TIMER2_CLK), + AM335X_GENERIC_CLOCK_DEV(TIMER3_CLK), + AM335X_GENERIC_CLOCK_DEV(TIMER4_CLK), + AM335X_GENERIC_CLOCK_DEV(TIMER5_CLK), + AM335X_GENERIC_CLOCK_DEV(TIMER6_CLK), + AM335X_GENERIC_CLOCK_DEV(TIMER7_CLK), - /* GPIO */ - AM335X_GPIO_CLOCK_DEV(GPIO0_CLK), + /* GPIO, we use hwmods as reference, not units in spec */ AM335X_GPIO_CLOCK_DEV(GPIO1_CLK), AM335X_GPIO_CLOCK_DEV(GPIO2_CLK), AM335X_GPIO_CLOCK_DEV(GPIO3_CLK), + AM335X_GPIO_CLOCK_DEV(GPIO4_CLK), - /* I2C */ - AM335X_GENERIC_CLOCK_DEV(I2C0_CLK), + /* I2C we use hwmods as reference, not units in spec */ AM335X_GENERIC_CLOCK_DEV(I2C1_CLK), AM335X_GENERIC_CLOCK_DEV(I2C2_CLK), + AM335X_GENERIC_CLOCK_DEV(I2C3_CLK), /* TSC_ADC */ AM335X_GENERIC_CLOCK_DEV(TSC_ADC_CLK), /* EDMA */ AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK), AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK), AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK), AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK), /* MMCHS */ - AM335X_MMCHS_CLOCK_DEV(MMC0_CLK), AM335X_MMCHS_CLOCK_DEV(MMC1_CLK), AM335X_MMCHS_CLOCK_DEV(MMC2_CLK), + AM335X_MMCHS_CLOCK_DEV(MMC3_CLK), /* PWMSS */ AM335X_GENERIC_CLOCK_DEV(PWMSS0_CLK), AM335X_GENERIC_CLOCK_DEV(PWMSS1_CLK), AM335X_GENERIC_CLOCK_DEV(PWMSS2_CLK), /* System Mailbox clock */ AM335X_GENERIC_CLOCK_DEV(MAILBOX0_CLK), /* SPINLOCK */ AM335X_GENERIC_CLOCK_DEV(SPINLOCK0_CLK), /* PRU-ICSS */ { .id = PRUSS_CLK, .clk_activate = am335x_clk_pruss_activate, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = NULL, }, /* RTC */ AM335X_GENERIC_CLOCK_DEV(RTC_CLK), { INVALID_CLK_IDENT, NULL, NULL, NULL, NULL } }; struct am335x_clk_details { clk_ident_t id; uint32_t clkctrl_reg; uint32_t clksel_reg; }; #define _CLK_DETAIL(i, c, s) \ { .id = (i), \ .clkctrl_reg = (c), \ .clksel_reg = (s), \ } static struct am335x_clk_details g_am335x_clk_details[] = { /* UART. UART0 clock not controllable. */ - _CLK_DETAIL(UART0_CLK, 0, 0), - _CLK_DETAIL(UART1_CLK, CM_PER_UART1_CLKCTRL, 0), - _CLK_DETAIL(UART2_CLK, CM_PER_UART2_CLKCTRL, 0), - _CLK_DETAIL(UART3_CLK, CM_PER_UART3_CLKCTRL, 0), - _CLK_DETAIL(UART4_CLK, CM_PER_UART4_CLKCTRL, 0), - _CLK_DETAIL(UART5_CLK, CM_PER_UART5_CLKCTRL, 0), + _CLK_DETAIL(UART1_CLK, 0, 0), + _CLK_DETAIL(UART2_CLK, CM_PER_UART1_CLKCTRL, 0), + _CLK_DETAIL(UART3_CLK, CM_PER_UART2_CLKCTRL, 0), + _CLK_DETAIL(UART4_CLK, CM_PER_UART3_CLKCTRL, 0), + _CLK_DETAIL(UART5_CLK, CM_PER_UART4_CLKCTRL, 0), + _CLK_DETAIL(UART6_CLK, CM_PER_UART5_CLKCTRL, 0), /* DMTimer modules */ - _CLK_DETAIL(DMTIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK), - _CLK_DETAIL(DMTIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK), - _CLK_DETAIL(DMTIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK), - _CLK_DETAIL(DMTIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK), - _CLK_DETAIL(DMTIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK), - _CLK_DETAIL(DMTIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK), + _CLK_DETAIL(TIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK), + _CLK_DETAIL(TIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK), + _CLK_DETAIL(TIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK), + _CLK_DETAIL(TIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK), + _CLK_DETAIL(TIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK), + _CLK_DETAIL(TIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK), - /* GPIO modules */ - _CLK_DETAIL(GPIO0_CLK, CM_WKUP_GPIO0_CLKCTRL, 0), - _CLK_DETAIL(GPIO1_CLK, CM_PER_GPIO1_CLKCTRL, 0), - _CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO2_CLKCTRL, 0), - _CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO3_CLKCTRL, 0), + /* GPIO modules, hwmods start with gpio1 */ + _CLK_DETAIL(GPIO1_CLK, CM_WKUP_GPIO0_CLKCTRL, 0), + _CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO1_CLKCTRL, 0), + _CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO2_CLKCTRL, 0), + _CLK_DETAIL(GPIO4_CLK, CM_PER_GPIO3_CLKCTRL, 0), - /* I2C modules */ - _CLK_DETAIL(I2C0_CLK, CM_WKUP_I2C0_CLKCTRL, 0), - _CLK_DETAIL(I2C1_CLK, CM_PER_I2C1_CLKCTRL, 0), - _CLK_DETAIL(I2C2_CLK, CM_PER_I2C2_CLKCTRL, 0), + /* I2C modules, hwmods start with i2c1 */ + _CLK_DETAIL(I2C1_CLK, CM_WKUP_I2C0_CLKCTRL, 0), + _CLK_DETAIL(I2C2_CLK, CM_PER_I2C1_CLKCTRL, 0), + _CLK_DETAIL(I2C3_CLK, CM_PER_I2C2_CLKCTRL, 0), /* TSC_ADC module */ _CLK_DETAIL(TSC_ADC_CLK, CM_WKUP_ADC_TSC_CLKCTRL, 0), /* EDMA modules */ _CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0), _CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0), _CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0), _CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0), - /* MMCHS modules*/ - _CLK_DETAIL(MMC0_CLK, CM_PER_MMC0_CLKCTRL, 0), - _CLK_DETAIL(MMC1_CLK, CM_PER_MMC1_CLKCTRL, 0), + /* MMCHS modules, hwmods start with mmc1*/ + _CLK_DETAIL(MMC1_CLK, CM_PER_MMC0_CLKCTRL, 0), _CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0), + _CLK_DETAIL(MMC3_CLK, CM_PER_MMC1_CLKCTRL, 0), /* PWMSS modules */ _CLK_DETAIL(PWMSS0_CLK, CM_PER_EPWMSS0_CLKCTRL, 0), _CLK_DETAIL(PWMSS1_CLK, CM_PER_EPWMSS1_CLKCTRL, 0), _CLK_DETAIL(PWMSS2_CLK, CM_PER_EPWMSS2_CLKCTRL, 0), _CLK_DETAIL(MAILBOX0_CLK, CM_PER_MAILBOX0_CLKCTRL, 0), _CLK_DETAIL(SPINLOCK0_CLK, CM_PER_SPINLOCK0_CLKCTRL, 0), /* RTC module */ _CLK_DETAIL(RTC_CLK, CM_RTC_RTC_CLKCTRL, 0), { INVALID_CLK_IDENT, 0}, }; /* Read/Write macros */ #define prcm_read_4(reg) \ bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg) #define prcm_write_4(reg, val) \ bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val) void am335x_prcm_setup_dmtimer(int); static int am335x_prcm_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (ofw_bus_is_compatible(dev, "am335x,prcm")) { + if (ofw_bus_is_compatible(dev, "ti,am3-prcm")) { device_set_desc(dev, "AM335x Power and Clock Management"); return(BUS_PROBE_DEFAULT); } return (ENXIO); } static int am335x_prcm_attach(device_t dev) { struct am335x_prcm_softc *sc = device_get_softc(dev); unsigned int sysclk, fclk; if (am335x_prcm_sc) return (ENXIO); if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->bst = rman_get_bustag(sc->res[0]); sc->bsh = rman_get_bushandle(sc->res[0]); am335x_prcm_sc = sc; ti_cpu_reset = am335x_prcm_reset; - am335x_clk_get_sysclk_freq(NULL, &sysclk); - am335x_clk_get_arm_fclk_freq(NULL, &fclk); - device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n", - sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000); + if (am335x_clk_get_sysclk_freq(NULL, &sysclk) != 0) + sysclk = 0; + if (am335x_clk_get_arm_fclk_freq(NULL, &fclk) != 0) + fclk = 0; + if (sysclk && fclk) + device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n", + sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000); + else + device_printf(dev, "can't read frequencies yet (SCM device not ready?)\n"); return (0); } static device_method_t am335x_prcm_methods[] = { DEVMETHOD(device_probe, am335x_prcm_probe), DEVMETHOD(device_attach, am335x_prcm_attach), { 0, 0 } }; static driver_t am335x_prcm_driver = { "am335x_prcm", am335x_prcm_methods, sizeof(struct am335x_prcm_softc), }; static devclass_t am335x_prcm_devclass; DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver, am335x_prcm_devclass, 0, 0); MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1); static struct am335x_clk_details* am335x_clk_details(clk_ident_t id) { struct am335x_clk_details *walker; for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) { if (id == walker->id) return (walker); } return NULL; } static int am335x_clk_noop_activate(struct ti_clock_dev *clkdev) { return (0); } static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; struct am335x_clk_details* clk_details; if (sc == NULL) return ENXIO; clk_details = am335x_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); /* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */ prcm_write_4(clk_details->clkctrl_reg, 2); while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2) DELAY(10); return (0); } static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; struct am335x_clk_details* clk_details; if (sc == NULL) return ENXIO; clk_details = am335x_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); /* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */ /* set *_CLKCTRL register OPTFCLKEN_GPIO_1_G DBCLK[18] to FCLK_EN(1) */ prcm_write_4(clk_details->clkctrl_reg, 2 | (1 << 18)); while ((prcm_read_4(clk_details->clkctrl_reg) & (3 | (1 << 18) )) != (2 | (1 << 18))) DELAY(10); return (0); } static int am335x_clk_noop_deactivate(struct ti_clock_dev *clkdev) { return(0); } static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; struct am335x_clk_details* clk_details; if (sc == NULL) return ENXIO; clk_details = am335x_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); /* set *_CLKCTRL register MODULEMODE[1:0] to disable(0) */ prcm_write_4(clk_details->clkctrl_reg, 0); while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 0) DELAY(10); return (0); } static int am335x_clk_noop_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) { return (0); } static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) { struct am335x_prcm_softc *sc = am335x_prcm_sc; struct am335x_clk_details* clk_details; uint32_t reg; if (sc == NULL) return ENXIO; clk_details = am335x_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); switch (clksrc) { case EXT_CLK: reg = 0; /* SEL2: TCLKIN clock */ break; case SYSCLK_CLK: reg = 1; /* SEL1: CLK_M_OSC clock */ break; case F32KHZ_CLK: reg = 2; /* SEL3: CLK_32KHZ clock */ break; default: return (ENXIO); } prcm_write_4(clk_details->clksel_reg, reg); while ((prcm_read_4(clk_details->clksel_reg) & 0x3) != reg) DELAY(10); return (0); } static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { *freq = 96000000; return (0); } static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { uint32_t ctrl_status; /* Read the input clock freq from the control module */ /* control_status reg (0x40) */ if (ti_scm_reg_read_4(0x40, &ctrl_status)) return ENXIO; switch ((ctrl_status>>22) & 0x3) { case 0x0: /* 19.2Mhz */ *freq = 19200000; break; case 0x1: /* 24Mhz */ *freq = 24000000; break; case 0x2: /* 25Mhz */ *freq = 25000000; break; case 0x3: /* 26Mhz */ *freq = 26000000; break; } return (0); } #define DPLL_BYP_CLKSEL(reg) ((reg>>23) & 1) #define DPLL_DIV(reg) ((reg & 0x7f)+1) #define DPLL_MULT(reg) ((reg>>8) & 0x7FF) static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { uint32_t reg; uint32_t sysclk; reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_MPU); /*Check if we are running in bypass */ if (DPLL_BYP_CLKSEL(reg)) return ENXIO; am335x_clk_get_sysclk_freq(NULL, &sysclk); *freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg)); return(0); } static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { uint32_t reg; uint32_t sysclk; reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_DISP); /*Check if we are running in bypass */ if (DPLL_BYP_CLKSEL(reg)) return ENXIO; am335x_clk_get_sysclk_freq(NULL, &sysclk); *freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg)); return(0); } static void am335x_prcm_reset(void) { prcm_write_4(PRM_RSTCTRL, (1<<1)); } static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; if (sc == NULL) return ENXIO; /* set MODULENAME to ENABLE */ prcm_write_4(CM_PER_CPGMAC0_CLKCTRL, 2); /* wait for IDLEST to become Func(0) */ while(prcm_read_4(CM_PER_CPGMAC0_CLKCTRL) & (3<<16)); /*set CLKTRCTRL to SW_WKUP(2) */ prcm_write_4(CM_PER_CPSW_CLKSTCTRL, 2); /* wait for 125 MHz OCP clock to become active */ while((prcm_read_4(CM_PER_CPSW_CLKSTCTRL) & (1<<4)) == 0); return(0); } static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; if (sc == NULL) return ENXIO; /* set ST_DPLL_CLKDCOLDO(9) to CLK_GATED(1) */ /* set DPLL_CLKDCOLDO_GATE_CTRL(8) to CLK_ENABLE(1)*/ prcm_write_4(CM_WKUP_CM_CLKDCOLDO_DPLL_PER, 0x300); /*set MODULEMODE to ENABLE(2) */ prcm_write_4(CM_PER_USB0_CLKCTRL, 2); /* wait for MODULEMODE to become ENABLE(2) */ while ((prcm_read_4(CM_PER_USB0_CLKCTRL) & 0x3) != 2) DELAY(10); /* wait for IDLEST to become Func(0) */ while(prcm_read_4(CM_PER_USB0_CLKCTRL) & (3<<16)) DELAY(10); return(0); } static int am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; if (sc == NULL) return (ENXIO); /* Bypass mode */ prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x4); /* Make sure it's in bypass mode */ while (!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP) & (1 << 8))) DELAY(10); /* * For now set frequency to 99*SYSFREQ/8 which is twice as * HDMI 1080p pixel clock (minimum LCDC freq divisor is 2) */ prcm_write_4(CM_WKUP_CM_CLKSEL_DPLL_DISP, (99 << 8) | 8); /* Locked mode */ prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x7); int timeout = 10000; while ((!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP) & (1 << 0))) && timeout--) DELAY(10); /*set MODULEMODE to ENABLE(2) */ prcm_write_4(CM_PER_LCDC_CLKCTRL, 2); /* wait for MODULEMODE to become ENABLE(2) */ while ((prcm_read_4(CM_PER_LCDC_CLKCTRL) & 0x3) != 2) DELAY(10); /* wait for IDLEST to become Func(0) */ while(prcm_read_4(CM_PER_LCDC_CLKCTRL) & (3<<16)) DELAY(10); return (0); } static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; if (sc == NULL) return (ENXIO); /* Set MODULEMODE to ENABLE(2) */ prcm_write_4(CM_PER_PRUSS_CLKCTRL, 2); /* Wait for MODULEMODE to become ENABLE(2) */ while ((prcm_read_4(CM_PER_PRUSS_CLKCTRL) & 0x3) != 2) DELAY(10); /* Set CLKTRCTRL to SW_WKUP(2) */ prcm_write_4(CM_PER_PRUSS_CLKSTCTRL, 2); /* Wait for the 200 MHz OCP clock to become active */ while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<4)) == 0) DELAY(10); /* Wait for the 200 MHz IEP clock to become active */ while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<5)) == 0) DELAY(10); /* Wait for the 192 MHz UART clock to become active */ while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<6)) == 0) DELAY(10); /* Select L3F as OCP clock */ prcm_write_4(CLKSEL_PRUSS_OCP_CLK, 0); while ((prcm_read_4(CLKSEL_PRUSS_OCP_CLK) & 0x3) != 0) DELAY(10); /* Clear the RESET bit */ prcm_write_4(PRM_PER_RSTCTRL, prcm_read_4(PRM_PER_RSTCTRL) & ~2); return (0); } Index: head/sys/arm/ti/am335x/am335x_pwm.h =================================================================== --- head/sys/arm/ti/am335x/am335x_pwm.h (revision 283275) +++ head/sys/arm/ti/am335x/am335x_pwm.h (revision 283276) @@ -1,33 +1,33 @@ /*- * Copyright (c) 2013 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 __AM335X_PWM_H__ #define __AM335X_PWM_H__ -int am335x_pwm_config_ecas(int unit, int period, int duty); +int am335x_pwm_config_ecap(int unit, int period, int duty); #endif /* __AM335X_PWM_H__ */ Index: head/sys/arm/ti/am335x/am335x_pwmss.c =================================================================== --- head/sys/arm/ti/am335x/am335x_pwmss.c (nonexistent) +++ head/sys/arm/ti/am335x/am335x_pwmss.c (revision 283276) @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 2013 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "am335x_pwm.h" +#include "am335x_scm.h" + +#define PWMSS_IDVER 0x00 +#define PWMSS_SYSCONFIG 0x04 +#define PWMSS_CLKCONFIG 0x08 +#define CLKCONFIG_EPWMCLK_EN (1 << 8) +#define PWMSS_CLKSTATUS 0x0C + +static device_probe_t am335x_pwmss_probe; +static device_attach_t am335x_pwmss_attach; +static device_detach_t am335x_pwmss_detach; + +struct am335x_pwmss_softc { + device_t sc_dev; + clk_ident_t sc_clk; +}; + +static device_method_t am335x_pwmss_methods[] = { + DEVMETHOD(device_probe, am335x_pwmss_probe), + DEVMETHOD(device_attach, am335x_pwmss_attach), + DEVMETHOD(device_detach, am335x_pwmss_detach), + + DEVMETHOD_END +}; + +static int +am335x_pwmss_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ti,am33xx-pwmss")) + return (ENXIO); + + device_set_desc(dev, "AM335x PWM"); + + return (BUS_PROBE_DEFAULT); +} + +static int +am335x_pwmss_attach(device_t dev) +{ + struct am335x_pwmss_softc *sc; + uint32_t reg, id; + phandle_t node; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + sc->sc_clk = ti_hwmods_get_clock(dev); + if (sc->sc_clk == INVALID_CLK_IDENT) { + device_printf(dev, "failed to get device id based on ti,hwmods\n"); + return (EINVAL); + } + + ti_prcm_clk_enable(sc->sc_clk); + ti_scm_reg_read_4(SCM_PWMSS_CTRL, ®); + switch (sc->sc_clk) { + case PWMSS0_CLK: + id = 0; + break; + case PWMSS1_CLK: + id = 1; + break; + + case PWMSS2_CLK: + id = 2; + break; + default: + device_printf(dev, "unknown pwmss clock id: %d\n", sc->sc_clk); + return (EINVAL); + } + reg |= (1 << id); + ti_scm_reg_write_4(SCM_PWMSS_CTRL, reg); + + node = ofw_bus_get_node(dev); + + if (node == -1) + return (ENXIO); + + simplebus_init(dev, node); + + /* + * Allow devices to identify. + */ + bus_generic_probe(dev); + + /* + * Now walk the OFW tree and attach top-level devices. + */ + for (node = OF_child(node); node > 0; node = OF_peer(node)) + simplebus_add_device(dev, node, 0, NULL, -1, NULL); + + return (bus_generic_attach(dev)); +} + +static int +am335x_pwmss_detach(device_t dev) +{ + + return (0); +} + +DEFINE_CLASS_1(am335x_pwmss, am335x_pwmss_driver, am335x_pwmss_methods, + sizeof(struct am335x_pwmss_softc), simplebus_driver); +static devclass_t am335x_pwmss_devclass; +DRIVER_MODULE(am335x_pwmss, simplebus, am335x_pwmss_driver, am335x_pwmss_devclass, 0, 0); +MODULE_VERSION(am335x_pwmss, 1); Property changes on: head/sys/arm/ti/am335x/am335x_pwmss.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/am335x/am335x_scm_padconf.c =================================================================== --- head/sys/arm/ti/am335x/am335x_scm_padconf.c (revision 283275) +++ head/sys/arm/ti/am335x/am335x_scm_padconf.c (revision 283276) @@ -1,303 +1,303 @@ /*- * Copyright (c) 2012 Damjan Marion * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #define _PIN(r, b, gp, gm, m0, m1, m2, m3, m4, m5, m6, m7) \ { .reg_off = r, \ .gpio_pin = gp, \ .gpio_mode = gm, \ .ballname = b, \ .muxmodes[0] = m0, \ .muxmodes[1] = m1, \ .muxmodes[2] = m2, \ .muxmodes[3] = m3, \ .muxmodes[4] = m4, \ .muxmodes[5] = m5, \ .muxmodes[6] = m6, \ .muxmodes[7] = m7, \ } -const static struct ti_scm_padstate ti_padstate_devmap[] = { +const static struct ti_pinmux_padstate ti_padstate_devmap[] = { {"output", PADCONF_OUTPUT }, {"output_pullup", PADCONF_OUTPUT_PULLUP }, {"input", PADCONF_INPUT }, {"input_pulldown", PADCONF_INPUT_PULLDOWN }, {"input_pullup", PADCONF_INPUT_PULLUP }, {"i2c", PADCONF_INPUT_PULLUP_SLOW }, { .state = NULL } }; -const static struct ti_scm_padconf ti_padconf_devmap[] = { - _PIN(0x800, "GPMC_AD0", 32, 7,"gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0"), - _PIN(0x804, "GPMC_AD1", 33, 7,"gpmc_ad1", "mmc1_dat1", NULL, NULL, NULL, NULL, NULL, "gpio1_1"), - _PIN(0x808, "GPMC_AD2", 34, 7,"gpmc_ad2", "mmc1_dat2", NULL, NULL, NULL, NULL, NULL, "gpio1_2"), - _PIN(0x80C, "GPMC_AD3", 35, 7,"gpmc_ad3", "mmc1_dat3", NULL, NULL, NULL, NULL, NULL, "gpio1_3"), - _PIN(0x810, "GPMC_AD4", 36, 7,"gpmc_ad4", "mmc1_dat4", NULL, NULL, NULL, NULL, NULL, "gpio1_4"), - _PIN(0x814, "GPMC_AD5", 37, 7,"gpmc_ad5", "mmc1_dat5", NULL, NULL, NULL, NULL, NULL, "gpio1_5"), - _PIN(0x818, "GPMC_AD6", 38, 7,"gpmc_ad6", "mmc1_dat6", NULL, NULL, NULL, NULL, NULL, "gpio1_6"), - _PIN(0x81C, "GPMC_AD7", 39, 7,"gpmc_ad7", "mmc1_dat7", NULL, NULL, NULL, NULL, NULL, "gpio1_7"), - _PIN(0x820, "GPMC_AD8", 22, 7, "gpmc_ad8", "lcd_data23", "mmc1_dat0", "mmc2_dat4", "ehrpwm2A", NULL, NULL, "gpio0_22"), - _PIN(0x824, "GPMC_AD9", 23, 7, "gpmc_ad9", "lcd_data22", "mmc1_dat1", "mmc2_dat5", "ehrpwm2B", NULL, NULL, "gpio0_23"), - _PIN(0x828, "GPMC_AD10", 26, 7, "gpmc_ad10", "lcd_data21", "mmc1_dat2", "mmc2_dat6", "ehrpwm2_tripzone_in", NULL, NULL, "gpio0_26"), - _PIN(0x82C, "GPMC_AD11", 27, 7, "gpmc_ad11", "lcd_data20", "mmc1_dat3", "mmc2_dat7", "ehrpwm0_synco", NULL, NULL, "gpio0_27"), - _PIN(0x830, "GPMC_AD12", 44, 7, "gpmc_ad12", "lcd_data19", "mmc1_dat4", "mmc2_dat0", "eQEP2A_in", "pr1_mii0_txd2", "pr1_pru0_pru_r30_14", "gpio1_12"), - _PIN(0x834, "GPMC_AD13", 45, 7, "gpmc_ad13", "lcd_data18", "mmc1_dat5", "mmc2_dat1", "eQEP2B_in", "pr1_mii0_txd1", "pr1_pru0_pru_r30_15", "gpio1_13"), - _PIN(0x838, "GPMC_AD14", 46, 7, "gpmc_ad14", "lcd_data17", "mmc1_dat6", "mmc2_dat2", "eQEP2_index", "pr1_mii0_txd0", "pr1_pru0_pru_r31_14", "gpio1_14"), - _PIN(0x83C, "GPMC_AD15", 47, 7, "gpmc_ad15", "lcd_data16", "mmc1_dat7", "mmc2_dat3", "eQEP2_strobe", "pr1_ecap0_ecap_capin_apwm_o", "pr1_pru0_pru_r31_15", "gpio1_15"), - _PIN(0x840, "GPMC_A0", 48, 7, "gpmc_a0", "gmii2_txen", "rgmii2_tctl", "rmii2_txen", "gpmc_a16", "pr1_mii_mt1_clk", "ehrpwm1_tripzone_input", "gpio1_16"), - _PIN(0x844, "GPMC_A1", 49, 7, "gpmc_a1", "gmii2_rxdv", "rgmii2_rctl", "mmc2_dat0", "gpmc_a17", "pr1_mii1_txd3", "ehrpwm0_synco", "gpio1_17"), - _PIN(0x848, "GPMC_A2", 50, 7, "gpmc_a2", "gmii2_txd3", "rgmii2_td3", "mmc2_dat1", "gpmc_a18", "pr1_mii1_txd2", "ehrpwm1A", "gpio1_18"), - _PIN(0x84C, "GPMC_A3", 51, 7, "gpmc_a3", "gmii2_txd2", "rgmii2_td2", "mmc2_dat2", "gpmc_a19", "pr1_mii1_txd1", "ehrpwm1B", "gpio1_19"), - _PIN(0x850, "GPMC_A4", 52, 7, "gpmc_a4", "gmii2_txd1", "rgmii2_td1", "rmii2_tdx1", "gpmc_a20", "pr1_mii1_txd0", "eQEP1A_in", "gpio1_20"), - _PIN(0x854, "GPMC_A5", 53, 7, "gpmc_a5", "gmii2_txd0", "rgmii2_td0", "rmii2_txd0", "gpmc_a21", "pr1_mii1_rxd3", "eQEP1B_in", "gpio1_21"), - _PIN(0x858, "GPMC_A6", 54, 7, "gpmc_a6", "gmii2_txclk", "rgmii2_tclk", "mmc2_dat4", "gpmc_a22", "pr1_mii1_rxd2", "eQEP1_index", "gpio1_22"), - _PIN(0x85C, "GPMC_A7", 55, 7, "gpmc_a7", "gmii2_rxclk", "rgmii2_rclk", "mmc2_dat5", "gpmc_a23", "pr1_mii1_rxd1", "eQEP1_strobe", "gpio1_23"), - _PIN(0x860, "GPMC_A8", 56, 7, "gpmc_a8", "gmii2_rxd3", "rgmii2_rd3", "mmc2_dat6", "gpmc_a24", "pr1_mii1_rxd0", "mcasp0_aclkx", "gpio1_24"), - _PIN(0x864, "GPMC_A9", 57, 7, "gmpc_a9", "gmii2_rxd2", "rgmii2_rd2", "mmc2_dat7 / rmii2_crs_dv", "gpmc_a25", "pr1_mii_mr1_clk", "mcasp0_fsx", "gpio1_25"), - _PIN(0x868, "GPMC_A10", 58, 7, "gmpc_a10", "gmii2_rxd1", "rgmii2_rd1", "rmii2_rxd1", "gpmc_a26", "pr1_mii1_rxdv", "mcasp0_arx0", "gpio1_26"), - _PIN(0x86C, "GPMC_A11", 59, 7, "gmpc_a11", "gmii2_rxd0", "rgmii2_rd0", "rmii2_rxd0", "gpmc_a27", "pr1_mii1_rxer", "mcasp0_axr1", "gpio1_27"), - _PIN(0x870, "GPMC_WAIT0", 30, 7, "gpmc_wait0", "gmii2_crs", "gpmc_csn4", "rmii2_crs_dv", "mmc1_sdcd", "pr1_mii1_col", "uart4_rxd", "gpio0_30"), - _PIN(0x874, "GPMC_WPn", 31, 7, "gpmc_wpn", "gmii2_rxerr", "gpmc_csn5", "rmii2_rxerr", "mmc2_sdcd", "pr1_mii1_txen", "uart4_txd", "gpio0_31"), - _PIN(0x878, "GPMC_BEn1", 60, 7, "gpmc_be1n", "gmii2_col", "gmpc_csn6","mmc2_dat3", "gpmc_dir", "pr1_mii1_rxlink", "mcasp0_aclkr", "gpio1_28"), - _PIN(0x87c, "GPMC_CSn0", 61, 7, "gpmc_csn0", NULL, NULL, NULL, NULL, NULL, NULL, "gpio1_29"), - _PIN(0x880, "GPMC_CSn1", 62, 7, "gpmc_csn1", "gpmc_clk", "mmc1_clk", "pr1_edio_data_in6", "pr1_edio_data_out6", "pr1_pru1_pru_r30_12", "pr1_pru1_pru_r31_12", "gpio1_30"), - _PIN(0x884, "GPMC_CSn2", 63, 7, "gpmc_csn2", "gpmc_be1n", "mmc1_cmd", "pr1_edio_data_in7", "pr1_edio_data_out7", "pr1_pru1_pru_r30_13", "pr1_pru1_pru_r31_13", "gpio1_31"), - _PIN(0x888, "GPMC_CSn3", 64, 7, "gpmc_csn3", "gpmc_a3", "rmii2_crs_dv", "mmc2_cmd", "pr1_mii0_crs", "pr1_mdio_data", "EMU4", "gpio2_0"), - _PIN(0x88c, "GPMC_CLK", 65, 7, "gpmc_clk", "lcd_memory_clk", "gpmc_wait1", "mmc2_clk", "pr1_mii1_crs", "pr1_mdio_mdclk", "mcasp0_fsr", "gpio2_1"), - _PIN(0x890, "GPMC_ADVn_ALE", 66, 7, "gpmc_advn_ale", NULL, "timer4", NULL, NULL, NULL, NULL, "gpio2_2"), - _PIN(0x894, "GPMC_OEn_REn", 67, 7, "gpmc_oen_ren", NULL, "timer7", NULL, NULL, NULL, NULL, "gpio2_3"), - _PIN(0x898, "GPMC_WEn", 68, 7, "gpmc_wen", NULL, "timer6", NULL, NULL, NULL, NULL, "gpio2_4"), - _PIN(0x89c, "GPMC_BEn0_CLE", 67, 7, "gpmc_ben0_cle", NULL, "timer5", NULL, NULL, NULL, NULL, "gpio2_5"), - _PIN(0x8a0, "LCD_DATA0", 68, 7, "lcd_data0", "gpmc_a0", "pr1_mii_mt0_clk", "ehrpwm2A", NULL, "pr1_pru1_pru_r30_0", "pr1_pru1_pru_r31_0", "gpio2_6"), - _PIN(0x8a4, "LCD_DATA1", 69, 7, "lcd_data1", "gpmc_a1", "pr1_mii0_txen", "ehrpwm2B", NULL, "pr1_pru1_pru_r30_1", "pr1_pru1_pru_r31_1", "gpio2_7"), - _PIN(0x8a8, "LCD_DATA2", 70, 7, "lcd_data2", "gpmc_a2", "pr1_mii0_txd3", "ehrpwm2_tripzone_input", NULL, "pr1_pru1_pru_r30_2", "pr1_pru1_pru_r31_2", "gpio2_8"), - _PIN(0x8ac, "LCD_DATA3", 71, 7, "lcd_data3", "gpmc_a3", "pr1_mii0_txd2", "ehrpwm0_synco", NULL, "pr1_pru1_pru_r30_3", "pr1_pru1_pru_r31_3", "gpio2_9"), - _PIN(0x8b0, "LCD_DATA4", 72, 7, "lcd_data4", "gpmc_a4", "pr1_mii0_txd1", "eQEP2A_in", NULL, "pr1_pru1_pru_r30_4", "pr1_pru1_pru_r31_4", "gpio2_10"), - _PIN(0x8b4, "LCD_DATA5", 73, 7, "lcd_data5", "gpmc_a5", "pr1_mii0_txd0", "eQEP2B_in", NULL, "pr1_pru1_pru_r30_5", "pr1_pru1_pru_r31_5", "gpio2_11"), - _PIN(0x8b8, "LCD_DATA6", 74, 7, "lcd_data6", "gpmc_a6", "pr1_edio_data_in6", "eQEP2_index", "pr1_edio_data_out6", "pr1_pru1_pru_r30_6", "pr1_pru1_pru_r31_6", "gpio2_12"), - _PIN(0x8bc, "LCD_DATA7", 75, 7, "lcd_data7", "gpmc_a7", "pr1_edio_data_in7", "eQEP2_strobe", "pr1_edio_data_out7", "pr1_pru1_pru_r30_7", "pr1_pru1_pru_r31_7", "gpio2_13"), - _PIN(0x8c0, "LCD_DATA8", 76, 7, "lcd_data8", "gpmc_a12", "ehrpwm1_tripzone_input", "mcasp0_aclkx", "uart5_txd", "pr1_mii0_rxd3", "uart2_ctsn", "gpio2_14"), - _PIN(0x8c4, "LCD_DATA9", 76, 7, "lcd_data9", "gpmc_a13", "ehrpwm0_synco", "mcasp0_fsx", "uart5_rxd", "pr1_mii0_rxd2", "uart2_rtsn", "gpio2_15"), - _PIN(0x8c8, "LCD_DATA10", 77, 7, "lcd_data10", "gpmc_a14", "ehrpwm1A", "mcasp0_axr0", NULL, "pr1_mii0_rxd1", "uart3_ctsn", "gpio2_16"), - _PIN(0x8cc, "LCD_DATA11", 78, 7, "lcd_data11", "gpmc_a15", "ehrpwm1B", "mcasp0_ahclkr", "mcasp0_axr2", "pr1_mii0_rxd0", "uart3_rtsn", "gpio2_17"), - _PIN(0x8d0, "LCD_DATA12", 8, 7, "lcd_data12", "gpmc_a16", "eQEP1A_in", "mcasp0_aclkr", "mcasp0_axr2", "pr1_mii0_rxlink", "uart4_ctsn", "gpio0_8"), - _PIN(0x8d4, "LCD_DATA13", 9, 7, "lcd_data13", "gpmc_a17", "eQEP1B_in", "mcasp0_fsr", "mcasp0_axr3", "pr1_mii0_rxer", "uart4_rtsn", "gpio0_9"), - _PIN(0x8d8, "LCD_DATA14", 10, 7, "lcd_data14", "gpmc_a18", "eQEP1_index", "mcasp0_axr1", "uart5_rxd", "pr1_mii_mr0_clk", "uart5_ctsn", "gpio0_10"), - _PIN(0x8dc, "LCD_DATA15", 11, 7, "lcd_data15", "gpmc_a19", "eQEP1_strobe", "mcasp0_ahclkx", "mcasp0_axr3", "pr1_mii0_rxdv", "uart5_rtsn", "gpio0_11"), - _PIN(0x8e0, "LCD_VSYNC", 86, 7, "lcd_vsync", "gpmc_a8", "gpmc_a1", "pr1_edio_data_in2", "pr1_edio_data_out2", "pr1_pru1_pru_r30_8", "pr1_pru1_pru_r31_8", "gpio2_22"), - _PIN(0x8e4, "LCD_HSYNC", 87, 7, "lcd_hsync", "gmpc_a9", "gpmc_a2", "pr1_edio_data_in3", "pr1_edio_data_out3", "pr1_pru1_pru_r30_9", "pr1_pru1_pru_r31_9", "gpio2_23"), - _PIN(0x8e8, "LCD_PCLK", 88, 7, "lcd_pclk", "gpmc_a10", "pr1_mii0_crs", "pr1_edio_data_in4", "pr1_edio_data_out4", "pr1_pru1_pru_r30_10", "pr1_pru1_pru_r31_10", "gpio2_24"), - _PIN(0x8ec, "LCD_AC_BIAS_EN", 89, 7, "lcd_ac_bias_en", "gpmc_a11", "pr1_mii1_crs", "pr1_edio_data_in5", "pr1_edio_data_out5", "pr1_pru1_pru_r30_11", "pr1_pru1_pru_r31_11", "gpio2_25"), - _PIN(0x8f0, "MMC0_DAT3", 90, 7, "mmc0_dat3", "gpmc_a20", "uart4_ctsn", "timer5", "uart1_dcdn", "pr1_pru0_pru_r30_8", "pr1_pru0_pru_r31_8", "gpio2_26"), - _PIN(0x8f4, "MMC0_DAT2", 91, 7, "mmc0_dat2", "gpmc_a21", "uart4_rtsn", "timer6", "uart1_dsrn", "pr1_pru0_pru_r30_9", "pr1_pru0_pru_r31_9", "gpio2_27"), - _PIN(0x8f8, "MMC0_DAT1", 92, 7, "mmc0_dat1", "gpmc_a22", "uart5_ctsn", "uart3_rxd", "uart1_dtrn", "pr1_pru0_pru_r30_10", "pr1_pru0_pru_r31_10", "gpio2_28"), - _PIN(0x8fc, "MMC0_DAT0", 93, 7, "mmc0_dat0", "gpmc_a23", "uart5_rtsn", "uart3_txd", "uart1_rin", "pr1_pru0_pru_r30_11", "pr1_pru0_pru_r31_11", "gpio2_29"), - _PIN(0x900, "MMC0_CLK", 94, 7, "mmc0_clk", "gpmc_a24", "uart3_ctsn", "uart2_rxd", "dcan1_tx", "pr1_pru0_pru_r30_12", "pr1_pru0_pru_r31_12", "gpio2_30"), - _PIN(0x904, "MMC0_CMD", 95, 7, "mmc0_cmd", "gpmc_a25", "uart3_rtsn", "uart2_txd", "dcan1_rx", "pr1_pru0_pru_r30_13", "pr1_pru0_pru_r31_13", "gpio2_31"), - _PIN(0x908, "MII1_COL", 96, 7, "gmii1_col", "rmii2_refclk", "spi1_sclk", "uart5_rxd", "mcasp1_axr2", "mmc2_dat3", "mcasp0_axr2", "gpio3_0"), - _PIN(0x90c, "MII1_CRS", 97, 7, "gmii1_crs", "rmii1_crs_dv", "spi1_d0", "I2C1_SDA", "mcasp1_aclkx", "uart5_ctsn", "uart2_rxd", "gpio3_1"), - _PIN(0x910, "MII1_RX_ER", 98, 7, "gmii1_rxerr", "rmii1_rxerr", "spi1_d1", "I2C1_SCL", "mcasp1_fsx", "uart5_rtsn", "uart2_txd", "gpio3_2"), - _PIN(0x914, "MII1_TX_EN", 99, 7, "gmii1_txen", "rmii1_txen", "rgmii1_tctl", "timer4", "mcasp1_axr0", "eQEP0_index", "mmc2_cmd", "gpio3_3"), - _PIN(0x918, "MII1_RX_DV", 100, 7, "gmii1_rxdv", "cd_memory_clk", "rgmii1_rctl", "uart5_txd", "mcasp1_aclkx", "mmc2_dat0", "mcasp0_aclkr", "gpio3_4"), - _PIN(0x91c, "MII1_TXD3", 16, 7, "gmii1_txd3", "dcan0_tx", "rgmii1_td3", "uart4_rxd", "mcasp1_fsx", "mmc2_dat1", "mcasp0_fsr", "gpio0_16"), - _PIN(0x920, "MII1_TXD2", 17, 7, "gmii1_txd2", "dcan0_rx", "rgmii1_td2", "uart4_txd", "mcasp1_axr0", "mmc2_dat2", "mcasp0_ahclkx", "gpio0_17"), - _PIN(0x924, "MII1_TXD1", 21, 7, "gmii1_txd1", "rmii1_txd1", "rgmii1_td1", "mcasp1_fsr", "mcasp1_axr1", "eQEP0A_in", "mmc1_cmd", "gpio0_21"), - _PIN(0x928, "MII1_TXD0", 28, 7, "gmii1_txd0", "rmii1_txd0", "rgmii1_td0", "mcasp1_axr2", "mcasp1_aclkr", "eQEP0B_in", "mmc1_clk", "gpio0_28"), - _PIN(0x92c, "MII1_TX_CLK", 105, 7, "gmii1_txclk", "uart2_rxd", "rgmii1_tclk", "mmc0_dat7", "mmc1_dat0", "uart1_dcdn", "mcasp0_aclkx", "gpio3_9"), - _PIN(0x930, "MII1_RX_CLK", 106, 7, "gmii1_rxclk", "uart2_txd", "rgmii1_rclk", "mmc0_dat6", "mmc1_dat1", "uart1_dsrn", "mcasp0_fsx", "gpio3_10"), - _PIN(0x934, "MII1_RXD3", 82, 7, "gmii1_rxd3", "uart3_rxd", "rgmii1_rd3", "mmc0_dat5", "mmc1_dat2", "uart1_dtrn", "mcasp0_axr0", "gpio2_18"), - _PIN(0x938, "MII1_RXD2", 83, 7, "gmii1_rxd2", "uart3_txd", "rgmii1_rd2", "mmc0_dat4", "mmc1_dat3", "uart1_rin", "mcasp0_axr1", "gpio2_19"), - _PIN(0x93c, "MII1_RXD1", 84, 7, "gmii1_rxd1", "rmii1_rxd1", "rgmii1_rd1", "mcasp1_axr3", "mcasp1_fsr", "eQEP0_strobe", "mmc2_clk", "gpio2_20"), - _PIN(0x940, "MII1_RXD0", 85, 7, "gmii1_rxd0", "rmii1_rxd0", "rgmii1_rd0", "mcasp1_ahclkx", "mcasp1_ahclkr", "mcasp1_aclkr", "mcasp0_axr3", "gpio2_21"), - _PIN(0x944, "RMII1_REF_CLK", 29, 7, "rmii1_refclk", "xdma_event_intr2", "spi1_cs0", "uart5_txd", "mcasp1_axr3", "mmc0_pow", "mcasp1_ahclkx", "gpio0_29"), - _PIN(0x948, "MDIO", 0, 7, "mdio_data", "timer6", "uart5_rxd", "uart3_ctsn", "mmc0_sdcd","mmc1_cmd", "mmc2_cmd","gpio0_0"), - _PIN(0x94c, "MDC", 1, 7, "mdio_clk", "timer5", "uart5_txd", "uart3_rtsn", "mmc0_sdwp", "mmc1_clk", "mmc2_clk", "gpio0_1"), - _PIN(0x950, "SPI0_SCLK", 2, 7, "spi0_sclk", "uart2_rxd", "I2C2_SDA", "ehrpwm0A", "pr1_uart0_cts_n", "pr1_edio_sof", "EMU2", "gpio0_2"), - _PIN(0x954, "SPI0_D0", 3, 7, "spi0_d0", "uart2_txd", "I2C2_SCL", "ehrpwm0B", "pr1_uart0_rts_n", "pr1_edio_latch_in", "EMU3", "gpio0_3"), - _PIN(0x958, "SPI0_D1", 4, 7, "spi0_d1", "mmc1_sdwp", "I2C1_SDA", "ehrpwm0_tripzone_input", "pr1_uart0_rxd", "pr1_edio_data_in0", "pr1_edio_data_out0", "gpio0_4"), - _PIN(0x95c, "SPI0_CS0", 5, 7, "spi0_cs0", "mmc2_sdwp", "I2C1_SCL", "ehrpwm0_synci", "pr1_uart0_txd", "pr1_edio_data_in1", "pr1_edio_data_out1", "gpio0_5"), - _PIN(0x960, "SPI0_CS1", 6, 7, "spi0_cs1", "uart3_rxd", "eCAP1_in_PWM1_out", "mcc0_pow", "xdm_event_intr2", "mmc0_sdcd", "EMU4", "gpio0_6"), - _PIN(0x964, "ECAP0_IN_PWM0_OUT",7, 7, "eCAP0_in_PWM0_out", "uart3_txd", "spi1_cs1", "pr1_ecap0_ecap_capin_apwm_o", "spi1_sclk", "mmc0_sdwp", "xdma_event_intr2", "gpio0_7"), - _PIN(0x968, "UART0_CTSn", 40, 7, "uart0_ctsn", "uart4_rxd", "dcan1_tx", "I2C1_SDA", "spi1_d0", "timer7", "pr1_edc_sync0_out", "gpio1_8"), - _PIN(0x96c, "UART0_RTSn", 41, 7, "uart0_rtsn", "uart4_txd", "dcan1_rx", "I2C1_SCL", "spi1_d1", "spi1_cs0", "pr1_edc_sync1_out", "gpio1_9"), - _PIN(0x970, "UART0_rxd", 42, 7, "uart0_rxd", "spi1_cs0", "dcan0_tx", "I2C2_SDA", "eCAP2_in_PWM2_out", "pr1_pru1_pru_r30_14", "pr1_pru1_pru_r31_14", "gpio1_10"), - _PIN(0x974, "UART0_txd", 43, 7, "uart0_txd", "spi1_cs1", "dcan0_rx", "I2C2_SCL", "eCAP1_in_PWM1_out", "pr1_pru1_pru_r30_15", "pr1_pru1_pru_r31_15", "gpio1_11"), - _PIN(0x978, "UART1_CTSn", 12, 7, "uart1_ctsn", "timer6_mux1", "dcan0_tx", "I2C2_SDA", "spi1_cs0", "pr1_uart0_cts_n", "pr1_edc_latch0_in", "gpio0_12"), - _PIN(0x97c, "UART1_RTSn", 13, 7, "uart1_rtsn", "timer5_mux1", "dcan0_rx", "I2C2_SCL", "spi1_cs1", "pr1_uart0_rts_n", "pr1_edc_latch1_in", "gpio0_13"), - _PIN(0x980, "UART1_RXD", 14, 7, "uart1_rxd", "mmc1_sdwp", "dcan1_tx", "I2C1_SDA", NULL, "pr1_uart0_rxd", "pr1_pru1_pru_r31_16", "gpio0_14"), - _PIN(0x984, "UART1_TXD", 15, 7, "uart1_txd", "mmc2_sdwp", "dcan1_rx", "I2C1_SCL", NULL, "pr1_uart0_txd", "pr1_pru0_pru_r31_16", "gpio0_15"), - _PIN(0x988, "I2C0_SDA", 101, 7, "I2C0_SDA", "timer4", "uart2_ctsn", "eCAP2_in_PWM2_out", NULL, NULL, NULL, "gpio3_5"), - _PIN(0x98c, "I2C0_SCL", 102, 7, "I2C0_SCL", "timer7", "uart2_rtsn", "eCAP1_in_PWM1_out", NULL, NULL, NULL, "gpio3_6"), - _PIN(0x990, "MCASP0_ACLKX", 110, 7, "mcasp0_aclkx", "ehrpwm0A", NULL, "spi1_sclk", "mmc0_sdcd", "pr1_pru0_pru_r30_0", "pr1_pru0_pru_r31_0", "gpio3_14"), - _PIN(0x994, "MCASP0_FSX", 111, 7, "mcasp0_fsx", "ehrpwm0B", NULL, "spi1_d0", "mmc1_sdcd", "pr1_pru0_pru_r30_1", "pr1_pru0_pru_r31_1", "gpio3_15"), - _PIN(0x998, "MCASP0_AXR0", 112, 7, "mcasp0_axr0", "ehrpwm0_tripzone_input", NULL, "spi1_d1", "mmc2_sdcd", "pr1_pru0_pru_r30_2", "pr1_pru0_pru_r31_2", "gpio3_16"), - _PIN(0x99c, "MCASP0_AHCLKR", 113, 7, "mcasp0_ahclkr", "ehrpwm0_synci", "mcasp0_axr2", "spi1_cs0", "eCAP2_in_PWM2_out", "pr1_pru0_pru_r30_3", "pr1_pru0_pru_r31_3", "gpio3_17"), - _PIN(0x9a0, "MCASP0_ACLKR", 114, 7, "mcasp0_aclkr", "eQEP0A_in", "mcasp0_axr2", "mcasp1_aclkx", "mmc0_sdwp", "pr1_pru0_pru_r30_4", "pr1_pru0_pru_r31_4", "gpio3_18"), - _PIN(0x9a4, "MCASP0_FSR", 115, 7, "mcasp0_fsr", "eQEP0B_in", "mcasp0_axr3", "mcasp1_fsx", "EMU2", "pr1_pru0_pru_r30_5", "pr1_pru0_pru_r31_5", "gpio3_19"), - _PIN(0x9a8, "MCASP0_AXR1", 116, 7, "mcasp0_axr1", "eQEP0_index", NULL, "mcasp1_axr0", "EMU3", "pr1_pru0_pru_r30_6", "pr1_pru0_pru_r31_6", "gpio3_20"), - _PIN(0x9ac, "MCASP0_AHCLKX", 117, 7, "mcasp0_ahclkx", "eQEP0_strobe", "mcasp0_axr3", "mcasp1_axr1", "EMU4", "pr1_pru0_pru_r30_7", "pr1_pru0_pru_r31_7", "gpio3_21"), - _PIN(0x9b0, "XDMA_EVENT_INTR0", 19, 7, "xdma_event_intr0", NULL, "timer4", "clkout1", "spi1_cs1", "pr1_pru1_pru_r31_16", "EMU2", "gpio0_19"), - _PIN(0x9b4, "XDMA_EVENT_INTR1", 20, 7, "xdma_event_intr1", NULL, "tclkin", "clkout2", "timer7", "pr1_pru0_pru_r31_16", "EMU3", "gpio0_20"), +const static struct ti_pinmux_padconf ti_padconf_devmap[] = { + _PIN(0x000, "GPMC_AD0", 32, 7,"gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0"), + _PIN(0x004, "GPMC_AD1", 33, 7,"gpmc_ad1", "mmc1_dat1", NULL, NULL, NULL, NULL, NULL, "gpio1_1"), + _PIN(0x008, "GPMC_AD2", 34, 7,"gpmc_ad2", "mmc1_dat2", NULL, NULL, NULL, NULL, NULL, "gpio1_2"), + _PIN(0x00C, "GPMC_AD3", 35, 7,"gpmc_ad3", "mmc1_dat3", NULL, NULL, NULL, NULL, NULL, "gpio1_3"), + _PIN(0x010, "GPMC_AD4", 36, 7,"gpmc_ad4", "mmc1_dat4", NULL, NULL, NULL, NULL, NULL, "gpio1_4"), + _PIN(0x014, "GPMC_AD5", 37, 7,"gpmc_ad5", "mmc1_dat5", NULL, NULL, NULL, NULL, NULL, "gpio1_5"), + _PIN(0x018, "GPMC_AD6", 38, 7,"gpmc_ad6", "mmc1_dat6", NULL, NULL, NULL, NULL, NULL, "gpio1_6"), + _PIN(0x01C, "GPMC_AD7", 39, 7,"gpmc_ad7", "mmc1_dat7", NULL, NULL, NULL, NULL, NULL, "gpio1_7"), + _PIN(0x020, "GPMC_AD8", 22, 7, "gpmc_ad8", "lcd_data23", "mmc1_dat0", "mmc2_dat4", "ehrpwm2A", NULL, NULL, "gpio0_22"), + _PIN(0x024, "GPMC_AD9", 23, 7, "gpmc_ad9", "lcd_data22", "mmc1_dat1", "mmc2_dat5", "ehrpwm2B", NULL, NULL, "gpio0_23"), + _PIN(0x028, "GPMC_AD10", 26, 7, "gpmc_ad10", "lcd_data21", "mmc1_dat2", "mmc2_dat6", "ehrpwm2_tripzone_in", NULL, NULL, "gpio0_26"), + _PIN(0x02C, "GPMC_AD11", 27, 7, "gpmc_ad11", "lcd_data20", "mmc1_dat3", "mmc2_dat7", "ehrpwm0_synco", NULL, NULL, "gpio0_27"), + _PIN(0x030, "GPMC_AD12", 44, 7, "gpmc_ad12", "lcd_data19", "mmc1_dat4", "mmc2_dat0", "eQEP2A_in", "pr1_mii0_txd2", "pr1_pru0_pru_r30_14", "gpio1_12"), + _PIN(0x034, "GPMC_AD13", 45, 7, "gpmc_ad13", "lcd_data18", "mmc1_dat5", "mmc2_dat1", "eQEP2B_in", "pr1_mii0_txd1", "pr1_pru0_pru_r30_15", "gpio1_13"), + _PIN(0x038, "GPMC_AD14", 46, 7, "gpmc_ad14", "lcd_data17", "mmc1_dat6", "mmc2_dat2", "eQEP2_index", "pr1_mii0_txd0", "pr1_pru0_pru_r31_14", "gpio1_14"), + _PIN(0x03C, "GPMC_AD15", 47, 7, "gpmc_ad15", "lcd_data16", "mmc1_dat7", "mmc2_dat3", "eQEP2_strobe", "pr1_ecap0_ecap_capin_apwm_o", "pr1_pru0_pru_r31_15", "gpio1_15"), + _PIN(0x040, "GPMC_A0", 48, 7, "gpmc_a0", "gmii2_txen", "rgmii2_tctl", "rmii2_txen", "gpmc_a16", "pr1_mii_mt1_clk", "ehrpwm1_tripzone_input", "gpio1_16"), + _PIN(0x044, "GPMC_A1", 49, 7, "gpmc_a1", "gmii2_rxdv", "rgmii2_rctl", "mmc2_dat0", "gpmc_a17", "pr1_mii1_txd3", "ehrpwm0_synco", "gpio1_17"), + _PIN(0x048, "GPMC_A2", 50, 7, "gpmc_a2", "gmii2_txd3", "rgmii2_td3", "mmc2_dat1", "gpmc_a18", "pr1_mii1_txd2", "ehrpwm1A", "gpio1_18"), + _PIN(0x04C, "GPMC_A3", 51, 7, "gpmc_a3", "gmii2_txd2", "rgmii2_td2", "mmc2_dat2", "gpmc_a19", "pr1_mii1_txd1", "ehrpwm1B", "gpio1_19"), + _PIN(0x050, "GPMC_A4", 52, 7, "gpmc_a4", "gmii2_txd1", "rgmii2_td1", "rmii2_tdx1", "gpmc_a20", "pr1_mii1_txd0", "eQEP1A_in", "gpio1_20"), + _PIN(0x054, "GPMC_A5", 53, 7, "gpmc_a5", "gmii2_txd0", "rgmii2_td0", "rmii2_txd0", "gpmc_a21", "pr1_mii1_rxd3", "eQEP1B_in", "gpio1_21"), + _PIN(0x058, "GPMC_A6", 54, 7, "gpmc_a6", "gmii2_txclk", "rgmii2_tclk", "mmc2_dat4", "gpmc_a22", "pr1_mii1_rxd2", "eQEP1_index", "gpio1_22"), + _PIN(0x05C, "GPMC_A7", 55, 7, "gpmc_a7", "gmii2_rxclk", "rgmii2_rclk", "mmc2_dat5", "gpmc_a23", "pr1_mii1_rxd1", "eQEP1_strobe", "gpio1_23"), + _PIN(0x060, "GPMC_A8", 56, 7, "gpmc_a8", "gmii2_rxd3", "rgmii2_rd3", "mmc2_dat6", "gpmc_a24", "pr1_mii1_rxd0", "mcasp0_aclkx", "gpio1_24"), + _PIN(0x064, "GPMC_A9", 57, 7, "gmpc_a9", "gmii2_rxd2", "rgmii2_rd2", "mmc2_dat7 / rmii2_crs_dv", "gpmc_a25", "pr1_mii_mr1_clk", "mcasp0_fsx", "gpio1_25"), + _PIN(0x068, "GPMC_A10", 58, 7, "gmpc_a10", "gmii2_rxd1", "rgmii2_rd1", "rmii2_rxd1", "gpmc_a26", "pr1_mii1_rxdv", "mcasp0_arx0", "gpio1_26"), + _PIN(0x06C, "GPMC_A11", 59, 7, "gmpc_a11", "gmii2_rxd0", "rgmii2_rd0", "rmii2_rxd0", "gpmc_a27", "pr1_mii1_rxer", "mcasp0_axr1", "gpio1_27"), + _PIN(0x070, "GPMC_WAIT0", 30, 7, "gpmc_wait0", "gmii2_crs", "gpmc_csn4", "rmii2_crs_dv", "mmc1_sdcd", "pr1_mii1_col", "uart4_rxd", "gpio0_30"), + _PIN(0x074, "GPMC_WPn", 31, 7, "gpmc_wpn", "gmii2_rxerr", "gpmc_csn5", "rmii2_rxerr", "mmc2_sdcd", "pr1_mii1_txen", "uart4_txd", "gpio0_31"), + _PIN(0x078, "GPMC_BEn1", 60, 7, "gpmc_be1n", "gmii2_col", "gmpc_csn6","mmc2_dat3", "gpmc_dir", "pr1_mii1_rxlink", "mcasp0_aclkr", "gpio1_28"), + _PIN(0x07c, "GPMC_CSn0", 61, 7, "gpmc_csn0", NULL, NULL, NULL, NULL, NULL, NULL, "gpio1_29"), + _PIN(0x080, "GPMC_CSn1", 62, 7, "gpmc_csn1", "gpmc_clk", "mmc1_clk", "pr1_edio_data_in6", "pr1_edio_data_out6", "pr1_pru1_pru_r30_12", "pr1_pru1_pru_r31_12", "gpio1_30"), + _PIN(0x084, "GPMC_CSn2", 63, 7, "gpmc_csn2", "gpmc_be1n", "mmc1_cmd", "pr1_edio_data_in7", "pr1_edio_data_out7", "pr1_pru1_pru_r30_13", "pr1_pru1_pru_r31_13", "gpio1_31"), + _PIN(0x088, "GPMC_CSn3", 64, 7, "gpmc_csn3", "gpmc_a3", "rmii2_crs_dv", "mmc2_cmd", "pr1_mii0_crs", "pr1_mdio_data", "EMU4", "gpio2_0"), + _PIN(0x08c, "GPMC_CLK", 65, 7, "gpmc_clk", "lcd_memory_clk", "gpmc_wait1", "mmc2_clk", "pr1_mii1_crs", "pr1_mdio_mdclk", "mcasp0_fsr", "gpio2_1"), + _PIN(0x090, "GPMC_ADVn_ALE", 66, 7, "gpmc_advn_ale", NULL, "timer4", NULL, NULL, NULL, NULL, "gpio2_2"), + _PIN(0x094, "GPMC_OEn_REn", 67, 7, "gpmc_oen_ren", NULL, "timer7", NULL, NULL, NULL, NULL, "gpio2_3"), + _PIN(0x098, "GPMC_WEn", 68, 7, "gpmc_wen", NULL, "timer6", NULL, NULL, NULL, NULL, "gpio2_4"), + _PIN(0x09c, "GPMC_BEn0_CLE", 67, 7, "gpmc_ben0_cle", NULL, "timer5", NULL, NULL, NULL, NULL, "gpio2_5"), + _PIN(0x0a0, "LCD_DATA0", 68, 7, "lcd_data0", "gpmc_a0", "pr1_mii_mt0_clk", "ehrpwm2A", NULL, "pr1_pru1_pru_r30_0", "pr1_pru1_pru_r31_0", "gpio2_6"), + _PIN(0x0a4, "LCD_DATA1", 69, 7, "lcd_data1", "gpmc_a1", "pr1_mii0_txen", "ehrpwm2B", NULL, "pr1_pru1_pru_r30_1", "pr1_pru1_pru_r31_1", "gpio2_7"), + _PIN(0x0a8, "LCD_DATA2", 70, 7, "lcd_data2", "gpmc_a2", "pr1_mii0_txd3", "ehrpwm2_tripzone_input", NULL, "pr1_pru1_pru_r30_2", "pr1_pru1_pru_r31_2", "gpio2_8"), + _PIN(0x0ac, "LCD_DATA3", 71, 7, "lcd_data3", "gpmc_a3", "pr1_mii0_txd2", "ehrpwm0_synco", NULL, "pr1_pru1_pru_r30_3", "pr1_pru1_pru_r31_3", "gpio2_9"), + _PIN(0x0b0, "LCD_DATA4", 72, 7, "lcd_data4", "gpmc_a4", "pr1_mii0_txd1", "eQEP2A_in", NULL, "pr1_pru1_pru_r30_4", "pr1_pru1_pru_r31_4", "gpio2_10"), + _PIN(0x0b4, "LCD_DATA5", 73, 7, "lcd_data5", "gpmc_a5", "pr1_mii0_txd0", "eQEP2B_in", NULL, "pr1_pru1_pru_r30_5", "pr1_pru1_pru_r31_5", "gpio2_11"), + _PIN(0x0b8, "LCD_DATA6", 74, 7, "lcd_data6", "gpmc_a6", "pr1_edio_data_in6", "eQEP2_index", "pr1_edio_data_out6", "pr1_pru1_pru_r30_6", "pr1_pru1_pru_r31_6", "gpio2_12"), + _PIN(0x0bc, "LCD_DATA7", 75, 7, "lcd_data7", "gpmc_a7", "pr1_edio_data_in7", "eQEP2_strobe", "pr1_edio_data_out7", "pr1_pru1_pru_r30_7", "pr1_pru1_pru_r31_7", "gpio2_13"), + _PIN(0x0c0, "LCD_DATA8", 76, 7, "lcd_data8", "gpmc_a12", "ehrpwm1_tripzone_input", "mcasp0_aclkx", "uart5_txd", "pr1_mii0_rxd3", "uart2_ctsn", "gpio2_14"), + _PIN(0x0c4, "LCD_DATA9", 76, 7, "lcd_data9", "gpmc_a13", "ehrpwm0_synco", "mcasp0_fsx", "uart5_rxd", "pr1_mii0_rxd2", "uart2_rtsn", "gpio2_15"), + _PIN(0x0c8, "LCD_DATA10", 77, 7, "lcd_data10", "gpmc_a14", "ehrpwm1A", "mcasp0_axr0", NULL, "pr1_mii0_rxd1", "uart3_ctsn", "gpio2_16"), + _PIN(0x0cc, "LCD_DATA11", 78, 7, "lcd_data11", "gpmc_a15", "ehrpwm1B", "mcasp0_ahclkr", "mcasp0_axr2", "pr1_mii0_rxd0", "uart3_rtsn", "gpio2_17"), + _PIN(0x0d0, "LCD_DATA12", 8, 7, "lcd_data12", "gpmc_a16", "eQEP1A_in", "mcasp0_aclkr", "mcasp0_axr2", "pr1_mii0_rxlink", "uart4_ctsn", "gpio0_8"), + _PIN(0x0d4, "LCD_DATA13", 9, 7, "lcd_data13", "gpmc_a17", "eQEP1B_in", "mcasp0_fsr", "mcasp0_axr3", "pr1_mii0_rxer", "uart4_rtsn", "gpio0_9"), + _PIN(0x0d8, "LCD_DATA14", 10, 7, "lcd_data14", "gpmc_a18", "eQEP1_index", "mcasp0_axr1", "uart5_rxd", "pr1_mii_mr0_clk", "uart5_ctsn", "gpio0_10"), + _PIN(0x0dc, "LCD_DATA15", 11, 7, "lcd_data15", "gpmc_a19", "eQEP1_strobe", "mcasp0_ahclkx", "mcasp0_axr3", "pr1_mii0_rxdv", "uart5_rtsn", "gpio0_11"), + _PIN(0x0e0, "LCD_VSYNC", 86, 7, "lcd_vsync", "gpmc_a8", "gpmc_a1", "pr1_edio_data_in2", "pr1_edio_data_out2", "pr1_pru1_pru_r30_8", "pr1_pru1_pru_r31_8", "gpio2_22"), + _PIN(0x0e4, "LCD_HSYNC", 87, 7, "lcd_hsync", "gmpc_a9", "gpmc_a2", "pr1_edio_data_in3", "pr1_edio_data_out3", "pr1_pru1_pru_r30_9", "pr1_pru1_pru_r31_9", "gpio2_23"), + _PIN(0x0e8, "LCD_PCLK", 88, 7, "lcd_pclk", "gpmc_a10", "pr1_mii0_crs", "pr1_edio_data_in4", "pr1_edio_data_out4", "pr1_pru1_pru_r30_10", "pr1_pru1_pru_r31_10", "gpio2_24"), + _PIN(0x0ec, "LCD_AC_BIAS_EN", 89, 7, "lcd_ac_bias_en", "gpmc_a11", "pr1_mii1_crs", "pr1_edio_data_in5", "pr1_edio_data_out5", "pr1_pru1_pru_r30_11", "pr1_pru1_pru_r31_11", "gpio2_25"), + _PIN(0x0f0, "MMC0_DAT3", 90, 7, "mmc0_dat3", "gpmc_a20", "uart4_ctsn", "timer5", "uart1_dcdn", "pr1_pru0_pru_r30_8", "pr1_pru0_pru_r31_8", "gpio2_26"), + _PIN(0x0f4, "MMC0_DAT2", 91, 7, "mmc0_dat2", "gpmc_a21", "uart4_rtsn", "timer6", "uart1_dsrn", "pr1_pru0_pru_r30_9", "pr1_pru0_pru_r31_9", "gpio2_27"), + _PIN(0x0f8, "MMC0_DAT1", 92, 7, "mmc0_dat1", "gpmc_a22", "uart5_ctsn", "uart3_rxd", "uart1_dtrn", "pr1_pru0_pru_r30_10", "pr1_pru0_pru_r31_10", "gpio2_28"), + _PIN(0x0fc, "MMC0_DAT0", 93, 7, "mmc0_dat0", "gpmc_a23", "uart5_rtsn", "uart3_txd", "uart1_rin", "pr1_pru0_pru_r30_11", "pr1_pru0_pru_r31_11", "gpio2_29"), + _PIN(0x100, "MMC0_CLK", 94, 7, "mmc0_clk", "gpmc_a24", "uart3_ctsn", "uart2_rxd", "dcan1_tx", "pr1_pru0_pru_r30_12", "pr1_pru0_pru_r31_12", "gpio2_30"), + _PIN(0x104, "MMC0_CMD", 95, 7, "mmc0_cmd", "gpmc_a25", "uart3_rtsn", "uart2_txd", "dcan1_rx", "pr1_pru0_pru_r30_13", "pr1_pru0_pru_r31_13", "gpio2_31"), + _PIN(0x108, "MII1_COL", 96, 7, "gmii1_col", "rmii2_refclk", "spi1_sclk", "uart5_rxd", "mcasp1_axr2", "mmc2_dat3", "mcasp0_axr2", "gpio3_0"), + _PIN(0x10c, "MII1_CRS", 97, 7, "gmii1_crs", "rmii1_crs_dv", "spi1_d0", "I2C1_SDA", "mcasp1_aclkx", "uart5_ctsn", "uart2_rxd", "gpio3_1"), + _PIN(0x110, "MII1_RX_ER", 98, 7, "gmii1_rxerr", "rmii1_rxerr", "spi1_d1", "I2C1_SCL", "mcasp1_fsx", "uart5_rtsn", "uart2_txd", "gpio3_2"), + _PIN(0x114, "MII1_TX_EN", 99, 7, "gmii1_txen", "rmii1_txen", "rgmii1_tctl", "timer4", "mcasp1_axr0", "eQEP0_index", "mmc2_cmd", "gpio3_3"), + _PIN(0x118, "MII1_RX_DV", 100, 7, "gmii1_rxdv", "cd_memory_clk", "rgmii1_rctl", "uart5_txd", "mcasp1_aclkx", "mmc2_dat0", "mcasp0_aclkr", "gpio3_4"), + _PIN(0x11c, "MII1_TXD3", 16, 7, "gmii1_txd3", "dcan0_tx", "rgmii1_td3", "uart4_rxd", "mcasp1_fsx", "mmc2_dat1", "mcasp0_fsr", "gpio0_16"), + _PIN(0x120, "MII1_TXD2", 17, 7, "gmii1_txd2", "dcan0_rx", "rgmii1_td2", "uart4_txd", "mcasp1_axr0", "mmc2_dat2", "mcasp0_ahclkx", "gpio0_17"), + _PIN(0x124, "MII1_TXD1", 21, 7, "gmii1_txd1", "rmii1_txd1", "rgmii1_td1", "mcasp1_fsr", "mcasp1_axr1", "eQEP0A_in", "mmc1_cmd", "gpio0_21"), + _PIN(0x128, "MII1_TXD0", 28, 7, "gmii1_txd0", "rmii1_txd0", "rgmii1_td0", "mcasp1_axr2", "mcasp1_aclkr", "eQEP0B_in", "mmc1_clk", "gpio0_28"), + _PIN(0x12c, "MII1_TX_CLK", 105, 7, "gmii1_txclk", "uart2_rxd", "rgmii1_tclk", "mmc0_dat7", "mmc1_dat0", "uart1_dcdn", "mcasp0_aclkx", "gpio3_9"), + _PIN(0x130, "MII1_RX_CLK", 106, 7, "gmii1_rxclk", "uart2_txd", "rgmii1_rclk", "mmc0_dat6", "mmc1_dat1", "uart1_dsrn", "mcasp0_fsx", "gpio3_10"), + _PIN(0x134, "MII1_RXD3", 82, 7, "gmii1_rxd3", "uart3_rxd", "rgmii1_rd3", "mmc0_dat5", "mmc1_dat2", "uart1_dtrn", "mcasp0_axr0", "gpio2_18"), + _PIN(0x138, "MII1_RXD2", 83, 7, "gmii1_rxd2", "uart3_txd", "rgmii1_rd2", "mmc0_dat4", "mmc1_dat3", "uart1_rin", "mcasp0_axr1", "gpio2_19"), + _PIN(0x13c, "MII1_RXD1", 84, 7, "gmii1_rxd1", "rmii1_rxd1", "rgmii1_rd1", "mcasp1_axr3", "mcasp1_fsr", "eQEP0_strobe", "mmc2_clk", "gpio2_20"), + _PIN(0x140, "MII1_RXD0", 85, 7, "gmii1_rxd0", "rmii1_rxd0", "rgmii1_rd0", "mcasp1_ahclkx", "mcasp1_ahclkr", "mcasp1_aclkr", "mcasp0_axr3", "gpio2_21"), + _PIN(0x144, "RMII1_REF_CLK", 29, 7, "rmii1_refclk", "xdma_event_intr2", "spi1_cs0", "uart5_txd", "mcasp1_axr3", "mmc0_pow", "mcasp1_ahclkx", "gpio0_29"), + _PIN(0x148, "MDIO", 0, 7, "mdio_data", "timer6", "uart5_rxd", "uart3_ctsn", "mmc0_sdcd","mmc1_cmd", "mmc2_cmd","gpio0_0"), + _PIN(0x14c, "MDC", 1, 7, "mdio_clk", "timer5", "uart5_txd", "uart3_rtsn", "mmc0_sdwp", "mmc1_clk", "mmc2_clk", "gpio0_1"), + _PIN(0x150, "SPI0_SCLK", 2, 7, "spi0_sclk", "uart2_rxd", "I2C2_SDA", "ehrpwm0A", "pr1_uart0_cts_n", "pr1_edio_sof", "EMU2", "gpio0_2"), + _PIN(0x154, "SPI0_D0", 3, 7, "spi0_d0", "uart2_txd", "I2C2_SCL", "ehrpwm0B", "pr1_uart0_rts_n", "pr1_edio_latch_in", "EMU3", "gpio0_3"), + _PIN(0x158, "SPI0_D1", 4, 7, "spi0_d1", "mmc1_sdwp", "I2C1_SDA", "ehrpwm0_tripzone_input", "pr1_uart0_rxd", "pr1_edio_data_in0", "pr1_edio_data_out0", "gpio0_4"), + _PIN(0x15c, "SPI0_CS0", 5, 7, "spi0_cs0", "mmc2_sdwp", "I2C1_SCL", "ehrpwm0_synci", "pr1_uart0_txd", "pr1_edio_data_in1", "pr1_edio_data_out1", "gpio0_5"), + _PIN(0x160, "SPI0_CS1", 6, 7, "spi0_cs1", "uart3_rxd", "eCAP1_in_PWM1_out", "mcc0_pow", "xdm_event_intr2", "mmc0_sdcd", "EMU4", "gpio0_6"), + _PIN(0x164, "ECAP0_IN_PWM0_OUT",7, 7, "eCAP0_in_PWM0_out", "uart3_txd", "spi1_cs1", "pr1_ecap0_ecap_capin_apwm_o", "spi1_sclk", "mmc0_sdwp", "xdma_event_intr2", "gpio0_7"), + _PIN(0x168, "UART0_CTSn", 40, 7, "uart0_ctsn", "uart4_rxd", "dcan1_tx", "I2C1_SDA", "spi1_d0", "timer7", "pr1_edc_sync0_out", "gpio1_8"), + _PIN(0x16c, "UART0_RTSn", 41, 7, "uart0_rtsn", "uart4_txd", "dcan1_rx", "I2C1_SCL", "spi1_d1", "spi1_cs0", "pr1_edc_sync1_out", "gpio1_9"), + _PIN(0x170, "UART0_rxd", 42, 7, "uart0_rxd", "spi1_cs0", "dcan0_tx", "I2C2_SDA", "eCAP2_in_PWM2_out", "pr1_pru1_pru_r30_14", "pr1_pru1_pru_r31_14", "gpio1_10"), + _PIN(0x174, "UART0_txd", 43, 7, "uart0_txd", "spi1_cs1", "dcan0_rx", "I2C2_SCL", "eCAP1_in_PWM1_out", "pr1_pru1_pru_r30_15", "pr1_pru1_pru_r31_15", "gpio1_11"), + _PIN(0x178, "UART1_CTSn", 12, 7, "uart1_ctsn", "timer6_mux1", "dcan0_tx", "I2C2_SDA", "spi1_cs0", "pr1_uart0_cts_n", "pr1_edc_latch0_in", "gpio0_12"), + _PIN(0x17c, "UART1_RTSn", 13, 7, "uart1_rtsn", "timer5_mux1", "dcan0_rx", "I2C2_SCL", "spi1_cs1", "pr1_uart0_rts_n", "pr1_edc_latch1_in", "gpio0_13"), + _PIN(0x180, "UART1_RXD", 14, 7, "uart1_rxd", "mmc1_sdwp", "dcan1_tx", "I2C1_SDA", NULL, "pr1_uart0_rxd", "pr1_pru1_pru_r31_16", "gpio0_14"), + _PIN(0x184, "UART1_TXD", 15, 7, "uart1_txd", "mmc2_sdwp", "dcan1_rx", "I2C1_SCL", NULL, "pr1_uart0_txd", "pr1_pru0_pru_r31_16", "gpio0_15"), + _PIN(0x188, "I2C0_SDA", 101, 7, "I2C0_SDA", "timer4", "uart2_ctsn", "eCAP2_in_PWM2_out", NULL, NULL, NULL, "gpio3_5"), + _PIN(0x18c, "I2C0_SCL", 102, 7, "I2C0_SCL", "timer7", "uart2_rtsn", "eCAP1_in_PWM1_out", NULL, NULL, NULL, "gpio3_6"), + _PIN(0x190, "MCASP0_ACLKX", 110, 7, "mcasp0_aclkx", "ehrpwm0A", NULL, "spi1_sclk", "mmc0_sdcd", "pr1_pru0_pru_r30_0", "pr1_pru0_pru_r31_0", "gpio3_14"), + _PIN(0x194, "MCASP0_FSX", 111, 7, "mcasp0_fsx", "ehrpwm0B", NULL, "spi1_d0", "mmc1_sdcd", "pr1_pru0_pru_r30_1", "pr1_pru0_pru_r31_1", "gpio3_15"), + _PIN(0x198, "MCASP0_AXR0", 112, 7, "mcasp0_axr0", "ehrpwm0_tripzone_input", NULL, "spi1_d1", "mmc2_sdcd", "pr1_pru0_pru_r30_2", "pr1_pru0_pru_r31_2", "gpio3_16"), + _PIN(0x19c, "MCASP0_AHCLKR", 113, 7, "mcasp0_ahclkr", "ehrpwm0_synci", "mcasp0_axr2", "spi1_cs0", "eCAP2_in_PWM2_out", "pr1_pru0_pru_r30_3", "pr1_pru0_pru_r31_3", "gpio3_17"), + _PIN(0x1a0, "MCASP0_ACLKR", 114, 7, "mcasp0_aclkr", "eQEP0A_in", "mcasp0_axr2", "mcasp1_aclkx", "mmc0_sdwp", "pr1_pru0_pru_r30_4", "pr1_pru0_pru_r31_4", "gpio3_18"), + _PIN(0x1a4, "MCASP0_FSR", 115, 7, "mcasp0_fsr", "eQEP0B_in", "mcasp0_axr3", "mcasp1_fsx", "EMU2", "pr1_pru0_pru_r30_5", "pr1_pru0_pru_r31_5", "gpio3_19"), + _PIN(0x1a8, "MCASP0_AXR1", 116, 7, "mcasp0_axr1", "eQEP0_index", NULL, "mcasp1_axr0", "EMU3", "pr1_pru0_pru_r30_6", "pr1_pru0_pru_r31_6", "gpio3_20"), + _PIN(0x1ac, "MCASP0_AHCLKX", 117, 7, "mcasp0_ahclkx", "eQEP0_strobe", "mcasp0_axr3", "mcasp1_axr1", "EMU4", "pr1_pru0_pru_r30_7", "pr1_pru0_pru_r31_7", "gpio3_21"), + _PIN(0x1b0, "XDMA_EVENT_INTR0", 19, 7, "xdma_event_intr0", NULL, "timer4", "clkout1", "spi1_cs1", "pr1_pru1_pru_r31_16", "EMU2", "gpio0_19"), + _PIN(0x1b4, "XDMA_EVENT_INTR1", 20, 7, "xdma_event_intr1", NULL, "tclkin", "clkout2", "timer7", "pr1_pru0_pru_r31_16", "EMU3", "gpio0_20"), #if 0 - _PIN(0x9b8, "nresetin_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9bc, "porz", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9c0, "nnmi", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9c4, "osc0_in", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9c8, "osc0_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9cc, "osc0_vss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9d0, "tms", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9d4, "tdi", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9d8, "tdo", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9dc, "tck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9e0, "ntrst", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1b8, "nresetin_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1bc, "porz", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1c0, "nnmi", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1c4, "osc0_in", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1c8, "osc0_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1cc, "osc0_vss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1d0, "tms", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1d4, "tdi", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1d8, "tdo", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1dc, "tck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1e0, "ntrst", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), #endif - _PIN(0x9e4, "EMU0", 103, 7, "EMU0", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_7"), - _PIN(0x9e8, "EMU1", 104, 0, "EMU1", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_8"), + _PIN(0x1e4, "EMU0", 103, 7, "EMU0", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_7"), + _PIN(0x1e8, "EMU1", 104, 0, "EMU1", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_8"), #if 0 - _PIN(0x9ec, "osc1_in", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9f0, "osc1_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9f4, "osc1_vss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9f8, "rtc_porz", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0x9fc, "pmic_power_en", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa00, "ext_wakeup", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa04, "enz_kaldo_1p8v", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1ec, "osc1_in", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1f0, "osc1_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1f4, "osc1_vss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1f8, "rtc_porz", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x1fc, "pmic_power_en", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x200, "ext_wakeup", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x204, "enz_kaldo_1p8v", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), #endif - _PIN(0xa08, "USB0_DM", 0, 0, "USB0_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa0c, "USB0_DP", 0, 0, "USB0_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa10, "USB0_CE", 0, 0, "USB0_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa14, "USB0_ID", 0, 0, "USB0_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa18, "USB0_VBUS", 0, 0, "USB0_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa1c, "USB0_DRVVBUS", 18, 7, "USB0_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio0_18"), - _PIN(0xa20, "USB1_DM", 0, 0, "USB1_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa24, "USB1_DP", 0, 0, "USB1_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa28, "USB1_CE", 0, 0, "USB1_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa2c, "USB1_ID", 0, 0, "USB1_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa30, "USB1_VBUS", 0, 0, "USB1_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa34, "USB1_DRVVBUS", 109, 7, "USB1_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_13"), + _PIN(0x208, "USB0_DM", 0, 0, "USB0_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x20c, "USB0_DP", 0, 0, "USB0_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x210, "USB0_CE", 0, 0, "USB0_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x214, "USB0_ID", 0, 0, "USB0_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x218, "USB0_VBUS", 0, 0, "USB0_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x21c, "USB0_DRVVBUS", 18, 7, "USB0_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio0_18"), + _PIN(0x220, "USB1_DM", 0, 0, "USB1_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x224, "USB1_DP", 0, 0, "USB1_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x228, "USB1_CE", 0, 0, "USB1_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x22c, "USB1_ID", 0, 0, "USB1_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x230, "USB1_VBUS", 0, 0, "USB1_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x234, "USB1_DRVVBUS", 109, 7, "USB1_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_13"), #if 0 - _PIN(0xa38, "ddr_resetn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa3c, "ddr_csn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa40, "ddr_cke", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa44, "ddr_ck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa48, "ddr_nck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa4c, "ddr_casn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa50, "ddr_rasn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa54, "ddr_wen", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa58, "ddr_ba0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa5c, "ddr_ba1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa60, "ddr_ba2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa64, "ddr_a0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa68, "ddr_a1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa6c, "ddr_a2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa70, "ddr_a3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa74, "ddr_a4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa78, "ddr_a5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa7c, "ddr_a6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa80, "ddr_a7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa84, "ddr_a8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa88, "ddr_a9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa8c, "ddr_a10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa90, "ddr_a11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa94, "ddr_a12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa98, "ddr_a13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xa9c, "ddr_a14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xaa0, "ddr_a15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xaa4, "ddr_odt", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xaa8, "ddr_d0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xaac, "ddr_d1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xab0, "ddr_d2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xab4, "ddr_d3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xab8, "ddr_d4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xabc, "ddr_d5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xac0, "ddr_d6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xac4, "ddr_d7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xac8, "ddr_d8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xacc, "ddr_d9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xad0, "ddr_d10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xad4, "ddr_d11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xad8, "ddr_d12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xadc, "ddr_d13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xae0, "ddr_d14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xae4, "ddr_d15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xae8, "ddr_dqm0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xaec, "ddr_dqm1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xaf0, "ddr_dqs0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xaf4, "ddr_dqsn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xaf8, "ddr_dqs1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xafc, "ddr_dqsn1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb00, "ddr_vref", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb04, "ddr_vtp", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb08, "ddr_strben0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb0c, "ddr_strben1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb2c, "ain0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb28, "ain1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb24, "ain2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb20, "ain3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb1c, "ain4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb18, "ain5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb14, "ain6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb10, "ain7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb30, "vrefp", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb34, "vrefn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb38, "avdd", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb3c, "avss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb40, "iforce", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb44, "vsense", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PIN(0xb48, "testout", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x238, "ddr_resetn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x23c, "ddr_csn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x240, "ddr_cke", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x244, "ddr_ck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x248, "ddr_nck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x24c, "ddr_casn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x250, "ddr_rasn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x254, "ddr_wen", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x258, "ddr_ba0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x25c, "ddr_ba1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x260, "ddr_ba2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x264, "ddr_a0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x268, "ddr_a1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x26c, "ddr_a2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x270, "ddr_a3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x274, "ddr_a4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x278, "ddr_a5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x27c, "ddr_a6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x280, "ddr_a7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x284, "ddr_a8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x288, "ddr_a9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x28c, "ddr_a10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x290, "ddr_a11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x294, "ddr_a12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x298, "ddr_a13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x29c, "ddr_a14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2a0, "ddr_a15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2a4, "ddr_odt", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2a8, "ddr_d0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2ac, "ddr_d1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2b0, "ddr_d2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2b4, "ddr_d3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2b8, "ddr_d4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2bc, "ddr_d5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2c0, "ddr_d6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2c4, "ddr_d7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2c8, "ddr_d8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2cc, "ddr_d9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2d0, "ddr_d10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2d4, "ddr_d11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2d8, "ddr_d12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2dc, "ddr_d13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2e0, "ddr_d14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2e4, "ddr_d15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2e8, "ddr_dqm0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2ec, "ddr_dqm1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2f0, "ddr_dqs0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2f4, "ddr_dqsn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2f8, "ddr_dqs1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x2fc, "ddr_dqsn1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x300, "ddr_vref", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x304, "ddr_vtp", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x308, "ddr_strben0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x30c, "ddr_strben1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x32c, "ain0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x328, "ain1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x324, "ain2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x320, "ain3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x31c, "ain4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x318, "ain5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x314, "ain6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x310, "ain7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x330, "vrefp", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x334, "vrefn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x338, "avdd", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x33c, "avss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x340, "iforce", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x344, "vsense", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x348, "testout", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), #endif { .ballname = NULL }, }; -const struct ti_scm_device ti_scm_dev = { +const struct ti_pinmux_device ti_pinmux_dev = { .padconf_muxmode_mask = 0x7, .padconf_sate_mask = 0x78, .padstate = ti_padstate_devmap, .padconf = ti_padconf_devmap, }; Index: head/sys/arm/ti/am335x/am335x_usbss.c =================================================================== --- head/sys/arm/ti/am335x/am335x_usbss.c (revision 283275) +++ head/sys/arm/ti/am335x/am335x_usbss.c (revision 283276) @@ -1,495 +1,225 @@ /*- * Copyright (c) 2013 Oleksandr Tymoshenko * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include -#define USB_DEBUG_VAR usbssdebug - #include #include #include #include #include #include #include #include #define AM335X_USB_PORTS 2 #define USBSS_REVREG 0x00 #define USBSS_SYSCONFIG 0x10 #define USBSS_SYSCONFIG_SRESET 1 #define USBCTRL_REV 0x00 #define USBCTRL_CTRL 0x14 #define USBCTRL_STAT 0x18 #define USBCTRL_IRQ_STAT0 0x30 #define IRQ_STAT0_RXSHIFT 16 #define IRQ_STAT0_TXSHIFT 0 #define USBCTRL_IRQ_STAT1 0x34 #define IRQ_STAT1_DRVVBUS (1 << 8) #define USBCTRL_INTEN_SET0 0x38 #define USBCTRL_INTEN_SET1 0x3C #define USBCTRL_INTEN_USB_ALL 0x1ff #define USBCTRL_INTEN_USB_SOF (1 << 3) #define USBCTRL_INTEN_CLR0 0x40 #define USBCTRL_INTEN_CLR1 0x44 #define USBCTRL_UTMI 0xE0 #define USBCTRL_UTMI_FSDATAEXT (1 << 1) #define USBCTRL_MODE 0xE8 #define USBCTRL_MODE_IDDIG (1 << 8) #define USBCTRL_MODE_IDDIGMUX (1 << 7) -/* USBSS resource + 2 MUSB ports */ - -#define RES_USBSS 0 -#define RES_USBCTRL(i) (3*i+1) -#define RES_USBPHY(i) (3*i+2) -#define RES_USBCORE(i) (3*i+3) - -#define USB_WRITE4(sc, idx, reg, val) do { \ - bus_write_4((sc)->sc_mem_res[idx], (reg), (val)); \ -} while (0) - -#define USB_READ4(sc, idx, reg) bus_read_4((sc)->sc_mem_res[idx], (reg)) - #define USBSS_WRITE4(sc, reg, val) \ - USB_WRITE4((sc), RES_USBSS, (reg), (val)) + bus_write_4((sc)->sc_mem_res, (reg), (val)) #define USBSS_READ4(sc, reg) \ - USB_READ4((sc), RES_USBSS, (reg)) -#define USBCTRL_WRITE4(sc, unit, reg, val) \ - USB_WRITE4((sc), RES_USBCTRL(unit), (reg), (val)) -#define USBCTRL_READ4(sc, unit, reg) \ - USB_READ4((sc), RES_USBCTRL(unit), (reg)) -#define USBPHY_WRITE4(sc, unit, reg, val) \ - USB_WRITE4((sc), RES_USBPHY(unit), (reg), (val)) -#define USBPHY_READ4(sc, unit, reg) \ - USB_READ4((sc), RES_USBPHY(unit), (reg)) + bus_read_4((sc)->sc_mem_res, (reg)) -static struct resource_spec am335x_musbotg_mem_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_MEMORY, 1, RF_ACTIVE }, - { SYS_RES_MEMORY, 2, RF_ACTIVE }, - { SYS_RES_MEMORY, 3, RF_ACTIVE }, - { SYS_RES_MEMORY, 4, RF_ACTIVE }, - { SYS_RES_MEMORY, 5, RF_ACTIVE }, - { SYS_RES_MEMORY, 6, RF_ACTIVE }, - { -1, 0, 0 } -}; +static device_probe_t usbss_probe; +static device_attach_t usbss_attach; +static device_detach_t usbss_detach; -static struct resource_spec am335x_musbotg_irq_spec[] = { - { SYS_RES_IRQ, 0, RF_ACTIVE }, - { SYS_RES_IRQ, 1, RF_ACTIVE }, - { SYS_RES_IRQ, 2, RF_ACTIVE }, - { -1, 0, 0 } +struct usbss_softc { + struct simplebus_softc simplebus_sc; + struct resource *sc_mem_res; + int sc_mem_rid; }; -#ifdef USB_DEBUG -static int usbssdebug = 0; - -static SYSCTL_NODE(_hw_usb, OID_AUTO, am335x_usbss, CTLFLAG_RW, 0, "AM335x USBSS"); -SYSCTL_INT(_hw_usb_am335x_usbss, OID_AUTO, debug, CTLFLAG_RW, - &usbssdebug, 0, "Debug level"); -#endif - -static device_probe_t musbotg_probe; -static device_attach_t musbotg_attach; -static device_detach_t musbotg_detach; - -struct musbotg_super_softc { - struct musbotg_softc sc_otg[AM335X_USB_PORTS]; - struct resource *sc_mem_res[AM335X_USB_PORTS*3+1]; - struct resource *sc_irq_res[AM335X_USB_PORTS+1]; - void *sc_intr_hdl; -}; - -static void -musbotg_vbus_poll(struct musbotg_super_softc *sc, int port) -{ - uint32_t stat; - - if (sc->sc_otg[port].sc_mode == MUSB2_DEVICE_MODE) - musbotg_vbus_interrupt(&sc->sc_otg[port], 1); - else { - stat = USBCTRL_READ4(sc, port, USBCTRL_STAT); - musbotg_vbus_interrupt(&sc->sc_otg[port], stat & 1); - } -} - -/* - * Arg to musbotg_clocks_on and musbot_clocks_off is - * a uint32_t * pointing to the SCM register offset. - */ -static uint32_t USB_CTRL[] = {SCM_USB_CTRL0, SCM_USB_CTRL1}; - -static void -musbotg_clocks_on(void *arg) -{ - uint32_t c, reg = *(uint32_t *)arg; - - ti_scm_reg_read_4(reg, &c); - c &= ~3; /* Enable power */ - c |= 1 << 19; /* VBUS detect enable */ - c |= 1 << 20; /* Session end enable */ - ti_scm_reg_write_4(reg, c); -} - -static void -musbotg_clocks_off(void *arg) -{ - uint32_t c, reg = *(uint32_t *)arg; - - /* Disable power to PHY */ - ti_scm_reg_read_4(reg, &c); - ti_scm_reg_write_4(reg, c | 3); -} - -static void -musbotg_ep_int_set(struct musbotg_softc *sc, int ep, int on) -{ - struct musbotg_super_softc *ssc = sc->sc_platform_data; - uint32_t epmask; - - epmask = ((1 << ep) << IRQ_STAT0_RXSHIFT); - epmask |= ((1 << ep) << IRQ_STAT0_TXSHIFT); - if (on) - USBCTRL_WRITE4(ssc, sc->sc_id, - USBCTRL_INTEN_SET0, epmask); - else - USBCTRL_WRITE4(ssc, sc->sc_id, - USBCTRL_INTEN_CLR0, epmask); -} - -static void -musbotg_usbss_interrupt(void *arg) -{ - panic("USBSS real interrupt"); -} - -static void -musbotg_wrapper_interrupt(void *arg) -{ - struct musbotg_softc *sc = arg; - struct musbotg_super_softc *ssc = sc->sc_platform_data; - uint32_t stat, stat0, stat1; - stat = USBCTRL_READ4(ssc, sc->sc_id, USBCTRL_STAT); - stat0 = USBCTRL_READ4(ssc, sc->sc_id, USBCTRL_IRQ_STAT0); - stat1 = USBCTRL_READ4(ssc, sc->sc_id, USBCTRL_IRQ_STAT1); - if (stat0) - USBCTRL_WRITE4(ssc, sc->sc_id, USBCTRL_IRQ_STAT0, stat0); - if (stat1) - USBCTRL_WRITE4(ssc, sc->sc_id, USBCTRL_IRQ_STAT1, stat1); - - DPRINTFN(4, "port%d: stat0=%08x stat1=%08x, stat=%08x\n", - sc->sc_id, stat0, stat1, stat); - - if (stat1 & IRQ_STAT1_DRVVBUS) - musbotg_vbus_interrupt(sc, stat & 1); - - musbotg_interrupt(arg, ((stat0 >> 16) & 0xffff), - stat0 & 0xffff, stat1 & 0xff); -} - static int -musbotg_probe(device_t dev) +usbss_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,musb-am33xx")) + if (!ofw_bus_is_compatible(dev, "ti,am33xx-usb")) return (ENXIO); device_set_desc(dev, "TI AM33xx integrated USB OTG controller"); return (BUS_PROBE_DEFAULT); } static int -musbotg_attach(device_t dev) +usbss_attach(device_t dev) { - struct musbotg_super_softc *sc = device_get_softc(dev); - int err; + struct usbss_softc *sc = device_get_softc(dev); int i; - uint32_t rev, reg; + uint32_t rev; + phandle_t node; /* Request the memory resources */ - err = bus_alloc_resources(dev, am335x_musbotg_mem_spec, - sc->sc_mem_res); - if (err) { + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->sc_mem_rid, RF_ACTIVE); + if (sc->sc_mem_res == NULL) { device_printf(dev, "Error: could not allocate mem resources\n"); return (ENXIO); } - /* Request the IRQ resources */ - err = bus_alloc_resources(dev, am335x_musbotg_irq_spec, - sc->sc_irq_res); - if (err) { - device_printf(dev, - "Error: could not allocate irq resources\n"); - return (ENXIO); - } - /* Enable device clocks. */ ti_prcm_clk_enable(MUSB0_CLK); /* * Reset USBSS, USB0 and USB1. * The registers of USB subsystem must not be accessed while the * reset pulse is active (200ns). */ USBSS_WRITE4(sc, USBSS_SYSCONFIG, USBSS_SYSCONFIG_SRESET); DELAY(100); i = 10; while (USBSS_READ4(sc, USBSS_SYSCONFIG) & USBSS_SYSCONFIG_SRESET) { DELAY(100); if (i-- == 0) { device_printf(dev, "reset timeout.\n"); return (ENXIO); } } /* Read the module revision. */ rev = USBSS_READ4(sc, USBSS_REVREG); device_printf(dev, "TI AM335X USBSS v%d.%d.%d\n", (rev >> 8) & 7, (rev >> 6) & 3, rev & 63); - err = bus_setup_intr(dev, sc->sc_irq_res[0], - INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (driver_intr_t *)musbotg_usbss_interrupt, sc, - &sc->sc_intr_hdl); - - if (err) { - sc->sc_intr_hdl = NULL; - device_printf(dev, "Failed to setup USBSS interrupt\n"); - goto error; + node = ofw_bus_get_node(dev); + + if (node == -1) { + usbss_detach(dev); + return (ENXIO); } - for (i = 0; i < AM335X_USB_PORTS; i++) { - /* setup MUSB OTG USB controller interface softc */ - sc->sc_otg[i].sc_clocks_on = &musbotg_clocks_on; - sc->sc_otg[i].sc_clocks_off = &musbotg_clocks_off; - sc->sc_otg[i].sc_clocks_arg = &USB_CTRL[i]; + simplebus_init(dev, node); - sc->sc_otg[i].sc_ep_int_set = musbotg_ep_int_set; + /* + * Allow devices to identify. + */ + bus_generic_probe(dev); - /* initialise some bus fields */ - sc->sc_otg[i].sc_bus.parent = dev; - sc->sc_otg[i].sc_bus.devices = sc->sc_otg[i].sc_devices; - sc->sc_otg[i].sc_bus.devices_max = MUSB2_MAX_DEVICES; - sc->sc_otg[i].sc_bus.dma_bits = 32; + /* + * Now walk the OFW tree and attach top-level devices. + */ + for (node = OF_child(node); node > 0; node = OF_peer(node)) + simplebus_add_device(dev, node, 0, NULL, -1, NULL); - /* get all DMA memory */ - if (usb_bus_mem_alloc_all(&sc->sc_otg[i].sc_bus, - USB_GET_DMA_TAG(dev), NULL)) { - device_printf(dev, - "Failed allocate bus mem for musb%d\n", i); - return (ENOMEM); - } - sc->sc_otg[i].sc_io_res = sc->sc_mem_res[RES_USBCORE(i)]; - sc->sc_otg[i].sc_io_tag = - rman_get_bustag(sc->sc_otg[i].sc_io_res); - sc->sc_otg[i].sc_io_hdl = - rman_get_bushandle(sc->sc_otg[i].sc_io_res); - sc->sc_otg[i].sc_io_size = - rman_get_size(sc->sc_otg[i].sc_io_res); - - sc->sc_otg[i].sc_irq_res = sc->sc_irq_res[i+1]; - - sc->sc_otg[i].sc_bus.bdev = device_add_child(dev, "usbus", -1); - if (!(sc->sc_otg[i].sc_bus.bdev)) { - device_printf(dev, "No busdev for musb%d\n", i); - goto error; - } - device_set_ivars(sc->sc_otg[i].sc_bus.bdev, - &sc->sc_otg[i].sc_bus); - - err = bus_setup_intr(dev, sc->sc_otg[i].sc_irq_res, - INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (driver_intr_t *)musbotg_wrapper_interrupt, - &sc->sc_otg[i], &sc->sc_otg[i].sc_intr_hdl); - if (err) { - sc->sc_otg[i].sc_intr_hdl = NULL; - device_printf(dev, - "Failed to setup interrupt for musb%d\n", i); - goto error; - } - - sc->sc_otg[i].sc_id = i; - sc->sc_otg[i].sc_platform_data = sc; - if (i == 0) - sc->sc_otg[i].sc_mode = MUSB2_DEVICE_MODE; - else - sc->sc_otg[i].sc_mode = MUSB2_HOST_MODE; - - /* - * software-controlled function - */ - - if (sc->sc_otg[i].sc_mode == MUSB2_HOST_MODE) { - reg = USBCTRL_READ4(sc, i, USBCTRL_MODE); - reg |= USBCTRL_MODE_IDDIGMUX; - reg &= ~USBCTRL_MODE_IDDIG; - USBCTRL_WRITE4(sc, i, USBCTRL_MODE, reg); - USBCTRL_WRITE4(sc, i, USBCTRL_UTMI, - USBCTRL_UTMI_FSDATAEXT); - } else { - reg = USBCTRL_READ4(sc, i, USBCTRL_MODE); - reg |= USBCTRL_MODE_IDDIGMUX; - reg |= USBCTRL_MODE_IDDIG; - USBCTRL_WRITE4(sc, i, USBCTRL_MODE, reg); - } - - reg = USBCTRL_INTEN_USB_ALL & ~USBCTRL_INTEN_USB_SOF; - USBCTRL_WRITE4(sc, i, USBCTRL_INTEN_SET1, reg); - USBCTRL_WRITE4(sc, i, USBCTRL_INTEN_CLR0, 0xffffffff); - - err = musbotg_init(&sc->sc_otg[i]); - if (!err) - err = device_probe_and_attach(sc->sc_otg[i].sc_bus.bdev); - - if (err) - goto error; - - /* poll VBUS one time */ - musbotg_vbus_poll(sc, i); - } - - return (0); - -error: - musbotg_detach(dev); - return (ENXIO); + return (bus_generic_attach(dev)); } static int -musbotg_detach(device_t dev) +usbss_detach(device_t dev) { - struct musbotg_super_softc *sc = device_get_softc(dev); - device_t bdev; - int err; - int i; + struct usbss_softc *sc = device_get_softc(dev); - for (i = 0; i < AM335X_USB_PORTS; i++) { - if (sc->sc_otg[i].sc_bus.bdev) { - bdev = sc->sc_otg[i].sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - - if (sc->sc_otg[i].sc_irq_res && sc->sc_otg[i].sc_intr_hdl) { - /* - * only call musbotg_uninit() after musbotg_init() - */ - musbotg_uninit(&sc->sc_otg[i]); - - err = bus_teardown_intr(dev, sc->sc_otg[i].sc_irq_res, - sc->sc_otg[i].sc_intr_hdl); - sc->sc_otg[i].sc_intr_hdl = NULL; - } - - usb_bus_mem_free_all(&sc->sc_otg[i].sc_bus, NULL); - } - - if (sc->sc_intr_hdl) { - bus_teardown_intr(dev, sc->sc_irq_res[0], - sc->sc_intr_hdl); - sc->sc_intr_hdl = NULL; - } - - /* Free resources if any */ - if (sc->sc_mem_res[0]) - bus_release_resources(dev, am335x_musbotg_mem_spec, + if (sc->sc_mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, sc->sc_mem_res); - if (sc->sc_irq_res[0]) - bus_release_resources(dev, am335x_musbotg_irq_spec, - sc->sc_irq_res); - /* during module unload there are lots of children leftover */ device_delete_children(dev); return (0); } -static device_method_t musbotg_methods[] = { +static device_method_t usbss_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, musbotg_probe), - DEVMETHOD(device_attach, musbotg_attach), - DEVMETHOD(device_detach, musbotg_detach), + DEVMETHOD(device_probe, usbss_probe), + DEVMETHOD(device_attach, usbss_attach), + DEVMETHOD(device_detach, usbss_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; -static driver_t musbotg_driver = { - .name = "musbotg", - .methods = musbotg_methods, - .size = sizeof(struct musbotg_super_softc), -}; - -static devclass_t musbotg_devclass; - -DRIVER_MODULE(musbotg, simplebus, musbotg_driver, musbotg_devclass, 0, 0); -MODULE_DEPEND(musbotg, usb, 1, 1, 1); +DEFINE_CLASS_1(usbss, usbss_driver, usbss_methods, + sizeof(struct usbss_softc), simplebus_driver); +static devclass_t usbss_devclass; +DRIVER_MODULE(usbss, simplebus, usbss_driver, usbss_devclass, 0, 0); +MODULE_DEPEND(usbss, usb, 1, 1, 1); Index: head/sys/arm/ti/am335x/files.am335x =================================================================== --- head/sys/arm/ti/am335x/files.am335x (revision 283275) +++ head/sys/arm/ti/am335x/files.am335x (revision 283276) @@ -1,17 +1,20 @@ #$FreeBSD$ arm/ti/aintc.c standard arm/ti/am335x/am335x_dmtimer.c standard arm/ti/am335x/am335x_gpio.c optional gpio arm/ti/am335x/am335x_lcd.c optional sc | vt arm/ti/am335x/am335x_lcd_syscons.c optional sc arm/ti/am335x/am335x_pmic.c optional am335x_pmic arm/ti/am335x/am335x_prcm.c standard -arm/ti/am335x/am335x_pwm.c standard +arm/ti/am335x/am335x_pwmss.c standard +arm/ti/am335x/am335x_ehrpwm.c standard +arm/ti/am335x/am335x_ecap.c standard arm/ti/am335x/am335x_rtc.c optional am335x_rtc arm/ti/am335x/am335x_scm_padconf.c standard arm/ti/am335x/am335x_usbss.c optional musb fdt +arm/ti/am335x/am335x_musb.c optional musb fdt arm/ti/ti_edma3.c standard arm/ti/cpsw/if_cpsw.c optional cpsw Index: head/sys/arm/ti/cpsw/if_cpsw.c =================================================================== --- head/sys/arm/ti/cpsw/if_cpsw.c (revision 283275) +++ head/sys/arm/ti/cpsw/if_cpsw.c (revision 283276) @@ -1,2197 +1,2237 @@ /*- * Copyright (c) 2012 Damjan Marion * 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. */ /* * TI Common Platform Ethernet Switch (CPSW) Driver * Found in TI8148 "DaVinci" and AM335x "Sitara" SoCs. * * This controller is documented in the AM335x Technical Reference * Manual, in the TMS320DM814x DaVinci Digital Video Processors TRM * and in the TMS320C6452 3 Port Switch Ethernet Subsystem TRM. * * It is basically a single Ethernet port (port 0) wired internally to * a 3-port store-and-forward switch connected to two independent * "sliver" controllers (port 1 and port 2). You can operate the * controller in a variety of different ways by suitably configuring * the slivers and the Address Lookup Engine (ALE) that routes packets * between the ports. * * This code was developed and tested on a BeagleBone with * an AM335x SoC. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "if_cpswreg.h" #include "if_cpswvar.h" #include #include "miibus_if.h" /* Device probe/attach/detach. */ static int cpsw_probe(device_t); static void cpsw_init_slots(struct cpsw_softc *); static int cpsw_attach(device_t); static void cpsw_free_slot(struct cpsw_softc *, struct cpsw_slot *); static int cpsw_detach(device_t); /* Device Init/shutdown. */ static void cpsw_init(void *); static void cpsw_init_locked(void *); static int cpsw_shutdown(device_t); static void cpsw_shutdown_locked(struct cpsw_softc *); /* Device Suspend/Resume. */ static int cpsw_suspend(device_t); static int cpsw_resume(device_t); /* Ioctl. */ static int cpsw_ioctl(struct ifnet *, u_long command, caddr_t data); static int cpsw_miibus_readreg(device_t, int phy, int reg); static int cpsw_miibus_writereg(device_t, int phy, int reg, int value); /* Send/Receive packets. */ static void cpsw_intr_rx(void *arg); static struct mbuf *cpsw_rx_dequeue(struct cpsw_softc *); static void cpsw_rx_enqueue(struct cpsw_softc *); static void cpsw_start(struct ifnet *); static void cpsw_tx_enqueue(struct cpsw_softc *); static int cpsw_tx_dequeue(struct cpsw_softc *); /* Misc interrupts and watchdog. */ static void cpsw_intr_rx_thresh(void *); static void cpsw_intr_misc(void *); static void cpsw_tick(void *); static void cpsw_ifmedia_sts(struct ifnet *, struct ifmediareq *); static int cpsw_ifmedia_upd(struct ifnet *); static void cpsw_tx_watchdog(struct cpsw_softc *); /* ALE support */ static void cpsw_ale_read_entry(struct cpsw_softc *, uint16_t idx, uint32_t *ale_entry); static void cpsw_ale_write_entry(struct cpsw_softc *, uint16_t idx, uint32_t *ale_entry); static int cpsw_ale_mc_entry_set(struct cpsw_softc *, uint8_t portmap, uint8_t *mac); static int cpsw_ale_update_addresses(struct cpsw_softc *, int purge); static void cpsw_ale_dump_table(struct cpsw_softc *); /* Statistics and sysctls. */ static void cpsw_add_sysctls(struct cpsw_softc *); static void cpsw_stats_collect(struct cpsw_softc *); static int cpsw_stats_sysctl(SYSCTL_HANDLER_ARGS); /* * Arbitrary limit on number of segments in an mbuf to be transmitted. * Packets with more segments than this will be defragmented before * they are queued. */ #define CPSW_TXFRAGS 8 /* * TODO: The CPSW subsystem (CPSW_SS) can drive two independent PHYs * as separate Ethernet ports. To properly support this, we should * break this into two separate devices: a CPSW_SS device that owns * the interrupts and actually talks to the CPSW hardware, and a * separate CPSW Ethernet child device for each Ethernet port. The RX * interrupt, for example, would be part of CPSW_SS; it would receive * a packet, note the input port, and then dispatch it to the child * device's interface queue. Similarly for transmit. * * It's not clear to me whether the device tree should be restructured * with a cpsw_ss node and two child nodes. That would allow specifying * MAC addresses for each port, for example, but might be overkill. * * Unfortunately, I don't have hardware right now that supports two * Ethernet ports via CPSW. */ static device_method_t cpsw_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cpsw_probe), DEVMETHOD(device_attach, cpsw_attach), DEVMETHOD(device_detach, cpsw_detach), DEVMETHOD(device_shutdown, cpsw_shutdown), DEVMETHOD(device_suspend, cpsw_suspend), DEVMETHOD(device_resume, cpsw_resume), /* MII interface */ DEVMETHOD(miibus_readreg, cpsw_miibus_readreg), DEVMETHOD(miibus_writereg, cpsw_miibus_writereg), { 0, 0 } }; static driver_t cpsw_driver = { "cpsw", cpsw_methods, sizeof(struct cpsw_softc), }; static devclass_t cpsw_devclass; DRIVER_MODULE(cpsw, simplebus, cpsw_driver, cpsw_devclass, 0, 0); DRIVER_MODULE(miibus, cpsw, miibus_driver, miibus_devclass, 0, 0); MODULE_DEPEND(cpsw, ether, 1, 1, 1); MODULE_DEPEND(cpsw, miibus, 1, 1, 1); -static struct resource_spec res_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, +static struct resource_spec irq_res_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, { SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE }, { SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE }, { SYS_RES_IRQ, 3, RF_ACTIVE | RF_SHAREABLE }, { -1, 0 } }; /* Number of entries here must match size of stats * array in struct cpsw_softc. */ static struct cpsw_stat { int reg; char *oid; } cpsw_stat_sysctls[CPSW_SYSCTL_COUNT] = { {0x00, "GoodRxFrames"}, {0x04, "BroadcastRxFrames"}, {0x08, "MulticastRxFrames"}, {0x0C, "PauseRxFrames"}, {0x10, "RxCrcErrors"}, {0x14, "RxAlignErrors"}, {0x18, "OversizeRxFrames"}, {0x1c, "RxJabbers"}, {0x20, "ShortRxFrames"}, {0x24, "RxFragments"}, {0x30, "RxOctets"}, {0x34, "GoodTxFrames"}, {0x38, "BroadcastTxFrames"}, {0x3c, "MulticastTxFrames"}, {0x40, "PauseTxFrames"}, {0x44, "DeferredTxFrames"}, {0x48, "CollisionsTxFrames"}, {0x4c, "SingleCollisionTxFrames"}, {0x50, "MultipleCollisionTxFrames"}, {0x54, "ExcessiveCollisions"}, {0x58, "LateCollisions"}, {0x5c, "TxUnderrun"}, {0x60, "CarrierSenseErrors"}, {0x64, "TxOctets"}, {0x68, "RxTx64OctetFrames"}, {0x6c, "RxTx65to127OctetFrames"}, {0x70, "RxTx128to255OctetFrames"}, {0x74, "RxTx256to511OctetFrames"}, {0x78, "RxTx512to1024OctetFrames"}, {0x7c, "RxTx1024upOctetFrames"}, {0x80, "NetOctets"}, {0x84, "RxStartOfFrameOverruns"}, {0x88, "RxMiddleOfFrameOverruns"}, {0x8c, "RxDmaOverruns"} }; /* * Basic debug support. */ #define IF_DEBUG(sc) if (sc->cpsw_if_flags & IFF_DEBUG) static void cpsw_debugf_head(const char *funcname) { int t = (int)(time_second % (24 * 60 * 60)); printf("%02d:%02d:%02d %s ", t / (60 * 60), (t / 60) % 60, t % 60, funcname); } #include static void cpsw_debugf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); } #define CPSW_DEBUGF(a) do { \ IF_DEBUG(sc) { \ cpsw_debugf_head(__func__); \ cpsw_debugf a; \ } \ } while (0) /* * Locking macros */ #define CPSW_TX_LOCK(sc) do { \ mtx_assert(&(sc)->rx.lock, MA_NOTOWNED); \ mtx_lock(&(sc)->tx.lock); \ } while (0) #define CPSW_TX_UNLOCK(sc) mtx_unlock(&(sc)->tx.lock) #define CPSW_TX_LOCK_ASSERT(sc) mtx_assert(&(sc)->tx.lock, MA_OWNED) #define CPSW_RX_LOCK(sc) do { \ mtx_assert(&(sc)->tx.lock, MA_NOTOWNED); \ mtx_lock(&(sc)->rx.lock); \ } while (0) #define CPSW_RX_UNLOCK(sc) mtx_unlock(&(sc)->rx.lock) #define CPSW_RX_LOCK_ASSERT(sc) mtx_assert(&(sc)->rx.lock, MA_OWNED) #define CPSW_GLOBAL_LOCK(sc) do { \ if ((mtx_owned(&(sc)->tx.lock) ? 1 : 0) != \ (mtx_owned(&(sc)->rx.lock) ? 1 : 0)) { \ panic("cpsw deadlock possibility detection!"); \ } \ mtx_lock(&(sc)->tx.lock); \ mtx_lock(&(sc)->rx.lock); \ } while (0) #define CPSW_GLOBAL_UNLOCK(sc) do { \ CPSW_RX_UNLOCK(sc); \ CPSW_TX_UNLOCK(sc); \ } while (0) #define CPSW_GLOBAL_LOCK_ASSERT(sc) do { \ CPSW_TX_LOCK_ASSERT(sc); \ CPSW_RX_LOCK_ASSERT(sc); \ } while (0) /* * Read/Write macros */ -#define cpsw_read_4(sc, reg) bus_read_4(sc->res[0], reg) -#define cpsw_write_4(sc, reg, val) bus_write_4(sc->res[0], reg, val) +#define cpsw_read_4(sc, reg) bus_read_4(sc->mem_res, reg) +#define cpsw_write_4(sc, reg, val) bus_write_4(sc->mem_res, reg, val) #define cpsw_cpdma_bd_offset(i) (CPSW_CPPI_RAM_OFFSET + ((i)*16)) #define cpsw_cpdma_bd_paddr(sc, slot) \ - BUS_SPACE_PHYSADDR(sc->res[0], slot->bd_offset) + BUS_SPACE_PHYSADDR(sc->mem_res, slot->bd_offset) #define cpsw_cpdma_read_bd(sc, slot, val) \ - bus_read_region_4(sc->res[0], slot->bd_offset, (uint32_t *) val, 4) + bus_read_region_4(sc->mem_res, slot->bd_offset, (uint32_t *) val, 4) #define cpsw_cpdma_write_bd(sc, slot, val) \ - bus_write_region_4(sc->res[0], slot->bd_offset, (uint32_t *) val, 4) + bus_write_region_4(sc->mem_res, slot->bd_offset, (uint32_t *) val, 4) #define cpsw_cpdma_write_bd_next(sc, slot, next_slot) \ cpsw_write_4(sc, slot->bd_offset, cpsw_cpdma_bd_paddr(sc, next_slot)) #define cpsw_cpdma_read_bd_flags(sc, slot) \ - bus_read_2(sc->res[0], slot->bd_offset + 14) + bus_read_2(sc->mem_res, slot->bd_offset + 14) #define cpsw_write_hdp_slot(sc, queue, slot) \ cpsw_write_4(sc, (queue)->hdp_offset, cpsw_cpdma_bd_paddr(sc, slot)) #define CP_OFFSET (CPSW_CPDMA_TX_CP(0) - CPSW_CPDMA_TX_HDP(0)) #define cpsw_read_cp(sc, queue) \ cpsw_read_4(sc, (queue)->hdp_offset + CP_OFFSET) #define cpsw_write_cp(sc, queue, val) \ cpsw_write_4(sc, (queue)->hdp_offset + CP_OFFSET, (val)) #define cpsw_write_cp_slot(sc, queue, slot) \ cpsw_write_cp(sc, queue, cpsw_cpdma_bd_paddr(sc, slot)) #if 0 /* XXX temporary function versions for debugging. */ static void cpsw_write_hdp_slotX(struct cpsw_softc *sc, struct cpsw_queue *queue, struct cpsw_slot *slot) { uint32_t reg = queue->hdp_offset; uint32_t v = cpsw_cpdma_bd_paddr(sc, slot); CPSW_DEBUGF(("HDP <=== 0x%08x (was 0x%08x)", v, cpsw_read_4(sc, reg))); cpsw_write_4(sc, reg, v); } static void cpsw_write_cp_slotX(struct cpsw_softc *sc, struct cpsw_queue *queue, struct cpsw_slot *slot) { uint32_t v = cpsw_cpdma_bd_paddr(sc, slot); CPSW_DEBUGF(("CP <=== 0x%08x (expecting 0x%08x)", v, cpsw_read_cp(sc, queue))); cpsw_write_cp(sc, queue, v); } #endif /* * Expanded dump routines for verbose debugging. */ static void cpsw_dump_slot(struct cpsw_softc *sc, struct cpsw_slot *slot) { static const char *flags[] = {"SOP", "EOP", "Owner", "EOQ", "TDownCmplt", "PassCRC", "Long", "Short", "MacCtl", "Overrun", "PktErr1", "PortEn/PktErr0", "RxVlanEncap", "Port2", "Port1", "Port0"}; struct cpsw_cpdma_bd bd; const char *sep; int i; cpsw_cpdma_read_bd(sc, slot, &bd); printf("BD Addr: 0x%08x Next: 0x%08x\n", cpsw_cpdma_bd_paddr(sc, slot), bd.next); printf(" BufPtr: 0x%08x BufLen: 0x%08x\n", bd.bufptr, bd.buflen); printf(" BufOff: 0x%08x PktLen: 0x%08x\n", bd.bufoff, bd.pktlen); printf(" Flags: "); sep = ""; for (i = 0; i < 16; ++i) { if (bd.flags & (1 << (15 - i))) { printf("%s%s", sep, flags[i]); sep = ","; } } printf("\n"); if (slot->mbuf) { printf(" Ether: %14D\n", (char *)(slot->mbuf->m_data), " "); printf(" Packet: %16D\n", (char *)(slot->mbuf->m_data) + 14, " "); } } #define CPSW_DUMP_SLOT(cs, slot) do { \ IF_DEBUG(sc) { \ cpsw_dump_slot(sc, slot); \ } \ } while (0) static void cpsw_dump_queue(struct cpsw_softc *sc, struct cpsw_slots *q) { struct cpsw_slot *slot; int i = 0; int others = 0; STAILQ_FOREACH(slot, q, next) { if (i > 4) ++others; else cpsw_dump_slot(sc, slot); ++i; } if (others) printf(" ... and %d more.\n", others); printf("\n"); } #define CPSW_DUMP_QUEUE(sc, q) do { \ IF_DEBUG(sc) { \ cpsw_dump_queue(sc, q); \ } \ } while (0) /* * * Device Probe, Attach, Detach. * */ static int cpsw_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "ti,cpsw")) return (ENXIO); device_set_desc(dev, "3-port Switch Ethernet Subsystem"); return (BUS_PROBE_DEFAULT); } static void cpsw_init_slots(struct cpsw_softc *sc) { struct cpsw_slot *slot; int i; STAILQ_INIT(&sc->avail); /* Put the slot descriptors onto the global avail list. */ for (i = 0; i < sizeof(sc->_slots) / sizeof(sc->_slots[0]); i++) { slot = &sc->_slots[i]; slot->bd_offset = cpsw_cpdma_bd_offset(i); STAILQ_INSERT_TAIL(&sc->avail, slot, next); } } /* * bind an interrupt, add the relevant info to sc->interrupts */ static int cpsw_attach_interrupt(struct cpsw_softc *sc, struct resource *res, driver_intr_t *handler, const char *description) { void **pcookie; int error; sc->interrupts[sc->interrupt_count].res = res; sc->interrupts[sc->interrupt_count].description = description; pcookie = &sc->interrupts[sc->interrupt_count].ih_cookie; error = bus_setup_intr(sc->dev, res, INTR_TYPE_NET | INTR_MPSAFE, NULL, *handler, sc, pcookie); if (error) device_printf(sc->dev, "could not setup %s\n", description); else ++sc->interrupt_count; return (error); } /* * teardown everything in sc->interrupts. */ static void cpsw_detach_interrupts(struct cpsw_softc *sc) { int error; int i; for (i = 0; i < sizeof(sc->interrupts) / sizeof(sc->interrupts[0]); ++i) { if (!sc->interrupts[i].ih_cookie) continue; error = bus_teardown_intr(sc->dev, sc->interrupts[i].res, sc->interrupts[i].ih_cookie); if (error) device_printf(sc->dev, "could not release %s\n", sc->interrupts[i].description); sc->interrupts[i].ih_cookie = NULL; } } static int cpsw_add_slots(struct cpsw_softc *sc, struct cpsw_queue *queue, int requested) { const int max_slots = sizeof(sc->_slots) / sizeof(sc->_slots[0]); struct cpsw_slot *slot; int i; if (requested < 0) requested = max_slots; for (i = 0; i < requested; ++i) { slot = STAILQ_FIRST(&sc->avail); if (slot == NULL) return (0); if (bus_dmamap_create(sc->mbuf_dtag, 0, &slot->dmamap)) { if_printf(sc->ifp, "failed to create dmamap\n"); return (ENOMEM); } STAILQ_REMOVE_HEAD(&sc->avail, next); STAILQ_INSERT_TAIL(&queue->avail, slot, next); ++queue->avail_queue_len; ++queue->queue_slots; } return (0); } static int cpsw_attach(device_t dev) { bus_dma_segment_t segs[1]; struct cpsw_softc *sc = device_get_softc(dev); struct mii_softc *miisc; struct ifnet *ifp; - void *phy_sc; - int error, phy, nsegs; + int phy, nsegs, error; uint32_t reg; + pcell_t phy_id[3]; + u_long mem_base, mem_size; + phandle_t child; + int len; CPSW_DEBUGF(("")); getbinuptime(&sc->attach_uptime); sc->dev = dev; sc->node = ofw_bus_get_node(dev); - /* Get phy address from fdt */ - if (fdt_get_phyaddr(sc->node, sc->dev, &phy, &phy_sc) != 0) { + /* TODO: handle multiple slaves */ + phy = -1; + + /* Find any slave with phy_id */ + for (child = OF_child(sc->node); child != 0; child = OF_peer(child)) { + len = OF_getproplen(child, "phy_id"); + if (len <= 0) + continue; + + /* Get phy address from fdt */ + if (OF_getencprop(child, "phy_id", phy_id, len) <= 0) + continue; + + phy = phy_id[1]; + /* TODO: get memory window for MDIO */ + + break; + } + + if (phy == -1) { device_printf(dev, "failed to get PHY address from FDT\n"); return (ENXIO); } + + mem_base = 0; + mem_size = 0; + + if (fdt_regsize(sc->node, &mem_base, &mem_size) != 0) { + device_printf(sc->dev, "no regs property in cpsw node\n"); + return (ENXIO); + } + /* Initialize mutexes */ mtx_init(&sc->tx.lock, device_get_nameunit(dev), "cpsw TX lock", MTX_DEF); mtx_init(&sc->rx.lock, device_get_nameunit(dev), "cpsw RX lock", MTX_DEF); - /* Allocate IO and IRQ resources */ - error = bus_alloc_resources(dev, res_spec, sc->res); + /* Allocate IRQ resources */ + error = bus_alloc_resources(dev, irq_res_spec, sc->irq_res); if (error) { - device_printf(dev, "could not allocate resources\n"); + device_printf(dev, "could not allocate IRQ resources\n"); cpsw_detach(dev); return (ENXIO); } + sc->mem_rid = 0; + sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, + &sc->mem_rid, mem_base, mem_base + CPSW_MEMWINDOW_SIZE -1, + CPSW_MEMWINDOW_SIZE, RF_ACTIVE); + if (sc->mem_res == NULL) { + device_printf(sc->dev, "failed to allocate memory resource\n"); + cpsw_detach(dev); + return (ENXIO); + } + reg = cpsw_read_4(sc, CPSW_SS_IDVER); device_printf(dev, "CPSW SS Version %d.%d (%d)\n", (reg >> 8 & 0x7), reg & 0xFF, (reg >> 11) & 0x1F); cpsw_add_sysctls(sc); /* Allocate a busdma tag and DMA safe memory for mbufs. */ error = bus_dma_tag_create( bus_get_dma_tag(sc->dev), /* parent */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filtfunc, filtfuncarg */ MCLBYTES, CPSW_TXFRAGS, /* maxsize, nsegments */ MCLBYTES, 0, /* maxsegsz, flags */ NULL, NULL, /* lockfunc, lockfuncarg */ &sc->mbuf_dtag); /* dmatag */ if (error) { device_printf(dev, "bus_dma_tag_create failed\n"); cpsw_detach(dev); return (error); } /* Allocate network interface */ ifp = sc->ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "if_alloc() failed\n"); cpsw_detach(dev); return (ENOMEM); } /* Allocate the null mbuf and pre-sync it. */ sc->null_mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); memset(sc->null_mbuf->m_data, 0, sc->null_mbuf->m_ext.ext_size); bus_dmamap_create(sc->mbuf_dtag, 0, &sc->null_mbuf_dmamap); bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, sc->null_mbuf_dmamap, sc->null_mbuf, segs, &nsegs, BUS_DMA_NOWAIT); bus_dmamap_sync(sc->mbuf_dtag, sc->null_mbuf_dmamap, BUS_DMASYNC_PREWRITE); sc->null_mbuf_paddr = segs[0].ds_addr; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_softc = sc; ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST; ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; //FIXME VLAN? ifp->if_capenable = ifp->if_capabilities; ifp->if_init = cpsw_init; ifp->if_start = cpsw_start; ifp->if_ioctl = cpsw_ioctl; cpsw_init_slots(sc); /* Allocate slots to TX and RX queues. */ STAILQ_INIT(&sc->rx.avail); STAILQ_INIT(&sc->rx.active); STAILQ_INIT(&sc->tx.avail); STAILQ_INIT(&sc->tx.active); // For now: 128 slots to TX, rest to RX. // XXX TODO: start with 32/64 and grow dynamically based on demand. if (cpsw_add_slots(sc, &sc->tx, 128) || cpsw_add_slots(sc, &sc->rx, -1)) { device_printf(dev, "failed to allocate dmamaps\n"); cpsw_detach(dev); return (ENOMEM); } device_printf(dev, "Initial queue size TX=%d RX=%d\n", sc->tx.queue_slots, sc->rx.queue_slots); ifp->if_snd.ifq_drv_maxlen = sc->tx.queue_slots; IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); IFQ_SET_READY(&ifp->if_snd); sc->tx.hdp_offset = CPSW_CPDMA_TX_HDP(0); sc->rx.hdp_offset = CPSW_CPDMA_RX_HDP(0); /* Get high part of MAC address from control module (mac_id0_hi) */ /* TODO: Get MAC ID1 as well as MAC ID0. */ ti_scm_reg_read_4(0x634, ®); sc->mac_addr[0] = reg & 0xFF; sc->mac_addr[1] = (reg >> 8) & 0xFF; sc->mac_addr[2] = (reg >> 16) & 0xFF; sc->mac_addr[3] = (reg >> 24) & 0xFF; /* Get low part of MAC address from control module (mac_id0_lo) */ ti_scm_reg_read_4(0x630, ®); sc->mac_addr[4] = reg & 0xFF; sc->mac_addr[5] = (reg >> 8) & 0xFF; /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */ /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */ cpsw_write_4(sc, MDIOCONTROL, 1 << 30 | 1 << 18 | 0xFF); /* Clear ALE */ cpsw_write_4(sc, CPSW_ALE_CONTROL, 1 << 30); /* Attach PHY(s) */ error = mii_attach(dev, &sc->miibus, ifp, cpsw_ifmedia_upd, cpsw_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); if (error) { device_printf(dev, "attaching PHYs failed\n"); cpsw_detach(dev); return (error); } sc->mii = device_get_softc(sc->miibus); /* Tell the MAC where to find the PHY so autoneg works */ miisc = LIST_FIRST(&sc->mii->mii_phys); /* Select PHY and enable interrupts */ cpsw_write_4(sc, MDIOUSERPHYSEL0, 1 << 6 | (miisc->mii_phy & 0x1F)); /* Note: We don't use sc->res[3] (TX interrupt) */ - if (cpsw_attach_interrupt(sc, sc->res[1], + if (cpsw_attach_interrupt(sc, sc->irq_res[0], cpsw_intr_rx_thresh, "CPSW RX threshold interrupt") || - cpsw_attach_interrupt(sc, sc->res[2], + cpsw_attach_interrupt(sc, sc->irq_res[1], cpsw_intr_rx, "CPSW RX interrupt") || - cpsw_attach_interrupt(sc, sc->res[4], + cpsw_attach_interrupt(sc, sc->irq_res[3], cpsw_intr_misc, "CPSW misc interrupt")) { cpsw_detach(dev); return (ENXIO); } ether_ifattach(ifp, sc->mac_addr); callout_init(&sc->watchdog.callout, 0); return (0); } static void cpsw_free_slot(struct cpsw_softc *sc, struct cpsw_slot *slot) { int error; if (slot->dmamap) { error = bus_dmamap_destroy(sc->mbuf_dtag, slot->dmamap); KASSERT(error == 0, ("Mapping still active")); slot->dmamap = NULL; } if (slot->mbuf) { m_freem(slot->mbuf); slot->mbuf = NULL; } } static int cpsw_detach(device_t dev) { struct cpsw_softc *sc = device_get_softc(dev); int error, i; CPSW_DEBUGF(("")); /* Stop controller and free TX queue */ if (device_is_attached(dev)) { ether_ifdetach(sc->ifp); CPSW_GLOBAL_LOCK(sc); cpsw_shutdown_locked(sc); CPSW_GLOBAL_UNLOCK(sc); callout_drain(&sc->watchdog.callout); } bus_generic_detach(dev); if (sc->miibus) device_delete_child(dev, sc->miibus); /* Stop and release all interrupts */ cpsw_detach_interrupts(sc); /* Free dmamaps and mbufs */ for (i = 0; i < sizeof(sc->_slots) / sizeof(sc->_slots[0]); ++i) cpsw_free_slot(sc, &sc->_slots[i]); if (sc->null_mbuf_dmamap) { error = bus_dmamap_destroy(sc->mbuf_dtag, sc->null_mbuf_dmamap); KASSERT(error == 0, ("Mapping still active")); } if (sc->null_mbuf) m_freem(sc->null_mbuf); /* Free DMA tag */ error = bus_dma_tag_destroy(sc->mbuf_dtag); KASSERT(error == 0, ("Unable to destroy DMA tag")); /* Free IO memory handler */ - bus_release_resources(dev, res_spec, sc->res); + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); + bus_release_resources(dev, irq_res_spec, sc->irq_res); if (sc->ifp != NULL) if_free(sc->ifp); /* Destroy mutexes */ mtx_destroy(&sc->rx.lock); mtx_destroy(&sc->tx.lock); return (0); } /* * * Init/Shutdown. * */ static void cpsw_reset(struct cpsw_softc *sc) { int i; /* Reset RMII/RGMII wrapper. */ cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1); while (cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1) ; /* Disable TX and RX interrupts for all cores. */ for (i = 0; i < 3; ++i) { cpsw_write_4(sc, CPSW_WR_C_RX_THRESH_EN(i), 0x00); cpsw_write_4(sc, CPSW_WR_C_TX_EN(i), 0x00); cpsw_write_4(sc, CPSW_WR_C_RX_EN(i), 0x00); cpsw_write_4(sc, CPSW_WR_C_MISC_EN(i), 0x00); } /* Reset CPSW subsystem. */ cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1); while (cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1) ; /* Reset Sliver port 1 and 2 */ for (i = 0; i < 2; i++) { /* Reset */ cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1); while (cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1) ; } /* Reset DMA controller. */ cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1); while (cpsw_read_4(sc, CPSW_CPDMA_SOFT_RESET) & 1) ; /* Disable TX & RX DMA */ cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 0); cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 0); /* Clear all queues. */ for (i = 0; i < 8; i++) { cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(i), 0); cpsw_write_4(sc, CPSW_CPDMA_RX_HDP(i), 0); cpsw_write_4(sc, CPSW_CPDMA_TX_CP(i), 0); cpsw_write_4(sc, CPSW_CPDMA_RX_CP(i), 0); } /* Clear all interrupt Masks */ cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF); cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF); } static void cpsw_init(void *arg) { struct cpsw_softc *sc = arg; CPSW_DEBUGF(("")); CPSW_GLOBAL_LOCK(sc); cpsw_init_locked(arg); CPSW_GLOBAL_UNLOCK(sc); } static void cpsw_init_locked(void *arg) { struct ifnet *ifp; struct cpsw_softc *sc = arg; struct cpsw_slot *slot; uint32_t i; CPSW_DEBUGF(("")); ifp = sc->ifp; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) return; getbinuptime(&sc->init_uptime); /* Reset the controller. */ cpsw_reset(sc); /* Enable ALE */ cpsw_write_4(sc, CPSW_ALE_CONTROL, 1 << 31 | 1 << 4); /* Init Sliver port 1 and 2 */ for (i = 0; i < 2; i++) { /* Set Slave Mapping */ cpsw_write_4(sc, CPSW_SL_RX_PRI_MAP(i), 0x76543210); cpsw_write_4(sc, CPSW_PORT_P_TX_PRI_MAP(i + 1), 0x33221100); cpsw_write_4(sc, CPSW_SL_RX_MAXLEN(i), 0x5f2); /* Set MACCONTROL for ports 0,1: IFCTL_B(16), IFCTL_A(15), GMII_EN(5), FULLDUPLEX(1) */ /* TODO: Docs claim that IFCTL_B and IFCTL_A do the same thing? */ /* Huh? Docs call bit 0 "Loopback" some places, "FullDuplex" others. */ cpsw_write_4(sc, CPSW_SL_MACCONTROL(i), 1 << 15 | 1 << 5 | 1); } /* Set Host Port Mapping */ cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210); cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0); /* Initialize ALE: all ports set to forwarding(3), initialize addrs */ for (i = 0; i < 3; i++) cpsw_write_4(sc, CPSW_ALE_PORTCTL(i), 3); cpsw_ale_update_addresses(sc, 1); cpsw_write_4(sc, CPSW_SS_PTYPE, 0); /* Enable statistics for ports 0, 1 and 2 */ cpsw_write_4(sc, CPSW_SS_STAT_PORT_EN, 7); /* Experiment: Turn off flow control */ /* This seems to fix the watchdog resets that have plagued earlier versions of this driver; I'm not yet sure if there are negative effects yet. */ cpsw_write_4(sc, CPSW_SS_FLOW_CONTROL, 0); /* Make IP hdr aligned with 4 */ cpsw_write_4(sc, CPSW_CPDMA_RX_BUFFER_OFFSET, 2); /* Initialize RX Buffer Descriptors */ cpsw_write_4(sc, CPSW_CPDMA_RX_FREEBUFFER(0), 0); /* Enable TX & RX DMA */ cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 1); cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 1); /* Enable Interrupts for core 0 */ cpsw_write_4(sc, CPSW_WR_C_RX_THRESH_EN(0), 0xFF); cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 0xFF); cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x3F); /* Enable host Error Interrupt */ cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_SET, 3); /* Enable interrupts for RX Channel 0 */ cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_SET, 1); /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */ /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */ cpsw_write_4(sc, MDIOCONTROL, 1 << 30 | 1 << 18 | 0xFF); /* Select MII in GMII_SEL, Internal Delay mode */ //ti_scm_reg_write_4(0x650, 0); /* Initialize active queues. */ slot = STAILQ_FIRST(&sc->tx.active); if (slot != NULL) cpsw_write_hdp_slot(sc, &sc->tx, slot); slot = STAILQ_FIRST(&sc->rx.active); if (slot != NULL) cpsw_write_hdp_slot(sc, &sc->rx, slot); cpsw_rx_enqueue(sc); /* Activate network interface */ sc->rx.running = 1; sc->tx.running = 1; sc->watchdog.timer = 0; callout_reset(&sc->watchdog.callout, hz, cpsw_tick, sc); sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } static int cpsw_shutdown(device_t dev) { struct cpsw_softc *sc = device_get_softc(dev); CPSW_DEBUGF(("")); CPSW_GLOBAL_LOCK(sc); cpsw_shutdown_locked(sc); CPSW_GLOBAL_UNLOCK(sc); return (0); } static void cpsw_rx_teardown_locked(struct cpsw_softc *sc) { struct mbuf *received, *next; int i = 0; CPSW_DEBUGF(("starting RX teardown")); cpsw_write_4(sc, CPSW_CPDMA_RX_TEARDOWN, 0); for (;;) { received = cpsw_rx_dequeue(sc); CPSW_GLOBAL_UNLOCK(sc); while (received != NULL) { next = received->m_nextpkt; received->m_nextpkt = NULL; (*sc->ifp->if_input)(sc->ifp, received); received = next; } CPSW_GLOBAL_LOCK(sc); if (!sc->rx.running) { CPSW_DEBUGF(("finished RX teardown (%d retries)", i)); return; } if (++i > 10) { if_printf(sc->ifp, "Unable to cleanly shutdown receiver\n"); return; } DELAY(10); } } static void cpsw_tx_teardown_locked(struct cpsw_softc *sc) { int i = 0; CPSW_DEBUGF(("starting TX teardown")); cpsw_write_4(sc, CPSW_CPDMA_TX_TEARDOWN, 0); cpsw_tx_dequeue(sc); while (sc->tx.running && ++i < 10) { DELAY(10); cpsw_tx_dequeue(sc); } if (sc->tx.running) if_printf(sc->ifp, "Unable to cleanly shutdown transmitter\n"); CPSW_DEBUGF(("finished TX teardown (%d retries, %d idle buffers)", i, sc->tx.active_queue_len)); } static void cpsw_shutdown_locked(struct cpsw_softc *sc) { struct ifnet *ifp; CPSW_DEBUGF(("")); CPSW_GLOBAL_LOCK_ASSERT(sc); ifp = sc->ifp; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; /* Disable interface */ ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ifp->if_drv_flags |= IFF_DRV_OACTIVE; /* Stop ticker */ callout_stop(&sc->watchdog.callout); /* Tear down the RX/TX queues. */ cpsw_rx_teardown_locked(sc); cpsw_tx_teardown_locked(sc); /* Capture stats before we reset controller. */ cpsw_stats_collect(sc); cpsw_reset(sc); } /* * Suspend/Resume. */ static int cpsw_suspend(device_t dev) { struct cpsw_softc *sc = device_get_softc(dev); CPSW_DEBUGF(("")); CPSW_GLOBAL_LOCK(sc); cpsw_shutdown_locked(sc); CPSW_GLOBAL_UNLOCK(sc); return (0); } static int cpsw_resume(device_t dev) { struct cpsw_softc *sc = device_get_softc(dev); CPSW_DEBUGF(("UNIMPLEMENTED")); return (0); } /* * * IOCTL * */ static void cpsw_set_promisc(struct cpsw_softc *sc, int set) { /* * Enabling promiscuous mode requires two bits of work: First, * ALE_BYPASS needs to be enabled. That disables the ALE * forwarding logic and causes every packet to be sent to the * host port. That makes us promiscuous wrt received packets. * * With ALE forwarding disabled, the transmitter needs to set * an explicit output port on every packet to route it to the * correct egress. This should be doable for systems such as * BeagleBone where only one egress port is actually wired to * a PHY. If you have both egress ports wired up, life gets a * lot more interesting. * * Hmmm.... NetBSD driver uses ALE_BYPASS always and doesn't * seem to set explicit egress ports. Does that mean they * are always promiscuous? */ if (set) { printf("Promiscuous mode unimplemented\n"); } } static void cpsw_set_allmulti(struct cpsw_softc *sc, int set) { if (set) { printf("All-multicast mode unimplemented\n"); } } static int cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct cpsw_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; int error; uint32_t changed; error = 0; switch (command) { case SIOCSIFFLAGS: CPSW_GLOBAL_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { changed = ifp->if_flags ^ sc->cpsw_if_flags; CPSW_DEBUGF(("SIOCSIFFLAGS: UP & RUNNING (changed=0x%x)", changed)); if (changed & IFF_PROMISC) cpsw_set_promisc(sc, ifp->if_flags & IFF_PROMISC); if (changed & IFF_ALLMULTI) cpsw_set_allmulti(sc, ifp->if_flags & IFF_ALLMULTI); } else { CPSW_DEBUGF(("SIOCSIFFLAGS: UP but not RUNNING; starting up")); cpsw_init_locked(sc); } } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) { CPSW_DEBUGF(("SIOCSIFFLAGS: not UP but RUNNING; shutting down")); cpsw_shutdown_locked(sc); } sc->cpsw_if_flags = ifp->if_flags; CPSW_GLOBAL_UNLOCK(sc); break; case SIOCADDMULTI: cpsw_ale_update_addresses(sc, 0); break; case SIOCDELMULTI: /* Ugh. DELMULTI doesn't provide the specific address being removed, so the best we can do is remove everything and rebuild it all. */ cpsw_ale_update_addresses(sc, 1); break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command); break; default: error = ether_ioctl(ifp, command, data); } return (error); } /* * * MIIBUS * */ static int cpsw_miibus_ready(struct cpsw_softc *sc) { uint32_t r, retries = CPSW_MIIBUS_RETRIES; while (--retries) { r = cpsw_read_4(sc, MDIOUSERACCESS0); if ((r & 1 << 31) == 0) return 1; DELAY(CPSW_MIIBUS_DELAY); } return 0; } static int cpsw_miibus_readreg(device_t dev, int phy, int reg) { struct cpsw_softc *sc = device_get_softc(dev); uint32_t cmd, r; if (!cpsw_miibus_ready(sc)) { device_printf(dev, "MDIO not ready to read\n"); return 0; } /* Set GO, reg, phy */ cmd = 1 << 31 | (reg & 0x1F) << 21 | (phy & 0x1F) << 16; cpsw_write_4(sc, MDIOUSERACCESS0, cmd); if (!cpsw_miibus_ready(sc)) { device_printf(dev, "MDIO timed out during read\n"); return 0; } r = cpsw_read_4(sc, MDIOUSERACCESS0); if((r & 1 << 29) == 0) { device_printf(dev, "Failed to read from PHY.\n"); r = 0; } return (r & 0xFFFF); } static int cpsw_miibus_writereg(device_t dev, int phy, int reg, int value) { struct cpsw_softc *sc = device_get_softc(dev); uint32_t cmd; if (!cpsw_miibus_ready(sc)) { device_printf(dev, "MDIO not ready to write\n"); return 0; } /* Set GO, WRITE, reg, phy, and value */ cmd = 3 << 30 | (reg & 0x1F) << 21 | (phy & 0x1F) << 16 | (value & 0xFFFF); cpsw_write_4(sc, MDIOUSERACCESS0, cmd); if (!cpsw_miibus_ready(sc)) { device_printf(dev, "MDIO timed out during write\n"); return 0; } if((cpsw_read_4(sc, MDIOUSERACCESS0) & (1 << 29)) == 0) device_printf(dev, "Failed to write to PHY.\n"); return 0; } /* * * Transmit/Receive Packets. * */ static void cpsw_intr_rx(void *arg) { struct cpsw_softc *sc = arg; struct mbuf *received, *next; CPSW_RX_LOCK(sc); received = cpsw_rx_dequeue(sc); cpsw_rx_enqueue(sc); cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, 1); CPSW_RX_UNLOCK(sc); while (received != NULL) { next = received->m_nextpkt; received->m_nextpkt = NULL; (*sc->ifp->if_input)(sc->ifp, received); received = next; } } static struct mbuf * cpsw_rx_dequeue(struct cpsw_softc *sc) { struct cpsw_cpdma_bd bd; struct cpsw_slot *slot; struct ifnet *ifp; struct mbuf *mb_head, *mb_tail; int removed = 0; ifp = sc->ifp; mb_head = mb_tail = NULL; /* Pull completed packets off hardware RX queue. */ while ((slot = STAILQ_FIRST(&sc->rx.active)) != NULL) { cpsw_cpdma_read_bd(sc, slot, &bd); if (bd.flags & CPDMA_BD_OWNER) break; /* Still in use by hardware */ CPSW_DEBUGF(("Removing received packet from RX queue")); ++removed; STAILQ_REMOVE_HEAD(&sc->rx.active, next); STAILQ_INSERT_TAIL(&sc->rx.avail, slot, next); bus_dmamap_sync(sc->mbuf_dtag, slot->dmamap, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap); if (bd.flags & CPDMA_BD_TDOWNCMPLT) { CPSW_DEBUGF(("RX teardown in progress")); m_freem(slot->mbuf); slot->mbuf = NULL; cpsw_write_cp(sc, &sc->rx, 0xfffffffc); sc->rx.running = 0; break; } cpsw_write_cp_slot(sc, &sc->rx, slot); /* Set up mbuf */ /* TODO: track SOP/EOP bits to assemble a full mbuf out of received fragments. */ slot->mbuf->m_data += bd.bufoff; slot->mbuf->m_len = bd.pktlen - 4; slot->mbuf->m_pkthdr.len = bd.pktlen - 4; slot->mbuf->m_flags |= M_PKTHDR; slot->mbuf->m_pkthdr.rcvif = ifp; slot->mbuf->m_nextpkt = NULL; if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) { /* check for valid CRC by looking into pkt_err[5:4] */ if ((bd.flags & CPDMA_BD_PKT_ERR_MASK) == 0) { slot->mbuf->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; slot->mbuf->m_pkthdr.csum_flags |= CSUM_IP_VALID; slot->mbuf->m_pkthdr.csum_data = 0xffff; } } /* Add mbuf to packet list to be returned. */ if (mb_tail) { mb_tail->m_nextpkt = slot->mbuf; } else { mb_head = slot->mbuf; } mb_tail = slot->mbuf; slot->mbuf = NULL; } if (removed != 0) { sc->rx.queue_removes += removed; sc->rx.active_queue_len -= removed; sc->rx.avail_queue_len += removed; if (sc->rx.avail_queue_len > sc->rx.max_avail_queue_len) sc->rx.max_avail_queue_len = sc->rx.avail_queue_len; } return (mb_head); } static void cpsw_rx_enqueue(struct cpsw_softc *sc) { bus_dma_segment_t seg[1]; struct cpsw_cpdma_bd bd; struct ifnet *ifp = sc->ifp; struct cpsw_slots tmpqueue = STAILQ_HEAD_INITIALIZER(tmpqueue); struct cpsw_slot *slot, *prev_slot = NULL; struct cpsw_slot *last_old_slot, *first_new_slot; int error, nsegs, added = 0; /* Register new mbufs with hardware. */ while ((slot = STAILQ_FIRST(&sc->rx.avail)) != NULL) { if (slot->mbuf == NULL) { slot->mbuf = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (slot->mbuf == NULL) { if_printf(sc->ifp, "Unable to fill RX queue\n"); break; } slot->mbuf->m_len = slot->mbuf->m_pkthdr.len = slot->mbuf->m_ext.ext_size; } error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, slot->dmamap, slot->mbuf, seg, &nsegs, BUS_DMA_NOWAIT); KASSERT(nsegs == 1, ("More than one segment (nsegs=%d)", nsegs)); KASSERT(error == 0, ("DMA error (error=%d)", error)); if (error != 0 || nsegs != 1) { if_printf(ifp, "%s: Can't prep RX buf for DMA (nsegs=%d, error=%d)\n", __func__, nsegs, error); bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap); m_freem(slot->mbuf); slot->mbuf = NULL; break; } bus_dmamap_sync(sc->mbuf_dtag, slot->dmamap, BUS_DMASYNC_PREREAD); /* Create and submit new rx descriptor*/ bd.next = 0; bd.bufptr = seg->ds_addr; bd.bufoff = 0; bd.buflen = MCLBYTES - 1; bd.pktlen = bd.buflen; bd.flags = CPDMA_BD_OWNER; cpsw_cpdma_write_bd(sc, slot, &bd); ++added; if (prev_slot != NULL) cpsw_cpdma_write_bd_next(sc, prev_slot, slot); prev_slot = slot; STAILQ_REMOVE_HEAD(&sc->rx.avail, next); sc->rx.avail_queue_len--; STAILQ_INSERT_TAIL(&tmpqueue, slot, next); } if (added == 0) return; CPSW_DEBUGF(("Adding %d buffers to RX queue", added)); /* Link new entries to hardware RX queue. */ last_old_slot = STAILQ_LAST(&sc->rx.active, cpsw_slot, next); first_new_slot = STAILQ_FIRST(&tmpqueue); STAILQ_CONCAT(&sc->rx.active, &tmpqueue); if (first_new_slot == NULL) { return; } else if (last_old_slot == NULL) { /* Start a fresh queue. */ cpsw_write_hdp_slot(sc, &sc->rx, first_new_slot); } else { /* Add buffers to end of current queue. */ cpsw_cpdma_write_bd_next(sc, last_old_slot, first_new_slot); /* If underrun, restart queue. */ if (cpsw_cpdma_read_bd_flags(sc, last_old_slot) & CPDMA_BD_EOQ) { cpsw_write_hdp_slot(sc, &sc->rx, first_new_slot); } } sc->rx.queue_adds += added; sc->rx.active_queue_len += added; if (sc->rx.active_queue_len > sc->rx.max_active_queue_len) { sc->rx.max_active_queue_len = sc->rx.active_queue_len; } } static void cpsw_start(struct ifnet *ifp) { struct cpsw_softc *sc = ifp->if_softc; CPSW_TX_LOCK(sc); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->tx.running) { cpsw_tx_enqueue(sc); cpsw_tx_dequeue(sc); } CPSW_TX_UNLOCK(sc); } static void cpsw_tx_enqueue(struct cpsw_softc *sc) { bus_dma_segment_t segs[CPSW_TXFRAGS]; struct cpsw_cpdma_bd bd; struct cpsw_slots tmpqueue = STAILQ_HEAD_INITIALIZER(tmpqueue); struct cpsw_slot *slot, *prev_slot = NULL; struct cpsw_slot *last_old_slot, *first_new_slot; struct mbuf *m0; int error, nsegs, seg, added = 0, padlen; /* Pull pending packets from IF queue and prep them for DMA. */ while ((slot = STAILQ_FIRST(&sc->tx.avail)) != NULL) { IF_DEQUEUE(&sc->ifp->if_snd, m0); if (m0 == NULL) break; slot->mbuf = m0; padlen = ETHER_MIN_LEN - slot->mbuf->m_pkthdr.len; if (padlen < 0) padlen = 0; /* Create mapping in DMA memory */ error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, slot->dmamap, slot->mbuf, segs, &nsegs, BUS_DMA_NOWAIT); /* If the packet is too fragmented, try to simplify. */ if (error == EFBIG || (error == 0 && nsegs + (padlen > 0 ? 1 : 0) > sc->tx.avail_queue_len)) { bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap); if (padlen > 0) /* May as well add padding. */ m_append(slot->mbuf, padlen, sc->null_mbuf->m_data); m0 = m_defrag(slot->mbuf, M_NOWAIT); if (m0 == NULL) { if_printf(sc->ifp, "Can't defragment packet; dropping\n"); m_freem(slot->mbuf); } else { CPSW_DEBUGF(("Requeueing defragmented packet")); IF_PREPEND(&sc->ifp->if_snd, m0); } slot->mbuf = NULL; continue; } if (error != 0) { if_printf(sc->ifp, "%s: Can't setup DMA (error=%d), dropping packet\n", __func__, error); bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap); m_freem(slot->mbuf); slot->mbuf = NULL; break; } bus_dmamap_sync(sc->mbuf_dtag, slot->dmamap, BUS_DMASYNC_PREWRITE); CPSW_DEBUGF(("Queueing TX packet: %d segments + %d pad bytes", nsegs, padlen)); /* If there is only one segment, the for() loop * gets skipped and the single buffer gets set up * as both SOP and EOP. */ /* Start by setting up the first buffer */ bd.next = 0; bd.bufptr = segs[0].ds_addr; bd.bufoff = 0; bd.buflen = segs[0].ds_len; bd.pktlen = m_length(slot->mbuf, NULL) + padlen; bd.flags = CPDMA_BD_SOP | CPDMA_BD_OWNER; for (seg = 1; seg < nsegs; ++seg) { /* Save the previous buffer (which isn't EOP) */ cpsw_cpdma_write_bd(sc, slot, &bd); if (prev_slot != NULL) cpsw_cpdma_write_bd_next(sc, prev_slot, slot); prev_slot = slot; STAILQ_REMOVE_HEAD(&sc->tx.avail, next); sc->tx.avail_queue_len--; STAILQ_INSERT_TAIL(&tmpqueue, slot, next); ++added; slot = STAILQ_FIRST(&sc->tx.avail); /* Setup next buffer (which isn't SOP) */ bd.next = 0; bd.bufptr = segs[seg].ds_addr; bd.bufoff = 0; bd.buflen = segs[seg].ds_len; bd.pktlen = 0; bd.flags = CPDMA_BD_OWNER; } /* Save the final buffer. */ if (padlen <= 0) bd.flags |= CPDMA_BD_EOP; cpsw_cpdma_write_bd(sc, slot, &bd); if (prev_slot != NULL) cpsw_cpdma_write_bd_next(sc, prev_slot, slot); prev_slot = slot; STAILQ_REMOVE_HEAD(&sc->tx.avail, next); sc->tx.avail_queue_len--; STAILQ_INSERT_TAIL(&tmpqueue, slot, next); ++added; if (padlen > 0) { slot = STAILQ_FIRST(&sc->tx.avail); STAILQ_REMOVE_HEAD(&sc->tx.avail, next); sc->tx.avail_queue_len--; STAILQ_INSERT_TAIL(&tmpqueue, slot, next); ++added; /* Setup buffer of null pad bytes (definitely EOP) */ cpsw_cpdma_write_bd_next(sc, prev_slot, slot); prev_slot = slot; bd.next = 0; bd.bufptr = sc->null_mbuf_paddr; bd.bufoff = 0; bd.buflen = padlen; bd.pktlen = 0; bd.flags = CPDMA_BD_EOP | CPDMA_BD_OWNER; cpsw_cpdma_write_bd(sc, slot, &bd); ++nsegs; } if (nsegs > sc->tx.longest_chain) sc->tx.longest_chain = nsegs; // TODO: Should we defer the BPF tap until // after all packets are queued? BPF_MTAP(sc->ifp, m0); } /* Attach the list of new buffers to the hardware TX queue. */ last_old_slot = STAILQ_LAST(&sc->tx.active, cpsw_slot, next); first_new_slot = STAILQ_FIRST(&tmpqueue); STAILQ_CONCAT(&sc->tx.active, &tmpqueue); if (first_new_slot == NULL) { return; } else if (last_old_slot == NULL) { /* Start a fresh queue. */ cpsw_write_hdp_slot(sc, &sc->tx, first_new_slot); } else { /* Add buffers to end of current queue. */ cpsw_cpdma_write_bd_next(sc, last_old_slot, first_new_slot); /* If underrun, restart queue. */ if (cpsw_cpdma_read_bd_flags(sc, last_old_slot) & CPDMA_BD_EOQ) { cpsw_write_hdp_slot(sc, &sc->tx, first_new_slot); } } sc->tx.queue_adds += added; sc->tx.active_queue_len += added; if (sc->tx.active_queue_len > sc->tx.max_active_queue_len) { sc->tx.max_active_queue_len = sc->tx.active_queue_len; } } static int cpsw_tx_dequeue(struct cpsw_softc *sc) { struct cpsw_slot *slot, *last_removed_slot = NULL; uint32_t flags, removed = 0; slot = STAILQ_FIRST(&sc->tx.active); if (slot == NULL && cpsw_read_cp(sc, &sc->tx) == 0xfffffffc) { CPSW_DEBUGF(("TX teardown of an empty queue")); cpsw_write_cp(sc, &sc->tx, 0xfffffffc); sc->tx.running = 0; return (0); } /* Pull completed buffers off the hardware TX queue. */ while (slot != NULL) { flags = cpsw_cpdma_read_bd_flags(sc, slot); if (flags & CPDMA_BD_OWNER) break; /* Hardware is still using this packet. */ CPSW_DEBUGF(("TX removing completed packet")); bus_dmamap_sync(sc->mbuf_dtag, slot->dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->mbuf_dtag, slot->dmamap); m_freem(slot->mbuf); slot->mbuf = NULL; /* Dequeue any additional buffers used by this packet. */ while (slot != NULL && slot->mbuf == NULL) { STAILQ_REMOVE_HEAD(&sc->tx.active, next); STAILQ_INSERT_TAIL(&sc->tx.avail, slot, next); ++removed; last_removed_slot = slot; slot = STAILQ_FIRST(&sc->tx.active); } /* TearDown complete is only marked on the SOP for the packet. */ if (flags & CPDMA_BD_TDOWNCMPLT) { CPSW_DEBUGF(("TX teardown in progress")); cpsw_write_cp(sc, &sc->tx, 0xfffffffc); // TODO: Increment a count of dropped TX packets sc->tx.running = 0; break; } } if (removed != 0) { cpsw_write_cp_slot(sc, &sc->tx, last_removed_slot); sc->tx.queue_removes += removed; sc->tx.active_queue_len -= removed; sc->tx.avail_queue_len += removed; if (sc->tx.avail_queue_len > sc->tx.max_avail_queue_len) sc->tx.max_avail_queue_len = sc->tx.avail_queue_len; } return (removed); } /* * * Miscellaneous interrupts. * */ static void cpsw_intr_rx_thresh(void *arg) { struct cpsw_softc *sc = arg; uint32_t stat = cpsw_read_4(sc, CPSW_WR_C_RX_THRESH_STAT(0)); CPSW_DEBUGF(("stat=%x", stat)); cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, 0); } static void cpsw_intr_misc_host_error(struct cpsw_softc *sc) { uint32_t intstat; uint32_t dmastat; int txerr, rxerr, txchan, rxchan; printf("\n\n"); device_printf(sc->dev, "HOST ERROR: PROGRAMMING ERROR DETECTED BY HARDWARE\n"); printf("\n\n"); intstat = cpsw_read_4(sc, CPSW_CPDMA_DMA_INTSTAT_MASKED); device_printf(sc->dev, "CPSW_CPDMA_DMA_INTSTAT_MASKED=0x%x\n", intstat); dmastat = cpsw_read_4(sc, CPSW_CPDMA_DMASTATUS); device_printf(sc->dev, "CPSW_CPDMA_DMASTATUS=0x%x\n", dmastat); txerr = (dmastat >> 20) & 15; txchan = (dmastat >> 16) & 7; rxerr = (dmastat >> 12) & 15; rxchan = (dmastat >> 8) & 7; switch (txerr) { case 0: break; case 1: printf("SOP error on TX channel %d\n", txchan); break; case 2: printf("Ownership bit not set on SOP buffer on TX channel %d\n", txchan); break; case 3: printf("Zero Next Buffer but not EOP on TX channel %d\n", txchan); break; case 4: printf("Zero Buffer Pointer on TX channel %d\n", txchan); break; case 5: printf("Zero Buffer Length on TX channel %d\n", txchan); break; case 6: printf("Packet length error on TX channel %d\n", txchan); break; default: printf("Unknown error on TX channel %d\n", txchan); break; } if (txerr != 0) { printf("CPSW_CPDMA_TX%d_HDP=0x%x\n", txchan, cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(txchan))); printf("CPSW_CPDMA_TX%d_CP=0x%x\n", txchan, cpsw_read_4(sc, CPSW_CPDMA_TX_CP(txchan))); cpsw_dump_queue(sc, &sc->tx.active); } switch (rxerr) { case 0: break; case 2: printf("Ownership bit not set on RX channel %d\n", rxchan); break; case 4: printf("Zero Buffer Pointer on RX channel %d\n", rxchan); break; case 5: printf("Zero Buffer Length on RX channel %d\n", rxchan); break; case 6: printf("Buffer offset too big on RX channel %d\n", rxchan); break; default: printf("Unknown RX error on RX channel %d\n", rxchan); break; } if (rxerr != 0) { printf("CPSW_CPDMA_RX%d_HDP=0x%x\n", rxchan, cpsw_read_4(sc,CPSW_CPDMA_RX_HDP(rxchan))); printf("CPSW_CPDMA_RX%d_CP=0x%x\n", rxchan, cpsw_read_4(sc, CPSW_CPDMA_RX_CP(rxchan))); cpsw_dump_queue(sc, &sc->rx.active); } printf("\nALE Table\n"); cpsw_ale_dump_table(sc); // XXX do something useful here?? panic("CPSW HOST ERROR INTERRUPT"); // Suppress this interrupt in the future. cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_CLEAR, intstat); printf("XXX HOST ERROR INTERRUPT SUPPRESSED\n"); // The watchdog will probably reset the controller // in a little while. It will probably fail again. } static void cpsw_intr_misc(void *arg) { struct cpsw_softc *sc = arg; uint32_t stat = cpsw_read_4(sc, CPSW_WR_C_MISC_STAT(0)); if (stat & 16) CPSW_DEBUGF(("Time sync event interrupt unimplemented")); if (stat & 8) cpsw_stats_collect(sc); if (stat & 4) cpsw_intr_misc_host_error(sc); if (stat & 2) CPSW_DEBUGF(("MDIO link change interrupt unimplemented")); if (stat & 1) CPSW_DEBUGF(("MDIO operation completed interrupt unimplemented")); cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, 3); } /* * * Periodic Checks and Watchdog. * */ static void cpsw_tick(void *msc) { struct cpsw_softc *sc = msc; /* Check for TX timeout */ cpsw_tx_watchdog(sc); /* Check for media type change */ mii_tick(sc->mii); if(sc->cpsw_media_status != sc->mii->mii_media.ifm_media) { printf("%s: media type changed (ifm_media=%x)\n", __func__, sc->mii->mii_media.ifm_media); cpsw_ifmedia_upd(sc->ifp); } /* Schedule another timeout one second from now */ callout_reset(&sc->watchdog.callout, hz, cpsw_tick, sc); } static void cpsw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct cpsw_softc *sc = ifp->if_softc; struct mii_data *mii; CPSW_DEBUGF(("")); CPSW_TX_LOCK(sc); mii = sc->mii; mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; CPSW_TX_UNLOCK(sc); } static int cpsw_ifmedia_upd(struct ifnet *ifp) { struct cpsw_softc *sc = ifp->if_softc; CPSW_DEBUGF(("")); if (ifp->if_flags & IFF_UP) { CPSW_GLOBAL_LOCK(sc); sc->cpsw_media_status = sc->mii->mii_media.ifm_media; mii_mediachg(sc->mii); cpsw_init_locked(sc); CPSW_GLOBAL_UNLOCK(sc); } return (0); } static void cpsw_tx_watchdog_full_reset(struct cpsw_softc *sc) { cpsw_debugf_head("CPSW watchdog"); if_printf(sc->ifp, "watchdog timeout\n"); cpsw_shutdown_locked(sc); cpsw_init_locked(sc); } static void cpsw_tx_watchdog(struct cpsw_softc *sc) { struct ifnet *ifp = sc->ifp; CPSW_GLOBAL_LOCK(sc); if (sc->tx.active_queue_len == 0 || (ifp->if_flags & IFF_UP) == 0 || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || !sc->tx.running) { sc->watchdog.timer = 0; /* Nothing to do. */ } else if (sc->tx.queue_removes > sc->tx.queue_removes_at_last_tick) { sc->watchdog.timer = 0; /* Stuff done while we weren't looking. */ } else if (cpsw_tx_dequeue(sc) > 0) { sc->watchdog.timer = 0; /* We just did something. */ } else { /* There was something to do but it didn't get done. */ ++sc->watchdog.timer; if (sc->watchdog.timer > 2) { sc->watchdog.timer = 0; if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); ++sc->watchdog.resets; cpsw_tx_watchdog_full_reset(sc); } } sc->tx.queue_removes_at_last_tick = sc->tx.queue_removes; CPSW_GLOBAL_UNLOCK(sc); } /* * * ALE support routines. * */ static void cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry) { cpsw_write_4(sc, CPSW_ALE_TBLCTL, idx & 1023); ale_entry[0] = cpsw_read_4(sc, CPSW_ALE_TBLW0); ale_entry[1] = cpsw_read_4(sc, CPSW_ALE_TBLW1); ale_entry[2] = cpsw_read_4(sc, CPSW_ALE_TBLW2); } static void cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry) { cpsw_write_4(sc, CPSW_ALE_TBLW0, ale_entry[0]); cpsw_write_4(sc, CPSW_ALE_TBLW1, ale_entry[1]); cpsw_write_4(sc, CPSW_ALE_TBLW2, ale_entry[2]); cpsw_write_4(sc, CPSW_ALE_TBLCTL, 1 << 31 | (idx & 1023)); } static int cpsw_ale_remove_all_mc_entries(struct cpsw_softc *sc) { int i; uint32_t ale_entry[3]; /* First two entries are link address and broadcast. */ for (i = 2; i < CPSW_MAX_ALE_ENTRIES; i++) { cpsw_ale_read_entry(sc, i, ale_entry); if (((ale_entry[1] >> 28) & 3) == 1 && /* Address entry */ ((ale_entry[1] >> 8) & 1) == 1) { /* MCast link addr */ ale_entry[0] = ale_entry[1] = ale_entry[2] = 0; cpsw_ale_write_entry(sc, i, ale_entry); } } return CPSW_MAX_ALE_ENTRIES; } static int cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac) { int free_index = -1, matching_index = -1, i; uint32_t ale_entry[3]; /* Find a matching entry or a free entry. */ for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) { cpsw_ale_read_entry(sc, i, ale_entry); /* Entry Type[61:60] is 0 for free entry */ if (free_index < 0 && ((ale_entry[1] >> 28) & 3) == 0) { free_index = i; } if ((((ale_entry[1] >> 8) & 0xFF) == mac[0]) && (((ale_entry[1] >> 0) & 0xFF) == mac[1]) && (((ale_entry[0] >>24) & 0xFF) == mac[2]) && (((ale_entry[0] >>16) & 0xFF) == mac[3]) && (((ale_entry[0] >> 8) & 0xFF) == mac[4]) && (((ale_entry[0] >> 0) & 0xFF) == mac[5])) { matching_index = i; break; } } if (matching_index < 0) { if (free_index < 0) return (ENOMEM); i = free_index; } /* Set MAC address */ ale_entry[0] = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; ale_entry[1] = mac[0] << 8 | mac[1]; /* Entry type[61:60] is addr entry(1), Mcast fwd state[63:62] is fw(3)*/ ale_entry[1] |= 0xd0 << 24; /* Set portmask [68:66] */ ale_entry[2] = (portmap & 7) << 2; cpsw_ale_write_entry(sc, i, ale_entry); return 0; } static void cpsw_ale_dump_table(struct cpsw_softc *sc) { int i; uint32_t ale_entry[3]; for (i = 0; i < CPSW_MAX_ALE_ENTRIES; i++) { cpsw_ale_read_entry(sc, i, ale_entry); if (ale_entry[0] || ale_entry[1] || ale_entry[2]) { printf("ALE[%4u] %08x %08x %08x ", i, ale_entry[0], ale_entry[1], ale_entry[2]); printf("mac: %02x:%02x:%02x:%02x:%02x:%02x ", (ale_entry[1] >> 8) & 0xFF, (ale_entry[1] >> 0) & 0xFF, (ale_entry[0] >>24) & 0xFF, (ale_entry[0] >>16) & 0xFF, (ale_entry[0] >> 8) & 0xFF, (ale_entry[0] >> 0) & 0xFF); printf(((ale_entry[1] >> 8) & 1) ? "mcast " : "ucast "); printf("type: %u ", (ale_entry[1] >> 28) & 3); printf("port: %u ", (ale_entry[2] >> 2) & 7); printf("\n"); } } printf("\n"); } static int cpsw_ale_update_addresses(struct cpsw_softc *sc, int purge) { uint8_t *mac; uint32_t ale_entry[3]; struct ifnet *ifp = sc->ifp; struct ifmultiaddr *ifma; int i; /* Route incoming packets for our MAC address to Port 0 (host). */ /* For simplicity, keep this entry at table index 0 in the ALE. */ if_addr_rlock(ifp); mac = LLADDR((struct sockaddr_dl *)ifp->if_addr->ifa_addr); ale_entry[0] = mac[2] << 24 | mac[3] << 16 | mac[4] << 8 | mac[5]; ale_entry[1] = 0x10 << 24 | mac[0] << 8 | mac[1]; /* addr entry + mac */ ale_entry[2] = 0; /* port = 0 */ cpsw_ale_write_entry(sc, 0, ale_entry); /* Set outgoing MAC Address for Ports 1 and 2. */ for (i = 1; i < 3; ++i) { cpsw_write_4(sc, CPSW_PORT_P_SA_HI(i), mac[3] << 24 | mac[2] << 16 | mac[1] << 8 | mac[0]); cpsw_write_4(sc, CPSW_PORT_P_SA_LO(i), mac[5] << 8 | mac[4]); } if_addr_runlock(ifp); /* Keep the broadcast address at table entry 1. */ ale_entry[0] = 0xffffffff; /* Lower 32 bits of MAC */ ale_entry[1] = 0xd000ffff; /* FW (3 << 30), Addr entry (1 << 24), upper 16 bits of Mac */ ale_entry[2] = 0x0000001c; /* Forward to all ports */ cpsw_ale_write_entry(sc, 1, ale_entry); /* SIOCDELMULTI doesn't specify the particular address being removed, so we have to remove all and rebuild. */ if (purge) cpsw_ale_remove_all_mc_entries(sc); /* Set other multicast addrs desired. */ if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; cpsw_ale_mc_entry_set(sc, 7, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); } if_maddr_runlock(ifp); return (0); } /* * * Statistics and Sysctls. * */ #if 0 static void cpsw_stats_dump(struct cpsw_softc *sc) { int i; uint32_t r; for (i = 0; i < CPSW_SYSCTL_COUNT; ++i) { r = cpsw_read_4(sc, CPSW_STATS_OFFSET + cpsw_stat_sysctls[i].reg); CPSW_DEBUGF(("%s: %ju + %u = %ju", cpsw_stat_sysctls[i].oid, (intmax_t)sc->shadow_stats[i], r, (intmax_t)sc->shadow_stats[i] + r)); } } #endif static void cpsw_stats_collect(struct cpsw_softc *sc) { int i; uint32_t r; CPSW_DEBUGF(("Controller shadow statistics updated.")); for (i = 0; i < CPSW_SYSCTL_COUNT; ++i) { r = cpsw_read_4(sc, CPSW_STATS_OFFSET + cpsw_stat_sysctls[i].reg); sc->shadow_stats[i] += r; cpsw_write_4(sc, CPSW_STATS_OFFSET + cpsw_stat_sysctls[i].reg, r); } } static int cpsw_stats_sysctl(SYSCTL_HANDLER_ARGS) { struct cpsw_softc *sc; struct cpsw_stat *stat; uint64_t result; sc = (struct cpsw_softc *)arg1; stat = &cpsw_stat_sysctls[oidp->oid_number]; result = sc->shadow_stats[oidp->oid_number]; result += cpsw_read_4(sc, CPSW_STATS_OFFSET + stat->reg); return (sysctl_handle_64(oidp, &result, 0, req)); } static int cpsw_stat_attached(SYSCTL_HANDLER_ARGS) { struct cpsw_softc *sc; struct bintime t; unsigned result; sc = (struct cpsw_softc *)arg1; getbinuptime(&t); bintime_sub(&t, &sc->attach_uptime); result = t.sec; return (sysctl_handle_int(oidp, &result, 0, req)); } static int cpsw_stat_uptime(SYSCTL_HANDLER_ARGS) { struct cpsw_softc *sc; struct bintime t; unsigned result; sc = (struct cpsw_softc *)arg1; if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) { getbinuptime(&t); bintime_sub(&t, &sc->init_uptime); result = t.sec; } else result = 0; return (sysctl_handle_int(oidp, &result, 0, req)); } static void cpsw_add_queue_sysctls(struct sysctl_ctx_list *ctx, struct sysctl_oid *node, struct cpsw_queue *queue) { struct sysctl_oid_list *parent; parent = SYSCTL_CHILDREN(node); SYSCTL_ADD_INT(ctx, parent, OID_AUTO, "totalBuffers", CTLFLAG_RD, &queue->queue_slots, 0, "Total buffers currently assigned to this queue"); SYSCTL_ADD_INT(ctx, parent, OID_AUTO, "activeBuffers", CTLFLAG_RD, &queue->active_queue_len, 0, "Buffers currently registered with hardware controller"); SYSCTL_ADD_INT(ctx, parent, OID_AUTO, "maxActiveBuffers", CTLFLAG_RD, &queue->max_active_queue_len, 0, "Max value of activeBuffers since last driver reset"); SYSCTL_ADD_INT(ctx, parent, OID_AUTO, "availBuffers", CTLFLAG_RD, &queue->avail_queue_len, 0, "Buffers allocated to this queue but not currently " "registered with hardware controller"); SYSCTL_ADD_INT(ctx, parent, OID_AUTO, "maxAvailBuffers", CTLFLAG_RD, &queue->max_avail_queue_len, 0, "Max value of availBuffers since last driver reset"); SYSCTL_ADD_UINT(ctx, parent, OID_AUTO, "totalEnqueued", CTLFLAG_RD, &queue->queue_adds, 0, "Total buffers added to queue"); SYSCTL_ADD_UINT(ctx, parent, OID_AUTO, "totalDequeued", CTLFLAG_RD, &queue->queue_removes, 0, "Total buffers removed from queue"); SYSCTL_ADD_UINT(ctx, parent, OID_AUTO, "longestChain", CTLFLAG_RD, &queue->longest_chain, 0, "Max buffers used for a single packet"); } static void cpsw_add_watchdog_sysctls(struct sysctl_ctx_list *ctx, struct sysctl_oid *node, struct cpsw_softc *sc) { struct sysctl_oid_list *parent; parent = SYSCTL_CHILDREN(node); SYSCTL_ADD_INT(ctx, parent, OID_AUTO, "resets", CTLFLAG_RD, &sc->watchdog.resets, 0, "Total number of watchdog resets"); } static void cpsw_add_sysctls(struct cpsw_softc *sc) { struct sysctl_ctx_list *ctx; struct sysctl_oid *stats_node, *queue_node, *node; struct sysctl_oid_list *parent, *stats_parent, *queue_parent; int i; ctx = device_get_sysctl_ctx(sc->dev); parent = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "attachedSecs", CTLTYPE_UINT | CTLFLAG_RD, sc, 0, cpsw_stat_attached, "IU", "Time since driver attach"); SYSCTL_ADD_PROC(ctx, parent, OID_AUTO, "uptime", CTLTYPE_UINT | CTLFLAG_RD, sc, 0, cpsw_stat_uptime, "IU", "Seconds since driver init"); stats_node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "stats", CTLFLAG_RD, NULL, "CPSW Statistics"); stats_parent = SYSCTL_CHILDREN(stats_node); for (i = 0; i < CPSW_SYSCTL_COUNT; ++i) { SYSCTL_ADD_PROC(ctx, stats_parent, i, cpsw_stat_sysctls[i].oid, CTLTYPE_U64 | CTLFLAG_RD, sc, 0, cpsw_stats_sysctl, "IU", cpsw_stat_sysctls[i].oid); } queue_node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "queue", CTLFLAG_RD, NULL, "CPSW Queue Statistics"); queue_parent = SYSCTL_CHILDREN(queue_node); node = SYSCTL_ADD_NODE(ctx, queue_parent, OID_AUTO, "tx", CTLFLAG_RD, NULL, "TX Queue Statistics"); cpsw_add_queue_sysctls(ctx, node, &sc->tx); node = SYSCTL_ADD_NODE(ctx, queue_parent, OID_AUTO, "rx", CTLFLAG_RD, NULL, "RX Queue Statistics"); cpsw_add_queue_sysctls(ctx, node, &sc->rx); node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "watchdog", CTLFLAG_RD, NULL, "Watchdog Statistics"); cpsw_add_watchdog_sysctls(ctx, node, sc); } Index: head/sys/arm/ti/cpsw/if_cpswreg.h =================================================================== --- head/sys/arm/ti/cpsw/if_cpswreg.h (revision 283275) +++ head/sys/arm/ti/cpsw/if_cpswreg.h (revision 283276) @@ -1,137 +1,139 @@ /*- * Copyright (c) 2012 Damjan Marion * 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 _IF_CPSWREG_H #define _IF_CPSWREG_H #define CPSW_SS_OFFSET 0x0000 #define CPSW_SS_IDVER (CPSW_SS_OFFSET + 0x00) #define CPSW_SS_SOFT_RESET (CPSW_SS_OFFSET + 0x08) #define CPSW_SS_STAT_PORT_EN (CPSW_SS_OFFSET + 0x0C) #define CPSW_SS_PTYPE (CPSW_SS_OFFSET + 0x10) #define CPSW_SS_FLOW_CONTROL (CPSW_SS_OFFSET + 0x24) #define CPSW_PORT_OFFSET 0x0100 #define CPSW_PORT_P_MAX_BLKS(p) (CPSW_PORT_OFFSET + 0x08 + ((p) * 0x100)) #define CPSW_PORT_P_BLK_CNT(p) (CPSW_PORT_OFFSET + 0x0C + ((p) * 0x100)) #define CPSW_PORT_P_TX_PRI_MAP(p) (CPSW_PORT_OFFSET + 0x118 + ((p-1) * 0x100)) #define CPSW_PORT_P0_CPDMA_TX_PRI_MAP (CPSW_PORT_OFFSET + 0x01C) #define CPSW_PORT_P0_CPDMA_RX_CH_MAP (CPSW_PORT_OFFSET + 0x020) #define CPSW_PORT_P_SA_LO(p) (CPSW_PORT_OFFSET + 0x120 + ((p-1) * 0x100)) #define CPSW_PORT_P_SA_HI(p) (CPSW_PORT_OFFSET + 0x124 + ((p-1) * 0x100)) #define CPSW_CPDMA_OFFSET 0x0800 #define CPSW_CPDMA_TX_CONTROL (CPSW_CPDMA_OFFSET + 0x04) #define CPSW_CPDMA_TX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x08) #define CPSW_CPDMA_RX_CONTROL (CPSW_CPDMA_OFFSET + 0x14) #define CPSW_CPDMA_RX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x18) #define CPSW_CPDMA_SOFT_RESET (CPSW_CPDMA_OFFSET + 0x1c) #define CPSW_CPDMA_DMACONTROL (CPSW_CPDMA_OFFSET + 0x20) #define CPSW_CPDMA_DMASTATUS (CPSW_CPDMA_OFFSET + 0x24) #define CPSW_CPDMA_RX_BUFFER_OFFSET (CPSW_CPDMA_OFFSET + 0x28) #define CPSW_CPDMA_TX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0x80) #define CPSW_CPDMA_TX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0x84) #define CPSW_CPDMA_TX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0x88) #define CPSW_CPDMA_TX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0x8C) #define CPSW_CPDMA_CPDMA_EOI_VECTOR (CPSW_CPDMA_OFFSET + 0x94) #define CPSW_CPDMA_RX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xA0) #define CPSW_CPDMA_RX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xA4) #define CPSW_CPDMA_RX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xA8) #define CPSW_CPDMA_RX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xAc) #define CPSW_CPDMA_DMA_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xB0) #define CPSW_CPDMA_DMA_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xB4) #define CPSW_CPDMA_DMA_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xB8) #define CPSW_CPDMA_DMA_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xBC) #define CPSW_CPDMA_RX_FREEBUFFER(p) (CPSW_CPDMA_OFFSET + 0x0e0 + ((p) * 0x04)) #define CPSW_STATS_OFFSET 0x0900 #define CPSW_STATERAM_OFFSET 0x0A00 #define CPSW_CPDMA_TX_HDP(p) (CPSW_STATERAM_OFFSET + 0x00 + ((p) * 0x04)) #define CPSW_CPDMA_RX_HDP(p) (CPSW_STATERAM_OFFSET + 0x20 + ((p) * 0x04)) #define CPSW_CPDMA_TX_CP(p) (CPSW_STATERAM_OFFSET + 0x40 + ((p) * 0x04)) #define CPSW_CPDMA_RX_CP(p) (CPSW_STATERAM_OFFSET + 0x60 + ((p) * 0x04)) #define CPSW_CPTS_OFFSET 0x0C00 #define CPSW_ALE_OFFSET 0x0D00 #define CPSW_ALE_CONTROL (CPSW_ALE_OFFSET + 0x08) #define CPSW_ALE_TBLCTL (CPSW_ALE_OFFSET + 0x20) #define CPSW_ALE_TBLW2 (CPSW_ALE_OFFSET + 0x34) #define CPSW_ALE_TBLW1 (CPSW_ALE_OFFSET + 0x38) #define CPSW_ALE_TBLW0 (CPSW_ALE_OFFSET + 0x3C) #define CPSW_ALE_PORTCTL(p) (CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04)) /* SL1 is at 0x0D80, SL2 is at 0x0DC0 */ #define CPSW_SL_OFFSET 0x0D80 #define CPSW_SL_MACCONTROL(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x04) #define CPSW_SL_MACSTATUS(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x08) #define CPSW_SL_SOFT_RESET(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x0C) #define CPSW_SL_RX_MAXLEN(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x10) #define CPSW_SL_RX_PAUSE(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x18) #define CPSW_SL_TX_PAUSE(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x1C) #define CPSW_SL_RX_PRI_MAP(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x24) #define MDIO_OFFSET 0x1000 #define MDIOCONTROL (MDIO_OFFSET + 0x04) #define MDIOUSERACCESS0 (MDIO_OFFSET + 0x80) #define MDIOUSERPHYSEL0 (MDIO_OFFSET + 0x84) #define CPSW_WR_OFFSET 0x1200 #define CPSW_WR_SOFT_RESET (CPSW_WR_OFFSET + 0x04) #define CPSW_WR_CONTROL (CPSW_WR_OFFSET + 0x08) #define CPSW_WR_INT_CONTROL (CPSW_WR_OFFSET + 0x0c) #define CPSW_WR_C_RX_THRESH_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x10) #define CPSW_WR_C_RX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x14) #define CPSW_WR_C_TX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x18) #define CPSW_WR_C_MISC_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x1C) #define CPSW_WR_C_RX_THRESH_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x40) #define CPSW_WR_C_RX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x44) #define CPSW_WR_C_TX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x48) #define CPSW_WR_C_MISC_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C) #define CPSW_CPPI_RAM_OFFSET 0x2000 #define CPSW_CPPI_RAM_SIZE 0x2000 +#define CPSW_MEMWINDOW_SIZE 0x4000 + #define CPDMA_BD_SOP (1<<15) #define CPDMA_BD_EOP (1<<14) #define CPDMA_BD_OWNER (1<<13) #define CPDMA_BD_EOQ (1<<12) #define CPDMA_BD_TDOWNCMPLT (1<<11) #define CPDMA_BD_PKT_ERR_MASK (3<< 4) struct cpsw_cpdma_bd { volatile uint32_t next; volatile uint32_t bufptr; volatile uint16_t buflen; volatile uint16_t bufoff; volatile uint16_t pktlen; volatile uint16_t flags; }; #endif /*_IF_CPSWREG_H */ Index: head/sys/arm/ti/cpsw/if_cpswvar.h =================================================================== --- head/sys/arm/ti/cpsw/if_cpswvar.h (revision 283275) +++ head/sys/arm/ti/cpsw/if_cpswvar.h (revision 283276) @@ -1,124 +1,126 @@ /*- * Copyright (c) 2012 Damjan Marion * 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 _IF_CPSWVAR_H #define _IF_CPSWVAR_H #define CPSW_INTR_COUNT 4 /* MII BUS */ #define CPSW_MIIBUS_RETRIES 5 #define CPSW_MIIBUS_DELAY 1000 #define CPSW_MAX_ALE_ENTRIES 1024 #define CPSW_SYSCTL_COUNT 34 struct cpsw_slot { uint32_t bd_offset; /* Offset of corresponding BD within CPPI RAM. */ bus_dmamap_t dmamap; struct mbuf *mbuf; STAILQ_ENTRY(cpsw_slot) next; }; STAILQ_HEAD(cpsw_slots, cpsw_slot); struct cpsw_queue { struct mtx lock; int running; struct cpsw_slots active; struct cpsw_slots avail; uint32_t queue_adds; /* total bufs added */ uint32_t queue_removes; /* total bufs removed */ uint32_t queue_removes_at_last_tick; /* Used by watchdog */ int queue_slots; int active_queue_len; int max_active_queue_len; int avail_queue_len; int max_avail_queue_len; int longest_chain; /* Largest # segments in a single packet. */ int hdp_offset; }; struct cpsw_softc { struct ifnet *ifp; phandle_t node; device_t dev; struct bintime attach_uptime; /* system uptime when attach happened. */ struct bintime init_uptime; /* system uptime when init happened. */ /* TODO: We should set up a child structure for each port; store mac, phy information, etc, in that structure. */ uint8_t mac_addr[ETHER_ADDR_LEN]; device_t miibus; struct mii_data *mii; /* We expect 1 memory resource and 4 interrupts from the device tree. */ - struct resource *res[1 + CPSW_INTR_COUNT]; + struct resource *mem_res; + int mem_rid; + struct resource *irq_res[CPSW_INTR_COUNT]; /* Interrupts get recorded here as we initialize them. */ /* Interrupt teardown just walks this list. */ struct { struct resource *res; void *ih_cookie; const char *description; } interrupts[CPSW_INTR_COUNT]; int interrupt_count; uint32_t cpsw_if_flags; int cpsw_media_status; struct { int resets; int timer; struct callout callout; } watchdog; bus_dma_tag_t mbuf_dtag; /* An mbuf full of nulls for TX padding. */ bus_dmamap_t null_mbuf_dmamap; struct mbuf *null_mbuf; bus_addr_t null_mbuf_paddr; /* RX and TX buffer tracking */ struct cpsw_queue rx, tx; /* 64-bit versions of 32-bit hardware statistics counters */ uint64_t shadow_stats[CPSW_SYSCTL_COUNT]; /* CPPI STATERAM has 512 slots for building TX/RX queues. */ /* TODO: Size here supposedly varies with different versions of the controller. Check DaVinci specs and find a good way to adjust this. One option is to have a separate Device Tree parameter for number slots; another option is to calculate it from the memory size in the device tree. */ struct cpsw_slot _slots[CPSW_CPPI_RAM_SIZE / sizeof(struct cpsw_cpdma_bd)]; struct cpsw_slots avail; }; #endif /*_IF_CPSWVAR_H */ Index: head/sys/arm/ti/files.ti =================================================================== --- head/sys/arm/ti/files.ti (revision 283275) +++ head/sys/arm/ti/files.ti (revision 283276) @@ -1,27 +1,29 @@ #$FreeBSD$ kern/kern_clocksource.c standard arm/arm/bus_space_base.c standard arm/arm/bus_space_generic.c standard arm/arm/bus_space_asm_generic.S standard arm/arm/pmu.c optional hwpmc arm/ti/ti_common.c standard arm/ti/ti_cpuid.c standard +arm/ti/ti_hwmods.c standard arm/ti/ti_machdep.c standard arm/ti/ti_prcm.c standard arm/ti/ti_scm.c standard +arm/ti/ti_pinmux.c standard dev/mbox/mbox_if.m optional ti_mbox arm/ti/ti_mbox.c optional ti_mbox arm/ti/ti_pruss.c optional ti_pruss arm/ti/ti_wdt.c optional ti_wdt arm/ti/ti_adc.c optional ti_adc arm/ti/ti_gpio.c optional gpio arm/ti/ti_gpio_if.m optional gpio arm/ti/ti_i2c.c optional ti_i2c arm/ti/ti_sdhci.c optional sdhci dev/uart/uart_dev_ti8250.c optional uart dev/uart/uart_dev_ns8250.c optional uart Index: head/sys/arm/ti/omap4/files.omap4 =================================================================== --- head/sys/arm/ti/omap4/files.omap4 (revision 283275) +++ head/sys/arm/ti/omap4/files.omap4 (revision 283276) @@ -1,18 +1,20 @@ #$FreeBSD$ arm/arm/mpcore_timer.c standard arm/ti/ti_smc.S standard arm/ti/usb/omap_ehci.c optional usb ehci +arm/ti/usb/omap_host.c optional usb +arm/ti/usb/omap_tll.c optional usb arm/ti/ti_sdma.c optional ti_sdma arm/ti/omap4/omap4_gpio.c optional gpio arm/ti/omap4/omap4_l2cache.c optional pl310 arm/ti/omap4/omap4_prcm_clks.c standard arm/ti/omap4/omap4_scm_padconf.c standard arm/ti/omap4/omap4_mp.c optional smp arm/ti/twl/twl.c optional twl arm/ti/twl/twl_vreg.c optional twl twl_vreg arm/ti/twl/twl_clks.c optional twl twl_clks Index: head/sys/arm/ti/omap4/omap4_gpio.c =================================================================== --- head/sys/arm/ti/omap4/omap4_gpio.c (revision 283275) +++ head/sys/arm/ti/omap4/omap4_gpio.c (revision 283276) @@ -1,143 +1,149 @@ /*- * Copyright (c) 2011 Ben Gray . * Copyright (c) 2014 Andrew Turner * 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. * 3. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include "ti_gpio_if.h" static struct ofw_compat_data compat_data[] = { {"ti,omap4-gpio", 1}, {"ti,gpio", 1}, {NULL, 0}, }; static int omap4_gpio_probe(device_t dev) { if (ti_chip() != CHIP_OMAP_4) return (ENXIO); if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Ti OMAP4 General Purpose I/O (GPIO)"); return (0); } static int omap4_gpio_set_flags(device_t dev, uint32_t gpio, uint32_t flags) { unsigned int state = 0; + struct ti_gpio_softc *sc; + + sc = device_get_softc(dev); /* First the SCM driver needs to be told to put the pad into GPIO mode */ if (flags & GPIO_PIN_OUTPUT) state = PADCONF_PIN_OUTPUT; else if (flags & GPIO_PIN_INPUT) { if (flags & GPIO_PIN_PULLUP) state = PADCONF_PIN_INPUT_PULLUP; else if (flags & GPIO_PIN_PULLDOWN) state = PADCONF_PIN_INPUT_PULLDOWN; else state = PADCONF_PIN_INPUT; } - return ti_scm_padconf_set_gpiomode(gpio, state); + return ti_pinmux_padconf_set_gpiomode((sc->sc_bank-1)*32 + gpio, state); } static int omap4_gpio_get_flags(device_t dev, uint32_t gpio, uint32_t *flags) { unsigned int state; + struct ti_gpio_softc *sc; + sc = device_get_softc(dev); + /* Get the current pin state */ - if (ti_scm_padconf_get_gpiomode(gpio, &state) != 0) { + if (ti_pinmux_padconf_get_gpiomode((sc->sc_bank-1)*32 + gpio, &state) != 0) { *flags = 0; return (EINVAL); } else { switch (state) { case PADCONF_PIN_OUTPUT: *flags = GPIO_PIN_OUTPUT; break; case PADCONF_PIN_INPUT: *flags = GPIO_PIN_INPUT; break; case PADCONF_PIN_INPUT_PULLUP: *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP; break; case PADCONF_PIN_INPUT_PULLDOWN: *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLDOWN; break; default: *flags = 0; break; } } return (0); } static device_method_t omap4_gpio_methods[] = { /* bus interface */ DEVMETHOD(device_probe, omap4_gpio_probe), /* ti_gpio interface */ DEVMETHOD(ti_gpio_set_flags, omap4_gpio_set_flags), DEVMETHOD(ti_gpio_get_flags, omap4_gpio_get_flags), DEVMETHOD_END }; extern driver_t ti_gpio_driver; static devclass_t omap4_gpio_devclass; DEFINE_CLASS_1(gpio, omap4_gpio_driver, omap4_gpio_methods, sizeof(struct ti_gpio_softc), ti_gpio_driver); DRIVER_MODULE(omap4_gpio, simplebus, omap4_gpio_driver, omap4_gpio_devclass, 0, 0); Index: head/sys/arm/ti/omap4/omap4_prcm_clks.c =================================================================== --- head/sys/arm/ti/omap4/omap4_prcm_clks.c (revision 283275) +++ head/sys/arm/ti/omap4/omap4_prcm_clks.c (revision 283276) @@ -1,1428 +1,1490 @@ /*- * Copyright (c) 2011 * Ben Gray . * 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. * 3. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This file defines the clock configuration for the OMAP4xxx series of * devices. * * How This is Suppose to Work * =========================== * - There is a top level omap_prcm module that defines all OMAP SoC drivers * should use to enable/disable the system clocks regardless of the version * of OMAP device they are running on. This top level PRCM module is just * a thin shim to chip specific functions that perform the donkey work of * configuring the clock - this file is the 'donkey' for OMAP44xx devices. * * - The key bit in this file is the omap_clk_devmap array, it's * used by the omap_prcm driver to determine what clocks are valid and which * functions to call to manipulate them. * * - In essence you just need to define some callbacks for each of the * clocks and then you're done. * * - The other thing that is worth noting is that when the omap_prcm device * is registered you typically pass in some memory ranges which are the * SYS_MEMORY resources. These resources are in turn allocated using * bus_allocate_resources(...) and the resource handles are passed to all * individual clock callback handlers. * * * * OMAP4 devices are different from the previous OMAP3 devices in that there * is no longer a separate functional and interface clock for each module, * instead there is typically an interface clock that spans many modules. */ #define FREQ_96MHZ 96000000 #define FREQ_64MHZ 64000000 #define FREQ_48MHZ 48000000 #define FREQ_32KHZ 32000 -/** - * We need three memory regions to cover all the clock configuration registers. - * - * PRM Instance - 0x4A30 6000 : 0x4A30 8000 - * CM1 Instance - 0x4A00 4000 : 0x4A00 5000 - * CM2 Instance - 0x4A00 8000 : 0x4A00 A000 - * - */ -#define PRM_INSTANCE_MEM_REGION 0 -#define CM1_INSTANCE_MEM_REGION 1 -#define CM2_INSTANCE_MEM_REGION 2 +#define PRM_INSTANCE 1 +#define CM1_INSTANCE 2 +#define CM2_INSTANCE 3 /** * Address offsets from the PRM memory region to the top level clock control * registers. */ #define CKGEN_PRM_OFFSET 0x00000100UL #define MPU_PRM_OFFSET 0x00000300UL #define DSP_PRM_OFFSET 0x00000400UL #define ABE_PRM_OFFSET 0x00000500UL #define ALWAYS_ON_PRM_OFFSET 0x00000600UL #define CORE_PRM_OFFSET 0x00000700UL #define IVAHD_PRM_OFFSET 0x00000F00UL #define CAM_PRM_OFFSET 0x00001000UL #define DSS_PRM_OFFSET 0x00001100UL #define SGX_PRM_OFFSET 0x00001200UL #define L3INIT_PRM_OFFSET 0x00001300UL #define L4PER_PRM_OFFSET 0x00001400UL #define WKUP_PRM_OFFSET 0x00001700UL #define WKUP_CM_OFFSET 0x00001800UL #define EMU_PRM_OFFSET 0x00001900UL #define EMU_CM_OFFSET 0x00001A00UL #define DEVICE_PRM_OFFSET 0x00001B00UL #define INSTR_PRM_OFFSET 0x00001F00UL #define CM_ABE_DSS_SYS_CLKSEL_OFFSET (CKGEN_PRM_OFFSET + 0x0000UL) #define CM_L4_WKUP_CLKSELL_OFFSET (CKGEN_PRM_OFFSET + 0x0008UL) #define CM_ABE_PLL_REF_CLKSEL_OFFSET (CKGEN_PRM_OFFSET + 0x000CUL) #define CM_SYS_CLKSEL_OFFSET (CKGEN_PRM_OFFSET + 0x0010UL) /** * Address offsets from the CM1 memory region to the top level clock control * registers. */ #define CKGEN_CM1_OFFSET 0x00000100UL #define MPU_CM1_OFFSET 0x00000300UL #define DSP_CM1_OFFSET 0x00000400UL #define ABE_CM1_OFFSET 0x00000500UL #define RESTORE_CM1_OFFSET 0x00000E00UL #define INSTR_CM1_OFFSET 0x00000F00UL #define CM_CLKSEL_DPLL_MPU (CKGEN_CM1_OFFSET + 0x006CUL) /** * Address offsets from the CM2 memory region to the top level clock control * registers. */ #define INTRCONN_SOCKET_CM2_OFFSET 0x00000000UL #define CKGEN_CM2_OFFSET 0x00000100UL #define ALWAYS_ON_CM2_OFFSET 0x00000600UL #define CORE_CM2_OFFSET 0x00000700UL #define IVAHD_CM2_OFFSET 0x00000F00UL #define CAM_CM2_OFFSET 0x00001000UL #define DSS_CM2_OFFSET 0x00001100UL #define SGX_CM2_OFFSET 0x00001200UL #define L3INIT_CM2_OFFSET 0x00001300UL #define L4PER_CM2_OFFSET 0x00001400UL #define RESTORE_CM2_OFFSET 0x00001E00UL #define INSTR_CM2_OFFSET 0x00001F00UL #define CLKCTRL_MODULEMODE_MASK 0x00000003UL #define CLKCTRL_MODULEMODE_DISABLE 0x00000000UL #define CLKCTRL_MODULEMODE_AUTO 0x00000001UL #define CLKCTRL_MODULEMODE_ENABLE 0x00000001UL #define CLKCTRL_IDLEST_MASK 0x00030000UL #define CLKCTRL_IDLEST_ENABLED 0x00000000UL #define CLKCTRL_IDLEST_WAKING 0x00010000UL #define CLKCTRL_IDLEST_IDLE 0x00020000UL #define CLKCTRL_IDLEST_DISABLED 0x00030000UL -static struct resource_spec omap4_scm_res_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */ - { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* Control memory window */ - { SYS_RES_MEMORY, 2, RF_ACTIVE }, /* Control memory window */ - { -1, 0 } +static struct ofw_compat_data compat_data[] = { + {"ti,omap4-cm1", (uintptr_t)CM1_INSTANCE}, + {"ti,omap4-cm2", (uintptr_t)CM2_INSTANCE}, + {"ti,omap4-prm", (uintptr_t)PRM_INSTANCE}, + {NULL, (uintptr_t)0}, }; struct omap4_prcm_softc { - struct resource *sc_res[3]; + struct resource *sc_res; + int sc_rid; + int sc_instance; }; -static struct omap4_prcm_softc *omap4_prcm_sc; - static int omap4_clk_generic_activate(struct ti_clock_dev *clkdev); static int omap4_clk_generic_deactivate(struct ti_clock_dev *clkdev); static int omap4_clk_generic_accessible(struct ti_clock_dev *clkdev); static int omap4_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); static int omap4_clk_generic_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int omap4_clk_gptimer_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); static int omap4_clk_gptimer_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int omap4_clk_hsmmc_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); static int omap4_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int omap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); static int omap4_clk_hsusbhost_activate(struct ti_clock_dev *clkdev); static int omap4_clk_hsusbhost_deactivate(struct ti_clock_dev *clkdev); static int omap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev); static int omap4_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); /** * omap_clk_devmap - Array of clock devices available on OMAP4xxx devices * * This map only defines which clocks are valid and the callback functions * for clock activate, deactivate, etc. It is used by the top level omap_prcm * driver. * * The actual details of the clocks (config registers, bit fields, sources, * etc) are in the private g_omap3_clk_details array below. * */ #define OMAP4_GENERIC_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = omap4_clk_generic_activate, \ .clk_deactivate = omap4_clk_generic_deactivate, \ .clk_set_source = omap4_clk_generic_set_source, \ .clk_accessible = omap4_clk_generic_accessible, \ .clk_get_source_freq = omap4_clk_generic_get_source_freq \ } #define OMAP4_GPTIMER_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = omap4_clk_generic_activate, \ .clk_deactivate = omap4_clk_generic_deactivate, \ .clk_set_source = omap4_clk_gptimer_set_source, \ .clk_accessible = omap4_clk_generic_accessible, \ .clk_get_source_freq = omap4_clk_gptimer_get_source_freq \ } #define OMAP4_HSMMC_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = omap4_clk_generic_activate, \ .clk_deactivate = omap4_clk_generic_deactivate, \ .clk_set_source = omap4_clk_hsmmc_set_source, \ .clk_accessible = omap4_clk_generic_accessible, \ .clk_get_source_freq = omap4_clk_hsmmc_get_source_freq \ } #define OMAP4_HSUSBHOST_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = omap4_clk_hsusbhost_activate, \ .clk_deactivate = omap4_clk_hsusbhost_deactivate, \ .clk_set_source = omap4_clk_hsusbhost_set_source, \ .clk_accessible = omap4_clk_hsusbhost_accessible, \ .clk_get_source_freq = NULL \ } struct ti_clock_dev ti_omap4_clk_devmap[] = { /* System clocks */ { .id = SYS_CLK, .clk_activate = NULL, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = omap4_clk_get_sysclk_freq, }, /* MPU (ARM) core clocks */ { .id = MPU_CLK, .clk_activate = NULL, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = omap4_clk_get_arm_fclk_freq, }, /* UART device clocks */ OMAP4_GENERIC_CLOCK_DEV(UART1_CLK), OMAP4_GENERIC_CLOCK_DEV(UART2_CLK), OMAP4_GENERIC_CLOCK_DEV(UART3_CLK), OMAP4_GENERIC_CLOCK_DEV(UART4_CLK), /* Timer device source clocks */ - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER1_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER2_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER3_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER4_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER5_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER6_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER7_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER8_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER9_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER10_CLK), - OMAP4_GPTIMER_CLOCK_DEV(GPTIMER11_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER1_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER2_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER3_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER4_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER5_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER6_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER7_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER8_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER9_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER10_CLK), + OMAP4_GPTIMER_CLOCK_DEV(TIMER11_CLK), /* MMC device clocks (MMC1 and MMC2 can have different input clocks) */ OMAP4_HSMMC_CLOCK_DEV(MMC1_CLK), OMAP4_HSMMC_CLOCK_DEV(MMC2_CLK), OMAP4_GENERIC_CLOCK_DEV(MMC3_CLK), OMAP4_GENERIC_CLOCK_DEV(MMC4_CLK), OMAP4_GENERIC_CLOCK_DEV(MMC5_CLK), /* USB HS (high speed TLL, EHCI and OHCI) */ OMAP4_HSUSBHOST_CLOCK_DEV(USBTLL_CLK), OMAP4_HSUSBHOST_CLOCK_DEV(USBHSHOST_CLK), OMAP4_HSUSBHOST_CLOCK_DEV(USBFSHOST_CLK), OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_PHY_CLK), OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_PHY_CLK), OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_UTMI_CLK), OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_UTMI_CLK), OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_HSIC_CLK), OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_HSIC_CLK), /* GPIO */ OMAP4_GENERIC_CLOCK_DEV(GPIO1_CLK), OMAP4_GENERIC_CLOCK_DEV(GPIO2_CLK), OMAP4_GENERIC_CLOCK_DEV(GPIO3_CLK), OMAP4_GENERIC_CLOCK_DEV(GPIO4_CLK), OMAP4_GENERIC_CLOCK_DEV(GPIO5_CLK), OMAP4_GENERIC_CLOCK_DEV(GPIO6_CLK), /* sDMA */ OMAP4_GENERIC_CLOCK_DEV(SDMA_CLK), /* I2C */ OMAP4_GENERIC_CLOCK_DEV(I2C1_CLK), OMAP4_GENERIC_CLOCK_DEV(I2C2_CLK), OMAP4_GENERIC_CLOCK_DEV(I2C3_CLK), OMAP4_GENERIC_CLOCK_DEV(I2C4_CLK), { INVALID_CLK_IDENT, NULL, NULL, NULL, NULL } }; /** * omap4_clk_details - Stores details for all the different clocks supported * * Whenever an operation on a clock is being performed (activated, deactivated, * etc) this array is looked up to find the correct register and bit(s) we * should be modifying. * */ struct omap4_clk_details { clk_ident_t id; - uint32_t mem_region; + uint32_t instance; uint32_t clksel_reg; int32_t src_freq; uint32_t enable_mode; }; -#define OMAP4_GENERIC_CLOCK_DETAILS(i, f, m, r, e) \ +#define OMAP4_GENERIC_CLOCK_DETAILS(i, f, di, r, e) \ { .id = (i), \ - .mem_region = (m), \ + .instance = (di), \ .clksel_reg = (r), \ .src_freq = (f), \ .enable_mode = (e), \ } static struct omap4_clk_details g_omap4_clk_details[] = { /* UART */ - OMAP4_GENERIC_CLOCK_DETAILS(UART1_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(UART1_CLK, FREQ_48MHZ, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x0140), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(UART2_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(UART2_CLK, FREQ_48MHZ, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x0148), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(UART3_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(UART3_CLK, FREQ_48MHZ, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x0140), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(UART4_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(UART4_CLK, FREQ_48MHZ, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x0148), CLKCTRL_MODULEMODE_ENABLE), /* General purpose timers */ - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER1_CLK, -1, PRM_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER1_CLK, -1, PRM_INSTANCE, (WKUP_CM_OFFSET + 0x040), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER2_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER2_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x038), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER3_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER3_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x040), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER4_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER4_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x048), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER5_CLK, -1, CM1_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER5_CLK, -1, CM1_INSTANCE, (ABE_CM1_OFFSET + 0x068), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER6_CLK, -1, CM1_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER6_CLK, -1, CM1_INSTANCE, (ABE_CM1_OFFSET + 0x070), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER7_CLK, -1, CM1_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER7_CLK, -1, CM1_INSTANCE, (ABE_CM1_OFFSET + 0x078), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER8_CLK, -1, CM1_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER8_CLK, -1, CM1_INSTANCE, (ABE_CM1_OFFSET + 0x080), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER9_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER9_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x050), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER10_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER10_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x028), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER11_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(TIMER11_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x030), CLKCTRL_MODULEMODE_ENABLE), /* HSMMC (MMC1 and MMC2 can have different input clocks) */ - OMAP4_GENERIC_CLOCK_DETAILS(MMC1_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(MMC1_CLK, -1, CM2_INSTANCE, (L3INIT_CM2_OFFSET + 0x028), /*CLKCTRL_MODULEMODE_ENABLE*/2), - OMAP4_GENERIC_CLOCK_DETAILS(MMC2_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(MMC2_CLK, -1, CM2_INSTANCE, (L3INIT_CM2_OFFSET + 0x030), /*CLKCTRL_MODULEMODE_ENABLE*/2), - OMAP4_GENERIC_CLOCK_DETAILS(MMC3_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(MMC3_CLK, FREQ_48MHZ, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x120), /*CLKCTRL_MODULEMODE_ENABLE*/2), - OMAP4_GENERIC_CLOCK_DETAILS(MMC4_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(MMC4_CLK, FREQ_48MHZ, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x128), /*CLKCTRL_MODULEMODE_ENABLE*/2), - OMAP4_GENERIC_CLOCK_DETAILS(MMC5_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(MMC5_CLK, FREQ_48MHZ, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x160), /*CLKCTRL_MODULEMODE_ENABLE*/1), /* GPIO modules */ - OMAP4_GENERIC_CLOCK_DETAILS(GPIO1_CLK, -1, PRM_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(GPIO1_CLK, -1, PRM_INSTANCE, (WKUP_CM_OFFSET + 0x038), CLKCTRL_MODULEMODE_AUTO), - OMAP4_GENERIC_CLOCK_DETAILS(GPIO2_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(GPIO2_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x060), CLKCTRL_MODULEMODE_AUTO), - OMAP4_GENERIC_CLOCK_DETAILS(GPIO3_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(GPIO3_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x068), CLKCTRL_MODULEMODE_AUTO), - OMAP4_GENERIC_CLOCK_DETAILS(GPIO4_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(GPIO4_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x070), CLKCTRL_MODULEMODE_AUTO), - OMAP4_GENERIC_CLOCK_DETAILS(GPIO5_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(GPIO5_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x078), CLKCTRL_MODULEMODE_AUTO), - OMAP4_GENERIC_CLOCK_DETAILS(GPIO6_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(GPIO6_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x080), CLKCTRL_MODULEMODE_AUTO), /* sDMA block */ - OMAP4_GENERIC_CLOCK_DETAILS(SDMA_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(SDMA_CLK, -1, CM2_INSTANCE, (CORE_CM2_OFFSET + 0x300), CLKCTRL_MODULEMODE_AUTO), /* I2C modules */ - OMAP4_GENERIC_CLOCK_DETAILS(I2C1_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(I2C1_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x0A0), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(I2C2_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(I2C2_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x0A8), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(I2C3_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(I2C3_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x0B0), CLKCTRL_MODULEMODE_ENABLE), - OMAP4_GENERIC_CLOCK_DETAILS(I2C4_CLK, -1, CM2_INSTANCE_MEM_REGION, + OMAP4_GENERIC_CLOCK_DETAILS(I2C4_CLK, -1, CM2_INSTANCE, (L4PER_CM2_OFFSET + 0x0B8), CLKCTRL_MODULEMODE_ENABLE), { INVALID_CLK_IDENT, 0, 0, 0, 0 }, }; /** * MAX_MODULE_ENABLE_WAIT - the number of loops to wait for the module to come * alive. * */ #define MAX_MODULE_ENABLE_WAIT 100 /** * ARRAY_SIZE - Macro to return the number of elements in a static const array. * */ #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /** * omap4_clk_details - writes a 32-bit value to one of the timer registers * @timer: Timer device context * @off: The offset of a register from the timer register address range * @val: The value to write into the register * * * RETURNS: * nothing */ static struct omap4_clk_details* omap4_clk_details(clk_ident_t id) { struct omap4_clk_details *walker; for (walker = g_omap4_clk_details; walker->id != INVALID_CLK_IDENT; walker++) { if (id == walker->id) return (walker); } return NULL; } + +static struct omap4_prcm_softc * +omap4_prcm_get_instance_softc(int module_instance) +{ + int i, maxunit; + devclass_t prcm_devclass; + device_t dev; + struct omap4_prcm_softc *sc; + + prcm_devclass = devclass_find("omap4_prcm"); + maxunit = devclass_get_maxunit(prcm_devclass); + + for (i = 0; i < maxunit; i++) { + dev = devclass_get_device(prcm_devclass, i); + sc = device_get_softc(dev); + if (sc->sc_instance == module_instance) + return (sc); + } + + return (NULL); +} /** * omap4_clk_generic_activate - checks if a module is accessible * @module: identifier for the module to check, see omap3_prcm.h for a list * of possible modules. * Example: OMAP3_MODULE_MMC1 * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a positive error code on failure. */ static int omap4_clk_generic_activate(struct ti_clock_dev *clkdev) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct omap4_clk_details* clk_details; struct resource* clk_mem_res; uint32_t clksel; unsigned int i; - - if (sc == NULL) - return ENXIO; - clk_details = omap4_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); - clk_mem_res = sc->sc_res[clk_details->mem_region]; + sc = omap4_prcm_get_instance_softc(clk_details->instance); + if (sc == NULL) + return ENXIO; + clk_mem_res = sc->sc_res; + if (clk_mem_res == NULL) return (EINVAL); /* All the 'generic' clocks have a CLKCTRL register which is more or less * generic - the have at least two fielda called MODULEMODE and IDLEST. */ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg); clksel &= ~CLKCTRL_MODULEMODE_MASK; clksel |= clk_details->enable_mode; bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel); /* Now poll on the IDLEST register to tell us if the module has come up. * TODO: We need to take into account the parent clocks. */ /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */ for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) { clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg); if ((clksel & CLKCTRL_IDLEST_MASK) == CLKCTRL_IDLEST_ENABLED) break; DELAY(10); } /* Check the enabled state */ if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) { printf("Error: failed to enable module with clock %d\n", clkdev->id); printf("Error: 0x%08x => 0x%08x\n", clk_details->clksel_reg, clksel); return (ETIMEDOUT); } return (0); } /** * omap4_clk_generic_deactivate - checks if a module is accessible * @module: identifier for the module to check, see omap3_prcm.h for a list * of possible modules. * Example: OMAP3_MODULE_MMC1 * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a positive error code on failure. */ static int omap4_clk_generic_deactivate(struct ti_clock_dev *clkdev) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct omap4_clk_details* clk_details; struct resource* clk_mem_res; uint32_t clksel; - if (sc == NULL) - return ENXIO; - clk_details = omap4_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); - clk_mem_res = sc->sc_res[clk_details->mem_region]; + sc = omap4_prcm_get_instance_softc(clk_details->instance); + if (sc == NULL) + return ENXIO; + clk_mem_res = sc->sc_res; + if (clk_mem_res == NULL) return (EINVAL); /* All the 'generic' clocks have a CLKCTRL register which is more or less * generic - the have at least two fielda called MODULEMODE and IDLEST. */ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg); clksel &= ~CLKCTRL_MODULEMODE_MASK; clksel |= CLKCTRL_MODULEMODE_DISABLE; bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel); return (0); } /** * omap4_clk_generic_set_source - checks if a module is accessible * @module: identifier for the module to check, see omap3_prcm.h for a list * of possible modules. * Example: OMAP3_MODULE_MMC1 * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a positive error code on failure. */ static int omap4_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) { return (0); } /** * omap4_clk_generic_accessible - checks if a module is accessible * @module: identifier for the module to check, see omap3_prcm.h for a list * of possible modules. * Example: OMAP3_MODULE_MMC1 * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a negative error code on failure. */ static int omap4_clk_generic_accessible(struct ti_clock_dev *clkdev) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct omap4_clk_details* clk_details; struct resource* clk_mem_res; uint32_t clksel; - if (sc == NULL) - return ENXIO; - clk_details = omap4_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); - clk_mem_res = sc->sc_res[clk_details->mem_region]; + sc = omap4_prcm_get_instance_softc(clk_details->instance); + if (sc == NULL) + return ENXIO; + clk_mem_res = sc->sc_res; + if (clk_mem_res == NULL) return (EINVAL); clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg); /* Check the enabled state */ if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) return (0); return (1); } /** * omap4_clk_generic_get_source_freq - checks if a module is accessible * @module: identifier for the module to check, see omap3_prcm.h for a list * of possible modules. * Example: OMAP3_MODULE_MMC1 * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a negative error code on failure. */ static int omap4_clk_generic_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq ) { struct omap4_clk_details* clk_details = omap4_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); /* Simply return the stored frequency */ if (freq) *freq = (unsigned int)clk_details->src_freq; return (0); } /** * omap4_clk_gptimer_set_source - checks if a module is accessible * @module: identifier for the module to check, see omap3_prcm.h for a list * of possible modules. * Example: OMAP3_MODULE_MMC1 * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a negative error code on failure. */ static int omap4_clk_gptimer_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct omap4_clk_details* clk_details; struct resource* clk_mem_res; - if (sc == NULL) - return ENXIO; - clk_details = omap4_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); - clk_mem_res = sc->sc_res[clk_details->mem_region]; + sc = omap4_prcm_get_instance_softc(clk_details->instance); + if (sc == NULL) + return ENXIO; + clk_mem_res = sc->sc_res; + if (clk_mem_res == NULL) return (EINVAL); /* TODO: Implement */ return (0); } /** * omap4_clk_gptimer_get_source_freq - checks if a module is accessible * @module: identifier for the module to check, see omap3_prcm.h for a list * of possible modules. * Example: OMAP3_MODULE_MMC1 * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a negative error code on failure. */ static int omap4_clk_gptimer_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq ) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct omap4_clk_details* clk_details; struct resource* clk_mem_res; uint32_t clksel; unsigned int src_freq; - if (sc == NULL) - return ENXIO; - clk_details = omap4_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); - clk_mem_res = sc->sc_res[clk_details->mem_region]; + sc = omap4_prcm_get_instance_softc(clk_details->instance); + if (sc == NULL) + return ENXIO; + clk_mem_res = sc->sc_res; + if (clk_mem_res == NULL) return (EINVAL); /* Need to read the CLKSEL field to determine the clock source */ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg); if (clksel & (0x1UL << 24)) src_freq = FREQ_32KHZ; else omap4_clk_get_sysclk_freq(NULL, &src_freq); /* Return the frequency */ if (freq) *freq = src_freq; return (0); } /** * omap4_clk_hsmmc_set_source - sets the source clock (freq) * @clkdev: pointer to the clockdev structure (id field will contain clock id) * * The MMC 1 and 2 clocks can be source from either a 64MHz or 96MHz clock. * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a negative error code on failure. */ static int omap4_clk_hsmmc_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct omap4_clk_details* clk_details; struct resource* clk_mem_res; uint32_t clksel; - if (sc == NULL) - return ENXIO; - clk_details = omap4_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); - clk_mem_res = sc->sc_res[clk_details->mem_region]; + sc = omap4_prcm_get_instance_softc(clk_details->instance); + if (sc == NULL) + return ENXIO; + + clk_mem_res = sc->sc_res; + if (clk_mem_res == NULL) return (EINVAL); /* For MMC modules 3, 4 & 5 you can't change the freq, it's always 48MHz */ if ((clkdev->id == MMC3_CLK) || (clkdev->id == MMC4_CLK) || (clkdev->id == MMC5_CLK)) { if (clksrc != F48MHZ_CLK) return (EINVAL); return 0; } clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg); /* Bit 24 is set if 96MHz clock or cleared for 64MHz clock */ if (clksrc == F64MHZ_CLK) clksel &= ~(0x1UL << 24); else if (clksrc == F96MHZ_CLK) clksel |= (0x1UL << 24); else return (EINVAL); bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel); return (0); } /** * omap4_clk_hsmmc_get_source_freq - checks if a module is accessible * @clkdev: pointer to the clockdev structure (id field will contain clock id) * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a negative error code on failure. */ static int omap4_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq ) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct omap4_clk_details* clk_details; struct resource* clk_mem_res; uint32_t clksel; unsigned int src_freq; - if (sc == NULL) - return ENXIO; - clk_details = omap4_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); - clk_mem_res = sc->sc_res[clk_details->mem_region]; + sc = omap4_prcm_get_instance_softc(clk_details->instance); + if (sc == NULL) + return ENXIO; + clk_mem_res = sc->sc_res; + if (clk_mem_res == NULL) return (EINVAL); switch (clkdev->id) { case MMC1_CLK: case MMC2_CLK: /* Need to read the CLKSEL field to determine the clock source */ clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg); if (clksel & (0x1UL << 24)) src_freq = FREQ_96MHZ; else src_freq = FREQ_64MHZ; break; case MMC3_CLK: case MMC4_CLK: case MMC5_CLK: src_freq = FREQ_48MHZ; break; default: return (EINVAL); } /* Return the frequency */ if (freq) *freq = src_freq; return (0); } /** * omap4_clk_get_sysclk_freq - gets the sysclk frequency * @sc: pointer to the clk module/device context * * Read the clocking information from the power-control/boot-strap registers, * and stored in two global variables. * * RETURNS: * nothing, values are saved in global variables */ static int omap4_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { uint32_t clksel; uint32_t sysclk; - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; + sc = omap4_prcm_get_instance_softc(PRM_INSTANCE); if (sc == NULL) return ENXIO; /* Read the input clock freq from the configuration register (CM_SYS_CLKSEL) */ - clksel = bus_read_4(sc->sc_res[PRM_INSTANCE_MEM_REGION], CM_SYS_CLKSEL_OFFSET); + clksel = bus_read_4(sc->sc_res, CM_SYS_CLKSEL_OFFSET); switch (clksel & 0x7) { case 0x1: /* 12Mhz */ sysclk = 12000000; break; case 0x3: /* 16.8Mhz */ sysclk = 16800000; break; case 0x4: /* 19.2Mhz */ sysclk = 19200000; break; case 0x5: /* 26Mhz */ sysclk = 26000000; break; case 0x7: /* 38.4Mhz */ sysclk = 38400000; break; default: panic("%s: Invalid clock freq", __func__); } /* Return the value */ if (freq) *freq = sysclk; return (0); } /** * omap4_clk_get_arm_fclk_freq - gets the MPU clock frequency * @clkdev: ignored * @freq: pointer which upon return will contain the freq in hz * @mem_res: array of allocated memory resources * * Reads the frequency setting information registers and returns the value * in the freq variable. * * RETURNS: * returns 0 on success, a positive error code on failure. */ static int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { uint32_t clksel; uint32_t pll_mult, pll_div; uint32_t mpuclk, sysclk; - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; + sc = omap4_prcm_get_instance_softc(CM1_INSTANCE); if (sc == NULL) return ENXIO; /* Read the clksel register which contains the DPLL multiple and divide * values. These are applied to the sysclk. */ - clksel = bus_read_4(sc->sc_res[CM1_INSTANCE_MEM_REGION], CM_CLKSEL_DPLL_MPU); + clksel = bus_read_4(sc->sc_res, CM_CLKSEL_DPLL_MPU); pll_mult = ((clksel >> 8) & 0x7ff); pll_div = (clksel & 0x7f) + 1; /* Get the system clock freq */ omap4_clk_get_sysclk_freq(NULL, &sysclk); /* Calculate the MPU freq */ mpuclk = ((uint64_t)sysclk * pll_mult) / pll_div; /* Return the value */ if (freq) *freq = mpuclk; return (0); } /** * omap4_clk_hsusbhost_activate - activates the USB clocks for the given module * @clkdev: pointer to the clock device structure. * @mem_res: array of memory resources allocated by the top level PRCM driver. * * The USB clocking setup seems to be a bit more tricky than the other modules, * to start with the clocking diagram for the HS host module shows 13 different * clocks. So to try and make it easier to follow the clocking activation * and deactivation is handled in it's own set of callbacks. * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a positive error code on failure. */ struct dpll_param { unsigned int m; unsigned int n; unsigned int m2; unsigned int m3; unsigned int m4; unsigned int m5; unsigned int m6; unsigned int m7; }; /* USB parameters */ struct dpll_param usb_dpll_param[7] = { /* 12M values */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 13M values */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 16.8M values */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 19.2M values */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 26M values */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 27M values */ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* 38.4M values */ #ifdef CONFIG_OMAP4_SDC {0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0}, #else {0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0}, #endif }; static int omap4_clk_hsusbhost_activate(struct ti_clock_dev *clkdev) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct resource* clk_mem_res; uint32_t clksel_reg_off; uint32_t clksel; unsigned int i; + sc = omap4_prcm_get_instance_softc(CM2_INSTANCE); if (sc == NULL) return ENXIO; switch (clkdev->id) { case USBTLL_CLK: /* For the USBTLL module we need to enable the following clocks: * - INIT_L4_ICLK (will be enabled by bootloader) * - TLL_CH0_FCLK * - TLL_CH1_FCLK */ /* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */ - clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION]; + clk_mem_res = sc->sc_res; clksel_reg_off = L3INIT_CM2_OFFSET + 0x68; /* Enable the module and also enable the optional func clocks for * channels 0 & 1 (is this needed ?) */ clksel = bus_read_4(clk_mem_res, clksel_reg_off); clksel &= ~CLKCTRL_MODULEMODE_MASK; clksel |= CLKCTRL_MODULEMODE_ENABLE; clksel |= (0x1 << 8); /* USB-HOST optional clock: USB_CH0_CLK */ clksel |= (0x1 << 9); /* USB-HOST optional clock: USB_CH1_CLK */ break; case USBHSHOST_CLK: case USBP1_PHY_CLK: case USBP2_PHY_CLK: case USBP1_UTMI_CLK: case USBP2_UTMI_CLK: case USBP1_HSIC_CLK: case USBP2_HSIC_CLK: /* For the USB HS HOST module we need to enable the following clocks: * - INIT_L4_ICLK (will be enabled by bootloader) * - INIT_L3_ICLK (will be enabled by bootloader) * - INIT_48MC_FCLK * - UTMI_ROOT_GFCLK (UTMI only, create a new clock for that ?) * - UTMI_P1_FCLK (UTMI only, create a new clock for that ?) * - UTMI_P2_FCLK (UTMI only, create a new clock for that ?) * - HSIC_P1_60 (HSIC only, create a new clock for that ?) * - HSIC_P1_480 (HSIC only, create a new clock for that ?) * - HSIC_P2_60 (HSIC only, create a new clock for that ?) * - HSIC_P2_480 (HSIC only, create a new clock for that ?) */ /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */ - clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION]; + clk_mem_res = sc->sc_res; clksel_reg_off = L3INIT_CM2_OFFSET + 0x58; clksel = bus_read_4(clk_mem_res, clksel_reg_off); /* Enable the module and also enable the optional func clocks */ if (clkdev->id == USBHSHOST_CLK) { clksel &= ~CLKCTRL_MODULEMODE_MASK; clksel |= /*CLKCTRL_MODULEMODE_ENABLE*/2; clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */ } else if (clkdev->id == USBP1_UTMI_CLK) clksel |= (0x1 << 8); /* UTMI_P1_CLK */ else if (clkdev->id == USBP2_UTMI_CLK) clksel |= (0x1 << 9); /* UTMI_P2_CLK */ else if (clkdev->id == USBP1_HSIC_CLK) clksel |= (0x5 << 11); /* HSIC60M_P1_CLK + HSIC480M_P1_CLK */ else if (clkdev->id == USBP2_HSIC_CLK) clksel |= (0x5 << 12); /* HSIC60M_P2_CLK + HSIC480M_P2_CLK */ break; default: return (EINVAL); } bus_write_4(clk_mem_res, clksel_reg_off, clksel); /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */ for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) { clksel = bus_read_4(clk_mem_res, clksel_reg_off); if ((clksel & CLKCTRL_IDLEST_MASK) == CLKCTRL_IDLEST_ENABLED) break; } /* Check the enabled state */ if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) { printf("Error: HERE failed to enable module with clock %d\n", clkdev->id); printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel); return (ETIMEDOUT); } return (0); } /** * omap4_clk_generic_deactivate - checks if a module is accessible * @clkdev: pointer to the clock device structure. * @mem_res: array of memory resources allocated by the top level PRCM driver. * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 on success or a positive error code on failure. */ static int omap4_clk_hsusbhost_deactivate(struct ti_clock_dev *clkdev) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct resource* clk_mem_res; uint32_t clksel_reg_off; uint32_t clksel; + sc = omap4_prcm_get_instance_softc(CM2_INSTANCE); if (sc == NULL) return ENXIO; switch (clkdev->id) { case USBTLL_CLK: /* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */ - clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION]; + clk_mem_res = sc->sc_res; clksel_reg_off = L3INIT_CM2_OFFSET + 0x68; clksel = bus_read_4(clk_mem_res, clksel_reg_off); clksel &= ~CLKCTRL_MODULEMODE_MASK; clksel |= CLKCTRL_MODULEMODE_DISABLE; break; case USBHSHOST_CLK: case USBP1_PHY_CLK: case USBP2_PHY_CLK: case USBP1_UTMI_CLK: case USBP2_UTMI_CLK: case USBP1_HSIC_CLK: case USBP2_HSIC_CLK: /* For the USB HS HOST module we need to enable the following clocks: * - INIT_L4_ICLK (will be enabled by bootloader) * - INIT_L3_ICLK (will be enabled by bootloader) * - INIT_48MC_FCLK * - UTMI_ROOT_GFCLK (UTMI only, create a new clock for that ?) * - UTMI_P1_FCLK (UTMI only, create a new clock for that ?) * - UTMI_P2_FCLK (UTMI only, create a new clock for that ?) * - HSIC_P1_60 (HSIC only, create a new clock for that ?) * - HSIC_P1_480 (HSIC only, create a new clock for that ?) * - HSIC_P2_60 (HSIC only, create a new clock for that ?) * - HSIC_P2_480 (HSIC only, create a new clock for that ?) */ /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */ - clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION]; + clk_mem_res = sc->sc_res; clksel_reg_off = L3INIT_CM2_OFFSET + 0x58; clksel = bus_read_4(clk_mem_res, clksel_reg_off); /* Enable the module and also enable the optional func clocks */ if (clkdev->id == USBHSHOST_CLK) { clksel &= ~CLKCTRL_MODULEMODE_MASK; clksel |= CLKCTRL_MODULEMODE_DISABLE; clksel &= ~(0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */ } else if (clkdev->id == USBP1_UTMI_CLK) clksel &= ~(0x1 << 8); /* UTMI_P1_CLK */ else if (clkdev->id == USBP2_UTMI_CLK) clksel &= ~(0x1 << 9); /* UTMI_P2_CLK */ else if (clkdev->id == USBP1_HSIC_CLK) clksel &= ~(0x5 << 11); /* HSIC60M_P1_CLK + HSIC480M_P1_CLK */ else if (clkdev->id == USBP2_HSIC_CLK) clksel &= ~(0x5 << 12); /* HSIC60M_P2_CLK + HSIC480M_P2_CLK */ break; default: return (EINVAL); } bus_write_4(clk_mem_res, clksel_reg_off, clksel); return (0); } /** * omap4_clk_hsusbhost_accessible - checks if a module is accessible * @clkdev: pointer to the clock device structure. * @mem_res: array of memory resources allocated by the top level PRCM driver. * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 if module is not enable, 1 if module is enabled or a negative * error code on failure. */ static int omap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct resource* clk_mem_res; uint32_t clksel_reg_off; uint32_t clksel; + sc = omap4_prcm_get_instance_softc(CM2_INSTANCE); if (sc == NULL) return ENXIO; if (clkdev->id == USBTLL_CLK) { /* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */ - clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION]; + clk_mem_res = sc->sc_res; clksel_reg_off = L3INIT_CM2_OFFSET + 0x68; } else if (clkdev->id == USBHSHOST_CLK) { /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */ - clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION]; + clk_mem_res = sc->sc_res; clksel_reg_off = L3INIT_CM2_OFFSET + 0x58; } else { return (EINVAL); } clksel = bus_read_4(clk_mem_res, clksel_reg_off); /* Check the enabled state */ if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) return (0); return (1); } /** * omap4_clk_hsusbhost_set_source - sets the source clocks * @clkdev: pointer to the clock device structure. * @clksrc: the clock source ID for the given clock. * @mem_res: array of memory resources allocated by the top level PRCM driver. * * * * LOCKING: * Inherits the locks from the omap_prcm driver, no internal locking. * * RETURNS: * Returns 0 if sucessful otherwise a negative error code on failure. */ static int omap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; + struct omap4_prcm_softc *sc; struct resource* clk_mem_res; uint32_t clksel_reg_off; uint32_t clksel; unsigned int bit; + sc = omap4_prcm_get_instance_softc(CM2_INSTANCE); if (sc == NULL) return ENXIO; if (clkdev->id == USBP1_PHY_CLK) bit = 24; else if (clkdev->id != USBP2_PHY_CLK) bit = 25; else return (EINVAL); /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */ - clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION]; + clk_mem_res = sc->sc_res; clksel_reg_off = L3INIT_CM2_OFFSET + 0x58; clksel = bus_read_4(clk_mem_res, clksel_reg_off); /* Set the clock source to either external or internal */ if (clksrc == EXT_CLK) clksel |= (0x1 << bit); else clksel &= ~(0x1 << bit); bus_write_4(clk_mem_res, clksel_reg_off, clksel); return (0); } #define PRM_RSTCTRL 0x1b00 #define PRM_RSTCTRL_RESET 0x2 static void omap4_prcm_reset(void) { - struct omap4_prcm_softc *sc = omap4_prcm_sc; - bus_write_4(sc->sc_res[0], PRM_RSTCTRL, - bus_read_4(sc->sc_res[0], PRM_RSTCTRL) | PRM_RSTCTRL_RESET); - bus_read_4(sc->sc_res[0], PRM_RSTCTRL); + struct omap4_prcm_softc *sc; + + sc = omap4_prcm_get_instance_softc(PRM_INSTANCE); + if (sc == NULL) + return; + + bus_write_4(sc->sc_res, PRM_RSTCTRL, + bus_read_4(sc->sc_res, PRM_RSTCTRL) | PRM_RSTCTRL_RESET); + bus_read_4(sc->sc_res, PRM_RSTCTRL); } /** * omap4_prcm_probe - probe function for the driver * @dev: prcm device handle * * Simply sets the name of the driver module. * * LOCKING: * None * * RETURNS: * Always returns 0 */ static int omap4_prcm_probe(device_t dev) { + const struct ofw_compat_data *ocd; if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,omap4_prcm")) + ocd = ofw_bus_search_compatible(dev, compat_data); + if ((int)ocd->ocd_data == 0) return (ENXIO); - device_set_desc(dev, "TI OMAP Power, Reset and Clock Management"); - return (0); + switch ((int)ocd->ocd_data) { + case PRM_INSTANCE: + device_set_desc(dev, "TI OMAP Power, Reset and Clock Management (PRM)"); + break; + case CM1_INSTANCE: + device_set_desc(dev, "TI OMAP Power, Reset and Clock Management (C1)"); + break; + case CM2_INSTANCE: + device_set_desc(dev, "TI OMAP Power, Reset and Clock Management (C2)"); + break; + default: + device_printf(dev, "unknown instance type: %d\n", (int)ocd->ocd_data); + return (ENXIO); + } + + return (BUS_PROBE_DEFAULT); } /** * omap_prcm_attach - attach function for the driver * @dev: prcm device handle * * Allocates and sets up the driver context, this simply entails creating a * bus mappings for the PRCM register set. * * LOCKING: * None * * RETURNS: * Always returns 0 */ extern uint32_t platform_arm_tmr_freq; static int omap4_prcm_attach(device_t dev) { - struct omap4_prcm_softc *sc = device_get_softc(dev); + struct omap4_prcm_softc *sc; unsigned int freq; + const struct ofw_compat_data *ocd; - if (bus_alloc_resources(dev, omap4_scm_res_spec, sc->sc_res)) { + + sc = device_get_softc(dev); + ocd = ofw_bus_search_compatible(dev, compat_data); + sc->sc_instance = (int)ocd->ocd_data; + + sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, + RF_ACTIVE); + if (sc->sc_res == NULL) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } - omap4_prcm_sc = sc; ti_cpu_reset = omap4_prcm_reset; - omap4_clk_get_arm_fclk_freq(NULL, &freq); - arm_tmr_change_frequency(freq / 2); + + /* + * In order to determine ARM frequency we need both RPM and CM1 + * instances up and running. So wait until all CRM devices are + * initialized. Should be replaced with proper clock framework + */ + if (device_get_unit(dev) == 2) { + omap4_clk_get_arm_fclk_freq(NULL, &freq); + arm_tmr_change_frequency(freq / 2); + } return (0); } static device_method_t omap4_prcm_methods[] = { DEVMETHOD(device_probe, omap4_prcm_probe), DEVMETHOD(device_attach, omap4_prcm_attach), {0, 0}, }; static driver_t omap4_prcm_driver = { "omap4_prcm", omap4_prcm_methods, sizeof(struct omap4_prcm_softc), }; static devclass_t omap4_prcm_devclass; EARLY_DRIVER_MODULE(omap4_prcm, simplebus, omap4_prcm_driver, omap4_prcm_devclass, 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_EARLY); MODULE_VERSION(omap4_prcm, 1); Index: head/sys/arm/ti/omap4/omap4_scm_padconf.c =================================================================== --- head/sys/arm/ti/omap4/omap4_scm_padconf.c (revision 283275) +++ head/sys/arm/ti/omap4/omap4_scm_padconf.c (revision 283276) @@ -1,303 +1,303 @@ /*- * Copyright (c) 2011 * Ben Gray . * 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. * 3. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include -#include +#include #include /* * This file defines the pin mux configuration for the OMAP4xxx series of * devices. * * How This is Suppose to Work * =========================== * - There is a top level ti_scm module (System Control Module) that is * the interface for all omap drivers, which can use it to change the mux * settings for individual pins. (That said, typically the pin mux settings * are set to defaults by the 'hints' and then not altered by the driver). * * - For this to work the top level driver needs all the pin info, and hence * this is where this file comes in. Here we define all the pin information * that is supplied to the top level driver. * */ #define _PINDEF(r, b, gp, gm, m0, m1, m2, m3, m4, m5, m6, m7) \ { .reg_off = r, \ .gpio_pin = gp, \ .gpio_mode = gm, \ .ballname = b, \ .muxmodes[0] = m0, \ .muxmodes[1] = m1, \ .muxmodes[2] = m2, \ .muxmodes[3] = m3, \ .muxmodes[4] = m4, \ .muxmodes[5] = m5, \ .muxmodes[6] = m6, \ .muxmodes[7] = m7, \ } -const static struct ti_scm_padstate ti_padstate_devmap[] = { +const static struct ti_pinmux_padstate ti_padstate_devmap[] = { {"output", PADCONF_PIN_OUTPUT}, {"input", PADCONF_PIN_INPUT}, {"input_pullup", PADCONF_PIN_INPUT_PULLUP}, {"input_pulldown", PADCONF_PIN_INPUT_PULLDOWN}, { .state = NULL } }; /* * Table 18-10, p. 3470 */ -const static struct ti_scm_padconf ti_padconf_devmap[] = { - _PINDEF(0x0040, "c12", 0, 0, "gpmc_ad0", "sdmmc2_dat0", NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0042, "d12", 0, 0, "gpmc_ad1", "sdmmc2_dat1", NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0044, "c13", 0, 0, "gpmc_ad2", "sdmmc2_dat2", NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0046, "d13", 0, 0, "gpmc_ad3", "sdmmc2_dat3", NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0048, "c15", 0, 0, "gpmc_ad4", "sdmmc2_dat4", "sdmmc2_dir_dat0", NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x004a, "d15", 0, 0, "gpmc_ad5", "sdmmc2_dat5", "sdmmc2_dir_dat1", NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x004c, "a16", 0, 0, "gpmc_ad6", "sdmmc2_dat6", "sdmmc2_dir_cmd", NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x004e, "b16", 0, 0, "gpmc_ad7", "sdmmc2_dat7", "sdmmc2_clk_fdbk", NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0050, "c16", 32, 3, "gpmc_ad8", "kpd_row0", "c2c_data15", "gpio_32", NULL, "sdmmc1_dat0", NULL, NULL), - _PINDEF(0x0052, "d16", 33, 3, "gpmc_ad9", "kpd_row1", "c2c_data14", "gpio_33", NULL, "sdmmc1_dat1", NULL, NULL), - _PINDEF(0x0054, "c17", 34, 3, "gpmc_ad10", "kpd_row2", "c2c_data13", "gpio_34", NULL, "sdmmc1_dat2", NULL, NULL), - _PINDEF(0x0056, "d17", 35, 3, "gpmc_ad11", "kpd_row3", "c2c_data12", "gpio_35", NULL, "sdmmc1_dat3", NULL, NULL), - _PINDEF(0x0058, "c18", 36, 3, "gpmc_ad12", "kpd_col0", "c2c_data11", "gpio_36", NULL, "sdmmc1_dat4", NULL, NULL), - _PINDEF(0x005a, "d18", 37, 3, "gpmc_ad13", "kpd_col1", "c2c_data10", "gpio_37", NULL, "sdmmc1_dat5", NULL, NULL), - _PINDEF(0x005c, "c19", 38, 3, "gpmc_ad14", "kpd_col2", "c2c_data9", "gpio_38", NULL, "sdmmc1_dat6", NULL, NULL), - _PINDEF(0x005e, "d19", 39, 3, "gpmc_ad15", "kpd_col3", "c2c_data8", "gpio_39", NULL, "sdmmc1_dat7", NULL, NULL), - _PINDEF(0x0060, "b17", 40, 3, "gpmc_a16", "kpd_row4", "c2c_datain0", "gpio_40", "venc_656_data0", NULL, NULL, "safe_mode"), - _PINDEF(0x0062, "a18", 41, 3, "gpmc_a17", "kpd_row5", "c2c_datain1", "gpio_41", "venc_656_data1", NULL, NULL, "safe_mode"), - _PINDEF(0x0064, "b18", 42, 3, "gpmc_a18", "kpd_row6", "c2c_datain2", "gpio_42", "venc_656_data2", NULL, NULL, "safe_mode"), - _PINDEF(0x0066, "a19", 43, 3, "gpmc_a19", "kpd_row7", "c2c_datain3", "gpio_43", "venc_656_data3", NULL, NULL, "safe_mode"), - _PINDEF(0x0068, "b19", 44, 3, "gpmc_a20", "kpd_col4", "c2c_datain4", "gpio_44", "venc_656_data4", NULL, NULL, "safe_mode"), - _PINDEF(0x006a, "b20", 45, 3, "gpmc_a21", "kpd_col5", "c2c_datain5", "gpio_45", "venc_656_data5", NULL, NULL, "safe_mode"), - _PINDEF(0x006c, "a21", 46, 3, "gpmc_a22", "kpd_col6", "c2c_datain6", "gpio_46", "venc_656_data6", NULL, NULL, "safe_mode"), - _PINDEF(0x006e, "b21", 47, 3, "gpmc_a23", "kpd_col7", "c2c_datain7", "gpio_47", "venc_656_data7", NULL, NULL, "safe_mode"), - _PINDEF(0x0070, "c20", 48, 3, "gpmc_a24", "kpd_col8", "c2c_clkout0", "gpio_48", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0072, "d20", 49, 3, "gpmc_a25", NULL, "c2c_clkout1", "gpio_49", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0074, "b25", 50, 3, "gpmc_ncs0", NULL, NULL, "gpio_50", "sys_ndmareq0", NULL, NULL, NULL), - _PINDEF(0x0076, "c21", 51, 3, "gpmc_ncs1", NULL, "c2c_dataout6", "gpio_51", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0078, "d21", 52, 3, "gpmc_ncs2", "kpd_row8", "c2c_dataout7", "gpio_52", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x007a, "c22", 53, 3, "gpmc_ncs3", "gpmc_dir", "c2c_dataout4", "gpio_53", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x007c, "c25", 54, 3, "gpmc_nwp", "dsi1_te0", NULL, "gpio_54", "sys_ndmareq1", NULL, NULL, NULL), - _PINDEF(0x007e, "b22", 55, 3, "gpmc_clk", NULL, NULL, "gpio_55", "sys_ndmareq2", "sdmmc1_cmd", NULL, NULL), - _PINDEF(0x0080, "d25", 56, 3, "gpmc_nadv_ale", "dsi1_te1", NULL, "gpio_56", "sys_ndmareq3", "sdmmc1_clk", NULL, NULL), - _PINDEF(0x0082, "b11", 0, 0, "gpmc_noe", "sdmmc2_clk", NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0084, "b12", 0, 0, "gpmc_nwe", "sdmmc2_cmd", NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0086, "c23", 59, 3, "gpmc_nbe0_cle", "dsi2_te0", NULL, "gpio_59", NULL, NULL, NULL, NULL), - _PINDEF(0x0088, "d22", 60, 3, "gpmc_nbe1", NULL, "c2c_dataout5", "gpio_60", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x008a, "b26", 61, 3, "gpmc_wait0", "dsi2_te1", NULL, "gpio_61", NULL, NULL, NULL, NULL), - _PINDEF(0x008c, "b23", 62, 3, "gpmc_wait1", NULL, "c2c_dataout2", "gpio_62", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x008e, "d23", 100, 3, "gpmc_wait2", "usbc1_icusb_txen", "c2c_dataout3", "gpio_100", "sys_ndmareq0", NULL, NULL, "safe_mode"), - _PINDEF(0x0090, "a24", 101, 3, "gpmc_ncs4", "dsi1_te0", "c2c_clkin0", "gpio_101", "sys_ndmareq1", NULL, NULL, "safe_mode"), - _PINDEF(0x0092, "b24", 102, 3, "gpmc_ncs5", "dsi1_te1", "c2c_clkin1", "gpio_102", "sys_ndmareq2", NULL, NULL, "safe_mode"), - _PINDEF(0x0094, "c24", 103, 3, "gpmc_ncs6", "dsi2_te0", "c2c_dataout0", "gpio_103", "sys_ndmareq3", NULL, NULL, "safe_mode"), - _PINDEF(0x0096, "d24", 104, 3, "gpmc_ncs7", "dsi2_te1", "c2c_dataout1", "gpio_104", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0098, "b9", 63, 3, "hdmi_hpd", NULL, NULL, "gpio_63", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x009a, "b10", 64, 3, "hdmi_cec", NULL, NULL, "gpio_64", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x009c, "a8", 65, 3, "hdmi_ddc_scl", NULL, NULL, "gpio_65", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x009e, "b8", 66, 3, "hdmi_ddc_sda", NULL, NULL, "gpio_66", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00a0, "r26", 0, 0, "csi21_dx0", NULL, NULL, "gpi_67", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00a2, "r25", 0, 0, "csi21_dy0", NULL, NULL, "gpi_68", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00a4, "t26", 0, 0, "csi21_dx1", NULL, NULL, "gpi_69", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00a6, "t25", 0, 0, "csi21_dy1", NULL, NULL, "gpi_70", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00a8, "u26", 0, 0, "csi21_dx2", NULL, NULL, "gpi_71", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00aa, "u25", 0, 0, "csi21_dy2", NULL, NULL, "gpi_72", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00ac, "v26", 0, 0, "csi21_dx3", NULL, NULL, "gpi_73", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00ae, "v25", 0, 0, "csi21_dy3", NULL, NULL, "gpi_74", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00b0, "w26", 0, 0, "csi21_dx4", NULL, NULL, "gpi_75", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00b2, "w25", 0, 0, "csi21_dy4", NULL, NULL, "gpi_76", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00b4, "m26", 0, 0, "csi22_dx0", NULL, NULL, "gpi_77", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00b6, "m25", 0, 0, "csi22_dy0", NULL, NULL, "gpi_78", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00b8, "n26", 0, 0, "csi22_dx1", NULL, NULL, "gpi_79", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00ba, "n25", 0, 0, "csi22_dy1", NULL, NULL, "gpi_80", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00bc, "t27", 81, 3, "cam_shutter", NULL, NULL, "gpio_81", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00be, "u27", 82, 3, "cam_strobe", NULL, NULL, "gpio_82", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00c0, "v27", 83, 3, "cam_globalreset", NULL, NULL, "gpio_83", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00c2, "ae18", 84, 3, "usbb1_ulpitll_clk", "hsi1_cawake", NULL, "gpio_84", "usbb1_ulpiphy_clk", NULL, "hw_dbg20", "safe_mode"), - _PINDEF(0x00c4, "ag19", 85, 3, "usbb1_ulpitll_stp", "hsi1_cadata", "mcbsp4_clkr", "gpio_85", "usbb1_ulpiphy_stp", "usbb1_mm_rxdp", "hw_dbg21", "safe_mode"), - _PINDEF(0x00c6, "af19", 86, 3, "usbb1_ulpitll_dir", "hsi1_caflag", "mcbsp4_fsr", "gpio_86", "usbb1_ulpiphy_dir", NULL, "hw_dbg22", "safe_mode"), - _PINDEF(0x00c8, "ae19", 87, 3, "usbb1_ulpitll_nxt", "hsi1_acready", "mcbsp4_fsx", "gpio_87", "usbb1_ulpiphy_nxt", "usbb1_mm_rxdm", "hw_dbg23", "safe_mode"), - _PINDEF(0x00ca, "af18", 88, 3, "usbb1_ulpitll_dat0", "hsi1_acwake", "mcbsp4_clkx", "gpio_88", "usbb1_ulpiphy_dat0", "usbb1_mm_txen", "hw_dbg24", "safe_mode"), - _PINDEF(0x00cc, "ag18", 89, 3, "usbb1_ulpitll_dat1", "hsi1_acdata", "mcbsp4_dx", "gpio_89", "usbb1_ulpiphy_dat1", "usbb1_mm_txdat", "hw_dbg25", "safe_mode"), - _PINDEF(0x00ce, "ae17", 90, 3, "usbb1_ulpitll_dat2", "hsi1_acflag", "mcbsp4_dr", "gpio_90", "usbb1_ulpiphy_dat2", "usbb1_mm_txse0", "hw_dbg26", "safe_mode"), - _PINDEF(0x00d0, "af17", 91, 3, "usbb1_ulpitll_dat3", "hsi1_caready", NULL, "gpio_91", "usbb1_ulpiphy_dat3", "usbb1_mm_rxrcv", "hw_dbg27", "safe_mode"), - _PINDEF(0x00d2, "ah17", 92, 3, "usbb1_ulpitll_dat4", "dmtimer8_pwm_evt", "abe_mcbsp3_dr", "gpio_92", "usbb1_ulpiphy_dat4", NULL, "hw_dbg28", "safe_mode"), - _PINDEF(0x00d4, "ae16", 93, 3, "usbb1_ulpitll_dat5", "dmtimer9_pwm_evt", "abe_mcbsp3_dx", "gpio_93", "usbb1_ulpiphy_dat5", NULL, "hw_dbg29", "safe_mode"), - _PINDEF(0x00d6, "af16", 94, 3, "usbb1_ulpitll_dat6", "dmtimer10_pwm_evt", "abe_mcbsp3_clkx", "gpio_94", "usbb1_ulpiphy_dat6", "abe_dmic_din3", "hw_dbg30", "safe_mode"), - _PINDEF(0x00d8, "ag16", 95, 3, "usbb1_ulpitll_dat7", "dmtimer11_pwm_evt", "abe_mcbsp3_fsx", "gpio_95", "usbb1_ulpiphy_dat7", "abe_dmic_clk3", "hw_dbg31", "safe_mode"), - _PINDEF(0x00da, "af14", 96, 3, "usbb1_hsic_data", NULL, NULL, "gpio_96", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00dc, "ae14", 97, 3, "usbb1_hsic_strobe", NULL, NULL, "gpio_97", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00de, "h2", 98, 3, "usbc1_icusb_dp", NULL, NULL, "gpio_98", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00e0, "h3", 99, 3, "usbc1_icusb_dm", NULL, NULL, "gpio_99", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00e2, "d2", 100, 3, "sdmmc1_clk", NULL, "dpm_emu19", "gpio_100", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00e4, "e3", 101, 3, "sdmmc1_cmd", NULL, "uart1_rx", "gpio_101", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00e6, "e4", 102, 3, "sdmmc1_dat0", NULL, "dpm_emu18", "gpio_102", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00e8, "e2", 103, 3, "sdmmc1_dat1", NULL, "dpm_emu17", "gpio_103", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00ea, "e1", 104, 3, "sdmmc1_dat2", NULL, "dpm_emu16", "gpio_104", "jtag_tms_tmsc", NULL, NULL, "safe_mode"), - _PINDEF(0x00ec, "f4", 105, 3, "sdmmc1_dat3", NULL, "dpm_emu15", "gpio_105", "jtag_tck", NULL, NULL, "safe_mode"), - _PINDEF(0x00ee, "f3", 106, 3, "sdmmc1_dat4", NULL, NULL, "gpio_106", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00f0, "f1", 107, 3, "sdmmc1_dat5", NULL, NULL, "gpio_107", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00f2, "g4", 108, 3, "sdmmc1_dat6", NULL, NULL, "gpio_108", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00f4, "g3", 109, 3, "sdmmc1_dat7", NULL, NULL, "gpio_109", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x00f6, "ad27", 110, 3, "abe_mcbsp2_clkx", "mcspi2_clk", "abe_mcasp_ahclkx", "gpio_110", "usbb2_mm_rxdm", NULL, NULL, "safe_mode"), - _PINDEF(0x00f8, "ad26", 111, 3, "abe_mcbsp2_dr", "mcspi2_somi", "abe_mcasp_axr", "gpio_111", "usbb2_mm_rxdp", NULL, NULL, "safe_mode"), - _PINDEF(0x00fa, "ad25", 112, 3, "abe_mcbsp2_dx", "mcspi2_simo", "abe_mcasp_amute", "gpio_112", "usbb2_mm_rxrcv", NULL, NULL, "safe_mode"), - _PINDEF(0x00fc, "ac28", 113, 3, "abe_mcbsp2_fsx", "mcspi2_cs0", "abe_mcasp_afsx", "gpio_113", "usbb2_mm_txen", NULL, NULL, "safe_mode"), - _PINDEF(0x00fe, "ac26", 114, 3, "abe_mcbsp1_clkx", "abe_slimbus1_clock", NULL, "gpio_114", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0100, "ac25", 115, 3, "abe_mcbsp1_dr", "abe_slimbus1_data", NULL, "gpio_115", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0102, "ab25", 116, 3, "abe_mcbsp1_dx", "sdmmc3_dat2", "abe_mcasp_aclkx", "gpio_116", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0104, "ac27", 117, 3, "abe_mcbsp1_fsx", "sdmmc3_dat3", "abe_mcasp_amutein", "gpio_117", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0106, "ag25", 0, 0, "abe_pdm_ul_data", "abe_mcbsp3_dr", NULL, NULL, NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0108, "af25", 0, 0, "abe_pdm_dl_data", "abe_mcbsp3_dx", NULL, NULL, NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x010a, "ae25", 0, 0, "abe_pdm_frame", "abe_mcbsp3_clkx", NULL, NULL, NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x010c, "af26", 0, 0, "abe_pdm_lb_clk", "abe_mcbsp3_fsx", NULL, NULL, NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x010e, "ah26", 118, 3, "abe_clks", NULL, NULL, "gpio_118", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0110, "ae24", 119, 3, "abe_dmic_clk1", NULL, NULL, "gpio_119", "usbb2_mm_txse0", "uart4_cts", NULL, "safe_mode"), - _PINDEF(0x0112, "af24", 120, 3, "abe_dmic_din1", NULL, NULL, "gpio_120", "usbb2_mm_txdat", "uart4_rts", NULL, "safe_mode"), - _PINDEF(0x0114, "ag24", 121, 3, "abe_dmic_din2", "slimbus2_clock", "abe_mcasp_axr", "gpio_121", NULL, "dmtimer11_pwm_evt", NULL, "safe_mode"), - _PINDEF(0x0116, "ah24", 122, 3, "abe_dmic_din3", "slimbus2_data", "abe_dmic_clk2", "gpio_122", NULL, "dmtimer9_pwm_evt", NULL, "safe_mode"), - _PINDEF(0x0118, "ab26", 123, 3, "uart2_cts", "sdmmc3_clk", NULL, "gpio_123", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x011a, "ab27", 124, 3, "uart2_rts", "sdmmc3_cmd", NULL, "gpio_124", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x011c, "aa25", 125, 3, "uart2_rx", "sdmmc3_dat0", NULL, "gpio_125", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x011e, "aa26", 126, 3, "uart2_tx", "sdmmc3_dat1", NULL, "gpio_126", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0120, "aa27", 127, 3, "hdq_sio", "i2c3_sccb", "i2c2_sccb", "gpio_127", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0122, "ae28", 0, 0, "i2c1_scl", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0124, "ae26", 0, 0, "i2c1_sda", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0126, "c26", 128, 3, "i2c2_scl", "uart1_rx", NULL, "gpio_128", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0128, "d26", 129, 3, "i2c2_sda", "uart1_tx", NULL, "gpio_129", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x012a, "w27", 130, 3, "i2c3_scl", NULL, NULL, "gpio_130", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x012c, "y27", 131, 3, "i2c3_sda", NULL, NULL, "gpio_131", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x012e, "ag21", 132, 3, "i2c4_scl", NULL, NULL, "gpio_132", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0130, "ah22", 133, 3, "i2c4_sda", NULL, NULL, "gpio_133", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0132, "af22", 134, 3, "mcspi1_clk", NULL, NULL, "gpio_134", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0134, "ae22", 135, 3, "mcspi1_somi", NULL, NULL, "gpio_135", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0136, "ag22", 136, 3, "mcspi1_simo", NULL, NULL, "gpio_136", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0138, "ae23", 137, 3, "mcspi1_cs0", NULL, NULL, "gpio_137", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x013a, "af23", 138, 3, "mcspi1_cs1", "uart1_rx", NULL, "gpio_138", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x013c, "ag23", 139, 3, "mcspi1_cs2", "uart1_cts", "slimbus2_clock", "gpio_139", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x013e, "ah23", 140, 3, "mcspi1_cs3", "uart1_rts", "slimbus2_data", "gpio_140", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0140, "f27", 141, 3, "uart3_cts_rctx", "uart1_tx", NULL, "gpio_141", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0142, "f28", 142, 3, "uart3_rts_sd", NULL, NULL, "gpio_142", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0144, "g27", 143, 3, "uart3_rx_irrx", "dmtimer8_pwm_evt", NULL, "gpio_143", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0146, "g28", 144, 3, "uart3_tx_irtx", "dmtimer9_pwm_evt", NULL, "gpio_144", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0148, "ae5", 145, 3, "sdmmc5_clk", "mcspi2_clk", "usbc1_icusb_dp", "gpio_145", NULL, "sdmmc2_clk", NULL, "safe_mode"), - _PINDEF(0x014a, "af5", 146, 3, "sdmmc5_cmd", "mcspi2_simo", "usbc1_icusb_dm", "gpio_146", NULL, "sdmmc2_cmd", NULL, "safe_mode"), - _PINDEF(0x014c, "ae4", 147, 3, "sdmmc5_dat0", "mcspi2_somi", "usbc1_icusb_rcv", "gpio_147", NULL, "sdmmc2_dat0", NULL, "safe_mode"), - _PINDEF(0x014e, "af4", 148, 3, "sdmmc5_dat1", NULL, "usbc1_icusb_txen", "gpio_148", NULL, "sdmmc2_dat1", NULL, "safe_mode"), - _PINDEF(0x0150, "ag3", 149, 3, "sdmmc5_dat2", "mcspi2_cs1", NULL, "gpio_149", NULL, "sdmmc2_dat2", NULL, "safe_mode"), - _PINDEF(0x0152, "af3", 150, 3, "sdmmc5_dat3", "mcspi2_cs0", NULL, "gpio_150", NULL, "sdmmc2_dat3", NULL, "safe_mode"), - _PINDEF(0x0154, "ae21", 151, 3, "mcspi4_clk", "sdmmc4_clk", "kpd_col6", "gpio_151", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0156, "af20", 152, 3, "mcspi4_simo", "sdmmc4_cmd", "kpd_col7", "gpio_152", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0158, "af21", 153, 3, "mcspi4_somi", "sdmmc4_dat0", "kpd_row6", "gpio_153", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x015a, "ae20", 154, 3, "mcspi4_cs0", "sdmmc4_dat3", "kpd_row7", "gpio_154", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x015c, "ag20", 155, 3, "uart4_rx", "sdmmc4_dat2", "kpd_row8", "gpio_155", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x015e, "ah19", 156, 3, "uart4_tx", "sdmmc4_dat1", "kpd_col8", "gpio_156", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0160, "ag12", 157, 3, "usbb2_ulpitll_clk", "usbb2_ulpiphy_clk", "sdmmc4_cmd", "gpio_157", "hsi2_cawake", NULL, NULL, "safe_mode"), - _PINDEF(0x0162, "af12", 158, 3, "usbb2_ulpitll_stp", "usbb2_ulpiphy_stp", "sdmmc4_clk", "gpio_158", "hsi2_cadata", "dispc2_data23", NULL, "safe_mode"), - _PINDEF(0x0164, "ae12", 159, 3, "usbb2_ulpitll_dir", "usbb2_ulpiphy_dir", "sdmmc4_dat0", "gpio_159", "hsi2_caflag", "dispc2_data22", NULL, "safe_mode"), - _PINDEF(0x0166, "ag13", 160, 3, "usbb2_ulpitll_nxt", "usbb2_ulpiphy_nxt", "sdmmc4_dat1", "gpio_160", "hsi2_acready", "dispc2_data21", NULL, "safe_mode"), - _PINDEF(0x0168, "ae11", 161, 3, "usbb2_ulpitll_dat0", "usbb2_ulpiphy_dat0", "sdmmc4_dat2", "gpio_161", "hsi2_acwake", "dispc2_data20", "usbb2_mm_txen", "safe_mode"), - _PINDEF(0x016a, "af11", 162, 3, "usbb2_ulpitll_dat1", "usbb2_ulpiphy_dat1", "sdmmc4_dat3", "gpio_162", "hsi2_acdata", "dispc2_data19", "usbb2_mm_txdat", "safe_mode"), - _PINDEF(0x016c, "ag11", 163, 3, "usbb2_ulpitll_dat2", "usbb2_ulpiphy_dat2", "sdmmc3_dat2", "gpio_163", "hsi2_acflag", "dispc2_data18", "usbb2_mm_txse0", "safe_mode"), - _PINDEF(0x016e, "ah11", 164, 3, "usbb2_ulpitll_dat3", "usbb2_ulpiphy_dat3", "sdmmc3_dat1", "gpio_164", "hsi2_caready", "dispc2_data15", "rfbi_data15", "safe_mode"), - _PINDEF(0x0170, "ae10", 165, 3, "usbb2_ulpitll_dat4", "usbb2_ulpiphy_dat4", "sdmmc3_dat0", "gpio_165", "mcspi3_somi", "dispc2_data14", "rfbi_data14", "safe_mode"), - _PINDEF(0x0172, "af10", 166, 3, "usbb2_ulpitll_dat5", "usbb2_ulpiphy_dat5", "sdmmc3_dat3", "gpio_166", "mcspi3_cs0", "dispc2_data13", "rfbi_data13", "safe_mode"), - _PINDEF(0x0174, "ag10", 167, 3, "usbb2_ulpitll_dat6", "usbb2_ulpiphy_dat6", "sdmmc3_cmd", "gpio_167", "mcspi3_simo", "dispc2_data12", "rfbi_data12", "safe_mode"), - _PINDEF(0x0176, "ae9", 168, 3, "usbb2_ulpitll_dat7", "usbb2_ulpiphy_dat7", "sdmmc3_clk", "gpio_168", "mcspi3_clk", "dispc2_data11", "rfbi_data11", "safe_mode"), - _PINDEF(0x0178, "af13", 169, 3, "usbb2_hsic_data", NULL, NULL, "gpio_169", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x017a, "ae13", 170, 3, "usbb2_hsic_strobe", NULL, NULL, "gpio_170", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x017c, "g26", 171, 3, "kpd_col3", "kpd_col0", NULL, "gpio_171", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x017e, "g25", 172, 3, "kpd_col4", "kpd_col1", NULL, "gpio_172", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0180, "h26", 173, 3, "kpd_col5", "kpd_col2", NULL, "gpio_173", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0182, "h25", 174, 3, "kpd_col0", "kpd_col3", NULL, "gpio_174", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0184, "j27", 0, 0, "kpd_col1", "kpd_col4", NULL, "gpio_0", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0186, "h27", 1, 3, "kpd_col2", "kpd_col5", NULL, "gpio_1", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0188, "j26", 175, 3, "kpd_row3", "kpd_row0", NULL, "gpio_175", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x018a, "j25", 176, 3, "kpd_row4", "kpd_row1", NULL, "gpio_176", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x018c, "k26", 177, 3, "kpd_row5", "kpd_row2", NULL, "gpio_177", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x018e, "k25", 178, 3, "kpd_row0", "kpd_row3", NULL, "gpio_178", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0190, "l27", 2, 3, "kpd_row1", "kpd_row4", NULL, "gpio_2", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0192, "k27", 3, 3, "kpd_row2", "kpd_row5", NULL, "gpio_3", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0194, "c3", 0, 0, "usba0_otg_ce", NULL, NULL, NULL, NULL, NULL, NULL, NULL), - _PINDEF(0x0196, "b5", 0, 0, "usba0_otg_dp", "uart3_rx_irrx", "uart2_rx", NULL, NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x0198, "b4", 0, 0, "usba0_otg_dm", "uart3_tx_irtx", "uart2_tx", NULL, NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x019a, "aa28", 181, 3, "fref_clk1_out", NULL, NULL, "gpio_181", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x019c, "y28", 182, 3, "fref_clk2_out", NULL, NULL, "gpio_182", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x019e, "ae6", 0, 0, "sys_nirq1", NULL, NULL, NULL, NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x01a0, "af6", 183, 3, "sys_nirq2", NULL, NULL, "gpio_183", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x01a2, "f26", 184, 3, "sys_boot0", NULL, NULL, "gpio_184", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x01a4, "e27", 185, 3, "sys_boot1", NULL, NULL, "gpio_185", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x01a6, "e26", 186, 3, "sys_boot2", NULL, NULL, "gpio_186", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x01a8, "e25", 187, 3, "sys_boot3", NULL, NULL, "gpio_187", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x01aa, "d28", 188, 3, "sys_boot4", NULL, NULL, "gpio_188", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x01ac, "d27", 189, 3, "sys_boot5", NULL, NULL, "gpio_189", NULL, NULL, NULL, "safe_mode"), - _PINDEF(0x01ae, "m2", 11, 3, "dpm_emu0", NULL, NULL, "gpio_11", NULL, NULL, "hw_dbg0", "safe_mode"), - _PINDEF(0x01b0, "n2", 12, 3, "dpm_emu1", NULL, NULL, "gpio_12", NULL, NULL, "hw_dbg1", "safe_mode"), - _PINDEF(0x01b2, "p2", 13, 3, "dpm_emu2", "usba0_ulpiphy_clk", NULL, "gpio_13", NULL, "dispc2_fid", "hw_dbg2", "safe_mode"), - _PINDEF(0x01b4, "v1", 14, 3, "dpm_emu3", "usba0_ulpiphy_stp", NULL, "gpio_14", "rfbi_data10", "dispc2_data10", "hw_dbg3", "safe_mode"), - _PINDEF(0x01b6, "v2", 15, 3, "dpm_emu4", "usba0_ulpiphy_dir", NULL, "gpio_15", "rfbi_data9", "dispc2_data9", "hw_dbg4", "safe_mode"), - _PINDEF(0x01b8, "w1", 16, 3, "dpm_emu5", "usba0_ulpiphy_nxt", NULL, "gpio_16", "rfbi_te_vsync0", "dispc2_data16", "hw_dbg5", "safe_mode"), - _PINDEF(0x01ba, "w2", 17, 3, "dpm_emu6", "usba0_ulpiphy_dat0", "uart3_tx_irtx", "gpio_17", "rfbi_hsync0", "dispc2_data17", "hw_dbg6", "safe_mode"), - _PINDEF(0x01bc, "w3", 18, 3, "dpm_emu7", "usba0_ulpiphy_dat1", "uart3_rx_irrx", "gpio_18", "rfbi_cs0", "dispc2_hsync", "hw_dbg7", "safe_mode"), - _PINDEF(0x01be, "w4", 19, 3, "dpm_emu8", "usba0_ulpiphy_dat2", "uart3_rts_sd", "gpio_19", "rfbi_re", "dispc2_pclk", "hw_dbg8", "safe_mode"), - _PINDEF(0x01c0, "y2", 20, 3, "dpm_emu9", "usba0_ulpiphy_dat3", "uart3_cts_rctx", "gpio_20", "rfbi_we", "dispc2_vsync", "hw_dbg9", "safe_mode"), - _PINDEF(0x01c2, "y3", 21, 3, "dpm_emu10", "usba0_ulpiphy_dat4", NULL, "gpio_21", "rfbi_a0", "dispc2_de", "hw_dbg10", "safe_mode"), - _PINDEF(0x01c4, "y4", 22, 3, "dpm_emu11", "usba0_ulpiphy_dat5", NULL, "gpio_22", "rfbi_data8", "dispc2_data8", "hw_dbg11", "safe_mode"), - _PINDEF(0x01c6, "aa1", 23, 3, "dpm_emu12", "usba0_ulpiphy_dat6", NULL, "gpio_23", "rfbi_data7", "dispc2_data7", "hw_dbg12", "safe_mode"), - _PINDEF(0x01c8, "aa2", 24, 3, "dpm_emu13", "usba0_ulpiphy_dat7", NULL, "gpio_24", "rfbi_data6", "dispc2_data6", "hw_dbg13", "safe_mode"), - _PINDEF(0x01ca, "aa3", 25, 3, "dpm_emu14", "sys_drm_msecure", "uart1_rx", "gpio_25", "rfbi_data5", "dispc2_data5", "hw_dbg14", "safe_mode"), - _PINDEF(0x01cc, "aa4", 26, 3, "dpm_emu15", "sys_secure_indicator", NULL, "gpio_26", "rfbi_data4", "dispc2_data4", "hw_dbg15", "safe_mode"), - _PINDEF(0x01ce, "ab2", 27, 3, "dpm_emu16", "dmtimer8_pwm_evt", "dsi1_te0", "gpio_27", "rfbi_data3", "dispc2_data3", "hw_dbg16", "safe_mode"), - _PINDEF(0x01d0, "ab3", 28, 3, "dpm_emu17", "dmtimer9_pwm_evt", "dsi1_te1", "gpio_28", "rfbi_data2", "dispc2_data2", "hw_dbg17", "safe_mode"), - _PINDEF(0x01d2, "ab4", 190, 3, "dpm_emu18", "dmtimer10_pwm_evt", "dsi2_te0", "gpio_190", "rfbi_data1", "dispc2_data1", "hw_dbg18", "safe_mode"), - _PINDEF(0x01d4, "ac4", 191, 3, "dpm_emu19", "dmtimer11_pwm_evt", "dsi2_te1", "gpio_191", "rfbi_data0", "dispc2_data0", "hw_dbg19", "safe_mode"), +const static struct ti_pinmux_padconf ti_padconf_devmap[] = { + _PINDEF(0x0000, "c12", 0, 0, "gpmc_ad0", "sdmmc2_dat0", NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x0002, "d12", 0, 0, "gpmc_ad1", "sdmmc2_dat1", NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x0004, "c13", 0, 0, "gpmc_ad2", "sdmmc2_dat2", NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x0006, "d13", 0, 0, "gpmc_ad3", "sdmmc2_dat3", NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x0008, "c15", 0, 0, "gpmc_ad4", "sdmmc2_dat4", "sdmmc2_dir_dat0", NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x000a, "d15", 0, 0, "gpmc_ad5", "sdmmc2_dat5", "sdmmc2_dir_dat1", NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x000c, "a16", 0, 0, "gpmc_ad6", "sdmmc2_dat6", "sdmmc2_dir_cmd", NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x000e, "b16", 0, 0, "gpmc_ad7", "sdmmc2_dat7", "sdmmc2_clk_fdbk", NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x0010, "c16", 32, 3, "gpmc_ad8", "kpd_row0", "c2c_data15", "gpio_32", NULL, "sdmmc1_dat0", NULL, NULL), + _PINDEF(0x0012, "d16", 33, 3, "gpmc_ad9", "kpd_row1", "c2c_data14", "gpio_33", NULL, "sdmmc1_dat1", NULL, NULL), + _PINDEF(0x0014, "c17", 34, 3, "gpmc_ad10", "kpd_row2", "c2c_data13", "gpio_34", NULL, "sdmmc1_dat2", NULL, NULL), + _PINDEF(0x0016, "d17", 35, 3, "gpmc_ad11", "kpd_row3", "c2c_data12", "gpio_35", NULL, "sdmmc1_dat3", NULL, NULL), + _PINDEF(0x0018, "c18", 36, 3, "gpmc_ad12", "kpd_col0", "c2c_data11", "gpio_36", NULL, "sdmmc1_dat4", NULL, NULL), + _PINDEF(0x001a, "d18", 37, 3, "gpmc_ad13", "kpd_col1", "c2c_data10", "gpio_37", NULL, "sdmmc1_dat5", NULL, NULL), + _PINDEF(0x001c, "c19", 38, 3, "gpmc_ad14", "kpd_col2", "c2c_data9", "gpio_38", NULL, "sdmmc1_dat6", NULL, NULL), + _PINDEF(0x001e, "d19", 39, 3, "gpmc_ad15", "kpd_col3", "c2c_data8", "gpio_39", NULL, "sdmmc1_dat7", NULL, NULL), + _PINDEF(0x0020, "b17", 40, 3, "gpmc_a16", "kpd_row4", "c2c_datain0", "gpio_40", "venc_656_data0", NULL, NULL, "safe_mode"), + _PINDEF(0x0022, "a18", 41, 3, "gpmc_a17", "kpd_row5", "c2c_datain1", "gpio_41", "venc_656_data1", NULL, NULL, "safe_mode"), + _PINDEF(0x0024, "b18", 42, 3, "gpmc_a18", "kpd_row6", "c2c_datain2", "gpio_42", "venc_656_data2", NULL, NULL, "safe_mode"), + _PINDEF(0x0026, "a19", 43, 3, "gpmc_a19", "kpd_row7", "c2c_datain3", "gpio_43", "venc_656_data3", NULL, NULL, "safe_mode"), + _PINDEF(0x0028, "b19", 44, 3, "gpmc_a20", "kpd_col4", "c2c_datain4", "gpio_44", "venc_656_data4", NULL, NULL, "safe_mode"), + _PINDEF(0x002a, "b20", 45, 3, "gpmc_a21", "kpd_col5", "c2c_datain5", "gpio_45", "venc_656_data5", NULL, NULL, "safe_mode"), + _PINDEF(0x002c, "a21", 46, 3, "gpmc_a22", "kpd_col6", "c2c_datain6", "gpio_46", "venc_656_data6", NULL, NULL, "safe_mode"), + _PINDEF(0x002e, "b21", 47, 3, "gpmc_a23", "kpd_col7", "c2c_datain7", "gpio_47", "venc_656_data7", NULL, NULL, "safe_mode"), + _PINDEF(0x0030, "c20", 48, 3, "gpmc_a24", "kpd_col8", "c2c_clkout0", "gpio_48", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0032, "d20", 49, 3, "gpmc_a25", NULL, "c2c_clkout1", "gpio_49", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0034, "b25", 50, 3, "gpmc_ncs0", NULL, NULL, "gpio_50", "sys_ndmareq0", NULL, NULL, NULL), + _PINDEF(0x0036, "c21", 51, 3, "gpmc_ncs1", NULL, "c2c_dataout6", "gpio_51", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0038, "d21", 52, 3, "gpmc_ncs2", "kpd_row8", "c2c_dataout7", "gpio_52", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x003a, "c22", 53, 3, "gpmc_ncs3", "gpmc_dir", "c2c_dataout4", "gpio_53", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x003c, "c25", 54, 3, "gpmc_nwp", "dsi1_te0", NULL, "gpio_54", "sys_ndmareq1", NULL, NULL, NULL), + _PINDEF(0x003e, "b22", 55, 3, "gpmc_clk", NULL, NULL, "gpio_55", "sys_ndmareq2", "sdmmc1_cmd", NULL, NULL), + _PINDEF(0x0040, "d25", 56, 3, "gpmc_nadv_ale", "dsi1_te1", NULL, "gpio_56", "sys_ndmareq3", "sdmmc1_clk", NULL, NULL), + _PINDEF(0x0042, "b11", 0, 0, "gpmc_noe", "sdmmc2_clk", NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x0044, "b12", 0, 0, "gpmc_nwe", "sdmmc2_cmd", NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x0046, "c23", 59, 3, "gpmc_nbe0_cle", "dsi2_te0", NULL, "gpio_59", NULL, NULL, NULL, NULL), + _PINDEF(0x0048, "d22", 60, 3, "gpmc_nbe1", NULL, "c2c_dataout5", "gpio_60", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x004a, "b26", 61, 3, "gpmc_wait0", "dsi2_te1", NULL, "gpio_61", NULL, NULL, NULL, NULL), + _PINDEF(0x004c, "b23", 62, 3, "gpmc_wait1", NULL, "c2c_dataout2", "gpio_62", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x004e, "d23", 100, 3, "gpmc_wait2", "usbc1_icusb_txen", "c2c_dataout3", "gpio_100", "sys_ndmareq0", NULL, NULL, "safe_mode"), + _PINDEF(0x0050, "a24", 101, 3, "gpmc_ncs4", "dsi1_te0", "c2c_clkin0", "gpio_101", "sys_ndmareq1", NULL, NULL, "safe_mode"), + _PINDEF(0x0052, "b24", 102, 3, "gpmc_ncs5", "dsi1_te1", "c2c_clkin1", "gpio_102", "sys_ndmareq2", NULL, NULL, "safe_mode"), + _PINDEF(0x0054, "c24", 103, 3, "gpmc_ncs6", "dsi2_te0", "c2c_dataout0", "gpio_103", "sys_ndmareq3", NULL, NULL, "safe_mode"), + _PINDEF(0x0056, "d24", 104, 3, "gpmc_ncs7", "dsi2_te1", "c2c_dataout1", "gpio_104", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0058, "b9", 63, 3, "hdmi_hpd", NULL, NULL, "gpio_63", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x005a, "b10", 64, 3, "hdmi_cec", NULL, NULL, "gpio_64", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x005c, "a8", 65, 3, "hdmi_ddc_scl", NULL, NULL, "gpio_65", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x005e, "b8", 66, 3, "hdmi_ddc_sda", NULL, NULL, "gpio_66", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0060, "r26", 0, 0, "csi21_dx0", NULL, NULL, "gpi_67", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0062, "r25", 0, 0, "csi21_dy0", NULL, NULL, "gpi_68", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0064, "t26", 0, 0, "csi21_dx1", NULL, NULL, "gpi_69", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0066, "t25", 0, 0, "csi21_dy1", NULL, NULL, "gpi_70", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0068, "u26", 0, 0, "csi21_dx2", NULL, NULL, "gpi_71", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x006a, "u25", 0, 0, "csi21_dy2", NULL, NULL, "gpi_72", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x006c, "v26", 0, 0, "csi21_dx3", NULL, NULL, "gpi_73", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x006e, "v25", 0, 0, "csi21_dy3", NULL, NULL, "gpi_74", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0070, "w26", 0, 0, "csi21_dx4", NULL, NULL, "gpi_75", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0072, "w25", 0, 0, "csi21_dy4", NULL, NULL, "gpi_76", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0074, "m26", 0, 0, "csi22_dx0", NULL, NULL, "gpi_77", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0076, "m25", 0, 0, "csi22_dy0", NULL, NULL, "gpi_78", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0078, "n26", 0, 0, "csi22_dx1", NULL, NULL, "gpi_79", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x007a, "n25", 0, 0, "csi22_dy1", NULL, NULL, "gpi_80", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x007c, "t27", 81, 3, "cam_shutter", NULL, NULL, "gpio_81", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x007e, "u27", 82, 3, "cam_strobe", NULL, NULL, "gpio_82", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0080, "v27", 83, 3, "cam_globalreset", NULL, NULL, "gpio_83", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0082, "ae18", 84, 3, "usbb1_ulpitll_clk", "hsi1_cawake", NULL, "gpio_84", "usbb1_ulpiphy_clk", NULL, "hw_dbg20", "safe_mode"), + _PINDEF(0x0084, "ag19", 85, 3, "usbb1_ulpitll_stp", "hsi1_cadata", "mcbsp4_clkr", "gpio_85", "usbb1_ulpiphy_stp", "usbb1_mm_rxdp", "hw_dbg21", "safe_mode"), + _PINDEF(0x0086, "af19", 86, 3, "usbb1_ulpitll_dir", "hsi1_caflag", "mcbsp4_fsr", "gpio_86", "usbb1_ulpiphy_dir", NULL, "hw_dbg22", "safe_mode"), + _PINDEF(0x0088, "ae19", 87, 3, "usbb1_ulpitll_nxt", "hsi1_acready", "mcbsp4_fsx", "gpio_87", "usbb1_ulpiphy_nxt", "usbb1_mm_rxdm", "hw_dbg23", "safe_mode"), + _PINDEF(0x008a, "af18", 88, 3, "usbb1_ulpitll_dat0", "hsi1_acwake", "mcbsp4_clkx", "gpio_88", "usbb1_ulpiphy_dat0", "usbb1_mm_txen", "hw_dbg24", "safe_mode"), + _PINDEF(0x008c, "ag18", 89, 3, "usbb1_ulpitll_dat1", "hsi1_acdata", "mcbsp4_dx", "gpio_89", "usbb1_ulpiphy_dat1", "usbb1_mm_txdat", "hw_dbg25", "safe_mode"), + _PINDEF(0x008e, "ae17", 90, 3, "usbb1_ulpitll_dat2", "hsi1_acflag", "mcbsp4_dr", "gpio_90", "usbb1_ulpiphy_dat2", "usbb1_mm_txse0", "hw_dbg26", "safe_mode"), + _PINDEF(0x0090, "af17", 91, 3, "usbb1_ulpitll_dat3", "hsi1_caready", NULL, "gpio_91", "usbb1_ulpiphy_dat3", "usbb1_mm_rxrcv", "hw_dbg27", "safe_mode"), + _PINDEF(0x0092, "ah17", 92, 3, "usbb1_ulpitll_dat4", "dmtimer8_pwm_evt", "abe_mcbsp3_dr", "gpio_92", "usbb1_ulpiphy_dat4", NULL, "hw_dbg28", "safe_mode"), + _PINDEF(0x0094, "ae16", 93, 3, "usbb1_ulpitll_dat5", "dmtimer9_pwm_evt", "abe_mcbsp3_dx", "gpio_93", "usbb1_ulpiphy_dat5", NULL, "hw_dbg29", "safe_mode"), + _PINDEF(0x0096, "af16", 94, 3, "usbb1_ulpitll_dat6", "dmtimer10_pwm_evt", "abe_mcbsp3_clkx", "gpio_94", "usbb1_ulpiphy_dat6", "abe_dmic_din3", "hw_dbg30", "safe_mode"), + _PINDEF(0x0098, "ag16", 95, 3, "usbb1_ulpitll_dat7", "dmtimer11_pwm_evt", "abe_mcbsp3_fsx", "gpio_95", "usbb1_ulpiphy_dat7", "abe_dmic_clk3", "hw_dbg31", "safe_mode"), + _PINDEF(0x009a, "af14", 96, 3, "usbb1_hsic_data", NULL, NULL, "gpio_96", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x009c, "ae14", 97, 3, "usbb1_hsic_strobe", NULL, NULL, "gpio_97", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x009e, "h2", 98, 3, "usbc1_icusb_dp", NULL, NULL, "gpio_98", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00a0, "h3", 99, 3, "usbc1_icusb_dm", NULL, NULL, "gpio_99", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00a2, "d2", 100, 3, "sdmmc1_clk", NULL, "dpm_emu19", "gpio_100", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00a4, "e3", 101, 3, "sdmmc1_cmd", NULL, "uart1_rx", "gpio_101", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00a6, "e4", 102, 3, "sdmmc1_dat0", NULL, "dpm_emu18", "gpio_102", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00a8, "e2", 103, 3, "sdmmc1_dat1", NULL, "dpm_emu17", "gpio_103", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00aa, "e1", 104, 3, "sdmmc1_dat2", NULL, "dpm_emu16", "gpio_104", "jtag_tms_tmsc", NULL, NULL, "safe_mode"), + _PINDEF(0x00ac, "f4", 105, 3, "sdmmc1_dat3", NULL, "dpm_emu15", "gpio_105", "jtag_tck", NULL, NULL, "safe_mode"), + _PINDEF(0x00ae, "f3", 106, 3, "sdmmc1_dat4", NULL, NULL, "gpio_106", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00b0, "f1", 107, 3, "sdmmc1_dat5", NULL, NULL, "gpio_107", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00b2, "g4", 108, 3, "sdmmc1_dat6", NULL, NULL, "gpio_108", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00b4, "g3", 109, 3, "sdmmc1_dat7", NULL, NULL, "gpio_109", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00b6, "ad27", 110, 3, "abe_mcbsp2_clkx", "mcspi2_clk", "abe_mcasp_ahclkx", "gpio_110", "usbb2_mm_rxdm", NULL, NULL, "safe_mode"), + _PINDEF(0x00b8, "ad26", 111, 3, "abe_mcbsp2_dr", "mcspi2_somi", "abe_mcasp_axr", "gpio_111", "usbb2_mm_rxdp", NULL, NULL, "safe_mode"), + _PINDEF(0x00ba, "ad25", 112, 3, "abe_mcbsp2_dx", "mcspi2_simo", "abe_mcasp_amute", "gpio_112", "usbb2_mm_rxrcv", NULL, NULL, "safe_mode"), + _PINDEF(0x00bc, "ac28", 113, 3, "abe_mcbsp2_fsx", "mcspi2_cs0", "abe_mcasp_afsx", "gpio_113", "usbb2_mm_txen", NULL, NULL, "safe_mode"), + _PINDEF(0x00be, "ac26", 114, 3, "abe_mcbsp1_clkx", "abe_slimbus1_clock", NULL, "gpio_114", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00c0, "ac25", 115, 3, "abe_mcbsp1_dr", "abe_slimbus1_data", NULL, "gpio_115", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00c2, "ab25", 116, 3, "abe_mcbsp1_dx", "sdmmc3_dat2", "abe_mcasp_aclkx", "gpio_116", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00c4, "ac27", 117, 3, "abe_mcbsp1_fsx", "sdmmc3_dat3", "abe_mcasp_amutein", "gpio_117", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00c6, "ag25", 0, 0, "abe_pdm_ul_data", "abe_mcbsp3_dr", NULL, NULL, NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00c8, "af25", 0, 0, "abe_pdm_dl_data", "abe_mcbsp3_dx", NULL, NULL, NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00ca, "ae25", 0, 0, "abe_pdm_frame", "abe_mcbsp3_clkx", NULL, NULL, NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00cc, "af26", 0, 0, "abe_pdm_lb_clk", "abe_mcbsp3_fsx", NULL, NULL, NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00ce, "ah26", 118, 3, "abe_clks", NULL, NULL, "gpio_118", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00d0, "ae24", 119, 3, "abe_dmic_clk1", NULL, NULL, "gpio_119", "usbb2_mm_txse0", "uart4_cts", NULL, "safe_mode"), + _PINDEF(0x00d2, "af24", 120, 3, "abe_dmic_din1", NULL, NULL, "gpio_120", "usbb2_mm_txdat", "uart4_rts", NULL, "safe_mode"), + _PINDEF(0x00d4, "ag24", 121, 3, "abe_dmic_din2", "slimbus2_clock", "abe_mcasp_axr", "gpio_121", NULL, "dmtimer11_pwm_evt", NULL, "safe_mode"), + _PINDEF(0x00d6, "ah24", 122, 3, "abe_dmic_din3", "slimbus2_data", "abe_dmic_clk2", "gpio_122", NULL, "dmtimer9_pwm_evt", NULL, "safe_mode"), + _PINDEF(0x00d8, "ab26", 123, 3, "uart2_cts", "sdmmc3_clk", NULL, "gpio_123", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00da, "ab27", 124, 3, "uart2_rts", "sdmmc3_cmd", NULL, "gpio_124", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00dc, "aa25", 125, 3, "uart2_rx", "sdmmc3_dat0", NULL, "gpio_125", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00de, "aa26", 126, 3, "uart2_tx", "sdmmc3_dat1", NULL, "gpio_126", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00e0, "aa27", 127, 3, "hdq_sio", "i2c3_sccb", "i2c2_sccb", "gpio_127", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00e2, "ae28", 0, 0, "i2c1_scl", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x00e4, "ae26", 0, 0, "i2c1_sda", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x00e6, "c26", 128, 3, "i2c2_scl", "uart1_rx", NULL, "gpio_128", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00e8, "d26", 129, 3, "i2c2_sda", "uart1_tx", NULL, "gpio_129", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00ea, "w27", 130, 3, "i2c3_scl", NULL, NULL, "gpio_130", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00ec, "y27", 131, 3, "i2c3_sda", NULL, NULL, "gpio_131", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00ee, "ag21", 132, 3, "i2c4_scl", NULL, NULL, "gpio_132", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00f0, "ah22", 133, 3, "i2c4_sda", NULL, NULL, "gpio_133", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00f2, "af22", 134, 3, "mcspi1_clk", NULL, NULL, "gpio_134", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00f4, "ae22", 135, 3, "mcspi1_somi", NULL, NULL, "gpio_135", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00f6, "ag22", 136, 3, "mcspi1_simo", NULL, NULL, "gpio_136", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00f8, "ae23", 137, 3, "mcspi1_cs0", NULL, NULL, "gpio_137", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00fa, "af23", 138, 3, "mcspi1_cs1", "uart1_rx", NULL, "gpio_138", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00fc, "ag23", 139, 3, "mcspi1_cs2", "uart1_cts", "slimbus2_clock", "gpio_139", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x00fe, "ah23", 140, 3, "mcspi1_cs3", "uart1_rts", "slimbus2_data", "gpio_140", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0100, "f27", 141, 3, "uart3_cts_rctx", "uart1_tx", NULL, "gpio_141", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0102, "f28", 142, 3, "uart3_rts_sd", NULL, NULL, "gpio_142", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0104, "g27", 143, 3, "uart3_rx_irrx", "dmtimer8_pwm_evt", NULL, "gpio_143", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0106, "g28", 144, 3, "uart3_tx_irtx", "dmtimer9_pwm_evt", NULL, "gpio_144", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0108, "ae5", 145, 3, "sdmmc5_clk", "mcspi2_clk", "usbc1_icusb_dp", "gpio_145", NULL, "sdmmc2_clk", NULL, "safe_mode"), + _PINDEF(0x010a, "af5", 146, 3, "sdmmc5_cmd", "mcspi2_simo", "usbc1_icusb_dm", "gpio_146", NULL, "sdmmc2_cmd", NULL, "safe_mode"), + _PINDEF(0x010c, "ae4", 147, 3, "sdmmc5_dat0", "mcspi2_somi", "usbc1_icusb_rcv", "gpio_147", NULL, "sdmmc2_dat0", NULL, "safe_mode"), + _PINDEF(0x010e, "af4", 148, 3, "sdmmc5_dat1", NULL, "usbc1_icusb_txen", "gpio_148", NULL, "sdmmc2_dat1", NULL, "safe_mode"), + _PINDEF(0x0110, "ag3", 149, 3, "sdmmc5_dat2", "mcspi2_cs1", NULL, "gpio_149", NULL, "sdmmc2_dat2", NULL, "safe_mode"), + _PINDEF(0x0112, "af3", 150, 3, "sdmmc5_dat3", "mcspi2_cs0", NULL, "gpio_150", NULL, "sdmmc2_dat3", NULL, "safe_mode"), + _PINDEF(0x0114, "ae21", 151, 3, "mcspi4_clk", "sdmmc4_clk", "kpd_col6", "gpio_151", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0116, "af20", 152, 3, "mcspi4_simo", "sdmmc4_cmd", "kpd_col7", "gpio_152", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0118, "af21", 153, 3, "mcspi4_somi", "sdmmc4_dat0", "kpd_row6", "gpio_153", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x011a, "ae20", 154, 3, "mcspi4_cs0", "sdmmc4_dat3", "kpd_row7", "gpio_154", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x011c, "ag20", 155, 3, "uart4_rx", "sdmmc4_dat2", "kpd_row8", "gpio_155", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x011e, "ah19", 156, 3, "uart4_tx", "sdmmc4_dat1", "kpd_col8", "gpio_156", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0120, "ag12", 157, 3, "usbb2_ulpitll_clk", "usbb2_ulpiphy_clk", "sdmmc4_cmd", "gpio_157", "hsi2_cawake", NULL, NULL, "safe_mode"), + _PINDEF(0x0122, "af12", 158, 3, "usbb2_ulpitll_stp", "usbb2_ulpiphy_stp", "sdmmc4_clk", "gpio_158", "hsi2_cadata", "dispc2_data23", NULL, "safe_mode"), + _PINDEF(0x0124, "ae12", 159, 3, "usbb2_ulpitll_dir", "usbb2_ulpiphy_dir", "sdmmc4_dat0", "gpio_159", "hsi2_caflag", "dispc2_data22", NULL, "safe_mode"), + _PINDEF(0x0126, "ag13", 160, 3, "usbb2_ulpitll_nxt", "usbb2_ulpiphy_nxt", "sdmmc4_dat1", "gpio_160", "hsi2_acready", "dispc2_data21", NULL, "safe_mode"), + _PINDEF(0x0128, "ae11", 161, 3, "usbb2_ulpitll_dat0", "usbb2_ulpiphy_dat0", "sdmmc4_dat2", "gpio_161", "hsi2_acwake", "dispc2_data20", "usbb2_mm_txen", "safe_mode"), + _PINDEF(0x012a, "af11", 162, 3, "usbb2_ulpitll_dat1", "usbb2_ulpiphy_dat1", "sdmmc4_dat3", "gpio_162", "hsi2_acdata", "dispc2_data19", "usbb2_mm_txdat", "safe_mode"), + _PINDEF(0x012c, "ag11", 163, 3, "usbb2_ulpitll_dat2", "usbb2_ulpiphy_dat2", "sdmmc3_dat2", "gpio_163", "hsi2_acflag", "dispc2_data18", "usbb2_mm_txse0", "safe_mode"), + _PINDEF(0x012e, "ah11", 164, 3, "usbb2_ulpitll_dat3", "usbb2_ulpiphy_dat3", "sdmmc3_dat1", "gpio_164", "hsi2_caready", "dispc2_data15", "rfbi_data15", "safe_mode"), + _PINDEF(0x0130, "ae10", 165, 3, "usbb2_ulpitll_dat4", "usbb2_ulpiphy_dat4", "sdmmc3_dat0", "gpio_165", "mcspi3_somi", "dispc2_data14", "rfbi_data14", "safe_mode"), + _PINDEF(0x0132, "af10", 166, 3, "usbb2_ulpitll_dat5", "usbb2_ulpiphy_dat5", "sdmmc3_dat3", "gpio_166", "mcspi3_cs0", "dispc2_data13", "rfbi_data13", "safe_mode"), + _PINDEF(0x0134, "ag10", 167, 3, "usbb2_ulpitll_dat6", "usbb2_ulpiphy_dat6", "sdmmc3_cmd", "gpio_167", "mcspi3_simo", "dispc2_data12", "rfbi_data12", "safe_mode"), + _PINDEF(0x0136, "ae9", 168, 3, "usbb2_ulpitll_dat7", "usbb2_ulpiphy_dat7", "sdmmc3_clk", "gpio_168", "mcspi3_clk", "dispc2_data11", "rfbi_data11", "safe_mode"), + _PINDEF(0x0138, "af13", 169, 3, "usbb2_hsic_data", NULL, NULL, "gpio_169", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x013a, "ae13", 170, 3, "usbb2_hsic_strobe", NULL, NULL, "gpio_170", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x013c, "g26", 171, 3, "kpd_col3", "kpd_col0", NULL, "gpio_171", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x013e, "g25", 172, 3, "kpd_col4", "kpd_col1", NULL, "gpio_172", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0140, "h26", 173, 3, "kpd_col5", "kpd_col2", NULL, "gpio_173", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0142, "h25", 174, 3, "kpd_col0", "kpd_col3", NULL, "gpio_174", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0144, "j27", 0, 0, "kpd_col1", "kpd_col4", NULL, "gpio_0", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0146, "h27", 1, 3, "kpd_col2", "kpd_col5", NULL, "gpio_1", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0148, "j26", 175, 3, "kpd_row3", "kpd_row0", NULL, "gpio_175", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x014a, "j25", 176, 3, "kpd_row4", "kpd_row1", NULL, "gpio_176", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x014c, "k26", 177, 3, "kpd_row5", "kpd_row2", NULL, "gpio_177", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x014e, "k25", 178, 3, "kpd_row0", "kpd_row3", NULL, "gpio_178", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0150, "l27", 2, 3, "kpd_row1", "kpd_row4", NULL, "gpio_2", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0152, "k27", 3, 3, "kpd_row2", "kpd_row5", NULL, "gpio_3", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0154, "c3", 0, 0, "usba0_otg_ce", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PINDEF(0x0156, "b5", 0, 0, "usba0_otg_dp", "uart3_rx_irrx", "uart2_rx", NULL, NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0158, "b4", 0, 0, "usba0_otg_dm", "uart3_tx_irtx", "uart2_tx", NULL, NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x015a, "aa28", 181, 3, "fref_clk1_out", NULL, NULL, "gpio_181", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x015c, "y28", 182, 3, "fref_clk2_out", NULL, NULL, "gpio_182", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x015e, "ae6", 0, 0, "sys_nirq1", NULL, NULL, NULL, NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0160, "af6", 183, 3, "sys_nirq2", NULL, NULL, "gpio_183", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0162, "f26", 184, 3, "sys_boot0", NULL, NULL, "gpio_184", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0164, "e27", 185, 3, "sys_boot1", NULL, NULL, "gpio_185", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0166, "e26", 186, 3, "sys_boot2", NULL, NULL, "gpio_186", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x0168, "e25", 187, 3, "sys_boot3", NULL, NULL, "gpio_187", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x016a, "d28", 188, 3, "sys_boot4", NULL, NULL, "gpio_188", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x016c, "d27", 189, 3, "sys_boot5", NULL, NULL, "gpio_189", NULL, NULL, NULL, "safe_mode"), + _PINDEF(0x016e, "m2", 11, 3, "dpm_emu0", NULL, NULL, "gpio_11", NULL, NULL, "hw_dbg0", "safe_mode"), + _PINDEF(0x0170, "n2", 12, 3, "dpm_emu1", NULL, NULL, "gpio_12", NULL, NULL, "hw_dbg1", "safe_mode"), + _PINDEF(0x0172, "p2", 13, 3, "dpm_emu2", "usba0_ulpiphy_clk", NULL, "gpio_13", NULL, "dispc2_fid", "hw_dbg2", "safe_mode"), + _PINDEF(0x0174, "v1", 14, 3, "dpm_emu3", "usba0_ulpiphy_stp", NULL, "gpio_14", "rfbi_data10", "dispc2_data10", "hw_dbg3", "safe_mode"), + _PINDEF(0x0176, "v2", 15, 3, "dpm_emu4", "usba0_ulpiphy_dir", NULL, "gpio_15", "rfbi_data9", "dispc2_data9", "hw_dbg4", "safe_mode"), + _PINDEF(0x0178, "w1", 16, 3, "dpm_emu5", "usba0_ulpiphy_nxt", NULL, "gpio_16", "rfbi_te_vsync0", "dispc2_data16", "hw_dbg5", "safe_mode"), + _PINDEF(0x017a, "w2", 17, 3, "dpm_emu6", "usba0_ulpiphy_dat0", "uart3_tx_irtx", "gpio_17", "rfbi_hsync0", "dispc2_data17", "hw_dbg6", "safe_mode"), + _PINDEF(0x017c, "w3", 18, 3, "dpm_emu7", "usba0_ulpiphy_dat1", "uart3_rx_irrx", "gpio_18", "rfbi_cs0", "dispc2_hsync", "hw_dbg7", "safe_mode"), + _PINDEF(0x017e, "w4", 19, 3, "dpm_emu8", "usba0_ulpiphy_dat2", "uart3_rts_sd", "gpio_19", "rfbi_re", "dispc2_pclk", "hw_dbg8", "safe_mode"), + _PINDEF(0x0180, "y2", 20, 3, "dpm_emu9", "usba0_ulpiphy_dat3", "uart3_cts_rctx", "gpio_20", "rfbi_we", "dispc2_vsync", "hw_dbg9", "safe_mode"), + _PINDEF(0x0182, "y3", 21, 3, "dpm_emu10", "usba0_ulpiphy_dat4", NULL, "gpio_21", "rfbi_a0", "dispc2_de", "hw_dbg10", "safe_mode"), + _PINDEF(0x0184, "y4", 22, 3, "dpm_emu11", "usba0_ulpiphy_dat5", NULL, "gpio_22", "rfbi_data8", "dispc2_data8", "hw_dbg11", "safe_mode"), + _PINDEF(0x0186, "aa1", 23, 3, "dpm_emu12", "usba0_ulpiphy_dat6", NULL, "gpio_23", "rfbi_data7", "dispc2_data7", "hw_dbg12", "safe_mode"), + _PINDEF(0x0188, "aa2", 24, 3, "dpm_emu13", "usba0_ulpiphy_dat7", NULL, "gpio_24", "rfbi_data6", "dispc2_data6", "hw_dbg13", "safe_mode"), + _PINDEF(0x018a, "aa3", 25, 3, "dpm_emu14", "sys_drm_msecure", "uart1_rx", "gpio_25", "rfbi_data5", "dispc2_data5", "hw_dbg14", "safe_mode"), + _PINDEF(0x018c, "aa4", 26, 3, "dpm_emu15", "sys_secure_indicator", NULL, "gpio_26", "rfbi_data4", "dispc2_data4", "hw_dbg15", "safe_mode"), + _PINDEF(0x018e, "ab2", 27, 3, "dpm_emu16", "dmtimer8_pwm_evt", "dsi1_te0", "gpio_27", "rfbi_data3", "dispc2_data3", "hw_dbg16", "safe_mode"), + _PINDEF(0x0190, "ab3", 28, 3, "dpm_emu17", "dmtimer9_pwm_evt", "dsi1_te1", "gpio_28", "rfbi_data2", "dispc2_data2", "hw_dbg17", "safe_mode"), + _PINDEF(0x0192, "ab4", 190, 3, "dpm_emu18", "dmtimer10_pwm_evt", "dsi2_te0", "gpio_190", "rfbi_data1", "dispc2_data1", "hw_dbg18", "safe_mode"), + _PINDEF(0x0194, "ac4", 191, 3, "dpm_emu19", "dmtimer11_pwm_evt", "dsi2_te1", "gpio_191", "rfbi_data0", "dispc2_data0", "hw_dbg19", "safe_mode"), { .ballname = NULL }, }; -const struct ti_scm_device ti_scm_dev = { +const struct ti_pinmux_device ti_pinmux_dev = { .padconf_muxmode_mask = CONTROL_PADCONF_MUXMODE_MASK, .padconf_sate_mask = CONTROL_PADCONF_SATE_MASK, .padstate = ti_padstate_devmap, .padconf = ti_padconf_devmap, }; Index: head/sys/arm/ti/ti_adc.c =================================================================== --- head/sys/arm/ti/ti_adc.c (revision 283275) +++ head/sys/arm/ti/ti_adc.c (revision 283276) @@ -1,594 +1,594 @@ /*- * Copyright 2014 Luiz Otavio O Souza * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Define our 8 steps, one for each input channel. */ static struct ti_adc_input ti_adc_inputs[TI_ADC_NPINS] = { { .stepconfig = ADC_STEPCFG1, .stepdelay = ADC_STEPDLY1 }, { .stepconfig = ADC_STEPCFG2, .stepdelay = ADC_STEPDLY2 }, { .stepconfig = ADC_STEPCFG3, .stepdelay = ADC_STEPDLY3 }, { .stepconfig = ADC_STEPCFG4, .stepdelay = ADC_STEPDLY4 }, { .stepconfig = ADC_STEPCFG5, .stepdelay = ADC_STEPDLY5 }, { .stepconfig = ADC_STEPCFG6, .stepdelay = ADC_STEPDLY6 }, { .stepconfig = ADC_STEPCFG7, .stepdelay = ADC_STEPDLY7 }, { .stepconfig = ADC_STEPCFG8, .stepdelay = ADC_STEPDLY8 }, }; static int ti_adc_samples[5] = { 0, 2, 4, 8, 16 }; static void ti_adc_enable(struct ti_adc_softc *sc) { TI_ADC_LOCK_ASSERT(sc); if (sc->sc_last_state == 1) return; /* Enable the FIFO0 threshold and the end of sequence interrupt. */ ADC_WRITE4(sc, ADC_IRQENABLE_SET, ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ); /* Enable the ADC. Run thru enabled steps, start the conversions. */ ADC_WRITE4(sc, ADC_CTRL, ADC_READ4(sc, ADC_CTRL) | ADC_CTRL_ENABLE); sc->sc_last_state = 1; } static void ti_adc_disable(struct ti_adc_softc *sc) { int count; uint32_t data; TI_ADC_LOCK_ASSERT(sc); if (sc->sc_last_state == 0) return; /* Disable all the enabled steps. */ ADC_WRITE4(sc, ADC_STEPENABLE, 0); /* Disable the ADC. */ ADC_WRITE4(sc, ADC_CTRL, ADC_READ4(sc, ADC_CTRL) & ~ADC_CTRL_ENABLE); /* Disable the FIFO0 threshold and the end of sequence interrupt. */ ADC_WRITE4(sc, ADC_IRQENABLE_CLR, ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ); /* ACK any pending interrupt. */ ADC_WRITE4(sc, ADC_IRQSTATUS, ADC_READ4(sc, ADC_IRQSTATUS)); /* Drain the FIFO data. */ count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; while (count > 0) { data = ADC_READ4(sc, ADC_FIFO0DATA); count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; } sc->sc_last_state = 0; } static int ti_adc_setup(struct ti_adc_softc *sc) { int ain; uint32_t enabled; TI_ADC_LOCK_ASSERT(sc); /* Check for enabled inputs. */ enabled = 0; for (ain = 0; ain < TI_ADC_NPINS; ain++) { if (ti_adc_inputs[ain].enable) enabled |= (1U << (ain + 1)); } /* Set the ADC global status. */ if (enabled != 0) { ti_adc_enable(sc); /* Update the enabled steps. */ if (enabled != ADC_READ4(sc, ADC_STEPENABLE)) ADC_WRITE4(sc, ADC_STEPENABLE, enabled); } else ti_adc_disable(sc); return (0); } static void ti_adc_input_setup(struct ti_adc_softc *sc, int32_t ain) { struct ti_adc_input *input; uint32_t reg, val; TI_ADC_LOCK_ASSERT(sc); input = &ti_adc_inputs[ain]; reg = input->stepconfig; val = ADC_READ4(sc, reg); /* Set single ended operation. */ val &= ~ADC_STEP_DIFF_CNTRL; /* Set the negative voltage reference. */ val &= ~ADC_STEP_RFM_MSK; val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT; /* Set the positive voltage reference. */ val &= ~ADC_STEP_RFP_MSK; val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT; /* Set the samples average. */ val &= ~ADC_STEP_AVG_MSK; val |= input->samples << ADC_STEP_AVG_SHIFT; /* Select the desired input. */ val &= ~ADC_STEP_INP_MSK; val |= ain << ADC_STEP_INP_SHIFT; /* Set the ADC to one-shot mode. */ val &= ~ADC_STEP_MODE_MSK; ADC_WRITE4(sc, reg, val); } static void ti_adc_reset(struct ti_adc_softc *sc) { int ain; TI_ADC_LOCK_ASSERT(sc); /* Disable all the inputs. */ for (ain = 0; ain < TI_ADC_NPINS; ain++) ti_adc_inputs[ain].enable = 0; } static int ti_adc_clockdiv_proc(SYSCTL_HANDLER_ARGS) { int error, reg; struct ti_adc_softc *sc; sc = (struct ti_adc_softc *)arg1; TI_ADC_LOCK(sc); reg = (int)ADC_READ4(sc, ADC_CLKDIV) + 1; TI_ADC_UNLOCK(sc); error = sysctl_handle_int(oidp, ®, sizeof(reg), req); if (error != 0 || req->newptr == NULL) return (error); /* * The actual written value is the prescaler setting - 1. * Enforce a minimum value of 10 (i.e. 9) which limits the maximum * ADC clock to ~2.4Mhz (CLK_M_OSC / 10). */ reg--; if (reg < 9) reg = 9; if (reg > USHRT_MAX) reg = USHRT_MAX; TI_ADC_LOCK(sc); /* Disable the ADC. */ ti_adc_disable(sc); /* Update the ADC prescaler setting. */ ADC_WRITE4(sc, ADC_CLKDIV, reg); /* Enable the ADC again. */ ti_adc_setup(sc); TI_ADC_UNLOCK(sc); return (0); } static int ti_adc_enable_proc(SYSCTL_HANDLER_ARGS) { int error; int32_t enable; struct ti_adc_softc *sc; struct ti_adc_input *input; input = (struct ti_adc_input *)arg1; sc = input->sc; enable = input->enable; error = sysctl_handle_int(oidp, &enable, sizeof(enable), req); if (error != 0 || req->newptr == NULL) return (error); if (enable) enable = 1; TI_ADC_LOCK(sc); /* Setup the ADC as needed. */ if (input->enable != enable) { input->enable = enable; ti_adc_setup(sc); if (input->enable == 0) input->value = 0; } TI_ADC_UNLOCK(sc); return (0); } static int ti_adc_open_delay_proc(SYSCTL_HANDLER_ARGS) { int error, reg; struct ti_adc_softc *sc; struct ti_adc_input *input; input = (struct ti_adc_input *)arg1; sc = input->sc; TI_ADC_LOCK(sc); reg = (int)ADC_READ4(sc, input->stepdelay) & ADC_STEP_OPEN_DELAY; TI_ADC_UNLOCK(sc); error = sysctl_handle_int(oidp, ®, sizeof(reg), req); if (error != 0 || req->newptr == NULL) return (error); if (reg < 0) reg = 0; TI_ADC_LOCK(sc); ADC_WRITE4(sc, input->stepdelay, reg & ADC_STEP_OPEN_DELAY); TI_ADC_UNLOCK(sc); return (0); } static int ti_adc_samples_avg_proc(SYSCTL_HANDLER_ARGS) { int error, samples, i; struct ti_adc_softc *sc; struct ti_adc_input *input; input = (struct ti_adc_input *)arg1; sc = input->sc; if (input->samples > nitems(ti_adc_samples)) input->samples = nitems(ti_adc_samples); samples = ti_adc_samples[input->samples]; error = sysctl_handle_int(oidp, &samples, 0, req); if (error != 0 || req->newptr == NULL) return (error); TI_ADC_LOCK(sc); if (samples != ti_adc_samples[input->samples]) { input->samples = 0; for (i = 0; i < nitems(ti_adc_samples); i++) if (samples >= ti_adc_samples[i]) input->samples = i; ti_adc_input_setup(sc, input->input); } TI_ADC_UNLOCK(sc); return (error); } static void ti_adc_read_data(struct ti_adc_softc *sc) { int count, ain; struct ti_adc_input *input; uint32_t data; TI_ADC_LOCK_ASSERT(sc); /* Read the available data. */ count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; while (count > 0) { data = ADC_READ4(sc, ADC_FIFO0DATA); ain = (data & ADC_FIFO_STEP_ID_MSK) >> ADC_FIFO_STEP_ID_SHIFT; input = &ti_adc_inputs[ain]; if (input->enable == 0) input->value = 0; else input->value = (int32_t)(data & ADC_FIFO_DATA_MSK); count = ADC_READ4(sc, ADC_FIFO0COUNT) & ADC_FIFO_COUNT_MSK; } } static void ti_adc_intr(void *arg) { struct ti_adc_softc *sc; uint32_t status; sc = (struct ti_adc_softc *)arg; status = ADC_READ4(sc, ADC_IRQSTATUS); if (status == 0) return; if (status & ~(ADC_IRQ_FIFO0_THRES | ADC_IRQ_END_OF_SEQ)) device_printf(sc->sc_dev, "stray interrupt: %#x\n", status); TI_ADC_LOCK(sc); /* ACK the interrupt. */ ADC_WRITE4(sc, ADC_IRQSTATUS, status); /* Read the available data. */ if (status & ADC_IRQ_FIFO0_THRES) ti_adc_read_data(sc); /* Start the next conversion ? */ if (status & ADC_IRQ_END_OF_SEQ) ti_adc_setup(sc); TI_ADC_UNLOCK(sc); } static void ti_adc_sysctl_init(struct ti_adc_softc *sc) { char pinbuf[3]; struct sysctl_ctx_list *ctx; struct sysctl_oid *tree_node, *inp_node, *inpN_node; struct sysctl_oid_list *tree, *inp_tree, *inpN_tree; int ain; /* * Add per-pin sysctl tree/handlers. */ ctx = device_get_sysctl_ctx(sc->sc_dev); tree_node = device_get_sysctl_tree(sc->sc_dev); tree = SYSCTL_CHILDREN(tree_node); SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "clockdiv", CTLFLAG_RW | CTLTYPE_UINT, sc, 0, ti_adc_clockdiv_proc, "IU", "ADC clock prescaler"); inp_node = SYSCTL_ADD_NODE(ctx, tree, OID_AUTO, "ain", CTLFLAG_RD, NULL, "ADC inputs"); inp_tree = SYSCTL_CHILDREN(inp_node); for (ain = 0; ain < TI_ADC_NPINS; ain++) { snprintf(pinbuf, sizeof(pinbuf), "%d", ain); inpN_node = SYSCTL_ADD_NODE(ctx, inp_tree, OID_AUTO, pinbuf, CTLFLAG_RD, NULL, "ADC input"); inpN_tree = SYSCTL_CHILDREN(inpN_node); SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "enable", CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, ti_adc_enable_proc, "IU", "Enable ADC input"); SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "open_delay", CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, ti_adc_open_delay_proc, "IU", "ADC open delay"); SYSCTL_ADD_PROC(ctx, inpN_tree, OID_AUTO, "samples_avg", CTLFLAG_RW | CTLTYPE_UINT, &ti_adc_inputs[ain], 0, ti_adc_samples_avg_proc, "IU", "ADC samples average"); SYSCTL_ADD_INT(ctx, inpN_tree, OID_AUTO, "input", CTLFLAG_RD, &ti_adc_inputs[ain].value, 0, "Converted raw value for the ADC input"); } } static void ti_adc_inputs_init(struct ti_adc_softc *sc) { int ain; struct ti_adc_input *input; TI_ADC_LOCK(sc); for (ain = 0; ain < TI_ADC_NPINS; ain++) { input = &ti_adc_inputs[ain]; input->sc = sc; input->input = ain; input->value = 0; input->enable = 0; input->samples = 0; ti_adc_input_setup(sc, ain); } TI_ADC_UNLOCK(sc); } static void ti_adc_idlestep_init(struct ti_adc_softc *sc) { uint32_t val; val = ADC_READ4(sc, ADC_IDLECONFIG); /* Set single ended operation. */ val &= ~ADC_STEP_DIFF_CNTRL; /* Set the negative voltage reference. */ val &= ~ADC_STEP_RFM_MSK; val |= ADC_STEP_RFM_VREFN << ADC_STEP_RFM_SHIFT; /* Set the positive voltage reference. */ val &= ~ADC_STEP_RFP_MSK; val |= ADC_STEP_RFP_VREFP << ADC_STEP_RFP_SHIFT; /* Connect the input to VREFN. */ val &= ~ADC_STEP_INP_MSK; val |= ADC_STEP_IN_VREFN << ADC_STEP_INP_SHIFT; ADC_WRITE4(sc, ADC_IDLECONFIG, val); } static int ti_adc_probe(device_t dev) { - if (!ofw_bus_is_compatible(dev, "ti,adc")) + if (!ofw_bus_is_compatible(dev, "ti,am3359-tscadc")) return (ENXIO); device_set_desc(dev, "TI ADC controller"); return (BUS_PROBE_DEFAULT); } static int ti_adc_attach(device_t dev) { int err, rid; struct ti_adc_softc *sc; uint32_t reg, rev; sc = device_get_softc(dev); sc->sc_dev = dev; rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_mem_res) { device_printf(dev, "cannot allocate memory window\n"); return (ENXIO); } rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (!sc->sc_irq_res) { bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); device_printf(dev, "cannot allocate interrupt\n"); return (ENXIO); } if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, ti_adc_intr, sc, &sc->sc_intrhand) != 0) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); device_printf(dev, "Unable to setup the irq handler.\n"); return (ENXIO); } /* Activate the ADC_TSC module. */ err = ti_prcm_clk_enable(TSC_ADC_CLK); if (err) return (err); /* Check the ADC revision. */ rev = ADC_READ4(sc, ADC_REVISION); device_printf(dev, "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n", (rev & ADC_REV_SCHEME_MSK) >> ADC_REV_SCHEME_SHIFT, (rev & ADC_REV_FUNC_MSK) >> ADC_REV_FUNC_SHIFT, (rev & ADC_REV_RTL_MSK) >> ADC_REV_RTL_SHIFT, (rev & ADC_REV_MAJOR_MSK) >> ADC_REV_MAJOR_SHIFT, rev & ADC_REV_MINOR_MSK, (rev & ADC_REV_CUSTOM_MSK) >> ADC_REV_CUSTOM_SHIFT); /* * Disable the step write protect and make it store the step ID for * the captured data on FIFO. */ reg = ADC_READ4(sc, ADC_CTRL); ADC_WRITE4(sc, ADC_CTRL, reg | ADC_CTRL_STEP_WP | ADC_CTRL_STEP_ID); /* * Set the ADC prescaler to 2400 (yes, the actual value written here * is 2400 - 1). * This sets the ADC clock to ~10Khz (CLK_M_OSC / 2400). */ ADC_WRITE4(sc, ADC_CLKDIV, 2399); TI_ADC_LOCK_INIT(sc); ti_adc_idlestep_init(sc); ti_adc_inputs_init(sc); ti_adc_sysctl_init(sc); return (0); } static int ti_adc_detach(device_t dev) { struct ti_adc_softc *sc; sc = device_get_softc(dev); /* Turn off the ADC. */ TI_ADC_LOCK(sc); ti_adc_reset(sc); ti_adc_setup(sc); TI_ADC_UNLOCK(sc); TI_ADC_LOCK_DESTROY(sc); if (sc->sc_intrhand) bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); if (sc->sc_irq_res) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); if (sc->sc_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); return (bus_generic_detach(dev)); } static device_method_t ti_adc_methods[] = { DEVMETHOD(device_probe, ti_adc_probe), DEVMETHOD(device_attach, ti_adc_attach), DEVMETHOD(device_detach, ti_adc_detach), DEVMETHOD_END }; static driver_t ti_adc_driver = { "ti_adc", ti_adc_methods, sizeof(struct ti_adc_softc), }; static devclass_t ti_adc_devclass; DRIVER_MODULE(ti_adc, simplebus, ti_adc_driver, ti_adc_devclass, 0, 0); MODULE_VERSION(ti_adc, 1); MODULE_DEPEND(ti_adc, simplebus, 1, 1, 1); Index: head/sys/arm/ti/ti_common.c =================================================================== --- head/sys/arm/ti/ti_common.c (revision 283275) +++ head/sys/arm/ti/ti_common.c (revision 283276) @@ -1,95 +1,80 @@ /*- * Copyright (C) 2008-2011 MARVELL INTERNATIONAL LTD. * All rights reserved. * * Developed by Semihalf. * * 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. * 3. Neither the name of MARVELL nor the names of contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY 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 AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include +#include #include struct fdt_fixup_entry fdt_fixup_table[] = { { NULL, NULL } }; -#ifdef SOC_OMAP4 -static int -fdt_gic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, - int *pol) -{ - - if (!fdt_is_compatible(node, "arm,gic")) - return (ENXIO); - - *interrupt = fdt32_to_cpu(intr[0]); - *trig = INTR_TRIGGER_CONFORM; - *pol = INTR_POLARITY_CONFORM; - - return (0); -} -#endif - #ifdef SOC_TI_AM335X static int fdt_aintc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, int *pol) { - if (!fdt_is_compatible(node, "ti,aintc")) + if (!fdt_is_compatible(node, "ti,aintc") && + !fdt_is_compatible(node, "ti,am33xx-intc")) return (ENXIO); *interrupt = fdt32_to_cpu(intr[0]); *trig = INTR_TRIGGER_CONFORM; *pol = INTR_POLARITY_CONFORM; return (0); } #endif fdt_pic_decode_t fdt_pic_table[] = { #ifdef SOC_OMAP4 - &fdt_gic_decode_ic, + &gic_decode_fdt, #endif #ifdef SOC_TI_AM335X &fdt_aintc_decode_ic, #endif NULL }; Index: head/sys/arm/ti/ti_edma3.c =================================================================== --- head/sys/arm/ti/ti_edma3.c (revision 283275) +++ head/sys/arm/ti/ti_edma3.c (revision 283276) @@ -1,428 +1,427 @@ /*- * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (c) 2012 Damjan Marion * 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. * 3. Neither the name of authors nor the names of its contributors may be * used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TI_EDMA3_NUM_TCS 3 #define TI_EDMA3_NUM_IRQS 3 #define TI_EDMA3_NUM_DMA_CHS 64 #define TI_EDMA3_NUM_QDMA_CHS 8 #define TI_EDMA3CC_PID 0x000 #define TI_EDMA3CC_DCHMAP(p) (0x100 + ((p)*4)) #define TI_EDMA3CC_DMAQNUM(n) (0x240 + ((n)*4)) #define TI_EDMA3CC_QDMAQNUM 0x260 #define TI_EDMA3CC_EMCR 0x308 #define TI_EDMA3CC_EMCRH 0x30C #define TI_EDMA3CC_QEMCR 0x314 #define TI_EDMA3CC_CCERR 0x318 #define TI_EDMA3CC_CCERRCLR 0x31C #define TI_EDMA3CC_DRAE(p) (0x340 + ((p)*8)) #define TI_EDMA3CC_DRAEH(p) (0x344 + ((p)*8)) #define TI_EDMA3CC_QRAE(p) (0x380 + ((p)*4)) #define TI_EDMA3CC_S_ESR(p) (0x2010 + ((p)*0x200)) #define TI_EDMA3CC_S_ESRH(p) (0x2014 + ((p)*0x200)) #define TI_EDMA3CC_S_SECR(p) (0x2040 + ((p)*0x200)) #define TI_EDMA3CC_S_SECRH(p) (0x2044 + ((p)*0x200)) #define TI_EDMA3CC_S_EESR(p) (0x2030 + ((p)*0x200)) #define TI_EDMA3CC_S_EESRH(p) (0x2034 + ((p)*0x200)) #define TI_EDMA3CC_S_IESR(p) (0x2060 + ((p)*0x200)) #define TI_EDMA3CC_S_IESRH(p) (0x2064 + ((p)*0x200)) #define TI_EDMA3CC_S_IPR(p) (0x2068 + ((p)*0x200)) #define TI_EDMA3CC_S_IPRH(p) (0x206C + ((p)*0x200)) #define TI_EDMA3CC_S_QEESR(p) (0x208C + ((p)*0x200)) #define TI_EDMA3CC_PARAM_OFFSET 0x4000 #define TI_EDMA3CC_OPT(p) (TI_EDMA3CC_PARAM_OFFSET + 0x0 + ((p)*0x20)) #define TI_EDMA3CC_DMAQNUM_SET(c,q) ((0x7 & (q)) << (((c) % 8) * 4)) #define TI_EDMA3CC_DMAQNUM_CLR(c) (~(0x7 << (((c) % 8) * 4))) #define TI_EDMA3CC_QDMAQNUM_SET(c,q) ((0x7 & (q)) << ((c) * 4)) #define TI_EDMA3CC_QDMAQNUM_CLR(c) (~(0x7 << ((c) * 4))) #define TI_EDMA3CC_OPT_TCC_CLR (~(0x3F000)) #define TI_EDMA3CC_OPT_TCC_SET(p) (((0x3F000 >> 12) & (p)) << 12) struct ti_edma3_softc { device_t sc_dev; - struct resource * mem_res[TI_EDMA3_NUM_TCS+1]; + /* + * We use one-element array in case if we need to add + * mem resources for transfer control windows + */ + struct resource * mem_res[1]; struct resource * irq_res[TI_EDMA3_NUM_IRQS]; void *ih_cookie[TI_EDMA3_NUM_IRQS]; }; static struct ti_edma3_softc *ti_edma3_sc = NULL; static struct resource_spec ti_edma3_mem_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_MEMORY, 1, RF_ACTIVE }, - { SYS_RES_MEMORY, 2, RF_ACTIVE }, - { SYS_RES_MEMORY, 3, RF_ACTIVE }, { -1, 0, 0 } }; static struct resource_spec ti_edma3_irq_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, { SYS_RES_IRQ, 1, RF_ACTIVE }, { SYS_RES_IRQ, 2, RF_ACTIVE }, { -1, 0, 0 } }; /* Read/Write macros */ #define ti_edma3_cc_rd_4(reg) bus_read_4(ti_edma3_sc->mem_res[0], reg) #define ti_edma3_cc_wr_4(reg, val) bus_write_4(ti_edma3_sc->mem_res[0], reg, val) -#define ti_edma3_tc_rd_4(c, reg) bus_read_4(ti_edma3_sc->mem_res[c+1], reg) -#define ti_edma3_tc_wr_4(c, reg, val) bus_write_4(ti_edma3_sc->mem_res[c+1], reg, val) static void ti_edma3_intr_comp(void *arg); static void ti_edma3_intr_mperr(void *arg); static void ti_edma3_intr_err(void *arg); static struct { driver_intr_t *handler; char * description; } ti_edma3_intrs[TI_EDMA3_NUM_IRQS] = { { ti_edma3_intr_comp, "EDMA Completion Interrupt" }, { ti_edma3_intr_mperr, "EDMA Memory Protection Error Interrupt" }, { ti_edma3_intr_err, "EDMA Error Interrupt" }, }; static int ti_edma3_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "ti,edma3")) return (ENXIO); device_set_desc(dev, "TI EDMA Controller"); return (0); } static int ti_edma3_attach(device_t dev) { struct ti_edma3_softc *sc = device_get_softc(dev); uint32_t reg; int err; int i; if (ti_edma3_sc) return (ENXIO); ti_edma3_sc = sc; sc->sc_dev = dev; /* Request the memory resources */ err = bus_alloc_resources(dev, ti_edma3_mem_spec, sc->mem_res); if (err) { device_printf(dev, "Error: could not allocate mem resources\n"); return (ENXIO); } /* Request the IRQ resources */ err = bus_alloc_resources(dev, ti_edma3_irq_spec, sc->irq_res); if (err) { device_printf(dev, "Error: could not allocate irq resources\n"); return (ENXIO); } /* Enable Channel Controller */ ti_prcm_clk_enable(EDMA_TPCC_CLK); reg = ti_edma3_cc_rd_4(TI_EDMA3CC_PID); device_printf(dev, "EDMA revision %08x\n", reg); /* Attach interrupt handlers */ for (i = 0; i < TI_EDMA3_NUM_IRQS; ++i) { err = bus_setup_intr(dev, sc->irq_res[i], INTR_TYPE_MISC | INTR_MPSAFE, NULL, *ti_edma3_intrs[i].handler, sc, &sc->ih_cookie[i]); if (err) { device_printf(dev, "could not setup %s\n", ti_edma3_intrs[i].description); return (err); } } return (0); } static device_method_t ti_edma3_methods[] = { DEVMETHOD(device_probe, ti_edma3_probe), DEVMETHOD(device_attach, ti_edma3_attach), {0, 0}, }; static driver_t ti_edma3_driver = { "ti_edma3", ti_edma3_methods, sizeof(struct ti_edma3_softc), }; static devclass_t ti_edma3_devclass; DRIVER_MODULE(ti_edma3, simplebus, ti_edma3_driver, ti_edma3_devclass, 0, 0); MODULE_DEPEND(ti_edma3, ti_prcm, 1, 1, 1); static void ti_edma3_intr_comp(void *arg) { printf("%s: unimplemented\n", __func__); } static void ti_edma3_intr_mperr(void *arg) { printf("%s: unimplemented\n", __func__); } static void ti_edma3_intr_err(void *arg) { printf("%s: unimplemented\n", __func__); } void ti_edma3_init(unsigned int eqn) { uint32_t reg; int i; /* on AM335x Event queue 0 is always mapped to Transfer Controller 0, * event queue 1 to TC2, etc. So we are asking PRCM to power on specific * TC based on what event queue we need to initialize */ ti_prcm_clk_enable(EDMA_TPTC0_CLK + eqn); /* Clear Event Missed Regs */ ti_edma3_cc_wr_4(TI_EDMA3CC_EMCR, 0xFFFFFFFF); ti_edma3_cc_wr_4(TI_EDMA3CC_EMCRH, 0xFFFFFFFF); ti_edma3_cc_wr_4(TI_EDMA3CC_QEMCR, 0xFFFFFFFF); /* Clear Error Reg */ ti_edma3_cc_wr_4(TI_EDMA3CC_CCERRCLR, 0xFFFFFFFF); /* Enable DMA channels 0-63 */ ti_edma3_cc_wr_4(TI_EDMA3CC_DRAE(0), 0xFFFFFFFF); ti_edma3_cc_wr_4(TI_EDMA3CC_DRAEH(0), 0xFFFFFFFF); for (i = 0; i < 64; i++) { ti_edma3_cc_wr_4(TI_EDMA3CC_DCHMAP(i), i<<5); } /* Initialize the DMA Queue Number Registers */ for (i = 0; i < TI_EDMA3_NUM_DMA_CHS; i++) { reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DMAQNUM(i>>3)); reg &= TI_EDMA3CC_DMAQNUM_CLR(i); reg |= TI_EDMA3CC_DMAQNUM_SET(i, eqn); ti_edma3_cc_wr_4(TI_EDMA3CC_DMAQNUM(i>>3), reg); } /* Enable the QDMA Region access for all channels */ ti_edma3_cc_wr_4(TI_EDMA3CC_QRAE(0), (1 << TI_EDMA3_NUM_QDMA_CHS) - 1); /*Initialize QDMA Queue Number Registers */ for (i = 0; i < TI_EDMA3_NUM_QDMA_CHS; i++) { reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QDMAQNUM); reg &= TI_EDMA3CC_QDMAQNUM_CLR(i); reg |= TI_EDMA3CC_QDMAQNUM_SET(i, eqn); ti_edma3_cc_wr_4(TI_EDMA3CC_QDMAQNUM, reg); } } #ifdef notyet int ti_edma3_enable_event_intr(unsigned int ch) { uint32_t reg; if (ch >= TI_EDMA3_NUM_DMA_CHS) return (EINVAL); if (ch < 32) { ti_edma3_cc_wr_4(TI_EDMA3CC_S_IESR(0), 1 << ch); } else { ti_edma3_cc_wr_4(TI_EDMA3CC_S_IESRH(0), 1 << (ch - 32)); } return 0; } #endif int ti_edma3_request_dma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn) { uint32_t reg; if (ch >= TI_EDMA3_NUM_DMA_CHS) return (EINVAL); /* Enable the DMA channel in the DRAE/DRAEH registers */ if (ch < 32) { reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DRAE(0)); reg |= (0x01 << ch); ti_edma3_cc_wr_4(TI_EDMA3CC_DRAE(0), reg); } else { reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DRAEH(0)); reg |= (0x01 << (ch - 32)); ti_edma3_cc_wr_4(TI_EDMA3CC_DRAEH(0), reg); } /* Associate DMA Channel to Event Queue */ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DMAQNUM(ch >> 3)); reg &= TI_EDMA3CC_DMAQNUM_CLR(ch); reg |= TI_EDMA3CC_DMAQNUM_SET((ch), eqn); ti_edma3_cc_wr_4(TI_EDMA3CC_DMAQNUM(ch >> 3), reg); /* Set TCC in corresponding PaRAM Entry */ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_OPT(ch)); reg &= TI_EDMA3CC_OPT_TCC_CLR; reg |= TI_EDMA3CC_OPT_TCC_SET(ch); ti_edma3_cc_wr_4(TI_EDMA3CC_OPT(ch), reg); return 0; } int ti_edma3_request_qdma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn) { uint32_t reg; if (ch >= TI_EDMA3_NUM_DMA_CHS) return (EINVAL); /* Enable the QDMA channel in the QRAE registers */ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QRAE(0)); reg |= (0x01 << ch); ti_edma3_cc_wr_4(TI_EDMA3CC_QRAE(0), reg); /* Associate QDMA Channel to Event Queue */ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QDMAQNUM); reg |= TI_EDMA3CC_QDMAQNUM_SET(ch, eqn); ti_edma3_cc_wr_4(TI_EDMA3CC_QDMAQNUM, reg); /* Set TCC in corresponding PaRAM Entry */ reg = ti_edma3_cc_rd_4(TI_EDMA3CC_OPT(ch)); reg &= TI_EDMA3CC_OPT_TCC_CLR; reg |= TI_EDMA3CC_OPT_TCC_SET(ch); ti_edma3_cc_wr_4(TI_EDMA3CC_OPT(ch), reg); return 0; } int ti_edma3_enable_transfer_manual(unsigned int ch) { if (ch >= TI_EDMA3_NUM_DMA_CHS) return (EINVAL); /* set corresponding bit in ESR/ESRH to set a event */ if (ch < 32) { ti_edma3_cc_wr_4(TI_EDMA3CC_S_ESR(0), 1 << ch); } else { ti_edma3_cc_wr_4(TI_EDMA3CC_S_ESRH(0), 1 << (ch - 32)); } return 0; } int ti_edma3_enable_transfer_qdma(unsigned int ch) { if (ch >= TI_EDMA3_NUM_QDMA_CHS) return (EINVAL); /* set corresponding bit in QEESR to enable QDMA event */ ti_edma3_cc_wr_4(TI_EDMA3CC_S_QEESR(0), (1 << ch)); return 0; } int ti_edma3_enable_transfer_event(unsigned int ch) { if (ch >= TI_EDMA3_NUM_DMA_CHS) return (EINVAL); /* Clear SECR(H) & EMCR(H) to clean any previous NULL request * and set corresponding bit in EESR to enable DMA event */ if(ch < 32) { ti_edma3_cc_wr_4(TI_EDMA3CC_S_SECR(0), (1 << ch)); ti_edma3_cc_wr_4(TI_EDMA3CC_EMCR, (1 << ch)); ti_edma3_cc_wr_4(TI_EDMA3CC_S_EESR(0), (1 << ch)); } else { ti_edma3_cc_wr_4(TI_EDMA3CC_S_SECRH(0), 1 << (ch - 32)); ti_edma3_cc_wr_4(TI_EDMA3CC_EMCRH, 1 << (ch - 32)); ti_edma3_cc_wr_4(TI_EDMA3CC_S_EESRH(0), 1 << (ch - 32)); } return 0; } void ti_edma3_param_write(unsigned int ch, struct ti_edma3cc_param_set *prs) { bus_write_region_4(ti_edma3_sc->mem_res[0], TI_EDMA3CC_OPT(ch), (uint32_t *) prs, 8); } void ti_edma3_param_read(unsigned int ch, struct ti_edma3cc_param_set *prs) { bus_read_region_4(ti_edma3_sc->mem_res[0], TI_EDMA3CC_OPT(ch), (uint32_t *) prs, 8); } Index: head/sys/arm/ti/ti_gpio.c =================================================================== --- head/sys/arm/ti/ti_gpio.c (revision 283275) +++ head/sys/arm/ti/ti_gpio.c (revision 283276) @@ -1,1107 +1,1006 @@ /*- * Copyright (c) 2011 Ben Gray . * Copyright (c) 2014 Luiz Otavio O Souza . * 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 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 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. */ /** * Beware that the OMAP4 datasheet(s) lists GPIO banks 1-6, whereas the code * here uses 0-5. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include "gpio_if.h" #include "ti_gpio_if.h" #if !defined(SOC_OMAP4) && !defined(SOC_TI_AM335X) #error "Unknown SoC" #endif /* Register definitions */ #define TI_GPIO_REVISION 0x0000 #define TI_GPIO_SYSCONFIG 0x0010 #define TI_GPIO_IRQSTATUS_RAW_0 0x0024 #define TI_GPIO_IRQSTATUS_RAW_1 0x0028 #define TI_GPIO_IRQSTATUS_0 0x002C #define TI_GPIO_IRQSTATUS_1 0x0030 #define TI_GPIO_IRQSTATUS_SET_0 0x0034 #define TI_GPIO_IRQSTATUS_SET_1 0x0038 #define TI_GPIO_IRQSTATUS_CLR_0 0x003C #define TI_GPIO_IRQSTATUS_CLR_1 0x0040 #define TI_GPIO_IRQWAKEN_0 0x0044 #define TI_GPIO_IRQWAKEN_1 0x0048 #define TI_GPIO_SYSSTATUS 0x0114 #define TI_GPIO_IRQSTATUS1 0x0118 #define TI_GPIO_IRQENABLE1 0x011C #define TI_GPIO_WAKEUPENABLE 0x0120 #define TI_GPIO_IRQSTATUS2 0x0128 #define TI_GPIO_IRQENABLE2 0x012C #define TI_GPIO_CTRL 0x0130 #define TI_GPIO_OE 0x0134 #define TI_GPIO_DATAIN 0x0138 #define TI_GPIO_DATAOUT 0x013C #define TI_GPIO_LEVELDETECT0 0x0140 #define TI_GPIO_LEVELDETECT1 0x0144 #define TI_GPIO_RISINGDETECT 0x0148 #define TI_GPIO_FALLINGDETECT 0x014C #define TI_GPIO_DEBOUNCENABLE 0x0150 #define TI_GPIO_DEBOUNCINGTIME 0x0154 #define TI_GPIO_CLEARWKUPENA 0x0180 #define TI_GPIO_SETWKUENA 0x0184 #define TI_GPIO_CLEARDATAOUT 0x0190 #define TI_GPIO_SETDATAOUT 0x0194 /* Other SoC Specific definitions */ -#define OMAP4_MAX_GPIO_BANKS 6 #define OMAP4_FIRST_GPIO_BANK 1 #define OMAP4_INTR_PER_BANK 1 #define OMAP4_GPIO_REV 0x50600801 -#define AM335X_MAX_GPIO_BANKS 4 #define AM335X_FIRST_GPIO_BANK 0 #define AM335X_INTR_PER_BANK 2 #define AM335X_GPIO_REV 0x50600801 #define PINS_PER_BANK 32 -#define TI_GPIO_BANK(p) ((p) / PINS_PER_BANK) #define TI_GPIO_MASK(p) (1U << ((p) % PINS_PER_BANK)) -static struct ti_gpio_softc *ti_gpio_sc = NULL; static int ti_gpio_detach(device_t); static u_int -ti_max_gpio_banks(void) -{ - switch(ti_chip()) { -#ifdef SOC_OMAP4 - case CHIP_OMAP_4: - return (OMAP4_MAX_GPIO_BANKS); -#endif -#ifdef SOC_TI_AM335X - case CHIP_AM335X: - return (AM335X_MAX_GPIO_BANKS); -#endif - } - return (0); -} - -static u_int -ti_max_gpio_intrs(void) -{ - switch(ti_chip()) { -#ifdef SOC_OMAP4 - case CHIP_OMAP_4: - return (OMAP4_MAX_GPIO_BANKS * OMAP4_INTR_PER_BANK); -#endif -#ifdef SOC_TI_AM335X - case CHIP_AM335X: - return (AM335X_MAX_GPIO_BANKS * AM335X_INTR_PER_BANK); -#endif - } - return (0); -} - -static u_int ti_first_gpio_bank(void) { switch(ti_chip()) { #ifdef SOC_OMAP4 case CHIP_OMAP_4: return (OMAP4_FIRST_GPIO_BANK); #endif #ifdef SOC_TI_AM335X case CHIP_AM335X: return (AM335X_FIRST_GPIO_BANK); #endif } return (0); } static uint32_t ti_gpio_rev(void) { switch(ti_chip()) { #ifdef SOC_OMAP4 case CHIP_OMAP_4: return (OMAP4_GPIO_REV); #endif #ifdef SOC_TI_AM335X case CHIP_AM335X: return (AM335X_GPIO_REV); #endif } return (0); } /** - * ti_gpio_mem_spec - Resource specification used when allocating resources - * ti_gpio_irq_spec - Resource specification used when allocating resources - * - * This driver module can have up to six independent memory regions, each - * region typically controls 32 GPIO pins. - * - * On OMAP3 and OMAP4 there is only one physical interrupt line per bank, - * but there are two set of registers which control the interrupt delivery - * to internal subsystems. The first set of registers control the - * interrupts delivery to the MPU and the second set control the - * interrupts delivery to the DSP. - * - * On AM335x there are two physical interrupt lines for each GPIO module. - * Each interrupt line is controlled by a set of registers. - */ -static struct resource_spec ti_gpio_mem_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, - { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_MEMORY, 3, RF_ACTIVE | RF_OPTIONAL }, -#if !defined(SOC_TI_AM335X) - { SYS_RES_MEMORY, 4, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_MEMORY, 5, RF_ACTIVE | RF_OPTIONAL }, -#endif - { -1, 0, 0 } -}; -static struct resource_spec ti_gpio_irq_spec[] = { - { SYS_RES_IRQ, 0, RF_ACTIVE }, - { SYS_RES_IRQ, 1, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 4, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 5, RF_ACTIVE | RF_OPTIONAL }, -#if defined(SOC_TI_AM335X) - { SYS_RES_IRQ, 6, RF_ACTIVE | RF_OPTIONAL }, - { SYS_RES_IRQ, 7, RF_ACTIVE | RF_OPTIONAL }, -#endif - { -1, 0, 0 } -}; - -/** * Macros for driver mutex locking */ #define TI_GPIO_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) #define TI_GPIO_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) #define TI_GPIO_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ "ti_gpio", MTX_SPIN) #define TI_GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) #define TI_GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) #define TI_GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED) /** * ti_gpio_read_4 - reads a 32-bit value from one of the GPIO registers * @sc: GPIO device context * @bank: The bank to read from * @off: The offset of a register from the GPIO register address range * * * RETURNS: * 32-bit value read from the register. */ static inline uint32_t -ti_gpio_read_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off) +ti_gpio_read_4(struct ti_gpio_softc *sc, bus_size_t off) { - return (bus_read_4(sc->sc_mem_res[bank], off)); + return (bus_read_4(sc->sc_mem_res, off)); } /** * ti_gpio_write_4 - writes a 32-bit value to one of the GPIO registers * @sc: GPIO device context * @bank: The bank to write to * @off: The offset of a register from the GPIO register address range * @val: The value to write into the register * * RETURNS: * nothing */ static inline void -ti_gpio_write_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off, +ti_gpio_write_4(struct ti_gpio_softc *sc, bus_size_t off, uint32_t val) { - bus_write_4(sc->sc_mem_res[bank], off, val); + bus_write_4(sc->sc_mem_res, off, val); } static inline void -ti_gpio_intr_clr(struct ti_gpio_softc *sc, unsigned int bank, uint32_t mask) +ti_gpio_intr_clr(struct ti_gpio_softc *sc, uint32_t mask) { /* We clear both set of registers. */ - ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_CLR_0, mask); - ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_CLR_1, mask); + ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_CLR_0, mask); + ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_CLR_1, mask); } static inline void -ti_gpio_intr_set(struct ti_gpio_softc *sc, unsigned int bank, uint32_t mask) +ti_gpio_intr_set(struct ti_gpio_softc *sc, uint32_t mask) { /* * On OMAP4 we unmask only the MPU interrupt and on AM335x we * also activate only the first interrupt. */ - ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_SET_0, mask); + ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_SET_0, mask); } static inline void -ti_gpio_intr_ack(struct ti_gpio_softc *sc, unsigned int bank, uint32_t mask) +ti_gpio_intr_ack(struct ti_gpio_softc *sc, uint32_t mask) { /* * Acknowledge the interrupt on both registers even if we use only * the first one. */ - ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_0, mask); - ti_gpio_write_4(sc, bank, TI_GPIO_IRQSTATUS_1, mask); + ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_0, mask); + ti_gpio_write_4(sc, TI_GPIO_IRQSTATUS_1, mask); } static inline uint32_t -ti_gpio_intr_status(struct ti_gpio_softc *sc, unsigned int bank) +ti_gpio_intr_status(struct ti_gpio_softc *sc) { uint32_t reg; /* Get the status from both registers. */ - reg = ti_gpio_read_4(sc, bank, TI_GPIO_IRQSTATUS_0); - reg |= ti_gpio_read_4(sc, bank, TI_GPIO_IRQSTATUS_1); + reg = ti_gpio_read_4(sc, TI_GPIO_IRQSTATUS_0); + reg |= ti_gpio_read_4(sc, TI_GPIO_IRQSTATUS_1); return (reg); } static device_t ti_gpio_get_bus(device_t dev) { struct ti_gpio_softc *sc; sc = device_get_softc(dev); return (sc->sc_busdev); } /** * ti_gpio_pin_max - Returns the maximum number of GPIO pins * @dev: gpio device handle * @maxpin: pointer to a value that upon return will contain the maximum number * of pins in the device. * * * LOCKING: * No locking required, returns static data. * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_max(device_t dev, int *maxpin) { - *maxpin = ti_max_gpio_banks() * PINS_PER_BANK - 1; + *maxpin = PINS_PER_BANK - 1; return (0); } static int ti_gpio_valid_pin(struct ti_gpio_softc *sc, int pin) { - if (pin >= sc->sc_maxpin || - TI_GPIO_BANK(pin) >= ti_max_gpio_banks() || - sc->sc_mem_res[TI_GPIO_BANK(pin)] == NULL) { + if (pin >= sc->sc_maxpin || sc->sc_mem_res == NULL) return (EINVAL); - } return (0); } /** * ti_gpio_pin_getcaps - Gets the capabilties of a given pin * @dev: gpio device handle * @pin: the number of the pin * @caps: pointer to a value that upon return will contain the capabilities * * Currently all pins have the same capability, notably: * - GPIO_PIN_INPUT * - GPIO_PIN_OUTPUT * - GPIO_PIN_PULLUP * - GPIO_PIN_PULLDOWN * * LOCKING: * No locking required, returns static data. * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct ti_gpio_softc *sc; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN); return (0); } /** * ti_gpio_pin_getflags - Gets the current flags of a given pin * @dev: gpio device handle * @pin: the number of the pin * @flags: upon return will contain the current flags of the pin * * Reads the current flags of a given pin, here we actually read the H/W * registers to determine the flags, rather than storing the value in the * setflags call. * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct ti_gpio_softc *sc; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* Get the current pin state */ TI_GPIO_LOCK(sc); TI_GPIO_GET_FLAGS(dev, pin, flags); TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_pin_getname - Gets the name of a given pin * @dev: gpio device handle * @pin: the number of the pin * @name: buffer to put the name in * * The driver simply calls the pins gpio_n, where 'n' is obviously the number * of the pin. * * LOCKING: * No locking required, returns static data. * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct ti_gpio_softc *sc; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* Set a very simple name */ snprintf(name, GPIOMAXNAME, "gpio_%u", pin); name[GPIOMAXNAME - 1] = '\0'; return (0); } /** * ti_gpio_pin_setflags - Sets the flags for a given pin * @dev: gpio device handle * @pin: the number of the pin * @flags: the flags to set * * The flags of the pin correspond to things like input/output mode, pull-ups, * pull-downs, etc. This driver doesn't support all flags, only the following: * - GPIO_PIN_INPUT * - GPIO_PIN_OUTPUT * - GPIO_PIN_PULLUP * - GPIO_PIN_PULLDOWN * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise an error code */ static int ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct ti_gpio_softc *sc; uint32_t oe; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* Set the GPIO mode and state */ TI_GPIO_LOCK(sc); if (TI_GPIO_SET_FLAGS(dev, pin, flags) != 0) { TI_GPIO_UNLOCK(sc); return (EINVAL); } /* If configuring as an output set the "output enable" bit */ - oe = ti_gpio_read_4(sc, TI_GPIO_BANK(pin), TI_GPIO_OE); + oe = ti_gpio_read_4(sc, TI_GPIO_OE); if (flags & GPIO_PIN_INPUT) oe |= TI_GPIO_MASK(pin); else oe &= ~TI_GPIO_MASK(pin); - ti_gpio_write_4(sc, TI_GPIO_BANK(pin), TI_GPIO_OE, oe); + ti_gpio_write_4(sc, TI_GPIO_OE, oe); TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_pin_set - Sets the current level on a GPIO pin * @dev: gpio device handle * @pin: the number of the pin * @value: non-zero value will drive the pin high, otherwise the pin is * driven low. * * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise a error code */ static int ti_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct ti_gpio_softc *sc; uint32_t reg; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); TI_GPIO_LOCK(sc); if (value == GPIO_PIN_LOW) reg = TI_GPIO_CLEARDATAOUT; else reg = TI_GPIO_SETDATAOUT; - ti_gpio_write_4(sc, TI_GPIO_BANK(pin), reg, TI_GPIO_MASK(pin)); + ti_gpio_write_4(sc, reg, TI_GPIO_MASK(pin)); TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_pin_get - Gets the current level on a GPIO pin * @dev: gpio device handle * @pin: the number of the pin * @value: pointer to a value that upond return will contain the pin value * * The pin must be configured as an input pin beforehand, otherwise this * function will fail. * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise a error code */ static int ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) { struct ti_gpio_softc *sc; uint32_t oe, reg, val; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* * Return data from output latch when set as output and from the * input register otherwise. */ TI_GPIO_LOCK(sc); - oe = ti_gpio_read_4(sc, TI_GPIO_BANK(pin), TI_GPIO_OE); + oe = ti_gpio_read_4(sc, TI_GPIO_OE); if (oe & TI_GPIO_MASK(pin)) reg = TI_GPIO_DATAIN; else reg = TI_GPIO_DATAOUT; - val = ti_gpio_read_4(sc, TI_GPIO_BANK(pin), reg); + val = ti_gpio_read_4(sc, reg); *value = (val & TI_GPIO_MASK(pin)) ? 1 : 0; TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_pin_toggle - Toggles a given GPIO pin * @dev: gpio device handle * @pin: the number of the pin * * * LOCKING: * Internally locks the context * * RETURNS: * Returns 0 on success otherwise a error code */ static int ti_gpio_pin_toggle(device_t dev, uint32_t pin) { struct ti_gpio_softc *sc; uint32_t reg, val; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, pin) != 0) return (EINVAL); /* Toggle the pin */ TI_GPIO_LOCK(sc); - val = ti_gpio_read_4(sc, TI_GPIO_BANK(pin), TI_GPIO_DATAOUT); + val = ti_gpio_read_4(sc, TI_GPIO_DATAOUT); if (val & TI_GPIO_MASK(pin)) reg = TI_GPIO_CLEARDATAOUT; else reg = TI_GPIO_SETDATAOUT; - ti_gpio_write_4(sc, TI_GPIO_BANK(pin), reg, TI_GPIO_MASK(pin)); + ti_gpio_write_4(sc, reg, TI_GPIO_MASK(pin)); TI_GPIO_UNLOCK(sc); return (0); } /** * ti_gpio_intr - ISR for all GPIO modules * @arg: the soft context pointer * * LOCKING: * Internally locks the context * */ static int ti_gpio_intr(void *arg) { int bank_last, irq; struct intr_event *event; struct ti_gpio_softc *sc; uint32_t reg; sc = (struct ti_gpio_softc *)arg; bank_last = -1; reg = 0; /* squelch bogus gcc warning */ + reg = ti_gpio_intr_status(sc); for (irq = 0; irq < sc->sc_maxpin; irq++) { - - /* Read interrupt status only once for each bank. */ - if (TI_GPIO_BANK(irq) != bank_last) { - reg = ti_gpio_intr_status(sc, TI_GPIO_BANK(irq)); - bank_last = TI_GPIO_BANK(irq); - } if ((reg & TI_GPIO_MASK(irq)) == 0) continue; event = sc->sc_events[irq]; if (event != NULL && !TAILQ_EMPTY(&event->ie_handlers)) intr_event_handle(event, NULL); else device_printf(sc->sc_dev, "Stray IRQ %d\n", irq); /* Ack the IRQ Status bit. */ - ti_gpio_intr_ack(sc, TI_GPIO_BANK(irq), TI_GPIO_MASK(irq)); + ti_gpio_intr_ack(sc, TI_GPIO_MASK(irq)); } return (FILTER_HANDLED); } static int -ti_gpio_attach_intr(device_t dev) +ti_gpio_bank_init(device_t dev) { - int i; - struct ti_gpio_softc *sc; - - sc = device_get_softc(dev); - for (i = 0; i < ti_max_gpio_intrs(); i++) { - if (sc->sc_irq_res[i] == NULL) - break; - - /* - * Register our interrupt filter for each of the IRQ resources. - */ - if (bus_setup_intr(dev, sc->sc_irq_res[i], - INTR_TYPE_MISC | INTR_MPSAFE, ti_gpio_intr, NULL, sc, - &sc->sc_irq_hdl[i]) != 0) { - device_printf(dev, - "WARNING: unable to register interrupt filter\n"); - return (-1); - } - } - - return (0); -} - -static int -ti_gpio_detach_intr(device_t dev) -{ - int i; - struct ti_gpio_softc *sc; - - /* Teardown our interrupt filters. */ - sc = device_get_softc(dev); - for (i = 0; i < ti_max_gpio_intrs(); i++) { - if (sc->sc_irq_res[i] == NULL) - break; - - if (sc->sc_irq_hdl[i]) { - bus_teardown_intr(dev, sc->sc_irq_res[i], - sc->sc_irq_hdl[i]); - } - } - - return (0); -} - -static int -ti_gpio_bank_init(device_t dev, int bank) -{ int pin; struct ti_gpio_softc *sc; uint32_t flags, reg_oe, rev; + clk_ident_t clk; sc = device_get_softc(dev); /* Enable the interface and functional clocks for the module. */ - ti_prcm_clk_enable(GPIO0_CLK + ti_first_gpio_bank() + bank); + clk = ti_hwmods_get_clock(dev); + if (clk == INVALID_CLK_IDENT) { + device_printf(dev, "failed to get device id based on ti,hwmods\n"); + return (EINVAL); + } + sc->sc_bank = clk - GPIO1_CLK + ti_first_gpio_bank(); + ti_prcm_clk_enable(clk); + /* * Read the revision number of the module. TI don't publish the * actual revision numbers, so instead the values have been * determined by experimentation. */ - rev = ti_gpio_read_4(sc, bank, TI_GPIO_REVISION); + rev = ti_gpio_read_4(sc, TI_GPIO_REVISION); /* Check the revision. */ if (rev != ti_gpio_rev()) { device_printf(dev, "Warning: could not determine the revision " - "of GPIO module %d (revision:0x%08x)\n", bank, rev); + "of GPIO module (revision:0x%08x)\n", rev); return (EINVAL); } /* Disable interrupts for all pins. */ - ti_gpio_intr_clr(sc, bank, 0xffffffff); + ti_gpio_intr_clr(sc, 0xffffffff); /* Init OE register based on pads configuration. */ reg_oe = 0xffffffff; for (pin = 0; pin < PINS_PER_BANK; pin++) { - TI_GPIO_GET_FLAGS(dev, PINS_PER_BANK * bank + pin, &flags); + TI_GPIO_GET_FLAGS(dev, pin, &flags); if (flags & GPIO_PIN_OUTPUT) reg_oe &= ~(1UL << pin); } - ti_gpio_write_4(sc, bank, TI_GPIO_OE, reg_oe); + ti_gpio_write_4(sc, TI_GPIO_OE, reg_oe); return (0); } /** * ti_gpio_attach - attach function for the driver * @dev: gpio device handle * * Allocates and sets up the driver context for all GPIO banks. This function * expects the memory ranges and IRQs to already be allocated to the driver. * * LOCKING: * None * * RETURNS: * Always returns 0 */ static int ti_gpio_attach(device_t dev) { struct ti_gpio_softc *sc; unsigned int i; int err; - if (ti_gpio_sc != NULL) - return (ENXIO); - - ti_gpio_sc = sc = device_get_softc(dev); + sc = device_get_softc(dev); sc->sc_dev = dev; TI_GPIO_LOCK_INIT(sc); ti_gpio_pin_max(dev, &sc->sc_maxpin); sc->sc_maxpin++; - /* There are up to 6 different GPIO register sets located in different - * memory areas on the chip. The memory range should have been set for - * the driver when it was added as a child. - */ - if (bus_alloc_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res) != 0) { + sc->sc_mem_rid = 0; + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->sc_mem_rid, RF_ACTIVE); + if (!sc->sc_mem_res) { device_printf(dev, "Error: could not allocate mem resources\n"); ti_gpio_detach(dev); return (ENXIO); } - /* Request the IRQ resources */ - if (bus_alloc_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res) != 0) { + sc->sc_irq_rid = 0; + sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->sc_irq_rid, RF_ACTIVE); + if (!sc->sc_irq_res) { device_printf(dev, "Error: could not allocate irq resources\n"); ti_gpio_detach(dev); return (ENXIO); } - /* Setup the IRQ resources */ - if (ti_gpio_attach_intr(dev) != 0) { - device_printf(dev, "Error: could not setup irq handlers\n"); + /* + * Register our interrupt filter for each of the IRQ resources. + */ + if (bus_setup_intr(dev, sc->sc_irq_res, + INTR_TYPE_MISC | INTR_MPSAFE, ti_gpio_intr, NULL, sc, + &sc->sc_irq_hdl) != 0) { + device_printf(dev, + "WARNING: unable to register interrupt filter\n"); ti_gpio_detach(dev); return (ENXIO); } /* * Initialize the interrupt settings. The default is active-low * interrupts. */ sc->sc_irq_trigger = malloc( sizeof(*sc->sc_irq_trigger) * sc->sc_maxpin, M_DEVBUF, M_WAITOK | M_ZERO); sc->sc_irq_polarity = malloc( sizeof(*sc->sc_irq_polarity) * sc->sc_maxpin, M_DEVBUF, M_WAITOK | M_ZERO); for (i = 0; i < sc->sc_maxpin; i++) { sc->sc_irq_trigger[i] = INTR_TRIGGER_LEVEL; sc->sc_irq_polarity[i] = INTR_POLARITY_LOW; } sc->sc_events = malloc(sizeof(struct intr_event *) * sc->sc_maxpin, M_DEVBUF, M_WAITOK | M_ZERO); + sc->sc_mask_args = malloc(sizeof(struct ti_gpio_mask_arg) * sc->sc_maxpin, + M_DEVBUF, M_WAITOK | M_ZERO); + /* We need to go through each block and ensure the clocks are running and * the module is enabled. It might be better to do this only when the * pins are configured which would result in less power used if the GPIO * pins weren't used ... */ - for (i = 0; i < ti_max_gpio_banks(); i++) { - if (sc->sc_mem_res[i] != NULL) { - /* Initialize the GPIO module. */ - err = ti_gpio_bank_init(dev, i); - if (err != 0) { - ti_gpio_detach(dev); - return (err); - } + if (sc->sc_mem_res != NULL) { + /* Initialize the GPIO module. */ + err = ti_gpio_bank_init(dev); + if (err != 0) { + ti_gpio_detach(dev); + return (err); } } + sc->sc_busdev = gpiobus_attach_bus(dev); if (sc->sc_busdev == NULL) { ti_gpio_detach(dev); return (ENXIO); } return (0); } /** * ti_gpio_detach - detach function for the driver * @dev: scm device handle * * Allocates and sets up the driver context, this simply entails creating a * bus mappings for the SCM register set. * * LOCKING: * None * * RETURNS: * Always returns 0 */ static int ti_gpio_detach(device_t dev) { struct ti_gpio_softc *sc = device_get_softc(dev); - unsigned int i; KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized")); /* Disable all interrupts */ - for (i = 0; i < ti_max_gpio_banks(); i++) { - if (sc->sc_mem_res[i] != NULL) - ti_gpio_intr_clr(sc, i, 0xffffffff); - } + if (sc->sc_mem_res != NULL) + ti_gpio_intr_clr(sc, 0xffffffff); gpiobus_detach_bus(dev); if (sc->sc_events) free(sc->sc_events, M_DEVBUF); + if (sc->sc_mask_args) + free(sc->sc_mask_args, M_DEVBUF); if (sc->sc_irq_polarity) free(sc->sc_irq_polarity, M_DEVBUF); if (sc->sc_irq_trigger) free(sc->sc_irq_trigger, M_DEVBUF); /* Release the memory and IRQ resources. */ - ti_gpio_detach_intr(dev); - bus_release_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res); - bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); + if (sc->sc_irq_hdl) { + bus_teardown_intr(dev, sc->sc_irq_res, + sc->sc_irq_hdl); + } + bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, + sc->sc_irq_res); + bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, + sc->sc_mem_res); TI_GPIO_LOCK_DESTROY(sc); return (0); } static uint32_t ti_gpio_intr_reg(struct ti_gpio_softc *sc, int irq) { if (ti_gpio_valid_pin(sc, irq) != 0) return (0); if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_LEVEL) { if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) return (TI_GPIO_LEVELDETECT0); else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) return (TI_GPIO_LEVELDETECT1); } else if (sc->sc_irq_trigger[irq] == INTR_TRIGGER_EDGE) { if (sc->sc_irq_polarity[irq] == INTR_POLARITY_LOW) return (TI_GPIO_FALLINGDETECT); else if (sc->sc_irq_polarity[irq] == INTR_POLARITY_HIGH) return (TI_GPIO_RISINGDETECT); } return (0); } static void -ti_gpio_mask_irq(void *source) +ti_gpio_mask_irq_internal(struct ti_gpio_softc *sc, int irq) { - int irq; uint32_t reg, val; - irq = (int)source; - if (ti_gpio_valid_pin(ti_gpio_sc, irq) != 0) + if (ti_gpio_valid_pin(sc, irq) != 0) return; - TI_GPIO_LOCK(ti_gpio_sc); - ti_gpio_intr_clr(ti_gpio_sc, TI_GPIO_BANK(irq), TI_GPIO_MASK(irq)); - reg = ti_gpio_intr_reg(ti_gpio_sc, irq); + TI_GPIO_LOCK(sc); + ti_gpio_intr_clr(sc, TI_GPIO_MASK(irq)); + reg = ti_gpio_intr_reg(sc, irq); if (reg != 0) { - val = ti_gpio_read_4(ti_gpio_sc, TI_GPIO_BANK(irq), reg); + val = ti_gpio_read_4(sc, reg); val &= ~TI_GPIO_MASK(irq); - ti_gpio_write_4(ti_gpio_sc, TI_GPIO_BANK(irq), reg, val); + ti_gpio_write_4(sc, reg, val); } - TI_GPIO_UNLOCK(ti_gpio_sc); + TI_GPIO_UNLOCK(sc); } static void -ti_gpio_unmask_irq(void *source) +ti_gpio_unmask_irq_internal(struct ti_gpio_softc *sc, int irq) { - int irq; uint32_t reg, val; - irq = (int)source; - if (ti_gpio_valid_pin(ti_gpio_sc, irq) != 0) + if (ti_gpio_valid_pin(sc, irq) != 0) return; - TI_GPIO_LOCK(ti_gpio_sc); - reg = ti_gpio_intr_reg(ti_gpio_sc, irq); + TI_GPIO_LOCK(sc); + reg = ti_gpio_intr_reg(sc, irq); if (reg != 0) { - val = ti_gpio_read_4(ti_gpio_sc, TI_GPIO_BANK(irq), reg); + val = ti_gpio_read_4(sc, reg); val |= TI_GPIO_MASK(irq); - ti_gpio_write_4(ti_gpio_sc, TI_GPIO_BANK(irq), reg, val); - ti_gpio_intr_set(ti_gpio_sc, TI_GPIO_BANK(irq), - TI_GPIO_MASK(irq)); + ti_gpio_write_4(sc, reg, val); + ti_gpio_intr_set(sc, TI_GPIO_MASK(irq)); } - TI_GPIO_UNLOCK(ti_gpio_sc); + TI_GPIO_UNLOCK(sc); } +static void +ti_gpio_mask_irq(void *source) +{ + struct ti_gpio_mask_arg *arg = source; + + ti_gpio_mask_irq_internal(arg->softc, arg->pin); +} + +static void +ti_gpio_unmask_irq(void *source) +{ + struct ti_gpio_mask_arg *arg = source; + + ti_gpio_unmask_irq_internal(arg->softc, arg->pin); +} + static int ti_gpio_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *res) { int pin; if (type != SYS_RES_IRQ) return (ENXIO); /* Unmask the interrupt. */ pin = rman_get_start(res); ti_gpio_unmask_irq((void *)(uintptr_t)pin); return (0); } static int ti_gpio_deactivate_resource(device_t dev, device_t child, int type, int rid, struct resource *res) { int pin; if (type != SYS_RES_IRQ) return (ENXIO); /* Mask the interrupt. */ pin = rman_get_start(res); ti_gpio_mask_irq((void *)(uintptr_t)pin); return (0); } static int ti_gpio_config_intr(device_t dev, int irq, enum intr_trigger trig, enum intr_polarity pol) { struct ti_gpio_softc *sc; uint32_t oldreg, reg, val; sc = device_get_softc(dev); if (ti_gpio_valid_pin(sc, irq) != 0) return (EINVAL); /* There is no standard trigger or polarity. */ if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM) return (EINVAL); TI_GPIO_LOCK(sc); /* * TRM recommends add the new event before remove the old one to * avoid losing interrupts. */ oldreg = ti_gpio_intr_reg(sc, irq); sc->sc_irq_trigger[irq] = trig; sc->sc_irq_polarity[irq] = pol; reg = ti_gpio_intr_reg(sc, irq); if (reg != 0) { /* Apply the new settings. */ - val = ti_gpio_read_4(sc, TI_GPIO_BANK(irq), reg); + val = ti_gpio_read_4(sc, reg); val |= TI_GPIO_MASK(irq); - ti_gpio_write_4(sc, TI_GPIO_BANK(irq), reg, val); + ti_gpio_write_4(sc, reg, val); } if (reg != oldreg && oldreg != 0) { /* Remove the old settings. */ - val = ti_gpio_read_4(sc, TI_GPIO_BANK(irq), oldreg); + val = ti_gpio_read_4(sc, oldreg); val &= ~TI_GPIO_MASK(irq); - ti_gpio_write_4(sc, TI_GPIO_BANK(irq), oldreg, val); + ti_gpio_write_4(sc, oldreg, val); } TI_GPIO_UNLOCK(sc); return (0); } static int ti_gpio_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct ti_gpio_softc *sc; struct intr_event *event; int pin, error; sc = device_get_softc(dev); pin = rman_get_start(ires); if (ti_gpio_valid_pin(sc, pin) != 0) panic("%s: bad pin %d", __func__, pin); event = sc->sc_events[pin]; if (event == NULL) { - error = intr_event_create(&event, (void *)(uintptr_t)pin, 0, + sc->sc_mask_args[pin].softc = sc; + sc->sc_mask_args[pin].pin = pin; + error = intr_event_create(&event, (void *)&sc->sc_mask_args[pin], 0, pin, ti_gpio_mask_irq, ti_gpio_unmask_irq, NULL, NULL, "gpio%d pin%d:", device_get_unit(dev), pin); if (error != 0) return (error); sc->sc_events[pin] = event; } intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); return (0); } static int ti_gpio_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct ti_gpio_softc *sc; int pin, err; sc = device_get_softc(dev); pin = rman_get_start(ires); if (ti_gpio_valid_pin(sc, pin) != 0) panic("%s: bad pin %d", __func__, pin); if (sc->sc_events[pin] == NULL) panic("Trying to teardown unoccupied IRQ"); err = intr_event_remove_handler(cookie); if (!err) sc->sc_events[pin] = NULL; return (err); } static phandle_t ti_gpio_get_node(device_t bus, device_t dev) { /* We only have one child, the GPIO bus, which needs our own node. */ return (ofw_bus_get_node(bus)); } static device_method_t ti_gpio_methods[] = { DEVMETHOD(device_attach, ti_gpio_attach), DEVMETHOD(device_detach, ti_gpio_detach), /* GPIO protocol */ DEVMETHOD(gpio_get_bus, ti_gpio_get_bus), DEVMETHOD(gpio_pin_max, ti_gpio_pin_max), DEVMETHOD(gpio_pin_getname, ti_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, ti_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, ti_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, ti_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, ti_gpio_pin_get), DEVMETHOD(gpio_pin_set, ti_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle), /* Bus interface */ DEVMETHOD(bus_activate_resource, ti_gpio_activate_resource), DEVMETHOD(bus_deactivate_resource, ti_gpio_deactivate_resource), DEVMETHOD(bus_config_intr, ti_gpio_config_intr), DEVMETHOD(bus_setup_intr, ti_gpio_setup_intr), DEVMETHOD(bus_teardown_intr, ti_gpio_teardown_intr), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, ti_gpio_get_node), {0, 0}, }; driver_t ti_gpio_driver = { "gpio", ti_gpio_methods, sizeof(struct ti_gpio_softc), }; Index: head/sys/arm/ti/ti_gpio.h =================================================================== --- head/sys/arm/ti/ti_gpio.h (revision 283275) +++ head/sys/arm/ti/ti_gpio.h (revision 283276) @@ -1,73 +1,77 @@ /*- * Copyright (c) 2011 * Ben Gray . * 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 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 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 TI_GPIO_H #define TI_GPIO_H /* The maximum number of banks for any SoC */ #define MAX_GPIO_BANKS 6 /* * Maximum GPIOS possible, max of *_MAX_GPIO_BANKS * *_INTR_PER_BANK. * These are defined in ti_gpio.c */ #define MAX_GPIO_INTRS 8 +struct ti_gpio_mask_arg { + void *softc; + int pin; +}; + /** * Structure that stores the driver context. * * This structure is allocated during driver attach. */ struct ti_gpio_softc { device_t sc_dev; device_t sc_busdev; /* Interrupt trigger type and level. */ enum intr_trigger *sc_irq_trigger; enum intr_polarity *sc_irq_polarity; + int sc_bank; int sc_maxpin; struct mtx sc_mtx; - /* - * The memory resource(s) for the PRCM register set, when the device is - * created the caller can assign up to 6 memory regions depending on - * the SoC type. - */ - struct resource *sc_mem_res[MAX_GPIO_BANKS]; - struct resource *sc_irq_res[MAX_GPIO_INTRS]; + int sc_mem_rid; + struct resource *sc_mem_res; + int sc_irq_rid; + struct resource *sc_irq_res; /* Interrupt events. */ struct intr_event **sc_events; + struct ti_gpio_mask_arg *sc_mask_args; /* The handle for the register IRQ handlers. */ - void *sc_irq_hdl[MAX_GPIO_INTRS]; + void *sc_irq_hdl; }; #endif /* TI_GPIO_H */ Index: head/sys/arm/ti/ti_hwmods.c =================================================================== --- head/sys/arm/ti/ti_hwmods.c (nonexistent) +++ head/sys/arm/ti/ti_hwmods.c (revision 283276) @@ -0,0 +1,170 @@ +/*- + * Copyright (c) 2015 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +struct hwmod { + const char *name; + int clock_id; +}; + +struct hwmod ti_hwmods[] = { + {"i2c1", I2C1_CLK}, + {"i2c2", I2C2_CLK}, + {"i2c3", I2C3_CLK}, + {"i2c4", I2C4_CLK}, + {"i2c5", I2C5_CLK}, + + {"gpio1", GPIO1_CLK}, + {"gpio2", GPIO2_CLK}, + {"gpio3", GPIO3_CLK}, + {"gpio4", GPIO4_CLK}, + {"gpio5", GPIO5_CLK}, + {"gpio6", GPIO6_CLK}, + {"gpio7", GPIO7_CLK}, + + {"mmc1", MMC1_CLK}, + {"mmc2", MMC2_CLK}, + {"mmc3", MMC3_CLK}, + {"mmc4", MMC4_CLK}, + {"mmc5", MMC5_CLK}, + {"mmc6", MMC6_CLK}, + + {"epwmss0", PWMSS0_CLK}, + {"epwmss1", PWMSS1_CLK}, + {"epwmss2", PWMSS2_CLK}, + + {"timer1", TIMER1_CLK}, + {"timer2", TIMER2_CLK}, + {"timer3", TIMER3_CLK}, + {"timer4", TIMER4_CLK}, + {"timer5", TIMER5_CLK}, + {"timer6", TIMER6_CLK}, + {"timer7", TIMER7_CLK}, + + {"uart1", UART1_CLK}, + {"uart2", UART2_CLK}, + {"uart3", UART3_CLK}, + {"uart4", UART4_CLK}, + {"uart5", UART5_CLK}, + {"uart6", UART6_CLK}, + {"uart7", UART7_CLK}, + + {NULL, 0} +}; + +clk_ident_t +ti_hwmods_get_clock(device_t dev) +{ + phandle_t node; + int len, l; + char *name; + char *buf; + int clk; + struct hwmod *hw; + + if ((node = ofw_bus_get_node(dev)) == 0) + return (INVALID_CLK_IDENT); + + if ((len = OF_getprop_alloc(node, "ti,hwmods", 1, (void**)&name)) <= 0) + return (INVALID_CLK_IDENT); + + buf = name; + + clk = INVALID_CLK_IDENT; + while ((len > 0) && (clk == INVALID_CLK_IDENT)) { + for (hw = ti_hwmods; hw->name != NULL; ++hw) { + if (strcmp(hw->name, name) == 0) { + clk = hw->clock_id; + break; + } + } + + /* Slide to the next sub-string. */ + l = strlen(name) + 1; + name += l; + len -= l; + } + + if (len > 0) + device_printf(dev, "WARNING: more then one ti,hwmod \n"); + + free(buf, M_OFWPROP); + return (clk); +} + +int ti_hwmods_contains(device_t dev, const char *hwmod) +{ + phandle_t node; + int len, l; + char *name; + char *buf; + int result; + + if ((node = ofw_bus_get_node(dev)) == 0) + return (0); + + if ((len = OF_getprop_alloc(node, "ti,hwmods", 1, (void**)&name)) <= 0) + return (0); + + buf = name; + + result = 0; + while (len > 0) { + if (strcmp(name, hwmod) == 0) { + result = 1; + break; + } + + /* Slide to the next sub-string. */ + l = strlen(name) + 1; + name += l; + len -= l; + } + + free(buf, M_OFWPROP); + + return (result); +} Property changes on: head/sys/arm/ti/ti_hwmods.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/ti_hwmods.h =================================================================== --- head/sys/arm/ti/ti_hwmods.h (nonexistent) +++ head/sys/arm/ti/ti_hwmods.h (revision 283276) @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2015 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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 _TI_HWMODS_H_ +#define _TI_HWMODS_H_ + +clk_ident_t ti_hwmods_get_clock(device_t dev); +int ti_hwmods_contains(device_t dev, const char *hwmod); + +#endif /* _TI_HWMODS_H_ */ Property changes on: head/sys/arm/ti/ti_hwmods.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/ti_i2c.c =================================================================== --- head/sys/arm/ti/ti_i2c.c (revision 283275) +++ head/sys/arm/ti/ti_i2c.c (revision 283276) @@ -1,990 +1,988 @@ /*- * Copyright (c) 2011 Ben Gray . * Copyright (c) 2014 Luiz Otavio O Souza . * 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 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 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. */ /** * Driver for the I2C module on the TI SoC. * * This driver is heavily based on the TWI driver for the AT91 (at91_twi.c). * * CAUTION: The I2Ci registers are limited to 16 bit and 8 bit data accesses, * 32 bit data access is not allowed and can corrupt register content. * * This driver currently doesn't use DMA for the transfer, although I hope to * incorporate that sometime in the future. The idea being that for transaction * larger than a certain size the DMA engine is used, for anything less the * normal interrupt/fifo driven option is used. * * * WARNING: This driver uses mtx_sleep and interrupts to perform transactions, * which means you can't do a transaction during startup before the interrupts * have been enabled. Hint - the freebsd function config_intrhook_establish(). */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include "iicbus_if.h" /** * I2C device driver context, a pointer to this is stored in the device * driver structure. */ struct ti_i2c_softc { device_t sc_dev; - uint32_t device_id; + clk_ident_t clk_id; struct resource* sc_irq_res; struct resource* sc_mem_res; device_t sc_iicbus; void* sc_irq_h; struct mtx sc_mtx; struct iic_msg* sc_buffer; int sc_bus_inuse; int sc_buffer_pos; int sc_error; int sc_fifo_trsh; int sc_timeout; uint16_t sc_con_reg; uint16_t sc_rev; }; struct ti_i2c_clock_config { u_int frequency; /* Bus frequency in Hz */ uint8_t psc; /* Fast/Standard mode prescale divider */ uint8_t scll; /* Fast/Standard mode SCL low time */ uint8_t sclh; /* Fast/Standard mode SCL high time */ uint8_t hsscll; /* High Speed mode SCL low time */ uint8_t hssclh; /* High Speed mode SCL high time */ }; #if defined(SOC_OMAP4) /* * OMAP4 i2c bus clock is 96MHz / ((psc + 1) * (scll + 7 + sclh + 5)). * The prescaler values for 100KHz and 400KHz modes come from the table in the * OMAP4 TRM. The table doesn't list 1MHz; these values should give that speed. */ static struct ti_i2c_clock_config ti_omap4_i2c_clock_configs[] = { { 100000, 23, 13, 15, 0, 0}, { 400000, 9, 5, 7, 0, 0}, { 1000000, 3, 5, 7, 0, 0}, /* { 3200000, 1, 113, 115, 7, 10}, - HS mode */ { 0 /* Table terminator */ } }; #endif #if defined(SOC_TI_AM335X) /* * AM335x i2c bus clock is 48MHZ / ((psc + 1) * (scll + 7 + sclh + 5)) * In all cases we prescale the clock to 24MHz as recommended in the manual. */ static struct ti_i2c_clock_config ti_am335x_i2c_clock_configs[] = { { 100000, 1, 111, 117, 0, 0}, { 400000, 1, 23, 25, 0, 0}, { 1000000, 1, 5, 7, 0, 0}, { 0 /* Table terminator */ } }; #endif /** * Locking macros used throughout the driver */ #define TI_I2C_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define TI_I2C_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define TI_I2C_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ "ti_i2c", MTX_DEF) #define TI_I2C_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx) #define TI_I2C_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED) #define TI_I2C_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED) #ifdef DEBUG #define ti_i2c_dbg(_sc, fmt, args...) \ device_printf((_sc)->sc_dev, fmt, ##args) #else #define ti_i2c_dbg(_sc, fmt, args...) #endif /** * ti_i2c_read_2 - reads a 16-bit value from one of the I2C registers * @sc: I2C device context * @off: the byte offset within the register bank to read from. * * * LOCKING: * No locking required * * RETURNS: * 16-bit value read from the register. */ static inline uint16_t ti_i2c_read_2(struct ti_i2c_softc *sc, bus_size_t off) { return (bus_read_2(sc->sc_mem_res, off)); } /** * ti_i2c_write_2 - writes a 16-bit value to one of the I2C registers * @sc: I2C device context * @off: the byte offset within the register bank to read from. * @val: the value to write into the register * * LOCKING: * No locking required * * RETURNS: * 16-bit value read from the register. */ static inline void ti_i2c_write_2(struct ti_i2c_softc *sc, bus_size_t off, uint16_t val) { bus_write_2(sc->sc_mem_res, off, val); } static int ti_i2c_transfer_intr(struct ti_i2c_softc* sc, uint16_t status) { int amount, done, i; done = 0; amount = 0; /* Check for the error conditions. */ if (status & I2C_STAT_NACK) { /* No ACK from slave. */ ti_i2c_dbg(sc, "NACK\n"); ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_NACK); sc->sc_error = ENXIO; } else if (status & I2C_STAT_AL) { /* Arbitration lost. */ ti_i2c_dbg(sc, "Arbitration lost\n"); ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_AL); sc->sc_error = ENXIO; } /* Check if we have finished. */ if (status & I2C_STAT_ARDY) { /* Register access ready - transaction complete basically. */ ti_i2c_dbg(sc, "ARDY transaction complete\n"); if (sc->sc_error != 0 && sc->sc_buffer->flags & IIC_M_NOSTOP) { ti_i2c_write_2(sc, I2C_REG_CON, sc->sc_con_reg | I2C_CON_STP); } ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_ARDY | I2C_STAT_RDR | I2C_STAT_RRDY | I2C_STAT_XDR | I2C_STAT_XRDY); return (1); } if (sc->sc_buffer->flags & IIC_M_RD) { /* Read some data. */ if (status & I2C_STAT_RDR) { /* * Receive draining interrupt - last data received. * The set FIFO threshold wont be reached to trigger * RRDY. */ ti_i2c_dbg(sc, "Receive draining interrupt\n"); /* * Drain the FIFO. Read the pending data in the FIFO. */ amount = sc->sc_buffer->len - sc->sc_buffer_pos; } else if (status & I2C_STAT_RRDY) { /* * Receive data ready interrupt - FIFO has reached the * set threshold. */ ti_i2c_dbg(sc, "Receive data ready interrupt\n"); amount = min(sc->sc_fifo_trsh, sc->sc_buffer->len - sc->sc_buffer_pos); } /* Read the bytes from the fifo. */ for (i = 0; i < amount; i++) sc->sc_buffer->buf[sc->sc_buffer_pos++] = (uint8_t)(ti_i2c_read_2(sc, I2C_REG_DATA) & 0xff); if (status & I2C_STAT_RDR) ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_RDR); if (status & I2C_STAT_RRDY) ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_RRDY); } else { /* Write some data. */ if (status & I2C_STAT_XDR) { /* * Transmit draining interrupt - FIFO level is below * the set threshold and the amount of data still to * be transferred wont reach the set FIFO threshold. */ ti_i2c_dbg(sc, "Transmit draining interrupt\n"); /* * Drain the TX data. Write the pending data in the * FIFO. */ amount = sc->sc_buffer->len - sc->sc_buffer_pos; } else if (status & I2C_STAT_XRDY) { /* * Transmit data ready interrupt - the FIFO level * is below the set threshold. */ ti_i2c_dbg(sc, "Transmit data ready interrupt\n"); amount = min(sc->sc_fifo_trsh, sc->sc_buffer->len - sc->sc_buffer_pos); } /* Write the bytes from the fifo. */ for (i = 0; i < amount; i++) ti_i2c_write_2(sc, I2C_REG_DATA, sc->sc_buffer->buf[sc->sc_buffer_pos++]); if (status & I2C_STAT_XDR) ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_XDR); if (status & I2C_STAT_XRDY) ti_i2c_write_2(sc, I2C_REG_STATUS, I2C_STAT_XRDY); } return (done); } /** * ti_i2c_intr - interrupt handler for the I2C module * @dev: i2c device handle * * * * LOCKING: * Called from timer context * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ static void ti_i2c_intr(void *arg) { int done; struct ti_i2c_softc *sc; uint16_t events, status; sc = (struct ti_i2c_softc *)arg; TI_I2C_LOCK(sc); status = ti_i2c_read_2(sc, I2C_REG_STATUS); if (status == 0) { TI_I2C_UNLOCK(sc); return; } /* Save enabled interrupts. */ events = ti_i2c_read_2(sc, I2C_REG_IRQENABLE_SET); /* We only care about enabled interrupts. */ status &= events; done = 0; if (sc->sc_buffer != NULL) done = ti_i2c_transfer_intr(sc, status); else { ti_i2c_dbg(sc, "Transfer interrupt without buffer\n"); sc->sc_error = EINVAL; done = 1; } if (done) /* Wakeup the process that started the transaction. */ wakeup(sc); TI_I2C_UNLOCK(sc); } /** * ti_i2c_transfer - called to perform the transfer * @dev: i2c device handle * @msgs: the messages to send/receive * @nmsgs: the number of messages in the msgs array * * * LOCKING: * Internally locked * * RETURNS: * 0 on function succeeded * EINVAL if invalid message is passed as an arg */ static int ti_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) { int err, i, repstart, timeout; struct ti_i2c_softc *sc; uint16_t reg; sc = device_get_softc(dev); TI_I2C_LOCK(sc); /* If the controller is busy wait until it is available. */ while (sc->sc_bus_inuse == 1) mtx_sleep(sc, &sc->sc_mtx, 0, "i2cbuswait", 0); /* Now we have control over the I2C controller. */ sc->sc_bus_inuse = 1; err = 0; repstart = 0; for (i = 0; i < nmsgs; i++) { sc->sc_buffer = &msgs[i]; sc->sc_buffer_pos = 0; sc->sc_error = 0; /* Zero byte transfers aren't allowed. */ if (sc->sc_buffer == NULL || sc->sc_buffer->buf == NULL || sc->sc_buffer->len == 0) { err = EINVAL; break; } /* Check if the i2c bus is free. */ if (repstart == 0) { /* * On repeated start we send the START condition while * the bus _is_ busy. */ timeout = 0; while (ti_i2c_read_2(sc, I2C_REG_STATUS_RAW) & I2C_STAT_BB) { if (timeout++ > 100) { err = EBUSY; goto out; } DELAY(1000); } timeout = 0; } else repstart = 0; if (sc->sc_buffer->flags & IIC_M_NOSTOP) repstart = 1; /* Set the slave address. */ ti_i2c_write_2(sc, I2C_REG_SA, msgs[i].slave >> 1); /* Write the data length. */ ti_i2c_write_2(sc, I2C_REG_CNT, sc->sc_buffer->len); /* Clear the RX and the TX FIFO. */ reg = ti_i2c_read_2(sc, I2C_REG_BUF); reg |= I2C_BUF_RXFIFO_CLR | I2C_BUF_TXFIFO_CLR; ti_i2c_write_2(sc, I2C_REG_BUF, reg); reg = sc->sc_con_reg | I2C_CON_STT; if (repstart == 0) reg |= I2C_CON_STP; if ((sc->sc_buffer->flags & IIC_M_RD) == 0) reg |= I2C_CON_TRX; ti_i2c_write_2(sc, I2C_REG_CON, reg); /* Wait for an event. */ err = mtx_sleep(sc, &sc->sc_mtx, 0, "i2ciowait", sc->sc_timeout); if (err == 0) err = sc->sc_error; if (err) break; } out: if (timeout == 0) { while (ti_i2c_read_2(sc, I2C_REG_STATUS_RAW) & I2C_STAT_BB) { if (timeout++ > 100) break; DELAY(1000); } } /* Put the controller in master mode again. */ if ((ti_i2c_read_2(sc, I2C_REG_CON) & I2C_CON_MST) == 0) ti_i2c_write_2(sc, I2C_REG_CON, sc->sc_con_reg); sc->sc_buffer = NULL; sc->sc_bus_inuse = 0; /* Wake up the processes that are waiting for the bus. */ wakeup(sc); TI_I2C_UNLOCK(sc); return (err); } static int ti_i2c_reset(struct ti_i2c_softc *sc, u_char speed) { int timeout; struct ti_i2c_clock_config *clkcfg; u_int busfreq; uint16_t fifo_trsh, reg, scll, sclh; switch (ti_chip()) { #ifdef SOC_OMAP4 case CHIP_OMAP_4: clkcfg = ti_omap4_i2c_clock_configs; break; #endif #ifdef SOC_TI_AM335X case CHIP_AM335X: clkcfg = ti_am335x_i2c_clock_configs; break; #endif default: panic("Unknown Ti SoC, unable to reset the i2c"); } /* * If we haven't attached the bus yet, just init at the default slow * speed. This lets us get the hardware initialized enough to attach * the bus which is where the real speed configuration is handled. After * the bus is attached, get the configured speed from it. Search the * configuration table for the best speed we can do that doesn't exceed * the requested speed. */ if (sc->sc_iicbus == NULL) busfreq = 100000; else busfreq = IICBUS_GET_FREQUENCY(sc->sc_iicbus, speed); for (;;) { if (clkcfg[1].frequency == 0 || clkcfg[1].frequency > busfreq) break; clkcfg++; } /* * 23.1.4.3 - HS I2C Software Reset * From OMAP4 TRM at page 4068. * * 1. Ensure that the module is disabled. */ sc->sc_con_reg = 0; ti_i2c_write_2(sc, I2C_REG_CON, sc->sc_con_reg); /* 2. Issue a softreset to the controller. */ bus_write_2(sc->sc_mem_res, I2C_REG_SYSC, I2C_REG_SYSC_SRST); /* * 3. Enable the module. * The I2Ci.I2C_SYSS[0] RDONE bit is asserted only after the module * is enabled by setting the I2Ci.I2C_CON[15] I2C_EN bit to 1. */ ti_i2c_write_2(sc, I2C_REG_CON, I2C_CON_I2C_EN); /* 4. Wait for the software reset to complete. */ timeout = 0; while ((ti_i2c_read_2(sc, I2C_REG_SYSS) & I2C_SYSS_RDONE) == 0) { if (timeout++ > 100) return (EBUSY); DELAY(100); } /* * Disable the I2C controller once again, now that the reset has * finished. */ ti_i2c_write_2(sc, I2C_REG_CON, sc->sc_con_reg); /* * The following sequence is taken from the OMAP4 TRM at page 4077. * * 1. Enable the functional and interface clocks (see Section * 23.1.5.1.1.1.1). Done at ti_i2c_activate(). * * 2. Program the prescaler to obtain an approximately 12MHz internal * sampling clock (I2Ci_INTERNAL_CLK) by programming the * corresponding value in the I2Ci.I2C_PSC[3:0] PSC field. * This value depends on the frequency of the functional clock * (I2Ci_FCLK). Because this frequency is 96MHz, the * I2Ci.I2C_PSC[7:0] PSC field value is 0x7. */ ti_i2c_write_2(sc, I2C_REG_PSC, clkcfg->psc); /* * 3. Program the I2Ci.I2C_SCLL[7:0] SCLL and I2Ci.I2C_SCLH[7:0] SCLH * bit fields to obtain a bit rate of 100 Kbps, 400 Kbps or 1Mbps. * These values depend on the internal sampling clock frequency * (see Table 23-8). */ scll = clkcfg->scll & I2C_SCLL_MASK; sclh = clkcfg->sclh & I2C_SCLH_MASK; /* * 4. (Optional) Program the I2Ci.I2C_SCLL[15:8] HSSCLL and * I2Ci.I2C_SCLH[15:8] HSSCLH fields to obtain a bit rate of * 400K bps or 3.4M bps (for the second phase of HS mode). These * values depend on the internal sampling clock frequency (see * Table 23-8). * * 5. (Optional) If a bit rate of 3.4M bps is used and the bus line * capacitance exceeds 45 pF, (see Section 18.4.8, PAD Functional * Multiplexing and Configuration). */ switch (ti_chip()) { #ifdef SOC_OMAP4 case CHIP_OMAP_4: if ((clkcfg->hsscll + clkcfg->hssclh) > 0) { scll |= clkcfg->hsscll << I2C_HSSCLL_SHIFT; sclh |= clkcfg->hssclh << I2C_HSSCLH_SHIFT; sc->sc_con_reg |= I2C_CON_OPMODE_HS; } break; #endif } /* Write the selected bit rate. */ ti_i2c_write_2(sc, I2C_REG_SCLL, scll); ti_i2c_write_2(sc, I2C_REG_SCLH, sclh); /* * 6. Configure the Own Address of the I2C controller by storing it in * the I2Ci.I2C_OA0 register. Up to four Own Addresses can be * programmed in the I2Ci.I2C_OAi registers (where i = 0, 1, 2, 3) * for each I2C controller. * * Note: For a 10-bit address, set the corresponding expand Own Address * bit in the I2Ci.I2C_CON register. * * Driver currently always in single master mode so ignore this step. */ /* * 7. Set the TX threshold (in transmitter mode) and the RX threshold * (in receiver mode) by setting the I2Ci.I2C_BUF[5:0]XTRSH field to * (TX threshold - 1) and the I2Ci.I2C_BUF[13:8]RTRSH field to (RX * threshold - 1), where the TX and RX thresholds are greater than * or equal to 1. * * The threshold is set to 5 for now. */ fifo_trsh = (sc->sc_fifo_trsh - 1) & I2C_BUF_TRSH_MASK; reg = fifo_trsh | (fifo_trsh << I2C_BUF_RXTRSH_SHIFT); ti_i2c_write_2(sc, I2C_REG_BUF, reg); /* * 8. Take the I2C controller out of reset by setting the * I2Ci.I2C_CON[15] I2C_EN bit to 1. * * 23.1.5.1.1.1.2 - Initialize the I2C Controller * * To initialize the I2C controller, perform the following steps: * * 1. Configure the I2Ci.I2C_CON register: * . For master or slave mode, set the I2Ci.I2C_CON[10] MST bit * (0: slave, 1: master). * . For transmitter or receiver mode, set the I2Ci.I2C_CON[9] TRX * bit (0: receiver, 1: transmitter). */ /* Enable the I2C controller in master mode. */ sc->sc_con_reg |= I2C_CON_I2C_EN | I2C_CON_MST; ti_i2c_write_2(sc, I2C_REG_CON, sc->sc_con_reg); /* * 2. If using an interrupt to transmit/receive data, set the * corresponding bit in the I2Ci.I2C_IE register (the I2Ci.I2C_IE[4] * XRDY_IE bit for the transmit interrupt, the I2Ci.I2C_IE[3] RRDY * bit for the receive interrupt). */ /* Set the interrupts we want to be notified. */ reg = I2C_IE_XDR | /* Transmit draining interrupt. */ I2C_IE_XRDY | /* Transmit Data Ready interrupt. */ I2C_IE_RDR | /* Receive draining interrupt. */ I2C_IE_RRDY | /* Receive Data Ready interrupt. */ I2C_IE_ARDY | /* Register Access Ready interrupt. */ I2C_IE_NACK | /* No Acknowledgment interrupt. */ I2C_IE_AL; /* Arbitration lost interrupt. */ /* Enable the interrupts. */ ti_i2c_write_2(sc, I2C_REG_IRQENABLE_SET, reg); /* * 3. If using DMA to receive/transmit data, set to 1 the corresponding * bit in the I2Ci.I2C_BUF register (the I2Ci.I2C_BUF[15] RDMA_EN * bit for the receive DMA channel, the I2Ci.I2C_BUF[7] XDMA_EN bit * for the transmit DMA channel). * * Not using DMA for now, so ignore this. */ return (0); } static int ti_i2c_iicbus_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { struct ti_i2c_softc *sc; int err; sc = device_get_softc(dev); TI_I2C_LOCK(sc); err = ti_i2c_reset(sc, speed); TI_I2C_UNLOCK(sc); if (err) return (err); return (IIC_ENOADDR); } static int ti_i2c_activate(device_t dev) { - clk_ident_t clk; int err; struct ti_i2c_softc *sc; sc = (struct ti_i2c_softc*)device_get_softc(dev); /* * 1. Enable the functional and interface clocks (see Section * 23.1.5.1.1.1.1). */ - clk = I2C0_CLK + sc->device_id; - err = ti_prcm_clk_enable(clk); + err = ti_prcm_clk_enable(sc->clk_id); if (err) return (err); return (ti_i2c_reset(sc, IIC_UNKNOWN)); } /** * ti_i2c_deactivate - deactivates the controller and releases resources * @dev: i2c device handle * * * * LOCKING: * Assumed called in an atomic context. * * RETURNS: * nothing */ static void ti_i2c_deactivate(device_t dev) { struct ti_i2c_softc *sc = device_get_softc(dev); - clk_ident_t clk; /* Disable the controller - cancel all transactions. */ ti_i2c_write_2(sc, I2C_REG_IRQENABLE_CLR, 0xffff); ti_i2c_write_2(sc, I2C_REG_STATUS, 0xffff); ti_i2c_write_2(sc, I2C_REG_CON, 0); /* Release the interrupt handler. */ if (sc->sc_irq_h != NULL) { bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h); sc->sc_irq_h = NULL; } bus_generic_detach(sc->sc_dev); /* Unmap the I2C controller registers. */ if (sc->sc_mem_res != NULL) { bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); sc->sc_mem_res = NULL; } /* Release the IRQ resource. */ if (sc->sc_irq_res != NULL) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); sc->sc_irq_res = NULL; } /* Finally disable the functional and interface clocks. */ - clk = I2C0_CLK + sc->device_id; - ti_prcm_clk_disable(clk); + ti_prcm_clk_disable(sc->clk_id); } static int ti_i2c_sysctl_clk(SYSCTL_HANDLER_ARGS) { int clk, psc, sclh, scll; struct ti_i2c_softc *sc; sc = arg1; TI_I2C_LOCK(sc); /* Get the system prescaler value. */ psc = (int)ti_i2c_read_2(sc, I2C_REG_PSC) + 1; /* Get the bitrate. */ scll = (int)ti_i2c_read_2(sc, I2C_REG_SCLL) & I2C_SCLL_MASK; sclh = (int)ti_i2c_read_2(sc, I2C_REG_SCLH) & I2C_SCLH_MASK; clk = I2C_CLK / psc / (scll + 7 + sclh + 5); TI_I2C_UNLOCK(sc); return (sysctl_handle_int(oidp, &clk, 0, req)); } static int ti_i2c_sysctl_timeout(SYSCTL_HANDLER_ARGS) { struct ti_i2c_softc *sc; unsigned int val; int err; sc = arg1; /* * MTX_DEF lock can't be held while doing uimove in * sysctl_handle_int */ TI_I2C_LOCK(sc); val = sc->sc_timeout; TI_I2C_UNLOCK(sc); err = sysctl_handle_int(oidp, &val, 0, req); /* Write request? */ if ((err == 0) && (req->newptr != NULL)) { TI_I2C_LOCK(sc); sc->sc_timeout = val; TI_I2C_UNLOCK(sc); } return (err); } static int ti_i2c_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,i2c")) + if (!ofw_bus_is_compatible(dev, "ti,omap4-i2c")) return (ENXIO); device_set_desc(dev, "TI I2C Controller"); return (0); } static int ti_i2c_attach(device_t dev) { int err, rid; phandle_t node; struct ti_i2c_softc *sc; struct sysctl_ctx_list *ctx; struct sysctl_oid_list *tree; uint16_t fifosz; sc = device_get_softc(dev); sc->sc_dev = dev; /* Get the i2c device id from FDT. */ node = ofw_bus_get_node(dev); - if ((OF_getencprop(node, "i2c-device-id", &sc->device_id, - sizeof(sc->device_id))) <= 0) { - device_printf(dev, "missing i2c-device-id attribute in FDT\n"); + /* i2c ti,hwmods bindings is special: it start with index 1 */ + sc->clk_id = ti_hwmods_get_clock(dev); + if (sc->clk_id == INVALID_CLK_IDENT) { + device_printf(dev, "failed to get device id using ti,hwmod\n"); return (ENXIO); } /* Get the memory resource for the register mapping. */ rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_mem_res == NULL) { device_printf(dev, "Cannot map registers.\n"); return (ENXIO); } /* Allocate our IRQ resource. */ rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->sc_irq_res == NULL) { bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); device_printf(dev, "Cannot allocate interrupt.\n"); return (ENXIO); } TI_I2C_LOCK_INIT(sc); /* First of all, we _must_ activate the H/W. */ err = ti_i2c_activate(dev); if (err) { device_printf(dev, "ti_i2c_activate failed\n"); goto out; } /* Read the version number of the I2C module */ sc->sc_rev = ti_i2c_read_2(sc, I2C_REG_REVNB_HI) & 0xff; /* Get the fifo size. */ fifosz = ti_i2c_read_2(sc, I2C_REG_BUFSTAT); fifosz >>= I2C_BUFSTAT_FIFODEPTH_SHIFT; fifosz &= I2C_BUFSTAT_FIFODEPTH_MASK; device_printf(dev, "I2C revision %d.%d FIFO size: %d bytes\n", sc->sc_rev >> 4, sc->sc_rev & 0xf, 8 << fifosz); /* Set the FIFO threshold to 5 for now. */ sc->sc_fifo_trsh = 5; /* Set I2C bus timeout */ sc->sc_timeout = 5*hz; ctx = device_get_sysctl_ctx(dev); tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "i2c_clock", CTLFLAG_RD | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, ti_i2c_sysctl_clk, "IU", "I2C bus clock"); SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "i2c_timeout", CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0, ti_i2c_sysctl_timeout, "IU", "I2C bus timeout (in ticks)"); /* Activate the interrupt. */ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, ti_i2c_intr, sc, &sc->sc_irq_h); if (err) goto out; /* Attach the iicbus. */ if ((sc->sc_iicbus = device_add_child(dev, "iicbus", -1)) == NULL) { device_printf(dev, "could not allocate iicbus instance\n"); err = ENXIO; goto out; } /* Probe and attach the iicbus */ bus_generic_attach(dev); out: if (err) { ti_i2c_deactivate(dev); TI_I2C_LOCK_DESTROY(sc); } return (err); } static int ti_i2c_detach(device_t dev) { struct ti_i2c_softc *sc; int rv; sc = device_get_softc(dev); ti_i2c_deactivate(dev); TI_I2C_LOCK_DESTROY(sc); if (sc->sc_iicbus && (rv = device_delete_child(dev, sc->sc_iicbus)) != 0) return (rv); return (0); } static phandle_t ti_i2c_get_node(device_t bus, device_t dev) { /* Share controller node with iibus device. */ return (ofw_bus_get_node(bus)); } static device_method_t ti_i2c_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ti_i2c_probe), DEVMETHOD(device_attach, ti_i2c_attach), DEVMETHOD(device_detach, ti_i2c_detach), /* Bus interface */ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), /* OFW methods */ DEVMETHOD(ofw_bus_get_node, ti_i2c_get_node), /* iicbus interface */ DEVMETHOD(iicbus_callback, iicbus_null_callback), DEVMETHOD(iicbus_reset, ti_i2c_iicbus_reset), DEVMETHOD(iicbus_transfer, ti_i2c_transfer), DEVMETHOD_END }; static driver_t ti_i2c_driver = { "iichb", ti_i2c_methods, sizeof(struct ti_i2c_softc), }; static devclass_t ti_i2c_devclass; DRIVER_MODULE(ti_iic, simplebus, ti_i2c_driver, ti_i2c_devclass, 0, 0); DRIVER_MODULE(iicbus, ti_iic, iicbus_driver, iicbus_devclass, 0, 0); MODULE_DEPEND(ti_iic, ti_prcm, 1, 1, 1); MODULE_DEPEND(ti_iic, iicbus, 1, 1, 1); Index: head/sys/arm/ti/ti_mbox.c =================================================================== --- head/sys/arm/ti/ti_mbox.c (revision 283275) +++ head/sys/arm/ti/ti_mbox.c (revision 283276) @@ -1,264 +1,264 @@ /*- * Copyright (c) 2013 Rui Paulo * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mbox_if.h" #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ printf("%s: ", __func__); \ printf(fmt, __VA_ARGS__); \ } while (0) #else #define DPRINTF(fmt, ...) #endif static device_probe_t ti_mbox_probe; static device_attach_t ti_mbox_attach; static device_detach_t ti_mbox_detach; static void ti_mbox_intr(void *); static int ti_mbox_read(device_t, int, uint32_t *); static int ti_mbox_write(device_t, int, uint32_t); struct ti_mbox_softc { struct mtx sc_mtx; struct resource *sc_mem_res; struct resource *sc_irq_res; void *sc_intr; bus_space_tag_t sc_bt; bus_space_handle_t sc_bh; }; #define TI_MBOX_LOCK(sc) mtx_lock(&(sc)->sc_mtx) #define TI_MBOX_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) static device_method_t ti_mbox_methods[] = { DEVMETHOD(device_probe, ti_mbox_probe), DEVMETHOD(device_attach, ti_mbox_attach), DEVMETHOD(device_detach, ti_mbox_detach), DEVMETHOD(mbox_read, ti_mbox_read), DEVMETHOD(mbox_write, ti_mbox_write), DEVMETHOD_END }; static driver_t ti_mbox_driver = { "ti_mbox", ti_mbox_methods, sizeof(struct ti_mbox_softc) }; static devclass_t ti_mbox_devclass; DRIVER_MODULE(ti_mbox, simplebus, ti_mbox_driver, ti_mbox_devclass, 0, 0); static __inline uint32_t ti_mbox_reg_read(struct ti_mbox_softc *sc, uint16_t reg) { return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg)); } static __inline void ti_mbox_reg_write(struct ti_mbox_softc *sc, uint16_t reg, uint32_t val) { bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val); } static int ti_mbox_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (ofw_bus_is_compatible(dev, "ti,system-mbox")) { + if (ofw_bus_is_compatible(dev, "ti,omap4-mailbox")) { device_set_desc(dev, "TI System Mailbox"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int ti_mbox_attach(device_t dev) { struct ti_mbox_softc *sc; int rid, delay, chan; uint32_t rev, sysconfig; if (ti_prcm_clk_enable(MAILBOX0_CLK) != 0) { device_printf(dev, "could not enable MBOX clock\n"); return (ENXIO); } sc = device_get_softc(dev); rid = 0; mtx_init(&sc->sc_mtx, "TI mbox", NULL, MTX_DEF); sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_mem_res == NULL) { device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); } sc->sc_bt = rman_get_bustag(sc->sc_mem_res); sc->sc_bh = rman_get_bushandle(sc->sc_mem_res); rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(dev, "could not allocate interrupt resource\n"); ti_mbox_detach(dev); return (ENXIO); } if (bus_setup_intr(dev, sc->sc_irq_res, INTR_MPSAFE | INTR_TYPE_MISC, NULL, ti_mbox_intr, sc, &sc->sc_intr) != 0) { device_printf(dev, "unable to setup the interrupt handler\n"); ti_mbox_detach(dev); return (ENXIO); } /* * Reset the controller. */ sysconfig = ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG); DPRINTF("initial sysconfig %d\n", sysconfig); sysconfig |= TI_MBOX_SYSCONFIG_SOFTRST; delay = 100; while (ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG) & TI_MBOX_SYSCONFIG_SOFTRST) { delay--; DELAY(10); } if (delay == 0) { device_printf(dev, "controller reset failed\n"); ti_mbox_detach(dev); return (ENXIO); } /* * Enable smart idle mode. */ ti_mbox_reg_write(sc, TI_MBOX_SYSCONFIG, ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG) | TI_MBOX_SYSCONFIG_SMARTIDLE); rev = ti_mbox_reg_read(sc, TI_MBOX_REVISION); DPRINTF("rev %d\n", rev); device_printf(dev, "revision %d.%d\n", (rev >> 8) & 0x4, rev & 0x40); /* * Enable message interrupts. */ for (chan = 0; chan < 8; chan++) ti_mbox_reg_write(sc, TI_MBOX_IRQENABLE_SET(chan), 1); return (0); } static int ti_mbox_detach(device_t dev) { struct ti_mbox_softc *sc; sc = device_get_softc(dev); if (sc->sc_intr) bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr); if (sc->sc_irq_res) bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res), sc->sc_irq_res); if (sc->sc_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_mem_res), sc->sc_mem_res); return (0); } static void ti_mbox_intr(void *arg) { struct ti_mbox_softc *sc; sc = arg; DPRINTF("interrupt %p", sc); } static int ti_mbox_read(device_t dev, int chan, uint32_t *data) { struct ti_mbox_softc *sc; if (chan < 0 || chan > 7) return (EINVAL); sc = device_get_softc(dev); return (ti_mbox_reg_read(sc, TI_MBOX_MESSAGE(chan))); } static int ti_mbox_write(device_t dev, int chan, uint32_t data) { int limit = 500; struct ti_mbox_softc *sc; if (chan < 0 || chan > 7) return (EINVAL); sc = device_get_softc(dev); TI_MBOX_LOCK(sc); /* XXX implement interrupt method */ while (ti_mbox_reg_read(sc, TI_MBOX_FIFOSTATUS(chan)) == 1 && limit--) { DELAY(10); } if (limit == 0) { device_printf(dev, "FIFOSTAUS%d stuck\n", chan); TI_MBOX_UNLOCK(sc); return (EAGAIN); } ti_mbox_reg_write(sc, TI_MBOX_MESSAGE(chan), data); return (0); } Index: head/sys/arm/ti/ti_pinmux.c =================================================================== --- head/sys/arm/ti/ti_pinmux.c (nonexistent) +++ head/sys/arm/ti/ti_pinmux.c (revision 283276) @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/** + * Exposes pinmux module to pinctrl-compatible interface + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ti_pinmux.h" + +struct pincfg { + uint32_t reg; + uint32_t conf; +}; + +static struct resource_spec ti_pinmux_res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */ + { -1, 0 } +}; + +static struct ti_pinmux_softc *ti_pinmux_sc; + +#define ti_pinmux_read_2(sc, reg) \ + bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define ti_pinmux_write_2(sc, reg, val) \ + bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) +#define ti_pinmux_read_4(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define ti_pinmux_write_4(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + + +/** + * ti_padconf_devmap - Array of pins, should be defined one per SoC + * + * This array is typically defined in one of the targeted *_scm_pinumx.c + * files and is specific to the given SoC platform. Each entry in the array + * corresponds to an individual pin. + */ +extern const struct ti_pinmux_device ti_pinmux_dev; + + +/** + * ti_pinmux_padconf_from_name - searches the list of pads and returns entry + * with matching ball name. + * @ballname: the name of the ball + * + * RETURNS: + * A pointer to the matching padconf or NULL if the ball wasn't found. + */ +static const struct ti_pinmux_padconf* +ti_pinmux_padconf_from_name(const char *ballname) +{ + const struct ti_pinmux_padconf *padconf; + + padconf = ti_pinmux_dev.padconf; + while (padconf->ballname != NULL) { + if (strcmp(ballname, padconf->ballname) == 0) + return(padconf); + padconf++; + } + + return (NULL); +} + +/** + * ti_pinmux_padconf_set_internal - sets the muxmode and state for a pad/pin + * @padconf: pointer to the pad structure + * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx" + * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or already in use. + */ +static int +ti_pinmux_padconf_set_internal(struct ti_pinmux_softc *sc, + const struct ti_pinmux_padconf *padconf, + const char *muxmode, unsigned int state) +{ + unsigned int mode; + uint16_t reg_val; + + /* populate the new value for the PADCONF register */ + reg_val = (uint16_t)(state & ti_pinmux_dev.padconf_sate_mask); + + /* find the new mode requested */ + for (mode = 0; mode < 8; mode++) { + if ((padconf->muxmodes[mode] != NULL) && + (strcmp(padconf->muxmodes[mode], muxmode) == 0)) { + break; + } + } + + /* couldn't find the mux mode */ + if (mode >= 8) { + printf("Invalid mode \"%s\"\n", muxmode); + return (EINVAL); + } + + /* set the mux mode */ + reg_val |= (uint16_t)(mode & ti_pinmux_dev.padconf_muxmode_mask); + + if (bootverbose) + device_printf(sc->sc_dev, "setting internal %x for %s\n", + reg_val, muxmode); + /* write the register value (16-bit writes) */ + ti_pinmux_write_2(sc, padconf->reg_off, reg_val); + + return (0); +} + +/** + * ti_pinmux_padconf_set - sets the muxmode and state for a pad/pin + * @padname: the name of the pad, i.e. "c12" + * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx" + * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or already in use. + */ +int +ti_pinmux_padconf_set(const char *padname, const char *muxmode, unsigned int state) +{ + const struct ti_pinmux_padconf *padconf; + + if (!ti_pinmux_sc) + return (ENXIO); + + /* find the pin in the devmap */ + padconf = ti_pinmux_padconf_from_name(padname); + if (padconf == NULL) + return (EINVAL); + + return (ti_pinmux_padconf_set_internal(ti_pinmux_sc, padconf, muxmode, state)); +} + +/** + * ti_pinmux_padconf_get - gets the muxmode and state for a pad/pin + * @padname: the name of the pad, i.e. "c12" + * @muxmode: upon return will contain the name of the muxmode of the pin + * @state: upon return will contain the state of the pad/pin + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or already in use. + */ +int +ti_pinmux_padconf_get(const char *padname, const char **muxmode, + unsigned int *state) +{ + const struct ti_pinmux_padconf *padconf; + uint16_t reg_val; + + if (!ti_pinmux_sc) + return (ENXIO); + + /* find the pin in the devmap */ + padconf = ti_pinmux_padconf_from_name(padname); + if (padconf == NULL) + return (EINVAL); + + /* read the register value (16-bit reads) */ + reg_val = ti_pinmux_read_2(ti_pinmux_sc, padconf->reg_off); + + /* save the state */ + if (state) + *state = (reg_val & ti_pinmux_dev.padconf_sate_mask); + + /* save the mode */ + if (muxmode) + *muxmode = padconf->muxmodes[(reg_val & ti_pinmux_dev.padconf_muxmode_mask)]; + + return (0); +} + +/** + * ti_pinmux_padconf_set_gpiomode - converts a pad to GPIO mode. + * @gpio: the GPIO pin number (0-195) + * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? + * + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or already in use. + */ +int +ti_pinmux_padconf_set_gpiomode(uint32_t gpio, unsigned int state) +{ + const struct ti_pinmux_padconf *padconf; + uint16_t reg_val; + + if (!ti_pinmux_sc) + return (ENXIO); + + /* find the gpio pin in the padconf array */ + padconf = ti_pinmux_dev.padconf; + while (padconf->ballname != NULL) { + if (padconf->gpio_pin == gpio) + break; + padconf++; + } + if (padconf->ballname == NULL) + return (EINVAL); + + /* populate the new value for the PADCONF register */ + reg_val = (uint16_t)(state & ti_pinmux_dev.padconf_sate_mask); + + /* set the mux mode */ + reg_val |= (uint16_t)(padconf->gpio_mode & ti_pinmux_dev.padconf_muxmode_mask); + + /* write the register value (16-bit writes) */ + ti_pinmux_write_2(ti_pinmux_sc, padconf->reg_off, reg_val); + + return (0); +} + +/** + * ti_pinmux_padconf_get_gpiomode - gets the current GPIO mode of the pin + * @gpio: the GPIO pin number (0-195) + * @state: upon return will contain the state + * + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or not configured as GPIO. + */ +int +ti_pinmux_padconf_get_gpiomode(uint32_t gpio, unsigned int *state) +{ + const struct ti_pinmux_padconf *padconf; + uint16_t reg_val; + + if (!ti_pinmux_sc) + return (ENXIO); + + /* find the gpio pin in the padconf array */ + padconf = ti_pinmux_dev.padconf; + while (padconf->ballname != NULL) { + if (padconf->gpio_pin == gpio) + break; + padconf++; + } + if (padconf->ballname == NULL) + return (EINVAL); + + /* read the current register settings */ + reg_val = ti_pinmux_read_2(ti_pinmux_sc, padconf->reg_off); + + /* check to make sure the pins is configured as GPIO in the first state */ + if ((reg_val & ti_pinmux_dev.padconf_muxmode_mask) != padconf->gpio_mode) + return (EINVAL); + + /* read and store the reset of the state, i.e. pull-up, pull-down, etc */ + if (state) + *state = (reg_val & ti_pinmux_dev.padconf_sate_mask); + + return (0); +} + +static int +ti_pinmux_configure_pins(device_t dev, phandle_t cfgxref) +{ + struct pincfg *cfgtuples, *cfg; + phandle_t cfgnode; + int i, ntuples; + static struct ti_pinmux_softc *sc; + + sc = device_get_softc(dev); + cfgnode = OF_node_from_xref(cfgxref); + ntuples = OF_getencprop_alloc(cfgnode, "pinctrl-single,pins", sizeof(*cfgtuples), + (void **)&cfgtuples); + + if (ntuples < 0) + return (ENOENT); + + if (ntuples == 0) + return (0); /* Empty property is not an error. */ + + for (i = 0, cfg = cfgtuples; i < ntuples; i++, cfg++) { + if (bootverbose) { + char name[32]; + OF_getprop(cfgnode, "name", &name, sizeof(name)); + printf("%16s: muxreg 0x%04x muxval 0x%02x\n", + name, cfg->reg, cfg->conf); + } + + /* write the register value (16-bit writes) */ + ti_pinmux_write_2(sc, cfg->reg, cfg->conf); + } + + free(cfgtuples, M_OFWPROP); + + return (0); +} + +/* + * Device part of OMAP SCM driver + */ + +static int +ti_pinmux_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "pinctrl-single")) + return (ENXIO); + + if (ti_pinmux_sc) { + printf("%s: multiple pinctrl modules in device tree data, ignoring\n", + __func__); + return (EEXIST); + } + + device_set_desc(dev, "TI Pinmux Module"); + return (BUS_PROBE_DEFAULT); +} + +/** + * ti_pinmux_attach - attaches the pinmux to the simplebus + * @dev: new device + * + * RETURNS + * Zero on sucess or ENXIO if an error occuried. + */ +static int +ti_pinmux_attach(device_t dev) +{ + struct ti_pinmux_softc *sc = device_get_softc(dev); + +#if 0 + if (ti_pinmux_sc) + return (ENXIO); +#endif + + sc->sc_dev = dev; + + if (bus_alloc_resources(dev, ti_pinmux_res_spec, sc->sc_res)) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->sc_bst = rman_get_bustag(sc->sc_res[0]); + sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); + + if (ti_pinmux_sc == NULL) + ti_pinmux_sc = sc; + + fdt_pinctrl_register(dev, "pinctrl-single,pins"); + fdt_pinctrl_configure_tree(dev); + + return (0); +} + +static device_method_t ti_pinmux_methods[] = { + DEVMETHOD(device_probe, ti_pinmux_probe), + DEVMETHOD(device_attach, ti_pinmux_attach), + + /* fdt_pinctrl interface */ + DEVMETHOD(fdt_pinctrl_configure, ti_pinmux_configure_pins), + { 0, 0 } +}; + +static driver_t ti_pinmux_driver = { + "ti_pinmux", + ti_pinmux_methods, + sizeof(struct ti_pinmux_softc), +}; + +static devclass_t ti_pinmux_devclass; + +DRIVER_MODULE(ti_pinmux, simplebus, ti_pinmux_driver, ti_pinmux_devclass, 0, 0); Property changes on: head/sys/arm/ti/ti_pinmux.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/ti_pinmux.h =================================================================== --- head/sys/arm/ti/ti_pinmux.h (nonexistent) +++ head/sys/arm/ti/ti_pinmux.h (revision 283276) @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010 + * Ben Gray . + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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$ + */ + + +/** + * Functions to configure the PIN multiplexing on the chip. + * + * This is different from the GPIO module in that it is used to configure the + * pins between modules not just GPIO input output. + * + */ +#ifndef _TI_PINMUX_H_ +#define _TI_PINMUX_H_ + +struct ti_pinmux_padconf { + uint16_t reg_off; + uint16_t gpio_pin; + uint16_t gpio_mode; + const char *ballname; + const char *muxmodes[8]; +}; + +struct ti_pinmux_padstate { + const char *state; + uint16_t reg; +}; + +struct ti_pinmux_device { + uint16_t padconf_muxmode_mask; + uint16_t padconf_sate_mask; + const struct ti_pinmux_padstate *padstate; + const struct ti_pinmux_padconf *padconf; +}; + +struct ti_pinmux_softc { + device_t sc_dev; + struct resource * sc_res[4]; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; +}; + +int ti_pinmux_padconf_set(const char *padname, const char *muxmode, + unsigned int state); +int ti_pinmux_padconf_get(const char *padname, const char **muxmode, + unsigned int *state); +int ti_pinmux_padconf_set_gpiomode(uint32_t gpio, unsigned int state); +int ti_pinmux_padconf_get_gpiomode(uint32_t gpio, unsigned int *state); + +#endif /* _TI_SCM_H_ */ Property changes on: head/sys/arm/ti/ti_pinmux.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/ti_prcm.h =================================================================== --- head/sys/arm/ti/ti_prcm.h (revision 283275) +++ head/sys/arm/ti/ti_prcm.h (revision 283276) @@ -1,211 +1,200 @@ /* * Copyright (c) 2010 * Ben Gray . * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Ben Gray. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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$ */ /* * Texas Instruments - OMAP3xxx series processors * * Reference: * OMAP35x Applications Processor * Technical Reference Manual * (omap35xx_techref.pdf) */ #ifndef _TI_PRCM_H_ #define _TI_PRCM_H_ typedef enum { + INVALID_CLK_IDENT = 0, + /* System clocks, typically you can only call ti_prcm_clk_get_source_freq() * on these clocks as they are enabled by default. */ SYS_CLK = 1, /* The MPU (ARM) core clock */ MPU_CLK = 20, /* MMC modules */ - MMC0_CLK = 100, - MMC1_CLK, + MMC1_CLK = 100, MMC2_CLK, MMC3_CLK, MMC4_CLK, MMC5_CLK, + MMC6_CLK, /* I2C modules */ - I2C0_CLK = 200, - I2C1_CLK, + I2C1_CLK = 200, I2C2_CLK, I2C3_CLK, I2C4_CLK, + I2C5_CLK, /* USB module(s) */ USBTLL_CLK = 300, USBHSHOST_CLK, USBFSHOST_CLK, USBP1_PHY_CLK, USBP2_PHY_CLK, USBP1_UTMI_CLK, USBP2_UTMI_CLK, USBP1_HSIC_CLK, USBP2_HSIC_CLK, /* UART modules */ - UART0_CLK = 400, - UART1_CLK, + UART1_CLK = 400, UART2_CLK, UART3_CLK, UART4_CLK, UART5_CLK, UART6_CLK, UART7_CLK, UART8_CLK, + UART9_CLK, /* General purpose timer modules */ - GPTIMER1_CLK = 500, - GPTIMER2_CLK, - GPTIMER3_CLK, - GPTIMER4_CLK, - GPTIMER5_CLK, - GPTIMER6_CLK, - GPTIMER7_CLK, - GPTIMER8_CLK, - GPTIMER9_CLK, - GPTIMER10_CLK, - GPTIMER11_CLK, - GPTIMER12_CLK, + TIMER1_CLK = 500, + TIMER2_CLK, + TIMER3_CLK, + TIMER4_CLK, + TIMER5_CLK, + TIMER6_CLK, + TIMER7_CLK, + TIMER8_CLK, + TIMER9_CLK, + TIMER10_CLK, + TIMER11_CLK, + TIMER12_CLK, /* McBSP module(s) */ MCBSP1_CLK = 600, MCBSP2_CLK, MCBSP3_CLK, MCBSP4_CLK, MCBSP5_CLK, /* General purpose I/O modules */ - GPIO0_CLK = 700, - GPIO1_CLK, + GPIO1_CLK = 700, GPIO2_CLK, GPIO3_CLK, GPIO4_CLK, GPIO5_CLK, GPIO6_CLK, + GPIO7_CLK, /* sDMA module */ SDMA_CLK = 800, - /* DMTimer modules */ - DMTIMER0_CLK = 900, - DMTIMER1_CLK, - DMTIMER2_CLK, - DMTIMER3_CLK, - DMTIMER4_CLK, - DMTIMER5_CLK, - DMTIMER6_CLK, - DMTIMER7_CLK, - /* CPSW modules */ CPSW_CLK = 1000, /* Mentor USB modules */ MUSB0_CLK = 1100, /* EDMA module */ EDMA_TPCC_CLK = 1200, EDMA_TPTC0_CLK, EDMA_TPTC1_CLK, EDMA_TPTC2_CLK, /* LCD controller module */ LCDC_CLK = 1300, /* PWM modules */ PWMSS0_CLK = 1400, PWMSS1_CLK, PWMSS2_CLK, /* Mailbox modules */ MAILBOX0_CLK = 1500, /* Spinlock modules */ SPINLOCK0_CLK = 1600, PRUSS_CLK = 1700, TSC_ADC_CLK = 1800, /* RTC module */ RTC_CLK = 1900, - - INVALID_CLK_IDENT - } clk_ident_t; /* * */ typedef enum { SYSCLK_CLK, /* System clock */ EXT_CLK, F32KHZ_CLK, /* 32KHz clock */ F48MHZ_CLK, /* 48MHz clock */ F64MHZ_CLK, /* 64MHz clock */ F96MHZ_CLK, /* 96MHz clock */ } clk_src_t; struct ti_clock_dev { /* The profile of the timer */ clk_ident_t id; /* A bunch of callbacks associated with the clock device */ int (*clk_activate)(struct ti_clock_dev *clkdev); int (*clk_deactivate)(struct ti_clock_dev *clkdev); int (*clk_set_source)(struct ti_clock_dev *clkdev, clk_src_t clksrc); int (*clk_accessible)(struct ti_clock_dev *clkdev); int (*clk_get_source_freq)(struct ti_clock_dev *clkdev, unsigned int *freq); }; int ti_prcm_clk_valid(clk_ident_t clk); int ti_prcm_clk_enable(clk_ident_t clk); int ti_prcm_clk_disable(clk_ident_t clk); int ti_prcm_clk_accessible(clk_ident_t clk); int ti_prcm_clk_disable_autoidle(clk_ident_t clk); int ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc); int ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq); void ti_prcm_reset(void); #endif /* _TI_PRCM_H_ */ Index: head/sys/arm/ti/ti_scm.c =================================================================== --- head/sys/arm/ti/ti_scm.c (revision 283275) +++ head/sys/arm/ti/ti_scm.c (revision 283276) @@ -1,503 +1,175 @@ /* * Copyright (c) 2010 * Ben Gray . * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Ben Gray. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. */ /** * SCM - System Control Module * * Hopefully in the end this module will contain a bunch of utility functions * for configuring and querying the general system control registers, but for * now it only does pin(pad) multiplexing. * * This is different from the GPIO module in that it is used to configure the * pins between modules not just GPIO input/output. * * This file contains the generic top level driver, however it relies on chip * specific settings and therefore expects an array of ti_scm_padconf structs * call ti_padconf_devmap to be located somewhere in the kernel. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include "ti_scm.h" static struct resource_spec ti_scm_res_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */ { -1, 0 } }; static struct ti_scm_softc *ti_scm_sc; -#define ti_scm_read_2(sc, reg) \ - bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg)) -#define ti_scm_write_2(sc, reg, val) \ - bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) #define ti_scm_read_4(sc, reg) \ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) #define ti_scm_write_4(sc, reg, val) \ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) - -/** - * ti_padconf_devmap - Array of pins, should be defined one per SoC - * - * This array is typically defined in one of the targeted *_scm_pinumx.c - * files and is specific to the given SoC platform. Each entry in the array - * corresponds to an individual pin. - */ -extern const struct ti_scm_device ti_scm_dev; - - -/** - * ti_scm_padconf_from_name - searches the list of pads and returns entry - * with matching ball name. - * @ballname: the name of the ball - * - * RETURNS: - * A pointer to the matching padconf or NULL if the ball wasn't found. - */ -static const struct ti_scm_padconf* -ti_scm_padconf_from_name(const char *ballname) -{ - const struct ti_scm_padconf *padconf; - - padconf = ti_scm_dev.padconf; - while (padconf->ballname != NULL) { - if (strcmp(ballname, padconf->ballname) == 0) - return(padconf); - padconf++; - } - - return (NULL); -} - -/** - * ti_scm_padconf_set_internal - sets the muxmode and state for a pad/pin - * @padconf: pointer to the pad structure - * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx" - * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? - * - * - * LOCKING: - * Internally locks it's own context. - * - * RETURNS: - * 0 on success. - * EINVAL if pin requested is outside valid range or already in use. - */ -static int -ti_scm_padconf_set_internal(struct ti_scm_softc *sc, - const struct ti_scm_padconf *padconf, - const char *muxmode, unsigned int state) -{ - unsigned int mode; - uint16_t reg_val; - - /* populate the new value for the PADCONF register */ - reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask); - - /* find the new mode requested */ - for (mode = 0; mode < 8; mode++) { - if ((padconf->muxmodes[mode] != NULL) && - (strcmp(padconf->muxmodes[mode], muxmode) == 0)) { - break; - } - } - - /* couldn't find the mux mode */ - if (mode >= 8) { - printf("Invalid mode \"%s\"\n", muxmode); - return (EINVAL); - } - - /* set the mux mode */ - reg_val |= (uint16_t)(mode & ti_scm_dev.padconf_muxmode_mask); - - if (bootverbose) - device_printf(sc->sc_dev, "setting internal %x for %s\n", - reg_val, muxmode); - /* write the register value (16-bit writes) */ - ti_scm_write_2(sc, padconf->reg_off, reg_val); - - return (0); -} - -/** - * ti_scm_padconf_set - sets the muxmode and state for a pad/pin - * @padname: the name of the pad, i.e. "c12" - * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx" - * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? - * - * - * LOCKING: - * Internally locks it's own context. - * - * RETURNS: - * 0 on success. - * EINVAL if pin requested is outside valid range or already in use. - */ -int -ti_scm_padconf_set(const char *padname, const char *muxmode, unsigned int state) -{ - const struct ti_scm_padconf *padconf; - - if (!ti_scm_sc) - return (ENXIO); - - /* find the pin in the devmap */ - padconf = ti_scm_padconf_from_name(padname); - if (padconf == NULL) - return (EINVAL); - - return (ti_scm_padconf_set_internal(ti_scm_sc, padconf, muxmode, state)); -} - -/** - * ti_scm_padconf_get - gets the muxmode and state for a pad/pin - * @padname: the name of the pad, i.e. "c12" - * @muxmode: upon return will contain the name of the muxmode of the pin - * @state: upon return will contain the state of the pad/pin - * - * - * LOCKING: - * Internally locks it's own context. - * - * RETURNS: - * 0 on success. - * EINVAL if pin requested is outside valid range or already in use. - */ -int -ti_scm_padconf_get(const char *padname, const char **muxmode, - unsigned int *state) -{ - const struct ti_scm_padconf *padconf; - uint16_t reg_val; - - if (!ti_scm_sc) - return (ENXIO); - - /* find the pin in the devmap */ - padconf = ti_scm_padconf_from_name(padname); - if (padconf == NULL) - return (EINVAL); - - /* read the register value (16-bit reads) */ - reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off); - - /* save the state */ - if (state) - *state = (reg_val & ti_scm_dev.padconf_sate_mask); - - /* save the mode */ - if (muxmode) - *muxmode = padconf->muxmodes[(reg_val & ti_scm_dev.padconf_muxmode_mask)]; - - return (0); -} - -/** - * ti_scm_padconf_set_gpiomode - converts a pad to GPIO mode. - * @gpio: the GPIO pin number (0-195) - * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? - * - * - * - * LOCKING: - * Internally locks it's own context. - * - * RETURNS: - * 0 on success. - * EINVAL if pin requested is outside valid range or already in use. - */ -int -ti_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state) -{ - const struct ti_scm_padconf *padconf; - uint16_t reg_val; - - if (!ti_scm_sc) - return (ENXIO); - - /* find the gpio pin in the padconf array */ - padconf = ti_scm_dev.padconf; - while (padconf->ballname != NULL) { - if (padconf->gpio_pin == gpio) - break; - padconf++; - } - if (padconf->ballname == NULL) - return (EINVAL); - - /* populate the new value for the PADCONF register */ - reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask); - - /* set the mux mode */ - reg_val |= (uint16_t)(padconf->gpio_mode & ti_scm_dev.padconf_muxmode_mask); - - /* write the register value (16-bit writes) */ - ti_scm_write_2(ti_scm_sc, padconf->reg_off, reg_val); - - return (0); -} - -/** - * ti_scm_padconf_get_gpiomode - gets the current GPIO mode of the pin - * @gpio: the GPIO pin number (0-195) - * @state: upon return will contain the state - * - * - * - * LOCKING: - * Internally locks it's own context. - * - * RETURNS: - * 0 on success. - * EINVAL if pin requested is outside valid range or not configured as GPIO. - */ -int -ti_scm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state) -{ - const struct ti_scm_padconf *padconf; - uint16_t reg_val; - - if (!ti_scm_sc) - return (ENXIO); - - /* find the gpio pin in the padconf array */ - padconf = ti_scm_dev.padconf; - while (padconf->ballname != NULL) { - if (padconf->gpio_pin == gpio) - break; - padconf++; - } - if (padconf->ballname == NULL) - return (EINVAL); - - /* read the current register settings */ - reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off); - - /* check to make sure the pins is configured as GPIO in the first state */ - if ((reg_val & ti_scm_dev.padconf_muxmode_mask) != padconf->gpio_mode) - return (EINVAL); - - /* read and store the reset of the state, i.e. pull-up, pull-down, etc */ - if (state) - *state = (reg_val & ti_scm_dev.padconf_sate_mask); - - return (0); -} - -/** - * ti_scm_padconf_init_from_hints - processes the hints for padconf - * @sc: the driver soft context - * - * - * - * LOCKING: - * Internally locks it's own context. - * - * RETURNS: - * 0 on success. - * EINVAL if pin requested is outside valid range or already in use. - */ -static int -ti_scm_padconf_init_from_fdt(struct ti_scm_softc *sc) -{ - const struct ti_scm_padconf *padconf; - const struct ti_scm_padstate *padstates; - int err; - phandle_t node; - int len; - char *fdt_pad_config; - int i; - char *padname, *muxname, *padstate; - - node = ofw_bus_get_node(sc->sc_dev); - len = OF_getproplen(node, "scm-pad-config"); - OF_getprop_alloc(node, "scm-pad-config", 1, (void **)&fdt_pad_config); - - i = len; - while (i > 0) { - padname = fdt_pad_config; - fdt_pad_config += strlen(padname) + 1; - i -= strlen(padname) + 1; - if (i <= 0) - break; - - muxname = fdt_pad_config; - fdt_pad_config += strlen(muxname) + 1; - i -= strlen(muxname) + 1; - if (i <= 0) - break; - - padstate = fdt_pad_config; - fdt_pad_config += strlen(padstate) + 1; - i -= strlen(padstate) + 1; - if (i < 0) - break; - - padconf = ti_scm_dev.padconf; - - while (padconf->ballname != NULL) { - if (strcmp(padconf->ballname, padname) == 0) { - padstates = ti_scm_dev.padstate; - err = 1; - while (padstates->state != NULL) { - if (strcmp(padstates->state, padstate) == 0) { - err = ti_scm_padconf_set_internal(sc, - padconf, muxname, padstates->reg); - } - padstates++; - } - if (err) - device_printf(sc->sc_dev, - "err: failed to configure " - "pin \"%s\" as \"%s\"\n", - padconf->ballname, - muxname); - } - padconf++; - } - } - return (0); -} - /* * Device part of OMAP SCM driver */ - static int ti_scm_probe(device_t dev) { - if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,scm")) + if (!ofw_bus_is_compatible(dev, "syscon")) return (ENXIO); + if (ti_scm_sc) { + printf("%s: multiple SCM modules in device tree data, ignoring\n", + __func__); + return (EEXIST); + } + device_set_desc(dev, "TI Control Module"); return (BUS_PROBE_DEFAULT); } /** * ti_scm_attach - attaches the timer to the simplebus * @dev: new device * * Reserves memory and interrupt resources, stores the softc structure * globally and registers both the timecount and eventtimer objects. * * RETURNS * Zero on sucess or ENXIO if an error occuried. */ static int ti_scm_attach(device_t dev) { struct ti_scm_softc *sc = device_get_softc(dev); - if (ti_scm_sc) - return (ENXIO); - sc->sc_dev = dev; if (bus_alloc_resources(dev, ti_scm_res_spec, sc->sc_res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } /* Global timer interface */ sc->sc_bst = rman_get_bustag(sc->sc_res[0]); sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); ti_scm_sc = sc; - ti_scm_padconf_init_from_fdt(sc); - return (0); } int ti_scm_reg_read_4(uint32_t reg, uint32_t *val) { if (!ti_scm_sc) return (ENXIO); *val = ti_scm_read_4(ti_scm_sc, reg); return (0); } int ti_scm_reg_write_4(uint32_t reg, uint32_t val) { if (!ti_scm_sc) return (ENXIO); ti_scm_write_4(ti_scm_sc, reg, val); return (0); } static device_method_t ti_scm_methods[] = { DEVMETHOD(device_probe, ti_scm_probe), DEVMETHOD(device_attach, ti_scm_attach), + { 0, 0 } }; static driver_t ti_scm_driver = { "ti_scm", ti_scm_methods, sizeof(struct ti_scm_softc), }; static devclass_t ti_scm_devclass; DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, ti_scm_devclass, 0, 0); Index: head/sys/arm/ti/ti_scm.h =================================================================== --- head/sys/arm/ti/ti_scm.h (revision 283275) +++ head/sys/arm/ti/ti_scm.h (revision 283276) @@ -1,82 +1,56 @@ /* * Copyright (c) 2010 * Ben Gray . * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Ben Gray. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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$ */ /** * Functions to configure the PIN multiplexing on the chip. * * This is different from the GPIO module in that it is used to configure the * pins between modules not just GPIO input output. * */ #ifndef _TI_SCM_H_ #define _TI_SCM_H_ -struct ti_scm_padconf { - uint16_t reg_off; - uint16_t gpio_pin; - uint16_t gpio_mode; - const char *ballname; - const char *muxmodes[8]; -}; - -struct ti_scm_padstate { - const char *state; - uint16_t reg; -}; - -struct ti_scm_device { - uint16_t padconf_muxmode_mask; - uint16_t padconf_sate_mask; - const struct ti_scm_padstate *padstate; - const struct ti_scm_padconf *padconf; -}; - struct ti_scm_softc { device_t sc_dev; struct resource * sc_res[4]; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; }; -int ti_scm_padconf_set(const char *padname, const char *muxmode, - unsigned int state); -int ti_scm_padconf_get(const char *padname, const char **muxmode, - unsigned int *state); -int ti_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state); -int ti_scm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state); int ti_scm_reg_read_4(uint32_t reg, uint32_t *val); int ti_scm_reg_write_4(uint32_t reg, uint32_t val); #endif /* _TI_SCM_H_ */ Index: head/sys/arm/ti/ti_sdhci.c =================================================================== --- head/sys/arm/ti/ti_sdhci.c (revision 283275) +++ head/sys/arm/ti/ti_sdhci.c (revision 283276) @@ -1,725 +1,723 @@ /*- * Copyright (c) 2013 Ian Lepore * Copyright (c) 2011 Ben Gray . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sdhci_if.h" #include #include +#include #include "gpio_if.h" struct ti_sdhci_softc { device_t dev; device_t gpio_dev; struct resource * mem_res; struct resource * irq_res; void * intr_cookie; struct sdhci_slot slot; - uint32_t mmchs_device_id; + clk_ident_t mmchs_clk_id; uint32_t mmchs_reg_off; uint32_t sdhci_reg_off; uint32_t baseclk_hz; uint32_t wp_gpio_pin; uint32_t cmd_and_mode; uint32_t sdhci_clkdiv; boolean_t disable_highspeed; boolean_t force_card_present; }; /* * Table of supported FDT compat strings. * * Note that "ti,mmchs" is our own invention, and should be phased out in favor * of the documented names. * * Note that vendor Beaglebone dtsi files use "ti,omap3-hsmmc" for the am335x. */ static struct ofw_compat_data compat_data[] = { {"ti,omap3-hsmmc", 1}, {"ti,omap4-hsmmc", 1}, {"ti,mmchs", 1}, {NULL, 0}, }; /* * The MMCHS hardware has a few control and status registers at the beginning of * the device's memory map, followed by the standard sdhci register block. * Different SoCs have the register blocks at different offsets from the * beginning of the device. Define some constants to map out the registers we * access, and the various per-SoC offsets. The SDHCI_REG_OFFSET is how far * beyond the MMCHS block the SDHCI block is found; it's the same on all SoCs. */ #define OMAP3_MMCHS_REG_OFFSET 0x000 #define OMAP4_MMCHS_REG_OFFSET 0x100 #define AM335X_MMCHS_REG_OFFSET 0x100 #define SDHCI_REG_OFFSET 0x100 #define MMCHS_SYSCONFIG 0x010 #define MMCHS_SYSCONFIG_RESET (1 << 1) #define MMCHS_SYSSTATUS 0x014 #define MMCHS_SYSSTATUS_RESETDONE (1 << 0) #define MMCHS_CON 0x02C #define MMCHS_CON_DW8 (1 << 5) #define MMCHS_CON_DVAL_8_4MS (3 << 9) #define MMCHS_CON_OD (1 << 0) #define MMCHS_SYSCTL 0x12C #define MMCHS_SYSCTL_CLKD_MASK 0x3FF #define MMCHS_SYSCTL_CLKD_SHIFT 6 #define MMCHS_SD_CAPA 0x140 #define MMCHS_SD_CAPA_VS18 (1 << 26) #define MMCHS_SD_CAPA_VS30 (1 << 25) #define MMCHS_SD_CAPA_VS33 (1 << 24) static inline uint32_t ti_mmchs_read_4(struct ti_sdhci_softc *sc, bus_size_t off) { return (bus_read_4(sc->mem_res, off + sc->mmchs_reg_off)); } static inline void ti_mmchs_write_4(struct ti_sdhci_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off + sc->mmchs_reg_off, val); } static inline uint32_t RD4(struct ti_sdhci_softc *sc, bus_size_t off) { return (bus_read_4(sc->mem_res, off + sc->sdhci_reg_off)); } static inline void WR4(struct ti_sdhci_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off + sc->sdhci_reg_off, val); } static uint8_t ti_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct ti_sdhci_softc *sc = device_get_softc(dev); return ((RD4(sc, off & ~3) >> (off & 3) * 8) & 0xff); } static uint16_t ti_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct ti_sdhci_softc *sc = device_get_softc(dev); uint32_t clkdiv, val32; /* * The MMCHS hardware has a non-standard interpretation of the sdclock * divisor bits. It uses the same bit positions as SDHCI 3.0 (15..6) * but doesn't split them into low:high fields. Instead they're a * single number in the range 0..1023 and the number is exactly the * clock divisor (with 0 and 1 both meaning divide by 1). The SDHCI * driver code expects a v2.0 or v3.0 divisor. The shifting and masking * here extracts the MMCHS representation from the hardware word, cleans * those bits out, applies the 2N adjustment, and plugs the result into * the bit positions for the 2.0 or 3.0 divisor in the returned register * value. The ti_sdhci_write_2() routine performs the opposite * transformation when the SDHCI driver writes to the register. */ if (off == SDHCI_CLOCK_CONTROL) { val32 = RD4(sc, SDHCI_CLOCK_CONTROL); clkdiv = ((val32 >> MMCHS_SYSCTL_CLKD_SHIFT) & MMCHS_SYSCTL_CLKD_MASK) / 2; val32 &= ~(MMCHS_SYSCTL_CLKD_MASK << MMCHS_SYSCTL_CLKD_SHIFT); val32 |= (clkdiv & SDHCI_DIVIDER_MASK) << SDHCI_DIVIDER_SHIFT; if (slot->version >= SDHCI_SPEC_300) val32 |= ((clkdiv >> SDHCI_DIVIDER_MASK_LEN) & SDHCI_DIVIDER_HI_MASK) << SDHCI_DIVIDER_HI_SHIFT; return (val32 & 0xffff); } /* * Standard 32-bit handling of command and transfer mode. */ if (off == SDHCI_TRANSFER_MODE) { return (sc->cmd_and_mode >> 16); } else if (off == SDHCI_COMMAND_FLAGS) { return (sc->cmd_and_mode & 0x0000ffff); } return ((RD4(sc, off & ~3) >> (off & 3) * 8) & 0xffff); } static uint32_t ti_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off) { struct ti_sdhci_softc *sc = device_get_softc(dev); uint32_t val32; val32 = RD4(sc, off); /* * If we need to disallow highspeed mode due to the OMAP4 erratum, strip * that flag from the returned capabilities. */ if (off == SDHCI_CAPABILITIES && sc->disable_highspeed) val32 &= ~SDHCI_CAN_DO_HISPD; /* * Force the card-present state if necessary. */ if (off == SDHCI_PRESENT_STATE && sc->force_card_present) val32 |= SDHCI_CARD_PRESENT; return (val32); } static void ti_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct ti_sdhci_softc *sc = device_get_softc(dev); bus_read_multi_4(sc->mem_res, off + sc->sdhci_reg_off, data, count); } static void ti_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val) { struct ti_sdhci_softc *sc = device_get_softc(dev); uint32_t val32; val32 = RD4(sc, off & ~3); val32 &= ~(0xff << (off & 3) * 8); val32 |= (val << (off & 3) * 8); WR4(sc, off & ~3, val32); } static void ti_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val) { struct ti_sdhci_softc *sc = device_get_softc(dev); uint32_t clkdiv, val32; /* * Translate between the hardware and SDHCI 2.0 or 3.0 representations * of the clock divisor. See the comments in ti_sdhci_read_2() for * details. */ if (off == SDHCI_CLOCK_CONTROL) { clkdiv = (val >> SDHCI_DIVIDER_SHIFT) & SDHCI_DIVIDER_MASK; if (slot->version >= SDHCI_SPEC_300) clkdiv |= ((val >> SDHCI_DIVIDER_HI_SHIFT) & SDHCI_DIVIDER_HI_MASK) << SDHCI_DIVIDER_MASK_LEN; clkdiv *= 2; if (clkdiv > MMCHS_SYSCTL_CLKD_MASK) clkdiv = MMCHS_SYSCTL_CLKD_MASK; val32 = RD4(sc, SDHCI_CLOCK_CONTROL); val32 &= 0xffff0000; val32 |= val & ~(MMCHS_SYSCTL_CLKD_MASK << MMCHS_SYSCTL_CLKD_SHIFT); val32 |= clkdiv << MMCHS_SYSCTL_CLKD_SHIFT; WR4(sc, SDHCI_CLOCK_CONTROL, val32); return; } /* * Standard 32-bit handling of command and transfer mode. */ if (off == SDHCI_TRANSFER_MODE) { sc->cmd_and_mode = (sc->cmd_and_mode & 0xffff0000) | ((uint32_t)val & 0x0000ffff); return; } else if (off == SDHCI_COMMAND_FLAGS) { sc->cmd_and_mode = (sc->cmd_and_mode & 0x0000ffff) | ((uint32_t)val << 16); WR4(sc, SDHCI_TRANSFER_MODE, sc->cmd_and_mode); return; } val32 = RD4(sc, off & ~3); val32 &= ~(0xffff << (off & 3) * 8); val32 |= ((val & 0xffff) << (off & 3) * 8); WR4(sc, off & ~3, val32); } static void ti_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val) { struct ti_sdhci_softc *sc = device_get_softc(dev); WR4(sc, off, val); } static void ti_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t *data, bus_size_t count) { struct ti_sdhci_softc *sc = device_get_softc(dev); bus_write_multi_4(sc->mem_res, off + sc->sdhci_reg_off, data, count); } static void ti_sdhci_intr(void *arg) { struct ti_sdhci_softc *sc = arg; sdhci_generic_intr(&sc->slot); } static int ti_sdhci_update_ios(device_t brdev, device_t reqdev) { struct ti_sdhci_softc *sc = device_get_softc(brdev); struct sdhci_slot *slot; struct mmc_ios *ios; uint32_t val32, newval32; slot = device_get_ivars(reqdev); ios = &slot->host.ios; /* * There is an 8-bit-bus bit in the MMCHS control register which, when * set, overrides the 1 vs 4 bit setting in the standard SDHCI * registers. Set that bit first according to whether an 8-bit bus is * requested, then let the standard driver handle everything else. */ val32 = ti_mmchs_read_4(sc, MMCHS_CON); newval32 = val32; if (ios->bus_width == bus_width_8) newval32 |= MMCHS_CON_DW8; else newval32 &= ~MMCHS_CON_DW8; if (ios->bus_mode == opendrain) newval32 |= MMCHS_CON_OD; else /* if (ios->bus_mode == pushpull) */ newval32 &= ~MMCHS_CON_OD; if (newval32 != val32) ti_mmchs_write_4(sc, MMCHS_CON, newval32); return (sdhci_generic_update_ios(brdev, reqdev)); } static int ti_sdhci_get_ro(device_t brdev, device_t reqdev) { struct ti_sdhci_softc *sc = device_get_softc(brdev); unsigned int readonly = 0; /* If a gpio pin is configured, read it. */ if (sc->gpio_dev != NULL) { GPIO_PIN_GET(sc->gpio_dev, sc->wp_gpio_pin, &readonly); } return (readonly); } static int ti_sdhci_detach(device_t dev) { return (EBUSY); } static void ti_sdhci_hw_init(device_t dev) { struct ti_sdhci_softc *sc = device_get_softc(dev); - clk_ident_t clk; uint32_t regval; unsigned long timeout; /* Enable the controller and interface/functional clocks */ - clk = MMC0_CLK + sc->mmchs_device_id; - if (ti_prcm_clk_enable(clk) != 0) { + if (ti_prcm_clk_enable(sc->mmchs_clk_id) != 0) { device_printf(dev, "Error: failed to enable MMC clock\n"); return; } /* Get the frequency of the source clock */ - if (ti_prcm_clk_get_source_freq(clk, &sc->baseclk_hz) != 0) { + if (ti_prcm_clk_get_source_freq(sc->mmchs_clk_id, + &sc->baseclk_hz) != 0) { device_printf(dev, "Error: failed to get source clock freq\n"); return; } /* Issue a softreset to the controller */ ti_mmchs_write_4(sc, MMCHS_SYSCONFIG, MMCHS_SYSCONFIG_RESET); timeout = 1000; while (!(ti_mmchs_read_4(sc, MMCHS_SYSSTATUS) & MMCHS_SYSSTATUS_RESETDONE)) { if (--timeout == 0) { device_printf(dev, "Error: Controller reset operation timed out\n"); break; } DELAY(100); } /* * Reset the command and data state machines and also other aspects of * the controller such as bus clock and power. * * If we read the software reset register too fast after writing it we * can get back a zero that means the reset hasn't started yet rather * than that the reset is complete. Per TI recommendations, work around * it by reading until we see the reset bit asserted, then read until * it's clear. We also set the SDHCI_QUIRK_WAITFOR_RESET_ASSERTED quirk * so that the main sdhci driver uses this same logic in its resets. */ ti_sdhci_write_1(dev, NULL, SDHCI_SOFTWARE_RESET, SDHCI_RESET_ALL); timeout = 10000; while ((ti_sdhci_read_1(dev, NULL, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL) != SDHCI_RESET_ALL) { if (--timeout == 0) { break; } DELAY(1); } timeout = 10000; while ((ti_sdhci_read_1(dev, NULL, SDHCI_SOFTWARE_RESET) & SDHCI_RESET_ALL)) { if (--timeout == 0) { device_printf(dev, "Error: Software reset operation timed out\n"); break; } DELAY(100); } /* * The attach() routine has examined fdt data and set flags in * slot.host.caps to reflect what voltages we can handle. Set those * values in the CAPA register. The manual says that these values can * only be set once, "before initialization" whatever that means, and * that they survive a reset. So maybe doing this will be a no-op if * u-boot has already initialized the hardware. */ regval = ti_mmchs_read_4(sc, MMCHS_SD_CAPA); if (sc->slot.host.caps & MMC_OCR_LOW_VOLTAGE) regval |= MMCHS_SD_CAPA_VS18; if (sc->slot.host.caps & (MMC_OCR_290_300 | MMC_OCR_300_310)) regval |= MMCHS_SD_CAPA_VS30; ti_mmchs_write_4(sc, MMCHS_SD_CAPA, regval); /* Set initial host configuration (1-bit, std speed, pwr off). */ ti_sdhci_write_1(dev, NULL, SDHCI_HOST_CONTROL, 0); ti_sdhci_write_1(dev, NULL, SDHCI_POWER_CONTROL, 0); /* Set the initial controller configuration. */ ti_mmchs_write_4(sc, MMCHS_CON, MMCHS_CON_DVAL_8_4MS); } static int ti_sdhci_attach(device_t dev) { struct ti_sdhci_softc *sc = device_get_softc(dev); int rid, err; pcell_t prop; phandle_t node; sc->dev = dev; /* * Get the MMCHS device id from FDT. If it's not there use the newbus * unit number (which will work as long as the devices are in order and * none are skipped in the fdt). Note that this is a property we made * up and added in freebsd, it doesn't exist in the published bindings. */ node = ofw_bus_get_node(dev); - if ((OF_getprop(node, "mmchs-device-id", &prop, sizeof(prop))) <= 0) { - sc->mmchs_device_id = device_get_unit(dev); - device_printf(dev, "missing mmchs-device-id attribute in FDT, " - "using unit number (%d)", sc->mmchs_device_id); - } else - sc->mmchs_device_id = fdt32_to_cpu(prop); + sc->mmchs_clk_id = ti_hwmods_get_clock(dev); + if (sc->mmchs_clk_id == INVALID_CLK_IDENT) { + device_printf(dev, "failed to get clock based on hwmods property\n"); + } /* * The hardware can inherently do dual-voltage (1p8v, 3p0v) on the first * device, and only 1p8v on other devices unless an external transceiver * is used. The only way we could know about a transceiver is fdt data. * Note that we have to do this before calling ti_sdhci_hw_init() so * that it can set the right values in the CAPA register, which can only * be done once and never reset. */ sc->slot.host.caps |= MMC_OCR_LOW_VOLTAGE; - if (sc->mmchs_device_id == 0 || OF_hasprop(node, "ti,dual-volt")) { + if (sc->mmchs_clk_id == MMC1_CLK || OF_hasprop(node, "ti,dual-volt")) { sc->slot.host.caps |= MMC_OCR_290_300 | MMC_OCR_300_310; } /* * See if we've got a GPIO-based write detect pin. This is not the * standard documented property for this, we added it in freebsd. */ if ((OF_getprop(node, "mmchs-wp-gpio-pin", &prop, sizeof(prop))) <= 0) sc->wp_gpio_pin = 0xffffffff; else sc->wp_gpio_pin = fdt32_to_cpu(prop); if (sc->wp_gpio_pin != 0xffffffff) { sc->gpio_dev = devclass_get_device(devclass_find("gpio"), 0); if (sc->gpio_dev == NULL) device_printf(dev, "Error: No GPIO device, " "Write Protect pin will not function\n"); else GPIO_PIN_SETFLAGS(sc->gpio_dev, sc->wp_gpio_pin, GPIO_PIN_INPUT); } /* * Set the offset from the device's memory start to the MMCHS registers. * Also for OMAP4 disable high speed mode due to erratum ID i626. */ switch (ti_chip()) { #ifdef SOC_OMAP4 case CHIP_OMAP_4: sc->mmchs_reg_off = OMAP4_MMCHS_REG_OFFSET; sc->disable_highspeed = true; break; #endif #ifdef SOC_TI_AM335X case CHIP_AM335X: sc->mmchs_reg_off = AM335X_MMCHS_REG_OFFSET; break; #endif default: panic("Unknown OMAP device\n"); } /* * The standard SDHCI registers are at a fixed offset (the same on all * SoCs) beyond the MMCHS registers. */ sc->sdhci_reg_off = sc->mmchs_reg_off + SDHCI_REG_OFFSET; /* Resource setup. */ rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->mem_res) { device_printf(dev, "cannot allocate memory window\n"); err = ENXIO; goto fail; } rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (!sc->irq_res) { device_printf(dev, "cannot allocate interrupt\n"); err = ENXIO; goto fail; } if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, ti_sdhci_intr, sc, &sc->intr_cookie)) { device_printf(dev, "cannot setup interrupt handler\n"); err = ENXIO; goto fail; } /* Initialise the MMCHS hardware. */ ti_sdhci_hw_init(dev); /* * The capabilities register can only express base clock frequencies in * the range of 0-63MHz for a v2.0 controller. Since our clock runs * faster than that, the hardware sets the frequency to zero in the * register. When the register contains zero, the sdhci driver expects * slot.max_clk to already have the right value in it. */ sc->slot.max_clk = sc->baseclk_hz; /* * The MMCHS timeout counter is based on the output sdclock. Tell the * sdhci driver to recalculate the timeout clock whenever the output * sdclock frequency changes. */ sc->slot.quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; /* * The MMCHS hardware shifts the 136-bit response data (in violation of * the spec), so tell the sdhci driver not to do the same in software. */ sc->slot.quirks |= SDHCI_QUIRK_DONT_SHIFT_RESPONSE; /* * Reset bits are broken, have to wait to see the bits asserted * before waiting to see them de-asserted. */ sc->slot.quirks |= SDHCI_QUIRK_WAITFOR_RESET_ASSERTED; /* * DMA is not really broken, I just haven't implemented it yet. */ sc->slot.quirks |= SDHCI_QUIRK_BROKEN_DMA; /* * Set up the hardware and go. Note that this sets many of the * slot.host.* fields, so we have to do this before overriding any of * those values based on fdt data, below. */ sdhci_init_slot(dev, &sc->slot, 0); /* * The SDHCI controller doesn't realize it, but we can support 8-bit * even though we're not a v3.0 controller. If there's an fdt bus-width * property, honor it. */ if (OF_getencprop(node, "bus-width", &prop, sizeof(prop)) > 0) { sc->slot.host.caps &= ~(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA); switch (prop) { case 8: sc->slot.host.caps |= MMC_CAP_8_BIT_DATA; /* FALLTHROUGH */ case 4: sc->slot.host.caps |= MMC_CAP_4_BIT_DATA; break; case 1: break; default: device_printf(dev, "Bad bus-width value %u\n", prop); break; } } /* * If the slot is flagged with the non-removable property, set our flag * to always force the SDHCI_CARD_PRESENT bit on. */ node = ofw_bus_get_node(dev); if (OF_hasprop(node, "non-removable")) sc->force_card_present = true; bus_generic_probe(dev); bus_generic_attach(dev); sdhci_start_slot(&sc->slot); return (0); fail: if (sc->intr_cookie) bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie); if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); return (err); } static int ti_sdhci_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { device_set_desc(dev, "TI MMCHS (SDHCI 2.0)"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static device_method_t ti_sdhci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ti_sdhci_probe), DEVMETHOD(device_attach, ti_sdhci_attach), DEVMETHOD(device_detach, ti_sdhci_detach), /* Bus interface */ DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar), DEVMETHOD(bus_print_child, bus_generic_print_child), /* MMC bridge interface */ DEVMETHOD(mmcbr_update_ios, ti_sdhci_update_ios), DEVMETHOD(mmcbr_request, sdhci_generic_request), DEVMETHOD(mmcbr_get_ro, ti_sdhci_get_ro), DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host), DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host), /* SDHCI registers accessors */ DEVMETHOD(sdhci_read_1, ti_sdhci_read_1), DEVMETHOD(sdhci_read_2, ti_sdhci_read_2), DEVMETHOD(sdhci_read_4, ti_sdhci_read_4), DEVMETHOD(sdhci_read_multi_4, ti_sdhci_read_multi_4), DEVMETHOD(sdhci_write_1, ti_sdhci_write_1), DEVMETHOD(sdhci_write_2, ti_sdhci_write_2), DEVMETHOD(sdhci_write_4, ti_sdhci_write_4), DEVMETHOD(sdhci_write_multi_4, ti_sdhci_write_multi_4), DEVMETHOD_END }; static devclass_t ti_sdhci_devclass; static driver_t ti_sdhci_driver = { "sdhci_ti", ti_sdhci_methods, sizeof(struct ti_sdhci_softc), }; DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, 0, 0); MODULE_DEPEND(sdhci_ti, sdhci, 1, 1, 1); Index: head/sys/arm/ti/ti_sdma.c =================================================================== --- head/sys/arm/ti/ti_sdma.c (revision 283275) +++ head/sys/arm/ti/ti_sdma.c (revision 283276) @@ -1,1250 +1,1250 @@ /*- * Copyright (c) 2011 * Ben Gray . * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Kernel functions for using the DMA controller * * * DMA TRANSFERS: * A DMA transfer block consists of a number of frames (FN). Each frame * consists of a number of elements, and each element can have a size of 8, 16, * or 32 bits. * * OMAP44xx and newer chips support linked list (aka scatter gather) transfers, * where a linked list of source/destination pairs can be placed in memory * for the H/W to process. Earlier chips only allowed you to chain multiple * channels together. However currently this linked list feature is not * supported by the driver. * */ /** * Data structure per DMA channel. * * */ struct ti_sdma_channel { /* * The configuration registers for the given channel, these are modified * by the set functions and only written to the actual registers when a * transaction is started. */ uint32_t reg_csdp; uint32_t reg_ccr; uint32_t reg_cicr; /* Set when one of the configuration registers above change */ uint32_t need_reg_write; /* Callback function used when an interrupt is tripped on the given channel */ void (*callback)(unsigned int ch, uint32_t ch_status, void *data); /* Callback data passed in the callback ... duh */ void* callback_data; }; /** * DMA driver context, allocated and stored globally, this driver is not * intetned to ever be unloaded (see ti_sdma_sc). * */ struct ti_sdma_softc { device_t sc_dev; struct resource* sc_irq_res; struct resource* sc_mem_res; /* * I guess in theory we should have a mutex per DMA channel for register * modifications. But since we know we are never going to be run on a SMP * system, we can use just the single lock for all channels. */ struct mtx sc_mtx; /* Stores the H/W revision read from the registers */ uint32_t sc_hw_rev; /* * Bits in the sc_active_channels data field indicate if the channel has * been activated. */ uint32_t sc_active_channels; struct ti_sdma_channel sc_channel[NUM_DMA_CHANNELS]; }; static struct ti_sdma_softc *ti_sdma_sc = NULL; /** * Macros for driver mutex locking */ #define TI_SDMA_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) #define TI_SDMA_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) #define TI_SDMA_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ "ti_sdma", MTX_SPIN) #define TI_SDMA_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define TI_SDMA_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define TI_SDMA_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); /** * Function prototypes * */ static void ti_sdma_intr(void *); /** * ti_sdma_read_4 - reads a 32-bit value from one of the DMA registers * @sc: DMA device context * @off: The offset of a register from the DMA register address range * * * RETURNS: * 32-bit value read from the register. */ static inline uint32_t ti_sdma_read_4(struct ti_sdma_softc *sc, bus_size_t off) { return bus_read_4(sc->sc_mem_res, off); } /** * ti_sdma_write_4 - writes a 32-bit value to one of the DMA registers * @sc: DMA device context * @off: The offset of a register from the DMA register address range * * * RETURNS: * 32-bit value read from the register. */ static inline void ti_sdma_write_4(struct ti_sdma_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->sc_mem_res, off, val); } /** * ti_sdma_is_omap3_rev - returns true if H/W is from OMAP3 series * @sc: DMA device context * */ static inline int ti_sdma_is_omap3_rev(struct ti_sdma_softc *sc) { return (sc->sc_hw_rev == DMA4_OMAP3_REV); } /** * ti_sdma_is_omap4_rev - returns true if H/W is from OMAP4 series * @sc: DMA device context * */ static inline int ti_sdma_is_omap4_rev(struct ti_sdma_softc *sc) { return (sc->sc_hw_rev == DMA4_OMAP4_REV); } /** * ti_sdma_intr - interrupt handler for all 4 DMA IRQs * @arg: ignored * * Called when any of the four DMA IRQs are triggered. * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * nothing */ static void ti_sdma_intr(void *arg) { struct ti_sdma_softc *sc = ti_sdma_sc; uint32_t intr; uint32_t csr; unsigned int ch, j; struct ti_sdma_channel* channel; TI_SDMA_LOCK(sc); for (j = 0; j < NUM_DMA_IRQS; j++) { /* Get the flag interrupts (enabled) */ intr = ti_sdma_read_4(sc, DMA4_IRQSTATUS_L(j)); intr &= ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j)); if (intr == 0x00000000) continue; /* Loop through checking the status bits */ for (ch = 0; ch < NUM_DMA_CHANNELS; ch++) { if (intr & (1 << ch)) { channel = &sc->sc_channel[ch]; /* Read the CSR regsiter and verify we don't have a spurious IRQ */ csr = ti_sdma_read_4(sc, DMA4_CSR(ch)); if (csr == 0) { device_printf(sc->sc_dev, "Spurious DMA IRQ for channel " "%d\n", ch); continue; } /* Sanity check this channel is active */ if ((sc->sc_active_channels & (1 << ch)) == 0) { device_printf(sc->sc_dev, "IRQ %d for a non-activated " "channel %d\n", j, ch); continue; } /* Check the status error codes */ if (csr & DMA4_CSR_DROP) device_printf(sc->sc_dev, "Synchronization event drop " "occurred during the transfer on channel %u\n", ch); if (csr & DMA4_CSR_SECURE_ERR) device_printf(sc->sc_dev, "Secure transaction error event " "on channel %u\n", ch); if (csr & DMA4_CSR_MISALIGNED_ADRS_ERR) device_printf(sc->sc_dev, "Misaligned address error event " "on channel %u\n", ch); if (csr & DMA4_CSR_TRANS_ERR) { device_printf(sc->sc_dev, "Transaction error event on " "channel %u\n", ch); /* * Apparently according to linux code, there is an errata * that says the channel is not disabled upon this error. * They explicitly disable the channel here .. since I * haven't seen the errata, I'm going to ignore for now. */ } /* Clear the status flags for the IRQ */ ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK); ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch)); /* Call the callback for the given channel */ if (channel->callback) channel->callback(ch, csr, channel->callback_data); } } } TI_SDMA_UNLOCK(sc); return; } /** * ti_sdma_activate_channel - activates a DMA channel * @ch: upon return contains the channel allocated * @callback: a callback function to associate with the channel * @data: optional data supplied when the callback is called * * Simply activates a channel be enabling and writing default values to the * channel's register set. It doesn't start a transaction, just populates the * internal data structures and sets defaults. * * Note this function doesn't enable interrupts, for that you need to call * ti_sdma_enable_channel_irq(). If not using IRQ to detect the end of the * transfer, you can use ti_sdma_status_poll() to detect a change in the * status. * * A channel must be activated before any of the other DMA functions can be * called on it. * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * 0 on success, otherwise an error code */ int ti_sdma_activate_channel(unsigned int *ch, void (*callback)(unsigned int ch, uint32_t status, void *data), void *data) { struct ti_sdma_softc *sc = ti_sdma_sc; struct ti_sdma_channel *channel = NULL; uint32_t addr; unsigned int i; /* Sanity check */ if (sc == NULL) return (ENOMEM); if (ch == NULL) return (EINVAL); TI_SDMA_LOCK(sc); /* Check to see if all channels are in use */ if (sc->sc_active_channels == 0xffffffff) { TI_SDMA_UNLOCK(sc); return (ENOMEM); } /* Find the first non-active channel */ for (i = 0; i < NUM_DMA_CHANNELS; i++) { if (!(sc->sc_active_channels & (0x1 << i))) { sc->sc_active_channels |= (0x1 << i); *ch = i; break; } } /* Get the channel struct and populate the fields */ channel = &sc->sc_channel[*ch]; channel->callback = callback; channel->callback_data = data; channel->need_reg_write = 1; /* Set the default configuration for the DMA channel */ channel->reg_csdp = DMA4_CSDP_DATA_TYPE(0x2) | DMA4_CSDP_SRC_BURST_MODE(0) | DMA4_CSDP_DST_BURST_MODE(0) | DMA4_CSDP_SRC_ENDIANISM(0) | DMA4_CSDP_DST_ENDIANISM(0) | DMA4_CSDP_WRITE_MODE(0) | DMA4_CSDP_SRC_PACKED(0) | DMA4_CSDP_DST_PACKED(0); channel->reg_ccr = DMA4_CCR_DST_ADDRESS_MODE(1) | DMA4_CCR_SRC_ADDRESS_MODE(1) | DMA4_CCR_READ_PRIORITY(0) | DMA4_CCR_WRITE_PRIORITY(0) | DMA4_CCR_SYNC_TRIGGER(0) | DMA4_CCR_FRAME_SYNC(0) | DMA4_CCR_BLOCK_SYNC(0); channel->reg_cicr = DMA4_CICR_TRANS_ERR_IE | DMA4_CICR_SECURE_ERR_IE | DMA4_CICR_SUPERVISOR_ERR_IE | DMA4_CICR_MISALIGNED_ADRS_ERR_IE; /* Clear all the channel registers, this should abort any transaction */ for (addr = DMA4_CCR(*ch); addr <= DMA4_COLOR(*ch); addr += 4) ti_sdma_write_4(sc, addr, 0x00000000); TI_SDMA_UNLOCK(sc); return 0; } /** * ti_sdma_deactivate_channel - deactivates a channel * @ch: the channel to deactivate * * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_deactivate_channel(unsigned int ch) { struct ti_sdma_softc *sc = ti_sdma_sc; unsigned int j; unsigned int addr; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); /* First check if the channel is currently active */ if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EBUSY); } /* Mark the channel as inactive */ sc->sc_active_channels &= ~(1 << ch); /* Disable all DMA interrupts for the channel. */ ti_sdma_write_4(sc, DMA4_CICR(ch), 0); /* Make sure the DMA transfer is stopped. */ ti_sdma_write_4(sc, DMA4_CCR(ch), 0); /* Clear the CSR register and IRQ status register */ ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK); for (j = 0; j < NUM_DMA_IRQS; j++) { ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch)); } /* Clear all the channel registers, this should abort any transaction */ for (addr = DMA4_CCR(ch); addr <= DMA4_COLOR(ch); addr += 4) ti_sdma_write_4(sc, addr, 0x00000000); TI_SDMA_UNLOCK(sc); return 0; } /** * ti_sdma_disable_channel_irq - disables IRQ's on the given channel * @ch: the channel to disable IRQ's on * * Disable interupt generation for the given channel. * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_disable_channel_irq(unsigned int ch) { struct ti_sdma_softc *sc = ti_sdma_sc; uint32_t irq_enable; unsigned int j; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } /* Disable all the individual error conditions */ sc->sc_channel[ch].reg_cicr = 0x0000; ti_sdma_write_4(sc, DMA4_CICR(ch), 0x0000); /* Disable the channel interrupt enable */ for (j = 0; j < NUM_DMA_IRQS; j++) { irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j)); irq_enable &= ~(1 << ch); ti_sdma_write_4(sc, DMA4_IRQENABLE_L(j), irq_enable); } /* Indicate the registers need to be rewritten on the next transaction */ sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return (0); } /** * ti_sdma_disable_channel_irq - enables IRQ's on the given channel * @ch: the channel to enable IRQ's on * @flags: bitmask of interrupt types to enable * * Flags can be a bitmask of the following options: * DMA_IRQ_FLAG_DROP * DMA_IRQ_FLAG_HALF_FRAME_COMPL * DMA_IRQ_FLAG_FRAME_COMPL * DMA_IRQ_FLAG_START_LAST_FRAME * DMA_IRQ_FLAG_BLOCK_COMPL * DMA_IRQ_FLAG_ENDOF_PKT * DMA_IRQ_FLAG_DRAIN * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_enable_channel_irq(unsigned int ch, uint32_t flags) { struct ti_sdma_softc *sc = ti_sdma_sc; uint32_t irq_enable; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } /* Always enable the error interrupts if we have interrupts enabled */ flags |= DMA4_CICR_TRANS_ERR_IE | DMA4_CICR_SECURE_ERR_IE | DMA4_CICR_SUPERVISOR_ERR_IE | DMA4_CICR_MISALIGNED_ADRS_ERR_IE; sc->sc_channel[ch].reg_cicr = flags; /* Write the values to the register */ ti_sdma_write_4(sc, DMA4_CICR(ch), flags); /* Enable the channel interrupt enable */ irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(0)); irq_enable |= (1 << ch); ti_sdma_write_4(sc, DMA4_IRQENABLE_L(0), irq_enable); /* Indicate the registers need to be rewritten on the next transaction */ sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return (0); } /** * ti_sdma_get_channel_status - returns the status of a given channel * @ch: the channel number to get the status of * @status: upon return will contain the status bitmask, see below for possible * values. * * DMA_STATUS_DROP * DMA_STATUS_HALF * DMA_STATUS_FRAME * DMA_STATUS_LAST * DMA_STATUS_BLOCK * DMA_STATUS_SYNC * DMA_STATUS_PKT * DMA_STATUS_TRANS_ERR * DMA_STATUS_SECURE_ERR * DMA_STATUS_SUPERVISOR_ERR * DMA_STATUS_MISALIGNED_ADRS_ERR * DMA_STATUS_DRAIN_END * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_get_channel_status(unsigned int ch, uint32_t *status) { struct ti_sdma_softc *sc = ti_sdma_sc; uint32_t csr; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } TI_SDMA_UNLOCK(sc); csr = ti_sdma_read_4(sc, DMA4_CSR(ch)); if (status != NULL) *status = csr; return (0); } /** * ti_sdma_start_xfer - starts a DMA transfer * @ch: the channel number to set the endianess of * @src_paddr: the source phsyical address * @dst_paddr: the destination phsyical address * @frmcnt: the number of frames per block * @elmcnt: the number of elements in a frame, an element is either an 8, 16 * or 32-bit value as defined by ti_sdma_set_xfer_burst() * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_start_xfer(unsigned int ch, unsigned int src_paddr, unsigned long dst_paddr, unsigned int frmcnt, unsigned int elmcnt) { struct ti_sdma_softc *sc = ti_sdma_sc; struct ti_sdma_channel *channel; uint32_t ccr; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } channel = &sc->sc_channel[ch]; /* a) Write the CSDP register */ ti_sdma_write_4(sc, DMA4_CSDP(ch), channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1)); /* b) Set the number of element per frame CEN[23:0] */ ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt); /* c) Set the number of frame per block CFN[15:0] */ ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt); /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */ ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr); ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr); /* e) Write the CCR register */ ti_sdma_write_4(sc, DMA4_CCR(ch), channel->reg_ccr); /* f) - Set the source element index increment CSEI[15:0] */ ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001); /* - Set the source frame index increment CSFI[15:0] */ ti_sdma_write_4(sc, DMA4_CSF(ch), 0x0001); /* - Set the destination element index increment CDEI[15:0]*/ ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001); /* - Set the destination frame index increment CDFI[31:0] */ ti_sdma_write_4(sc, DMA4_CDF(ch), 0x0001); /* Clear the status register */ ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE); /* Write the start-bit and away we go */ ccr = ti_sdma_read_4(sc, DMA4_CCR(ch)); ccr |= (1 << 7); ti_sdma_write_4(sc, DMA4_CCR(ch), ccr); /* Clear the reg write flag */ channel->need_reg_write = 0; TI_SDMA_UNLOCK(sc); return (0); } /** * ti_sdma_start_xfer_packet - starts a packet DMA transfer * @ch: the channel number to use for the transfer * @src_paddr: the source physical address * @dst_paddr: the destination physical address * @frmcnt: the number of frames to transfer * @elmcnt: the number of elements in a frame, an element is either an 8, 16 * or 32-bit value as defined by ti_sdma_set_xfer_burst() * @pktsize: the number of elements in each transfer packet * * The @frmcnt and @elmcnt define the overall number of bytes to transfer, * typically @frmcnt is 1 and @elmcnt contains the total number of elements. * @pktsize is the size of each individual packet, there might be multiple * packets per transfer. i.e. for the following with element size of 32-bits * * frmcnt = 1, elmcnt = 512, pktsize = 128 * * Total transfer bytes = 1 * 512 = 512 elements or 2048 bytes * Packets transfered = 128 / 512 = 4 * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr, unsigned long dst_paddr, unsigned int frmcnt, unsigned int elmcnt, unsigned int pktsize) { struct ti_sdma_softc *sc = ti_sdma_sc; struct ti_sdma_channel *channel; uint32_t ccr; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } channel = &sc->sc_channel[ch]; /* a) Write the CSDP register */ if (channel->need_reg_write) ti_sdma_write_4(sc, DMA4_CSDP(ch), channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1)); /* b) Set the number of elements to transfer CEN[23:0] */ ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt); /* c) Set the number of frames to transfer CFN[15:0] */ ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt); /* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */ ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr); ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr); /* e) Write the CCR register */ ti_sdma_write_4(sc, DMA4_CCR(ch), channel->reg_ccr | DMA4_CCR_PACKET_TRANS); /* f) - Set the source element index increment CSEI[15:0] */ ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001); /* - Set the packet size, this is dependent on the sync source */ if (channel->reg_ccr & DMA4_CCR_SEL_SRC_DST_SYNC(1)) ti_sdma_write_4(sc, DMA4_CSF(ch), pktsize); else ti_sdma_write_4(sc, DMA4_CDF(ch), pktsize); /* - Set the destination frame index increment CDFI[31:0] */ ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001); /* Clear the status register */ ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE); /* Write the start-bit and away we go */ ccr = ti_sdma_read_4(sc, DMA4_CCR(ch)); ccr |= (1 << 7); ti_sdma_write_4(sc, DMA4_CCR(ch), ccr); /* Clear the reg write flag */ channel->need_reg_write = 0; TI_SDMA_UNLOCK(sc); return (0); } /** * ti_sdma_stop_xfer - stops any currently active transfers * @ch: the channel number to set the endianess of * * This function call is effectively a NOP if no transaction is in progress. * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_stop_xfer(unsigned int ch) { struct ti_sdma_softc *sc = ti_sdma_sc; unsigned int j; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } /* Disable all DMA interrupts for the channel. */ ti_sdma_write_4(sc, DMA4_CICR(ch), 0); /* Make sure the DMA transfer is stopped. */ ti_sdma_write_4(sc, DMA4_CCR(ch), 0); /* Clear the CSR register and IRQ status register */ ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK); for (j = 0; j < NUM_DMA_IRQS; j++) { ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch)); } /* Configuration registers need to be re-written on the next xfer */ sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return (0); } /** * ti_sdma_set_xfer_endianess - sets the endianess of subsequent transfers * @ch: the channel number to set the endianess of * @src: the source endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG) * @dst: the destination endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG) * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst) { struct ti_sdma_softc *sc = ti_sdma_sc; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_ENDIANISM(1); sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_ENDIANISM(src); sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_ENDIANISM(1); sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_ENDIANISM(dst); sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return 0; } /** * ti_sdma_set_xfer_burst - sets the source and destination element size * @ch: the channel number to set the burst settings of * @src: the source endianess (either DMA_BURST_NONE, DMA_BURST_16, DMA_BURST_32 * or DMA_BURST_64) * @dst: the destination endianess (either DMA_BURST_NONE, DMA_BURST_16, * DMA_BURST_32 or DMA_BURST_64) * * This function sets the size of the elements for all subsequent transfers. * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst) { struct ti_sdma_softc *sc = ti_sdma_sc; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_BURST_MODE(0x3); sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_BURST_MODE(src); sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_BURST_MODE(0x3); sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_BURST_MODE(dst); sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return 0; } /** * ti_sdma_set_xfer_data_type - driver attach function * @ch: the channel number to set the endianess of * @type: the xfer data type (either DMA_DATA_8BITS_SCALAR, DMA_DATA_16BITS_SCALAR * or DMA_DATA_32BITS_SCALAR) * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_set_xfer_data_type(unsigned int ch, unsigned int type) { struct ti_sdma_softc *sc = ti_sdma_sc; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DATA_TYPE(0x3); sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DATA_TYPE(type); sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return 0; } /** * ti_sdma_set_callback - driver attach function * @dev: dma device handle * * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_set_callback(unsigned int ch, void (*callback)(unsigned int ch, uint32_t status, void *data), void *data) { struct ti_sdma_softc *sc = ti_sdma_sc; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } sc->sc_channel[ch].callback = callback; sc->sc_channel[ch].callback_data = data; sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return 0; } /** * ti_sdma_sync_params - sets channel sync settings * @ch: the channel number to set the sync on * @trigger: the number of the sync trigger, this depends on what other H/W * module is triggering/receiving the DMA transactions * @mode: flags describing the sync mode to use, it may have one or more of * the following bits set; TI_SDMA_SYNC_FRAME, * TI_SDMA_SYNC_BLOCK, TI_SDMA_SYNC_TRIG_ON_SRC. * * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode) { struct ti_sdma_softc *sc = ti_sdma_sc; uint32_t ccr; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } ccr = sc->sc_channel[ch].reg_ccr; ccr &= ~DMA4_CCR_SYNC_TRIGGER(0x7F); ccr |= DMA4_CCR_SYNC_TRIGGER(trigger + 1); if (mode & TI_SDMA_SYNC_FRAME) ccr |= DMA4_CCR_FRAME_SYNC(1); else ccr &= ~DMA4_CCR_FRAME_SYNC(1); if (mode & TI_SDMA_SYNC_BLOCK) ccr |= DMA4_CCR_BLOCK_SYNC(1); else ccr &= ~DMA4_CCR_BLOCK_SYNC(1); if (mode & TI_SDMA_SYNC_TRIG_ON_SRC) ccr |= DMA4_CCR_SEL_SRC_DST_SYNC(1); else ccr &= ~DMA4_CCR_SEL_SRC_DST_SYNC(1); sc->sc_channel[ch].reg_ccr = ccr; sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return 0; } /** * ti_sdma_set_addr_mode - driver attach function * @ch: the channel number to set the endianess of * @rd_mode: the xfer source addressing mode (either DMA_ADDR_CONSTANT, * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or * DMA_ADDR_DOUBLE_INDEX) * @wr_mode: the xfer destination addressing mode (either DMA_ADDR_CONSTANT, * DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or * DMA_ADDR_DOUBLE_INDEX) * * * LOCKING: * DMA registers protected by internal mutex * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ int ti_sdma_set_addr_mode(unsigned int ch, unsigned int src_mode, unsigned int dst_mode) { struct ti_sdma_softc *sc = ti_sdma_sc; uint32_t ccr; /* Sanity check */ if (sc == NULL) return (ENOMEM); TI_SDMA_LOCK(sc); if ((sc->sc_active_channels & (1 << ch)) == 0) { TI_SDMA_UNLOCK(sc); return (EINVAL); } ccr = sc->sc_channel[ch].reg_ccr; ccr &= ~DMA4_CCR_SRC_ADDRESS_MODE(0x3); ccr |= DMA4_CCR_SRC_ADDRESS_MODE(src_mode); ccr &= ~DMA4_CCR_DST_ADDRESS_MODE(0x3); ccr |= DMA4_CCR_DST_ADDRESS_MODE(dst_mode); sc->sc_channel[ch].reg_ccr = ccr; sc->sc_channel[ch].need_reg_write = 1; TI_SDMA_UNLOCK(sc); return 0; } /** * ti_sdma_probe - driver probe function * @dev: dma device handle * * * * RETURNS: * Always returns 0. */ static int ti_sdma_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,sdma")) + if (!ofw_bus_is_compatible(dev, "ti,omap4430-sdma")) return (ENXIO); device_set_desc(dev, "TI sDMA Controller"); return (0); } /** * ti_sdma_attach - driver attach function * @dev: dma device handle * * Initialises memory mapping/pointers to the DMA register set and requests * IRQs. This is effectively the setup function for the driver. * * RETURNS: * 0 on success or a negative error code failure. */ static int ti_sdma_attach(device_t dev) { struct ti_sdma_softc *sc = device_get_softc(dev); unsigned int timeout; unsigned int i; int rid; void *ihl; int err; /* Setup the basics */ sc->sc_dev = dev; /* No channels active at the moment */ sc->sc_active_channels = 0x00000000; /* Mutex to protect the shared data structures */ TI_SDMA_LOCK_INIT(sc); /* Get the memory resource for the register mapping */ rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_mem_res == NULL) panic("%s: Cannot map registers", device_get_name(dev)); /* Enable the interface and functional clocks */ ti_prcm_clk_enable(SDMA_CLK); /* Read the sDMA revision register and sanity check it's known */ sc->sc_hw_rev = ti_sdma_read_4(sc, DMA4_REVISION); device_printf(dev, "sDMA revision %08x\n", sc->sc_hw_rev); if (!ti_sdma_is_omap4_rev(sc) && !ti_sdma_is_omap3_rev(sc)) { device_printf(sc->sc_dev, "error - unknown sDMA H/W revision\n"); return (EINVAL); } /* Disable all interrupts */ for (i = 0; i < NUM_DMA_IRQS; i++) { ti_sdma_write_4(sc, DMA4_IRQENABLE_L(i), 0x00000000); } /* Soft-reset is only supported on pre-OMAP44xx devices */ if (ti_sdma_is_omap3_rev(sc)) { /* Soft-reset */ ti_sdma_write_4(sc, DMA4_OCP_SYSCONFIG, 0x0002); /* Set the timeout to 100ms*/ timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); /* Wait for DMA reset to complete */ while ((ti_sdma_read_4(sc, DMA4_SYSSTATUS) & 0x1) == 0x0) { /* Sleep for a tick */ pause("DMARESET", 1); if (timeout-- == 0) { device_printf(sc->sc_dev, "sDMA reset operation timed out\n"); return (EINVAL); } } } /* * Install interrupt handlers for the for possible interrupts. Any channel * can trip one of the four IRQs */ rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->sc_irq_res == NULL) panic("Unable to setup the dma irq handler.\n"); err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, ti_sdma_intr, NULL, &ihl); if (err) panic("%s: Cannot register IRQ", device_get_name(dev)); /* Store the DMA structure globally ... this driver should never be unloaded */ ti_sdma_sc = sc; return (0); } static device_method_t ti_sdma_methods[] = { DEVMETHOD(device_probe, ti_sdma_probe), DEVMETHOD(device_attach, ti_sdma_attach), {0, 0}, }; static driver_t ti_sdma_driver = { "ti_sdma", ti_sdma_methods, sizeof(struct ti_sdma_softc), }; static devclass_t ti_sdma_devclass; DRIVER_MODULE(ti_sdma, simplebus, ti_sdma_driver, ti_sdma_devclass, 0, 0); MODULE_DEPEND(ti_sdma, ti_prcm, 1, 1, 1); Index: head/sys/arm/ti/usb/omap_ehci.c =================================================================== --- head/sys/arm/ti/usb/omap_ehci.c (revision 283275) +++ head/sys/arm/ti/usb/omap_ehci.c (revision 283276) @@ -1,1023 +1,463 @@ /*- * Copyright (c) 2011 * Ben Gray . * 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 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 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. */ - -/** - * Driver for the High Speed USB EHCI module on the TI OMAP3530 SoC. - * - * WARNING: I've only tried this driver on a limited number of USB peripherals, - * it is still very raw and bound to have numerous bugs in it. - * - * This driver is based on the FreeBSD IXP4xx EHCI driver with a lot of the - * setup sequence coming from the Linux community and their EHCI driver for - * OMAP. Without these as a base I don't think I would have been able to get - * this driver working. - * - * The driver only contains the EHCI parts, the module also supports OHCI and - * USB on-the-go (OTG), currently neither are supported. - * - * CAUTION: This driver was written to run on the beaglebaord dev board, so I - * have made some assumptions about the type of PHY used and some of the other - * settings. Bare that in mind if you intend to use this driver on another - * platform. - * - * NOTE: This module uses a few different clocks, one being a 60Mhz clock for - * the TTL part of the module. This clock is derived from DPPL5 which must be - * configured prior to loading this driver - it is not configured by the - * bootloader. It took me a long time to figure this out, and caused much - * frustration. This PLL is now setup in the timer/clocks part of the BSP, - * check out the omap_prcm_setup_dpll5() function in omap_prcm.c for more info. - * - */ - #include __FBSDID("$FreeBSD$"); -#include "opt_bus.h" - -#include -#include #include -#include -#include #include +#include #include -#include #include -#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include +#include #include #include #include #include #include #include #include #include #include #include #include -#include -#include -#include +#include +#include #include -#include "gpio_if.h" +/* EHCI */ +#define OMAP_USBHOST_HCCAPBASE 0x0000 +#define OMAP_USBHOST_HCSPARAMS 0x0004 +#define OMAP_USBHOST_HCCPARAMS 0x0008 +#define OMAP_USBHOST_USBCMD 0x0010 +#define OMAP_USBHOST_USBSTS 0x0014 +#define OMAP_USBHOST_USBINTR 0x0018 +#define OMAP_USBHOST_FRINDEX 0x001C +#define OMAP_USBHOST_CTRLDSSEGMENT 0x0020 +#define OMAP_USBHOST_PERIODICLISTBASE 0x0024 +#define OMAP_USBHOST_ASYNCLISTADDR 0x0028 +#define OMAP_USBHOST_CONFIGFLAG 0x0050 +#define OMAP_USBHOST_PORTSC(i) (0x0054 + (0x04 * (i))) +#define OMAP_USBHOST_INSNREG00 0x0090 +#define OMAP_USBHOST_INSNREG01 0x0094 +#define OMAP_USBHOST_INSNREG02 0x0098 +#define OMAP_USBHOST_INSNREG03 0x009C +#define OMAP_USBHOST_INSNREG04 0x00A0 +#define OMAP_USBHOST_INSNREG05_UTMI 0x00A4 +#define OMAP_USBHOST_INSNREG05_ULPI 0x00A4 +#define OMAP_USBHOST_INSNREG06 0x00A8 +#define OMAP_USBHOST_INSNREG07 0x00AC +#define OMAP_USBHOST_INSNREG08 0x00B0 -struct omap_ehci_softc { - ehci_softc_t base; /* storage for EHCI code */ +#define OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND (1 << 5) - device_t sc_dev; - device_t sc_gpio_dev; +#define OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT 31 +#define OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT 24 +#define OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT 22 +#define OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT 16 +#define OMAP_USBHOST_INSNREG05_ULPI_EXTREGADD_SHIFT 8 +#define OMAP_USBHOST_INSNREG05_ULPI_WRDATA_SHIFT 0 - /* TLL register set */ - struct resource* tll_mem_res; +#define ULPI_FUNC_CTRL_RESET (1 << 5) - /* UHH register set */ - struct resource* uhh_mem_res; +/*-------------------------------------------------------------------------*/ - /* The revision of the HS USB HOST read from UHH_REVISION */ - uint32_t ehci_rev; +/* + * Macros for Set and Clear + * See ULPI 1.1 specification to find the registers with Set and Clear offsets + */ +#define ULPI_SET(a) (a + 1) +#define ULPI_CLR(a) (a + 2) - /* The following details are provided by conf hints */ - int port_mode[3]; - int phy_reset[3]; - int reset_gpio_pin[3]; -}; +/*-------------------------------------------------------------------------*/ -static device_attach_t omap_ehci_attach; -static device_detach_t omap_ehci_detach; -static device_shutdown_t omap_ehci_shutdown; -static device_suspend_t omap_ehci_suspend; -static device_resume_t omap_ehci_resume; - -/** - * omap_tll_read_4 - read a 32-bit value from the USBTLL registers - * omap_tll_write_4 - write a 32-bit value from the USBTLL registers - * omap_tll_readb - read an 8-bit value from the USBTLL registers - * omap_tll_writeb - write an 8-bit value from the USBTLL registers - * @sc: omap ehci device context - * @off: byte offset within the register set to read from - * @val: the value to write into the register - * - * - * LOCKING: - * None - * - * RETURNS: - * nothing in case of write function, if read function returns the value read. +/* + * Register Map */ -static inline uint32_t -omap_tll_read_4(struct omap_ehci_softc *sc, bus_size_t off) -{ - return bus_read_4(sc->tll_mem_res, off); -} +#define ULPI_VENDOR_ID_LOW 0x00 +#define ULPI_VENDOR_ID_HIGH 0x01 +#define ULPI_PRODUCT_ID_LOW 0x02 +#define ULPI_PRODUCT_ID_HIGH 0x03 +#define ULPI_FUNC_CTRL 0x04 +#define ULPI_IFC_CTRL 0x07 +#define ULPI_OTG_CTRL 0x0a +#define ULPI_USB_INT_EN_RISE 0x0d +#define ULPI_USB_INT_EN_FALL 0x10 +#define ULPI_USB_INT_STS 0x13 +#define ULPI_USB_INT_LATCH 0x14 +#define ULPI_DEBUG 0x15 +#define ULPI_SCRATCH 0x16 -static inline void -omap_tll_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val) -{ - bus_write_4(sc->tll_mem_res, off, val); -} +#define OMAP_EHCI_HC_DEVSTR "TI OMAP USB 2.0 controller" -static inline uint8_t -omap_tll_readb(struct omap_ehci_softc *sc, bus_size_t off) -{ - return bus_read_1(sc->tll_mem_res, off); -} +struct omap_ehci_softc { + ehci_softc_t base; /* storage for EHCI code */ + device_t sc_dev; +}; -static inline void -omap_tll_writeb(struct omap_ehci_softc *sc, bus_size_t off, uint8_t val) -{ - bus_write_1(sc->tll_mem_res, off, val); -} +static device_attach_t omap_ehci_attach; +static device_detach_t omap_ehci_detach; /** * omap_ehci_read_4 - read a 32-bit value from the EHCI registers * omap_ehci_write_4 - write a 32-bit value from the EHCI registers * @sc: omap ehci device context * @off: byte offset within the register set to read from * @val: the value to write into the register * * * LOCKING: * None * * RETURNS: * nothing in case of write function, if read function returns the value read. */ static inline uint32_t omap_ehci_read_4(struct omap_ehci_softc *sc, bus_size_t off) { return (bus_read_4(sc->base.sc_io_res, off)); } + static inline void omap_ehci_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->base.sc_io_res, off, val); } /** - * omap_uhh_read_4 - read a 32-bit value from the UHH registers - * omap_uhh_write_4 - write a 32-bit value from the UHH registers - * @sc: omap ehci device context - * @off: byte offset within the register set to read from - * @val: the value to write into the register - * - * - * LOCKING: - * None - * - * RETURNS: - * nothing in case of write function, if read function returns the value read. - */ -static inline uint32_t -omap_uhh_read_4(struct omap_ehci_softc *sc, bus_size_t off) -{ - return bus_read_4(sc->uhh_mem_res, off); -} -static inline void -omap_uhh_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val) -{ - bus_write_4(sc->uhh_mem_res, off, val); -} - -/** - * omap_ehci_utmi_init - initialises the UTMI part of the controller - * @isc: omap ehci device context - * - * - * - * LOCKING: - * none - * - * RETURNS: - * nothing - */ -static void -omap_ehci_utmi_init(struct omap_ehci_softc *isc, unsigned int en_mask) -{ - unsigned int i; - uint32_t reg; - - /* There are 3 TLL channels, one per USB controller so set them all up the - * same, SDR mode, bit stuffing and no autoidle. - */ - for (i=0; i<3; i++) { - reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i)); - - reg &= ~(TLL_CHANNEL_CONF_UTMIAUTOIDLE - | TLL_CHANNEL_CONF_ULPINOBITSTUFF - | TLL_CHANNEL_CONF_ULPIDDRMODE); - - omap_tll_write_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg); - } - - /* Program the common TLL register */ - reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_SHARED_CONF); - - reg &= ~( TLL_SHARED_CONF_USB_90D_DDR_EN - | TLL_SHARED_CONF_USB_DIVRATIO_MASK); - reg |= ( TLL_SHARED_CONF_FCLK_IS_ON - | TLL_SHARED_CONF_USB_DIVRATIO_2 - | TLL_SHARED_CONF_USB_180D_SDR_EN); - - omap_tll_write_4(isc, OMAP_USBTLL_TLL_SHARED_CONF, reg); - - /* Enable channels now */ - for (i = 0; i < 3; i++) { - reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i)); - - /* Enable only the reg that is needed */ - if ((en_mask & (1 << i)) == 0) - continue; - - reg |= TLL_CHANNEL_CONF_CHANEN; - omap_tll_write_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg); - } -} - -/** * omap_ehci_soft_phy_reset - resets the phy using the reset command * @isc: omap ehci device context * @port: port to send the reset over * * * LOCKING: * none * * RETURNS: * nothing */ static void omap_ehci_soft_phy_reset(struct omap_ehci_softc *isc, unsigned int port) { unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); uint32_t reg; reg = ULPI_FUNC_CTRL_RESET /* FUNCTION_CTRL_SET register */ | (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT) /* Write */ | (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT) /* PORTn */ | ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT) /* start ULPI access*/ | (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT); omap_ehci_write_4(isc, OMAP_USBHOST_INSNREG05_ULPI, reg); /* Wait for ULPI access completion */ while ((omap_ehci_read_4(isc, OMAP_USBHOST_INSNREG05_ULPI) & (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) { /* Sleep for a tick */ pause("USBPHY_RESET", 1); if (timeout-- == 0) { device_printf(isc->sc_dev, "PHY reset operation timed out\n"); break; } } } - /** * omap_ehci_init - initialises the USB host EHCI controller * @isc: omap ehci device context * * This initialisation routine is quite heavily based on the work done by the * OMAP Linux team (for which I thank them very much). The init sequence is * almost identical, diverging only for the FreeBSD specifics. * * LOCKING: * none * * RETURNS: * 0 on success, a negative error code on failure. */ static int omap_ehci_init(struct omap_ehci_softc *isc) { - unsigned long timeout; - int ret = 0; - uint8_t tll_ch_mask = 0; uint32_t reg = 0; - int reset_performed = 0; int i; + device_t uhh_dev; + uhh_dev = device_get_parent(isc->sc_dev); device_printf(isc->sc_dev, "Starting TI EHCI USB Controller\n"); - - - /* Enable Clocks for high speed USBHOST */ - ti_prcm_clk_enable(USBHSHOST_CLK); - - /* Hold the PHY in reset while configuring */ - for (int i = 0; i < 3; i++) { - if (isc->phy_reset[i]) { - /* Configure the GPIO to drive low (hold in reset) */ - if ((isc->reset_gpio_pin[i] != -1) && (isc->sc_gpio_dev != NULL)) { - GPIO_PIN_SETFLAGS(isc->sc_gpio_dev, isc->reset_gpio_pin[i], - GPIO_PIN_OUTPUT); - GPIO_PIN_SET(isc->sc_gpio_dev, isc->reset_gpio_pin[i], - GPIO_PIN_LOW); - reset_performed = 1; - } - } - } - /* Hold the PHY in RESET for enough time till DIR is high */ - if (reset_performed) - DELAY(10); - - /* Read the UHH revision */ - isc->ehci_rev = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_REVISION); - device_printf(isc->sc_dev, "UHH revision 0x%08x\n", isc->ehci_rev); - - /* Initilise the low level interface module(s) */ - if (isc->ehci_rev == OMAP_EHCI_REV1) { - - /* Enable the USB TLL */ - ti_prcm_clk_enable(USBTLL_CLK); - - /* Perform TLL soft reset, and wait until reset is complete */ - omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); - - /* Set the timeout to 100ms*/ - timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); - - /* Wait for TLL reset to complete */ - while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) & - TLL_SYSSTATUS_RESETDONE) == 0x00) { - - /* Sleep for a tick */ - pause("USBRESET", 1); - - if (timeout-- == 0) { - device_printf(isc->sc_dev, "TLL reset operation timed out\n"); - ret = EINVAL; - goto err_sys_status; - } - } - - device_printf(isc->sc_dev, "TLL RESET DONE\n"); - - /* CLOCKACTIVITY = 1 : OCP-derived internal clocks ON during idle - * SIDLEMODE = 2 : Smart-idle mode. Sidleack asserted after Idlereq - * assertion when no more activity on the USB. - * ENAWAKEUP = 1 : Wakeup generation enabled - */ - omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_ENAWAKEUP | - TLL_SYSCONFIG_AUTOIDLE | - TLL_SYSCONFIG_SIDLE_SMART_IDLE | - TLL_SYSCONFIG_CACTIVITY); - - } else if (isc->ehci_rev == OMAP_EHCI_REV2) { - - /* For OMAP44xx devices you have to enable the per-port clocks: - * PHY_MODE - External ULPI clock - * TTL_MODE - Internal UTMI clock - * HSIC_MODE - Internal 480Mhz and 60Mhz clocks - */ - if (isc->ehci_rev == OMAP_EHCI_REV2) { - if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) { - ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK); - ti_prcm_clk_enable(USBP1_PHY_CLK); - } else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) - ti_prcm_clk_enable(USBP1_UTMI_CLK); - else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) - ti_prcm_clk_enable(USBP1_HSIC_CLK); - - if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) { - ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK); - ti_prcm_clk_enable(USBP2_PHY_CLK); - } else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) - ti_prcm_clk_enable(USBP2_UTMI_CLK); - else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) - ti_prcm_clk_enable(USBP2_HSIC_CLK); - } - } - - /* Put UHH in SmartIdle/SmartStandby mode */ - reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSCONFIG); - if (isc->ehci_rev == OMAP_EHCI_REV1) { - reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK | - UHH_SYSCONFIG_MIDLEMODE_MASK); - reg |= (UHH_SYSCONFIG_ENAWAKEUP | - UHH_SYSCONFIG_AUTOIDLE | - UHH_SYSCONFIG_CLOCKACTIVITY | - UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE | - UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY); - } else if (isc->ehci_rev == OMAP_EHCI_REV2) { - reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK; - reg |= UHH_SYSCONFIG_IDLEMODE_NOIDLE; - reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK; - reg |= UHH_SYSCONFIG_STANDBYMODE_NOSTDBY; - } - omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, reg); - device_printf(isc->sc_dev, "OMAP_UHH_SYSCONFIG: 0x%08x\n", reg); - - reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG); - - /* Setup ULPI bypass and burst configurations */ - reg |= (UHH_HOSTCONFIG_ENA_INCR4 | - UHH_HOSTCONFIG_ENA_INCR8 | - UHH_HOSTCONFIG_ENA_INCR16); - reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; - - if (isc->ehci_rev == OMAP_EHCI_REV1) { - if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) - reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS; - if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) - reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS; - if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) - reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS; - - /* Bypass the TLL module for PHY mode operation */ - if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || - (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || - (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) - reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS; - else - reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS; - - } else if (isc->ehci_rev == OMAP_EHCI_REV2) { - reg |= UHH_HOSTCONFIG_APP_START_CLK; - - /* Clear port mode fields for PHY mode*/ - reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK; - reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK; - - if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) - reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY; - else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) - reg |= UHH_HOSTCONFIG_P1_MODE_HSIC; - - if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) - reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY; - else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) - reg |= UHH_HOSTCONFIG_P2_MODE_HSIC; - } - - omap_uhh_write_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG, reg); - device_printf(isc->sc_dev, "UHH setup done, uhh_hostconfig=0x%08x\n", reg); - - - /* I found the code and comments in the Linux EHCI driver - thanks guys :) - * - * "An undocumented "feature" in the OMAP3 EHCI controller, causes suspended - * ports to be taken out of suspend when the USBCMD.Run/Stop bit is cleared - * (for example when we do ehci_bus_suspend). This breaks suspend-resume if - * the root-hub is allowed to suspend. Writing 1 to this undocumented - * register bit disables this feature and restores normal behavior." - */ -#if 0 - omap_ehci_write_4(isc, OMAP_USBHOST_INSNREG04, - OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND); -#endif - - /* If any of the ports are configured in TLL mode, enable them */ - if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) || - (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) || - (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) { - - if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) - tll_ch_mask |= 0x1; - if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) - tll_ch_mask |= 0x2; - if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) - tll_ch_mask |= 0x4; - - /* Enable UTMI mode for required TLL channels */ - omap_ehci_utmi_init(isc, tll_ch_mask); - } - - - /* Release the PHY reset signal now we have configured everything */ - if (reset_performed) { - - /* Delay for 10ms */ - DELAY(10000); - - for (i = 0; i < 3; i++) { - /* Release reset */ - - if (isc->phy_reset[i] && (isc->reset_gpio_pin[i] != -1) - && (isc->sc_gpio_dev != NULL)) { - GPIO_PIN_SET(isc->sc_gpio_dev, - isc->reset_gpio_pin[i], GPIO_PIN_HIGH); - } - } - } - /* Set the interrupt threshold control, it controls the maximum rate at * which the host controller issues interrupts. We set it to 1 microframe * at startup - the default is 8 mircoframes (equates to 1ms). */ reg = omap_ehci_read_4(isc, OMAP_USBHOST_USBCMD); reg &= 0xff00ffff; reg |= (1 << 16); omap_ehci_write_4(isc, OMAP_USBHOST_USBCMD, reg); /* Soft reset the PHY using PHY reset command over ULPI */ - if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) - omap_ehci_soft_phy_reset(isc, 0); - if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) - omap_ehci_soft_phy_reset(isc, 1); + for (i = 0; i < OMAP_HS_USB_PORTS; i++) { + if (omap_usb_port_mode(uhh_dev, i) == EHCI_HCD_OMAP_MODE_PHY) + omap_ehci_soft_phy_reset(isc, i); - return(0); - -err_sys_status: - - /* Disable the TLL clocks */ - ti_prcm_clk_disable(USBTLL_CLK); - - /* Disable Clocks for USBHOST */ - ti_prcm_clk_disable(USBHSHOST_CLK); - - return(ret); -} - - -/** - * omap_ehci_fini - shutdown the EHCI controller - * @isc: omap ehci device context - * - * - * - * LOCKING: - * none - * - * RETURNS: - * 0 on success, a negative error code on failure. - */ -static void -omap_ehci_fini(struct omap_ehci_softc *isc) -{ - unsigned long timeout; - - device_printf(isc->sc_dev, "Stopping TI EHCI USB Controller\n"); - - /* Set the timeout */ - if (hz < 10) - timeout = 1; - else - timeout = (100 * hz) / 1000; - - /* Reset the UHH, OHCI and EHCI modules */ - omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, 0x0002); - while ((omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSSTATUS) & 0x07) == 0x00) { - /* Sleep for a tick */ - pause("USBRESET", 1); - - if (timeout-- == 0) { - device_printf(isc->sc_dev, "operation timed out\n"); - break; - } } - - /* Set the timeout */ - if (hz < 10) - timeout = 1; - else - timeout = (100 * hz) / 1000; - - /* Reset the TLL module */ - omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, 0x0002); - while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) & (0x01)) == 0x00) { - /* Sleep for a tick */ - pause("USBRESET", 1); - - if (timeout-- == 0) { - device_printf(isc->sc_dev, "operation timed out\n"); - break; - } - } - - - /* Disable functional and interface clocks for the TLL and HOST modules */ - ti_prcm_clk_disable(USBTLL_CLK); - ti_prcm_clk_disable(USBHSHOST_CLK); - - device_printf(isc->sc_dev, "Clock to USB host has been disabled\n"); - + return(0); } - - /** - * omap_ehci_suspend - suspends the bus - * @dev: omap ehci device - * - * Effectively boilerplate EHCI suspend code. - * - * TODO: There is a lot more we could do here - i.e. force the controller into - * idle mode and disable all the clocks for start. - * - * LOCKING: - * none - * - * RETURNS: - * 0 on success or a positive error code - */ -static int -omap_ehci_suspend(device_t dev) -{ - int err; - - err = bus_generic_suspend(dev); - if (err) - return (err); - return (0); -} - - -/** - * omap_ehci_resume - resumes a suspended bus - * @dev: omap ehci device - * - * Effectively boilerplate EHCI resume code. - * - * LOCKING: - * none - * - * RETURNS: - * 0 on success or a positive error code on failure - */ -static int -omap_ehci_resume(device_t dev) -{ - - bus_generic_resume(dev); - - return (0); -} - - -/** - * omap_ehci_shutdown - starts the given command - * @dev: - * - * Effectively boilerplate EHCI shutdown code. - * - * LOCKING: - * none. - * - * RETURNS: - * 0 on success or a positive error code on failure - */ -static int -omap_ehci_shutdown(device_t dev) -{ - int err; - - err = bus_generic_shutdown(dev); - if (err) - return (err); - - return (0); -} - - -/** * omap_ehci_probe - starts the given command * @dev: * * Effectively boilerplate EHCI resume code. * * LOCKING: * Caller should be holding the OMAP3_MMC lock. * * RETURNS: * EH_HANDLED or EH_NOT_HANDLED */ static int omap_ehci_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "ti,usb-ehci")) + if (!ofw_bus_is_compatible(dev, "ti,ehci-omap")) return (ENXIO); device_set_desc(dev, OMAP_EHCI_HC_DEVSTR); return (BUS_PROBE_DEFAULT); } /** * omap_ehci_attach - driver entry point, sets up the ECHI controller/driver * @dev: the new device handle * * Sets up bus spaces, interrupt handles, etc for the EHCI controller. It also * parses the resource hints and calls omap_ehci_init() to initialise the * H/W. * * LOCKING: * none * * RETURNS: * 0 on success or a positive error code on failure. */ static int omap_ehci_attach(device_t dev) { struct omap_ehci_softc *isc = device_get_softc(dev); - phandle_t node; - /* 3 ports with 3 cells per port */ - pcell_t phyconf[3 * 3]; - pcell_t *phyconf_ptr; ehci_softc_t *sc = &isc->base; int err; int rid; - int len, tuple_size; - int i; /* initialise some bus fields */ sc->sc_bus.parent = dev; sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = EHCI_MAX_DEVICES; sc->sc_bus.dma_bits = 32; + sprintf(sc->sc_vendor, "Texas Instruments"); + /* save the device */ isc->sc_dev = dev; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev), &ehci_iterate_hw_softc)) { return (ENOMEM); } - /* When the EHCI driver is added to the tree it is expected that 3 - * memory resources and 1 interrupt resource is assigned. The memory - * resources should be: - * 0 => EHCI register range - * 1 => UHH register range - * 2 => TLL register range - * - * The interrupt resource is just the single interupt for the controller. - */ - /* Allocate resource for the EHCI register set */ rid = 0; sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_io_res) { device_printf(dev, "Error: Could not map EHCI memory\n"); goto error; } /* Request an interrupt resource */ rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(dev, "Error: could not allocate irq\n"); goto error; } - /* Allocate resource for the UHH register set */ - rid = 1; - isc->uhh_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!isc->uhh_mem_res) { - device_printf(dev, "Error: Could not map UHH memory\n"); - goto error; - } - /* Allocate resource for the TLL register set */ - rid = 2; - isc->tll_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!isc->tll_mem_res) { - device_printf(dev, "Error: Could not map TLL memory\n"); - goto error; - } - /* Add this device as a child of the USBus device */ sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); if (!sc->sc_bus.bdev) { device_printf(dev, "Error: could not add USB device\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); device_set_desc(sc->sc_bus.bdev, OMAP_EHCI_HC_DEVSTR); - /* Set the vendor name */ - sprintf(sc->sc_vendor, "Texas Instruments"); - - /* Get the GPIO device, we may need this if the driver needs to toggle - * some pins for external PHY resets. - */ - isc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0); - if (isc->sc_gpio_dev == NULL) { - device_printf(dev, "Error: failed to get the GPIO device\n"); - goto error; - } - - /* Set the defaults for the hints */ - for (i = 0; i < 3; i++) { - isc->phy_reset[i] = 0; - isc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN; - isc->reset_gpio_pin[i] = -1; - } - - tuple_size = sizeof(pcell_t) * 3; - node = ofw_bus_get_node(dev); - len = OF_getprop(node, "phy-config", phyconf, sizeof(phyconf)); - if (len > 0) { - if (len % tuple_size) - goto error; - if ((len / tuple_size) != 3) - goto error; - - phyconf_ptr = phyconf; - for (i = 0; i < 3; i++) { - isc->port_mode[i] = fdt32_to_cpu(*phyconf_ptr); - isc->phy_reset[i] = fdt32_to_cpu(*(phyconf_ptr + 1)); - isc->reset_gpio_pin[i] = fdt32_to_cpu(*(phyconf_ptr + 2)); - - phyconf_ptr += 3; - } - } - /* Initialise the ECHI registers */ err = omap_ehci_init(isc); if (err) { device_printf(dev, "Error: could not setup OMAP EHCI, %d\n", err); goto error; } - /* Set the tag and size of the register set in the EHCI context */ sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); - /* Setup the interrupt */ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); if (err) { device_printf(dev, "Error: could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; goto error; } - /* Finally we are ready to kick off the ECHI host controller */ err = ehci_init(sc); if (err == 0) { err = device_probe_and_attach(sc->sc_bus.bdev); } if (err) { device_printf(dev, "Error: USB init failed err=%d\n", err); goto error; } return (0); error: omap_ehci_detach(dev); return (ENXIO); } /** * omap_ehci_detach - detach the device and cleanup the driver * @dev: device handle * * Clean-up routine where everything initialised in omap_ehci_attach is * freed and cleaned up. This function calls omap_ehci_fini() to shutdown * the on-chip module. * * LOCKING: * none * * RETURNS: * Always returns 0 (success). */ static int omap_ehci_detach(device_t dev) { struct omap_ehci_softc *isc = device_get_softc(dev); ehci_softc_t *sc = &isc->base; device_t bdev; int err; if (sc->sc_bus.bdev) { bdev = sc->sc_bus.bdev; device_detach(bdev); device_delete_child(dev, bdev); } /* during module unload there are lots of children leftover */ device_delete_children(dev); /* * disable interrupts that might have been switched on in ehci_init */ if (sc->sc_io_res) { EWRITE4(sc, EHCI_USBINTR, 0); } if (sc->sc_irq_res && sc->sc_intr_hdl) { /* * only call ehci_detach() after ehci_init() */ ehci_detach(sc); err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); if (err) device_printf(dev, "Error: could not tear down irq, %d\n", err); sc->sc_intr_hdl = NULL; } /* Free the resources stored in the base EHCI handler */ if (sc->sc_irq_res) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); sc->sc_irq_res = NULL; } if (sc->sc_io_res) { bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_io_res); sc->sc_io_res = NULL; } - /* Release the other register set memory maps */ - if (isc->tll_mem_res) { - bus_release_resource(dev, SYS_RES_MEMORY, 0, isc->tll_mem_res); - isc->tll_mem_res = NULL; - } - if (isc->uhh_mem_res) { - bus_release_resource(dev, SYS_RES_MEMORY, 0, isc->uhh_mem_res); - isc->uhh_mem_res = NULL; - } - - usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); - - omap_ehci_fini(isc); - return (0); } static device_method_t ehci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, omap_ehci_probe), DEVMETHOD(device_attach, omap_ehci_attach), DEVMETHOD(device_detach, omap_ehci_detach), - DEVMETHOD(device_suspend, omap_ehci_suspend), - DEVMETHOD(device_resume, omap_ehci_resume), - DEVMETHOD(device_shutdown, omap_ehci_shutdown), + + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), /* Bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), {0, 0} }; static driver_t ehci_driver = { "ehci", ehci_methods, sizeof(struct omap_ehci_softc), }; static devclass_t ehci_devclass; -DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); +DRIVER_MODULE(ehci, omap_uhh, ehci_driver, ehci_devclass, 0, 0); Index: head/sys/arm/ti/usb/omap_host.c =================================================================== --- head/sys/arm/ti/usb/omap_host.c (nonexistent) +++ head/sys/arm/ti/usb/omap_host.c (revision 283276) @@ -0,0 +1,466 @@ +/*- + * Copyright (c) 2015 Oleksandr Tymoshenko + * Copyright (c) 2011 Ben Gray . + * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +/* + * USB Host Module + */ + +/* UHH */ +#define OMAP_USBHOST_UHH_REVISION 0x0000 +#define OMAP_USBHOST_UHH_SYSCONFIG 0x0010 +#define OMAP_USBHOST_UHH_SYSSTATUS 0x0014 +#define OMAP_USBHOST_UHH_HOSTCONFIG 0x0040 +#define OMAP_USBHOST_UHH_DEBUG_CSR 0x0044 + +/* UHH Register Set */ +#define UHH_SYSCONFIG_MIDLEMODE_MASK (3UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY (2UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY (1UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY (0UL << 12) +#define UHH_SYSCONFIG_CLOCKACTIVITY (1UL << 8) +#define UHH_SYSCONFIG_SIDLEMODE_MASK (3UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE (2UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE (1UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE (0UL << 3) +#define UHH_SYSCONFIG_ENAWAKEUP (1UL << 2) +#define UHH_SYSCONFIG_SOFTRESET (1UL << 1) +#define UHH_SYSCONFIG_AUTOIDLE (1UL << 0) + +#define UHH_HOSTCONFIG_APP_START_CLK (1UL << 31) +#define UHH_HOSTCONFIG_P3_CONNECT_STATUS (1UL << 10) +#define UHH_HOSTCONFIG_P2_CONNECT_STATUS (1UL << 9) +#define UHH_HOSTCONFIG_P1_CONNECT_STATUS (1UL << 8) +#define UHH_HOSTCONFIG_ENA_INCR_ALIGN (1UL << 5) +#define UHH_HOSTCONFIG_ENA_INCR16 (1UL << 4) +#define UHH_HOSTCONFIG_ENA_INCR8 (1UL << 3) +#define UHH_HOSTCONFIG_ENA_INCR4 (1UL << 2) +#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN (1UL << 1) +#define UHH_HOSTCONFIG_P1_ULPI_BYPASS (1UL << 0) + +/* The following are on rev2 (OMAP44xx) of the EHCI only */ +#define UHH_SYSCONFIG_IDLEMODE_MASK (3UL << 2) +#define UHH_SYSCONFIG_IDLEMODE_NOIDLE (1UL << 2) +#define UHH_SYSCONFIG_STANDBYMODE_MASK (3UL << 4) +#define UHH_SYSCONFIG_STANDBYMODE_NOSTDBY (1UL << 4) + +#define UHH_HOSTCONFIG_P1_MODE_MASK (3UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_ULPI_PHY (0UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_UTMI_PHY (1UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_HSIC (3UL << 16) +#define UHH_HOSTCONFIG_P2_MODE_MASK (3UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_ULPI_PHY (0UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_UTMI_PHY (1UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_HSIC (3UL << 18) + +/* + * Values of UHH_REVISION - Note: these are not given in the TRM but taken + * from the linux OMAP EHCI driver (thanks guys). It has been verified on + * a Panda and Beagle board. + */ +#define OMAP_UHH_REV1 0x00000010 /* OMAP3 */ +#define OMAP_UHH_REV2 0x50700100 /* OMAP4 */ + +struct omap_uhh_softc { + struct simplebus_softc simplebus_sc; + device_t sc_dev; + + /* UHH register set */ + struct resource* uhh_mem_res; + + /* The revision of the HS USB HOST read from UHH_REVISION */ + uint32_t uhh_rev; + + /* The following details are provided by conf hints */ + int port_mode[3]; +}; + +static device_attach_t omap_uhh_attach; +static device_detach_t omap_uhh_detach; + +static inline uint32_t +omap_uhh_read_4(struct omap_uhh_softc *sc, bus_size_t off) +{ + return bus_read_4(sc->uhh_mem_res, off); +} + +static inline void +omap_uhh_write_4(struct omap_uhh_softc *sc, bus_size_t off, uint32_t val) +{ + bus_write_4(sc->uhh_mem_res, off, val); +} + +static int +omap_uhh_init(struct omap_uhh_softc *isc) +{ + uint8_t tll_ch_mask; + uint32_t reg; + int i; + + /* Enable Clocks for high speed USBHOST */ + ti_prcm_clk_enable(USBHSHOST_CLK); + + /* Read the UHH revision */ + isc->uhh_rev = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_REVISION); + device_printf(isc->sc_dev, "UHH revision 0x%08x\n", isc->uhh_rev); + + if (isc->uhh_rev == OMAP_UHH_REV2) { + /* For OMAP44xx devices you have to enable the per-port clocks: + * PHY_MODE - External ULPI clock + * TTL_MODE - Internal UTMI clock + * HSIC_MODE - Internal 480Mhz and 60Mhz clocks + */ + switch(isc->port_mode[0]) { + case EHCI_HCD_OMAP_MODE_UNKNOWN: + break; + case EHCI_HCD_OMAP_MODE_PHY: + if (ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK)) + device_printf(isc->sc_dev, + "failed to set clock source for port 0\n"); + if (ti_prcm_clk_enable(USBP1_PHY_CLK)) + device_printf(isc->sc_dev, + "failed to set clock USBP1_PHY_CLK source for port 0\n"); + break; + case EHCI_HCD_OMAP_MODE_TLL: + if (ti_prcm_clk_enable(USBP1_UTMI_CLK)) + device_printf(isc->sc_dev, + "failed to set clock USBP1_PHY_CLK source for port 0\n"); + break; + case EHCI_HCD_OMAP_MODE_HSIC: + if (ti_prcm_clk_enable(USBP1_HSIC_CLK)) + device_printf(isc->sc_dev, + "failed to set clock USBP1_PHY_CLK source for port 0\n"); + break; + default: + device_printf(isc->sc_dev, "unknown port mode %d for port 0\n", isc->port_mode[0]); + } + switch(isc->port_mode[1]) { + case EHCI_HCD_OMAP_MODE_UNKNOWN: + break; + case EHCI_HCD_OMAP_MODE_PHY: + if (ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK)) + device_printf(isc->sc_dev, + "failed to set clock source for port 0\n"); + if (ti_prcm_clk_enable(USBP2_PHY_CLK)) + device_printf(isc->sc_dev, + "failed to set clock USBP2_PHY_CLK source for port 1\n"); + break; + case EHCI_HCD_OMAP_MODE_TLL: + if (ti_prcm_clk_enable(USBP2_UTMI_CLK)) + device_printf(isc->sc_dev, + "failed to set clock USBP2_UTMI_CLK source for port 1\n"); + break; + case EHCI_HCD_OMAP_MODE_HSIC: + if (ti_prcm_clk_enable(USBP2_HSIC_CLK)) + device_printf(isc->sc_dev, + "failed to set clock USBP2_HSIC_CLK source for port 1\n"); + break; + default: + device_printf(isc->sc_dev, "unknown port mode %d for port 1\n", isc->port_mode[1]); + } + } + + /* Put UHH in SmartIdle/SmartStandby mode */ + reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSCONFIG); + if (isc->uhh_rev == OMAP_UHH_REV1) { + reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK | + UHH_SYSCONFIG_MIDLEMODE_MASK); + reg |= (UHH_SYSCONFIG_ENAWAKEUP | + UHH_SYSCONFIG_AUTOIDLE | + UHH_SYSCONFIG_CLOCKACTIVITY | + UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE | + UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY); + } else if (isc->uhh_rev == OMAP_UHH_REV2) { + reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK; + reg |= UHH_SYSCONFIG_IDLEMODE_NOIDLE; + reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK; + reg |= UHH_SYSCONFIG_STANDBYMODE_NOSTDBY; + } + omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, reg); + device_printf(isc->sc_dev, "OMAP_UHH_SYSCONFIG: 0x%08x\n", reg); + + reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG); + + /* Setup ULPI bypass and burst configurations */ + reg |= (UHH_HOSTCONFIG_ENA_INCR4 | + UHH_HOSTCONFIG_ENA_INCR8 | + UHH_HOSTCONFIG_ENA_INCR16); + reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; + + if (isc->uhh_rev == OMAP_UHH_REV1) { + if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS; + if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS; + if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS; + + /* Bypass the TLL module for PHY mode operation */ + if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || + (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || + (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) + reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS; + else + reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS; + + } else if (isc->uhh_rev == OMAP_UHH_REV2) { + reg |= UHH_HOSTCONFIG_APP_START_CLK; + + /* Clear port mode fields for PHY mode*/ + reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK; + reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK; + + if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) + reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY; + else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) + reg |= UHH_HOSTCONFIG_P1_MODE_HSIC; + + if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) + reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY; + else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) + reg |= UHH_HOSTCONFIG_P2_MODE_HSIC; + } + + omap_uhh_write_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG, reg); + device_printf(isc->sc_dev, "UHH setup done, uhh_hostconfig=0x%08x\n", reg); + + + /* I found the code and comments in the Linux EHCI driver - thanks guys :) + * + * "An undocumented "feature" in the OMAP3 EHCI controller, causes suspended + * ports to be taken out of suspend when the USBCMD.Run/Stop bit is cleared + * (for example when we do omap_uhh_bus_suspend). This breaks suspend-resume if + * the root-hub is allowed to suspend. Writing 1 to this undocumented + * register bit disables this feature and restores normal behavior." + */ +#if 0 + omap_uhh_write_4(isc, OMAP_USBHOST_INSNREG04, + OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND); +#endif + tll_ch_mask = 0; + for (i = 0; i < OMAP_HS_USB_PORTS; i++) { + if (isc->port_mode[i] == EHCI_HCD_OMAP_MODE_TLL) + tll_ch_mask |= (1 << i); + } + if (tll_ch_mask) + omap_tll_utmi_enable(tll_ch_mask); + + return(0); +} + +/** + * omap_uhh_fini - shutdown the EHCI controller + * @isc: omap ehci device context + * + * + * + * LOCKING: + * none + * + * RETURNS: + * 0 on success, a negative error code on failure. + */ +static void +omap_uhh_fini(struct omap_uhh_softc *isc) +{ + unsigned long timeout; + + device_printf(isc->sc_dev, "Stopping TI EHCI USB Controller\n"); + + /* Set the timeout */ + if (hz < 10) + timeout = 1; + else + timeout = (100 * hz) / 1000; + + /* Reset the UHH, OHCI and EHCI modules */ + omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, 0x0002); + while ((omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSSTATUS) & 0x07) == 0x00) { + /* Sleep for a tick */ + pause("USBRESET", 1); + + if (timeout-- == 0) { + device_printf(isc->sc_dev, "operation timed out\n"); + break; + } + } + + /* Disable functional and interface clocks for the TLL and HOST modules */ + ti_prcm_clk_disable(USBHSHOST_CLK); + + device_printf(isc->sc_dev, "Clock to USB host has been disabled\n"); +} + +int +omap_usb_port_mode(device_t dev, int port) +{ + struct omap_uhh_softc *isc; + + isc = device_get_softc(dev); + if ((port < 0) || (port >= OMAP_HS_USB_PORTS)) + return (-1); + + return isc->port_mode[port]; +} + +static int +omap_uhh_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ti,usbhs-host")) + return (ENXIO); + + device_set_desc(dev, "TI OMAP USB 2.0 Host module"); + + return (BUS_PROBE_DEFAULT); +} + +static int +omap_uhh_attach(device_t dev) +{ + struct omap_uhh_softc *isc = device_get_softc(dev); + int err; + int rid; + int i; + phandle_t node; + char propname[16]; + char *mode; + + /* save the device */ + isc->sc_dev = dev; + + /* Allocate resource for the UHH register set */ + rid = 0; + isc->uhh_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (!isc->uhh_mem_res) { + device_printf(dev, "Error: Could not map UHH memory\n"); + goto error; + } + + node = ofw_bus_get_node(dev); + + if (node == -1) + goto error; + + /* Get port modes from FDT */ + for (i = 0; i < OMAP_HS_USB_PORTS; i++) { + isc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN; + snprintf(propname, sizeof(propname), + "port%d-mode", i+1); + + if (OF_getprop_alloc(node, propname, 1, (void**)&mode) <= 0) + continue; + if (strcmp(mode, "ehci-phy") == 0) + isc->port_mode[i] = EHCI_HCD_OMAP_MODE_PHY; + else if (strcmp(mode, "ehci-tll") == 0) + isc->port_mode[i] = EHCI_HCD_OMAP_MODE_TLL; + else if (strcmp(mode, "ehci-hsic") == 0) + isc->port_mode[i] = EHCI_HCD_OMAP_MODE_HSIC; + } + + /* Initialise the ECHI registers */ + err = omap_uhh_init(isc); + if (err) { + device_printf(dev, "Error: could not setup OMAP EHCI, %d\n", err); + goto error; + } + + simplebus_init(dev, node); + + /* + * Allow devices to identify. + */ + bus_generic_probe(dev); + + /* + * Now walk the OFW tree and attach top-level devices. + */ + for (node = OF_child(node); node > 0; node = OF_peer(node)) + simplebus_add_device(dev, node, 0, NULL, -1, NULL); + return (bus_generic_attach(dev)); + +error: + omap_uhh_detach(dev); + return (ENXIO); +} + +static int +omap_uhh_detach(device_t dev) +{ + struct omap_uhh_softc *isc = device_get_softc(dev); + + /* during module unload there are lots of children leftover */ + device_delete_children(dev); + + if (isc->uhh_mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, 0, isc->uhh_mem_res); + isc->uhh_mem_res = NULL; + } + + omap_uhh_fini(isc); + + return (0); +} + +static device_method_t omap_uhh_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, omap_uhh_probe), + DEVMETHOD(device_attach, omap_uhh_attach), + DEVMETHOD(device_detach, omap_uhh_detach), + + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(omap_uhh, omap_uhh_driver, omap_uhh_methods, + sizeof(struct omap_uhh_softc), simplebus_driver); +static devclass_t omap_uhh_devclass; +DRIVER_MODULE(omap_uhh, simplebus, omap_uhh_driver, omap_uhh_devclass, 0, 0); Property changes on: head/sys/arm/ti/usb/omap_host.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/usb/omap_tll.c =================================================================== --- head/sys/arm/ti/usb/omap_tll.c (nonexistent) +++ head/sys/arm/ti/usb/omap_tll.c (revision 283276) @@ -0,0 +1,364 @@ +/*- + * Copyright (c) 2011 + * Ben Gray . + * 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +/* + * USB TLL Module + */ +#define OMAP_USBTLL_REVISION 0x0000 +#define OMAP_USBTLL_SYSCONFIG 0x0010 +#define OMAP_USBTLL_SYSSTATUS 0x0014 +#define OMAP_USBTLL_IRQSTATUS 0x0018 +#define OMAP_USBTLL_IRQENABLE 0x001C +#define OMAP_USBTLL_TLL_SHARED_CONF 0x0030 +#define OMAP_USBTLL_TLL_CHANNEL_CONF(i) (0x0040 + (0x04 * (i))) +#define OMAP_USBTLL_SAR_CNTX(i) (0x0400 + (0x04 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_ID_LO(i) (0x0800 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_ID_HI(i) (0x0801 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_PRODUCT_ID_LO(i) (0x0802 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_PRODUCT_ID_HI(i) (0x0803 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL(i) (0x0804 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_SET(i) (0x0805 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_CLR(i) (0x0806 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL(i) (0x0807 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_SET(i) (0x0808 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_CLR(i) (0x0809 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL(i) (0x080A + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL_SET(i) (0x080B + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL_CLR(i) (0x080C + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE(i) (0x080D + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_SET(i) (0x080E + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i) (0x080F + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL(i) (0x0810 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_SET(i) (0x0811 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i) (0x0812 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_STATUS(i) (0x0813 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_LATCH(i) (0x0814 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_DEBUG(i) (0x0815 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER(i) (0x0816 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_SET(i) (0x0817 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i) (0x0818 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_EXTENDED_SET_ACCESS(i) (0x082F + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN(i) (0x0830 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i) (0x0831 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i) (0x0832 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i) (0x0833 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i) (0x0834 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS(i) (0x0835 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_SET(i) (0x0836 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_CLR(i) (0x0837 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i) (0x0838 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN(i) (0x083B + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_SET(i) (0x083C + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_CLR(i) (0x083D + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_STATUS(i) (0x083E + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_LATCH(i) (0x083F + (0x100 * (i))) + +/* TLL Register Set */ +#define TLL_SYSCONFIG_CACTIVITY (1UL << 8) +#define TLL_SYSCONFIG_SIDLE_SMART_IDLE (2UL << 3) +#define TLL_SYSCONFIG_SIDLE_NO_IDLE (1UL << 3) +#define TLL_SYSCONFIG_SIDLE_FORCED_IDLE (0UL << 3) +#define TLL_SYSCONFIG_ENAWAKEUP (1UL << 2) +#define TLL_SYSCONFIG_SOFTRESET (1UL << 1) +#define TLL_SYSCONFIG_AUTOIDLE (1UL << 0) + +#define TLL_SYSSTATUS_RESETDONE (1UL << 0) + +#define TLL_SHARED_CONF_USB_90D_DDR_EN (1UL << 6) +#define TLL_SHARED_CONF_USB_180D_SDR_EN (1UL << 5) +#define TLL_SHARED_CONF_USB_DIVRATIO_MASK (7UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_128 (7UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_64 (6UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_32 (5UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_16 (4UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_8 (3UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_4 (2UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_2 (1UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_1 (0UL << 2) +#define TLL_SHARED_CONF_FCLK_REQ (1UL << 1) +#define TLL_SHARED_CONF_FCLK_IS_ON (1UL << 0) + +#define TLL_CHANNEL_CONF_DRVVBUS (1UL << 16) +#define TLL_CHANNEL_CONF_CHRGVBUS (1UL << 15) +#define TLL_CHANNEL_CONF_ULPINOBITSTUFF (1UL << 11) +#define TLL_CHANNEL_CONF_ULPIAUTOIDLE (1UL << 10) +#define TLL_CHANNEL_CONF_UTMIAUTOIDLE (1UL << 9) +#define TLL_CHANNEL_CONF_ULPIDDRMODE (1UL << 8) +#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE (1UL << 7) +#define TLL_CHANNEL_CONF_TLLFULLSPEED (1UL << 6) +#define TLL_CHANNEL_CONF_TLLCONNECT (1UL << 5) +#define TLL_CHANNEL_CONF_TLLATTACH (1UL << 4) +#define TLL_CHANNEL_CONF_UTMIISADEV (1UL << 3) +#define TLL_CHANNEL_CONF_CHANEN (1UL << 0) + +struct omap_tll_softc { + device_t sc_dev; + + /* TLL register set */ + struct resource* tll_mem_res; + int tll_mem_rid; +}; + +static struct omap_tll_softc *omap_tll_sc; + +static int omap_tll_attach(device_t dev); +static int omap_tll_detach(device_t dev); + +static inline uint32_t +omap_tll_read_4(struct omap_tll_softc *sc, bus_size_t off) +{ + return bus_read_4(sc->tll_mem_res, off); +} + +static inline void +omap_tll_write_4(struct omap_tll_softc *sc, bus_size_t off, uint32_t val) +{ + bus_write_4(sc->tll_mem_res, off, val); +} + +void +omap_tll_utmi_enable(unsigned int en_mask) +{ + struct omap_tll_softc *sc; + unsigned int i; + uint32_t reg; + + sc = omap_tll_sc; + if (sc == NULL) + return; + + /* There are 3 TLL channels, one per USB controller so set them all up the + * same, SDR mode, bit stuffing and no autoidle. + */ + for (i=0; i<3; i++) { + reg = omap_tll_read_4(sc, OMAP_USBTLL_TLL_CHANNEL_CONF(i)); + + reg &= ~(TLL_CHANNEL_CONF_UTMIAUTOIDLE + | TLL_CHANNEL_CONF_ULPINOBITSTUFF + | TLL_CHANNEL_CONF_ULPIDDRMODE); + + omap_tll_write_4(sc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg); + } + + /* Program the common TLL register */ + reg = omap_tll_read_4(sc, OMAP_USBTLL_TLL_SHARED_CONF); + + reg &= ~( TLL_SHARED_CONF_USB_90D_DDR_EN + | TLL_SHARED_CONF_USB_DIVRATIO_MASK); + reg |= ( TLL_SHARED_CONF_FCLK_IS_ON + | TLL_SHARED_CONF_USB_DIVRATIO_2 + | TLL_SHARED_CONF_USB_180D_SDR_EN); + + omap_tll_write_4(sc, OMAP_USBTLL_TLL_SHARED_CONF, reg); + + /* Enable channels now */ + for (i = 0; i < 3; i++) { + reg = omap_tll_read_4(sc, OMAP_USBTLL_TLL_CHANNEL_CONF(i)); + + /* Enable only the reg that is needed */ + if ((en_mask & (1 << i)) == 0) + continue; + + reg |= TLL_CHANNEL_CONF_CHANEN; + omap_tll_write_4(sc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg); + } +} + +static int +omap_tll_init(struct omap_tll_softc *sc) +{ + unsigned long timeout; + int ret = 0; + + /* Enable the USB TLL */ + ti_prcm_clk_enable(USBTLL_CLK); + + /* Perform TLL soft reset, and wait until reset is complete */ + omap_tll_write_4(sc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); + + /* Set the timeout to 100ms*/ + timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); + + /* Wait for TLL reset to complete */ + while ((omap_tll_read_4(sc, OMAP_USBTLL_SYSSTATUS) & + TLL_SYSSTATUS_RESETDONE) == 0x00) { + + /* Sleep for a tick */ + pause("USBRESET", 1); + + if (timeout-- == 0) { + device_printf(sc->sc_dev, "TLL reset operation timed out\n"); + ret = EINVAL; + goto err_sys_status; + } + } + + /* CLOCKACTIVITY = 1 : OCP-derived internal clocks ON during idle + * SIDLEMODE = 2 : Smart-idle mode. Sidleack asserted after Idlereq + * assertion when no more activity on the USB. + * ENAWAKEUP = 1 : Wakeup generation enabled + */ + omap_tll_write_4(sc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_ENAWAKEUP | + TLL_SYSCONFIG_AUTOIDLE | + TLL_SYSCONFIG_SIDLE_SMART_IDLE | + TLL_SYSCONFIG_CACTIVITY); + + return(0); + +err_sys_status: + /* Disable the TLL clocks */ + ti_prcm_clk_disable(USBTLL_CLK); + + return(ret); +} + +static void +omap_tll_disable(struct omap_tll_softc *sc) +{ + unsigned long timeout; + + timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); + + /* Reset the TLL module */ + omap_tll_write_4(sc, OMAP_USBTLL_SYSCONFIG, 0x0002); + while ((omap_tll_read_4(sc, OMAP_USBTLL_SYSSTATUS) & (0x01)) == 0x00) { + /* Sleep for a tick */ + pause("USBRESET", 1); + + if (timeout-- == 0) { + device_printf(sc->sc_dev, "operation timed out\n"); + break; + } + } + + /* Disable functional and interface clocks for the TLL and HOST modules */ + ti_prcm_clk_disable(USBTLL_CLK); +} + +static int +omap_tll_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ti,usbhs-tll")) + return (ENXIO); + + device_set_desc(dev, "TI OMAP USB 2.0 TLL module"); + + return (BUS_PROBE_DEFAULT); +} + +static int +omap_tll_attach(device_t dev) +{ + struct omap_tll_softc *sc; + + sc = device_get_softc(dev); + /* save the device */ + sc->sc_dev = dev; + + /* Allocate resource for the TLL register set */ + sc->tll_mem_rid = 0; + sc->tll_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->tll_mem_rid, RF_ACTIVE); + if (!sc->tll_mem_res) { + device_printf(dev, "Error: Could not map TLL memory\n"); + goto error; + } + + omap_tll_init(sc); + + omap_tll_sc = sc; + + return (0); + +error: + omap_tll_detach(dev); + return (ENXIO); +} + +static int +omap_tll_detach(device_t dev) +{ + struct omap_tll_softc *sc; + + sc = device_get_softc(dev); + omap_tll_disable(sc); + + /* Release the other register set memory maps */ + if (sc->tll_mem_res) { + bus_release_resource(dev, SYS_RES_MEMORY, + sc->tll_mem_rid, sc->tll_mem_res); + sc->tll_mem_res = NULL; + } + + omap_tll_sc = NULL; + + return (0); +} + +static device_method_t omap_tll_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, omap_tll_probe), + DEVMETHOD(device_attach, omap_tll_attach), + DEVMETHOD(device_detach, omap_tll_detach), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + {0, 0} +}; + +static driver_t omap_tll_driver = { + "omap_tll", + omap_tll_methods, + sizeof(struct omap_tll_softc), +}; + +static devclass_t omap_tll_devclass; + +DRIVER_MODULE(omap_tll, simplebus, omap_tll_driver, omap_tll_devclass, 0, 0); Property changes on: head/sys/arm/ti/usb/omap_tll.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/usb/omap_usb.h =================================================================== --- head/sys/arm/ti/usb/omap_usb.h (revision 283275) +++ head/sys/arm/ti/usb/omap_usb.h (revision 283276) @@ -1,264 +1,48 @@ /* * Copyright (c) 2010 * Ben Gray . * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Ben Gray. * 4. The name of the company nor the name of the author may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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 _OMAP_USB_H_ #define _OMAP_USB_H_ -/* - * USB TTL Module - */ -#define OMAP_USBTLL_REVISION 0x0000 -#define OMAP_USBTLL_SYSCONFIG 0x0010 -#define OMAP_USBTLL_SYSSTATUS 0x0014 -#define OMAP_USBTLL_IRQSTATUS 0x0018 -#define OMAP_USBTLL_IRQENABLE 0x001C -#define OMAP_USBTLL_TLL_SHARED_CONF 0x0030 -#define OMAP_USBTLL_TLL_CHANNEL_CONF(i) (0x0040 + (0x04 * (i))) -#define OMAP_USBTLL_SAR_CNTX(i) (0x0400 + (0x04 * (i))) -#define OMAP_USBTLL_ULPI_VENDOR_ID_LO(i) (0x0800 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_VENDOR_ID_HI(i) (0x0801 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_PRODUCT_ID_LO(i) (0x0802 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_PRODUCT_ID_HI(i) (0x0803 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_FUNCTION_CTRL(i) (0x0804 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_SET(i) (0x0805 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_CLR(i) (0x0806 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_INTERFACE_CTRL(i) (0x0807 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_SET(i) (0x0808 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_CLR(i) (0x0809 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_OTG_CTRL(i) (0x080A + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_OTG_CTRL_SET(i) (0x080B + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_OTG_CTRL_CLR(i) (0x080C + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE(i) (0x080D + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_SET(i) (0x080E + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i) (0x080F + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL(i) (0x0810 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_SET(i) (0x0811 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i) (0x0812 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_STATUS(i) (0x0813 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_LATCH(i) (0x0814 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_DEBUG(i) (0x0815 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER(i) (0x0816 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_SET(i) (0x0817 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i) (0x0818 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_EXTENDED_SET_ACCESS(i) (0x082F + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN(i) (0x0830 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i) (0x0831 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i) (0x0832 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i) (0x0833 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i) (0x0834 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_UTMI_VSTATUS(i) (0x0835 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_SET(i) (0x0836 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_CLR(i) (0x0837 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i) (0x0838 + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_VENDOR_INT_EN(i) (0x083B + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_SET(i) (0x083C + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_CLR(i) (0x083D + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_VENDOR_INT_STATUS(i) (0x083E + (0x100 * (i))) -#define OMAP_USBTLL_ULPI_VENDOR_INT_LATCH(i) (0x083F + (0x100 * (i))) +#define OMAP_HS_USB_PORTS 3 - -/* - * USB Host Module - */ - -/* UHH */ -#define OMAP_USBHOST_UHH_REVISION 0x0000 -#define OMAP_USBHOST_UHH_SYSCONFIG 0x0010 -#define OMAP_USBHOST_UHH_SYSSTATUS 0x0014 -#define OMAP_USBHOST_UHH_HOSTCONFIG 0x0040 -#define OMAP_USBHOST_UHH_DEBUG_CSR 0x0044 - -/* EHCI */ -#define OMAP_USBHOST_HCCAPBASE 0x0000 -#define OMAP_USBHOST_HCSPARAMS 0x0004 -#define OMAP_USBHOST_HCCPARAMS 0x0008 -#define OMAP_USBHOST_USBCMD 0x0010 -#define OMAP_USBHOST_USBSTS 0x0014 -#define OMAP_USBHOST_USBINTR 0x0018 -#define OMAP_USBHOST_FRINDEX 0x001C -#define OMAP_USBHOST_CTRLDSSEGMENT 0x0020 -#define OMAP_USBHOST_PERIODICLISTBASE 0x0024 -#define OMAP_USBHOST_ASYNCLISTADDR 0x0028 -#define OMAP_USBHOST_CONFIGFLAG 0x0050 -#define OMAP_USBHOST_PORTSC(i) (0x0054 + (0x04 * (i))) -#define OMAP_USBHOST_INSNREG00 0x0090 -#define OMAP_USBHOST_INSNREG01 0x0094 -#define OMAP_USBHOST_INSNREG02 0x0098 -#define OMAP_USBHOST_INSNREG03 0x009C -#define OMAP_USBHOST_INSNREG04 0x00A0 -#define OMAP_USBHOST_INSNREG05_UTMI 0x00A4 -#define OMAP_USBHOST_INSNREG05_ULPI 0x00A4 -#define OMAP_USBHOST_INSNREG06 0x00A8 -#define OMAP_USBHOST_INSNREG07 0x00AC -#define OMAP_USBHOST_INSNREG08 0x00B0 - -#define OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND (1 << 5) - -#define OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT 31 -#define OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT 24 -#define OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT 22 -#define OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT 16 -#define OMAP_USBHOST_INSNREG05_ULPI_EXTREGADD_SHIFT 8 -#define OMAP_USBHOST_INSNREG05_ULPI_WRDATA_SHIFT 0 - - - - - -/* TLL Register Set */ -#define TLL_SYSCONFIG_CACTIVITY (1UL << 8) -#define TLL_SYSCONFIG_SIDLE_SMART_IDLE (2UL << 3) -#define TLL_SYSCONFIG_SIDLE_NO_IDLE (1UL << 3) -#define TLL_SYSCONFIG_SIDLE_FORCED_IDLE (0UL << 3) -#define TLL_SYSCONFIG_ENAWAKEUP (1UL << 2) -#define TLL_SYSCONFIG_SOFTRESET (1UL << 1) -#define TLL_SYSCONFIG_AUTOIDLE (1UL << 0) - -#define TLL_SYSSTATUS_RESETDONE (1UL << 0) - -#define TLL_SHARED_CONF_USB_90D_DDR_EN (1UL << 6) -#define TLL_SHARED_CONF_USB_180D_SDR_EN (1UL << 5) -#define TLL_SHARED_CONF_USB_DIVRATIO_MASK (7UL << 2) -#define TLL_SHARED_CONF_USB_DIVRATIO_128 (7UL << 2) -#define TLL_SHARED_CONF_USB_DIVRATIO_64 (6UL << 2) -#define TLL_SHARED_CONF_USB_DIVRATIO_32 (5UL << 2) -#define TLL_SHARED_CONF_USB_DIVRATIO_16 (4UL << 2) -#define TLL_SHARED_CONF_USB_DIVRATIO_8 (3UL << 2) -#define TLL_SHARED_CONF_USB_DIVRATIO_4 (2UL << 2) -#define TLL_SHARED_CONF_USB_DIVRATIO_2 (1UL << 2) -#define TLL_SHARED_CONF_USB_DIVRATIO_1 (0UL << 2) -#define TLL_SHARED_CONF_FCLK_REQ (1UL << 1) -#define TLL_SHARED_CONF_FCLK_IS_ON (1UL << 0) - -#define TLL_CHANNEL_CONF_DRVVBUS (1UL << 16) -#define TLL_CHANNEL_CONF_CHRGVBUS (1UL << 15) -#define TLL_CHANNEL_CONF_ULPINOBITSTUFF (1UL << 11) -#define TLL_CHANNEL_CONF_ULPIAUTOIDLE (1UL << 10) -#define TLL_CHANNEL_CONF_UTMIAUTOIDLE (1UL << 9) -#define TLL_CHANNEL_CONF_ULPIDDRMODE (1UL << 8) -#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE (1UL << 7) -#define TLL_CHANNEL_CONF_TLLFULLSPEED (1UL << 6) -#define TLL_CHANNEL_CONF_TLLCONNECT (1UL << 5) -#define TLL_CHANNEL_CONF_TLLATTACH (1UL << 4) -#define TLL_CHANNEL_CONF_UTMIISADEV (1UL << 3) -#define TLL_CHANNEL_CONF_CHANEN (1UL << 0) - - -/* UHH Register Set */ -#define UHH_SYSCONFIG_MIDLEMODE_MASK (3UL << 12) -#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY (2UL << 12) -#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY (1UL << 12) -#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY (0UL << 12) -#define UHH_SYSCONFIG_CLOCKACTIVITY (1UL << 8) -#define UHH_SYSCONFIG_SIDLEMODE_MASK (3UL << 3) -#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE (2UL << 3) -#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE (1UL << 3) -#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE (0UL << 3) -#define UHH_SYSCONFIG_ENAWAKEUP (1UL << 2) -#define UHH_SYSCONFIG_SOFTRESET (1UL << 1) -#define UHH_SYSCONFIG_AUTOIDLE (1UL << 0) - -#define UHH_HOSTCONFIG_APP_START_CLK (1UL << 31) -#define UHH_HOSTCONFIG_P3_CONNECT_STATUS (1UL << 10) -#define UHH_HOSTCONFIG_P2_CONNECT_STATUS (1UL << 9) -#define UHH_HOSTCONFIG_P1_CONNECT_STATUS (1UL << 8) -#define UHH_HOSTCONFIG_ENA_INCR_ALIGN (1UL << 5) -#define UHH_HOSTCONFIG_ENA_INCR16 (1UL << 4) -#define UHH_HOSTCONFIG_ENA_INCR8 (1UL << 3) -#define UHH_HOSTCONFIG_ENA_INCR4 (1UL << 2) -#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN (1UL << 1) -#define UHH_HOSTCONFIG_P1_ULPI_BYPASS (1UL << 0) - -/* The following are on rev2 (OMAP44xx) of the EHCI only */ -#define UHH_SYSCONFIG_IDLEMODE_MASK (3UL << 2) -#define UHH_SYSCONFIG_IDLEMODE_NOIDLE (1UL << 2) -#define UHH_SYSCONFIG_STANDBYMODE_MASK (3UL << 4) -#define UHH_SYSCONFIG_STANDBYMODE_NOSTDBY (1UL << 4) - -#define UHH_HOSTCONFIG_P1_MODE_MASK (3UL << 16) -#define UHH_HOSTCONFIG_P1_MODE_ULPI_PHY (0UL << 16) -#define UHH_HOSTCONFIG_P1_MODE_UTMI_PHY (1UL << 16) -#define UHH_HOSTCONFIG_P1_MODE_HSIC (3UL << 16) -#define UHH_HOSTCONFIG_P2_MODE_MASK (3UL << 18) -#define UHH_HOSTCONFIG_P2_MODE_ULPI_PHY (0UL << 18) -#define UHH_HOSTCONFIG_P2_MODE_UTMI_PHY (1UL << 18) -#define UHH_HOSTCONFIG_P2_MODE_HSIC (3UL << 18) - -#define ULPI_FUNC_CTRL_RESET (1 << 5) - -/*-------------------------------------------------------------------------*/ - -/* - * Macros for Set and Clear - * See ULPI 1.1 specification to find the registers with Set and Clear offsets - */ -#define ULPI_SET(a) (a + 1) -#define ULPI_CLR(a) (a + 2) - -/*-------------------------------------------------------------------------*/ - -/* - * Register Map - */ -#define ULPI_VENDOR_ID_LOW 0x00 -#define ULPI_VENDOR_ID_HIGH 0x01 -#define ULPI_PRODUCT_ID_LOW 0x02 -#define ULPI_PRODUCT_ID_HIGH 0x03 -#define ULPI_FUNC_CTRL 0x04 -#define ULPI_IFC_CTRL 0x07 -#define ULPI_OTG_CTRL 0x0a -#define ULPI_USB_INT_EN_RISE 0x0d -#define ULPI_USB_INT_EN_FALL 0x10 -#define ULPI_USB_INT_STS 0x13 -#define ULPI_USB_INT_LATCH 0x14 -#define ULPI_DEBUG 0x15 -#define ULPI_SCRATCH 0x16 - -/* - * Values of UHH_REVISION - Note: these are not given in the TRM but taken - * from the linux OMAP EHCI driver (thanks guys). It has been verified on - * a Panda and Beagle board. - */ -#define OMAP_EHCI_REV1 0x00000010 /* OMAP3 */ -#define OMAP_EHCI_REV2 0x50700100 /* OMAP4 */ - -#define EHCI_VENDORID_OMAP3 0x42fa05 -#define OMAP_EHCI_HC_DEVSTR "TI OMAP USB 2.0 controller" - #define EHCI_HCD_OMAP_MODE_UNKNOWN 0 #define EHCI_HCD_OMAP_MODE_PHY 1 #define EHCI_HCD_OMAP_MODE_TLL 2 #define EHCI_HCD_OMAP_MODE_HSIC 3 + +void omap_tll_utmi_enable(unsigned int en_mask); +int omap_usb_port_mode(device_t dev, int port); #endif /* _OMAP_USB_H_ */ Index: head/sys/boot/fdt/dts/arm/am335x.dtsi =================================================================== --- head/sys/boot/fdt/dts/arm/am335x.dtsi (revision 283275) +++ head/sys/boot/fdt/dts/arm/am335x.dtsi (nonexistent) @@ -1,349 +0,0 @@ -/*- - * Copyright (c) 2012 Damjan Marion - * 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$ - */ - -/ { - #address-cells = <1>; - #size-cells = <1>; - - interrupt-parent = <&AINTC>; - - SOC: am335x { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - ranges; - bus-frequency = <0>; - - AINTC: interrupt-controller@48200000 { - compatible = "ti,aintc"; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <1>; - reg = < 0x48200000 0x1000 >; - }; - - pmu { - compatible = "arm,cortex-a8-pmu"; - interrupts = <3>; - }; - - scm@44e10000 { - compatible = "ti,scm"; - reg = < 0x44e10000 0x2000 >; - }; - - prcm@44E00000 { - compatible = "am335x,prcm"; - #address-cells = <1>; - #size-cells = <1>; - reg = < 0x44E00000 0x1300 >; - }; - - dmtimers@44E05000 { - compatible = "ti,am335x-dmtimer"; - #address-cells = <1>; - #size-cells = <1>; - reg = < 0x44E05000 0x1000 - 0x44E31000 0x1000 - 0x48040000 0x1000 - 0x48042000 0x1000 - 0x48044000 0x1000 - 0x48046000 0x1000 - 0x48048000 0x1000 - 0x4804A000 0x1000 >; - interrupts = < 66 67 68 69 92 93 94 95 >; - interrupt-parent = <&AINTC>; - }; - - rtc: rtc@44E3E000 { - compatible = "ti,da830-rtc"; - reg = <0x44E3E000 0x1000>; - interrupts = < 75 76 >; - interrupt-parent = <&AINTC>; - }; - - adc0: adc@44E0D000 { - compatible = "ti,adc"; - reg = <0x44E0D000 0x2000>; - interrupts = < 16 >; - interrupt-parent = <&AINTC>; - }; - - wdt1@44E35000 { - compatible = "ti,omap3-wdt"; - reg = <0x44E35000 0x1000>; - interrupts = <91>; - interrupt-parent = <&AINTC>; - }; - - GPIO: gpio { - #gpio-cells = <3>; - compatible = "ti,gpio"; - gpio-controller; - reg =< 0x44E07000 0x1000 - 0x4804C000 0x1000 - 0x481AC000 0x1000 - 0x481AE000 0x1000 >; - interrupts = < 96 97 98 99 32 33 62 63 >; - interrupt-parent = <&AINTC>; - interrupt-controller; - #interrupt-cells = <1>; - }; - - uart0: serial@44E09000 { - compatible = "ti,ns16550"; - reg = <0x44E09000 0x1000>; - reg-shift = <2>; - interrupts = < 72 >; - interrupt-parent = <&AINTC>; - clock-frequency = < 48000000 >; - uart-device-id = < 0 >; - }; - - uart1: serial@48022000 { - compatible = "ti,ns16550"; - reg = <0x48022000 0x1000>; - reg-shift = <2>; - interrupts = < 73 >; - interrupt-parent = <&AINTC>; - clock-frequency = < 48000000 >; - uart-device-id = < 1 >; - status = "disabled"; - }; - - uart2: serial@48024000 { - compatible = "ti,ns16550"; - reg = <0x48024000 0x1000>; - reg-shift = <2>; - interrupts = < 74 >; - interrupt-parent = <&AINTC>; - clock-frequency = < 48000000 >; - uart-device-id = < 2 >; - status = "disabled"; - }; - - uart3: serial@481a6000 { - compatible = "ti,ns16550"; - reg = <0x481A6000 0x1000>; - reg-shift = <2>; - interrupts = < 44 >; - interrupt-parent = <&AINTC>; - clock-frequency = < 48000000 >; - uart-device-id = < 3 >; - status = "disabled"; - }; - - uart4: serial@481a8000 { - compatible = "ti,ns16550"; - reg = <0x481A8000 0x1000>; - reg-shift = <2>; - interrupts = < 45 >; - interrupt-parent = <&AINTC>; - clock-frequency = < 48000000 >; - uart-device-id = < 4 >; - status = "disabled"; - }; - - uart5: serial@481aa000 { - compatible = "ti,ns16550"; - reg = <0x481AA000 0x1000>; - reg-shift = <2>; - interrupts = < 46 >; - interrupt-parent = <&AINTC>; - clock-frequency = < 48000000 >; - uart-device-id = < 5 >; - status = "disabled"; - }; - - edma3@49000000 { - compatible = "ti,edma3"; - reg =< 0x49000000 0x100000 /* Channel Controller Regs */ - 0x49800000 0x100000 /* Transfer Controller 0 Regs */ - 0x49900000 0x100000 /* Transfer Controller 1 Regs */ - 0x49a00000 0x100000 >; /* Transfer Controller 2 Regs */ - interrupts = <12 13 14>; - interrupt-parent = <&AINTC>; - }; - - mmchs0@48060000 { - compatible = "ti,omap3-hsmmc", "ti,mmchs"; - reg =<0x48060000 0x1000 >; - interrupts = <64>; - interrupt-parent = <&AINTC>; - mmchs-device-id = <0>; - mmchs-wp-gpio-pin = <0xffffffff>; - ti,dual-volt; - }; - - mmchs1@481D8000 { - compatible = "ti,omap3-hsmmc", "ti,mmchs"; - reg =<0x481D8000 0x1000 >; - interrupts = <28>; - interrupt-parent = <&AINTC>; - mmchs-device-id = <1>; - mmchs-wp-gpio-pin = <0xffffffff>; - status = "disabled"; - }; - - enet0: ethernet@4A100000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "ti,cpsw"; - reg = <0x4A100000 0x4000>; - interrupts = <40 41 42 43>; - interrupt-parent = <&AINTC>; - phy-handle = <&phy0>; - mdio@0 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ti,cpsw-mdio"; - phy0: ethernet-phy@0 { - reg = <0x0>; - }; - }; - }; - - i2c0: i2c@44e0b000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ti,i2c"; - reg =< 0x44e0b000 0x1000 >; - interrupts = <70>; - interrupt-parent = <&AINTC>; - i2c-device-id = <0>; - }; - - i2c1: i2c@4802a000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ti,i2c"; - reg =< 0x4802a000 0x1000 >; - interrupts = <71>; - interrupt-parent = <&AINTC>; - i2c-device-id = <1>; - }; - - i2c2: i2c@4819c000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ti,i2c"; - reg =< 0x4819c000 0x1000 >; - interrupts = <30>; - interrupt-parent = <&AINTC>; - i2c-device-id = <2>; - }; - - pwm@48300000 { - compatible = "ti,am335x-pwm"; - #address-cells = <1>; - #size-cells = <1>; - reg = < 0x48300000 0x100 /* PWMSS0 */ - 0x48300100 0x80 /* eCAP0 */ - 0x48300180 0x80 /* eQEP0 */ - 0x48300200 0x60 /* ePWM0 */ - >; - interrupts = <86 58>; /* ePWM0INT, ePWM0_TZINT */ - interrupt-parent = <&AINTC>; - pwm-device-id = <0>; - }; - - pwm@48302000 { - compatible = "ti,am335x-pwm"; - #address-cells = <1>; - #size-cells = <1>; - reg = < 0x48302000 0x100 /* PWMSS1 */ - 0x48302100 0x80 /* eCAP1 */ - 0x48302180 0x80 /* eQEP1 */ - 0x48302200 0x60 /* ePWM1 */ - >; - interrupts = <87 59>; /* ePWM1INT, ePWM1_TZINT */ - interrupt-parent = <&AINTC>; - pwm-device-id = <1>; - }; - - pwm@48304000 { - compatible = "ti,am335x-pwm"; - #address-cells = <1>; - #size-cells = <1>; - reg = < 0x48304000 0x100 /* PWMSS2 */ - 0x48304100 0x80 /* eCAP2 */ - 0x48304180 0x80 /* eQEP2 */ - 0x48304200 0x60 /* ePWM2 */ - >; - interrupts = <88 60>; /* ePWM2INT, ePWM2_TZINT */ - interrupt-parent = <&AINTC>; - pwm-device-id = <2>; - }; - - lcd: lcd@4830e000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ti,am335x-lcd"; - reg =< 0x4830e000 0x1000 >; - interrupts = <36>; - interrupt-parent = <&AINTC>; - }; - - usb@47400000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ti,musb-am33xx"; - reg =< 0x47400000 0x1000 /* USBSS */ - 0x47401000 0x300 /* USB0 */ - 0x47401300 0x100 /* USB0_PHY */ - 0x47401400 0x400 /* USB0_CORE */ - 0x47401800 0x300 /* USB1 */ - 0x47401B00 0x100 /* USB1_PHY */ - 0x47401C00 0x400 /* USB1_CORE */ - >; - interrupts = <17 18 19>; - interrupt-parent = <&AINTC>; - /* 1 - Host Mode, 0 - Device Mode */ - modemask = <2>; - }; - - mbox0@480C8000 { - compatible = "am335x,system-mbox"; - reg = < 0x480C8000 0x1000 >; - interrupts = <77>; - interrupt-parent = <&AINTC>; - }; - - spinlock0@480CA000 { - compatible = "am335x,spinlock"; - reg = < 0x480CA000 0x1000 >; - }; - - pruss@4A300000 { - compatible = "ti,pruss-v2"; - reg = <0x4A300000 0x80000>; - interrupt-parent = <&AINTC>; - interrupts = <20 21 22 23 24 25 26 27>; - }; - }; -}; Property changes on: head/sys/boot/fdt/dts/arm/am335x.dtsi ___________________________________________________________________ Deleted: svn:eol-style ## -1 +0,0 ## -native \ No newline at end of property Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Deleted: svn:mime-type ## -1 +0,0 ## -text/plain \ No newline at end of property Index: head/sys/boot/fdt/dts/arm/am335x-evm.dts =================================================================== --- head/sys/boot/fdt/dts/arm/am335x-evm.dts (revision 283275) +++ head/sys/boot/fdt/dts/arm/am335x-evm.dts (revision 283276) @@ -1,183 +1,29 @@ /*- - * Copyright (c) 2012 Damjan Marion + * Copyright (c) 2015 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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$ */ -/dts-v1/; - -/include/ "am335x.dtsi" - -/ { - model = "TMDXEVM3358"; - compatible = "ti,am335x"; - - aliases { - soc = &SOC; - uart0 = &uart0; - }; - - memory { - device_type = "memory"; - reg = < 0x80000000 0x10000000 >; /* 256MB RAM */ - }; - - am335x { - scm@44e10000 { - /* Set of triplets < padname, muxname, padstate> */ - scm-pad-config = - /* I2C0 */ - "I2C0_SDA", "I2C0_SDA","i2c", - "I2C0_SCL", "I2C0_SCL","i2c", - /* Ethernet */ - "MII1_RX_ER", "gmii1_rxerr", "input_pulldown", - "MII1_TX_EN", "gmii1_txen", "output", - "MII1_RX_DV", "gmii1_rxdv", "input_pulldown", - "MII1_TXD3", "gmii1_txd3", "output", - "MII1_TXD2", "gmii1_txd2", "output", - "MII1_TXD1", "gmii1_txd1", "output", - "MII1_TXD0", "gmii1_txd0", "output", - "MII1_TX_CLK", "gmii1_txclk", "input_pulldown", - "MII1_RX_CLK", "gmii1_rxclk", "input_pulldown", - "MII1_RXD3", "gmii1_rxd3", "input_pulldown", - "MII1_RXD2", "gmii1_rxd2", "input_pulldown", - "MII1_RXD1", "gmii1_rxd1", "input_pulldown", - "MII1_RXD0", "gmii1_rxd0", "input_pulldown", - "MDIO", "mdio_data", "input_pullup", - "MDC", "mdio_clk", "output_pullup", - /* MMCSD0 */ - "MMC0_CMD", "mmc0_cmd", "input_pullup", - "MMC0_CLK", "mmc0_clk", "input_pullup", - "MMC0_DAT0", "mmc0_dat0", "input_pullup", - "MMC0_DAT1", "mmc0_dat1", "input_pullup", - "MMC0_DAT2", "mmc0_dat2", "input_pullup", - "MMC0_DAT3", "mmc0_dat3", "input_pullup", - /* GPIO */ - "GPMC_AD10", "gpio0_26", "input_pulldown", - "GPMC_AD11", "gpio0_27", "input_pulldown", - "GPMC_AD0", "gpio1_0", "input_pulldown", - "GPMC_AD1", "gpio1_1", "input_pulldown", - "GPMC_AD2", "gpio1_2", "input_pulldown", - "GPMC_AD3", "gpio1_3", "input_pulldown", - "GPMC_AD4", "gpio1_4", "input_pulldown", - "GPMC_AD5", "gpio1_5", "input_pulldown", - "GPMC_AD6", "gpio1_6", "input_pulldown", - "GPMC_AD7", "gpio1_7", "input_pulldown", - "GPMC_AD12", "gpio1_12", "input_pulldown", - "GPMC_AD13", "gpio1_13", "input_pulldown", - "GPMC_AD14", "gpio1_14", "input_pulldown", - "GPMC_AD15", "gpio1_15", "input_pulldown", - "GPMC_A0", "gpio1_16", "input_pulldown", - "GPMC_A1", "gpio1_17", "input_pulldown", - "GPMC_A5", "gpio1_21", "output", /* User LED 1 */ - "GPMC_A6", "gpio1_22", "output", /* User LED 2 */ - "GPMC_A7", "gpio1_23", "output", /* User LED 3 */ - "GPMC_A8", "gpio1_24", "output", /* User LED 4 */ - "GPMC_BEn1", "gpio1_28", "input_pulldown", - "GPMC_CSn0", "gpio1_29", "input_pulldown", - "GPMC_CSn1", "gpio1_30", "input_pulldown", - "GPMC_CSn2", "gpio1_31", "input_pulldown", - "MCASP0_FSR", "gpio3_19", "input_pulldown", - "MCASP0_AHCLKX", "gpio3_21", "input_pulldown", - /* TIMERs */ - "GPMC_ADVn_ALE", "timer4", "output", - "GPMC_BEn0_CLE", "timer5", "output", - "GPMC_WEn", "timer6", "output", - "GPMC_OEn_REn", "timer7", "output", - /* USB0 and USB1 */ - "USB0_DRVVBUS", "USB0_DRVVBUS", "output", - "USB1_DRVVBUS", "USB1_DRVVBUS", "output", - /* LCD */ - "GPMC_AD8", "lcd_data23", "output", - "GPMC_AD9", "lcd_data22", "output", - "GPMC_AD10", "lcd_data21", "output", - "GPMC_AD11", "lcd_data20", "output", - "GPMC_AD12", "lcd_data19", "output", - "GPMC_AD13", "lcd_data18", "output", - "GPMC_AD14", "lcd_data17", "output", - "GPMC_AD15", "lcd_data16", "output", - "GPMC_CLK", "lcd_memory_clk", "output", - "LCD_DATA0", "lcd_data0", "output", - "LCD_DATA1", "lcd_data1", "output", - "LCD_DATA2", "lcd_data2", "output", - "LCD_DATA3", "lcd_data3", "output", - "LCD_DATA4", "lcd_data4", "output", - "LCD_DATA5", "lcd_data5", "output", - "LCD_DATA6", "lcd_data6", "output", - "LCD_DATA7", "lcd_data7", "output", - "LCD_DATA8", "lcd_data8", "output", - "LCD_DATA9", "lcd_data9", "output", - "LCD_DATA10", "lcd_data10", "output", - "LCD_DATA11", "lcd_data11", "output", - "LCD_DATA12", "lcd_data12", "output", - "LCD_DATA13", "lcd_data13", "output", - "LCD_DATA14", "lcd_data14", "output", - "LCD_DATA15", "lcd_data15", "output", - "LCD_VSYNC", "lcd_vsync", "output", - "LCD_HSYNC", "lcd_hsync", "output", - "LCD_PCLK", "lcd_pclk", "output", - "LCD_AC_BIAS_EN", "lcd_ac_bias_en", "output", - "ECAP0_IN_PWM0_OUT", "eCAP0_in_PWM0_out", "output"; - - }; - - lcd@4830e000 { - panel_name = "TFC_S9700RTWV35TR_01B"; - panel_width = <800>; - panel_height = <480>; - panel_hfp = <39>; - panel_hbp = <39>; - panel_hsw = <47>; - panel_vfp = <13>; - panel_vbp = <29>; - panel_vsw = <2>; - panel_pxl_clk = <30000000>; - panel_invert_pxl_clk = <0>; - panel_type = <1>; /* Active or passive, compatibility */ - panel_max_bpp = <32>; /* compatibility */ - panel_min_bpp = <32>; /* compatibility */ - panel_shade = <1>; /* compatibility */ - ac_bias = <255>; - ac_bias_intrpt = <0>; - dma_burst_sz = <16>; - bpp = <32>; - fdd = <128>; - tft_alt_mode = <0>; /* compatiblity */ - stn_565_mode = <0>; /* compatibility */ - mono_8bit_mode = <0>; /* compatibilty */ - invert_line_clock = <1>; - invert_frm_clock = <1>; - sync_edge = <0>; - sync_ctrl = <1>; - raster_order = <0>; /* compatibity */ - }; - - }; - - chosen { - stdin = "uart0"; - stdout = "uart0"; - }; -}; +#include "am335x-evm.dts" Index: head/sys/boot/fdt/dts/arm/beaglebone-black.dts =================================================================== --- head/sys/boot/fdt/dts/arm/beaglebone-black.dts (revision 283275) +++ head/sys/boot/fdt/dts/arm/beaglebone-black.dts (revision 283276) @@ -1,186 +1,31 @@ /*- - * Copyright (c) 2012 Damjan Marion + * Copyright (c) 2015 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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$ */ -/dts-v1/; -/include/ "am335x.dtsi" - -/ { - model = "beaglebone-black"; - compatible = "beaglebone-black", "beaglebone", "ti,am335x"; - - - aliases { - soc = &SOC; - uart0 = &uart0; - }; - - memory { - device_type = "memory"; - reg = < 0x80000000 0x20000000 >; /* 512MB RAM */ - }; - - am335x { - scm@44e10000 { - /* Set of triplets < padname, muxname, padstate> */ - scm-pad-config = - /* I2C0 */ - "I2C0_SDA", "I2C0_SDA","i2c", - "I2C0_SCL", "I2C0_SCL","i2c", - /* I2C1 */ - "SPI0_D1", "I2C1_SDA", "i2c", - "SPI0_CS0", "I2C1_SCL", "i2c", - /* I2C2 */ - "UART1_CTSn", "I2C2_SDA", "i2c", - "UART1_RTSn", "I2C2_SCL", "i2c", - /* Ethernet */ - "MII1_RX_ER", "gmii1_rxerr", "input_pulldown", - "MII1_TX_EN", "gmii1_txen", "output", - "MII1_RX_DV", "gmii1_rxdv", "input_pulldown", - "MII1_TXD3", "gmii1_txd3", "output", - "MII1_TXD2", "gmii1_txd2", "output", - "MII1_TXD1", "gmii1_txd1", "output", - "MII1_TXD0", "gmii1_txd0", "output", - "MII1_TX_CLK", "gmii1_txclk", "input_pulldown", - "MII1_RX_CLK", "gmii1_rxclk", "input_pulldown", - "MII1_RXD3", "gmii1_rxd3", "input_pulldown", - "MII1_RXD2", "gmii1_rxd2", "input_pulldown", - "MII1_RXD1", "gmii1_rxd1", "input_pulldown", - "MII1_RXD0", "gmii1_rxd0", "input_pulldown", - "MDIO", "mdio_data", "input_pullup", - "MDC", "mdio_clk", "output_pullup", - /* MMCSD0 */ - "MMC0_CMD", "mmc0_cmd", "input_pullup", - "MMC0_CLK", "mmc0_clk", "input_pullup", - "MMC0_DAT0", "mmc0_dat0", "input_pullup", - "MMC0_DAT1", "mmc0_dat1", "input_pullup", - "MMC0_DAT2", "mmc0_dat2", "input_pullup", - "MMC0_DAT3", "mmc0_dat3", "input_pullup", - /* MMC1 */ - "GPMC_CSn1", "mmc1_clk", "input_pullup", - "GPMC_CSn2", "mmc1_cmd", "input_pullup", - "GPMC_CSn3", "gpio2_0", "output_pullup", /* Reset */ - "GPMC_AD0", "mmc1_dat0", "input_pullup", - "GPMC_AD1", "mmc1_dat1", "input_pullup", - "GPMC_AD2", "mmc1_dat2", "input_pullup", - "GPMC_AD3", "mmc1_dat3", "input_pullup", - "GPMC_AD4", "mmc1_dat4", "input_pullup", - "GPMC_AD5", "mmc1_dat5", "input_pullup", - "GPMC_AD6", "mmc1_dat6", "input_pullup", - "GPMC_AD7", "mmc1_dat7", "input_pullup", - /* GPIO */ - "ECAP0_IN_PWM0_OUT", "gpio0_7", "input_pulldown", - "GPMC_AD10", "gpio0_26", "input_pulldown", - "GPMC_AD11", "gpio0_27", "input_pulldown", - "GPMC_AD12", "gpio1_12", "input_pulldown", - "GPMC_AD13", "gpio1_13", "input_pulldown", - "GPMC_AD14", "gpio1_14", "input_pulldown", - "GPMC_AD15", "gpio1_15", "input_pulldown", - "GPMC_A0", "gpio1_16", "input_pulldown", - "GPMC_A1", "gpio1_17", "input_pulldown", - "GPMC_A5", "gpio1_21", "output", /* User LED 1 */ - "GPMC_A6", "gpio1_22", "output", /* User LED 2 */ - "GPMC_A7", "gpio1_23", "output", /* User LED 3 */ - "GPMC_A8", "gpio1_24", "output", /* User LED 4 */ - "GPMC_BEn1", "gpio1_28", "input_pulldown", - "GPMC_CSn0", "gpio1_29", "input_pulldown", - "GPMC_CLK", "gpio2_1", "input_pulldown", - "LCD_DATA0", "gpio2_6", "input_pulldown", - "LCD_DATA1", "gpio2_7", "input_pulldown", - "LCD_DATA2", "gpio2_8", "input_pulldown", - "LCD_DATA3", "gpio2_9", "input_pulldown", - "LCD_DATA4", "gpio2_10", "input_pulldown", - "LCD_DATA5", "gpio2_11", "input_pulldown", - "LCD_DATA6", "gpio2_12", "input_pulldown", - "LCD_DATA7", "gpio2_13", "input_pulldown", - "LCD_VSYNC", "gpio2_22", "input_pulldown", - "LCD_HSYNC", "gpio2_23", "input_pulldown", - "LCD_PCLK", "gpio2_24", "input_pulldown", - "LCD_AC_BIAS_EN", "gpio2_25", "input_pulldown", - "MCASP0_FSR", "gpio3_19", "input_pulldown", - "MCASP0_AHCLKX", "gpio3_21", "input_pulldown", - /* TIMERs */ - "GPMC_ADVn_ALE", "timer4", "output", - "GPMC_BEn0_CLE", "timer5", "output", - "GPMC_WEn", "timer6", "output", - "GPMC_OEn_REn", "timer7", "output", - /* USB0 and USB1 */ - "USB0_DRVVBUS", "USB0_DRVVBUS", "output", - "USB1_DRVVBUS", "USB1_DRVVBUS", "output", - /* PWM */ - "GPMC_A2", "ehrpwm1A", "output", - "GPMC_A3", "ehrpwm1B", "output", - "GPMC_AD8", "ehrpwm2A", "output", - "GPMC_AD9", "ehrpwm2B", "output"; - }; - - mmchs1@481D8000 { - bus-width = <8>; - status = "okay"; - non-removable; - }; - - i2c@44e0b000 { - pmic@48 { - compatible = "ti,am335x-pmic"; - reg = <0x48>; - interrupts = <7>; /* nNMI */ - interrupt-parent = <&AINTC>; - }; - }; - }; - - leds { - compatible = "gpio-leds"; - - led1 { - gpios = <&GPIO 53 2 0>; - name = "led1"; - }; - - led2 { - gpios = <&GPIO 54 2 0>; - name = "led2"; - }; - - led3 { - gpios = <&GPIO 55 2 0>; - name = "led3"; - }; - - led4 { - gpios = <&GPIO 56 2 0>; - name = "led4"; - }; - }; - - chosen { - stdin = "uart0"; - stdout = "uart0"; - }; -}; +#include "am335x-boneblack.dts" +#include "beaglebone-common.dtsi" Index: head/sys/boot/fdt/dts/arm/beaglebone-common.dtsi =================================================================== --- head/sys/boot/fdt/dts/arm/beaglebone-common.dtsi (nonexistent) +++ head/sys/boot/fdt/dts/arm/beaglebone-common.dtsi (revision 283276) @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2015 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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$ + */ + +/ { + ocp { + pruss@4A300000 { + compatible = "ti,pruss-v2"; + reg = <0x4A300000 0x80000>; + interrupt-parent = <&intc>; + interrupts = <20 21 22 23 24 25 26 27>; + }; + + }; + +}; + +&tps { + interrupt-parent = <&intc>; + interrupts = <7>; +}; Property changes on: head/sys/boot/fdt/dts/arm/beaglebone-common.dtsi ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/boot/fdt/dts/arm/beaglebone.dts =================================================================== --- head/sys/boot/fdt/dts/arm/beaglebone.dts (revision 283275) +++ head/sys/boot/fdt/dts/arm/beaglebone.dts (revision 283276) @@ -1,145 +1,30 @@ /*- - * Copyright (c) 2012 Damjan Marion + * Copyright (c) 2015 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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$ */ -/dts-v1/; - -/include/ "am335x.dtsi" - -/ { - model = "beaglebone"; - compatible = "beaglebone", "ti,am335x"; - - aliases { - soc = &SOC; - uart0 = &uart0; - }; - - memory { - device_type = "memory"; - reg = < 0x80000000 0x10000000 >; /* 256MB RAM */ - }; - - am335x { - scm@44e10000 { - /* Set of triplets < padname, muxname, padstate> */ - scm-pad-config = - /* I2C0 */ - "I2C0_SDA", "I2C0_SDA","i2c", - "I2C0_SCL", "I2C0_SCL","i2c", - /* Ethernet */ - "MII1_RX_ER", "gmii1_rxerr", "input_pulldown", - "MII1_TX_EN", "gmii1_txen", "output", - "MII1_RX_DV", "gmii1_rxdv", "input_pulldown", - "MII1_TXD3", "gmii1_txd3", "output", - "MII1_TXD2", "gmii1_txd2", "output", - "MII1_TXD1", "gmii1_txd1", "output", - "MII1_TXD0", "gmii1_txd0", "output", - "MII1_TX_CLK", "gmii1_txclk", "input_pulldown", - "MII1_RX_CLK", "gmii1_rxclk", "input_pulldown", - "MII1_RXD3", "gmii1_rxd3", "input_pulldown", - "MII1_RXD2", "gmii1_rxd2", "input_pulldown", - "MII1_RXD1", "gmii1_rxd1", "input_pulldown", - "MII1_RXD0", "gmii1_rxd0", "input_pulldown", - "MDIO", "mdio_data", "input_pullup", - "MDC", "mdio_clk", "output_pullup", - /* MMCSD0 */ - "MMC0_CMD", "mmc0_cmd", "input_pullup", - "MMC0_CLK", "mmc0_clk", "input_pullup", - "MMC0_DAT0", "mmc0_dat0", "input_pullup", - "MMC0_DAT1", "mmc0_dat1", "input_pullup", - "MMC0_DAT2", "mmc0_dat2", "input_pullup", - "MMC0_DAT3", "mmc0_dat3", "input_pullup", - /* USB0 and USB1 */ - "USB0_DRVVBUS", "USB0_DRVVBUS", "output", - "USB1_DRVVBUS", "USB1_DRVVBUS", "output", - /* GPIO */ - "ECAP0_IN_PWM0_OUT", "gpio0_7", "input_pulldown", - "GPMC_AD10", "gpio0_26", "input_pulldown", - "GPMC_AD11", "gpio0_27", "input_pulldown", - "GPMC_AD0", "gpio1_0", "input_pulldown", - "GPMC_AD1", "gpio1_1", "input_pulldown", - "GPMC_AD2", "gpio1_2", "input_pulldown", - "GPMC_AD3", "gpio1_3", "input_pulldown", - "GPMC_AD4", "gpio1_4", "input_pulldown", - "GPMC_AD5", "gpio1_5", "input_pulldown", - "GPMC_AD6", "gpio1_6", "input_pulldown", - "GPMC_AD7", "gpio1_7", "input_pulldown", - "GPMC_AD12", "gpio1_12", "input_pulldown", - "GPMC_AD13", "gpio1_13", "input_pulldown", - "GPMC_AD14", "gpio1_14", "input_pulldown", - "GPMC_AD15", "gpio1_15", "input_pulldown", - "GPMC_A0", "gpio1_16", "input_pulldown", - "GPMC_A1", "gpio1_17", "input_pulldown", - "GPMC_A5", "gpio1_21", "output", /* User LED 1 */ - "GPMC_A6", "gpio1_22", "output", /* User LED 2 */ - "GPMC_A7", "gpio1_23", "output", /* User LED 3 */ - "GPMC_A8", "gpio1_24", "output", /* User LED 4 */ - "GPMC_BEn1", "gpio1_28", "input_pulldown", - "GPMC_CSn0", "gpio1_29", "input_pulldown", - "GPMC_CSn1", "gpio1_30", "input_pulldown", - "GPMC_CSn2", "gpio1_31", "input_pulldown", - "GPMC_CLK", "gpio2_1", "input_pulldown", - "LCD_DATA0", "gpio2_6", "input_pulldown", - "LCD_DATA1", "gpio2_7", "input_pulldown", - "LCD_DATA2", "gpio2_8", "input_pulldown", - "LCD_DATA3", "gpio2_9", "input_pulldown", - "LCD_DATA4", "gpio2_10", "input_pulldown", - "LCD_DATA5", "gpio2_11", "input_pulldown", - "LCD_DATA6", "gpio2_12", "input_pulldown", - "LCD_DATA7", "gpio2_13", "input_pulldown", - "LCD_VSYNC", "gpio2_22", "input_pulldown", - "LCD_HSYNC", "gpio2_23", "input_pulldown", - "LCD_PCLK", "gpio2_24", "input_pulldown", - "LCD_AC_BIAS_EN", "gpio2_25", "input_pulldown", - "MCASP0_FSR", "gpio3_19", "input_pulldown", - "MCASP0_AHCLKX", "gpio3_21", "input_pulldown", - /* TIMERs */ - "GPMC_ADVn_ALE", "timer4", "output", - "GPMC_BEn0_CLE", "timer5", "output", - "GPMC_WEn", "timer6", "output", - "GPMC_OEn_REn", "timer7", "output", - /* PWM */ - "GPMC_A2", "ehrpwm1A", "output", - "GPMC_A3", "ehrpwm1B", "output", - "GPMC_AD8", "ehrpwm2A", "output", - "GPMC_AD9", "ehrpwm2B", "output"; - }; - - i2c@44e0b000 { - pmic@24 { - compatible = "ti,am335x-pmic"; - reg = <0x48>; - }; - }; - }; - - chosen { - stdin = "uart0"; - stdout = "uart0"; - }; -}; +#include "am335x-bone.dts" +#include "beaglebone-common.dtsi" Index: head/sys/boot/fdt/dts/arm/pandaboard-common.dtsi =================================================================== --- head/sys/boot/fdt/dts/arm/pandaboard-common.dtsi (nonexistent) +++ head/sys/boot/fdt/dts/arm/pandaboard-common.dtsi (revision 283276) @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2015 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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$ + */ + +&mmc1 { + non-removable; /* XXX need real solution */ +}; + +&mmc5 { + status = "disabled"; +}; + +/ { + ocp { + global-timer@48240600 { + compatible = "arm,cortex-a9-global-timer"; + reg = <0x48240200 0x20>; + interrupts = ; + }; + }; + chosen { + stdin = "serial2"; + stdout = "serial2"; + }; +}; Property changes on: head/sys/boot/fdt/dts/arm/pandaboard-common.dtsi ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/boot/fdt/dts/arm/pandaboard-es.dts =================================================================== --- head/sys/boot/fdt/dts/arm/pandaboard-es.dts (nonexistent) +++ head/sys/boot/fdt/dts/arm/pandaboard-es.dts (revision 283276) @@ -0,0 +1,31 @@ +/*- + * Copyright (c) 2015 Oleksandr Tymoshenko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + + +#include "omap4-panda-es.dts" +#include "pandaboard-common.dtsi" Property changes on: head/sys/boot/fdt/dts/arm/pandaboard-es.dts ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/boot/fdt/dts/arm/pandaboard.dts =================================================================== --- head/sys/boot/fdt/dts/arm/pandaboard.dts (revision 283275) +++ head/sys/boot/fdt/dts/arm/pandaboard.dts (revision 283276) @@ -1,186 +1,31 @@ /*- - * Copyright (c) 2011 The FreeBSD Foundation + * Copyright (c) 2015 Oleksandr Tymoshenko * All rights reserved. * - * Developed by Damjan Marion - * * 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$ */ -/dts-v1/; -/ { - model = "pandaboard"; - compatible = "pandaboard", "ti,omap4430"; - #address-cells = <1>; - #size-cells = <1>; - - interrupt-parent = <&GIC>; - - aliases { - soc = &SOC; - uart3 = &uart3; - }; - - memory { - device_type = "memory"; - reg = < 0x80000000 0x40000000 >; /* 1GB RAM at 0x0 */ - }; - - SOC: omap4430 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - ranges; - bus-frequency = <0>; - - GIC: interrupt-controller@48241000 { - compatible = "arm,gic"; - interrupt-controller; - #address-cells = <0>; - #interrupt-cells = <1>; - reg = < 0x48241000 0x1000 >, /* Distributor Registers */ - < 0x48240100 0x0100 >; /* CPU Interface Registers */ - }; - - omap4_prcm@4a306000 { - compatible = "ti,omap4_prcm"; - reg =< 0x4a306000 0x2000 - 0x4a004000 0x1000 - 0x4a008000 0x8000>; - }; - - pl310@48242000 { - compatible = "arm,pl310"; - reg = < 0x48242000 0x1000 >; - interrupts = < 32 >; - interrupt-parent = < &GIC >; - }; - mp_tmr@48240200 { - compatible = "arm,mpcore-timers"; - #address-cells = <1>; - #size-cells = <0>; - reg = < 0x48240200 0x100 >, /* Global Timer Registers */ - < 0x48240600 0x100 >; /* Private Timer Registers */ - interrupts = < 27 29 >; - interrupt-parent = < &GIC >; - }; - - uart3: serial@48020000 { - compatible = "ns16550"; - reg = <0x48020000 0x1000>; - reg-shift = <2>; - interrupts = < 106 >; - interrupt-parent = <&GIC>; - clock-frequency = < 48000000 >; /* 48Mhz clock for all uarts */ - /* (techref 17.3.1.1) */ - }; - - scm@4a100000 { - compatible = "ti,scm"; - reg = < 0x4a100000 0x1000 >; - /* Set of triplets < padname, muxname, padstate> */ - scm-pad-config = - "ag19", "usbb1_ulpiphy_stp", "output", - "ae18", "usbb1_ulpiphy_clk", "input_pulldown", - "af19", "usbb1_ulpiphy_dir", "input_pulldown", - "ae19", "usbb1_ulpiphy_nxt", "input_pulldown", - "af18", "usbb1_ulpiphy_dat0", "input_pulldown", - "ag18", "usbb1_ulpiphy_dat1", "input_pulldown", - "ae17", "usbb1_ulpiphy_dat2", "input_pulldown", - "af17", "usbb1_ulpiphy_dat3", "input_pulldown", - "ah17", "usbb1_ulpiphy_dat4", "input_pulldown", - "ae16", "usbb1_ulpiphy_dat5", "input_pulldown", - "af16", "usbb1_ulpiphy_dat6", "input_pulldown", - "ag16", "usbb1_ulpiphy_dat7", "input_pulldown"; - }; - - GPIO: gpio { - #gpio-cells = <3>; - compatible = "ti,gpio"; - gpio-controller; - reg =< 0x4a310000 0x1000 - 0x48055000 0x1000 - 0x48057000 0x1000 - 0x48059000 0x1000 - 0x4805b000 0x1000 - 0x4805d000 0x1000>; - interrupts = <61 62 63 64 65 66>; - interrupt-parent = <&GIC>; - }; - - ehci { - compatible = "ti,usb-ehci", "usb-ehci"; - /* - * USB port PHY configuration is a tuple: - * mode is one of the following values: - * 0 - unknown - * 1 - PHY - * 2 - TLL - * 3 - HSIC - * - * reset indicates (if non-zero) if port reset is required - * gpio_pin - GPIO pin that is used to perform reset - */ - phy-config = < 1 0 0 - 0 0 0 - 0 0 0>; - reg = < 0x4a064c00 0x100 /* EHCI regs */ - 0x4a064000 0x700 /* UHH regs */ - 0x4a062000 0x1000>; /* TLL regs */ - interrupts = <109>; - interrupt-parent = <&GIC>; - }; - - I2C1: i2c@x48070000 { - compatible = "ti,i2c"; - reg =< 0x48070000 0x100 >; - interrupts = <88>; - interrupt-parent = <&GIC>; - i2c-device-id = <1>; - }; - - sdma@x48070000 { - compatible = "ti,sdma"; - reg =< 0x4A056000 0x1000 >; - interrupts = <44 45 46 47>; - interrupt-parent = <&GIC>; - }; - - mmc@x4809C000 { - compatible = "ti,mmchs"; - reg =<0x4809C000 0x1000 >; - interrupts = <115>; - interrupt-parent = <&GIC>; - mmchs-device-id = <1>; - non-removable; /* XXX need real solution */ - }; - - }; - - chosen { - stdin = "uart3"; - stdout = "uart3"; - }; -}; +#include "omap4-panda.dts" +#include "pandaboard-common.dtsi" Index: head/sys/dev/uart/uart_dev_ti8250.c =================================================================== --- head/sys/dev/uart/uart_dev_ti8250.c (revision 283275) +++ head/sys/dev/uart/uart_dev_ti8250.c (revision 283276) @@ -1,147 +1,136 @@ /*- * Copyright (c) 2013 Ian Lepore * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include "uart_if.h" /* * High-level UART interface. */ struct ti8250_softc { struct ns8250_softc ns8250_base; /*uint32_t mystuff;*/ }; #define MDR1_REG 8 #define MDR1_MODE_UART 0 #define MDR1_MODE_DISABLE 7 #define SYSCC_REG 15 #define SYSCC_SOFTRESET (1 << 1) #define SYSS_REG 16 #define SYSS_STATUS_RESETDONE (1 << 0) static int ti8250_bus_probe(struct uart_softc *sc) { int status; - int devid; clk_ident_t clkid; - pcell_t prop; - phandle_t node; - /* - * Get the device id from FDT. If it's not there we can't turn on the - * right clocks, so bail, unless we're doing unit 0. We assume that's - * the serial console, whose clock isn't controllable anyway, and we - * sure don't want to break the console because of a config error. - */ - node = ofw_bus_get_node(sc->sc_dev); - if ((OF_getprop(node, "uart-device-id", &prop, sizeof(prop))) <= 0) { - device_printf(sc->sc_dev, - "missing uart-device-id attribute in FDT\n"); - if (device_get_unit(sc->sc_dev) != 0) - return (ENXIO); - devid = 0; - } else - devid = fdt32_to_cpu(prop); - /* Enable clocks for this device. We can't continue if that fails. */ - clkid = UART0_CLK + devid; + clkid = ti_hwmods_get_clock(sc->sc_dev); + if (clkid == INVALID_CLK_IDENT) { + device_printf(sc->sc_dev, + "failed to get clock based on hwmods\n"); + clkid = UART1_CLK + device_get_unit(sc->sc_dev); + } if ((status = ti_prcm_clk_enable(clkid)) != 0) return (status); /* * Set the hardware to disabled mode, do a full device reset, then set * it to uart mode. Most devices will be reset-and-disabled already, * but you never know what a bootloader might have done. */ uart_setreg(&sc->sc_bas, MDR1_REG, MDR1_MODE_DISABLE); uart_setreg(&sc->sc_bas, SYSCC_REG, SYSCC_SOFTRESET); while (uart_getreg(&sc->sc_bas, SYSS_REG) & SYSS_STATUS_RESETDONE) continue; uart_setreg(&sc->sc_bas, MDR1_REG, MDR1_MODE_UART); status = ns8250_bus_probe(sc); if (status == 0) device_set_desc(sc->sc_dev, "TI UART (16550 compatible)"); return (status); } static kobj_method_t ti8250_methods[] = { KOBJMETHOD(uart_probe, ti8250_bus_probe), KOBJMETHOD(uart_attach, ns8250_bus_attach), KOBJMETHOD(uart_detach, ns8250_bus_detach), KOBJMETHOD(uart_flush, ns8250_bus_flush), KOBJMETHOD(uart_getsig, ns8250_bus_getsig), KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl), KOBJMETHOD(uart_ipend, ns8250_bus_ipend), KOBJMETHOD(uart_param, ns8250_bus_param), KOBJMETHOD(uart_receive, ns8250_bus_receive), KOBJMETHOD(uart_setsig, ns8250_bus_setsig), KOBJMETHOD(uart_transmit, ns8250_bus_transmit), KOBJMETHOD_END }; static struct uart_class uart_ti8250_class = { "ti8250", ti8250_methods, sizeof(struct ti8250_softc), .uc_ops = &uart_ns8250_ops, .uc_range = 0x88, .uc_rclk = 48000000, - .uc_rshift = 0 + .uc_rshift = 2 }; static struct ofw_compat_data compat_data[] = { {"ti,ns16550", (uintptr_t)&uart_ti8250_class}, + {"ti,omap3-uart", (uintptr_t)&uart_ti8250_class}, + {"ti,omap4-uart", (uintptr_t)&uart_ti8250_class}, {NULL, (uintptr_t)NULL}, }; UART_FDT_CLASS_AND_DEVICE(compat_data);